mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Show mod path in hover tooltip
This commit is contained in:
parent
aff82cf7ac
commit
32f5276465
4 changed files with 132 additions and 29 deletions
|
@ -480,6 +480,14 @@ impl Adt {
|
|||
pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
|
||||
Some(self.module(db).krate())
|
||||
}
|
||||
|
||||
pub fn name(&self, db: &impl HirDatabase) -> Name {
|
||||
match self {
|
||||
Adt::Struct(s) => s.name(db),
|
||||
Adt::Union(u) => u.name(db),
|
||||
Adt::Enum(e) => e.name(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -507,6 +515,14 @@ impl VariantDef {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn name(&self, db: &impl HirDatabase) -> Name {
|
||||
match self {
|
||||
VariantDef::Struct(s) => s.name(db),
|
||||
VariantDef::Union(u) => u.name(db),
|
||||
VariantDef::EnumVariant(e) => e.name(db),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
|
||||
match self {
|
||||
VariantDef::Struct(it) => it.variant_data(db),
|
||||
|
@ -534,6 +550,14 @@ impl DefWithBody {
|
|||
DefWithBody::Static(s) => s.module(db),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
|
||||
match self {
|
||||
DefWithBody::Function(f) => Some(f.name(db)),
|
||||
DefWithBody::Static(s) => s.name(db),
|
||||
DefWithBody::Const(c) => c.name(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -68,17 +68,23 @@ pub(crate) fn macro_label(node: &ast::MacroCall) -> String {
|
|||
}
|
||||
|
||||
pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String {
|
||||
rust_code_markup_with_doc::<_, &str>(val, None)
|
||||
rust_code_markup_with_doc::<_, &str>(val, None, None)
|
||||
}
|
||||
|
||||
pub(crate) fn rust_code_markup_with_doc<CODE, DOC>(val: CODE, doc: Option<DOC>) -> String
|
||||
pub(crate) fn rust_code_markup_with_doc<CODE, DOC>(
|
||||
val: CODE,
|
||||
doc: Option<DOC>,
|
||||
mod_path: Option<String>,
|
||||
) -> String
|
||||
where
|
||||
CODE: AsRef<str>,
|
||||
DOC: AsRef<str>,
|
||||
{
|
||||
let mod_path =
|
||||
mod_path.filter(|path| !path.is_empty()).map(|path| path + "\n").unwrap_or_default();
|
||||
if let Some(doc) = doc {
|
||||
format!("```rust\n{}\n```\n\n{}", val.as_ref(), doc.as_ref())
|
||||
format!("```rust\n{}{}\n```\n\n{}", mod_path, val.as_ref(), doc.as_ref())
|
||||
} else {
|
||||
format!("```rust\n{}\n```", val.as_ref())
|
||||
format!("```rust\n{}{}\n```", mod_path, val.as_ref())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//! FIXME: write short doc here
|
||||
|
||||
use hir::{Adt, HasSource, HirDisplay, Semantics};
|
||||
use hir::{
|
||||
Adt, AsAssocItem, AssocItemContainer, HasSource, HirDisplay, ModuleDef, ModuleSource, Semantics,
|
||||
};
|
||||
use ra_ide_db::{
|
||||
defs::{classify_name, classify_name_ref, Definition},
|
||||
RootDatabase,
|
||||
|
@ -16,6 +18,8 @@ use crate::{
|
|||
display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel},
|
||||
FilePosition, RangeInfo,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use std::iter::once;
|
||||
|
||||
/// Contains the results when hovering over an item
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -83,44 +87,86 @@ impl HoverResult {
|
|||
}
|
||||
}
|
||||
|
||||
fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> {
|
||||
match (desc, docs) {
|
||||
(Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)),
|
||||
(None, Some(docs)) => Some(docs),
|
||||
fn hover_text(
|
||||
docs: Option<String>,
|
||||
desc: Option<String>,
|
||||
mod_path: Option<String>,
|
||||
) -> Option<String> {
|
||||
match (desc, docs, mod_path) {
|
||||
(Some(desc), docs, mod_path) => Some(rust_code_markup_with_doc(desc, docs, mod_path)),
|
||||
(None, Some(docs), _) => Some(docs),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
|
||||
match def {
|
||||
Definition::StructField(f) => Some(f.parent_def(db).name(db)),
|
||||
Definition::Local(l) => l.parent(db).name(db),
|
||||
Definition::ModuleDef(md) => match md {
|
||||
ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
|
||||
AssocItemContainer::Trait(t) => Some(t.name(db)),
|
||||
AssocItemContainer::ImplDef(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)),
|
||||
},
|
||||
ModuleDef::EnumVariant(e) => Some(e.parent_enum(db).name(db)),
|
||||
_ => None,
|
||||
},
|
||||
Definition::SelfType(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)),
|
||||
_ => None,
|
||||
}
|
||||
.map(|name| name.to_string())
|
||||
}
|
||||
|
||||
fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
|
||||
let mod_path = def.module(db).map(|module| {
|
||||
once(db.get_crate_original_name(&module.krate().into()))
|
||||
.chain(
|
||||
module
|
||||
.path_to_root(db)
|
||||
.into_iter()
|
||||
.rev()
|
||||
.map(|it| it.name(db).map(|name| name.to_string())),
|
||||
)
|
||||
.chain(once(definition_owner_name(db, def)))
|
||||
.filter_map(std::convert::identity)
|
||||
.join("::")
|
||||
});
|
||||
mod_path
|
||||
}
|
||||
|
||||
fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> {
|
||||
let mod_path = determine_mod_path(db, &def);
|
||||
return match def {
|
||||
Definition::Macro(it) => {
|
||||
let src = it.source(db);
|
||||
hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)))
|
||||
hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path)
|
||||
}
|
||||
Definition::StructField(it) => {
|
||||
let src = it.source(db);
|
||||
match src.value {
|
||||
hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()),
|
||||
hir::FieldSource::Named(it) => {
|
||||
hover_text(it.doc_comment_text(), it.short_label(), mod_path)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Definition::ModuleDef(it) => match it {
|
||||
hir::ModuleDef::Module(it) => match it.definition_source(db).value {
|
||||
hir::ModuleSource::Module(it) => {
|
||||
hover_text(it.doc_comment_text(), it.short_label())
|
||||
ModuleDef::Module(it) => match it.definition_source(db).value {
|
||||
ModuleSource::Module(it) => {
|
||||
hover_text(it.doc_comment_text(), it.short_label(), mod_path)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
hir::ModuleDef::Function(it) => from_def_source(db, it),
|
||||
hir::ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it),
|
||||
hir::ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it),
|
||||
hir::ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it),
|
||||
hir::ModuleDef::EnumVariant(it) => from_def_source(db, it),
|
||||
hir::ModuleDef::Const(it) => from_def_source(db, it),
|
||||
hir::ModuleDef::Static(it) => from_def_source(db, it),
|
||||
hir::ModuleDef::Trait(it) => from_def_source(db, it),
|
||||
hir::ModuleDef::TypeAlias(it) => from_def_source(db, it),
|
||||
hir::ModuleDef::BuiltinType(it) => Some(it.to_string()),
|
||||
ModuleDef::Function(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::EnumVariant(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Const(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Static(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::BuiltinType(it) => Some(it.to_string()),
|
||||
},
|
||||
Definition::Local(it) => {
|
||||
Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string()))
|
||||
|
@ -131,13 +177,13 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
|
|||
}
|
||||
};
|
||||
|
||||
fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String>
|
||||
fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String>
|
||||
where
|
||||
D: HasSource<Ast = A>,
|
||||
A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
|
||||
{
|
||||
let src = def.source(db);
|
||||
hover_text(src.value.doc_comment_text(), src.value.short_label())
|
||||
hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,7 +391,7 @@ mod tests {
|
|||
};
|
||||
}
|
||||
"#,
|
||||
&["field_a: u32"],
|
||||
&["Foo\nfield_a: u32"],
|
||||
);
|
||||
|
||||
// Hovering over the field in the definition
|
||||
|
@ -362,7 +408,7 @@ mod tests {
|
|||
};
|
||||
}
|
||||
"#,
|
||||
&["field_a: u32"],
|
||||
&["Foo\nfield_a: u32"],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -415,7 +461,7 @@ fn main() {
|
|||
",
|
||||
);
|
||||
let hover = analysis.hover(position).unwrap().unwrap();
|
||||
assert_eq!(trim_markup_opt(hover.info.first()), Some("Some"));
|
||||
assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\nSome"));
|
||||
|
||||
let (analysis, position) = single_file_with_position(
|
||||
"
|
||||
|
@ -442,6 +488,7 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
&["
|
||||
Option
|
||||
None
|
||||
```
|
||||
|
||||
|
@ -462,6 +509,7 @@ The None variant
|
|||
}
|
||||
"#,
|
||||
&["
|
||||
Option
|
||||
Some
|
||||
```
|
||||
|
||||
|
@ -815,4 +863,25 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
|||
&["fn foo()\n```\n\n<- `\u{3000}` here"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zzz() {
|
||||
check_hover_result(
|
||||
"
|
||||
//- /main.rs
|
||||
mod vvv {
|
||||
pub struct Test;
|
||||
|
||||
impl Test {
|
||||
pub fn whatever() {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
vvv::Test::what<|>ever();
|
||||
}
|
||||
",
|
||||
&["vvv::Test\npub fn whatever()"],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,6 +104,10 @@ impl RootDatabase {
|
|||
db.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity);
|
||||
db
|
||||
}
|
||||
|
||||
pub fn get_crate_original_name(&self, crate_id: &CrateId) -> Option<String> {
|
||||
self.debug_data.crate_names.get(crate_id).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl salsa::ParallelDatabase for RootDatabase {
|
||||
|
|
Loading…
Reference in a new issue