diff --git a/extensions/typescript-language-features/src/languageFeatures/hover.ts b/extensions/typescript-language-features/src/languageFeatures/hover.ts index c6c4860f663..a4de074897f 100644 --- a/extensions/typescript-language-features/src/languageFeatures/hover.ts +++ b/extensions/typescript-language-features/src/languageFeatures/hover.ts @@ -5,7 +5,8 @@ import * as vscode from 'vscode'; import type * as Proto from '../protocol'; -import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; +import { localize } from '../tsServer/versionProvider'; +import { ClientCapability, ITypeScriptServiceClient, ServerType } from '../typescriptService'; import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration'; import { DocumentSelector } from '../utils/documentSelector'; import { markdownDocumentation } from '../utils/previewer'; @@ -35,17 +36,30 @@ class TypeScriptHoverProvider implements vscode.HoverProvider { } return new vscode.Hover( - TypeScriptHoverProvider.getContents(response.body), + this.getContents(response.body, response._serverType), typeConverters.Range.fromTextSpan(response.body)); } - private static getContents( - data: Proto.QuickInfoResponseBody + private getContents( + data: Proto.QuickInfoResponseBody, + source: ServerType | undefined, ) { - const parts = []; + const parts: vscode.MarkedString[] = []; if (data.displayString) { - parts.push({ language: 'typescript', value: data.displayString }); + const displayParts: string[] = []; + + if (source === ServerType.Syntax && this.client.capabilities.has(ClientCapability.Semantic)) { + displayParts.push( + localize({ + key: 'loadingPrefix', + comment: ['Prefix displayed for hover entries while the server is still loading'] + }, "(loading...)")); + } + + displayParts.push(data.displayString); + + parts.push({ language: 'typescript', value: displayParts.join(' ') }); } parts.push(markdownDocumentation(data.documentation, data.tags)); return parts; diff --git a/extensions/typescript-language-features/src/protocol.d.ts b/extensions/typescript-language-features/src/protocol.d.ts index 6e926eb8d7e..e81fe81f2db 100644 --- a/extensions/typescript-language-features/src/protocol.d.ts +++ b/extensions/typescript-language-features/src/protocol.d.ts @@ -1,2 +1,12 @@ import * as Proto from 'typescript/lib/protocol'; export = Proto; + +declare enum ServerType { + Syntax = 'syntax', + Semantic = 'semantic', +} +declare module 'typescript/lib/protocol' { + interface Response { + readonly _serverType?: ServerType; + } +} diff --git a/extensions/typescript-language-features/src/test/server.test.ts b/extensions/typescript-language-features/src/test/server.test.ts index 7e27e366b5c..5caad737a48 100644 --- a/extensions/typescript-language-features/src/test/server.test.ts +++ b/extensions/typescript-language-features/src/test/server.test.ts @@ -9,6 +9,7 @@ import * as stream from 'stream'; import type * as Proto from '../protocol'; import { NodeRequestCanceller } from '../tsServer/cancellation.electron'; import { ProcessBasedTsServer, TsServerProcess } from '../tsServer/server'; +import { ServerType } from '../typescriptService'; import { nulToken } from '../utils/cancellation'; import { Logger } from '../utils/logger'; import { TelemetryReporter } from '../utils/telemetry'; @@ -64,7 +65,7 @@ suite('Server', () => { test('should send requests with increasing sequence numbers', async () => { const process = new FakeServerProcess(); - const server = new ProcessBasedTsServer('semantic', process, undefined, new NodeRequestCanceller('semantic', tracer), undefined!, NoopTelemetryReporter, tracer); + const server = new ProcessBasedTsServer('semantic', ServerType.Semantic, process, undefined, new NodeRequestCanceller('semantic', tracer), undefined!, NoopTelemetryReporter, tracer); const onWrite1 = process.onWrite(); server.executeImpl('geterr', {}, { isAsync: false, token: nulToken, expectsResult: true }); diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index fc7841322bd..6ad3d015679 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -9,7 +9,7 @@ import { EventName } from '../protocol.const'; import { CallbackMap } from '../tsServer/callbackMap'; import { RequestItem, RequestQueue, RequestQueueingType } from '../tsServer/requestQueue'; import { TypeScriptServerError } from '../tsServer/serverError'; -import { ServerResponse, TypeScriptRequests } from '../typescriptService'; +import { ServerResponse, ServerType, TypeScriptRequests } from '../typescriptService'; import { TypeScriptServiceConfiguration } from '../utils/configuration'; import { Disposable } from '../utils/dispose'; import { TelemetryReporter } from '../utils/telemetry'; @@ -77,6 +77,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe constructor( private readonly _serverId: string, + private readonly _serverSource: ServerType, private readonly _process: TsServerProcess, private readonly _tsServerLogFile: string | undefined, private readonly _requestCanceller: OngoingRequestCanceller, @@ -130,7 +131,14 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe try { switch (message.type) { case 'response': - this.dispatchResponse(message as Proto.Response); + if (this._serverSource) { + this.dispatchResponse({ + ...(message as Proto.Response), + _serverType: this._serverSource + }); + } else { + this.dispatchResponse(message as Proto.Response); + } break; case 'event': diff --git a/extensions/typescript-language-features/src/tsServer/spawner.ts b/extensions/typescript-language-features/src/tsServer/spawner.ts index 70f1b41574e..7f4aaeefe13 100644 --- a/extensions/typescript-language-features/src/tsServer/spawner.ts +++ b/extensions/typescript-language-features/src/tsServer/spawner.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import * as vscode from 'vscode'; import { OngoingRequestCancellerFactory } from '../tsServer/cancellation'; -import { ClientCapabilities, ClientCapability } from '../typescriptService'; +import { ClientCapabilities, ClientCapability, ServerType } from '../typescriptService'; import API from '../utils/api'; import { SeparateSyntaxServerConfiguration, TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration'; import { Logger } from '../utils/logger'; @@ -143,6 +143,7 @@ export class TypeScriptServerSpawner { return new ProcessBasedTsServer( kind, + this.kindToServerType(kind), process!, tsServerLogFile, canceller, @@ -151,6 +152,19 @@ export class TypeScriptServerSpawner { this._tracer); } + private kindToServerType(kind: TsServerProcessKind): ServerType { + switch (kind) { + case TsServerProcessKind.Syntax: + return ServerType.Syntax; + + case TsServerProcessKind.Main: + case TsServerProcessKind.Semantic: + case TsServerProcessKind.Diagnostics: + default: + return ServerType.Semantic; + } + } + private getTsServerArgs( kind: TsServerProcessKind, configuration: TypeScriptServiceConfiguration, diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index de32927d816..8a59d97105c 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -13,6 +13,11 @@ import { TypeScriptServiceConfiguration } from './utils/configuration'; import { PluginManager } from './utils/plugins'; import { TelemetryReporter } from './utils/telemetry'; +export enum ServerType { + Syntax = 'syntax', + Semantic = 'semantic', +} + export namespace ServerResponse { export class Cancelled {