diff options
39 files changed, 616 insertions, 268 deletions
diff --git a/Cargo.lock b/Cargo.lock index 1a4a63550..494011068 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -139,9 +139,9 @@ dependencies = [ | |||
139 | 139 | ||
140 | [[package]] | 140 | [[package]] |
141 | name = "cc" | 141 | name = "cc" |
142 | version = "1.0.61" | 142 | version = "1.0.62" |
143 | source = "registry+https://github.com/rust-lang/crates.io-index" | 143 | source = "registry+https://github.com/rust-lang/crates.io-index" |
144 | checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" | 144 | checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" |
145 | 145 | ||
146 | [[package]] | 146 | [[package]] |
147 | name = "cfg" | 147 | name = "cfg" |
@@ -398,11 +398,11 @@ dependencies = [ | |||
398 | 398 | ||
399 | [[package]] | 399 | [[package]] |
400 | name = "filetime" | 400 | name = "filetime" |
401 | version = "0.2.12" | 401 | version = "0.2.13" |
402 | source = "registry+https://github.com/rust-lang/crates.io-index" | 402 | source = "registry+https://github.com/rust-lang/crates.io-index" |
403 | checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" | 403 | checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" |
404 | dependencies = [ | 404 | dependencies = [ |
405 | "cfg-if 0.1.10", | 405 | "cfg-if 1.0.0", |
406 | "libc", | 406 | "libc", |
407 | "redox_syscall", | 407 | "redox_syscall", |
408 | "winapi 0.3.9", | 408 | "winapi 0.3.9", |
@@ -439,6 +439,16 @@ dependencies = [ | |||
439 | ] | 439 | ] |
440 | 440 | ||
441 | [[package]] | 441 | [[package]] |
442 | name = "form_urlencoded" | ||
443 | version = "1.0.0" | ||
444 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
445 | checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" | ||
446 | dependencies = [ | ||
447 | "matches", | ||
448 | "percent-encoding", | ||
449 | ] | ||
450 | |||
451 | [[package]] | ||
442 | name = "fsevent" | 452 | name = "fsevent" |
443 | version = "2.0.2" | 453 | version = "2.0.2" |
444 | source = "registry+https://github.com/rust-lang/crates.io-index" | 454 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -612,6 +622,7 @@ dependencies = [ | |||
612 | "hir_expand", | 622 | "hir_expand", |
613 | "itertools", | 623 | "itertools", |
614 | "log", | 624 | "log", |
625 | "once_cell", | ||
615 | "profile", | 626 | "profile", |
616 | "rustc-hash", | 627 | "rustc-hash", |
617 | "scoped-tls", | 628 | "scoped-tls", |
@@ -714,9 +725,9 @@ dependencies = [ | |||
714 | 725 | ||
715 | [[package]] | 726 | [[package]] |
716 | name = "inotify-sys" | 727 | name = "inotify-sys" |
717 | version = "0.1.3" | 728 | version = "0.1.4" |
718 | source = "registry+https://github.com/rust-lang/crates.io-index" | 729 | source = "registry+https://github.com/rust-lang/crates.io-index" |
719 | checksum = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" | 730 | checksum = "c4563555856585ab3180a5bf0b2f9f8d301a728462afffc8195b3f5394229c55" |
720 | dependencies = [ | 731 | dependencies = [ |
721 | "libc", | 732 | "libc", |
722 | ] | 733 | ] |
@@ -1053,9 +1064,9 @@ checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" | |||
1053 | 1064 | ||
1054 | [[package]] | 1065 | [[package]] |
1055 | name = "once_cell" | 1066 | name = "once_cell" |
1056 | version = "1.4.1" | 1067 | version = "1.5.1" |
1057 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1068 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1058 | checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" | 1069 | checksum = "f53cef67919d7d247eb9a2f128ca9e522789967ef1eb4ccd8c71a95a8aedf596" |
1059 | 1070 | ||
1060 | [[package]] | 1071 | [[package]] |
1061 | name = "oorandom" | 1072 | name = "oorandom" |
@@ -1383,9 +1394,9 @@ dependencies = [ | |||
1383 | 1394 | ||
1384 | [[package]] | 1395 | [[package]] |
1385 | name = "rustc-ap-rustc_lexer" | 1396 | name = "rustc-ap-rustc_lexer" |
1386 | version = "686.0.0" | 1397 | version = "688.0.0" |
1387 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1388 | checksum = "a5b04cd2159495584d976d501c5394498470c2e94e4f0cebb8186562d407a678" | 1399 | checksum = "ebbdcc99bd015349093fcbae4780fda21416fec5d8843acfb3d1733e130cd4db" |
1389 | dependencies = [ | 1400 | dependencies = [ |
1390 | "unicode-xid", | 1401 | "unicode-xid", |
1391 | ] | 1402 | ] |
@@ -1888,10 +1899,11 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" | |||
1888 | 1899 | ||
1889 | [[package]] | 1900 | [[package]] |
1890 | name = "url" | 1901 | name = "url" |
1891 | version = "2.1.1" | 1902 | version = "2.2.0" |
1892 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1903 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1893 | checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" | 1904 | checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" |
1894 | dependencies = [ | 1905 | dependencies = [ |
1906 | "form_urlencoded", | ||
1895 | "idna", | 1907 | "idna", |
1896 | "matches", | 1908 | "matches", |
1897 | "percent-encoding", | 1909 | "percent-encoding", |
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs index 84a0dffdd..af3fc96b6 100644 --- a/crates/assists/src/utils/insert_use.rs +++ b/crates/assists/src/utils/insert_use.rs | |||
@@ -9,7 +9,7 @@ use syntax::{ | |||
9 | edit::{AstNodeEdit, IndentLevel}, | 9 | edit::{AstNodeEdit, IndentLevel}, |
10 | make, AstNode, PathSegmentKind, VisibilityOwner, | 10 | make, AstNode, PathSegmentKind, VisibilityOwner, |
11 | }, | 11 | }, |
12 | InsertPosition, SyntaxElement, SyntaxNode, | 12 | AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, |
13 | }; | 13 | }; |
14 | use test_utils::mark; | 14 | use test_utils::mark; |
15 | 15 | ||
@@ -63,27 +63,30 @@ impl ImportScope { | |||
63 | } | 63 | } |
64 | } | 64 | } |
65 | 65 | ||
66 | fn insert_pos_after_inner_attribute(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) { | 66 | fn insert_pos_after_last_inner_element(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) { |
67 | // check if the scope has inner attributes, we dont want to insert in front of them | 67 | self.as_syntax_node() |
68 | match self | 68 | .children_with_tokens() |
69 | .as_syntax_node() | 69 | .filter(|child| match child { |
70 | .children() | 70 | NodeOrToken::Node(node) => is_inner_attribute(node.clone()), |
71 | // no flat_map here cause we want to short circuit the iterator | 71 | NodeOrToken::Token(token) => is_inner_comment(token.clone()), |
72 | .map(ast::Attr::cast) | ||
73 | .take_while(|attr| { | ||
74 | attr.as_ref().map(|attr| attr.kind() == ast::AttrKind::Inner).unwrap_or(false) | ||
75 | }) | 72 | }) |
76 | .last() | 73 | .last() |
77 | .flatten() | 74 | .map(|last_inner_element| { |
78 | { | 75 | (InsertPosition::After(last_inner_element.into()), AddBlankLine::BeforeTwice) |
79 | Some(attr) => { | 76 | }) |
80 | (InsertPosition::After(attr.syntax().clone().into()), AddBlankLine::BeforeTwice) | 77 | .unwrap_or_else(|| self.first_insert_pos()) |
81 | } | ||
82 | None => self.first_insert_pos(), | ||
83 | } | ||
84 | } | 78 | } |
85 | } | 79 | } |
86 | 80 | ||
81 | fn is_inner_attribute(node: SyntaxNode) -> bool { | ||
82 | ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner) | ||
83 | } | ||
84 | |||
85 | fn is_inner_comment(token: SyntaxToken) -> bool { | ||
86 | ast::Comment::cast(token).and_then(|comment| comment.kind().doc) | ||
87 | == Some(ast::CommentPlacement::Inner) | ||
88 | } | ||
89 | |||
87 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. | 90 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. |
88 | pub(crate) fn insert_use<'a>( | 91 | pub(crate) fn insert_use<'a>( |
89 | scope: &ImportScope, | 92 | scope: &ImportScope, |
@@ -558,7 +561,7 @@ fn find_insert_position( | |||
558 | (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice) | 561 | (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice) |
559 | } | 562 | } |
560 | // there are no imports in this file at all | 563 | // there are no imports in this file at all |
561 | None => scope.insert_pos_after_inner_attribute(), | 564 | None => scope.insert_pos_after_last_inner_element(), |
562 | }, | 565 | }, |
563 | } | 566 | } |
564 | } | 567 | } |
@@ -830,12 +833,67 @@ use foo::bar;", | |||
830 | "foo::bar", | 833 | "foo::bar", |
831 | r"#![allow(unused_imports)] | 834 | r"#![allow(unused_imports)] |
832 | 835 | ||
836 | #![no_std] | ||
833 | fn main() {}", | 837 | fn main() {}", |
834 | r"#![allow(unused_imports)] | 838 | r"#![allow(unused_imports)] |
835 | 839 | ||
836 | use foo::bar; | 840 | #![no_std] |
837 | 841 | ||
842 | use foo::bar; | ||
838 | fn main() {}", | 843 | fn main() {}", |
844 | ); | ||
845 | } | ||
846 | |||
847 | #[test] | ||
848 | fn inserts_after_single_line_inner_comments() { | ||
849 | check_none( | ||
850 | "foo::bar::Baz", | ||
851 | "//! Single line inner comments do not allow any code before them.", | ||
852 | r#"//! Single line inner comments do not allow any code before them. | ||
853 | |||
854 | use foo::bar::Baz;"#, | ||
855 | ); | ||
856 | } | ||
857 | |||
858 | #[test] | ||
859 | fn inserts_after_multiline_inner_comments() { | ||
860 | check_none( | ||
861 | "foo::bar::Baz", | ||
862 | r#"/*! Multiline inner comments do not allow any code before them. */ | ||
863 | |||
864 | /*! Still an inner comment, cannot place any code before. */ | ||
865 | fn main() {}"#, | ||
866 | r#"/*! Multiline inner comments do not allow any code before them. */ | ||
867 | |||
868 | /*! Still an inner comment, cannot place any code before. */ | ||
869 | |||
870 | use foo::bar::Baz; | ||
871 | fn main() {}"#, | ||
872 | ) | ||
873 | } | ||
874 | |||
875 | #[test] | ||
876 | fn inserts_after_all_inner_items() { | ||
877 | check_none( | ||
878 | "foo::bar::Baz", | ||
879 | r#"#![allow(unused_imports)] | ||
880 | /*! Multiline line comment 2 */ | ||
881 | |||
882 | |||
883 | //! Single line comment 1 | ||
884 | #![no_std] | ||
885 | //! Single line comment 2 | ||
886 | fn main() {}"#, | ||
887 | r#"#![allow(unused_imports)] | ||
888 | /*! Multiline line comment 2 */ | ||
889 | |||
890 | |||
891 | //! Single line comment 1 | ||
892 | #![no_std] | ||
893 | //! Single line comment 2 | ||
894 | |||
895 | use foo::bar::Baz; | ||
896 | fn main() {}"#, | ||
839 | ) | 897 | ) |
840 | } | 898 | } |
841 | 899 | ||
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index fdc65a5c3..cf5c38a23 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -35,3 +35,4 @@ expect-test = "1.0" | |||
35 | tracing = "0.1" | 35 | tracing = "0.1" |
36 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } | 36 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } |
37 | tracing-tree = { version = "0.1.4" } | 37 | tracing-tree = { version = "0.1.4" } |
38 | once_cell = { version = "1.5.0", features = ["unstable"] } | ||
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index 104ef334c..0a400cb70 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -22,7 +22,8 @@ use hir_def::{ | |||
22 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, | 22 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, |
23 | }; | 23 | }; |
24 | use hir_expand::{db::AstDatabase, InFile}; | 24 | use hir_expand::{db::AstDatabase, InFile}; |
25 | use stdx::{format_to, RacyFlag}; | 25 | use once_cell::race::OnceBool; |
26 | use stdx::format_to; | ||
26 | use syntax::{ | 27 | use syntax::{ |
27 | algo, | 28 | algo, |
28 | ast::{self, AstNode}, | 29 | ast::{self, AstNode}, |
@@ -40,8 +41,8 @@ use crate::{ | |||
40 | // `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots. | 41 | // `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots. |
41 | 42 | ||
42 | fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { | 43 | fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { |
43 | static ENABLE: RacyFlag = RacyFlag::new(); | 44 | static ENABLE: OnceBool = OnceBool::new(); |
44 | if !ENABLE.get(|| env::var("CHALK_DEBUG").is_ok()) { | 45 | if !ENABLE.get_or_init(|| env::var("CHALK_DEBUG").is_ok()) { |
45 | return None; | 46 | return None; |
46 | } | 47 | } |
47 | 48 | ||
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 37ab7a8f6..1ed77b40b 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -6,7 +6,7 @@ pub(crate) mod tags; | |||
6 | #[cfg(test)] | 6 | #[cfg(test)] |
7 | mod tests; | 7 | mod tests; |
8 | 8 | ||
9 | use hir::{Local, Name, Semantics, VariantDef}; | 9 | use hir::{AsAssocItem, Local, Name, Semantics, VariantDef}; |
10 | use ide_db::{ | 10 | use ide_db::{ |
11 | defs::{Definition, NameClass, NameRefClass}, | 11 | defs::{Definition, NameClass, NameRefClass}, |
12 | RootDatabase, | 12 | RootDatabase, |
@@ -746,6 +746,9 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
746 | if func.is_unsafe(db) { | 746 | if func.is_unsafe(db) { |
747 | h |= HighlightModifier::Unsafe; | 747 | h |= HighlightModifier::Unsafe; |
748 | } | 748 | } |
749 | if func.as_assoc_item(db).is_some() && func.self_param(db).is_none() { | ||
750 | h |= HighlightModifier::Static; | ||
751 | } | ||
749 | return h; | 752 | return h; |
750 | } | 753 | } |
751 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, | 754 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index e8f78ad52..65e0671a5 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -65,6 +65,8 @@ pub enum HighlightModifier { | |||
65 | Consuming, | 65 | Consuming, |
66 | Unsafe, | 66 | Unsafe, |
67 | Callable, | 67 | Callable, |
68 | /// Used for associated functions | ||
69 | Static, | ||
68 | } | 70 | } |
69 | 71 | ||
70 | impl HighlightTag { | 72 | impl HighlightTag { |
@@ -124,6 +126,7 @@ impl HighlightModifier { | |||
124 | HighlightModifier::Consuming, | 126 | HighlightModifier::Consuming, |
125 | HighlightModifier::Unsafe, | 127 | HighlightModifier::Unsafe, |
126 | HighlightModifier::Callable, | 128 | HighlightModifier::Callable, |
129 | HighlightModifier::Static, | ||
127 | ]; | 130 | ]; |
128 | 131 | ||
129 | fn as_str(self) -> &'static str { | 132 | fn as_str(self) -> &'static str { |
@@ -137,6 +140,7 @@ impl HighlightModifier { | |||
137 | HighlightModifier::Consuming => "consuming", | 140 | HighlightModifier::Consuming => "consuming", |
138 | HighlightModifier::Unsafe => "unsafe", | 141 | HighlightModifier::Unsafe => "unsafe", |
139 | HighlightModifier::Callable => "callable", | 142 | HighlightModifier::Callable => "callable", |
143 | HighlightModifier::Static => "static", | ||
140 | } | 144 | } |
141 | } | 145 | } |
142 | 146 | ||
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html new file mode 100644 index 000000000..cd80d72b7 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -0,0 +1,56 @@ | |||
1 | |||
2 | <style> | ||
3 | body { margin: 0; } | ||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | ||
5 | |||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | ||
8 | .documentation { color: #629755; } | ||
9 | .injected { opacity: 0.65 ; } | ||
10 | .struct, .enum { color: #7CB8BB; } | ||
11 | .enum_variant { color: #BDE0F3; } | ||
12 | .string_literal { color: #CC9393; } | ||
13 | .field { color: #94BFF3; } | ||
14 | .function { color: #93E0E3; } | ||
15 | .function.unsafe { color: #BC8383; } | ||
16 | .operator.unsafe { color: #BC8383; } | ||
17 | .parameter { color: #94BFF3; } | ||
18 | .text { color: #DCDCCC; } | ||
19 | .type { color: #7CB8BB; } | ||
20 | .builtin_type { color: #8CD0D3; } | ||
21 | .type_param { color: #DFAF8F; } | ||
22 | .attribute { color: #94BFF3; } | ||
23 | .numeric_literal { color: #BFEBBF; } | ||
24 | .bool_literal { color: #BFE6EB; } | ||
25 | .macro { color: #94BFF3; } | ||
26 | .module { color: #AFD8AF; } | ||
27 | .value_param { color: #DCDCCC; } | ||
28 | .variable { color: #DCDCCC; } | ||
29 | .format_specifier { color: #CC696B; } | ||
30 | .mutable { text-decoration: underline; } | ||
31 | .escape_sequence { color: #94BFF3; } | ||
32 | .keyword { color: #F0DFAF; font-weight: bold; } | ||
33 | .keyword.unsafe { color: #BC8383; font-weight: bold; } | ||
34 | .control { font-style: italic; } | ||
35 | |||
36 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | ||
37 | </style> | ||
38 | <pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
39 | |||
40 | <span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
41 | |||
42 | <span class="keyword">impl</span> <span class="struct">foo</span> <span class="punctuation">{</span> | ||
43 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
44 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
45 | <span class="punctuation">}</span> | ||
46 | |||
47 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="punctuation">{</span> | ||
48 | <span class="keyword">fn</span> <span class="function declaration static">t_is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
49 | <span class="keyword">fn</span> <span class="function declaration">t_is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
50 | <span class="punctuation">}</span> | ||
51 | |||
52 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="punctuation">{</span> | ||
53 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
54 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
55 | <span class="punctuation">}</span> | ||
56 | </code></pre> \ No newline at end of file | ||
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index f44fe457d..6be88f856 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -53,7 +53,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
53 | <span class="comment documentation">/// #</span><span class="generic injected"> </span><span class="attribute injected">#</span><span class="attribute injected">!</span><span class="attribute injected">[</span><span class="function attribute injected">allow</span><span class="punctuation injected">(</span><span class="attribute injected">unused_mut</span><span class="punctuation injected">)</span><span class="attribute injected">]</span> | 53 | <span class="comment documentation">/// #</span><span class="generic injected"> </span><span class="attribute injected">#</span><span class="attribute injected">!</span><span class="attribute injected">[</span><span class="function attribute injected">allow</span><span class="punctuation injected">(</span><span class="attribute injected">unused_mut</span><span class="punctuation injected">)</span><span class="attribute injected">]</span> |
54 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="keyword injected">mut</span><span class="generic injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 54 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="keyword injected">mut</span><span class="generic injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> |
55 | </span> <span class="comment documentation">/// ```</span> | 55 | </span> <span class="comment documentation">/// ```</span> |
56 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 56 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="struct">Foo</span> <span class="punctuation">{</span> |
57 | <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">bar</span><span class="punctuation">:</span> <span class="bool_literal">true</span> <span class="punctuation">}</span> | 57 | <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">bar</span><span class="punctuation">:</span> <span class="bool_literal">true</span> <span class="punctuation">}</span> |
58 | <span class="punctuation">}</span> | 58 | <span class="punctuation">}</span> |
59 | 59 | ||
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 18addd00d..57c178916 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -40,7 +40,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
40 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 40 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> |
41 | <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span> | 41 | <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span> |
42 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span> | 42 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span> |
43 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 43 | <span class="keyword">fn</span> <span class="function declaration static">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> |
44 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> | 44 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> |
45 | <span class="punctuation">}</span> | 45 | <span class="punctuation">}</span> |
46 | <span class="punctuation">}</span><span class="string_literal">"#</span> | 46 | <span class="punctuation">}</span><span class="string_literal">"#</span> |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 2b667b0d4..5c22e2fce 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -513,6 +513,34 @@ fn test_extern_crate() { | |||
513 | ); | 513 | ); |
514 | } | 514 | } |
515 | 515 | ||
516 | #[test] | ||
517 | fn test_associated_function() { | ||
518 | check_highlighting( | ||
519 | r#" | ||
520 | fn not_static() {} | ||
521 | |||
522 | struct foo {} | ||
523 | |||
524 | impl foo { | ||
525 | pub fn is_static() {} | ||
526 | pub fn is_not_static(&self) {} | ||
527 | } | ||
528 | |||
529 | trait t { | ||
530 | fn t_is_static() {} | ||
531 | fn t_is_not_static(&self) {} | ||
532 | } | ||
533 | |||
534 | impl t for foo { | ||
535 | pub fn is_static() {} | ||
536 | pub fn is_not_static(&self) {} | ||
537 | } | ||
538 | "#, | ||
539 | expect_file!["./test_data/highlight_assoc_functions.html"], | ||
540 | false, | ||
541 | ) | ||
542 | } | ||
543 | |||
516 | /// Highlights the code given by the `ra_fixture` argument, renders the | 544 | /// Highlights the code given by the `ra_fixture` argument, renders the |
517 | /// result as HTML, and compares it with the HTML file given as `snapshot`. | 545 | /// result as HTML, and compares it with the HTML file given as `snapshot`. |
518 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | 546 | /// Note that the `snapshot` file is overwritten by the rendered HTML. |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index ff1ae9575..9a8870053 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -16,8 +16,6 @@ use serde_json::json; | |||
16 | use crate::semantic_tokens; | 16 | use crate::semantic_tokens; |
17 | 17 | ||
18 | pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities { | 18 | pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities { |
19 | let code_action_provider = code_action_capabilities(client_caps); | ||
20 | |||
21 | ServerCapabilities { | 19 | ServerCapabilities { |
22 | text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { | 20 | text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { |
23 | open_close: Some(true), | 21 | open_close: Some(true), |
@@ -49,7 +47,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
49 | document_highlight_provider: Some(OneOf::Left(true)), | 47 | document_highlight_provider: Some(OneOf::Left(true)), |
50 | document_symbol_provider: Some(OneOf::Left(true)), | 48 | document_symbol_provider: Some(OneOf::Left(true)), |
51 | workspace_symbol_provider: Some(OneOf::Left(true)), | 49 | workspace_symbol_provider: Some(OneOf::Left(true)), |
52 | code_action_provider: Some(code_action_provider), | 50 | code_action_provider: Some(code_action_capabilities(client_caps)), |
53 | code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), | 51 | code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), |
54 | document_formatting_provider: Some(OneOf::Left(true)), | 52 | document_formatting_provider: Some(OneOf::Left(true)), |
55 | document_range_formatting_provider: None, | 53 | document_range_formatting_provider: None, |
@@ -113,7 +111,7 @@ fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProvi | |||
113 | CodeActionKind::REFACTOR_INLINE, | 111 | CodeActionKind::REFACTOR_INLINE, |
114 | CodeActionKind::REFACTOR_REWRITE, | 112 | CodeActionKind::REFACTOR_REWRITE, |
115 | ]), | 113 | ]), |
116 | resolve_provider: None, | 114 | resolve_provider: Some(true), |
117 | work_done_progress_options: Default::default(), | 115 | work_done_progress_options: Default::default(), |
118 | }) | 116 | }) |
119 | }) | 117 | }) |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 2ed6a0d82..b4c738272 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -144,7 +144,7 @@ pub struct ClientCapsConfig { | |||
144 | pub code_action_literals: bool, | 144 | pub code_action_literals: bool, |
145 | pub work_done_progress: bool, | 145 | pub work_done_progress: bool, |
146 | pub code_action_group: bool, | 146 | pub code_action_group: bool, |
147 | pub resolve_code_action: bool, | 147 | pub code_action_resolve: bool, |
148 | pub hover_actions: bool, | 148 | pub hover_actions: bool, |
149 | pub status_notification: bool, | 149 | pub status_notification: bool, |
150 | pub signature_help_label_offsets: bool, | 150 | pub signature_help_label_offsets: bool, |
@@ -383,6 +383,17 @@ impl Config { | |||
383 | } | 383 | } |
384 | } | 384 | } |
385 | } | 385 | } |
386 | |||
387 | if let Some(code_action) = &doc_caps.code_action { | ||
388 | match (code_action.data_support, &code_action.resolve_support) { | ||
389 | (Some(true), Some(resolve_support)) => { | ||
390 | if resolve_support.properties.iter().any(|it| it == "edit") { | ||
391 | self.client_caps.code_action_resolve = true; | ||
392 | } | ||
393 | } | ||
394 | _ => (), | ||
395 | } | ||
396 | } | ||
386 | } | 397 | } |
387 | 398 | ||
388 | if let Some(window_caps) = caps.window.as_ref() { | 399 | if let Some(window_caps) = caps.window.as_ref() { |
@@ -400,7 +411,6 @@ impl Config { | |||
400 | self.assist.allow_snippets(snippet_text_edit); | 411 | self.assist.allow_snippets(snippet_text_edit); |
401 | 412 | ||
402 | self.client_caps.code_action_group = get_bool("codeActionGroup"); | 413 | self.client_caps.code_action_group = get_bool("codeActionGroup"); |
403 | self.client_caps.resolve_code_action = get_bool("resolveCodeAction"); | ||
404 | self.client_caps.hover_actions = get_bool("hoverActions"); | 414 | self.client_caps.hover_actions = get_bool("hoverActions"); |
405 | self.client_caps.status_notification = get_bool("statusNotification"); | 415 | self.client_caps.status_notification = get_bool("statusNotification"); |
406 | } | 416 | } |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt index 58d47d32a..5b2e5187a 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/compiler/mir/tagset.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/compiler/mir/tagset.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -29,7 +36,14 @@ | |||
29 | [ | 36 | [ |
30 | DiagnosticRelatedInformation { | 37 | DiagnosticRelatedInformation { |
31 | location: Location { | 38 | location: Location { |
32 | uri: "file:///test/compiler/lib.rs", | 39 | uri: Url { |
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/compiler/lib.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
33 | range: Range { | 47 | range: Range { |
34 | start: Position { | 48 | start: Position { |
35 | line: 0, | 49 | line: 0, |
@@ -45,7 +59,14 @@ | |||
45 | }, | 59 | }, |
46 | DiagnosticRelatedInformation { | 60 | DiagnosticRelatedInformation { |
47 | location: Location { | 61 | location: Location { |
48 | uri: "file:///test/compiler/mir/tagset.rs", | 62 | uri: Url { |
63 | scheme: "file", | ||
64 | host: None, | ||
65 | port: None, | ||
66 | path: "/test/compiler/mir/tagset.rs", | ||
67 | query: None, | ||
68 | fragment: None, | ||
69 | }, | ||
49 | range: Range { | 70 | range: Range { |
50 | start: Position { | 71 | start: Position { |
51 | line: 41, | 72 | line: 41, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt index 6aa26bf63..116f0ff73 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/src/main.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/src/main.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt index 7aaffaba2..bbec6a796 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/crates/hir_def/src/data.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/crates/hir_def/src/data.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -25,7 +32,14 @@ | |||
25 | [ | 32 | [ |
26 | DiagnosticRelatedInformation { | 33 | DiagnosticRelatedInformation { |
27 | location: Location { | 34 | location: Location { |
28 | uri: "file:///test/crates/hir_def/src/path.rs", | 35 | uri: Url { |
36 | scheme: "file", | ||
37 | host: None, | ||
38 | port: None, | ||
39 | path: "/test/crates/hir_def/src/path.rs", | ||
40 | query: None, | ||
41 | fragment: None, | ||
42 | }, | ||
29 | range: Range { | 43 | range: Range { |
30 | start: Position { | 44 | start: Position { |
31 | line: 264, | 45 | line: 264, |
@@ -47,7 +61,14 @@ | |||
47 | fixes: [], | 61 | fixes: [], |
48 | }, | 62 | }, |
49 | MappedRustDiagnostic { | 63 | MappedRustDiagnostic { |
50 | url: "file:///test/crates/hir_def/src/path.rs", | 64 | url: Url { |
65 | scheme: "file", | ||
66 | host: None, | ||
67 | port: None, | ||
68 | path: "/test/crates/hir_def/src/path.rs", | ||
69 | query: None, | ||
70 | fragment: None, | ||
71 | }, | ||
51 | diagnostic: Diagnostic { | 72 | diagnostic: Diagnostic { |
52 | range: Range { | 73 | range: Range { |
53 | start: Position { | 74 | start: Position { |
@@ -72,7 +93,14 @@ | |||
72 | [ | 93 | [ |
73 | DiagnosticRelatedInformation { | 94 | DiagnosticRelatedInformation { |
74 | location: Location { | 95 | location: Location { |
75 | uri: "file:///test/crates/hir_def/src/data.rs", | 96 | uri: Url { |
97 | scheme: "file", | ||
98 | host: None, | ||
99 | port: None, | ||
100 | path: "/test/crates/hir_def/src/data.rs", | ||
101 | query: None, | ||
102 | fragment: None, | ||
103 | }, | ||
76 | range: Range { | 104 | range: Range { |
77 | start: Position { | 105 | start: Position { |
78 | line: 79, | 106 | line: 79, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt index 584213420..2cbf657e5 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/compiler/ty/list_iter.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/compiler/ty/list_iter.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt index 2610e4e20..1142dc2ac 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/runtime/compiler_support.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/runtime/compiler_support.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt index 8dc53391e..c709de95f 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/driver/subcommand/repl.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/driver/subcommand/repl.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -36,7 +43,6 @@ | |||
36 | fixes: [ | 43 | fixes: [ |
37 | CodeAction { | 44 | CodeAction { |
38 | title: "consider prefixing with an underscore", | 45 | title: "consider prefixing with an underscore", |
39 | id: None, | ||
40 | group: None, | 46 | group: None, |
41 | kind: Some( | 47 | kind: Some( |
42 | CodeActionKind( | 48 | CodeActionKind( |
@@ -47,7 +53,14 @@ | |||
47 | SnippetWorkspaceEdit { | 53 | SnippetWorkspaceEdit { |
48 | changes: Some( | 54 | changes: Some( |
49 | { | 55 | { |
50 | "file:///test/driver/subcommand/repl.rs": [ | 56 | Url { |
57 | scheme: "file", | ||
58 | host: None, | ||
59 | port: None, | ||
60 | path: "/test/driver/subcommand/repl.rs", | ||
61 | query: None, | ||
62 | fragment: None, | ||
63 | }: [ | ||
51 | TextEdit { | 64 | TextEdit { |
52 | range: Range { | 65 | range: Range { |
53 | start: Position { | 66 | start: Position { |
@@ -70,6 +83,7 @@ | |||
70 | is_preferred: Some( | 83 | is_preferred: Some( |
71 | true, | 84 | true, |
72 | ), | 85 | ), |
86 | data: None, | ||
73 | }, | 87 | }, |
74 | ], | 88 | ], |
75 | }, | 89 | }, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt index c8703194c..632f438d7 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/driver/subcommand/repl.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/driver/subcommand/repl.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -36,7 +43,6 @@ | |||
36 | fixes: [ | 43 | fixes: [ |
37 | CodeAction { | 44 | CodeAction { |
38 | title: "consider prefixing with an underscore", | 45 | title: "consider prefixing with an underscore", |
39 | id: None, | ||
40 | group: None, | 46 | group: None, |
41 | kind: Some( | 47 | kind: Some( |
42 | CodeActionKind( | 48 | CodeActionKind( |
@@ -47,7 +53,14 @@ | |||
47 | SnippetWorkspaceEdit { | 53 | SnippetWorkspaceEdit { |
48 | changes: Some( | 54 | changes: Some( |
49 | { | 55 | { |
50 | "file:///test/driver/subcommand/repl.rs": [ | 56 | Url { |
57 | scheme: "file", | ||
58 | host: None, | ||
59 | port: None, | ||
60 | path: "/test/driver/subcommand/repl.rs", | ||
61 | query: None, | ||
62 | fragment: None, | ||
63 | }: [ | ||
51 | TextEdit { | 64 | TextEdit { |
52 | range: Range { | 65 | range: Range { |
53 | start: Position { | 66 | start: Position { |
@@ -70,6 +83,7 @@ | |||
70 | is_preferred: Some( | 83 | is_preferred: Some( |
71 | true, | 84 | true, |
72 | ), | 85 | ), |
86 | data: None, | ||
73 | }, | 87 | }, |
74 | ], | 88 | ], |
75 | }, | 89 | }, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt index dc93227ad..c0b79428d 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/driver/subcommand/repl.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/driver/subcommand/repl.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -36,7 +43,6 @@ | |||
36 | fixes: [ | 43 | fixes: [ |
37 | CodeAction { | 44 | CodeAction { |
38 | title: "consider prefixing with an underscore", | 45 | title: "consider prefixing with an underscore", |
39 | id: None, | ||
40 | group: None, | 46 | group: None, |
41 | kind: Some( | 47 | kind: Some( |
42 | CodeActionKind( | 48 | CodeActionKind( |
@@ -47,7 +53,14 @@ | |||
47 | SnippetWorkspaceEdit { | 53 | SnippetWorkspaceEdit { |
48 | changes: Some( | 54 | changes: Some( |
49 | { | 55 | { |
50 | "file:///test/driver/subcommand/repl.rs": [ | 56 | Url { |
57 | scheme: "file", | ||
58 | host: None, | ||
59 | port: None, | ||
60 | path: "/test/driver/subcommand/repl.rs", | ||
61 | query: None, | ||
62 | fragment: None, | ||
63 | }: [ | ||
51 | TextEdit { | 64 | TextEdit { |
52 | range: Range { | 65 | range: Range { |
53 | start: Position { | 66 | start: Position { |
@@ -70,6 +83,7 @@ | |||
70 | is_preferred: Some( | 83 | is_preferred: Some( |
71 | true, | 84 | true, |
72 | ), | 85 | ), |
86 | data: None, | ||
73 | }, | 87 | }, |
74 | ], | 88 | ], |
75 | }, | 89 | }, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt index ba1b98b33..782c72dbd 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/compiler/ty/select.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/compiler/ty/select.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -29,7 +36,14 @@ | |||
29 | [ | 36 | [ |
30 | DiagnosticRelatedInformation { | 37 | DiagnosticRelatedInformation { |
31 | location: Location { | 38 | location: Location { |
32 | uri: "file:///test/compiler/ty/select.rs", | 39 | uri: Url { |
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/compiler/ty/select.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
33 | range: Range { | 47 | range: Range { |
34 | start: Position { | 48 | start: Position { |
35 | line: 218, | 49 | line: 218, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt index 81f752672..d3f27ab6a 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/src/main.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/src/main.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -29,7 +36,14 @@ | |||
29 | [ | 36 | [ |
30 | DiagnosticRelatedInformation { | 37 | DiagnosticRelatedInformation { |
31 | location: Location { | 38 | location: Location { |
32 | uri: "file:///test/src/main.rs", | 39 | uri: Url { |
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/src/main.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
33 | range: Range { | 47 | range: Range { |
34 | start: Position { | 48 | start: Position { |
35 | line: 2, | 49 | line: 2, |
@@ -51,7 +65,6 @@ | |||
51 | fixes: [ | 65 | fixes: [ |
52 | CodeAction { | 66 | CodeAction { |
53 | title: "return the expression directly", | 67 | title: "return the expression directly", |
54 | id: None, | ||
55 | group: None, | 68 | group: None, |
56 | kind: Some( | 69 | kind: Some( |
57 | CodeActionKind( | 70 | CodeActionKind( |
@@ -62,7 +75,14 @@ | |||
62 | SnippetWorkspaceEdit { | 75 | SnippetWorkspaceEdit { |
63 | changes: Some( | 76 | changes: Some( |
64 | { | 77 | { |
65 | "file:///test/src/main.rs": [ | 78 | Url { |
79 | scheme: "file", | ||
80 | host: None, | ||
81 | port: None, | ||
82 | path: "/test/src/main.rs", | ||
83 | query: None, | ||
84 | fragment: None, | ||
85 | }: [ | ||
66 | TextEdit { | 86 | TextEdit { |
67 | range: Range { | 87 | range: Range { |
68 | start: Position { | 88 | start: Position { |
@@ -98,6 +118,7 @@ | |||
98 | is_preferred: Some( | 118 | is_preferred: Some( |
99 | true, | 119 | true, |
100 | ), | 120 | ), |
121 | data: None, | ||
101 | }, | 122 | }, |
102 | ], | 123 | ], |
103 | }, | 124 | }, |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index b949577c1..15145415b 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -110,7 +110,6 @@ fn map_rust_child_diagnostic( | |||
110 | } else { | 110 | } else { |
111 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { | 111 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { |
112 | title: rd.message.clone(), | 112 | title: rd.message.clone(), |
113 | id: None, | ||
114 | group: None, | 113 | group: None, |
115 | kind: Some(lsp_types::CodeActionKind::QUICKFIX), | 114 | kind: Some(lsp_types::CodeActionKind::QUICKFIX), |
116 | edit: Some(lsp_ext::SnippetWorkspaceEdit { | 115 | edit: Some(lsp_ext::SnippetWorkspaceEdit { |
@@ -119,6 +118,7 @@ fn map_rust_child_diagnostic( | |||
119 | document_changes: None, | 118 | document_changes: None, |
120 | }), | 119 | }), |
121 | is_preferred: Some(true), | 120 | is_preferred: Some(true), |
121 | data: None, | ||
122 | }) | 122 | }) |
123 | } | 123 | } |
124 | } | 124 | } |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 049c583a4..95659b0db 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -806,11 +806,11 @@ fn handle_fixes( | |||
806 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; | 806 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; |
807 | let action = lsp_ext::CodeAction { | 807 | let action = lsp_ext::CodeAction { |
808 | title: fix.label.to_string(), | 808 | title: fix.label.to_string(), |
809 | id: None, | ||
810 | group: None, | 809 | group: None, |
811 | kind: Some(CodeActionKind::QUICKFIX), | 810 | kind: Some(CodeActionKind::QUICKFIX), |
812 | edit: Some(edit), | 811 | edit: Some(edit), |
813 | is_preferred: Some(false), | 812 | is_preferred: Some(false), |
813 | data: None, | ||
814 | }; | 814 | }; |
815 | res.push(action); | 815 | res.push(action); |
816 | } | 816 | } |
@@ -852,11 +852,11 @@ pub(crate) fn handle_code_action( | |||
852 | 852 | ||
853 | handle_fixes(&snap, ¶ms, &mut res)?; | 853 | handle_fixes(&snap, ¶ms, &mut res)?; |
854 | 854 | ||
855 | if snap.config.client_caps.resolve_code_action { | 855 | if snap.config.client_caps.code_action_resolve { |
856 | for (index, assist) in | 856 | for (index, assist) in |
857 | snap.analysis.unresolved_assists(&snap.config.assist, frange)?.into_iter().enumerate() | 857 | snap.analysis.unresolved_assists(&snap.config.assist, frange)?.into_iter().enumerate() |
858 | { | 858 | { |
859 | res.push(to_proto::unresolved_code_action(&snap, assist, index)?); | 859 | res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?); |
860 | } | 860 | } |
861 | } else { | 861 | } else { |
862 | for assist in snap.analysis.resolved_assists(&snap.config.assist, frange)?.into_iter() { | 862 | for assist in snap.analysis.resolved_assists(&snap.config.assist, frange)?.into_iter() { |
@@ -867,11 +867,16 @@ pub(crate) fn handle_code_action( | |||
867 | Ok(Some(res)) | 867 | Ok(Some(res)) |
868 | } | 868 | } |
869 | 869 | ||
870 | pub(crate) fn handle_resolve_code_action( | 870 | pub(crate) fn handle_code_action_resolve( |
871 | mut snap: GlobalStateSnapshot, | 871 | mut snap: GlobalStateSnapshot, |
872 | params: lsp_ext::ResolveCodeActionParams, | 872 | mut code_action: lsp_ext::CodeAction, |
873 | ) -> Result<Option<lsp_ext::SnippetWorkspaceEdit>> { | 873 | ) -> Result<lsp_ext::CodeAction> { |
874 | let _p = profile::span("handle_resolve_code_action"); | 874 | let _p = profile::span("handle_code_action_resolve"); |
875 | let params = match code_action.data.take() { | ||
876 | Some(it) => it, | ||
877 | None => Err("can't resolve code action without data")?, | ||
878 | }; | ||
879 | |||
875 | let file_id = from_proto::file_id(&snap, ¶ms.code_action_params.text_document.uri)?; | 880 | let file_id = from_proto::file_id(&snap, ¶ms.code_action_params.text_document.uri)?; |
876 | let line_index = snap.analysis.file_line_index(file_id)?; | 881 | let line_index = snap.analysis.file_line_index(file_id)?; |
877 | let range = from_proto::text_range(&line_index, params.code_action_params.range); | 882 | let range = from_proto::text_range(&line_index, params.code_action_params.range); |
@@ -888,7 +893,9 @@ pub(crate) fn handle_resolve_code_action( | |||
888 | let index = index.parse::<usize>().unwrap(); | 893 | let index = index.parse::<usize>().unwrap(); |
889 | let assist = &assists[index]; | 894 | let assist = &assists[index]; |
890 | assert!(assist.assist.id.0 == id); | 895 | assert!(assist.assist.id.0 == id); |
891 | Ok(to_proto::resolved_code_action(&snap, assist.clone())?.edit) | 896 | let edit = to_proto::resolved_code_action(&snap, assist.clone())?.edit; |
897 | code_action.edit = edit; | ||
898 | Ok(code_action) | ||
892 | } | 899 | } |
893 | 900 | ||
894 | pub(crate) fn handle_code_lens( | 901 | pub(crate) fn handle_code_lens( |
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index f31f8d900..a7c3028e4 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -113,22 +113,6 @@ pub struct JoinLinesParams { | |||
113 | pub ranges: Vec<Range>, | 113 | pub ranges: Vec<Range>, |
114 | } | 114 | } |
115 | 115 | ||
116 | pub enum ResolveCodeActionRequest {} | ||
117 | |||
118 | impl Request for ResolveCodeActionRequest { | ||
119 | type Params = ResolveCodeActionParams; | ||
120 | type Result = Option<SnippetWorkspaceEdit>; | ||
121 | const METHOD: &'static str = "experimental/resolveCodeAction"; | ||
122 | } | ||
123 | |||
124 | /// Params for the ResolveCodeActionRequest | ||
125 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] | ||
126 | #[serde(rename_all = "camelCase")] | ||
127 | pub struct ResolveCodeActionParams { | ||
128 | pub code_action_params: lsp_types::CodeActionParams, | ||
129 | pub id: String, | ||
130 | } | ||
131 | |||
132 | pub enum OnEnter {} | 116 | pub enum OnEnter {} |
133 | 117 | ||
134 | impl Request for OnEnter { | 118 | impl Request for OnEnter { |
@@ -265,13 +249,18 @@ impl Request for CodeActionRequest { | |||
265 | const METHOD: &'static str = "textDocument/codeAction"; | 249 | const METHOD: &'static str = "textDocument/codeAction"; |
266 | } | 250 | } |
267 | 251 | ||
252 | pub enum CodeActionResolveRequest {} | ||
253 | impl Request for CodeActionResolveRequest { | ||
254 | type Params = CodeAction; | ||
255 | type Result = CodeAction; | ||
256 | const METHOD: &'static str = "codeAction/resolve"; | ||
257 | } | ||
258 | |||
268 | #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] | 259 | #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] |
269 | #[serde(rename_all = "camelCase")] | 260 | #[serde(rename_all = "camelCase")] |
270 | pub struct CodeAction { | 261 | pub struct CodeAction { |
271 | pub title: String, | 262 | pub title: String, |
272 | #[serde(skip_serializing_if = "Option::is_none")] | 263 | #[serde(skip_serializing_if = "Option::is_none")] |
273 | pub id: Option<String>, | ||
274 | #[serde(skip_serializing_if = "Option::is_none")] | ||
275 | pub group: Option<String>, | 264 | pub group: Option<String>, |
276 | #[serde(skip_serializing_if = "Option::is_none")] | 265 | #[serde(skip_serializing_if = "Option::is_none")] |
277 | pub kind: Option<CodeActionKind>, | 266 | pub kind: Option<CodeActionKind>, |
@@ -282,6 +271,16 @@ pub struct CodeAction { | |||
282 | pub edit: Option<SnippetWorkspaceEdit>, | 271 | pub edit: Option<SnippetWorkspaceEdit>, |
283 | #[serde(skip_serializing_if = "Option::is_none")] | 272 | #[serde(skip_serializing_if = "Option::is_none")] |
284 | pub is_preferred: Option<bool>, | 273 | pub is_preferred: Option<bool>, |
274 | |||
275 | #[serde(skip_serializing_if = "Option::is_none")] | ||
276 | pub data: Option<CodeActionData>, | ||
277 | } | ||
278 | |||
279 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] | ||
280 | #[serde(rename_all = "camelCase")] | ||
281 | pub struct CodeActionData { | ||
282 | pub code_action_params: lsp_types::CodeActionParams, | ||
283 | pub id: String, | ||
285 | } | 284 | } |
286 | 285 | ||
287 | #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] | 286 | #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index d504572a8..6e6cac42e 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -435,7 +435,7 @@ impl GlobalState { | |||
435 | .on::<lsp_ext::Runnables>(handlers::handle_runnables) | 435 | .on::<lsp_ext::Runnables>(handlers::handle_runnables) |
436 | .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints) | 436 | .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints) |
437 | .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action) | 437 | .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action) |
438 | .on::<lsp_ext::ResolveCodeActionRequest>(handlers::handle_resolve_code_action) | 438 | .on::<lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve) |
439 | .on::<lsp_ext::HoverRequest>(handlers::handle_hover) | 439 | .on::<lsp_ext::HoverRequest>(handlers::handle_hover) |
440 | .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs) | 440 | .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs) |
441 | .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting) | 441 | .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting) |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 92b7c7b68..4bdf4bf0f 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -426,6 +426,7 @@ fn semantic_token_type_and_modifiers( | |||
426 | HighlightModifier::Consuming => semantic_tokens::CONSUMING, | 426 | HighlightModifier::Consuming => semantic_tokens::CONSUMING, |
427 | HighlightModifier::Unsafe => semantic_tokens::UNSAFE, | 427 | HighlightModifier::Unsafe => semantic_tokens::UNSAFE, |
428 | HighlightModifier::Callable => semantic_tokens::CALLABLE, | 428 | HighlightModifier::Callable => semantic_tokens::CALLABLE, |
429 | HighlightModifier::Static => lsp_types::SemanticTokenModifier::STATIC, | ||
429 | }; | 430 | }; |
430 | mods |= modifier; | 431 | mods |= modifier; |
431 | } | 432 | } |
@@ -734,16 +735,20 @@ pub(crate) fn code_action_kind(kind: AssistKind) -> lsp_types::CodeActionKind { | |||
734 | 735 | ||
735 | pub(crate) fn unresolved_code_action( | 736 | pub(crate) fn unresolved_code_action( |
736 | snap: &GlobalStateSnapshot, | 737 | snap: &GlobalStateSnapshot, |
738 | code_action_params: lsp_types::CodeActionParams, | ||
737 | assist: Assist, | 739 | assist: Assist, |
738 | index: usize, | 740 | index: usize, |
739 | ) -> Result<lsp_ext::CodeAction> { | 741 | ) -> Result<lsp_ext::CodeAction> { |
740 | let res = lsp_ext::CodeAction { | 742 | let res = lsp_ext::CodeAction { |
741 | title: assist.label.to_string(), | 743 | title: assist.label.to_string(), |
742 | id: Some(format!("{}:{}", assist.id.0, index.to_string())), | ||
743 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), | 744 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), |
744 | kind: Some(code_action_kind(assist.id.1)), | 745 | kind: Some(code_action_kind(assist.id.1)), |
745 | edit: None, | 746 | edit: None, |
746 | is_preferred: None, | 747 | is_preferred: None, |
748 | data: Some(lsp_ext::CodeActionData { | ||
749 | id: format!("{}:{}", assist.id.0, index.to_string()), | ||
750 | code_action_params, | ||
751 | }), | ||
747 | }; | 752 | }; |
748 | Ok(res) | 753 | Ok(res) |
749 | } | 754 | } |
@@ -753,13 +758,19 @@ pub(crate) fn resolved_code_action( | |||
753 | assist: ResolvedAssist, | 758 | assist: ResolvedAssist, |
754 | ) -> Result<lsp_ext::CodeAction> { | 759 | ) -> Result<lsp_ext::CodeAction> { |
755 | let change = assist.source_change; | 760 | let change = assist.source_change; |
756 | unresolved_code_action(snap, assist.assist, 0).and_then(|it| { | 761 | let res = lsp_ext::CodeAction { |
757 | Ok(lsp_ext::CodeAction { | 762 | edit: Some(snippet_workspace_edit(snap, change)?), |
758 | id: None, | 763 | title: assist.assist.label.to_string(), |
759 | edit: Some(snippet_workspace_edit(snap, change)?), | 764 | group: assist |
760 | ..it | 765 | .assist |
761 | }) | 766 | .group |
762 | }) | 767 | .filter(|_| snap.config.client_caps.code_action_group) |
768 | .map(|gr| gr.0), | ||
769 | kind: Some(code_action_kind(assist.assist.id.1)), | ||
770 | is_preferred: None, | ||
771 | data: None, | ||
772 | }; | ||
773 | Ok(res) | ||
763 | } | 774 | } |
764 | 775 | ||
765 | pub(crate) fn runnable( | 776 | pub(crate) fn runnable( |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 59d89f47d..374ed5910 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -1,8 +1,5 @@ | |||
1 | //! Missing batteries for standard libraries. | 1 | //! Missing batteries for standard libraries. |
2 | use std::{ | 2 | use std::time::Instant; |
3 | sync::atomic::{AtomicUsize, Ordering}, | ||
4 | time::Instant, | ||
5 | }; | ||
6 | 3 | ||
7 | mod macros; | 4 | mod macros; |
8 | pub mod panic_context; | 5 | pub mod panic_context; |
@@ -150,31 +147,6 @@ where | |||
150 | left | 147 | left |
151 | } | 148 | } |
152 | 149 | ||
153 | pub struct RacyFlag(AtomicUsize); | ||
154 | |||
155 | impl RacyFlag { | ||
156 | pub const fn new() -> RacyFlag { | ||
157 | RacyFlag(AtomicUsize::new(!0)) | ||
158 | } | ||
159 | |||
160 | pub fn get(&self, init: impl FnMut() -> bool) -> bool { | ||
161 | let mut init = Some(init); | ||
162 | self.get_impl(&mut || init.take().map_or(false, |mut f| f())) | ||
163 | } | ||
164 | |||
165 | fn get_impl(&self, init: &mut dyn FnMut() -> bool) -> bool { | ||
166 | match self.0.load(Ordering::Relaxed) { | ||
167 | 0 => false, | ||
168 | 1 => true, | ||
169 | _ => { | ||
170 | let res = init(); | ||
171 | self.0.store(if res { 1 } else { 0 }, Ordering::Relaxed); | ||
172 | res | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | #[cfg(test)] | 150 | #[cfg(test)] |
179 | mod tests { | 151 | mod tests { |
180 | use super::*; | 152 | use super::*; |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 61d2acb49..1fe907753 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.9.0" | 14 | itertools = "0.9.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "686.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "688.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 30adb7217..320c430c9 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -111,18 +111,28 @@ pub enum InsertPosition<T> { | |||
111 | 111 | ||
112 | type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>; | 112 | type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>; |
113 | 113 | ||
114 | #[derive(Debug, Hash, PartialEq, Eq)] | ||
115 | enum TreeDiffInsertPos { | ||
116 | After(SyntaxElement), | ||
117 | AsFirstChild(SyntaxElement), | ||
118 | } | ||
119 | |||
114 | #[derive(Debug)] | 120 | #[derive(Debug)] |
115 | pub struct TreeDiff { | 121 | pub struct TreeDiff { |
116 | replacements: FxHashMap<SyntaxElement, SyntaxElement>, | 122 | replacements: FxHashMap<SyntaxElement, SyntaxElement>, |
117 | deletions: Vec<SyntaxElement>, | 123 | deletions: Vec<SyntaxElement>, |
118 | // the vec as well as the indexmap are both here to preserve order | 124 | // the vec as well as the indexmap are both here to preserve order |
119 | insertions: FxIndexMap<SyntaxElement, Vec<SyntaxElement>>, | 125 | insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>, |
120 | } | 126 | } |
121 | 127 | ||
122 | impl TreeDiff { | 128 | impl TreeDiff { |
123 | pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { | 129 | pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { |
124 | for (anchor, to) in self.insertions.iter() { | 130 | for (anchor, to) in self.insertions.iter() { |
125 | to.iter().for_each(|to| builder.insert(anchor.text_range().end(), to.to_string())); | 131 | let offset = match anchor { |
132 | TreeDiffInsertPos::After(it) => it.text_range().end(), | ||
133 | TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(), | ||
134 | }; | ||
135 | to.iter().for_each(|to| builder.insert(offset, to.to_string())); | ||
126 | } | 136 | } |
127 | for (from, to) in self.replacements.iter() { | 137 | for (from, to) in self.replacements.iter() { |
128 | builder.replace(from.text_range(), to.to_string()) | 138 | builder.replace(from.text_range(), to.to_string()) |
@@ -188,19 +198,20 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { | |||
188 | let lhs_child = lhs_children.next(); | 198 | let lhs_child = lhs_children.next(); |
189 | match (lhs_child.clone(), rhs_children.next()) { | 199 | match (lhs_child.clone(), rhs_children.next()) { |
190 | (None, None) => break, | 200 | (None, None) => break, |
191 | (None, Some(element)) => match last_lhs.clone() { | 201 | (None, Some(element)) => { |
192 | Some(prev) => { | 202 | let insert_pos = match last_lhs.clone() { |
193 | mark::hit!(diff_insert); | 203 | Some(prev) => { |
194 | diff.insertions.entry(prev).or_insert_with(Vec::new).push(element); | 204 | mark::hit!(diff_insert); |
195 | } | 205 | TreeDiffInsertPos::After(prev) |
196 | // first iteration, this means we got no anchor element to insert after | 206 | } |
197 | // therefor replace the parent node instead | 207 | // first iteration, insert into out parent as the first child |
198 | None => { | 208 | None => { |
199 | mark::hit!(diff_replace_parent); | 209 | mark::hit!(diff_insert_as_first_child); |
200 | diff.replacements.insert(lhs.clone().into(), rhs.clone().into()); | 210 | TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) |
201 | break; | 211 | } |
202 | } | 212 | }; |
203 | }, | 213 | diff.insertions.entry(insert_pos).or_insert_with(Vec::new).push(element); |
214 | } | ||
204 | (Some(element), None) => { | 215 | (Some(element), None) => { |
205 | mark::hit!(diff_delete); | 216 | mark::hit!(diff_delete); |
206 | diff.deletions.push(element); | 217 | diff.deletions.push(element); |
@@ -224,8 +235,15 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { | |||
224 | } | 235 | } |
225 | } | 236 | } |
226 | let drain = look_ahead_scratch.drain(..); | 237 | let drain = look_ahead_scratch.drain(..); |
227 | if let Some(prev) = last_lhs.clone().filter(|_| insert) { | 238 | if insert { |
228 | diff.insertions.entry(prev).or_insert_with(Vec::new).extend(drain); | 239 | let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) { |
240 | TreeDiffInsertPos::After(prev) | ||
241 | } else { | ||
242 | mark::hit!(insert_first_child); | ||
243 | TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) | ||
244 | }; | ||
245 | |||
246 | diff.insertions.entry(insert_pos).or_insert_with(Vec::new).extend(drain); | ||
229 | rhs_children = rhs_children_clone; | 247 | rhs_children = rhs_children_clone; |
230 | } else { | 248 | } else { |
231 | go(diff, lhs_ele, rhs_ele) | 249 | go(diff, lhs_ele, rhs_ele) |
@@ -632,18 +650,19 @@ mod tests { | |||
632 | 650 | ||
633 | #[test] | 651 | #[test] |
634 | fn replace_parent() { | 652 | fn replace_parent() { |
635 | mark::check!(diff_replace_parent); | 653 | mark::check!(diff_insert_as_first_child); |
636 | check_diff( | 654 | check_diff( |
637 | r#""#, | 655 | r#""#, |
638 | r#"use foo::bar;"#, | 656 | r#"use foo::bar;"#, |
639 | expect![[r#" | 657 | expect![[r#" |
640 | insertions: | 658 | insertions: |
641 | 659 | ||
642 | 660 | Line 0: AsFirstChild(Node([email protected])) | |
661 | -> use foo::bar; | ||
643 | 662 | ||
644 | replacements: | 663 | replacements: |
645 | 664 | ||
646 | Line 0: Node([email protected]) -> use foo::bar; | 665 | |
647 | 666 | ||
648 | deletions: | 667 | deletions: |
649 | 668 | ||
@@ -666,7 +685,7 @@ use baz;"#, | |||
666 | expect![[r#" | 685 | expect![[r#" |
667 | insertions: | 686 | insertions: |
668 | 687 | ||
669 | Line 2: Node([email protected]) | 688 | Line 2: After(Node([email protected])) |
670 | -> "\n" | 689 | -> "\n" |
671 | -> use baz; | 690 | -> use baz; |
672 | 691 | ||
@@ -694,7 +713,7 @@ use baz;"#, | |||
694 | expect![[r#" | 713 | expect![[r#" |
695 | insertions: | 714 | insertions: |
696 | 715 | ||
697 | Line 2: Token([email protected] "\n") | 716 | Line 2: After(Token([email protected] "\n")) |
698 | -> use bar; | 717 | -> use bar; |
699 | -> "\n" | 718 | -> "\n" |
700 | 719 | ||
@@ -722,7 +741,7 @@ use baz;"#, | |||
722 | expect![[r#" | 741 | expect![[r#" |
723 | insertions: | 742 | insertions: |
724 | 743 | ||
725 | Line 0: Token([email protected] "\n") | 744 | Line 0: After(Token([email protected] "\n")) |
726 | -> use foo; | 745 | -> use foo; |
727 | -> "\n" | 746 | -> "\n" |
728 | 747 | ||
@@ -738,6 +757,36 @@ use baz;"#, | |||
738 | } | 757 | } |
739 | 758 | ||
740 | #[test] | 759 | #[test] |
760 | fn first_child_insertion() { | ||
761 | mark::check!(insert_first_child); | ||
762 | check_diff( | ||
763 | r#"fn main() { | ||
764 | stdi | ||
765 | }"#, | ||
766 | r#"use foo::bar; | ||
767 | |||
768 | fn main() { | ||
769 | stdi | ||
770 | }"#, | ||
771 | expect![[r#" | ||
772 | insertions: | ||
773 | |||
774 | Line 0: AsFirstChild(Node([email protected])) | ||
775 | -> use foo::bar; | ||
776 | -> "\n\n " | ||
777 | |||
778 | replacements: | ||
779 | |||
780 | |||
781 | |||
782 | deletions: | ||
783 | |||
784 | |||
785 | "#]], | ||
786 | ); | ||
787 | } | ||
788 | |||
789 | #[test] | ||
741 | fn delete_last() { | 790 | fn delete_last() { |
742 | mark::check!(diff_delete); | 791 | mark::check!(diff_delete); |
743 | check_diff( | 792 | check_diff( |
@@ -779,7 +828,7 @@ use crate::AstNode; | |||
779 | expect![[r#" | 828 | expect![[r#" |
780 | insertions: | 829 | insertions: |
781 | 830 | ||
782 | Line 1: Node([email protected]) | 831 | Line 1: After(Node([email protected])) |
783 | -> "\n\n" | 832 | -> "\n\n" |
784 | -> use crate::AstNode; | 833 | -> use crate::AstNode; |
785 | 834 | ||
@@ -845,10 +894,10 @@ use std::ops::{self, RangeInclusive}; | |||
845 | expect![[r#" | 894 | expect![[r#" |
846 | insertions: | 895 | insertions: |
847 | 896 | ||
848 | Line 2: Node([email protected]) | 897 | Line 2: After(Node([email protected])) |
849 | -> :: | 898 | -> :: |
850 | -> fmt | 899 | -> fmt |
851 | Line 6: Token([email protected] "\n") | 900 | Line 6: After(Token([email protected] "\n")) |
852 | -> use std::hash::BuildHasherDefault; | 901 | -> use std::hash::BuildHasherDefault; |
853 | -> "\n" | 902 | -> "\n" |
854 | -> use std::ops::{self, RangeInclusive}; | 903 | -> use std::ops::{self, RangeInclusive}; |
@@ -892,14 +941,14 @@ fn main() { | |||
892 | expect![[r#" | 941 | expect![[r#" |
893 | insertions: | 942 | insertions: |
894 | 943 | ||
895 | Line 3: Node([email protected]) | 944 | Line 3: After(Node([email protected])) |
896 | -> " " | 945 | -> " " |
897 | -> match Err(92) { | 946 | -> match Err(92) { |
898 | Ok(it) => it, | 947 | Ok(it) => it, |
899 | _ => return, | 948 | _ => return, |
900 | } | 949 | } |
901 | -> ; | 950 | -> ; |
902 | Line 3: Node([email protected]) | 951 | Line 3: After(Node([email protected])) |
903 | -> "\n " | 952 | -> "\n " |
904 | -> foo(x); | 953 | -> foo(x); |
905 | 954 | ||
@@ -934,14 +983,18 @@ fn main() { | |||
934 | _ => format!("{}", syn), | 983 | _ => format!("{}", syn), |
935 | }; | 984 | }; |
936 | 985 | ||
937 | let insertions = diff.insertions.iter().format_with("\n", |(k, v), f| { | 986 | let insertions = |
938 | f(&format!( | 987 | diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> { |
939 | "Line {}: {:?}\n-> {}", | 988 | f(&format!( |
940 | line_number(k), | 989 | "Line {}: {:?}\n-> {}", |
941 | k, | 990 | line_number(match k { |
942 | v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) | 991 | super::TreeDiffInsertPos::After(syn) => syn, |
943 | )) | 992 | super::TreeDiffInsertPos::AsFirstChild(syn) => syn, |
944 | }); | 993 | }), |
994 | k, | ||
995 | v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) | ||
996 | )) | ||
997 | }); | ||
945 | 998 | ||
946 | let replacements = diff | 999 | let replacements = diff |
947 | .replacements | 1000 | .replacements |
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index 8a0e3d27b..7844f9ed6 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs | |||
@@ -115,10 +115,10 @@ fn test_doc_comment_none() { | |||
115 | } | 115 | } |
116 | 116 | ||
117 | #[test] | 117 | #[test] |
118 | fn test_doc_comment_of_items() { | 118 | fn test_outer_doc_comment_of_items() { |
119 | let file = SourceFile::parse( | 119 | let file = SourceFile::parse( |
120 | r#" | 120 | r#" |
121 | //! doc | 121 | /// doc |
122 | // non-doc | 122 | // non-doc |
123 | mod foo {} | 123 | mod foo {} |
124 | "#, | 124 | "#, |
@@ -130,6 +130,21 @@ fn test_doc_comment_of_items() { | |||
130 | } | 130 | } |
131 | 131 | ||
132 | #[test] | 132 | #[test] |
133 | fn test_inner_doc_comment_of_items() { | ||
134 | let file = SourceFile::parse( | ||
135 | r#" | ||
136 | //! doc | ||
137 | // non-doc | ||
138 | mod foo {} | ||
139 | "#, | ||
140 | ) | ||
141 | .ok() | ||
142 | .unwrap(); | ||
143 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | ||
144 | assert!(module.doc_comment_text().is_none()); | ||
145 | } | ||
146 | |||
147 | #[test] | ||
133 | fn test_doc_comment_of_statics() { | 148 | fn test_doc_comment_of_statics() { |
134 | let file = SourceFile::parse( | 149 | let file = SourceFile::parse( |
135 | r#" | 150 | r#" |
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index e4e512f2e..2661c753e 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs | |||
@@ -14,16 +14,15 @@ use crate::{ | |||
14 | 14 | ||
15 | impl ast::Comment { | 15 | impl ast::Comment { |
16 | pub fn kind(&self) -> CommentKind { | 16 | pub fn kind(&self) -> CommentKind { |
17 | kind_by_prefix(self.text()) | 17 | CommentKind::from_text(self.text()) |
18 | } | 18 | } |
19 | 19 | ||
20 | pub fn prefix(&self) -> &'static str { | 20 | pub fn prefix(&self) -> &'static str { |
21 | for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() { | 21 | let &(prefix, _kind) = CommentKind::BY_PREFIX |
22 | if *k == self.kind() && self.text().starts_with(prefix) { | 22 | .iter() |
23 | return prefix; | 23 | .find(|&(prefix, kind)| self.kind() == *kind && self.text().starts_with(prefix)) |
24 | } | 24 | .unwrap(); |
25 | } | 25 | prefix |
26 | unreachable!() | ||
27 | } | 26 | } |
28 | } | 27 | } |
29 | 28 | ||
@@ -55,29 +54,25 @@ pub enum CommentPlacement { | |||
55 | Outer, | 54 | Outer, |
56 | } | 55 | } |
57 | 56 | ||
58 | const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { | 57 | impl CommentKind { |
59 | use {CommentPlacement::*, CommentShape::*}; | 58 | const BY_PREFIX: [(&'static str, CommentKind); 8] = [ |
60 | &[ | 59 | ("/**/", CommentKind { shape: CommentShape::Block, doc: None }), |
61 | ("////", CommentKind { shape: Line, doc: None }), | 60 | ("////", CommentKind { shape: CommentShape::Line, doc: None }), |
62 | ("///", CommentKind { shape: Line, doc: Some(Outer) }), | 61 | ("///", CommentKind { shape: CommentShape::Line, doc: Some(CommentPlacement::Outer) }), |
63 | ("//!", CommentKind { shape: Line, doc: Some(Inner) }), | 62 | ("//!", CommentKind { shape: CommentShape::Line, doc: Some(CommentPlacement::Inner) }), |
64 | ("/**", CommentKind { shape: Block, doc: Some(Outer) }), | 63 | ("/**", CommentKind { shape: CommentShape::Block, doc: Some(CommentPlacement::Outer) }), |
65 | ("/*!", CommentKind { shape: Block, doc: Some(Inner) }), | 64 | ("/*!", CommentKind { shape: CommentShape::Block, doc: Some(CommentPlacement::Inner) }), |
66 | ("//", CommentKind { shape: Line, doc: None }), | 65 | ("//", CommentKind { shape: CommentShape::Line, doc: None }), |
67 | ("/*", CommentKind { shape: Block, doc: None }), | 66 | ("/*", CommentKind { shape: CommentShape::Block, doc: None }), |
68 | ] | 67 | ]; |
69 | }; | ||
70 | 68 | ||
71 | fn kind_by_prefix(text: &str) -> CommentKind { | 69 | pub(crate) fn from_text(text: &str) -> CommentKind { |
72 | if text == "/**/" { | 70 | let &(_prefix, kind) = CommentKind::BY_PREFIX |
73 | return CommentKind { shape: CommentShape::Block, doc: None }; | 71 | .iter() |
74 | } | 72 | .find(|&(prefix, _kind)| text.starts_with(prefix)) |
75 | for (prefix, kind) in COMMENT_PREFIX_TO_KIND.iter() { | 73 | .unwrap(); |
76 | if text.starts_with(prefix) { | 74 | kind |
77 | return *kind; | ||
78 | } | ||
79 | } | 75 | } |
80 | panic!("bad comment text: {:?}", text) | ||
81 | } | 76 | } |
82 | 77 | ||
83 | impl ast::Whitespace { | 78 | impl ast::Whitespace { |
diff --git a/crates/syntax/src/parsing/text_tree_sink.rs b/crates/syntax/src/parsing/text_tree_sink.rs index c1b5f246d..997bc5d28 100644 --- a/crates/syntax/src/parsing/text_tree_sink.rs +++ b/crates/syntax/src/parsing/text_tree_sink.rs | |||
@@ -5,6 +5,7 @@ use std::mem; | |||
5 | use parser::{ParseError, TreeSink}; | 5 | use parser::{ParseError, TreeSink}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | ast, | ||
8 | parsing::Token, | 9 | parsing::Token, |
9 | syntax_node::GreenNode, | 10 | syntax_node::GreenNode, |
10 | SmolStr, SyntaxError, | 11 | SmolStr, SyntaxError, |
@@ -153,24 +154,22 @@ fn n_attached_trivias<'a>( | |||
153 | 154 | ||
154 | while let Some((i, (kind, text))) = trivias.next() { | 155 | while let Some((i, (kind, text))) = trivias.next() { |
155 | match kind { | 156 | match kind { |
156 | WHITESPACE => { | 157 | WHITESPACE if text.contains("\n\n") => { |
157 | if text.contains("\n\n") { | 158 | // we check whether the next token is a doc-comment |
158 | // we check whether the next token is a doc-comment | 159 | // and skip the whitespace in this case |
159 | // and skip the whitespace in this case | 160 | if let Some((COMMENT, peek_text)) = trivias.peek().map(|(_, pair)| pair) { |
160 | if let Some((peek_kind, peek_text)) = | 161 | let comment_kind = ast::CommentKind::from_text(peek_text); |
161 | trivias.peek().map(|(_, pair)| pair) | 162 | if comment_kind.doc == Some(ast::CommentPlacement::Outer) { |
162 | { | 163 | continue; |
163 | if *peek_kind == COMMENT | ||
164 | && peek_text.starts_with("///") | ||
165 | && !peek_text.starts_with("////") | ||
166 | { | ||
167 | continue; | ||
168 | } | ||
169 | } | 164 | } |
170 | break; | ||
171 | } | 165 | } |
166 | break; | ||
172 | } | 167 | } |
173 | COMMENT => { | 168 | COMMENT => { |
169 | let comment_kind = ast::CommentKind::from_text(text); | ||
170 | if comment_kind.doc == Some(ast::CommentPlacement::Inner) { | ||
171 | break; | ||
172 | } | ||
174 | res = i + 1; | 173 | res = i + 1; |
175 | } | 174 | } |
176 | _ => (), | 175 | _ => (), |
diff --git a/crates/syntax/test_data/parser/ok/0037_mod.rast b/crates/syntax/test_data/parser/ok/0037_mod.rast index 1d5d94bde..35577272e 100644 --- a/crates/syntax/test_data/parser/ok/0037_mod.rast +++ b/crates/syntax/test_data/parser/ok/0037_mod.rast | |||
@@ -1,9 +1,9 @@ | |||
1 | [email protected] | 1 | [email protected] |
2 | [email protected] "// https://github.com ..." | 2 | [email protected] "// https://github.com ..." |
3 | [email protected] "\n\n" | 3 | [email protected] "\n\n" |
4 | MODULE@62..93 | 4 | COMMENT@62..70 "//! docs" |
5 | COMMENT@62..70 "//! docs" | 5 | WHITESPACE@70..71 "\n" |
6 | WHITESPACE@70..71 "\n" | 6 | MODULE@71..93 |
7 | [email protected] "// non-docs" | 7 | [email protected] "// non-docs" |
8 | [email protected] "\n" | 8 | [email protected] "\n" |
9 | [email protected] "mod" | 9 | [email protected] "mod" |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 780f5cb91..77d4e0ec9 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -1,5 +1,5 @@ | |||
1 | <!--- | 1 | <!--- |
2 | lsp_ext.rs hash: 286f8bbac885531a | 2 | lsp_ext.rs hash: 4f86fb54e4b2870e |
3 | 3 | ||
4 | If you need to change the above hash to make the test pass, please check if you | 4 | If you need to change the above hash to make the test pass, please check if you |
5 | need to adjust this doc as well and ping this issue: | 5 | need to adjust this doc as well and ping this issue: |
@@ -109,30 +109,6 @@ Invoking code action at this position will yield two code actions for importing | |||
109 | * Is a fixed two-level structure enough? | 109 | * Is a fixed two-level structure enough? |
110 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? | 110 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? |
111 | 111 | ||
112 | ## Lazy assists with `ResolveCodeAction` | ||
113 | |||
114 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/787 | ||
115 | |||
116 | **Client Capability** `{ "resolveCodeAction": boolean }` | ||
117 | |||
118 | If this capability is set, the assists will be computed lazily. Thus `CodeAction` returned from the server will only contain `id` but not `edit` or `command` fields. The only exclusion from the rule is the diagnostic edits. | ||
119 | |||
120 | After the client got the id, it should then call `experimental/resolveCodeAction` command on the server and provide the following payload: | ||
121 | |||
122 | ```typescript | ||
123 | interface ResolveCodeActionParams { | ||
124 | id: string; | ||
125 | codeActionParams: lc.CodeActionParams; | ||
126 | } | ||
127 | ``` | ||
128 | |||
129 | As a result of the command call the client will get the respective workspace edit (`lc.WorkspaceEdit`). | ||
130 | |||
131 | ### Unresolved Questions | ||
132 | |||
133 | * Apply smarter filtering for ids? | ||
134 | * Upon `resolveCodeAction` command only call the assits which should be resolved and not all of them? | ||
135 | |||
136 | ## Parent Module | 112 | ## Parent Module |
137 | 113 | ||
138 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 | 114 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 |
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json index b3a10795e..cd4775d27 100644 --- a/editors/code/rust.tmGrammar.json +++ b/editors/code/rust.tmGrammar.json | |||
@@ -307,9 +307,14 @@ | |||
307 | "block-comments": { | 307 | "block-comments": { |
308 | "patterns": [ | 308 | "patterns": [ |
309 | { | 309 | { |
310 | "comment": "block comments", | 310 | "comment": "empty block comments", |
311 | "name": "comment.block.rust", | 311 | "name": "comment.block.rust", |
312 | "begin": "/\\*(?!\\*)", | 312 | "match": "/\\*\\*/" |
313 | }, | ||
314 | { | ||
315 | "comment": "block documentation comments", | ||
316 | "name": "comment.block.documentation.rust", | ||
317 | "begin": "/\\*\\*", | ||
313 | "end": "\\*/", | 318 | "end": "\\*/", |
314 | "patterns": [ | 319 | "patterns": [ |
315 | { | 320 | { |
@@ -318,9 +323,9 @@ | |||
318 | ] | 323 | ] |
319 | }, | 324 | }, |
320 | { | 325 | { |
321 | "comment": "block documentation comments", | 326 | "comment": "block comments", |
322 | "name": "comment.block.documentation.rust", | 327 | "name": "comment.block.rust", |
323 | "begin": "/\\*\\*", | 328 | "begin": "/\\*(?!\\*)", |
324 | "end": "\\*/", | 329 | "end": "\\*/", |
325 | "patterns": [ | 330 | "patterns": [ |
326 | { | 331 | { |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index d032b45b7..c9d032ead 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -4,6 +4,7 @@ import * as ra from '../src/lsp_ext'; | |||
4 | import * as Is from 'vscode-languageclient/lib/common/utils/is'; | 4 | import * as Is from 'vscode-languageclient/lib/common/utils/is'; |
5 | import { DocumentSemanticsTokensSignature, DocumentSemanticsTokensEditsSignature, DocumentRangeSemanticTokensSignature } from 'vscode-languageclient/lib/common/semanticTokens'; | 5 | import { DocumentSemanticsTokensSignature, DocumentSemanticsTokensEditsSignature, DocumentRangeSemanticTokensSignature } from 'vscode-languageclient/lib/common/semanticTokens'; |
6 | import { assert } from './util'; | 6 | import { assert } from './util'; |
7 | import { WorkspaceEdit } from 'vscode'; | ||
7 | 8 | ||
8 | function renderCommand(cmd: ra.CommandLink) { | 9 | function renderCommand(cmd: ra.CommandLink) { |
9 | return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`; | 10 | return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`; |
@@ -75,8 +76,8 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
75 | return Promise.resolve(null); | 76 | return Promise.resolve(null); |
76 | }); | 77 | }); |
77 | }, | 78 | }, |
78 | // Using custom handling of CodeActions where each code action is resolved lazily | 79 | // Using custom handling of CodeActions to support action groups and snippet edits. |
79 | // That's why we are not waiting for any command or edits | 80 | // Note that this means we have to re-implement lazy edit resolving ourselves as well. |
80 | async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) { | 81 | async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) { |
81 | const params: lc.CodeActionParams = { | 82 | const params: lc.CodeActionParams = { |
82 | textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), | 83 | textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), |
@@ -99,16 +100,15 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
99 | const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind); | 100 | const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind); |
100 | const action = new vscode.CodeAction(item.title, kind); | 101 | const action = new vscode.CodeAction(item.title, kind); |
101 | const group = (item as any).group; | 102 | const group = (item as any).group; |
102 | const id = (item as any).id; | ||
103 | const resolveParams: ra.ResolveCodeActionParams = { | ||
104 | id: id, | ||
105 | codeActionParams: params | ||
106 | }; | ||
107 | action.command = { | 103 | action.command = { |
108 | command: "rust-analyzer.resolveCodeAction", | 104 | command: "rust-analyzer.resolveCodeAction", |
109 | title: item.title, | 105 | title: item.title, |
110 | arguments: [resolveParams], | 106 | arguments: [item], |
111 | }; | 107 | }; |
108 | |||
109 | // Set a dummy edit, so that VS Code doesn't try to resolve this. | ||
110 | action.edit = new WorkspaceEdit(); | ||
111 | |||
112 | if (group) { | 112 | if (group) { |
113 | let entry = groups.get(group); | 113 | let entry = groups.get(group); |
114 | if (!entry) { | 114 | if (!entry) { |
@@ -134,6 +134,10 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
134 | return { label: item.title, arguments: item.command!!.arguments!![0] }; | 134 | return { label: item.title, arguments: item.command!!.arguments!![0] }; |
135 | })], | 135 | })], |
136 | }; | 136 | }; |
137 | |||
138 | // Set a dummy edit, so that VS Code doesn't try to resolve this. | ||
139 | action.edit = new WorkspaceEdit(); | ||
140 | |||
137 | result[index] = action; | 141 | result[index] = action; |
138 | } | 142 | } |
139 | } | 143 | } |
@@ -164,7 +168,6 @@ class ExperimentalFeatures implements lc.StaticFeature { | |||
164 | const caps: any = capabilities.experimental ?? {}; | 168 | const caps: any = capabilities.experimental ?? {}; |
165 | caps.snippetTextEdit = true; | 169 | caps.snippetTextEdit = true; |
166 | caps.codeActionGroup = true; | 170 | caps.codeActionGroup = true; |
167 | caps.resolveCodeAction = true; | ||
168 | caps.hoverActions = true; | 171 | caps.hoverActions = true; |
169 | caps.statusNotification = true; | 172 | caps.statusNotification = true; |
170 | capabilities.experimental = caps; | 173 | capabilities.experimental = caps; |
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 22509e874..cf34622c3 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts | |||
@@ -395,7 +395,7 @@ export function showReferences(ctx: Ctx): Cmd { | |||
395 | } | 395 | } |
396 | 396 | ||
397 | export function applyActionGroup(_ctx: Ctx): Cmd { | 397 | export function applyActionGroup(_ctx: Ctx): Cmd { |
398 | return async (actions: { label: string; arguments: ra.ResolveCodeActionParams }[]) => { | 398 | return async (actions: { label: string; arguments: lc.CodeAction }[]) => { |
399 | const selectedAction = await vscode.window.showQuickPick(actions); | 399 | const selectedAction = await vscode.window.showQuickPick(actions); |
400 | if (!selectedAction) return; | 400 | if (!selectedAction) return; |
401 | vscode.commands.executeCommand( | 401 | vscode.commands.executeCommand( |
@@ -442,12 +442,13 @@ export function openDocs(ctx: Ctx): Cmd { | |||
442 | 442 | ||
443 | export function resolveCodeAction(ctx: Ctx): Cmd { | 443 | export function resolveCodeAction(ctx: Ctx): Cmd { |
444 | const client = ctx.client; | 444 | const client = ctx.client; |
445 | return async (params: ra.ResolveCodeActionParams) => { | 445 | return async (params: lc.CodeAction) => { |
446 | const item: lc.WorkspaceEdit = await client.sendRequest(ra.resolveCodeAction, params); | 446 | params.command = undefined; |
447 | if (!item) { | 447 | const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params); |
448 | if (!item.edit) { | ||
448 | return; | 449 | return; |
449 | } | 450 | } |
450 | const edit = client.protocol2CodeConverter.asWorkspaceEdit(item); | 451 | const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit); |
451 | await applySnippetWorkspaceEdit(edit); | 452 | await applySnippetWorkspaceEdit(edit); |
452 | }; | 453 | }; |
453 | } | 454 | } |
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index fc8e120b3..d320c3cd7 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts | |||
@@ -43,12 +43,6 @@ export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position | |||
43 | 43 | ||
44 | export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule"); | 44 | export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule"); |
45 | 45 | ||
46 | export interface ResolveCodeActionParams { | ||
47 | id: string; | ||
48 | codeActionParams: lc.CodeActionParams; | ||
49 | } | ||
50 | export const resolveCodeAction = new lc.RequestType<ResolveCodeActionParams, lc.WorkspaceEdit, unknown>('experimental/resolveCodeAction'); | ||
51 | |||
52 | export interface JoinLinesParams { | 46 | export interface JoinLinesParams { |
53 | textDocument: lc.TextDocumentIdentifier; | 47 | textDocument: lc.TextDocumentIdentifier; |
54 | ranges: lc.Range[]; | 48 | ranges: lc.Range[]; |