feat: Completed the client side implementation of rust-analyzer/hoverRange

This commit is contained in:
Alexander Gonzalez 2021-07-25 17:26:54 -04:00
parent 8ca3bb8fcd
commit 18644720eb
7 changed files with 129 additions and 30 deletions

View file

@ -867,28 +867,40 @@ pub(crate) fn handle_signature_help(
pub(crate) fn handle_hover( pub(crate) fn handle_hover(
snap: GlobalStateSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::HoverParams, params: lsp_types::HoverParams,
) -> Result<Option<lsp_ext::Hover>> { ) -> Result<Option<lsp_ext::Hover>> {
let _p = profile::span("handle_hover"); let _p = profile::span("handle_hover");
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let info = match snap.analysis.hover(&snap.config.hover(), position)? {
None => return Ok(None),
Some(info) => info,
};
let line_index = snap.file_line_index(position.file_id)?;
let range = to_proto::range(&line_index, info.range);
let hover = lsp_ext::Hover {
hover: lsp_types::Hover {
contents: HoverContents::Markup(to_proto::markup_content(info.info.markup)),
range: Some(range),
},
actions: prepare_hover_actions(&snap, &info.info.actions),
};
Ok(Some(hover))
}
pub(crate) fn handle_hover_range(
snap: GlobalStateSnapshot,
params: lsp_ext::HoverRangeParams,
) -> Result<Option<lsp_ext::Hover>> {
let _p = profile::span("handle_hover_range");
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let range = from_proto::file_range(&snap, params.text_document, params.range)?; let range = from_proto::file_range(&snap, params.text_document, params.range)?;
let info = if range.range.is_empty() { log::info!("Triggered range hover");
// It's a hover over a position let info = match snap.analysis.hover_range(&snap.config.hover(), range)? {
match snap None => return Ok(None),
.analysis Some(info) => info,
.hover(&snap.config.hover(), FilePosition { file_id, offset: range.range.start() })?
{
None => return Ok(None),
Some(info) => info,
}
} else {
// It's a hover over a range
log::info!("Triggered range hover");
match snap.analysis.hover_range(&snap.config.hover(), range)? {
None => return Ok(None),
Some(info) => info,
}
}; };
let line_index = snap.file_line_index(range.file_id)?; let line_index = snap.file_line_index(range.file_id)?;

View file

@ -376,14 +376,22 @@ pub struct SnippetTextEdit {
pub enum HoverRequest {} pub enum HoverRequest {}
impl Request for HoverRequest { impl Request for HoverRequest {
type Params = HoverParams; type Params = lsp_types::HoverParams;
type Result = Option<Hover>; type Result = Option<Hover>;
const METHOD: &'static str = "textDocument/hover"; const METHOD: &'static str = "textDocument/hover";
} }
pub enum HoverRangeRequest {}
impl Request for HoverRangeRequest {
type Params = HoverRangeParams;
type Result = Option<Hover>;
const METHOD: &'static str = "rust-analyzer/hoverRange";
}
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct HoverParams { pub struct HoverRangeParams {
pub text_document: TextDocumentIdentifier, pub text_document: TextDocumentIdentifier,
pub range: Range, pub range: Range,
} }

View file

@ -542,6 +542,7 @@ impl GlobalState {
.on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action) .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)
.on::<lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve) .on::<lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve)
.on::<lsp_ext::HoverRequest>(handlers::handle_hover) .on::<lsp_ext::HoverRequest>(handlers::handle_hover)
.on::<lsp_ext::HoverRangeRequest>(handlers::handle_hover_range)
.on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs) .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
.on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml) .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
.on::<lsp_ext::MoveItem>(handlers::handle_move_item) .on::<lsp_ext::MoveItem>(handlers::handle_move_item)

View file

@ -56,21 +56,67 @@ export function createClient(serverPath: string, workspace: Workspace, extraEnv:
traceOutputChannel, traceOutputChannel,
middleware: { middleware: {
async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, _next: lc.ProvideHoverSignature) { async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, _next: lc.ProvideHoverSignature) {
return client.sendRequest(lc.HoverRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then( const editor = vscode.window.activeTextEditor;
(result) => { const selection = editor?.selection;
const hover = client.protocol2CodeConverter.asHover(result); return selection?.contains(position)
if (hover) { ? client
.sendRequest(
ra.hoverRange,
{
textDocument:
client.code2ProtocolConverter.asTextDocumentIdentifier(
document
),
range: client.code2ProtocolConverter.asRange(
editor?.selection
),
},
token
)
.then(
(result) =>
client.protocol2CodeConverter.asHover(result),
(error) => {
client.handleFailedRequest(
lc.HoverRequest.type,
undefined,
error,
null
);
return Promise.resolve(null);
}
)
: client
.sendRequest(
lc.HoverRequest.type,
client.code2ProtocolConverter.asTextDocumentPositionParams(
document,
position
),
token
)
.then(
(result) => {
const hover =
client.protocol2CodeConverter.asHover(result);
if (hover) {
const actions = (<any>result).actions; const actions = (<any>result).actions;
if (actions) { if (actions) {
hover.contents.push(renderHoverActions(actions)); hover.contents.push(renderHoverActions(actions));
} }
}
return hover;
},
(error) => {
client.handleFailedRequest(
lc.HoverRequest.type,
token,
error,
null
);
return Promise.resolve(null);
} }
return hover; );
},
(error) => {
client.handleFailedRequest(lc.HoverRequest.type, token, error, null);
return Promise.resolve(null);
});
}, },
// Using custom handling of CodeActions to support action groups and snippet edits. // Using custom handling of CodeActions to support action groups and snippet edits.
// Note that this means we have to re-implement lazy edit resolving ourselves as well. // Note that this means we have to re-implement lazy edit resolving ourselves as well.

View file

@ -116,6 +116,30 @@ export function matchingBrace(ctx: Ctx): Cmd {
}; };
} }
export function hoverRange(ctx: Ctx): Cmd {
return async () => {
const editor = ctx.activeRustEditor;
const client = ctx.client;
if (!editor || !client) return;
client
.sendRequest(ra.hoverRange, {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
editor.document
),
range: client.code2ProtocolConverter.asRange(editor.selection),
})
.then(
(result) => client.protocol2CodeConverter.asHover(result),
(error) => {
client.handleFailedRequest(lc.HoverRequest.type, undefined, error, null);
return Promise.resolve(null);
}
);
};
}
export function joinLines(ctx: Ctx): Cmd { export function joinLines(ctx: Ctx): Cmd {
return async () => { return async () => {
const editor = ctx.activeRustEditor; const editor = ctx.activeRustEditor;

View file

@ -19,6 +19,13 @@ export const serverStatus = new lc.NotificationType<ServerStatusParams>("experim
export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace"); export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace");
export const hoverRange = new lc.RequestType<HoverRangeParams, lc.Hover | null, void>("rust-analyzer/hoverRange");
export interface HoverRangeParams {
textDocument: lc.TextDocumentIdentifier;
range: lc.Range;
}
export interface SyntaxTreeParams { export interface SyntaxTreeParams {
textDocument: lc.TextDocumentIdentifier; textDocument: lc.TextDocumentIdentifier;
range: lc.Range | null; range: lc.Range | null;

View file

@ -118,6 +118,7 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
ctx.registerCommand('reloadWorkspace', commands.reloadWorkspace); ctx.registerCommand('reloadWorkspace', commands.reloadWorkspace);
ctx.registerCommand('matchingBrace', commands.matchingBrace); ctx.registerCommand('matchingBrace', commands.matchingBrace);
ctx.registerCommand('joinLines', commands.joinLines); ctx.registerCommand('joinLines', commands.joinLines);
ctx.registerCommand('hoverRange', commands.hoverRange);
ctx.registerCommand('parentModule', commands.parentModule); ctx.registerCommand('parentModule', commands.parentModule);
ctx.registerCommand('syntaxTree', commands.syntaxTree); ctx.registerCommand('syntaxTree', commands.syntaxTree);
ctx.registerCommand('viewHir', commands.viewHir); ctx.registerCommand('viewHir', commands.viewHir);