From e41c19505142614f706ad853bd5c4c2ad0f74e89 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 20 Jul 2020 16:08:06 -0700 Subject: [PATCH] Work towards allowing enhanced syntax server commands to be run against any file We currently restrict the TS server to working with a small set of file schemes. This is done because the TS server itself cannot read files from on of VS Code's virtual file system providers (and will crash if it tries to do so) However we can enable single file commands for these other file schemes, so long as they are treated as in-memory files. This change works towards supporting that by changing when certain providers are enabled/disabled --- .../src/features/callHierarchy.ts | 10 ++-- .../src/features/completions.ts | 10 ++-- .../src/features/definitions.ts | 14 +++-- .../features/directiveCommentCompletions.ts | 5 +- .../src/features/documentHighlight.ts | 5 +- .../src/features/documentSymbol.ts | 9 +-- .../src/features/fixAll.ts | 12 ++-- .../src/features/folding.ts | 5 +- .../src/features/formatting.ts | 7 ++- .../src/features/hover.ts | 14 +++-- .../src/features/implementations.ts | 14 +++-- .../src/features/implementationsCodeLens.ts | 9 +-- .../src/features/jsDocCompletions.ts | 5 +- .../src/features/organizeImports.ts | 5 +- .../src/features/quickFix.ts | 9 +-- .../src/features/refactor.ts | 9 +-- .../src/features/references.ts | 14 +++-- .../src/features/referencesCodeLens.ts | 18 ++++-- .../src/features/rename.ts | 9 +-- .../src/features/semanticTokens.ts | 12 ++-- .../src/features/signatureHelp.ts | 18 ++++-- .../src/features/smartSelect.ts | 5 +- .../src/features/tagClosing.ts | 5 +- .../src/features/typeDefinitions.ts | 14 +++-- .../src/features/updatePathsOnRename.ts | 4 +- .../src/languageProvider.ts | 24 +++++--- .../src/lazyClientHost.ts | 10 +--- .../src/tsServer/server.ts | 56 +++++++++++++------ .../src/typescriptService.ts | 18 +++++- .../src/typescriptServiceClient.ts | 53 +++++++++--------- .../src/utils/dependentRegistration.ts | 6 +- .../src/utils/documentSelector.ts | 18 ++++++ .../src/utils/fileSchemes.ts | 7 +-- src/vs/base/common/json.ts | 1 + 34 files changed, 276 insertions(+), 158 deletions(-) create mode 100644 extensions/typescript-language-features/src/utils/documentSelector.ts diff --git a/extensions/typescript-language-features/src/features/callHierarchy.ts b/extensions/typescript-language-features/src/features/callHierarchy.ts index 1bc85e4ca11..85115b59e5f 100644 --- a/extensions/typescript-language-features/src/features/callHierarchy.ts +++ b/extensions/typescript-language-features/src/features/callHierarchy.ts @@ -7,9 +7,10 @@ import * as path from 'path'; import * as vscode from 'vscode'; import type * as Proto from '../protocol'; import * as PConst from '../protocol.const'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; -import { conditionalRegistration, requireMinVersion } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability, requireMinVersion } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import { parseKindModifier } from '../utils/modifiers'; import * as typeConverters from '../utils/typeConverters'; @@ -117,13 +118,14 @@ function fromProtocolCallHierchyOutgoingCall(item: Proto.CallHierarchyOutgoingCa } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient ) { return conditionalRegistration([ requireMinVersion(client, TypeScriptCallHierarchySupport.minVersion), + requireSomeCapability(client, ClientCapability.EnhancedSyntax, ClientCapability.Semantic), ], () => { - return vscode.languages.registerCallHierarchyProvider(selector, + return vscode.languages.registerCallHierarchyProvider(selector.syntax, new TypeScriptCallHierarchySupport(client)); }); } diff --git a/extensions/typescript-language-features/src/features/completions.ts b/extensions/typescript-language-features/src/features/completions.ts index 5ef98b8b07e..229192d9e08 100644 --- a/extensions/typescript-language-features/src/features/completions.ts +++ b/extensions/typescript-language-features/src/features/completions.ts @@ -7,12 +7,13 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import type * as Proto from '../protocol'; import * as PConst from '../protocol.const'; -import { ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; import API from '../utils/api'; import { nulToken } from '../utils/cancellation'; import { applyCodeAction } from '../utils/codeAction'; import { Command, CommandManager } from '../utils/commandManager'; -import { conditionalRegistration, requireConfiguration } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability, requireConfiguration } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import { parseKindModifier } from '../utils/modifiers'; import * as Previewer from '../utils/previewer'; import { snippetForFunctionCall } from '../utils/snippetForFunctionCall'; @@ -795,7 +796,7 @@ function shouldExcludeCompletionEntry( } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, modeId: string, client: ITypeScriptServiceClient, typingsStatus: TypingsStatus, @@ -806,8 +807,9 @@ export function register( ) { return conditionalRegistration([ requireConfiguration(modeId, 'suggest.enabled'), + requireSomeCapability(client, ClientCapability.EnhancedSyntax, ClientCapability.Semantic), ], () => { - return vscode.languages.registerCompletionItemProvider(selector, + return vscode.languages.registerCompletionItemProvider(selector.syntax, new TypeScriptCompletionItemProvider(client, modeId, typingsStatus, fileConfigurationManager, commandManager, telemetryReporter, onCompletionAccepted), ...TypeScriptCompletionItemProvider.triggerCharacters); }); diff --git a/extensions/typescript-language-features/src/features/definitions.ts b/extensions/typescript-language-features/src/features/definitions.ts index fd3a1f10e79..7c01400c206 100644 --- a/extensions/typescript-language-features/src/features/definitions.ts +++ b/extensions/typescript-language-features/src/features/definitions.ts @@ -4,8 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; +import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; import DefinitionProviderBase from './definitionProviderBase'; @@ -58,9 +60,13 @@ export default class TypeScriptDefinitionProvider extends DefinitionProviderBase } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, ) { - return vscode.languages.registerDefinitionProvider(selector, - new TypeScriptDefinitionProvider(client)); + return conditionalRegistration([ + requireSomeCapability(client, ClientCapability.EnhancedSyntax, ClientCapability.Semantic), + ], () => { + return vscode.languages.registerDefinitionProvider(selector.syntax, + new TypeScriptDefinitionProvider(client)); + }); } diff --git a/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts b/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts index cfa35571d1d..2b0f683e589 100644 --- a/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts +++ b/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts @@ -7,6 +7,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; +import { DocumentSelector } from '../utils/documentSelector'; const localize = nls.loadMessageBundle(); @@ -80,10 +81,10 @@ class DirectiveCommentCompletionProvider implements vscode.CompletionItemProvide } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, ) { - return vscode.languages.registerCompletionItemProvider(selector, + return vscode.languages.registerCompletionItemProvider(selector.syntax, new DirectiveCommentCompletionProvider(client), '@'); } diff --git a/extensions/typescript-language-features/src/features/documentHighlight.ts b/extensions/typescript-language-features/src/features/documentHighlight.ts index 61477e06749..3a7b43ed5eb 100644 --- a/extensions/typescript-language-features/src/features/documentHighlight.ts +++ b/extensions/typescript-language-features/src/features/documentHighlight.ts @@ -7,6 +7,7 @@ import * as vscode from 'vscode'; import type * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; import { flatten } from '../utils/arrays'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; class TypeScriptDocumentHighlightProvider implements vscode.DocumentHighlightProvider { @@ -48,9 +49,9 @@ function convertDocumentHighlight(highlight: Proto.DocumentHighlightsItem): Read } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, ) { - return vscode.languages.registerDocumentHighlightProvider(selector, + return vscode.languages.registerDocumentHighlightProvider(selector.syntax, new TypeScriptDocumentHighlightProvider(client)); } diff --git a/extensions/typescript-language-features/src/features/documentSymbol.ts b/extensions/typescript-language-features/src/features/documentSymbol.ts index 8b44581c6de..d0b8b9ad901 100644 --- a/extensions/typescript-language-features/src/features/documentSymbol.ts +++ b/extensions/typescript-language-features/src/features/documentSymbol.ts @@ -6,10 +6,11 @@ import * as vscode from 'vscode'; import type * as Proto from '../protocol'; import * as PConst from '../protocol.const'; -import { ITypeScriptServiceClient } from '../typescriptService'; -import * as typeConverters from '../utils/typeConverters'; import { CachedResponse } from '../tsServer/cachedResponse'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { DocumentSelector } from '../utils/documentSelector'; import { parseKindModifier } from '../utils/modifiers'; +import * as typeConverters from '../utils/typeConverters'; const getSymbolKind = (kind: string): vscode.SymbolKind => { switch (kind) { @@ -111,10 +112,10 @@ class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, cachedResponse: CachedResponse, ) { - return vscode.languages.registerDocumentSymbolProvider(selector, + return vscode.languages.registerDocumentSymbolProvider(selector.syntax, new TypeScriptDocumentSymbolProvider(client, cachedResponse), { label: 'TypeScript' }); } diff --git a/extensions/typescript-language-features/src/features/fixAll.ts b/extensions/typescript-language-features/src/features/fixAll.ts index 422c26e4131..6a43c535a8b 100644 --- a/extensions/typescript-language-features/src/features/fixAll.ts +++ b/extensions/typescript-language-features/src/features/fixAll.ts @@ -6,9 +6,10 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import type * as Proto from '../protocol'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; -import { conditionalRegistration, requireMinVersion } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability, requireMinVersion } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as errorCodes from '../utils/errorCodes'; import * as fixNames from '../utils/fixNames'; import * as typeConverters from '../utils/typeConverters'; @@ -249,15 +250,16 @@ class TypeScriptAutoFixProvider implements vscode.CodeActionProvider { } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, fileConfigurationManager: FileConfigurationManager, diagnosticsManager: DiagnosticsManager, ) { return conditionalRegistration([ - requireMinVersion(client, API.v300) + requireMinVersion(client, API.v300), + requireSomeCapability(client, ClientCapability.Semantic), ], () => { const provider = new TypeScriptAutoFixProvider(client, fileConfigurationManager, diagnosticsManager); - return vscode.languages.registerCodeActionsProvider(selector, provider, provider.metadata); + return vscode.languages.registerCodeActionsProvider(selector.semantic, provider, provider.metadata); }); } diff --git a/extensions/typescript-language-features/src/features/folding.ts b/extensions/typescript-language-features/src/features/folding.ts index c61028cb6ef..5b18decb440 100644 --- a/extensions/typescript-language-features/src/features/folding.ts +++ b/extensions/typescript-language-features/src/features/folding.ts @@ -9,6 +9,7 @@ import { ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; import { coalesce } from '../utils/arrays'; import { conditionalRegistration, requireMinVersion } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; class TypeScriptFoldingProvider implements vscode.FoldingRangeProvider { @@ -73,13 +74,13 @@ class TypeScriptFoldingProvider implements vscode.FoldingRangeProvider { } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, ): vscode.Disposable { return conditionalRegistration([ requireMinVersion(client, TypeScriptFoldingProvider.minVersion), ], () => { - return vscode.languages.registerFoldingRangeProvider(selector, + return vscode.languages.registerFoldingRangeProvider(selector.syntax, new TypeScriptFoldingProvider(client)); }); } diff --git a/extensions/typescript-language-features/src/features/formatting.ts b/extensions/typescript-language-features/src/features/formatting.ts index 525567e0bb2..cc2469774a5 100644 --- a/extensions/typescript-language-features/src/features/formatting.ts +++ b/extensions/typescript-language-features/src/features/formatting.ts @@ -7,6 +7,7 @@ import * as vscode from 'vscode'; import type * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; import { conditionalRegistration, requireConfiguration } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; import FileConfigurationManager from './fileConfigurationManager'; @@ -84,7 +85,7 @@ class TypeScriptFormattingProvider implements vscode.DocumentRangeFormattingEdit } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, modeId: string, client: ITypeScriptServiceClient, fileConfigurationManager: FileConfigurationManager @@ -94,8 +95,8 @@ export function register( ], () => { const formattingProvider = new TypeScriptFormattingProvider(client, fileConfigurationManager); return vscode.Disposable.from( - vscode.languages.registerOnTypeFormattingEditProvider(selector, formattingProvider, ';', '}', '\n'), - vscode.languages.registerDocumentRangeFormattingEditProvider(selector, formattingProvider), + vscode.languages.registerOnTypeFormattingEditProvider(selector.syntax, formattingProvider, ';', '}', '\n'), + vscode.languages.registerDocumentRangeFormattingEditProvider(selector.syntax, formattingProvider), ); }); } diff --git a/extensions/typescript-language-features/src/features/hover.ts b/extensions/typescript-language-features/src/features/hover.ts index 2ff92d6e308..c6c4860f663 100644 --- a/extensions/typescript-language-features/src/features/hover.ts +++ b/extensions/typescript-language-features/src/features/hover.ts @@ -5,7 +5,9 @@ import * as vscode from 'vscode'; import type * as Proto from '../protocol'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; +import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import { markdownDocumentation } from '../utils/previewer'; import * as typeConverters from '../utils/typeConverters'; @@ -51,9 +53,13 @@ class TypeScriptHoverProvider implements vscode.HoverProvider { } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient ): vscode.Disposable { - return vscode.languages.registerHoverProvider(selector, - new TypeScriptHoverProvider(client)); + return conditionalRegistration([ + requireSomeCapability(client, ClientCapability.EnhancedSyntax, ClientCapability.Semantic), + ], () => { + return vscode.languages.registerHoverProvider(selector.syntax, + new TypeScriptHoverProvider(client)); + }); } diff --git a/extensions/typescript-language-features/src/features/implementations.ts b/extensions/typescript-language-features/src/features/implementations.ts index c7cdeeb755f..bf3ddfee414 100644 --- a/extensions/typescript-language-features/src/features/implementations.ts +++ b/extensions/typescript-language-features/src/features/implementations.ts @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; +import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import DefinitionProviderBase from './definitionProviderBase'; class TypeScriptImplementationProvider extends DefinitionProviderBase implements vscode.ImplementationProvider { @@ -14,9 +16,13 @@ class TypeScriptImplementationProvider extends DefinitionProviderBase implements } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, ) { - return vscode.languages.registerImplementationProvider(selector, - new TypeScriptImplementationProvider(client)); + return conditionalRegistration([ + requireSomeCapability(client, ClientCapability.Semantic), + ], () => { + return vscode.languages.registerImplementationProvider(selector.semantic, + new TypeScriptImplementationProvider(client)); + }); } diff --git a/extensions/typescript-language-features/src/features/implementationsCodeLens.ts b/extensions/typescript-language-features/src/features/implementationsCodeLens.ts index 4e56d6499e7..0fc3c242400 100644 --- a/extensions/typescript-language-features/src/features/implementationsCodeLens.ts +++ b/extensions/typescript-language-features/src/features/implementationsCodeLens.ts @@ -9,7 +9,8 @@ import type * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { CachedResponse } from '../tsServer/cachedResponse'; import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; -import { conditionalRegistration, requireCapability, requireConfiguration } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability, requireConfiguration } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; import { getSymbolRange, ReferencesCodeLens, TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'; @@ -89,16 +90,16 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, modeId: string, client: ITypeScriptServiceClient, cachedResponse: CachedResponse, ) { return conditionalRegistration([ requireConfiguration(modeId, 'implementationsCodeLens.enabled'), - requireCapability(client, ClientCapability.Semantic), + requireSomeCapability(client, ClientCapability.Semantic), ], () => { - return vscode.languages.registerCodeLensProvider(selector, + return vscode.languages.registerCodeLensProvider(selector.semantic, new TypeScriptImplementationsCodeLensProvider(client, cachedResponse)); }); } diff --git a/extensions/typescript-language-features/src/features/jsDocCompletions.ts b/extensions/typescript-language-features/src/features/jsDocCompletions.ts index 9c930ac5ad7..6e091af1692 100644 --- a/extensions/typescript-language-features/src/features/jsDocCompletions.ts +++ b/extensions/typescript-language-features/src/features/jsDocCompletions.ts @@ -7,6 +7,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { ITypeScriptServiceClient } from '../typescriptService'; import { conditionalRegistration, requireConfiguration } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; @@ -110,14 +111,14 @@ export function templateToSnippet(template: string): vscode.SnippetString { } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, modeId: string, client: ITypeScriptServiceClient, ): vscode.Disposable { return conditionalRegistration([ requireConfiguration(modeId, 'suggest.completeJSDocs') ], () => { - return vscode.languages.registerCompletionItemProvider(selector, + return vscode.languages.registerCompletionItemProvider(selector.syntax, new JsDocCompletionProvider(client), '*'); }); diff --git a/extensions/typescript-language-features/src/features/organizeImports.ts b/extensions/typescript-language-features/src/features/organizeImports.ts index 186d12e3f2e..80175554c9e 100644 --- a/extensions/typescript-language-features/src/features/organizeImports.ts +++ b/extensions/typescript-language-features/src/features/organizeImports.ts @@ -11,6 +11,7 @@ import API from '../utils/api'; import { nulToken } from '../utils/cancellation'; import { Command, CommandManager } from '../utils/commandManager'; import { conditionalRegistration, requireMinVersion } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import { TelemetryReporter } from '../utils/telemetry'; import * as typeconverts from '../utils/typeConverters'; import FileConfigurationManager from './fileConfigurationManager'; @@ -99,7 +100,7 @@ export class OrganizeImportsCodeActionProvider implements vscode.CodeActionProvi } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, commandManager: CommandManager, fileConfigurationManager: FileConfigurationManager, @@ -109,7 +110,7 @@ export function register( requireMinVersion(client, OrganizeImportsCodeActionProvider.minVersion) ], () => { const organizeImportsProvider = new OrganizeImportsCodeActionProvider(client, commandManager, fileConfigurationManager, telemetryReporter); - return vscode.languages.registerCodeActionsProvider(selector, + return vscode.languages.registerCodeActionsProvider(selector.syntax, organizeImportsProvider, organizeImportsProvider.metadata); }); diff --git a/extensions/typescript-language-features/src/features/quickFix.ts b/extensions/typescript-language-features/src/features/quickFix.ts index 1d6fd6aa349..b2c2e031df2 100644 --- a/extensions/typescript-language-features/src/features/quickFix.ts +++ b/extensions/typescript-language-features/src/features/quickFix.ts @@ -18,7 +18,8 @@ import * as typeConverters from '../utils/typeConverters'; import { DiagnosticsManager } from './diagnostics'; import FileConfigurationManager from './fileConfigurationManager'; import { equals } from '../utils/objects'; -import { conditionalRegistration, requireCapability } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; const localize = nls.loadMessageBundle(); @@ -403,7 +404,7 @@ function isPreferredFix( } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, fileConfigurationManager: FileConfigurationManager, commandManager: CommandManager, @@ -411,9 +412,9 @@ export function register( telemetryReporter: TelemetryReporter ) { return conditionalRegistration([ - requireCapability(client, ClientCapability.Semantic), + requireSomeCapability(client, ClientCapability.Semantic), ], () => { - return vscode.languages.registerCodeActionsProvider(selector, + return vscode.languages.registerCodeActionsProvider(selector.semantic, new TypeScriptQuickFixProvider(client, fileConfigurationManager, commandManager, diagnosticsManager, telemetryReporter), TypeScriptQuickFixProvider.metadata); }); diff --git a/extensions/typescript-language-features/src/features/refactor.ts b/extensions/typescript-language-features/src/features/refactor.ts index a56267acb42..4b5612e41e7 100644 --- a/extensions/typescript-language-features/src/features/refactor.ts +++ b/extensions/typescript-language-features/src/features/refactor.ts @@ -11,7 +11,8 @@ import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService import API from '../utils/api'; import { nulToken } from '../utils/cancellation'; import { Command, CommandManager } from '../utils/commandManager'; -import { conditionalRegistration, requireCapability, requireMinVersion } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability, requireMinVersion } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as fileSchemes from '../utils/fileSchemes'; import { TelemetryReporter } from '../utils/telemetry'; import * as typeConverters from '../utils/typeConverters'; @@ -396,7 +397,7 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider { } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, formattingOptionsManager: FormattingOptionsManager, commandManager: CommandManager, @@ -404,9 +405,9 @@ export function register( ) { return conditionalRegistration([ requireMinVersion(client, TypeScriptRefactorProvider.minVersion), - requireCapability(client, ClientCapability.Semantic), + requireSomeCapability(client, ClientCapability.Semantic), ], () => { - return vscode.languages.registerCodeActionsProvider(selector, + return vscode.languages.registerCodeActionsProvider(selector.semantic, new TypeScriptRefactorProvider(client, formattingOptionsManager, commandManager, telemetryReporter), TypeScriptRefactorProvider.metadata); }); diff --git a/extensions/typescript-language-features/src/features/references.ts b/extensions/typescript-language-features/src/features/references.ts index d77ecc5b10b..1ee8d150429 100644 --- a/extensions/typescript-language-features/src/features/references.ts +++ b/extensions/typescript-language-features/src/features/references.ts @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; +import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; class TypeScriptReferenceSupport implements vscode.ReferenceProvider { @@ -42,9 +44,13 @@ class TypeScriptReferenceSupport implements vscode.ReferenceProvider { } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient ) { - return vscode.languages.registerReferenceProvider(selector, - new TypeScriptReferenceSupport(client)); + return conditionalRegistration([ + requireSomeCapability(client, ClientCapability.EnhancedSyntax, ClientCapability.Semantic), + ], () => { + return vscode.languages.registerReferenceProvider(selector.syntax, + new TypeScriptReferenceSupport(client)); + }); } diff --git a/extensions/typescript-language-features/src/features/referencesCodeLens.ts b/extensions/typescript-language-features/src/features/referencesCodeLens.ts index bfda4f07230..0666ba4a3d5 100644 --- a/extensions/typescript-language-features/src/features/referencesCodeLens.ts +++ b/extensions/typescript-language-features/src/features/referencesCodeLens.ts @@ -8,8 +8,10 @@ import * as nls from 'vscode-nls'; import type * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { CachedResponse } from '../tsServer/cachedResponse'; -import { ITypeScriptServiceClient, ClientCapability } from '../typescriptService'; -import { conditionalRegistration, requireConfiguration, requireCapability } from '../utils/dependentRegistration'; +import { ExectuionTarget } from '../tsServer/server'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; +import { conditionalRegistration, requireConfiguration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; import { getSymbolRange, ReferencesCodeLens, TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'; @@ -27,7 +29,11 @@ export class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLens public async resolveCodeLens(inputCodeLens: vscode.CodeLens, token: vscode.CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start); - const response = await this.client.execute('references', args, token, { lowPriority: true, cancelOnResourceChange: codeLens.document }); + const response = await this.client.execute('references', args, token, { + lowPriority: true, + executionTarget: ExectuionTarget.Semantic, + cancelOnResourceChange: codeLens.document, + }); if (response.type !== 'response' || !response.body) { codeLens.command = response.type === 'cancelled' ? TypeScriptBaseCodeLensProvider.cancelledCommand @@ -122,16 +128,16 @@ export class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLens } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, modeId: string, client: ITypeScriptServiceClient, cachedResponse: CachedResponse, ) { return conditionalRegistration([ requireConfiguration(modeId, 'referencesCodeLens.enabled'), - requireCapability(client, ClientCapability.Semantic), + requireSomeCapability(client, ClientCapability.Semantic), ], () => { - return vscode.languages.registerCodeLensProvider(selector, + return vscode.languages.registerCodeLensProvider(selector.semantic, new TypeScriptReferencesCodeLensProvider(client, cachedResponse, modeId)); }); } diff --git a/extensions/typescript-language-features/src/features/rename.ts b/extensions/typescript-language-features/src/features/rename.ts index da784760d66..e3e1b3c694e 100644 --- a/extensions/typescript-language-features/src/features/rename.ts +++ b/extensions/typescript-language-features/src/features/rename.ts @@ -9,7 +9,8 @@ import * as nls from 'vscode-nls'; import type * as Proto from '../protocol'; import { ClientCapability, ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; import API from '../utils/api'; -import { conditionalRegistration, requireCapability } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; import FileConfigurationManager from './fileConfigurationManager'; @@ -138,14 +139,14 @@ class TypeScriptRenameProvider implements vscode.RenameProvider { } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, fileConfigurationManager: FileConfigurationManager, ) { return conditionalRegistration([ - requireCapability(client, ClientCapability.Semantic), + requireSomeCapability(client, ClientCapability.Semantic), ], () => { - return vscode.languages.registerRenameProvider(selector, + return vscode.languages.registerRenameProvider(selector.semantic, new TypeScriptRenameProvider(client, fileConfigurationManager)); }); } diff --git a/extensions/typescript-language-features/src/features/semanticTokens.ts b/extensions/typescript-language-features/src/features/semanticTokens.ts index 6174b51c8e5..c404ac0b95a 100644 --- a/extensions/typescript-language-features/src/features/semanticTokens.ts +++ b/extensions/typescript-language-features/src/features/semanticTokens.ts @@ -9,7 +9,8 @@ import * as vscode from 'vscode'; import * as Proto from '../protocol'; import { ClientCapability, ExecConfig, ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; import API from '../utils/api'; -import { conditionalRegistration, requireCapability, requireMinVersion } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability, requireMinVersion } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; const minTypeScriptVersion = API.fromVersionString(`${VersionRequirement.major}.${VersionRequirement.minor}`); @@ -17,15 +18,18 @@ const minTypeScriptVersion = API.fromVersionString(`${VersionRequirement.major}. // as we don't do deltas, for performance reasons, don't compute semantic tokens for documents above that limit const CONTENT_LENGTH_LIMIT = 100000; -export function register(selector: vscode.DocumentSelector, client: ITypeScriptServiceClient) { +export function register( + selector: DocumentSelector, + client: ITypeScriptServiceClient, +) { return conditionalRegistration([ requireMinVersion(client, minTypeScriptVersion), - requireCapability(client, ClientCapability.Semantic), + requireSomeCapability(client, ClientCapability.Semantic), ], () => { const provider = new DocumentSemanticTokensProvider(client); return vscode.Disposable.from( // register only as a range provider - vscode.languages.registerDocumentRangeSemanticTokensProvider(selector, provider, provider.getLegend()), + vscode.languages.registerDocumentRangeSemanticTokensProvider(selector.semantic, provider, provider.getLegend()), ); }); } diff --git a/extensions/typescript-language-features/src/features/signatureHelp.ts b/extensions/typescript-language-features/src/features/signatureHelp.ts index 8e751f8c114..93901b9bb25 100644 --- a/extensions/typescript-language-features/src/features/signatureHelp.ts +++ b/extensions/typescript-language-features/src/features/signatureHelp.ts @@ -5,7 +5,9 @@ import * as vscode from 'vscode'; import type * as Proto from '../protocol'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; +import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as Previewer from '../utils/previewer'; import * as typeConverters from '../utils/typeConverters'; @@ -120,12 +122,16 @@ function toTsTriggerReason(context: vscode.SignatureHelpContext): Proto.Signatur } } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, ) { - return vscode.languages.registerSignatureHelpProvider(selector, - new TypeScriptSignatureHelpProvider(client), { - triggerCharacters: TypeScriptSignatureHelpProvider.triggerCharacters, - retriggerCharacters: TypeScriptSignatureHelpProvider.retriggerCharacters + return conditionalRegistration([ + requireSomeCapability(client, ClientCapability.EnhancedSyntax, ClientCapability.Semantic), + ], () => { + return vscode.languages.registerSignatureHelpProvider(selector.syntax, + new TypeScriptSignatureHelpProvider(client), { + triggerCharacters: TypeScriptSignatureHelpProvider.triggerCharacters, + retriggerCharacters: TypeScriptSignatureHelpProvider.retriggerCharacters + }); }); } diff --git a/extensions/typescript-language-features/src/features/smartSelect.ts b/extensions/typescript-language-features/src/features/smartSelect.ts index e61c168bd8c..f769347f15c 100644 --- a/extensions/typescript-language-features/src/features/smartSelect.ts +++ b/extensions/typescript-language-features/src/features/smartSelect.ts @@ -8,6 +8,7 @@ import type * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; import { conditionalRegistration, requireMinVersion } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; class SmartSelection implements vscode.SelectionRangeProvider { @@ -49,12 +50,12 @@ class SmartSelection implements vscode.SelectionRangeProvider { } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, ) { return conditionalRegistration([ requireMinVersion(client, SmartSelection.minVersion), ], () => { - return vscode.languages.registerSelectionRangeProvider(selector, new SmartSelection(client)); + return vscode.languages.registerSelectionRangeProvider(selector.syntax, new SmartSelection(client)); }); } diff --git a/extensions/typescript-language-features/src/features/tagClosing.ts b/extensions/typescript-language-features/src/features/tagClosing.ts index 40fee040f3e..289ce73b293 100644 --- a/extensions/typescript-language-features/src/features/tagClosing.ts +++ b/extensions/typescript-language-features/src/features/tagClosing.ts @@ -9,6 +9,7 @@ import { ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; import { conditionalRegistration, requireMinVersion, requireConfiguration, Condition } from '../utils/dependentRegistration'; import { Disposable } from '../utils/dispose'; +import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; class TagClosing extends Disposable { @@ -151,13 +152,13 @@ function requireActiveDocument( } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, modeId: string, client: ITypeScriptServiceClient, ) { return conditionalRegistration([ requireMinVersion(client, TagClosing.minVersion), requireConfiguration(modeId, 'autoClosingTags'), - requireActiveDocument(selector) + requireActiveDocument(selector.syntax) ], () => new TagClosing(client)); } diff --git a/extensions/typescript-language-features/src/features/typeDefinitions.ts b/extensions/typescript-language-features/src/features/typeDefinitions.ts index 6f63e44df0a..4aef4f41ed4 100644 --- a/extensions/typescript-language-features/src/features/typeDefinitions.ts +++ b/extensions/typescript-language-features/src/features/typeDefinitions.ts @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; +import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; +import { DocumentSelector } from '../utils/documentSelector'; import DefinitionProviderBase from './definitionProviderBase'; export default class TypeScriptTypeDefinitionProvider extends DefinitionProviderBase implements vscode.TypeDefinitionProvider { @@ -14,9 +16,13 @@ export default class TypeScriptTypeDefinitionProvider extends DefinitionProvider } export function register( - selector: vscode.DocumentSelector, + selector: DocumentSelector, client: ITypeScriptServiceClient, ) { - return vscode.languages.registerTypeDefinitionProvider(selector, - new TypeScriptTypeDefinitionProvider(client)); + return conditionalRegistration([ + requireSomeCapability(client, ClientCapability.EnhancedSyntax, ClientCapability.Semantic), + ], () => { + return vscode.languages.registerTypeDefinitionProvider(selector.syntax, + new TypeScriptTypeDefinitionProvider(client)); + }); } diff --git a/extensions/typescript-language-features/src/features/updatePathsOnRename.ts b/extensions/typescript-language-features/src/features/updatePathsOnRename.ts index 84171e18fb7..2c6354c01a8 100644 --- a/extensions/typescript-language-features/src/features/updatePathsOnRename.ts +++ b/extensions/typescript-language-features/src/features/updatePathsOnRename.ts @@ -11,7 +11,7 @@ import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService import API from '../utils/api'; import { Delayer } from '../utils/async'; import { nulToken } from '../utils/cancellation'; -import { conditionalRegistration, requireCapability, requireMinVersion } from '../utils/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability, requireMinVersion } from '../utils/dependentRegistration'; import { Disposable } from '../utils/dispose'; import * as fileSchemes from '../utils/fileSchemes'; import { doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription'; @@ -296,7 +296,7 @@ export function register( ) { return conditionalRegistration([ requireMinVersion(client, UpdateImportsOnFileRenameHandler.minVersion), - requireCapability(client, ClientCapability.Semantic), + requireSomeCapability(client, ClientCapability.Semantic), ], () => { return new UpdateImportsOnFileRenameHandler(client, fileConfigurationManager, handles); }); diff --git a/extensions/typescript-language-features/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts index ee040667b68..e1dee8db669 100644 --- a/extensions/typescript-language-features/src/languageProvider.ts +++ b/extensions/typescript-language-features/src/languageProvider.ts @@ -5,15 +5,16 @@ import { basename } from 'path'; import * as vscode from 'vscode'; -import { CachedResponse } from './tsServer/cachedResponse'; import { DiagnosticKind } from './features/diagnostics'; import FileConfigurationManager from './features/fileConfigurationManager'; +import { CachedResponse } from './tsServer/cachedResponse'; +import { ClientCapability } from './typescriptService'; import TypeScriptServiceClient from './typescriptServiceClient'; import { CommandManager } from './utils/commandManager'; import { Disposable } from './utils/dispose'; +import { DocumentSelector } from './utils/documentSelector'; import * as fileSchemes from './utils/fileSchemes'; import { LanguageDescription } from './utils/languageDescription'; -import { memoize } from './utils/memoize'; import { TelemetryReporter } from './utils/telemetry'; import TypingsStatus from './utils/typingsStatus'; @@ -39,15 +40,22 @@ export default class LanguageProvider extends Disposable { client.onReady(() => this.registerProviders()); } - @memoize - private get documentSelector(): vscode.DocumentFilter[] { - const documentSelector = []; + private get documentSelector(): DocumentSelector { + const semantic: vscode.DocumentFilter[] = []; + const syntax: vscode.DocumentFilter[] = []; for (const language of this.description.modeIds) { - for (const scheme of fileSchemes.supportedSchemes) { - documentSelector.push({ language, scheme }); + syntax.push({ language }); + for (const scheme of fileSchemes.semanticSupportedSchemes) { + semantic.push({ language, scheme }); } } - return documentSelector; + + if (this.client.capabilities.has(ClientCapability.EnhancedSyntax)) { + return { semantic, syntax }; + } + + // If we don't have a + return { semantic, syntax: semantic }; } private async registerProviders(): Promise { diff --git a/extensions/typescript-language-features/src/lazyClientHost.ts b/extensions/typescript-language-features/src/lazyClientHost.ts index 02cbd68006b..4dc11db4ad8 100644 --- a/extensions/typescript-language-features/src/lazyClientHost.ts +++ b/extensions/typescript-language-features/src/lazyClientHost.ts @@ -5,14 +5,13 @@ import * as vscode from 'vscode'; import { OngoingRequestCancellerFactory } from './tsServer/cancellation'; +import { ILogDirectoryProvider } from './tsServer/logDirectoryProvider'; import TypeScriptServiceClientHost from './typeScriptServiceClientHost'; import { flatten } from './utils/arrays'; import { CommandManager } from './utils/commandManager'; -import * as fileSchemes from './utils/fileSchemes'; import { standardLanguageDescriptions } from './utils/languageDescription'; import * as ProjectStatus from './utils/largeProjectStatus'; import { lazy, Lazy } from './utils/lazy'; -import { ILogDirectoryProvider } from './tsServer/logDirectoryProvider'; import ManagedFileContextManager from './utils/managedFileContext'; import { PluginManager } from './utils/plugins'; @@ -87,11 +86,8 @@ export function lazilyActivateClient( } function isSupportedDocument( - supportedLanguage: string[], + supportedLanguage: readonly string[], document: vscode.TextDocument ): boolean { - if (supportedLanguage.indexOf(document.languageId) < 0) { - return false; - } - return fileSchemes.isSupportedScheme(document.uri.scheme); + return supportedLanguage.indexOf(document.languageId) >= 0; } diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index d051a216b96..6880474d69a 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -16,6 +16,10 @@ import { TelemetryReporter } from '../utils/telemetry'; import Tracer from '../utils/tracer'; import { TypeScriptVersion } from '../utils/versionProvider'; +export enum ExectuionTarget { + Semantic, + Syntax +} export interface ITypeScriptServer { readonly onEvent: vscode.Event; @@ -26,9 +30,9 @@ export interface ITypeScriptServer { kill(): void; - executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined; + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, executionTarget?: ExectuionTarget }): undefined; + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExectuionTarget }): Promise>; + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExectuionTarget }): Promise> | undefined; dispose(): void; } @@ -172,9 +176,9 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe } } - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, executionTarget?: ExectuionTarget }): undefined; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExectuionTarget }): Promise>; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExectuionTarget }): Promise> | undefined { const request = this._requestQueue.createRequest(command, args); const requestInfo: RequestItem = { request, @@ -272,6 +276,14 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe } +interface ExecuteInfo { + readonly isAsync: boolean; + readonly token?: vscode.CancellationToken; + readonly expectsResult: boolean; + readonly lowPriority?: boolean; + readonly executionTarget?: ExectuionTarget; +} + class RequestRouter { private static readonly sharedCommands = new Set([ @@ -284,13 +296,16 @@ class RequestRouter { ]); constructor( - private readonly servers: ReadonlyArray<{ readonly server: ITypeScriptServer, canRun?(command: keyof TypeScriptRequests): void }>, + private readonly servers: ReadonlyArray<{ + readonly server: ITypeScriptServer; + canRun?(command: keyof TypeScriptRequests, executeInfo: ExecuteInfo): void; + }>, private readonly delegate: TsServerDelegate, ) { } - public execute(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { - if (RequestRouter.sharedCommands.has(command)) { - // Dispatch shared commands to all server but only return from first one one + public execute(command: keyof TypeScriptRequests, args: any, executeInfo: ExecuteInfo): Promise> | undefined { + if (RequestRouter.sharedCommands.has(command) && typeof executeInfo.executionTarget === 'undefined') { + // Dispatch shared commands to all servers but only return from first one const requestStates: RequestState.State[] = this.servers.map(() => RequestState.Unresolved); @@ -344,7 +359,7 @@ class RequestRouter { } for (const { canRun, server } of this.servers) { - if (!canRun || canRun(command)) { + if (!canRun || canRun(command, executeInfo)) { return server.executeImpl(command, args, executeInfo); } } @@ -420,9 +435,9 @@ export class GetErrRoutingTsServer extends Disposable implements ITypeScriptServ this.mainServer.kill(); } - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, executionTarget?: ExectuionTarget }): undefined; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExectuionTarget }): Promise>; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExectuionTarget }): Promise> | undefined { return this.router.execute(command, args, executeInfo); } } @@ -490,7 +505,12 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ [ { server: this.syntaxServer, - canRun: (command) => { + canRun: (command, execInfo) => { + switch (execInfo.executionTarget) { + case ExectuionTarget.Semantic: return false; + case ExectuionTarget.Syntax: return true; + } + if (SyntaxRoutingTsServer.syntaxAlwaysCommands.has(command)) { return true; } @@ -556,9 +576,9 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ this.semanticServer.kill(); } - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, executionTarget?: ExectuionTarget }): undefined; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExectuionTarget }): Promise>; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExectuionTarget }): Promise> | undefined { return this.router.execute(command, args, executeInfo); } } diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index 2c6ddefe9f3..dd6bf911f45 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; import BufferSyncSupport from './features/bufferSyncSupport'; import * as Proto from './protocol'; +import { ExectuionTarget } from './tsServer/server'; import API from './utils/api'; import { TypeScriptServiceConfiguration } from './utils/configuration'; import { PluginManager } from './utils/plugins'; @@ -82,11 +83,24 @@ export type TypeScriptRequests = StandardTsServerRequests & NoResponseTsServerRe export type ExecConfig = { readonly lowPriority?: boolean; readonly nonRecoverable?: boolean; - readonly cancelOnResourceChange?: vscode.Uri + readonly cancelOnResourceChange?: vscode.Uri; + readonly executionTarget?: ExectuionTarget; }; export enum ClientCapability { + /** + * Basic syntax server. All clients should support this. + */ Syntax, + + /** + * Advanced syntax server that can provide single file IntelliSense. + */ + EnhancedSyntax, + + /** + * Complete, multi-file semantic server + */ Semantic, } @@ -138,7 +152,7 @@ export interface ITypeScriptServiceClient { readonly onTypesInstallerInitializationFailed: vscode.Event; readonly capabilities: ClientCapabilities; - readonly onDidChangeCapabilities: vscode.Event; + readonly onDidChangeCapabilities: vscode.Event; onReady(f: () => void): Promise; diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 3574a765c1a..df1de8af7c9 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -207,13 +207,18 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public get capabilities() { + if (this.apiVersion.gte(API.v400)) { + return new ClientCapabilities( + ClientCapability.Syntax, + ClientCapability.EnhancedSyntax, + ClientCapability.Semantic); + } return new ClientCapabilities( - ClientCapability.Semantic, ClientCapability.Syntax, - ); + ClientCapability.Semantic); } - private readonly _onDidChangeCapabilities = this._register(new vscode.EventEmitter()); + private readonly _onDidChangeCapabilities = this._register(new vscode.EventEmitter()); readonly onDidChangeCapabilities = this._onDidChangeCapabilities.event; private cancelInflightRequestsForResource(resource: vscode.Uri): void { @@ -437,7 +442,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType this._onReady!.resolve(); this._onTsServerStarted.fire({ version: version, usedApiVersion: apiVersion }); - + this._onDidChangeCapabilities.fire(); return this.serverState; } @@ -608,27 +613,23 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public normalizedPath(resource: vscode.Uri): string | undefined { - if (resource.scheme === fileSchemes.walkThroughSnippet || resource.scheme === fileSchemes.untitled) { - const dirName = path.dirname(resource.path); - const fileName = this.inMemoryResourcePrefix + path.basename(resource.path); - return resource.with({ path: path.posix.join(dirName, fileName), query: '' }).toString(true); - } + switch (resource.scheme) { + case fileSchemes.file: + { + let result = resource.fsPath; + if (!result) { + return undefined; + } + result = path.normalize(result); - if (resource.scheme !== fileSchemes.file) { - return undefined; + // Both \ and / must be escaped in regular expressions + return result.replace(new RegExp('\\' + this.pathSeparator, 'g'), '/'); + } + default: + { + return this.inMemoryResourcePrefix + resource.toString(true); + } } - - let result = resource.fsPath; - if (!result) { - return undefined; - } - - if (resource.scheme === fileSchemes.file) { - result = path.normalize(result); - } - - // Both \ and / must be escaped in regular expressions - return result.replace(new RegExp('\\' + this.pathSeparator, 'g'), '/'); } public toPath(resource: vscode.Uri): string | undefined { @@ -735,9 +736,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } - private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, requireSemantic?: boolean }): undefined; + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, requireSemantic?: boolean }): Promise>; + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, requireSemantic?: boolean }): Promise> | undefined { this.bufferSyncSupport.beforeCommand(command); const runningServerState = this.service(); return runningServerState.server.executeImpl(command, args, executeInfo); diff --git a/extensions/typescript-language-features/src/utils/dependentRegistration.ts b/extensions/typescript-language-features/src/utils/dependentRegistration.ts index a10a33ba80c..29597ab50cb 100644 --- a/extensions/typescript-language-features/src/utils/dependentRegistration.ts +++ b/extensions/typescript-language-features/src/utils/dependentRegistration.ts @@ -96,12 +96,12 @@ export function requireConfiguration( ); } -export function requireCapability( +export function requireSomeCapability( client: ITypeScriptServiceClient, - requiredCapability: ClientCapability, + ...capabilities: readonly ClientCapability[] ) { return new Condition( - () => client.capabilities.has(requiredCapability), + () => capabilities.some(requiredCapability => client.capabilities.has(requiredCapability)), client.onDidChangeCapabilities ); } diff --git a/extensions/typescript-language-features/src/utils/documentSelector.ts b/extensions/typescript-language-features/src/utils/documentSelector.ts new file mode 100644 index 00000000000..0574c3f587d --- /dev/null +++ b/extensions/typescript-language-features/src/utils/documentSelector.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * 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'; + +export interface DocumentSelector { + /** + * Selector for files which only require a basic syntax server. + */ + readonly syntax: vscode.DocumentFilter[]; + + /** + * Selector for files which require semantic server support. + */ + readonly semantic: vscode.DocumentFilter[]; +} diff --git a/extensions/typescript-language-features/src/utils/fileSchemes.ts b/extensions/typescript-language-features/src/utils/fileSchemes.ts index 6efcfab4d3b..4e94d547bd6 100644 --- a/extensions/typescript-language-features/src/utils/fileSchemes.ts +++ b/extensions/typescript-language-features/src/utils/fileSchemes.ts @@ -8,12 +8,7 @@ export const untitled = 'untitled'; export const git = 'git'; export const walkThroughSnippet = 'walkThroughSnippet'; -export const supportedSchemes = [ +export const semanticSupportedSchemes = [ file, untitled, - walkThroughSnippet ]; - -export function isSupportedScheme(scheme: string): boolean { - return supportedSchemes.indexOf(scheme) >= 0; -} diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index df362c06589..933e370f92c 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -72,6 +72,7 @@ export interface JSONScanner { } + export interface ParseError { error: ParseErrorCode; offset: number;