Split hover actions config into its own config struct
This commit is contained in:
parent
8b3d93ee29
commit
99c95b8fa1
@ -1,5 +1,5 @@
|
||||
use either::Either;
|
||||
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay};
|
||||
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
|
||||
use ide_db::{
|
||||
base_db::SourceDatabase,
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
@ -30,41 +30,11 @@
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct HoverConfig {
|
||||
pub implementations: bool,
|
||||
pub references: bool,
|
||||
pub run: bool,
|
||||
pub debug: bool,
|
||||
pub goto_type_def: bool,
|
||||
pub links_in_hover: bool,
|
||||
pub markdown: bool,
|
||||
pub documentation: bool,
|
||||
}
|
||||
|
||||
impl HoverConfig {
|
||||
pub const NO_ACTIONS: Self = Self {
|
||||
implementations: false,
|
||||
references: false,
|
||||
run: false,
|
||||
debug: false,
|
||||
goto_type_def: false,
|
||||
links_in_hover: true,
|
||||
markdown: true,
|
||||
documentation: true,
|
||||
};
|
||||
|
||||
pub fn any_actions(&self) -> bool {
|
||||
self.implementations || self.references || self.runnable() || self.goto_type_def
|
||||
}
|
||||
|
||||
pub fn no_actions(&self) -> bool {
|
||||
!self.any_actions()
|
||||
}
|
||||
|
||||
pub fn runnable(&self) -> bool {
|
||||
self.run || self.debug
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HoverAction {
|
||||
Runnable(Runnable),
|
||||
@ -95,9 +65,7 @@ pub struct HoverResult {
|
||||
pub(crate) fn hover(
|
||||
db: &RootDatabase,
|
||||
position: FilePosition,
|
||||
links_in_hover: bool,
|
||||
documentation: bool,
|
||||
markdown: bool,
|
||||
config: &HoverConfig,
|
||||
) -> Option<RangeInfo<HoverResult>> {
|
||||
let sema = hir::Semantics::new(db);
|
||||
let file = sema.parse(position.file_id).syntax().clone();
|
||||
@ -156,10 +124,14 @@ pub(crate) fn hover(
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(markup) =
|
||||
hover_for_definition(db, definition, famous_defs.as_ref(), documentation)
|
||||
{
|
||||
res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown);
|
||||
if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref(), config) {
|
||||
res.markup = process_markup(
|
||||
sema.db,
|
||||
definition,
|
||||
&markup,
|
||||
config.links_in_hover,
|
||||
config.markdown,
|
||||
);
|
||||
if let Some(action) = show_implementations_action(db, definition) {
|
||||
res.actions.push(action);
|
||||
}
|
||||
@ -181,8 +153,7 @@ pub(crate) fn hover(
|
||||
}
|
||||
}
|
||||
|
||||
if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, documentation, &token)
|
||||
{
|
||||
if let res @ Some(_) = hover_for_keyword(&sema, config, &token) {
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -201,7 +172,7 @@ pub(crate) fn hover(
|
||||
}
|
||||
};
|
||||
|
||||
res.markup = if markdown {
|
||||
res.markup = if config.markdown {
|
||||
Markup::fenced_block(&ty.display(db))
|
||||
} else {
|
||||
ty.display(db).to_string().into()
|
||||
@ -428,7 +399,7 @@ fn hover_for_definition(
|
||||
db: &RootDatabase,
|
||||
def: Definition,
|
||||
famous_defs: Option<&FamousDefs>,
|
||||
documentation: bool,
|
||||
config: &HoverConfig,
|
||||
) -> Option<Markup> {
|
||||
let mod_path = definition_mod_path(db, &def);
|
||||
let (label, docs) = match def {
|
||||
@ -466,7 +437,7 @@ fn hover_for_definition(
|
||||
Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
|
||||
};
|
||||
|
||||
return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path);
|
||||
return hover_markup(docs.filter(|_| config.documentation).map(Into::into), label, mod_path);
|
||||
|
||||
fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
|
||||
where
|
||||
@ -502,13 +473,11 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
|
||||
}
|
||||
|
||||
fn hover_for_keyword(
|
||||
sema: &hir::Semantics<RootDatabase>,
|
||||
links_in_hover: bool,
|
||||
markdown: bool,
|
||||
documentation: bool,
|
||||
sema: &Semantics<RootDatabase>,
|
||||
config: &HoverConfig,
|
||||
token: &SyntaxToken,
|
||||
) -> Option<RangeInfo<HoverResult>> {
|
||||
if !token.kind().is_keyword() || !documentation {
|
||||
if !token.kind().is_keyword() || !config.documentation {
|
||||
return None;
|
||||
}
|
||||
let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate());
|
||||
@ -520,8 +489,8 @@ fn hover_for_keyword(
|
||||
sema.db,
|
||||
Definition::ModuleDef(doc_owner.into()),
|
||||
&hover_markup(Some(docs.into()), token.text().into(), None)?,
|
||||
links_in_hover,
|
||||
markdown,
|
||||
config.links_in_hover,
|
||||
config.markdown,
|
||||
);
|
||||
Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() }))
|
||||
}
|
||||
@ -561,16 +530,28 @@ mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
use ide_db::base_db::FileLoader;
|
||||
|
||||
use crate::fixture;
|
||||
use crate::{fixture, HoverConfig};
|
||||
|
||||
fn check_hover_no_result(ra_fixture: &str) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
assert!(analysis.hover(position, true, true, true).unwrap().is_none());
|
||||
assert!(analysis
|
||||
.hover(
|
||||
position,
|
||||
&HoverConfig { links_in_hover: true, markdown: true, documentation: true }
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let hover = analysis.hover(position, true, true, true).unwrap().unwrap();
|
||||
let hover = analysis
|
||||
.hover(
|
||||
position,
|
||||
&HoverConfig { links_in_hover: true, markdown: true, documentation: true },
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let content = analysis.db.file_text(position.file_id);
|
||||
let hovered_element = &content[hover.range];
|
||||
@ -581,7 +562,13 @@ fn check(ra_fixture: &str, expect: Expect) {
|
||||
|
||||
fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let hover = analysis.hover(position, false, true, true).unwrap().unwrap();
|
||||
let hover = analysis
|
||||
.hover(
|
||||
position,
|
||||
&HoverConfig { links_in_hover: false, markdown: true, documentation: true },
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let content = analysis.db.file_text(position.file_id);
|
||||
let hovered_element = &content[hover.range];
|
||||
@ -592,7 +579,13 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
|
||||
|
||||
fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let hover = analysis.hover(position, true, true, false).unwrap().unwrap();
|
||||
let hover = analysis
|
||||
.hover(
|
||||
position,
|
||||
&HoverConfig { links_in_hover: true, markdown: false, documentation: true },
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let content = analysis.db.file_text(position.file_id);
|
||||
let hovered_element = &content[hover.range];
|
||||
@ -603,7 +596,13 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
|
||||
|
||||
fn check_actions(ra_fixture: &str, expect: Expect) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let hover = analysis.hover(position, true, true, true).unwrap().unwrap();
|
||||
let hover = analysis
|
||||
.hover(
|
||||
position,
|
||||
&HoverConfig { links_in_hover: true, markdown: true, documentation: true },
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
expect.assert_debug_eq(&hover.info.actions)
|
||||
}
|
||||
|
||||
|
@ -408,11 +408,9 @@ pub fn find_all_methods(&self, file_id: FileId) -> Cancellable<Vec<FileRange>> {
|
||||
pub fn hover(
|
||||
&self,
|
||||
position: FilePosition,
|
||||
links_in_hover: bool,
|
||||
documentation: bool,
|
||||
markdown: bool,
|
||||
config: &HoverConfig,
|
||||
) -> Cancellable<Option<RangeInfo<HoverResult>>> {
|
||||
self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown))
|
||||
self.with_db(|db| hover::hover(db, position, config))
|
||||
}
|
||||
|
||||
/// Return URL(s) for the documentation of the symbol under the cursor.
|
||||
|
@ -32,6 +32,9 @@
|
||||
//
|
||||
// However, editor specific config, which the server doesn't know about, should
|
||||
// be specified directly in `package.json`.
|
||||
//
|
||||
// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
|
||||
// parsing the old name.
|
||||
config_data! {
|
||||
struct ConfigData {
|
||||
/// How imports should be grouped into use statements.
|
||||
@ -309,6 +312,37 @@ pub fn references(&self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct HoverActionsConfig {
|
||||
pub implementations: bool,
|
||||
pub references: bool,
|
||||
pub run: bool,
|
||||
pub debug: bool,
|
||||
pub goto_type_def: bool,
|
||||
}
|
||||
|
||||
impl HoverActionsConfig {
|
||||
pub const NO_ACTIONS: Self = Self {
|
||||
implementations: false,
|
||||
references: false,
|
||||
run: false,
|
||||
debug: false,
|
||||
goto_type_def: false,
|
||||
};
|
||||
|
||||
pub fn any(&self) -> bool {
|
||||
self.implementations || self.references || self.runnable() || self.goto_type_def
|
||||
}
|
||||
|
||||
pub fn none(&self) -> bool {
|
||||
!self.any()
|
||||
}
|
||||
|
||||
pub fn runnable(&self) -> bool {
|
||||
self.run || self.debug
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FilesConfig {
|
||||
pub watcher: FilesWatcher,
|
||||
@ -527,7 +561,7 @@ fn experimental(&self, index: &'static str) -> bool {
|
||||
pub fn code_action_group(&self) -> bool {
|
||||
self.experimental("codeActionGroup")
|
||||
}
|
||||
pub fn hover_actions(&self) -> bool {
|
||||
pub fn experimental_hover_actions(&self) -> bool {
|
||||
self.experimental("hoverActions")
|
||||
}
|
||||
pub fn server_status_notification(&self) -> bool {
|
||||
@ -727,17 +761,21 @@ pub fn lens(&self) -> LensConfig {
|
||||
refs: self.data.lens_enable && self.data.lens_references,
|
||||
}
|
||||
}
|
||||
pub fn highlighting_strings(&self) -> bool {
|
||||
self.data.highlighting_strings
|
||||
}
|
||||
pub fn hover(&self) -> HoverConfig {
|
||||
HoverConfig {
|
||||
pub fn hover_actions(&self) -> HoverActionsConfig {
|
||||
HoverActionsConfig {
|
||||
implementations: self.data.hoverActions_enable
|
||||
&& self.data.hoverActions_implementations,
|
||||
references: self.data.hoverActions_enable && self.data.hoverActions_references,
|
||||
run: self.data.hoverActions_enable && self.data.hoverActions_run,
|
||||
debug: self.data.hoverActions_enable && self.data.hoverActions_debug,
|
||||
goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef,
|
||||
}
|
||||
}
|
||||
pub fn highlighting_strings(&self) -> bool {
|
||||
self.data.highlighting_strings
|
||||
}
|
||||
pub fn hover(&self) -> HoverConfig {
|
||||
HoverConfig {
|
||||
links_in_hover: self.data.hover_linksInHover,
|
||||
markdown: try_or!(
|
||||
self.caps
|
||||
|
@ -861,13 +861,7 @@ pub(crate) fn handle_hover(
|
||||
) -> Result<Option<lsp_ext::Hover>> {
|
||||
let _p = profile::span("handle_hover");
|
||||
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
|
||||
let hover_config = snap.config.hover();
|
||||
let info = match snap.analysis.hover(
|
||||
position,
|
||||
hover_config.links_in_hover,
|
||||
hover_config.documentation,
|
||||
hover_config.markdown,
|
||||
)? {
|
||||
let info = match snap.analysis.hover(position, &snap.config.hover())? {
|
||||
None => return Ok(None),
|
||||
Some(info) => info,
|
||||
};
|
||||
@ -1487,7 +1481,7 @@ fn show_impl_command_link(
|
||||
snap: &GlobalStateSnapshot,
|
||||
position: &FilePosition,
|
||||
) -> Option<lsp_ext::CommandLinkGroup> {
|
||||
if snap.config.hover().implementations {
|
||||
if snap.config.hover_actions().implementations {
|
||||
if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
|
||||
let uri = to_proto::url(snap, position.file_id);
|
||||
let line_index = snap.file_line_index(position.file_id).ok()?;
|
||||
@ -1513,7 +1507,7 @@ fn show_ref_command_link(
|
||||
snap: &GlobalStateSnapshot,
|
||||
position: &FilePosition,
|
||||
) -> Option<lsp_ext::CommandLinkGroup> {
|
||||
if snap.config.hover().references {
|
||||
if snap.config.hover_actions().references {
|
||||
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()?;
|
||||
@ -1544,8 +1538,8 @@ fn runnable_action_links(
|
||||
runnable: Runnable,
|
||||
) -> Option<lsp_ext::CommandLinkGroup> {
|
||||
let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
|
||||
let hover_config = snap.config.hover();
|
||||
if !hover_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) {
|
||||
let hover_actions_config = snap.config.hover_actions();
|
||||
if !hover_actions_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -1553,12 +1547,12 @@ fn runnable_action_links(
|
||||
to_proto::runnable(snap, runnable).ok().map(|r| {
|
||||
let mut group = lsp_ext::CommandLinkGroup::default();
|
||||
|
||||
if hover_config.run {
|
||||
if hover_actions_config.run {
|
||||
let run_command = to_proto::command::run_single(&r, action.run_title);
|
||||
group.commands.push(to_command_link(run_command, r.label.clone()));
|
||||
}
|
||||
|
||||
if hover_config.debug {
|
||||
if hover_actions_config.debug {
|
||||
let dbg_command = to_proto::command::debug_single(&r);
|
||||
group.commands.push(to_command_link(dbg_command, r.label));
|
||||
}
|
||||
@ -1571,7 +1565,7 @@ 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() {
|
||||
if !snap.config.hover_actions().goto_type_def || nav_targets.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -1591,7 +1585,7 @@ fn prepare_hover_actions(
|
||||
snap: &GlobalStateSnapshot,
|
||||
actions: &[HoverAction],
|
||||
) -> Vec<lsp_ext::CommandLinkGroup> {
|
||||
if snap.config.hover().no_actions() || !snap.config.hover_actions() {
|
||||
if snap.config.hover_actions().none() || !snap.config.experimental_hover_actions() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user