-
Notifications
You must be signed in to change notification settings - Fork 446
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add capability to select projects to be imported
Signed-off-by: Sheng Chen <[email protected]>
- Loading branch information
Showing
10 changed files
with
332 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
import { ExtensionContext, MessageItem, QuickPickItem, QuickPickItemKind, Uri, WorkspaceFolder, extensions, window, workspace } from "vscode"; | ||
import { getExclusionGlob as getExclusionGlobPattern } from "./utils"; | ||
import * as path from "path"; | ||
|
||
const PICKED_BUILD_FILES = "java.pickedBuildFiles"; | ||
export class BuildFileSelector { | ||
private buildTypes: IBuildType[] = []; | ||
private context: ExtensionContext; | ||
|
||
constructor(context: ExtensionContext) { | ||
this.context = context; | ||
for (const extension of extensions.all) { | ||
const javaBuildTypes: IBuildType[] = extension.packageJSON.contributes?.javaBuildTypes; | ||
if (!Array.isArray(javaBuildTypes)) { | ||
continue; | ||
} | ||
|
||
for (const buildType of javaBuildTypes) { | ||
if (!this.isValidBuildTypeConfiguration(buildType)) { | ||
continue; | ||
} | ||
|
||
if (buildType.controlledBy && !workspace.getConfiguration().get(buildType.controlledBy)) { | ||
continue; | ||
} | ||
|
||
this.buildTypes.push(buildType); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Get the uri strings for the build files that the user selected. | ||
*/ | ||
public async getBuildFiles(): Promise<string[]> { | ||
const cache = this.context.workspaceState.get<string[]>(PICKED_BUILD_FILES); | ||
if (cache !== undefined) { | ||
return cache; | ||
} | ||
|
||
const pickers = await this.getBuildFilePickers(); | ||
const choice = await this.chooseBuildFilePickers(pickers); | ||
const pickedUris = await this.ensureNoBuildToolConflict(choice); | ||
if (pickedUris.length > 0) { | ||
this.context.workspaceState.update(PICKED_BUILD_FILES, pickedUris); | ||
} | ||
return pickedUris; | ||
} | ||
|
||
private isValidBuildTypeConfiguration(buildType: IBuildType): boolean { | ||
return !!buildType.displayName && !!buildType.fileSearchPattern; | ||
} | ||
|
||
private async getBuildFilePickers(): Promise<IBuildFilePicker[]> { | ||
// TODO: should we introduce the exclusion globs into the contribution point? | ||
const exclusionGlobPattern: string = getExclusionGlobPattern(["**/target/**", "**/bin/**", "**/build/**"]); | ||
const addedFolders: Map<string, IBuildFilePicker> = new Map<string, IBuildFilePicker>(); | ||
for (const buildType of this.buildTypes) { | ||
const uris: Uri[] = await workspace.findFiles(buildType.fileSearchPattern, exclusionGlobPattern); | ||
for (const uri of uris) { | ||
const containingFolder = path.dirname(uri.fsPath); | ||
if (addedFolders.has(containingFolder)) { | ||
const picker = addedFolders.get(containingFolder); | ||
if (!picker.buildTypeAndUri.has(buildType)) { | ||
picker.detail += `, ./${workspace.asRelativePath(uri)}`; | ||
picker.description += `, ${buildType.displayName}`; | ||
picker.buildTypeAndUri.set(buildType, uri); | ||
} | ||
} else { | ||
addedFolders.set(containingFolder, { | ||
label: path.basename(containingFolder), | ||
detail: `./${workspace.asRelativePath(uri)}`, | ||
description: buildType.displayName, | ||
buildTypeAndUri: new Map<IBuildType, Uri>([[buildType, uri]]), | ||
picked: true, | ||
}); | ||
} | ||
} | ||
} | ||
const pickers: IBuildFilePicker[] = Array.from(addedFolders.values()); | ||
return pickers; | ||
} | ||
|
||
private async chooseBuildFilePickers(pickers: IBuildFilePicker[]): Promise<IBuildFilePicker[]> { | ||
// group pickers by their containing workspace folder | ||
const workspaceFolders = new Map<WorkspaceFolder, IBuildFilePicker[]>(); | ||
for (const picker of pickers) { | ||
const folder = workspace.getWorkspaceFolder(picker.buildTypeAndUri.values().next().value); | ||
if (!folder) { | ||
continue; | ||
} | ||
if (!workspaceFolders.has(folder)) { | ||
workspaceFolders.set(folder, []); | ||
} | ||
workspaceFolders.get(folder)?.push(picker); | ||
} | ||
|
||
let needPick = false; | ||
const newPickers: IBuildFilePicker[] = []; | ||
for (const [folder, pickersInFolder] of workspaceFolders.entries()) { | ||
if (pickersInFolder.length > 1) { | ||
needPick = true; | ||
} | ||
newPickers.push({ | ||
label: folder.name, | ||
kind: QuickPickItemKind.Separator, | ||
buildTypeAndUri: null | ||
}); | ||
newPickers.push(...this.sortPickers(pickersInFolder)); | ||
} | ||
|
||
if (needPick) { | ||
return window.showQuickPick(newPickers, { | ||
placeHolder: "Select build file to import", | ||
ignoreFocusOut: true, | ||
canPickMany: true, | ||
matchOnDescription: true, | ||
matchOnDetail: true, | ||
}); | ||
} | ||
|
||
return pickers; | ||
} | ||
|
||
private sortPickers(pickers: IBuildFilePicker[]): IBuildFilePicker[] { | ||
return pickers.sort((a, b) => { | ||
const pathA = path.dirname(a.buildTypeAndUri.values().next().value.fsPath); | ||
const pathB = path.dirname(b.buildTypeAndUri.values().next().value.fsPath); | ||
return pathA.localeCompare(pathB); | ||
}); | ||
} | ||
|
||
private async ensureNoBuildToolConflict(choice?: IBuildFilePicker[]): Promise<string[]> { | ||
if (!choice) { | ||
return []; | ||
} | ||
const conflictPickers = new Set<IBuildFilePicker>(); | ||
const result: string[] = []; | ||
for (const picker of choice) { | ||
if (picker.buildTypeAndUri.size > 1) { | ||
conflictPickers.add(picker); | ||
} else { | ||
result.push(picker.buildTypeAndUri.values().next().value.toString()); | ||
} | ||
} | ||
|
||
if (conflictPickers.size > 0) { | ||
for (const picker of conflictPickers) { | ||
const conflictItems: IConflictItem[] = [{ | ||
title: "Skip", | ||
isCloseAffordance: true, | ||
}]; | ||
for (const buildType of picker.buildTypeAndUri.keys()) { | ||
conflictItems.push({ | ||
title: buildType.displayName, | ||
uri: picker.buildTypeAndUri.get(buildType), | ||
}); | ||
} | ||
const choice = await window.showInformationMessage<IConflictItem>( | ||
`Which build tool would you like to use for folder: ${picker.label}?`, | ||
{ | ||
modal: true, | ||
}, | ||
...conflictItems | ||
); | ||
|
||
if (choice?.title !== "Skip" && choice?.uri) { | ||
result.push(choice.uri.toString()); | ||
} | ||
} | ||
} | ||
return result; | ||
} | ||
} | ||
|
||
interface IBuildType { | ||
displayName: string; | ||
fileSearchPattern: string; | ||
controlledBy: string | undefined; | ||
} | ||
|
||
interface IConflictItem extends MessageItem { | ||
uri?: Uri; | ||
} | ||
|
||
interface IBuildFilePicker extends QuickPickItem { | ||
buildTypeAndUri: Map<IBuildType, Uri>; | ||
} | ||
|
||
export function cleanupProjectPickerCache(context: ExtensionContext) { | ||
context.workspaceState.update(PICKED_BUILD_FILES, undefined); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.