From 5a52142eeafd00fcda88f60f9fe0aee8f912c625 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 2 Dec 2024 12:58:43 +0100 Subject: Fix debug configuration querying not inheriting environment --- src/tools/rust-analyzer/editors/code/src/config.ts | 27 ++++- src/tools/rust-analyzer/editors/code/src/debug.ts | 12 +- src/tools/rust-analyzer/editors/code/src/run.ts | 35 ++---- .../editors/code/tests/unit/runnable_env.test.ts | 122 --------------------- 4 files changed, 42 insertions(+), 154 deletions(-) delete mode 100644 src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 67bc72f1e12..f979d545471 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -261,9 +261,9 @@ export class Config { return this.get("testExplorer"); } - get runnablesExtraEnv() { + runnablesExtraEnv(label: string): Record | undefined { const item = this.get("runnables.extraEnv") ?? this.get("runnableEnv"); - if (!item) return item; + if (!item) return undefined; const fixRecord = (r: Record) => { for (const key in r) { if (typeof r[key] !== "string") { @@ -271,11 +271,28 @@ export class Config { } } }; + + const platform = process.platform; + const checkPlatform = (it: RunnableEnvCfgItem) => { + if (it.platform) { + const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; + return platforms.indexOf(platform) >= 0; + } + return true; + }; + if (item instanceof Array) { - item.forEach((x) => fixRecord(x.env)); - } else { - fixRecord(item); + const env = {}; + for (const it of item) { + const masked = !it.mask || new RegExp(it.mask).test(label); + if (masked && checkPlatform(it)) { + Object.assign(env, it.env); + } + } + fixRecord(env); + return env; } + fixRecord(item); return item; } diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts index 9e2e3d2185b..f21ca2e8f96 100644 --- a/src/tools/rust-analyzer/editors/code/src/debug.ts +++ b/src/tools/rust-analyzer/editors/code/src/debug.ts @@ -148,8 +148,16 @@ async function getDebugConfiguration( return path.normalize(p).replace(wsFolder, `\${workspaceFolder${workspaceQualifier}}`); } - const env = prepareEnv(inheritEnv, runnable.label, runnableArgs, config.runnablesExtraEnv); - const executable = await getDebugExecutable(runnableArgs, env); + const executable = await getDebugExecutable( + runnableArgs, + prepareEnv(true, {}, config.runnablesExtraEnv(runnable.label)), + ); + + const env = prepareEnv( + inheritEnv, + runnableArgs.environment, + config.runnablesExtraEnv(runnable.label), + ); let sourceFileMap = debugOptions.sourceFileMap; if (sourceFileMap === "auto") { diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index 8a82a5a58cf..f71ab7ffbd8 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -5,7 +5,7 @@ import * as tasks from "./tasks"; import type { CtxInit } from "./ctx"; import { makeDebugConfig } from "./debug"; -import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config"; +import type { Config } from "./config"; import type { LanguageClient } from "vscode-languageclient/node"; import { unwrapUndefinable, type RustEditor } from "./util"; @@ -81,32 +81,13 @@ export function prepareBaseEnv( export function prepareEnv( inheritEnv: boolean, - label: string, - runnableArgs: ra.CargoRunnableArgs, - runnableEnvCfg?: RunnableEnvCfg, + runnableEnv?: Record, + runnableEnvCfg?: Record, ): Record { - const env = prepareBaseEnv(inheritEnv, runnableArgs.environment); - const platform = process.platform; - - const checkPlatform = (it: RunnableEnvCfgItem) => { - if (it.platform) { - const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; - return platforms.indexOf(platform) >= 0; - } - return true; - }; + const env = prepareBaseEnv(inheritEnv, runnableEnv); if (runnableEnvCfg) { - if (Array.isArray(runnableEnvCfg)) { - for (const it of runnableEnvCfg) { - const masked = !it.mask || new RegExp(it.mask).test(label); - if (masked && checkPlatform(it)) { - Object.assign(env, it.env); - } - } - } else { - Object.assign(env, runnableEnvCfg); - } + Object.assign(env, runnableEnvCfg); } return env; @@ -140,7 +121,11 @@ export async function createTaskFromRunnable( }; options = { cwd: runnableArgs.workspaceRoot || ".", - env: prepareEnv(true, runnable.label, runnableArgs, config.runnablesExtraEnv), + env: prepareEnv( + true, + runnableArgs.environment, + config.runnablesExtraEnv(runnable.label), + ), }; } else { const runnableArgs = runnable.args; diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts deleted file mode 100644 index f0a62a3cce2..00000000000 --- a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as assert from "assert"; -import { prepareEnv } from "../../src/run"; -import type { RunnableEnvCfg } from "../../src/config"; -import type { Context } from "."; -import type * as ra from "../../src/lsp_ext"; - -function makeRunnable(label: string): ra.Runnable { - return { - label, - kind: "cargo", - args: { - cargoArgs: [], - cwd: ".", - executableArgs: [], - }, - }; -} - -function fakePrepareEnv(runnableName: string, config?: RunnableEnvCfg): Record { - const runnable = makeRunnable(runnableName); - const runnableArgs = runnable.args as ra.CargoRunnableArgs; - return prepareEnv(false, runnable.label, runnableArgs, config); -} - -export async function getTests(ctx: Context) { - 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" }); - assert.strictEqual(testEnv["GLOBAL"], "g"); - }); - - suite.addTest("null mask works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "data"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "data"); - }); - - suite.addTest("order works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - env: { DATA: "newdata" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "newdata"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "newdata"); - }); - - suite.addTest("mask works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "^run", - env: { DATA: "rundata" }, - }, - { - mask: "special_test$", - env: { DATA: "special_test" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "rundata"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "data"); - - const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config); - assert.strictEqual(specialTestEnv["DATA"], "special_test"); - }); - - suite.addTest("exact test name works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "some::mod::test_name", - env: { DATA: "test special" }, - }, - ]; - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "test special"); - - const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); - assert.strictEqual(specialTestEnv["DATA"], "data"); - }); - - suite.addTest("test mod name works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "some::mod", - env: { DATA: "mod special" }, - }, - ]; - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "mod special"); - - const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); - assert.strictEqual(specialTestEnv["DATA"], "mod special"); - }); - }); -} -- cgit 1.4.1-3-g733a5 From 97feb0334493d870e09f7a5a02c6d320a7e8a4ae Mon Sep 17 00:00:00 2001 From: David Richey Date: Tue, 3 Dec 2024 14:14:53 +0000 Subject: Only show status bar item in relevant files --- src/tools/rust-analyzer/editors/code/package.json | 35 ++++++++++++++++++++++ src/tools/rust-analyzer/editors/code/src/config.ts | 4 +++ src/tools/rust-analyzer/editors/code/src/ctx.ts | 18 ++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 82c43b76fdd..46f7803c8a8 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -425,6 +425,41 @@ ], "default": "openLogs", "markdownDescription": "Action to run when clicking the extension status bar item." + }, + "rust-analyzer.statusBar.documentSelector": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "language": { + "type": [ + "string", + "null" + ] + }, + "pattern": { + "type": [ + "string", + "null" + ] + } + } + }, + "default": [ + { + "language": "rust" + }, + { + "pattern": "**/Cargo.toml" + }, + { + "pattern": "**/Cargo.lock" + } + ], + "markdownDescription": "Determines when to show the extension status bar item based on the currently open file. Use `{ \"pattern\": \"**\" }` to always show. Use `null` to never show." } } }, diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index f979d545471..f7ef80df2ba 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -348,6 +348,10 @@ export class Config { return this.get("statusBar.clickAction"); } + get statusBarDocumentSelector() { + return this.get("statusBar.documentSelector"); + } + get initializeStopped() { return this.get("initializeStopped"); } diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 234fe6ab024..4a3f66b00d0 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -88,6 +88,7 @@ export class Ctx implements RustAnalyzerExtensionApi { private _treeView: vscode.TreeView | undefined; private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" }; private _serverVersion: string; + private statusBarActiveEditorListener: Disposable; get serverPath(): string | undefined { return this._serverPath; @@ -119,6 +120,10 @@ export class Ctx implements RustAnalyzerExtensionApi { this._serverVersion = ""; this.config = new Config(extCtx.subscriptions); this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + this.updateStatusBarVisibility(vscode.window.activeTextEditor); + this.statusBarActiveEditorListener = vscode.window.onDidChangeActiveTextEditor((editor) => + this.updateStatusBarVisibility(editor), + ); if (this.config.testExplorer) { this.testController = vscode.tests.createTestController( "rustAnalyzerTestController", @@ -141,6 +146,7 @@ export class Ctx implements RustAnalyzerExtensionApi { dispose() { this.config.dispose(); this.statusBar.dispose(); + this.statusBarActiveEditorListener.dispose(); this.testController?.dispose(); void this.disposeClient(); this.commandDisposables.forEach((disposable) => disposable.dispose()); @@ -404,7 +410,6 @@ export class Ctx implements RustAnalyzerExtensionApi { let icon = ""; const status = this.lastStatus; const statusBar = this.statusBar; - statusBar.show(); statusBar.tooltip = new vscode.MarkdownString("", true); statusBar.tooltip.isTrusted = true; switch (status.health) { @@ -472,6 +477,17 @@ export class Ctx implements RustAnalyzerExtensionApi { statusBar.text = `${icon}rust-analyzer`; } + private updateStatusBarVisibility(editor: vscode.TextEditor | undefined) { + const documentSelector = this.config.statusBarDocumentSelector; + if (documentSelector != null) { + if (editor != null && vscode.languages.match(documentSelector, editor.document) > 0) { + this.statusBar.show(); + return; + } + } + this.statusBar.hide(); + } + pushExtCleanup(d: Disposable) { this.extCtx.subscriptions.push(d); } -- cgit 1.4.1-3-g733a5 From b94c5355b207568b4c66852e46f823437455dcf4 Mon Sep 17 00:00:00 2001 From: Tarek Date: Sun, 17 Nov 2024 15:25:23 +0200 Subject: internal: Make exclude characters for typing assists configurable, default to None Signed-off-by: Tarek --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 6 ++++++ src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 6 ++++++ .../crates/rust-analyzer/src/handlers/request.rs | 9 +++++++-- src/tools/rust-analyzer/docs/user/generated_config.adoc | 5 +++++ src/tools/rust-analyzer/editors/code/package.json | 13 +++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index d4ef9570e1a..b4f3de3b178 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -411,6 +411,7 @@ impl Analysis { position: FilePosition, char_typed: char, autoclose: bool, + chars_to_exclude: Option, ) -> Cancellable> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { @@ -419,6 +420,11 @@ impl Analysis { if char_typed == '<' && !autoclose { return Ok(None); } + if let Some(chars_to_exclude) = chars_to_exclude { + if chars_to_exclude.contains(char_typed) { + return Ok(None); + } + } self.with_db(|db| typing::on_char_typed(db, position, char_typed)) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 152ce2944a0..c2d6196ca41 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -310,6 +310,8 @@ config_data! { /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. typing_autoClosingAngleBrackets_enable: bool = false, + /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. + typing_excludeChars: Option = None, /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. @@ -2160,6 +2162,10 @@ impl Config { *self.typing_autoClosingAngleBrackets_enable() } + pub fn typing_exclude_chars(&self) -> Option { + self.typing_excludeChars().clone() + } + // VSCode is our reference implementation, so we allow ourselves to work around issues by // special casing certain versions pub fn visual_studio_code_version(&self) -> Option<&Version> { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 4975467ece9..29820a3e37e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -459,9 +459,14 @@ pub(crate) fn handle_on_type_formatting( if char_typed == '>' { return Ok(None); } + let chars_to_exclude = snap.config.typing_exclude_chars(); - let edit = - snap.analysis.on_char_typed(position, char_typed, snap.config.typing_autoclose_angle())?; + let edit = snap.analysis.on_char_typed( + position, + char_typed, + snap.config.typing_autoclose_angle(), + chars_to_exclude, + )?; let edit = match edit { Some(it) => it, None => return Ok(None), diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 052d0a2a41d..d0c95912c3d 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -997,6 +997,11 @@ Show documentation. -- Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. -- +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: ++ +-- +Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. +-- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 46f7803c8a8..e98205e0eab 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2612,6 +2612,19 @@ } } }, + { + "title": "typing", + "properties": { + "rust-analyzer.typing.excludeChars": { + "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", + "default": null, + "type": [ + "null", + "string" + ] + } + } + }, { "title": "workspace", "properties": { -- cgit 1.4.1-3-g733a5 From 68cd57940a2f82ab1bdbc0c799ffecc095c03f88 Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 3 Dec 2024 22:38:21 +0200 Subject: chore: deprecate `typing.autoClosingAngleBrackets` configuration Signed-off-by: Tarek --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 4 ---- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 6 ------ .../rust-analyzer/crates/rust-analyzer/src/handlers/request.rs | 7 +------ src/tools/rust-analyzer/docs/user/generated_config.adoc | 5 ----- src/tools/rust-analyzer/editors/code/package.json | 10 ---------- 5 files changed, 1 insertion(+), 31 deletions(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index b4f3de3b178..b43685ffeed 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -410,16 +410,12 @@ impl Analysis { &self, position: FilePosition, char_typed: char, - autoclose: bool, chars_to_exclude: Option, ) -> Cancellable> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { return Ok(None); } - if char_typed == '<' && !autoclose { - return Ok(None); - } if let Some(chars_to_exclude) = chars_to_exclude { if chars_to_exclude.contains(char_typed) { return Ok(None); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index c2d6196ca41..392bfbf15fe 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -308,8 +308,6 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. - typing_autoClosingAngleBrackets_enable: bool = false, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. typing_excludeChars: Option = None, @@ -2158,10 +2156,6 @@ impl Config { } } - pub fn typing_autoclose_angle(&self) -> bool { - *self.typing_autoClosingAngleBrackets_enable() - } - pub fn typing_exclude_chars(&self) -> Option { self.typing_excludeChars().clone() } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 29820a3e37e..0fadfa6c420 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -461,12 +461,7 @@ pub(crate) fn handle_on_type_formatting( } let chars_to_exclude = snap.config.typing_exclude_chars(); - let edit = snap.analysis.on_char_typed( - position, - char_typed, - snap.config.typing_autoclose_angle(), - chars_to_exclude, - )?; + let edit = snap.analysis.on_char_typed(position, char_typed, chars_to_exclude)?; let edit = match edit { Some(it) => it, None => return Ok(None), diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index d0c95912c3d..a3172c7ca2c 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,11 +992,6 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.autoClosingAngleBrackets.enable]]rust-analyzer.typing.autoClosingAngleBrackets.enable (default: `false`):: -+ --- -Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. --- [[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index e98205e0eab..68c61e4bf62 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2602,16 +2602,6 @@ } } }, - { - "title": "typing", - "properties": { - "rust-analyzer.typing.autoClosingAngleBrackets.enable": { - "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.", - "default": false, - "type": "boolean" - } - } - }, { "title": "typing", "properties": { -- cgit 1.4.1-3-g733a5 From a9afc99c1347eacdb9495ffa2601bb032997f2ae Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 09:44:17 +0100 Subject: Disable `<` typing handler again --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- src/tools/rust-analyzer/docs/user/generated_config.adoc | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 392bfbf15fe..aa9f919679d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -309,7 +309,7 @@ config_data! { signatureInfo_documentation_enable: bool = true, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = None, + typing_excludeChars: Option = Some("<".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index a3172c7ca2c..96a2a5a27d3 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: + -- Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 68c61e4bf62..7529651ca7a 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2607,7 +2607,7 @@ "properties": { "rust-analyzer.typing.excludeChars": { "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": null, + "default": "<", "type": [ "null", "string" -- cgit 1.4.1-3-g733a5 From 069fb0f475c6e7398e4ef75c3f765415197707aa Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 4 Nov 2024 11:03:36 +0100 Subject: Make bracket typing handler work on more things --- src/tools/rust-analyzer/crates/ide/src/typing.rs | 321 +++++++++++++-------- .../crates/rust-analyzer/src/config.rs | 2 +- .../rust-analyzer/docs/user/generated_config.adoc | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- src/tools/rust-analyzer/editors/code/src/client.ts | 2 +- 5 files changed, 199 insertions(+), 130 deletions(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index 9bb5de9f2e3..5840719ff68 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -16,11 +16,11 @@ mod on_enter; use ide_db::{base_db::SourceDatabase, FilePosition, RootDatabase}; -use span::EditionedFileId; +use span::{Edition, EditionedFileId}; use syntax::{ algo::{ancestors_at_offset, find_node_at_offset}, ast::{self, edit::IndentLevel, AstToken}, - AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T, + AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, }; use ide_db::text_edit::TextEdit; @@ -47,6 +47,7 @@ struct ExtendedTextEdit { // - typing `.` in a chain method call auto-indents // - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression // - typing `{` in a use item adds a closing `}` in the right place +// - typing `>` to complete a return type `->` will insert a whitespace after it // // VS Code:: // @@ -66,55 +67,65 @@ pub(crate) fn on_char_typed( if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { return None; } - let file = &db.parse(EditionedFileId::current_edition(position.file_id)); - if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) { + // FIXME: We need to figure out the edition of the file here, but that means hitting the + // database for more than just parsing the file which is bad. + // FIXME: We are hitting the database here, if we are unlucky this call might block momentarily + // causing the editor to feel sluggish! + let edition = Edition::CURRENT_FIXME; + let file = &db.parse(EditionedFileId::new(position.file_id, edition)); + let char_matches_position = + file.tree().syntax().text().char_at(position.offset) == Some(char_typed); + if !stdx::always!(char_matches_position) { return None; } - let edit = on_char_typed_inner(file, position.offset, char_typed)?; + + let edit = on_char_typed_(file, position.offset, char_typed, edition)?; + let mut sc = SourceChange::from_text_edit(position.file_id, edit.edit); sc.is_snippet = edit.is_snippet; Some(sc) } -fn on_char_typed_inner( +fn on_char_typed_( file: &Parse, offset: TextSize, char_typed: char, + edition: Edition, ) -> Option { - if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { - return None; - } - let conv = |text_edit: Option| { - Some(ExtendedTextEdit { edit: text_edit?, is_snippet: false }) - }; match char_typed { - '.' => conv(on_dot_typed(&file.tree(), offset)), - '=' => conv(on_eq_typed(&file.tree(), offset)), - '<' => on_left_angle_typed(&file.tree(), offset), - '>' => conv(on_right_angle_typed(&file.tree(), offset)), - '{' => conv(on_opening_bracket_typed(file, offset, '{')), - '(' => conv(on_opening_bracket_typed(file, offset, '(')), + '.' => on_dot_typed(&file.tree(), offset), + '=' => on_eq_typed(&file.tree(), offset), + '>' => on_right_angle_typed(&file.tree(), offset), + '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition), _ => None, } + .map(conv) +} + +fn conv(edit: TextEdit) -> ExtendedTextEdit { + ExtendedTextEdit { edit, is_snippet: false } } -/// Inserts a closing bracket when the user types an opening bracket, wrapping an existing expression in a +/// Inserts a closing delimiter when the user types an opening bracket, wrapping an existing expression in a /// block, or a part of a `use` item (for `{`). -fn on_opening_bracket_typed( +fn on_opening_delimiter_typed( file: &Parse, offset: TextSize, opening_bracket: char, + edition: Edition, ) -> Option { - let (closing_bracket, expected_ast_bracket) = match opening_bracket { - '{' => ('}', SyntaxKind::L_CURLY), - '(' => (')', SyntaxKind::L_PAREN), + type FilterFn = fn(SyntaxKind) -> bool; + let (closing_bracket, expected_ast_bracket, allowed_kinds) = match opening_bracket { + '{' => ('}', SyntaxKind::L_CURLY, &[ast::Expr::can_cast as FilterFn] as &[FilterFn]), + '(' => ( + ')', + SyntaxKind::L_PAREN, + &[ast::Expr::can_cast, ast::Pat::can_cast, ast::Type::can_cast] as &[FilterFn], + ), + '<' => ('>', SyntaxKind::L_ANGLE, &[ast::Type::can_cast as FilterFn] as &[FilterFn]), _ => return None, }; - if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some(opening_bracket)) { - return None; - } - let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; if brace_token.kind() != expected_ast_bracket { return None; @@ -125,58 +136,53 @@ fn on_opening_bracket_typed( if !stdx::always!(range.len() == TextSize::of(opening_bracket)) { return None; } - // FIXME: Edition - let file = file.reparse(range, "", span::Edition::CURRENT_FIXME); + let reparsed = file.reparse(range, "", edition).tree(); - if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) { + if let Some(edit) = + on_delimited_node_typed(&reparsed, offset, opening_bracket, closing_bracket, allowed_kinds) + { return Some(edit); } - if closing_bracket == '}' { - if let Some(edit) = brace_use_path(&file.tree(), offset) { - return Some(edit); - } + match opening_bracket { + '{' => on_left_brace_typed(&reparsed, offset), + '<' => on_left_angle_typed(&file.tree(), &reparsed, offset), + _ => None, } +} - return None; - - fn brace_use_path(file: &SourceFile, offset: TextSize) -> Option { - let segment: ast::PathSegment = find_node_at_offset(file.syntax(), offset)?; - if segment.syntax().text_range().start() != offset { - return None; - } - - let tree: ast::UseTree = find_node_at_offset(file.syntax(), offset)?; - - Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned())) +fn on_left_brace_typed(reparsed: &SourceFile, offset: TextSize) -> Option { + let segment: ast::PathSegment = find_node_at_offset(reparsed.syntax(), offset)?; + if segment.syntax().text_range().start() != offset { + return None; } - fn bracket_expr( - file: &SourceFile, - offset: TextSize, - opening_bracket: char, - closing_bracket: char, - ) -> Option { - let mut expr: ast::Expr = find_node_at_offset(file.syntax(), offset)?; - if expr.syntax().text_range().start() != offset { - return None; - } - - // Enclose the outermost expression starting at `offset` - while let Some(parent) = expr.syntax().parent() { - if parent.text_range().start() != expr.syntax().text_range().start() { - break; - } + let tree: ast::UseTree = find_node_at_offset(reparsed.syntax(), offset)?; - match ast::Expr::cast(parent) { - Some(parent) => expr = parent, - None => break, - } - } + Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned())) +} - if let Some(parent) = expr.syntax().parent().and_then(ast::Expr::cast) { - let mut node = expr.syntax().clone(); - let all_prev_sib_attr = loop { +fn on_delimited_node_typed( + reparsed: &SourceFile, + offset: TextSize, + opening_bracket: char, + closing_bracket: char, + kinds: &[fn(SyntaxKind) -> bool], +) -> Option { + let t = reparsed.syntax().token_at_offset(offset).right_biased()?; + let (filter, node) = t + .parent_ancestors() + .take_while(|n| n.text_range().start() == offset) + .find_map(|n| kinds.iter().find(|&kind_filter| kind_filter(n.kind())).zip(Some(n)))?; + let mut node = node + .ancestors() + .take_while(|n| n.text_range().start() == offset && filter(n.kind())) + .last()?; + + if let Some(parent) = node.parent().filter(|it| filter(it.kind())) { + let all_prev_sib_attr = { + let mut node = node.clone(); + loop { match node.prev_sibling() { Some(sib) if sib.kind().is_trivia() || sib.kind() == SyntaxKind::ATTR => { node = sib @@ -184,21 +190,20 @@ fn on_opening_bracket_typed( Some(_) => break false, None => break true, }; - }; - - if all_prev_sib_attr { - expr = parent; } - } + }; - // Insert the closing bracket right after the expression. - Some(TextEdit::insert( - expr.syntax().text_range().end() + TextSize::of(opening_bracket), - closing_bracket.to_string(), - )) + if all_prev_sib_attr { + node = parent; + } } -} + // Insert the closing bracket right after the node. + Some(TextEdit::insert( + node.text_range().end() + TextSize::of(opening_bracket), + closing_bracket.to_string(), + )) +} /// Returns an edit which should be applied after `=` was typed. Primarily, /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. @@ -342,14 +347,15 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { } /// Add closing `>` for generic arguments/parameters. -fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option { - let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('<')) { - return None; - } +fn on_left_angle_typed( + file: &SourceFile, + reparsed: &SourceFile, + offset: TextSize, +) -> Option { + let file_text = reparsed.syntax().text(); - // Find the next non-whitespace char in the line. - let mut next_offset = offset + TextSize::of('<'); + // Find the next non-whitespace char in the line, check if its a `>` + let mut next_offset = offset; while file_text.char_at(next_offset) == Some(' ') { next_offset += TextSize::of(' ') } @@ -357,23 +363,14 @@ fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option".to_owned()), - is_snippet: true, - }); - } - } - - if ancestors_at_offset(file.syntax(), offset).any(|n| { - ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) - }) { - Some(ExtendedTextEdit { - edit: TextEdit::replace(range, "<$0>".to_owned()), - is_snippet: true, + if ancestors_at_offset(file.syntax(), offset) + .take_while(|n| !ast::Item::can_cast(n.kind())) + .any(|n| { + ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) }) + { + // Insert the closing bracket right after + Some(TextEdit::insert(offset + TextSize::of('<'), '>'.to_string())) } else { None } @@ -411,7 +408,7 @@ mod tests { let edit = TextEdit::insert(offset, char_typed.to_string()); edit.apply(&mut before); let parse = SourceFile::parse(&before, span::Edition::CURRENT_FIXME); - on_char_typed_inner(&parse, offset, char_typed).map(|it| { + on_char_typed_(&parse, offset, char_typed, span::Edition::CURRENT_FIXME).map(|it| { it.apply(&mut before); before.to_string() }) @@ -426,7 +423,7 @@ mod tests { fn type_char_noop(char_typed: char, ra_fixture_before: &str) { let file_change = do_type_char(char_typed, ra_fixture_before); - assert!(file_change.is_none()) + assert_eq!(file_change, None) } #[test] @@ -1066,6 +1063,81 @@ fn f() { ); } + #[test] + fn adds_closing_parenthesis_for_pat() { + type_char( + '(', + r#" +fn f() { match () { $0() => () } } +"#, + r#" +fn f() { match () { (()) => () } } +"#, + ); + type_char( + '(', + r#" +fn f($0n: ()) {} +"#, + r#" +fn f((n): ()) {} +"#, + ); + } + + #[test] + fn adds_closing_parenthesis_for_ty() { + type_char( + '(', + r#" +fn f(n: $0()) {} +"#, + r#" +fn f(n: (())) {} +"#, + ); + type_char( + '(', + r#" +fn f(n: $0a::b::::c) {} +"#, + r#" +fn f(n: (a::b::::c)) {} +"#, + ); + } + + #[test] + fn adds_closing_angles_for_ty() { + type_char( + '<', + r#" +fn f(n: $0()) {} +"#, + r#" +fn f(n: <()>) {} +"#, + ); + type_char( + '<', + r#" +fn f(n: $0a::b::::c) {} +"#, + r#" +fn f(n: ::c>) {} +"#, + ); + type_char( + '<', + r#" +fn f(n: a$0b::::c) {} +"#, + r#" +fn f(n: a<>b::::c) {} +"#, + ); + } + #[test] fn parenthesis_noop_in_string_literal() { // Regression test for #9351 @@ -1154,6 +1226,12 @@ use $0Thing as _; type_char_noop( '(', r#" +use some::pa$0th::to::Item; + "#, + ); + type_char_noop( + '<', + r#" use some::pa$0th::to::Item; "#, ); @@ -1170,7 +1248,7 @@ fn foo() { "#, r#" fn foo() { - bar::<$0> + bar::<> } "#, ); @@ -1184,7 +1262,7 @@ fn foo(bar: &[u64]) { "#, r#" fn foo(bar: &[u64]) { - bar.iter().collect::<$0>(); + bar.iter().collect::<>(); } "#, ); @@ -1198,7 +1276,7 @@ fn foo(bar: &[u64]) { fn foo$0() {} "#, r#" -fn foo<$0>() {} +fn foo<>() {} "#, ); type_char( @@ -1207,7 +1285,7 @@ fn foo<$0>() {} fn foo$0 "#, r#" -fn foo<$0> +fn foo<> "#, ); type_char( @@ -1216,7 +1294,7 @@ fn foo<$0> struct Foo$0 {} "#, r#" -struct Foo<$0> {} +struct Foo<> {} "#, ); type_char( @@ -1225,7 +1303,7 @@ struct Foo<$0> {} struct Foo$0(); "#, r#" -struct Foo<$0>(); +struct Foo<>(); "#, ); type_char( @@ -1234,7 +1312,7 @@ struct Foo<$0>(); struct Foo$0 "#, r#" -struct Foo<$0> +struct Foo<> "#, ); type_char( @@ -1243,7 +1321,7 @@ struct Foo<$0> enum Foo$0 "#, r#" -enum Foo<$0> +enum Foo<> "#, ); type_char( @@ -1252,7 +1330,7 @@ enum Foo<$0> trait Foo$0 "#, r#" -trait Foo<$0> +trait Foo<> "#, ); type_char( @@ -1261,16 +1339,7 @@ trait Foo<$0> type Foo$0 = Bar; "#, r#" -type Foo<$0> = Bar; - "#, - ); - type_char( - '<', - r#" -impl$0 Foo {} - "#, - r#" -impl<$0> Foo {} +type Foo<> = Bar; "#, ); type_char( @@ -1279,7 +1348,7 @@ impl<$0> Foo {} impl Foo$0 {} "#, r#" -impl Foo<$0> {} +impl Foo<> {} "#, ); type_char( @@ -1288,7 +1357,7 @@ impl Foo<$0> {} impl Foo$0 {} "#, r#" -impl Foo<$0> {} +impl Foo<> {} "#, ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index aa9f919679d..392bfbf15fe 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -309,7 +309,7 @@ config_data! { signatureInfo_documentation_enable: bool = true, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = Some("<".to_owned()), + typing_excludeChars: Option = None, /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 96a2a5a27d3..a3172c7ca2c 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: + -- Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 7529651ca7a..68c61e4bf62 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2607,7 +2607,7 @@ "properties": { "rust-analyzer.typing.excludeChars": { "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": "<", + "default": null, "type": [ "null", "string" diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index eac7b849fdb..4ce19f5c665 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -324,7 +324,7 @@ class ExperimentalFeatures implements lc.StaticFeature { } fillClientCapabilities(capabilities: lc.ClientCapabilities): void { capabilities.experimental = { - snippetTextEdit: true, + snippetTextEdit: false, codeActionGroup: true, hoverActions: true, serverStatusNotification: true, -- cgit 1.4.1-3-g733a5 From 3fe75c7d90e9e42dbbc7c6542337a68ff9b817cf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 15:35:13 +0100 Subject: Add typing handler for param list pipe --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 2 + src/tools/rust-analyzer/crates/ide/src/typing.rs | 67 ++++++++++++++++++---- .../crates/rust-analyzer/src/config.rs | 4 +- .../crates/rust-analyzer/src/lsp/capabilities.rs | 17 ++---- .../rust-analyzer/docs/user/generated_config.adoc | 4 +- src/tools/rust-analyzer/editors/code/package.json | 4 +- 6 files changed, 69 insertions(+), 29 deletions(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index b43685ffeed..c960b88a3e9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -402,6 +402,8 @@ impl Analysis { self.with_db(|db| typing::on_enter(db, position)) } + pub const SUPPORTED_TRIGGER_CHARS: &'static str = typing::TRIGGER_CHARS; + /// Returns an edit which should be applied after a character was typed. /// /// This is useful for some on-the-fly fixups, like adding `;` to `let =` diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index cfa1d6ff031..3d9146cc4c7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -32,7 +32,7 @@ use crate::SourceChange; pub(crate) use on_enter::on_enter; // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. -pub(crate) const TRIGGER_CHARS: &str = ".=<>{("; +pub(crate) const TRIGGER_CHARS: &str = ".=<>{(|"; struct ExtendedTextEdit { edit: TextEdit, @@ -99,6 +99,7 @@ fn on_char_typed_( '=' => on_eq_typed(&file.tree(), offset), '>' => on_right_angle_typed(&file.tree(), offset), '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition), + '|' => on_pipe_typed(&file.tree(), offset), _ => None, } .map(conv) @@ -212,10 +213,6 @@ fn on_delimited_node_typed( // FIXME: use a snippet completion instead of this hack here. fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { let text = file.syntax().text(); - if !stdx::always!(text.char_at(offset) == Some('=')) { - return None; - } - let has_newline = iter::successors(Some(offset), |&offset| Some(offset + TextSize::new(1))) .filter_map(|offset| text.char_at(offset)) .find(|&c| !c.is_whitespace() || c == '\n') @@ -308,9 +305,6 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) { - return None; - } let whitespace = file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; @@ -380,7 +374,9 @@ fn on_left_angle_typed( if ancestors_at_offset(file.syntax(), offset) .take_while(|n| !ast::Item::can_cast(n.kind())) .any(|n| { - ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) + ast::GenericParamList::can_cast(n.kind()) + || ast::GenericArgList::can_cast(n.kind()) + || ast::UseBoundGenericArgs::can_cast(n.kind()) }) { // Insert the closing bracket right after @@ -390,12 +386,21 @@ fn on_left_angle_typed( } } +fn on_pipe_typed(file: &SourceFile, offset: TextSize) -> Option { + let pipe_token = file.syntax().token_at_offset(offset).right_biased()?; + if pipe_token.kind() != SyntaxKind::PIPE { + return None; + } + if pipe_token.parent().and_then(ast::ParamList::cast)?.r_paren_token().is_some() { + return None; + } + let after_lpipe = offset + TextSize::of('|'); + Some(TextEdit::insert(after_lpipe, "|".to_owned())) +} + /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option { let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('>')) { - return None; - } let after_arrow = offset + TextSize::of('>'); if file_text.char_at(after_arrow) != Some('{') { return None; @@ -1527,6 +1532,44 @@ fn foo() { ) $0 } +"#, + ); + } + + #[test] + fn completes_pipe_param_list() { + type_char( + '|', + r#" +fn foo() { + $0 +} +"#, + r#" +fn foo() { + || +} +"#, + ); + type_char( + '|', + r#" +fn foo() { + $0 a +} +"#, + r#" +fn foo() { + || a +} +"#, + ); + type_char_noop( + '|', + r#" +fn foo() { + let $0 +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 392bfbf15fe..0fdc48a0e7a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -308,8 +308,8 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = None, + /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. + typing_excludeChars: Option = Some('<'.to_string()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index bd496e8ddc3..82e6ae2b49c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -72,9 +72,12 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)), _ => Some(OneOf::Left(false)), }, - document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { - first_trigger_character: "=".to_owned(), - more_trigger_character: Some(more_trigger_character(config)), + document_on_type_formatting_provider: Some({ + let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.chars(); + DocumentOnTypeFormattingOptions { + first_trigger_character: chars.next().unwrap().to_string(), + more_trigger_character: Some(chars.map(|c| c.to_string()).collect()), + } }), selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), @@ -528,11 +531,3 @@ impl ClientCapabilities { .unwrap_or_default() } } - -fn more_trigger_character(config: &Config) -> Vec { - let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()]; - if config.snippet_cap().is_some() { - res.push("<".to_owned()); - } - res -} diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index a3172c7ca2c..715f8d43adc 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,10 +992,10 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: + -- -Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. +Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. -- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 68c61e4bf62..70d26c97078 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2606,8 +2606,8 @@ "title": "typing", "properties": { "rust-analyzer.typing.excludeChars": { - "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": null, + "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.", + "default": "<", "type": [ "null", "string" -- cgit 1.4.1-3-g733a5 From 2ad6d7103cab511a72706c7fb2a06d8c4fe62c4e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 9 Dec 2024 15:52:04 +0100 Subject: Disable pipe on typing handler --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- src/tools/rust-analyzer/docs/user/generated_config.adoc | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index dd7351bcf26..fd4c8d0e687 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -309,7 +309,7 @@ config_data! { signatureInfo_documentation_enable: bool = true, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. - typing_excludeChars: Option = Some('<'.to_string()), + typing_excludeChars: Option = Some("|<".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 715f8d43adc..1195a85cf70 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"|<"`):: + -- Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 70d26c97078..469c1b458d5 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2607,7 +2607,7 @@ "properties": { "rust-analyzer.typing.excludeChars": { "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.", - "default": "<", + "default": "|<", "type": [ "null", "string" -- cgit 1.4.1-3-g733a5