diff --git a/package-lock.json b/package-lock.json index bfd47d34..07ce188a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -463,6 +463,14 @@ "requires": { "exec-sh": "^0.3.2", "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + } } }, "@discoveryjs/json-ext": { @@ -1311,10 +1319,10 @@ } } }, - "@nut-tree/opencv-build-linux": { + "@nut-tree/opencv-build-win32": { "version": "4.1.1-7", - "resolved": "https://registry.npmjs.org/@nut-tree/opencv-build-linux/-/opencv-build-linux-4.1.1-7.tgz", - "integrity": "sha512-EkQq7TEYoIXmLJxdToW6HtD3DyLVj+qD9L6anVtfl/Kn70GuxRcBcIGtFhuc/JXOjnEa35vT2rWsAVkbWg8/ng==", + "resolved": "https://registry.npmjs.org/@nut-tree/opencv-build-win32/-/opencv-build-win32-4.1.1-7.tgz", + "integrity": "sha512-u0WaUAl4hSL7lBOl3ut/ssk1kBJAIbTmfKWZSzEIYBy+CoiPSi3T66AxUAv4Dbw0nU0R0mEagBKVrrBhu28wzw==", "dev": true, "requires": { "jest": "^26.0.1", @@ -8621,7 +8629,14 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true + "dev": true, + "dependencies": { + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + } + } }, "jsonfile": { "version": "4.0.0", @@ -10043,7 +10058,7 @@ "integrity": "sha512-l0JealJQRgSnvQHMFDP2mM/hFn8o9zOqPjljGyAzSFXzJZkR0KgXbm66Ezwjsk+IcaSo90+OUMz3D645lNUdVw==", "dev": true, "requires": { - "@nut-tree/opencv-build-linux": "^4.1.1-7", + "@nut-tree/opencv-build-win32": "^4.1.1-7", "@types/node": ">6", "nan": "^2.14.0", "native-node-utils": "^0.2.7", @@ -11120,6 +11135,14 @@ "micromatch": "^3.1.4", "minimist": "^1.1.1", "walker": "~1.0.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + } } }, "sanitize-filename": { @@ -12846,62 +12869,43 @@ } }, "vscode-jsonrpc": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz", - "integrity": "sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ==" + "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.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz", - "integrity": "sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==", + "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.16.0" + "semver": "^7.3.5", + "vscode-languageserver-protocol": "3.17.2" }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "requires": { "lru-cache": "^6.0.0" } - }, - "vscode-jsonrpc": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", - "integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==" - }, - "vscode-languageserver-protocol": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz", - "integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==", - "requires": { - "vscode-jsonrpc": "6.0.0", - "vscode-languageserver-types": "3.16.0" - } - }, - "vscode-languageserver-types": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", - "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==" } } }, "vscode-languageserver-protocol": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz", - "integrity": "sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg==", + "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": "8.0.1", - "vscode-languageserver-types": "3.17.1" + "vscode-jsonrpc": "8.0.2", + "vscode-languageserver-types": "3.17.2" } }, "vscode-languageserver-types": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz", - "integrity": "sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ==" + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", + "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" }, "vscode-test": { "version": "1.5.1", diff --git a/package.json b/package.json index c0a289d4..ab829218 100644 --- a/package.json +++ b/package.json @@ -480,8 +480,8 @@ "lodash": "^4.17.21", "request": "^2.88.0", "request-promise": "^4.2.4", - "vscode-languageclient": "^7.0.0", - "vscode-languageserver-protocol": "^3.17.1", + "vscode-languageclient": "^8.0.2", + "vscode-languageserver-protocol": "^3.17.2", "which": "^2.0.2", "yauzl": "^2.10.0" } diff --git a/src/qute/languageServer/client.ts b/src/qute/languageServer/client.ts index c5f692cc..21a3c023 100644 --- a/src/qute/languageServer/client.ts +++ b/src/qute/languageServer/client.ts @@ -1,130 +1,121 @@ -import * as requirements from './requirements'; +import { resolveRequirements } from './requirements'; import { DidChangeConfigurationNotification, LanguageClientOptions } from 'vscode-languageclient'; import { LanguageClient } from 'vscode-languageclient/node'; -import { ExtensionContext, commands, workspace, window, ConfigurationTarget, languages } from 'vscode'; +import { ExtensionContext, commands, workspace, window, ConfigurationTarget } from 'vscode'; import { prepareExecutable } from './quteServerStarter'; import { registerQuteExecuteWorkspaceCommand, registerVSCodeQuteCommands, synchronizeQuteValidationButton } from '../commands/registerCommands'; import { QuteClientCommandConstants } from '../commands/commandConstants'; import { QuteSettings } from './settings'; import { JavaExtensionAPI } from '../../extension'; -import { QuteInlayHintsProvider } from './inlayHintsProvider'; -export function connectToQuteLS(context: ExtensionContext, api: JavaExtensionAPI) { +export async function connectToQuteLS(context: ExtensionContext, api: JavaExtensionAPI) { registerVSCodeQuteCommands(context); - - return requirements.resolveRequirements(api).then(requirements => { - const clientOptions: LanguageClientOptions = { - documentSelector: [ - { scheme: 'file', language: 'qute-html' }, - { scheme: 'file', language: 'qute-json' }, - { scheme: 'file', language: 'qute-yaml' }, - { scheme: 'file', language: 'qute-txt' }, - { scheme: 'untitled', language: 'qute-html' }, - { scheme: 'vscode-notebook-cell', language: 'qute-html' }, - { scheme: 'file', language: 'java' } - ], - // wrap with key 'settings' so it can be handled same a DidChangeConfiguration - initializationOptions: { - settings: getQuteSettings(), - extendedClientCapabilities: { - commands: { - commandsKind: { - valueSet: [ - QuteClientCommandConstants.OPEN_URI, - QuteClientCommandConstants.JAVA_DEFINTION, - QuteClientCommandConstants.COMMAND_CONFIGURATION_UPDATE - ] - } - }, - shouldLanguageServerExitOnShutdown: true - } - }, - synchronize: { - // preferences starting with these will trigger didChangeConfiguration - configurationSection: ['qute'] - }, - middleware: { - workspace: { - didChangeConfiguration: async () => { - // A settings.json is updated: - // 1. send the new Quet settings to the Qute language server - quteLanguageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getQuteSettings() }); - // 2. synchronize the Qute toggle button for validation - await synchronizeQuteValidationButton(window.activeTextEditor); + const requirements = await resolveRequirements(api); + + const clientOptions: LanguageClientOptions = { + documentSelector: [ + { scheme: 'file', language: 'qute-html' }, + { scheme: 'file', language: 'qute-json' }, + { scheme: 'file', language: 'qute-yaml' }, + { scheme: 'file', language: 'qute-txt' }, + { scheme: 'untitled', language: 'qute-html' }, + { scheme: 'vscode-notebook-cell', language: 'qute-html' }, + { scheme: 'file', language: 'java' } + ], + // wrap with key 'settings' so it can be handled same a DidChangeConfiguration + initializationOptions: { + settings: getQuteSettings(), + extendedClientCapabilities: { + commands: { + commandsKind: { + valueSet: [ + QuteClientCommandConstants.OPEN_URI, + QuteClientCommandConstants.JAVA_DEFINTION, + QuteClientCommandConstants.COMMAND_CONFIGURATION_UPDATE + ] } } } - }; - - function bindQuteRequest(request: string) { - quteLanguageClient.onRequest(request, async (params: any) => - await commands.executeCommand("java.execute.workspaceCommand", request, params) - ); - } - - function bindQuteNotification(notification: string) { - context.subscriptions.push(commands.registerCommand(notification, (event: any) => { - quteLanguageClient.sendNotification(notification, event); - })); + }, + synchronize: { + // preferences starting with these will trigger didChangeConfiguration + configurationSection: ['qute'] + }, + middleware: { + workspace: { + didChangeConfiguration: async () => { + // A settings.json is updated: + // 1. send the new Quet settings to the Qute language server + const result = quteLanguageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getQuteSettings() }); + // 2. synchronize the Qute toggle button for validation + await synchronizeQuteValidationButton(window.activeTextEditor); + return result; + } + } } + }; - const serverOptions = prepareExecutable(requirements); - const quteLanguageClient = new LanguageClient('qute', 'Qute Support', serverOptions, clientOptions); - context.subscriptions.push(quteLanguageClient.start()); + function bindQuteRequest(request: string) { + quteLanguageClient.onRequest(request, async (params: any) => + await commands.executeCommand("java.execute.workspaceCommand", request, params) + ); + } - return quteLanguageClient.onReady().then(async () => { - bindQuteRequest('qute/template/project'); - bindQuteRequest('qute/template/projectDataModel'); - bindQuteRequest('qute/template/userTags'); - bindQuteRequest('qute/template/javaTypes'); - bindQuteRequest('qute/template/resolvedJavaType'); - bindQuteRequest('qute/template/javaDefinition'); - bindQuteRequest('qute/template/javadoc'); - bindQuteRequest('qute/template/generateMissingJavaMember'); - bindQuteRequest('qute/java/codeLens'); - bindQuteRequest('qute/java/diagnostics'); - bindQuteRequest('qute/java/documentLink'); - bindQuteNotification('qute/dataModelChanged'); + function bindQuteNotification(notification: string) { + context.subscriptions.push(commands.registerCommand(notification, (event: any) => { + quteLanguageClient.sendNotification(notification, event); + })); + } - registerQuteExecuteWorkspaceCommand(context, quteLanguageClient); - // Refresh the Qute context when editor tab has the focus - context.subscriptions.push( - window.onDidChangeActiveTextEditor(async editor => { - await synchronizeQuteValidationButton(editor); - }) - ); - // Refresh the Qute context when the language id changed (HTML -> Qute HTML or Qute HTML -> HTML) - context.subscriptions.push( - workspace.onDidOpenTextDocument(async (document) => { - // when settings.json is updated, onDidOpenTextDocument is called, - // the Qute context must be refreshed only for the activate text editor. - if (window.activeTextEditor?.document === document) { - await synchronizeQuteValidationButton(window.activeTextEditor); - } - // Display the experimental Qute validation pop-up if it hasn't been displayed and a Qute file is open - if (!hasShownQuteValidationPopUp(context) && document.languageId.includes('qute')) { - showQuteValidationPopUp(context); - } - }) - ); + const serverOptions = prepareExecutable(requirements); + const quteLanguageClient = new LanguageClient('qute', 'Qute Support', serverOptions, clientOptions); + await quteLanguageClient.start(); + + bindQuteRequest('qute/template/project'); + bindQuteRequest('qute/template/projectDataModel'); + bindQuteRequest('qute/template/userTags'); + bindQuteRequest('qute/template/javaTypes'); + bindQuteRequest('qute/template/resolvedJavaType'); + bindQuteRequest('qute/template/javaDefinition'); + bindQuteRequest('qute/template/javadoc'); + bindQuteRequest('qute/template/generateMissingJavaMember'); + bindQuteRequest('qute/java/codeLens'); + bindQuteRequest('qute/java/diagnostics'); + bindQuteRequest('qute/java/documentLink'); + bindQuteNotification('qute/dataModelChanged'); + + registerQuteExecuteWorkspaceCommand(context, quteLanguageClient); + // Refresh the Qute context when editor tab has the focus + context.subscriptions.push( + window.onDidChangeActiveTextEditor(async editor => { + await synchronizeQuteValidationButton(editor); + }) + ); + // Refresh the Qute context when the language id changed (HTML -> Qute HTML or Qute HTML -> HTML) + context.subscriptions.push( + workspace.onDidOpenTextDocument(async (document) => { + // when settings.json is updated, onDidOpenTextDocument is called, + // the Qute context must be refreshed only for the activate text editor. + if (window.activeTextEditor?.document === document) { + await synchronizeQuteValidationButton(window.activeTextEditor); + } // Display the experimental Qute validation pop-up if it hasn't been displayed and a Qute file is open - if (!hasShownQuteValidationPopUp(context)) { - for (const textDocument of workspace.textDocuments) { - if (textDocument.languageId.includes('qute')) { - showQuteValidationPopUp(context); - } - } + if (!hasShownQuteValidationPopUp(context) && document.languageId.includes('qute')) { + showQuteValidationPopUp(context); } - await setQuteValidationEnabledContext(); - await synchronizeQuteValidationButton(window.activeTextEditor); - - const supportRegisterInlayHintsProvider = (languages as any).registerInlayHintsProvider; - if (supportRegisterInlayHintsProvider) { - context.subscriptions.push(languages.registerInlayHintsProvider(clientOptions.documentSelector, new QuteInlayHintsProvider(quteLanguageClient))); + }) + ); + // Display the experimental Qute validation pop-up if it hasn't been displayed and a Qute file is open + if (!hasShownQuteValidationPopUp(context)) { + for (const textDocument of workspace.textDocuments) { + if (textDocument.languageId.includes('qute')) { + showQuteValidationPopUp(context); } - }); - }); + } + } + await setQuteValidationEnabledContext(); + await synchronizeQuteValidationButton(window.activeTextEditor); } /** diff --git a/src/qute/languageServer/inlayHintsProvider.ts b/src/qute/languageServer/inlayHintsProvider.ts deleted file mode 100644 index 6fb32966..00000000 --- a/src/qute/languageServer/inlayHintsProvider.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { CancellationToken, Command, EventEmitter, InlayHint, InlayHintKind, InlayHintLabelPart, InlayHintsProvider, MarkdownString, Range, TextDocument } from "vscode"; -import * as ls from 'vscode-languageserver-protocol'; -import { LanguageClient, RequestType } from "vscode-languageclient/node"; - -export class QuteInlayHintsProvider implements InlayHintsProvider { - - private onDidChange = new EventEmitter(); - public onDidChangeInlayHints = this.onDidChange.event; - - constructor(private client: LanguageClient) { - this.client.onRequest(InlayHintRefreshRequest.type, async () => { - this.onDidChange.fire(); - }); - } - - public async provideInlayHints(document: TextDocument, range: Range, token: CancellationToken): Promise { - const requestParams: InlayHintParams = { - textDocument: this.client.code2ProtocolConverter.asTextDocumentIdentifier(document), - range: this.client.code2ProtocolConverter.asRange(range) - }; - try { - const values = await this.client.sendRequest(InlayHintRequest.type, requestParams, token); - if (token.isCancellationRequested) { - return []; - } - return asInlayHints(values, this.client); - } catch (error) { - if (token.isCancellationRequested) { - return []; - } - return this.client.handleFailedRequest(InlayHintRequest.type, token, error); - } - } -} - -/** - * A parameter literal used in inlay hints requests. - * - * @since 3.17.0 - proposed state - */ -export type InlayHintParams = /*WorkDoneProgressParams &*/ { - /** - * The text document. - */ - textDocument: ls.TextDocumentIdentifier; - - /** - * The document range for which inlay hints should be computed. - */ - range: ls.Range; -}; - -/** - * Inlay hint information. - * - * @since 3.17.0 - proposed state - */ -export type LSInlayHint = { - - /** - * The position of this hint. - */ - position: ls.Position; - - /** - * The label of this hint. A human readable string or an array of - * InlayHintLabelPart label parts. - * - * *Note* that neither the string nor the label part can be empty. - */ - label: string | LSInlayHintLabelPart[]; -}; - -export type LSInlayHintLabelPart = { - - /** - * The value of this label part. - */ - value: string; - - /** - * An optional command for this label part. - * - * Depending on the client capability `inlayHint.resolveSupport` clients - * might resolve this property late using the resolve request. - */ - command?: ls.Command; - - /** - * The tooltip text when you hover over this label part. Depending on - * the client capability `inlayHint.resolveSupport` clients might resolve - * this property late using the resolve request. - */ - tooltip?: string | ls.MarkupContent; - -}; - -namespace InlayHintRequest { - export const type: RequestType = new RequestType('textDocument/inlayHint'); -} - -/** - * @since 3.17.0 - proposed state - */ -namespace InlayHintRefreshRequest { - export const type: RequestType = new RequestType('workspace/inlayHint/refresh'); -} - -async function asInlayHints(values: LSInlayHint[] | undefined | null, client: LanguageClient,): Promise { - if (!Array.isArray(values)) { - return undefined; - } - return values.map(lsHint => asInlayHint(lsHint, client)); -} - -function asInlayHint(item: LSInlayHint, client: LanguageClient): InlayHint { - const label = typeof item.label === 'string' - ? item.label - : item.label.map(asInlayHintLabelPart); - const result = new InlayHint(client.protocol2CodeConverter.asPosition(item.position), label); - result.paddingRight = true; - result.kind = InlayHintKind.Parameter; - return result; -} - -function asInlayHintLabelPart(item: LSInlayHintLabelPart): InlayHintLabelPart { - const result = new InlayHintLabelPart(item.value); - if (item.command !== undefined) { result.command = asCommand(item.command); } - if (item.tooltip !== undefined) { result.tooltip = asTooltip(item.tooltip); } - return result; -} - -function asCommand(item: ls.Command): Command { - const result = { title: item.title, command: item.command } as Command; - if (item.arguments) { result.arguments = item.arguments; } - return result; -} - -function asTooltip(value: string | ls.MarkupContent): string | MarkdownString { - if (typeof value === 'string') { - return value; - } - const result = new MarkdownString(value.value); - return result; -}