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;
pub enum InlayKind {
BindingModeHint,
ChainingHint,
- ClosingBraceHint,
+ ClosingBraceHint(Option<TextSize>),
ClosureReturnTypeHint,
GenericParamListHint,
ImplicitReborrowHint,
) -> 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()?;
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,
}
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()?;
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,
}
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;
};
acc.push(InlayHint {
range: closing_token.text_range(),
- kind: InlayKind::ClosingBraceHint,
+ kind: InlayKind::ClosingBraceHint(name_offset),
label,
});
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<InlayHint> {
- 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)
}
pub imports: Vec<CompletionImport>,
}
+#[derive(Debug, Serialize, Deserialize)]
+pub struct InlayHintResolveData {
+ pub position: lsp_types::TextDocumentPositionParams,
+}
+
#[derive(Debug, Serialize, Deserialize)]
pub struct CompletionImport {
pub full_import_path: String,
}
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 {
| 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
| InlayKind::GenericParamListHint
| InlayKind::ImplicitReborrowHint
| InlayKind::TypeHint
- | InlayKind::ClosingBraceHint => false,
+ | InlayKind::ClosingBraceHint(_) => false,
InlayKind::BindingModeHint => inlay_hint.label != "&",
InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
}),
| 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,
+ },
}
}