mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Moved CodeLens to ide crate
This commit is contained in:
parent
935830d05b
commit
185da286d2
7 changed files with 388 additions and 202 deletions
142
crates/ide/src/annotations.rs
Normal file
142
crates/ide/src/annotations.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
use hir::Semantics;
|
||||
use ide_db::{
|
||||
base_db::{FileId, FilePosition, FileRange, SourceDatabase},
|
||||
RootDatabase, SymbolKind,
|
||||
};
|
||||
use syntax::TextRange;
|
||||
|
||||
use crate::{
|
||||
file_structure::file_structure,
|
||||
fn_references::find_all_methods,
|
||||
goto_implementation::goto_implementation,
|
||||
references::find_all_refs,
|
||||
runnables::{runnables, Runnable},
|
||||
NavigationTarget, RunnableKind,
|
||||
};
|
||||
|
||||
// Feature: Annotations
|
||||
//
|
||||
// Provides user with annotations above items for looking up references or impl blocks
|
||||
// and running/debugging binaries.
|
||||
pub struct Annotation {
|
||||
pub range: TextRange,
|
||||
pub kind: AnnotationKind,
|
||||
}
|
||||
|
||||
pub enum AnnotationKind {
|
||||
Runnable { debug: bool, runnable: Runnable },
|
||||
HasImpls { position: FilePosition, data: Option<Vec<NavigationTarget>> },
|
||||
HasReferences { position: FilePosition, data: Option<Vec<FileRange>> },
|
||||
}
|
||||
|
||||
pub struct AnnotationConfig {
|
||||
pub binary_target: bool,
|
||||
pub annotate_runnables: bool,
|
||||
pub annotate_impls: bool,
|
||||
pub annotate_references: bool,
|
||||
pub annotate_method_references: bool,
|
||||
pub run: bool,
|
||||
pub debug: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn annotations(
|
||||
db: &RootDatabase,
|
||||
file_id: FileId,
|
||||
config: AnnotationConfig,
|
||||
) -> Vec<Annotation> {
|
||||
let mut annotations = Vec::default();
|
||||
|
||||
if config.annotate_runnables {
|
||||
for runnable in runnables(db, file_id) {
|
||||
if !matches!(runnable.kind, RunnableKind::Bin) || !config.binary_target {
|
||||
continue;
|
||||
}
|
||||
|
||||
let action = runnable.action();
|
||||
let range = runnable.nav.full_range;
|
||||
|
||||
if config.run {
|
||||
annotations.push(Annotation {
|
||||
range,
|
||||
// FIXME: This one allocates without reason if run is enabled, but debug is disabled
|
||||
kind: AnnotationKind::Runnable { debug: false, runnable: runnable.clone() },
|
||||
});
|
||||
}
|
||||
|
||||
if action.debugee && config.debug {
|
||||
annotations.push(Annotation {
|
||||
range,
|
||||
kind: AnnotationKind::Runnable { debug: true, runnable },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file_structure(&db.parse(file_id).tree())
|
||||
.into_iter()
|
||||
.filter(|node| {
|
||||
matches!(
|
||||
node.kind,
|
||||
SymbolKind::Trait
|
||||
| SymbolKind::Struct
|
||||
| SymbolKind::Enum
|
||||
| SymbolKind::Union
|
||||
| SymbolKind::Const
|
||||
)
|
||||
})
|
||||
.for_each(|node| {
|
||||
if config.annotate_impls && node.kind != SymbolKind::Const {
|
||||
annotations.push(Annotation {
|
||||
range: node.node_range,
|
||||
kind: AnnotationKind::HasImpls {
|
||||
position: FilePosition { file_id, offset: node.navigation_range.start() },
|
||||
data: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if config.annotate_references {
|
||||
annotations.push(Annotation {
|
||||
range: node.node_range,
|
||||
kind: AnnotationKind::HasReferences {
|
||||
position: FilePosition { file_id, offset: node.navigation_range.start() },
|
||||
data: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if config.annotate_method_references {
|
||||
annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation {
|
||||
range: method.range,
|
||||
kind: AnnotationKind::HasReferences {
|
||||
position: FilePosition { file_id, offset: method.range.start() },
|
||||
data: None,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
annotations
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
|
||||
match annotation.kind {
|
||||
AnnotationKind::HasImpls { position, ref mut data } => {
|
||||
*data = goto_implementation(db, position).map(|range| range.info);
|
||||
}
|
||||
AnnotationKind::HasReferences { position, ref mut data } => {
|
||||
*data = find_all_refs(&Semantics::new(db), position, None).map(|result| {
|
||||
result
|
||||
.references
|
||||
.into_iter()
|
||||
.map(|(_, access)| access.into_iter())
|
||||
.flatten()
|
||||
.map(|(range, _)| FileRange { file_id: position.file_id, range })
|
||||
.collect()
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
annotation
|
||||
}
|
|
@ -22,6 +22,7 @@ mod markup;
|
|||
mod prime_caches;
|
||||
mod display;
|
||||
|
||||
mod annotations;
|
||||
mod call_hierarchy;
|
||||
mod diagnostics;
|
||||
mod expand_macro;
|
||||
|
@ -63,6 +64,7 @@ use syntax::SourceFile;
|
|||
use crate::display::ToNav;
|
||||
|
||||
pub use crate::{
|
||||
annotations::{Annotation, AnnotationConfig, AnnotationKind},
|
||||
call_hierarchy::CallItem,
|
||||
diagnostics::{Diagnostic, DiagnosticsConfig, Fix, Severity},
|
||||
display::navigation_target::NavigationTarget,
|
||||
|
@ -555,6 +557,18 @@ impl Analysis {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn annotations(
|
||||
&self,
|
||||
file_id: FileId,
|
||||
config: AnnotationConfig,
|
||||
) -> Cancelable<Vec<Annotation>> {
|
||||
self.with_db(|db| annotations::annotations(db, file_id, config))
|
||||
}
|
||||
|
||||
pub fn resolve_annotation(&self, annotation: Annotation) -> Cancelable<Annotation> {
|
||||
self.with_db(|db| annotations::resolve_annotation(db, annotation))
|
||||
}
|
||||
|
||||
/// Performs an operation on that may be Canceled.
|
||||
fn with_db<F, T>(&self, f: F) -> Cancelable<T>
|
||||
where
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
//! Conversion lsp_types types to rust-analyzer specific ones.
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use ide::{AssistKind, LineCol, LineIndex};
|
||||
use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineIndex};
|
||||
use ide_db::base_db::{FileId, FilePosition, FileRange};
|
||||
use syntax::{TextRange, TextSize};
|
||||
use vfs::AbsPathBuf;
|
||||
|
||||
use crate::{global_state::GlobalStateSnapshot, Result};
|
||||
use crate::{from_json, global_state::GlobalStateSnapshot, lsp_ext, Result};
|
||||
|
||||
pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> {
|
||||
let path = url.to_file_path().map_err(|()| "url is not a file")?;
|
||||
|
@ -66,3 +66,39 @@ pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind>
|
|||
|
||||
Some(assist_kind)
|
||||
}
|
||||
|
||||
pub(crate) fn annotation(
|
||||
world: &GlobalStateSnapshot,
|
||||
code_lens: lsp_types::CodeLens,
|
||||
) -> Result<Annotation> {
|
||||
let data = code_lens.data.unwrap();
|
||||
let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", data)?;
|
||||
|
||||
match resolve {
|
||||
lsp_ext::CodeLensResolveData::Impls(params) => {
|
||||
let file_id =
|
||||
world.url_to_file_id(¶ms.text_document_position_params.text_document.uri)?;
|
||||
let line_index = world.analysis.file_line_index(file_id)?;
|
||||
|
||||
Ok(Annotation {
|
||||
range: text_range(&line_index, code_lens.range),
|
||||
kind: AnnotationKind::HasImpls {
|
||||
position: file_position(world, params.text_document_position_params)?,
|
||||
data: None,
|
||||
},
|
||||
})
|
||||
}
|
||||
lsp_ext::CodeLensResolveData::References(params) => {
|
||||
let file_id = world.url_to_file_id(¶ms.text_document.uri)?;
|
||||
let line_index = world.analysis.file_line_index(file_id)?;
|
||||
|
||||
Ok(Annotation {
|
||||
range: text_range(&line_index, code_lens.range),
|
||||
kind: AnnotationKind::HasReferences {
|
||||
position: file_position(world, params)?,
|
||||
data: None,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,9 @@ use std::{
|
|||
};
|
||||
|
||||
use ide::{
|
||||
FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, NavigationTarget,
|
||||
Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit,
|
||||
AnnotationConfig, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex,
|
||||
NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange,
|
||||
TextEdit,
|
||||
};
|
||||
use ide_db::SymbolKind;
|
||||
use itertools::Itertools;
|
||||
|
@ -35,7 +36,7 @@ use crate::{
|
|||
cargo_target_spec::CargoTargetSpec,
|
||||
config::RustfmtConfig,
|
||||
diff::diff,
|
||||
from_json, from_proto,
|
||||
from_proto,
|
||||
global_state::{GlobalState, GlobalStateSnapshot},
|
||||
line_endings::LineEndings,
|
||||
lsp_ext::{self, InlayHint, InlayHintsParams},
|
||||
|
@ -1078,177 +1079,51 @@ pub(crate) fn handle_code_lens(
|
|||
params: lsp_types::CodeLensParams,
|
||||
) -> Result<Option<Vec<CodeLens>>> {
|
||||
let _p = profile::span("handle_code_lens");
|
||||
let mut lenses: Vec<CodeLens> = Default::default();
|
||||
|
||||
let lens_config = snap.config.lens();
|
||||
if lens_config.none() {
|
||||
// early return before any db query!
|
||||
return Ok(Some(lenses));
|
||||
return Ok(Some(Vec::default()));
|
||||
}
|
||||
|
||||
let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?;
|
||||
let line_index = snap.analysis.file_line_index(file_id)?;
|
||||
let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
|
||||
let cargo_target_spec = CargoTargetSpec::for_file(&snap, file_id)?;
|
||||
|
||||
if lens_config.runnable() {
|
||||
// Gather runnables
|
||||
for runnable in snap.analysis.runnables(file_id)? {
|
||||
if should_skip_target(&runnable, cargo_spec.as_ref()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let action = runnable.action();
|
||||
let range = to_proto::range(&line_index, runnable.nav.full_range);
|
||||
let r = to_proto::runnable(&snap, file_id, runnable)?;
|
||||
if lens_config.run {
|
||||
let lens = CodeLens {
|
||||
range,
|
||||
command: Some(run_single_command(&r, action.run_title)),
|
||||
data: None,
|
||||
};
|
||||
lenses.push(lens);
|
||||
}
|
||||
|
||||
if action.debugee && lens_config.debug {
|
||||
let debug_lens =
|
||||
CodeLens { range, command: Some(debug_single_command(&r)), data: None };
|
||||
lenses.push(debug_lens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if lens_config.implementations || lens_config.refs {
|
||||
snap.analysis
|
||||
.file_structure(file_id)?
|
||||
.into_iter()
|
||||
.filter(|it| {
|
||||
matches!(
|
||||
it.kind,
|
||||
SymbolKind::Trait | SymbolKind::Struct | SymbolKind::Enum | SymbolKind::Union
|
||||
)
|
||||
})
|
||||
.for_each(|it| {
|
||||
let range = to_proto::range(&line_index, it.node_range);
|
||||
let position = to_proto::position(&line_index, it.navigation_range.start());
|
||||
let doc_pos = lsp_types::TextDocumentPositionParams::new(
|
||||
params.text_document.clone(),
|
||||
position,
|
||||
);
|
||||
let goto_params = lsp_types::request::GotoImplementationParams {
|
||||
text_document_position_params: doc_pos.clone(),
|
||||
work_done_progress_params: Default::default(),
|
||||
partial_result_params: Default::default(),
|
||||
};
|
||||
|
||||
if lens_config.implementations {
|
||||
lenses.push(CodeLens {
|
||||
range,
|
||||
command: None,
|
||||
data: Some(to_value(CodeLensResolveData::Impls(goto_params)).unwrap()),
|
||||
let lenses = snap
|
||||
.analysis
|
||||
.annotations(
|
||||
file_id,
|
||||
AnnotationConfig {
|
||||
binary_target: cargo_target_spec
|
||||
.map(|spec| {
|
||||
matches!(
|
||||
spec.target_kind,
|
||||
TargetKind::Bin | TargetKind::Example | TargetKind::Test
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if lens_config.refs {
|
||||
lenses.push(CodeLens {
|
||||
range,
|
||||
command: None,
|
||||
data: Some(to_value(CodeLensResolveData::References(doc_pos)).unwrap()),
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if lens_config.method_refs {
|
||||
lenses.extend(snap.analysis.find_all_methods(file_id)?.into_iter().map(|it| {
|
||||
let range = to_proto::range(&line_index, it.range);
|
||||
let position = to_proto::position(&line_index, it.range.start());
|
||||
let lens_params =
|
||||
lsp_types::TextDocumentPositionParams::new(params.text_document.clone(), position);
|
||||
|
||||
CodeLens {
|
||||
range,
|
||||
command: None,
|
||||
data: Some(to_value(CodeLensResolveData::References(lens_params)).unwrap()),
|
||||
}
|
||||
}));
|
||||
}
|
||||
.unwrap_or(false),
|
||||
annotate_runnables: lens_config.runnable(),
|
||||
annotate_impls: lens_config.implementations,
|
||||
annotate_references: lens_config.refs,
|
||||
annotate_method_references: lens_config.method_refs,
|
||||
run: lens_config.run,
|
||||
debug: lens_config.debug,
|
||||
},
|
||||
)?
|
||||
.into_iter()
|
||||
.map(|annotation| to_proto::code_lens(&snap, annotation).unwrap())
|
||||
.collect();
|
||||
|
||||
Ok(Some(lenses))
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
enum CodeLensResolveData {
|
||||
Impls(lsp_types::request::GotoImplementationParams),
|
||||
References(lsp_types::TextDocumentPositionParams),
|
||||
}
|
||||
|
||||
pub(crate) fn handle_code_lens_resolve(
|
||||
snap: GlobalStateSnapshot,
|
||||
code_lens: CodeLens,
|
||||
) -> Result<CodeLens> {
|
||||
let _p = profile::span("handle_code_lens_resolve");
|
||||
let data = code_lens.data.unwrap();
|
||||
let resolve = from_json::<Option<CodeLensResolveData>>("CodeLensResolveData", data)?;
|
||||
match resolve {
|
||||
Some(CodeLensResolveData::Impls(lens_params)) => {
|
||||
let locations: Vec<Location> =
|
||||
match handle_goto_implementation(snap, lens_params.clone())? {
|
||||
Some(lsp_types::GotoDefinitionResponse::Scalar(loc)) => vec![loc],
|
||||
Some(lsp_types::GotoDefinitionResponse::Array(locs)) => locs,
|
||||
Some(lsp_types::GotoDefinitionResponse::Link(links)) => links
|
||||
.into_iter()
|
||||
.map(|link| Location::new(link.target_uri, link.target_selection_range))
|
||||
.collect(),
|
||||
_ => vec![],
|
||||
};
|
||||
let annotation = from_proto::annotation(&snap, code_lens)?;
|
||||
|
||||
let title = implementation_title(locations.len());
|
||||
let cmd = show_references_command(
|
||||
title,
|
||||
&lens_params.text_document_position_params.text_document.uri,
|
||||
code_lens.range.start,
|
||||
locations,
|
||||
);
|
||||
Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None })
|
||||
}
|
||||
Some(CodeLensResolveData::References(doc_position)) => {
|
||||
let position = from_proto::file_position(&snap, doc_position.clone())?;
|
||||
let locations = snap
|
||||
.analysis
|
||||
.find_all_refs(position, None)
|
||||
.unwrap_or(None)
|
||||
.map(|r| {
|
||||
r.references
|
||||
.into_iter()
|
||||
.flat_map(|(file_id, ranges)| {
|
||||
ranges.into_iter().map(move |(range, _)| FileRange { file_id, range })
|
||||
})
|
||||
.filter_map(|frange| to_proto::location(&snap, frange).ok())
|
||||
.collect_vec()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let title = reference_title(locations.len());
|
||||
let cmd = if locations.is_empty() {
|
||||
Command { title, command: "".into(), arguments: None }
|
||||
} else {
|
||||
show_references_command(
|
||||
title,
|
||||
&doc_position.text_document.uri,
|
||||
code_lens.range.start,
|
||||
locations,
|
||||
)
|
||||
};
|
||||
|
||||
Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None })
|
||||
}
|
||||
None => Ok(CodeLens {
|
||||
range: code_lens.range,
|
||||
command: Some(Command { title: "Error".into(), ..Default::default() }),
|
||||
data: None,
|
||||
}),
|
||||
}
|
||||
Ok(to_proto::code_lens(&snap, snap.analysis.resolve_annotation(annotation)?)?)
|
||||
}
|
||||
|
||||
pub(crate) fn handle_document_highlight(
|
||||
|
@ -1547,43 +1422,6 @@ pub(crate) fn handle_open_cargo_toml(
|
|||
Ok(Some(res))
|
||||
}
|
||||
|
||||
fn implementation_title(count: usize) -> String {
|
||||
if count == 1 {
|
||||
"1 implementation".into()
|
||||
} else {
|
||||
format!("{} implementations", count)
|
||||
}
|
||||
}
|
||||
|
||||
fn reference_title(count: usize) -> String {
|
||||
if count == 1 {
|
||||
"1 reference".into()
|
||||
} else {
|
||||
format!("{} references", count)
|
||||
}
|
||||
}
|
||||
|
||||
fn show_references_command(
|
||||
title: String,
|
||||
uri: &lsp_types::Url,
|
||||
position: lsp_types::Position,
|
||||
locations: Vec<lsp_types::Location>,
|
||||
) -> Command {
|
||||
// We cannot use the 'editor.action.showReferences' command directly
|
||||
// because that command requires vscode types which we convert in the handler
|
||||
// on the client side.
|
||||
|
||||
Command {
|
||||
title,
|
||||
command: "rust-analyzer.showReferences".into(),
|
||||
arguments: Some(vec![
|
||||
to_value(uri).unwrap(),
|
||||
to_value(position).unwrap(),
|
||||
to_value(locations).unwrap(),
|
||||
]),
|
||||
}
|
||||
}
|
||||
|
||||
fn run_single_command(runnable: &lsp_ext::Runnable, title: &str) -> Command {
|
||||
Command {
|
||||
title: title.to_string(),
|
||||
|
@ -1635,8 +1473,8 @@ fn show_impl_command_link(
|
|||
.into_iter()
|
||||
.filter_map(|nav| to_proto::location_from_nav(snap, nav).ok())
|
||||
.collect();
|
||||
let title = implementation_title(locations.len());
|
||||
let command = show_references_command(title, &uri, position, locations);
|
||||
let title = to_proto::implementation_title(locations.len());
|
||||
let command = to_proto::show_references_command(title, &uri, position, locations);
|
||||
|
||||
return Some(lsp_ext::CommandLinkGroup {
|
||||
commands: vec![to_command_link(command, "Go to implementations".into())],
|
||||
|
|
|
@ -377,3 +377,11 @@ impl Request for OpenCargoToml {
|
|||
pub struct OpenCargoTomlParams {
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
}
|
||||
|
||||
/// Information about CodeLens, that is to be resolved.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) enum CodeLensResolveData {
|
||||
Impls(lsp_types::request::GotoImplementationParams),
|
||||
References(lsp_types::TextDocumentPositionParams),
|
||||
}
|
||||
|
|
|
@ -5,13 +5,15 @@ use std::{
|
|||
};
|
||||
|
||||
use ide::{
|
||||
Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId,
|
||||
FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, HlRange, HlTag, Indel,
|
||||
InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, ReferenceAccess,
|
||||
RenameError, Runnable, Severity, SourceChange, TextEdit, TextRange, TextSize,
|
||||
Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind,
|
||||
Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct,
|
||||
HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup,
|
||||
NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity, SourceChange, TextEdit,
|
||||
TextRange, TextSize,
|
||||
};
|
||||
use ide_db::SymbolKind;
|
||||
use itertools::Itertools;
|
||||
use serde_json::to_value;
|
||||
|
||||
use crate::{
|
||||
cargo_target_spec::CargoTargetSpec, global_state::GlobalStateSnapshot,
|
||||
|
@ -863,6 +865,141 @@ pub(crate) fn runnable(
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn code_lens(
|
||||
snap: &GlobalStateSnapshot,
|
||||
annotation: Annotation,
|
||||
) -> Result<lsp_types::CodeLens> {
|
||||
match annotation.kind {
|
||||
AnnotationKind::Runnable { debug, runnable: run } => {
|
||||
let line_index = snap.analysis.file_line_index(run.nav.file_id)?;
|
||||
let annotation_range = range(&line_index, annotation.range);
|
||||
|
||||
let action = run.action();
|
||||
let r = runnable(&snap, run.nav.file_id, run)?;
|
||||
|
||||
let command = if debug {
|
||||
lsp_types::Command {
|
||||
title: action.run_title.to_string(),
|
||||
command: "rust-analyzer.runSingle".into(),
|
||||
arguments: Some(vec![to_value(r).unwrap()]),
|
||||
}
|
||||
} else {
|
||||
lsp_types::Command {
|
||||
title: "Debug".into(),
|
||||
command: "rust-analyzer.debugSingle".into(),
|
||||
arguments: Some(vec![to_value(r).unwrap()]),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(lsp_types::CodeLens { range: annotation_range, command: Some(command), data: None })
|
||||
}
|
||||
AnnotationKind::HasImpls { position: file_position, data } => {
|
||||
let line_index = snap.analysis.file_line_index(file_position.file_id)?;
|
||||
let annotation_range = range(&line_index, annotation.range);
|
||||
let url = url(snap, file_position.file_id);
|
||||
|
||||
let position = position(&line_index, file_position.offset);
|
||||
|
||||
let id = lsp_types::TextDocumentIdentifier { uri: url.clone() };
|
||||
|
||||
let doc_pos = lsp_types::TextDocumentPositionParams::new(id.clone(), position);
|
||||
|
||||
let goto_params = lsp_types::request::GotoImplementationParams {
|
||||
text_document_position_params: doc_pos.clone(),
|
||||
work_done_progress_params: Default::default(),
|
||||
partial_result_params: Default::default(),
|
||||
};
|
||||
|
||||
let command = data.map(|ranges| {
|
||||
let locations: Vec<lsp_types::Location> = ranges
|
||||
.into_iter()
|
||||
.filter_map(|target| {
|
||||
location(
|
||||
snap,
|
||||
FileRange { file_id: target.file_id, range: target.full_range },
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.collect();
|
||||
|
||||
show_references_command(
|
||||
implementation_title(locations.len()),
|
||||
&url,
|
||||
position,
|
||||
locations,
|
||||
)
|
||||
});
|
||||
|
||||
Ok(lsp_types::CodeLens {
|
||||
range: annotation_range,
|
||||
command,
|
||||
data: Some(to_value(lsp_ext::CodeLensResolveData::Impls(goto_params)).unwrap()),
|
||||
})
|
||||
}
|
||||
AnnotationKind::HasReferences { position: file_position, data } => {
|
||||
let line_index = snap.analysis.file_line_index(file_position.file_id)?;
|
||||
let annotation_range = range(&line_index, annotation.range);
|
||||
let url = url(snap, file_position.file_id);
|
||||
|
||||
let position = position(&line_index, file_position.offset);
|
||||
|
||||
let id = lsp_types::TextDocumentIdentifier { uri: url.clone() };
|
||||
|
||||
let doc_pos = lsp_types::TextDocumentPositionParams::new(id, position);
|
||||
|
||||
let command = data.map(|ranges| {
|
||||
let locations: Vec<lsp_types::Location> =
|
||||
ranges.into_iter().filter_map(|range| location(snap, range).ok()).collect();
|
||||
|
||||
show_references_command(reference_title(locations.len()), &url, position, locations)
|
||||
});
|
||||
|
||||
Ok(lsp_types::CodeLens {
|
||||
range: annotation_range,
|
||||
command,
|
||||
data: Some(to_value(lsp_ext::CodeLensResolveData::References(doc_pos)).unwrap()),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn show_references_command(
|
||||
title: String,
|
||||
uri: &lsp_types::Url,
|
||||
position: lsp_types::Position,
|
||||
locations: Vec<lsp_types::Location>,
|
||||
) -> lsp_types::Command {
|
||||
// We cannot use the 'editor.action.showReferences' command directly
|
||||
// because that command requires vscode types which we convert in the handler
|
||||
// on the client side.
|
||||
|
||||
lsp_types::Command {
|
||||
title,
|
||||
command: "rust-analyzer.showReferences".into(),
|
||||
arguments: Some(vec![
|
||||
to_value(uri).unwrap(),
|
||||
to_value(position).unwrap(),
|
||||
to_value(locations).unwrap(),
|
||||
]),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn implementation_title(count: usize) -> String {
|
||||
if count == 1 {
|
||||
"1 implementation".into()
|
||||
} else {
|
||||
format!("{} implementations", count)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reference_title(count: usize) -> String {
|
||||
if count == 1 {
|
||||
"1 reference".into()
|
||||
} else {
|
||||
format!("{} references", count)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent {
|
||||
let value = crate::markdown::format_docs(markup.as_str());
|
||||
lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!---
|
||||
lsp_ext.rs hash: 8f1ae8530f69e3a3
|
||||
lsp_ext.rs hash: 34aec6bfeaeb97a
|
||||
|
||||
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:
|
||||
|
@ -573,3 +573,14 @@ This request is sent from client to server to open the current project's Cargo.t
|
|||
```
|
||||
|
||||
`experimental/openCargoToml` returns a single `Link` to the start of the `[package]` keyword.
|
||||
|
||||
## CodeLens resolve request
|
||||
|
||||
This request is sent from client to server to resolve previously provided CodeLens.
|
||||
|
||||
As an alternative to `any` type in `data` field of `CodeLens`, you may use `CodeLensResolveData`:
|
||||
```typescript
|
||||
interface CodeLensResolveData {
|
||||
data: (DefinitionParams | TextDocumentPositionParams),
|
||||
}
|
||||
```
|
||||
|
|
Loading…
Reference in a new issue