Add function references hover action

This commit is contained in:
Lukas Wirth 2021-06-04 15:49:43 +02:00
parent cd46255d7e
commit 07394316ff
6 changed files with 75 additions and 1 deletions

View file

@ -28,6 +28,7 @@ use crate::{
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct HoverConfig { pub struct HoverConfig {
pub implementations: bool, pub implementations: bool,
pub references: bool,
pub run: bool, pub run: bool,
pub debug: bool, pub debug: bool,
pub goto_type_def: bool, pub goto_type_def: bool,
@ -38,6 +39,7 @@ pub struct HoverConfig {
impl HoverConfig { impl HoverConfig {
pub const NO_ACTIONS: Self = Self { pub const NO_ACTIONS: Self = Self {
implementations: false, implementations: false,
references: false,
run: false, run: false,
debug: false, debug: false,
goto_type_def: false, goto_type_def: false,
@ -46,7 +48,7 @@ impl HoverConfig {
}; };
pub fn any(&self) -> bool { pub fn any(&self) -> bool {
self.implementations || self.runnable() || self.goto_type_def self.implementations || self.references || self.runnable() || self.goto_type_def
} }
pub fn none(&self) -> bool { pub fn none(&self) -> bool {
@ -62,6 +64,7 @@ impl HoverConfig {
pub enum HoverAction { pub enum HoverAction {
Runnable(Runnable), Runnable(Runnable),
Implementation(FilePosition), Implementation(FilePosition),
Reference(FilePosition),
GoToType(Vec<HoverGotoTypeData>), GoToType(Vec<HoverGotoTypeData>),
} }
@ -148,6 +151,10 @@ pub(crate) fn hover(
res.actions.push(action); res.actions.push(action);
} }
if let Some(action) = show_fn_references_action(db, definition) {
res.actions.push(action);
}
if let Some(action) = runnable_action(&sema, definition, position.file_id) { if let Some(action) = runnable_action(&sema, definition, position.file_id) {
res.actions.push(action); res.actions.push(action);
} }
@ -211,6 +218,18 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
adt.try_to_nav(db).map(to_action) adt.try_to_nav(db).map(to_action)
} }
fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
match def {
Definition::ModuleDef(ModuleDef::Function(it)) => it.try_to_nav(db).map(|nav_target| {
HoverAction::Reference(FilePosition {
file_id: nav_target.file_id,
offset: nav_target.focus_or_full_range().start(),
})
}),
_ => None,
}
}
fn runnable_action( fn runnable_action(
sema: &Semantics<RootDatabase>, sema: &Semantics<RootDatabase>,
def: Definition, def: Definition,
@ -2377,6 +2396,14 @@ fn foo_$0test() {}
"#, "#,
expect![[r#" expect![[r#"
[ [
Reference(
FilePosition {
file_id: FileId(
0,
),
offset: 11,
},
),
Runnable( Runnable(
Runnable { Runnable {
nav: NavigationTarget { nav: NavigationTarget {

View file

@ -152,6 +152,9 @@ config_data! {
/// Whether to show `Implementations` action. Only applies when /// Whether to show `Implementations` action. Only applies when
/// `#rust-analyzer.hoverActions.enable#` is set. /// `#rust-analyzer.hoverActions.enable#` is set.
hoverActions_implementations: bool = "true", hoverActions_implementations: bool = "true",
/// Whether to show `References` action. Only applies when
/// `#rust-analyzer.hoverActions.enable#` is set.
hoverActions_references: bool = "false",
/// Whether to show `Run` action. Only applies when /// Whether to show `Run` action. Only applies when
/// `#rust-analyzer.hoverActions.enable#` is set. /// `#rust-analyzer.hoverActions.enable#` is set.
hoverActions_run: bool = "true", hoverActions_run: bool = "true",
@ -719,6 +722,7 @@ impl Config {
HoverConfig { HoverConfig {
implementations: self.data.hoverActions_enable implementations: self.data.hoverActions_enable
&& self.data.hoverActions_implementations, && self.data.hoverActions_implementations,
references: self.data.hoverActions_enable && self.data.hoverActions_references,
run: self.data.hoverActions_enable && self.data.hoverActions_run, run: self.data.hoverActions_enable && self.data.hoverActions_run,
debug: self.data.hoverActions_enable && self.data.hoverActions_debug, debug: self.data.hoverActions_enable && self.data.hoverActions_debug,
goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef,

View file

@ -1506,6 +1506,36 @@ fn show_impl_command_link(
None None
} }
fn show_ref_command_link(
snap: &GlobalStateSnapshot,
position: &FilePosition,
) -> Option<lsp_ext::CommandLinkGroup> {
if snap.config.hover().implementations {
if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
let uri = to_proto::url(snap, position.file_id);
let line_index = snap.file_line_index(position.file_id).ok()?;
let position = to_proto::position(&line_index, position.offset);
let locations: Vec<_> = ref_search_res
.references
.into_iter()
.flat_map(|(file_id, ranges)| {
ranges.into_iter().filter_map(move |(range, _)| {
to_proto::location(snap, FileRange { file_id, range }).ok()
})
})
.collect();
let title = to_proto::reference_title(locations.len());
let command = to_proto::command::show_references(title, &uri, position, locations);
return Some(lsp_ext::CommandLinkGroup {
commands: vec![to_command_link(command, "Go to references".into())],
..Default::default()
});
}
}
None
}
fn runnable_action_links( fn runnable_action_links(
snap: &GlobalStateSnapshot, snap: &GlobalStateSnapshot,
runnable: Runnable, runnable: Runnable,
@ -1566,6 +1596,7 @@ fn prepare_hover_actions(
.iter() .iter()
.filter_map(|it| match it { .filter_map(|it| match it {
HoverAction::Implementation(position) => show_impl_command_link(snap, position), HoverAction::Implementation(position) => show_impl_command_link(snap, position),
HoverAction::Reference(position) => show_ref_command_link(snap, position),
HoverAction::Runnable(r) => runnable_action_links(snap, r.clone()), HoverAction::Runnable(r) => runnable_action_links(snap, r.clone()),
HoverAction::GoToType(targets) => goto_type_action_links(snap, targets), HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
}) })

View file

@ -228,6 +228,12 @@ Whether to show `Go to Type Definition` action. Only applies when
Whether to show `Implementations` action. Only applies when Whether to show `Implementations` action. Only applies when
`#rust-analyzer.hoverActions.enable#` is set. `#rust-analyzer.hoverActions.enable#` is set.
-- --
[[rust-analyzer.hoverActions.references]]rust-analyzer.hoverActions.references (default: `false`)::
+
--
Whether to show `References` action. Only applies when
`#rust-analyzer.hoverActions.enable#` is set.
--
[[rust-analyzer.hoverActions.run]]rust-analyzer.hoverActions.run (default: `true`):: [[rust-analyzer.hoverActions.run]]rust-analyzer.hoverActions.run (default: `true`)::
+ +
-- --

View file

@ -660,6 +660,11 @@
"default": true, "default": true,
"type": "boolean" "type": "boolean"
}, },
"rust-analyzer.hoverActions.references": {
"markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.",
"default": false,
"type": "boolean"
},
"rust-analyzer.hoverActions.run": { "rust-analyzer.hoverActions.run": {
"markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.", "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.",
"default": true, "default": true,

View file

@ -165,6 +165,7 @@ export class Config {
return { return {
enable: this.get<boolean>("hoverActions.enable"), enable: this.get<boolean>("hoverActions.enable"),
implementations: this.get<boolean>("hoverActions.implementations"), implementations: this.get<boolean>("hoverActions.implementations"),
references: this.get<boolean>("hoverActions.references"),
run: this.get<boolean>("hoverActions.run"), run: this.get<boolean>("hoverActions.run"),
debug: this.get<boolean>("hoverActions.debug"), debug: this.get<boolean>("hoverActions.debug"),
gotoTypeDef: this.get<boolean>("hoverActions.gotoTypeDef"), gotoTypeDef: this.get<boolean>("hoverActions.gotoTypeDef"),