mirror of
https://github.com/Microsoft/vscode
synced 2024-09-12 21:24:38 +00:00
Add ts inline hints (#113412)
* Add ts server for inline hints * Add some feature related configure * Add more config * Rename all options * Support range * use new interface * Fix cr issues * Update inlay hints for ts plugin * Avoid call chain hints * Avoid more option * Update protos * Update extensions/typescript-language-features/package.nls.json Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> * Use suppress for some option * Update CR issues * Fix missing typedef * Avoid changes Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
parent
c5f12c7226
commit
e144d6e951
|
@ -270,6 +270,111 @@
|
|||
"description": "%configuration.suggest.includeAutomaticOptionalChainCompletions%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.parameterNames.enabled": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"literals",
|
||||
"all"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%inlayHints.parameterNames.none%",
|
||||
"%inlayHints.parameterNames.literals%",
|
||||
"%inlayHints.parameterNames.all%"
|
||||
],
|
||||
"default": "none",
|
||||
"description": "%configuration.inlayHints.parameterNames.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%configuration.inlayHints.parameterNames.suppressWhenArgumentMatchesName%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.parameterTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.parameterTypes.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.variableTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.variableTypes.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
|
||||
"typescript.inlayHints.propertyDeclarationTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.propertyDeclarationTypes.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.functionLikeReturnTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.functionLikeReturnTypes.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.enumMemberValues.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.enumMemberValues.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.parameterNames.enabled": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"literals",
|
||||
"all"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%inlayHints.parameterNames.none%",
|
||||
"%inlayHints.parameterNames.literals%",
|
||||
"%inlayHints.parameterNames.all%"
|
||||
],
|
||||
"default": "none",
|
||||
"description": "%configuration.inlayHints.parameterNames.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%configuration.inlayHints.parameterNames.suppressWhenArgumentMatchesName%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.parameterTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.parameterTypes.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.variableTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.variableTypes.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.propertyDeclarationTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.propertyDeclarationTypes.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.functionLikeReturnTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.functionLikeReturnTypes.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.enumMemberValues.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.inlayHints.enumMemberValues.enabled%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.suggest.includeCompletionsForImportStatements": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
|
|
|
@ -74,6 +74,16 @@
|
|||
"configuration.implicitProjectConfig.strictFunctionTypes": "Enable/disable [strict function types](https://www.typescriptlang.org/tsconfig#strictFunctionTypes) in JavaScript and TypeScript files that are not part of a project. Existing `jsconfig.json` or `tsconfig.json` files override this setting.",
|
||||
"configuration.suggest.jsdoc.generateReturns": "Enable/disable generating `@return` annotations for JSDoc templates. Requires using TypeScript 4.2+ in the workspace.",
|
||||
"configuration.suggest.autoImports": "Enable/disable auto import suggestions.",
|
||||
"inlayHints.parameterNames.none": "Disable parameter name hints.",
|
||||
"inlayHints.parameterNames.literals": "Enable parameter name hints only for literal arguments.",
|
||||
"inlayHints.parameterNames.all": "Enable parameter name hints for literal and non-literal arguments.",
|
||||
"configuration.inlayHints.parameterNames.enabled": "Enable/disable inlay hints of parameter names.",
|
||||
"configuration.inlayHints.parameterNames.suppressWhenArgumentMatchesName": "Suppress parameter name hints on arguments whose text is identical to the parameter name.",
|
||||
"configuration.inlayHints.parameterTypes.enabled": "Enable/disable inlay hints of parameter types.",
|
||||
"configuration.inlayHints.variableTypes.enabled": "Enable/disable inlay hints of variable types.",
|
||||
"configuration.inlayHints.propertyDeclarationTypes.enabled": "Enable/disable inlay hints of property declarations.",
|
||||
"configuration.inlayHints.functionLikeReturnTypes.enabled": "Enable/disable inlay hints of return type for function signatures.",
|
||||
"configuration.inlayHints.enumMemberValues.enabled": "Enable/disable inlay hints of enum member values.",
|
||||
"taskDefinition.tsconfig.description": "The tsconfig file that defines the TS build.",
|
||||
"javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor.",
|
||||
"typescript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for TypeScript files in the editor.",
|
||||
|
|
|
@ -13,6 +13,20 @@ import { isTypeScriptDocument } from '../utils/languageModeIds';
|
|||
import { equals } from '../utils/objects';
|
||||
import { ResourceMap } from '../utils/resourceMap';
|
||||
|
||||
namespace ExperimentalProto {
|
||||
export interface UserPreferences extends Proto.UserPreferences {
|
||||
displayPartsForJSDoc: true
|
||||
|
||||
includeInlayParameterNameHints?: 'none' | 'literals' | 'all';
|
||||
includeInlayParameterNameHintsWhenArgumentMatchesName?: boolean;
|
||||
includeInlayFunctionParameterTypeHints?: boolean;
|
||||
includeInlayVariableTypeHints?: boolean;
|
||||
includeInlayPropertyDeclarationTypeHints?: boolean;
|
||||
includeInlayFunctionLikeReturnTypeHints?: boolean;
|
||||
includeInlayEnumMemberValueHints?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
interface FileConfiguration {
|
||||
readonly formatOptions: Proto.FormatCodeSettings;
|
||||
readonly preferences: Proto.UserPreferences;
|
||||
|
@ -173,7 +187,7 @@ export default class FileConfigurationManager extends Disposable {
|
|||
isTypeScriptDocument(document) ? 'typescript.preferences' : 'javascript.preferences',
|
||||
document.uri);
|
||||
|
||||
const preferences: Proto.UserPreferences & { displayPartsForJSDoc: true } = {
|
||||
const preferences: ExperimentalProto.UserPreferences = {
|
||||
quotePreference: this.getQuoteStylePreference(preferencesConfig),
|
||||
importModuleSpecifierPreference: getImportModuleSpecifierPreference(preferencesConfig),
|
||||
importModuleSpecifierEnding: getImportModuleSpecifierEndingPreference(preferencesConfig),
|
||||
|
@ -188,6 +202,7 @@ export default class FileConfigurationManager extends Disposable {
|
|||
// @ts-expect-error until 4.4
|
||||
allowIncompleteCompletions: true,
|
||||
displayPartsForJSDoc: true,
|
||||
...getInlayHintsPreferences(config),
|
||||
};
|
||||
|
||||
return preferences;
|
||||
|
@ -202,6 +217,27 @@ export default class FileConfigurationManager extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
export function getInlayHintsPreferences(config: vscode.WorkspaceConfiguration) {
|
||||
return {
|
||||
includeInlayParameterNameHints: getInlayParameterNameHintsPreference(config),
|
||||
includeInlayParameterNameHintsWhenArgumentMatchesName: !config.get<boolean>('inlayHints.parameterNames.suppressWhenArgumentMatchesName', true),
|
||||
includeInlayFunctionParameterTypeHints: config.get<boolean>('inlayHints.parameterTypes.enabled', false),
|
||||
includeInlayVariableTypeHints: config.get<boolean>('inlayHints.variableTypes.enabled', false),
|
||||
includeInlayPropertyDeclarationTypeHints: config.get<boolean>('inlayHints.propertyDeclarationTypes.enabled', false),
|
||||
includeInlayFunctionLikeReturnTypeHints: config.get<boolean>('inlayHints.functionLikeReturnTypes.enabled', false),
|
||||
includeInlayEnumMemberValueHints: config.get<boolean>('inlayHints.enumMemberValues.enabled', false),
|
||||
} as const;
|
||||
}
|
||||
|
||||
function getInlayParameterNameHintsPreference(config: vscode.WorkspaceConfiguration) {
|
||||
switch (config.get<string>('inlayHints.parameterNames.enabled')) {
|
||||
case 'none': return 'none';
|
||||
case 'literals': return 'literals';
|
||||
case 'all': return 'all';
|
||||
default: return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function getImportModuleSpecifierPreference(config: vscode.WorkspaceConfiguration) {
|
||||
switch (config.get<string>('importModuleSpecifier')) {
|
||||
case 'project-relative': return 'project-relative';
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as Proto from '../protocol';
|
||||
import { DocumentSelector } from '../utils/documentSelector';
|
||||
import { ClientCapability, ITypeScriptServiceClient, ServerResponse, ExecConfig } from '../typescriptService';
|
||||
import { Condition, conditionalRegistration, requireMinVersion, requireSomeCapability } from '../utils/dependentRegistration';
|
||||
import { Position } from '../utils/typeConverters';
|
||||
import FileConfigurationManager, { getInlayHintsPreferences } from './fileConfigurationManager';
|
||||
import API from '../utils/api';
|
||||
|
||||
namespace ExperimentalProto {
|
||||
export const enum CommandTypes {
|
||||
ProvideInlineHints = 'ProvideInlayHints'
|
||||
}
|
||||
|
||||
export interface InlayHintsArgs extends Proto.FileRequestArgs {
|
||||
/**
|
||||
* Start position of the span.
|
||||
*/
|
||||
start: number;
|
||||
/**
|
||||
* Length of the span.
|
||||
*/
|
||||
length: number;
|
||||
}
|
||||
|
||||
export interface InlineHintsRequest extends Proto.Request {
|
||||
command: CommandTypes.ProvideInlineHints;
|
||||
arguments: InlayHintsArgs;
|
||||
}
|
||||
|
||||
export enum InlayHintKind {
|
||||
Type = 'Type',
|
||||
Parameter = 'Parameter',
|
||||
Enum = 'Enum'
|
||||
}
|
||||
|
||||
interface InlayHintItem {
|
||||
text: string;
|
||||
position: Proto.Location;
|
||||
kind?: InlayHintKind;
|
||||
whitespaceBefore?: boolean;
|
||||
whitespaceAfter?: boolean;
|
||||
}
|
||||
|
||||
export interface InlayHintsResponse extends Proto.Response {
|
||||
body?: InlayHintItem[];
|
||||
}
|
||||
|
||||
export interface IExtendedTypeScriptServiceClient {
|
||||
execute<K extends keyof ExtendedTsServerRequests>(
|
||||
command: K,
|
||||
args: ExtendedTsServerRequests[K][0],
|
||||
token: vscode.CancellationToken,
|
||||
config?: ExecConfig
|
||||
): Promise<ServerResponse.Response<ExtendedTsServerRequests[K][1]>>;
|
||||
}
|
||||
|
||||
export interface ExtendedTsServerRequests {
|
||||
'provideInlayHints': [InlayHintsArgs, InlayHintsResponse];
|
||||
}
|
||||
|
||||
export namespace InlayHintKind {
|
||||
export function fromProtocolInlayHintKind(kind: InlayHintKind): vscode.InlayHintKind {
|
||||
switch (kind) {
|
||||
case InlayHintKind.Parameter:
|
||||
return vscode.InlayHintKind.Parameter;
|
||||
case InlayHintKind.Type:
|
||||
return vscode.InlayHintKind.Type;
|
||||
case InlayHintKind.Enum:
|
||||
return vscode.InlayHintKind.Other;
|
||||
default:
|
||||
return vscode.InlayHintKind.Other;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TypeScriptInlayHintsProvider implements vscode.InlayHintsProvider {
|
||||
public static readonly minVersion = API.v440;
|
||||
|
||||
constructor(
|
||||
private readonly client: ITypeScriptServiceClient,
|
||||
private readonly fileConfigurationManager: FileConfigurationManager
|
||||
) { }
|
||||
|
||||
async provideInlayHints(model: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): Promise<vscode.InlayHint[]> {
|
||||
const filepath = this.client.toOpenedFilePath(model);
|
||||
if (!filepath) {
|
||||
return [];
|
||||
}
|
||||
|
||||
await this.fileConfigurationManager.ensureConfigurationForDocument(model, token);
|
||||
|
||||
const start = model.offsetAt(range.start);
|
||||
const length = model.offsetAt(range.end) - start;
|
||||
|
||||
const response = await (this.client as ExperimentalProto.IExtendedTypeScriptServiceClient).execute('provideInlayHints', { file: filepath, start, length }, token);
|
||||
if (response.type !== 'response' || !response.success || !response.body) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return response.body.map(hint => {
|
||||
const result = new vscode.InlayHint(
|
||||
hint.text,
|
||||
Position.fromLocation(hint.position),
|
||||
hint.kind && ExperimentalProto.InlayHintKind.fromProtocolInlayHintKind(hint.kind)
|
||||
);
|
||||
result.whitespaceBefore = hint.whitespaceBefore;
|
||||
result.whitespaceAfter = hint.whitespaceAfter;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function requireInlayHintsConfiguration(
|
||||
language: string
|
||||
) {
|
||||
return new Condition(
|
||||
() => {
|
||||
const config = vscode.workspace.getConfiguration(language, null);
|
||||
const preferences = getInlayHintsPreferences(config);
|
||||
|
||||
return preferences.includeInlayParameterNameHints === 'literals' ||
|
||||
preferences.includeInlayParameterNameHints === 'all' ||
|
||||
preferences.includeInlayEnumMemberValueHints ||
|
||||
preferences.includeInlayFunctionLikeReturnTypeHints ||
|
||||
preferences.includeInlayFunctionParameterTypeHints ||
|
||||
preferences.includeInlayPropertyDeclarationTypeHints ||
|
||||
preferences.includeInlayVariableTypeHints;
|
||||
},
|
||||
vscode.workspace.onDidChangeConfiguration
|
||||
);
|
||||
}
|
||||
|
||||
export function register(
|
||||
selector: DocumentSelector,
|
||||
modeId: string,
|
||||
client: ITypeScriptServiceClient,
|
||||
fileConfigurationManager: FileConfigurationManager
|
||||
) {
|
||||
return conditionalRegistration([
|
||||
requireInlayHintsConfiguration(modeId),
|
||||
requireMinVersion(client, TypeScriptInlayHintsProvider.minVersion),
|
||||
requireSomeCapability(client, ClientCapability.Semantic),
|
||||
], () => {
|
||||
return vscode.languages.registerInlayHintsProvider(selector.semantic,
|
||||
new TypeScriptInlayHintsProvider(client, fileConfigurationManager));
|
||||
});
|
||||
}
|
|
@ -83,6 +83,7 @@ export default class LanguageProvider extends Disposable {
|
|||
import('./languageFeatures/smartSelect').then(provider => this._register(provider.register(selector, this.client))),
|
||||
import('./languageFeatures/tagClosing').then(provider => this._register(provider.register(selector, this.description.id, this.client))),
|
||||
import('./languageFeatures/typeDefinitions').then(provider => this._register(provider.register(selector, this.client))),
|
||||
import('./languageFeatures/inlayHints').then(provider => this._register(provider.register(selector, this.description.id, this.client, this.fileConfigurationManager))),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ export default class API {
|
|||
public static readonly v401 = API.fromSimpleString('4.0.1');
|
||||
public static readonly v420 = API.fromSimpleString('4.2.0');
|
||||
public static readonly v430 = API.fromSimpleString('4.3.0');
|
||||
public static readonly v440 = API.fromSimpleString('4.4.0');
|
||||
|
||||
public static fromVersionString(versionString: string): API {
|
||||
let version = semver.valid(versionString);
|
||||
|
|
Loading…
Reference in a new issue