aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yaml112
-rw-r--r--Cargo.lock8
-rw-r--r--crates/assists/src/assist_context.rs13
-rw-r--r--crates/assists/src/handlers/extract_module_to_file.rs133
-rw-r--r--crates/assists/src/handlers/invert_if.rs9
-rw-r--r--crates/assists/src/handlers/remove_unused_param.rs81
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests.rs28
-rw-r--r--crates/assists/src/tests/generated.rs15
-rw-r--r--crates/assists/src/utils.rs8
-rw-r--r--crates/completion/src/completions.rs33
-rw-r--r--crates/completion/src/completions/pattern.rs178
-rw-r--r--crates/completion/src/context.rs21
-rw-r--r--crates/completion/src/render.rs7
-rw-r--r--crates/completion/src/render/builder_ext.rs1
-rw-r--r--crates/completion/src/render/enum_variant.rs45
-rw-r--r--crates/completion/src/render/pattern.rs148
-rw-r--r--crates/hir/src/code_model.rs5
-rw-r--r--crates/hir_def/src/generics.rs37
-rw-r--r--crates/hir_def/src/nameres/mod_resolution.rs2
-rw-r--r--crates/hir_expand/src/builtin_macro.rs5
-rw-r--r--crates/hir_expand/src/db.rs9
-rw-r--r--crates/hir_expand/src/eager.rs14
-rw-r--r--crates/hir_expand/src/lib.rs27
-rw-r--r--crates/hir_ty/src/lower.rs18
-rw-r--r--crates/hir_ty/src/utils.rs9
-rw-r--r--crates/ide/src/diagnostics.rs1
-rw-r--r--crates/ide/src/diagnostics/fixes.rs1
-rw-r--r--crates/ide/src/goto_definition.rs53
-rw-r--r--crates/ide/src/references.rs48
-rw-r--r--crates/ide_db/src/source_change.rs2
-rw-r--r--crates/mbe/src/tests.rs12
-rw-r--r--crates/parser/src/grammar.rs2
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs8
-rw-r--r--crates/parser/src/grammar/params.rs17
-rw-r--r--crates/parser/src/grammar/type_params.rs2
-rw-r--r--crates/parser/src/grammar/types.rs26
-rw-r--r--crates/parser/src/lib.rs2
-rw-r--r--crates/proc_macro_srv/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/config.rs38
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs4
-rw-r--r--crates/rust-analyzer/src/to_proto.rs37
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast20
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast43
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs1
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast50
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs1
-rw-r--r--crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast222
-rw-r--r--crates/syntax/test_data/parser/ok/0063_variadic_fun.rast28
-rw-r--r--docs/user/generated_config.adoc26
-rw-r--r--docs/user/manual.adoc45
-rw-r--r--editors/code/.vscodeignore1
-rw-r--r--editors/code/package.json55
-rw-r--r--editors/code/rust.tmGrammar.json1140
-rw-r--r--editors/code/src/commands.ts2
-rw-r--r--editors/code/src/main.ts50
-rw-r--r--xtask/src/dist.rs73
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
17jobs: 17jobs:
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]]
1253name = "quote" 1253name = "quote"
1254version = "1.0.7" 1254version = "1.0.8"
1255source = "registry+https://github.com/rust-lang/crates.io-index" 1255source = "registry+https://github.com/rust-lang/crates.io-index"
1256checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" 1256checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
1257dependencies = [ 1257dependencies = [
1258 "proc-macro2", 1258 "proc-macro2",
1259] 1259]
@@ -1588,9 +1588,9 @@ version = "0.0.0"
1588 1588
1589[[package]] 1589[[package]]
1590name = "syn" 1590name = "syn"
1591version = "1.0.54" 1591version = "1.0.55"
1592source = "registry+https://github.com/rust-lang/crates.io-index" 1592source = "registry+https://github.com/rust-lang/crates.io-index"
1593checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" 1593checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a"
1594dependencies = [ 1594dependencies = [
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
5use algo::find_covering_element; 5use algo::find_covering_element;
6use hir::Semantics; 6use hir::Semantics;
7use ide_db::base_db::{FileId, FileRange}; 7use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange};
8use ide_db::{ 8use 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};
13use syntax::{ 13use 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
214impl AssistBuilder { 215impl 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 @@
1use ast::edit::IndentLevel;
2use ide_db::base_db::AnchoredPathBuf;
3use syntax::{
4 ast::{self, edit::AstNodeEdit, NameOwner},
5 AstNode,
6};
7
8use 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// ```
23pub(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)]
65mod 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#"
75mod tests {<|>
76 #[test] fn t() {}
77}
78"#,
79 r#"
80//- /main.rs
81mod 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
94mod submod;
95//- /submod.rs
96mod inner<|> {
97 fn f() {}
98}
99fn g() {}
100"#,
101 r#"
102//- /submod.rs
103mod inner;
104fn g() {}
105//- /submod/inner.rs
106fn 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
117mod submodule;
118//- /submodule/mod.rs
119mod inner<|> {
120 fn f() {}
121}
122fn g() {}
123"#,
124 r#"
125//- /submodule/mod.rs
126mod inner;
127fn g() {}
128//- /submodule/inner.rs
129fn 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};
2use syntax::{ 2use 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};
7use test_utils::mark; 7use test_utils::mark;
8use SyntaxKind::WHITESPACE;
8 9
9use crate::{ 10use 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
88fn range_with_coma(node: &SyntaxNode) -> TextRange { 89fn 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#"
142fn foo(<|>x: i32, y: i32) { y; }
143fn a() { foo(1, 2) }
144fn b() { foo(1, 2,) }
145"#,
146 r#"
147fn foo(y: i32) { y; }
148fn a() { foo(2) }
149fn b() { foo(2,) }
150"#,
151 );
152 }
153
154 #[test]
155 fn remove_unused_single_param() {
156 check_assist(
157 remove_unused_param,
158 r#"
159fn foo(<|>x: i32) { 0; }
160fn a() { foo(1) }
161fn b() { foo(1, ) }
162"#,
163 r#"
164fn foo() { 0; }
165fn a() { foo() }
166fn b() { foo( ) }
167"#,
168 );
169 }
170
171 #[test]
172 fn remove_unused_surrounded_by_parms() {
173 check_assist(
174 remove_unused_param,
175 r#"
176fn foo(x: i32, <|>y: i32, z: i32) { x; }
177fn a() { foo(1, 2, 3) }
178fn b() { foo(1, 2, 3,) }
179"#,
180 r#"
181fn foo(x: i32, z: i32) { x; }
182fn a() { foo(1, 3) }
183fn 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
3use hir::Semantics; 3use hir::Semantics;
4use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; 4use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
5use ide_db::source_change::FileSystemEdit;
5use ide_db::RootDatabase; 6use ide_db::RootDatabase;
6use syntax::TextRange; 7use syntax::TextRange;
7use test_utils::{assert_eq_text, extract_offset, extract_range}; 8use 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]
239fn doctest_extract_module_to_file() {
240 check_doc_test(
241 "extract_module_to_file",
242 r#####"
243mod foo {<|>
244 fn t() {}
245}
246"#####,
247 r#####"
248mod foo;
249"#####,
250 )
251}
252
253#[test]
239fn doctest_extract_struct_from_enum_variant() { 254fn 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};
19use crate::{ 19use 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
3use crate::{CompletionContext, Completions}; 3use crate::{CompletionContext, Completions};
4 4
5/// Completes constats and paths in patterns. 5/// Completes constants and paths in patterns.
6pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { 6pub(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) {
42mod tests { 43mod 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#"
131enum E { X }
132
133static FOO: E = E::X;
134struct Bar { f: u32 }
135
136fn 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#"
149struct Bar { f: u32 }
150
151fn 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#"
165struct Foo { bar: String, baz: String }
166struct Bar(String, String);
167struct Baz;
168fn 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#"
181struct Foo { bar: String, baz: String }
182struct Bar(String, String);
183struct Baz;
184fn 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#"
199struct Foo { bar: i32, baz: i32 }
200struct Bar(String, String);
201struct Baz;
202fn 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#"
219mod foo {
220 pub struct Foo { pub bar: i32, baz: i32 }
221 pub struct Bar(pub String, String);
222 pub struct Invisible(String, String);
223}
224use foo::*;
225
226fn 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#"
244struct Foo(i32);
245fn main() {
246 match Foo(92) {
247 <|>(92) => (),
248 }
249}
250"#,
251 r#"
252struct Foo(i32);
253fn 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_;
5pub(crate) mod function; 5pub(crate) mod function;
6pub(crate) mod enum_variant; 6pub(crate) mod enum_variant;
7pub(crate) mod const_; 7pub(crate) mod const_;
8pub(crate) mod pattern;
8pub(crate) mod type_alias; 9pub(crate) mod type_alias;
9 10
10mod builder_ext; 11mod 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#"
132enum Option<T> { Some(T), None }
133use Option::*;
134fn main(value: Option<i32>) {
135 match value {
136 Som<|>
137 }
138}
139"#,
140 r#"
141enum Option<T> { Some(T), None }
142use Option::*;
143fn 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#"
158enum E { Var(i32) }
159fn main() {
160 match E::Var(92) {
161 E::<|>(92) => (),
162 }
163}
164"#,
165 r#"
166enum E { Var(i32) }
167fn 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
3use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
4use itertools::Itertools;
5
6use crate::{
7 config::SnippetCap, item::CompletionKind, render::RenderContext, CompletionItem,
8 CompletionItemKind,
9};
10
11fn 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
29pub(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
50pub(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
66fn 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
85fn 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
113fn 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
141fn 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)]
1273pub struct Impl { 1276pub 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 {
62pub enum WherePredicate { 62pub 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(&lt))
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(&macro_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;
5use base_db::{salsa, SourceDatabase}; 5use base_db::{salsa, SourceDatabase};
6use mbe::{ExpandError, ExpandResult, MacroRules}; 6use mbe::{ExpandError, ExpandResult, MacroRules};
7use parser::FragmentKind; 7use parser::FragmentKind;
8use syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; 8use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode};
9 9
10use crate::{ 10use 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> {
129fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 129fn 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(&macro_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;
5use hir_def::{ 5use 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]
758macro_rules! include {}
759
760 include!("foo.rs");
761//^^^^^^^^^^^^^^^^^^^
762
763fn f() {
764 foo<|>();
765}
766
767mod confuse_index {
768 pub fn foo() {}
769}
770
771//- /foo.rs
772fn 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> {}
1111fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {}
1112 //^^
1113"#,
1114 );
1115 check(
1116 r#"trait Foo<T> {}
1117fn 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> {}
1128fn 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
178fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { 178fn 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#"
1094macro_rules! foo {($i:ident) => {$i} }
1095fn 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#"
1112macro_rules! foo {($i:ident) => {$i} }
1113fn 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)]
46pub enum FileSystemEdit { 46pub 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]
1007fn 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]
1007fn test_lifetime() { 1019fn 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
78struct Variadic(bool); 81struct Variadic(bool);
79 82
80fn param(p: &mut Parser, flavor: Flavor) -> Variadic { 83fn 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// }
154fn opt_self_param(p: &mut Parser) { 156fn 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>;
230pub(super) fn for_type(p: &mut Parser) { 230pub(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
313fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) { 319fn 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"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] } 13object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe"] }
14libloading = "0.6.0" 14libloading = "0.6.0"
15memmap = "0.7" 15memmap = "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
637pub(crate) fn resource_op( 637pub(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
663pub(crate) fn snippet_workspace_edit( 680pub(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"`)::
5rust-analyzer.callInfo.full (default: `true`):: 5rust-analyzer.callInfo.full (default: `true`)::
6 Show function name and docs in parameter hints. 6 Show function name and docs in parameter hints.
7rust-analyzer.cargo.autoreload (default: `true`):: 7rust-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.
9rust-analyzer.cargo.allFeatures (default: `false`):: 9rust-analyzer.cargo.allFeatures (default: `false`)::
10 Activate all available features. 10 Activate all available features.
11rust-analyzer.cargo.features (default: `[]`):: 11rust-analyzer.cargo.features (default: `[]`)::
@@ -21,7 +21,7 @@ rust-analyzer.cargo.noSysroot (default: `false`)::
21rust-analyzer.checkOnSave.enable (default: `true`):: 21rust-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.
23rust-analyzer.checkOnSave.allFeatures (default: `null`):: 23rust-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#`.
25rust-analyzer.checkOnSave.allTargets (default: `true`):: 25rust-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`).
27rust-analyzer.checkOnSave.command (default: `"check"`):: 27rust-analyzer.checkOnSave.command (default: `"check"`)::
@@ -29,11 +29,11 @@ rust-analyzer.checkOnSave.command (default: `"check"`)::
29rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`):: 29rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`)::
30 Do not activate the `default` feature. 30 Do not activate the `default` feature.
31rust-analyzer.checkOnSave.target (default: `null`):: 31rust-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#`.
33rust-analyzer.checkOnSave.extraArgs (default: `[]`):: 33rust-analyzer.checkOnSave.extraArgs (default: `[]`)::
34 Extra arguments for `cargo check`. 34 Extra arguments for `cargo check`.
35rust-analyzer.checkOnSave.features (default: `null`):: 35rust-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#`.
37rust-analyzer.checkOnSave.overrideCommand (default: `null`):: 37rust-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.
39rust-analyzer.completion.addCallArgumentSnippets (default: `true`):: 39rust-analyzer.completion.addCallArgumentSnippets (default: `true`)::
@@ -43,7 +43,7 @@ rust-analyzer.completion.addCallParenthesis (default: `true`)::
43rust-analyzer.completion.postfix.enable (default: `true`):: 43rust-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.
45rust-analyzer.completion.autoimport.enable (default: `true`):: 45rust-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.
47rust-analyzer.diagnostics.enable (default: `true`):: 47rust-analyzer.diagnostics.enable (default: `true`)::
48 Whether to show native rust-analyzer diagnostics. 48 Whether to show native rust-analyzer diagnostics.
49rust-analyzer.diagnostics.enableExperimental (default: `true`):: 49rust-analyzer.diagnostics.enableExperimental (default: `true`)::
@@ -51,9 +51,9 @@ rust-analyzer.diagnostics.enableExperimental (default: `true`)::
51rust-analyzer.diagnostics.disabled (default: `[]`):: 51rust-analyzer.diagnostics.disabled (default: `[]`)::
52 List of rust-analyzer diagnostics to disable. 52 List of rust-analyzer diagnostics to disable.
53rust-analyzer.diagnostics.warningsAsHint (default: `[]`):: 53rust-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`.
55rust-analyzer.diagnostics.warningsAsInfo (default: `[]`):: 55rust-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`.
57rust-analyzer.files.watcher (default: `"client"`):: 57rust-analyzer.files.watcher (default: `"client"`)::
58 Controls file watching implementation. 58 Controls file watching implementation.
59rust-analyzer.hoverActions.debug (default: `true`):: 59rust-analyzer.hoverActions.debug (default: `true`)::
@@ -71,7 +71,7 @@ rust-analyzer.hoverActions.linksInHover (default: `true`)::
71rust-analyzer.inlayHints.chainingHints (default: `true`):: 71rust-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.
73rust-analyzer.inlayHints.maxLength (default: `null`):: 73rust-analyzer.inlayHints.maxLength (default: `null`)::
74 Maximum length for inlay hints. 74 Maximum length for inlay hints. Default is unlimited.
75rust-analyzer.inlayHints.parameterHints (default: `true`):: 75rust-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.
77rust-analyzer.inlayHints.typeHints (default: `true`):: 77rust-analyzer.inlayHints.typeHints (default: `true`)::
@@ -87,20 +87,20 @@ rust-analyzer.lens.run (default: `true`)::
87rust-analyzer.lens.methodReferences (default: `false`):: 87rust-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.
89rust-analyzer.linkedProjects (default: `[]`):: 89rust-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.
91rust-analyzer.lruCapacity (default: `null`):: 91rust-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.
93rust-analyzer.notifications.cargoTomlNotFound (default: `true`):: 93rust-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.
95rust-analyzer.procMacro.enable (default: `false`):: 95rust-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.
97rust-analyzer.runnables.overrideCargo (default: `null`):: 97rust-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.
99rust-analyzer.runnables.cargoExtraArgs (default: `[]`):: 99rust-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`.
101rust-analyzer.rustcSource (default: `null`):: 101rust-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.
103rust-analyzer.rustfmt.extraArgs (default: `[]`):: 103rust-analyzer.rustfmt.extraArgs (default: `[]`)::
104 Additional arguments to rustfmt. 104 Additional arguments to `rustfmt`.
105rust-analyzer.rustfmt.overrideCommand (default: `null`):: 105rust-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
46https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. 46https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace].
47 47
48Note that the plugin may cause conflicts with the 48Note that the plugin may cause conflicts with the
49https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin]. It is 49https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin].
50recommended to disable the Rust plugin when using the rust-analyzer extension. 50It is recommended to disable the Rust plugin when using the rust-analyzer extension.
51 51
52By default, the plugin will prompt you to download the matching version of the server as well: 52By 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
77The 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. 77The extension will be updated automatically as new versions become available.
78It will ask your permission to download the matching language server version binary if needed.
78 79
79===== Nightly 80===== Nightly
80 81
81We 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: 82We ship nightly releases for VS Code.
83To 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
88You 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. 90You will be prompted to install the `nightly` extension version.
91Just click `Download now` and from that moment you will get automatic updates every 24 hours.
89 92
90If 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`: 93If 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
161Ensure `~/.local/bin` is listed in the `$PATH` variable. 164Ensure `~/.local/bin` is listed in the `$PATH` variable.
162 165
163Alternatively, you can install it from source using the following command: 166Alternatively, you can install it from source using the command below.
167You'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
201Prerequisites: 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. 205Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
206Not needed if the extension can install/update it on its own, coc-rust-analyzer is one example.
202 207
203The are several LSP client implementations for vim or neovim: 208The 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
271Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. 276Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
272 277
273You also need the `LSP` package. To install it: 278You also need the `LSP` package.
279To install it:
274 280
2751. If you've never installed a Sublime Text package, install Package Control: 2811. 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
2782. In the command palette, run `Package control: Install package`, and in the list that pops up, type `LSP` and press enter. 2842. In the command palette, run `Package control: Install package`, and in the list that pops up, type `LSP` and press enter.
279 285
280Finally, 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. 286Finally, 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.
287The latter means that rust-analyzer is enabled by default in Rust projects.
281 288
282If 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. 289If 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
288GNOME 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. 295GNOME Builder 3.37.1 and newer has native `rust-analyzer` support.
296If 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
294rust-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. 302rust-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.
295Please consult your editor's documentation to learn how to configure LSP servers. 303Please consult your editor's documentation to learn how to configure LSP servers.
296 304
305To verify which configuration is actually used by rust-analyzer, set `RA_LOG` environment variable to `rust_analyzer=info` and look for config-related messages.
306Logs should show both the JSON that rust-analyzer sees as well as the updated config.
307
297This is the list of config options rust-analyzer supports: 308This is the list of config options rust-analyzer supports:
298 309
299include::./generated_config.adoc[] 310include::./generated_config.adoc[]
@@ -413,8 +424,8 @@ include::./generated_diagnostic.adoc[]
413 424
414==== Color configurations 425==== Color configurations
415 426
416It is possible to change the foreground/background color of inlay hints. Just add this to your 427It is possible to change the foreground/background color of inlay hints.
417`settings.json`: 428Just 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
439You 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`: 450You can customize the look of different semantic elements in the source code.
451For 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.
455You may use `inRustProject` context to configure keybindings for rust projects only. For example: 467You may use `inRustProject` context to configure keybindings for rust projects only.
468For 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
494You 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. 508You can use any valid regular expression as a mask.
509Also 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;
19const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; 19const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
20 20
21export async function activate(context: vscode.ExtensionContext) { 21export 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
354async 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
351async function downloadWithRetryDialog<T>(state: PersistentState, downloadFunc: () => Promise<T>): Promise<T> { 363async 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
404function warnAboutRustLangExtensionConflict() { 416function 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
60fn dist_server() -> Result<()> { 60fn 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
96fn 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
113fn exe_suffix(target: &str) -> String {
114 if target.contains("-windows-") {
115 ".exe".into()
116 } else {
117 "".into()
118 }
119}
120
121fn toolchain(target: &str) -> String {
122 match target {
123 "aarch64-apple-darwin" => "beta".to_string(),
124 _ => "stable".to_string(),
125 }
126}
127
85fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { 128fn 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)?);