diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 343a8f7acce..4684f92ae8d 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -8,7 +8,8 @@ use stdx::to_lower_snake_case; use syntax::{ ast::{self, AstNode, HasArgList, HasGenericParams, HasName, UnaryOp}, - match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, T, + match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, + TextSize, T, }; use crate::FileId; @@ -47,7 +48,7 @@ pub enum ReborrowHints { pub enum InlayKind { BindingModeHint, ChainingHint, - ClosingBraceHint, + ClosingBraceHint(Option), ClosureReturnTypeHint, GenericParamListHint, ImplicitReborrowHint, @@ -164,8 +165,10 @@ fn closing_brace_hints( ) -> Option<()> { let min_lines = config.closing_brace_hints_min_lines?; + let name = |it: ast::Name| it.syntax().text_range().start(); + let mut closing_token; - let label = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { + let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { closing_token = item_list.r_curly_token()?; let parent = item_list.syntax().parent()?; @@ -176,13 +179,13 @@ fn closing_brace_hints( let ty = imp.self_ty(sema.db); let trait_ = imp.trait_(sema.db); - match trait_ { + (match trait_ { Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)), None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)), - } + }, None) }, ast::Trait(tr) => { - format!("trait {}", tr.name()?) + (format!("trait {}", tr.name()?), tr.name().map(name)) }, _ => return None, } @@ -191,7 +194,7 @@ fn closing_brace_hints( closing_token = list.r_curly_token()?; let module = ast::Module::cast(list.syntax().parent()?)?; - format!("mod {}", module.name()?) + (format!("mod {}", module.name()?), module.name().map(name)) } else if let Some(block) = ast::BlockExpr::cast(node.clone()) { closing_token = block.stmt_list()?.r_curly_token()?; @@ -201,14 +204,14 @@ fn closing_brace_hints( ast::Fn(it) => { // FIXME: this could include parameters, but `HirDisplay` prints too much info // and doesn't respect the max length either, so the hints end up way too long - format!("fn {}", it.name()?) + (format!("fn {}", it.name()?), it.name().map(name)) }, - ast::Static(it) => format!("static {}", it.name()?), + ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)), ast::Const(it) => { if it.underscore_token().is_some() { - "const _".into() + ("const _".into(), None) } else { - format!("const {}", it.name()?) + (format!("const {}", it.name()?), it.name().map(name)) } }, _ => return None, @@ -221,7 +224,10 @@ fn closing_brace_hints( } closing_token = last_token; - format!("{}!", mac.path()?) + ( + format!("{}!", mac.path()?), + mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()), + ) } else { return None; }; @@ -247,7 +253,7 @@ fn closing_brace_hints( acc.push(InlayHint { range: closing_token.text_range(), - kind: InlayKind::ClosingBraceHint, + kind: InlayKind::ClosingBraceHint(name_offset), label, }); diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index e832f4b45a0..95a6f4f1945 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1343,21 +1343,63 @@ pub(crate) fn handle_inlay_hints( snap.analysis .inlay_hints(&inlay_hints_config, file_id, Some(range))? .into_iter() - .map(|it| to_proto::inlay_hint(inlay_hints_config.render_colons, &line_index, it)) + .map(|it| { + to_proto::inlay_hint( + &line_index, + ¶ms.text_document, + inlay_hints_config.render_colons, + it, + ) + }) .collect(), )) } pub(crate) fn handle_inlay_hints_resolve( - _snap: GlobalStateSnapshot, + snap: GlobalStateSnapshot, mut hint: InlayHint, ) -> Result { - if let lsp_types::InlayHintLabel::String(s) = &hint.label { - hint.tooltip = Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent { - kind: lsp_types::MarkupKind::PlainText, - value: s.clone(), - })); + let _p = profile::span("handle_inlay_hints_resolve"); + let succ = (|| { + let data = match hint.data.take() { + Some(it) => it, + None => return Ok(None), + }; + + let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?; + + let file_range = from_proto::file_range( + &snap, + resolve_data.position.text_document, + Range::new(resolve_data.position.position, resolve_data.position.position), + )?; + let info = match snap.analysis.hover(&snap.config.hover(), file_range)? { + None => return Ok(None), + Some(info) => info, + }; + + let markup_kind = + snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind); + + // FIXME: hover actions? + hint.tooltip = Some(lsp_types::InlayHintTooltip::MarkupContent(to_proto::markup_content( + info.info.markup, + markup_kind, + ))); + Result::<_, crate::Error>::Ok(Some(())) + })()? + .is_some(); + + if !succ { + if let lsp_types::InlayHintLabel::String(s) = &hint.label { + hint.tooltip = + Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent { + kind: lsp_types::MarkupKind::PlainText, + value: s.clone(), + })); + } } + Ok(hint) } diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 1cfaa133274..8e7e2e23642 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -518,6 +518,11 @@ pub struct CompletionResolveData { pub imports: Vec, } +#[derive(Debug, Serialize, Deserialize)] +pub struct InlayHintResolveData { + pub position: lsp_types::TextDocumentPositionParams, +} + #[derive(Debug, Serialize, Deserialize)] pub struct CompletionImport { pub full_import_path: String, diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 83d863ce36b..9287d7c53e3 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -415,8 +415,9 @@ pub(crate) fn signature_help( } pub(crate) fn inlay_hint( - render_colons: bool, line_index: &LineIndex, + text_document: &lsp_types::TextDocumentIdentifier, + render_colons: bool, inlay_hint: InlayHint, ) -> lsp_types::InlayHint { lsp_types::InlayHint { @@ -431,11 +432,11 @@ pub(crate) fn inlay_hint( | InlayKind::ChainingHint | InlayKind::GenericParamListHint | InlayKind::LifetimeHint - | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()), + | InlayKind::ClosingBraceHint(_) => position(line_index, inlay_hint.range.end()), }, padding_left: Some(match inlay_hint.kind { InlayKind::TypeHint => !render_colons, - InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true, + InlayKind::ChainingHint | InlayKind::ClosingBraceHint(_) => true, InlayKind::BindingModeHint | InlayKind::ClosureReturnTypeHint | InlayKind::GenericParamListHint @@ -449,7 +450,7 @@ pub(crate) fn inlay_hint( | InlayKind::GenericParamListHint | InlayKind::ImplicitReborrowHint | InlayKind::TypeHint - | InlayKind::ClosingBraceHint => false, + | InlayKind::ClosingBraceHint(_) => false, InlayKind::BindingModeHint => inlay_hint.label != "&", InlayKind::ParameterHint | InlayKind::LifetimeHint => true, }), @@ -468,11 +469,22 @@ pub(crate) fn inlay_hint( | InlayKind::GenericParamListHint | InlayKind::LifetimeHint | InlayKind::ImplicitReborrowHint - | InlayKind::ClosingBraceHint => None, + | InlayKind::ClosingBraceHint(_) => None, }, text_edits: None, tooltip: None, - data: None, + data: match inlay_hint.kind { + InlayKind::ClosingBraceHint(Some(offset)) => Some( + to_value(lsp_ext::InlayHintResolveData { + position: lsp_types::TextDocumentPositionParams { + text_document: text_document.clone(), + position: position(line_index, offset), + }, + }) + .unwrap(), + ), + _ => None, + }, } }