diff --git a/package-lock.json b/package-lock.json index 8171aa46c4..51a893d091 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,9 +101,9 @@ "dev": true }, "@types/vscode": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.53.0.tgz", - "integrity": "sha512-XjFWbSPOM0EKIT2XhhYm3D3cx3nn3lshMUcWNy1eqefk+oqRuBq8unVb6BYIZqXy9lQZyeUl7eaBCOZWv+LcXQ==", + "version": "1.65.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz", + "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==", "dev": true }, "@types/winreg": { diff --git a/package.json b/package.json index 6c08f7c0e3..53a424db9b 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "virtualWorkspaces": false }, "engines": { - "vscode": "^1.61.0" + "vscode": "^1.65.0" }, "repository": { "type": "git", @@ -857,6 +857,22 @@ "default": "line", "description": "Show quickfixes at the problem or line level.", "scope": "window" + }, + "java.inlayHints.parameterNames.enabled": { + "type": "string", + "enum": [ + "none", + "literals", + "all" + ], + "enumDescriptions": [ + "Disable parameter name hints", + "Enable parameter name hints only for literal arguments", + "Enable parameter name hints for literal and non-literal arguments" + ], + "default": "literals", + "markdownDescription": "Enable/disable inlay hints for parameter names:\n```java\n\nInteger.valueOf(/* s: */ '123', /* radix: */ 10)\n \n```\n", + "scope": "window" } } }, @@ -1141,7 +1157,7 @@ "@types/mocha": "^5.2.5", "@types/node": "^8.10.51", "@types/semver": "^7.3.8", - "@types/vscode": "^1.53.0", + "@types/vscode": "^1.65.0", "@types/winreg": "^1.2.30", "@types/winston": "^2.4.4", "gulp": "^4.0.2", diff --git a/src/extension.ts b/src/extension.ts index 3902936e24..3fb66889f6 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import * as os from 'os'; import * as fs from 'fs'; import * as fse from 'fs-extra'; -import { workspace, extensions, ExtensionContext, window, commands, ViewColumn, Uri, languages, IndentAction, InputBoxOptions, EventEmitter, OutputChannel, TextDocument, RelativePattern, ConfigurationTarget, WorkspaceConfiguration, env, UIKind, CodeActionContext, Diagnostic } from 'vscode'; +import { workspace, extensions, ExtensionContext, window, commands, ViewColumn, Uri, languages, IndentAction, InputBoxOptions, EventEmitter, OutputChannel, TextDocument, RelativePattern, ConfigurationTarget, WorkspaceConfiguration, env, UIKind, CodeActionContext, Diagnostic, CodeActionTriggerKind } from 'vscode'; import { ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, RevealOutputChannelOn, ErrorHandler, Message, ErrorAction, CloseAction, DidChangeConfigurationNotification, CancellationToken, CodeActionRequest, CodeActionParams, Command } from 'vscode-languageclient'; import { LanguageClient } from 'vscode-languageclient/node'; import { collectJavaExtensions, isContributedPartUpdated } from './plugin'; @@ -134,6 +134,11 @@ export class OutputInfoCollector implements OutputChannel { this.channel.appendLine(value); } + replace(value: string): void { + this.clear(); + this.append(value); + } + clear(): void { this.channel.clear(); } @@ -279,6 +284,7 @@ export function activate(context: ExtensionContext): Promise { const codeActionContext: CodeActionContext = { diagnostics: allDiagnostics, only: context.only, + triggerKind: CodeActionTriggerKind.Invoke, }; params.context = client.code2ProtocolConverter.asCodeActionContext(codeActionContext); } diff --git a/src/hoverAction.ts b/src/hoverAction.ts index 6cfca3c424..1accdea08e 100644 --- a/src/hoverAction.ts +++ b/src/hoverAction.ts @@ -75,10 +75,10 @@ class JavaHoverProvider implements HoverProvider { const contributed = new MarkdownString(contributedCommands.map((command) => this.convertCommandToMarkdown(command)).join(' | ')); contributed.isTrusted = true; - let contents: MarkedString[] = [ contributed ]; + let contents: MarkdownString[] = [ contributed ]; let range; if (serverHover && serverHover.contents) { - contents = contents.concat(serverHover.contents); + contents = contents.concat(serverHover.contents as MarkdownString[]); range = serverHover.range; } return new Hover(contents, range); diff --git a/src/inlayHintsProvider.ts b/src/inlayHintsProvider.ts new file mode 100644 index 0000000000..ca07027e38 --- /dev/null +++ b/src/inlayHintsProvider.ts @@ -0,0 +1,95 @@ +import { CancellationToken, EventEmitter, InlayHint, InlayHintKind, InlayHintsProvider, Range, TextDocument } from "vscode"; +import * as ls from 'vscode-languageserver-protocol'; +import { LanguageClient, RequestType } from "vscode-languageclient/node"; + +export class JavaInlayHintsProvider 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) { + 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; // label: string | InlayHintLabelPart[]; +}; + +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(value: LSInlayHint, client: LanguageClient): InlayHint { + const label = value.label; + const result = new InlayHint(client.protocol2CodeConverter.asPosition(value.position), label); + result.paddingRight = true; + result.kind = InlayHintKind.Parameter; + return result; +} diff --git a/src/standardLanguageClient.ts b/src/standardLanguageClient.ts index e2ba98ad63..0cc05743c2 100644 --- a/src/standardLanguageClient.ts +++ b/src/standardLanguageClient.ts @@ -34,6 +34,7 @@ import { buildFilePatterns } from './plugin'; import { pomCodeActionMetadata, PomCodeActionProvider } from "./pom/pomCodeActionProvider"; import { findRuntimes, IJavaRuntime } from "jdk-utils"; import { snippetCompletionProvider } from "./snippetCompletionProvider"; +import { JavaInlayHintsProvider } from "./inlayHintsProvider"; const extensionName = 'Language Support for Java'; const GRADLE_CHECKSUM = "gradle/checksum/prompt"; @@ -501,6 +502,14 @@ export class StandardLanguageClient { scheme: "file", pattern: "**/pom.xml" }, new PomCodeActionProvider(context), pomCodeActionMetadata); + + if (languages.registerInlayHintsProvider) { + context.subscriptions.push(languages.registerInlayHintsProvider([ + { scheme: "file", language: "java", pattern: "**/*.java" }, + { scheme: "jdt", language: "java", pattern: "**/*.class" }, + { scheme: "untitled", language: "java", pattern: "**/*.java" } + ], new JavaInlayHintsProvider(this.languageClient))); + } }); }