diff options
-rw-r--r-- | crates/assists/src/handlers/auto_import.rs | 8 | ||||
-rw-r--r-- | crates/assists/src/handlers/expand_glob_import.rs | 8 | ||||
-rw-r--r-- | crates/assists/src/handlers/extract_struct_from_enum_variant.rs | 7 | ||||
-rw-r--r-- | crates/assists/src/handlers/replace_qualified_name_with_use.rs | 26 | ||||
-rw-r--r-- | crates/hir_def/src/path.rs | 26 | ||||
-rw-r--r-- | crates/ide/src/fn_references.rs | 95 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 113 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 14 | ||||
-rw-r--r-- | crates/ide/src/link_rewrite.rs | 37 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 23 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 56 | ||||
-rw-r--r-- | crates/syntax/src/ast/make.rs | 33 | ||||
-rw-r--r-- | editors/code/package.json | 5 | ||||
-rw-r--r-- | editors/code/src/config.ts | 1 |
15 files changed, 385 insertions, 69 deletions
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index ee7277c04..fa524ffd9 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use std::collections::BTreeSet; | 1 | use std::collections::BTreeSet; |
2 | 2 | ||
3 | use ast::make; | ||
4 | use either::Either; | 3 | use either::Either; |
5 | use hir::{ | 4 | use hir::{ |
6 | AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, | 5 | AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, |
@@ -54,11 +53,8 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
54 | format!("Import `{}`", &import), | 53 | format!("Import `{}`", &import), |
55 | range, | 54 | range, |
56 | |builder| { | 55 | |builder| { |
57 | let new_syntax = insert_use( | 56 | let new_syntax = |
58 | &scope, | 57 | insert_use(&scope, import.to_ast_path(), ctx.config.insert_use.merge); |
59 | make::path_from_text(&import.to_string()), | ||
60 | ctx.config.insert_use.merge, | ||
61 | ); | ||
62 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 58 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
63 | }, | 59 | }, |
64 | ); | 60 | ); |
diff --git a/crates/assists/src/handlers/expand_glob_import.rs b/crates/assists/src/handlers/expand_glob_import.rs index e14ac7f65..d1adff972 100644 --- a/crates/assists/src/handlers/expand_glob_import.rs +++ b/crates/assists/src/handlers/expand_glob_import.rs | |||
@@ -264,12 +264,8 @@ fn replace_ast( | |||
264 | match use_trees.as_slice() { | 264 | match use_trees.as_slice() { |
265 | [name] => { | 265 | [name] => { |
266 | if let Some(end_path) = name.path() { | 266 | if let Some(end_path) = name.path() { |
267 | let replacement = make::use_tree( | 267 | let replacement = |
268 | make::path_from_text(&format!("{}::{}", path, end_path)), | 268 | make::use_tree(make::path_concat(path, end_path), None, None, false); |
269 | None, | ||
270 | None, | ||
271 | false, | ||
272 | ); | ||
273 | 269 | ||
274 | algo::diff( | 270 | algo::diff( |
275 | &parent.either(|n| n.syntax().clone(), |n| n.syntax().clone()), | 271 | &parent.either(|n| n.syntax().clone(), |n| n.syntax().clone()), |
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index 3ea50f375..d1eadaa99 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -12,7 +12,6 @@ use syntax::{ | |||
12 | use crate::{ | 12 | use crate::{ |
13 | assist_context::AssistBuilder, utils::insert_use, AssistContext, AssistId, AssistKind, Assists, | 13 | assist_context::AssistBuilder, utils::insert_use, AssistContext, AssistId, AssistKind, Assists, |
14 | }; | 14 | }; |
15 | use ast::make; | ||
16 | use insert_use::ImportScope; | 15 | use insert_use::ImportScope; |
17 | 16 | ||
18 | // Assist: extract_struct_from_enum_variant | 17 | // Assist: extract_struct_from_enum_variant |
@@ -112,11 +111,7 @@ fn insert_import( | |||
112 | let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; | 111 | let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; |
113 | let syntax = scope.as_syntax_node(); | 112 | let syntax = scope.as_syntax_node(); |
114 | 113 | ||
115 | let new_syntax = insert_use( | 114 | let new_syntax = insert_use(&scope, mod_path.to_ast_path(), ctx.config.insert_use.merge); |
116 | &scope, | ||
117 | make::path_from_text(&mod_path.to_string()), | ||
118 | ctx.config.insert_use.merge, | ||
119 | ); | ||
120 | // FIXME: this will currently panic as multiple imports will have overlapping text ranges | 115 | // FIXME: this will currently panic as multiple imports will have overlapping text ranges |
121 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 116 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
122 | } | 117 | } |
diff --git a/crates/assists/src/handlers/replace_qualified_name_with_use.rs b/crates/assists/src/handlers/replace_qualified_name_with_use.rs index 8ac907707..74afc123b 100644 --- a/crates/assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -1,11 +1,10 @@ | |||
1 | use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode, TextRange}; | 1 | use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode}; |
2 | use test_utils::mark; | 2 | use test_utils::mark; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | utils::{insert_use, ImportScope}, | 5 | utils::{insert_use, ImportScope}, |
6 | AssistContext, AssistId, AssistKind, Assists, | 6 | AssistContext, AssistId, AssistKind, Assists, |
7 | }; | 7 | }; |
8 | use ast::make; | ||
9 | 8 | ||
10 | // Assist: replace_qualified_name_with_use | 9 | // Assist: replace_qualified_name_with_use |
11 | // | 10 | // |
@@ -33,15 +32,6 @@ pub(crate) fn replace_qualified_name_with_use( | |||
33 | mark::hit!(dont_import_trivial_paths); | 32 | mark::hit!(dont_import_trivial_paths); |
34 | return None; | 33 | return None; |
35 | } | 34 | } |
36 | let path_to_import = path.to_string(); | ||
37 | let path_to_import = match path.segment()?.generic_arg_list() { | ||
38 | Some(generic_args) => { | ||
39 | let generic_args_start = | ||
40 | generic_args.syntax().text_range().start() - path.syntax().text_range().start(); | ||
41 | &path_to_import[TextRange::up_to(generic_args_start)] | ||
42 | } | ||
43 | None => path_to_import.as_str(), | ||
44 | }; | ||
45 | 35 | ||
46 | let target = path.syntax().text_range(); | 36 | let target = path.syntax().text_range(); |
47 | let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; | 37 | let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; |
@@ -54,14 +44,10 @@ pub(crate) fn replace_qualified_name_with_use( | |||
54 | // Now that we've brought the name into scope, re-qualify all paths that could be | 44 | // Now that we've brought the name into scope, re-qualify all paths that could be |
55 | // affected (that is, all paths inside the node we added the `use` to). | 45 | // affected (that is, all paths inside the node we added the `use` to). |
56 | let mut rewriter = SyntaxRewriter::default(); | 46 | let mut rewriter = SyntaxRewriter::default(); |
57 | shorten_paths(&mut rewriter, syntax.clone(), path); | 47 | shorten_paths(&mut rewriter, syntax.clone(), &path); |
58 | let rewritten_syntax = rewriter.rewrite(&syntax); | 48 | let rewritten_syntax = rewriter.rewrite(&syntax); |
59 | if let Some(ref import_scope) = ImportScope::from(rewritten_syntax) { | 49 | if let Some(ref import_scope) = ImportScope::from(rewritten_syntax) { |
60 | let new_syntax = insert_use( | 50 | let new_syntax = insert_use(import_scope, path, ctx.config.insert_use.merge); |
61 | import_scope, | ||
62 | make::path_from_text(path_to_import), | ||
63 | ctx.config.insert_use.merge, | ||
64 | ); | ||
65 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 51 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
66 | } | 52 | } |
67 | }, | 53 | }, |
@@ -69,7 +55,7 @@ pub(crate) fn replace_qualified_name_with_use( | |||
69 | } | 55 | } |
70 | 56 | ||
71 | /// Adds replacements to `re` that shorten `path` in all descendants of `node`. | 57 | /// Adds replacements to `re` that shorten `path` in all descendants of `node`. |
72 | fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: ast::Path) { | 58 | fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: &ast::Path) { |
73 | for child in node.children() { | 59 | for child in node.children() { |
74 | match_ast! { | 60 | match_ast! { |
75 | match child { | 61 | match child { |
@@ -82,10 +68,10 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: | |||
82 | ast::Path(p) => { | 68 | ast::Path(p) => { |
83 | match maybe_replace_path(rewriter, p.clone(), path.clone()) { | 69 | match maybe_replace_path(rewriter, p.clone(), path.clone()) { |
84 | Some(()) => {}, | 70 | Some(()) => {}, |
85 | None => shorten_paths(rewriter, p.syntax().clone(), path.clone()), | 71 | None => shorten_paths(rewriter, p.syntax().clone(), path), |
86 | } | 72 | } |
87 | }, | 73 | }, |
88 | _ => shorten_paths(rewriter, child, path.clone()), | 74 | _ => shorten_paths(rewriter, child, path), |
89 | } | 75 | } |
90 | } | 76 | } |
91 | } | 77 | } |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 734310458..209b18e78 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -13,7 +13,7 @@ use hir_expand::{ | |||
13 | hygiene::Hygiene, | 13 | hygiene::Hygiene, |
14 | name::{AsName, Name}, | 14 | name::{AsName, Name}, |
15 | }; | 15 | }; |
16 | use syntax::ast; | 16 | use syntax::ast::{self, make}; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | type_ref::{TypeBound, TypeRef}, | 19 | type_ref::{TypeBound, TypeRef}, |
@@ -100,6 +100,26 @@ impl ModPath { | |||
100 | } | 100 | } |
101 | self.segments.first() | 101 | self.segments.first() |
102 | } | 102 | } |
103 | |||
104 | pub fn to_ast_path(&self) -> ast::Path { | ||
105 | let mut segments = Vec::new(); | ||
106 | let mut is_abs = false; | ||
107 | match self.kind { | ||
108 | PathKind::Plain => {} | ||
109 | PathKind::Super(0) => segments.push(make::path_segment_self()), | ||
110 | PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())), | ||
111 | PathKind::Crate => segments.push(make::path_segment_crate()), | ||
112 | PathKind::Abs => is_abs = true, | ||
113 | PathKind::DollarCrate(_) => (), | ||
114 | } | ||
115 | |||
116 | segments.extend( | ||
117 | self.segments | ||
118 | .iter() | ||
119 | .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))), | ||
120 | ); | ||
121 | make::path_from_segments(segments, is_abs) | ||
122 | } | ||
103 | } | 123 | } |
104 | 124 | ||
105 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 125 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -286,10 +306,8 @@ impl Display for ModPath { | |||
286 | }; | 306 | }; |
287 | match self.kind { | 307 | match self.kind { |
288 | PathKind::Plain => {} | 308 | PathKind::Plain => {} |
309 | PathKind::Super(0) => add_segment("self")?, | ||
289 | PathKind::Super(n) => { | 310 | PathKind::Super(n) => { |
290 | if n == 0 { | ||
291 | add_segment("self")?; | ||
292 | } | ||
293 | for _ in 0..n { | 311 | for _ in 0..n { |
294 | add_segment("super")?; | 312 | add_segment("super")?; |
295 | } | 313 | } |
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/fn_references.rs new file mode 100644 index 000000000..1989a562b --- /dev/null +++ b/crates/ide/src/fn_references.rs | |||
@@ -0,0 +1,95 @@ | |||
1 | //! This module implements a methods and free functions search in the specified file. | ||
2 | //! We have to skip tests, so cannot reuse file_structure module. | ||
3 | |||
4 | use hir::Semantics; | ||
5 | use ide_db::RootDatabase; | ||
6 | use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode}; | ||
7 | |||
8 | use crate::{runnables::has_test_related_attribute, FileId, FileRange}; | ||
9 | |||
10 | pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> { | ||
11 | let sema = Semantics::new(db); | ||
12 | let source_file = sema.parse(file_id); | ||
13 | source_file.syntax().descendants().filter_map(|it| method_range(it, file_id)).collect() | ||
14 | } | ||
15 | |||
16 | fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> { | ||
17 | ast::Fn::cast(item).and_then(|fn_def| { | ||
18 | if has_test_related_attribute(&fn_def) { | ||
19 | None | ||
20 | } else { | ||
21 | fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() }) | ||
22 | } | ||
23 | }) | ||
24 | } | ||
25 | |||
26 | #[cfg(test)] | ||
27 | mod tests { | ||
28 | use crate::mock_analysis::analysis_and_position; | ||
29 | use crate::{FileRange, TextSize}; | ||
30 | use std::ops::RangeInclusive; | ||
31 | |||
32 | #[test] | ||
33 | fn test_find_all_methods() { | ||
34 | let (analysis, pos) = analysis_and_position( | ||
35 | r#" | ||
36 | //- /lib.rs | ||
37 | fn private_fn() {<|>} | ||
38 | |||
39 | pub fn pub_fn() {} | ||
40 | |||
41 | pub fn generic_fn<T>(arg: T) {} | ||
42 | "#, | ||
43 | ); | ||
44 | |||
45 | let refs = analysis.find_all_methods(pos.file_id).unwrap(); | ||
46 | check_result(&refs, &[3..=13, 27..=33, 47..=57]); | ||
47 | } | ||
48 | |||
49 | #[test] | ||
50 | fn test_find_trait_methods() { | ||
51 | let (analysis, pos) = analysis_and_position( | ||
52 | r#" | ||
53 | //- /lib.rs | ||
54 | trait Foo { | ||
55 | fn bar() {<|>} | ||
56 | fn baz() {} | ||
57 | } | ||
58 | "#, | ||
59 | ); | ||
60 | |||
61 | let refs = analysis.find_all_methods(pos.file_id).unwrap(); | ||
62 | check_result(&refs, &[19..=22, 35..=38]); | ||
63 | } | ||
64 | |||
65 | #[test] | ||
66 | fn test_skip_tests() { | ||
67 | let (analysis, pos) = analysis_and_position( | ||
68 | r#" | ||
69 | //- /lib.rs | ||
70 | #[test] | ||
71 | fn foo() {<|>} | ||
72 | |||
73 | pub fn pub_fn() {} | ||
74 | |||
75 | mod tests { | ||
76 | #[test] | ||
77 | fn bar() {} | ||
78 | } | ||
79 | "#, | ||
80 | ); | ||
81 | |||
82 | let refs = analysis.find_all_methods(pos.file_id).unwrap(); | ||
83 | check_result(&refs, &[28..=34]); | ||
84 | } | ||
85 | |||
86 | fn check_result(refs: &[FileRange], expected: &[RangeInclusive<u32>]) { | ||
87 | assert_eq!(refs.len(), expected.len()); | ||
88 | |||
89 | for (i, item) in refs.iter().enumerate() { | ||
90 | let range = &expected[i]; | ||
91 | assert_eq!(TextSize::from(*range.start()), item.range.start()); | ||
92 | assert_eq!(TextSize::from(*range.end()), item.range.end()); | ||
93 | } | ||
94 | } | ||
95 | } | ||
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 37171cbef..bb9f12cd3 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -14,7 +14,7 @@ use test_utils::mark; | |||
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | display::{macro_label, ShortLabel, ToNav, TryToNav}, | 16 | display::{macro_label, ShortLabel, ToNav, TryToNav}, |
17 | link_rewrite::rewrite_links, | 17 | link_rewrite::{remove_links, rewrite_links}, |
18 | markup::Markup, | 18 | markup::Markup, |
19 | runnables::runnable, | 19 | runnables::runnable, |
20 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | 20 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, |
@@ -26,17 +26,29 @@ pub struct HoverConfig { | |||
26 | pub run: bool, | 26 | pub run: bool, |
27 | pub debug: bool, | 27 | pub debug: bool, |
28 | pub goto_type_def: bool, | 28 | pub goto_type_def: bool, |
29 | pub links_in_hover: bool, | ||
29 | } | 30 | } |
30 | 31 | ||
31 | impl Default for HoverConfig { | 32 | impl Default for HoverConfig { |
32 | fn default() -> Self { | 33 | fn default() -> Self { |
33 | Self { implementations: true, run: true, debug: true, goto_type_def: true } | 34 | Self { |
35 | implementations: true, | ||
36 | run: true, | ||
37 | debug: true, | ||
38 | goto_type_def: true, | ||
39 | links_in_hover: true, | ||
40 | } | ||
34 | } | 41 | } |
35 | } | 42 | } |
36 | 43 | ||
37 | impl HoverConfig { | 44 | impl HoverConfig { |
38 | pub const NO_ACTIONS: Self = | 45 | pub const NO_ACTIONS: Self = Self { |
39 | Self { implementations: false, run: false, debug: false, goto_type_def: false }; | 46 | implementations: false, |
47 | run: false, | ||
48 | debug: false, | ||
49 | goto_type_def: false, | ||
50 | links_in_hover: true, | ||
51 | }; | ||
40 | 52 | ||
41 | pub fn any(&self) -> bool { | 53 | pub fn any(&self) -> bool { |
42 | self.implementations || self.runnable() || self.goto_type_def | 54 | self.implementations || self.runnable() || self.goto_type_def |
@@ -75,7 +87,11 @@ pub struct HoverResult { | |||
75 | // | 87 | // |
76 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. | 88 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. |
77 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. | 89 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. |
78 | pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { | 90 | pub(crate) fn hover( |
91 | db: &RootDatabase, | ||
92 | position: FilePosition, | ||
93 | links_in_hover: bool, | ||
94 | ) -> Option<RangeInfo<HoverResult>> { | ||
79 | let sema = Semantics::new(db); | 95 | let sema = Semantics::new(db); |
80 | let file = sema.parse(position.file_id).syntax().clone(); | 96 | let file = sema.parse(position.file_id).syntax().clone(); |
81 | let token = pick_best(file.token_at_offset(position.offset))?; | 97 | let token = pick_best(file.token_at_offset(position.offset))?; |
@@ -93,7 +109,11 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
93 | }; | 109 | }; |
94 | if let Some(definition) = definition { | 110 | if let Some(definition) = definition { |
95 | if let Some(markup) = hover_for_definition(db, definition) { | 111 | if let Some(markup) = hover_for_definition(db, definition) { |
96 | let markup = rewrite_links(db, &markup.as_str(), &definition); | 112 | let markup = if links_in_hover { |
113 | rewrite_links(db, &markup.as_str(), &definition) | ||
114 | } else { | ||
115 | remove_links(&markup.as_str()) | ||
116 | }; | ||
97 | res.markup = Markup::from(markup); | 117 | res.markup = Markup::from(markup); |
98 | if let Some(action) = show_implementations_action(db, definition) { | 118 | if let Some(action) = show_implementations_action(db, definition) { |
99 | res.actions.push(action); | 119 | res.actions.push(action); |
@@ -363,12 +383,23 @@ mod tests { | |||
363 | 383 | ||
364 | fn check_hover_no_result(ra_fixture: &str) { | 384 | fn check_hover_no_result(ra_fixture: &str) { |
365 | let (analysis, position) = analysis_and_position(ra_fixture); | 385 | let (analysis, position) = analysis_and_position(ra_fixture); |
366 | assert!(analysis.hover(position).unwrap().is_none()); | 386 | assert!(analysis.hover(position, true).unwrap().is_none()); |
367 | } | 387 | } |
368 | 388 | ||
369 | fn check(ra_fixture: &str, expect: Expect) { | 389 | fn check(ra_fixture: &str, expect: Expect) { |
370 | let (analysis, position) = analysis_and_position(ra_fixture); | 390 | let (analysis, position) = analysis_and_position(ra_fixture); |
371 | let hover = analysis.hover(position).unwrap().unwrap(); | 391 | let hover = analysis.hover(position, true).unwrap().unwrap(); |
392 | |||
393 | let content = analysis.db.file_text(position.file_id); | ||
394 | let hovered_element = &content[hover.range]; | ||
395 | |||
396 | let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup); | ||
397 | expect.assert_eq(&actual) | ||
398 | } | ||
399 | |||
400 | fn check_hover_no_links(ra_fixture: &str, expect: Expect) { | ||
401 | let (analysis, position) = analysis_and_position(ra_fixture); | ||
402 | let hover = analysis.hover(position, false).unwrap().unwrap(); | ||
372 | 403 | ||
373 | let content = analysis.db.file_text(position.file_id); | 404 | let content = analysis.db.file_text(position.file_id); |
374 | let hovered_element = &content[hover.range]; | 405 | let hovered_element = &content[hover.range]; |
@@ -379,7 +410,7 @@ mod tests { | |||
379 | 410 | ||
380 | fn check_actions(ra_fixture: &str, expect: Expect) { | 411 | fn check_actions(ra_fixture: &str, expect: Expect) { |
381 | let (analysis, position) = analysis_and_position(ra_fixture); | 412 | let (analysis, position) = analysis_and_position(ra_fixture); |
382 | let hover = analysis.hover(position).unwrap().unwrap(); | 413 | let hover = analysis.hover(position, true).unwrap().unwrap(); |
383 | expect.assert_debug_eq(&hover.info.actions) | 414 | expect.assert_debug_eq(&hover.info.actions) |
384 | } | 415 | } |
385 | 416 | ||
@@ -1810,6 +1841,70 @@ struct S { | |||
1810 | } | 1841 | } |
1811 | 1842 | ||
1812 | #[test] | 1843 | #[test] |
1844 | fn test_hover_no_links() { | ||
1845 | check_hover_no_links( | ||
1846 | r#" | ||
1847 | /// Test cases: | ||
1848 | /// case 1. bare URL: https://www.example.com/ | ||
1849 | /// case 2. inline URL with title: [example](https://www.example.com/) | ||
1850 | /// case 3. code refrence: [`Result`] | ||
1851 | /// case 4. code refrence but miss footnote: [`String`] | ||
1852 | /// case 5. autolink: <http://www.example.com/> | ||
1853 | /// case 6. email address: <[email protected]> | ||
1854 | /// case 7. refrence: [example][example] | ||
1855 | /// case 8. collapsed link: [example][] | ||
1856 | /// case 9. shortcut link: [example] | ||
1857 | /// case 10. inline without URL: [example]() | ||
1858 | /// case 11. refrence: [foo][foo] | ||
1859 | /// case 12. refrence: [foo][bar] | ||
1860 | /// case 13. collapsed link: [foo][] | ||
1861 | /// case 14. shortcut link: [foo] | ||
1862 | /// case 15. inline without URL: [foo]() | ||
1863 | /// case 16. just escaped text: \[foo] | ||
1864 | /// case 17. inline link: [Foo](foo::Foo) | ||
1865 | /// | ||
1866 | /// [`Result`]: ../../std/result/enum.Result.html | ||
1867 | /// [^example]: https://www.example.com/ | ||
1868 | pub fn fo<|>o() {} | ||
1869 | "#, | ||
1870 | expect![[r#" | ||
1871 | *foo* | ||
1872 | |||
1873 | ```rust | ||
1874 | test | ||
1875 | ``` | ||
1876 | |||
1877 | ```rust | ||
1878 | pub fn foo() | ||
1879 | ``` | ||
1880 | |||
1881 | --- | ||
1882 | |||
1883 | Test cases: | ||
1884 | case 1. bare URL: https://www.example.com/ | ||
1885 | case 2. inline URL with title: [example](https://www.example.com/) | ||
1886 | case 3. code refrence: `Result` | ||
1887 | case 4. code refrence but miss footnote: `String` | ||
1888 | case 5. autolink: http://www.example.com/ | ||
1889 | case 6. email address: [email protected] | ||
1890 | case 7. refrence: example | ||
1891 | case 8. collapsed link: example | ||
1892 | case 9. shortcut link: example | ||
1893 | case 10. inline without URL: example | ||
1894 | case 11. refrence: foo | ||
1895 | case 12. refrence: foo | ||
1896 | case 13. collapsed link: foo | ||
1897 | case 14. shortcut link: foo | ||
1898 | case 15. inline without URL: foo | ||
1899 | case 16. just escaped text: \[foo] | ||
1900 | case 17. inline link: Foo | ||
1901 | |||
1902 | [^example]: https://www.example.com/ | ||
1903 | "#]], | ||
1904 | ); | ||
1905 | } | ||
1906 | |||
1907 | #[test] | ||
1813 | fn test_hover_macro_generated_struct_fn_doc_comment() { | 1908 | fn test_hover_macro_generated_struct_fn_doc_comment() { |
1814 | mark::check!(hover_macro_generated_struct_fn_doc_comment); | 1909 | mark::check!(hover_macro_generated_struct_fn_doc_comment); |
1815 | 1910 | ||
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 3b97e087f..31f2bcba3 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -38,6 +38,7 @@ mod join_lines; | |||
38 | mod matching_brace; | 38 | mod matching_brace; |
39 | mod parent_module; | 39 | mod parent_module; |
40 | mod references; | 40 | mod references; |
41 | mod fn_references; | ||
41 | mod runnables; | 42 | mod runnables; |
42 | mod status; | 43 | mod status; |
43 | mod syntax_highlighting; | 44 | mod syntax_highlighting; |
@@ -369,9 +370,18 @@ impl Analysis { | |||
369 | }) | 370 | }) |
370 | } | 371 | } |
371 | 372 | ||
373 | /// Finds all methods and free functions for the file. Does not return tests! | ||
374 | pub fn find_all_methods(&self, file_id: FileId) -> Cancelable<Vec<FileRange>> { | ||
375 | self.with_db(|db| fn_references::find_all_methods(db, file_id)) | ||
376 | } | ||
377 | |||
372 | /// Returns a short text describing element at position. | 378 | /// Returns a short text describing element at position. |
373 | pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<HoverResult>>> { | 379 | pub fn hover( |
374 | self.with_db(|db| hover::hover(db, position)) | 380 | &self, |
381 | position: FilePosition, | ||
382 | links_in_hover: bool, | ||
383 | ) -> Cancelable<Option<RangeInfo<HoverResult>>> { | ||
384 | self.with_db(|db| hover::hover(db, position, links_in_hover)) | ||
375 | } | 385 | } |
376 | 386 | ||
377 | /// Computes parameter information for the given call expression. | 387 | /// Computes parameter information for the given call expression. |
diff --git a/crates/ide/src/link_rewrite.rs b/crates/ide/src/link_rewrite.rs index acedea71b..107787bb9 100644 --- a/crates/ide/src/link_rewrite.rs +++ b/crates/ide/src/link_rewrite.rs | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | use hir::{Adt, Crate, HasAttrs, ModuleDef}; | 5 | use hir::{Adt, Crate, HasAttrs, ModuleDef}; |
6 | use ide_db::{defs::Definition, RootDatabase}; | 6 | use ide_db::{defs::Definition, RootDatabase}; |
7 | use pulldown_cmark::{CowStr, Event, Options, Parser, Tag}; | 7 | use pulldown_cmark::{CowStr, Event, LinkType, Options, Parser, Tag}; |
8 | use pulldown_cmark_to_cmark::{cmark_with_options, Options as CmarkOptions}; | 8 | use pulldown_cmark_to_cmark::{cmark_with_options, Options as CmarkOptions}; |
9 | use url::Url; | 9 | use url::Url; |
10 | 10 | ||
@@ -45,6 +45,41 @@ pub fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) | |||
45 | out | 45 | out |
46 | } | 46 | } |
47 | 47 | ||
48 | /// Remove all links in markdown documentation. | ||
49 | pub fn remove_links(markdown: &str) -> String { | ||
50 | let mut drop_link = false; | ||
51 | |||
52 | let mut opts = Options::empty(); | ||
53 | opts.insert(Options::ENABLE_FOOTNOTES); | ||
54 | |||
55 | let doc = Parser::new_with_broken_link_callback( | ||
56 | markdown, | ||
57 | opts, | ||
58 | Some(&|_, _| Some((String::new(), String::new()))), | ||
59 | ); | ||
60 | let doc = doc.filter_map(move |evt| match evt { | ||
61 | Event::Start(Tag::Link(link_type, ref target, ref title)) => { | ||
62 | if link_type == LinkType::Inline && target.contains("://") { | ||
63 | Some(Event::Start(Tag::Link(link_type, target.clone(), title.clone()))) | ||
64 | } else { | ||
65 | drop_link = true; | ||
66 | None | ||
67 | } | ||
68 | } | ||
69 | Event::End(_) if drop_link => { | ||
70 | drop_link = false; | ||
71 | None | ||
72 | } | ||
73 | _ => Some(evt), | ||
74 | }); | ||
75 | |||
76 | let mut out = String::new(); | ||
77 | let mut options = CmarkOptions::default(); | ||
78 | options.code_block_backticks = 3; | ||
79 | cmark_with_options(doc, &mut out, None, options).ok(); | ||
80 | out | ||
81 | } | ||
82 | |||
48 | fn rewrite_intra_doc_link( | 83 | fn rewrite_intra_doc_link( |
49 | db: &RootDatabase, | 84 | db: &RootDatabase, |
50 | def: Definition, | 85 | def: Definition, |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 989a63c09..cfeff40c1 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -203,7 +203,7 @@ impl TestAttr { | |||
203 | /// | 203 | /// |
204 | /// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test, | 204 | /// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test, |
205 | /// but it's better than not to have the runnables for the tests at all. | 205 | /// but it's better than not to have the runnables for the tests at all. |
206 | fn has_test_related_attribute(fn_def: &ast::Fn) -> bool { | 206 | pub(crate) fn has_test_related_attribute(fn_def: &ast::Fn) -> bool { |
207 | fn_def | 207 | fn_def |
208 | .attrs() | 208 | .attrs() |
209 | .filter_map(|attr| attr.path()) | 209 | .filter_map(|attr| attr.path()) |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 69d05aed5..42e1ad376 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -74,19 +74,18 @@ pub struct LensConfig { | |||
74 | pub run: bool, | 74 | pub run: bool, |
75 | pub debug: bool, | 75 | pub debug: bool, |
76 | pub implementations: bool, | 76 | pub implementations: bool, |
77 | pub method_refs: bool, | ||
77 | } | 78 | } |
78 | 79 | ||
79 | impl Default for LensConfig { | 80 | impl Default for LensConfig { |
80 | fn default() -> Self { | 81 | fn default() -> Self { |
81 | Self { run: true, debug: true, implementations: true } | 82 | Self { run: true, debug: true, implementations: true, method_refs: false } |
82 | } | 83 | } |
83 | } | 84 | } |
84 | 85 | ||
85 | impl LensConfig { | 86 | impl LensConfig { |
86 | pub const NO_LENS: LensConfig = Self { run: false, debug: false, implementations: false }; | ||
87 | |||
88 | pub fn any(&self) -> bool { | 87 | pub fn any(&self) -> bool { |
89 | self.implementations || self.runnable() | 88 | self.implementations || self.runnable() || self.references() |
90 | } | 89 | } |
91 | 90 | ||
92 | pub fn none(&self) -> bool { | 91 | pub fn none(&self) -> bool { |
@@ -96,6 +95,10 @@ impl LensConfig { | |||
96 | pub fn runnable(&self) -> bool { | 95 | pub fn runnable(&self) -> bool { |
97 | self.run || self.debug | 96 | self.run || self.debug |
98 | } | 97 | } |
98 | |||
99 | pub fn references(&self) -> bool { | ||
100 | self.method_refs | ||
101 | } | ||
99 | } | 102 | } |
100 | 103 | ||
101 | #[derive(Debug, Clone)] | 104 | #[derive(Debug, Clone)] |
@@ -278,6 +281,7 @@ impl Config { | |||
278 | run: data.lens_enable && data.lens_run, | 281 | run: data.lens_enable && data.lens_run, |
279 | debug: data.lens_enable && data.lens_debug, | 282 | debug: data.lens_enable && data.lens_debug, |
280 | implementations: data.lens_enable && data.lens_implementations, | 283 | implementations: data.lens_enable && data.lens_implementations, |
284 | method_refs: data.lens_enable && data.lens_methodReferences, | ||
281 | }; | 285 | }; |
282 | 286 | ||
283 | if !data.linkedProjects.is_empty() { | 287 | if !data.linkedProjects.is_empty() { |
@@ -307,6 +311,7 @@ impl Config { | |||
307 | run: data.hoverActions_enable && data.hoverActions_run, | 311 | run: data.hoverActions_enable && data.hoverActions_run, |
308 | debug: data.hoverActions_enable && data.hoverActions_debug, | 312 | debug: data.hoverActions_enable && data.hoverActions_debug, |
309 | goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef, | 313 | goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef, |
314 | links_in_hover: data.hoverActions_linksInHover, | ||
310 | }; | 315 | }; |
311 | 316 | ||
312 | log::info!("Config::update() = {:#?}", self); | 317 | log::info!("Config::update() = {:#?}", self); |
@@ -451,16 +456,18 @@ config_data! { | |||
451 | hoverActions_gotoTypeDef: bool = true, | 456 | hoverActions_gotoTypeDef: bool = true, |
452 | hoverActions_implementations: bool = true, | 457 | hoverActions_implementations: bool = true, |
453 | hoverActions_run: bool = true, | 458 | hoverActions_run: bool = true, |
459 | hoverActions_linksInHover: bool = true, | ||
454 | 460 | ||
455 | inlayHints_chainingHints: bool = true, | 461 | inlayHints_chainingHints: bool = true, |
456 | inlayHints_maxLength: Option<usize> = None, | 462 | inlayHints_maxLength: Option<usize> = None, |
457 | inlayHints_parameterHints: bool = true, | 463 | inlayHints_parameterHints: bool = true, |
458 | inlayHints_typeHints: bool = true, | 464 | inlayHints_typeHints: bool = true, |
459 | 465 | ||
460 | lens_debug: bool = true, | 466 | lens_debug: bool = true, |
461 | lens_enable: bool = true, | 467 | lens_enable: bool = true, |
462 | lens_implementations: bool = true, | 468 | lens_implementations: bool = true, |
463 | lens_run: bool = true, | 469 | lens_run: bool = true, |
470 | lens_methodReferences: bool = false, | ||
464 | 471 | ||
465 | linkedProjects: Vec<ManifestOrProjectJson> = Vec::new(), | 472 | linkedProjects: Vec<ManifestOrProjectJson> = Vec::new(), |
466 | lruCapacity: Option<usize> = None, | 473 | lruCapacity: Option<usize> = None, |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index c0943a54d..7ac1a30f6 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -11,6 +11,7 @@ use ide::{ | |||
11 | FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query, | 11 | FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query, |
12 | RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit, | 12 | RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit, |
13 | }; | 13 | }; |
14 | use itertools::Itertools; | ||
14 | use lsp_server::ErrorCode; | 15 | use lsp_server::ErrorCode; |
15 | use lsp_types::{ | 16 | use lsp_types::{ |
16 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, | 17 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, |
@@ -597,7 +598,7 @@ pub(crate) fn handle_hover( | |||
597 | ) -> Result<Option<lsp_ext::Hover>> { | 598 | ) -> Result<Option<lsp_ext::Hover>> { |
598 | let _p = profile::span("handle_hover"); | 599 | let _p = profile::span("handle_hover"); |
599 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; | 600 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
600 | let info = match snap.analysis.hover(position)? { | 601 | let info = match snap.analysis.hover(position, snap.config.hover.links_in_hover)? { |
601 | None => return Ok(None), | 602 | None => return Ok(None), |
602 | Some(info) => info, | 603 | Some(info) => info, |
603 | }; | 604 | }; |
@@ -952,6 +953,22 @@ pub(crate) fn handle_code_lens( | |||
952 | }), | 953 | }), |
953 | ); | 954 | ); |
954 | } | 955 | } |
956 | |||
957 | if snap.config.lens.references() { | ||
958 | lenses.extend(snap.analysis.find_all_methods(file_id)?.into_iter().map(|it| { | ||
959 | let range = to_proto::range(&line_index, it.range); | ||
960 | let position = to_proto::position(&line_index, it.range.start()); | ||
961 | let lens_params = | ||
962 | lsp_types::TextDocumentPositionParams::new(params.text_document.clone(), position); | ||
963 | |||
964 | CodeLens { | ||
965 | range, | ||
966 | command: None, | ||
967 | data: Some(to_value(CodeLensResolveData::References(lens_params)).unwrap()), | ||
968 | } | ||
969 | })); | ||
970 | } | ||
971 | |||
955 | Ok(Some(lenses)) | 972 | Ok(Some(lenses)) |
956 | } | 973 | } |
957 | 974 | ||
@@ -959,6 +976,7 @@ pub(crate) fn handle_code_lens( | |||
959 | #[serde(rename_all = "camelCase")] | 976 | #[serde(rename_all = "camelCase")] |
960 | enum CodeLensResolveData { | 977 | enum CodeLensResolveData { |
961 | Impls(lsp_types::request::GotoImplementationParams), | 978 | Impls(lsp_types::request::GotoImplementationParams), |
979 | References(lsp_types::TextDocumentPositionParams), | ||
962 | } | 980 | } |
963 | 981 | ||
964 | pub(crate) fn handle_code_lens_resolve( | 982 | pub(crate) fn handle_code_lens_resolve( |
@@ -990,6 +1008,34 @@ pub(crate) fn handle_code_lens_resolve( | |||
990 | ); | 1008 | ); |
991 | Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None }) | 1009 | Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None }) |
992 | } | 1010 | } |
1011 | Some(CodeLensResolveData::References(doc_position)) => { | ||
1012 | let position = from_proto::file_position(&snap, doc_position.clone())?; | ||
1013 | let locations = snap | ||
1014 | .analysis | ||
1015 | .find_all_refs(position, None) | ||
1016 | .unwrap_or(None) | ||
1017 | .map(|r| { | ||
1018 | r.references() | ||
1019 | .iter() | ||
1020 | .filter_map(|it| to_proto::location(&snap, it.file_range).ok()) | ||
1021 | .collect_vec() | ||
1022 | }) | ||
1023 | .unwrap_or_default(); | ||
1024 | |||
1025 | let title = reference_title(locations.len()); | ||
1026 | let cmd = if locations.is_empty() { | ||
1027 | Command { title, command: "".into(), arguments: None } | ||
1028 | } else { | ||
1029 | show_references_command( | ||
1030 | title, | ||
1031 | &doc_position.text_document.uri, | ||
1032 | code_lens.range.start, | ||
1033 | locations, | ||
1034 | ) | ||
1035 | }; | ||
1036 | |||
1037 | Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None }) | ||
1038 | } | ||
993 | None => Ok(CodeLens { | 1039 | None => Ok(CodeLens { |
994 | range: code_lens.range, | 1040 | range: code_lens.range, |
995 | command: Some(Command { title: "Error".into(), ..Default::default() }), | 1041 | command: Some(Command { title: "Error".into(), ..Default::default() }), |
@@ -1248,6 +1294,14 @@ fn implementation_title(count: usize) -> String { | |||
1248 | } | 1294 | } |
1249 | } | 1295 | } |
1250 | 1296 | ||
1297 | fn reference_title(count: usize) -> String { | ||
1298 | if count == 1 { | ||
1299 | "1 reference".into() | ||
1300 | } else { | ||
1301 | format!("{} references", count) | ||
1302 | } | ||
1303 | } | ||
1304 | |||
1251 | fn show_references_command( | 1305 | fn show_references_command( |
1252 | title: String, | 1306 | title: String, |
1253 | uri: &lsp_types::Url, | 1307 | uri: &lsp_types::Url, |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 4a0ffcbb0..3a184094c 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -28,18 +28,41 @@ pub fn assoc_item_list() -> ast::AssocItemList { | |||
28 | pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { | 28 | pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { |
29 | ast_from_text(&format!("use {};", name_ref)) | 29 | ast_from_text(&format!("use {};", name_ref)) |
30 | } | 30 | } |
31 | |||
31 | pub fn path_segment_self() -> ast::PathSegment { | 32 | pub fn path_segment_self() -> ast::PathSegment { |
32 | ast_from_text("use self;") | 33 | ast_from_text("use self;") |
33 | } | 34 | } |
35 | |||
36 | pub fn path_segment_super() -> ast::PathSegment { | ||
37 | ast_from_text("use super;") | ||
38 | } | ||
39 | |||
40 | pub fn path_segment_crate() -> ast::PathSegment { | ||
41 | ast_from_text("use crate;") | ||
42 | } | ||
43 | |||
34 | pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { | 44 | pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { |
35 | path_from_text(&format!("use {}", segment)) | 45 | ast_from_text(&format!("use {}", segment)) |
36 | } | 46 | } |
47 | |||
37 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { | 48 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { |
38 | path_from_text(&format!("{}::{}", qual, segment)) | 49 | ast_from_text(&format!("{}::{}", qual, segment)) |
39 | } | 50 | } |
40 | // FIXME: make this private | 51 | |
41 | pub fn path_from_text(text: &str) -> ast::Path { | 52 | pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path { |
42 | ast_from_text(text) | 53 | ast_from_text(&format!("{}::{}", first, second)) |
54 | } | ||
55 | |||
56 | pub fn path_from_segments( | ||
57 | segments: impl IntoIterator<Item = ast::PathSegment>, | ||
58 | is_abs: bool, | ||
59 | ) -> ast::Path { | ||
60 | let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::"); | ||
61 | ast_from_text(&if is_abs { | ||
62 | format!("use ::{};", segments) | ||
63 | } else { | ||
64 | format!("use {};", segments) | ||
65 | }) | ||
43 | } | 66 | } |
44 | 67 | ||
45 | pub fn glob_use_tree() -> ast::UseTree { | 68 | pub fn glob_use_tree() -> ast::UseTree { |
diff --git a/editors/code/package.json b/editors/code/package.json index 132664926..bdd8a0c29 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -554,6 +554,11 @@ | |||
554 | "type": "boolean", | 554 | "type": "boolean", |
555 | "default": true | 555 | "default": true |
556 | }, | 556 | }, |
557 | "rust-analyzer.lens.methodReferences": { | ||
558 | "markdownDescription": "Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | ||
559 | "type": "boolean", | ||
560 | "default": false | ||
561 | }, | ||
557 | "rust-analyzer.hoverActions.enable": { | 562 | "rust-analyzer.hoverActions.enable": { |
558 | "description": "Whether to show HoverActions in Rust files.", | 563 | "description": "Whether to show HoverActions in Rust files.", |
559 | "type": "boolean", | 564 | "type": "boolean", |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 033b04b60..848e92af9 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -138,6 +138,7 @@ export class Config { | |||
138 | run: this.get<boolean>("lens.run"), | 138 | run: this.get<boolean>("lens.run"), |
139 | debug: this.get<boolean>("lens.debug"), | 139 | debug: this.get<boolean>("lens.debug"), |
140 | implementations: this.get<boolean>("lens.implementations"), | 140 | implementations: this.get<boolean>("lens.implementations"), |
141 | methodReferences: this.get<boolean>("lens.methodReferences"), | ||
141 | }; | 142 | }; |
142 | } | 143 | } |
143 | 144 | ||