Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'editors/code/src/config.ts')
| -rw-r--r-- | editors/code/src/config.ts | 184 |
1 files changed, 108 insertions, 76 deletions
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index eb4f965291..1faa0ad910 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 ?? []; |