diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/hover.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 75 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/highlights.rs | 12 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/injector.rs | 3 |
4 files changed, 50 insertions, 44 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index c34708324..e331f8886 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -17,7 +17,7 @@ use crate::{ | |||
17 | doc_links::{remove_links, rewrite_links}, | 17 | doc_links::{remove_links, rewrite_links}, |
18 | markdown_remove::remove_markdown, | 18 | markdown_remove::remove_markdown, |
19 | markup::Markup, | 19 | markup::Markup, |
20 | runnables::{runnable, runnable_fn}, | 20 | runnables::{runnable_fn, runnable_mod}, |
21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | 21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, |
22 | }; | 22 | }; |
23 | 23 | ||
@@ -192,7 +192,7 @@ fn runnable_action( | |||
192 | Definition::ModuleDef(it) => match it { | 192 | Definition::ModuleDef(it) => match it { |
193 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { | 193 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { |
194 | ModuleSource::Module(it) => { | 194 | ModuleSource::Module(it) => { |
195 | runnable(&sema, it.syntax().clone()).map(|it| HoverAction::Runnable(it)) | 195 | runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it)) |
196 | } | 196 | } |
197 | _ => None, | 197 | _ => None, |
198 | }, | 198 | }, |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 557563d7e..3a1e204db 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -96,21 +96,23 @@ impl Runnable { | |||
96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
97 | let sema = Semantics::new(db); | 97 | let sema = Semantics::new(db); |
98 | let source_file = sema.parse(file_id); | 98 | let source_file = sema.parse(file_id); |
99 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i)).collect() | 99 | source_file |
100 | } | 100 | .syntax() |
101 | 101 | .descendants() | |
102 | pub(crate) fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { | 102 | .filter_map(|item| { |
103 | let runnable_item = match_ast! { | 103 | let runnable = match_ast! { |
104 | match (item.clone()) { | 104 | match item { |
105 | ast::Fn(func) => { | 105 | ast::Fn(func) => { |
106 | let def = sema.to_def(&func)?; | 106 | let def = sema.to_def(&func)?; |
107 | runnable_fn(sema, def) | 107 | runnable_fn(&sema, def) |
108 | }, | 108 | }, |
109 | ast::Module(it) => runnable_mod(sema, it), | 109 | ast::Module(it) => runnable_mod(&sema, it), |
110 | _ => None, | 110 | _ => None, |
111 | } | 111 | } |
112 | }; | 112 | }; |
113 | runnable_item.or_else(|| runnable_doctest(sema, item)) | 113 | runnable.or_else(|| runnable_doctest(&sema, item)) |
114 | }) | ||
115 | .collect() | ||
114 | } | 116 | } |
115 | 117 | ||
116 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { | 118 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { |
@@ -145,6 +147,29 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> | |||
145 | Some(Runnable { nav, kind, cfg }) | 147 | Some(Runnable { nav, kind, cfg }) |
146 | } | 148 | } |
147 | 149 | ||
150 | pub(crate) fn runnable_mod( | ||
151 | sema: &Semantics<RootDatabase>, | ||
152 | module: ast::Module, | ||
153 | ) -> Option<Runnable> { | ||
154 | if !has_test_function_or_multiple_test_submodules(&module) { | ||
155 | return None; | ||
156 | } | ||
157 | let module_def = sema.to_def(&module)?; | ||
158 | |||
159 | let path = module_def | ||
160 | .path_to_root(sema.db) | ||
161 | .into_iter() | ||
162 | .rev() | ||
163 | .filter_map(|it| it.name(sema.db)) | ||
164 | .join("::"); | ||
165 | |||
166 | let def = sema.to_def(&module)?; | ||
167 | let attrs = def.attrs(sema.db); | ||
168 | let cfg = attrs.cfg(); | ||
169 | let nav = module_def.to_nav(sema.db); | ||
170 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) | ||
171 | } | ||
172 | |||
148 | fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { | 173 | fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { |
149 | match_ast! { | 174 | match_ast! { |
150 | match item { | 175 | match item { |
@@ -253,26 +278,6 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { | |||
253 | }) | 278 | }) |
254 | } | 279 | } |
255 | 280 | ||
256 | fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { | ||
257 | if !has_test_function_or_multiple_test_submodules(&module) { | ||
258 | return None; | ||
259 | } | ||
260 | let module_def = sema.to_def(&module)?; | ||
261 | |||
262 | let path = module_def | ||
263 | .path_to_root(sema.db) | ||
264 | .into_iter() | ||
265 | .rev() | ||
266 | .filter_map(|it| it.name(sema.db)) | ||
267 | .join("::"); | ||
268 | |||
269 | let def = sema.to_def(&module)?; | ||
270 | let attrs = def.attrs(sema.db); | ||
271 | let cfg = attrs.cfg(); | ||
272 | let nav = module_def.to_nav(sema.db); | ||
273 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) | ||
274 | } | ||
275 | |||
276 | // We could create runnables for modules with number_of_test_submodules > 0, | 281 | // We could create runnables for modules with number_of_test_submodules > 0, |
277 | // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already | 282 | // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already |
278 | fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { | 283 | fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { |
diff --git a/crates/ide/src/syntax_highlighting/highlights.rs b/crates/ide/src/syntax_highlighting/highlights.rs index 11c11ed28..c6f0417ec 100644 --- a/crates/ide/src/syntax_highlighting/highlights.rs +++ b/crates/ide/src/syntax_highlighting/highlights.rs | |||
@@ -51,18 +51,20 @@ impl Node { | |||
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | let (start, len) = | 54 | let overlapping = |
55 | equal_range_by(&self.nested, |n| ordering(n.hl_range.range, hl_range.range)); | 55 | equal_range_by(&self.nested, |n| ordering(n.hl_range.range, hl_range.range)); |
56 | 56 | ||
57 | if len == 1 && self.nested[start].hl_range.range.contains_range(hl_range.range) { | 57 | if overlapping.len() == 1 |
58 | return self.nested[start].add(hl_range); | 58 | && self.nested[overlapping.start].hl_range.range.contains_range(hl_range.range) |
59 | { | ||
60 | return self.nested[overlapping.start].add(hl_range); | ||
59 | } | 61 | } |
60 | 62 | ||
61 | let nested = self | 63 | let nested = self |
62 | .nested | 64 | .nested |
63 | .splice(start..start + len, iter::once(Node::new(hl_range))) | 65 | .splice(overlapping.clone(), iter::once(Node::new(hl_range))) |
64 | .collect::<Vec<_>>(); | 66 | .collect::<Vec<_>>(); |
65 | self.nested[start].nested = nested; | 67 | self.nested[overlapping.start].nested = nested; |
66 | } | 68 | } |
67 | 69 | ||
68 | fn flatten(&self, acc: &mut Vec<HlRange>) { | 70 | fn flatten(&self, acc: &mut Vec<HlRange>) { |
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs index e8f17eb69..fd4025694 100644 --- a/crates/ide/src/syntax_highlighting/injector.rs +++ b/crates/ide/src/syntax_highlighting/injector.rs | |||
@@ -33,8 +33,7 @@ impl Injector { | |||
33 | &self.buf | 33 | &self.buf |
34 | } | 34 | } |
35 | pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | 35 | pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { |
36 | let (start, len) = equal_range_by(&self.ranges, |&(r, _)| ordering(r, range)); | 36 | equal_range_by(&self.ranges, |&(r, _)| ordering(r, range)).filter_map(move |i| { |
37 | (start..start + len).filter_map(move |i| { | ||
38 | let (target_range, delta) = self.ranges[i]; | 37 | let (target_range, delta) = self.ranges[i]; |
39 | let intersection = target_range.intersect(range).unwrap(); | 38 | let intersection = target_range.intersect(range).unwrap(); |
40 | Some(intersection + delta?) | 39 | Some(intersection + delta?) |