diff options
-rw-r--r-- | crates/ra_hir_def/src/attr.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_def/src/find_path.rs | 78 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 32 | ||||
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 50 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 37 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 37 | ||||
-rw-r--r-- | editors/code/src/client.ts | 2 | ||||
-rw-r--r-- | editors/code/src/ctx.ts | 2 |
10 files changed, 239 insertions, 32 deletions
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 714a66b02..5a86af8ba 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -13,7 +13,8 @@ use ra_syntax::{ | |||
13 | use tt::Subtree; | 13 | use tt::Subtree; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | db::DefDatabase, path::ModPath, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup, | 16 | db::DefDatabase, nameres::ModuleSource, path::ModPath, src::HasChildSource, src::HasSource, |
17 | AdtId, AttrDefId, Lookup, | ||
17 | }; | 18 | }; |
18 | 19 | ||
19 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 20 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
@@ -37,11 +38,19 @@ impl Attrs { | |||
37 | match def { | 38 | match def { |
38 | AttrDefId::ModuleId(module) => { | 39 | AttrDefId::ModuleId(module) => { |
39 | let def_map = db.crate_def_map(module.krate); | 40 | let def_map = db.crate_def_map(module.krate); |
40 | let src = match def_map[module.local_id].declaration_source(db) { | 41 | let mod_data = &def_map[module.local_id]; |
41 | Some(it) => it, | 42 | match mod_data.declaration_source(db) { |
42 | None => return Attrs::default(), | 43 | Some(it) => { |
43 | }; | 44 | Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner)) |
44 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) | 45 | } |
46 | None => Attrs::from_attrs_owner( | ||
47 | db, | ||
48 | mod_data.definition_source(db).as_ref().map(|src| match src { | ||
49 | ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, | ||
50 | ModuleSource::Module(module) => module as &dyn AttrsOwner, | ||
51 | }), | ||
52 | ), | ||
53 | } | ||
45 | } | 54 | } |
46 | AttrDefId::FieldId(it) => { | 55 | AttrDefId::FieldId(it) => { |
47 | let src = it.parent.child_source(db); | 56 | let src = it.parent.child_source(db); |
@@ -106,7 +115,9 @@ pub struct Attr { | |||
106 | 115 | ||
107 | #[derive(Debug, Clone, PartialEq, Eq)] | 116 | #[derive(Debug, Clone, PartialEq, Eq)] |
108 | pub enum AttrInput { | 117 | pub enum AttrInput { |
118 | /// `#[attr = "string"]` | ||
109 | Literal(SmolStr), | 119 | Literal(SmolStr), |
120 | /// `#[attr(subtree)]` | ||
110 | TokenTree(Subtree), | 121 | TokenTree(Subtree), |
111 | } | 122 | } |
112 | 123 | ||
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 0caedd8d8..571603854 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -141,6 +141,10 @@ impl ExprCollector<'_> { | |||
141 | 141 | ||
142 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { | 142 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { |
143 | let syntax_ptr = AstPtr::new(&expr); | 143 | let syntax_ptr = AstPtr::new(&expr); |
144 | let attrs = self.expander.parse_attrs(&expr); | ||
145 | if !self.expander.is_cfg_enabled(&attrs) { | ||
146 | return self.missing_expr(); | ||
147 | } | ||
144 | match expr { | 148 | match expr { |
145 | ast::Expr::IfExpr(e) => { | 149 | ast::Expr::IfExpr(e) => { |
146 | let then_branch = self.collect_block_opt(e.then_branch()); | 150 | let then_branch = self.collect_block_opt(e.then_branch()); |
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 81eff5bfe..70dcb03e6 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -19,7 +19,7 @@ impl ModPath { | |||
19 | 19 | ||
20 | // When std library is present, paths starting with `std::` | 20 | // When std library is present, paths starting with `std::` |
21 | // should be preferred over paths starting with `core::` and `alloc::` | 21 | // should be preferred over paths starting with `core::` and `alloc::` |
22 | fn should_start_with_std(&self) -> bool { | 22 | fn can_start_with_std(&self) -> bool { |
23 | self.segments | 23 | self.segments |
24 | .first() | 24 | .first() |
25 | .filter(|&first_segment| { | 25 | .filter(|&first_segment| { |
@@ -132,6 +132,9 @@ fn find_path_inner( | |||
132 | } | 132 | } |
133 | 133 | ||
134 | // - otherwise, look for modules containing (reexporting) it and import it from one of those | 134 | // - otherwise, look for modules containing (reexporting) it and import it from one of those |
135 | let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; | ||
136 | let crate_attrs = db.attrs(crate_root.into()); | ||
137 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); | ||
135 | let importable_locations = find_importable_locations(db, item, from); | 138 | let importable_locations = find_importable_locations(db, item, from); |
136 | let mut best_path = None; | 139 | let mut best_path = None; |
137 | let mut best_path_len = max_len; | 140 | let mut best_path_len = max_len; |
@@ -147,21 +150,32 @@ fn find_path_inner( | |||
147 | }; | 150 | }; |
148 | path.segments.push(name); | 151 | path.segments.push(name); |
149 | 152 | ||
150 | let new_path = | 153 | let new_path = if let Some(best_path) = best_path { |
151 | if let Some(best_path) = best_path { select_best_path(best_path, path) } else { path }; | 154 | select_best_path(best_path, path, prefer_no_std) |
155 | } else { | ||
156 | path | ||
157 | }; | ||
152 | best_path_len = new_path.len(); | 158 | best_path_len = new_path.len(); |
153 | best_path = Some(new_path); | 159 | best_path = Some(new_path); |
154 | } | 160 | } |
155 | best_path | 161 | best_path |
156 | } | 162 | } |
157 | 163 | ||
158 | fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath { | 164 | fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { |
159 | if old_path.starts_with_std() && new_path.should_start_with_std() { | 165 | if old_path.starts_with_std() && new_path.can_start_with_std() { |
160 | tested_by!(prefer_std_paths); | 166 | tested_by!(prefer_std_paths); |
161 | old_path | 167 | if prefer_no_std { |
162 | } else if new_path.starts_with_std() && old_path.should_start_with_std() { | 168 | new_path |
169 | } else { | ||
170 | old_path | ||
171 | } | ||
172 | } else if new_path.starts_with_std() && old_path.can_start_with_std() { | ||
163 | tested_by!(prefer_std_paths); | 173 | tested_by!(prefer_std_paths); |
164 | new_path | 174 | if prefer_no_std { |
175 | old_path | ||
176 | } else { | ||
177 | new_path | ||
178 | } | ||
165 | } else if new_path.len() < old_path.len() { | 179 | } else if new_path.len() < old_path.len() { |
166 | new_path | 180 | new_path |
167 | } else { | 181 | } else { |
@@ -513,6 +527,54 @@ mod tests { | |||
513 | } | 527 | } |
514 | 528 | ||
515 | #[test] | 529 | #[test] |
530 | fn prefer_alloc_paths_over_std() { | ||
531 | covers!(prefer_std_paths); | ||
532 | let code = r#" | ||
533 | //- /main.rs crate:main deps:alloc,std | ||
534 | #![no_std] | ||
535 | |||
536 | <|> | ||
537 | |||
538 | //- /std.rs crate:std deps:alloc | ||
539 | |||
540 | pub mod sync { | ||
541 | pub use alloc::sync::Arc; | ||
542 | } | ||
543 | |||
544 | //- /zzz.rs crate:alloc | ||
545 | |||
546 | pub mod sync { | ||
547 | pub struct Arc; | ||
548 | } | ||
549 | "#; | ||
550 | check_found_path(code, "alloc::sync::Arc"); | ||
551 | } | ||
552 | |||
553 | #[test] | ||
554 | fn prefer_core_paths_over_std() { | ||
555 | covers!(prefer_std_paths); | ||
556 | let code = r#" | ||
557 | //- /main.rs crate:main deps:core,std | ||
558 | #![no_std] | ||
559 | |||
560 | <|> | ||
561 | |||
562 | //- /std.rs crate:std deps:core | ||
563 | |||
564 | pub mod fmt { | ||
565 | pub use core::fmt::Error; | ||
566 | } | ||
567 | |||
568 | //- /zzz.rs crate:core | ||
569 | |||
570 | pub mod fmt { | ||
571 | pub struct Error; | ||
572 | } | ||
573 | "#; | ||
574 | check_found_path(code, "core::fmt::Error"); | ||
575 | } | ||
576 | |||
577 | #[test] | ||
516 | fn prefer_shorter_paths_if_not_alloc() { | 578 | fn prefer_shorter_paths_if_not_alloc() { |
517 | let code = r#" | 579 | let code = r#" |
518 | //- /main.rs crate:main deps:megaalloc,std | 580 | //- /main.rs crate:main deps:megaalloc,std |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index b6a96bb5c..588d81282 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -391,6 +391,38 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | |||
391 | } | 391 | } |
392 | 392 | ||
393 | #[test] | 393 | #[test] |
394 | fn no_such_field_with_feature_flag_diagnostics_on_block_expr() { | ||
395 | let diagnostics = TestDB::with_files( | ||
396 | r#" | ||
397 | //- /lib.rs crate:foo cfg:feature=foo | ||
398 | struct S { | ||
399 | #[cfg(feature = "foo")] | ||
400 | foo: u32, | ||
401 | #[cfg(not(feature = "foo"))] | ||
402 | bar: u32, | ||
403 | } | ||
404 | |||
405 | impl S { | ||
406 | fn new(bar: u32) -> Self { | ||
407 | #[cfg(feature = "foo")] | ||
408 | { | ||
409 | Self { foo: bar } | ||
410 | } | ||
411 | #[cfg(not(feature = "foo"))] | ||
412 | { | ||
413 | Self { bar } | ||
414 | } | ||
415 | } | ||
416 | } | ||
417 | "#, | ||
418 | ) | ||
419 | .diagnostics() | ||
420 | .0; | ||
421 | |||
422 | assert_snapshot!(diagnostics, @r###""###); | ||
423 | } | ||
424 | |||
425 | #[test] | ||
394 | fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { | 426 | fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { |
395 | let diagnostics = TestDB::with_files( | 427 | let diagnostics = TestDB::with_files( |
396 | r#" | 428 | r#" |
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 535b7daa0..1a020398e 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -19,6 +19,7 @@ use crate::{ | |||
19 | #[derive(Debug, PartialEq, Eq)] | 19 | #[derive(Debug, PartialEq, Eq)] |
20 | pub enum ParseError { | 20 | pub enum ParseError { |
21 | Expected(String), | 21 | Expected(String), |
22 | RepetitionEmtpyTokenTree, | ||
22 | } | 23 | } |
23 | 24 | ||
24 | #[derive(Debug, PartialEq, Eq)] | 25 | #[derive(Debug, PartialEq, Eq)] |
@@ -194,20 +195,46 @@ impl Rule { | |||
194 | } | 195 | } |
195 | } | 196 | } |
196 | 197 | ||
198 | fn to_parse_error(e: ExpandError) -> ParseError { | ||
199 | let msg = match e { | ||
200 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), | ||
201 | _ => "invalid macro definition".to_string(), | ||
202 | }; | ||
203 | ParseError::Expected(msg) | ||
204 | } | ||
205 | |||
197 | fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { | 206 | fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { |
198 | for op in parse_pattern(pattern) { | 207 | for op in parse_pattern(pattern) { |
199 | let op = match op { | 208 | let op = op.map_err(to_parse_error)?; |
200 | Ok(it) => it, | 209 | |
201 | Err(e) => { | ||
202 | let msg = match e { | ||
203 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), | ||
204 | _ => "invalid macro definition".to_string(), | ||
205 | }; | ||
206 | return Err(ParseError::Expected(msg)); | ||
207 | } | ||
208 | }; | ||
209 | match op { | 210 | match op { |
210 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) | Op::Repeat { subtree, .. } => { | 211 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) => validate(subtree)?, |
212 | Op::Repeat { subtree, separator, .. } => { | ||
213 | // Checks that no repetition which could match an empty token | ||
214 | // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 | ||
215 | |||
216 | if separator.is_none() { | ||
217 | if parse_pattern(subtree).all(|child_op| { | ||
218 | match child_op.map_err(to_parse_error) { | ||
219 | Ok(Op::Var { kind, .. }) => { | ||
220 | // vis is optional | ||
221 | if kind.map_or(false, |it| it == "vis") { | ||
222 | return true; | ||
223 | } | ||
224 | } | ||
225 | Ok(Op::Repeat { kind, .. }) => { | ||
226 | return matches!( | ||
227 | kind, | ||
228 | parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne | ||
229 | ) | ||
230 | } | ||
231 | _ => {} | ||
232 | } | ||
233 | false | ||
234 | }) { | ||
235 | return Err(ParseError::RepetitionEmtpyTokenTree); | ||
236 | } | ||
237 | } | ||
211 | validate(subtree)? | 238 | validate(subtree)? |
212 | } | 239 | } |
213 | _ => (), | 240 | _ => (), |
@@ -216,6 +243,7 @@ fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { | |||
216 | Ok(()) | 243 | Ok(()) |
217 | } | 244 | } |
218 | 245 | ||
246 | #[derive(Debug)] | ||
219 | pub struct ExpandResult<T>(pub T, pub Option<ExpandError>); | 247 | pub struct ExpandResult<T>(pub T, pub Option<ExpandError>); |
220 | 248 | ||
221 | impl<T> ExpandResult<T> { | 249 | impl<T> ExpandResult<T> { |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 7ceec7752..0d924ce58 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -1657,7 +1657,7 @@ impl MacroFixture { | |||
1657 | } | 1657 | } |
1658 | } | 1658 | } |
1659 | 1659 | ||
1660 | pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture { | 1660 | fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree { |
1661 | let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); | 1661 | let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); |
1662 | let macro_definition = | 1662 | let macro_definition = |
1663 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 1663 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); |
@@ -1671,10 +1671,24 @@ pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture { | |||
1671 | .0; | 1671 | .0; |
1672 | assert_eq!(definition_tt, parsed); | 1672 | assert_eq!(definition_tt, parsed); |
1673 | 1673 | ||
1674 | definition_tt | ||
1675 | } | ||
1676 | |||
1677 | pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture { | ||
1678 | let definition_tt = parse_macro_to_tt(ra_fixture); | ||
1674 | let rules = MacroRules::parse(&definition_tt).unwrap(); | 1679 | let rules = MacroRules::parse(&definition_tt).unwrap(); |
1675 | MacroFixture { rules } | 1680 | MacroFixture { rules } |
1676 | } | 1681 | } |
1677 | 1682 | ||
1683 | pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError { | ||
1684 | let definition_tt = parse_macro_to_tt(ra_fixture); | ||
1685 | |||
1686 | match MacroRules::parse(&definition_tt) { | ||
1687 | Ok(_) => panic!("Expect error"), | ||
1688 | Err(err) => err, | ||
1689 | } | ||
1690 | } | ||
1691 | |||
1678 | pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree { | 1692 | pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree { |
1679 | let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); | 1693 | let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); |
1680 | let tt = syntax_node_to_token_tree(source_file.syntax()).unwrap().0; | 1694 | let tt = syntax_node_to_token_tree(source_file.syntax()).unwrap().0; |
@@ -1840,6 +1854,27 @@ fn test_no_space_after_semi_colon() { | |||
1840 | ); | 1854 | ); |
1841 | } | 1855 | } |
1842 | 1856 | ||
1857 | // https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57597.rs | ||
1858 | #[test] | ||
1859 | fn test_rustc_issue_57597() { | ||
1860 | fn test_error(fixture: &str) { | ||
1861 | assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmtpyTokenTree); | ||
1862 | } | ||
1863 | |||
1864 | test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }"); | ||
1865 | test_error("macro_rules! foo { ($($($i:ident)?)*) => {}; }"); | ||
1866 | test_error("macro_rules! foo { ($($($i:ident)?)?) => {}; }"); | ||
1867 | test_error("macro_rules! foo { ($($($($i:ident)?)?)?) => {}; }"); | ||
1868 | test_error("macro_rules! foo { ($($($($i:ident)*)?)?) => {}; }"); | ||
1869 | test_error("macro_rules! foo { ($($($($i:ident)?)*)?) => {}; }"); | ||
1870 | test_error("macro_rules! foo { ($($($($i:ident)?)?)*) => {}; }"); | ||
1871 | test_error("macro_rules! foo { ($($($($i:ident)*)*)?) => {}; }"); | ||
1872 | test_error("macro_rules! foo { ($($($($i:ident)?)*)*) => {}; }"); | ||
1873 | test_error("macro_rules! foo { ($($($($i:ident)?)*)+) => {}; }"); | ||
1874 | test_error("macro_rules! foo { ($($($($i:ident)+)?)*) => {}; }"); | ||
1875 | test_error("macro_rules! foo { ($($($($i:ident)+)*)?) => {}; }"); | ||
1876 | } | ||
1877 | |||
1843 | #[test] | 1878 | #[test] |
1844 | fn test_expand_bad_literal() { | 1879 | fn test_expand_bad_literal() { |
1845 | parse_macro( | 1880 | parse_macro( |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 715eddadb..74a63e32a 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -69,6 +69,7 @@ pub enum RustfmtConfig { | |||
69 | pub struct ClientCapsConfig { | 69 | pub struct ClientCapsConfig { |
70 | pub location_link: bool, | 70 | pub location_link: bool, |
71 | pub line_folding_only: bool, | 71 | pub line_folding_only: bool, |
72 | pub hierarchical_symbols: bool, | ||
72 | } | 73 | } |
73 | 74 | ||
74 | impl Default for Config { | 75 | impl Default for Config { |
@@ -215,6 +216,11 @@ impl Config { | |||
215 | if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) { | 216 | if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) { |
216 | self.client_caps.line_folding_only = value | 217 | self.client_caps.line_folding_only = value |
217 | } | 218 | } |
219 | if let Some(value) = | ||
220 | caps.document_symbol.as_ref().and_then(|it| it.hierarchical_document_symbol_support) | ||
221 | { | ||
222 | self.client_caps.hierarchical_symbols = value | ||
223 | } | ||
218 | self.completion.allow_snippets(false); | 224 | self.completion.allow_snippets(false); |
219 | if let Some(completion) = &caps.completion { | 225 | if let Some(completion) = &caps.completion { |
220 | if let Some(completion_item) = &completion.completion_item { | 226 | if let Some(completion_item) = &completion.completion_item { |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index c2c1a23cd..e87e8db5d 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -16,7 +16,7 @@ use lsp_types::{ | |||
16 | Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse, | 16 | Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse, |
17 | Range, RenameParams, SemanticTokensParams, SemanticTokensRangeParams, | 17 | Range, RenameParams, SemanticTokensParams, SemanticTokensRangeParams, |
18 | SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, | 18 | SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, |
19 | TextEdit, WorkspaceEdit, | 19 | TextEdit, Url, WorkspaceEdit, |
20 | }; | 20 | }; |
21 | use ra_ide::{ | 21 | use ra_ide::{ |
22 | Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, | 22 | Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, |
@@ -219,6 +219,7 @@ pub fn handle_document_symbol( | |||
219 | let _p = profile("handle_document_symbol"); | 219 | let _p = profile("handle_document_symbol"); |
220 | let file_id = params.text_document.try_conv_with(&world)?; | 220 | let file_id = params.text_document.try_conv_with(&world)?; |
221 | let line_index = world.analysis().file_line_index(file_id)?; | 221 | let line_index = world.analysis().file_line_index(file_id)?; |
222 | let url = file_id.try_conv_with(&world)?; | ||
222 | 223 | ||
223 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); | 224 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); |
224 | 225 | ||
@@ -234,10 +235,10 @@ pub fn handle_document_symbol( | |||
234 | }; | 235 | }; |
235 | parents.push((doc_symbol, symbol.parent)); | 236 | parents.push((doc_symbol, symbol.parent)); |
236 | } | 237 | } |
237 | let mut res = Vec::new(); | 238 | let mut document_symbols = Vec::new(); |
238 | while let Some((node, parent)) = parents.pop() { | 239 | while let Some((node, parent)) = parents.pop() { |
239 | match parent { | 240 | match parent { |
240 | None => res.push(node), | 241 | None => document_symbols.push(node), |
241 | Some(i) => { | 242 | Some(i) => { |
242 | let children = &mut parents[i].0.children; | 243 | let children = &mut parents[i].0.children; |
243 | if children.is_none() { | 244 | if children.is_none() { |
@@ -248,7 +249,35 @@ pub fn handle_document_symbol( | |||
248 | } | 249 | } |
249 | } | 250 | } |
250 | 251 | ||
251 | Ok(Some(res.into())) | 252 | if world.config.client_caps.hierarchical_symbols { |
253 | Ok(Some(document_symbols.into())) | ||
254 | } else { | ||
255 | let mut symbol_information = Vec::<SymbolInformation>::new(); | ||
256 | for symbol in document_symbols { | ||
257 | flatten_document_symbol(&symbol, None, &url, &mut symbol_information); | ||
258 | } | ||
259 | |||
260 | Ok(Some(symbol_information.into())) | ||
261 | } | ||
262 | } | ||
263 | |||
264 | fn flatten_document_symbol( | ||
265 | symbol: &DocumentSymbol, | ||
266 | container_name: Option<String>, | ||
267 | url: &Url, | ||
268 | res: &mut Vec<SymbolInformation>, | ||
269 | ) { | ||
270 | res.push(SymbolInformation { | ||
271 | name: symbol.name.clone(), | ||
272 | kind: symbol.kind, | ||
273 | deprecated: symbol.deprecated, | ||
274 | location: Location::new(url.clone(), symbol.range), | ||
275 | container_name: container_name, | ||
276 | }); | ||
277 | |||
278 | for child in symbol.children.iter().flatten() { | ||
279 | flatten_document_symbol(child, Some(symbol.name.clone()), url, res); | ||
280 | } | ||
252 | } | 281 | } |
253 | 282 | ||
254 | pub fn handle_workspace_symbol( | 283 | pub fn handle_workspace_symbol( |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 0ad4b63ae..97e794091 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -4,7 +4,7 @@ import * as vscode from 'vscode'; | |||
4 | import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; | 4 | import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; |
5 | import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; | 5 | import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; |
6 | 6 | ||
7 | export async function createClient(serverPath: string, cwd: string): Promise<lc.LanguageClient> { | 7 | export function createClient(serverPath: string, cwd: string): lc.LanguageClient { |
8 | // '.' Is the fallback if no folder is open | 8 | // '.' Is the fallback if no folder is open |
9 | // TODO?: Workspace folders support Uri's (eg: file://test.txt). | 9 | // TODO?: Workspace folders support Uri's (eg: file://test.txt). |
10 | // It might be a good idea to test if the uri points to a file. | 10 | // It might be a good idea to test if the uri points to a file. |
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index f7ed62d03..41df11991 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts | |||
@@ -21,7 +21,7 @@ export class Ctx { | |||
21 | serverPath: string, | 21 | serverPath: string, |
22 | cwd: string, | 22 | cwd: string, |
23 | ): Promise<Ctx> { | 23 | ): Promise<Ctx> { |
24 | const client = await createClient(serverPath, cwd); | 24 | const client = createClient(serverPath, cwd); |
25 | const res = new Ctx(config, extCtx, client, serverPath); | 25 | const res = new Ctx(config, extCtx, client, serverPath); |
26 | res.pushCleanup(client.start()); | 26 | res.pushCleanup(client.start()); |
27 | await client.onReady(); | 27 | await client.onReady(); |