diff options
57 files changed, 1397 insertions, 1583 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 919d58925..7b9fbe6b8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -15,12 +15,11 @@ env: | |||
15 | RUSTUP_MAX_RETRIES: 10 | 15 | RUSTUP_MAX_RETRIES: 10 |
16 | 16 | ||
17 | jobs: | 17 | jobs: |
18 | dist: | 18 | dist-windows: |
19 | name: dist | 19 | name: dist (Windows) |
20 | runs-on: ${{ matrix.os }} | 20 | runs-on: windows-latest |
21 | strategy: | 21 | env: |
22 | matrix: | 22 | RA_TARGET: x86_64-pc-windows-msvc |
23 | os: [ubuntu-16.04, windows-latest, macos-latest] | ||
24 | 23 | ||
25 | steps: | 24 | steps: |
26 | - name: Checkout repository | 25 | - name: Checkout repository |
@@ -30,8 +29,7 @@ jobs: | |||
30 | # which takes a long time. The fastest way to do this is to rename the | 29 | # which takes a long time. The fastest way to do this is to rename the |
31 | # existing folder, as deleting it takes about as much time as not doing | 30 | # existing folder, as deleting it takes about as much time as not doing |
32 | # anything and just updating rust-docs. | 31 | # anything and just updating rust-docs. |
33 | - name: Rename existing rust toolchain (Windows) | 32 | - name: Rename existing rust toolchain |
34 | if: matrix.os == 'windows-latest' | ||
35 | run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old | 33 | run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old |
36 | 34 | ||
37 | - name: Install Rust toolchain | 35 | - name: Install Rust toolchain |
@@ -41,38 +39,112 @@ jobs: | |||
41 | profile: minimal | 39 | profile: minimal |
42 | override: true | 40 | override: true |
43 | 41 | ||
42 | - name: Dist | ||
43 | run: cargo xtask dist | ||
44 | |||
45 | - name: Upload artifacts | ||
46 | uses: actions/upload-artifact@v1 | ||
47 | with: | ||
48 | name: dist-windows-latest | ||
49 | path: ./dist | ||
50 | |||
51 | dist-ubuntu: | ||
52 | name: dist (Ubuntu 16.04) | ||
53 | runs-on: ubuntu-16.04 | ||
54 | env: | ||
55 | RA_TARGET: x86_64-unknown-linux-gnu | ||
56 | |||
57 | steps: | ||
58 | - name: Checkout repository | ||
59 | uses: actions/checkout@v2 | ||
60 | |||
61 | - name: Install Rust toolchain | ||
62 | uses: actions-rs/toolchain@v1 | ||
63 | with: | ||
64 | toolchain: stable | ||
65 | profile: minimal | ||
66 | override: true | ||
67 | |||
44 | - name: Install Nodejs | 68 | - name: Install Nodejs |
45 | if: matrix.os == 'ubuntu-16.04' | ||
46 | uses: actions/setup-node@v1 | 69 | uses: actions/setup-node@v1 |
47 | with: | 70 | with: |
48 | node-version: 12.x | 71 | node-version: 12.x |
49 | 72 | ||
50 | - name: Dist | 73 | - name: Dist |
51 | if: matrix.os == 'ubuntu-16.04' && github.ref == 'refs/heads/release' | 74 | if: github.ref == 'refs/heads/release' |
52 | run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER | 75 | run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER |
53 | 76 | ||
54 | - name: Dist | 77 | - name: Dist |
55 | if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release' | 78 | if: github.ref != 'refs/heads/release' |
56 | run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly | 79 | run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly |
57 | 80 | ||
81 | - name: Nightly analysis-stats check | ||
82 | if: github.ref != 'refs/heads/release' | ||
83 | run: target/${{ env.RA_TARGET }}/release/rust-analyzer analysis-stats . | ||
84 | |||
85 | - name: Upload artifacts | ||
86 | uses: actions/upload-artifact@v1 | ||
87 | with: | ||
88 | name: dist-ubuntu-16.04 | ||
89 | path: ./dist | ||
90 | |||
91 | dist-macos-latest: | ||
92 | name: dist (MacOS latest) | ||
93 | runs-on: macos-latest | ||
94 | env: | ||
95 | RA_TARGET: x86_64-apple-darwin | ||
96 | |||
97 | steps: | ||
98 | - name: Checkout repository | ||
99 | uses: actions/checkout@v2 | ||
100 | |||
101 | - name: Install Rust toolchain | ||
102 | uses: actions-rs/toolchain@v1 | ||
103 | with: | ||
104 | toolchain: stable | ||
105 | profile: minimal | ||
106 | override: true | ||
107 | |||
58 | - name: Dist | 108 | - name: Dist |
59 | if: matrix.os != 'ubuntu-16.04' | ||
60 | run: cargo xtask dist | 109 | run: cargo xtask dist |
61 | 110 | ||
62 | - name: Nightly analysis-stats check | 111 | - name: Upload artifacts |
63 | if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release' | 112 | uses: actions/upload-artifact@v1 |
64 | run: ./dist/rust-analyzer-linux analysis-stats . | 113 | with: |
114 | name: dist-macos-latest | ||
115 | path: ./dist | ||
116 | |||
117 | dist-macos-11: | ||
118 | name: dist (MacOS 11.0) | ||
119 | runs-on: macos-11.0 | ||
120 | env: | ||
121 | RA_TARGET: aarch64-apple-darwin | ||
122 | |||
123 | steps: | ||
124 | - name: Checkout repository | ||
125 | uses: actions/checkout@v2 | ||
126 | |||
127 | - name: Install Rust toolchain (beta) | ||
128 | uses: actions-rs/toolchain@v1 | ||
129 | with: | ||
130 | toolchain: beta | ||
131 | target: aarch64-apple-darwin | ||
132 | profile: minimal | ||
133 | override: true | ||
134 | |||
135 | - name: Dist | ||
136 | run: cargo xtask dist | ||
65 | 137 | ||
66 | - name: Upload artifacts | 138 | - name: Upload artifacts |
67 | uses: actions/upload-artifact@v1 | 139 | uses: actions/upload-artifact@v1 |
68 | with: | 140 | with: |
69 | name: dist-${{ matrix.os }} | 141 | name: dist-macos-11.0 |
70 | path: ./dist | 142 | path: ./dist |
71 | 143 | ||
72 | publish: | 144 | publish: |
73 | name: publish | 145 | name: publish |
74 | runs-on: ubuntu-16.04 | 146 | runs-on: ubuntu-16.04 |
75 | needs: ['dist'] | 147 | needs: ['dist-windows', 'dist-ubuntu', 'dist-macos-latest', 'dist-macos-11'] |
76 | steps: | 148 | steps: |
77 | - name: Install Nodejs | 149 | - name: Install Nodejs |
78 | uses: actions/setup-node@v1 | 150 | uses: actions/setup-node@v1 |
@@ -93,6 +165,10 @@ jobs: | |||
93 | 165 | ||
94 | - uses: actions/download-artifact@v1 | 166 | - uses: actions/download-artifact@v1 |
95 | with: | 167 | with: |
168 | name: dist-macos-11.0 | ||
169 | path: dist | ||
170 | - uses: actions/download-artifact@v1 | ||
171 | with: | ||
96 | name: dist-macos-latest | 172 | name: dist-macos-latest |
97 | path: dist | 173 | path: dist |
98 | - uses: actions/download-artifact@v1 | 174 | - uses: actions/download-artifact@v1 |
@@ -103,7 +179,7 @@ jobs: | |||
103 | with: | 179 | with: |
104 | name: dist-windows-latest | 180 | name: dist-windows-latest |
105 | path: dist | 181 | path: dist |
106 | - run: ls -all ./dist | 182 | - run: ls -al ./dist |
107 | 183 | ||
108 | - name: Publish Release | 184 | - name: Publish Release |
109 | uses: ./.github/actions/github-release | 185 | uses: ./.github/actions/github-release |
diff --git a/Cargo.lock b/Cargo.lock index 1051c4ec6..fbb79e01f 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1251,9 +1251,9 @@ dependencies = [ | |||
1251 | 1251 | ||
1252 | [[package]] | 1252 | [[package]] |
1253 | name = "quote" | 1253 | name = "quote" |
1254 | version = "1.0.7" | 1254 | version = "1.0.8" |
1255 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1256 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" | 1256 | checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" |
1257 | dependencies = [ | 1257 | dependencies = [ |
1258 | "proc-macro2", | 1258 | "proc-macro2", |
1259 | ] | 1259 | ] |
@@ -1588,9 +1588,9 @@ version = "0.0.0" | |||
1588 | 1588 | ||
1589 | [[package]] | 1589 | [[package]] |
1590 | name = "syn" | 1590 | name = "syn" |
1591 | version = "1.0.54" | 1591 | version = "1.0.55" |
1592 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1593 | checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" | 1593 | checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" |
1594 | dependencies = [ | 1594 | dependencies = [ |
1595 | "proc-macro2", | 1595 | "proc-macro2", |
1596 | "quote", | 1596 | "quote", |
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs index 69499ea32..80cf9aba1 100644 --- a/crates/assists/src/assist_context.rs +++ b/crates/assists/src/assist_context.rs | |||
@@ -4,10 +4,10 @@ use std::mem; | |||
4 | 4 | ||
5 | use algo::find_covering_element; | 5 | use algo::find_covering_element; |
6 | use hir::Semantics; | 6 | use hir::Semantics; |
7 | use ide_db::base_db::{FileId, FileRange}; | 7 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange}; |
8 | use ide_db::{ | 8 | use ide_db::{ |
9 | label::Label, | 9 | label::Label, |
10 | source_change::{SourceChange, SourceFileEdit}, | 10 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use syntax::{ | 13 | use syntax::{ |
@@ -209,6 +209,7 @@ pub(crate) struct AssistBuilder { | |||
209 | file_id: FileId, | 209 | file_id: FileId, |
210 | is_snippet: bool, | 210 | is_snippet: bool, |
211 | source_file_edits: Vec<SourceFileEdit>, | 211 | source_file_edits: Vec<SourceFileEdit>, |
212 | file_system_edits: Vec<FileSystemEdit>, | ||
212 | } | 213 | } |
213 | 214 | ||
214 | impl AssistBuilder { | 215 | impl AssistBuilder { |
@@ -218,6 +219,7 @@ impl AssistBuilder { | |||
218 | file_id, | 219 | file_id, |
219 | is_snippet: false, | 220 | is_snippet: false, |
220 | source_file_edits: Vec::default(), | 221 | source_file_edits: Vec::default(), |
222 | file_system_edits: Vec::default(), | ||
221 | } | 223 | } |
222 | } | 224 | } |
223 | 225 | ||
@@ -282,12 +284,17 @@ impl AssistBuilder { | |||
282 | algo::diff(&node, &new).into_text_edit(&mut self.edit); | 284 | algo::diff(&node, &new).into_text_edit(&mut self.edit); |
283 | } | 285 | } |
284 | } | 286 | } |
287 | pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { | ||
288 | let file_system_edit = | ||
289 | FileSystemEdit::CreateFile { dst: dst.clone(), initial_contents: content.into() }; | ||
290 | self.file_system_edits.push(file_system_edit); | ||
291 | } | ||
285 | 292 | ||
286 | fn finish(mut self) -> SourceChange { | 293 | fn finish(mut self) -> SourceChange { |
287 | self.commit(); | 294 | self.commit(); |
288 | SourceChange { | 295 | SourceChange { |
289 | source_file_edits: mem::take(&mut self.source_file_edits), | 296 | source_file_edits: mem::take(&mut self.source_file_edits), |
290 | file_system_edits: Default::default(), | 297 | file_system_edits: mem::take(&mut self.file_system_edits), |
291 | is_snippet: self.is_snippet, | 298 | is_snippet: self.is_snippet, |
292 | } | 299 | } |
293 | } | 300 | } |
diff --git a/crates/assists/src/handlers/extract_module_to_file.rs b/crates/assists/src/handlers/extract_module_to_file.rs new file mode 100644 index 000000000..50bf67ef7 --- /dev/null +++ b/crates/assists/src/handlers/extract_module_to_file.rs | |||
@@ -0,0 +1,133 @@ | |||
1 | use ast::edit::IndentLevel; | ||
2 | use ide_db::base_db::AnchoredPathBuf; | ||
3 | use syntax::{ | ||
4 | ast::{self, edit::AstNodeEdit, NameOwner}, | ||
5 | AstNode, | ||
6 | }; | ||
7 | |||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
9 | |||
10 | // Assist: extract_module_to_file | ||
11 | // | ||
12 | // This assist extract module to file. | ||
13 | // | ||
14 | // ``` | ||
15 | // mod foo {<|> | ||
16 | // fn t() {} | ||
17 | // } | ||
18 | // ``` | ||
19 | // -> | ||
20 | // ``` | ||
21 | // mod foo; | ||
22 | // ``` | ||
23 | pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
24 | let module_ast = ctx.find_node_at_offset::<ast::Module>()?; | ||
25 | let module_name = module_ast.name()?; | ||
26 | |||
27 | let module_def = ctx.sema.to_def(&module_ast)?; | ||
28 | let parent_module = module_def.parent(ctx.db())?; | ||
29 | |||
30 | let module_items = module_ast.item_list()?; | ||
31 | let target = module_ast.syntax().text_range(); | ||
32 | let anchor_file_id = ctx.frange.file_id; | ||
33 | |||
34 | acc.add( | ||
35 | AssistId("extract_module_to_file", AssistKind::RefactorExtract), | ||
36 | "Extract module to file", | ||
37 | target, | ||
38 | |builder| { | ||
39 | let path = { | ||
40 | let dir = match parent_module.name(ctx.db()) { | ||
41 | Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name), | ||
42 | _ => String::new(), | ||
43 | }; | ||
44 | format!("./{}{}.rs", dir, module_name) | ||
45 | }; | ||
46 | let contents = { | ||
47 | let items = module_items.dedent(IndentLevel(1)).to_string(); | ||
48 | let mut items = | ||
49 | items.trim_start_matches('{').trim_end_matches('}').trim().to_string(); | ||
50 | if !items.is_empty() { | ||
51 | items.push('\n'); | ||
52 | } | ||
53 | items | ||
54 | }; | ||
55 | |||
56 | builder.replace(target, format!("mod {};", module_name)); | ||
57 | |||
58 | let dst = AnchoredPathBuf { anchor: anchor_file_id, path }; | ||
59 | builder.create_file(dst, contents); | ||
60 | }, | ||
61 | ) | ||
62 | } | ||
63 | |||
64 | #[cfg(test)] | ||
65 | mod tests { | ||
66 | use crate::tests::check_assist; | ||
67 | |||
68 | use super::*; | ||
69 | |||
70 | #[test] | ||
71 | fn extract_from_root() { | ||
72 | check_assist( | ||
73 | extract_module_to_file, | ||
74 | r#" | ||
75 | mod tests {<|> | ||
76 | #[test] fn t() {} | ||
77 | } | ||
78 | "#, | ||
79 | r#" | ||
80 | //- /main.rs | ||
81 | mod tests; | ||
82 | //- /tests.rs | ||
83 | #[test] fn t() {} | ||
84 | "#, | ||
85 | ); | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn extract_from_submodule() { | ||
90 | check_assist( | ||
91 | extract_module_to_file, | ||
92 | r#" | ||
93 | //- /main.rs | ||
94 | mod submod; | ||
95 | //- /submod.rs | ||
96 | mod inner<|> { | ||
97 | fn f() {} | ||
98 | } | ||
99 | fn g() {} | ||
100 | "#, | ||
101 | r#" | ||
102 | //- /submod.rs | ||
103 | mod inner; | ||
104 | fn g() {} | ||
105 | //- /submod/inner.rs | ||
106 | fn f() {} | ||
107 | "#, | ||
108 | ); | ||
109 | } | ||
110 | |||
111 | #[test] | ||
112 | fn extract_from_mod_rs() { | ||
113 | check_assist( | ||
114 | extract_module_to_file, | ||
115 | r#" | ||
116 | //- /main.rs | ||
117 | mod submodule; | ||
118 | //- /submodule/mod.rs | ||
119 | mod inner<|> { | ||
120 | fn f() {} | ||
121 | } | ||
122 | fn g() {} | ||
123 | "#, | ||
124 | r#" | ||
125 | //- /submodule/mod.rs | ||
126 | mod inner; | ||
127 | fn g() {} | ||
128 | //- /submodule/inner.rs | ||
129 | fn f() {} | ||
130 | "#, | ||
131 | ); | ||
132 | } | ||
133 | } | ||
diff --git a/crates/assists/src/handlers/invert_if.rs b/crates/assists/src/handlers/invert_if.rs index 91e2f5c8c..f9c33b3f7 100644 --- a/crates/assists/src/handlers/invert_if.rs +++ b/crates/assists/src/handlers/invert_if.rs | |||
@@ -78,6 +78,15 @@ mod tests { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | #[test] | 80 | #[test] |
81 | fn invert_if_remove_not_parentheses() { | ||
82 | check_assist( | ||
83 | invert_if, | ||
84 | "fn f() { i<|>f !(x == 3 || x == 4 || x == 5) { 3 * 2 } else { 1 } }", | ||
85 | "fn f() { if x == 3 || x == 4 || x == 5 { 1 } else { 3 * 2 } }", | ||
86 | ) | ||
87 | } | ||
88 | |||
89 | #[test] | ||
81 | fn invert_if_remove_inequality() { | 90 | fn invert_if_remove_inequality() { |
82 | check_assist( | 91 | check_assist( |
83 | invert_if, | 92 | invert_if, |
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs index 1ff5e92b0..f72dd49ed 100644 --- a/crates/assists/src/handlers/remove_unused_param.rs +++ b/crates/assists/src/handlers/remove_unused_param.rs | |||
@@ -2,9 +2,10 @@ use ide_db::{defs::Definition, search::Reference}; | |||
2 | use syntax::{ | 2 | use syntax::{ |
3 | algo::find_node_at_range, | 3 | algo::find_node_at_range, |
4 | ast::{self, ArgListOwner}, | 4 | ast::{self, ArgListOwner}, |
5 | AstNode, SyntaxNode, TextRange, T, | 5 | AstNode, SyntaxKind, SyntaxNode, TextRange, T, |
6 | }; | 6 | }; |
7 | use test_utils::mark; | 7 | use test_utils::mark; |
8 | use SyntaxKind::WHITESPACE; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists, | 11 | assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists, |
@@ -56,7 +57,7 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
56 | "Remove unused parameter", | 57 | "Remove unused parameter", |
57 | param.syntax().text_range(), | 58 | param.syntax().text_range(), |
58 | |builder| { | 59 | |builder| { |
59 | builder.delete(range_with_coma(param.syntax())); | 60 | builder.delete(range_to_remove(param.syntax())); |
60 | for usage in fn_def.usages(&ctx.sema).all() { | 61 | for usage in fn_def.usages(&ctx.sema).all() { |
61 | process_usage(ctx, builder, usage, param_position); | 62 | process_usage(ctx, builder, usage, param_position); |
62 | } | 63 | } |
@@ -80,19 +81,34 @@ fn process_usage( | |||
80 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; | 81 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; |
81 | 82 | ||
82 | builder.edit_file(usage.file_range.file_id); | 83 | builder.edit_file(usage.file_range.file_id); |
83 | builder.delete(range_with_coma(arg.syntax())); | 84 | builder.delete(range_to_remove(arg.syntax())); |
84 | 85 | ||
85 | Some(()) | 86 | Some(()) |
86 | } | 87 | } |
87 | 88 | ||
88 | fn range_with_coma(node: &SyntaxNode) -> TextRange { | 89 | fn range_to_remove(node: &SyntaxNode) -> TextRange { |
89 | let up_to = next_prev().find_map(|dir| { | 90 | let up_to_comma = next_prev().find_map(|dir| { |
90 | node.siblings_with_tokens(dir) | 91 | node.siblings_with_tokens(dir) |
91 | .filter_map(|it| it.into_token()) | 92 | .filter_map(|it| it.into_token()) |
92 | .find(|it| it.kind() == T![,]) | 93 | .find(|it| it.kind() == T![,]) |
94 | .map(|it| (dir, it)) | ||
93 | }); | 95 | }); |
94 | let up_to = up_to.map_or(node.text_range(), |it| it.text_range()); | 96 | if let Some((dir, token)) = up_to_comma { |
95 | node.text_range().cover(up_to) | 97 | if node.next_sibling().is_some() { |
98 | let up_to_space = token | ||
99 | .siblings_with_tokens(dir) | ||
100 | .skip(1) | ||
101 | .take_while(|it| it.kind() == WHITESPACE) | ||
102 | .last() | ||
103 | .and_then(|it| it.into_token()); | ||
104 | return node | ||
105 | .text_range() | ||
106 | .cover(up_to_space.map_or(token.text_range(), |it| it.text_range())); | ||
107 | } | ||
108 | node.text_range().cover(token.text_range()) | ||
109 | } else { | ||
110 | node.text_range() | ||
111 | } | ||
96 | } | 112 | } |
97 | 113 | ||
98 | #[cfg(test)] | 114 | #[cfg(test)] |
@@ -119,6 +135,57 @@ fn b() { foo(9, ) } | |||
119 | } | 135 | } |
120 | 136 | ||
121 | #[test] | 137 | #[test] |
138 | fn remove_unused_first_param() { | ||
139 | check_assist( | ||
140 | remove_unused_param, | ||
141 | r#" | ||
142 | fn foo(<|>x: i32, y: i32) { y; } | ||
143 | fn a() { foo(1, 2) } | ||
144 | fn b() { foo(1, 2,) } | ||
145 | "#, | ||
146 | r#" | ||
147 | fn foo(y: i32) { y; } | ||
148 | fn a() { foo(2) } | ||
149 | fn b() { foo(2,) } | ||
150 | "#, | ||
151 | ); | ||
152 | } | ||
153 | |||
154 | #[test] | ||
155 | fn remove_unused_single_param() { | ||
156 | check_assist( | ||
157 | remove_unused_param, | ||
158 | r#" | ||
159 | fn foo(<|>x: i32) { 0; } | ||
160 | fn a() { foo(1) } | ||
161 | fn b() { foo(1, ) } | ||
162 | "#, | ||
163 | r#" | ||
164 | fn foo() { 0; } | ||
165 | fn a() { foo() } | ||
166 | fn b() { foo( ) } | ||
167 | "#, | ||
168 | ); | ||
169 | } | ||
170 | |||
171 | #[test] | ||
172 | fn remove_unused_surrounded_by_parms() { | ||
173 | check_assist( | ||
174 | remove_unused_param, | ||
175 | r#" | ||
176 | fn foo(x: i32, <|>y: i32, z: i32) { x; } | ||
177 | fn a() { foo(1, 2, 3) } | ||
178 | fn b() { foo(1, 2, 3,) } | ||
179 | "#, | ||
180 | r#" | ||
181 | fn foo(x: i32, z: i32) { x; } | ||
182 | fn a() { foo(1, 3) } | ||
183 | fn b() { foo(1, 3,) } | ||
184 | "#, | ||
185 | ); | ||
186 | } | ||
187 | |||
188 | #[test] | ||
122 | fn remove_unused_qualified_call() { | 189 | fn remove_unused_qualified_call() { |
123 | check_assist( | 190 | check_assist( |
124 | remove_unused_param, | 191 | remove_unused_param, |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index 6e736ccb3..6b89b2d04 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -129,6 +129,7 @@ mod handlers { | |||
129 | mod convert_integer_literal; | 129 | mod convert_integer_literal; |
130 | mod early_return; | 130 | mod early_return; |
131 | mod expand_glob_import; | 131 | mod expand_glob_import; |
132 | mod extract_module_to_file; | ||
132 | mod extract_struct_from_enum_variant; | 133 | mod extract_struct_from_enum_variant; |
133 | mod extract_variable; | 134 | mod extract_variable; |
134 | mod fill_match_arms; | 135 | mod fill_match_arms; |
@@ -179,6 +180,7 @@ mod handlers { | |||
179 | convert_integer_literal::convert_integer_literal, | 180 | convert_integer_literal::convert_integer_literal, |
180 | early_return::convert_to_guarded_return, | 181 | early_return::convert_to_guarded_return, |
181 | expand_glob_import::expand_glob_import, | 182 | expand_glob_import::expand_glob_import, |
183 | extract_module_to_file::extract_module_to_file, | ||
182 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 184 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
183 | extract_variable::extract_variable, | 185 | extract_variable::extract_variable, |
184 | fill_match_arms::fill_match_arms, | 186 | fill_match_arms::fill_match_arms, |
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs index 709a34d03..b41f4874a 100644 --- a/crates/assists/src/tests.rs +++ b/crates/assists/src/tests.rs | |||
@@ -2,6 +2,7 @@ mod generated; | |||
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | 4 | use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; |
5 | use ide_db::source_change::FileSystemEdit; | ||
5 | use ide_db::RootDatabase; | 6 | use ide_db::RootDatabase; |
6 | use syntax::TextRange; | 7 | use syntax::TextRange; |
7 | use test_utils::{assert_eq_text, extract_offset, extract_range}; | 8 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
@@ -47,7 +48,7 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
47 | let before = db.file_text(file_id).to_string(); | 48 | let before = db.file_text(file_id).to_string(); |
48 | let frange = FileRange { file_id, range: selection.into() }; | 49 | let frange = FileRange { file_id, range: selection.into() }; |
49 | 50 | ||
50 | let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange) | 51 | let assist = Assist::resolved(&db, &AssistConfig::default(), frange) |
51 | .into_iter() | 52 | .into_iter() |
52 | .find(|assist| assist.assist.id.0 == assist_id) | 53 | .find(|assist| assist.assist.id.0 == assist_id) |
53 | .unwrap_or_else(|| { | 54 | .unwrap_or_else(|| { |
@@ -63,9 +64,12 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
63 | }); | 64 | }); |
64 | 65 | ||
65 | let actual = { | 66 | let actual = { |
66 | let change = assist.source_change.source_file_edits.pop().unwrap(); | ||
67 | let mut actual = before; | 67 | let mut actual = before; |
68 | change.edit.apply(&mut actual); | 68 | for source_file_edit in assist.source_change.source_file_edits { |
69 | if source_file_edit.file_id == file_id { | ||
70 | source_file_edit.edit.apply(&mut actual) | ||
71 | } | ||
72 | } | ||
69 | actual | 73 | actual |
70 | }; | 74 | }; |
71 | assert_eq_text!(&after, &actual); | 75 | assert_eq_text!(&after, &actual); |
@@ -99,7 +103,8 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
99 | (Some(assist), ExpectedResult::After(after)) => { | 103 | (Some(assist), ExpectedResult::After(after)) => { |
100 | let mut source_change = assist.source_change; | 104 | let mut source_change = assist.source_change; |
101 | assert!(!source_change.source_file_edits.is_empty()); | 105 | assert!(!source_change.source_file_edits.is_empty()); |
102 | let skip_header = source_change.source_file_edits.len() == 1; | 106 | let skip_header = source_change.source_file_edits.len() == 1 |
107 | && source_change.file_system_edits.len() == 0; | ||
103 | source_change.source_file_edits.sort_by_key(|it| it.file_id); | 108 | source_change.source_file_edits.sort_by_key(|it| it.file_id); |
104 | 109 | ||
105 | let mut buf = String::new(); | 110 | let mut buf = String::new(); |
@@ -115,6 +120,21 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
115 | buf.push_str(&text); | 120 | buf.push_str(&text); |
116 | } | 121 | } |
117 | 122 | ||
123 | for file_system_edit in source_change.file_system_edits.clone() { | ||
124 | match file_system_edit { | ||
125 | FileSystemEdit::CreateFile { dst, initial_contents } => { | ||
126 | let sr = db.file_source_root(dst.anchor); | ||
127 | let sr = db.source_root(sr); | ||
128 | let mut base = sr.path_for_file(&dst.anchor).unwrap().clone(); | ||
129 | base.pop(); | ||
130 | let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]); | ||
131 | format_to!(buf, "//- {}\n", created_file_path); | ||
132 | buf.push_str(&initial_contents); | ||
133 | } | ||
134 | _ => (), | ||
135 | } | ||
136 | } | ||
137 | |||
118 | assert_eq_text!(after, &buf); | 138 | assert_eq_text!(after, &buf); |
119 | } | 139 | } |
120 | (Some(assist), ExpectedResult::Target(target)) => { | 140 | (Some(assist), ExpectedResult::Target(target)) => { |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index cc7c4a343..e9093ec53 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -236,6 +236,21 @@ fn qux(bar: Bar, baz: Baz) {} | |||
236 | } | 236 | } |
237 | 237 | ||
238 | #[test] | 238 | #[test] |
239 | fn doctest_extract_module_to_file() { | ||
240 | check_doc_test( | ||
241 | "extract_module_to_file", | ||
242 | r#####" | ||
243 | mod foo {<|> | ||
244 | fn t() {} | ||
245 | } | ||
246 | "#####, | ||
247 | r#####" | ||
248 | mod foo; | ||
249 | "#####, | ||
250 | ) | ||
251 | } | ||
252 | |||
253 | #[test] | ||
239 | fn doctest_extract_struct_from_enum_variant() { | 254 | fn doctest_extract_struct_from_enum_variant() { |
240 | check_doc_test( | 255 | check_doc_test( |
241 | "extract_struct_from_enum_variant", | 256 | "extract_struct_from_enum_variant", |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index f2cacf7c8..d41084b59 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -232,7 +232,13 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | |||
232 | }; | 232 | }; |
233 | Some(make::expr_method_call(receiver, method, arg_list)) | 233 | Some(make::expr_method_call(receiver, method, arg_list)) |
234 | } | 234 | } |
235 | ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(), | 235 | ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => { |
236 | if let ast::Expr::ParenExpr(parexpr) = pe.expr()? { | ||
237 | parexpr.expr() | ||
238 | } else { | ||
239 | pe.expr() | ||
240 | } | ||
241 | } | ||
236 | // FIXME: | 242 | // FIXME: |
237 | // ast::Expr::Literal(true | false ) | 243 | // ast::Expr::Literal(true | false ) |
238 | _ => None, | 244 | _ => None, |
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 1ef6b5f48..d9fe13485 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -19,9 +19,14 @@ use hir::{ModPath, ScopeDef, Type}; | |||
19 | use crate::{ | 19 | use crate::{ |
20 | item::Builder, | 20 | item::Builder, |
21 | render::{ | 21 | render::{ |
22 | const_::render_const, enum_variant::render_variant, function::render_fn, | 22 | const_::render_const, |
23 | macro_::render_macro, render_field, render_resolution, render_tuple_field, | 23 | enum_variant::render_variant, |
24 | type_alias::render_type_alias, RenderContext, | 24 | function::render_fn, |
25 | macro_::render_macro, | ||
26 | pattern::{render_struct_pat, render_variant_pat}, | ||
27 | render_field, render_resolution, render_tuple_field, | ||
28 | type_alias::render_type_alias, | ||
29 | RenderContext, | ||
25 | }, | 30 | }, |
26 | CompletionContext, CompletionItem, | 31 | CompletionContext, CompletionItem, |
27 | }; | 32 | }; |
@@ -105,6 +110,28 @@ impl Completions { | |||
105 | self.add(item) | 110 | self.add(item) |
106 | } | 111 | } |
107 | 112 | ||
113 | pub(crate) fn add_variant_pat( | ||
114 | &mut self, | ||
115 | ctx: &CompletionContext, | ||
116 | variant: hir::Variant, | ||
117 | local_name: Option<hir::Name>, | ||
118 | ) { | ||
119 | if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, local_name) { | ||
120 | self.add(item); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | pub(crate) fn add_struct_pat( | ||
125 | &mut self, | ||
126 | ctx: &CompletionContext, | ||
127 | strukt: hir::Struct, | ||
128 | local_name: Option<hir::Name>, | ||
129 | ) { | ||
130 | if let Some(item) = render_struct_pat(RenderContext::new(ctx), strukt, local_name) { | ||
131 | self.add(item); | ||
132 | } | ||
133 | } | ||
134 | |||
108 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | 135 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { |
109 | if let Some(item) = render_const(RenderContext::new(ctx), constant) { | 136 | if let Some(item) = render_const(RenderContext::new(ctx), constant) { |
110 | self.add(item); | 137 | self.add(item); |
diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs index 4d56731ec..eee31098d 100644 --- a/crates/completion/src/completions/pattern.rs +++ b/crates/completion/src/completions/pattern.rs | |||
@@ -2,9 +2,9 @@ | |||
2 | 2 | ||
3 | use crate::{CompletionContext, Completions}; | 3 | use crate::{CompletionContext, Completions}; |
4 | 4 | ||
5 | /// Completes constats and paths in patterns. | 5 | /// Completes constants and paths in patterns. |
6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { |
7 | if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_let_pat_binding) { | 7 | if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_pat_binding) { |
8 | return; | 8 | return; |
9 | } | 9 | } |
10 | if ctx.record_pat_syntax.is_some() { | 10 | if ctx.record_pat_syntax.is_some() { |
@@ -15,20 +15,21 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
15 | // suggest variants + auto-imports | 15 | // suggest variants + auto-imports |
16 | ctx.scope.process_all_names(&mut |name, res| { | 16 | ctx.scope.process_all_names(&mut |name, res| { |
17 | let add_resolution = match &res { | 17 | let add_resolution = match &res { |
18 | hir::ScopeDef::ModuleDef(def) => { | 18 | hir::ScopeDef::ModuleDef(def) => match def { |
19 | if ctx.is_irrefutable_let_pat_binding { | 19 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { |
20 | matches!(def, hir::ModuleDef::Adt(hir::Adt::Struct(_))) | 20 | acc.add_struct_pat(ctx, strukt.clone(), Some(name.clone())); |
21 | } else { | 21 | true |
22 | matches!( | ||
23 | def, | ||
24 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | ||
25 | | hir::ModuleDef::Adt(hir::Adt::Struct(..)) | ||
26 | | hir::ModuleDef::Variant(..) | ||
27 | | hir::ModuleDef::Const(..) | ||
28 | | hir::ModuleDef::Module(..) | ||
29 | ) | ||
30 | } | 22 | } |
31 | } | 23 | hir::ModuleDef::Variant(variant) if !ctx.is_irrefutable_pat_binding => { |
24 | acc.add_variant_pat(ctx, variant.clone(), Some(name.clone())); | ||
25 | true | ||
26 | } | ||
27 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | ||
28 | | hir::ModuleDef::Variant(..) | ||
29 | | hir::ModuleDef::Const(..) | ||
30 | | hir::ModuleDef::Module(..) => !ctx.is_irrefutable_pat_binding, | ||
31 | _ => false, | ||
32 | }, | ||
32 | hir::ScopeDef::MacroDef(_) => true, | 33 | hir::ScopeDef::MacroDef(_) => true, |
33 | _ => false, | 34 | _ => false, |
34 | }; | 35 | }; |
@@ -42,13 +43,21 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
42 | mod tests { | 43 | mod tests { |
43 | use expect_test::{expect, Expect}; | 44 | use expect_test::{expect, Expect}; |
44 | 45 | ||
45 | use crate::{test_utils::completion_list, CompletionKind}; | 46 | use crate::{ |
47 | test_utils::{check_edit, completion_list}, | ||
48 | CompletionKind, | ||
49 | }; | ||
46 | 50 | ||
47 | fn check(ra_fixture: &str, expect: Expect) { | 51 | fn check(ra_fixture: &str, expect: Expect) { |
48 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 52 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
49 | expect.assert_eq(&actual) | 53 | expect.assert_eq(&actual) |
50 | } | 54 | } |
51 | 55 | ||
56 | fn check_snippet(ra_fixture: &str, expect: Expect) { | ||
57 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | ||
58 | expect.assert_eq(&actual) | ||
59 | } | ||
60 | |||
52 | #[test] | 61 | #[test] |
53 | fn completes_enum_variants_and_modules() { | 62 | fn completes_enum_variants_and_modules() { |
54 | check( | 63 | check( |
@@ -69,7 +78,7 @@ fn foo() { | |||
69 | en E | 78 | en E |
70 | ct Z | 79 | ct Z |
71 | st Bar | 80 | st Bar |
72 | ev X () | 81 | ev X |
73 | md m | 82 | md m |
74 | "#]], | 83 | "#]], |
75 | ); | 84 | ); |
@@ -114,4 +123,139 @@ fn foo() { | |||
114 | "#]], | 123 | "#]], |
115 | ); | 124 | ); |
116 | } | 125 | } |
126 | |||
127 | #[test] | ||
128 | fn completes_in_param() { | ||
129 | check( | ||
130 | r#" | ||
131 | enum E { X } | ||
132 | |||
133 | static FOO: E = E::X; | ||
134 | struct Bar { f: u32 } | ||
135 | |||
136 | fn foo(<|>) { | ||
137 | } | ||
138 | "#, | ||
139 | expect![[r#" | ||
140 | st Bar | ||
141 | "#]], | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn completes_pat_in_let() { | ||
147 | check_snippet( | ||
148 | r#" | ||
149 | struct Bar { f: u32 } | ||
150 | |||
151 | fn foo() { | ||
152 | let <|> | ||
153 | } | ||
154 | "#, | ||
155 | expect![[r#" | ||
156 | bn Bar Bar { f$1 }$0 | ||
157 | "#]], | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn completes_param_pattern() { | ||
163 | check_snippet( | ||
164 | r#" | ||
165 | struct Foo { bar: String, baz: String } | ||
166 | struct Bar(String, String); | ||
167 | struct Baz; | ||
168 | fn outer(<|>) {} | ||
169 | "#, | ||
170 | expect![[r#" | ||
171 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | ||
172 | bn Bar Bar($1, $2): Bar$0 | ||
173 | "#]], | ||
174 | ) | ||
175 | } | ||
176 | |||
177 | #[test] | ||
178 | fn completes_let_pattern() { | ||
179 | check_snippet( | ||
180 | r#" | ||
181 | struct Foo { bar: String, baz: String } | ||
182 | struct Bar(String, String); | ||
183 | struct Baz; | ||
184 | fn outer() { | ||
185 | let <|> | ||
186 | } | ||
187 | "#, | ||
188 | expect![[r#" | ||
189 | bn Foo Foo { bar$1, baz$2 }$0 | ||
190 | bn Bar Bar($1, $2)$0 | ||
191 | "#]], | ||
192 | ) | ||
193 | } | ||
194 | |||
195 | #[test] | ||
196 | fn completes_refutable_pattern() { | ||
197 | check_snippet( | ||
198 | r#" | ||
199 | struct Foo { bar: i32, baz: i32 } | ||
200 | struct Bar(String, String); | ||
201 | struct Baz; | ||
202 | fn outer() { | ||
203 | match () { | ||
204 | <|> | ||
205 | } | ||
206 | } | ||
207 | "#, | ||
208 | expect![[r#" | ||
209 | bn Foo Foo { bar$1, baz$2 }$0 | ||
210 | bn Bar Bar($1, $2)$0 | ||
211 | "#]], | ||
212 | ) | ||
213 | } | ||
214 | |||
215 | #[test] | ||
216 | fn omits_private_fields_pat() { | ||
217 | check_snippet( | ||
218 | r#" | ||
219 | mod foo { | ||
220 | pub struct Foo { pub bar: i32, baz: i32 } | ||
221 | pub struct Bar(pub String, String); | ||
222 | pub struct Invisible(String, String); | ||
223 | } | ||
224 | use foo::*; | ||
225 | |||
226 | fn outer() { | ||
227 | match () { | ||
228 | <|> | ||
229 | } | ||
230 | } | ||
231 | "#, | ||
232 | expect![[r#" | ||
233 | bn Foo Foo { bar$1, .. }$0 | ||
234 | bn Bar Bar($1, ..)$0 | ||
235 | "#]], | ||
236 | ) | ||
237 | } | ||
238 | |||
239 | #[test] | ||
240 | fn only_shows_ident_completion() { | ||
241 | check_edit( | ||
242 | "Foo", | ||
243 | r#" | ||
244 | struct Foo(i32); | ||
245 | fn main() { | ||
246 | match Foo(92) { | ||
247 | <|>(92) => (), | ||
248 | } | ||
249 | } | ||
250 | "#, | ||
251 | r#" | ||
252 | struct Foo(i32); | ||
253 | fn main() { | ||
254 | match Foo(92) { | ||
255 | Foo(92) => (), | ||
256 | } | ||
257 | } | ||
258 | "#, | ||
259 | ); | ||
260 | } | ||
117 | } | 261 | } |
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs index 5cd11cf77..41de324d8 100644 --- a/crates/completion/src/context.rs +++ b/crates/completion/src/context.rs | |||
@@ -51,7 +51,7 @@ pub(crate) struct CompletionContext<'a> { | |||
51 | /// If a name-binding or reference to a const in a pattern. | 51 | /// If a name-binding or reference to a const in a pattern. |
52 | /// Irrefutable patterns (like let) are excluded. | 52 | /// Irrefutable patterns (like let) are excluded. |
53 | pub(super) is_pat_binding_or_const: bool, | 53 | pub(super) is_pat_binding_or_const: bool, |
54 | pub(super) is_irrefutable_let_pat_binding: bool, | 54 | pub(super) is_irrefutable_pat_binding: bool, |
55 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. | 55 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. |
56 | pub(super) is_trivial_path: bool, | 56 | pub(super) is_trivial_path: bool, |
57 | /// If not a trivial path, the prefix (qualifier). | 57 | /// If not a trivial path, the prefix (qualifier). |
@@ -147,7 +147,7 @@ impl<'a> CompletionContext<'a> { | |||
147 | active_parameter: ActiveParameter::at(db, position), | 147 | active_parameter: ActiveParameter::at(db, position), |
148 | is_param: false, | 148 | is_param: false, |
149 | is_pat_binding_or_const: false, | 149 | is_pat_binding_or_const: false, |
150 | is_irrefutable_let_pat_binding: false, | 150 | is_irrefutable_pat_binding: false, |
151 | is_trivial_path: false, | 151 | is_trivial_path: false, |
152 | path_qual: None, | 152 | path_qual: None, |
153 | after_if: false, | 153 | after_if: false, |
@@ -327,14 +327,19 @@ impl<'a> CompletionContext<'a> { | |||
327 | if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() { | 327 | if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() { |
328 | self.is_pat_binding_or_const = false; | 328 | self.is_pat_binding_or_const = false; |
329 | } | 329 | } |
330 | if let Some(let_stmt) = bind_pat.syntax().ancestors().find_map(ast::LetStmt::cast) { | 330 | if let Some(Some(pat)) = bind_pat.syntax().ancestors().find_map(|node| { |
331 | if let Some(pat) = let_stmt.pat() { | 331 | match_ast! { |
332 | if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) | 332 | match node { |
333 | { | 333 | ast::LetStmt(it) => Some(it.pat()), |
334 | self.is_pat_binding_or_const = false; | 334 | ast::Param(it) => Some(it.pat()), |
335 | self.is_irrefutable_let_pat_binding = true; | 335 | _ => None, |
336 | } | 336 | } |
337 | } | 337 | } |
338 | }) { | ||
339 | if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) { | ||
340 | self.is_pat_binding_or_const = false; | ||
341 | self.is_irrefutable_pat_binding = true; | ||
342 | } | ||
338 | } | 343 | } |
339 | } | 344 | } |
340 | if is_node::<ast::Param>(name.syntax()) { | 345 | if is_node::<ast::Param>(name.syntax()) { |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 1092a4825..1ba7201a1 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -5,6 +5,7 @@ pub(crate) mod macro_; | |||
5 | pub(crate) mod function; | 5 | pub(crate) mod function; |
6 | pub(crate) mod enum_variant; | 6 | pub(crate) mod enum_variant; |
7 | pub(crate) mod const_; | 7 | pub(crate) mod const_; |
8 | pub(crate) mod pattern; | ||
8 | pub(crate) mod type_alias; | 9 | pub(crate) mod type_alias; |
9 | 10 | ||
10 | mod builder_ext; | 11 | mod builder_ext; |
@@ -159,6 +160,12 @@ impl<'a> Render<'a> { | |||
159 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); | 160 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); |
160 | return Some(item); | 161 | return Some(item); |
161 | } | 162 | } |
163 | ScopeDef::ModuleDef(Variant(_)) | ||
164 | if self.ctx.completion.is_pat_binding_or_const | ||
165 | | self.ctx.completion.is_irrefutable_pat_binding => | ||
166 | { | ||
167 | CompletionItemKind::EnumVariant | ||
168 | } | ||
162 | ScopeDef::ModuleDef(Variant(var)) => { | 169 | ScopeDef::ModuleDef(Variant(var)) => { |
163 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); | 170 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); |
164 | return Some(item); | 171 | return Some(item); |
diff --git a/crates/completion/src/render/builder_ext.rs b/crates/completion/src/render/builder_ext.rs index ce8718bd5..d053a988b 100644 --- a/crates/completion/src/render/builder_ext.rs +++ b/crates/completion/src/render/builder_ext.rs | |||
@@ -34,7 +34,6 @@ impl Builder { | |||
34 | return false; | 34 | return false; |
35 | } | 35 | } |
36 | if ctx.is_pattern_call { | 36 | if ctx.is_pattern_call { |
37 | mark::hit!(dont_duplicate_pattern_parens); | ||
38 | return false; | 37 | return false; |
39 | } | 38 | } |
40 | if ctx.is_call { | 39 | if ctx.is_call { |
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs index 7176fd9b3..732e139ec 100644 --- a/crates/completion/src/render/enum_variant.rs +++ b/crates/completion/src/render/enum_variant.rs | |||
@@ -126,50 +126,5 @@ fn main() -> Option<i32> { | |||
126 | } | 126 | } |
127 | "#, | 127 | "#, |
128 | ); | 128 | ); |
129 | check_edit( | ||
130 | "Some", | ||
131 | r#" | ||
132 | enum Option<T> { Some(T), None } | ||
133 | use Option::*; | ||
134 | fn main(value: Option<i32>) { | ||
135 | match value { | ||
136 | Som<|> | ||
137 | } | ||
138 | } | ||
139 | "#, | ||
140 | r#" | ||
141 | enum Option<T> { Some(T), None } | ||
142 | use Option::*; | ||
143 | fn main(value: Option<i32>) { | ||
144 | match value { | ||
145 | Some($0) | ||
146 | } | ||
147 | } | ||
148 | "#, | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn dont_duplicate_pattern_parens() { | ||
154 | mark::check!(dont_duplicate_pattern_parens); | ||
155 | check_edit( | ||
156 | "Var", | ||
157 | r#" | ||
158 | enum E { Var(i32) } | ||
159 | fn main() { | ||
160 | match E::Var(92) { | ||
161 | E::<|>(92) => (), | ||
162 | } | ||
163 | } | ||
164 | "#, | ||
165 | r#" | ||
166 | enum E { Var(i32) } | ||
167 | fn main() { | ||
168 | match E::Var(92) { | ||
169 | E::Var(92) => (), | ||
170 | } | ||
171 | } | ||
172 | "#, | ||
173 | ); | ||
174 | } | 129 | } |
175 | } | 130 | } |
diff --git a/crates/completion/src/render/pattern.rs b/crates/completion/src/render/pattern.rs new file mode 100644 index 000000000..a3b6a3cac --- /dev/null +++ b/crates/completion/src/render/pattern.rs | |||
@@ -0,0 +1,148 @@ | |||
1 | //! Renderer for patterns. | ||
2 | |||
3 | use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; | ||
4 | use itertools::Itertools; | ||
5 | |||
6 | use crate::{ | ||
7 | config::SnippetCap, item::CompletionKind, render::RenderContext, CompletionItem, | ||
8 | CompletionItemKind, | ||
9 | }; | ||
10 | |||
11 | fn visible_fields( | ||
12 | ctx: &RenderContext<'_>, | ||
13 | fields: &[hir::Field], | ||
14 | item: impl HasAttrs, | ||
15 | ) -> Option<(Vec<hir::Field>, bool)> { | ||
16 | let module = ctx.completion.scope.module()?; | ||
17 | let n_fields = fields.len(); | ||
18 | let fields = fields | ||
19 | .into_iter() | ||
20 | .filter(|field| field.is_visible_from(ctx.db(), module)) | ||
21 | .copied() | ||
22 | .collect::<Vec<_>>(); | ||
23 | |||
24 | let fields_omitted = | ||
25 | n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists(); | ||
26 | Some((fields, fields_omitted)) | ||
27 | } | ||
28 | |||
29 | pub(crate) fn render_struct_pat( | ||
30 | ctx: RenderContext<'_>, | ||
31 | strukt: hir::Struct, | ||
32 | local_name: Option<Name>, | ||
33 | ) -> Option<CompletionItem> { | ||
34 | let _p = profile::span("render_struct_pat"); | ||
35 | |||
36 | let fields = strukt.fields(ctx.db()); | ||
37 | let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, strukt)?; | ||
38 | |||
39 | if visible_fields.is_empty() { | ||
40 | // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields | ||
41 | return None; | ||
42 | } | ||
43 | |||
44 | let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string(); | ||
45 | let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?; | ||
46 | |||
47 | Some(build_completion(ctx, name, pat, strukt)) | ||
48 | } | ||
49 | |||
50 | pub(crate) fn render_variant_pat( | ||
51 | ctx: RenderContext<'_>, | ||
52 | variant: hir::Variant, | ||
53 | local_name: Option<Name>, | ||
54 | ) -> Option<CompletionItem> { | ||
55 | let _p = profile::span("render_variant_pat"); | ||
56 | |||
57 | let fields = variant.fields(ctx.db()); | ||
58 | let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?; | ||
59 | |||
60 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string(); | ||
61 | let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?; | ||
62 | |||
63 | Some(build_completion(ctx, name, pat, variant)) | ||
64 | } | ||
65 | |||
66 | fn build_completion( | ||
67 | ctx: RenderContext<'_>, | ||
68 | name: String, | ||
69 | pat: String, | ||
70 | item: impl HasAttrs + Copy, | ||
71 | ) -> CompletionItem { | ||
72 | let completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name) | ||
73 | .kind(CompletionItemKind::Binding) | ||
74 | .set_documentation(ctx.docs(item)) | ||
75 | .set_deprecated(ctx.is_deprecated(item)) | ||
76 | .detail(&pat); | ||
77 | let completion = if let Some(snippet_cap) = ctx.snippet_cap() { | ||
78 | completion.insert_snippet(snippet_cap, pat) | ||
79 | } else { | ||
80 | completion.insert_text(pat) | ||
81 | }; | ||
82 | completion.build() | ||
83 | } | ||
84 | |||
85 | fn render_pat( | ||
86 | ctx: &RenderContext<'_>, | ||
87 | name: &str, | ||
88 | kind: StructKind, | ||
89 | fields: &[hir::Field], | ||
90 | fields_omitted: bool, | ||
91 | ) -> Option<String> { | ||
92 | let mut pat = match kind { | ||
93 | StructKind::Tuple if ctx.snippet_cap().is_some() => { | ||
94 | render_tuple_as_pat(&fields, &name, fields_omitted) | ||
95 | } | ||
96 | StructKind::Record => { | ||
97 | render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted) | ||
98 | } | ||
99 | _ => return None, | ||
100 | }; | ||
101 | |||
102 | if ctx.completion.is_param { | ||
103 | pat.push(':'); | ||
104 | pat.push(' '); | ||
105 | pat.push_str(&name); | ||
106 | } | ||
107 | if ctx.snippet_cap().is_some() { | ||
108 | pat.push_str("$0"); | ||
109 | } | ||
110 | Some(pat) | ||
111 | } | ||
112 | |||
113 | fn render_record_as_pat( | ||
114 | db: &dyn HirDatabase, | ||
115 | snippet_cap: Option<SnippetCap>, | ||
116 | fields: &[hir::Field], | ||
117 | name: &str, | ||
118 | fields_omitted: bool, | ||
119 | ) -> String { | ||
120 | let fields = fields.iter(); | ||
121 | if snippet_cap.is_some() { | ||
122 | format!( | ||
123 | "{name} {{ {}{} }}", | ||
124 | fields | ||
125 | .enumerate() | ||
126 | .map(|(idx, field)| format!("{}${}", field.name(db), idx + 1)) | ||
127 | .format(", "), | ||
128 | if fields_omitted { ", .." } else { "" }, | ||
129 | name = name | ||
130 | ) | ||
131 | } else { | ||
132 | format!( | ||
133 | "{name} {{ {}{} }}", | ||
134 | fields.map(|field| field.name(db)).format(", "), | ||
135 | if fields_omitted { ", .." } else { "" }, | ||
136 | name = name | ||
137 | ) | ||
138 | } | ||
139 | } | ||
140 | |||
141 | fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) -> String { | ||
142 | format!( | ||
143 | "{name}({}{})", | ||
144 | fields.iter().enumerate().map(|(idx, _)| format!("${}", idx + 1)).format(", "), | ||
145 | if fields_omitted { ", .." } else { "" }, | ||
146 | name = name | ||
147 | ) | ||
148 | } | ||
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index d6c7e71ea..1d7e5ddd7 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -511,6 +511,10 @@ impl Struct { | |||
511 | db.struct_data(self.id).repr.clone() | 511 | db.struct_data(self.id).repr.clone() |
512 | } | 512 | } |
513 | 513 | ||
514 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
515 | self.variant_data(db).kind() | ||
516 | } | ||
517 | |||
514 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | 518 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { |
515 | db.struct_data(self.id).variant_data.clone() | 519 | db.struct_data(self.id).variant_data.clone() |
516 | } | 520 | } |
@@ -1268,7 +1272,6 @@ impl LifetimeParam { | |||
1268 | } | 1272 | } |
1269 | } | 1273 | } |
1270 | 1274 | ||
1271 | // FIXME: rename from `ImplDef` to `Impl` | ||
1272 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1275 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1273 | pub struct Impl { | 1276 | pub struct Impl { |
1274 | pub(crate) id: ImplId, | 1277 | pub(crate) id: ImplId, |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 41134d23b..bb8fca009 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -62,6 +62,7 @@ pub struct GenericParams { | |||
62 | pub enum WherePredicate { | 62 | pub enum WherePredicate { |
63 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, | 63 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, |
64 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, | 64 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, |
65 | ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, | ||
65 | } | 66 | } |
66 | 67 | ||
67 | #[derive(Clone, PartialEq, Eq, Debug)] | 68 | #[derive(Clone, PartialEq, Eq, Debug)] |
@@ -69,7 +70,6 @@ pub enum WherePredicateTypeTarget { | |||
69 | TypeRef(TypeRef), | 70 | TypeRef(TypeRef), |
70 | /// For desugared where predicates that can directly refer to a type param. | 71 | /// For desugared where predicates that can directly refer to a type param. |
71 | TypeParam(LocalTypeParamId), | 72 | TypeParam(LocalTypeParamId), |
72 | // FIXME: ForLifetime(Vec<LifetimeParamId>, TypeRef) | ||
73 | } | 73 | } |
74 | 74 | ||
75 | #[derive(Default)] | 75 | #[derive(Default)] |
@@ -234,7 +234,7 @@ impl GenericParams { | |||
234 | for bound in | 234 | for bound in |
235 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | 235 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) |
236 | { | 236 | { |
237 | self.add_where_predicate_from_bound(lower_ctx, bound, target.clone()); | 237 | self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone()); |
238 | } | 238 | } |
239 | } | 239 | } |
240 | 240 | ||
@@ -279,8 +279,25 @@ impl GenericParams { | |||
279 | } else { | 279 | } else { |
280 | continue; | 280 | continue; |
281 | }; | 281 | }; |
282 | |||
283 | let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| { | ||
284 | // Higher-Ranked Trait Bounds | ||
285 | param_list | ||
286 | .lifetime_params() | ||
287 | .map(|lifetime_param| { | ||
288 | lifetime_param | ||
289 | .lifetime() | ||
290 | .map_or_else(Name::missing, |lt| Name::new_lifetime(<)) | ||
291 | }) | ||
292 | .collect() | ||
293 | }); | ||
282 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | 294 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { |
283 | self.add_where_predicate_from_bound(lower_ctx, bound, target.clone()); | 295 | self.add_where_predicate_from_bound( |
296 | lower_ctx, | ||
297 | bound, | ||
298 | lifetimes.as_ref(), | ||
299 | target.clone(), | ||
300 | ); | ||
284 | } | 301 | } |
285 | } | 302 | } |
286 | } | 303 | } |
@@ -289,6 +306,7 @@ impl GenericParams { | |||
289 | &mut self, | 306 | &mut self, |
290 | lower_ctx: &LowerCtx, | 307 | lower_ctx: &LowerCtx, |
291 | bound: ast::TypeBound, | 308 | bound: ast::TypeBound, |
309 | hrtb_lifetimes: Option<&Box<[Name]>>, | ||
292 | target: Either<TypeRef, LifetimeRef>, | 310 | target: Either<TypeRef, LifetimeRef>, |
293 | ) { | 311 | ) { |
294 | if bound.question_mark_token().is_some() { | 312 | if bound.question_mark_token().is_some() { |
@@ -297,9 +315,16 @@ impl GenericParams { | |||
297 | } | 315 | } |
298 | let bound = TypeBound::from_ast(lower_ctx, bound); | 316 | let bound = TypeBound::from_ast(lower_ctx, bound); |
299 | let predicate = match (target, bound) { | 317 | let predicate = match (target, bound) { |
300 | (Either::Left(type_ref), bound) => WherePredicate::TypeBound { | 318 | (Either::Left(type_ref), bound) => match hrtb_lifetimes { |
301 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 319 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { |
302 | bound, | 320 | lifetimes: hrtb_lifetimes.clone(), |
321 | target: WherePredicateTypeTarget::TypeRef(type_ref), | ||
322 | bound, | ||
323 | }, | ||
324 | None => WherePredicate::TypeBound { | ||
325 | target: WherePredicateTypeTarget::TypeRef(type_ref), | ||
326 | bound, | ||
327 | }, | ||
303 | }, | 328 | }, |
304 | (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { | 329 | (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { |
305 | WherePredicate::Lifetime { target: lifetime, bound } | 330 | WherePredicate::Lifetime { target: lifetime, bound } |
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs index b4ccd4488..af3262439 100644 --- a/crates/hir_def/src/nameres/mod_resolution.rs +++ b/crates/hir_def/src/nameres/mod_resolution.rs | |||
@@ -79,7 +79,7 @@ impl ModDir { | |||
79 | for candidate in candidate_files.iter() { | 79 | for candidate in candidate_files.iter() { |
80 | let path = AnchoredPath { anchor: file_id, path: candidate.as_str() }; | 80 | let path = AnchoredPath { anchor: file_id, path: candidate.as_str() }; |
81 | if let Some(file_id) = db.resolve_path(path) { | 81 | if let Some(file_id) = db.resolve_path(path) { |
82 | let is_mod_rs = candidate.ends_with("mod.rs"); | 82 | let is_mod_rs = candidate.ends_with("/mod.rs"); |
83 | 83 | ||
84 | let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { | 84 | let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { |
85 | (DirPath::empty(), false) | 85 | (DirPath::empty(), false) |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index dddbbcdac..6382521fb 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -563,6 +563,7 @@ mod tests { | |||
563 | 563 | ||
564 | let args = macro_call.token_tree().unwrap(); | 564 | let args = macro_call.token_tree().unwrap(); |
565 | let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; | 565 | let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; |
566 | let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)); | ||
566 | 567 | ||
567 | let arg_id = db.intern_eager_expansion({ | 568 | let arg_id = db.intern_eager_expansion({ |
568 | EagerCallLoc { | 569 | EagerCallLoc { |
@@ -570,7 +571,7 @@ mod tests { | |||
570 | fragment: FragmentKind::Expr, | 571 | fragment: FragmentKind::Expr, |
571 | subtree: Arc::new(parsed_args.clone()), | 572 | subtree: Arc::new(parsed_args.clone()), |
572 | krate, | 573 | krate, |
573 | file_id: file_id.into(), | 574 | call: call_id, |
574 | } | 575 | } |
575 | }); | 576 | }); |
576 | 577 | ||
@@ -580,7 +581,7 @@ mod tests { | |||
580 | fragment, | 581 | fragment, |
581 | subtree: Arc::new(subtree), | 582 | subtree: Arc::new(subtree), |
582 | krate, | 583 | krate, |
583 | file_id: file_id.into(), | 584 | call: call_id, |
584 | }; | 585 | }; |
585 | 586 | ||
586 | let id: MacroCallId = db.intern_eager_expansion(eager).into(); | 587 | let id: MacroCallId = db.intern_eager_expansion(eager).into(); |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 4477d867f..077de3727 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -5,7 +5,7 @@ use std::sync::Arc; | |||
5 | use base_db::{salsa, SourceDatabase}; | 5 | use base_db::{salsa, SourceDatabase}; |
6 | use mbe::{ExpandError, ExpandResult, MacroRules}; | 6 | use mbe::{ExpandError, ExpandResult, MacroRules}; |
7 | use parser::FragmentKind; | 7 | use parser::FragmentKind; |
8 | use syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; | 8 | use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, | 11 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, |
@@ -129,11 +129,11 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | |||
129 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 129 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
130 | match id.kind { | 130 | match id.kind { |
131 | MacroDefKind::Declarative => { | 131 | MacroDefKind::Declarative => { |
132 | let macro_call = match id.ast_id?.to_node(db) { | 132 | let macro_rules = match id.ast_id?.to_node(db) { |
133 | syntax::ast::Macro::MacroRules(mac) => mac, | 133 | syntax::ast::Macro::MacroRules(mac) => mac, |
134 | syntax::ast::Macro::MacroDef(_) => return None, | 134 | syntax::ast::Macro::MacroDef(_) => return None, |
135 | }; | 135 | }; |
136 | let arg = macro_call.token_tree()?; | 136 | let arg = macro_rules.token_tree()?; |
137 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { | 137 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { |
138 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | 138 | log::warn!("fail on macro_def to token tree: {:#?}", arg); |
139 | None | 139 | None |
@@ -141,7 +141,8 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, | |||
141 | let rules = match MacroRules::parse(&tt) { | 141 | let rules = match MacroRules::parse(&tt) { |
142 | Ok(it) => it, | 142 | Ok(it) => it, |
143 | Err(err) => { | 143 | Err(err) => { |
144 | log::warn!("fail on macro_def parse: error: {:#?} {:#?}", err, tt); | 144 | let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); |
145 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); | ||
145 | return None; | 146 | return None; |
146 | } | 147 | } |
147 | }; | 148 | }; |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 0229a836e..6354b090d 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -110,6 +110,9 @@ pub fn expand_eager_macro( | |||
110 | || err("malformed macro invocation"), | 110 | || err("malformed macro invocation"), |
111 | )?; | 111 | )?; |
112 | 112 | ||
113 | let ast_map = db.ast_id_map(macro_call.file_id); | ||
114 | let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); | ||
115 | |||
113 | // Note: | 116 | // Note: |
114 | // When `lazy_expand` is called, its *parent* file must be already exists. | 117 | // When `lazy_expand` is called, its *parent* file must be already exists. |
115 | // Here we store an eager macro id for the argument expanded subtree here | 118 | // Here we store an eager macro id for the argument expanded subtree here |
@@ -120,7 +123,7 @@ pub fn expand_eager_macro( | |||
120 | fragment: FragmentKind::Expr, | 123 | fragment: FragmentKind::Expr, |
121 | subtree: Arc::new(parsed_args.clone()), | 124 | subtree: Arc::new(parsed_args.clone()), |
122 | krate, | 125 | krate, |
123 | file_id: macro_call.file_id, | 126 | call: call_id, |
124 | } | 127 | } |
125 | }); | 128 | }); |
126 | let arg_file_id: MacroCallId = arg_id.into(); | 129 | let arg_file_id: MacroCallId = arg_id.into(); |
@@ -141,13 +144,8 @@ pub fn expand_eager_macro( | |||
141 | let res = eager.expand(db, arg_id, &subtree); | 144 | let res = eager.expand(db, arg_id, &subtree); |
142 | 145 | ||
143 | let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; | 146 | let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; |
144 | let eager = EagerCallLoc { | 147 | let eager = |
145 | def, | 148 | EagerCallLoc { def, fragment, subtree: Arc::new(subtree), krate, call: call_id }; |
146 | fragment, | ||
147 | subtree: Arc::new(subtree), | ||
148 | krate, | ||
149 | file_id: macro_call.file_id, | ||
150 | }; | ||
151 | 149 | ||
152 | Ok(db.intern_eager_expansion(eager)) | 150 | Ok(db.intern_eager_expansion(eager)) |
153 | } else { | 151 | } else { |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index d486186e5..3fa1b1d77 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -83,7 +83,7 @@ impl HirFileId { | |||
83 | } | 83 | } |
84 | MacroCallId::EagerMacro(id) => { | 84 | MacroCallId::EagerMacro(id) => { |
85 | let loc = db.lookup_intern_eager_expansion(id); | 85 | let loc = db.lookup_intern_eager_expansion(id); |
86 | loc.file_id | 86 | loc.call.file_id |
87 | } | 87 | } |
88 | }; | 88 | }; |
89 | file_id.original_file(db) | 89 | file_id.original_file(db) |
@@ -103,7 +103,7 @@ impl HirFileId { | |||
103 | } | 103 | } |
104 | MacroCallId::EagerMacro(id) => { | 104 | MacroCallId::EagerMacro(id) => { |
105 | let loc = db.lookup_intern_eager_expansion(id); | 105 | let loc = db.lookup_intern_eager_expansion(id); |
106 | loc.file_id | 106 | loc.call.file_id |
107 | } | 107 | } |
108 | }; | 108 | }; |
109 | } | 109 | } |
@@ -114,17 +114,16 @@ impl HirFileId { | |||
114 | pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { | 114 | pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { |
115 | match self.0 { | 115 | match self.0 { |
116 | HirFileIdRepr::FileId(_) => None, | 116 | HirFileIdRepr::FileId(_) => None, |
117 | HirFileIdRepr::MacroFile(macro_file) => { | 117 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { |
118 | let lazy_id = match macro_file.macro_call_id { | 118 | MacroCallId::LazyMacro(lazy_id) => { |
119 | MacroCallId::LazyMacro(id) => id, | 119 | let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); |
120 | MacroCallId::EagerMacro(_id) => { | 120 | Some(loc.kind.node(db)) |
121 | // FIXME: handle call node for eager macro | 121 | } |
122 | return None; | 122 | MacroCallId::EagerMacro(id) => { |
123 | } | 123 | let loc: EagerCallLoc = db.lookup_intern_eager_expansion(id); |
124 | }; | 124 | Some(loc.call.with_value(loc.call.to_node(db).syntax().clone())) |
125 | let loc = db.lookup_intern_macro(lazy_id); | 125 | } |
126 | Some(loc.kind.node(db)) | 126 | }, |
127 | } | ||
128 | } | 127 | } |
129 | } | 128 | } |
130 | 129 | ||
@@ -304,7 +303,7 @@ pub struct EagerCallLoc { | |||
304 | pub(crate) fragment: FragmentKind, | 303 | pub(crate) fragment: FragmentKind, |
305 | pub(crate) subtree: Arc<tt::Subtree>, | 304 | pub(crate) subtree: Arc<tt::Subtree>, |
306 | pub(crate) krate: CrateId, | 305 | pub(crate) krate: CrateId, |
307 | pub(crate) file_id: HirFileId, | 306 | pub(crate) call: AstId<ast::MacroCall>, |
308 | } | 307 | } |
309 | 308 | ||
310 | /// ExpansionInfo mainly describes how to map text range between src and expanded macro | 309 | /// ExpansionInfo mainly describes how to map text range between src and expanded macro |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 8392cb770..8da56cd11 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -675,7 +675,8 @@ impl GenericPredicate { | |||
675 | where_predicate: &'a WherePredicate, | 675 | where_predicate: &'a WherePredicate, |
676 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | 676 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
677 | match where_predicate { | 677 | match where_predicate { |
678 | WherePredicate::TypeBound { target, bound } => { | 678 | WherePredicate::ForLifetime { target, bound, .. } |
679 | | WherePredicate::TypeBound { target, bound } => { | ||
679 | let self_ty = match target { | 680 | let self_ty = match target { |
680 | WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), | 681 | WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), |
681 | WherePredicateTypeTarget::TypeParam(param_id) => { | 682 | WherePredicateTypeTarget::TypeParam(param_id) => { |
@@ -888,14 +889,13 @@ pub(crate) fn generic_predicates_for_param_query( | |||
888 | .where_predicates_in_scope() | 889 | .where_predicates_in_scope() |
889 | // we have to filter out all other predicates *first*, before attempting to lower them | 890 | // we have to filter out all other predicates *first*, before attempting to lower them |
890 | .filter(|pred| match pred { | 891 | .filter(|pred| match pred { |
891 | WherePredicate::TypeBound { | 892 | WherePredicate::ForLifetime { target, .. } |
892 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 893 | | WherePredicate::TypeBound { target, .. } => match target { |
893 | .. | 894 | WherePredicateTypeTarget::TypeRef(type_ref) => { |
894 | } => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id), | 895 | Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id) |
895 | WherePredicate::TypeBound { | 896 | } |
896 | target: WherePredicateTypeTarget::TypeParam(local_id), | 897 | WherePredicateTypeTarget::TypeParam(local_id) => *local_id == param_id.local_id, |
897 | .. | 898 | }, |
898 | } => *local_id == param_id.local_id, | ||
899 | WherePredicate::Lifetime { .. } => false, | 899 | WherePredicate::Lifetime { .. } => false, |
900 | }) | 900 | }) |
901 | .flat_map(|pred| { | 901 | .flat_map(|pred| { |
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs index af880c065..65b79df0d 100644 --- a/crates/hir_ty/src/utils.rs +++ b/crates/hir_ty/src/utils.rs | |||
@@ -5,7 +5,9 @@ use std::sync::Arc; | |||
5 | use hir_def::{ | 5 | use hir_def::{ |
6 | adt::VariantData, | 6 | adt::VariantData, |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | generics::{GenericParams, TypeParamData, TypeParamProvenance, WherePredicateTypeTarget}, | 8 | generics::{ |
9 | GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, | ||
10 | }, | ||
9 | path::Path, | 11 | path::Path, |
10 | resolver::{HasResolver, TypeNs}, | 12 | resolver::{HasResolver, TypeNs}, |
11 | type_ref::TypeRef, | 13 | type_ref::TypeRef, |
@@ -27,7 +29,8 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
27 | .where_predicates | 29 | .where_predicates |
28 | .iter() | 30 | .iter() |
29 | .filter_map(|pred| match pred { | 31 | .filter_map(|pred| match pred { |
30 | hir_def::generics::WherePredicate::TypeBound { target, bound } => match target { | 32 | WherePredicate::ForLifetime { target, bound, .. } |
33 | | WherePredicate::TypeBound { target, bound } => match target { | ||
31 | WherePredicateTypeTarget::TypeRef(TypeRef::Path(p)) | 34 | WherePredicateTypeTarget::TypeRef(TypeRef::Path(p)) |
32 | if p == &Path::from(name![Self]) => | 35 | if p == &Path::from(name![Self]) => |
33 | { | 36 | { |
@@ -38,7 +41,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
38 | } | 41 | } |
39 | _ => None, | 42 | _ => None, |
40 | }, | 43 | }, |
41 | hir_def::generics::WherePredicate::Lifetime { .. } => None, | 44 | WherePredicate::Lifetime { .. } => None, |
42 | }) | 45 | }) |
43 | .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { | 46 | .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { |
44 | Some(TypeNs::TraitId(t)) => Some(t), | 47 | Some(TypeNs::TraitId(t)) => Some(t), |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 049f808dc..3ad30f0c9 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -619,6 +619,7 @@ fn test_fn() { | |||
619 | ), | 619 | ), |
620 | path: "foo.rs", | 620 | path: "foo.rs", |
621 | }, | 621 | }, |
622 | initial_contents: "", | ||
622 | }, | 623 | }, |
623 | ], | 624 | ], |
624 | is_snippet: false, | 625 | is_snippet: false, |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index e8b896623..d79f5c170 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -40,6 +40,7 @@ impl DiagnosticWithFix for UnresolvedModule { | |||
40 | anchor: self.file.original_file(sema.db), | 40 | anchor: self.file.original_file(sema.db), |
41 | path: self.candidate.clone(), | 41 | path: self.candidate.clone(), |
42 | }, | 42 | }, |
43 | initial_contents: "".to_string(), | ||
43 | } | 44 | } |
44 | .into(), | 45 | .into(), |
45 | unresolved_module.syntax().text_range(), | 46 | unresolved_module.syntax().text_range(), |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 7a12e9965..47dd85ceb 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -750,6 +750,31 @@ fn test() { | |||
750 | } | 750 | } |
751 | 751 | ||
752 | #[test] | 752 | #[test] |
753 | fn goto_through_included_file() { | ||
754 | check( | ||
755 | r#" | ||
756 | //- /main.rs | ||
757 | #[rustc_builtin_macro] | ||
758 | macro_rules! include {} | ||
759 | |||
760 | include!("foo.rs"); | ||
761 | //^^^^^^^^^^^^^^^^^^^ | ||
762 | |||
763 | fn f() { | ||
764 | foo<|>(); | ||
765 | } | ||
766 | |||
767 | mod confuse_index { | ||
768 | pub fn foo() {} | ||
769 | } | ||
770 | |||
771 | //- /foo.rs | ||
772 | fn foo() {} | ||
773 | "#, | ||
774 | ); | ||
775 | } | ||
776 | |||
777 | #[test] | ||
753 | fn goto_for_type_param() { | 778 | fn goto_for_type_param() { |
754 | check( | 779 | check( |
755 | r#" | 780 | r#" |
@@ -1077,4 +1102,32 @@ fn foo<'foobar>(_: &'foobar ()) { | |||
1077 | }"#, | 1102 | }"#, |
1078 | ) | 1103 | ) |
1079 | } | 1104 | } |
1105 | |||
1106 | #[test] | ||
1107 | #[ignore] // requires the HIR to somehow track these hrtb lifetimes | ||
1108 | fn goto_lifetime_hrtb() { | ||
1109 | check( | ||
1110 | r#"trait Foo<T> {} | ||
1111 | fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {} | ||
1112 | //^^ | ||
1113 | "#, | ||
1114 | ); | ||
1115 | check( | ||
1116 | r#"trait Foo<T> {} | ||
1117 | fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} | ||
1118 | //^^ | ||
1119 | "#, | ||
1120 | ); | ||
1121 | } | ||
1122 | |||
1123 | #[test] | ||
1124 | #[ignore] // requires ForTypes to be implemented | ||
1125 | fn goto_lifetime_hrtb_for_type() { | ||
1126 | check( | ||
1127 | r#"trait Foo<T> {} | ||
1128 | fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {} | ||
1129 | //^^ | ||
1130 | "#, | ||
1131 | ); | ||
1132 | } | ||
1080 | } | 1133 | } |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 18ea19305..33b7358f7 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -147,20 +147,20 @@ fn find_name( | |||
147 | ) -> Option<RangeInfo<Definition>> { | 147 | ) -> Option<RangeInfo<Definition>> { |
148 | if let Some(name) = opt_name { | 148 | if let Some(name) = opt_name { |
149 | let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db); | 149 | let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db); |
150 | let range = name.syntax().text_range(); | 150 | let FileRange { range, .. } = sema.original_range(name.syntax()); |
151 | return Some(RangeInfo::new(range, def)); | 151 | return Some(RangeInfo::new(range, def)); |
152 | } | 152 | } |
153 | 153 | ||
154 | let (text_range, def) = if let Some(lifetime) = | 154 | let (FileRange { range, .. }, def) = if let Some(lifetime) = |
155 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) | 155 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) |
156 | { | 156 | { |
157 | if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime) | 157 | if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime) |
158 | .map(|class| NameRefClass::referenced(class, sema.db)) | 158 | .map(|class| NameRefClass::referenced(class, sema.db)) |
159 | { | 159 | { |
160 | (lifetime.syntax().text_range(), def) | 160 | (sema.original_range(lifetime.syntax()), def) |
161 | } else { | 161 | } else { |
162 | ( | 162 | ( |
163 | lifetime.syntax().text_range(), | 163 | sema.original_range(lifetime.syntax()), |
164 | NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db), | 164 | NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db), |
165 | ) | 165 | ) |
166 | } | 166 | } |
@@ -168,11 +168,11 @@ fn find_name( | |||
168 | let name_ref = | 168 | let name_ref = |
169 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; | 169 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; |
170 | ( | 170 | ( |
171 | name_ref.syntax().text_range(), | 171 | sema.original_range(name_ref.syntax()), |
172 | NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), | 172 | NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), |
173 | ) | 173 | ) |
174 | }; | 174 | }; |
175 | Some(RangeInfo::new(text_range, def)) | 175 | Some(RangeInfo::new(range, def)) |
176 | } | 176 | } |
177 | 177 | ||
178 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { | 178 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { |
@@ -1086,4 +1086,40 @@ impl<'a> Foo<'a> for &'a () { | |||
1086 | "#]], | 1086 | "#]], |
1087 | ); | 1087 | ); |
1088 | } | 1088 | } |
1089 | |||
1090 | #[test] | ||
1091 | fn test_map_range_to_original() { | ||
1092 | check( | ||
1093 | r#" | ||
1094 | macro_rules! foo {($i:ident) => {$i} } | ||
1095 | fn main() { | ||
1096 | let a<|> = "test"; | ||
1097 | foo!(a); | ||
1098 | } | ||
1099 | "#, | ||
1100 | expect![[r#" | ||
1101 | a Local FileId(0) 59..60 Other | ||
1102 | |||
1103 | FileId(0) 80..81 Other Read | ||
1104 | "#]], | ||
1105 | ); | ||
1106 | } | ||
1107 | |||
1108 | #[test] | ||
1109 | fn test_map_range_to_original_ref() { | ||
1110 | check( | ||
1111 | r#" | ||
1112 | macro_rules! foo {($i:ident) => {$i} } | ||
1113 | fn main() { | ||
1114 | let a = "test"; | ||
1115 | foo!(a<|>); | ||
1116 | } | ||
1117 | "#, | ||
1118 | expect![[r#" | ||
1119 | a Local FileId(0) 59..60 Other | ||
1120 | |||
1121 | FileId(0) 80..81 Other Read | ||
1122 | "#]], | ||
1123 | ); | ||
1124 | } | ||
1089 | } | 1125 | } |
diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs index e87d98dad..10c0abdac 100644 --- a/crates/ide_db/src/source_change.rs +++ b/crates/ide_db/src/source_change.rs | |||
@@ -44,7 +44,7 @@ impl From<Vec<SourceFileEdit>> for SourceChange { | |||
44 | 44 | ||
45 | #[derive(Debug, Clone)] | 45 | #[derive(Debug, Clone)] |
46 | pub enum FileSystemEdit { | 46 | pub enum FileSystemEdit { |
47 | CreateFile { dst: AnchoredPathBuf }, | 47 | CreateFile { dst: AnchoredPathBuf, initial_contents: String }, |
48 | MoveFile { src: FileId, dst: AnchoredPathBuf }, | 48 | MoveFile { src: FileId, dst: AnchoredPathBuf }, |
49 | } | 49 | } |
50 | 50 | ||
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index f10e7a9b6..451fa1456 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -1004,6 +1004,18 @@ fn test_underscore() { | |||
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | #[test] | 1006 | #[test] |
1007 | fn test_vertical_bar_with_pat() { | ||
1008 | parse_macro( | ||
1009 | r#" | ||
1010 | macro_rules! foo { | ||
1011 | (| $pat:pat | ) => { 0 } | ||
1012 | } | ||
1013 | "#, | ||
1014 | ) | ||
1015 | .assert_expand_items(r#"foo! { | x | }"#, r#"0"#); | ||
1016 | } | ||
1017 | |||
1018 | #[test] | ||
1007 | fn test_lifetime() { | 1019 | fn test_lifetime() { |
1008 | parse_macro( | 1020 | parse_macro( |
1009 | r#" | 1021 | r#" |
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 1a078f6b4..f08c8bab7 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs | |||
@@ -55,7 +55,7 @@ pub(crate) mod fragments { | |||
55 | use super::*; | 55 | use super::*; |
56 | 56 | ||
57 | pub(crate) use super::{ | 57 | pub(crate) use super::{ |
58 | expressions::block_expr, paths::type_path as path, patterns::pattern, types::type_, | 58 | expressions::block_expr, paths::type_path as path, patterns::pattern_single, types::type_, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | pub(crate) fn expr(p: &mut Parser) { | 61 | pub(crate) fn expr(p: &mut Parser) { |
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index 18b63feb7..e897d5a52 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs | |||
@@ -156,11 +156,13 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker { | |||
156 | let mut saw_expr = false; | 156 | let mut saw_expr = false; |
157 | while !p.at(EOF) && !p.at(T![')']) { | 157 | while !p.at(EOF) && !p.at(T![')']) { |
158 | saw_expr = true; | 158 | saw_expr = true; |
159 | if !p.at_ts(EXPR_FIRST) { | 159 | |
160 | p.error("expected expression"); | 160 | // test tuple_attrs |
161 | // const A: (i64, i64) = (1, #[cfg(test)] 2); | ||
162 | if !expr_with_attrs(p) { | ||
161 | break; | 163 | break; |
162 | } | 164 | } |
163 | expr(p); | 165 | |
164 | if !p.at(T![')']) { | 166 | if !p.at(T![')']) { |
165 | saw_comma = true; | 167 | saw_comma = true; |
166 | p.expect(T![,]); | 168 | p.expect(T![,]); |
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs index 3ee4e4fca..2d006a1d5 100644 --- a/crates/parser/src/grammar/params.rs +++ b/crates/parser/src/grammar/params.rs | |||
@@ -47,20 +47,23 @@ fn list_(p: &mut Parser, flavor: Flavor) { | |||
47 | if let FnDef = flavor { | 47 | if let FnDef = flavor { |
48 | // test self_param_outer_attr | 48 | // test self_param_outer_attr |
49 | // fn f(#[must_use] self) {} | 49 | // fn f(#[must_use] self) {} |
50 | let m = p.start(); | ||
50 | attributes::outer_attrs(p); | 51 | attributes::outer_attrs(p); |
51 | opt_self_param(p); | 52 | opt_self_param(p, m); |
52 | } | 53 | } |
53 | 54 | ||
54 | while !p.at(EOF) && !p.at(ket) { | 55 | while !p.at(EOF) && !p.at(ket) { |
55 | // test param_outer_arg | 56 | // test param_outer_arg |
56 | // fn f(#[attr1] pat: Type) {} | 57 | // fn f(#[attr1] pat: Type) {} |
58 | let m = p.start(); | ||
57 | attributes::outer_attrs(p); | 59 | attributes::outer_attrs(p); |
58 | 60 | ||
59 | if !p.at_ts(PARAM_FIRST) { | 61 | if !p.at_ts(PARAM_FIRST) { |
60 | p.error("expected value parameter"); | 62 | p.error("expected value parameter"); |
63 | m.abandon(p); | ||
61 | break; | 64 | break; |
62 | } | 65 | } |
63 | let param = param(p, flavor); | 66 | let param = param(p, m, flavor); |
64 | if !p.at(ket) { | 67 | if !p.at(ket) { |
65 | p.expect(T![,]); | 68 | p.expect(T![,]); |
66 | } | 69 | } |
@@ -77,9 +80,8 @@ const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); | |||
77 | 80 | ||
78 | struct Variadic(bool); | 81 | struct Variadic(bool); |
79 | 82 | ||
80 | fn param(p: &mut Parser, flavor: Flavor) -> Variadic { | 83 | fn param(p: &mut Parser, m: Marker, flavor: Flavor) -> Variadic { |
81 | let mut res = Variadic(false); | 84 | let mut res = Variadic(false); |
82 | let m = p.start(); | ||
83 | match flavor { | 85 | match flavor { |
84 | // test param_list_vararg | 86 | // test param_list_vararg |
85 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } | 87 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } |
@@ -151,10 +153,8 @@ fn variadic_param(p: &mut Parser) -> bool { | |||
151 | // fn d(&'a mut self, x: i32) {} | 153 | // fn d(&'a mut self, x: i32) {} |
152 | // fn e(mut self) {} | 154 | // fn e(mut self) {} |
153 | // } | 155 | // } |
154 | fn opt_self_param(p: &mut Parser) { | 156 | fn opt_self_param(p: &mut Parser, m: Marker) { |
155 | let m; | ||
156 | if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { | 157 | if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { |
157 | m = p.start(); | ||
158 | p.eat(T![mut]); | 158 | p.eat(T![mut]); |
159 | p.eat(T![self]); | 159 | p.eat(T![self]); |
160 | // test arb_self_types | 160 | // test arb_self_types |
@@ -174,9 +174,8 @@ fn opt_self_param(p: &mut Parser) { | |||
174 | (T![&], T![mut], T![self], _) => 3, | 174 | (T![&], T![mut], T![self], _) => 3, |
175 | (T![&], LIFETIME_IDENT, T![self], _) => 3, | 175 | (T![&], LIFETIME_IDENT, T![self], _) => 3, |
176 | (T![&], LIFETIME_IDENT, T![mut], T![self]) => 4, | 176 | (T![&], LIFETIME_IDENT, T![mut], T![self]) => 4, |
177 | _ => return, | 177 | _ => return m.abandon(p), |
178 | }; | 178 | }; |
179 | m = p.start(); | ||
180 | p.bump_any(); | 179 | p.bump_any(); |
181 | if p.at(LIFETIME_IDENT) { | 180 | if p.at(LIFETIME_IDENT) { |
182 | lifetime(p); | 181 | lifetime(p); |
diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs index 9c3f7c28a..4aeccd193 100644 --- a/crates/parser/src/grammar/type_params.rs +++ b/crates/parser/src/grammar/type_params.rs | |||
@@ -113,7 +113,7 @@ fn type_bound(p: &mut Parser) -> bool { | |||
113 | p.eat(T![?]); | 113 | p.eat(T![?]); |
114 | match p.current() { | 114 | match p.current() { |
115 | LIFETIME_IDENT => lifetime(p), | 115 | LIFETIME_IDENT => lifetime(p), |
116 | T![for] => types::for_type(p), | 116 | T![for] => types::for_type(p, false), |
117 | _ if paths::is_use_path_start(p) => types::path_type_(p, false), | 117 | _ if paths::is_use_path_start(p) => types::path_type_(p, false), |
118 | _ => { | 118 | _ => { |
119 | m.abandon(p); | 119 | m.abandon(p); |
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 36a15eace..94cbf7d85 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs | |||
@@ -44,7 +44,7 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) { | |||
44 | T![&] => ref_type(p), | 44 | T![&] => ref_type(p), |
45 | T![_] => infer_type(p), | 45 | T![_] => infer_type(p), |
46 | T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p), | 46 | T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p), |
47 | T![for] => for_type(p), | 47 | T![for] => for_type(p, allow_bounds), |
48 | T![impl] => impl_trait_type(p), | 48 | T![impl] => impl_trait_type(p), |
49 | T![dyn] => dyn_trait_type(p), | 49 | T![dyn] => dyn_trait_type(p), |
50 | // Some path types are not allowed to have bounds (no plus) | 50 | // Some path types are not allowed to have bounds (no plus) |
@@ -227,7 +227,7 @@ pub(super) fn for_binder(p: &mut Parser) { | |||
227 | // type A = for<'a> fn() -> (); | 227 | // type A = for<'a> fn() -> (); |
228 | // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); | 228 | // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); |
229 | // type Obj = for<'a> PartialEq<&'a i32>; | 229 | // type Obj = for<'a> PartialEq<&'a i32>; |
230 | pub(super) fn for_type(p: &mut Parser) { | 230 | pub(super) fn for_type(p: &mut Parser, allow_bounds: bool) { |
231 | assert!(p.at(T![for])); | 231 | assert!(p.at(T![for])); |
232 | let m = p.start(); | 232 | let m = p.start(); |
233 | for_binder(p); | 233 | for_binder(p); |
@@ -240,7 +240,13 @@ pub(super) fn for_type(p: &mut Parser) { | |||
240 | } | 240 | } |
241 | } | 241 | } |
242 | type_no_bounds(p); | 242 | type_no_bounds(p); |
243 | m.complete(p, FOR_TYPE); | 243 | let completed = m.complete(p, FOR_TYPE); |
244 | |||
245 | // test no_dyn_trait_leading_for | ||
246 | // type A = for<'a> Test<'a> + Send; | ||
247 | if allow_bounds { | ||
248 | opt_type_bounds_as_dyn_trait_type(p, completed); | ||
249 | } | ||
244 | } | 250 | } |
245 | 251 | ||
246 | // test impl_trait_type | 252 | // test impl_trait_type |
@@ -290,7 +296,7 @@ fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { | |||
290 | let path = m.complete(p, kind); | 296 | let path = m.complete(p, kind); |
291 | 297 | ||
292 | if allow_bounds { | 298 | if allow_bounds { |
293 | opt_path_type_bounds_as_dyn_trait_type(p, path); | 299 | opt_type_bounds_as_dyn_trait_type(p, path); |
294 | } | 300 | } |
295 | } | 301 | } |
296 | 302 | ||
@@ -304,19 +310,23 @@ pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { | |||
304 | // fn foo() -> Box<dyn T + 'f> {} | 310 | // fn foo() -> Box<dyn T + 'f> {} |
305 | let path = m.complete(p, PATH_TYPE); | 311 | let path = m.complete(p, PATH_TYPE); |
306 | if allow_bounds { | 312 | if allow_bounds { |
307 | opt_path_type_bounds_as_dyn_trait_type(p, path); | 313 | opt_type_bounds_as_dyn_trait_type(p, path); |
308 | } | 314 | } |
309 | } | 315 | } |
310 | 316 | ||
311 | /// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE | 317 | /// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE |
312 | /// with a TYPE_BOUND_LIST | 318 | /// with a TYPE_BOUND_LIST |
313 | fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) { | 319 | fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) { |
320 | assert!(matches!( | ||
321 | type_marker.kind(), | ||
322 | SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_CALL | ||
323 | )); | ||
314 | if !p.at(T![+]) { | 324 | if !p.at(T![+]) { |
315 | return; | 325 | return; |
316 | } | 326 | } |
317 | 327 | ||
318 | // First create a TYPE_BOUND from the completed PATH_TYPE | 328 | // First create a TYPE_BOUND from the completed PATH_TYPE |
319 | let m = path_type_marker.precede(p).complete(p, TYPE_BOUND); | 329 | let m = type_marker.precede(p).complete(p, TYPE_BOUND); |
320 | 330 | ||
321 | // Next setup a marker for the TYPE_BOUND_LIST | 331 | // Next setup a marker for the TYPE_BOUND_LIST |
322 | let m = m.precede(p); | 332 | let m = m.precede(p); |
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index ab8e4c70e..811e740f9 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs | |||
@@ -112,7 +112,7 @@ pub fn parse_fragment( | |||
112 | FragmentKind::Path => grammar::fragments::path, | 112 | FragmentKind::Path => grammar::fragments::path, |
113 | FragmentKind::Expr => grammar::fragments::expr, | 113 | FragmentKind::Expr => grammar::fragments::expr, |
114 | FragmentKind::Type => grammar::fragments::type_, | 114 | FragmentKind::Type => grammar::fragments::type_, |
115 | FragmentKind::Pattern => grammar::fragments::pattern, | 115 | FragmentKind::Pattern => grammar::fragments::pattern_single, |
116 | FragmentKind::Item => grammar::fragments::item, | 116 | FragmentKind::Item => grammar::fragments::item, |
117 | FragmentKind::Block => grammar::fragments::block_expr, | 117 | FragmentKind::Block => grammar::fragments::block_expr, |
118 | FragmentKind::Visibility => grammar::fragments::opt_visibility, | 118 | FragmentKind::Visibility => grammar::fragments::opt_visibility, |
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml index 1bfa6c3fc..df9a55c10 100644 --- a/crates/proc_macro_srv/Cargo.toml +++ b/crates/proc_macro_srv/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] } | 13 | object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe"] } |
14 | libloading = "0.6.0" | 14 | libloading = "0.6.0" |
15 | memmap = "0.7" | 15 | memmap = "0.7" |
16 | 16 | ||
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1f4b5c24c..1db5b4e7d 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -33,7 +33,7 @@ config_data! { | |||
33 | callInfo_full: bool = "true", | 33 | callInfo_full: bool = "true", |
34 | 34 | ||
35 | /// Automatically refresh project info via `cargo metadata` on | 35 | /// Automatically refresh project info via `cargo metadata` on |
36 | /// Cargo.toml changes. | 36 | /// `Cargo.toml` changes. |
37 | cargo_autoreload: bool = "true", | 37 | cargo_autoreload: bool = "true", |
38 | /// Activate all available features. | 38 | /// Activate all available features. |
39 | cargo_allFeatures: bool = "false", | 39 | cargo_allFeatures: bool = "false", |
@@ -52,7 +52,7 @@ config_data! { | |||
52 | /// Run specified `cargo check` command for diagnostics on save. | 52 | /// Run specified `cargo check` command for diagnostics on save. |
53 | checkOnSave_enable: bool = "true", | 53 | checkOnSave_enable: bool = "true", |
54 | /// Check with all features (will be passed as `--all-features`). | 54 | /// Check with all features (will be passed as `--all-features`). |
55 | /// Defaults to `rust-analyzer.cargo.allFeatures`. | 55 | /// Defaults to `#rust-analyzer.cargo.allFeatures#`. |
56 | checkOnSave_allFeatures: Option<bool> = "null", | 56 | checkOnSave_allFeatures: Option<bool> = "null", |
57 | /// Check all targets and tests (will be passed as `--all-targets`). | 57 | /// Check all targets and tests (will be passed as `--all-targets`). |
58 | checkOnSave_allTargets: bool = "true", | 58 | checkOnSave_allTargets: bool = "true", |
@@ -61,12 +61,12 @@ config_data! { | |||
61 | /// Do not activate the `default` feature. | 61 | /// Do not activate the `default` feature. |
62 | checkOnSave_noDefaultFeatures: Option<bool> = "null", | 62 | checkOnSave_noDefaultFeatures: Option<bool> = "null", |
63 | /// Check for a specific target. Defaults to | 63 | /// Check for a specific target. Defaults to |
64 | /// `rust-analyzer.cargo.target`. | 64 | /// `#rust-analyzer.cargo.target#`. |
65 | checkOnSave_target: Option<String> = "null", | 65 | checkOnSave_target: Option<String> = "null", |
66 | /// Extra arguments for `cargo check`. | 66 | /// Extra arguments for `cargo check`. |
67 | checkOnSave_extraArgs: Vec<String> = "[]", | 67 | checkOnSave_extraArgs: Vec<String> = "[]", |
68 | /// List of features to activate. Defaults to | 68 | /// List of features to activate. Defaults to |
69 | /// `rust-analyzer.cargo.features`. | 69 | /// `#rust-analyzer.cargo.features#`. |
70 | checkOnSave_features: Option<Vec<String>> = "null", | 70 | checkOnSave_features: Option<Vec<String>> = "null", |
71 | /// Advanced option, fully override the command rust-analyzer uses for | 71 | /// Advanced option, fully override the command rust-analyzer uses for |
72 | /// checking. The command should include `--message-format=json` or | 72 | /// checking. The command should include `--message-format=json` or |
@@ -80,7 +80,7 @@ config_data! { | |||
80 | /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. | 80 | /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. |
81 | completion_postfix_enable: bool = "true", | 81 | completion_postfix_enable: bool = "true", |
82 | /// Toggles the additional completions that automatically add imports when completed. | 82 | /// Toggles the additional completions that automatically add imports when completed. |
83 | /// Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. | 83 | /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. |
84 | completion_autoimport_enable: bool = "true", | 84 | completion_autoimport_enable: bool = "true", |
85 | 85 | ||
86 | /// Whether to show native rust-analyzer diagnostics. | 86 | /// Whether to show native rust-analyzer diagnostics. |
@@ -90,13 +90,13 @@ config_data! { | |||
90 | diagnostics_enableExperimental: bool = "true", | 90 | diagnostics_enableExperimental: bool = "true", |
91 | /// List of rust-analyzer diagnostics to disable. | 91 | /// List of rust-analyzer diagnostics to disable. |
92 | diagnostics_disabled: FxHashSet<String> = "[]", | 92 | diagnostics_disabled: FxHashSet<String> = "[]", |
93 | /// List of warnings that should be displayed with info severity.\nThe | 93 | /// List of warnings that should be displayed with info severity.\n\nThe |
94 | /// warnings will be indicated by a blue squiggly underline in code and | 94 | /// warnings will be indicated by a blue squiggly underline in code and |
95 | /// a blue icon in the problems panel. | 95 | /// a blue icon in the `Problems Panel`. |
96 | diagnostics_warningsAsHint: Vec<String> = "[]", | 96 | diagnostics_warningsAsHint: Vec<String> = "[]", |
97 | /// List of warnings that should be displayed with hint severity.\nThe | 97 | /// List of warnings that should be displayed with hint severity.\n\nThe |
98 | /// warnings will be indicated by faded text or three dots in code and | 98 | /// warnings will be indicated by faded text or three dots in code and |
99 | /// will not show up in the problems panel. | 99 | /// will not show up in the `Problems Panel`. |
100 | diagnostics_warningsAsInfo: Vec<String> = "[]", | 100 | diagnostics_warningsAsInfo: Vec<String> = "[]", |
101 | 101 | ||
102 | /// Controls file watching implementation. | 102 | /// Controls file watching implementation. |
@@ -121,7 +121,7 @@ config_data! { | |||
121 | 121 | ||
122 | /// Whether to show inlay type hints for method chains. | 122 | /// Whether to show inlay type hints for method chains. |
123 | inlayHints_chainingHints: bool = "true", | 123 | inlayHints_chainingHints: bool = "true", |
124 | /// Maximum length for inlay hints. | 124 | /// Maximum length for inlay hints. Default is unlimited. |
125 | inlayHints_maxLength: Option<usize> = "null", | 125 | inlayHints_maxLength: Option<usize> = "null", |
126 | /// Whether to show function parameter name inlay hints at the call | 126 | /// Whether to show function parameter name inlay hints at the call |
127 | /// site. | 127 | /// site. |
@@ -145,27 +145,27 @@ config_data! { | |||
145 | lens_methodReferences: bool = "false", | 145 | lens_methodReferences: bool = "false", |
146 | 146 | ||
147 | /// Disable project auto-discovery in favor of explicitly specified set | 147 | /// Disable project auto-discovery in favor of explicitly specified set |
148 | /// of projects. \nElements must be paths pointing to Cargo.toml, | 148 | /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, |
149 | /// rust-project.json, or JSON objects in rust-project.json format. | 149 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. |
150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", | 150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", |
151 | /// Number of syntax trees rust-analyzer keeps in memory. | 151 | /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. |
152 | lruCapacity: Option<usize> = "null", | 152 | lruCapacity: Option<usize> = "null", |
153 | /// Whether to show `can't find Cargo.toml` error message. | 153 | /// Whether to show `can't find Cargo.toml` error message. |
154 | notifications_cargoTomlNotFound: bool = "true", | 154 | notifications_cargoTomlNotFound: bool = "true", |
155 | /// Enable Proc macro support, cargo.loadOutDirsFromCheck must be | 155 | /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be |
156 | /// enabled. | 156 | /// enabled. |
157 | procMacro_enable: bool = "false", | 157 | procMacro_enable: bool = "false", |
158 | 158 | ||
159 | /// Command to be executed instead of 'cargo' for runnables. | 159 | /// Command to be executed instead of 'cargo' for runnables. |
160 | runnables_overrideCargo: Option<String> = "null", | 160 | runnables_overrideCargo: Option<String> = "null", |
161 | /// Additional arguments to be passed to cargo for runnables such as | 161 | /// Additional arguments to be passed to cargo for runnables such as |
162 | /// tests or binaries.\nFor example, it may be '--release'. | 162 | /// tests or binaries.\nFor example, it may be `--release`. |
163 | runnables_cargoExtraArgs: Vec<String> = "[]", | 163 | runnables_cargoExtraArgs: Vec<String> = "[]", |
164 | 164 | ||
165 | /// Path to the rust compiler sources, for usage in rustc_private projects. | 165 | /// Path to the rust compiler sources, for usage in rustc_private projects. |
166 | rustcSource : Option<String> = "null", | 166 | rustcSource : Option<String> = "null", |
167 | 167 | ||
168 | /// Additional arguments to rustfmt. | 168 | /// Additional arguments to `rustfmt`. |
169 | rustfmt_extraArgs: Vec<String> = "[]", | 169 | rustfmt_extraArgs: Vec<String> = "[]", |
170 | /// Advanced option, fully override the command rust-analyzer uses for | 170 | /// Advanced option, fully override the command rust-analyzer uses for |
171 | /// formatting. | 171 | /// formatting. |
@@ -349,12 +349,12 @@ impl Config { | |||
349 | res | 349 | res |
350 | } | 350 | } |
351 | pub fn update(&mut self, json: serde_json::Value) { | 351 | pub fn update(&mut self, json: serde_json::Value) { |
352 | log::info!("Config::update({:#})", json); | 352 | log::info!("updating config from JSON: {:#}", json); |
353 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { | 353 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { |
354 | return; | 354 | return; |
355 | } | 355 | } |
356 | self.do_update(json); | 356 | self.do_update(json); |
357 | log::info!("Config::update() = {:#?}", self); | 357 | log::info!("updated config: {:#?}", self); |
358 | } | 358 | } |
359 | fn do_update(&mut self, json: serde_json::Value) { | 359 | fn do_update(&mut self, json: serde_json::Value) { |
360 | let data = ConfigData::from_json(json); | 360 | let data = ConfigData::from_json(json); |
@@ -758,7 +758,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json | |||
758 | ], | 758 | ], |
759 | "enumDescriptions": [ | 759 | "enumDescriptions": [ |
760 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | 760 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", |
761 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", | 761 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", |
762 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | 762 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." |
763 | ], | 763 | ], |
764 | }, | 764 | }, |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index f16f97131..540759198 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -319,6 +319,10 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
319 | message: "original diagnostic".to_string(), | 319 | message: "original diagnostic".to_string(), |
320 | }; | 320 | }; |
321 | for info in &related_information { | 321 | for info in &related_information { |
322 | // Filter out empty/non-existent messages, as they greatly confuse VS Code. | ||
323 | if info.message.is_empty() { | ||
324 | continue; | ||
325 | } | ||
322 | diagnostics.push(MappedRustDiagnostic { | 326 | diagnostics.push(MappedRustDiagnostic { |
323 | url: info.location.uri.clone(), | 327 | url: info.location.uri.clone(), |
324 | fixes: fixes.clone(), // share fixes to make them easier to apply | 328 | fixes: fixes.clone(), // share fixes to make them easier to apply |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e0561b5a7..5a1ae96aa 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -634,30 +634,47 @@ pub(crate) fn snippet_text_document_edit( | |||
634 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) | 634 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) |
635 | } | 635 | } |
636 | 636 | ||
637 | pub(crate) fn resource_op( | 637 | pub(crate) fn snippet_text_document_ops( |
638 | snap: &GlobalStateSnapshot, | 638 | snap: &GlobalStateSnapshot, |
639 | file_system_edit: FileSystemEdit, | 639 | file_system_edit: FileSystemEdit, |
640 | ) -> lsp_types::ResourceOp { | 640 | ) -> Vec<lsp_ext::SnippetDocumentChangeOperation> { |
641 | let mut ops = Vec::new(); | ||
641 | match file_system_edit { | 642 | match file_system_edit { |
642 | FileSystemEdit::CreateFile { dst } => { | 643 | FileSystemEdit::CreateFile { dst, initial_contents } => { |
643 | let uri = snap.anchored_path(&dst); | 644 | let uri = snap.anchored_path(&dst); |
644 | lsp_types::ResourceOp::Create(lsp_types::CreateFile { | 645 | let create_file = lsp_types::ResourceOp::Create(lsp_types::CreateFile { |
645 | uri, | 646 | uri: uri.clone(), |
646 | options: None, | 647 | options: None, |
647 | annotation_id: None, | 648 | annotation_id: None, |
648 | }) | 649 | }); |
650 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(create_file)); | ||
651 | if !initial_contents.is_empty() { | ||
652 | let text_document = | ||
653 | lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; | ||
654 | let range = range(&LineIndex::new(""), TextRange::empty(TextSize::from(0))); | ||
655 | let text_edit = lsp_ext::SnippetTextEdit { | ||
656 | range, | ||
657 | new_text: initial_contents, | ||
658 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), | ||
659 | }; | ||
660 | let edit_file = | ||
661 | lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] }; | ||
662 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit_file)); | ||
663 | } | ||
649 | } | 664 | } |
650 | FileSystemEdit::MoveFile { src, dst } => { | 665 | FileSystemEdit::MoveFile { src, dst } => { |
651 | let old_uri = snap.file_id_to_url(src); | 666 | let old_uri = snap.file_id_to_url(src); |
652 | let new_uri = snap.anchored_path(&dst); | 667 | let new_uri = snap.anchored_path(&dst); |
653 | lsp_types::ResourceOp::Rename(lsp_types::RenameFile { | 668 | let rename_file = lsp_types::ResourceOp::Rename(lsp_types::RenameFile { |
654 | old_uri, | 669 | old_uri, |
655 | new_uri, | 670 | new_uri, |
656 | options: None, | 671 | options: None, |
657 | annotation_id: None, | 672 | annotation_id: None, |
658 | }) | 673 | }); |
674 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file)) | ||
659 | } | 675 | } |
660 | } | 676 | } |
677 | ops | ||
661 | } | 678 | } |
662 | 679 | ||
663 | pub(crate) fn snippet_workspace_edit( | 680 | pub(crate) fn snippet_workspace_edit( |
@@ -666,8 +683,8 @@ pub(crate) fn snippet_workspace_edit( | |||
666 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { | 683 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { |
667 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); | 684 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); |
668 | for op in source_change.file_system_edits { | 685 | for op in source_change.file_system_edits { |
669 | let op = resource_op(&snap, op); | 686 | let ops = snippet_text_document_ops(snap, op); |
670 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op)); | 687 | document_changes.extend_from_slice(&ops); |
671 | } | 688 | } |
672 | for edit in source_change.source_file_edits { | 689 | for edit in source_change.source_file_edits { |
673 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?; | 690 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?; |
diff --git a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast index 6403ff8d5..d3219f0b2 100644 --- a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast +++ b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast | |||
@@ -6,16 +6,16 @@ [email protected] | |||
6 | [email protected] "f" | 6 | [email protected] "f" |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] "(" | 8 | [email protected] "(" |
9 | ATT[email protected]6 | 9 | SELF_PARAM@5..21 |
10 | POUND@5..6 "#" | 10 | ATTR@5..16 |
11 | L_BRACK@6..7 "[" | 11 | POUND@5..6 "#" |
12 | PATH@7..15 | 12 | L_BRACK@6..7 "[" |
13 | PATH_SEGMENT@7..15 | 13 | [email protected] |
14 | NAME_REF@7..15 | 14 | PATH_SEGMENT@7..15 |
15 | IDENT@7..15 "must_use" | 15 | NAME_REF@7..15 |
16 | R_BRACK@15..16 "]" | 16 | IDENT@7..15 "must_use" |
17 | WHITESPACE@16..17 " " | 17 | R_BRACK@15..16 "]" |
18 | SELF_PARAM@17..21 | 18 | WHITESPACE@16..17 " " |
19 | [email protected] "self" | 19 | [email protected] "self" |
20 | [email protected] ")" | 20 | [email protected] ")" |
21 | [email protected] " " | 21 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast new file mode 100644 index 000000000..edfcb288c --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast | |||
@@ -0,0 +1,43 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "type" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "A" | ||
7 | [email protected] " " | ||
8 | [email protected] "=" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] "for" | ||
15 | [email protected] | ||
16 | [email protected] "<" | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "\'a" | ||
20 | [email protected] ">" | ||
21 | [email protected] " " | ||
22 | [email protected] | ||
23 | [email protected] | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] "Test" | ||
27 | [email protected] | ||
28 | [email protected] "<" | ||
29 | [email protected] | ||
30 | [email protected] | ||
31 | [email protected] "\'a" | ||
32 | [email protected] ">" | ||
33 | [email protected] " " | ||
34 | [email protected] "+" | ||
35 | [email protected] " " | ||
36 | [email protected] | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] | ||
41 | [email protected] "Send" | ||
42 | [email protected] ";" | ||
43 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs new file mode 100644 index 000000000..47a71fd19 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs | |||
@@ -0,0 +1 @@ | |||
type A = for<'a> Test<'a> + Send; | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast new file mode 100644 index 000000000..d34b21abe --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast | |||
@@ -0,0 +1,50 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "const" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "A" | ||
7 | [email protected] ":" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] "(" | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] "i64" | ||
16 | [email protected] "," | ||
17 | [email protected] " " | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] | ||
22 | [email protected] "i64" | ||
23 | [email protected] ")" | ||
24 | [email protected] " " | ||
25 | [email protected] "=" | ||
26 | [email protected] " " | ||
27 | [email protected] | ||
28 | [email protected] "(" | ||
29 | [email protected] | ||
30 | [email protected] "1" | ||
31 | [email protected] "," | ||
32 | [email protected] " " | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] "#" | ||
36 | [email protected] "[" | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] "cfg" | ||
41 | [email protected] | ||
42 | [email protected] "(" | ||
43 | [email protected] "test" | ||
44 | [email protected] ")" | ||
45 | [email protected] "]" | ||
46 | [email protected] " " | ||
47 | [email protected] "2" | ||
48 | [email protected] ")" | ||
49 | [email protected] ";" | ||
50 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs new file mode 100644 index 000000000..f84b7ab31 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs | |||
@@ -0,0 +1 @@ | |||
const A: (i64, i64) = (1, #[cfg(test)] 2); | |||
diff --git a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast index 8974f9e40..3fed11838 100644 --- a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast +++ b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast | |||
@@ -107,16 +107,16 @@ [email protected] | |||
107 | [email protected] "i8" | 107 | [email protected] "i8" |
108 | [email protected] "," | 108 | [email protected] "," |
109 | [email protected] " " | 109 | [email protected] " " |
110 | ATT[email protected]3 | 110 | PARAM@106..117 |
111 | POUND@106..107 "#" | 111 | ATTR@106..113 |
112 | L_BRACK@107..108 "[" | 112 | POUND@106..107 "#" |
113 | PATH@108..112 | 113 | L_BRACK@107..108 "[" |
114 | PATH_SEGMENT@108..112 | 114 | [email protected] |
115 | NAME_REF@108..112 | 115 | PATH_SEGMENT@108..112 |
116 | IDENT@108..112 "attr" | 116 | NAME_REF@108..112 |
117 | R_BRACK@112..113 "]" | 117 | IDENT@108..112 "attr" |
118 | WHITESPACE@113..114 " " | 118 | R_BRACK@112..113 "]" |
119 | PARAM@114..117 | 119 | WHITESPACE@113..114 " " |
120 | [email protected] "..." | 120 | [email protected] "..." |
121 | [email protected] ")" | 121 | [email protected] ")" |
122 | [email protected] " " | 122 | [email protected] " " |
@@ -153,16 +153,16 @@ [email protected] | |||
153 | [email protected] "FnMut" | 153 | [email protected] "FnMut" |
154 | [email protected] | 154 | [email protected] |
155 | [email protected] "(" | 155 | [email protected] "(" |
156 | ATT[email protected]53 | 156 | PARAM@146..166 |
157 | POUND@146..147 "#" | 157 | ATTR@146..153 |
158 | L_BRACK@147..148 "[" | 158 | POUND@146..147 "#" |
159 | PATH@148..152 | 159 | L_BRACK@147..148 "[" |
160 | PATH_SEGMENT@148..152 | 160 | [email protected] |
161 | NAME_REF@148..152 | 161 | PATH_SEGMENT@148..152 |
162 | IDENT@148..152 "attr" | 162 | NAME_REF@148..152 |
163 | R_BRACK@152..153 "]" | 163 | IDENT@148..152 "attr" |
164 | WHITESPACE@153..154 " " | 164 | R_BRACK@152..153 "]" |
165 | PARAM@154..166 | 165 | WHITESPACE@153..154 " " |
166 | [email protected] | 166 | [email protected] |
167 | [email protected] "&" | 167 | [email protected] "&" |
168 | [email protected] "mut" | 168 | [email protected] "mut" |
@@ -224,17 +224,17 @@ [email protected] | |||
224 | [email protected] "u64" | 224 | [email protected] "u64" |
225 | [email protected] "," | 225 | [email protected] "," |
226 | [email protected] " " | 226 | [email protected] " " |
227 | ATT[email protected]1 | 227 | PARAM@213..232 |
228 | POUND@213..214 "#" | 228 | ATTR@213..221 |
229 | WHITESPACE@214..215 " " | 229 | POUND@213..214 "#" |
230 | L_BRACK@215..216 "[" | 230 | WHITESPACE@214..215 " " |
231 | PATH@216..220 | 231 | L_BRACK@215..216 "[" |
232 | PATH_SEGMENT@216..220 | 232 | [email protected] |
233 | NAME_REF@216..220 | 233 | PATH_SEGMENT@216..220 |
234 | IDENT@216..220 "attr" | 234 | NAME_REF@216..220 |
235 | R_BRACK@220..221 "]" | 235 | IDENT@216..220 "attr" |
236 | WHITESPACE@221..222 " " | 236 | R_BRACK@220..221 "]" |
237 | PARAM@222..232 | 237 | WHITESPACE@221..222 " " |
238 | [email protected] | 238 | [email protected] |
239 | [email protected] "mut" | 239 | [email protected] "mut" |
240 | [email protected] " " | 240 | [email protected] " " |
@@ -271,16 +271,16 @@ [email protected] | |||
271 | [email protected] "f" | 271 | [email protected] "f" |
272 | [email protected] | 272 | [email protected] |
273 | [email protected] "(" | 273 | [email protected] "(" |
274 | ATT[email protected]68 | 274 | SELF_PARAM@257..273 |
275 | POUND@257..258 "#" | 275 | ATTR@257..268 |
276 | L_BRACK@258..259 "[" | 276 | POUND@257..258 "#" |
277 | PATH@259..267 | 277 | L_BRACK@258..259 "[" |
278 | PATH_SEGMENT@259..267 | 278 | [email protected] |
279 | NAME_REF@259..267 | 279 | PATH_SEGMENT@259..267 |
280 | IDENT@259..267 "must_use" | 280 | NAME_REF@259..267 |
281 | R_BRACK@267..268 "]" | 281 | IDENT@259..267 "must_use" |
282 | WHITESPACE@268..269 " " | 282 | R_BRACK@267..268 "]" |
283 | SELF_PARAM@269..273 | 283 | WHITESPACE@268..269 " " |
284 | [email protected] "self" | 284 | [email protected] "self" |
285 | [email protected] ")" | 285 | [email protected] ")" |
286 | [email protected] " " | 286 | [email protected] " " |
@@ -295,16 +295,16 @@ [email protected] | |||
295 | [email protected] "g1" | 295 | [email protected] "g1" |
296 | [email protected] | 296 | [email protected] |
297 | [email protected] "(" | 297 | [email protected] "(" |
298 | ATTR@289..296 | 298 | SELF_PARAM@289..301 |
299 | POUND@289..290 "#" | 299 | ATTR@289..296 |
300 | L_BRACK@290..291 "[" | 300 | POUND@289..290 "#" |
301 | PATH@291..295 | 301 | L_BRACK@290..291 "[" |
302 | PATH_SEGMENT@291..295 | 302 | [email protected] |
303 | NAME_REF@291..295 | 303 | PATH_SEGMENT@291..295 |
304 | IDENT@291..295 "attr" | 304 | NAME_REF@291..295 |
305 | R_BRACK@295..296 "]" | 305 | IDENT@291..295 "attr" |
306 | WHITESPACE@296..297 " " | 306 | R_BRACK@295..296 "]" |
307 | SELF_PARAM@297..301 | 307 | WHITESPACE@296..297 " " |
308 | [email protected] "self" | 308 | [email protected] "self" |
309 | [email protected] ")" | 309 | [email protected] ")" |
310 | [email protected] " " | 310 | [email protected] " " |
@@ -319,16 +319,16 @@ [email protected] | |||
319 | [email protected] "g2" | 319 | [email protected] "g2" |
320 | [email protected] | 320 | [email protected] |
321 | [email protected] "(" | 321 | [email protected] "(" |
322 | ATT[email protected]24 | 322 | SELF_PARAM@317..330 |
323 | POUND@317..318 "#" | 323 | ATTR@317..324 |
324 | L_BRACK@318..319 "[" | 324 | POUND@317..318 "#" |
325 | PATH@319..323 | 325 | L_BRACK@318..319 "[" |
326 | PATH_SEGMENT@319..323 | 326 | [email protected] |
327 | NAME_REF@319..323 | 327 | PATH_SEGMENT@319..323 |
328 | IDENT@319..323 "attr" | 328 | NAME_REF@319..323 |
329 | R_BRACK@323..324 "]" | 329 | IDENT@319..323 "attr" |
330 | WHITESPACE@324..325 " " | 330 | R_BRACK@323..324 "]" |
331 | SELF_PARAM@325..330 | 331 | WHITESPACE@324..325 " " |
332 | [email protected] "&" | 332 | [email protected] "&" |
333 | [email protected] "self" | 333 | [email protected] "self" |
334 | [email protected] ")" | 334 | [email protected] ")" |
@@ -350,16 +350,16 @@ [email protected] | |||
350 | [email protected] ">" | 350 | [email protected] ">" |
351 | [email protected] | 351 | [email protected] |
352 | [email protected] "(" | 352 | [email protected] "(" |
353 | ATT[email protected]57 | 353 | SELF_PARAM@350..367 |
354 | POUND@350..351 "#" | 354 | ATTR@350..357 |
355 | L_BRACK@351..352 "[" | 355 | POUND@350..351 "#" |
356 | PATH@352..356 | 356 | L_BRACK@351..352 "[" |
357 | PATH_SEGMENT@352..356 | 357 | [email protected] |
358 | NAME_REF@352..356 | 358 | PATH_SEGMENT@352..356 |
359 | IDENT@352..356 "attr" | 359 | NAME_REF@352..356 |
360 | R_BRACK@356..357 "]" | 360 | IDENT@352..356 "attr" |
361 | WHITESPACE@357..358 " " | 361 | R_BRACK@356..357 "]" |
362 | SELF_PARAM@358..367 | 362 | WHITESPACE@357..358 " " |
363 | [email protected] "&" | 363 | [email protected] "&" |
364 | [email protected] "mut" | 364 | [email protected] "mut" |
365 | [email protected] " " | 365 | [email protected] " " |
@@ -383,16 +383,16 @@ [email protected] | |||
383 | [email protected] ">" | 383 | [email protected] ">" |
384 | [email protected] | 384 | [email protected] |
385 | [email protected] "(" | 385 | [email protected] "(" |
386 | ATTR@387..394 | 386 | SELF_PARAM@387..403 |
387 | POUND@387..388 "#" | 387 | ATTR@387..394 |
388 | L_BRACK@388..389 "[" | 388 | POUND@387..388 "#" |
389 | PATH@389..393 | 389 | L_BRACK@388..389 "[" |
390 | PATH_SEGMENT@389..393 | 390 | [email protected] |
391 | NAME_REF@389..393 | 391 | PATH_SEGMENT@389..393 |
392 | IDENT@389..393 "attr" | 392 | NAME_REF@389..393 |
393 | R_BRACK@393..394 "]" | 393 | IDENT@389..393 "attr" |
394 | WHITESPACE@394..395 " " | 394 | R_BRACK@393..394 "]" |
395 | SELF_PARAM@395..403 | 395 | WHITESPACE@394..395 " " |
396 | [email protected] "&" | 396 | [email protected] "&" |
397 | [email protected] | 397 | [email protected] |
398 | [email protected] "\'a" | 398 | [email protected] "\'a" |
@@ -417,16 +417,16 @@ [email protected] | |||
417 | [email protected] ">" | 417 | [email protected] ">" |
418 | [email protected] | 418 | [email protected] |
419 | [email protected] "(" | 419 | [email protected] "(" |
420 | ATT[email protected]0 | 420 | SELF_PARAM@423..443 |
421 | POUND@423..424 "#" | 421 | ATTR@423..430 |
422 | L_BRACK@424..425 "[" | 422 | POUND@423..424 "#" |
423 | PATH@425..429 | 423 | L_BRACK@424..425 "[" |
424 | PATH_SEGMENT@425..429 | 424 | [email protected] |
425 | NAME_REF@425..429 | 425 | PATH_SEGMENT@425..429 |
426 | IDENT@425..429 "attr" | 426 | NAME_REF@425..429 |
427 | R_BRACK@429..430 "]" | 427 | IDENT@425..429 "attr" |
428 | WHITESPACE@430..431 " " | 428 | R_BRACK@429..430 "]" |
429 | SELF_PARAM@431..443 | 429 | WHITESPACE@430..431 " " |
430 | [email protected] "&" | 430 | [email protected] "&" |
431 | [email protected] | 431 | [email protected] |
432 | [email protected] "\'a" | 432 | [email protected] "\'a" |
@@ -447,16 +447,16 @@ [email protected] | |||
447 | [email protected] "c" | 447 | [email protected] "c" |
448 | [email protected] | 448 | [email protected] |
449 | [email protected] "(" | 449 | [email protected] "(" |
450 | ATT[email protected]5 | 450 | SELF_PARAM@458..476 |
451 | POUND@458..459 "#" | 451 | ATTR@458..465 |
452 | L_BRACK@459..460 "[" | 452 | POUND@458..459 "#" |
453 | PATH@460..464 | 453 | L_BRACK@459..460 "[" |
454 | PATH_SEGMENT@460..464 | 454 | [email protected] |
455 | NAME_REF@460..464 | 455 | PATH_SEGMENT@460..464 |
456 | IDENT@460..464 "attr" | 456 | NAME_REF@460..464 |
457 | R_BRACK@464..465 "]" | 457 | IDENT@460..464 "attr" |
458 | WHITESPACE@465..466 " " | 458 | R_BRACK@464..465 "]" |
459 | SELF_PARAM@466..476 | 459 | WHITESPACE@465..466 " " |
460 | [email protected] "self" | 460 | [email protected] "self" |
461 | [email protected] ":" | 461 | [email protected] ":" |
462 | [email protected] " " | 462 | [email protected] " " |
@@ -478,16 +478,16 @@ [email protected] | |||
478 | [email protected] "d" | 478 | [email protected] "d" |
479 | [email protected] | 479 | [email protected] |
480 | [email protected] "(" | 480 | [email protected] "(" |
481 | ATTR@491..498 | 481 | SELF_PARAM@491..513 |
482 | POUND@491..492 "#" | 482 | ATTR@491..498 |
483 | L_BRACK@492..493 "[" | 483 | POUND@491..492 "#" |
484 | PATH@493..497 | 484 | L_BRACK@492..493 "[" |
485 | PATH_SEGMENT@493..497 | 485 | [email protected] |
486 | NAME_REF@493..497 | 486 | PATH_SEGMENT@493..497 |
487 | IDENT@493..497 "attr" | 487 | NAME_REF@493..497 |
488 | R_BRACK@497..498 "]" | 488 | IDENT@493..497 "attr" |
489 | WHITESPACE@498..499 " " | 489 | R_BRACK@497..498 "]" |
490 | SELF_PARAM@499..513 | 490 | WHITESPACE@498..499 " " |
491 | [email protected] "self" | 491 | [email protected] "self" |
492 | [email protected] ":" | 492 | [email protected] ":" |
493 | [email protected] " " | 493 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast index 4009b3ff8..f7c094898 100644 --- a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast +++ b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast | |||
@@ -92,20 +92,20 @@ [email protected] | |||
92 | [email protected] "u8" | 92 | [email protected] "u8" |
93 | [email protected] "," | 93 | [email protected] "," |
94 | [email protected] " " | 94 | [email protected] " " |
95 | ATT[email protected]5 | 95 | PARAM@92..120 |
96 | POUND@92..93 "#" | 96 | ATTR@92..105 |
97 | L_BRACK@93..94 "[" | 97 | POUND@92..93 "#" |
98 | PATH@94..97 | 98 | L_BRACK@93..94 "[" |
99 | PATH_SEGMENT@94..97 | 99 | [email protected] |
100 | NAME_REF@94..97 | 100 | PATH_SEGMENT@94..97 |
101 | IDENT@94..97 "cfg" | 101 | NAME_REF@94..97 |
102 | TOKEN_TREE@97..104 | 102 | IDENT@94..97 "cfg" |
103 | L_PAREN@97..98 "(" | 103 | TOKEN_TREE@97..104 |
104 | IDENT@98..103 "never" | 104 | L_PAREN@97..98 "(" |
105 | R_PAREN@103..104 ")" | 105 | IDENT@98..103 "never" |
106 | R_BRACK@104..105 "]" | 106 | R_PAREN@103..104 ")" |
107 | WHITESPACE@105..106 " " | 107 | R_BRACK@104..105 "]" |
108 | PARAM@106..120 | 108 | WHITESPACE@105..106 " " |
109 | [email protected] | 109 | [email protected] |
110 | [email protected] "[" | 110 | [email protected] "[" |
111 | [email protected] | 111 | [email protected] |
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index cb2ae6fc1..3025dc8d6 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -5,7 +5,7 @@ rust-analyzer.assist.importPrefix (default: `"plain"`):: | |||
5 | rust-analyzer.callInfo.full (default: `true`):: | 5 | rust-analyzer.callInfo.full (default: `true`):: |
6 | Show function name and docs in parameter hints. | 6 | Show function name and docs in parameter hints. |
7 | rust-analyzer.cargo.autoreload (default: `true`):: | 7 | rust-analyzer.cargo.autoreload (default: `true`):: |
8 | Automatically refresh project info via `cargo metadata` on Cargo.toml changes. | 8 | Automatically refresh project info via `cargo metadata` on `Cargo.toml` changes. |
9 | rust-analyzer.cargo.allFeatures (default: `false`):: | 9 | rust-analyzer.cargo.allFeatures (default: `false`):: |
10 | Activate all available features. | 10 | Activate all available features. |
11 | rust-analyzer.cargo.features (default: `[]`):: | 11 | rust-analyzer.cargo.features (default: `[]`):: |
@@ -21,7 +21,7 @@ rust-analyzer.cargo.noSysroot (default: `false`):: | |||
21 | rust-analyzer.checkOnSave.enable (default: `true`):: | 21 | rust-analyzer.checkOnSave.enable (default: `true`):: |
22 | Run specified `cargo check` command for diagnostics on save. | 22 | Run specified `cargo check` command for diagnostics on save. |
23 | rust-analyzer.checkOnSave.allFeatures (default: `null`):: | 23 | rust-analyzer.checkOnSave.allFeatures (default: `null`):: |
24 | Check with all features (will be passed as `--all-features`). Defaults to `rust-analyzer.cargo.allFeatures`. | 24 | Check with all features (will be passed as `--all-features`). Defaults to `#rust-analyzer.cargo.allFeatures#`. |
25 | rust-analyzer.checkOnSave.allTargets (default: `true`):: | 25 | rust-analyzer.checkOnSave.allTargets (default: `true`):: |
26 | Check all targets and tests (will be passed as `--all-targets`). | 26 | Check all targets and tests (will be passed as `--all-targets`). |
27 | rust-analyzer.checkOnSave.command (default: `"check"`):: | 27 | rust-analyzer.checkOnSave.command (default: `"check"`):: |
@@ -29,11 +29,11 @@ rust-analyzer.checkOnSave.command (default: `"check"`):: | |||
29 | rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`):: | 29 | rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`):: |
30 | Do not activate the `default` feature. | 30 | Do not activate the `default` feature. |
31 | rust-analyzer.checkOnSave.target (default: `null`):: | 31 | rust-analyzer.checkOnSave.target (default: `null`):: |
32 | Check for a specific target. Defaults to `rust-analyzer.cargo.target`. | 32 | Check for a specific target. Defaults to `#rust-analyzer.cargo.target#`. |
33 | rust-analyzer.checkOnSave.extraArgs (default: `[]`):: | 33 | rust-analyzer.checkOnSave.extraArgs (default: `[]`):: |
34 | Extra arguments for `cargo check`. | 34 | Extra arguments for `cargo check`. |
35 | rust-analyzer.checkOnSave.features (default: `null`):: | 35 | rust-analyzer.checkOnSave.features (default: `null`):: |
36 | List of features to activate. Defaults to `rust-analyzer.cargo.features`. | 36 | List of features to activate. Defaults to `#rust-analyzer.cargo.features#`. |
37 | rust-analyzer.checkOnSave.overrideCommand (default: `null`):: | 37 | rust-analyzer.checkOnSave.overrideCommand (default: `null`):: |
38 | Advanced option, fully override the command rust-analyzer uses for checking. The command should include `--message-format=json` or similar option. | 38 | Advanced option, fully override the command rust-analyzer uses for checking. The command should include `--message-format=json` or similar option. |
39 | rust-analyzer.completion.addCallArgumentSnippets (default: `true`):: | 39 | rust-analyzer.completion.addCallArgumentSnippets (default: `true`):: |
@@ -43,7 +43,7 @@ rust-analyzer.completion.addCallParenthesis (default: `true`):: | |||
43 | rust-analyzer.completion.postfix.enable (default: `true`):: | 43 | rust-analyzer.completion.postfix.enable (default: `true`):: |
44 | Whether to show postfix snippets like `dbg`, `if`, `not`, etc. | 44 | Whether to show postfix snippets like `dbg`, `if`, `not`, etc. |
45 | rust-analyzer.completion.autoimport.enable (default: `true`):: | 45 | rust-analyzer.completion.autoimport.enable (default: `true`):: |
46 | Toggles the additional completions that automatically add imports when completed. Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. | 46 | Toggles the additional completions that automatically add imports when completed. Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. |
47 | rust-analyzer.diagnostics.enable (default: `true`):: | 47 | rust-analyzer.diagnostics.enable (default: `true`):: |
48 | Whether to show native rust-analyzer diagnostics. | 48 | Whether to show native rust-analyzer diagnostics. |
49 | rust-analyzer.diagnostics.enableExperimental (default: `true`):: | 49 | rust-analyzer.diagnostics.enableExperimental (default: `true`):: |
@@ -51,9 +51,9 @@ rust-analyzer.diagnostics.enableExperimental (default: `true`):: | |||
51 | rust-analyzer.diagnostics.disabled (default: `[]`):: | 51 | rust-analyzer.diagnostics.disabled (default: `[]`):: |
52 | List of rust-analyzer diagnostics to disable. | 52 | List of rust-analyzer diagnostics to disable. |
53 | rust-analyzer.diagnostics.warningsAsHint (default: `[]`):: | 53 | rust-analyzer.diagnostics.warningsAsHint (default: `[]`):: |
54 | List of warnings that should be displayed with info severity.\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel. | 54 | List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the `Problems Panel`. |
55 | rust-analyzer.diagnostics.warningsAsInfo (default: `[]`):: | 55 | rust-analyzer.diagnostics.warningsAsInfo (default: `[]`):: |
56 | List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel. | 56 | List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code and will not show up in the `Problems Panel`. |
57 | rust-analyzer.files.watcher (default: `"client"`):: | 57 | rust-analyzer.files.watcher (default: `"client"`):: |
58 | Controls file watching implementation. | 58 | Controls file watching implementation. |
59 | rust-analyzer.hoverActions.debug (default: `true`):: | 59 | rust-analyzer.hoverActions.debug (default: `true`):: |
@@ -71,7 +71,7 @@ rust-analyzer.hoverActions.linksInHover (default: `true`):: | |||
71 | rust-analyzer.inlayHints.chainingHints (default: `true`):: | 71 | rust-analyzer.inlayHints.chainingHints (default: `true`):: |
72 | Whether to show inlay type hints for method chains. | 72 | Whether to show inlay type hints for method chains. |
73 | rust-analyzer.inlayHints.maxLength (default: `null`):: | 73 | rust-analyzer.inlayHints.maxLength (default: `null`):: |
74 | Maximum length for inlay hints. | 74 | Maximum length for inlay hints. Default is unlimited. |
75 | rust-analyzer.inlayHints.parameterHints (default: `true`):: | 75 | rust-analyzer.inlayHints.parameterHints (default: `true`):: |
76 | Whether to show function parameter name inlay hints at the call site. | 76 | Whether to show function parameter name inlay hints at the call site. |
77 | rust-analyzer.inlayHints.typeHints (default: `true`):: | 77 | rust-analyzer.inlayHints.typeHints (default: `true`):: |
@@ -87,20 +87,20 @@ rust-analyzer.lens.run (default: `true`):: | |||
87 | rust-analyzer.lens.methodReferences (default: `false`):: | 87 | rust-analyzer.lens.methodReferences (default: `false`):: |
88 | Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set. | 88 | Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set. |
89 | rust-analyzer.linkedProjects (default: `[]`):: | 89 | rust-analyzer.linkedProjects (default: `[]`):: |
90 | Disable project auto-discovery in favor of explicitly specified set of projects. \nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format. | 90 | Disable project auto-discovery in favor of explicitly specified set of projects.\n\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format. |
91 | rust-analyzer.lruCapacity (default: `null`):: | 91 | rust-analyzer.lruCapacity (default: `null`):: |
92 | Number of syntax trees rust-analyzer keeps in memory. | 92 | Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. |
93 | rust-analyzer.notifications.cargoTomlNotFound (default: `true`):: | 93 | rust-analyzer.notifications.cargoTomlNotFound (default: `true`):: |
94 | Whether to show `can't find Cargo.toml` error message. | 94 | Whether to show `can't find Cargo.toml` error message. |
95 | rust-analyzer.procMacro.enable (default: `false`):: | 95 | rust-analyzer.procMacro.enable (default: `false`):: |
96 | Enable Proc macro support, cargo.loadOutDirsFromCheck must be enabled. | 96 | Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be enabled. |
97 | rust-analyzer.runnables.overrideCargo (default: `null`):: | 97 | rust-analyzer.runnables.overrideCargo (default: `null`):: |
98 | Command to be executed instead of 'cargo' for runnables. | 98 | Command to be executed instead of 'cargo' for runnables. |
99 | rust-analyzer.runnables.cargoExtraArgs (default: `[]`):: | 99 | rust-analyzer.runnables.cargoExtraArgs (default: `[]`):: |
100 | Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be '--release'. | 100 | Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be `--release`. |
101 | rust-analyzer.rustcSource (default: `null`):: | 101 | rust-analyzer.rustcSource (default: `null`):: |
102 | Path to the rust compiler sources, for usage in rustc_private projects. | 102 | Path to the rust compiler sources, for usage in rustc_private projects. |
103 | rust-analyzer.rustfmt.extraArgs (default: `[]`):: | 103 | rust-analyzer.rustfmt.extraArgs (default: `[]`):: |
104 | Additional arguments to rustfmt. | 104 | Additional arguments to `rustfmt`. |
105 | rust-analyzer.rustfmt.overrideCommand (default: `null`):: | 105 | rust-analyzer.rustfmt.overrideCommand (default: `null`):: |
106 | Advanced option, fully override the command rust-analyzer uses for formatting. | 106 | Advanced option, fully override the command rust-analyzer uses for formatting. |
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 1ec6e81bb..e3082d584 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc | |||
@@ -46,8 +46,8 @@ You can install the latest release of the plugin from | |||
46 | https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. | 46 | https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. |
47 | 47 | ||
48 | Note that the plugin may cause conflicts with the | 48 | Note that the plugin may cause conflicts with the |
49 | https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin]. It is | 49 | https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin]. |
50 | recommended to disable the Rust plugin when using the rust-analyzer extension. | 50 | It is recommended to disable the Rust plugin when using the rust-analyzer extension. |
51 | 51 | ||
52 | By default, the plugin will prompt you to download the matching version of the server as well: | 52 | By default, the plugin will prompt you to download the matching version of the server as well: |
53 | 53 | ||
@@ -74,18 +74,21 @@ Note that we only support two most recent versions of VS Code. | |||
74 | 74 | ||
75 | ==== Updates | 75 | ==== Updates |
76 | 76 | ||
77 | The extension will be updated automatically as new versions become available. It will ask your permission to download the matching language server version binary if needed. | 77 | The extension will be updated automatically as new versions become available. |
78 | It will ask your permission to download the matching language server version binary if needed. | ||
78 | 79 | ||
79 | ===== Nightly | 80 | ===== Nightly |
80 | 81 | ||
81 | We ship nightly releases for VS Code. To help us out with testing the newest code and follow the bleeding edge of our `master`, please use the following config: | 82 | We ship nightly releases for VS Code. |
83 | To help us out with testing the newest code and follow the bleeding edge of our `master`, please use the following config: | ||
82 | 84 | ||
83 | [source,json] | 85 | [source,json] |
84 | ---- | 86 | ---- |
85 | { "rust-analyzer.updates.channel": "nightly" } | 87 | { "rust-analyzer.updates.channel": "nightly" } |
86 | ---- | 88 | ---- |
87 | 89 | ||
88 | You will be prompted to install the `nightly` extension version. Just click `Download now` and from that moment you will get automatic updates every 24 hours. | 90 | You will be prompted to install the `nightly` extension version. |
91 | Just click `Download now` and from that moment you will get automatic updates every 24 hours. | ||
89 | 92 | ||
90 | If you don't want to be asked for `Download now` every day when the new nightly version is released add the following to your `settings.json`: | 93 | If you don't want to be asked for `Download now` every day when the new nightly version is released add the following to your `settings.json`: |
91 | [source,json] | 94 | [source,json] |
@@ -160,7 +163,8 @@ $ chmod +x ~/.local/bin/rust-analyzer | |||
160 | 163 | ||
161 | Ensure `~/.local/bin` is listed in the `$PATH` variable. | 164 | Ensure `~/.local/bin` is listed in the `$PATH` variable. |
162 | 165 | ||
163 | Alternatively, you can install it from source using the following command: | 166 | Alternatively, you can install it from source using the command below. |
167 | You'll need the latest stable version of the Rust toolchain. | ||
164 | 168 | ||
165 | [source,bash] | 169 | [source,bash] |
166 | ---- | 170 | ---- |
@@ -198,7 +202,8 @@ Emacs support is maintained as part of the https://github.com/emacs-lsp/lsp-mode | |||
198 | 202 | ||
199 | === Vim/NeoVim | 203 | === Vim/NeoVim |
200 | 204 | ||
201 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. Not needed if the extension can install/update it on its own, coc-rust-analyzer is one example. | 205 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. |
206 | Not needed if the extension can install/update it on its own, coc-rust-analyzer is one example. | ||
202 | 207 | ||
203 | The are several LSP client implementations for vim or neovim: | 208 | The are several LSP client implementations for vim or neovim: |
204 | 209 | ||
@@ -270,14 +275,16 @@ Once `neovim/nvim-lspconfig` is installed, use `+lua require'nvim_lsp'.rust_anal | |||
270 | 275 | ||
271 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. | 276 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. |
272 | 277 | ||
273 | You also need the `LSP` package. To install it: | 278 | You also need the `LSP` package. |
279 | To install it: | ||
274 | 280 | ||
275 | 1. If you've never installed a Sublime Text package, install Package Control: | 281 | 1. If you've never installed a Sublime Text package, install Package Control: |
276 | * Open the command palette (Win/Linux: `ctrl+shift+p`, Mac: `cmd+shift+p`) | 282 | * Open the command palette (Win/Linux: `ctrl+shift+p`, Mac: `cmd+shift+p`) |
277 | * Type `Install Package Control`, press enter | 283 | * Type `Install Package Control`, press enter |
278 | 2. In the command palette, run `Package control: Install package`, and in the list that pops up, type `LSP` and press enter. | 284 | 2. In the command palette, run `Package control: Install package`, and in the list that pops up, type `LSP` and press enter. |
279 | 285 | ||
280 | Finally, with your Rust project open, in the command palette, run `LSP: Enable Language Server In Project` or `LSP: Enable Language Server Globally`, then select `rust-analyzer` in the list that pops up to enable the rust-analyzer LSP. The latter means that rust-analyzer is enabled by default in Rust projects. | 286 | Finally, with your Rust project open, in the command palette, run `LSP: Enable Language Server In Project` or `LSP: Enable Language Server Globally`, then select `rust-analyzer` in the list that pops up to enable the rust-analyzer LSP. |
287 | The latter means that rust-analyzer is enabled by default in Rust projects. | ||
281 | 288 | ||
282 | If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available. | 289 | If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available. |
283 | 290 | ||
@@ -285,7 +292,8 @@ If you get an error saying `No such file or directory: 'rust-analyzer'`, see the | |||
285 | 292 | ||
286 | === GNOME Builder | 293 | === GNOME Builder |
287 | 294 | ||
288 | GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. If the LSP binary is not available, GNOME Builder can install it when opening a Rust file. | 295 | GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. |
296 | If the LSP binary is not available, GNOME Builder can install it when opening a Rust file. | ||
289 | 297 | ||
290 | == Configuration | 298 | == Configuration |
291 | 299 | ||
@@ -294,6 +302,9 @@ GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. If the LSP bi | |||
294 | rust-analyzer is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files. | 302 | rust-analyzer is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files. |
295 | Please consult your editor's documentation to learn how to configure LSP servers. | 303 | Please consult your editor's documentation to learn how to configure LSP servers. |
296 | 304 | ||
305 | To verify which configuration is actually used by rust-analyzer, set `RA_LOG` environment variable to `rust_analyzer=info` and look for config-related messages. | ||
306 | Logs should show both the JSON that rust-analyzer sees as well as the updated config. | ||
307 | |||
297 | This is the list of config options rust-analyzer supports: | 308 | This is the list of config options rust-analyzer supports: |
298 | 309 | ||
299 | include::./generated_config.adoc[] | 310 | include::./generated_config.adoc[] |
@@ -413,8 +424,8 @@ include::./generated_diagnostic.adoc[] | |||
413 | 424 | ||
414 | ==== Color configurations | 425 | ==== Color configurations |
415 | 426 | ||
416 | It is possible to change the foreground/background color of inlay hints. Just add this to your | 427 | It is possible to change the foreground/background color of inlay hints. |
417 | `settings.json`: | 428 | Just add this to your `settings.json`: |
418 | 429 | ||
419 | [source,jsonc] | 430 | [source,jsonc] |
420 | ---- | 431 | ---- |
@@ -436,7 +447,8 @@ It is possible to change the foreground/background color of inlay hints. Just ad | |||
436 | 447 | ||
437 | ==== Semantic style customizations | 448 | ==== Semantic style customizations |
438 | 449 | ||
439 | You can customize the look of different semantic elements in the source code. For example, mutable bindings are underlined by default and you can override this behavior by adding the following section to your `settings.json`: | 450 | You can customize the look of different semantic elements in the source code. |
451 | For example, mutable bindings are underlined by default and you can override this behavior by adding the following section to your `settings.json`: | ||
440 | 452 | ||
441 | [source,jsonc] | 453 | [source,jsonc] |
442 | ---- | 454 | ---- |
@@ -452,7 +464,9 @@ You can customize the look of different semantic elements in the source code. Fo | |||
452 | ---- | 464 | ---- |
453 | 465 | ||
454 | ==== Special `when` clause context for keybindings. | 466 | ==== Special `when` clause context for keybindings. |
455 | You may use `inRustProject` context to configure keybindings for rust projects only. For example: | 467 | You may use `inRustProject` context to configure keybindings for rust projects only. |
468 | For example: | ||
469 | |||
456 | [source,json] | 470 | [source,json] |
457 | ---- | 471 | ---- |
458 | { | 472 | { |
@@ -491,7 +505,8 @@ Or it is possible to specify vars more granularly: | |||
491 | ] | 505 | ] |
492 | ``` | 506 | ``` |
493 | 507 | ||
494 | You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. | 508 | You can use any valid regular expression as a mask. |
509 | Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. | ||
495 | 510 | ||
496 | ==== Compiler feedback from external commands | 511 | ==== Compiler feedback from external commands |
497 | 512 | ||
diff --git a/editors/code/.vscodeignore b/editors/code/.vscodeignore index 5096ce4da..c1cf00fa0 100644 --- a/editors/code/.vscodeignore +++ b/editors/code/.vscodeignore | |||
@@ -4,6 +4,5 @@ | |||
4 | !package.json | 4 | !package.json |
5 | !package-lock.json | 5 | !package-lock.json |
6 | !ra_syntax_tree.tmGrammar.json | 6 | !ra_syntax_tree.tmGrammar.json |
7 | !rust.tmGrammar.json | ||
8 | !icon.png | 7 | !icon.png |
9 | !README.md | 8 | !README.md |
diff --git a/editors/code/package.json b/editors/code/package.json index ad01fea7b..13749a084 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -250,12 +250,12 @@ | |||
250 | } | 250 | } |
251 | ], | 251 | ], |
252 | "default": null, | 252 | "default": null, |
253 | "description": "Environment variables passed to the runnable launched using `Test ` or `Debug` lens or `rust-analyzer.run` command." | 253 | "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command." |
254 | }, | 254 | }, |
255 | "rust-analyzer.inlayHints.enable": { | 255 | "rust-analyzer.inlayHints.enable": { |
256 | "type": "boolean", | 256 | "type": "boolean", |
257 | "default": true, | 257 | "default": true, |
258 | "description": "Whether to show inlay hints" | 258 | "description": "Whether to show inlay hints." |
259 | }, | 259 | }, |
260 | "rust-analyzer.updates.channel": { | 260 | "rust-analyzer.updates.channel": { |
261 | "type": "string", | 261 | "type": "string", |
@@ -265,15 +265,15 @@ | |||
265 | ], | 265 | ], |
266 | "default": "stable", | 266 | "default": "stable", |
267 | "markdownEnumDescriptions": [ | 267 | "markdownEnumDescriptions": [ |
268 | "`\"stable\"` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general", | 268 | "`stable` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general.", |
269 | "`\"nightly\"` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**" | 269 | "`nightly` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**." |
270 | ], | 270 | ], |
271 | "markdownDescription": "Choose `\"nightly\"` updates to get the latest features and bug fixes every day. While `\"stable\"` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs" | 271 | "markdownDescription": "Choose `nightly` updates to get the latest features and bug fixes every day. While `stable` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs." |
272 | }, | 272 | }, |
273 | "rust-analyzer.updates.askBeforeDownload": { | 273 | "rust-analyzer.updates.askBeforeDownload": { |
274 | "type": "boolean", | 274 | "type": "boolean", |
275 | "default": true, | 275 | "default": true, |
276 | "description": "Whether to ask for permission before downloading any files from the Internet" | 276 | "description": "Whether to ask for permission before downloading any files from the Internet." |
277 | }, | 277 | }, |
278 | "rust-analyzer.serverPath": { | 278 | "rust-analyzer.serverPath": { |
279 | "type": [ | 279 | "type": [ |
@@ -281,7 +281,7 @@ | |||
281 | "string" | 281 | "string" |
282 | ], | 282 | ], |
283 | "default": null, | 283 | "default": null, |
284 | "description": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then \"rust-analyzer.updates.channel\" setting is not used" | 284 | "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then `#rust-analyzer.updates.channel#` setting is not used" |
285 | }, | 285 | }, |
286 | "rust-analyzer.trace.server": { | 286 | "rust-analyzer.trace.server": { |
287 | "type": "string", | 287 | "type": "string", |
@@ -297,10 +297,10 @@ | |||
297 | "Full log" | 297 | "Full log" |
298 | ], | 298 | ], |
299 | "default": "off", | 299 | "default": "off", |
300 | "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)" | 300 | "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)." |
301 | }, | 301 | }, |
302 | "rust-analyzer.trace.extension": { | 302 | "rust-analyzer.trace.extension": { |
303 | "description": "Enable logging of VS Code extensions itself", | 303 | "description": "Enable logging of VS Code extensions itself.", |
304 | "type": "boolean", | 304 | "type": "boolean", |
305 | "default": false | 305 | "default": false |
306 | }, | 306 | }, |
@@ -327,14 +327,14 @@ | |||
327 | } | 327 | } |
328 | }, | 328 | }, |
329 | "rust-analyzer.debug.openDebugPane": { | 329 | "rust-analyzer.debug.openDebugPane": { |
330 | "description": "Whether to open up the Debug Pane on debugging start.", | 330 | "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.", |
331 | "type": "boolean", | 331 | "type": "boolean", |
332 | "default": false | 332 | "default": false |
333 | }, | 333 | }, |
334 | "rust-analyzer.debug.engineSettings": { | 334 | "rust-analyzer.debug.engineSettings": { |
335 | "type": "object", | 335 | "type": "object", |
336 | "default": {}, | 336 | "default": {}, |
337 | "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }" | 337 | "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" |
338 | }, | 338 | }, |
339 | "rust-analyzer.assist.importMergeBehaviour": { | 339 | "rust-analyzer.assist.importMergeBehaviour": { |
340 | "markdownDescription": "The strategy to use when inserting new imports or merging imports.", | 340 | "markdownDescription": "The strategy to use when inserting new imports or merging imports.", |
@@ -362,7 +362,7 @@ | |||
362 | ], | 362 | ], |
363 | "enumDescriptions": [ | 363 | "enumDescriptions": [ |
364 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | 364 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", |
365 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", | 365 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", |
366 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | 366 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." |
367 | ] | 367 | ] |
368 | }, | 368 | }, |
@@ -372,7 +372,7 @@ | |||
372 | "type": "boolean" | 372 | "type": "boolean" |
373 | }, | 373 | }, |
374 | "rust-analyzer.cargo.autoreload": { | 374 | "rust-analyzer.cargo.autoreload": { |
375 | "markdownDescription": "Automatically refresh project info via `cargo metadata` on Cargo.toml changes.", | 375 | "markdownDescription": "Automatically refresh project info via `cargo metadata` on `Cargo.toml` changes.", |
376 | "default": true, | 376 | "default": true, |
377 | "type": "boolean" | 377 | "type": "boolean" |
378 | }, | 378 | }, |
@@ -418,7 +418,7 @@ | |||
418 | "type": "boolean" | 418 | "type": "boolean" |
419 | }, | 419 | }, |
420 | "rust-analyzer.checkOnSave.allFeatures": { | 420 | "rust-analyzer.checkOnSave.allFeatures": { |
421 | "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `rust-analyzer.cargo.allFeatures`.", | 421 | "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `#rust-analyzer.cargo.allFeatures#`.", |
422 | "default": null, | 422 | "default": null, |
423 | "type": [ | 423 | "type": [ |
424 | "null", | 424 | "null", |
@@ -444,7 +444,7 @@ | |||
444 | ] | 444 | ] |
445 | }, | 445 | }, |
446 | "rust-analyzer.checkOnSave.target": { | 446 | "rust-analyzer.checkOnSave.target": { |
447 | "markdownDescription": "Check for a specific target. Defaults to `rust-analyzer.cargo.target`.", | 447 | "markdownDescription": "Check for a specific target. Defaults to `#rust-analyzer.cargo.target#`.", |
448 | "default": null, | 448 | "default": null, |
449 | "type": [ | 449 | "type": [ |
450 | "null", | 450 | "null", |
@@ -460,7 +460,7 @@ | |||
460 | } | 460 | } |
461 | }, | 461 | }, |
462 | "rust-analyzer.checkOnSave.features": { | 462 | "rust-analyzer.checkOnSave.features": { |
463 | "markdownDescription": "List of features to activate. Defaults to `rust-analyzer.cargo.features`.", | 463 | "markdownDescription": "List of features to activate. Defaults to `#rust-analyzer.cargo.features#`.", |
464 | "default": null, | 464 | "default": null, |
465 | "type": [ | 465 | "type": [ |
466 | "null", | 466 | "null", |
@@ -497,7 +497,7 @@ | |||
497 | "type": "boolean" | 497 | "type": "boolean" |
498 | }, | 498 | }, |
499 | "rust-analyzer.completion.autoimport.enable": { | 499 | "rust-analyzer.completion.autoimport.enable": { |
500 | "markdownDescription": "Toggles the additional completions that automatically add imports when completed. Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", | 500 | "markdownDescription": "Toggles the additional completions that automatically add imports when completed. Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", |
501 | "default": true, | 501 | "default": true, |
502 | "type": "boolean" | 502 | "type": "boolean" |
503 | }, | 503 | }, |
@@ -521,7 +521,7 @@ | |||
521 | "uniqueItems": true | 521 | "uniqueItems": true |
522 | }, | 522 | }, |
523 | "rust-analyzer.diagnostics.warningsAsHint": { | 523 | "rust-analyzer.diagnostics.warningsAsHint": { |
524 | "markdownDescription": "List of warnings that should be displayed with info severity.\\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.", | 524 | "markdownDescription": "List of warnings that should be displayed with info severity.\\n\\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the `Problems Panel`.", |
525 | "default": [], | 525 | "default": [], |
526 | "type": "array", | 526 | "type": "array", |
527 | "items": { | 527 | "items": { |
@@ -529,7 +529,7 @@ | |||
529 | } | 529 | } |
530 | }, | 530 | }, |
531 | "rust-analyzer.diagnostics.warningsAsInfo": { | 531 | "rust-analyzer.diagnostics.warningsAsInfo": { |
532 | "markdownDescription": "List of warnings that should be displayed with hint severity.\\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", | 532 | "markdownDescription": "List of warnings that should be displayed with hint severity.\\n\\nThe warnings will be indicated by faded text or three dots in code and will not show up in the `Problems Panel`.", |
533 | "default": [], | 533 | "default": [], |
534 | "type": "array", | 534 | "type": "array", |
535 | "items": { | 535 | "items": { |
@@ -577,7 +577,7 @@ | |||
577 | "type": "boolean" | 577 | "type": "boolean" |
578 | }, | 578 | }, |
579 | "rust-analyzer.inlayHints.maxLength": { | 579 | "rust-analyzer.inlayHints.maxLength": { |
580 | "markdownDescription": "Maximum length for inlay hints.", | 580 | "markdownDescription": "Maximum length for inlay hints. Default is unlimited.", |
581 | "default": null, | 581 | "default": null, |
582 | "type": [ | 582 | "type": [ |
583 | "null", | 583 | "null", |
@@ -621,7 +621,7 @@ | |||
621 | "type": "boolean" | 621 | "type": "boolean" |
622 | }, | 622 | }, |
623 | "rust-analyzer.linkedProjects": { | 623 | "rust-analyzer.linkedProjects": { |
624 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects. \\nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format.", | 624 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects.\\n\\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format.", |
625 | "default": [], | 625 | "default": [], |
626 | "type": "array", | 626 | "type": "array", |
627 | "items": { | 627 | "items": { |
@@ -632,7 +632,7 @@ | |||
632 | } | 632 | } |
633 | }, | 633 | }, |
634 | "rust-analyzer.lruCapacity": { | 634 | "rust-analyzer.lruCapacity": { |
635 | "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory.", | 635 | "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.", |
636 | "default": null, | 636 | "default": null, |
637 | "type": [ | 637 | "type": [ |
638 | "null", | 638 | "null", |
@@ -646,7 +646,7 @@ | |||
646 | "type": "boolean" | 646 | "type": "boolean" |
647 | }, | 647 | }, |
648 | "rust-analyzer.procMacro.enable": { | 648 | "rust-analyzer.procMacro.enable": { |
649 | "markdownDescription": "Enable Proc macro support, cargo.loadOutDirsFromCheck must be enabled.", | 649 | "markdownDescription": "Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be enabled.", |
650 | "default": false, | 650 | "default": false, |
651 | "type": "boolean" | 651 | "type": "boolean" |
652 | }, | 652 | }, |
@@ -659,7 +659,7 @@ | |||
659 | ] | 659 | ] |
660 | }, | 660 | }, |
661 | "rust-analyzer.runnables.cargoExtraArgs": { | 661 | "rust-analyzer.runnables.cargoExtraArgs": { |
662 | "markdownDescription": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\\nFor example, it may be '--release'.", | 662 | "markdownDescription": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\\nFor example, it may be `--release`.", |
663 | "default": [], | 663 | "default": [], |
664 | "type": "array", | 664 | "type": "array", |
665 | "items": { | 665 | "items": { |
@@ -675,7 +675,7 @@ | |||
675 | ] | 675 | ] |
676 | }, | 676 | }, |
677 | "rust-analyzer.rustfmt.extraArgs": { | 677 | "rust-analyzer.rustfmt.extraArgs": { |
678 | "markdownDescription": "Additional arguments to rustfmt.", | 678 | "markdownDescription": "Additional arguments to `rustfmt`.", |
679 | "default": [], | 679 | "default": [], |
680 | "type": "array", | 680 | "type": "array", |
681 | "items": { | 681 | "items": { |
@@ -749,11 +749,6 @@ | |||
749 | ], | 749 | ], |
750 | "grammars": [ | 750 | "grammars": [ |
751 | { | 751 | { |
752 | "language": "rust", | ||
753 | "scopeName": "source.rust", | ||
754 | "path": "rust.tmGrammar.json" | ||
755 | }, | ||
756 | { | ||
757 | "language": "ra_syntax_tree", | 752 | "language": "ra_syntax_tree", |
758 | "scopeName": "source.ra_syntax_tree", | 753 | "scopeName": "source.ra_syntax_tree", |
759 | "path": "ra_syntax_tree.tmGrammar.json" | 754 | "path": "ra_syntax_tree.tmGrammar.json" |
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json deleted file mode 100644 index 4759bb116..000000000 --- a/editors/code/rust.tmGrammar.json +++ /dev/null | |||
@@ -1,1140 +0,0 @@ | |||
1 | { | ||
2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", | ||
3 | "name": "Rust", | ||
4 | "fileTypes": [ | ||
5 | "rs" | ||
6 | ], | ||
7 | "scopeName": "source.rust", | ||
8 | "patterns": [ | ||
9 | { | ||
10 | "comment": "boxed slice literal", | ||
11 | "begin": "(<)(\\[)", | ||
12 | "beginCaptures": { | ||
13 | "1": { | ||
14 | "name": "punctuation.brackets.angle.rust" | ||
15 | }, | ||
16 | "2": { | ||
17 | "name": "punctuation.brackets.square.rust" | ||
18 | } | ||
19 | }, | ||
20 | "end": ">", | ||
21 | "endCaptures": { | ||
22 | "0": { | ||
23 | "name": "punctuation.brackets.angle.rust" | ||
24 | } | ||
25 | }, | ||
26 | "patterns": [ | ||
27 | { | ||
28 | "include": "#block-comments" | ||
29 | }, | ||
30 | { | ||
31 | "include": "#comments" | ||
32 | }, | ||
33 | { | ||
34 | "include": "#gtypes" | ||
35 | }, | ||
36 | { | ||
37 | "include": "#lvariables" | ||
38 | }, | ||
39 | { | ||
40 | "include": "#lifetimes" | ||
41 | }, | ||
42 | { | ||
43 | "include": "#punctuation" | ||
44 | }, | ||
45 | { | ||
46 | "include": "#types" | ||
47 | } | ||
48 | ] | ||
49 | }, | ||
50 | { | ||
51 | "comment": "macro type metavariables", | ||
52 | "name": "meta.macro.metavariable.type.rust", | ||
53 | "match": "(\\$)((crate)|([A-Z][A-Za-z0-9_]*))((:)(block|expr|ident|item|lifetime|literal|meta|path?|stmt|tt|ty|vis))?", | ||
54 | "captures": { | ||
55 | "1": { | ||
56 | "name": "keyword.operator.macro.dollar.rust" | ||
57 | }, | ||
58 | "3": { | ||
59 | "name": "keyword.other.crate.rust" | ||
60 | }, | ||
61 | "4": { | ||
62 | "name": "entity.name.type.metavariable.rust" | ||
63 | }, | ||
64 | "6": { | ||
65 | "name": "keyword.operator.key-value.rust" | ||
66 | }, | ||
67 | "7": { | ||
68 | "name": "variable.other.metavariable.specifier.rust" | ||
69 | } | ||
70 | }, | ||
71 | "patterns": [ | ||
72 | { | ||
73 | "include": "#keywords" | ||
74 | } | ||
75 | ] | ||
76 | }, | ||
77 | { | ||
78 | "comment": "macro metavariables", | ||
79 | "name": "meta.macro.metavariable.rust", | ||
80 | "match": "(\\$)([a-z][A-Za-z0-9_]*)((:)(block|expr|ident|item|lifetime|literal|meta|path?|stmt|tt|ty|vis))?", | ||
81 | "captures": { | ||
82 | "1": { | ||
83 | "name": "keyword.operator.macro.dollar.rust" | ||
84 | }, | ||
85 | "2": { | ||
86 | "name": "variable.other.metavariable.name.rust" | ||
87 | }, | ||
88 | "4": { | ||
89 | "name": "keyword.operator.key-value.rust" | ||
90 | }, | ||
91 | "5": { | ||
92 | "name": "variable.other.metavariable.specifier.rust" | ||
93 | } | ||
94 | }, | ||
95 | "patterns": [ | ||
96 | { | ||
97 | "include": "#keywords" | ||
98 | } | ||
99 | ] | ||
100 | }, | ||
101 | { | ||
102 | "comment": "macro rules", | ||
103 | "name": "meta.macro.rules.rust", | ||
104 | "match": "\\b(macro_rules!)\\s+(([a-z0-9_]+)|([A-Z][a-z0-9_]*))\\s+(\\{)", | ||
105 | "captures": { | ||
106 | "1": { | ||
107 | "name": "entity.name.function.macro.rules.rust" | ||
108 | }, | ||
109 | "3": { | ||
110 | "name": "entity.name.function.macro.rust" | ||
111 | }, | ||
112 | "4": { | ||
113 | "name": "entity.name.type.macro.rust" | ||
114 | }, | ||
115 | "5": { | ||
116 | "name": "punctuation.brackets.curly.rust" | ||
117 | } | ||
118 | } | ||
119 | }, | ||
120 | { | ||
121 | "comment": "attributes", | ||
122 | "name": "meta.attribute.rust", | ||
123 | "begin": "(#)(\\!?)(\\[)", | ||
124 | "beginCaptures": { | ||
125 | "1": { | ||
126 | "name": "punctuation.definition.attribute.rust" | ||
127 | }, | ||
128 | "2": { | ||
129 | "name": "keyword.operator.attribute.inner.rust" | ||
130 | }, | ||
131 | "3": { | ||
132 | "name": "punctuation.brackets.attribute.rust" | ||
133 | } | ||
134 | }, | ||
135 | "end": "\\]", | ||
136 | "endCaptures": { | ||
137 | "0": { | ||
138 | "name": "punctuation.brackets.attribute.rust" | ||
139 | } | ||
140 | }, | ||
141 | "patterns": [ | ||
142 | { | ||
143 | "include": "#block-comments" | ||
144 | }, | ||
145 | { | ||
146 | "include": "#comments" | ||
147 | }, | ||
148 | { | ||
149 | "include": "#keywords" | ||
150 | }, | ||
151 | { | ||
152 | "include": "#punctuation" | ||
153 | }, | ||
154 | { | ||
155 | "include": "#strings" | ||
156 | }, | ||
157 | { | ||
158 | "include": "#gtypes" | ||
159 | }, | ||
160 | { | ||
161 | "include": "#types" | ||
162 | } | ||
163 | ] | ||
164 | }, | ||
165 | { | ||
166 | "comment": "modules", | ||
167 | "match": "(mod)\\s+((?:r#(?!crate|[Ss]elf|super))?[a-z][A-Za-z0-9_]*)", | ||
168 | "captures": { | ||
169 | "1": { | ||
170 | "name": "storage.type.rust" | ||
171 | }, | ||
172 | "2": { | ||
173 | "name": "entity.name.module.rust" | ||
174 | } | ||
175 | } | ||
176 | }, | ||
177 | { | ||
178 | "comment": "external crate imports", | ||
179 | "name": "meta.import.rust", | ||
180 | "begin": "\\b(extern)\\s+(crate)", | ||
181 | "beginCaptures": { | ||
182 | "1": { | ||
183 | "name": "storage.type.rust" | ||
184 | }, | ||
185 | "2": { | ||
186 | "name": "keyword.other.crate.rust" | ||
187 | } | ||
188 | }, | ||
189 | "end": ";", | ||
190 | "endCaptures": { | ||
191 | "0": { | ||
192 | "name": "punctuation.semi.rust" | ||
193 | } | ||
194 | }, | ||
195 | "patterns": [ | ||
196 | { | ||
197 | "include": "#block-comments" | ||
198 | }, | ||
199 | { | ||
200 | "include": "#comments" | ||
201 | }, | ||
202 | { | ||
203 | "include": "#keywords" | ||
204 | }, | ||
205 | { | ||
206 | "include": "#punctuation" | ||
207 | } | ||
208 | ] | ||
209 | }, | ||
210 | { | ||
211 | "comment": "use statements", | ||
212 | "name": "meta.use.rust", | ||
213 | "begin": "\\b(use)\\s", | ||
214 | "beginCaptures": { | ||
215 | "1": { | ||
216 | "name": "keyword.other.rust" | ||
217 | } | ||
218 | }, | ||
219 | "end": ";", | ||
220 | "endCaptures": { | ||
221 | "0": { | ||
222 | "name": "punctuation.semi.rust" | ||
223 | } | ||
224 | }, | ||
225 | "patterns": [ | ||
226 | { | ||
227 | "include": "#block-comments" | ||
228 | }, | ||
229 | { | ||
230 | "include": "#comments" | ||
231 | }, | ||
232 | { | ||
233 | "include": "#keywords" | ||
234 | }, | ||
235 | { | ||
236 | "include": "#namespaces" | ||
237 | }, | ||
238 | { | ||
239 | "include": "#punctuation" | ||
240 | }, | ||
241 | { | ||
242 | "include": "#types" | ||
243 | }, | ||
244 | { | ||
245 | "include": "#lvariables" | ||
246 | } | ||
247 | ] | ||
248 | }, | ||
249 | { | ||
250 | "include": "#block-comments" | ||
251 | }, | ||
252 | { | ||
253 | "include": "#comments" | ||
254 | }, | ||
255 | { | ||
256 | "include": "#lvariables" | ||
257 | }, | ||
258 | { | ||
259 | "include": "#constants" | ||
260 | }, | ||
261 | { | ||
262 | "include": "#gtypes" | ||
263 | }, | ||
264 | { | ||
265 | "include": "#functions" | ||
266 | }, | ||
267 | { | ||
268 | "include": "#types" | ||
269 | }, | ||
270 | { | ||
271 | "include": "#keywords" | ||
272 | }, | ||
273 | { | ||
274 | "include": "#lifetimes" | ||
275 | }, | ||
276 | { | ||
277 | "include": "#macros" | ||
278 | }, | ||
279 | { | ||
280 | "include": "#namespaces" | ||
281 | }, | ||
282 | { | ||
283 | "include": "#punctuation" | ||
284 | }, | ||
285 | { | ||
286 | "include": "#strings" | ||
287 | }, | ||
288 | { | ||
289 | "include": "#variables" | ||
290 | } | ||
291 | ], | ||
292 | "repository": { | ||
293 | "comments": { | ||
294 | "patterns": [ | ||
295 | { | ||
296 | "comment": "documentation comments", | ||
297 | "name": "comment.line.documentation.rust", | ||
298 | "match": "^\\s*///.*" | ||
299 | }, | ||
300 | { | ||
301 | "comment": "line comments", | ||
302 | "name": "comment.line.double-slash.rust", | ||
303 | "match": "\\s*//.*" | ||
304 | } | ||
305 | ] | ||
306 | }, | ||
307 | "block-comments": { | ||
308 | "patterns": [ | ||
309 | { | ||
310 | "comment": "empty block comments", | ||
311 | "name": "comment.block.rust", | ||
312 | "match": "/\\*\\*/" | ||
313 | }, | ||
314 | { | ||
315 | "comment": "block documentation comments", | ||
316 | "name": "comment.block.documentation.rust", | ||
317 | "begin": "/\\*\\*", | ||
318 | "end": "\\*/", | ||
319 | "patterns": [ | ||
320 | { | ||
321 | "include": "#block-comments" | ||
322 | } | ||
323 | ] | ||
324 | }, | ||
325 | { | ||
326 | "comment": "block comments", | ||
327 | "name": "comment.block.rust", | ||
328 | "begin": "/\\*(?!\\*)", | ||
329 | "end": "\\*/", | ||
330 | "patterns": [ | ||
331 | { | ||
332 | "include": "#block-comments" | ||
333 | } | ||
334 | ] | ||
335 | } | ||
336 | ] | ||
337 | }, | ||
338 | "constants": { | ||
339 | "patterns": [ | ||
340 | { | ||
341 | "comment": "ALL CAPS constants", | ||
342 | "name": "constant.other.caps.rust", | ||
343 | "match": "\\b[A-Z]{2}[A-Z0-9_]*\\b" | ||
344 | }, | ||
345 | { | ||
346 | "comment": "constant declarations", | ||
347 | "match": "\\b(const)\\s+([A-Z][A-Za-z0-9_]*)\\b", | ||
348 | "captures": { | ||
349 | "1": { | ||
350 | "name": "storage.type.rust" | ||
351 | }, | ||
352 | "2": { | ||
353 | "name": "constant.other.caps.rust" | ||
354 | } | ||
355 | } | ||
356 | }, | ||
357 | { | ||
358 | "comment": "decimal integers and floats", | ||
359 | "name": "constant.numeric.decimal.rust", | ||
360 | "match": "\\b\\d[\\d_]*(\\.?)[\\d_]*(?:(E)([+-])([\\d_]+))?(f32|f64|i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", | ||
361 | "captures": { | ||
362 | "1": { | ||
363 | "name": "punctuation.separator.dot.decimal.rust" | ||
364 | }, | ||
365 | "2": { | ||
366 | "name": "keyword.operator.exponent.rust" | ||
367 | }, | ||
368 | "3": { | ||
369 | "name": "keyword.operator.exponent.sign.rust" | ||
370 | }, | ||
371 | "4": { | ||
372 | "name": "constant.numeric.decimal.exponent.mantissa.rust" | ||
373 | }, | ||
374 | "5": { | ||
375 | "name": "entity.name.type.numeric.rust" | ||
376 | } | ||
377 | } | ||
378 | }, | ||
379 | { | ||
380 | "comment": "hexadecimal integers", | ||
381 | "name": "constant.numeric.hex.rust", | ||
382 | "match": "\\b0x[\\da-fA-F_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", | ||
383 | "captures": { | ||
384 | "1": { | ||
385 | "name": "entity.name.type.numeric.rust" | ||
386 | } | ||
387 | } | ||
388 | }, | ||
389 | { | ||
390 | "comment": "octal integers", | ||
391 | "name": "constant.numeric.oct.rust", | ||
392 | "match": "\\b0o[0-7_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", | ||
393 | "captures": { | ||
394 | "1": { | ||
395 | "name": "entity.name.type.numeric.rust" | ||
396 | } | ||
397 | } | ||
398 | }, | ||
399 | { | ||
400 | "comment": "binary integers", | ||
401 | "name": "constant.numeric.bin.rust", | ||
402 | "match": "\\b0b[01_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", | ||
403 | "captures": { | ||
404 | "1": { | ||
405 | "name": "entity.name.type.numeric.rust" | ||
406 | } | ||
407 | } | ||
408 | }, | ||
409 | { | ||
410 | "comment": "booleans", | ||
411 | "name": "constant.language.bool.rust", | ||
412 | "match": "\\b(true|false)\\b" | ||
413 | } | ||
414 | ] | ||
415 | }, | ||
416 | "escapes": { | ||
417 | "comment": "escapes: ASCII, byte, Unicode, quote, regex", | ||
418 | "name": "constant.character.escape.rust", | ||
419 | "match": "(\\\\)(?:(?:(x[0-7][0-7a-fA-F])|(u(\\{)[\\da-fA-F]{4,6}(\\}))|.))", | ||
420 | "captures": { | ||
421 | "1": { | ||
422 | "name": "constant.character.escape.backslash.rust" | ||
423 | }, | ||
424 | "2": { | ||
425 | "name": "constant.character.escape.bit.rust" | ||
426 | }, | ||
427 | "3": { | ||
428 | "name": "constant.character.escape.unicode.rust" | ||
429 | }, | ||
430 | "4": { | ||
431 | "name": "constant.character.escape.unicode.punctuation.rust" | ||
432 | }, | ||
433 | "5": { | ||
434 | "name": "constant.character.escape.unicode.punctuation.rust" | ||
435 | } | ||
436 | } | ||
437 | }, | ||
438 | "functions": { | ||
439 | "patterns": [ | ||
440 | { | ||
441 | "comment": "pub as a function", | ||
442 | "match": "\\b(pub)(\\()", | ||
443 | "captures": { | ||
444 | "1": { | ||
445 | "name": "keyword.other.rust" | ||
446 | }, | ||
447 | "2": { | ||
448 | "name": "punctuation.brackets.round.rust" | ||
449 | } | ||
450 | } | ||
451 | }, | ||
452 | { | ||
453 | "comment": "function definition", | ||
454 | "name": "meta.function.definition.rust", | ||
455 | "begin": "\\b(fn)\\s+((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)((\\()|(<))", | ||
456 | "beginCaptures": { | ||
457 | "1": { | ||
458 | "name": "keyword.other.fn.rust" | ||
459 | }, | ||
460 | "2": { | ||
461 | "name": "entity.name.function.rust" | ||
462 | }, | ||
463 | "4": { | ||
464 | "name": "punctuation.brackets.round.rust" | ||
465 | }, | ||
466 | "5": { | ||
467 | "name": "punctuation.brackets.angle.rust" | ||
468 | } | ||
469 | }, | ||
470 | "end": "\\{|;", | ||
471 | "endCaptures": { | ||
472 | "0": { | ||
473 | "name": "punctuation.brackets.curly.rust" | ||
474 | } | ||
475 | }, | ||
476 | "patterns": [ | ||
477 | { | ||
478 | "include": "#block-comments" | ||
479 | }, | ||
480 | { | ||
481 | "include": "#comments" | ||
482 | }, | ||
483 | { | ||
484 | "include": "#keywords" | ||
485 | }, | ||
486 | { | ||
487 | "include": "#lvariables" | ||
488 | }, | ||
489 | { | ||
490 | "include": "#constants" | ||
491 | }, | ||
492 | { | ||
493 | "include": "#gtypes" | ||
494 | }, | ||
495 | { | ||
496 | "include": "#functions" | ||
497 | }, | ||
498 | { | ||
499 | "include": "#lifetimes" | ||
500 | }, | ||
501 | { | ||
502 | "include": "#macros" | ||
503 | }, | ||
504 | { | ||
505 | "include": "#namespaces" | ||
506 | }, | ||
507 | { | ||
508 | "include": "#punctuation" | ||
509 | }, | ||
510 | { | ||
511 | "include": "#strings" | ||
512 | }, | ||
513 | { | ||
514 | "include": "#types" | ||
515 | }, | ||
516 | { | ||
517 | "include": "#variables" | ||
518 | } | ||
519 | ] | ||
520 | }, | ||
521 | { | ||
522 | "comment": "function/method calls, chaining", | ||
523 | "name": "meta.function.call.rust", | ||
524 | "begin": "((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)(\\()", | ||
525 | "beginCaptures": { | ||
526 | "1": { | ||
527 | "name": "entity.name.function.rust" | ||
528 | }, | ||
529 | "2": { | ||
530 | "name": "punctuation.brackets.round.rust" | ||
531 | } | ||
532 | }, | ||
533 | "end": "\\)", | ||
534 | "endCaptures": { | ||
535 | "0": { | ||
536 | "name": "punctuation.brackets.round.rust" | ||
537 | } | ||
538 | }, | ||
539 | "patterns": [ | ||
540 | { | ||
541 | "include": "#block-comments" | ||
542 | }, | ||
543 | { | ||
544 | "include": "#comments" | ||
545 | }, | ||
546 | { | ||
547 | "include": "#keywords" | ||
548 | }, | ||
549 | { | ||
550 | "include": "#lvariables" | ||
551 | }, | ||
552 | { | ||
553 | "include": "#constants" | ||
554 | }, | ||
555 | { | ||
556 | "include": "#gtypes" | ||
557 | }, | ||
558 | { | ||
559 | "include": "#functions" | ||
560 | }, | ||
561 | { | ||
562 | "include": "#lifetimes" | ||
563 | }, | ||
564 | { | ||
565 | "include": "#macros" | ||
566 | }, | ||
567 | { | ||
568 | "include": "#namespaces" | ||
569 | }, | ||
570 | { | ||
571 | "include": "#punctuation" | ||
572 | }, | ||
573 | { | ||
574 | "include": "#strings" | ||
575 | }, | ||
576 | { | ||
577 | "include": "#types" | ||
578 | }, | ||
579 | { | ||
580 | "include": "#variables" | ||
581 | } | ||
582 | ] | ||
583 | }, | ||
584 | { | ||
585 | "comment": "function/method calls with turbofish", | ||
586 | "name": "meta.function.call.rust", | ||
587 | "begin": "((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)(?=::<.*>\\()", | ||
588 | "beginCaptures": { | ||
589 | "1": { | ||
590 | "name": "entity.name.function.rust" | ||
591 | } | ||
592 | }, | ||
593 | "end": "\\)", | ||
594 | "endCaptures": { | ||
595 | "0": { | ||
596 | "name": "punctuation.brackets.round.rust" | ||
597 | } | ||
598 | }, | ||
599 | "patterns": [ | ||
600 | { | ||
601 | "include": "#block-comments" | ||
602 | }, | ||
603 | { | ||
604 | "include": "#comments" | ||
605 | }, | ||
606 | { | ||
607 | "include": "#keywords" | ||
608 | }, | ||
609 | { | ||
610 | "include": "#lvariables" | ||
611 | }, | ||
612 | { | ||
613 | "include": "#constants" | ||
614 | }, | ||
615 | { | ||
616 | "include": "#gtypes" | ||
617 | }, | ||
618 | { | ||
619 | "include": "#functions" | ||
620 | }, | ||
621 | { | ||
622 | "include": "#lifetimes" | ||
623 | }, | ||
624 | { | ||
625 | "include": "#macros" | ||
626 | }, | ||
627 | { | ||
628 | "include": "#namespaces" | ||
629 | }, | ||
630 | { | ||
631 | "include": "#punctuation" | ||
632 | }, | ||
633 | { | ||
634 | "include": "#strings" | ||
635 | }, | ||
636 | { | ||
637 | "include": "#types" | ||
638 | }, | ||
639 | { | ||
640 | "include": "#variables" | ||
641 | } | ||
642 | ] | ||
643 | } | ||
644 | ] | ||
645 | }, | ||
646 | "keywords": { | ||
647 | "patterns": [ | ||
648 | { | ||
649 | "comment": "control flow keywords", | ||
650 | "name": "keyword.control.rust", | ||
651 | "match": "\\b(await|break|continue|do|else|for|if|loop|match|return|try|while|yield)\\b" | ||
652 | }, | ||
653 | { | ||
654 | "comment": "storage keywords", | ||
655 | "name": "storage.type.rust", | ||
656 | "match": "\\b(const|enum|extern|let|macro|mod|struct|trait|type)\\b" | ||
657 | }, | ||
658 | { | ||
659 | "comment": "storage modifiers", | ||
660 | "name": "storage.modifier.rust", | ||
661 | "match": "\\b(abstract|static)\\b" | ||
662 | }, | ||
663 | { | ||
664 | "comment": "other keywords", | ||
665 | "name": "keyword.other.rust", | ||
666 | "match": "\\b(as|async|become|box|dyn|move|final|impl|in|override|priv|pub|ref|typeof|union|unsafe|unsized|use|virtual|where)\\b" | ||
667 | }, | ||
668 | { | ||
669 | "comment": "fn", | ||
670 | "name": "keyword.other.fn.rust", | ||
671 | "match": "\\bfn\\b" | ||
672 | }, | ||
673 | { | ||
674 | "comment": "crate", | ||
675 | "name": "keyword.other.crate.rust", | ||
676 | "match": "\\bcrate\\b" | ||
677 | }, | ||
678 | { | ||
679 | "comment": "mut", | ||
680 | "name": "storage.modifier.mut.rust", | ||
681 | "match": "\\bmut\\b" | ||
682 | }, | ||
683 | { | ||
684 | "comment": "logical operators", | ||
685 | "name": "keyword.operator.logical.rust", | ||
686 | "match": "(\\^|\\||\\|\\||&&|<<|>>|!)(?!=)" | ||
687 | }, | ||
688 | { | ||
689 | "comment": "logical AND, borrow references", | ||
690 | "name": "keyword.operator.borrow.and.rust", | ||
691 | "match": "&(?![&=])" | ||
692 | }, | ||
693 | { | ||
694 | "comment": "assignment operators", | ||
695 | "name": "keyword.operator.assignment.rust", | ||
696 | "match": "(\\+=|-=|\\*=|/=|%=|\\^=|&=|\\|=|<<=|>>=)" | ||
697 | }, | ||
698 | { | ||
699 | "comment": "single equal", | ||
700 | "name": "keyword.operator.assignment.equal.rust", | ||
701 | "match": "(?<![<>])=(?!=|>)" | ||
702 | }, | ||
703 | { | ||
704 | "comment": "comparison operators", | ||
705 | "name": "keyword.operator.comparison.rust", | ||
706 | "match": "(=(=)?(?!>)|!=|<=|(?<!=)>=)" | ||
707 | }, | ||
708 | { | ||
709 | "comment": "math operators", | ||
710 | "name": "keyword.operator.math.rust", | ||
711 | "match": "(([+%]|(\\*(?!\\w)))(?!=))|(-(?!>))|(/(?!/))" | ||
712 | }, | ||
713 | { | ||
714 | "comment": "less than, greater than (special case)", | ||
715 | "match": "(?:\\b|(?:(\\))|(\\])|(\\})))[ \\t]+([<>])[ \\t]+(?:\\b|(?:(\\()|(\\[)|(\\{)))", | ||
716 | "captures": { | ||
717 | "1": { | ||
718 | "name": "punctuation.brackets.round.rust" | ||
719 | }, | ||
720 | "2": { | ||
721 | "name": "punctuation.brackets.square.rust" | ||
722 | }, | ||
723 | "3": { | ||
724 | "name": "punctuation.brackets.curly.rust" | ||
725 | }, | ||
726 | "4": { | ||
727 | "name": "keyword.operator.comparison.rust" | ||
728 | }, | ||
729 | "5": { | ||
730 | "name": "punctuation.brackets.round.rust" | ||
731 | }, | ||
732 | "6": { | ||
733 | "name": "punctuation.brackets.square.rust" | ||
734 | }, | ||
735 | "7": { | ||
736 | "name": "punctuation.brackets.curly.rust" | ||
737 | } | ||
738 | } | ||
739 | }, | ||
740 | { | ||
741 | "comment": "namespace operator", | ||
742 | "name": "keyword.operator.namespace.rust", | ||
743 | "match": "::" | ||
744 | }, | ||
745 | { | ||
746 | "comment": "dereference asterisk", | ||
747 | "match": "(\\*)(?=\\w+)", | ||
748 | "captures": { | ||
749 | "1": { | ||
750 | "name": "keyword.operator.dereference.rust" | ||
751 | } | ||
752 | } | ||
753 | }, | ||
754 | { | ||
755 | "comment": "subpattern binding", | ||
756 | "name": "keyword.operator.subpattern.rust", | ||
757 | "match": "@" | ||
758 | }, | ||
759 | { | ||
760 | "comment": "dot access", | ||
761 | "name": "keyword.operator.access.dot.rust", | ||
762 | "match": "\\.(?!\\.)" | ||
763 | }, | ||
764 | { | ||
765 | "comment": "ranges, range patterns", | ||
766 | "name": "keyword.operator.range.rust", | ||
767 | "match": "\\.{2}(=|\\.)?" | ||
768 | }, | ||
769 | { | ||
770 | "comment": "colon", | ||
771 | "name": "keyword.operator.key-value.rust", | ||
772 | "match": ":(?!:)" | ||
773 | }, | ||
774 | { | ||
775 | "comment": "dashrocket, skinny arrow", | ||
776 | "name": "keyword.operator.arrow.skinny.rust", | ||
777 | "match": "->" | ||
778 | }, | ||
779 | { | ||
780 | "comment": "hashrocket, fat arrow", | ||
781 | "name": "keyword.operator.arrow.fat.rust", | ||
782 | "match": "=>" | ||
783 | }, | ||
784 | { | ||
785 | "comment": "dollar macros", | ||
786 | "name": "keyword.operator.macro.dollar.rust", | ||
787 | "match": "\\$" | ||
788 | }, | ||
789 | { | ||
790 | "comment": "question mark operator, questionably sized, macro kleene matcher", | ||
791 | "name": "keyword.operator.question.rust", | ||
792 | "match": "\\?" | ||
793 | } | ||
794 | ] | ||
795 | }, | ||
796 | "interpolations": { | ||
797 | "comment": "curly brace interpolations", | ||
798 | "name": "meta.interpolation.rust", | ||
799 | "match": "({)[^\"{}]*(})", | ||
800 | "captures": { | ||
801 | "1": { | ||
802 | "name": "punctuation.definition.interpolation.rust" | ||
803 | }, | ||
804 | "2": { | ||
805 | "name": "punctuation.definition.interpolation.rust" | ||
806 | } | ||
807 | } | ||
808 | }, | ||
809 | "lifetimes": { | ||
810 | "patterns": [ | ||
811 | { | ||
812 | "comment": "named lifetime parameters", | ||
813 | "match": "(['])([a-zA-Z_][0-9a-zA-Z_]*)(?!['])\\b", | ||
814 | "captures": { | ||
815 | "1": { | ||
816 | "name": "punctuation.definition.lifetime.rust" | ||
817 | }, | ||
818 | "2": { | ||
819 | "name": "entity.name.type.lifetime.rust" | ||
820 | } | ||
821 | } | ||
822 | }, | ||
823 | { | ||
824 | "comment": "borrowing references to named lifetimes", | ||
825 | "match": "(\\&)(['])([a-zA-Z_][0-9a-zA-Z_]*)(?!['])\\b", | ||
826 | "captures": { | ||
827 | "1": { | ||
828 | "name": "keyword.operator.borrow.rust" | ||
829 | }, | ||
830 | "2": { | ||
831 | "name": "punctuation.definition.lifetime.rust" | ||
832 | }, | ||
833 | "3": { | ||
834 | "name": "entity.name.type.lifetime.rust" | ||
835 | } | ||
836 | } | ||
837 | } | ||
838 | ] | ||
839 | }, | ||
840 | "macros": { | ||
841 | "patterns": [ | ||
842 | { | ||
843 | "comment": "macros", | ||
844 | "name": "meta.macro.rust", | ||
845 | "match": "(([a-z_][A-Za-z0-9_]*!)|([A-Z_][A-Za-z0-9_]*!))", | ||
846 | "captures": { | ||
847 | "2": { | ||
848 | "name": "entity.name.function.macro.rust" | ||
849 | }, | ||
850 | "3": { | ||
851 | "name": "entity.name.type.macro.rust" | ||
852 | } | ||
853 | } | ||
854 | } | ||
855 | ] | ||
856 | }, | ||
857 | "namespaces": { | ||
858 | "patterns": [ | ||
859 | { | ||
860 | "comment": "namespace (non-type, non-function path segment)", | ||
861 | "match": "(?<![A-Za-z0-9_])([a-z0-9_]+)((?<!super|self)::)", | ||
862 | "captures": { | ||
863 | "1": { | ||
864 | "name": "entity.name.namespace.rust" | ||
865 | }, | ||
866 | "2": { | ||
867 | "name": "keyword.operator.namespace.rust" | ||
868 | } | ||
869 | } | ||
870 | } | ||
871 | ] | ||
872 | }, | ||
873 | "types": { | ||
874 | "patterns": [ | ||
875 | { | ||
876 | "comment": "numeric types", | ||
877 | "match": "(?<![A-Za-z])(f32|f64|i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)\\b", | ||
878 | "captures": { | ||
879 | "1": { | ||
880 | "name": "entity.name.type.numeric.rust" | ||
881 | } | ||
882 | } | ||
883 | }, | ||
884 | { | ||
885 | "comment": "parameterized types", | ||
886 | "begin": "\\b([A-Z][A-Za-z0-9]*)(<)", | ||
887 | "beginCaptures": { | ||
888 | "1": { | ||
889 | "name": "entity.name.type.rust" | ||
890 | }, | ||
891 | "2": { | ||
892 | "name": "punctuation.brackets.angle.rust" | ||
893 | } | ||
894 | }, | ||
895 | "end": ">", | ||
896 | "endCaptures": { | ||
897 | "0": { | ||
898 | "name": "punctuation.brackets.angle.rust" | ||
899 | } | ||
900 | }, | ||
901 | "patterns": [ | ||
902 | { | ||
903 | "include": "#block-comments" | ||
904 | }, | ||
905 | { | ||
906 | "include": "#comments" | ||
907 | }, | ||
908 | { | ||
909 | "include": "#keywords" | ||
910 | }, | ||
911 | { | ||
912 | "include": "#lvariables" | ||
913 | }, | ||
914 | { | ||
915 | "include": "#lifetimes" | ||
916 | }, | ||
917 | { | ||
918 | "include": "#punctuation" | ||
919 | }, | ||
920 | { | ||
921 | "include": "#types" | ||
922 | }, | ||
923 | { | ||
924 | "include": "#variables" | ||
925 | } | ||
926 | ] | ||
927 | }, | ||
928 | { | ||
929 | "comment": "primitive types", | ||
930 | "name": "entity.name.type.primitive.rust", | ||
931 | "match": "\\b(bool|char|str)\\b" | ||
932 | }, | ||
933 | { | ||
934 | "comment": "trait declarations", | ||
935 | "match": "\\b(trait)\\s+([A-Z][A-Za-z0-9]*)\\b", | ||
936 | "captures": { | ||
937 | "1": { | ||
938 | "name": "storage.type.rust" | ||
939 | }, | ||
940 | "2": { | ||
941 | "name": "entity.name.type.trait.rust" | ||
942 | } | ||
943 | } | ||
944 | }, | ||
945 | { | ||
946 | "comment": "struct declarations", | ||
947 | "match": "\\b(struct)\\s+([A-Z][A-Za-z0-9]*)\\b", | ||
948 | "captures": { | ||
949 | "1": { | ||
950 | "name": "storage.type.rust" | ||
951 | }, | ||
952 | "2": { | ||
953 | "name": "entity.name.type.struct.rust" | ||
954 | } | ||
955 | } | ||
956 | }, | ||
957 | { | ||
958 | "comment": "enum declarations", | ||
959 | "match": "\\b(enum)\\s+([A-Z][A-Za-z0-9_]*)\\b", | ||
960 | "captures": { | ||
961 | "1": { | ||
962 | "name": "storage.type.rust" | ||
963 | }, | ||
964 | "2": { | ||
965 | "name": "entity.name.type.enum.rust" | ||
966 | } | ||
967 | } | ||
968 | }, | ||
969 | { | ||
970 | "comment": "type declarations", | ||
971 | "match": "\\b(type)\\s+([A-Z][A-Za-z0-9_]*)\\b", | ||
972 | "captures": { | ||
973 | "1": { | ||
974 | "name": "storage.type.rust" | ||
975 | }, | ||
976 | "2": { | ||
977 | "name": "entity.name.type.declaration.rust" | ||
978 | } | ||
979 | } | ||
980 | }, | ||
981 | { | ||
982 | "comment": "types", | ||
983 | "name": "entity.name.type.rust", | ||
984 | "match": "\\b[A-Z][A-Za-z0-9]*\\b(?!!)" | ||
985 | } | ||
986 | ] | ||
987 | }, | ||
988 | "gtypes": { | ||
989 | "patterns": [ | ||
990 | { | ||
991 | "comment": "option types", | ||
992 | "name": "entity.name.type.option.rust", | ||
993 | "match": "\\b(Some|None)\\b" | ||
994 | }, | ||
995 | { | ||
996 | "comment": "result types", | ||
997 | "name": "entity.name.type.result.rust", | ||
998 | "match": "\\b(Ok|Err)\\b" | ||
999 | } | ||
1000 | ] | ||
1001 | }, | ||
1002 | "punctuation": { | ||
1003 | "patterns": [ | ||
1004 | { | ||
1005 | "comment": "comma", | ||
1006 | "name": "punctuation.comma.rust", | ||
1007 | "match": "," | ||
1008 | }, | ||
1009 | { | ||
1010 | "comment": "curly braces", | ||
1011 | "name": "punctuation.brackets.curly.rust", | ||
1012 | "match": "[{}]" | ||
1013 | }, | ||
1014 | { | ||
1015 | "comment": "parentheses, round brackets", | ||
1016 | "name": "punctuation.brackets.round.rust", | ||
1017 | "match": "[()]" | ||
1018 | }, | ||
1019 | { | ||
1020 | "comment": "semicolon", | ||
1021 | "name": "punctuation.semi.rust", | ||
1022 | "match": ";" | ||
1023 | }, | ||
1024 | { | ||
1025 | "comment": "square brackets", | ||
1026 | "name": "punctuation.brackets.square.rust", | ||
1027 | "match": "[\\[\\]]" | ||
1028 | }, | ||
1029 | { | ||
1030 | "comment": "angle brackets", | ||
1031 | "name": "punctuation.brackets.angle.rust", | ||
1032 | "match": "(?<!=)[<>]" | ||
1033 | } | ||
1034 | ] | ||
1035 | }, | ||
1036 | "strings": { | ||
1037 | "patterns": [ | ||
1038 | { | ||
1039 | "comment": "double-quoted strings and byte strings", | ||
1040 | "name": "string.quoted.double.rust", | ||
1041 | "begin": "(b?)(\")", | ||
1042 | "beginCaptures": { | ||
1043 | "1": { | ||
1044 | "name": "string.quoted.byte.raw.rust" | ||
1045 | }, | ||
1046 | "2": { | ||
1047 | "name": "punctuation.definition.string.rust" | ||
1048 | } | ||
1049 | }, | ||
1050 | "end": "\"", | ||
1051 | "endCaptures": { | ||
1052 | "0": { | ||
1053 | "name": "punctuation.definition.string.rust" | ||
1054 | } | ||
1055 | }, | ||
1056 | "patterns": [ | ||
1057 | { | ||
1058 | "include": "#escapes" | ||
1059 | }, | ||
1060 | { | ||
1061 | "include": "#interpolations" | ||
1062 | } | ||
1063 | ] | ||
1064 | }, | ||
1065 | { | ||
1066 | "comment": "double-quoted raw strings and raw byte strings", | ||
1067 | "name": "string.quoted.double.rust", | ||
1068 | "begin": "(b?r)(#*)(\")", | ||
1069 | "beginCaptures": { | ||
1070 | "1": { | ||
1071 | "name": "string.quoted.byte.raw.rust" | ||
1072 | }, | ||
1073 | "2": { | ||
1074 | "name": "punctuation.definition.string.raw.rust" | ||
1075 | }, | ||
1076 | "3": { | ||
1077 | "name": "punctuation.definition.string.rust" | ||
1078 | } | ||
1079 | }, | ||
1080 | "end": "(\")(\\2)", | ||
1081 | "endCaptures": { | ||
1082 | "1": { | ||
1083 | "name": "punctuation.definition.string.rust" | ||
1084 | }, | ||
1085 | "2": { | ||
1086 | "name": "punctuation.definition.string.raw.rust" | ||
1087 | } | ||
1088 | } | ||
1089 | }, | ||
1090 | { | ||
1091 | "comment": "characters and bytes", | ||
1092 | "name": "string.quoted.single.char.rust", | ||
1093 | "begin": "(b)?(')", | ||
1094 | "beginCaptures": { | ||
1095 | "1": { | ||
1096 | "name": "string.quoted.byte.raw.rust" | ||
1097 | }, | ||
1098 | "2": { | ||
1099 | "name": "punctuation.definition.char.rust" | ||
1100 | } | ||
1101 | }, | ||
1102 | "end": "'", | ||
1103 | "endCaptures": { | ||
1104 | "0": { | ||
1105 | "name": "punctuation.definition.char.rust" | ||
1106 | } | ||
1107 | }, | ||
1108 | "patterns": [ | ||
1109 | { | ||
1110 | "include": "#escapes" | ||
1111 | } | ||
1112 | ] | ||
1113 | } | ||
1114 | ] | ||
1115 | }, | ||
1116 | "lvariables": { | ||
1117 | "patterns": [ | ||
1118 | { | ||
1119 | "comment": "self", | ||
1120 | "name": "variable.language.self.rust", | ||
1121 | "match": "\\b[Ss]elf\\b" | ||
1122 | }, | ||
1123 | { | ||
1124 | "comment": "super", | ||
1125 | "name": "variable.language.super.rust", | ||
1126 | "match": "\\bsuper\\b" | ||
1127 | } | ||
1128 | ] | ||
1129 | }, | ||
1130 | "variables": { | ||
1131 | "patterns": [ | ||
1132 | { | ||
1133 | "comment": "variables", | ||
1134 | "name": "variable.other.rust", | ||
1135 | "match": "\\b(?<!(?<!\\.)\\.)(?:r#(?!(crate|[Ss]elf|super)))?[a-z0-9_]+\\b" | ||
1136 | } | ||
1137 | ] | ||
1138 | } | ||
1139 | } | ||
1140 | } | ||
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 92bc4d7f7..9d4823a34 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts | |||
@@ -470,7 +470,7 @@ export function resolveCodeAction(ctx: Ctx): Cmd { | |||
470 | return; | 470 | return; |
471 | } | 471 | } |
472 | const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit); | 472 | const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit); |
473 | await applySnippetWorkspaceEdit(edit); | 473 | await vscode.workspace.applyEdit(edit); |
474 | }; | 474 | }; |
475 | } | 475 | } |
476 | 476 | ||
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 191960960..282240d84 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -19,9 +19,8 @@ let ctx: Ctx | undefined; | |||
19 | const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; | 19 | const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; |
20 | 20 | ||
21 | export async function activate(context: vscode.ExtensionContext) { | 21 | export async function activate(context: vscode.ExtensionContext) { |
22 | // For some reason vscode not always shows pop-up error notifications | 22 | // VS Code doesn't show a notification when an extension fails to activate |
23 | // when an extension fails to activate, so we do it explicitly by ourselves. | 23 | // so we do it ourselves. |
24 | // FIXME: remove this bit of code once vscode fixes this issue: https://github.com/microsoft/vscode/issues/101242 | ||
25 | await tryActivate(context).catch(err => { | 24 | await tryActivate(context).catch(err => { |
26 | void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`); | 25 | void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`); |
27 | throw err; | 26 | throw err; |
@@ -132,7 +131,7 @@ async function tryActivate(context: vscode.ExtensionContext) { | |||
132 | ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config)); | 131 | ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config)); |
133 | 132 | ||
134 | activateInlayHints(ctx); | 133 | activateInlayHints(ctx); |
135 | warnAboutRustLangExtensionConflict(); | 134 | warnAboutExtensionConflicts(); |
136 | 135 | ||
137 | vscode.workspace.onDidChangeConfiguration( | 136 | vscode.workspace.onDidChangeConfiguration( |
138 | _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), | 137 | _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), |
@@ -288,10 +287,14 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
288 | if (config.package.releaseTag === null) return "rust-analyzer"; | 287 | if (config.package.releaseTag === null) return "rust-analyzer"; |
289 | 288 | ||
290 | let platform: string | undefined; | 289 | let platform: string | undefined; |
291 | if (process.arch === "x64" || process.arch === "ia32") { | 290 | if ((process.arch === "x64" || process.arch === "ia32") && process.platform === "win32") { |
292 | if (process.platform === "linux") platform = "linux"; | 291 | platform = "x86_64-pc-windows-msvc"; |
293 | if (process.platform === "darwin") platform = "mac"; | 292 | } else if (process.arch === "x64" && process.platform === "linux") { |
294 | if (process.platform === "win32") platform = "windows"; | 293 | platform = "x86_64-unknown-linux-gnu"; |
294 | } else if (process.arch === "x64" && process.platform === "darwin") { | ||
295 | platform = "x86_64-apple-darwin"; | ||
296 | } else if (process.arch === "arm64" && process.platform === "darwin") { | ||
297 | platform = "aarch64-apple-darwin"; | ||
295 | } | 298 | } |
296 | if (platform === undefined) { | 299 | if (platform === undefined) { |
297 | vscode.window.showErrorMessage( | 300 | vscode.window.showErrorMessage( |
@@ -304,7 +307,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
304 | ); | 307 | ); |
305 | return undefined; | 308 | return undefined; |
306 | } | 309 | } |
307 | const ext = platform === "windows" ? ".exe" : ""; | 310 | const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : ""; |
308 | const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); | 311 | const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); |
309 | const exists = await fs.stat(dest).then(() => true, () => false); | 312 | const exists = await fs.stat(dest).then(() => true, () => false); |
310 | if (!exists) { | 313 | if (!exists) { |
@@ -340,7 +343,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
340 | }); | 343 | }); |
341 | 344 | ||
342 | // Patching executable if that's NixOS. | 345 | // Patching executable if that's NixOS. |
343 | if (await fs.stat("/etc/nixos").then(_ => true).catch(_ => false)) { | 346 | if (await isNixOs()) { |
344 | await patchelf(dest); | 347 | await patchelf(dest); |
345 | } | 348 | } |
346 | 349 | ||
@@ -348,6 +351,15 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
348 | return dest; | 351 | return dest; |
349 | } | 352 | } |
350 | 353 | ||
354 | async function isNixOs(): Promise<boolean> { | ||
355 | try { | ||
356 | const contents = await fs.readFile("/etc/os-release"); | ||
357 | return contents.indexOf("ID=nixos") !== -1; | ||
358 | } catch (e) { | ||
359 | return false; | ||
360 | } | ||
361 | } | ||
362 | |||
351 | async function downloadWithRetryDialog<T>(state: PersistentState, downloadFunc: () => Promise<T>): Promise<T> { | 363 | async function downloadWithRetryDialog<T>(state: PersistentState, downloadFunc: () => Promise<T>): Promise<T> { |
352 | while (true) { | 364 | while (true) { |
353 | try { | 365 | try { |
@@ -401,11 +413,21 @@ async function queryForGithubToken(state: PersistentState): Promise<void> { | |||
401 | } | 413 | } |
402 | } | 414 | } |
403 | 415 | ||
404 | function warnAboutRustLangExtensionConflict() { | 416 | function warnAboutExtensionConflicts() { |
405 | const rustLangExt = vscode.extensions.getExtension("rust-lang.rust"); | 417 | const conflicting = [ |
406 | if (rustLangExt !== undefined) { | 418 | ["rust-analyzer", "matklad.rust-analyzer"], |
419 | ["Rust", "rust-lang.rust"], | ||
420 | ["Rust", "kalitaalexey.vscode-rust"], | ||
421 | ]; | ||
422 | |||
423 | const found = conflicting.filter( | ||
424 | nameId => vscode.extensions.getExtension(nameId[1]) !== undefined); | ||
425 | |||
426 | if (found.length > 1) { | ||
427 | const fst = found[0]; | ||
428 | const sec = found[1]; | ||
407 | vscode.window.showWarningMessage( | 429 | vscode.window.showWarningMessage( |
408 | "You have both rust-analyzer (matklad.rust-analyzer) and Rust (rust-lang.rust) " + | 430 | `You have both the ${fst[0]} (${fst[1]}) and ${sec[0]} (${sec[1]}) ` + |
409 | "plugins enabled. These are known to conflict and cause various functions of " + | 431 | "plugins enabled. These are known to conflict and cause various functions of " + |
410 | "both plugins to not work correctly. You should disable one of them.", "Got it"); | 432 | "both plugins to not work correctly. You should disable one of them.", "Got it"); |
411 | }; | 433 | }; |
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index 9e15a5a4c..d59b88131 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -58,30 +58,73 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | fn dist_server() -> Result<()> { | 60 | fn dist_server() -> Result<()> { |
61 | if cfg!(target_os = "linux") { | 61 | let target = get_target(); |
62 | if target.contains("-linux-gnu") { | ||
62 | env::set_var("CC", "clang"); | 63 | env::set_var("CC", "clang"); |
63 | } | 64 | } |
64 | cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release").run()?; | ||
65 | |||
66 | let (src, dst) = if cfg!(target_os = "linux") { | ||
67 | ("./target/release/rust-analyzer", "./dist/rust-analyzer-linux") | ||
68 | } else if cfg!(target_os = "windows") { | ||
69 | ("./target/release/rust-analyzer.exe", "./dist/rust-analyzer-windows.exe") | ||
70 | } else if cfg!(target_os = "macos") { | ||
71 | ("./target/release/rust-analyzer", "./dist/rust-analyzer-mac") | ||
72 | } else { | ||
73 | panic!("Unsupported OS") | ||
74 | }; | ||
75 | 65 | ||
76 | let src = Path::new(src); | 66 | let toolchain = toolchain(&target); |
77 | let dst = Path::new(dst); | 67 | cmd!("cargo +{toolchain} build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?; |
78 | 68 | ||
79 | cp(&src, &dst)?; | 69 | let suffix = exe_suffix(&target); |
70 | let src = | ||
71 | Path::new("target").join(&target).join("release").join(format!("rust-analyzer{}", suffix)); | ||
72 | let dst = Path::new("dist").join(format!("rust-analyzer-{}{}", target, suffix)); | ||
80 | gzip(&src, &dst.with_extension("gz"))?; | 73 | gzip(&src, &dst.with_extension("gz"))?; |
81 | 74 | ||
75 | // FIXME: the old names are temporarily kept for client compatibility, but they should be removed | ||
76 | // Remove this block after a couple of releases | ||
77 | match target.as_ref() { | ||
78 | "x86_64-unknown-linux-gnu" => { | ||
79 | cp(&src, "dist/rust-analyzer-linux")?; | ||
80 | gzip(&src, Path::new("dist/rust-analyzer-linux.gz"))?; | ||
81 | } | ||
82 | "x86_64-pc-windows-msvc" => { | ||
83 | cp(&src, "dist/rust-analyzer-windows.exe")?; | ||
84 | gzip(&src, Path::new("dist/rust-analyzer-windows.gz"))?; | ||
85 | } | ||
86 | "x86_64-apple-darwin" => { | ||
87 | cp(&src, "dist/rust-analyzer-mac")?; | ||
88 | gzip(&src, Path::new("dist/rust-analyzer-mac.gz"))?; | ||
89 | } | ||
90 | _ => {} | ||
91 | } | ||
92 | |||
82 | Ok(()) | 93 | Ok(()) |
83 | } | 94 | } |
84 | 95 | ||
96 | fn get_target() -> String { | ||
97 | match env::var("RA_TARGET") { | ||
98 | Ok(target) => target, | ||
99 | _ => { | ||
100 | if cfg!(target_os = "linux") { | ||
101 | "x86_64-unknown-linux-gnu".to_string() | ||
102 | } else if cfg!(target_os = "windows") { | ||
103 | "x86_64-pc-windows-msvc".to_string() | ||
104 | } else if cfg!(target_os = "macos") { | ||
105 | "x86_64-apple-darwin".to_string() | ||
106 | } else { | ||
107 | panic!("Unsupported OS, maybe try setting RA_TARGET") | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | fn exe_suffix(target: &str) -> String { | ||
114 | if target.contains("-windows-") { | ||
115 | ".exe".into() | ||
116 | } else { | ||
117 | "".into() | ||
118 | } | ||
119 | } | ||
120 | |||
121 | fn toolchain(target: &str) -> String { | ||
122 | match target { | ||
123 | "aarch64-apple-darwin" => "beta".to_string(), | ||
124 | _ => "stable".to_string(), | ||
125 | } | ||
126 | } | ||
127 | |||
85 | fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { | 128 | fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { |
86 | let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); | 129 | let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); |
87 | let mut input = io::BufReader::new(File::open(src_path)?); | 130 | let mut input = io::BufReader::new(File::open(src_path)?); |