CodeLens configuration options.

This commit is contained in:
vsrs 2020-05-17 19:51:44 +03:00
parent 71e94b1d0b
commit dc217bdf90
4 changed files with 168 additions and 92 deletions

View file

@ -33,6 +33,34 @@ pub struct Config {
pub inlay_hints: InlayHintsConfig, pub inlay_hints: InlayHintsConfig,
pub completion: CompletionConfig, pub completion: CompletionConfig,
pub call_info_full: bool, pub call_info_full: bool,
pub lens: LensConfig,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LensConfig {
pub run: bool,
pub debug: bool,
pub impementations: bool,
}
impl Default for LensConfig {
fn default() -> Self {
Self { run: true, debug: true, impementations: true }
}
}
impl LensConfig {
pub fn any(&self) -> bool {
self.impementations || self.runnable()
}
pub fn none(&self) -> bool {
!self.any()
}
pub fn runnable(&self) -> bool {
self.run || self.debug
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -107,6 +135,7 @@ impl Default for Config {
..CompletionConfig::default() ..CompletionConfig::default()
}, },
call_info_full: true, call_info_full: true,
lens: LensConfig::default(),
} }
} }
} }
@ -195,6 +224,9 @@ impl Config {
set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis); set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets); set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
set(value, "/callInfo/full", &mut self.call_info_full); set(value, "/callInfo/full", &mut self.call_info_full);
set(value, "/lens/run", &mut self.lens.run);
set(value, "/lens/debug", &mut self.lens.debug);
set(value, "/lens/implementations", &mut self.lens.impementations);
log::info!("Config::update() = {:#?}", self); log::info!("Config::update() = {:#?}", self);
@ -212,35 +244,35 @@ impl Config {
pub fn update_caps(&mut self, caps: &ClientCapabilities) { pub fn update_caps(&mut self, caps: &ClientCapabilities) {
if let Some(doc_caps) = caps.text_document.as_ref() { if let Some(doc_caps) = caps.text_document.as_ref() {
if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) { if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) {
self.client_caps.location_link = value; self.client_caps.location_link = value;
} }
if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only) if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only)
{ {
self.client_caps.line_folding_only = value self.client_caps.line_folding_only = value
} }
if let Some(value) = doc_caps if let Some(value) = doc_caps
.document_symbol .document_symbol
.as_ref() .as_ref()
.and_then(|it| it.hierarchical_document_symbol_support) .and_then(|it| it.hierarchical_document_symbol_support)
{ {
self.client_caps.hierarchical_symbols = value self.client_caps.hierarchical_symbols = value
} }
if let Some(value) = doc_caps if let Some(value) = doc_caps
.code_action .code_action
.as_ref() .as_ref()
.and_then(|it| Some(it.code_action_literal_support.is_some())) .and_then(|it| Some(it.code_action_literal_support.is_some()))
{ {
self.client_caps.code_action_literals = value; self.client_caps.code_action_literals = value;
} }
self.completion.allow_snippets(false); self.completion.allow_snippets(false);
if let Some(completion) = &doc_caps.completion { if let Some(completion) = &doc_caps.completion {
if let Some(completion_item) = &completion.completion_item { if let Some(completion_item) = &completion.completion_item {
if let Some(value) = completion_item.snippet_support { if let Some(value) = completion_item.snippet_support {
self.completion.allow_snippets(value); self.completion.allow_snippets(value);
}
} }
} }
} }
}
if let Some(window_caps) = caps.window.as_ref() { if let Some(window_caps) = caps.window.as_ref() {
if let Some(value) = window_caps.work_done_progress { if let Some(value) = window_caps.work_done_progress {

View file

@ -812,88 +812,106 @@ pub fn handle_code_lens(
params: lsp_types::CodeLensParams, params: lsp_types::CodeLensParams,
) -> Result<Option<Vec<CodeLens>>> { ) -> Result<Option<Vec<CodeLens>>> {
let _p = profile("handle_code_lens"); let _p = profile("handle_code_lens");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let mut lenses: Vec<CodeLens> = Default::default(); let mut lenses: Vec<CodeLens> = Default::default();
let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; if world.config.lens.none() {
// Gather runnables // early return before any db query!
for runnable in world.analysis().runnables(file_id)? { return Ok(Some(lenses));
let title = match &runnable.kind {
RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "\u{fe0e} Run Test",
RunnableKind::DocTest { .. } => "\u{fe0e} Run Doctest",
RunnableKind::Bench { .. } => "Run Bench",
RunnableKind::Bin => {
// Do not suggest binary run on other target than binary
match &cargo_spec {
Some(spec) => match spec.target_kind {
TargetKind::Bin => "Run",
_ => continue,
},
None => continue,
}
}
}
.to_string();
let mut r = to_lsp_runnable(&world, file_id, runnable)?;
let lens = CodeLens {
range: r.range,
command: Some(Command {
title,
command: "rust-analyzer.runSingle".into(),
arguments: Some(vec![to_value(&r).unwrap()]),
}),
data: None,
};
lenses.push(lens);
if r.args[0] == "run" {
r.args[0] = "build".into();
} else {
r.args.push("--no-run".into());
}
let debug_lens = CodeLens {
range: r.range,
command: Some(Command {
title: "Debug".into(),
command: "rust-analyzer.debugSingle".into(),
arguments: Some(vec![to_value(r).unwrap()]),
}),
data: None,
};
lenses.push(debug_lens);
} }
// Handle impls let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
lenses.extend( let line_index = world.analysis().file_line_index(file_id)?;
world let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?;
.analysis()
.file_structure(file_id)?
.into_iter()
.filter(|it| match it.kind {
SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true,
_ => false,
})
.map(|it| {
let range = to_proto::range(&line_index, it.node_range);
let pos = range.start;
let lens_params = lsp_types::request::GotoImplementationParams {
text_document_position_params: lsp_types::TextDocumentPositionParams::new(
params.text_document.clone(),
pos,
),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
CodeLens {
range,
command: None,
data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()),
}
}),
);
if world.config.lens.runnable() {
// Gather runnables
for runnable in world.analysis().runnables(file_id)? {
let (run_title, debugee ) = match &runnable.kind {
RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => ("▶️\u{fe0e}Run Test", true),
RunnableKind::DocTest { .. } => {
// cargo does not support -no-run for doctests
("▶️\u{fe0e}Run Doctest", false)
}
RunnableKind::Bench { .. } => {
// Nothing wrong with bench debugging
("Run Bench", true)
},
RunnableKind::Bin => {
// Do not suggest binary run on other target than binary
match &cargo_spec {
Some(spec) => match spec.target_kind {
TargetKind::Bin => ("Run", true),
_ => continue,
},
None => continue,
}
}
};
let mut r = to_lsp_runnable(&world, file_id, runnable)?;
if world.config.lens.run {
let lens = CodeLens {
range: r.range,
command: Some(Command {
title: run_title.to_string(),
command: "rust-analyzer.runSingle".into(),
arguments: Some(vec![to_value(&r).unwrap()]),
}),
data: None,
};
lenses.push(lens);
}
if debugee && world.config.lens.debug {
if r.args[0] == "run" {
r.args[0] = "build".into();
} else {
r.args.push("--no-run".into());
}
let debug_lens = CodeLens {
range: r.range,
command: Some(Command {
title: "Debug".into(),
command: "rust-analyzer.debugSingle".into(),
arguments: Some(vec![to_value(r).unwrap()]),
}),
data: None,
};
lenses.push(debug_lens);
}
}
}
if world.config.lens.impementations {
// Handle impls
lenses.extend(
world
.analysis()
.file_structure(file_id)?
.into_iter()
.filter(|it| match it.kind {
SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true,
_ => false,
})
.map(|it| {
let range = to_proto::range(&line_index, it.node_range);
let pos = range.start;
let lens_params = lsp_types::request::GotoImplementationParams {
text_document_position_params: lsp_types::TextDocumentPositionParams::new(
params.text_document.clone(),
pos,
),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
CodeLens {
range,
command: None,
data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()),
}
}),
);
}
Ok(Some(lenses)) Ok(Some(lenses))
} }

View file

@ -443,6 +443,21 @@
"type": "object", "type": "object",
"default": {}, "default": {},
"description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }" "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }"
},
"rust-analyzer.lens.run": {
"description": "Whether to show Run lens.",
"type": "boolean",
"default": true
},
"rust-analyzer.lens.debug": {
"description": "Whether to show Debug lens.",
"type": "boolean",
"default": true
},
"rust-analyzer.lens.implementations": {
"description": "Whether to show Implementations lens.",
"type": "boolean",
"default": true
} }
} }
}, },

View file

@ -16,6 +16,9 @@ export class Config {
"files", "files",
"highlighting", "highlighting",
"updates.channel", "updates.channel",
"lens.run",
"lens.debug",
"lens.implementations",
] ]
.map(opt => `${this.rootSection}.${opt}`); .map(opt => `${this.rootSection}.${opt}`);
@ -119,4 +122,12 @@ export class Config {
sourceFileMap: sourceFileMap sourceFileMap: sourceFileMap
}; };
} }
get lens() {
return {
run: this.get<boolean>("lens.run"),
debug: this.get<boolean>("lens.debug"),
implementations: this.get<boolean>("lens.implementations"),
};
}
} }