Implement lens for impls and support resolving lenses.

This commit is contained in:
Jeremy Kolb 2019-02-01 08:44:23 -05:00 committed by kjeremy
parent 13a2bdb0a8
commit 6ac4cca6c1
4 changed files with 97 additions and 3 deletions

View file

@ -33,7 +33,7 @@ pub fn server_capabilities() -> ServerCapabilities {
workspace_symbol_provider: Some(true), workspace_symbol_provider: Some(true),
code_action_provider: Some(CodeActionProviderCapability::Simple(true)), code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
code_lens_provider: Some(CodeLensOptions { code_lens_provider: Some(CodeLensOptions {
resolve_provider: None, resolve_provider: Some(true),
}), }),
document_formatting_provider: Some(true), document_formatting_provider: Some(true),
document_range_formatting_provider: None, document_range_formatting_provider: None,

View file

@ -312,6 +312,7 @@ fn on_request(
.on::<req::Completion>(handlers::handle_completion)? .on::<req::Completion>(handlers::handle_completion)?
.on::<req::CodeActionRequest>(handlers::handle_code_action)? .on::<req::CodeActionRequest>(handlers::handle_code_action)?
.on::<req::CodeLensRequest>(handlers::handle_code_lens)? .on::<req::CodeLensRequest>(handlers::handle_code_lens)?
.on::<req::CodeLensResolve>(handlers::handle_code_lens_resolve)?
.on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
.on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
.on::<req::HoverRequest>(handlers::handle_hover)? .on::<req::HoverRequest>(handlers::handle_hover)?

View file

@ -5,15 +5,17 @@ use lsp_types::{
FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent,
MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range,
RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit,
WorkspaceEdit WorkspaceEdit,
}; };
use ra_ide_api::{ use ra_ide_api::{
FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, Cancelable,
}; };
use ra_syntax::{AstNode, TextUnit}; use ra_syntax::{AstNode, SyntaxKind, TextUnit};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use serde::{Serialize, Deserialize};
use serde_json::to_value; use serde_json::to_value;
use std::io::Write; use std::io::Write;
use url_serde::Ser;
use crate::{ use crate::{
cargo_target_spec::{runnable_args, CargoTargetSpec}, cargo_target_spec::{runnable_args, CargoTargetSpec},
@ -616,6 +618,7 @@ pub fn handle_code_lens(
let mut lenses: Vec<CodeLens> = Default::default(); let mut lenses: Vec<CodeLens> = Default::default();
// Gather runnables
for runnable in world.analysis().runnables(file_id)? { for runnable in world.analysis().runnables(file_id)? {
let title = match &runnable.kind { let title = match &runnable.kind {
RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => { RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => {
@ -652,9 +655,87 @@ pub fn handle_code_lens(
} }
} }
// 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 = it.node_range.conv_with(&line_index);
let pos = range.start;
let lens_params =
req::TextDocumentPositionParams::new(params.text_document.clone(), pos);
CodeLens {
range,
command: None,
data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()),
}
}),
);
return Ok(Some(lenses)); return Ok(Some(lenses));
} }
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
enum CodeLensResolveData {
Impls(req::TextDocumentPositionParams),
}
pub fn handle_code_lens_resolve(world: ServerWorld, code_lens: CodeLens) -> Result<CodeLens> {
let data = code_lens.data.unwrap();
let resolve = serde_json::from_value(data)?;
match resolve {
Some(CodeLensResolveData::Impls(lens_params)) => {
let locations: Vec<Location> =
match handle_goto_implementation(world, lens_params.clone())? {
Some(req::GotoDefinitionResponse::Scalar(loc)) => vec![loc],
Some(req::GotoDefinitionResponse::Array(locs)) => locs,
Some(req::GotoDefinitionResponse::Link(links)) => links
.into_iter()
.map(|link| Location::new(link.target_uri, link.target_selection_range))
.collect(),
_ => vec![],
};
let title = if locations.len() == 1 {
"1 implementation".into()
} else {
format!("{} implementations", locations.len())
};
return Ok(CodeLens {
range: code_lens.range,
command: Some(Command {
title,
command: "rust-analyzer.showReferences".into(),
arguments: Some(vec![
to_value(&Ser::new(&lens_params.text_document.uri)).unwrap(),
to_value(code_lens.range.start).unwrap(),
to_value(locations).unwrap(),
]),
}),
data: None,
});
}
_ => {
return Ok(CodeLens {
range: code_lens.range,
command: Some(Command {
title: "Error".into(),
..Default::default()
}),
data: None,
});
}
}
}
pub fn handle_document_highlight( pub fn handle_document_highlight(
world: ServerWorld, world: ServerWorld,
params: req::TextDocumentPositionParams, params: req::TextDocumentPositionParams,

View file

@ -70,6 +70,18 @@ export function activate(context: vscode.ExtensionContext) {
'rust-analyzer.applySourceChange', 'rust-analyzer.applySourceChange',
commands.applySourceChange.handle commands.applySourceChange.handle
); );
registerCommand(
'rust-analyzer.showReferences',
(uri: string, position: lc.Position, locations: lc.Location[]) => {
vscode.commands.executeCommand(
'editor.action.showReferences',
vscode.Uri.parse(uri),
Server.client.protocol2CodeConverter.asPosition(position),
locations.map(Server.client.protocol2CodeConverter.asLocation)
);
}
);
overrideCommand('type', commands.onEnter.handle); overrideCommand('type', commands.onEnter.handle);
// Notifications are events triggered by the language server // Notifications are events triggered by the language server