mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
CodeLens configuration options.
This commit is contained in:
parent
71e94b1d0b
commit
dc217bdf90
4 changed files with 168 additions and 92 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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, ¶ms.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, ¶ms.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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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"),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue