Skip to content

Commit

Permalink
Address comments
Browse files Browse the repository at this point in the history
Signed-off-by: Sheng Chen <sheche@microsoft.com>
  • Loading branch information
jdneo committed Nov 13, 2023
1 parent 6b85b7f commit 9bd874c
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 59 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@
"javaBuildTools": [
{
"displayName": "Maven",
"fileSearchPattern": "**/pom.xml"
"buildFileNames": ["pom.xml"]
},
{
"displayName": "Gradle",
"fileSearchPattern": "**/{build,settings}.gradle*"
"buildFileNames": ["build.gradle", "settings.gradle", "build.gradle.kts", "settings.gradle.kts"]
}
],
"semanticTokenTypes": [
Expand Down
9 changes: 6 additions & 3 deletions schemas/package.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
"description": "The display name of the build file type.",
"type": "string"
},
"fileSearchPattern": {
"description": "The glob pattern used to search the build files.",
"type": "string"
"buildFileNames": {
"description": "The build file names that supported by the build tool.",
"type": "array",
"items": {
"type": "string"
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/apiManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Emitter } from "vscode-languageclient";
import { ServerMode } from "./settings";
import { registerHoverCommand } from "./hoverAction";
import { onDidRequestEnd, onWillRequestStart } from "./TracingLanguageClient";
import { getJavaConfiguration } from "./utils";

class ApiManager {

Expand All @@ -22,6 +23,11 @@ class ApiManager {
private serverReadyPromiseResolve: (result: boolean) => void;

public initialize(requirements: RequirementsData, serverMode: ServerMode): void {
// if it's manual import mode, set the server mode to lightwight, so that the
// project explorer won't spinning until import project is triggered.
if (getJavaConfiguration().get<string>("import.projectSelection") === "manual") {
serverMode = ServerMode.lightWeight;
}
const getDocumentSymbols: GetDocumentSymbolsCommand = getDocumentSymbolsProvider();
const goToDefinition: GoToDefinitionCommand = goToDefinitionProvider();

Expand Down
132 changes: 82 additions & 50 deletions src/buildFilesSelector.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { ExtensionContext, MessageItem, QuickPickItem, QuickPickItemKind, Uri, WorkspaceFolder, extensions, window, workspace } from "vscode";
import { getExclusionGlob as getExclusionGlobPattern } from "./utils";
import { convertToGlob, getExclusionGlob as getExclusionGlobPattern, getInclusionPatternsFromNegatedExclusion } from "./utils";
import * as path from "path";

export const PICKED_BUILD_FILES = "java.pickedBuildFiles";
export class BuildFileSelector {
private buildTypes: IBuildTool[] = [];
private context: ExtensionContext;
private exclusionGlobPattern: string;
// cached glob pattern for build files.
private searchPattern: string;
// cached glob pattern for build files that are explicitly
// included from the setting: "java.import.exclusions" (negated exclusion).
private negatedExclusionSearchPattern: string | undefined;

constructor(context: ExtensionContext) {
this.context = context;
Expand All @@ -26,18 +31,34 @@ export class BuildFileSelector {
this.buildTypes.push(buildType);
}
}
this.searchPattern = `**/{${this.buildTypes.map(buildType => buildType.buildFileNames.join(","))}}`;
const inclusionFolderPatterns: string[] = getInclusionPatternsFromNegatedExclusion();
if (inclusionFolderPatterns.length > 0) {
const buildFileNames: string[] = [];
this.buildTypes.forEach(buildType => buildFileNames.push(...buildType.buildFileNames));
this.negatedExclusionSearchPattern = convertToGlob(buildFileNames, inclusionFolderPatterns);
}
}

/**
* @returns `true` if there are build files in the workspace, `false` otherwise.
*/
public async hasBuildFiles(): Promise<boolean> {
for (const buildType of this.buildTypes) {
const uris: Uri[] = await workspace.findFiles(buildType.fileSearchPattern, this.exclusionGlobPattern, 1);
if (this.buildTypes.length === 0) {
return false;
}

let uris: Uri[];
if (this.negatedExclusionSearchPattern) {
uris = await workspace.findFiles(this.negatedExclusionSearchPattern, null /* force not use default exclusion */, 1);
if (uris.length > 0) {
return true;
}
}
uris = await workspace.findFiles(this.searchPattern, this.exclusionGlobPattern, 1);
if (uris.length > 0) {
return true;
}
return false;
}

Expand All @@ -61,7 +82,7 @@ export class BuildFileSelector {
}

private isValidBuildTypeConfiguration(buildType: IBuildTool): boolean {
return !!buildType.displayName && !!buildType.fileSearchPattern;
return !!buildType.displayName && !!buildType.buildFileNames;
}

private async chooseBuildFilePickers(): Promise<IBuildFilePicker[]> {
Expand All @@ -80,26 +101,31 @@ export class BuildFileSelector {
*/
private async getBuildFilePickers(): Promise<IBuildFilePicker[]> {
const addedFolders: Map<string, IBuildFilePicker> = new Map<string, IBuildFilePicker>();
for (const buildType of this.buildTypes) {
const uris: Uri[] = await workspace.findFiles(buildType.fileSearchPattern, this.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<IBuildTool, Uri>([[buildType, uri]]),
picked: true,
});
const uris: Uri[] = await workspace.findFiles(this.searchPattern, this.exclusionGlobPattern);
if (this.negatedExclusionSearchPattern) {
uris.push(...await workspace.findFiles(this.negatedExclusionSearchPattern, null /* force not use default exclusion */));
}
for (const uri of uris) {
const buildType = this.buildTypes.find(buildType => buildType.buildFileNames.includes(path.basename(uri.fsPath)));
if (!buildType) {
continue;
}
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<IBuildTool, Uri>([[buildType, uri]]),
picked: true,
});
}
}
const pickers: IBuildFilePicker[] = Array.from(addedFolders.values());
Expand Down Expand Up @@ -153,39 +179,45 @@ export class BuildFileSelector {
if (!choice) {
return [];
}
const conflictPickers = new Set<IBuildFilePicker>();
const conflictBuildTypeAndUris = new Map<IBuildTool, Uri[]>();
const result: string[] = [];
for (const picker of choice) {
if (picker.buildTypeAndUri.size > 1) {
conflictPickers.add(picker);
for (const [buildType, uri] of picker.buildTypeAndUri) {
if (!conflictBuildTypeAndUris.has(buildType)) {
conflictBuildTypeAndUris.set(buildType, []);
}
conflictBuildTypeAndUris.get(buildType)?.push(uri);
}
} 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());
}
if (conflictBuildTypeAndUris.size > 0) {
const conflictItems: IConflictItem[] = [];
for (const buildType of conflictBuildTypeAndUris.keys()) {
conflictItems.push({
title: buildType.displayName,
uris: conflictBuildTypeAndUris.get(buildType),
});
}
conflictItems.sort((a, b) => a.title.localeCompare(b.title));
conflictItems.push({
title: "Skip",
isCloseAffordance: true,
});

const choice = await window.showInformationMessage<IConflictItem>(
"Which build tool would you like to use for the workspace?",
{
modal: true,
},
...conflictItems
);

if (choice?.title !== "Skip" && choice?.uris) {
result.push(...choice.uris.map(uri => uri.toString()));
}
}
return result;
Expand All @@ -194,11 +226,11 @@ export class BuildFileSelector {

interface IBuildTool {
displayName: string;
fileSearchPattern: string;
buildFileNames: string[];
}

interface IConflictItem extends MessageItem {
uri?: Uri;
uris?: Uri[];
}

interface IBuildFilePicker extends QuickPickItem {
Expand Down
1 change: 1 addition & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ async function startStandardServer(context: ExtensionContext, requirements: requ
}
if (buildFiles.length === 0) {
// cancelled by user
commands.executeCommand('setContext', 'java:serverMode', ServerMode.lightWeight);
serverStatusBarProvider.showNotImportedStatus();
return;
}
Expand Down
7 changes: 3 additions & 4 deletions src/languageStatusItemFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ export namespace StatusCommands {
};

export const startStandardServerCommand = {
title: "Load Projects",
title: "Select Projects...",
command: Commands.SWITCH_SERVER_MODE,
arguments: ['Standard', true],
tooltip: "Load Projects"
tooltip: "Select Projects..."
};
}

Expand All @@ -66,8 +66,7 @@ export namespace ServerStatusItemFactory {

export function showNotImportedStatus(item: any): void {
item.severity = vscode.LanguageStatusSeverity?.Warning;
item.text = StatusIcon.notImported;
item.detail = "No projects are Imported";
item.text = "No projects are imported";
item.command = StatusCommands.startStandardServerCommand;
}

Expand Down

0 comments on commit 9bd874c

Please sign in to comment.