diff options
| author | Laurențiu Nicola <lnicola@dend.ro> | 2023-02-13 13:55:14 +0200 |
|---|---|---|
| committer | Laurențiu Nicola <lnicola@dend.ro> | 2023-02-13 13:55:14 +0200 |
| commit | bc45c7659a4668206922c290dfc1b78b7e57d375 (patch) | |
| tree | 327b3415d0ea1328ff60ee7862deca8fc9b72ae3 /editors/code/src | |
| parent | 3e0e51c108ad38aec4225769711df9c99df6347c (diff) | |
| download | rust-bc45c7659a4668206922c290dfc1b78b7e57d375.tar.gz rust-bc45c7659a4668206922c290dfc1b78b7e57d375.zip | |
:arrow_up: rust-analyzer
Diffstat (limited to 'editors/code/src')
| -rw-r--r-- | editors/code/src/bootstrap.ts | 96 | ||||
| -rw-r--r-- | editors/code/src/client.ts | 60 | ||||
| -rw-r--r-- | editors/code/src/commands.ts | 4 | ||||
| -rw-r--r-- | editors/code/src/config.ts | 184 | ||||
| -rw-r--r-- | editors/code/src/ctx.ts | 17 | ||||
| -rw-r--r-- | editors/code/src/debug.ts | 2 | ||||
| -rw-r--r-- | editors/code/src/lsp_ext.ts | 240 | ||||
| -rw-r--r-- | editors/code/src/util.ts | 48 |
8 files changed, 341 insertions, 310 deletions
diff --git a/editors/code/src/bootstrap.ts b/editors/code/src/bootstrap.ts index 374c3b8144c..b38fa06a85c 100644 --- a/editors/code/src/bootstrap.ts +++ b/editors/code/src/bootstrap.ts @@ -31,58 +31,12 @@ export async function bootstrap( return path; } - -async function patchelf(dest: vscode.Uri): Promise<void> { - await vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: "Patching rust-analyzer for NixOS", - }, - async (progress, _) => { - const expression = ` - {srcStr, pkgs ? import <nixpkgs> {}}: - pkgs.stdenv.mkDerivation { - name = "rust-analyzer"; - src = /. + srcStr; - phases = [ "installPhase" "fixupPhase" ]; - installPhase = "cp $src $out"; - fixupPhase = '' - chmod 755 $out - patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out - ''; - } - `; - const origFile = vscode.Uri.file(dest.fsPath + "-orig"); - await vscode.workspace.fs.rename(dest, origFile, { overwrite: true }); - try { - progress.report({ message: "Patching executable", increment: 20 }); - await new Promise((resolve, reject) => { - const handle = exec( - `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`, - (err, stdout, stderr) => { - if (err != null) { - reject(Error(stderr)); - } else { - resolve(stdout); - } - } - ); - handle.stdin?.write(expression); - handle.stdin?.end(); - }); - } finally { - await vscode.workspace.fs.delete(origFile); - } - } - ); -} - async function getServer( context: vscode.ExtensionContext, config: Config, state: PersistentState ): Promise<string | undefined> { - const explicitPath = serverPath(config); + const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; if (explicitPath) { if (explicitPath.startsWith("~/")) { return os.homedir() + explicitPath.slice("~".length); @@ -131,9 +85,6 @@ async function getServer( ); return undefined; } -function serverPath(config: Config): string | null { - return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; -} async function isNixOs(): Promise<boolean> { try { @@ -146,3 +97,48 @@ async function isNixOs(): Promise<boolean> { return false; } } + +async function patchelf(dest: vscode.Uri): Promise<void> { + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Patching rust-analyzer for NixOS", + }, + async (progress, _) => { + const expression = ` + {srcStr, pkgs ? import <nixpkgs> {}}: + pkgs.stdenv.mkDerivation { + name = "rust-analyzer"; + src = /. + srcStr; + phases = [ "installPhase" "fixupPhase" ]; + installPhase = "cp $src $out"; + fixupPhase = '' + chmod 755 $out + patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out + ''; + } + `; + const origFile = vscode.Uri.file(dest.fsPath + "-orig"); + await vscode.workspace.fs.rename(dest, origFile, { overwrite: true }); + try { + progress.report({ message: "Patching executable", increment: 20 }); + await new Promise((resolve, reject) => { + const handle = exec( + `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`, + (err, stdout, stderr) => { + if (err != null) { + reject(Error(stderr)); + } else { + resolve(stdout); + } + } + ); + handle.stdin?.write(expression); + handle.stdin?.end(); + }); + } finally { + await vscode.workspace.fs.delete(origFile); + } + } + ); +} diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 82cdf0390ac..62980ca0464 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -102,24 +102,6 @@ export async function createClient( } }, }, - async provideInlayHints(document, viewPort, token, next) { - const inlays = await next(document, viewPort, token); - if (!inlays) { - return inlays; - } - // U+200C is a zero-width non-joiner to prevent the editor from forming a ligature - // between code and hints - for (const inlay of inlays) { - if (typeof inlay.label === "string") { - inlay.label = `\u{200c}${inlay.label}\u{200c}`; - } else if (Array.isArray(inlay.label)) { - for (const it of inlay.label) { - it.value = `\u{200c}${it.value}\u{200c}`; - } - } - } - return inlays; - }, async handleDiagnostics( uri: vscode.Uri, diagnosticList: vscode.Diagnostic[], @@ -190,12 +172,10 @@ export async function createClient( ) .then( (result) => { + if (!result) return null; const hover = client.protocol2CodeConverter.asHover(result); - if (hover) { - const actions = (<any>result).actions; - if (actions) { - hover.contents.push(renderHoverActions(actions)); - } + if (!!result.actions) { + hover.contents.push(renderHoverActions(result.actions)); } return hover; }, @@ -328,25 +308,27 @@ class ExperimentalFeatures implements lc.StaticFeature { return { kind: "static" }; } fillClientCapabilities(capabilities: lc.ClientCapabilities): void { - const caps: any = capabilities.experimental ?? {}; - caps.snippetTextEdit = true; - caps.codeActionGroup = true; - caps.hoverActions = true; - caps.serverStatusNotification = true; - caps.colorDiagnosticOutput = true; - caps.commands = { - commands: [ - "rust-analyzer.runSingle", - "rust-analyzer.debugSingle", - "rust-analyzer.showReferences", - "rust-analyzer.gotoLocation", - "editor.action.triggerParameterHints", - ], + capabilities.experimental = { + snippetTextEdit: true, + codeActionGroup: true, + hoverActions: true, + serverStatusNotification: true, + colorDiagnosticOutput: true, + openServerLogs: true, + commands: { + commands: [ + "rust-analyzer.runSingle", + "rust-analyzer.debugSingle", + "rust-analyzer.showReferences", + "rust-analyzer.gotoLocation", + "editor.action.triggerParameterHints", + ], + }, + ...capabilities.experimental, }; - capabilities.experimental = caps; } initialize( - _capabilities: lc.ServerCapabilities<any>, + _capabilities: lc.ServerCapabilities, _documentSelector: lc.DocumentSelector | undefined ): void {} dispose(): void {} diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index cb4e13e2c60..b5b64e33e07 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -130,11 +130,11 @@ export function joinLines(ctx: CtxInit): Cmd { } export function moveItemUp(ctx: CtxInit): Cmd { - return moveItem(ctx, ra.Direction.Up); + return moveItem(ctx, "Up"); } export function moveItemDown(ctx: CtxInit): Cmd { - return moveItem(ctx, ra.Direction.Down); + return moveItem(ctx, "Down"); } export function moveItem(ctx: CtxInit, direction: ra.Direction): Cmd { diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index eb4f965291f..1faa0ad9106 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -1,5 +1,6 @@ -import * as path from "path"; +import * as Is from "vscode-languageclient/lib/common/utils/is"; import * as os from "os"; +import * as path from "path"; import * as vscode from "vscode"; import { Env } from "./client"; import { log } from "./util"; @@ -47,7 +48,7 @@ export class Config { } private refreshLogging() { - log.setEnabled(this.traceExtension); + log.setEnabled(this.traceExtension ?? false); log.info("Extension version:", this.package.version); const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function)); @@ -86,58 +87,84 @@ export class Config { * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076 */ private configureLanguage() { - if (this.typingContinueCommentsOnNewline && !this.configureLang) { + // Only need to dispose of the config if there's a change + if (this.configureLang) { + this.configureLang.dispose(); + this.configureLang = undefined; + } + + let onEnterRules: vscode.OnEnterRule[] = [ + { + // Carry indentation from the previous line + beforeText: /^\s*$/, + action: { indentAction: vscode.IndentAction.None }, + }, + { + // After the end of a function/field chain, + // with the semicolon on the same line + beforeText: /^\s+\..*;/, + action: { indentAction: vscode.IndentAction.Outdent }, + }, + { + // After the end of a function/field chain, + // with semicolon detached from the rest + beforeText: /^\s+;/, + previousLineText: /^\s+\..*/, + action: { indentAction: vscode.IndentAction.Outdent }, + }, + ]; + + if (this.typingContinueCommentsOnNewline) { const indentAction = vscode.IndentAction.None; - this.configureLang = vscode.languages.setLanguageConfiguration("rust", { - onEnterRules: [ - { - // Doc single-line comment - // e.g. ///| - beforeText: /^\s*\/{3}.*$/, - action: { indentAction, appendText: "/// " }, - }, - { - // Parent doc single-line comment - // e.g. //!| - beforeText: /^\s*\/{2}\!.*$/, - action: { indentAction, appendText: "//! " }, - }, - { - // Begins an auto-closed multi-line comment (standard or parent doc) - // e.g. /** | */ or /*! | */ - beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, - afterText: /^\s*\*\/$/, - action: { - indentAction: vscode.IndentAction.IndentOutdent, - appendText: " * ", - }, - }, - { - // Begins a multi-line comment (standard or parent doc) - // e.g. /** ...| or /*! ...| - beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, - action: { indentAction, appendText: " * " }, - }, - { - // Continues a multi-line comment - // e.g. * ...| - beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/, - action: { indentAction, appendText: "* " }, + onEnterRules = [ + ...onEnterRules, + { + // Doc single-line comment + // e.g. ///| + beforeText: /^\s*\/{3}.*$/, + action: { indentAction, appendText: "/// " }, + }, + { + // Parent doc single-line comment + // e.g. //!| + beforeText: /^\s*\/{2}\!.*$/, + action: { indentAction, appendText: "//! " }, + }, + { + // Begins an auto-closed multi-line comment (standard or parent doc) + // e.g. /** | */ or /*! | */ + beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { + indentAction: vscode.IndentAction.IndentOutdent, + appendText: " * ", }, - { - // Dedents after closing a multi-line comment - // e.g. */| - beforeText: /^(\ \ )*\ \*\/\s*$/, - action: { indentAction, removeText: 1 }, - }, - ], - }); - } - if (!this.typingContinueCommentsOnNewline && this.configureLang) { - this.configureLang.dispose(); - this.configureLang = undefined; + }, + { + // Begins a multi-line comment (standard or parent doc) + // e.g. /** ...| or /*! ...| + beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction, appendText: " * " }, + }, + { + // Continues a multi-line comment + // e.g. * ...| + beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/, + action: { indentAction, appendText: "* " }, + }, + { + // Dedents after closing a multi-line comment + // e.g. */| + beforeText: /^(\ \ )*\ \*\/\s*$/, + action: { indentAction, removeText: 1 }, + }, + ]; } + + this.configureLang = vscode.languages.setLanguageConfiguration("rust", { + onEnterRules, + }); } // We don't do runtime config validation here for simplicity. More on stackoverflow: @@ -163,18 +190,24 @@ export class Config { * ``` * So this getter handles this quirk by not requiring the caller to use postfix `!` */ - private get<T>(path: string): T { - return this.cfg.get<T>(path)!; + private get<T>(path: string): T | undefined { + return substituteVSCodeVariables(this.cfg.get<T>(path)); } get serverPath() { return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath"); } + get serverExtraEnv(): Env { const extraEnv = this.get<{ [key: string]: string | number } | null>("server.extraEnv") ?? {}; - return Object.fromEntries( - Object.entries(extraEnv).map(([k, v]) => [k, typeof v !== "string" ? v.toString() : v]) + return substituteVariablesInEnv( + Object.fromEntries( + Object.entries(extraEnv).map(([k, v]) => [ + k, + typeof v !== "string" ? v.toString() : v, + ]) + ) ); } get traceExtension() { @@ -216,13 +249,13 @@ export class Config { if (sourceFileMap !== "auto") { // "/rustc/<id>" used by suggestions only. const { ["/rustc/<id>"]: _, ...trimmed } = - this.get<Record<string, string>>("debug.sourceFileMap"); + this.get<Record<string, string>>("debug.sourceFileMap") ?? {}; sourceFileMap = trimmed; } return { engine: this.get<string>("debug.engine"), - engineSettings: this.get<object>("debug.engineSettings"), + engineSettings: this.get<object>("debug.engineSettings") ?? {}, openDebugPane: this.get<boolean>("debug.openDebugPane"), sourceFileMap: sourceFileMap, }; @@ -247,37 +280,25 @@ export class Config { } } -const VarRegex = new RegExp(/\$\{(.+?)\}/g); - -export function substituteVSCodeVariableInString(val: string): string { - return val.replace(VarRegex, (substring: string, varName) => { - if (typeof varName === "string") { - return computeVscodeVar(varName) || substring; - } else { - return substring; - } - }); -} - -export function substituteVSCodeVariables(resp: any): any { - if (typeof resp === "string") { - return substituteVSCodeVariableInString(resp); - } else if (resp && Array.isArray(resp)) { +export function substituteVSCodeVariables<T>(resp: T): T { + if (Is.string(resp)) { + return substituteVSCodeVariableInString(resp) as T; + } else if (resp && Is.array<any>(resp)) { return resp.map((val) => { return substituteVSCodeVariables(val); - }); + }) as T; } else if (resp && typeof resp === "object") { const res: { [key: string]: any } = {}; for (const key in resp) { const val = resp[key]; res[key] = substituteVSCodeVariables(val); } - return res; - } else if (typeof resp === "function") { - return null; + return res as T; } return resp; } + +// FIXME: Merge this with `substituteVSCodeVariables` above export function substituteVariablesInEnv(env: Env): Env { const missingDeps = new Set<string>(); // vscode uses `env:ENV_NAME` for env vars resolution, and it's easier @@ -355,6 +376,17 @@ export function substituteVariablesInEnv(env: Env): Env { return resolvedEnv; } +const VarRegex = new RegExp(/\$\{(.+?)\}/g); +function substituteVSCodeVariableInString(val: string): string { + return val.replace(VarRegex, (substring: string, varName) => { + if (Is.string(varName)) { + return computeVscodeVar(varName) || substring; + } else { + return substring; + } + }); +} + function computeVscodeVar(varName: string): string | null { const workspaceFolder = () => { const folders = vscode.workspace.workspaceFolders ?? []; diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index d6cee5c8fc6..e2a30e0cc45 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -2,9 +2,9 @@ import * as vscode from "vscode"; import * as lc from "vscode-languageclient/node"; import * as ra from "./lsp_ext"; -import { Config, substituteVariablesInEnv, substituteVSCodeVariables } from "./config"; +import { Config, substituteVSCodeVariables } from "./config"; import { createClient } from "./client"; -import { isRustDocument, isRustEditor, log, RustEditor } from "./util"; +import { isRustDocument, isRustEditor, LazyOutputChannel, log, RustEditor } from "./util"; import { ServerStatusParams } from "./lsp_ext"; import { PersistentState } from "./persistent_state"; import { bootstrap } from "./bootstrap"; @@ -128,9 +128,7 @@ export class Ctx { } if (!this.traceOutputChannel) { - this.traceOutputChannel = vscode.window.createOutputChannel( - "Rust Analyzer Language Server Trace" - ); + this.traceOutputChannel = new LazyOutputChannel("Rust Analyzer Language Server Trace"); this.pushExtCleanup(this.traceOutputChannel); } if (!this.outputChannel) { @@ -152,9 +150,7 @@ export class Ctx { throw new Error(message); } ); - const newEnv = substituteVariablesInEnv( - Object.assign({}, process.env, this.config.serverExtraEnv) - ); + const newEnv = Object.assign({}, process.env, this.config.serverExtraEnv); const run: lc.Executable = { command: this._serverPath, options: { env: newEnv }, @@ -187,6 +183,11 @@ export class Ctx { this.setServerStatus(params) ) ); + this.pushClientCleanup( + this._client.onNotification(ra.openServerLogs, () => { + this.outputChannel!.show(); + }) + ); } return this._client; } diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index bd45599227e..268b70b4fbb 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -84,7 +84,7 @@ async function getDebugConfiguration( debugEngine = vscode.extensions.getExtension(engineId); if (debugEngine) break; } - } else { + } else if (debugOptions.engine) { debugEngine = vscode.extensions.getExtension(debugOptions.engine); } diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 29349cc20f5..f6f5124dc41 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -4,130 +4,134 @@ import * as lc from "vscode-languageclient"; -export interface AnalyzerStatusParams { - textDocument?: lc.TextDocumentIdentifier; -} +// rust-analyzer overrides + +export const hover = new lc.RequestType< + HoverParams, + (lc.Hover & { actions: CommandLinkGroup[] }) | null, + void +>("textDocument/hover"); +export type HoverParams = { position: lc.Position | lc.Range } & Omit< + lc.TextDocumentPositionParams, + "position" +> & + lc.WorkDoneProgressParams; +export type CommandLink = { + /** + * A tooltip for the command, when represented in the UI. + */ + tooltip?: string; +} & lc.Command; +export type CommandLinkGroup = { + title?: string; + commands: CommandLink[]; +}; + +// rust-analyzer extensions + export const analyzerStatus = new lc.RequestType<AnalyzerStatusParams, string, void>( "rust-analyzer/analyzerStatus" ); +export const cancelFlycheck = new lc.NotificationType0("rust-analyzer/cancelFlycheck"); +export const clearFlycheck = new lc.NotificationType0("rust-analyzer/clearFlycheck"); +export const expandMacro = new lc.RequestType<ExpandMacroParams, ExpandedMacro | null, void>( + "rust-analyzer/expandMacro" +); export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage"); -export const shuffleCrateGraph = new lc.RequestType0<null, void>("rust-analyzer/shuffleCrateGraph"); - -export interface ServerStatusParams { - health: "ok" | "warning" | "error"; - quiescent: boolean; - message?: string; -} -export const serverStatus = new lc.NotificationType<ServerStatusParams>( - "experimental/serverStatus" +export const openServerLogs = new lc.NotificationType0("rust-analyzer/openServerLogs"); +export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, TestInfo[], void>( + "rust-analyzer/relatedTests" ); - export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace"); - -export const hover = new lc.RequestType<HoverParams, lc.Hover | null, void>("textDocument/hover"); - -export interface HoverParams extends lc.WorkDoneProgressParams { - textDocument: lc.TextDocumentIdentifier; - position: lc.Range | lc.Position; -} - -export interface SyntaxTreeParams { - textDocument: lc.TextDocumentIdentifier; - range: lc.Range | null; -} +export const runFlycheck = new lc.NotificationType<{ + textDocument: lc.TextDocumentIdentifier | null; +}>("rust-analyzer/runFlycheck"); +export const shuffleCrateGraph = new lc.RequestType0<null, void>("rust-analyzer/shuffleCrateGraph"); export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>( "rust-analyzer/syntaxTree" ); - -export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>( - "rust-analyzer/viewHir" +export const viewCrateGraph = new lc.RequestType<ViewCrateGraphParams, string, void>( + "rust-analyzer/viewCrateGraph" ); - export const viewFileText = new lc.RequestType<lc.TextDocumentIdentifier, string, void>( "rust-analyzer/viewFileText" ); - -export interface ViewItemTreeParams { - textDocument: lc.TextDocumentIdentifier; -} - +export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>( + "rust-analyzer/viewHir" +); export const viewItemTree = new lc.RequestType<ViewItemTreeParams, string, void>( "rust-analyzer/viewItemTree" ); -export interface ViewCrateGraphParams { - full: boolean; -} +export type AnalyzerStatusParams = { textDocument?: lc.TextDocumentIdentifier }; -export const viewCrateGraph = new lc.RequestType<ViewCrateGraphParams, string, void>( - "rust-analyzer/viewCrateGraph" -); - -export interface ExpandMacroParams { +export type ExpandMacroParams = { textDocument: lc.TextDocumentIdentifier; position: lc.Position; -} -export interface ExpandedMacro { +}; +export type ExpandedMacro = { name: string; expansion: string; -} -export const expandMacro = new lc.RequestType<ExpandMacroParams, ExpandedMacro | null, void>( - "rust-analyzer/expandMacro" -); - -export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, TestInfo[], void>( - "rust-analyzer/relatedTests" -); - -export const cancelFlycheck = new lc.NotificationType0("rust-analyzer/cancelFlycheck"); -export const clearFlycheck = new lc.NotificationType0("rust-analyzer/clearFlycheck"); -export const runFlycheck = new lc.NotificationType<{ - textDocument: lc.TextDocumentIdentifier | null; -}>("rust-analyzer/runFlycheck"); - -// Experimental extensions - -export interface SsrParams { - query: string; - parseOnly: boolean; +}; +export type TestInfo = { runnable: Runnable }; +export type SyntaxTreeParams = { textDocument: lc.TextDocumentIdentifier; - position: lc.Position; - selections: readonly lc.Range[]; -} -export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>("experimental/ssr"); + range: lc.Range | null; +}; +export type ViewCrateGraphParams = { full: boolean }; +export type ViewItemTreeParams = { textDocument: lc.TextDocumentIdentifier }; -export interface MatchingBraceParams { - textDocument: lc.TextDocumentIdentifier; - positions: lc.Position[]; -} +// experimental extensions + +export const joinLines = new lc.RequestType<JoinLinesParams, lc.TextEdit[], void>( + "experimental/joinLines" +); export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>( "experimental/matchingBrace" ); - +export const moveItem = new lc.RequestType<MoveItemParams, lc.TextEdit[], void>( + "experimental/moveItem" +); +export const onEnter = new lc.RequestType<lc.TextDocumentPositionParams, lc.TextEdit[], void>( + "experimental/onEnter" +); +export const openCargoToml = new lc.RequestType<OpenCargoTomlParams, lc.Location, void>( + "experimental/openCargoToml" +); +export const openDocs = new lc.RequestType<lc.TextDocumentPositionParams, string | void, void>( + "experimental/externalDocs" +); export const parentModule = new lc.RequestType< lc.TextDocumentPositionParams, lc.LocationLink[] | null, void >("experimental/parentModule"); - -export interface JoinLinesParams { - textDocument: lc.TextDocumentIdentifier; - ranges: lc.Range[]; -} -export const joinLines = new lc.RequestType<JoinLinesParams, lc.TextEdit[], void>( - "experimental/joinLines" +export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>( + "experimental/runnables" ); - -export const onEnter = new lc.RequestType<lc.TextDocumentPositionParams, lc.TextEdit[], void>( - "experimental/onEnter" +export const serverStatus = new lc.NotificationType<ServerStatusParams>( + "experimental/serverStatus" ); +export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>("experimental/ssr"); -export interface RunnablesParams { +export type JoinLinesParams = { textDocument: lc.TextDocumentIdentifier; - position: lc.Position | null; -} - -export interface Runnable { + ranges: lc.Range[]; +}; +export type MatchingBraceParams = { + textDocument: lc.TextDocumentIdentifier; + positions: lc.Position[]; +}; +export type MoveItemParams = { + textDocument: lc.TextDocumentIdentifier; + range: lc.Range; + direction: Direction; +}; +export type Direction = "Up" | "Down"; +export type OpenCargoTomlParams = { + textDocument: lc.TextDocumentIdentifier; +}; +export type Runnable = { label: string; location?: lc.LocationLink; kind: "cargo"; @@ -139,50 +143,20 @@ export interface Runnable { expectTest?: boolean; overrideCargo?: string; }; -} -export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>( - "experimental/runnables" -); - -export interface TestInfo { - runnable: Runnable; -} - -export interface CommandLink extends lc.Command { - /** - * A tooltip for the command, when represented in the UI. - */ - tooltip?: string; -} - -export interface CommandLinkGroup { - title?: string; - commands: CommandLink[]; -} - -export const openDocs = new lc.RequestType<lc.TextDocumentPositionParams, string | void, void>( - "experimental/externalDocs" -); - -export const openCargoToml = new lc.RequestType<OpenCargoTomlParams, lc.Location, void>( - "experimental/openCargoToml" -); - -export interface OpenCargoTomlParams { +}; +export type RunnablesParams = { textDocument: lc.TextDocumentIdentifier; -} - -export const moveItem = new lc.RequestType<MoveItemParams, lc.TextEdit[], void>( - "experimental/moveItem" -); - -export interface MoveItemParams { + position: lc.Position | null; +}; +export type ServerStatusParams = { + health: "ok" | "warning" | "error"; + quiescent: boolean; + message?: string; +}; +export type SsrParams = { + query: string; + parseOnly: boolean; textDocument: lc.TextDocumentIdentifier; - range: lc.Range; - direction: Direction; -} - -export const enum Direction { - Up = "Up", - Down = "Down", -} + position: lc.Position; + selections: readonly lc.Range[]; +}; diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index cd91932bb60..d93b9caeb16 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -117,7 +117,7 @@ export function isValidExecutable(path: string): boolean { const res = spawnSync(path, ["--version"], { encoding: "utf8" }); - const printOutput = res.error && (res.error as any).code !== "ENOENT" ? log.warn : log.debug; + const printOutput = res.error ? log.warn : log.info; printOutput(path, "--version:", res); return res.status === 0; @@ -166,3 +166,49 @@ export function execute(command: string, options: ExecOptions): Promise<string> }); }); } + +export class LazyOutputChannel implements vscode.OutputChannel { + constructor(name: string) { + this.name = name; + } + + name: string; + _channel: vscode.OutputChannel | undefined; + + get channel(): vscode.OutputChannel { + if (!this._channel) { + this._channel = vscode.window.createOutputChannel(this.name); + } + return this._channel; + } + + append(value: string): void { + this.channel.append(value); + } + appendLine(value: string): void { + this.channel.appendLine(value); + } + replace(value: string): void { + this.channel.replace(value); + } + clear(): void { + if (this._channel) { + this._channel.clear(); + } + } + show(preserveFocus?: boolean): void; + show(column?: vscode.ViewColumn, preserveFocus?: boolean): void; + show(column?: any, preserveFocus?: any): void { + this.channel.show(column, preserveFocus); + } + hide(): void { + if (this._channel) { + this._channel.hide(); + } + } + dispose(): void { + if (this._channel) { + this._channel.dispose(); + } + } +} |
