From c7455aea64c63a6260c7326915f6751b0911cb6c Mon Sep 17 00:00:00 2001 From: Shi Chen Date: Tue, 22 Mar 2022 21:48:24 +0800 Subject: [PATCH] update language client to 8.0.2 Signed-off-by: Shi Chen --- package-lock.json | 84 ++- package.json | 6 +- src/clientErrorHandler.ts | 26 +- src/extension.ts | 33 +- src/fileEventHandler.ts | 2 +- src/pasteEventHandler.ts | 2 +- src/providerDispatcher.ts | 4 +- src/refactorAction.ts | 2 +- src/sourceAction.ts | 2 +- src/standardLanguageClient.ts | 853 ++++++++++++++--------------- src/standardLanguageClientUtils.ts | 4 +- src/syntaxLanguageClient.ts | 58 +- 12 files changed, 541 insertions(+), 535 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c199d5642..624538eac1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -301,7 +301,7 @@ }, "@types/sinon": { "version": "10.0.13", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", "dev": true, "requires": { @@ -871,7 +871,7 @@ }, "ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, @@ -1453,7 +1453,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { @@ -2140,7 +2140,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true } @@ -2325,7 +2325,7 @@ }, "escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, @@ -3685,7 +3685,7 @@ "dependencies": { "request": { "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/request/-/request-2.88.2.tgz", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { @@ -3713,7 +3713,7 @@ }, "request-progress": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", "dev": true, "requires": { @@ -3730,7 +3730,7 @@ }, "gulp-util": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", "integrity": "sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw==", "dev": true, "requires": { @@ -3756,19 +3756,19 @@ "dependencies": { "clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true }, "clone-stats": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", "dev": true }, "lodash.template": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==", "dev": true, "requires": { @@ -3785,19 +3785,19 @@ }, "object-assign": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", "dev": true }, "replace-ext": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", "dev": true }, "vinyl": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==", "dev": true, "requires": { @@ -3844,7 +3844,7 @@ }, "has-ansi": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, "requires": { @@ -4869,7 +4869,7 @@ }, "minimist": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, @@ -6580,7 +6580,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true }, @@ -7254,46 +7254,34 @@ "vinyl": "^2.0.0" } }, + "vscode-jsonrpc": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", + "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==" + }, "vscode-languageclient": { - "version": "7.1.0-next.5", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.1.0-next.5.tgz", - "integrity": "sha512-TpzpAhpdCNJHaLzptFRs54xsU6xTmaiVPCse0W0rRB5jJBPjOBKilrFPMMm/sJA0y8Yxa9sOvZaNu6WPg3dYAw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz", + "integrity": "sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q==", "requires": { "minimatch": "^3.0.4", - "semver": "^7.3.4", - "vscode-languageserver-protocol": "3.17.0-next.6" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - } + "semver": "^7.3.5", + "vscode-languageserver-protocol": "3.17.2" } }, "vscode-languageserver-protocol": { - "version": "3.17.0-next.6", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.6.tgz", - "integrity": "sha512-f1kGsoOpISB5jSqQNeMDl2446enxVahyux2e5vZap6pu/TC+2UlvPT4DCR0gPph95KOQZweL9zq1SzLoPdqhuA==", + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz", + "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==", "requires": { - "vscode-jsonrpc": "7.0.0-next.1", - "vscode-languageserver-types": "3.17.0-next.2" - }, - "dependencies": { - "vscode-jsonrpc": { - "version": "7.0.0-next.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-7.0.0-next.1.tgz", - "integrity": "sha512-dEmliPZGbSyIcEeKRGzosCy7y7zsc8FXg1l5BBOGgMUbemlo3vUnsa2GFqpILJwJvlbvkRcF2QASNwIlKe9J7g==" - } + "vscode-jsonrpc": "8.0.2", + "vscode-languageserver-types": "3.17.2" } }, "vscode-languageserver-types": { - "version": "3.17.0-next.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.2.tgz", - "integrity": "sha512-L5S2kNLCgYJMVWgsZjBaorMM/6+itAfvOyl6Kv1bgFzDNaUKm9HsnUlehjpWPdV5DqnfJhJ5E03Z+/3Mw8ii+Q==" + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", + "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" }, "watchpack": { "version": "2.1.1", @@ -7637,7 +7625,7 @@ }, "yargs-parser": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "resolved": "https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", "dev": true, "requires": { diff --git a/package.json b/package.json index b252135a26..6642a1ead5 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "virtualWorkspaces": false }, "engines": { - "vscode": "^1.65.0" + "vscode": "^1.67.0" }, "repository": { "type": "git", @@ -1400,7 +1400,7 @@ "@types/node": "^8.10.51", "@types/semver": "^7.3.8", "@types/sinon": "^10.0.12", - "@types/vscode": "^1.65.0", + "@types/vscode": "^1.67.0", "@types/winreg": "^1.2.30", "@types/winston": "^2.4.4", "@vscode/test-electron": "^2.1.5", @@ -1431,7 +1431,7 @@ "htmlparser2": "6.0.1", "jdk-utils": "^0.4.4", "semver": "^7.3.5", - "vscode-languageclient": "7.1.0-next.5", + "vscode-languageclient": "8.0.2", "winreg-utf8": "^0.1.1", "winston": "^3.2.1", "winston-daily-rotate-file": "^3.10.0" diff --git a/src/clientErrorHandler.ts b/src/clientErrorHandler.ts index 2e3c2d1850..ff7f551180 100644 --- a/src/clientErrorHandler.ts +++ b/src/clientErrorHandler.ts @@ -1,5 +1,5 @@ import { window, commands } from "vscode"; -import { ErrorHandler, Message, ErrorAction, CloseAction } from "vscode-languageclient"; +import { ErrorHandler, Message, ErrorAction, CloseAction, ErrorHandlerResult, CloseHandlerResult } from "vscode-languageclient"; import { Commands } from "./commands"; import { logger } from "./log"; @@ -10,21 +10,27 @@ export class ClientErrorHandler implements ErrorHandler { this.restarts = []; } - public error(_error: Error, _message: Message, count: number): ErrorAction { + public error(_error: Error, _message: Message, count: number): ErrorHandlerResult { if (count && count <= 3) { logger.error(`${this.name} server encountered error: ${_message}, ${_error && _error.toString()}`); - return ErrorAction.Continue; + return { + action: ErrorAction.Continue + }; } logger.error(`${this.name} server encountered error and will shut down: ${_message}, ${_error && _error.toString()}`); - return ErrorAction.Shutdown; + return { + action: ErrorAction.Shutdown + }; } - public closed(): CloseAction { + public closed(): CloseHandlerResult { this.restarts.push(Date.now()); if (this.restarts.length < 5) { logger.error(`The ${this.name} server crashed and will restart.`); - return CloseAction.Restart; + return { + action: CloseAction.Restart + }; } else { const diff = this.restarts[this.restarts.length - 1] - this.restarts[0]; if (diff <= 3 * 60 * 1000) { @@ -36,12 +42,16 @@ export class ClientErrorHandler implements ErrorHandler { commands.executeCommand(Commands.OPEN_LOGS); } }); - return CloseAction.DoNotRestart; + return { + action: CloseAction.DoNotRestart + }; } logger.error(`The ${this.name} server crashed and will restart.`); this.restarts.shift(); - return CloseAction.Restart; + return { + action: CloseAction.Restart + }; } } } diff --git a/src/extension.ts b/src/extension.ts index 1dfeac1f06..5f07129707 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,7 +6,7 @@ import * as fse from 'fs-extra'; import * as os from 'os'; import * as path from 'path'; import { CodeActionContext, CodeActionTriggerKind, commands, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions, IndentAction, InputBoxOptions, languages, RelativePattern, TextDocument, UIKind, Uri, ViewColumn, window, workspace, WorkspaceConfiguration } from 'vscode'; -import { CancellationToken, CodeActionParams, CodeActionRequest, Command, DidChangeConfigurationNotification, ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, RevealOutputChannelOn } from 'vscode-languageclient'; +import { CancellationToken, CodeActionParams, CodeActionRequest, Command, DidChangeConfigurationNotification, ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, RevealOutputChannelOn, State } from 'vscode-languageclient'; import { LanguageClient } from 'vscode-languageclient/node'; import { apiManager } from './apiManager'; import { ClientErrorHandler } from './clientErrorHandler'; @@ -175,8 +175,8 @@ export function activate(context: ExtensionContext): Promise { }, middleware: { workspace: { - didChangeConfiguration: () => { - standardClient.getClient().sendNotification(DidChangeConfigurationNotification.type, { + didChangeConfiguration: async () => { + await standardClient.getClient().sendNotification(DidChangeConfigurationNotification.type, { settings: { java: getJavaConfig(requirements.java_home), } @@ -185,12 +185,12 @@ export function activate(context: ExtensionContext): Promise { }, // https://github.com/redhat-developer/vscode-java/issues/2130 // include all diagnostics for the current line in the CodeActionContext params for the performance reason - provideCodeActions: (document, range, context, token, next) => { + provideCodeActions: async (document, range, context, token, next) => { const client: LanguageClient = standardClient.getClient(); const params: CodeActionParams = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), range: client.code2ProtocolConverter.asRange(range), - context: client.code2ProtocolConverter.asCodeActionContext(context) + context: await client.code2ProtocolConverter.asCodeActionContext(context) }; const showAt = getJavaConfiguration().get("quickfix.showAt"); if (showAt === 'line' && range.start.line === range.end.line && range.start.character === range.end.character) { @@ -209,12 +209,12 @@ export function activate(context: ExtensionContext): Promise { const codeActionContext: CodeActionContext = { diagnostics: allDiagnostics, only: context.only, - triggerKind: CodeActionTriggerKind.Invoke, + triggerKind: context.triggerKind, }; - params.context = client.code2ProtocolConverter.asCodeActionContext(codeActionContext); + params.context = await client.code2ProtocolConverter.asCodeActionContext(codeActionContext); } } - return client.sendRequest(CodeActionRequest.type, params, token).then((values) => { + return client.sendRequest(CodeActionRequest.type, params, token).then(async (values) => { if (values === null) { return undefined; } @@ -224,7 +224,7 @@ export function activate(context: ExtensionContext): Promise { result.push(client.protocol2CodeConverter.asCommand(item)); } else { - result.push(client.protocol2CodeConverter.asCodeAction(item)); + result.push(await client.protocol2CodeConverter.asCodeAction(item)); } } return result; @@ -249,13 +249,16 @@ export function activate(context: ExtensionContext): Promise { // no need to pass `resolve` into any code past this point, // since `resolve` is a no-op from now on + const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, getJavaConfig(requirements.java_home), context, true); if (requireSyntaxServer) { if (process.env['SYNTAXLS_CLIENT_PORT']) { syntaxClient.initialize(requirements, clientOptions); } else { - syntaxClient.initialize(requirements, clientOptions, prepareExecutable(requirements, syntaxServerWorkspacePath, getJavaConfig(requirements.java_home), context, true)); + syntaxClient.initialize(requirements, clientOptions, serverOptions); } - syntaxClient.start(); + syntaxClient.start().then(() => { + syntaxClient.registerSyntaxClientActions(serverOptions); + }); serverStatusBarProvider.showLightWeightStatus(); } @@ -430,7 +433,9 @@ async function startStandardServer(context: ExtensionContext, requirements: requ apiManager.fireDidServerModeChange(ServerMode.hybrid); } await standardClient.initialize(context, requirements, clientOptions, workspacePath, jdtEventEmitter); - standardClient.start(); + standardClient.start().then(async () => { + standardClient.registerLanguageClientActions(context, await fse.pathExists(path.join(workspacePath, ".metadata", ".plugins")), jdtEventEmitter); + }); serverStatusBarProvider.showStandardStatus(); } @@ -532,7 +537,9 @@ export async function getActiveLanguageClient(): PromisesymbolResponse[0]).containerName) { - return languageClient.protocol2CodeConverter.asSymbolInformations(symbolResponse); + return await languageClient.protocol2CodeConverter.asSymbolInformations(symbolResponse); } - return languageClient.protocol2CodeConverter.asDocumentSymbols(symbolResponse); + return await languageClient.protocol2CodeConverter.asDocumentSymbols(symbolResponse); } }; } diff --git a/src/refactorAction.ts b/src/refactorAction.ts index 139aa9f321..bc90e103dc 100644 --- a/src/refactorAction.ts +++ b/src/refactorAction.ts @@ -226,7 +226,7 @@ async function applyRefactorEdit(languageClient: LanguageClient, refactorEdit: R } if (refactorEdit.edit) { - const edit = languageClient.protocol2CodeConverter.asWorkspaceEdit(refactorEdit.edit); + const edit = await languageClient.protocol2CodeConverter.asWorkspaceEdit(refactorEdit.edit); if (edit) { await workspace.applyEdit(edit); } diff --git a/src/sourceAction.ts b/src/sourceAction.ts index e0a2584422..c2acea150d 100644 --- a/src/sourceAction.ts +++ b/src/sourceAction.ts @@ -385,7 +385,7 @@ function registerGenerateDelegateMethodsCommand(languageClient: LanguageClient, } async function revealWorkspaceEdit(workspaceEdit: WorkspaceEdit, languageClient: LanguageClient): Promise { - const codeWorkspaceEdit = languageClient.protocol2CodeConverter.asWorkspaceEdit(workspaceEdit); + const codeWorkspaceEdit = await languageClient.protocol2CodeConverter.asWorkspaceEdit(workspaceEdit); if (!codeWorkspaceEdit) { return; } diff --git a/src/standardLanguageClient.ts b/src/standardLanguageClient.ts index 70828f0084..9819ebd936 100644 --- a/src/standardLanguageClient.ts +++ b/src/standardLanguageClient.ts @@ -5,7 +5,7 @@ import { findRuntimes } from "jdk-utils"; import * as net from 'net'; import * as path from 'path'; import { CancellationToken, CodeActionKind, commands, ConfigurationTarget, DocumentSelector, EventEmitter, ExtensionContext, extensions, languages, Location, ProgressLocation, TextEditor, Uri, ViewColumn, window, workspace } from "vscode"; -import { ConfigurationParams, ConfigurationRequest, LanguageClientOptions, Location as LSLocation, MessageType, Position as LSPosition, TextDocumentPositionParams } from "vscode-languageclient"; +import { ConfigurationParams, ConfigurationRequest, LanguageClientOptions, Location as LSLocation, MessageType, Position as LSPosition, TextDocumentPositionParams, WorkspaceEdit } from "vscode-languageclient"; import { LanguageClient, StreamInfo } from "vscode-languageclient/node"; import { apiManager } from "./apiManager"; import * as buildPath from './buildpath'; @@ -61,8 +61,6 @@ export class StandardLanguageClient { return; } - const hasImported: boolean = await fse.pathExists(path.join(workspacePath, ".metadata", ".plugins")); - if (workspace.getConfiguration().get("java.showBuildStatusOnStart.enabled") === "terminal") { commands.executeCommand(Commands.SHOW_SERVER_TASK_STATUS); } @@ -108,505 +106,506 @@ export class StandardLanguageClient { // Create the language client and start the client. this.languageClient = new LanguageClient('java', extensionName, serverOptions, clientOptions); - this.languageClient.onReady().then(() => { - activationProgressNotification.showProgress(); - this.languageClient.onNotification(StatusNotification.type, (report) => { - switch (report.type) { - case 'ServiceReady': - apiManager.updateServerMode(ServerMode.standard); - apiManager.fireDidServerModeChange(ServerMode.standard); - apiManager.resolveServerReadyPromise(); - - if (extensions.onDidChange) {// Theia doesn't support this API yet - extensions.onDidChange(async () => { - await onExtensionChange(extensions.all); - }); - } + this.registerCommandsForStandardServer(context, jdtEventEmitter); + fileEventHandler.registerFileEventHandlers(this.languageClient, context); - registerPasteEventHandler(context, this.languageClient); - activationProgressNotification.hide(); - if (!hasImported) { - showImportFinishNotification(context); - } - checkLombokDependency(context); - apiManager.getApiInstance().onDidClasspathUpdate((e: Uri) => { - checkLombokDependency(context); + collectBuildFilePattern(extensions.all); + + this.status = ClientStatus.initialized; + } + + public registerLanguageClientActions(context: ExtensionContext, hasImported: boolean, jdtEventEmitter: EventEmitter) { + activationProgressNotification.showProgress(); + this.languageClient.onNotification(StatusNotification.type, (report) => { + switch (report.type) { + case 'ServiceReady': + apiManager.updateServerMode(ServerMode.standard); + apiManager.fireDidServerModeChange(ServerMode.standard); + apiManager.resolveServerReadyPromise(); + + if (extensions.onDidChange) {// Theia doesn't support this API yet + extensions.onDidChange(async () => { + await onExtensionChange(extensions.all); }); - // Disable the client-side snippet provider since LS is ready. - snippetCompletionProvider.dispose(); - break; - case 'Started': + } + + registerPasteEventHandler(context, this.languageClient); + activationProgressNotification.hide(); + if (!hasImported) { + showImportFinishNotification(context); + } + checkLombokDependency(context); + apiManager.getApiInstance().onDidClasspathUpdate((e: Uri) => { + checkLombokDependency(context); + }); + // Disable the client-side snippet provider since LS is ready. + snippetCompletionProvider.dispose(); + break; + case 'Started': + this.status = ClientStatus.started; + serverStatus.updateServerStatus(ServerStatusKind.ready); + commands.executeCommand('setContext', 'javaLSReady', true); + apiManager.updateStatus(ClientStatus.started); + break; + case 'Error': + this.status = ClientStatus.error; + serverStatus.updateServerStatus(ServerStatusKind.error); + apiManager.updateStatus(ClientStatus.error); + break; + case 'ProjectStatus': + if (report.message === "WARNING") { + serverStatus.updateServerStatus(ServerStatusKind.warning); + } else if (report.message === "OK") { this.status = ClientStatus.started; + serverStatus.errorResolved(); serverStatus.updateServerStatus(ServerStatusKind.ready); - commands.executeCommand('setContext', 'javaLSReady', true); - apiManager.updateStatus(ClientStatus.started); - break; - case 'Error': - this.status = ClientStatus.error; - serverStatus.updateServerStatus(ServerStatusKind.error); - apiManager.updateStatus(ClientStatus.error); - break; - case 'ProjectStatus': - if (report.message === "WARNING") { - serverStatus.updateServerStatus(ServerStatusKind.warning); - } else if (report.message === "OK") { - this.status = ClientStatus.started; - serverStatus.errorResolved(); - serverStatus.updateServerStatus(ServerStatusKind.ready); - } - return; - case 'Starting': - case 'Message': - // message goes to progress report instead - break; - } - if (!serverStatus.hasErrors()) { - serverStatusBarProvider.updateTooltip(report.message); - } - }); + } + return; + case 'Starting': + case 'Message': + // message goes to progress report instead + break; + } + if (!serverStatus.hasErrors()) { + serverStatusBarProvider.updateTooltip(report.message); + } + }); - this.languageClient.onNotification(ProgressReportNotification.type, (progress) => { - serverTasks.updateServerTask(progress); - }); + this.languageClient.onNotification(ProgressReportNotification.type, (progress) => { + serverTasks.updateServerTask(progress); + }); - this.languageClient.onNotification(EventNotification.type, async (notification) => { - switch (notification.eventType) { - case EventType.classpathUpdated: - apiManager.fireDidClasspathUpdate(Uri.parse(notification.data)); - break; - case EventType.projectsImported: - const projectUris: Uri[] = []; - if (notification.data) { - for (const uriString of notification.data) { - projectUris.push(Uri.parse(uriString)); - } - } - if (projectUris.length > 0) { - apiManager.fireDidProjectsImport(projectUris); + this.languageClient.onNotification(EventNotification.type, async (notification) => { + switch (notification.eventType) { + case EventType.classpathUpdated: + apiManager.fireDidClasspathUpdate(Uri.parse(notification.data)); + break; + case EventType.projectsImported: + const projectUris: Uri[] = []; + if (notification.data) { + for (const uriString of notification.data) { + projectUris.push(Uri.parse(uriString)); } - break; - case EventType.incompatibleGradleJdkIssue: - const options: string[] = []; - const info = notification.data as GradleCompatibilityInfo; - const highestJavaVersion = Number(info.highestJavaVersion); - let runtimes = await findRuntimes({checkJavac: true, withVersion: true, withTags: true}); - runtimes = runtimes.filter(runtime => { - return runtime.version.major <= highestJavaVersion; + } + if (projectUris.length > 0) { + apiManager.fireDidProjectsImport(projectUris); + } + break; + case EventType.incompatibleGradleJdkIssue: + const options: string[] = []; + const info = notification.data as GradleCompatibilityInfo; + const highestJavaVersion = Number(info.highestJavaVersion); + let runtimes = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true }); + runtimes = runtimes.filter(runtime => { + return runtime.version.major <= highestJavaVersion; + }); + sortJdksByVersion(runtimes); + sortJdksBySource(runtimes); + options.push(UPGRADE_GRADLE + info.recommendedGradleVersion); + if (!runtimes.length) { + options.push(GET_JDK); + } else { + options.push(USE_JAVA + runtimes[0].version.major + AS_GRADLE_JVM); + } + this.showGradleCompatibilityIssueNotification(info.message, options, info.projectUri, info.recommendedGradleVersion, runtimes[0]?.homedir); + break; + case EventType.upgradeGradleWrapper: + const neverShow: boolean | undefined = context.globalState.get("java.neverShowUpgradeWrapperNotification"); + if (!neverShow) { + const upgradeInfo = notification.data as UpgradeGradleWrapperInfo; + const option = `Upgrade to ${upgradeInfo.recommendedGradleVersion}`; + window.showWarningMessage(upgradeInfo.message, option, "Don't show again").then(async (choice) => { + if (choice === option) { + await upgradeGradle(upgradeInfo.projectUri, upgradeInfo.recommendedGradleVersion); + } else if (choice === "Don't show again") { + context.globalState.update("java.neverShowUpgradeWrapperNotification", true); + } }); - sortJdksByVersion(runtimes); - sortJdksBySource(runtimes); - options.push(UPGRADE_GRADLE + info.recommendedGradleVersion); - if (!runtimes.length) { - options.push(GET_JDK); - } else { - options.push(USE_JAVA + runtimes[0].version.major + AS_GRADLE_JVM); - } - this.showGradleCompatibilityIssueNotification(info.message, options, info.projectUri, info.recommendedGradleVersion, runtimes[0]?.homedir); - break; - case EventType.upgradeGradleWrapper: - const neverShow: boolean | undefined = context.globalState.get("java.neverShowUpgradeWrapperNotification"); - if (!neverShow) { - const upgradeInfo = notification.data as UpgradeGradleWrapperInfo; - const option = `Upgrade to ${upgradeInfo.recommendedGradleVersion}`; - window.showWarningMessage(upgradeInfo.message, option, "Don't show again").then(async (choice) => { - if (choice === option) { - await upgradeGradle(upgradeInfo.projectUri, upgradeInfo.recommendedGradleVersion); - } else if (choice === "Don't show again") { - context.globalState.update("java.neverShowUpgradeWrapperNotification", true); - } - }); - } - break; - default: - break; - } - }); + } + break; + default: + break; + } + }); - this.languageClient.onNotification(ActionableNotification.type, (notification) => { - let show = null; - switch (notification.severity) { - case MessageType.Log: - show = logNotification; - break; - case MessageType.Info: - show = window.showInformationMessage; - break; - case MessageType.Warning: - show = window.showWarningMessage; - break; - case MessageType.Error: - show = window.showErrorMessage; + this.languageClient.onNotification(ActionableNotification.type, (notification) => { + let show = null; + switch (notification.severity) { + case MessageType.Log: + show = logNotification; + break; + case MessageType.Info: + show = window.showInformationMessage; + break; + case MessageType.Warning: + show = window.showWarningMessage; + break; + case MessageType.Error: + show = window.showErrorMessage; + break; + } + if (!show) { + return; + } + const titles = notification.commands.map(a => a.title); + show(notification.message, ...titles).then((selection) => { + for (const action of notification.commands) { + if (action.title === selection) { + const args: any[] = (action.arguments) ? action.arguments : []; + commands.executeCommand(action.command, ...args); break; - } - if (!show) { - return; - } - const titles = notification.commands.map(a => a.title); - show(notification.message, ...titles).then((selection) => { - for (const action of notification.commands) { - if (action.title === selection) { - const args: any[] = (action.arguments) ? action.arguments : []; - commands.executeCommand(action.command, ...args); - break; - } } - }); + } }); + }); - this.languageClient.onRequest(ExecuteClientCommandRequest.type, (params) => { - return commands.executeCommand(params.command, ...params.arguments); - }); + this.languageClient.onRequest(ExecuteClientCommandRequest.type, (params) => { + return commands.executeCommand(params.command, ...params.arguments); + }); - this.languageClient.onNotification(ServerNotification.type, (params) => { - commands.executeCommand(params.command, ...params.arguments); - }); + this.languageClient.onNotification(ServerNotification.type, (params) => { + commands.executeCommand(params.command, ...params.arguments); + }); - this.languageClient.onRequest(ConfigurationRequest.type, (params: ConfigurationParams) => { - const result: any[] = []; - const activeEditor: TextEditor | undefined = window.activeTextEditor; - for (const item of params.items) { - const scopeUri: Uri | undefined = item.scopeUri && Uri.parse(item.scopeUri); - if (scopeUri && scopeUri.toString() === activeEditor?.document.uri.toString()) { - if (item.section === "java.format.insertSpaces") { - result.push(activeEditor.options.insertSpaces); - } else if (item.section === "java.format.tabSize") { - result.push(activeEditor.options.tabSize); - } else { - result.push(null); - } + this.languageClient.onRequest(ConfigurationRequest.type, (params: ConfigurationParams) => { + const result: any[] = []; + const activeEditor: TextEditor | undefined = window.activeTextEditor; + for (const item of params.items) { + const scopeUri: Uri | undefined = item.scopeUri && Uri.parse(item.scopeUri); + if (scopeUri && scopeUri.toString() === activeEditor?.document.uri.toString()) { + if (item.section === "java.format.insertSpaces") { + result.push(activeEditor.options.insertSpaces); + } else if (item.section === "java.format.tabSize") { + result.push(activeEditor.options.tabSize); } else { - result.push(workspace.getConfiguration(null, scopeUri).get(item.section, null /* defaultValue */)); + result.push(null); } + } else { + result.push(workspace.getConfiguration(null, scopeUri).get(item.section, null /* defaultValue */)); } - return result; - }); - }); - - this.registerCommandsForStandardServer(context, jdtEventEmitter); - fileEventHandler.registerFileEventHandlers(this.languageClient, context); - - collectBuildFilePattern(extensions.all); - - this.status = ClientStatus.initialized; - } - - private showGradleCompatibilityIssueNotification(message: string, options: string[], projectUri: string, gradleVersion: string, newJavaHome: string) { - window.showErrorMessage(`${message} [Learn More](https://docs.gradle.org/current/userguide/compatibility.html)`, ...options).then(async (choice) => { - if (choice === GET_JDK) { - commands.executeCommand(Commands.OPEN_BROWSER, Uri.parse(getJdkUrl())); - } else if (choice.startsWith(USE_JAVA)) { - await workspace.getConfiguration().update(GRADLE_IMPORT_JVM, newJavaHome, ConfigurationTarget.Global); - commands.executeCommand("workbench.action.openSettings", GRADLE_IMPORT_JVM); - commands.executeCommand(Commands.IMPORT_PROJECTS_CMD); - } else if (choice.startsWith(UPGRADE_GRADLE)) { - await upgradeGradle(projectUri, gradleVersion); } + return result; }); - } - private registerCommandsForStandardServer(context: ExtensionContext, jdtEventEmitter: EventEmitter): void { - context.subscriptions.push(commands.registerCommand(Commands.IMPORT_PROJECTS_CMD, async () => { - return await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.IMPORT_PROJECTS); + context.subscriptions.push(commands.registerCommand(GRADLE_CHECKSUM, (wrapper: string, sha256: string) => { + setGradleWrapperChecksum(wrapper, sha256); })); - context.subscriptions.push(commands.registerCommand(Commands.OPEN_OUTPUT, () => this.languageClient.outputChannel.show(ViewColumn.Three))); - context.subscriptions.push(commands.registerCommand(Commands.SHOW_SERVER_TASK_STATUS, () => serverTaskPresenter.presentServerTaskView())); - - this.languageClient.onReady().then(() => { - context.subscriptions.push(commands.registerCommand(GRADLE_CHECKSUM, (wrapper: string, sha256: string) => { - setGradleWrapperChecksum(wrapper, sha256); - })); - - context.subscriptions.push(commands.registerCommand(Commands.SHOW_JAVA_REFERENCES, (uri: string, position: LSPosition, locations: LSLocation[]) => { - commands.executeCommand(Commands.SHOW_REFERENCES, Uri.parse(uri), this.languageClient.protocol2CodeConverter.asPosition(position), locations.map(this.languageClient.protocol2CodeConverter.asLocation)); - })); - context.subscriptions.push(commands.registerCommand(Commands.SHOW_JAVA_IMPLEMENTATIONS, (uri: string, position: LSPosition, locations: LSLocation[]) => { - commands.executeCommand(Commands.SHOW_REFERENCES, Uri.parse(uri), this.languageClient.protocol2CodeConverter.asPosition(position), locations.map(this.languageClient.protocol2CodeConverter.asLocation)); - })); + context.subscriptions.push(commands.registerCommand(Commands.SHOW_JAVA_REFERENCES, (uri: string, position: LSPosition, locations: LSLocation[]) => { + commands.executeCommand(Commands.SHOW_REFERENCES, Uri.parse(uri), this.languageClient.protocol2CodeConverter.asPosition(position), locations.map(this.languageClient.protocol2CodeConverter.asLocation)); + })); + context.subscriptions.push(commands.registerCommand(Commands.SHOW_JAVA_IMPLEMENTATIONS, (uri: string, position: LSPosition, locations: LSLocation[]) => { + commands.executeCommand(Commands.SHOW_REFERENCES, Uri.parse(uri), this.languageClient.protocol2CodeConverter.asPosition(position), locations.map(this.languageClient.protocol2CodeConverter.asLocation)); + })); - context.subscriptions.push(commands.registerCommand(Commands.CONFIGURATION_UPDATE, uri => projectConfigurationUpdate(this.languageClient, uri))); + context.subscriptions.push(commands.registerCommand(Commands.CONFIGURATION_UPDATE, async (uri) => { + await projectConfigurationUpdate(this.languageClient, uri); + })); - context.subscriptions.push(commands.registerCommand(Commands.IGNORE_INCOMPLETE_CLASSPATH, () => setIncompleteClasspathSeverity('ignore'))); + context.subscriptions.push(commands.registerCommand(Commands.IGNORE_INCOMPLETE_CLASSPATH, () => setIncompleteClasspathSeverity('ignore'))); - context.subscriptions.push(commands.registerCommand(Commands.IGNORE_INCOMPLETE_CLASSPATH_HELP, () => { - commands.executeCommand(Commands.OPEN_BROWSER, Uri.parse('https://github.com/redhat-developer/vscode-java/wiki/%22Classpath-is-incomplete%22-warning')); - })); + context.subscriptions.push(commands.registerCommand(Commands.IGNORE_INCOMPLETE_CLASSPATH_HELP, () => { + commands.executeCommand(Commands.OPEN_BROWSER, Uri.parse('https://github.com/redhat-developer/vscode-java/wiki/%22Classpath-is-incomplete%22-warning')); + })); - context.subscriptions.push(commands.registerCommand(Commands.PROJECT_CONFIGURATION_STATUS, (uri, status) => setProjectConfigurationUpdate(this.languageClient, uri, status))); + context.subscriptions.push(commands.registerCommand(Commands.PROJECT_CONFIGURATION_STATUS, async (uri, status) => { + await setProjectConfigurationUpdate(this.languageClient, uri, status); + })); - context.subscriptions.push(commands.registerCommand(Commands.NULL_ANALYSIS_SET_MODE, (status) => setNullAnalysisStatus(status))); + context.subscriptions.push(commands.registerCommand(Commands.NULL_ANALYSIS_SET_MODE, (status) => setNullAnalysisStatus(status))); - context.subscriptions.push(commands.registerCommand(Commands.APPLY_WORKSPACE_EDIT, (obj) => { - applyWorkspaceEdit(obj, this.languageClient); - })); + context.subscriptions.push(commands.registerCommand(Commands.APPLY_WORKSPACE_EDIT, (obj) => { + applyWorkspaceEdit(obj, this.languageClient); + })); - context.subscriptions.push(commands.registerCommand(Commands.NAVIGATE_TO_SUPER_IMPLEMENTATION_COMMAND, async (location: LinkLocation | Uri) => { - let superImplLocation: Location | undefined; + context.subscriptions.push(commands.registerCommand(Commands.NAVIGATE_TO_SUPER_IMPLEMENTATION_COMMAND, async (location: LinkLocation | Uri) => { + let superImplLocation: Location | undefined; - if (!location) { // comes from command palette - if (window.activeTextEditor?.document.languageId !== "java") { - return; - } - location = window.activeTextEditor.document.uri; + if (!location) { // comes from command palette + if (window.activeTextEditor?.document.languageId !== "java") { + return; } + location = window.activeTextEditor.document.uri; + } - if (location instanceof Uri) { // comes from context menu - const params: TextDocumentPositionParams = { - textDocument: { - uri: location.toString(), - }, - position: this.languageClient.code2ProtocolConverter.asPosition(window.activeTextEditor.selection.active), - }; - const response = await this.languageClient.sendRequest(FindLinks.type, { - type: 'superImplementation', - position: params, - }); + if (location instanceof Uri) { // comes from context menu + const params: TextDocumentPositionParams = { + textDocument: { + uri: location.toString(), + }, + position: this.languageClient.code2ProtocolConverter.asPosition(window.activeTextEditor.selection.active), + }; + const response = await this.languageClient.sendRequest(FindLinks.type, { + type: 'superImplementation', + position: params, + }); - if (response && response.length > 0) { - const superImpl = response[0]; - superImplLocation = new Location( - Uri.parse(superImpl.uri), - this.languageClient.protocol2CodeConverter.asRange(superImpl.range) - ); - } - } else { // comes from hover information + if (response && response.length > 0) { + const superImpl = response[0]; superImplLocation = new Location( - Uri.parse(decodeBase64(location.uri)), - this.languageClient.protocol2CodeConverter.asRange(location.range), + Uri.parse(superImpl.uri), + this.languageClient.protocol2CodeConverter.asRange(superImpl.range) ); } + } else { // comes from hover information + superImplLocation = new Location( + Uri.parse(decodeBase64(location.uri)), + this.languageClient.protocol2CodeConverter.asRange(location.range), + ); + } - if (superImplLocation) { - return window.showTextDocument(superImplLocation.uri, { - preserveFocus: true, - selection: superImplLocation.range, - }); - } else { - return showNoLocationFound('No super implementation found'); - } - })); + if (superImplLocation) { + return window.showTextDocument(superImplLocation.uri, { + preserveFocus: true, + selection: superImplLocation.range, + }); + } else { + return showNoLocationFound('No super implementation found'); + } + })); - context.subscriptions.push(commands.registerCommand(Commands.SHOW_TYPE_HIERARCHY, (location: any) => { - if (location instanceof Uri) { - typeHierarchyTree.setTypeHierarchy(new Location(location, window.activeTextEditor.selection.active), TypeHierarchyDirection.both); - } else { - if (window.activeTextEditor?.document?.languageId !== "java") { - return; - } - typeHierarchyTree.setTypeHierarchy(new Location(window.activeTextEditor.document.uri, window.activeTextEditor.selection.active), TypeHierarchyDirection.both); - } - })); - - context.subscriptions.push(commands.registerCommand(Commands.SHOW_CLASS_HIERARCHY, () => { - typeHierarchyTree.changeDirection(TypeHierarchyDirection.both); - })); - - context.subscriptions.push(commands.registerCommand(Commands.SHOW_SUPERTYPE_HIERARCHY, () => { - typeHierarchyTree.changeDirection(TypeHierarchyDirection.parents); - })); - - context.subscriptions.push(commands.registerCommand(Commands.SHOW_SUBTYPE_HIERARCHY, () => { - typeHierarchyTree.changeDirection(TypeHierarchyDirection.children); - })); - - context.subscriptions.push(commands.registerCommand(Commands.CHANGE_BASE_TYPE, async (item: TypeHierarchyItem) => { - typeHierarchyTree.changeBaseItem(item); - })); - - context.subscriptions.push(commands.registerCommand(Commands.BUILD_PROJECT, async (uris: Uri[] | Uri, isFullBuild: boolean, token: CancellationToken) => { - let resources: Uri[] = []; - if (uris instanceof Uri) { - resources.push(uris); - } else if (Array.isArray(uris)) { - for (const uri of uris) { - if (uri instanceof Uri) { - resources.push(uri); - } - } + context.subscriptions.push(commands.registerCommand(Commands.SHOW_TYPE_HIERARCHY, (location: any) => { + if (location instanceof Uri) { + typeHierarchyTree.setTypeHierarchy(new Location(location, window.activeTextEditor.selection.active), TypeHierarchyDirection.both); + } else { + if (window.activeTextEditor?.document?.languageId !== "java") { + return; } + typeHierarchyTree.setTypeHierarchy(new Location(window.activeTextEditor.document.uri, window.activeTextEditor.selection.active), TypeHierarchyDirection.both); + } + })); - if (!resources.length) { - resources = await askForProjects( - window.activeTextEditor?.document.uri, - "Please select the project(s) to rebuild.", - ); - if (!resources?.length) { - return; - } - } + context.subscriptions.push(commands.registerCommand(Commands.SHOW_CLASS_HIERARCHY, () => { + typeHierarchyTree.changeDirection(TypeHierarchyDirection.both); + })); - const params: BuildProjectParams = { - identifiers: resources.map((u => { - return { uri: u.toString() }; - })), - // we can consider expose 'isFullBuild' according to users' feedback, - // currently set it to true by default. - isFullBuild: isFullBuild === undefined ? true : isFullBuild, - }; + context.subscriptions.push(commands.registerCommand(Commands.SHOW_SUPERTYPE_HIERARCHY, () => { + typeHierarchyTree.changeDirection(TypeHierarchyDirection.parents); + })); - return window.withProgress({ location: ProgressLocation.Window }, async p => { - p.report({ message: 'Rebuilding projects...' }); - return new Promise(async (resolve, reject) => { - const start = new Date().getTime(); - - let res: CompileWorkspaceStatus; - try { - res = token ? await this.languageClient.sendRequest(BuildProjectRequest.type, params, token) : - await this.languageClient.sendRequest(BuildProjectRequest.type, params); - } catch (error) { - if (error && error.code === -32800) { // Check if the request is cancelled. - res = CompileWorkspaceStatus.cancelled; - } - reject(error); - } + context.subscriptions.push(commands.registerCommand(Commands.SHOW_SUBTYPE_HIERARCHY, () => { + typeHierarchyTree.changeDirection(TypeHierarchyDirection.children); + })); - const elapsed = new Date().getTime() - start; - const humanVisibleDelay = elapsed < 1000 ? 1000 : 0; - setTimeout(() => { // set a timeout so user would still see the message when build time is short - resolve(res); - }, humanVisibleDelay); - }); - }); - })); + context.subscriptions.push(commands.registerCommand(Commands.CHANGE_BASE_TYPE, async (item: TypeHierarchyItem) => { + typeHierarchyTree.changeBaseItem(item); + })); - context.subscriptions.push(commands.registerCommand(Commands.COMPILE_WORKSPACE, (isFullCompile: boolean, token?: CancellationToken) => { - return window.withProgress({ location: ProgressLocation.Window }, async p => { - if (typeof isFullCompile !== 'boolean') { - const selection = await window.showQuickPick(['Incremental', 'Full'], { placeHolder: 'please choose compile type:' }); - isFullCompile = selection !== 'Incremental'; + context.subscriptions.push(commands.registerCommand(Commands.BUILD_PROJECT, async (uris: Uri[] | Uri, isFullBuild: boolean, token: CancellationToken) => { + let resources: Uri[] = []; + if (uris instanceof Uri) { + resources.push(uris); + } else if (Array.isArray(uris)) { + for (const uri of uris) { + if (uri instanceof Uri) { + resources.push(uri); } - p.report({ message: 'Compiling workspace...' }); + } + } + + if (!resources.length) { + resources = await askForProjects( + window.activeTextEditor?.document.uri, + "Please select the project(s) to rebuild.", + ); + if (!resources?.length) { + return; + } + } + + const params: BuildProjectParams = { + identifiers: resources.map((u => { + return { uri: u.toString() }; + })), + // we can consider expose 'isFullBuild' according to users' feedback, + // currently set it to true by default. + isFullBuild: isFullBuild === undefined ? true : isFullBuild, + }; + + return window.withProgress({ location: ProgressLocation.Window }, async p => { + p.report({ message: 'Rebuilding projects...' }); + return new Promise(async (resolve, reject) => { const start = new Date().getTime(); + let res: CompileWorkspaceStatus; try { - res = token ? await this.languageClient.sendRequest(CompileWorkspaceRequest.type, isFullCompile, token) - : await this.languageClient.sendRequest(CompileWorkspaceRequest.type, isFullCompile); + res = token ? await this.languageClient.sendRequest(BuildProjectRequest.type, params, token) : + await this.languageClient.sendRequest(BuildProjectRequest.type, params); } catch (error) { if (error && error.code === -32800) { // Check if the request is cancelled. res = CompileWorkspaceStatus.cancelled; - } else { - throw error; } + reject(error); } const elapsed = new Date().getTime() - start; const humanVisibleDelay = elapsed < 1000 ? 1000 : 0; - return new Promise((resolve, reject) => { - setTimeout(() => { // set a timeout so user would still see the message when build time is short - if (res === CompileWorkspaceStatus.succeed) { - resolve(res); - } else { - reject(res); - } - }, humanVisibleDelay); - }); + setTimeout(() => { // set a timeout so user would still see the message when build time is short + resolve(res); + }, humanVisibleDelay); }); - })); + }); + })); - context.subscriptions.push(commands.registerCommand(Commands.UPDATE_SOURCE_ATTACHMENT_CMD, async (classFileUri: Uri): Promise => { - const resolveRequest: SourceAttachmentRequest = { - classFileUri: classFileUri.toString(), - }; - const resolveResult: SourceAttachmentResult = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.RESOLVE_SOURCE_ATTACHMENT, JSON.stringify(resolveRequest)); - if (resolveResult.errorMessage) { - window.showErrorMessage(resolveResult.errorMessage); - return false; + context.subscriptions.push(commands.registerCommand(Commands.COMPILE_WORKSPACE, (isFullCompile: boolean, token?: CancellationToken) => { + return window.withProgress({ location: ProgressLocation.Window }, async p => { + if (typeof isFullCompile !== 'boolean') { + const selection = await window.showQuickPick(['Incremental', 'Full'], { placeHolder: 'please choose compile type:' }); + isFullCompile = selection !== 'Incremental'; + } + p.report({ message: 'Compiling workspace...' }); + const start = new Date().getTime(); + let res: CompileWorkspaceStatus; + try { + res = token ? await this.languageClient.sendRequest(CompileWorkspaceRequest.type, isFullCompile, token) + : await this.languageClient.sendRequest(CompileWorkspaceRequest.type, isFullCompile); + } catch (error) { + if (error && error.code === -32800) { // Check if the request is cancelled. + res = CompileWorkspaceStatus.cancelled; + } else { + throw error; + } } - const attributes: SourceAttachmentAttribute = resolveResult.attributes || {}; - const defaultPath = attributes.sourceAttachmentPath || attributes.jarPath; - const sourceFileUris: Uri[] = await window.showOpenDialog({ - defaultUri: defaultPath ? Uri.file(defaultPath) : null, - openLabel: 'Select Source File', - canSelectFiles: true, - canSelectFolders: false, - canSelectMany: false, - filters: { - // eslint-disable-next-line @typescript-eslint/naming-convention - 'Source files': ['jar', 'zip'] - }, + const elapsed = new Date().getTime() - start; + const humanVisibleDelay = elapsed < 1000 ? 1000 : 0; + return new Promise((resolve, reject) => { + setTimeout(() => { // set a timeout so user would still see the message when build time is short + if (res === CompileWorkspaceStatus.succeed) { + resolve(res); + } else { + reject(res); + } + }, humanVisibleDelay); }); + }); + })); - if (sourceFileUris && sourceFileUris.length) { - const updateRequest: SourceAttachmentRequest = { - classFileUri: classFileUri.toString(), - attributes: { - ...attributes, - sourceAttachmentPath: sourceFileUris[0].fsPath - }, - }; - const updateResult: SourceAttachmentResult = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.UPDATE_SOURCE_ATTACHMENT, JSON.stringify(updateRequest)); - if (updateResult.errorMessage) { - window.showErrorMessage(updateResult.errorMessage); - return false; - } + context.subscriptions.push(commands.registerCommand(Commands.UPDATE_SOURCE_ATTACHMENT_CMD, async (classFileUri: Uri): Promise => { + const resolveRequest: SourceAttachmentRequest = { + classFileUri: classFileUri.toString(), + }; + const resolveResult: SourceAttachmentResult = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.RESOLVE_SOURCE_ATTACHMENT, JSON.stringify(resolveRequest)); + if (resolveResult.errorMessage) { + window.showErrorMessage(resolveResult.errorMessage); + return false; + } - // Notify jdt content provider to rerender the classfile contents. - jdtEventEmitter.fire(classFileUri); - return true; + const attributes: SourceAttachmentAttribute = resolveResult.attributes || {}; + const defaultPath = attributes.sourceAttachmentPath || attributes.jarPath; + const sourceFileUris: Uri[] = await window.showOpenDialog({ + defaultUri: defaultPath ? Uri.file(defaultPath) : null, + openLabel: 'Select Source File', + canSelectFiles: true, + canSelectFolders: false, + canSelectMany: false, + filters: { + // eslint-disable-next-line @typescript-eslint/naming-convention + 'Source files': ['jar', 'zip'] + }, + }); + + if (sourceFileUris && sourceFileUris.length) { + const updateRequest: SourceAttachmentRequest = { + classFileUri: classFileUri.toString(), + attributes: { + ...attributes, + sourceAttachmentPath: sourceFileUris[0].fsPath + }, + }; + const updateResult: SourceAttachmentResult = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.UPDATE_SOURCE_ATTACHMENT, JSON.stringify(updateRequest)); + if (updateResult.errorMessage) { + window.showErrorMessage(updateResult.errorMessage); + return false; } - })); - buildPath.registerCommands(context); - sourceAction.registerCommands(this.languageClient, context); - refactorAction.registerCommands(this.languageClient, context); - pasteAction.registerCommands(this.languageClient, context); + // Notify jdt content provider to rerender the classfile contents. + jdtEventEmitter.fire(classFileUri); + return true; + } + })); - excludeProjectSettingsFiles(); + buildPath.registerCommands(context); + sourceAction.registerCommands(this.languageClient, context); + refactorAction.registerCommands(this.languageClient, context); + pasteAction.registerCommands(this.languageClient, context); - context.subscriptions.push(languages.registerCodeActionsProvider({ scheme: 'file', language: 'java' }, new RefactorDocumentProvider(), RefactorDocumentProvider.metadata)); - context.subscriptions.push(commands.registerCommand(Commands.LEARN_MORE_ABOUT_REFACTORING, async (kind: CodeActionKind) => { - const sectionId: string = javaRefactorKinds.get(kind) || ''; - markdownPreviewProvider.show(context.asAbsolutePath(path.join('document', `${Commands.LEARN_MORE_ABOUT_REFACTORING}.md`)), 'Java Refactoring', sectionId, context); - })); + excludeProjectSettingsFiles(); - context.subscriptions.push(commands.registerCommand(Commands.CREATE_MODULE_INFO_COMMAND, async () => { - const uri = await askForProjects( - window.activeTextEditor?.document.uri, - "Please select the project to create module-info.java", - false, - ); - if (!uri?.length) { - return; - } + context.subscriptions.push(languages.registerCodeActionsProvider({ scheme: 'file', language: 'java' }, new RefactorDocumentProvider(), RefactorDocumentProvider.metadata)); + context.subscriptions.push(commands.registerCommand(Commands.LEARN_MORE_ABOUT_REFACTORING, async (kind: CodeActionKind) => { + const sectionId: string = javaRefactorKinds.get(kind) || ''; + markdownPreviewProvider.show(context.asAbsolutePath(path.join('document', `${Commands.LEARN_MORE_ABOUT_REFACTORING}.md`)), 'Java Refactoring', sectionId, context); + })); - const moduleInfoUri: string = await commands.executeCommand( - Commands.EXECUTE_WORKSPACE_COMMAND, - Commands.CREATE_MODULE_INFO, - uri[0].toString(), - ); + context.subscriptions.push(commands.registerCommand(Commands.CREATE_MODULE_INFO_COMMAND, async () => { + const uri = await askForProjects( + window.activeTextEditor?.document.uri, + "Please select the project to create module-info.java", + false, + ); + if (!uri?.length) { + return; + } - if (moduleInfoUri) { - await window.showTextDocument(Uri.parse(moduleInfoUri)); - } - })); + const moduleInfoUri: string = await commands.executeCommand( + Commands.EXECUTE_WORKSPACE_COMMAND, + Commands.CREATE_MODULE_INFO, + uri[0].toString(), + ); - context.subscriptions.push(commands.registerCommand(Commands.UPGRADE_GRADLE_WRAPPER, (projectUri: string, version?: string) => { - upgradeGradle(projectUri, version); - })); + if (moduleInfoUri) { + await window.showTextDocument(Uri.parse(moduleInfoUri)); + } + })); - languages.registerCodeActionsProvider({ - language: "xml", - scheme: "file", - pattern: "**/pom.xml" - }, new PomCodeActionProvider(context), pomCodeActionMetadata); + context.subscriptions.push(commands.registerCommand(Commands.UPGRADE_GRADLE_WRAPPER, (projectUri: string, version?: string) => { + upgradeGradle(projectUri, version); + })); - languages.registerCodeActionsProvider({ - scheme: "file", - pattern: "**/{gradle/wrapper/gradle-wrapper.properties,build.gradle,build.gradle.kts,settings.gradle,settings.gradle.kts}" - }, new GradleCodeActionProvider(), gradleCodeActionMetadata); + languages.registerCodeActionsProvider({ + language: "xml", + scheme: "file", + pattern: "**/pom.xml" + }, new PomCodeActionProvider(context), pomCodeActionMetadata); - if (languages.registerInlayHintsProvider) { - context.subscriptions.push(languages.registerInlayHintsProvider(JAVA_SELECTOR, new JavaInlayHintsProvider(this.languageClient))); - } + languages.registerCodeActionsProvider({ + scheme: "file", + pattern: "**/{gradle/wrapper/gradle-wrapper.properties,build.gradle,build.gradle.kts,settings.gradle,settings.gradle.kts}" + }, new GradleCodeActionProvider(), gradleCodeActionMetadata); + + if (languages.registerInlayHintsProvider) { + context.subscriptions.push(languages.registerInlayHintsProvider(JAVA_SELECTOR, new JavaInlayHintsProvider(this.languageClient))); + } + } + private showGradleCompatibilityIssueNotification(message: string, options: string[], projectUri: string, gradleVersion: string, newJavaHome: string) { + window.showErrorMessage(`${message} [Learn More](https://docs.gradle.org/current/userguide/compatibility.html)`, ...options).then(async (choice) => { + if (choice === GET_JDK) { + commands.executeCommand(Commands.OPEN_BROWSER, Uri.parse(getJdkUrl())); + } else if (choice.startsWith(USE_JAVA)) { + await workspace.getConfiguration().update(GRADLE_IMPORT_JVM, newJavaHome, ConfigurationTarget.Global); + commands.executeCommand("workbench.action.openSettings", GRADLE_IMPORT_JVM); + commands.executeCommand(Commands.IMPORT_PROJECTS_CMD); + } else if (choice.startsWith(UPGRADE_GRADLE)) { + await upgradeGradle(projectUri, gradleVersion); + } }); } - public start(): void { + private registerCommandsForStandardServer(context: ExtensionContext, jdtEventEmitter: EventEmitter): void { + context.subscriptions.push(commands.registerCommand(Commands.IMPORT_PROJECTS_CMD, async () => { + return await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.IMPORT_PROJECTS); + })); + + context.subscriptions.push(commands.registerCommand(Commands.OPEN_OUTPUT, () => this.languageClient.outputChannel.show(ViewColumn.Three))); + context.subscriptions.push(commands.registerCommand(Commands.SHOW_SERVER_TASK_STATUS, () => serverTaskPresenter.presentServerTaskView())); + } + + public start(): Promise { if (this.languageClient && this.status === ClientStatus.initialized) { - this.languageClient.start(); this.status = ClientStatus.starting; + return this.languageClient.start(); } } @@ -677,7 +676,7 @@ function setIncompleteClasspathSeverity(severity: string) { ); } -function setProjectConfigurationUpdate(languageClient: LanguageClient, uri: Uri, status: FeatureStatus) { +async function setProjectConfigurationUpdate(languageClient: LanguageClient, uri: Uri, status: FeatureStatus) { const config = getJavaConfiguration(); const section = 'configuration.updateBuildConfiguration'; @@ -687,7 +686,7 @@ function setProjectConfigurationUpdate(languageClient: LanguageClient, uri: Uri, (error) => logger.error(error) ); if (status !== FeatureStatus.disabled) { - projectConfigurationUpdate(languageClient, uri); + await projectConfigurationUpdate(languageClient, uri); } } @@ -717,10 +716,10 @@ export function showNoLocationFound(message: string): void { ); } -export function applyWorkspaceEdit(obj, languageClient): Thenable { - const edit = languageClient.protocol2CodeConverter.asWorkspaceEdit(obj); - if (edit) { - return workspace.applyEdit(edit); +export async function applyWorkspaceEdit(workspaceEdit: WorkspaceEdit, languageClient: LanguageClient): Promise { + const codeEdit = await languageClient.protocol2CodeConverter.asWorkspaceEdit(workspaceEdit); + if (codeEdit) { + return await workspace.applyEdit(codeEdit); } else { return Promise.resolve(true); } diff --git a/src/standardLanguageClientUtils.ts b/src/standardLanguageClientUtils.ts index cfe4090787..6b8723e699 100644 --- a/src/standardLanguageClientUtils.ts +++ b/src/standardLanguageClientUtils.ts @@ -33,11 +33,11 @@ export async function projectConfigurationUpdate(languageClient: LanguageClient, } if (resources.length === 1) { - languageClient.sendNotification(ProjectConfigurationUpdateRequest.type, { + await languageClient.sendNotification(ProjectConfigurationUpdateRequest.type, { uri: resources[0].toString(), }); } else if (resources.length > 1) { - languageClient.sendNotification(ProjectConfigurationUpdateRequest.typeV2, { + await languageClient.sendNotification(ProjectConfigurationUpdateRequest.typeV2, { identifiers: resources.map(r => { return { uri: r.toString() }; }), diff --git a/src/syntaxLanguageClient.ts b/src/syntaxLanguageClient.ts index 86ab554508..6af9d42713 100644 --- a/src/syntaxLanguageClient.ts +++ b/src/syntaxLanguageClient.ts @@ -24,8 +24,8 @@ export class SyntaxLanguageClient { const newClientOptions: LanguageClientOptions = Object.assign({}, clientOptions, { middleware: { workspace: { - didChangeConfiguration: () => { - this.languageClient.sendNotification(DidChangeConfigurationNotification.type, { + didChangeConfiguration: async () => { + await this.languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: { java: getJavaConfig(requirements.java_home), } @@ -56,39 +56,41 @@ export class SyntaxLanguageClient { if (serverOptions) { this.languageClient = new LanguageClient('java', extensionName, serverOptions, newClientOptions); - - // TODO: Currently only resolve the promise when the server mode is explicitly set to lightweight. - // This is to avoid breakings - this.languageClient.onReady().then(() => { - this.languageClient.onNotification(StatusNotification.type, (report) => { - switch (report.type) { - case 'Started': - this.status = ClientStatus.started; - apiManager.updateStatus(ClientStatus.started); - // Disable the client-side snippet provider since LS is ready. - snippetCompletionProvider.dispose(); - break; - case 'Error': - this.status = ClientStatus.error; - apiManager.updateStatus(ClientStatus.error); - break; - default: - break; - } - if (apiManager.getApiInstance().serverMode === ServerMode.lightWeight) { - apiManager.fireDidServerModeChange(ServerMode.lightWeight); - } - }); - }); } this.status = ClientStatus.initialized; } - public start(): void { + public registerSyntaxClientActions(serverOptions?: ServerOptions): void { + // TODO: Currently only resolve the promise when the server mode is explicitly set to lightweight. + // This is to avoid breakings + if (serverOptions) { + this.languageClient.onNotification(StatusNotification.type, (report) => { + switch (report.type) { + case 'Started': + this.status = ClientStatus.started; + apiManager.updateStatus(ClientStatus.started); + // Disable the client-side snippet provider since LS is ready. + snippetCompletionProvider.dispose(); + break; + case 'Error': + this.status = ClientStatus.error; + apiManager.updateStatus(ClientStatus.error); + break; + default: + break; + } + if (apiManager.getApiInstance().serverMode === ServerMode.lightWeight) { + apiManager.fireDidServerModeChange(ServerMode.lightWeight); + } + }); + } + } + + public start(): Promise { if (this.languageClient) { - this.languageClient.start(); this.status = ClientStatus.starting; + return this.languageClient.start(); } }