From 4fcdb0fea02d7d64450a6a48d4a9ac1b546b66f9 Mon Sep 17 00:00:00 2001 From: Andrei Listochkin Date: Wed, 11 May 2022 18:19:45 +0100 Subject: [PATCH 1/6] prettier config [Prettier][1] is an up-to date code formatter for JavaScript ecosystem. For settings we rely on [EditorConfig][2] for things like tab style and size (with added bonus that the code editor with an EditorConfig plugin does some automated code formatting on file save for you). Unfortunately, Prettier's Glob handling isn't great: 1. `*.{ts,js,json}` has no effect 2. Similarly, in a list of globs `*.ts,*.js,*.json` only the first glob has an effect, the rest are ignored. That's why the file looks the way it does. The only other setting we change is line width. [Lukas][3] suggested we use 100 instead of 80, because that's what Rustfmt is using. [1]: https://prettier.io [2]: https://editorconfig.org [3]: https://github.com/Veykril --- .editorconfig | 19 +++++++++++++++ editors/code/.eslintrc.js | 1 + editors/code/.prettierignore | 3 +++ editors/code/.prettierrc.js | 5 ++++ editors/code/package-lock.json | 42 ++++++++++++++++++++++++++++++++++ editors/code/package.json | 2 ++ 6 files changed, 72 insertions(+) create mode 100644 .editorconfig create mode 100644 editors/code/.prettierignore create mode 100644 editors/code/.prettierrc.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..314f79d3f9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# https://EditorConfig.org +root = true + +[*] +charset = utf-8 +trim_trailing_whitespace = true +end_of_line = lf +insert_final_newline = true +indent_style = space + +[*.{rs,toml}] +indent_size = 4 + +[*.ts] +indent_size = 4 +[*.js] +indent_size = 4 +[*.json] +indent_size = 4 diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index 631d956da2..518c5d0755 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -3,6 +3,7 @@ module.exports = { "es6": true, "node": true }, + "extends": ["prettier"], "parser": "@typescript-eslint/parser", "parserOptions": { "project": "tsconfig.eslint.json", diff --git a/editors/code/.prettierignore b/editors/code/.prettierignore new file mode 100644 index 0000000000..13baf68d7c --- /dev/null +++ b/editors/code/.prettierignore @@ -0,0 +1,3 @@ +node_modules +.vscode-test +out diff --git a/editors/code/.prettierrc.js b/editors/code/.prettierrc.js new file mode 100644 index 0000000000..cafb12f0e6 --- /dev/null +++ b/editors/code/.prettierrc.js @@ -0,0 +1,5 @@ +module.exports = { + // use 100 because it's Rustfmt's default + // https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#max_width + printWidth: 100, +}; diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 74cda037d8..d766f9f1c9 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -22,6 +22,8 @@ "cross-env": "^7.0.3", "esbuild": "^0.14.27", "eslint": "^8.11.0", + "eslint-config-prettier": "^8.5.0", + "prettier": "^2.6.2", "tslib": "^2.3.0", "typescript": "^4.6.3", "typescript-formatter": "^7.2.2", @@ -1988,6 +1990,18 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -3130,6 +3144,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5509,6 +5538,13 @@ } } }, + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "requires": {} + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -6386,6 +6422,12 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/editors/code/package.json b/editors/code/package.json index 04006d7434..e2888a088d 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -48,6 +48,8 @@ "cross-env": "^7.0.3", "esbuild": "^0.14.27", "eslint": "^8.11.0", + "eslint-config-prettier": "^8.5.0", + "prettier": "^2.6.2", "tslib": "^2.3.0", "typescript": "^4.6.3", "typescript-formatter": "^7.2.2", From 8e9f54f2380e8239586440eb8c7bf0aceb727322 Mon Sep 17 00:00:00 2001 From: Andrei Listochkin Date: Tue, 17 May 2022 16:07:30 +0100 Subject: [PATCH 2/6] use prettier to format the code --- editors/code/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index e2888a088d..2cc33a417f 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -29,8 +29,8 @@ "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16", "build": "npm run build-base -- --sourcemap", "watch": "npm run build-base -- --sourcemap --watch", - "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src ./tests", - "fix": " tsfmt -r && eslint -c .eslintrc.js --ext ts ./src ./tests --fix", + "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests", + "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix", "pretest": "tsc && npm run build", "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js" }, From f247090558c9ba3c551566eae5882b7ca865225f Mon Sep 17 00:00:00 2001 From: Andrei Listochkin Date: Tue, 17 May 2022 18:15:06 +0100 Subject: [PATCH 3/6] prettier run --- editors/code/.eslintrc.js | 53 +- editors/code/language-configuration.json | 10 +- editors/code/ra_syntax_tree.tmGrammar.json | 4 +- editors/code/src/ast_inspector.ts | 79 ++- editors/code/src/client.ts | 277 ++++++----- editors/code/src/commands.ts | 462 +++++++++++------- editors/code/src/config.ts | 210 ++++---- editors/code/src/ctx.ts | 38 +- editors/code/src/debug.ts | 77 ++- editors/code/src/lsp_ext.ts | 74 ++- editors/code/src/main.ts | 198 ++++---- editors/code/src/persistent_state.ts | 4 +- editors/code/src/run.ts | 58 ++- editors/code/src/snippets.ts | 49 +- editors/code/src/tasks.ts | 40 +- editors/code/src/toolchain.ts | 74 +-- editors/code/src/util.ts | 29 +- editors/code/tests/runTests.ts | 24 +- editors/code/tests/unit/index.ts | 8 +- editors/code/tests/unit/launch_config.test.ts | 85 +++- editors/code/tests/unit/runnable_env.test.ts | 62 +-- editors/code/tests/unit/settings.test.ts | 32 +- editors/code/tsconfig.eslint.json | 16 +- editors/code/tsconfig.json | 14 +- 24 files changed, 1169 insertions(+), 808 deletions(-) diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index 518c5d0755..684b5c6bd9 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -1,41 +1,36 @@ module.exports = { - "env": { - "es6": true, - "node": true + env: { + es6: true, + node: true, }, - "extends": ["prettier"], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.eslint.json", - "tsconfigRootDir": __dirname, - "sourceType": "module" + extends: ["prettier"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.eslint.json", + tsconfigRootDir: __dirname, + sourceType: "module", }, - "plugins": [ - "@typescript-eslint" - ], - "rules": { - "camelcase": ["error"], - "eqeqeq": ["error", "always", { "null": "ignore" }], + plugins: ["@typescript-eslint"], + rules: { + camelcase: ["error"], + eqeqeq: ["error", "always", { null: "ignore" }], "no-console": ["error", { allow: ["warn", "error"] }], "prefer-const": "error", "@typescript-eslint/member-delimiter-style": [ "error", { - "multiline": { - "delimiter": "semi", - "requireLast": true + multiline: { + delimiter: "semi", + requireLast: true, }, - "singleline": { - "delimiter": "semi", - "requireLast": false - } - } - ], - "@typescript-eslint/semi": [ - "error", - "always" + singleline: { + delimiter: "semi", + requireLast: false, + }, + }, ], + "@typescript-eslint/semi": ["error", "always"], "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/no-floating-promises": "error" - } + "@typescript-eslint/no-floating-promises": "error", + }, }; diff --git a/editors/code/language-configuration.json b/editors/code/language-configuration.json index cf7b20eb79..b1ee0843e3 100644 --- a/editors/code/language-configuration.json +++ b/editors/code/language-configuration.json @@ -1,7 +1,7 @@ { "comments": { "lineComment": "//", - "blockComment": [ "/*", "*/" ] + "blockComment": ["/*", "*/"] }, "brackets": [ ["{", "}"], @@ -9,10 +9,10 @@ ["(", ")"] ], "colorizedBracketPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], "autoClosingPairs": [ { "open": "{", "close": "}" }, { "open": "[", "close": "]" }, diff --git a/editors/code/ra_syntax_tree.tmGrammar.json b/editors/code/ra_syntax_tree.tmGrammar.json index 431d414f64..279e7bafa0 100644 --- a/editors/code/ra_syntax_tree.tmGrammar.json +++ b/editors/code/ra_syntax_tree.tmGrammar.json @@ -25,7 +25,5 @@ "name": "string" } }, - "fileTypes": [ - "rast" - ] + "fileTypes": ["rast"] } diff --git a/editors/code/src/ast_inspector.ts b/editors/code/src/ast_inspector.ts index 28d8b2a5fd..fca992299e 100644 --- a/editors/code/src/ast_inspector.ts +++ b/editors/code/src/ast_inspector.ts @@ -1,13 +1,13 @@ -import * as vscode from 'vscode'; +import * as vscode from "vscode"; -import { Ctx, Disposable } from './ctx'; -import { RustEditor, isRustEditor } from './util'; +import { Ctx, Disposable } from "./ctx"; +import { RustEditor, isRustEditor } from "./util"; // FIXME: consider implementing this via the Tree View API? // https://code.visualstudio.com/api/extension-guides/tree-view export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ - borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'), + borderColor: new vscode.ThemeColor("rust_analyzer.syntaxTreeBorder"), borderStyle: "solid", borderWidth: "2px", }); @@ -35,11 +35,23 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv }); constructor(ctx: Ctx) { - ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: 'rust-analyzer' }, this)); + ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this)); ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this)); - vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, ctx.subscriptions); - vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); - vscode.window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, ctx.subscriptions); + vscode.workspace.onDidCloseTextDocument( + this.onDidCloseTextDocument, + this, + ctx.subscriptions + ); + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeVisibleTextEditors( + this.onDidChangeVisibleTextEditors, + this, + ctx.subscriptions + ); ctx.pushCleanup(this); } @@ -48,7 +60,10 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv } private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if (this.rustEditor && event.document.uri.toString() === this.rustEditor.document.uri.toString()) { + if ( + this.rustEditor && + event.document.uri.toString() === this.rustEditor.document.uri.toString() + ) { this.rust2Ast.reset(); } } @@ -68,7 +83,9 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv } private findAstTextEditor(): undefined | vscode.TextEditor { - return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === 'rust-analyzer'); + return vscode.window.visibleTextEditors.find( + (it) => it.document.uri.scheme === "rust-analyzer" + ); } private setRustEditor(newRustEditor: undefined | RustEditor) { @@ -80,13 +97,19 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv } // additional positional params are omitted - provideDefinition(doc: vscode.TextDocument, pos: vscode.Position): vscode.ProviderResult { - if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) return; + provideDefinition( + doc: vscode.TextDocument, + pos: vscode.Position + ): vscode.ProviderResult { + if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) + return; const astEditor = this.findAstTextEditor(); if (!astEditor) return; - const rust2AstRanges = this.rust2Ast.get()?.find(([rustRange, _]) => rustRange.contains(pos)); + const rust2AstRanges = this.rust2Ast + .get() + ?.find(([rustRange, _]) => rustRange.contains(pos)); if (!rust2AstRanges) return; const [rustFileRange, astFileRange] = rust2AstRanges; @@ -94,16 +117,21 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv astEditor.revealRange(astFileRange); astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end); - return [{ - targetRange: astFileRange, - targetUri: astEditor.document.uri, - originSelectionRange: rustFileRange, - targetSelectionRange: astFileRange, - }]; + return [ + { + targetRange: astFileRange, + targetUri: astEditor.document.uri, + originSelectionRange: rustFileRange, + targetSelectionRange: astFileRange, + }, + ]; } // additional positional params are omitted - provideHover(doc: vscode.TextDocument, hoverPosition: vscode.Position): vscode.ProviderResult { + provideHover( + doc: vscode.TextDocument, + hoverPosition: vscode.Position + ): vscode.ProviderResult { if (!this.rustEditor) return; const astFileLine = doc.lineAt(hoverPosition.line); @@ -127,13 +155,14 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv return new vscode.Range(begin, end); } - private parseRustTextRange(doc: vscode.TextDocument, astLine: string): undefined | vscode.Range { + private parseRustTextRange( + doc: vscode.TextDocument, + astLine: string + ): undefined | vscode.Range { const parsedRange = /(\d+)\.\.(\d+)/.exec(astLine); if (!parsedRange) return; - const [begin, end] = parsedRange - .slice(1) - .map(off => this.positionAt(doc, +off)); + const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off)); return new vscode.Range(begin, end); } @@ -173,7 +202,7 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv class Lazy { val: undefined | T; - constructor(private readonly compute: () => undefined | T) { } + constructor(private readonly compute: () => undefined | T) {} get() { return this.val ?? (this.val = this.compute()); diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 7519cd3de3..c960e283d3 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -1,39 +1,47 @@ -import * as lc from 'vscode-languageclient/node'; -import * as vscode from 'vscode'; -import * as ra from '../src/lsp_ext'; -import * as Is from 'vscode-languageclient/lib/common/utils/is'; -import { assert } from './util'; -import { WorkspaceEdit } from 'vscode'; -import { Workspace } from './ctx'; -import { updateConfig } from './config'; -import { substituteVariablesInEnv } from './config'; +import * as lc from "vscode-languageclient/node"; +import * as vscode from "vscode"; +import * as ra from "../src/lsp_ext"; +import * as Is from "vscode-languageclient/lib/common/utils/is"; +import { assert } from "./util"; +import { WorkspaceEdit } from "vscode"; +import { Workspace } from "./ctx"; +import { updateConfig } from "./config"; +import { substituteVariablesInEnv } from "./config"; export interface Env { [name: string]: string; } function renderCommand(cmd: ra.CommandLink) { - return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip}')`; + return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent( + JSON.stringify(cmd.arguments) + )} '${cmd.tooltip}')`; } function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString { - const text = actions.map(group => - (group.title ? (group.title + " ") : "") + group.commands.map(renderCommand).join(' | ') - ).join('___'); + const text = actions + .map( + (group) => + (group.title ? group.title + " " : "") + + group.commands.map(renderCommand).join(" | ") + ) + .join("___"); const result = new vscode.MarkdownString(text); result.isTrusted = true; return result; } -export async function createClient(serverPath: string, workspace: Workspace, extraEnv: Env): Promise { +export async function createClient( + serverPath: string, + workspace: Workspace, + extraEnv: Env +): Promise { // '.' Is the fallback if no folder is open // TODO?: Workspace folders support Uri's (eg: file://test.txt). // It might be a good idea to test if the uri points to a file. - const newEnv = substituteVariablesInEnv(Object.assign( - {}, process.env, extraEnv - )); + const newEnv = substituteVariablesInEnv(Object.assign({}, process.env, extraEnv)); const run: lc.Executable = { command: serverPath, options: { env: newEnv }, @@ -43,137 +51,176 @@ export async function createClient(serverPath: string, workspace: Workspace, ext debug: run, }; const traceOutputChannel = vscode.window.createOutputChannel( - 'Rust Analyzer Language Server Trace', + "Rust Analyzer Language Server Trace" ); let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer"); // Update outdated user configs - await updateConfig(initializationOptions).catch(err => { + await updateConfig(initializationOptions).catch((err) => { void vscode.window.showErrorMessage(`Failed updating old config keys: ${err.message}`); }); if (workspace.kind === "Detached Files") { - initializationOptions = { "detachedFiles": workspace.files.map(file => file.uri.fsPath), ...initializationOptions }; + initializationOptions = { + detachedFiles: workspace.files.map((file) => file.uri.fsPath), + ...initializationOptions, + }; } const clientOptions: lc.LanguageClientOptions = { - documentSelector: [{ scheme: 'file', language: 'rust' }], + documentSelector: [{ scheme: "file", language: "rust" }], initializationOptions, diagnosticCollectionName: "rustc", traceOutputChannel, middleware: { - async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, _next: lc.ProvideHoverSignature) { + async provideHover( + document: vscode.TextDocument, + position: vscode.Position, + token: vscode.CancellationToken, + _next: lc.ProvideHoverSignature + ) { const editor = vscode.window.activeTextEditor; - const positionOrRange = editor?.selection?.contains(position) ? client.code2ProtocolConverter.asRange(editor.selection) : client.code2ProtocolConverter.asPosition(position); - return client.sendRequest(ra.hover, { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - position: positionOrRange - }, token).then( - (result) => { - const hover = - client.protocol2CodeConverter.asHover(result); - if (hover) { - const actions = (result).actions; - if (actions) { - hover.contents.push(renderHoverActions(actions)); + const positionOrRange = editor?.selection?.contains(position) + ? client.code2ProtocolConverter.asRange(editor.selection) + : client.code2ProtocolConverter.asPosition(position); + return client + .sendRequest( + ra.hover, + { + textDocument: + client.code2ProtocolConverter.asTextDocumentIdentifier(document), + position: positionOrRange, + }, + token + ) + .then( + (result) => { + const hover = client.protocol2CodeConverter.asHover(result); + if (hover) { + const actions = (result).actions; + if (actions) { + hover.contents.push(renderHoverActions(actions)); + } } + return hover; + }, + (error) => { + client.handleFailedRequest(lc.HoverRequest.type, token, error, null); + return Promise.resolve(null); } - return hover; - }, - (error) => { - client.handleFailedRequest( - lc.HoverRequest.type, - token, - error, - null - ); - return Promise.resolve(null); - } - ); + ); }, // Using custom handling of CodeActions to support action groups and snippet edits. // Note that this means we have to re-implement lazy edit resolving ourselves as well. - async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) { + async provideCodeActions( + document: vscode.TextDocument, + range: vscode.Range, + context: vscode.CodeActionContext, + token: vscode.CancellationToken, + _next: lc.ProvideCodeActionsSignature + ) { const params: lc.CodeActionParams = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), range: client.code2ProtocolConverter.asRange(range), - context: await client.code2ProtocolConverter.asCodeActionContext(context, token) + context: await client.code2ProtocolConverter.asCodeActionContext( + context, + token + ), }; - return client.sendRequest(lc.CodeActionRequest.type, params, token).then(async (values) => { - if (values === null) return undefined; - const result: (vscode.CodeAction | vscode.Command)[] = []; - const groups = new Map(); - for (const item of values) { - // In our case we expect to get code edits only from diagnostics - if (lc.CodeAction.is(item)) { - assert(!item.command, "We don't expect to receive commands in CodeActions"); - const action = await client.protocol2CodeConverter.asCodeAction(item, token); - result.push(action); - continue; - } - assert(isCodeActionWithoutEditsAndCommands(item), "We don't expect edits or commands here"); - const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind); - const action = new vscode.CodeAction(item.title, kind); - const group = (item as any).group; - action.command = { - command: "rust-analyzer.resolveCodeAction", - title: item.title, - arguments: [item], - }; - - // Set a dummy edit, so that VS Code doesn't try to resolve this. - action.edit = new WorkspaceEdit(); - - if (group) { - let entry = groups.get(group); - if (!entry) { - entry = { index: result.length, items: [] }; - groups.set(group, entry); + return client.sendRequest(lc.CodeActionRequest.type, params, token).then( + async (values) => { + if (values === null) return undefined; + const result: (vscode.CodeAction | vscode.Command)[] = []; + const groups = new Map< + string, + { index: number; items: vscode.CodeAction[] } + >(); + for (const item of values) { + // In our case we expect to get code edits only from diagnostics + if (lc.CodeAction.is(item)) { + assert( + !item.command, + "We don't expect to receive commands in CodeActions" + ); + const action = await client.protocol2CodeConverter.asCodeAction( + item, + token + ); result.push(action); + continue; } - entry.items.push(action); - } else { - result.push(action); - } - } - for (const [group, { index, items }] of groups) { - if (items.length === 1) { - result[index] = items[0]; - } else { - const action = new vscode.CodeAction(group); - action.kind = items[0].kind; + assert( + isCodeActionWithoutEditsAndCommands(item), + "We don't expect edits or commands here" + ); + const kind = client.protocol2CodeConverter.asCodeActionKind( + (item as any).kind + ); + const action = new vscode.CodeAction(item.title, kind); + const group = (item as any).group; action.command = { - command: "rust-analyzer.applyActionGroup", - title: "", - arguments: [items.map((item) => { - return { label: item.title, arguments: item.command!.arguments![0] }; - })], + command: "rust-analyzer.resolveCodeAction", + title: item.title, + arguments: [item], }; // Set a dummy edit, so that VS Code doesn't try to resolve this. action.edit = new WorkspaceEdit(); - result[index] = action; + if (group) { + let entry = groups.get(group); + if (!entry) { + entry = { index: result.length, items: [] }; + groups.set(group, entry); + result.push(action); + } + entry.items.push(action); + } else { + result.push(action); + } } - } - return result; - }, + for (const [group, { index, items }] of groups) { + if (items.length === 1) { + result[index] = items[0]; + } else { + const action = new vscode.CodeAction(group); + action.kind = items[0].kind; + action.command = { + command: "rust-analyzer.applyActionGroup", + title: "", + arguments: [ + items.map((item) => { + return { + label: item.title, + arguments: item.command!.arguments![0], + }; + }), + ], + }; + + // Set a dummy edit, so that VS Code doesn't try to resolve this. + action.edit = new WorkspaceEdit(); + + result[index] = action; + } + } + return result; + }, (_error) => undefined ); - } - + }, }, markdown: { supportHtml: true, - } + }, }; const client = new lc.LanguageClient( - 'rust-analyzer', - 'Rust Analyzer Language Server', + "rust-analyzer", + "Rust Analyzer Language Server", serverOptions, - clientOptions, + clientOptions ); // To turn on all proposed features use: client.registerProposedFeatures(); @@ -196,20 +243,26 @@ class ExperimentalFeatures implements lc.StaticFeature { "rust-analyzer.showReferences", "rust-analyzer.gotoLocation", "editor.action.triggerParameterHints", - ] + ], }; capabilities.experimental = caps; } - initialize(_capabilities: lc.ServerCapabilities, _documentSelector: lc.DocumentSelector | undefined): void { - } - dispose(): void { - } + initialize( + _capabilities: lc.ServerCapabilities, + _documentSelector: lc.DocumentSelector | undefined + ): void {} + dispose(): void {} } function isCodeActionWithoutEditsAndCommands(value: any): boolean { const candidate: lc.CodeAction = value; - return candidate && Is.string(candidate.title) && - (candidate.diagnostics === void 0 || Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) && + return ( + candidate && + Is.string(candidate.title) && + (candidate.diagnostics === void 0 || + Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) && (candidate.kind === void 0 || Is.string(candidate.kind)) && - (candidate.edit === void 0 && candidate.command === void 0); + candidate.edit === void 0 && + candidate.command === void 0 + ); } diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 1e89938c05..ae94ecac6d 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -1,32 +1,33 @@ -import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; -import * as ra from './lsp_ext'; -import * as path from 'path'; +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient"; +import * as ra from "./lsp_ext"; +import * as path from "path"; -import { Ctx, Cmd } from './ctx'; -import { applySnippetWorkspaceEdit, applySnippetTextEdits } from './snippets'; -import { spawnSync } from 'child_process'; -import { RunnableQuickPick, selectRunnable, createTask, createArgs } from './run'; -import { AstInspector } from './ast_inspector'; -import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor } from './util'; -import { startDebugSession, makeDebugConfig } from './debug'; -import { LanguageClient } from 'vscode-languageclient/node'; +import { Ctx, Cmd } from "./ctx"; +import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets"; +import { spawnSync } from "child_process"; +import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run"; +import { AstInspector } from "./ast_inspector"; +import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor } from "./util"; +import { startDebugSession, makeDebugConfig } from "./debug"; +import { LanguageClient } from "vscode-languageclient/node"; -export * from './ast_inspector'; -export * from './run'; +export * from "./ast_inspector"; +export * from "./run"; export function analyzerStatus(ctx: Ctx): Cmd { - const tdcp = new class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse('rust-analyzer-status://status'); + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer-status://status"); readonly eventEmitter = new vscode.EventEmitter(); provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult { - if (!vscode.window.activeTextEditor) return ''; + if (!vscode.window.activeTextEditor) return ""; const params: ra.AnalyzerStatusParams = {}; const doc = ctx.activeRustEditor?.document; if (doc != null) { - params.textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc); + params.textDocument = + ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc); } return ctx.client.sendRequest(ra.analyzerStatus, params); } @@ -34,48 +35,42 @@ export function analyzerStatus(ctx: Ctx): Cmd { get onDidChange(): vscode.Event { return this.eventEmitter.event; } - }(); + })(); ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider( - 'rust-analyzer-status', - tdcp, - ), + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-status", tdcp) ); return async () => { const document = await vscode.workspace.openTextDocument(tdcp.uri); tdcp.eventEmitter.fire(tdcp.uri); - void await vscode.window.showTextDocument(document, { + void (await vscode.window.showTextDocument(document, { viewColumn: vscode.ViewColumn.Two, - preserveFocus: true - }); + preserveFocus: true, + })); }; } export function memoryUsage(ctx: Ctx): Cmd { - const tdcp = new class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse('rust-analyzer-memory://memory'); + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory"); readonly eventEmitter = new vscode.EventEmitter(); provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult { - if (!vscode.window.activeTextEditor) return ''; + if (!vscode.window.activeTextEditor) return ""; return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => { - return 'Per-query memory usage:\n' + mem + '\n(note: database has been cleared)'; + return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)"; }); } get onDidChange(): vscode.Event { return this.eventEmitter.event; } - }(); + })(); ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider( - 'rust-analyzer-memory', - tdcp, - ), + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp) ); return async () => { @@ -101,15 +96,15 @@ export function matchingBrace(ctx: Ctx): Cmd { if (!editor || !client) return; const response = await client.sendRequest(ra.matchingBrace, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), - positions: editor.selections.map(s => - client.code2ProtocolConverter.asPosition(s.active), + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + positions: editor.selections.map((s) => + client.code2ProtocolConverter.asPosition(s.active) ), }); editor.selections = editor.selections.map((sel, idx) => { - const active = client.protocol2CodeConverter.asPosition( - response[idx], - ); + const active = client.protocol2CodeConverter.asPosition(response[idx]); const anchor = sel.isEmpty ? active : sel.anchor; return new vscode.Selection(anchor, active); }); @@ -125,7 +120,9 @@ export function joinLines(ctx: Ctx): Cmd { const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, { ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)), - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), }); await editor.edit(async (builder) => { (await client.protocol2CodeConverter.asTextEdits(items)).forEach((edit: any) => { @@ -151,8 +148,10 @@ export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd { const lcEdits = await client.sendRequest(ra.moveItem, { range: client.code2ProtocolConverter.asRange(editor.selection), - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), - direction + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + direction, }); if (!lcEdits) return; @@ -169,15 +168,17 @@ export function onEnter(ctx: Ctx): Cmd { if (!editor || !client) return false; - const lcEdits = await client.sendRequest(ra.onEnter, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), - position: client.code2ProtocolConverter.asPosition( - editor.selection.active, - ), - }).catch((_error: any) => { - // client.handleFailedRequest(OnEnterRequest.type, error, null); - return null; - }); + const lcEdits = await client + .sendRequest(ra.onEnter, { + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + position: client.code2ProtocolConverter.asPosition(editor.selection.active), + }) + .catch((_error: any) => { + // client.handleFailedRequest(OnEnterRequest.type, error, null); + return null; + }); if (!lcEdits) return false; const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits); @@ -188,7 +189,7 @@ export function onEnter(ctx: Ctx): Cmd { return async () => { if (await handleKeypress()) return; - await vscode.commands.executeCommand('default:type', { text: '\n' }); + await vscode.commands.executeCommand("default:type", { text: "\n" }); }; } @@ -200,10 +201,10 @@ export function parentModule(ctx: Ctx): Cmd { if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return; const locations = await client.sendRequest(ra.parentModule, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), - position: client.code2ProtocolConverter.asPosition( - editor.selection.active, + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document ), + position: client.code2ProtocolConverter.asPosition(editor.selection.active), }); if (!locations) return; @@ -220,7 +221,12 @@ export function parentModule(ctx: Ctx): Cmd { } else { const uri = editor.document.uri.toString(); const position = client.code2ProtocolConverter.asPosition(editor.selection.active); - await showReferencesImpl(client, uri, position, locations.map(loc => lc.Location.create(loc.targetUri, loc.targetRange))); + await showReferencesImpl( + client, + uri, + position, + locations.map((loc) => lc.Location.create(loc.targetUri, loc.targetRange)) + ); } }; } @@ -232,7 +238,9 @@ export function openCargoToml(ctx: Ctx): Cmd { if (!editor || !client) return; const response = await client.sendRequest(ra.openCargoToml, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), }); if (!response) return; @@ -254,7 +262,9 @@ export function ssr(ctx: Ctx): Cmd { const position = editor.selection.active; const selections = editor.selections; - const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document); + const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ); const options: vscode.InputBoxOptions = { value: "() ==>> ()", @@ -262,28 +272,41 @@ export function ssr(ctx: Ctx): Cmd { validateInput: async (x: string) => { try { await client.sendRequest(ra.ssr, { - query: x, parseOnly: true, textDocument, position, selections, + query: x, + parseOnly: true, + textDocument, + position, + selections, }); } catch (e) { return e.toString(); } return null; - } + }, }; const request = await vscode.window.showInputBox(options); if (!request) return; - await vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: "Structured search replace in progress...", - cancellable: false, - }, async (_progress, token) => { - const edit = await client.sendRequest(ra.ssr, { - query: request, parseOnly: false, textDocument, position, selections, - }); + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Structured search replace in progress...", + cancellable: false, + }, + async (_progress, token) => { + const edit = await client.sendRequest(ra.ssr, { + query: request, + parseOnly: false, + textDocument, + position, + selections, + }); - await vscode.workspace.applyEdit(await client.protocol2CodeConverter.asWorkspaceEdit(edit, token)); - }); + await vscode.workspace.applyEdit( + await client.protocol2CodeConverter.asWorkspaceEdit(edit, token) + ); + } + ); }; } @@ -292,17 +315,17 @@ export function serverVersion(ctx: Ctx): Cmd { const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" }); const versionString = stdout.slice(`rust-analyzer `.length).trim(); - void vscode.window.showInformationMessage( - `rust-analyzer version: ${versionString}` - ); + void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`); }; } export function toggleInlayHints(_ctx: Ctx): Cmd { return async () => { - const config = vscode.workspace.getConfiguration("editor.inlayHints", { languageId: "rust" }); + const config = vscode.workspace.getConfiguration("editor.inlayHints", { + languageId: "rust", + }); const value = !config.get("enabled"); - await config.update('enabled', value, vscode.ConfigurationTarget.Global); + await config.update("enabled", value, vscode.ConfigurationTarget.Global); }; } @@ -310,12 +333,20 @@ export function toggleInlayHints(_ctx: Ctx): Cmd { // // The contents of the file come from the `TextDocumentContentProvider` export function syntaxTree(ctx: Ctx): Cmd { - const tdcp = new class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast'); + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer://syntaxtree/tree.rast"); readonly eventEmitter = new vscode.EventEmitter(); constructor() { - vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); - vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeActiveTextEditor( + this.onDidChangeActiveTextEditor, + this, + ctx.subscriptions + ); } private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { @@ -331,47 +362,51 @@ export function syntaxTree(ctx: Ctx): Cmd { } } - provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult { + provideTextDocumentContent( + uri: vscode.Uri, + ct: vscode.CancellationToken + ): vscode.ProviderResult { const rustEditor = ctx.activeRustEditor; - if (!rustEditor) return ''; + if (!rustEditor) return ""; // When the range based query is enabled we take the range of the selection - const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty - ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection) - : null; + const range = + uri.query === "range=true" && !rustEditor.selection.isEmpty + ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection) + : null; - const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, }; + const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range }; return ctx.client.sendRequest(ra.syntaxTree, params, ct); } get onDidChange(): vscode.Event { return this.eventEmitter.event; } - }; + })(); void new AstInspector(ctx); - ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); - ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", { - brackets: [["[", ")"]], - })); + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider("rust-analyzer", tdcp)); + ctx.pushCleanup( + vscode.languages.setLanguageConfiguration("ra_syntax_tree", { + brackets: [["[", ")"]], + }) + ); return async () => { const editor = vscode.window.activeTextEditor; const rangeEnabled = !!editor && !editor.selection.isEmpty; - const uri = rangeEnabled - ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) - : tdcp.uri; + const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri; const document = await vscode.workspace.openTextDocument(uri); tdcp.eventEmitter.fire(uri); - void await vscode.window.showTextDocument(document, { + void (await vscode.window.showTextDocument(document, { viewColumn: vscode.ViewColumn.Two, - preserveFocus: true - }); + preserveFocus: true, + })); }; } @@ -379,12 +414,20 @@ export function syntaxTree(ctx: Ctx): Cmd { // // The contents of the file come from the `TextDocumentContentProvider` export function viewHir(ctx: Ctx): Cmd { - const tdcp = new class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse('rust-analyzer://viewHir/hir.txt'); + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer://viewHir/hir.txt"); readonly eventEmitter = new vscode.EventEmitter(); constructor() { - vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); - vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeActiveTextEditor( + this.onDidChangeActiveTextEditor, + this, + ctx.subscriptions + ); } private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { @@ -400,16 +443,19 @@ export function viewHir(ctx: Ctx): Cmd { } } - provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult { + provideTextDocumentContent( + _uri: vscode.Uri, + ct: vscode.CancellationToken + ): vscode.ProviderResult { const rustEditor = ctx.activeRustEditor; const client = ctx.client; - if (!rustEditor || !client) return ''; + if (!rustEditor || !client) return ""; const params = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document), - position: client.code2ProtocolConverter.asPosition( - rustEditor.selection.active, + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier( + rustEditor.document ), + position: client.code2ProtocolConverter.asPosition(rustEditor.selection.active), }; return client.sendRequest(ra.viewHir, params, ct); } @@ -417,27 +463,35 @@ export function viewHir(ctx: Ctx): Cmd { get onDidChange(): vscode.Event { return this.eventEmitter.event; } - }; + })(); - ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider("rust-analyzer", tdcp)); return async () => { const document = await vscode.workspace.openTextDocument(tdcp.uri); tdcp.eventEmitter.fire(tdcp.uri); - void await vscode.window.showTextDocument(document, { + void (await vscode.window.showTextDocument(document, { viewColumn: vscode.ViewColumn.Two, - preserveFocus: true - }); + preserveFocus: true, + })); }; } export function viewFileText(ctx: Ctx): Cmd { - const tdcp = new class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse('rust-analyzer://viewFileText/file.rs'); + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer://viewFileText/file.rs"); readonly eventEmitter = new vscode.EventEmitter(); constructor() { - vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); - vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeActiveTextEditor( + this.onDidChangeActiveTextEditor, + this, + ctx.subscriptions + ); } private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { @@ -453,39 +507,52 @@ export function viewFileText(ctx: Ctx): Cmd { } } - provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult { + provideTextDocumentContent( + _uri: vscode.Uri, + ct: vscode.CancellationToken + ): vscode.ProviderResult { const rustEditor = ctx.activeRustEditor; const client = ctx.client; - if (!rustEditor || !client) return ''; + if (!rustEditor || !client) return ""; - const params = client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document); + const params = client.code2ProtocolConverter.asTextDocumentIdentifier( + rustEditor.document + ); return client.sendRequest(ra.viewFileText, params, ct); } get onDidChange(): vscode.Event { return this.eventEmitter.event; } - }; + })(); - ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider("rust-analyzer", tdcp)); return async () => { const document = await vscode.workspace.openTextDocument(tdcp.uri); tdcp.eventEmitter.fire(tdcp.uri); - void await vscode.window.showTextDocument(document, { + void (await vscode.window.showTextDocument(document, { viewColumn: vscode.ViewColumn.Two, - preserveFocus: true - }); + preserveFocus: true, + })); }; } export function viewItemTree(ctx: Ctx): Cmd { - const tdcp = new class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse('rust-analyzer://viewItemTree/itemtree.rs'); + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer://viewItemTree/itemtree.rs"); readonly eventEmitter = new vscode.EventEmitter(); constructor() { - vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); - vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeActiveTextEditor( + this.onDidChangeActiveTextEditor, + this, + ctx.subscriptions + ); } private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { @@ -501,13 +568,18 @@ export function viewItemTree(ctx: Ctx): Cmd { } } - provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult { + provideTextDocumentContent( + _uri: vscode.Uri, + ct: vscode.CancellationToken + ): vscode.ProviderResult { const rustEditor = ctx.activeRustEditor; const client = ctx.client; - if (!rustEditor || !client) return ''; + if (!rustEditor || !client) return ""; const params = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document), + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier( + rustEditor.document + ), }; return client.sendRequest(ra.viewItemTree, params, ct); } @@ -515,17 +587,17 @@ export function viewItemTree(ctx: Ctx): Cmd { get onDidChange(): vscode.Event { return this.eventEmitter.event; } - }; + })(); - ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider("rust-analyzer", tdcp)); return async () => { const document = await vscode.workspace.openTextDocument(tdcp.uri); tdcp.eventEmitter.fire(tdcp.uri); - void await vscode.window.showTextDocument(document, { + void (await vscode.window.showTextDocument(document, { viewColumn: vscode.ViewColumn.Two, - preserveFocus: true - }); + preserveFocus: true, + })); }; } @@ -533,11 +605,16 @@ function crateGraph(ctx: Ctx, full: boolean): Cmd { return async () => { const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules")); - const panel = vscode.window.createWebviewPanel("rust-analyzer.crate-graph", "rust-analyzer crate graph", vscode.ViewColumn.Two, { - enableScripts: true, - retainContextWhenHidden: true, - localResourceRoots: [nodeModulesPath] - }); + const panel = vscode.window.createWebviewPanel( + "rust-analyzer.crate-graph", + "rust-analyzer crate graph", + vscode.ViewColumn.Two, + { + enableScripts: true, + retainContextWhenHidden: true, + localResourceRoots: [nodeModulesPath], + } + ); const params = { full: full, }; @@ -601,29 +678,31 @@ export function viewFullCrateGraph(ctx: Ctx): Cmd { export function expandMacro(ctx: Ctx): Cmd { function codeFormat(expanded: ra.ExpandedMacro): string { let result = `// Recursive expansion of ${expanded.name}! macro\n`; - result += '// ' + '='.repeat(result.length - 3); - result += '\n\n'; + result += "// " + "=".repeat(result.length - 3); + result += "\n\n"; result += expanded.expansion; return result; } - const tdcp = new class implements vscode.TextDocumentContentProvider { - uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs'); + const tdcp = new (class implements vscode.TextDocumentContentProvider { + uri = vscode.Uri.parse("rust-analyzer://expandMacro/[EXPANSION].rs"); eventEmitter = new vscode.EventEmitter(); async provideTextDocumentContent(_uri: vscode.Uri): Promise { const editor = vscode.window.activeTextEditor; const client = ctx.client; - if (!editor || !client) return ''; + if (!editor || !client) return ""; const position = editor.selection.active; const expanded = await client.sendRequest(ra.expandMacro, { - textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), position, }); - if (expanded == null) return 'Not available'; + if (expanded == null) return "Not available"; return codeFormat(expanded); } @@ -631,23 +710,14 @@ export function expandMacro(ctx: Ctx): Cmd { get onDidChange(): vscode.Event { return this.eventEmitter.event; } - }(); + })(); - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider( - 'rust-analyzer', - tdcp, - ), - ); + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider("rust-analyzer", tdcp)); return async () => { const document = await vscode.workspace.openTextDocument(tdcp.uri); tdcp.eventEmitter.fire(tdcp.uri); - return vscode.window.showTextDocument( - document, - vscode.ViewColumn.Two, - true, - ); + return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); }; } @@ -655,13 +725,18 @@ export function reloadWorkspace(ctx: Ctx): Cmd { return async () => ctx.client.sendRequest(ra.reloadWorkspace); } -async function showReferencesImpl(client: LanguageClient, uri: string, position: lc.Position, locations: lc.Location[]) { +async function showReferencesImpl( + client: LanguageClient, + uri: string, + position: lc.Position, + locations: lc.Location[] +) { if (client) { await vscode.commands.executeCommand( - 'editor.action.showReferences', + "editor.action.showReferences", vscode.Uri.parse(uri), client.protocol2CodeConverter.asPosition(position), - locations.map(client.protocol2CodeConverter.asLocation), + locations.map(client.protocol2CodeConverter.asLocation) ); } } @@ -677,8 +752,8 @@ export function applyActionGroup(_ctx: Ctx): Cmd { const selectedAction = await vscode.window.showQuickPick(actions); if (!selectedAction) return; await vscode.commands.executeCommand( - 'rust-analyzer.resolveCodeAction', - selectedAction.arguments, + "rust-analyzer.resolveCodeAction", + selectedAction.arguments ); }; } @@ -699,12 +774,11 @@ export function gotoLocation(ctx: Ctx): Cmd { export function openDocs(ctx: Ctx): Cmd { return async () => { - const client = ctx.client; const editor = vscode.window.activeTextEditor; if (!editor || !client) { return; - }; + } const position = editor.selection.active; const textDocument = { uri: editor.document.uri.toString() }; @@ -715,7 +789,6 @@ export function openDocs(ctx: Ctx): Cmd { await vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(doclink)); } }; - } export function resolveCodeAction(ctx: Ctx): Cmd { @@ -730,8 +803,13 @@ export function resolveCodeAction(ctx: Ctx): Cmd { const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit); // filter out all text edits and recreate the WorkspaceEdit without them so we can apply // snippet edits on our own - const lcFileSystemEdit = { ...itemEdit, documentChanges: itemEdit.documentChanges?.filter(change => "kind" in change) }; - const fileSystemEdit = await client.protocol2CodeConverter.asWorkspaceEdit(lcFileSystemEdit); + const lcFileSystemEdit = { + ...itemEdit, + documentChanges: itemEdit.documentChanges?.filter((change) => "kind" in change), + }; + const fileSystemEdit = await client.protocol2CodeConverter.asWorkspaceEdit( + lcFileSystemEdit + ); await vscode.workspace.applyEdit(fileSystemEdit); await applySnippetWorkspaceEdit(edit); if (item.command != null) { @@ -753,7 +831,7 @@ export function run(ctx: Ctx): Cmd { const item = await selectRunnable(ctx, prevRunnable); if (!item) return; - item.detail = 'rerun'; + item.detail = "rerun"; prevRunnable = item; const task = await createTask(item.runnable, ctx.config); return await vscode.tasks.executeTask(task); @@ -767,29 +845,33 @@ export function peekTests(ctx: Ctx): Cmd { const editor = ctx.activeRustEditor; if (!editor || !client) return; - await vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: "Looking for tests...", - cancellable: false, - }, async (_progress, _token) => { - const uri = editor.document.uri.toString(); - const position = client.code2ProtocolConverter.asPosition( - editor.selection.active, - ); + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Looking for tests...", + cancellable: false, + }, + async (_progress, _token) => { + const uri = editor.document.uri.toString(); + const position = client.code2ProtocolConverter.asPosition(editor.selection.active); - const tests = await client.sendRequest(ra.relatedTests, { - textDocument: { uri: uri }, - position: position, - }); - const locations: lc.Location[] = tests.map(it => - lc.Location.create(it.runnable.location!.targetUri, it.runnable.location!.targetSelectionRange)); + const tests = await client.sendRequest(ra.relatedTests, { + textDocument: { uri: uri }, + position: position, + }); + const locations: lc.Location[] = tests.map((it) => + lc.Location.create( + it.runnable.location!.targetUri, + it.runnable.location!.targetSelectionRange + ) + ); - await showReferencesImpl(client, uri, position, locations); - }); + await showReferencesImpl(client, uri, position, locations); + } + ); }; } - export function runSingle(ctx: Ctx): Cmd { return async (runnable: ra.Runnable) => { const editor = ctx.activeRustEditor; @@ -826,7 +908,7 @@ export function debug(ctx: Ctx): Cmd { const item = await selectRunnable(ctx, prevDebuggee, true); if (!item) return; - item.detail = 'restart'; + item.detail = "restart"; prevDebuggee = item; return await startDebugSession(ctx, item.runnable); }; diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 9837fd16f5..592ebe0ce3 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -1,13 +1,16 @@ -import path = require('path'); -import * as vscode from 'vscode'; -import { Env } from './client'; +import path = require("path"); +import * as vscode from "vscode"; +import { Env } from "./client"; import { log } from "./util"; export type UpdatesChannel = "stable" | "nightly"; const NIGHTLY_TAG = "nightly"; -export type RunnableEnvCfg = undefined | Record | { mask?: string; env: Record }[]; +export type RunnableEnvCfg = + | undefined + | Record + | { mask?: string; env: Record }[]; export class Config { readonly extensionId = "rust-lang.rust-analyzer"; @@ -20,8 +23,7 @@ export class Config { "procMacro", "files", "lens", // works as lens.* - ] - .map(opt => `${this.rootSection}.${opt}`); + ].map((opt) => `${this.rootSection}.${opt}`); readonly package: { version: string; @@ -33,7 +35,11 @@ export class Config { constructor(ctx: vscode.ExtensionContext) { this.globalStorageUri = ctx.globalStorageUri; - vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); + vscode.workspace.onDidChangeConfiguration( + this.onDidChangeConfiguration, + this, + ctx.subscriptions + ); this.refreshLogging(); } @@ -48,8 +54,8 @@ export class Config { private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) { this.refreshLogging(); - const requiresReloadOpt = this.requiresReloadOpts.find( - opt => event.affectsConfiguration(opt) + const requiresReloadOpt = this.requiresReloadOpts.find((opt) => + event.affectsConfiguration(opt) ); if (!requiresReloadOpt) return; @@ -94,8 +100,12 @@ export class Config { get serverPath() { return this.get("server.path") ?? this.get("serverPath"); } - get serverExtraEnv() { return this.get("server.extraEnv") ?? {}; } - get traceExtension() { return this.get("trace.extension"); } + get serverExtraEnv() { + return this.get("server.extraEnv") ?? {}; + } + get traceExtension() { + return this.get("trace.extension"); + } get cargoRunner() { return this.get("cargoRunner"); @@ -109,7 +119,8 @@ export class Config { let sourceFileMap = this.get | "auto">("debug.sourceFileMap"); if (sourceFileMap !== "auto") { // "/rustc/" used by suggestions only. - const { ["/rustc/"]: _, ...trimmed } = this.get>("debug.sourceFileMap"); + const { ["/rustc/"]: _, ...trimmed } = + this.get>("debug.sourceFileMap"); sourceFileMap = trimmed; } @@ -117,7 +128,7 @@ export class Config { engine: this.get("debug.engine"), engineSettings: this.get("debug.engineSettings"), openDebugPane: this.get("debug.openDebugPane"), - sourceFileMap: sourceFileMap + sourceFileMap: sourceFileMap, }; } @@ -139,57 +150,69 @@ export class Config { export async function updateConfig(config: vscode.WorkspaceConfiguration) { const renames = [ - ["assist.allowMergingIntoGlobImports", "imports.merge.glob",], - ["assist.exprFillDefault", "assist.expressionFillDefault",], - ["assist.importEnforceGranularity", "imports.granularity.enforce",], - ["assist.importGranularity", "imports.granularity.group",], - ["assist.importMergeBehavior", "imports.granularity.group",], - ["assist.importMergeBehaviour", "imports.granularity.group",], - ["assist.importGroup", "imports.group.enable",], - ["assist.importPrefix", "imports.prefix",], - ["primeCaches.enable", "cachePriming.enable",], - ["cache.warmup", "cachePriming.enable",], - ["cargo.loadOutDirsFromCheck", "cargo.buildScripts.enable",], - ["cargo.runBuildScripts", "cargo.buildScripts.enable",], - ["cargo.runBuildScriptsCommand", "cargo.buildScripts.overrideCommand",], - ["cargo.useRustcWrapperForBuildScripts", "cargo.buildScripts.useRustcWrapper",], - ["completion.snippets", "completion.snippets.custom",], - ["diagnostics.enableExperimental", "diagnostics.experimental.enable",], - ["experimental.procAttrMacros", "procMacro.attributes.enable",], - ["highlighting.strings", "semanticHighlighting.strings.enable",], - ["highlightRelated.breakPoints", "highlightRelated.breakPoints.enable",], - ["highlightRelated.exitPoints", "highlightRelated.exitPoints.enable",], - ["highlightRelated.yieldPoints", "highlightRelated.yieldPoints.enable",], - ["highlightRelated.references", "highlightRelated.references.enable",], - ["hover.documentation", "hover.documentation.enable",], - ["hover.linksInHover", "hover.links.enable",], - ["hoverActions.linksInHover", "hover.links.enable",], - ["hoverActions.debug", "hover.actions.debug.enable",], - ["hoverActions.enable", "hover.actions.enable.enable",], - ["hoverActions.gotoTypeDef", "hover.actions.gotoTypeDef.enable",], - ["hoverActions.implementations", "hover.actions.implementations.enable",], - ["hoverActions.references", "hover.actions.references.enable",], - ["hoverActions.run", "hover.actions.run.enable",], - ["inlayHints.chainingHints", "inlayHints.chainingHints.enable",], - ["inlayHints.closureReturnTypeHints", "inlayHints.closureReturnTypeHints.enable",], - ["inlayHints.hideNamedConstructorHints", "inlayHints.typeHints.hideNamedConstructor",], - ["inlayHints.parameterHints", "inlayHints.parameterHints.enable",], - ["inlayHints.reborrowHints", "inlayHints.reborrowHints.enable",], - ["inlayHints.typeHints", "inlayHints.typeHints.enable",], - ["lruCapacity", "lru.capacity",], - ["runnables.cargoExtraArgs", "runnables.extraArgs",], - ["runnables.overrideCargo", "runnables.command",], - ["rustcSource", "rustc.source",], - ["rustfmt.enableRangeFormatting", "rustfmt.rangeFormatting.enable"] + ["assist.allowMergingIntoGlobImports", "imports.merge.glob"], + ["assist.exprFillDefault", "assist.expressionFillDefault"], + ["assist.importEnforceGranularity", "imports.granularity.enforce"], + ["assist.importGranularity", "imports.granularity.group"], + ["assist.importMergeBehavior", "imports.granularity.group"], + ["assist.importMergeBehaviour", "imports.granularity.group"], + ["assist.importGroup", "imports.group.enable"], + ["assist.importPrefix", "imports.prefix"], + ["primeCaches.enable", "cachePriming.enable"], + ["cache.warmup", "cachePriming.enable"], + ["cargo.loadOutDirsFromCheck", "cargo.buildScripts.enable"], + ["cargo.runBuildScripts", "cargo.buildScripts.enable"], + ["cargo.runBuildScriptsCommand", "cargo.buildScripts.overrideCommand"], + ["cargo.useRustcWrapperForBuildScripts", "cargo.buildScripts.useRustcWrapper"], + ["completion.snippets", "completion.snippets.custom"], + ["diagnostics.enableExperimental", "diagnostics.experimental.enable"], + ["experimental.procAttrMacros", "procMacro.attributes.enable"], + ["highlighting.strings", "semanticHighlighting.strings.enable"], + ["highlightRelated.breakPoints", "highlightRelated.breakPoints.enable"], + ["highlightRelated.exitPoints", "highlightRelated.exitPoints.enable"], + ["highlightRelated.yieldPoints", "highlightRelated.yieldPoints.enable"], + ["highlightRelated.references", "highlightRelated.references.enable"], + ["hover.documentation", "hover.documentation.enable"], + ["hover.linksInHover", "hover.links.enable"], + ["hoverActions.linksInHover", "hover.links.enable"], + ["hoverActions.debug", "hover.actions.debug.enable"], + ["hoverActions.enable", "hover.actions.enable.enable"], + ["hoverActions.gotoTypeDef", "hover.actions.gotoTypeDef.enable"], + ["hoverActions.implementations", "hover.actions.implementations.enable"], + ["hoverActions.references", "hover.actions.references.enable"], + ["hoverActions.run", "hover.actions.run.enable"], + ["inlayHints.chainingHints", "inlayHints.chainingHints.enable"], + ["inlayHints.closureReturnTypeHints", "inlayHints.closureReturnTypeHints.enable"], + ["inlayHints.hideNamedConstructorHints", "inlayHints.typeHints.hideNamedConstructor"], + ["inlayHints.parameterHints", "inlayHints.parameterHints.enable"], + ["inlayHints.reborrowHints", "inlayHints.reborrowHints.enable"], + ["inlayHints.typeHints", "inlayHints.typeHints.enable"], + ["lruCapacity", "lru.capacity"], + ["runnables.cargoExtraArgs", "runnables.extraArgs"], + ["runnables.overrideCargo", "runnables.command"], + ["rustcSource", "rustc.source"], + ["rustfmt.enableRangeFormatting", "rustfmt.rangeFormatting.enable"], ]; for (const [oldKey, newKey] of renames) { const inspect = config.inspect(oldKey); if (inspect !== undefined) { const valMatrix = [ - { val: inspect.globalValue, langVal: inspect.globalLanguageValue, target: vscode.ConfigurationTarget.Global }, - { val: inspect.workspaceFolderValue, langVal: inspect.workspaceFolderLanguageValue, target: vscode.ConfigurationTarget.WorkspaceFolder }, - { val: inspect.workspaceValue, langVal: inspect.workspaceLanguageValue, target: vscode.ConfigurationTarget.Workspace } + { + val: inspect.globalValue, + langVal: inspect.globalLanguageValue, + target: vscode.ConfigurationTarget.Global, + }, + { + val: inspect.workspaceFolderValue, + langVal: inspect.workspaceFolderLanguageValue, + target: vscode.ConfigurationTarget.WorkspaceFolder, + }, + { + val: inspect.workspaceValue, + langVal: inspect.workspaceLanguageValue, + target: vscode.ConfigurationTarget.Workspace, + }, ]; for (const { val, langVal, target } of valMatrix) { const pred = (val: unknown) => { @@ -197,7 +220,14 @@ export async function updateConfig(config: vscode.WorkspaceConfiguration) { // that means on the next run we would find these again, but as objects with // these properties causing us to destroy the config // so filter those already updated ones out - return val !== undefined && !(typeof val === "object" && val !== null && (val.hasOwnProperty("enable") || val.hasOwnProperty("custom"))); + return ( + val !== undefined && + !( + typeof val === "object" && + val !== null && + (val.hasOwnProperty("enable") || val.hasOwnProperty("custom")) + ) + ); }; if (pred(val)) { await config.update(newKey, val, target, false); @@ -216,48 +246,50 @@ export function substituteVariablesInEnv(env: Env): Env { const missingDeps = new Set(); // vscode uses `env:ENV_NAME` for env vars resolution, and it's easier // to follow the same convention for our dependency tracking - const definedEnvKeys = new Set(Object.keys(env).map(key => `env:${key}`)); - const envWithDeps = Object.fromEntries(Object.entries(env).map(([key, value]) => { - const deps = new Set(); - const depRe = new RegExp(/\${(?.+?)}/g); - let match = undefined; - while ((match = depRe.exec(value))) { - const depName = match.groups!.depName; - deps.add(depName); - // `depName` at this point can have a form of `expression` or - // `prefix:expression` - if (!definedEnvKeys.has(depName)) { - missingDeps.add(depName); + const definedEnvKeys = new Set(Object.keys(env).map((key) => `env:${key}`)); + const envWithDeps = Object.fromEntries( + Object.entries(env).map(([key, value]) => { + const deps = new Set(); + const depRe = new RegExp(/\${(?.+?)}/g); + let match = undefined; + while ((match = depRe.exec(value))) { + const depName = match.groups!.depName; + deps.add(depName); + // `depName` at this point can have a form of `expression` or + // `prefix:expression` + if (!definedEnvKeys.has(depName)) { + missingDeps.add(depName); + } } - } - return [`env:${key}`, { deps: [...deps], value }]; - })); + return [`env:${key}`, { deps: [...deps], value }]; + }) + ); const resolved = new Set(); for (const dep of missingDeps) { const match = /(?.*?):(?.+)/.exec(dep); if (match) { const { prefix, body } = match.groups!; - if (prefix === 'env') { + if (prefix === "env") { const envName = body; envWithDeps[dep] = { - value: process.env[envName] ?? '', - deps: [] + value: process.env[envName] ?? "", + deps: [], }; resolved.add(dep); } else { // we can't handle other prefixes at the moment // leave values as is, but still mark them as resolved envWithDeps[dep] = { - value: '${' + dep + '}', - deps: [] + value: "${" + dep + "}", + deps: [], }; resolved.add(dep); } } else { envWithDeps[dep] = { value: computeVscodeVar(dep), - deps: [] + deps: [], }; } } @@ -267,11 +299,13 @@ export function substituteVariablesInEnv(env: Env): Env { do { leftToResolveSize = toResolve.size; for (const key of toResolve) { - if (envWithDeps[key].deps.every(dep => resolved.has(dep))) { + if (envWithDeps[key].deps.every((dep) => resolved.has(dep))) { envWithDeps[key].value = envWithDeps[key].value.replace( - /\${(?.+?)}/g, (_wholeMatch, depName) => { + /\${(?.+?)}/g, + (_wholeMatch, depName) => { return envWithDeps[depName].value; - }); + } + ); resolved.add(key); toResolve.delete(key); } @@ -302,16 +336,16 @@ function computeVscodeVar(varName: string): string { return folders[0].uri.fsPath; } else { // no workspace opened - return ''; + return ""; } }, workspaceFolderBasename: () => { - const workspaceFolder = computeVscodeVar('workspaceFolder'); + const workspaceFolder = computeVscodeVar("workspaceFolder"); if (workspaceFolder) { return path.basename(workspaceFolder); } else { - return ''; + return ""; } }, @@ -323,13 +357,13 @@ function computeVscodeVar(varName: string): string { // https://github.com/microsoft/vscode/blob/29eb316bb9f154b7870eb5204ec7f2e7cf649bec/src/vs/server/node/remoteTerminalChannel.ts#L56 execPath: () => process.env.VSCODE_EXEC_PATH ?? process.execPath, - pathSeparator: () => path.sep + pathSeparator: () => path.sep, }; if (varName in supportedVariables) { return supportedVariables[varName](); } else { // can't resolve, keep the expression as is - return '${' + varName + '}'; + return "${" + varName + "}"; } } diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 0c3e6810e9..fb2268f89f 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -1,20 +1,20 @@ -import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient/node'; -import * as ra from './lsp_ext'; +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient/node"; +import * as ra from "./lsp_ext"; -import { Config } from './config'; -import { createClient } from './client'; -import { isRustEditor, RustEditor } from './util'; -import { ServerStatusParams } from './lsp_ext'; +import { Config } from "./config"; +import { createClient } from "./client"; +import { isRustEditor, RustEditor } from "./util"; +import { ServerStatusParams } from "./lsp_ext"; export type Workspace = - { - kind: 'Workspace Folder'; - } | { - kind: 'Detached Files'; - files: vscode.TextDocument[]; - }; + kind: "Workspace Folder"; + } + | { + kind: "Detached Files"; + files: vscode.TextDocument[]; + }; export class Ctx { private constructor( @@ -22,16 +22,14 @@ export class Ctx { private readonly extCtx: vscode.ExtensionContext, readonly client: lc.LanguageClient, readonly serverPath: string, - readonly statusBar: vscode.StatusBarItem, - ) { - - } + readonly statusBar: vscode.StatusBarItem + ) {} static async create( config: Config, extCtx: vscode.ExtensionContext, serverPath: string, - workspace: Workspace, + workspace: Workspace ): Promise { const client = await createClient(serverPath, workspace, config.serverExtraEnv); @@ -52,9 +50,7 @@ export class Ctx { get activeRustEditor(): RustEditor | undefined { const editor = vscode.window.activeTextEditor; - return editor && isRustEditor(editor) - ? editor - : undefined; + return editor && isRustEditor(editor) ? editor : undefined; } get visibleRustEditors(): RustEditor[] { diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 830980f968..1f06c99576 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -1,14 +1,19 @@ import * as os from "os"; -import * as vscode from 'vscode'; -import * as path from 'path'; -import * as ra from './lsp_ext'; +import * as vscode from "vscode"; +import * as path from "path"; +import * as ra from "./lsp_ext"; -import { Cargo, getRustcId, getSysroot } from './toolchain'; +import { Cargo, getRustcId, getSysroot } from "./toolchain"; import { Ctx } from "./ctx"; import { prepareEnv } from "./run"; const debugOutput = vscode.window.createOutputChannel("Debug"); -type DebugConfigProvider = (config: ra.Runnable, executable: string, env: Record, sourceFileMap?: Record) => vscode.DebugConfiguration; +type DebugConfigProvider = ( + config: ra.Runnable, + executable: string, + env: Record, + sourceFileMap?: Record +) => vscode.DebugConfiguration; export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise { const scope = ctx.activeRustEditor?.document.uri; @@ -20,9 +25,13 @@ export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise< const wsLaunchSection = vscode.workspace.getConfiguration("launch", scope); const configurations = wsLaunchSection.get("configurations") || []; - const index = configurations.findIndex(c => c.name === debugConfig.name); + const index = configurations.findIndex((c) => c.name === debugConfig.name); if (index !== -1) { - const answer = await vscode.window.showErrorMessage(`Launch configuration '${debugConfig.name}' already exists!`, 'Cancel', 'Update'); + const answer = await vscode.window.showErrorMessage( + `Launch configuration '${debugConfig.name}' already exists!`, + "Cancel", + "Update" + ); if (answer === "Cancel") return; configurations[index] = debugConfig; @@ -40,7 +49,7 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis const wsLaunchSection = vscode.workspace.getConfiguration("launch"); const configurations = wsLaunchSection.get("configurations") || []; - const index = configurations.findIndex(c => c.name === runnable.label); + const index = configurations.findIndex((c) => c.name === runnable.label); if (-1 !== index) { debugConfig = configurations[index]; message = " (from launch.json)"; @@ -56,13 +65,16 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis return vscode.debug.startDebugging(undefined, debugConfig); } -async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise { +async function getDebugConfiguration( + ctx: Ctx, + runnable: ra.Runnable +): Promise { const editor = ctx.activeRustEditor; if (!editor) return; const knownEngines: Record = { "vadimcn.vscode-lldb": getLldbDebugConfig, - "ms-vscode.cpptools": getCppvsDebugConfig + "ms-vscode.cpptools": getCppvsDebugConfig, }; const debugOptions = ctx.config.debug; @@ -77,8 +89,10 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise 1; const firstWorkspace = workspaceFolders[0]; - const workspace = !isMultiFolderWorkspace || !runnable.args.workspaceRoot ? - firstWorkspace : - workspaceFolders.find(w => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) || firstWorkspace; + const workspace = + !isMultiFolderWorkspace || !runnable.args.workspaceRoot + ? firstWorkspace + : workspaceFolders.find((w) => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) || + firstWorkspace; const wsFolder = path.normalize(workspace.uri.fsPath); - const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : ''; + const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : ""; function simplifyPath(p: string): string { // see https://github.com/rust-analyzer/rust-analyzer/pull/5513#issuecomment-663458818 for why this is needed - return path.normalize(p).replace(wsFolder, '${workspaceFolder' + workspaceQualifier + '}'); + return path.normalize(p).replace(wsFolder, "${workspaceFolder" + workspaceQualifier + "}"); } const executable = await getDebugExecutable(runnable); @@ -114,7 +130,12 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise { - const cargo = new Cargo(runnable.args.workspaceRoot || '.', debugOutput); + const cargo = new Cargo(runnable.args.workspaceRoot || ".", debugOutput); const executable = await cargo.executableFromArgs(runnable.args.cargoArgs); // if we are here, there were no compilation errors. return executable; } -function getLldbDebugConfig(runnable: ra.Runnable, executable: string, env: Record, sourceFileMap?: Record): vscode.DebugConfiguration { +function getLldbDebugConfig( + runnable: ra.Runnable, + executable: string, + env: Record, + sourceFileMap?: Record +): vscode.DebugConfiguration { return { type: "lldb", request: "launch", @@ -153,13 +179,18 @@ function getLldbDebugConfig(runnable: ra.Runnable, executable: string, env: Reco cwd: runnable.args.workspaceRoot, sourceMap: sourceFileMap, sourceLanguages: ["rust"], - env + env, }; } -function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, env: Record, sourceFileMap?: Record): vscode.DebugConfiguration { +function getCppvsDebugConfig( + runnable: ra.Runnable, + executable: string, + env: Record, + sourceFileMap?: Record +): vscode.DebugConfiguration { return { - type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg", + type: os.platform() === "win32" ? "cppvsdbg" : "cppdbg", request: "launch", name: runnable.label, program: executable, diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 61078b58c7..f80af78a74 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -7,7 +7,9 @@ import * as lc from "vscode-languageclient"; export interface AnalyzerStatusParams { textDocument?: lc.TextDocumentIdentifier; } -export const analyzerStatus = new lc.RequestType("rust-analyzer/analyzerStatus"); +export const analyzerStatus = new lc.RequestType( + "rust-analyzer/analyzerStatus" +); export const memoryUsage = new lc.RequestType0("rust-analyzer/memoryUsage"); export const shuffleCrateGraph = new lc.RequestType0("rust-analyzer/shuffleCrateGraph"); @@ -16,7 +18,9 @@ export interface ServerStatusParams { quiescent: boolean; message?: string; } -export const serverStatus = new lc.NotificationType("experimental/serverStatus"); +export const serverStatus = new lc.NotificationType( + "experimental/serverStatus" +); export const reloadWorkspace = new lc.RequestType0("rust-analyzer/reloadWorkspace"); @@ -31,23 +35,33 @@ export interface SyntaxTreeParams { textDocument: lc.TextDocumentIdentifier; range: lc.Range | null; } -export const syntaxTree = new lc.RequestType("rust-analyzer/syntaxTree"); +export const syntaxTree = new lc.RequestType( + "rust-analyzer/syntaxTree" +); -export const viewHir = new lc.RequestType("rust-analyzer/viewHir"); +export const viewHir = new lc.RequestType( + "rust-analyzer/viewHir" +); -export const viewFileText = new lc.RequestType("rust-analyzer/viewFileText"); +export const viewFileText = new lc.RequestType( + "rust-analyzer/viewFileText" +); export interface ViewItemTreeParams { textDocument: lc.TextDocumentIdentifier; } -export const viewItemTree = new lc.RequestType("rust-analyzer/viewItemTree"); +export const viewItemTree = new lc.RequestType( + "rust-analyzer/viewItemTree" +); export interface ViewCrateGraphParams { full: boolean; } -export const viewCrateGraph = new lc.RequestType("rust-analyzer/viewCrateGraph"); +export const viewCrateGraph = new lc.RequestType( + "rust-analyzer/viewCrateGraph" +); export interface ExpandMacroParams { textDocument: lc.TextDocumentIdentifier; @@ -57,23 +71,35 @@ export interface ExpandedMacro { name: string; expansion: string; } -export const expandMacro = new lc.RequestType("rust-analyzer/expandMacro"); +export const expandMacro = new lc.RequestType( + "rust-analyzer/expandMacro" +); export interface MatchingBraceParams { textDocument: lc.TextDocumentIdentifier; positions: lc.Position[]; } -export const matchingBrace = new lc.RequestType("experimental/matchingBrace"); +export const matchingBrace = new lc.RequestType( + "experimental/matchingBrace" +); -export const parentModule = new lc.RequestType("experimental/parentModule"); +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("experimental/joinLines"); +export const joinLines = new lc.RequestType( + "experimental/joinLines" +); -export const onEnter = new lc.RequestType("experimental/onEnter"); +export const onEnter = new lc.RequestType( + "experimental/onEnter" +); export interface RunnablesParams { textDocument: lc.TextDocumentIdentifier; @@ -93,13 +119,17 @@ export interface Runnable { overrideCargo?: string; }; } -export const runnables = new lc.RequestType("experimental/runnables"); +export const runnables = new lc.RequestType( + "experimental/runnables" +); export interface TestInfo { runnable: Runnable; } -export const relatedTests = new lc.RequestType("rust-analyzer/relatedTests"); +export const relatedTests = new lc.RequestType( + "rust-analyzer/relatedTests" +); export interface SsrParams { query: string; @@ -108,7 +138,7 @@ export interface SsrParams { position: lc.Position; selections: readonly lc.Range[]; } -export const ssr = new lc.RequestType('experimental/ssr'); +export const ssr = new lc.RequestType("experimental/ssr"); export interface CommandLink extends lc.Command { /** @@ -122,15 +152,21 @@ export interface CommandLinkGroup { commands: CommandLink[]; } -export const openDocs = new lc.RequestType('experimental/externalDocs'); +export const openDocs = new lc.RequestType( + "experimental/externalDocs" +); -export const openCargoToml = new lc.RequestType("experimental/openCargoToml"); +export const openCargoToml = new lc.RequestType( + "experimental/openCargoToml" +); export interface OpenCargoTomlParams { textDocument: lc.TextDocumentIdentifier; } -export const moveItem = new lc.RequestType("experimental/moveItem"); +export const moveItem = new lc.RequestType( + "experimental/moveItem" +); export interface MoveItemParams { textDocument: lc.TextDocumentIdentifier; @@ -140,5 +176,5 @@ export interface MoveItemParams { export const enum Direction { Up = "Up", - Down = "Down" + Down = "Down", } diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 39bd73c663..61824fae21 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -1,15 +1,15 @@ -import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient/node'; +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient/node"; import * as os from "os"; -import * as commands from './commands'; -import { Ctx } from './ctx'; -import { Config } from './config'; -import { log, isValidExecutable, isRustDocument } from './util'; -import { PersistentState } from './persistent_state'; -import { activateTaskProvider } from './tasks'; -import { setContextValue } from './util'; -import { exec } from 'child_process'; +import * as commands from "./commands"; +import { Ctx } from "./ctx"; +import { Config } from "./config"; +import { log, isValidExecutable, isRustDocument } from "./util"; +import { PersistentState } from "./persistent_state"; +import { activateTaskProvider } from "./tasks"; +import { setContextValue } from "./util"; +import { exec } from "child_process"; let ctx: Ctx | undefined; @@ -19,10 +19,12 @@ export interface RustAnalyzerExtensionApi { client: lc.LanguageClient; } -export async function activate(context: vscode.ExtensionContext): Promise { +export async function activate( + context: vscode.ExtensionContext +): Promise { // VS Code doesn't show a notification when an extension fails to activate // so we do it ourselves. - return await tryActivate(context).catch(err => { + return await tryActivate(context).catch((err) => { void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`); throw err; }); @@ -31,7 +33,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { const config = new Config(context); const state = new PersistentState(context.globalState); - const serverPath = await bootstrap(context, config, state).catch(err => { + const serverPath = await bootstrap(context, config, state).catch((err) => { let message = "bootstrap error. "; message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). '; @@ -42,9 +44,14 @@ async function tryActivate(context: vscode.ExtensionContext): Promise isRustDocument(document)); + const rustDocuments = vscode.workspace.textDocuments.filter((document) => + isRustDocument(document) + ); if (rustDocuments.length > 0) { - ctx = await Ctx.create(config, context, serverPath, { kind: 'Detached Files', files: rustDocuments }); + ctx = await Ctx.create(config, context, serverPath, { + kind: "Detached Files", + files: rustDocuments, + }); } else { throw new Error("no rust files are opened"); } @@ -63,13 +70,16 @@ async function tryActivate(context: vscode.ExtensionContext): Promise ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }).catch(log.error), + (_) => + ctx?.client + ?.sendNotification("workspace/didChangeConfiguration", { settings: "" }) + .catch(log.error), null, - ctx.subscriptions, + ctx.subscriptions ); return { - client: ctx.client + client: ctx.client, }; } @@ -88,9 +98,8 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) { // "rust-analyzer is not available" // ), // ) - const defaultOnEnter = vscode.commands.registerCommand( - 'rust-analyzer.onEnter', - () => vscode.commands.executeCommand('default:type', { text: '\n' }), + const defaultOnEnter = vscode.commands.registerCommand("rust-analyzer.onEnter", () => + vscode.commands.executeCommand("default:type", { text: "\n" }) ); context.subscriptions.push(defaultOnEnter); @@ -99,8 +108,8 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) { // Commands which invokes manually via command palette, shortcut, etc. // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895 - ctx.registerCommand('reload', _ => async () => { - void vscode.window.showInformationMessage('Reloading rust-analyzer...'); + ctx.registerCommand("reload", (_) => async () => { + void vscode.window.showInformationMessage("Reloading rust-analyzer..."); await deactivate(); while (context.subscriptions.length > 0) { try { @@ -112,45 +121,45 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) { await activate(context).catch(log.error); }); - ctx.registerCommand('analyzerStatus', commands.analyzerStatus); - ctx.registerCommand('memoryUsage', commands.memoryUsage); - ctx.registerCommand('shuffleCrateGraph', commands.shuffleCrateGraph); - ctx.registerCommand('reloadWorkspace', commands.reloadWorkspace); - ctx.registerCommand('matchingBrace', commands.matchingBrace); - ctx.registerCommand('joinLines', commands.joinLines); - ctx.registerCommand('parentModule', commands.parentModule); - ctx.registerCommand('syntaxTree', commands.syntaxTree); - ctx.registerCommand('viewHir', commands.viewHir); - ctx.registerCommand('viewFileText', commands.viewFileText); - ctx.registerCommand('viewItemTree', commands.viewItemTree); - ctx.registerCommand('viewCrateGraph', commands.viewCrateGraph); - ctx.registerCommand('viewFullCrateGraph', commands.viewFullCrateGraph); - ctx.registerCommand('expandMacro', commands.expandMacro); - ctx.registerCommand('run', commands.run); - ctx.registerCommand('copyRunCommandLine', commands.copyRunCommandLine); - ctx.registerCommand('debug', commands.debug); - ctx.registerCommand('newDebugConfig', commands.newDebugConfig); - ctx.registerCommand('openDocs', commands.openDocs); - ctx.registerCommand('openCargoToml', commands.openCargoToml); - ctx.registerCommand('peekTests', commands.peekTests); - ctx.registerCommand('moveItemUp', commands.moveItemUp); - ctx.registerCommand('moveItemDown', commands.moveItemDown); + ctx.registerCommand("analyzerStatus", commands.analyzerStatus); + ctx.registerCommand("memoryUsage", commands.memoryUsage); + ctx.registerCommand("shuffleCrateGraph", commands.shuffleCrateGraph); + ctx.registerCommand("reloadWorkspace", commands.reloadWorkspace); + ctx.registerCommand("matchingBrace", commands.matchingBrace); + ctx.registerCommand("joinLines", commands.joinLines); + ctx.registerCommand("parentModule", commands.parentModule); + ctx.registerCommand("syntaxTree", commands.syntaxTree); + ctx.registerCommand("viewHir", commands.viewHir); + ctx.registerCommand("viewFileText", commands.viewFileText); + ctx.registerCommand("viewItemTree", commands.viewItemTree); + ctx.registerCommand("viewCrateGraph", commands.viewCrateGraph); + ctx.registerCommand("viewFullCrateGraph", commands.viewFullCrateGraph); + ctx.registerCommand("expandMacro", commands.expandMacro); + ctx.registerCommand("run", commands.run); + ctx.registerCommand("copyRunCommandLine", commands.copyRunCommandLine); + ctx.registerCommand("debug", commands.debug); + ctx.registerCommand("newDebugConfig", commands.newDebugConfig); + ctx.registerCommand("openDocs", commands.openDocs); + ctx.registerCommand("openCargoToml", commands.openCargoToml); + ctx.registerCommand("peekTests", commands.peekTests); + ctx.registerCommand("moveItemUp", commands.moveItemUp); + ctx.registerCommand("moveItemDown", commands.moveItemDown); defaultOnEnter.dispose(); - ctx.registerCommand('onEnter', commands.onEnter); + ctx.registerCommand("onEnter", commands.onEnter); - ctx.registerCommand('ssr', commands.ssr); - ctx.registerCommand('serverVersion', commands.serverVersion); - ctx.registerCommand('toggleInlayHints', commands.toggleInlayHints); + ctx.registerCommand("ssr", commands.ssr); + ctx.registerCommand("serverVersion", commands.serverVersion); + ctx.registerCommand("toggleInlayHints", commands.toggleInlayHints); // Internal commands which are invoked by the server. - ctx.registerCommand('runSingle', commands.runSingle); - ctx.registerCommand('debugSingle', commands.debugSingle); - ctx.registerCommand('showReferences', commands.showReferences); - ctx.registerCommand('applySnippetWorkspaceEdit', commands.applySnippetWorkspaceEditCommand); - ctx.registerCommand('resolveCodeAction', commands.resolveCodeAction); - ctx.registerCommand('applyActionGroup', commands.applyActionGroup); - ctx.registerCommand('gotoLocation', commands.gotoLocation); + ctx.registerCommand("runSingle", commands.runSingle); + ctx.registerCommand("debugSingle", commands.debugSingle); + ctx.registerCommand("showReferences", commands.showReferences); + ctx.registerCommand("applySnippetWorkspaceEdit", commands.applySnippetWorkspaceEditCommand); + ctx.registerCommand("resolveCodeAction", commands.resolveCodeAction); + ctx.registerCommand("applyActionGroup", commands.applyActionGroup); + ctx.registerCommand("gotoLocation", commands.gotoLocation); } export async function deactivate() { @@ -159,12 +168,16 @@ export async function deactivate() { ctx = undefined; } -async function bootstrap(context: vscode.ExtensionContext, config: Config, state: PersistentState): Promise { +async function bootstrap( + context: vscode.ExtensionContext, + config: Config, + state: PersistentState +): Promise { const path = await getServer(context, config, state); if (!path) { throw new Error( "Rust Analyzer Language Server is not available. " + - "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)." + "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)." ); } @@ -186,7 +199,7 @@ async function patchelf(dest: vscode.Uri): Promise { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, - title: "Patching rust-analyzer for NixOS" + title: "Patching rust-analyzer for NixOS", }, async (progress, _) => { const expression = ` @@ -207,14 +220,16 @@ async function patchelf(dest: vscode.Uri): Promise { 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}'`, + 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(); }); @@ -225,25 +240,35 @@ async function patchelf(dest: vscode.Uri): Promise { ); } -async function getServer(context: vscode.ExtensionContext, config: Config, state: PersistentState): Promise { +async function getServer( + context: vscode.ExtensionContext, + config: Config, + state: PersistentState +): Promise { const explicitPath = serverPath(config); if (explicitPath) { if (explicitPath.startsWith("~/")) { return os.homedir() + explicitPath.slice("~".length); } return explicitPath; - }; + } if (config.package.releaseTag === null) return "rust-analyzer"; const ext = process.platform === "win32" ? ".exe" : ""; const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`); - const bundledExists = await vscode.workspace.fs.stat(bundled).then(() => true, () => false); + const bundledExists = await vscode.workspace.fs.stat(bundled).then( + () => true, + () => false + ); if (bundledExists) { let server = bundled; if (await isNixOs()) { await vscode.workspace.fs.createDirectory(config.globalStorageUri).then(); const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`); - let exists = await vscode.workspace.fs.stat(dest).then(() => true, () => false); + let exists = await vscode.workspace.fs.stat(dest).then( + () => true, + () => false + ); if (exists && config.package.version !== state.serverVersion) { await vscode.workspace.fs.delete(dest); exists = false; @@ -261,11 +286,11 @@ async function getServer(context: vscode.ExtensionContext, config: Config, state await state.updateServerVersion(undefined); await vscode.window.showErrorMessage( "Unfortunately we don't ship binaries for your platform yet. " + - "You need to manually clone the rust-analyzer repository and " + - "run `cargo xtask install --server` to build the language server from sources. " + - "If you feel that your platform should be supported, please create an issue " + - "about that [here](https://github.com/rust-analyzer/rust-analyzer/issues) and we " + - "will consider it." + "You need to manually clone the rust-analyzer repository and " + + "run `cargo xtask install --server` to build the language server from sources. " + + "If you feel that your platform should be supported, please create an issue " + + "about that [here](https://github.com/rust-analyzer/rust-analyzer/issues) and we " + + "will consider it." ); return undefined; } @@ -276,8 +301,10 @@ function serverPath(config: Config): string | null { async function isNixOs(): Promise { try { - const contents = (await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))).toString(); - const idString = contents.split('\n').find((a) => a.startsWith("ID=")) || "ID=linux"; + const contents = ( + await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release")) + ).toString(); + const idString = contents.split("\n").find((a) => a.startsWith("ID=")) || "ID=linux"; return idString.indexOf("nixos") !== -1; } catch { return false; @@ -286,11 +313,14 @@ async function isNixOs(): Promise { function warnAboutExtensionConflicts() { if (vscode.extensions.getExtension("rust-lang.rust")) { - vscode.window.showWarningMessage( - `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` + - "plugins enabled. These are known to conflict and cause various functions of " + - "both plugins to not work correctly. You should disable one of them.", "Got it") - .then(() => { }, console.error); + vscode.window + .showWarningMessage( + `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` + + "plugins enabled. These are known to conflict and cause various functions of " + + "both plugins to not work correctly. You should disable one of them.", + "Got it" + ) + .then(() => {}, console.error); } } @@ -302,38 +332,38 @@ function warnAboutExtensionConflicts() { */ function configureLanguage(): vscode.Disposable { const indentAction = vscode.IndentAction.None; - return vscode.languages.setLanguageConfiguration('rust', { + return vscode.languages.setLanguageConfiguration("rust", { onEnterRules: [ { // Doc single-line comment // e.g. ///| beforeText: /^\s*\/{3}.*$/, - action: { indentAction, appendText: '/// ' }, + action: { indentAction, appendText: "/// " }, }, { // Parent doc single-line comment // e.g. //!| beforeText: /^\s*\/{2}\!.*$/, - action: { indentAction, appendText: '//! ' }, + 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: ' * ' }, + action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: " * " }, }, { // Begins a multi-line comment (standard or parent doc) // e.g. /** ...| or /*! ...| beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, - action: { indentAction, appendText: ' * ' }, + action: { indentAction, appendText: " * " }, }, { // Continues a multi-line comment // e.g. * ...| beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/, - action: { indentAction, appendText: '* ' }, + action: { indentAction, appendText: "* " }, }, { // Dedents after closing a multi-line comment diff --git a/editors/code/src/persistent_state.ts b/editors/code/src/persistent_state.ts index 3e86ed1e32..8964a78dc3 100644 --- a/editors/code/src/persistent_state.ts +++ b/editors/code/src/persistent_state.ts @@ -1,5 +1,5 @@ -import * as vscode from 'vscode'; -import { log } from './util'; +import * as vscode from "vscode"; +import { log } from "./util"; export class PersistentState { constructor(private readonly globalState: vscode.Memento) { diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index d0be840686..b3dff3db5d 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -1,15 +1,22 @@ -import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; -import * as ra from './lsp_ext'; -import * as tasks from './tasks'; +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient"; +import * as ra from "./lsp_ext"; +import * as tasks from "./tasks"; -import { Ctx } from './ctx'; -import { makeDebugConfig } from './debug'; -import { Config, RunnableEnvCfg } from './config'; +import { Ctx } from "./ctx"; +import { makeDebugConfig } from "./debug"; +import { Config, RunnableEnvCfg } from "./config"; -const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; +const quickPickButtons = [ + { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }, +]; -export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise { +export async function selectRunnable( + ctx: Ctx, + prevRunnable?: RunnableQuickPick, + debuggeeOnly = false, + showButtons: boolean = true +): Promise { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; @@ -20,23 +27,18 @@ export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, const runnables = await client.sendRequest(ra.runnables, { textDocument, - position: client.code2ProtocolConverter.asPosition( - editor.selection.active, - ), + position: client.code2ProtocolConverter.asPosition(editor.selection.active), }); const items: RunnableQuickPick[] = []; if (prevRunnable) { items.push(prevRunnable); } for (const r of runnables) { - if ( - prevRunnable && - JSON.stringify(prevRunnable.runnable) === JSON.stringify(r) - ) { + if (prevRunnable && JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)) { continue; } - if (debuggeeOnly && (r.label.startsWith('doctest') || r.label.startsWith('cargo'))) { + if (debuggeeOnly && (r.label.startsWith("doctest") || r.label.startsWith("cargo"))) { continue; } items.push(new RunnableQuickPick(r)); @@ -53,7 +55,7 @@ export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, const disposables: vscode.Disposable[] = []; const close = (result?: RunnableQuickPick) => { resolve(result); - disposables.forEach(d => d.dispose()); + disposables.forEach((d) => d.dispose()); }; const quickPick = vscode.window.createQuickPick(); @@ -71,7 +73,7 @@ export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, }), quickPick.onDidChangeActive((active) => { if (showButtons && active.length > 0) { - if (active[0].label.startsWith('cargo')) { + if (active[0].label.startsWith("cargo")) { // save button makes no sense for `cargo test` or `cargo check` quickPick.buttons = []; } else if (quickPick.buttons.length === 0) { @@ -96,8 +98,11 @@ export class RunnableQuickPick implements vscode.QuickPickItem { } } -export function prepareEnv(runnable: ra.Runnable, runnableEnvCfg: RunnableEnvCfg): Record { - const env: Record = { "RUST_BACKTRACE": "short" }; +export function prepareEnv( + runnable: ra.Runnable, + runnableEnvCfg: RunnableEnvCfg +): Record { + const env: Record = { RUST_BACKTRACE: "short" }; if (runnable.args.expectTest) { env["UPDATE_EXPECT"] = "1"; @@ -141,7 +146,14 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() - const cargoTask = await tasks.buildCargoTask(target, definition, runnable.label, args, config.cargoRunner, true); + const cargoTask = await tasks.buildCargoTask( + target, + definition, + runnable.label, + args, + config.cargoRunner, + true + ); cargoTask.presentationOptions.clear = true; // Sadly, this doesn't prevent focus stealing if the terminal is currently @@ -157,7 +169,7 @@ export function createArgs(runnable: ra.Runnable): string[] { args.push(...runnable.args.cargoExtraArgs); // Append user-specified cargo options. } if (runnable.args.executableArgs.length > 0) { - args.push('--', ...runnable.args.executableArgs); + args.push("--", ...runnable.args.executableArgs); } return args; } diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts index a409e52963..14c2121d08 100644 --- a/editors/code/src/snippets.ts +++ b/editors/code/src/snippets.ts @@ -1,6 +1,6 @@ -import * as vscode from 'vscode'; +import * as vscode from "vscode"; -import { assert } from './util'; +import { assert } from "./util"; export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { if (edit.entries().length === 1) { @@ -11,12 +11,16 @@ export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { } for (const [uri, edits] of edit.entries()) { const editor = await editorFromUri(uri); - if (editor) await editor.edit((builder) => { - for (const indel of edits) { - assert(!parseSnippet(indel.newText), `bad ws edit: snippet received with multiple edits: ${JSON.stringify(edit)}`); - builder.replace(indel.range, indel.newText); - } - }); + if (editor) + await editor.edit((builder) => { + for (const indel of edits) { + assert( + !parseSnippet(indel.newText), + `bad ws edit: snippet received with multiple edits: ${JSON.stringify(edit)}` + ); + builder.replace(indel.range, indel.newText); + } + }); } } @@ -25,7 +29,9 @@ async function editorFromUri(uri: vscode.Uri): Promise it.document.uri.toString() === uri.toString()); + return vscode.window.visibleTextEditors.find( + (it) => it.document.uri.toString() === uri.toString() + ); } export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) { @@ -37,22 +43,26 @@ export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vs if (parsed) { const [newText, [placeholderStart, placeholderLength]] = parsed; const prefix = newText.substr(0, placeholderStart); - const lastNewline = prefix.lastIndexOf('\n'); + const lastNewline = prefix.lastIndexOf("\n"); const startLine = indel.range.start.line + lineDelta + countLines(prefix); - const startColumn = lastNewline === -1 ? - indel.range.start.character + placeholderStart - : prefix.length - lastNewline - 1; + const startColumn = + lastNewline === -1 + ? indel.range.start.character + placeholderStart + : prefix.length - lastNewline - 1; const endColumn = startColumn + placeholderLength; - selections.push(new vscode.Selection( - new vscode.Position(startLine, startColumn), - new vscode.Position(startLine, endColumn), - )); + selections.push( + new vscode.Selection( + new vscode.Position(startLine, startColumn), + new vscode.Position(startLine, endColumn) + ) + ); builder.replace(indel.range, newText); } else { builder.replace(indel.range, indel.newText); } - lineDelta += countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); + lineDelta += + countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); } }); if (selections.length > 0) editor.selections = selections; @@ -65,8 +75,7 @@ function parseSnippet(snip: string): [string, [number, number]] | undefined { const m = snip.match(/\$(0|\{0:([^}]*)\})/); if (!m) return undefined; const placeholder = m[2] ?? ""; - if (m.index == null) - return undefined; + if (m.index == null) return undefined; const range: [number, number] = [m.index, placeholder.length]; const insert = snip.replace(m[0], placeholder); return [insert, range]; diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts index 99edd9ae9d..8aa6bcee19 100644 --- a/editors/code/src/tasks.ts +++ b/editors/code/src/tasks.ts @@ -1,12 +1,12 @@ -import * as vscode from 'vscode'; +import * as vscode from "vscode"; import * as toolchain from "./toolchain"; -import { Config } from './config'; -import { log } from './util'; +import { Config } from "./config"; +import { log } from "./util"; // This ends up as the `type` key in tasks.json. RLS also uses `cargo` and // our configuration should be compatible with it so use the same key. -export const TASK_TYPE = 'cargo'; -export const TASK_SOURCE = 'rust'; +export const TASK_TYPE = "cargo"; +export const TASK_SOURCE = "rust"; export interface CargoTaskDefinition extends vscode.TaskDefinition { command?: string; @@ -30,17 +30,23 @@ class CargoTaskProvider implements vscode.TaskProvider { // tasks.json - only tweaked. const defs = [ - { command: 'build', group: vscode.TaskGroup.Build }, - { command: 'check', group: vscode.TaskGroup.Build }, - { command: 'test', group: vscode.TaskGroup.Test }, - { command: 'clean', group: vscode.TaskGroup.Clean }, - { command: 'run', group: undefined }, + { command: "build", group: vscode.TaskGroup.Build }, + { command: "check", group: vscode.TaskGroup.Build }, + { command: "test", group: vscode.TaskGroup.Test }, + { command: "clean", group: vscode.TaskGroup.Clean }, + { command: "run", group: undefined }, ]; const tasks: vscode.Task[] = []; for (const workspaceTarget of vscode.workspace.workspaceFolders || []) { for (const def of defs) { - const vscodeTask = await buildCargoTask(workspaceTarget, { type: TASK_TYPE, command: def.command }, `cargo ${def.command}`, [def.command], this.config.cargoRunner); + const vscodeTask = await buildCargoTask( + workspaceTarget, + { type: TASK_TYPE, command: def.command }, + `cargo ${def.command}`, + [def.command], + this.config.cargoRunner + ); vscodeTask.group = def.group; tasks.push(vscodeTask); } @@ -58,7 +64,13 @@ class CargoTaskProvider implements vscode.TaskProvider { if (definition.type === TASK_TYPE && definition.command) { const args = [definition.command].concat(definition.args ?? []); - return await buildCargoTask(task.scope, definition, task.name, args, this.config.cargoRunner); + return await buildCargoTask( + task.scope, + definition, + task.name, + args, + this.config.cargoRunner + ); } return undefined; @@ -73,7 +85,6 @@ export async function buildCargoTask( customRunner?: string, throwOnError: boolean = false ): Promise { - let exec: vscode.ProcessExecution | vscode.ShellExecution | undefined = undefined; if (customRunner) { @@ -90,7 +101,6 @@ export async function buildCargoTask( } } // fallback to default processing - } catch (e) { if (throwOnError) throw `Cargo runner '${customRunner}' failed! ${e}`; // fallback to default processing @@ -117,7 +127,7 @@ export async function buildCargoTask( name, TASK_SOURCE, exec, - ['$rustc'] + ["$rustc"] ); } diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index 681932c93b..c23a9a8d9e 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts @@ -1,9 +1,9 @@ -import * as cp from 'child_process'; -import * as os from 'os'; -import * as path from 'path'; -import * as readline from 'readline'; -import * as vscode from 'vscode'; -import { execute, log, memoizeAsync } from './util'; +import * as cp from "child_process"; +import * as os from "os"; +import * as path from "path"; +import * as readline from "readline"; +import * as vscode from "vscode"; +import { execute, log, memoizeAsync } from "./util"; interface CompilationArtifact { fileName: string; @@ -18,7 +18,7 @@ export interface ArtifactSpec { } export class Cargo { - constructor(readonly rootFolder: string, readonly output: vscode.OutputChannel) { } + constructor(readonly rootFolder: string, readonly output: vscode.OutputChannel) {} // Made public for testing purposes static artifactSpec(args: readonly string[]): ArtifactSpec { @@ -27,7 +27,9 @@ export class Cargo { // arguments for a runnable from the quick pick should be updated. // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens switch (cargoArgs[0]) { - case "run": cargoArgs[0] = "build"; break; + case "run": + cargoArgs[0] = "build"; + break; case "test": { if (!cargoArgs.includes("--no-run")) { cargoArgs.push("--no-run"); @@ -40,7 +42,7 @@ export class Cargo { if (cargoArgs[0] === "test") { // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"} - result.filter = (artifacts) => artifacts.filter(it => it.isTest); + result.filter = (artifacts) => artifacts.filter((it) => it.isTest); } return result; @@ -50,24 +52,25 @@ export class Cargo { const artifacts: CompilationArtifact[] = []; try { - await this.runCargo(spec.cargoArgs, - message => { - if (message.reason === 'compiler-artifact' && message.executable) { - const isBinary = message.target.crate_types.includes('bin'); - const isBuildScript = message.target.kind.includes('custom-build'); + await this.runCargo( + spec.cargoArgs, + (message) => { + if (message.reason === "compiler-artifact" && message.executable) { + const isBinary = message.target.crate_types.includes("bin"); + const isBuildScript = message.target.kind.includes("custom-build"); if ((isBinary && !isBuildScript) || message.profile.test) { artifacts.push({ fileName: message.executable, name: message.target.name, kind: message.target.kind[0], - isTest: message.profile.test + isTest: message.profile.test, }); } - } else if (message.reason === 'compiler-message') { + } else if (message.reason === "compiler-message") { this.output.append(message.message.rendered); } }, - stderr => this.output.append(stderr), + (stderr) => this.output.append(stderr) ); } catch (err) { this.output.show(true); @@ -81,9 +84,9 @@ export class Cargo { const artifacts = await this.getArtifacts(Cargo.artifactSpec(args)); if (artifacts.length === 0) { - throw new Error('No compilation artifacts'); + throw new Error("No compilation artifacts"); } else if (artifacts.length > 1) { - throw new Error('Multiple compilation artifacts are not supported.'); + throw new Error("Multiple compilation artifacts are not supported."); } return artifacts[0].fileName; @@ -97,25 +100,23 @@ export class Cargo { const path = await cargoPath(); return await new Promise((resolve, reject) => { const cargo = cp.spawn(path, cargoArgs, { - stdio: ['ignore', 'pipe', 'pipe'], - cwd: this.rootFolder + stdio: ["ignore", "pipe", "pipe"], + cwd: this.rootFolder, }); - cargo.on('error', err => reject(new Error(`could not launch cargo: ${err}`))); + cargo.on("error", (err) => reject(new Error(`could not launch cargo: ${err}`))); - cargo.stderr.on('data', chunk => onStderrString(chunk.toString())); + cargo.stderr.on("data", (chunk) => onStderrString(chunk.toString())); const rl = readline.createInterface({ input: cargo.stdout }); - rl.on('line', line => { + rl.on("line", (line) => { const message = JSON.parse(line); onStdoutJson(message); }); - cargo.on('exit', (exitCode, _) => { - if (exitCode === 0) - resolve(exitCode); - else - reject(new Error(`exit code: ${exitCode}.`)); + cargo.on("exit", (exitCode, _) => { + if (exitCode === 0) resolve(exitCode); + else reject(new Error(`exit code: ${exitCode}.`)); }); }); } @@ -158,7 +159,12 @@ export const getPathForExecutable = memoizeAsync( try { // hmm, `os.homedir()` seems to be infallible // it is not mentioned in docs and cannot be infered by the type signature... - const standardPath = vscode.Uri.joinPath(vscode.Uri.file(os.homedir()), ".cargo", "bin", executableName); + const standardPath = vscode.Uri.joinPath( + vscode.Uri.file(os.homedir()), + ".cargo", + "bin", + executableName + ); if (await isFileAtUri(standardPath)) return standardPath.fsPath; } catch (err) { @@ -169,13 +175,11 @@ export const getPathForExecutable = memoizeAsync( ); async function lookupInPath(exec: string): Promise { - const paths = process.env.PATH ?? "";; + const paths = process.env.PATH ?? ""; - const candidates = paths.split(path.delimiter).flatMap(dirInPath => { + const candidates = paths.split(path.delimiter).flatMap((dirInPath) => { const candidate = path.join(dirInPath, exec); - return os.type() === "Windows_NT" - ? [candidate, `${candidate}.exe`] - : [candidate]; + return os.type() === "Windows_NT" ? [candidate, `${candidate}.exe`] : [candidate]; }); for await (const isFile of candidates.map(isFileAtPath)) { diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 057a3d2e19..cd91932bb6 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -13,7 +13,7 @@ export function assert(condition: boolean, explanation: string): asserts conditi } } -export const log = new class { +export const log = new (class { private enabled = true; private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client"); @@ -55,21 +55,20 @@ export const log = new class { depth: 6, // heuristic }); } -}; +})(); export async function sendRequestWithRetry( client: lc.LanguageClient, reqType: lc.RequestType, param: TParam, - token?: vscode.CancellationToken, + token?: vscode.CancellationToken ): Promise { // The sequence is `10 * (2 ** (2 * n))` where n is 1, 2, 3... for (const delay of [40, 160, 640, 2560, 10240, null]) { try { return await (token ? client.sendRequest(reqType, param, token) - : client.sendRequest(reqType, param) - ); + : client.sendRequest(reqType, param)); } catch (error) { if (delay === null) { log.warn("LSP request timed out", { method: reqType.method, param, error }); @@ -86,11 +85,11 @@ export async function sendRequestWithRetry( await sleep(delay); } } - throw 'unreachable'; + throw "unreachable"; } export function sleep(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); } export type RustDocument = vscode.TextDocument & { languageId: "rust" }; @@ -101,12 +100,12 @@ export function isRustDocument(document: vscode.TextDocument): document is RustD // by allowing only `file` schemes // unfortunately extensions that use diff views not always set this // to something different than 'file' (see ongoing bug: #4608) - return document.languageId === 'rust' && document.uri.scheme === 'file'; + return document.languageId === "rust" && document.uri.scheme === "file"; } export function isCargoTomlDocument(document: vscode.TextDocument): document is RustDocument { // ideally `document.languageId` should be 'toml' but user maybe not have toml extension installed - return document.uri.scheme === 'file' && document.fileName.endsWith('Cargo.toml'); + return document.uri.scheme === "file" && document.fileName.endsWith("Cargo.toml"); } export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { @@ -116,9 +115,9 @@ export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { export function isValidExecutable(path: string): boolean { log.debug("Checking availability of a binary at", path); - const res = spawnSync(path, ["--version"], { encoding: 'utf8' }); + 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 && (res.error as any).code !== "ENOENT" ? log.warn : log.debug; printOutput(path, "--version:", res); return res.status === 0; @@ -126,17 +125,19 @@ export function isValidExecutable(path: string): boolean { /** Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts) clause contexts */ export function setContextValue(key: string, value: any): Thenable { - return vscode.commands.executeCommand('setContext', key, value); + return vscode.commands.executeCommand("setContext", key, value); } /** * Returns a higher-order function that caches the results of invoking the * underlying async function. */ -export function memoizeAsync(func: (this: TThis, arg: Param) => Promise) { +export function memoizeAsync( + func: (this: TThis, arg: Param) => Promise +) { const cache = new Map(); - return async function(this: TThis, arg: Param) { + return async function (this: TThis, arg: Param) { const cached = cache.get(arg); if (cached) return cached; diff --git a/editors/code/tests/runTests.ts b/editors/code/tests/runTests.ts index 6172cc7d5f..08632ec3b4 100644 --- a/editors/code/tests/runTests.ts +++ b/editors/code/tests/runTests.ts @@ -1,43 +1,43 @@ -import * as path from 'path'; -import * as fs from 'fs'; +import * as path from "path"; +import * as fs from "fs"; -import { runTests } from '@vscode/test-electron'; +import { runTests } from "@vscode/test-electron"; async function main() { // The folder containing the Extension Manifest package.json // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../../'); + const extensionDevelopmentPath = path.resolve(__dirname, "../../"); // Minimum supported version. - const jsonData = fs.readFileSync(path.join(extensionDevelopmentPath, 'package.json')); + const jsonData = fs.readFileSync(path.join(extensionDevelopmentPath, "package.json")); const json = JSON.parse(jsonData.toString()); let minimalVersion: string = json.engines.vscode; - if (minimalVersion.startsWith('^')) minimalVersion = minimalVersion.slice(1); + if (minimalVersion.startsWith("^")) minimalVersion = minimalVersion.slice(1); const launchArgs = ["--disable-extensions", extensionDevelopmentPath]; // All test suites (either unit tests or integration tests) should be in subfolders. - const extensionTestsPath = path.resolve(__dirname, './unit/index'); + const extensionTestsPath = path.resolve(__dirname, "./unit/index"); // Run tests using the minimal supported version. await runTests({ version: minimalVersion, launchArgs, extensionDevelopmentPath, - extensionTestsPath + extensionTestsPath, }); // and the latest one await runTests({ - version: 'stable', + version: "stable", launchArgs, extensionDevelopmentPath, - extensionTestsPath + extensionTestsPath, }); } -main().catch(err => { +main().catch((err) => { // eslint-disable-next-line no-console - console.error('Failed to run tests', err); + console.error("Failed to run tests", err); process.exit(1); }); diff --git a/editors/code/tests/unit/index.ts b/editors/code/tests/unit/index.ts index 288bd60326..2fa223bed4 100644 --- a/editors/code/tests/unit/index.ts +++ b/editors/code/tests/unit/index.ts @@ -1,5 +1,5 @@ -import { readdir } from 'fs/promises'; -import * as path from 'path'; +import { readdir } from "fs/promises"; +import * as path from "path"; class Test { readonly name: string; @@ -59,7 +59,9 @@ export class Context { export async function run(): Promise { const context = new Context(); - const testFiles = (await readdir(path.resolve(__dirname))).filter(name => name.endsWith('.test.js')); + const testFiles = (await readdir(path.resolve(__dirname))).filter((name) => + name.endsWith(".test.js") + ); for (const testFile of testFiles) { try { const testModule = require(path.resolve(__dirname, testFile)); diff --git a/editors/code/tests/unit/launch_config.test.ts b/editors/code/tests/unit/launch_config.test.ts index aa7a6be269..0531e064d2 100644 --- a/editors/code/tests/unit/launch_config.test.ts +++ b/editors/code/tests/unit/launch_config.test.ts @@ -1,51 +1,98 @@ -import * as assert from 'assert'; -import { Cargo } from '../../src/toolchain'; -import { Context } from '.'; +import * as assert from "assert"; +import { Cargo } from "../../src/toolchain"; +import { Context } from "."; export async function getTests(ctx: Context) { - await ctx.suite('Launch configuration/Lens', suite => { - suite.addTest('A binary', async () => { - const args = Cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "pkg_name"]); + await ctx.suite("Launch configuration/Lens", (suite) => { + suite.addTest("A binary", async () => { + const args = Cargo.artifactSpec([ + "build", + "--package", + "pkg_name", + "--bin", + "pkg_name", + ]); - assert.deepStrictEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]); + assert.deepStrictEqual(args.cargoArgs, [ + "build", + "--package", + "pkg_name", + "--bin", + "pkg_name", + "--message-format=json", + ]); assert.deepStrictEqual(args.filter, undefined); }); - suite.addTest('One of Multiple Binaries', async () => { + suite.addTest("One of Multiple Binaries", async () => { const args = Cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "bin1"]); - assert.deepStrictEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin1", "--message-format=json"]); + assert.deepStrictEqual(args.cargoArgs, [ + "build", + "--package", + "pkg_name", + "--bin", + "bin1", + "--message-format=json", + ]); assert.deepStrictEqual(args.filter, undefined); }); - suite.addTest('A test', async () => { + suite.addTest("A test", async () => { const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib", "--no-run"]); - assert.deepStrictEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--no-run", "--message-format=json"]); + assert.deepStrictEqual(args.cargoArgs, [ + "test", + "--package", + "pkg_name", + "--lib", + "--no-run", + "--message-format=json", + ]); assert.notDeepStrictEqual(args.filter, undefined); }); }); - await ctx.suite('Launch configuration/QuickPick', suite => { - suite.addTest('A binary', async () => { + await ctx.suite("Launch configuration/QuickPick", (suite) => { + suite.addTest("A binary", async () => { const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "pkg_name"]); - assert.deepStrictEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]); + assert.deepStrictEqual(args.cargoArgs, [ + "build", + "--package", + "pkg_name", + "--bin", + "pkg_name", + "--message-format=json", + ]); assert.deepStrictEqual(args.filter, undefined); }); - - suite.addTest('One of Multiple Binaries', async () => { + suite.addTest("One of Multiple Binaries", async () => { const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "bin2"]); - assert.deepStrictEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin2", "--message-format=json"]); + assert.deepStrictEqual(args.cargoArgs, [ + "build", + "--package", + "pkg_name", + "--bin", + "bin2", + "--message-format=json", + ]); assert.deepStrictEqual(args.filter, undefined); }); - suite.addTest('A test', async () => { + suite.addTest("A test", async () => { const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib"]); - assert.deepStrictEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--message-format=json", "--no-run"]); + assert.deepStrictEqual(args.cargoArgs, [ + "test", + "--package", + "pkg_name", + "--lib", + "--message-format=json", + "--no-run", + ]); assert.notDeepStrictEqual(args.filter, undefined); }); }); diff --git a/editors/code/tests/unit/runnable_env.test.ts b/editors/code/tests/unit/runnable_env.test.ts index 085c96da92..b7d59e399d 100644 --- a/editors/code/tests/unit/runnable_env.test.ts +++ b/editors/code/tests/unit/runnable_env.test.ts @@ -1,8 +1,8 @@ -import * as assert from 'assert'; -import { prepareEnv } from '../../src/run'; -import { RunnableEnvCfg } from '../../src/config'; -import { Context } from '.'; -import * as ra from '../../src/lsp_ext'; +import * as assert from "assert"; +import { prepareEnv } from "../../src/run"; +import { RunnableEnvCfg } from "../../src/config"; +import { Context } from "."; +import * as ra from "../../src/lsp_ext"; function makeRunnable(label: string): ra.Runnable { return { @@ -11,8 +11,8 @@ function makeRunnable(label: string): ra.Runnable { args: { cargoArgs: [], executableArgs: [], - cargoExtraArgs: [] - } + cargoExtraArgs: [], + }, }; } @@ -22,20 +22,20 @@ function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record { - suite.addTest('Global config works', async () => { - const binEnv = fakePrepareEnv("run project_name", { "GLOBAL": "g" }); + await ctx.suite("Runnable env", (suite) => { + suite.addTest("Global config works", async () => { + const binEnv = fakePrepareEnv("run project_name", { GLOBAL: "g" }); assert.strictEqual(binEnv["GLOBAL"], "g"); - const testEnv = fakePrepareEnv("test some::mod::test_name", { "GLOBAL": "g" }); + const testEnv = fakePrepareEnv("test some::mod::test_name", { GLOBAL: "g" }); assert.strictEqual(testEnv["GLOBAL"], "g"); }); - suite.addTest('null mask works', async () => { + suite.addTest("null mask works", async () => { const config = [ { - env: { DATA: "data" } - } + env: { DATA: "data" }, + }, ]; const binEnv = fakePrepareEnv("run project_name", config); assert.strictEqual(binEnv["DATA"], "data"); @@ -44,14 +44,14 @@ export async function getTests(ctx: Context) { assert.strictEqual(testEnv["DATA"], "data"); }); - suite.addTest('order works', async () => { + suite.addTest("order works", async () => { const config = [ { - env: { DATA: "data" } + env: { DATA: "data" }, }, { - env: { DATA: "newdata" } - } + env: { DATA: "newdata" }, + }, ]; const binEnv = fakePrepareEnv("run project_name", config); assert.strictEqual(binEnv["DATA"], "newdata"); @@ -60,19 +60,19 @@ export async function getTests(ctx: Context) { assert.strictEqual(testEnv["DATA"], "newdata"); }); - suite.addTest('mask works', async () => { + suite.addTest("mask works", async () => { const config = [ { - env: { DATA: "data" } + env: { DATA: "data" }, }, { mask: "^run", - env: { DATA: "rundata" } + env: { DATA: "rundata" }, }, { mask: "special_test$", - env: { DATA: "special_test" } - } + env: { DATA: "special_test" }, + }, ]; const binEnv = fakePrepareEnv("run project_name", config); assert.strictEqual(binEnv["DATA"], "rundata"); @@ -84,15 +84,15 @@ export async function getTests(ctx: Context) { assert.strictEqual(specialTestEnv["DATA"], "special_test"); }); - suite.addTest('exact test name works', async () => { + suite.addTest("exact test name works", async () => { const config = [ { - env: { DATA: "data" } + env: { DATA: "data" }, }, { mask: "some::mod::test_name", - env: { DATA: "test special" } - } + env: { DATA: "test special" }, + }, ]; const testEnv = fakePrepareEnv("test some::mod::test_name", config); assert.strictEqual(testEnv["DATA"], "test special"); @@ -101,15 +101,15 @@ export async function getTests(ctx: Context) { assert.strictEqual(specialTestEnv["DATA"], "data"); }); - suite.addTest('test mod name works', async () => { + suite.addTest("test mod name works", async () => { const config = [ { - env: { DATA: "data" } + env: { DATA: "data" }, }, { mask: "some::mod", - env: { DATA: "mod special" } - } + env: { DATA: "mod special" }, + }, ]; const testEnv = fakePrepareEnv("test some::mod::test_name", config); assert.strictEqual(testEnv["DATA"], "mod special"); diff --git a/editors/code/tests/unit/settings.test.ts b/editors/code/tests/unit/settings.test.ts index dca4e38d13..224cea5a23 100644 --- a/editors/code/tests/unit/settings.test.ts +++ b/editors/code/tests/unit/settings.test.ts @@ -1,30 +1,30 @@ -import * as assert from 'assert'; -import { Context } from '.'; -import { substituteVariablesInEnv } from '../../src/config'; +import * as assert from "assert"; +import { Context } from "."; +import { substituteVariablesInEnv } from "../../src/config"; export async function getTests(ctx: Context) { - await ctx.suite('Server Env Settings', suite => { - suite.addTest('Replacing Env Variables', async () => { + await ctx.suite("Server Env Settings", (suite) => { + suite.addTest("Replacing Env Variables", async () => { const envJson = { USING_MY_VAR: "${env:MY_VAR} test ${env:MY_VAR}", - MY_VAR: "test" + MY_VAR: "test", }; const expectedEnv = { USING_MY_VAR: "test test test", - MY_VAR: "test" + MY_VAR: "test", }; const actualEnv = await substituteVariablesInEnv(envJson); assert.deepStrictEqual(actualEnv, expectedEnv); }); - suite.addTest('Circular dependencies remain as is', async () => { + suite.addTest("Circular dependencies remain as is", async () => { const envJson = { A_USES_B: "${env:B_USES_A}", B_USES_A: "${env:A_USES_B}", C_USES_ITSELF: "${env:C_USES_ITSELF}", D_USES_C: "${env:C_USES_ITSELF}", E_IS_ISOLATED: "test", - F_USES_E: "${env:E_IS_ISOLATED}" + F_USES_E: "${env:E_IS_ISOLATED}", }; const expectedEnv = { A_USES_B: "${env:B_USES_A}", @@ -32,30 +32,30 @@ export async function getTests(ctx: Context) { C_USES_ITSELF: "${env:C_USES_ITSELF}", D_USES_C: "${env:C_USES_ITSELF}", E_IS_ISOLATED: "test", - F_USES_E: "test" + F_USES_E: "test", }; const actualEnv = await substituteVariablesInEnv(envJson); assert.deepStrictEqual(actualEnv, expectedEnv); }); - suite.addTest('Should support external variables', async () => { + suite.addTest("Should support external variables", async () => { const envJson = { - USING_EXTERNAL_VAR: "${env:TEST_VARIABLE} test ${env:TEST_VARIABLE}" + USING_EXTERNAL_VAR: "${env:TEST_VARIABLE} test ${env:TEST_VARIABLE}", }; const expectedEnv = { - USING_EXTERNAL_VAR: "test test test" + USING_EXTERNAL_VAR: "test test test", }; const actualEnv = await substituteVariablesInEnv(envJson); assert.deepStrictEqual(actualEnv, expectedEnv); }); - suite.addTest('should support VSCode variables', async () => { + suite.addTest("should support VSCode variables", async () => { const envJson = { - USING_VSCODE_VAR: "${workspaceFolderBasename}" + USING_VSCODE_VAR: "${workspaceFolderBasename}", }; const actualEnv = await substituteVariablesInEnv(envJson); - assert.deepStrictEqual(actualEnv.USING_VSCODE_VAR, 'code'); + assert.deepStrictEqual(actualEnv.USING_VSCODE_VAR, "code"); }); }); } diff --git a/editors/code/tsconfig.eslint.json b/editors/code/tsconfig.eslint.json index 9eddf27986..5e2b33ca39 100644 --- a/editors/code/tsconfig.eslint.json +++ b/editors/code/tsconfig.eslint.json @@ -1,11 +1,11 @@ // Special typescript project file, used by eslint only. { - "extends": "./tsconfig.json", - "include": [ - // repeated from base config's "include" setting - "src", - "tests", - // these are the eslint-only inclusions - ".eslintrc.js", - ] + "extends": "./tsconfig.json", + "include": [ + // repeated from base config's "include" setting + "src", + "tests", + // these are the eslint-only inclusions + ".eslintrc.js" + ] } diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json index e2ba2f231a..42e2846858 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json @@ -3,9 +3,7 @@ "module": "commonjs", "target": "es2021", "outDir": "out", - "lib": [ - "es2021" - ], + "lib": ["es2021"], "sourceMap": true, "rootDir": ".", "strict": true, @@ -16,12 +14,6 @@ "noFallthroughCasesInSwitch": true, "newLine": "LF" }, - "exclude": [ - "node_modules", - ".vscode-test" - ], - "include": [ - "src", - "tests" - ] + "exclude": ["node_modules", ".vscode-test"], + "include": ["src", "tests"] } From 1add3e63950a47101aac2b0eb0978a50a1eb2914 Mon Sep 17 00:00:00 2001 From: Andrei Listochkin Date: Tue, 17 May 2022 16:29:01 +0100 Subject: [PATCH 4/6] add prettier format commit to ignored revisions --- .git-blame-ignore-revs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..a302e23781 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,8 @@ +# for this file to take effect make sure you use git ^2.23 and +# add ignoreFile to your git configuration: +# ``` +# git config --global blame.ignoreRevsFile .git-blame-ignore-revs +# ``` + +# prettier format +f247090558c9ba3c551566eae5882b7ca865225f From e0df2c9beed4107f66d185452fdbf0aed9271b8d Mon Sep 17 00:00:00 2001 From: Andrei Listochkin Date: Tue, 17 May 2022 16:33:58 +0100 Subject: [PATCH 5/6] remove tsfmt from dependencies --- editors/code/package-lock.json | 158 +-------------------------------- editors/code/package.json | 1 - 2 files changed, 2 insertions(+), 157 deletions(-) diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index d766f9f1c9..20d3a304f8 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -1,12 +1,12 @@ { "name": "rust-analyzer", - "version": "0.4.0-dev", + "version": "0.5.0-dev", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "rust-analyzer", - "version": "0.4.0-dev", + "version": "0.5.0-dev", "license": "MIT OR Apache-2.0", "dependencies": { "d3": "^7.3.0", @@ -26,7 +26,6 @@ "prettier": "^2.6.2", "tslib": "^2.3.0", "typescript": "^4.6.3", - "typescript-formatter": "^7.2.2", "vsce": "^2.7.0" }, "engines": { @@ -770,12 +769,6 @@ "node": ">= 10" } }, - "node_modules/commandpost": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", - "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", - "dev": true - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1494,52 +1487,6 @@ "readable-stream": "^2.0.2" } }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/editorconfig/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/editorconfig/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/editorconfig/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -3165,12 +3112,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -3441,12 +3382,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -3763,25 +3698,6 @@ "node": ">=4.2.0" } }, - "node_modules/typescript-formatter": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", - "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", - "dev": true, - "dependencies": { - "commandpost": "^1.0.0", - "editorconfig": "^0.15.0" - }, - "bin": { - "tsfmt": "bin/tsfmt" - }, - "engines": { - "node": ">= 4.2.0" - }, - "peerDependencies": { - "typescript": "^2.1.6 || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev" - } - }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -4688,12 +4604,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" }, - "commandpost": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", - "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5236,48 +5146,6 @@ "readable-stream": "^2.0.2" } }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -6434,12 +6302,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -6629,12 +6491,6 @@ "object-inspect": "^1.9.0" } }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -6862,16 +6718,6 @@ "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "dev": true }, - "typescript-formatter": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", - "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", - "dev": true, - "requires": { - "commandpost": "^1.0.0", - "editorconfig": "^0.15.0" - } - }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", diff --git a/editors/code/package.json b/editors/code/package.json index 2cc33a417f..02899b6d17 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -52,7 +52,6 @@ "prettier": "^2.6.2", "tslib": "^2.3.0", "typescript": "^4.6.3", - "typescript-formatter": "^7.2.2", "vsce": "^2.7.0" }, "activationEvents": [ From 00a97272f2fe00c09dd954c21fffb4efebc208af Mon Sep 17 00:00:00 2001 From: Andrei Listochkin Date: Tue, 17 May 2022 18:31:51 +0100 Subject: [PATCH 6/6] automate braceless return substitution for long lines Per [bjorn3][https://github.com/bjorn3] suggestion resolves cases where an early return is moved to a separate line due to line width formatting. This setting changes ``` if (a very long condition) return; ``` to ``` if (a very long condition) { return; } ``` while keeping ``` if (short) return; ``` as is. In pathological cases this may cause `npm run fix` not to fix formatting in one go and may require running it twice. --- editors/code/.eslintrc.js | 1 + editors/code/src/ast_inspector.ts | 3 ++- editors/code/src/snippets.ts | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index 684b5c6bd9..297e9fa1e5 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -14,6 +14,7 @@ module.exports = { rules: { camelcase: ["error"], eqeqeq: ["error", "always", { null: "ignore" }], + curly: ["error", "multi-line"], "no-console": ["error", { allow: ["warn", "error"] }], "prefer-const": "error", "@typescript-eslint/member-delimiter-style": [ diff --git a/editors/code/src/ast_inspector.ts b/editors/code/src/ast_inspector.ts index fca992299e..e57fb20e2c 100644 --- a/editors/code/src/ast_inspector.ts +++ b/editors/code/src/ast_inspector.ts @@ -101,8 +101,9 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv doc: vscode.TextDocument, pos: vscode.Position ): vscode.ProviderResult { - if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) + if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) { return; + } const astEditor = this.findAstTextEditor(); if (!astEditor) return; diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts index 14c2121d08..299d29c27e 100644 --- a/editors/code/src/snippets.ts +++ b/editors/code/src/snippets.ts @@ -11,7 +11,7 @@ export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { } for (const [uri, edits] of edit.entries()) { const editor = await editorFromUri(uri); - if (editor) + if (editor) { await editor.edit((builder) => { for (const indel of edits) { assert( @@ -21,6 +21,7 @@ export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { builder.replace(indel.range, indel.newText); } }); + } } }