Unnamed repository; edit this file 'description' to name the repository.
feat: support UpdateTest in codelens
roife 2024-12-26
parent dd78825 · commit edb61b1
-rw-r--r--crates/ide/src/annotations.rs68
-rw-r--r--crates/ide/src/hover/tests.rs52
-rw-r--r--crates/rust-analyzer/src/config.rs10
-rw-r--r--crates/rust-analyzer/src/lsp/ext.rs12
-rw-r--r--crates/rust-analyzer/src/lsp/to_proto.rs38
-rw-r--r--docs/dev/lsp-extensions.md2
-rw-r--r--docs/user/generated_config.adoc6
-rw-r--r--editors/code/package.json15
-rw-r--r--editors/code/src/client.ts17
-rw-r--r--editors/code/src/commands.ts26
-rw-r--r--editors/code/src/config.ts7
-rw-r--r--editors/code/src/main.ts8
12 files changed, 204 insertions, 57 deletions
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index 121a463c9f..6a4e5ba290 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -316,6 +316,11 @@ fn main() {
},
kind: Bin,
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
},
@@ -401,6 +406,11 @@ fn main() {
},
kind: Bin,
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
},
@@ -537,6 +547,11 @@ fn main() {
},
kind: Bin,
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
},
@@ -597,6 +612,11 @@ fn main() {}
},
kind: Bin,
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
},
@@ -709,6 +729,11 @@ fn main() {
},
kind: Bin,
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
},
@@ -746,6 +771,20 @@ mod tests {
[
Annotation {
range: 3..7,
+ kind: HasReferences {
+ pos: FilePositionWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ offset: 3,
+ },
+ data: Some(
+ [],
+ ),
+ },
+ },
+ Annotation {
+ range: 3..7,
kind: Runnable(
Runnable {
use_name_in_title: false,
@@ -760,24 +799,15 @@ mod tests {
},
kind: Bin,
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
},
Annotation {
- range: 3..7,
- kind: HasReferences {
- pos: FilePositionWrapper {
- file_id: FileId(
- 0,
- ),
- offset: 3,
- },
- data: Some(
- [],
- ),
- },
- },
- Annotation {
range: 18..23,
kind: Runnable(
Runnable {
@@ -796,6 +826,11 @@ mod tests {
path: "tests",
},
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
},
@@ -822,6 +857,11 @@ mod tests {
},
},
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
},
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index ed8cd64cdb..a7a5b8fb5a 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -3213,6 +3213,11 @@ fn foo_$0test() {}
},
},
cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
},
),
]
@@ -3230,28 +3235,33 @@ mod tests$0 {
}
"#,
expect![[r#"
- [
- Runnable(
- Runnable {
- use_name_in_title: false,
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 0..46,
- focus_range: 4..9,
- name: "tests",
- kind: Module,
- description: "mod tests",
- },
- kind: TestMod {
- path: "tests",
- },
- cfg: None,
+ [
+ Runnable(
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..46,
+ focus_range: 4..9,
+ name: "tests",
+ kind: Module,
+ description: "mod tests",
},
- ),
- ]
- "#]],
+ kind: TestMod {
+ path: "tests",
+ },
+ cfg: None,
+ update_test: UpdateTest {
+ expect_test: false,
+ insta: false,
+ snapbox: false,
+ },
+ },
+ ),
+ ]
+ "#]],
);
}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index c182952c73..1b37ab0aab 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -243,6 +243,9 @@ config_data! {
/// Whether to show `Run` lens. Only applies when
/// `#rust-analyzer.lens.enable#` is set.
lens_run_enable: bool = true,
+ /// Whether to show `Update Test` lens. Only applies when
+ /// `#rust-analyzer.lens.enable#` and `#rust-analyzer.lens.run.enable#` are set.
+ lens_update_test_enable: bool = true,
/// Disable project auto-discovery in favor of explicitly specified set
/// of projects.
@@ -1161,6 +1164,7 @@ pub struct LensConfig {
// runnables
pub run: bool,
pub debug: bool,
+ pub update_test: bool,
pub interpret: bool,
// implementations
@@ -1196,6 +1200,7 @@ impl LensConfig {
pub fn any(&self) -> bool {
self.run
|| self.debug
+ || self.update_test
|| self.implementations
|| self.method_refs
|| self.refs_adt
@@ -1208,7 +1213,7 @@ impl LensConfig {
}
pub fn runnable(&self) -> bool {
- self.run || self.debug
+ self.run || self.debug || self.update_test
}
pub fn references(&self) -> bool {
@@ -2120,6 +2125,9 @@ impl Config {
LensConfig {
run: *self.lens_enable() && *self.lens_run_enable(),
debug: *self.lens_enable() && *self.lens_debug_enable(),
+ update_test: *self.lens_enable()
+ && *self.lens_update_test_enable()
+ && *self.lens_run_enable(),
interpret: *self.lens_enable() && *self.lens_run_enable() && *self.interpret_tests(),
implementations: *self.lens_enable() && *self.lens_implementations_enable(),
method_refs: *self.lens_enable() && *self.lens_references_method_enable(),
diff --git a/crates/rust-analyzer/src/lsp/ext.rs b/crates/rust-analyzer/src/lsp/ext.rs
index c0173d9c24..e1677cbcda 100644
--- a/crates/rust-analyzer/src/lsp/ext.rs
+++ b/crates/rust-analyzer/src/lsp/ext.rs
@@ -427,14 +427,14 @@ impl Request for Runnables {
const METHOD: &'static str = "experimental/runnables";
}
-#[derive(Serialize, Deserialize, Debug)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RunnablesParams {
pub text_document: TextDocumentIdentifier,
pub position: Option<Position>,
}
-#[derive(Deserialize, Serialize, Debug)]
+#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Runnable {
pub label: String,
@@ -444,7 +444,7 @@ pub struct Runnable {
pub args: RunnableArgs,
}
-#[derive(Deserialize, Serialize, Debug)]
+#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(untagged)]
pub enum RunnableArgs {
@@ -452,14 +452,14 @@ pub enum RunnableArgs {
Shell(ShellRunnableArgs),
}
-#[derive(Serialize, Deserialize, Debug)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum RunnableKind {
Cargo,
Shell,
}
-#[derive(Deserialize, Serialize, Debug)]
+#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct CargoRunnableArgs {
#[serde(skip_serializing_if = "FxHashMap::is_empty")]
@@ -475,7 +475,7 @@ pub struct CargoRunnableArgs {
pub executable_args: Vec<String>,
}
-#[derive(Deserialize, Serialize, Debug)]
+#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ShellRunnableArgs {
#[serde(skip_serializing_if = "FxHashMap::is_empty")]
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index 05e93b4e6a..091ac77332 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -20,6 +20,7 @@ use itertools::Itertools;
use paths::{Utf8Component, Utf8Prefix};
use semver::VersionReq;
use serde_json::to_value;
+use syntax::SmolStr;
use vfs::AbsPath;
use crate::{
@@ -1567,6 +1568,7 @@ pub(crate) fn code_lens(
let line_index = snap.file_line_index(run.nav.file_id)?;
let annotation_range = range(&line_index, annotation.range);
+ let update_test = run.update_test;
let title = run.title();
let can_debug = match run.kind {
ide::RunnableKind::DocTest { .. } => false,
@@ -1602,6 +1604,17 @@ pub(crate) fn code_lens(
data: None,
})
}
+ if lens_config.update_test && client_commands_config.run_single {
+ let label = update_test.label();
+ if let Some(r) = make_update_runnable(&r, &label) {
+ let command = command::run_single(&r, label.unwrap().as_str());
+ acc.push(lsp_types::CodeLens {
+ range: annotation_range,
+ command: Some(command),
+ data: None,
+ })
+ }
+ }
}
if lens_config.interpret {
@@ -1786,7 +1799,7 @@ pub(crate) mod command {
pub(crate) fn debug_single(runnable: &lsp_ext::Runnable) -> lsp_types::Command {
lsp_types::Command {
- title: "Debug".into(),
+ title: "⚙\u{fe0e} Debug".into(),
command: "rust-analyzer.debugSingle".into(),
arguments: Some(vec![to_value(runnable).unwrap()]),
}
@@ -1838,6 +1851,29 @@ pub(crate) mod command {
}
}
+fn make_update_runnable(
+ runnable: &lsp_ext::Runnable,
+ label: &Option<SmolStr>,
+) -> Option<lsp_ext::Runnable> {
+ if !matches!(runnable.args, lsp_ext::RunnableArgs::Cargo(_)) {
+ return None;
+ }
+ let label = label.as_ref()?;
+
+ let mut runnable = runnable.clone();
+ runnable.label = format!("{} + {}", runnable.label, label);
+
+ let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args else {
+ unreachable!();
+ };
+
+ let environment_vars =
+ [("UPDATE_EXPECT", "1"), ("INSTA_UPDATE", "always"), ("SNAPSHOTS", "overwrite")];
+ r.environment.extend(environment_vars.into_iter().map(|(k, v)| (k.to_owned(), v.to_owned())));
+
+ Some(runnable)
+}
+
pub(crate) fn implementation_title(count: usize) -> String {
if count == 1 {
"1 implementation".into()
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 0e37611a54..826ce11244 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
<!---
-lsp/ext.rs hash: 9790509d87670c22
+lsp/ext.rs hash: 512c06cd8b46a21d
If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue:
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 5056c7d977..f5cdcc2b72 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -808,6 +808,12 @@ Only applies when `#rust-analyzer.lens.enable#` is set.
Whether to show `Run` lens. Only applies when
`#rust-analyzer.lens.enable#` is set.
--
+[[rust-analyzer.lens.update.test.enable]]rust-analyzer.lens.update.test.enable (default: `true`)::
++
+--
+Whether to show `Update Test` lens. Only applies when
+`#rust-analyzer.lens.enable#` and `#rust-analyzer.lens.run.enable#` are set.
+--
[[rust-analyzer.linkedProjects]]rust-analyzer.linkedProjects (default: `[]`)::
+
--
diff --git a/editors/code/package.json b/editors/code/package.json
index b9249e9ac8..7dc26c4436 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -407,6 +407,11 @@
"$rustc"
],
"markdownDescription": "Problem matchers to use for `rust-analyzer.run` command, eg `[\"$rustc\", \"$rust-panic\"]`."
+ },
+ "rust-analyzer.runnables.askBeforeUpdateTest": {
+ "type": "boolean",
+ "default": true,
+ "markdownDescription": "Ask before updating the test when running it."
}
}
},
@@ -2296,6 +2301,16 @@
}
},
{
+ "title": "lens",
+ "properties": {
+ "rust-analyzer.lens.update.test.enable": {
+ "markdownDescription": "Whether to show `Update Test` lens. Only applies when\n`#rust-analyzer.lens.enable#` and `#rust-analyzer.lens.run.enable#` are set.",
+ "default": true,
+ "type": "boolean"
+ }
+ }
+ },
+ {
"title": "general",
"properties": {
"rust-analyzer.linkedProjects": {
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index eac7b849fd..5d33d7a6ad 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -348,9 +348,9 @@ class ExperimentalFeatures implements lc.StaticFeature {
initialize(
_capabilities: lc.ServerCapabilities,
_documentSelector: lc.DocumentSelector | undefined,
- ): void {}
- dispose(): void {}
- clear(): void {}
+ ): void { }
+ dispose(): void { }
+ clear(): void { }
}
class OverrideFeatures implements lc.StaticFeature {
@@ -368,9 +368,9 @@ class OverrideFeatures implements lc.StaticFeature {
initialize(
_capabilities: lc.ServerCapabilities,
_documentSelector: lc.DocumentSelector | undefined,
- ): void {}
- dispose(): void {}
- clear(): void {}
+ ): void { }
+ dispose(): void { }
+ clear(): void { }
}
function isCodeActionWithoutEditsAndCommands(value: any): boolean {
@@ -398,9 +398,8 @@ export let HOVER_REFERENCE_COMMAND: ra.CommandLink[] = [];
function renderCommand(cmd: ra.CommandLink): string {
HOVER_REFERENCE_COMMAND.push(cmd);
- return `[${cmd.title}](command:rust-analyzer.hoverRefCommandProxy?${
- HOVER_REFERENCE_COMMAND.length - 1
- } '${cmd.tooltip}')`;
+ return `[${cmd.title}](command:rust-analyzer.hoverRefCommandProxy?${HOVER_REFERENCE_COMMAND.length - 1
+ } '${cmd.tooltip}')`;
}
function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString {
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 7ebc186a3e..dc35fddf49 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -1139,11 +1139,37 @@ export function peekTests(ctx: CtxInit): Cmd {
};
}
+function isUpdatingTest(runnable: ra.Runnable): boolean {
+ if (!isCargoRunnableArgs(runnable.args)) {
+ return false;
+ }
+
+ const env = runnable.args.environment;
+ return env ? ['UPDATE_EXPECT', 'INSTA_UPDATE', 'SNAPSHOTS'].some(key => key in env) : false;
+}
+
export function runSingle(ctx: CtxInit): Cmd {
return async (runnable: ra.Runnable) => {
const editor = ctx.activeRustEditor;
if (!editor) return;
+ if (isUpdatingTest(runnable) && ctx.config.askBeforeUpdateTest) {
+ const selection = await vscode.window.showInformationMessage(
+ 'rust-analyzer',
+ { detail: 'Do you want to update tests?', modal: true },
+ 'Update Now',
+ 'Update (and Don\'t ask again)',
+ );
+
+ if (selection !== 'Update Now' && selection !== 'Update (and Don\'t ask again)') {
+ return;
+ }
+
+ if (selection === 'Update (and Don\'t ask again)') {
+ ctx.config.setAskBeforeUpdateTest(false);
+ }
+ }
+
const task = await createTaskFromRunnable(runnable, ctx.config);
task.group = vscode.TaskGroup.Build;
task.presentationOptions = {
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index a97d4beab5..720c473c5b 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -362,6 +362,13 @@ export class Config {
get initializeStopped() {
return this.get<boolean>("initializeStopped");
}
+
+ get askBeforeUpdateTest() {
+ return this.get<boolean>("runnables.askBeforeUpdateTest");
+ }
+ async setAskBeforeUpdateTest(value: boolean) {
+ await this.cfg.update("runnables.askBeforeUpdateTest", value, true);
+ }
}
export function prepareVSCodeConfig<T>(resp: T): T {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index fdf43f66f9..478673d591 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -148,7 +148,7 @@ function createCommands(): Record<string, CommandFactory> {
health: "stopped",
});
},
- disabled: (_) => async () => {},
+ disabled: (_) => async () => { },
},
analyzerStatus: { enabled: commands.analyzerStatus },
@@ -207,10 +207,10 @@ function checkConflictingExtensions() {
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.",
+ "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);
+ .then(() => { }, console.error);
}
}