feat: support UpdateTest in codelens

This commit is contained in:
roife 2024-12-25 15:56:06 +08:00
parent dd788255b4
commit edb61b10ab
12 changed files with 204 additions and 57 deletions

View file

@ -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,
},
},
),
},
@ -744,6 +769,20 @@ mod tests {
"#,
expect![[r#"
[
Annotation {
range: 3..7,
kind: HasReferences {
pos: FilePositionWrapper {
file_id: FileId(
0,
),
offset: 3,
},
data: Some(
[],
),
},
},
Annotation {
range: 3..7,
kind: Runnable(
@ -760,23 +799,14 @@ 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(
@ -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,
},
},
),
},

View file

@ -3213,6 +3213,11 @@ fn foo_$0test() {}
},
},
cfg: None,
update_test: UpdateTest {
expect_test: false,
insta: false,
snapbox: false,
},
},
),
]
@ -3248,6 +3253,11 @@ mod tests$0 {
path: "tests",
},
cfg: None,
update_test: UpdateTest {
expect_test: false,
insta: false,
snapbox: false,
},
},
),
]

View file

@ -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(),

View file

@ -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")]

View file

@ -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()

View file

@ -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:

View file

@ -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: `[]`)::
+
--

View file

@ -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."
}
}
},
@ -2295,6 +2300,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": {

View file

@ -398,8 +398,7 @@ 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
return `[${cmd.title}](command:rust-analyzer.hoverRefCommandProxy?${HOVER_REFERENCE_COMMAND.length - 1
} '${cmd.tooltip}')`;
}

View file

@ -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 = {

View file

@ -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 {