Skip to content

Commit 33f12a3

Browse files
bors[bot]matklad
andauthored
Merge #9732
9732: feat: gate custom clint-side commands behind capabilities r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 1f81783 + be84f85 commit 33f12a3

File tree

8 files changed

+127
-124
lines changed

8 files changed

+127
-124
lines changed

crates/rust-analyzer/src/config.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ use serde::{de::DeserializeOwned, Deserialize};
2525
use vfs::AbsPathBuf;
2626

2727
use crate::{
28-
caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig,
29-
line_index::OffsetEncoding, lsp_ext::supports_utf8, lsp_ext::WorkspaceSymbolSearchKind,
28+
caps::completion_item_edit_resolve,
29+
diagnostics::DiagnosticsMapConfig,
30+
line_index::OffsetEncoding,
31+
lsp_ext::supports_utf8,
3032
lsp_ext::WorkspaceSymbolSearchScope,
33+
lsp_ext::{self, WorkspaceSymbolSearchKind},
3134
};
3235

3336
// Defines the server-side configuration of the rust-analyzer. We generate
@@ -221,6 +224,9 @@ config_data! {
221224
/// Whether to show `References` lens. Only applies when
222225
/// `#rust-analyzer.lens.enable#` is set.
223226
lens_references: bool = "false",
227+
/// Internal config: use custom client-side commands even when the
228+
/// client doesn't set the corresponding capability.
229+
lens_forceCustomCommands: bool = "true",
224230

225231
/// Disable project auto-discovery in favor of explicitly specified set
226232
/// of projects.
@@ -405,6 +411,14 @@ pub struct WorkspaceSymbolConfig {
405411
pub search_kind: WorkspaceSymbolSearchKind,
406412
}
407413

414+
pub struct ClientCommandsConfig {
415+
pub run_single: bool,
416+
pub debug_single: bool,
417+
pub show_reference: bool,
418+
pub goto_location: bool,
419+
pub trigger_parameter_hints: bool,
420+
}
421+
408422
impl Config {
409423
pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self {
410424
Config {
@@ -858,6 +872,24 @@ impl Config {
858872
false
859873
)
860874
}
875+
pub fn client_commands(&self) -> ClientCommandsConfig {
876+
let commands =
877+
try_or!(self.caps.experimental.as_ref()?.get("commands")?, &serde_json::Value::Null);
878+
let commands: Option<lsp_ext::ClientCommandOptions> =
879+
serde_json::from_value(commands.clone()).ok();
880+
let force = commands.is_none() && self.data.lens_forceCustomCommands;
881+
let commands = commands.map(|it| it.commands).unwrap_or_default();
882+
883+
let get = |name: &str| commands.iter().any(|it| it == name) || force;
884+
885+
ClientCommandsConfig {
886+
run_single: get("rust-analyzer.runSingle"),
887+
debug_single: get("rust-analyzer.debugSingle"),
888+
show_reference: get("rust-analyzer.showReferences"),
889+
goto_location: get("rust-analyzer.gotoLocation"),
890+
trigger_parameter_hints: get("editor.action.triggerParameterHints"),
891+
}
892+
}
861893

862894
pub fn highlight_related(&self) -> HighlightRelatedConfig {
863895
HighlightRelatedConfig {

crates/rust-analyzer/src/handlers.rs

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -768,13 +768,8 @@ pub(crate) fn handle_completion(
768768
};
769769
let line_index = snap.file_line_index(position.file_id)?;
770770

771-
let items = to_proto::completion_items(
772-
snap.config.insert_replace_support(),
773-
completion_config.enable_imports_on_the_fly,
774-
&line_index,
775-
text_document_position,
776-
items,
777-
);
771+
let items =
772+
to_proto::completion_items(&snap.config, &line_index, text_document_position, items);
778773

779774
let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
780775
Ok(Some(completion_list.into()))
@@ -1503,7 +1498,7 @@ fn show_impl_command_link(
15031498
snap: &GlobalStateSnapshot,
15041499
position: &FilePosition,
15051500
) -> Option<lsp_ext::CommandLinkGroup> {
1506-
if snap.config.hover_actions().implementations {
1501+
if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference {
15071502
if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
15081503
let uri = to_proto::url(snap, position.file_id);
15091504
let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -1529,7 +1524,7 @@ fn show_ref_command_link(
15291524
snap: &GlobalStateSnapshot,
15301525
position: &FilePosition,
15311526
) -> Option<lsp_ext::CommandLinkGroup> {
1532-
if snap.config.hover_actions().references {
1527+
if snap.config.hover_actions().references && snap.config.client_commands().show_reference {
15331528
if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
15341529
let uri = to_proto::url(snap, position.file_id);
15351530
let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -1559,35 +1554,47 @@ fn runnable_action_links(
15591554
snap: &GlobalStateSnapshot,
15601555
runnable: Runnable,
15611556
) -> Option<lsp_ext::CommandLinkGroup> {
1562-
let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
15631557
let hover_actions_config = snap.config.hover_actions();
1564-
if !hover_actions_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) {
1558+
if !hover_actions_config.runnable() {
1559+
return None;
1560+
}
1561+
1562+
let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
1563+
if should_skip_target(&runnable, cargo_spec.as_ref()) {
1564+
return None;
1565+
}
1566+
1567+
let client_commands_config = snap.config.client_commands();
1568+
if !(client_commands_config.run_single || client_commands_config.debug_single) {
15651569
return None;
15661570
}
15671571

15681572
let title = runnable.title();
1569-
to_proto::runnable(snap, runnable).ok().map(|r| {
1570-
let mut group = lsp_ext::CommandLinkGroup::default();
1573+
let r = to_proto::runnable(snap, runnable).ok()?;
15711574

1572-
if hover_actions_config.run {
1573-
let run_command = to_proto::command::run_single(&r, &title);
1574-
group.commands.push(to_command_link(run_command, r.label.clone()));
1575-
}
1575+
let mut group = lsp_ext::CommandLinkGroup::default();
15761576

1577-
if hover_actions_config.debug {
1578-
let dbg_command = to_proto::command::debug_single(&r);
1579-
group.commands.push(to_command_link(dbg_command, r.label));
1580-
}
1577+
if hover_actions_config.run && client_commands_config.run_single {
1578+
let run_command = to_proto::command::run_single(&r, &title);
1579+
group.commands.push(to_command_link(run_command, r.label.clone()));
1580+
}
15811581

1582-
group
1583-
})
1582+
if hover_actions_config.debug && client_commands_config.debug_single {
1583+
let dbg_command = to_proto::command::debug_single(&r);
1584+
group.commands.push(to_command_link(dbg_command, r.label));
1585+
}
1586+
1587+
Some(group)
15841588
}
15851589

15861590
fn goto_type_action_links(
15871591
snap: &GlobalStateSnapshot,
15881592
nav_targets: &[HoverGotoTypeData],
15891593
) -> Option<lsp_ext::CommandLinkGroup> {
1590-
if !snap.config.hover_actions().goto_type_def || nav_targets.is_empty() {
1594+
if !snap.config.hover_actions().goto_type_def
1595+
|| nav_targets.is_empty()
1596+
|| !snap.config.client_commands().goto_location
1597+
{
15911598
return None;
15921599
}
15931600

crates/rust-analyzer/src/lsp_ext.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,3 +523,8 @@ pub struct CompletionResolveData {
523523
pub full_import_path: String,
524524
pub imported_name: String,
525525
}
526+
527+
#[derive(Debug, Deserialize, Default)]
528+
pub struct ClientCommandOptions {
529+
pub commands: Vec<String>,
530+
}

crates/rust-analyzer/src/to_proto.rs

Lines changed: 16 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use vfs::AbsPath;
1818

1919
use crate::{
2020
cargo_target_spec::CargoTargetSpec,
21+
config::Config,
2122
global_state::GlobalStateSnapshot,
2223
line_index::{LineEndings, LineIndex, OffsetEncoding},
2324
lsp_ext, semantic_tokens, Result,
@@ -190,32 +191,22 @@ pub(crate) fn snippet_text_edit_vec(
190191
}
191192

192193
pub(crate) fn completion_items(
193-
insert_replace_support: bool,
194-
enable_imports_on_the_fly: bool,
194+
config: &Config,
195195
line_index: &LineIndex,
196196
tdpp: lsp_types::TextDocumentPositionParams,
197197
items: Vec<CompletionItem>,
198198
) -> Vec<lsp_types::CompletionItem> {
199199
let max_relevance = items.iter().map(|it| it.relevance().score()).max().unwrap_or_default();
200200
let mut res = Vec::with_capacity(items.len());
201201
for item in items {
202-
completion_item(
203-
&mut res,
204-
insert_replace_support,
205-
enable_imports_on_the_fly,
206-
line_index,
207-
&tdpp,
208-
max_relevance,
209-
item,
210-
)
202+
completion_item(&mut res, config, line_index, &tdpp, max_relevance, item)
211203
}
212204
res
213205
}
214206

215207
fn completion_item(
216208
acc: &mut Vec<lsp_types::CompletionItem>,
217-
insert_replace_support: bool,
218-
enable_imports_on_the_fly: bool,
209+
config: &Config,
219210
line_index: &LineIndex,
220211
tdpp: &lsp_types::TextDocumentPositionParams,
221212
max_relevance: u32,
@@ -230,7 +221,7 @@ fn completion_item(
230221
let source_range = item.source_range();
231222
for indel in item.text_edit().iter() {
232223
if indel.delete.contains_range(source_range) {
233-
let insert_replace_support = insert_replace_support.then(|| tdpp.position);
224+
let insert_replace_support = config.insert_replace_support().then(|| tdpp.position);
234225
text_edit = Some(if indel.delete == source_range {
235226
self::completion_text_edit(line_index, insert_replace_support, indel.clone())
236227
} else {
@@ -269,14 +260,14 @@ fn completion_item(
269260
lsp_item.tags = Some(vec![lsp_types::CompletionItemTag::Deprecated])
270261
}
271262

272-
if item.trigger_call_info() {
263+
if item.trigger_call_info() && config.client_commands().trigger_parameter_hints {
273264
lsp_item.command = Some(command::trigger_parameter_hints());
274265
}
275266

276267
if item.is_snippet() {
277268
lsp_item.insert_text_format = Some(lsp_types::InsertTextFormat::Snippet);
278269
}
279-
if enable_imports_on_the_fly {
270+
if config.completion().enable_imports_on_the_fly {
280271
if let Some(import_edit) = item.import_to_add() {
281272
let import_path = &import_edit.import.import_path;
282273
if let Some(import_name) = import_path.segments().last() {
@@ -992,6 +983,7 @@ pub(crate) fn code_lens(
992983
snap: &GlobalStateSnapshot,
993984
annotation: Annotation,
994985
) -> Result<()> {
986+
let client_commands_config = snap.config.client_commands();
995987
match annotation.kind {
996988
AnnotationKind::Runnable(run) => {
997989
let line_index = snap.file_line_index(run.nav.file_id)?;
@@ -1008,15 +1000,15 @@ pub(crate) fn code_lens(
10081000
let r = runnable(snap, run)?;
10091001

10101002
let lens_config = snap.config.lens();
1011-
if lens_config.run {
1003+
if lens_config.run && client_commands_config.run_single {
10121004
let command = command::run_single(&r, &title);
10131005
acc.push(lsp_types::CodeLens {
10141006
range: annotation_range,
10151007
command: Some(command),
10161008
data: None,
10171009
})
10181010
}
1019-
if lens_config.debug && can_debug {
1011+
if lens_config.debug && can_debug && client_commands_config.debug_single {
10201012
let command = command::debug_single(&r);
10211013
acc.push(lsp_types::CodeLens {
10221014
range: annotation_range,
@@ -1026,6 +1018,9 @@ pub(crate) fn code_lens(
10261018
}
10271019
}
10281020
AnnotationKind::HasImpls { position: file_position, data } => {
1021+
if !client_commands_config.show_reference {
1022+
return Ok(());
1023+
}
10291024
let line_index = snap.file_line_index(file_position.file_id)?;
10301025
let annotation_range = range(&line_index, annotation.range);
10311026
let url = url(snap, file_position.file_id);
@@ -1069,6 +1064,9 @@ pub(crate) fn code_lens(
10691064
})
10701065
}
10711066
AnnotationKind::HasReferences { position: file_position, data } => {
1067+
if !client_commands_config.show_reference {
1068+
return Ok(());
1069+
}
10721070
let line_index = snap.file_line_index(file_position.file_id)?;
10731071
let annotation_range = range(&line_index, annotation.range);
10741072
let url = url(snap, file_position.file_id);
@@ -1207,88 +1205,9 @@ mod tests {
12071205
use std::sync::Arc;
12081206

12091207
use ide::Analysis;
1210-
use ide_db::helpers::{
1211-
insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
1212-
SnippetCap,
1213-
};
12141208

12151209
use super::*;
12161210

1217-
#[test]
1218-
fn test_completion_with_ref() {
1219-
let fixture = r#"
1220-
struct Foo;
1221-
fn foo(arg: &Foo) {}
1222-
fn main() {
1223-
let arg = Foo;
1224-
foo($0)
1225-
}"#;
1226-
1227-
let (offset, text) = test_utils::extract_offset(fixture);
1228-
let line_index = LineIndex {
1229-
index: Arc::new(ide::LineIndex::new(&text)),
1230-
endings: LineEndings::Unix,
1231-
encoding: OffsetEncoding::Utf16,
1232-
};
1233-
let (analysis, file_id) = Analysis::from_single_file(text);
1234-
1235-
let file_position = ide_db::base_db::FilePosition { file_id, offset };
1236-
let mut items = analysis
1237-
.completions(
1238-
&ide::CompletionConfig {
1239-
enable_postfix_completions: true,
1240-
enable_imports_on_the_fly: true,
1241-
enable_self_on_the_fly: true,
1242-
add_call_parenthesis: true,
1243-
add_call_argument_snippets: true,
1244-
snippet_cap: SnippetCap::new(true),
1245-
insert_use: InsertUseConfig {
1246-
granularity: ImportGranularity::Item,
1247-
prefix_kind: PrefixKind::Plain,
1248-
enforce_granularity: true,
1249-
group: true,
1250-
skip_glob_imports: true,
1251-
},
1252-
},
1253-
file_position,
1254-
)
1255-
.unwrap()
1256-
.unwrap();
1257-
items.retain(|c| c.label().ends_with("arg"));
1258-
let items = completion_items(
1259-
false,
1260-
false,
1261-
&line_index,
1262-
lsp_types::TextDocumentPositionParams {
1263-
text_document: lsp_types::TextDocumentIdentifier {
1264-
uri: "file://main.rs".parse().unwrap(),
1265-
},
1266-
position: position(&line_index, file_position.offset),
1267-
},
1268-
items,
1269-
);
1270-
let items: Vec<(String, Option<String>)> =
1271-
items.into_iter().map(|c| (c.label, c.sort_text)).collect();
1272-
1273-
expect_test::expect![[r#"
1274-
[
1275-
(
1276-
"&arg",
1277-
Some(
1278-
"fffffff9",
1279-
),
1280-
),
1281-
(
1282-
"arg",
1283-
Some(
1284-
"fffffffd",
1285-
),
1286-
),
1287-
]
1288-
"#]]
1289-
.assert_debug_eq(&items);
1290-
}
1291-
12921211
#[test]
12931212
fn conv_fold_line_folding_only_fixup() {
12941213
let text = r#"mod a;

0 commit comments

Comments
 (0)