From 9d6054c99d63b934148051f1fb5ae22e926cc169 Mon Sep 17 00:00:00 2001 From: Wenlu Wang Date: Tue, 23 Jun 2020 05:01:37 +0800 Subject: [PATCH] Add ts/js deprecated support (#97742) * Add ts/js deprecated support * Support callhierarchy * avoid tags * fix lint * fix lint * Avoid changes * Avoid assign * Avoid changes * Avoid styles * Add temp deps for build * update version * add config item * fix type * Use expiremental namepsace * fix types --- .../src/features/callHierarchy.ts | 17 +++++++++++-- .../src/features/completions.ts | 12 ++++++---- .../src/features/diagnostics.ts | 2 +- .../src/features/documentSymbol.ts | 7 ++++++ .../src/features/workspaceSymbols.ts | 8 ++++++- .../src/languageProvider.ts | 9 +++++-- .../src/protocol.const.ts | 1 + .../src/typeScriptServiceClientHost.ts | 24 +++++++++++++++---- .../src/utils/modifiers.ts | 8 +++++++ src/vs/editor/common/config/editorOptions.ts | 9 +++++++ .../common/standalone/standaloneEnums.ts | 11 +++++---- src/vs/monaco.d.ts | 16 +++++++++---- .../api/common/extHostLanguageFeatures.ts | 3 ++- .../api/common/extHostTypeConverters.ts | 4 ++-- .../browser/callHierarchyTree.ts | 5 ++-- .../callHierarchy/common/callHierarchy.ts | 3 ++- 16 files changed, 108 insertions(+), 31 deletions(-) create mode 100644 extensions/typescript-language-features/src/utils/modifiers.ts diff --git a/extensions/typescript-language-features/src/features/callHierarchy.ts b/extensions/typescript-language-features/src/features/callHierarchy.ts index a76d8a6bea8..3e84d255ee5 100644 --- a/extensions/typescript-language-features/src/features/callHierarchy.ts +++ b/extensions/typescript-language-features/src/features/callHierarchy.ts @@ -11,6 +11,13 @@ import { VersionDependentRegistration } from '../utils/dependentRegistration'; import type * as Proto from '../protocol'; import * as path from 'path'; import * as PConst from '../protocol.const'; +import { parseKindModifier } from '../utils/modifiers'; + +namespace Experimental { + export interface CallHierarchyItem extends Proto.CallHierarchyItem { + readonly kindModifiers?: string; + } +} class TypeScriptCallHierarchySupport implements vscode.CallHierarchyProvider { public static readonly minVersion = API.v380; @@ -75,11 +82,11 @@ function isSourceFileItem(item: Proto.CallHierarchyItem) { return item.kind === PConst.Kind.script || item.kind === PConst.Kind.module && item.selectionSpan.start.line === 1 && item.selectionSpan.start.offset === 1; } -function fromProtocolCallHierarchyItem(item: Proto.CallHierarchyItem): vscode.CallHierarchyItem { +function fromProtocolCallHierarchyItem(item: Experimental.CallHierarchyItem): vscode.CallHierarchyItem { const useFileName = isSourceFileItem(item); const name = useFileName ? path.basename(item.file) : item.name; const detail = useFileName ? vscode.workspace.asRelativePath(path.dirname(item.file)) : ''; - return new vscode.CallHierarchyItem( + const result = new vscode.CallHierarchyItem( typeConverters.SymbolKind.fromProtocolScriptElementKind(item.kind), name, detail, @@ -87,6 +94,12 @@ function fromProtocolCallHierarchyItem(item: Proto.CallHierarchyItem): vscode.Ca typeConverters.Range.fromTextSpan(item.span), typeConverters.Range.fromTextSpan(item.selectionSpan) ); + + const kindModifiers = item.kindModifiers ? parseKindModifier(item.kindModifiers) : undefined; + if (kindModifiers?.has(PConst.KindModifiers.depreacted)) { + result.tags = [vscode.SymbolTag.Deprecated]; + } + return result; } function fromProtocolCallHierchyIncomingCall(item: Proto.CallHierarchyIncomingCall): vscode.CallHierarchyIncomingCall { diff --git a/extensions/typescript-language-features/src/features/completions.ts b/extensions/typescript-language-features/src/features/completions.ts index 97051395de9..79f617ba4d7 100644 --- a/extensions/typescript-language-features/src/features/completions.ts +++ b/extensions/typescript-language-features/src/features/completions.ts @@ -19,6 +19,7 @@ import { TelemetryReporter } from '../utils/telemetry'; import * as typeConverters from '../utils/typeConverters'; import TypingsStatus from '../utils/typingsStatus'; import FileConfigurationManager from './fileConfigurationManager'; +import { parseKindModifier } from '../utils/modifiers'; const localize = nls.loadMessageBundle(); @@ -90,8 +91,8 @@ class MyCompletionItem extends vscode.CompletionItem { } if (tsEntry.kindModifiers) { - const kindModifiers = tsEntry.kindModifiers.split(/,|\s+/g); - if (kindModifiers.includes(PConst.KindModifiers.optional)) { + const kindModifiers = parseKindModifier(tsEntry.kindModifiers); + if (kindModifiers.has(PConst.KindModifiers.optional)) { if (!this.insertText) { this.insertText = this.label; } @@ -101,14 +102,17 @@ class MyCompletionItem extends vscode.CompletionItem { } this.label += '?'; } + if (kindModifiers.has(PConst.KindModifiers.depreacted)) { + this.tags = [vscode.CompletionItemTag.Deprecated]; + } - if (kindModifiers.includes(PConst.KindModifiers.color)) { + if (kindModifiers.has(PConst.KindModifiers.color)) { this.kind = vscode.CompletionItemKind.Color; } if (tsEntry.kind === PConst.Kind.script) { for (const extModifier of PConst.KindModifiers.fileExtensionKindModifiers) { - if (kindModifiers.includes(extModifier)) { + if (kindModifiers.has(extModifier)) { if (tsEntry.name.toLowerCase().endsWith(extModifier)) { this.detail = tsEntry.name; } else { diff --git a/extensions/typescript-language-features/src/features/diagnostics.ts b/extensions/typescript-language-features/src/features/diagnostics.ts index 327573e8c18..ec0566d67cb 100644 --- a/extensions/typescript-language-features/src/features/diagnostics.ts +++ b/extensions/typescript-language-features/src/features/diagnostics.ts @@ -78,7 +78,7 @@ class FileDiagnostics { return this.get(DiagnosticKind.Suggestion).filter(x => { if (!enableSuggestions) { // Still show unused - return x.tags && x.tags.includes(vscode.DiagnosticTag.Unnecessary); + return x.tags && (x.tags.includes(vscode.DiagnosticTag.Unnecessary) || x.tags.includes(vscode.DiagnosticTag.Deprecated)); } return true; }); diff --git a/extensions/typescript-language-features/src/features/documentSymbol.ts b/extensions/typescript-language-features/src/features/documentSymbol.ts index e119b005bab..8b44581c6de 100644 --- a/extensions/typescript-language-features/src/features/documentSymbol.ts +++ b/extensions/typescript-language-features/src/features/documentSymbol.ts @@ -9,6 +9,7 @@ import * as PConst from '../protocol.const'; import { ITypeScriptServiceClient } from '../typescriptService'; import * as typeConverters from '../utils/typeConverters'; import { CachedResponse } from '../tsServer/cachedResponse'; +import { parseKindModifier } from '../utils/modifiers'; const getSymbolKind = (kind: string): vscode.SymbolKind => { switch (kind) { @@ -79,6 +80,12 @@ class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider range, range.contains(selectionRange) ? selectionRange : range); + + const kindModifiers = parseKindModifier(item.kindModifiers); + if (kindModifiers.has(PConst.KindModifiers.depreacted)) { + symbolInfo.tags = [vscode.SymbolTag.Deprecated]; + } + for (const child of children) { if (child.spans.some(span => !!range.intersection(typeConverters.Range.fromTextSpan(span)))) { const includedChild = TypeScriptDocumentSymbolProvider.convertNavTree(resource, symbolInfo.children, child); diff --git a/extensions/typescript-language-features/src/features/workspaceSymbols.ts b/extensions/typescript-language-features/src/features/workspaceSymbols.ts index be269a8ec41..73a142440e5 100644 --- a/extensions/typescript-language-features/src/features/workspaceSymbols.ts +++ b/extensions/typescript-language-features/src/features/workspaceSymbols.ts @@ -11,6 +11,7 @@ import API from '../utils/api'; import * as fileSchemes from '../utils/fileSchemes'; import { doesResourceLookLikeAJavaScriptFile, doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription'; import * as typeConverters from '../utils/typeConverters'; +import { parseKindModifier } from '../utils/modifiers'; function getSymbolKind(item: Proto.NavtoItem): vscode.SymbolKind { switch (item.kind) { @@ -90,11 +91,16 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide private toSymbolInformation(item: Proto.NavtoItem) { const label = TypeScriptWorkspaceSymbolProvider.getLabel(item); - return new vscode.SymbolInformation( + const info = new vscode.SymbolInformation( label, getSymbolKind(item), item.containerName || '', typeConverters.Location.fromTextSpan(this.client.toResource(item.file), item)); + const kindModifiers = item.kindModifiers ? parseKindModifier(item.kindModifiers) : undefined; + if (kindModifiers?.has(PConst.KindModifiers.depreacted)) { + info.tags = [vscode.SymbolTag.Deprecated]; + } + return info; } private static getLabel(item: Proto.NavtoItem) { diff --git a/extensions/typescript-language-features/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts index 644eed40441..b3bb76984e0 100644 --- a/extensions/typescript-language-features/src/languageProvider.ts +++ b/extensions/typescript-language-features/src/languageProvider.ts @@ -122,16 +122,21 @@ export default class LanguageProvider extends Disposable { this.client.bufferSyncSupport.requestAllDiagnostics(); } - public diagnosticsReceived(diagnosticsKind: DiagnosticKind, file: vscode.Uri, diagnostics: (vscode.Diagnostic & { reportUnnecessary: any })[]): void { + public diagnosticsReceived(diagnosticsKind: DiagnosticKind, file: vscode.Uri, diagnostics: (vscode.Diagnostic & { reportUnnecessary: any, reportDeprecated: any })[]): void { const config = vscode.workspace.getConfiguration(this.id, file); const reportUnnecessary = config.get('showUnused', true); + const reportDeprecated = config.get('showDeprecated', true); this.client.diagnosticsManager.updateDiagnostics(file, this._diagnosticLanguage, diagnosticsKind, diagnostics.filter(diag => { if (!reportUnnecessary) { - diag.tags = undefined; if (diag.reportUnnecessary && diag.severity === vscode.DiagnosticSeverity.Hint) { return false; } } + if (!reportDeprecated) { + if (diag.reportDeprecated && diag.severity === vscode.DiagnosticSeverity.Hint) { + return false; + } + } return true; })); } diff --git a/extensions/typescript-language-features/src/protocol.const.ts b/extensions/typescript-language-features/src/protocol.const.ts index ff2bfece14f..210e962c9aa 100644 --- a/extensions/typescript-language-features/src/protocol.const.ts +++ b/extensions/typescript-language-features/src/protocol.const.ts @@ -45,6 +45,7 @@ export class DiagnosticCategory { export class KindModifiers { public static readonly optional = 'optional'; + public static readonly depreacted = 'deprecated'; public static readonly color = 'color'; public static readonly dtsFile = '.d.ts'; diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index 32f0e47609a..1f1beaa382a 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -26,6 +26,12 @@ import * as typeConverters from './utils/typeConverters'; import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'; import VersionStatus from './utils/versionStatus'; +namespace Experimental { + export interface Diagnostic extends Proto.Diagnostic { + readonly reportsDeprecated?: {} + } +} + // Style check diagnostics that can be reported as warnings const styleCheckDiagnostics = new Set([ ...errorCodes.variableDeclaredButNeverUsed, @@ -233,11 +239,11 @@ export default class TypeScriptServiceClientHost extends Disposable { private createMarkerDatas( diagnostics: Proto.Diagnostic[], source: string - ): (vscode.Diagnostic & { reportUnnecessary: any })[] { + ): (vscode.Diagnostic & { reportUnnecessary: any, reportDeprecated: any })[] { return diagnostics.map(tsDiag => this.tsDiagnosticToVsDiagnostic(tsDiag, source)); } - private tsDiagnosticToVsDiagnostic(diagnostic: Proto.Diagnostic, source: string): vscode.Diagnostic & { reportUnnecessary: any } { + private tsDiagnosticToVsDiagnostic(diagnostic: Experimental.Diagnostic, source: string): vscode.Diagnostic & { reportUnnecessary: any, reportDeprecated: any } { const { start, end, text } = diagnostic; const range = new vscode.Range(typeConverters.Position.fromLocation(start), typeConverters.Position.fromLocation(end)); const converted = new vscode.Diagnostic(range, text, this.getDiagnosticSeverity(diagnostic)); @@ -255,11 +261,19 @@ export default class TypeScriptServiceClientHost extends Disposable { return new vscode.DiagnosticRelatedInformation(typeConverters.Location.fromTextSpan(this.client.toResource(span.file), span), info.message); })); } + const tags: vscode.DiagnosticTag[] = []; if (diagnostic.reportsUnnecessary) { - converted.tags = [vscode.DiagnosticTag.Unnecessary]; + tags.push(vscode.DiagnosticTag.Unnecessary); } - (converted as vscode.Diagnostic & { reportUnnecessary: any }).reportUnnecessary = diagnostic.reportsUnnecessary; - return converted as vscode.Diagnostic & { reportUnnecessary: any }; + if (diagnostic.reportsDeprecated) { + tags.push(vscode.DiagnosticTag.Deprecated); + } + converted.tags = tags.length ? tags : undefined; + + const resultConverted = converted as vscode.Diagnostic & { reportUnnecessary: any, reportDeprecated: any }; + resultConverted.reportUnnecessary = diagnostic.reportsUnnecessary; + resultConverted.reportDeprecated = diagnostic.reportsDeprecated; + return resultConverted; } private getDiagnosticSeverity(diagnostic: Proto.Diagnostic): vscode.DiagnosticSeverity { diff --git a/extensions/typescript-language-features/src/utils/modifiers.ts b/extensions/typescript-language-features/src/utils/modifiers.ts new file mode 100644 index 00000000000..589b5da3d52 --- /dev/null +++ b/extensions/typescript-language-features/src/utils/modifiers.ts @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export function parseKindModifier(kindModifiers: string): Set { + return new Set(kindModifiers.split(/,|\s+/g)); +} diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 90511cd1879..272f16429a1 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -594,6 +594,10 @@ export interface IEditorOptions { * Defaults to false. */ definitionLinkOpensInPeek?: boolean; + /** + * Controls strikethrough deprecated variables. + */ + showDeprecated?: boolean; } export interface IEditorConstructionOptions extends IEditorOptions { @@ -3591,6 +3595,7 @@ export const enum EditorOption { wordWrapMinified, wrappingIndent, wrappingStrategy, + showDeprecated, // Leave these at the end (because they have dependencies!) editorClassName, @@ -4077,6 +4082,10 @@ export const EditorOptions = { EditorOption.showUnused, 'showUnused', true, { description: nls.localize('showUnused', "Controls fading out of unused code.") } )), + showDeprecated: register(new EditorBooleanOption( + EditorOption.showDeprecated, 'showDeprecated', true, + { description: nls.localize('showDeprecated', "Controls strikethrough deprecated variables.") } + )), snippetSuggestions: register(new EditorStringEnumOption( EditorOption.snippetSuggestions, 'snippetSuggestions', 'inline' as 'top' | 'bottom' | 'inline' | 'none', diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 49e24e9eac5..b1832df3859 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -279,11 +279,12 @@ export enum EditorOption { wordWrapMinified = 109, wrappingIndent = 110, wrappingStrategy = 111, - editorClassName = 112, - pixelRatio = 113, - tabFocusMode = 114, - layoutInfo = 115, - wrappingInfo = 116 + showDeprecated = 112, + editorClassName = 113, + pixelRatio = 114, + tabFocusMode = 115, + layoutInfo = 116, + wrappingInfo = 117 } /** diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 947bdf93a47..8407dfa7ab7 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3129,6 +3129,10 @@ declare namespace monaco.editor { * Defaults to false. */ definitionLinkOpensInPeek?: boolean; + /** + * Controls strikethrough deprecated variables. + */ + showDeprecated?: boolean; } export interface IEditorConstructionOptions extends IEditorOptions { @@ -3945,11 +3949,12 @@ declare namespace monaco.editor { wordWrapMinified = 109, wrappingIndent = 110, wrappingStrategy = 111, - editorClassName = 112, - pixelRatio = 113, - tabFocusMode = 114, - layoutInfo = 115, - wrappingInfo = 116 + showDeprecated = 112, + editorClassName = 113, + pixelRatio = 114, + tabFocusMode = 115, + layoutInfo = 116, + wrappingInfo = 117 } export const EditorOptions: { acceptSuggestionOnCommitCharacter: IEditorOption; @@ -4045,6 +4050,7 @@ declare namespace monaco.editor { selectOnLineNumbers: IEditorOption; showFoldingControls: IEditorOption; showUnused: IEditorOption; + showDeprecated: IEditorOption; snippetSuggestions: IEditorOption; smoothScrolling: IEditorOption; stopRenderingLineAfter: IEditorOption; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index a114726c453..cbe85a2675e 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -73,7 +73,7 @@ class DocumentSymbolAdapter { const element: modes.DocumentSymbol = { name: info.name || '!!MISSING: name!!', kind: typeConvert.SymbolKind.from(info.kind), - tags: info.tags ? info.tags.map(typeConvert.SymbolTag.from) : [], + tags: info.tags?.map(typeConvert.SymbolTag.from) || [], detail: '', containerName: info.containerName, range: typeConvert.Range.from(info.location.range), @@ -1287,6 +1287,7 @@ class CallHierarchyAdapter { uri: item.uri, range: typeConvert.Range.from(item.range), selectionRange: typeConvert.Range.from(item.selectionRange), + tags: item.tags?.map(typeConvert.SymbolTag.from) }; map.set(dto._itemId, item); return dto; diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 6679b7bdd2a..6a7993f9ae7 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -646,7 +646,7 @@ export namespace DocumentSymbol { range: Range.from(info.range), selectionRange: Range.from(info.selectionRange), kind: SymbolKind.from(info.kind), - tags: info.tags ? info.tags.map(SymbolTag.from) : [] + tags: info.tags?.map(SymbolTag.from) ?? [] }; if (info.children) { result.children = info.children.map(from); @@ -911,7 +911,7 @@ export namespace CompletionItem { result.insertText = suggestion.insertText; result.kind = CompletionItemKind.to(suggestion.kind); - result.tags = suggestion.tags && suggestion.tags.map(CompletionItemTag.to); + result.tags = suggestion.tags?.map(CompletionItemTag.to); result.detail = suggestion.detail; result.documentation = htmlContent.isMarkdownString(suggestion.documentation) ? MarkdownString.to(suggestion.documentation) : suggestion.documentation; result.sortText = suggestion.sortText; diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts index 76758b30160..c1bc2e5377d 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts @@ -9,7 +9,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; -import { SymbolKinds, Location } from 'vs/editor/common/modes'; +import { SymbolKinds, Location, SymbolTag } from 'vs/editor/common/modes'; import { compare } from 'vs/base/common/strings'; import { Range } from 'vs/editor/common/core/range'; import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; @@ -117,11 +117,12 @@ export class CallRenderer implements ITreeRenderer, _index: number, template: CallRenderingTemplate): void { const { element, filterData } = node; + const deprecated = element.item.tags?.includes(SymbolTag.Deprecated); template.icon.className = SymbolKinds.toCssClassName(element.item.kind, true); template.label.setLabel( element.item.name, element.item.detail, - { labelEscapeNewLines: true, matches: createMatches(filterData) } + { labelEscapeNewLines: true, matches: createMatches(filterData), strikethrough: deprecated } ); } disposeTemplate(template: CallRenderingTemplate): void { diff --git a/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts b/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts index c82d0a7739d..28a29548511 100644 --- a/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts +++ b/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IRange } from 'vs/editor/common/core/range'; -import { SymbolKind, ProviderResult } from 'vs/editor/common/modes'; +import { SymbolKind, ProviderResult, SymbolTag } from 'vs/editor/common/modes'; import { ITextModel } from 'vs/editor/common/model'; import { CancellationToken } from 'vs/base/common/cancellation'; import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry'; @@ -32,6 +32,7 @@ export interface CallHierarchyItem { uri: URI; range: IRange; selectionRange: IRange; + tags?: SymbolTag[] } export interface IncomingCall {