mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 23:24:29 +00:00
Add Go to Type Definition
hover action.
This commit is contained in:
parent
4d6c6a6b1e
commit
c50157f330
8 changed files with 956 additions and 35 deletions
|
@ -26,8 +26,8 @@ use hir_ty::{
|
||||||
autoderef,
|
autoderef,
|
||||||
display::{HirDisplayError, HirFormatter},
|
display::{HirDisplayError, HirFormatter},
|
||||||
expr::ExprValidator,
|
expr::ExprValidator,
|
||||||
method_resolution, ApplicationTy, Canonical, InEnvironment, Substs, TraitEnvironment, Ty,
|
method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, OpaqueTyId,
|
||||||
TyDefId, TypeCtor,
|
Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk,
|
||||||
};
|
};
|
||||||
use ra_db::{CrateId, CrateName, Edition, FileId};
|
use ra_db::{CrateId, CrateName, Edition, FileId};
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
|
@ -1380,6 +1380,87 @@ impl Type {
|
||||||
ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
|
ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a flattened list of all the ADTs and Traits mentioned in the type
|
||||||
|
pub fn flattened_type_items(&self, db: &dyn HirDatabase) -> Vec<AdtOrTrait> {
|
||||||
|
fn push_new_item(item: AdtOrTrait, acc: &mut Vec<AdtOrTrait>) {
|
||||||
|
if !acc.contains(&item) {
|
||||||
|
acc.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_bounds(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
predicates: &[GenericPredicate],
|
||||||
|
acc: &mut Vec<AdtOrTrait>,
|
||||||
|
) {
|
||||||
|
for p in predicates.iter() {
|
||||||
|
match p {
|
||||||
|
GenericPredicate::Implemented(trait_ref) => {
|
||||||
|
push_new_item(Trait::from(trait_ref.trait_).into(), acc);
|
||||||
|
walk_types(db, &trait_ref.substs, acc);
|
||||||
|
}
|
||||||
|
GenericPredicate::Projection(_) => {}
|
||||||
|
GenericPredicate::Error => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_types<T: TypeWalk>(db: &dyn HirDatabase, tw: &T, acc: &mut Vec<AdtOrTrait>) {
|
||||||
|
tw.walk(&mut |ty| walk_type(db, ty, acc));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_type(db: &dyn HirDatabase, ty: &Ty, acc: &mut Vec<AdtOrTrait>) {
|
||||||
|
match ty.strip_references() {
|
||||||
|
Ty::Apply(ApplicationTy { ctor, parameters, .. }) => {
|
||||||
|
match ctor {
|
||||||
|
TypeCtor::Adt(adt_id) => push_new_item(Adt::from(*adt_id).into(), acc),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
// adt params, tuples, etc...
|
||||||
|
walk_types(db, parameters, acc);
|
||||||
|
}
|
||||||
|
Ty::Dyn(predicates) => {
|
||||||
|
push_bounds(db, predicates, acc);
|
||||||
|
}
|
||||||
|
Ty::Placeholder(id) => {
|
||||||
|
let generic_params = db.generic_params(id.parent);
|
||||||
|
let param_data = &generic_params.types[id.local_id];
|
||||||
|
match param_data.provenance {
|
||||||
|
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
|
||||||
|
let predicates: Vec<_> = db
|
||||||
|
.generic_predicates_for_param(*id)
|
||||||
|
.into_iter()
|
||||||
|
.map(|pred| pred.value.clone())
|
||||||
|
.collect();
|
||||||
|
push_bounds(db, &predicates, acc);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ty::Opaque(opaque_ty) => {
|
||||||
|
let bounds = match opaque_ty.opaque_ty_id {
|
||||||
|
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
||||||
|
let datas = db
|
||||||
|
.return_type_impl_traits(func)
|
||||||
|
.expect("impl trait id without data");
|
||||||
|
let data = (*datas)
|
||||||
|
.as_ref()
|
||||||
|
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||||
|
data.clone().subst(&opaque_ty.parameters)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
push_bounds(db, &bounds.value, acc);
|
||||||
|
walk_types(db, &opaque_ty.parameters, acc);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res: Vec<AdtOrTrait> = Vec::new(); // not a Set to preserve the order
|
||||||
|
walk_type(db, &self.ty.value, &mut res);
|
||||||
|
res
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HirDisplay for Type {
|
impl HirDisplay for Type {
|
||||||
|
@ -1488,3 +1569,26 @@ pub trait HasVisibility {
|
||||||
vis.is_visible_from(db.upcast(), module.id)
|
vis.is_visible_from(db.upcast(), module.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum AdtOrTrait {
|
||||||
|
Adt(Adt),
|
||||||
|
Trait(Trait),
|
||||||
|
}
|
||||||
|
impl_froms!(AdtOrTrait: Adt, Trait);
|
||||||
|
|
||||||
|
impl AdtOrTrait {
|
||||||
|
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||||
|
match self {
|
||||||
|
AdtOrTrait::Adt(adt) => adt.module(db),
|
||||||
|
AdtOrTrait::Trait(trait_) => trait_.module(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||||
|
match self {
|
||||||
|
AdtOrTrait::Adt(adt) => adt.name(db),
|
||||||
|
AdtOrTrait::Trait(trait_) => trait_.name(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -51,10 +51,10 @@ mod has_source;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
code_model::{
|
code_model::{
|
||||||
Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency,
|
Adt, AdtOrTrait, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate,
|
||||||
DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, GenericDef, HasAttrs,
|
CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function,
|
||||||
HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct,
|
GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef,
|
||||||
Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
|
Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
|
||||||
},
|
},
|
||||||
has_source::HasSource,
|
has_source::HasSource,
|
||||||
semantics::{original_range, PathResolution, Semantics, SemanticsScope},
|
semantics::{original_range, PathResolution, Semantics, SemanticsScope},
|
||||||
|
|
|
@ -1052,10 +1052,10 @@ pub enum OpaqueTyId {
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct ReturnTypeImplTraits {
|
pub struct ReturnTypeImplTraits {
|
||||||
pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
|
pub impl_traits: Vec<ReturnTypeImplTrait>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub(crate) struct ReturnTypeImplTrait {
|
pub struct ReturnTypeImplTrait {
|
||||||
pub(crate) bounds: Binders<Vec<GenericPredicate>>,
|
pub bounds: Binders<Vec<GenericPredicate>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,6 +321,15 @@ impl ToNav for hir::Adt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToNav for hir::AdtOrTrait {
|
||||||
|
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
|
||||||
|
match self {
|
||||||
|
hir::AdtOrTrait::Adt(adt) => adt.to_nav(db),
|
||||||
|
hir::AdtOrTrait::Trait(trait_) => trait_.to_nav(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToNav for hir::AssocItem {
|
impl ToNav for hir::AssocItem {
|
||||||
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
|
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
use hir::{
|
use hir::{
|
||||||
Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay,
|
Adt, AdtOrTrait, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource,
|
||||||
ModuleDef, ModuleSource, Semantics,
|
HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ra_db::SourceDatabase;
|
use ra_db::SourceDatabase;
|
||||||
|
@ -24,19 +24,21 @@ pub struct HoverConfig {
|
||||||
pub implementations: bool,
|
pub implementations: bool,
|
||||||
pub run: bool,
|
pub run: bool,
|
||||||
pub debug: bool,
|
pub debug: bool,
|
||||||
|
pub goto_type_def: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HoverConfig {
|
impl Default for HoverConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { implementations: true, run: true, debug: true }
|
Self { implementations: true, run: true, debug: true, goto_type_def: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HoverConfig {
|
impl HoverConfig {
|
||||||
pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false };
|
pub const NO_ACTIONS: Self =
|
||||||
|
Self { implementations: false, run: false, debug: false, goto_type_def: false };
|
||||||
|
|
||||||
pub fn any(&self) -> bool {
|
pub fn any(&self) -> bool {
|
||||||
self.implementations || self.runnable()
|
self.implementations || self.runnable() || self.goto_type_def
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn none(&self) -> bool {
|
pub fn none(&self) -> bool {
|
||||||
|
@ -52,6 +54,13 @@ impl HoverConfig {
|
||||||
pub enum HoverAction {
|
pub enum HoverAction {
|
||||||
Runnable(Runnable),
|
Runnable(Runnable),
|
||||||
Implementaion(FilePosition),
|
Implementaion(FilePosition),
|
||||||
|
GoToType(Vec<HoverGotoTypeData>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct HoverGotoTypeData {
|
||||||
|
pub mod_path: String,
|
||||||
|
pub nav: NavigationTarget,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains the results when hovering over an item
|
/// Contains the results when hovering over an item
|
||||||
|
@ -138,6 +147,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
|
||||||
res.push_action(action);
|
res.push_action(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(action) = goto_type_action(db, name_kind) {
|
||||||
|
res.push_action(action);
|
||||||
|
}
|
||||||
|
|
||||||
return Some(RangeInfo::new(range, res));
|
return Some(RangeInfo::new(range, res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +231,24 @@ fn runnable_action(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
|
||||||
|
match def {
|
||||||
|
Definition::Local(it) => {
|
||||||
|
let ty = it.ty(db);
|
||||||
|
let v = ty.flattened_type_items(db);
|
||||||
|
let targets = v.into_iter()
|
||||||
|
.map(|it| HoverGotoTypeData {
|
||||||
|
mod_path: adt_or_trait_mod_path(db, &it),
|
||||||
|
nav: it.to_nav(db),
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
Some(HoverAction::GoToType(targets))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn hover_text(
|
fn hover_text(
|
||||||
docs: Option<String>,
|
docs: Option<String>,
|
||||||
desc: Option<String>,
|
desc: Option<String>,
|
||||||
|
@ -248,25 +279,30 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
|
||||||
.map(|name| name.to_string())
|
.map(|name| name.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
|
fn determine_mod_path(db: &RootDatabase, module: Module, name: Option<String>) -> String {
|
||||||
let mod_path = def.module(db).map(|module| {
|
once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string))
|
||||||
once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string))
|
.chain(
|
||||||
.chain(
|
module
|
||||||
module
|
.path_to_root(db)
|
||||||
.path_to_root(db)
|
.into_iter()
|
||||||
.into_iter()
|
.rev()
|
||||||
.rev()
|
.map(|it| it.name(db).map(|name| name.to_string())),
|
||||||
.map(|it| it.name(db).map(|name| name.to_string())),
|
)
|
||||||
)
|
.chain(once(name))
|
||||||
.chain(once(definition_owner_name(db, def)))
|
.flatten()
|
||||||
.flatten()
|
.join("::")
|
||||||
.join("::")
|
}
|
||||||
});
|
|
||||||
mod_path
|
fn adt_or_trait_mod_path(db: &RootDatabase, item: &AdtOrTrait) -> String {
|
||||||
|
determine_mod_path(db, item.module(db), Some(item.name(db).to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
|
||||||
|
def.module(db).map(|module| determine_mod_path(db, module, definition_owner_name(db, def)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> {
|
fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> {
|
||||||
let mod_path = determine_mod_path(db, &def);
|
let mod_path = definition_mod_path(db, &def);
|
||||||
return match def {
|
return match def {
|
||||||
Definition::Macro(it) => {
|
Definition::Macro(it) => {
|
||||||
let src = it.source(db);
|
let src = it.source(db);
|
||||||
|
@ -1310,4 +1346,737 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
]
|
]
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_struct_has_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /main.rs
|
||||||
|
struct S{ f1: u32 }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s<|>t = S{ f1:0 };
|
||||||
|
}
|
||||||
|
",
|
||||||
|
&["S"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "S",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..19,
|
||||||
|
name: "S",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
7..8,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct S",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_generic_struct_has_goto_type_actions() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /main.rs
|
||||||
|
struct Arg(u32);
|
||||||
|
struct S<T>{ f1: T }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s<|>t = S{ f1:Arg(0) };
|
||||||
|
}
|
||||||
|
",
|
||||||
|
&["S<Arg>"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "S",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 17..37,
|
||||||
|
name: "S",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
24..25,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct S",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Arg",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..16,
|
||||||
|
name: "Arg",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
7..10,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct Arg",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_generic_struct_has_flattened_goto_type_actions() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /main.rs
|
||||||
|
struct Arg(u32);
|
||||||
|
struct S<T>{ f1: T }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s<|>t = S{ f1: S{ f1: Arg(0) } };
|
||||||
|
}
|
||||||
|
",
|
||||||
|
&["S<S<Arg>>"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "S",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 17..37,
|
||||||
|
name: "S",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
24..25,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct S",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Arg",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..16,
|
||||||
|
name: "Arg",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
7..10,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct Arg",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_tuple_has_goto_type_actions() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /main.rs
|
||||||
|
struct A(u32);
|
||||||
|
struct B(u32);
|
||||||
|
mod M {
|
||||||
|
pub struct C(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s<|>t = (A(1), B(2), M::C(3) );
|
||||||
|
}
|
||||||
|
",
|
||||||
|
&["(A, B, C)"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "A",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..14,
|
||||||
|
name: "A",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
7..8,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct A",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "B",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 15..29,
|
||||||
|
name: "B",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
22..23,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct B",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "M::C",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 42..60,
|
||||||
|
name: "C",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
53..54,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"pub struct C",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_return_impl_trait_has_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /main.rs
|
||||||
|
trait Foo {}
|
||||||
|
|
||||||
|
fn foo() -> impl Foo {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s<|>t = foo();
|
||||||
|
}
|
||||||
|
",
|
||||||
|
&["impl Foo"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Foo",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..12,
|
||||||
|
name: "Foo",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
6..9,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait Foo",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_generic_return_impl_trait_has_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /main.rs
|
||||||
|
trait Foo<T> {}
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
fn foo() -> impl Foo<S> {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s<|>t = foo();
|
||||||
|
}
|
||||||
|
",
|
||||||
|
&["impl Foo<S>"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Foo",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..15,
|
||||||
|
name: "Foo",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
6..9,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait Foo",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "S",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 16..25,
|
||||||
|
name: "S",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
23..24,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct S",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_arg_impl_trait_has_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /lib.rs
|
||||||
|
trait Foo {}
|
||||||
|
fn foo(ar<|>g: &impl Foo) {}
|
||||||
|
",
|
||||||
|
&["&impl Foo"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Foo",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..12,
|
||||||
|
name: "Foo",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
6..9,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait Foo",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /lib.rs
|
||||||
|
trait Foo<T> {}
|
||||||
|
struct S {}
|
||||||
|
fn foo(ar<|>g: &impl Foo<S>) {}
|
||||||
|
",
|
||||||
|
&["&impl Foo<S>"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Foo",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..15,
|
||||||
|
name: "Foo",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
6..9,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait Foo",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "S",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 16..27,
|
||||||
|
name: "S",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
23..24,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct S",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_dyn_return_has_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /main.rs
|
||||||
|
trait Foo {}
|
||||||
|
struct S;
|
||||||
|
impl Foo for S {}
|
||||||
|
|
||||||
|
struct B<T>{}
|
||||||
|
|
||||||
|
fn foo() -> B<dyn Foo> {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s<|>t = foo();
|
||||||
|
}
|
||||||
|
",
|
||||||
|
&["B<dyn Foo>"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "B",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 41..54,
|
||||||
|
name: "B",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
48..49,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct B",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Foo",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..12,
|
||||||
|
name: "Foo",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
6..9,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait Foo",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_dyn_arg_has_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /lib.rs
|
||||||
|
trait Foo {}
|
||||||
|
fn foo(ar<|>g: &dyn Foo) {}
|
||||||
|
",
|
||||||
|
&["&dyn Foo"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Foo",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..12,
|
||||||
|
name: "Foo",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
6..9,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait Foo",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_generic_dyn_arg_has_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /lib.rs
|
||||||
|
trait Foo<T> {}
|
||||||
|
struct S {}
|
||||||
|
fn foo(ar<|>g: &dyn Foo<S>) {}
|
||||||
|
",
|
||||||
|
&["&dyn Foo<S>"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "Foo",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..15,
|
||||||
|
name: "Foo",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
6..9,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait Foo",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "S",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 16..27,
|
||||||
|
name: "S",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
23..24,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct S",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hover_arg_goto_type_action() {
|
||||||
|
let (_, actions) = check_hover_result(
|
||||||
|
"
|
||||||
|
//- /lib.rs
|
||||||
|
trait ImplTrait<T> {}
|
||||||
|
trait DynTrait<T> {}
|
||||||
|
struct B<T> {}
|
||||||
|
struct S {}
|
||||||
|
|
||||||
|
fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<S>>>) {}
|
||||||
|
",
|
||||||
|
&["&impl ImplTrait<B<dyn DynTrait<S>>>"],
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(actions,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
GoToType(
|
||||||
|
[
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "ImplTrait",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 0..21,
|
||||||
|
name: "ImplTrait",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
6..15,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait ImplTrait",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "S",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 58..69,
|
||||||
|
name: "S",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
65..66,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct S",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "DynTrait",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 22..42,
|
||||||
|
name: "DynTrait",
|
||||||
|
kind: TRAIT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
28..36,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"trait DynTrait",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HoverGotoTypeData {
|
||||||
|
mod_path: "B",
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
full_range: 43..57,
|
||||||
|
name: "B",
|
||||||
|
kind: STRUCT_DEF,
|
||||||
|
focus_range: Some(
|
||||||
|
50..51,
|
||||||
|
),
|
||||||
|
container_name: None,
|
||||||
|
description: Some(
|
||||||
|
"struct B",
|
||||||
|
),
|
||||||
|
docs: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ pub use crate::{
|
||||||
display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
|
display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
|
||||||
expand_macro::ExpandedMacro,
|
expand_macro::ExpandedMacro,
|
||||||
folding_ranges::{Fold, FoldKind},
|
folding_ranges::{Fold, FoldKind},
|
||||||
hover::{HoverAction, HoverConfig, HoverResult},
|
hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
|
||||||
inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
|
inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
|
||||||
references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
|
references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
|
||||||
runnables::{Runnable, RunnableKind, TestId},
|
runnables::{Runnable, RunnableKind, TestId},
|
||||||
|
|
|
@ -296,6 +296,7 @@ impl Config {
|
||||||
set(value, "/hoverActions/implementations", &mut self.hover.implementations);
|
set(value, "/hoverActions/implementations", &mut self.hover.implementations);
|
||||||
set(value, "/hoverActions/run", &mut self.hover.run);
|
set(value, "/hoverActions/run", &mut self.hover.run);
|
||||||
set(value, "/hoverActions/debug", &mut self.hover.debug);
|
set(value, "/hoverActions/debug", &mut self.hover.debug);
|
||||||
|
set(value, "/hoverActions/gotoTypeDef", &mut self.hover.goto_type_def);
|
||||||
} else {
|
} else {
|
||||||
self.hover = HoverConfig::NO_ACTIONS;
|
self.hover = HoverConfig::NO_ACTIONS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ use lsp_types::{
|
||||||
TextDocumentIdentifier, Url, WorkspaceEdit,
|
TextDocumentIdentifier, Url, WorkspaceEdit,
|
||||||
};
|
};
|
||||||
use ra_ide::{
|
use ra_ide::{
|
||||||
FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, Runnable, RunnableKind,
|
FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
|
||||||
SearchScope, TextEdit,
|
RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit,
|
||||||
};
|
};
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
use ra_project_model::TargetKind;
|
use ra_project_model::TargetKind;
|
||||||
|
@ -1150,6 +1150,23 @@ fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> Option<Command> {
|
||||||
|
let value = if snap.config.client_caps.location_link {
|
||||||
|
let link = to_proto::location_link(snap, None, nav.clone()).ok()?;
|
||||||
|
to_value(link).ok()?
|
||||||
|
} else {
|
||||||
|
let range = FileRange { file_id: nav.file_id(), range: nav.range() };
|
||||||
|
let location = to_proto::location(snap, range).ok()?;
|
||||||
|
to_value(location).ok()?
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Command {
|
||||||
|
title: nav.name().to_string(),
|
||||||
|
command: "rust-analyzer.gotoLocation".into(),
|
||||||
|
arguments: Some(vec![value]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink {
|
fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink {
|
||||||
lsp_ext::CommandLink { tooltip: Some(tooltip), command }
|
lsp_ext::CommandLink { tooltip: Some(tooltip), command }
|
||||||
}
|
}
|
||||||
|
@ -1180,7 +1197,7 @@ fn show_impl_command_link(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_runnable_action(
|
fn runnable_action_links(
|
||||||
snap: &GlobalStateSnapshot,
|
snap: &GlobalStateSnapshot,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
runnable: Runnable,
|
runnable: Runnable,
|
||||||
|
@ -1208,6 +1225,26 @@ fn to_runnable_action(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn goto_type_action_links(
|
||||||
|
snap: &GlobalStateSnapshot,
|
||||||
|
nav_targets: &[HoverGotoTypeData],
|
||||||
|
) -> Option<lsp_ext::CommandLinkGroup> {
|
||||||
|
if !snap.config.hover.goto_type_def || nav_targets.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(lsp_ext::CommandLinkGroup {
|
||||||
|
title: Some("Go to ".into()),
|
||||||
|
commands: nav_targets
|
||||||
|
.iter()
|
||||||
|
.filter_map(|it| {
|
||||||
|
goto_location_command(snap, &it.nav)
|
||||||
|
.map(|cmd| to_command_link(cmd, it.mod_path.clone()))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn prepare_hover_actions(
|
fn prepare_hover_actions(
|
||||||
snap: &GlobalStateSnapshot,
|
snap: &GlobalStateSnapshot,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
|
@ -1221,7 +1258,8 @@ fn prepare_hover_actions(
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|it| match it {
|
.filter_map(|it| match it {
|
||||||
HoverAction::Implementaion(position) => show_impl_command_link(snap, position),
|
HoverAction::Implementaion(position) => show_impl_command_link(snap, position),
|
||||||
HoverAction::Runnable(r) => to_runnable_action(snap, file_id, r.clone()),
|
HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()),
|
||||||
|
HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue