diff --git a/client/src/commands.ts b/client/src/commands.ts index cd2370e7..d04525e2 100644 --- a/client/src/commands.ts +++ b/client/src/commands.ts @@ -21,6 +21,7 @@ import { WelcomePanel } from "./welcome"; import { assert, getDenoCommand } from "./util"; import { registryState } from "./lsp_extensions"; import { createRegistryStateHandler } from "./notification_handlers"; +import { DenoServerInfo } from "./server_info"; import * as semver from "semver"; import * as vscode from "vscode"; @@ -101,11 +102,10 @@ export function startLanguageServer( ): Callback { return async () => { // Stop the existing language server and reset the state - const { statusBarItem } = extensionContext; if (extensionContext.client) { const client = extensionContext.client; extensionContext.client = undefined; - statusBarItem.hide(); + extensionContext.statusBar.refresh(extensionContext); vscode.commands.executeCommand("setContext", ENABLEMENT_FLAG, false); await client.stop(); } @@ -141,15 +141,10 @@ export function startLanguageServer( extensionContext.client = client; vscode.commands.executeCommand("setContext", ENABLEMENT_FLAG, true); - const serverVersion = extensionContext.serverVersion = - (client.initializeResult?.serverInfo?.version ?? "") - .split( - " ", - )[0]; - statusBarItem.text = `Deno ${serverVersion}`; - statusBarItem.tooltip = client - .initializeResult?.serverInfo?.version; - statusBarItem.show(); + extensionContext.serverInfo = new DenoServerInfo( + client.initializeResult?.serverInfo, + ); + extensionContext.statusBar.refresh(extensionContext); context.subscriptions.push( client.onNotification( @@ -161,10 +156,10 @@ export function startLanguageServer( extensionContext.tsApi.refresh(); if ( - semver.valid(extensionContext.serverVersion) && - !semver.satisfies(extensionContext.serverVersion, SERVER_SEMVER) + semver.valid(extensionContext.serverInfo.version) && + !semver.satisfies(extensionContext.serverInfo.version, SERVER_SEMVER) ) { - notifyServerSemver(extensionContext.serverVersion); + notifyServerSemver(extensionContext.serverInfo.version); } else { showWelcomePageIfFirstUse(context, extensionContext); } diff --git a/client/src/extension.ts b/client/src/extension.ts index c08c46c3..7b2fc71c 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -4,13 +4,14 @@ import * as commands from "./commands"; import { ENABLEMENT_FLAG, EXTENSION_NS } from "./constants"; import { DenoTextDocumentContentProvider, SCHEME } from "./content_provider"; import { DenoDebugConfigurationProvider } from "./debug_config_provider"; +import { DenoStatusBar } from "./status_bar"; import { activateTaskProvider } from "./tasks"; +import { getTsApi } from "./ts_api"; import type { DenoExtensionContext, Settings } from "./types"; import { assert } from "./util"; import * as path from "path"; import * as vscode from "vscode"; -import { getTsApi } from "./ts_api"; /** The language IDs we care about. */ const LANGUAGES = [ @@ -108,6 +109,7 @@ function handleConfigurationChange(event: vscode.ConfigurationChangeEvent) { }; } extensionContext.tsApi.refresh(); + extensionContext.statusBar.refresh(extensionContext); // restart when "deno.path" changes if (event.affectsConfiguration("deno.path")) { @@ -180,11 +182,8 @@ export async function activate( context.subscriptions, ); - extensionContext.statusBarItem = vscode.window.createStatusBarItem( - vscode.StatusBarAlignment.Right, - 0, - ); - context.subscriptions.push(extensionContext.statusBarItem); + extensionContext.statusBar = new DenoStatusBar(); + context.subscriptions.push(extensionContext.statusBar); // Register a content provider for Deno resolved read-only files. context.subscriptions.push( @@ -238,7 +237,7 @@ export function deactivate(): Thenable | undefined { const client = extensionContext.client; extensionContext.client = undefined; - extensionContext.statusBarItem.hide(); + extensionContext.statusBar.refresh(extensionContext); vscode.commands.executeCommand("setContext", ENABLEMENT_FLAG, false); return client.stop(); } diff --git a/client/src/server_info.ts b/client/src/server_info.ts new file mode 100644 index 00000000..85f7a148 --- /dev/null +++ b/client/src/server_info.ts @@ -0,0 +1,21 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +import { InitializeResult } from "vscode-languageclient"; + +export class DenoServerInfo { + readonly #fullVersion: string; + + constructor(serverInfo: InitializeResult["serverInfo"]) { + this.#fullVersion = serverInfo?.version ?? ""; + } + + /** Gets the version with configuration and architecture. Ex: x.x.x (release, x86_64-etc) */ + get versionWithBuildInfo() { + return this.#fullVersion; + } + + /** Gets the version. Ex. x.x.x */ + get version() { + return this.#fullVersion.split(" ")[0]; + } +} diff --git a/client/src/shared_types.d.ts b/client/src/shared_types.d.ts new file mode 100644 index 00000000..88444027 --- /dev/null +++ b/client/src/shared_types.d.ts @@ -0,0 +1,59 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +import type { ConfigurationScope } from "vscode"; + +// types shared with typescript-deno-plugin + +/** When `vscode.WorkspaceSettings` get serialized, they keys of the + * configuration are available. This interface should mirror the configuration + * contributions made by the extension. + */ +export interface Settings { + /** Specify an explicit path to the `deno` cache instead of using DENO_DIR + * or the OS default. */ + cache: string | null; + /** Settings related to code lens. */ + codeLens: { + implementations: boolean; + references: boolean; + referencesAllFunctions: boolean; + test: boolean; + testArgs: string[]; + } | null; + /** A path to a `tsconfig.json` that should be applied. */ + config: string | null; + /** Is the extension enabled or not. */ + enable: boolean; + /** A path to an import map that should be applied. */ + importMap: string | null; + /** A flag that enables additional internal debug information to be printed + * to the _Deno Language Server_ output. */ + internalDebug: boolean; + /** Determine if the extension should be providing linting diagnostics. */ + lint: boolean; + /** Specify an explicit path to the `deno` binary. */ + path: string | null; + suggest: { + autoImports: boolean; + completeFunctionCalls: boolean; + names: boolean; + paths: boolean; + imports: { + autoDiscover: boolean; + hosts: Record; + } | null; + } | null; + /** Determine if the extension should be type checking against the unstable + * APIs. */ + unstable: boolean; +} + +export interface PluginSettings { + workspace: Settings; + documents: Record; +} + +export interface DocumentSettings { + scope: ConfigurationScope; + settings: Partial; +} diff --git a/client/src/status_bar.ts b/client/src/status_bar.ts new file mode 100644 index 00000000..bbe37bb5 --- /dev/null +++ b/client/src/status_bar.ts @@ -0,0 +1,38 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +import { DenoExtensionContext } from "./types"; + +import * as vscode from "vscode"; + +export class DenoStatusBar { + readonly #inner: vscode.StatusBarItem; + + constructor() { + this.#inner = vscode.window.createStatusBarItem( + vscode.StatusBarAlignment.Right, + 0, + ); + } + + dispose() { + this.#inner.dispose(); + } + + refresh(extensionContext: DenoExtensionContext) { + if (extensionContext.serverInfo) { + this.#inner.text = `Deno ${extensionContext.serverInfo.version}`; + this.#inner.tooltip = extensionContext.serverInfo.versionWithBuildInfo; + } + + // show only when "enable" is true and language server started + if ( + extensionContext.workspaceSettings.enable && + extensionContext.client && + extensionContext.serverInfo + ) { + this.#inner.show(); + } else { + this.#inner.hide(); + } + } +} diff --git a/client/src/types.d.ts b/client/src/types.d.ts index d3dd6cc2..38021a56 100644 --- a/client/src/types.d.ts +++ b/client/src/types.d.ts @@ -1,64 +1,14 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { ConfigurationScope, StatusBarItem } from "vscode"; import type { LanguageClient, LanguageClientOptions, } from "vscode-languageclient/node"; +import type { DenoServerInfo } from "./server_info"; +import type { DocumentSettings, Settings } from "./shared_types"; +import type { DenoStatusBar } from "./status_bar"; -/** When `vscode.WorkspaceSettings` get serialized, they keys of the - * configuration are available. This interface should mirror the configuration - * contributions made by the extension. - */ -export interface Settings { - /** Specify an explicit path to the `deno` cache instead of using DENO_DIR - * or the OS default. */ - cache: string | null; - /** Settings related to code lens. */ - codeLens: { - implementations: boolean; - references: boolean; - referencesAllFunctions: boolean; - test: boolean; - testArgs: string[]; - } | null; - /** A path to a `tsconfig.json` that should be applied. */ - config: string | null; - /** Is the extension enabled or not. */ - enable: boolean; - /** A path to an import map that should be applied. */ - importMap: string | null; - /** A flag that enables additional internal debug information to be printed - * to the _Deno Language Server_ output. */ - internalDebug: boolean; - /** Determine if the extension should be providing linting diagnostics. */ - lint: boolean; - /** Specify an explicit path to the `deno` binary. */ - path: string | null; - suggest: { - autoImports: boolean; - completeFunctionCalls: boolean; - names: boolean; - paths: boolean; - imports: { - autoDiscover: boolean; - hosts: Record; - } | null; - } | null; - /** Determine if the extension should be type checking against the unstable - * APIs. */ - unstable: boolean; -} - -export interface PluginSettings { - workspace: Settings; - documents: Record; -} - -export interface DocumentSettings { - scope: ConfigurationScope; - settings: Partial; -} +export * from "./shared_types"; export interface TsApi { /** Update the typescript-deno-plugin with settings. */ @@ -70,8 +20,8 @@ export interface DenoExtensionContext { clientOptions: LanguageClientOptions; /** A record of filepaths and their document settings. */ documentSettings: Record; - serverVersion: string; - statusBarItem: StatusBarItem; + serverInfo: DenoServerInfo | undefined; + statusBar: DenoStatusBar; tsApi: TsApi; /** The current workspace settings. */ workspaceSettings: Settings; diff --git a/typescript-deno-plugin/src/index.ts b/typescript-deno-plugin/src/index.ts index a95beb5e..d34629c3 100644 --- a/typescript-deno-plugin/src/index.ts +++ b/typescript-deno-plugin/src/index.ts @@ -1,6 +1,6 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import type { PluginSettings, Settings } from "../../client/src/types"; +import type { PluginSettings, Settings } from "../../client/src/shared_types"; import type * as ts from "../node_modules/typescript/lib/tsserverlibrary"; /** Extract the return type from a maybe function. */ diff --git a/typescript-deno-plugin/tsconfig.json b/typescript-deno-plugin/tsconfig.json index 9171d347..28b9f6ae 100644 --- a/typescript-deno-plugin/tsconfig.json +++ b/typescript-deno-plugin/tsconfig.json @@ -12,7 +12,7 @@ }, "include": [ "src", - "../client/src/interfaces.d.ts" + "../client/src/shared_types.d.ts" ], "exclude": [ "node_modules"