aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yaml114
-rw-r--r--crates/assists/src/handlers/extract_module_to_file.rs169
-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.rs4
-rw-r--r--crates/rust-analyzer/src/config.rs34
-rw-r--r--docs/user/generated_config.adoc26
-rw-r--r--editors/code/package.json50
-rw-r--r--editors/code/src/main.ts34
-rw-r--r--xtask/src/dist.rs72
15 files changed, 661 insertions, 275 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 919d58925..09752b817 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -15,12 +15,9 @@ 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:
22 matrix:
23 os: [ubuntu-16.04, windows-latest, macos-latest]
24 21
25 steps: 22 steps:
26 - name: Checkout repository 23 - name: Checkout repository
@@ -30,8 +27,7 @@ jobs:
30 # which takes a long time. The fastest way to do this is to rename the 27 # 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 28 # existing folder, as deleting it takes about as much time as not doing
32 # anything and just updating rust-docs. 29 # anything and just updating rust-docs.
33 - name: Rename existing rust toolchain (Windows) 30 - 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 31 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 32
37 - name: Install Rust toolchain 33 - name: Install Rust toolchain
@@ -41,38 +37,116 @@ jobs:
41 profile: minimal 37 profile: minimal
42 override: true 38 override: true
43 39
40 - name: Dist
41 run: cargo xtask dist
42 env:
43 RA_TARGET: x86_64-pc-windows-msvc
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
55 steps:
56 - name: Checkout repository
57 uses: actions/checkout@v2
58
59 - name: Install Rust toolchain
60 uses: actions-rs/toolchain@v1
61 with:
62 toolchain: stable
63 profile: minimal
64 override: true
65
44 - name: Install Nodejs 66 - name: Install Nodejs
45 if: matrix.os == 'ubuntu-16.04'
46 uses: actions/setup-node@v1 67 uses: actions/setup-node@v1
47 with: 68 with:
48 node-version: 12.x 69 node-version: 12.x
49 70
50 - name: Dist 71 - name: Dist
51 if: matrix.os == 'ubuntu-16.04' && github.ref == 'refs/heads/release' 72 if: github.ref == 'refs/heads/release'
52 run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER 73 run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER
74 env:
75 RA_TARGET: x86_64-unknown-linux-gnu
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
80 env:
81 RA_TARGET: x86_64-unknown-linux-gnu
82
83 - name: Nightly analysis-stats check
84 if: github.ref != 'refs/heads/release'
85 run: ./dist/rust-analyzer-x86_64-unknown-linux-gnu analysis-stats .
86
87 - name: Upload artifacts
88 uses: actions/upload-artifact@v1
89 with:
90 name: dist-ubuntu-16.04
91 path: ./dist
92
93 dist-macos-latest:
94 name: dist (MacOS latest)
95 runs-on: macos-latest
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
57 107
58 - name: Dist 108 - name: Dist
59 if: matrix.os != 'ubuntu-16.04'
60 run: cargo xtask dist 109 run: cargo xtask dist
110 env:
111 RA_TARGET: x86_64-apple-darwin
61 112
62 - name: Nightly analysis-stats check 113 - name: Upload artifacts
63 if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release' 114 uses: actions/upload-artifact@v1
64 run: ./dist/rust-analyzer-linux analysis-stats . 115 with:
116 name: dist-macos-latest
117 path: ./dist
118
119 dist-macos-11:
120 name: dist (MacOS 11.0)
121 runs-on: macos-11.0
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
137 env:
138 RA_TARGET: aarch64-apple-darwin
65 139
66 - name: Upload artifacts 140 - name: Upload artifacts
67 uses: actions/upload-artifact@v1 141 uses: actions/upload-artifact@v1
68 with: 142 with:
69 name: dist-${{ matrix.os }} 143 name: dist-macos-11.0
70 path: ./dist 144 path: ./dist
71 145
72 publish: 146 publish:
73 name: publish 147 name: publish
74 runs-on: ubuntu-16.04 148 runs-on: ubuntu-16.04
75 needs: ['dist'] 149 needs: ['dist-windows', 'dist-ubuntu', 'dist-macos-latest', 'dist-macos-11']
76 steps: 150 steps:
77 - name: Install Nodejs 151 - name: Install Nodejs
78 uses: actions/setup-node@v1 152 uses: actions/setup-node@v1
@@ -93,6 +167,10 @@ jobs:
93 167
94 - uses: actions/download-artifact@v1 168 - uses: actions/download-artifact@v1
95 with: 169 with:
170 name: dist-macos-11.0
171 path: dist
172 - uses: actions/download-artifact@v1
173 with:
96 name: dist-macos-latest 174 name: dist-macos-latest
97 path: dist 175 path: dist
98 - uses: actions/download-artifact@v1 176 - uses: actions/download-artifact@v1
@@ -103,7 +181,7 @@ jobs:
103 with: 181 with:
104 name: dist-windows-latest 182 name: dist-windows-latest
105 path: dist 183 path: dist
106 - run: ls -all ./dist 184 - run: ls -al ./dist
107 185
108 - name: Publish Release 186 - name: Publish Release
109 uses: ./.github/actions/github-release 187 uses: ./.github/actions/github-release
diff --git a/crates/assists/src/handlers/extract_module_to_file.rs b/crates/assists/src/handlers/extract_module_to_file.rs
index 5fc190fa6..3e67fdca2 100644
--- a/crates/assists/src/handlers/extract_module_to_file.rs
+++ b/crates/assists/src/handlers/extract_module_to_file.rs
@@ -1,5 +1,5 @@
1use ast::edit::IndentLevel; 1use ast::edit::IndentLevel;
2use ide_db::base_db::{AnchoredPathBuf, SourceDatabaseExt}; 2use ide_db::base_db::AnchoredPathBuf;
3use syntax::{ 3use syntax::{
4 ast::{self, edit::AstNodeEdit, NameOwner}, 4 ast::{self, edit::AstNodeEdit, NameOwner},
5 AstNode, 5 AstNode,
@@ -21,43 +21,44 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
21// mod foo; 21// mod foo;
22// ``` 22// ```
23pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 23pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let assist_id = AssistId("extract_module_to_file", AssistKind::RefactorExtract);
25 let assist_label = "Extract module to file";
26 let db = ctx.db();
27 let module_ast = ctx.find_node_at_offset::<ast::Module>()?; 24 let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
28 let module_items = module_ast.item_list()?;
29 let dedent_module_items_text = module_items.dedent(IndentLevel(1)).to_string();
30 let module_name = module_ast.name()?; 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(); 31 let target = module_ast.syntax().text_range();
32 let anchor_file_id = ctx.frange.file_id; 32 let anchor_file_id = ctx.frange.file_id;
33 let sr = db.file_source_root(anchor_file_id);
34 let sr = db.source_root(sr);
35 let file_path = sr.path_for_file(&anchor_file_id)?;
36 let (file_name, file_ext) = file_path.name_and_extension()?;
37 acc.add(assist_id, assist_label, target, |builder| {
38 builder.replace(target, format!("mod {};", module_name));
39 let path = if is_main_or_lib(file_name) {
40 format!("./{}.{}", module_name, file_ext.unwrap())
41 } else {
42 format!("./{}/{}.{}", file_name, module_name, file_ext.unwrap())
43 };
44 let dst = AnchoredPathBuf { anchor: anchor_file_id, path };
45 let contents = update_module_items_string(dedent_module_items_text);
46 builder.create_file(dst, contents);
47 })
48}
49fn is_main_or_lib(file_name: &str) -> bool {
50 file_name == "main".to_string() || file_name == "lib".to_string()
51}
52fn update_module_items_string(items_str: String) -> String {
53 let mut items_string_lines: Vec<&str> = items_str.lines().collect();
54 items_string_lines.pop(); // Delete last line
55 items_string_lines.reverse();
56 items_string_lines.pop(); // Delete first line
57 items_string_lines.reverse();
58 33
59 let string = items_string_lines.join("\n"); 34 acc.add(
60 format!("{}", string) 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 )
61} 62}
62 63
63#[cfg(test)] 64#[cfg(test)]
@@ -67,104 +68,66 @@ mod tests {
67 use super::*; 68 use super::*;
68 69
69 #[test] 70 #[test]
70 fn extract_module_to_file_with_basic_module() { 71 fn extract_from_root() {
71 check_assist( 72 check_assist(
72 extract_module_to_file, 73 extract_module_to_file,
73 r#" 74 r#"
74//- /foo.rs crate:foo
75mod tests {<|> 75mod tests {<|>
76 #[test] fn t() {} 76 #[test] fn t() {}
77} 77}
78"#, 78"#,
79 r#" 79 r#"
80//- /foo.rs 80//- /main.rs
81mod tests; 81mod tests;
82//- /foo/tests.rs 82//- /tests.rs
83#[test] fn t() {}"#, 83#[test] fn t() {}
84 )
85 }
86
87 #[test]
88 fn extract_module_to_file_with_file_path() {
89 check_assist(
90 extract_module_to_file,
91 r#"
92//- /src/foo.rs crate:foo
93mod bar {<|>
94 fn f() {
95
96 }
97}
98fn main() {
99 println!("Hello, world!");
100}
101"#, 84"#,
102 r#" 85 );
103//- /src/foo.rs
104mod bar;
105fn main() {
106 println!("Hello, world!");
107}
108//- /src/foo/bar.rs
109fn f() {
110
111}"#,
112 )
113 } 86 }
114 87
115 #[test] 88 #[test]
116 fn extract_module_to_file_with_main_filw() { 89 fn extract_from_submodule() {
117 check_assist( 90 check_assist(
118 extract_module_to_file, 91 extract_module_to_file,
119 r#" 92 r#"
120//- /main.rs 93//- /main.rs
121mod foo {<|> 94mod submodule;
122 fn f() { 95//- /submodule.rs
123 96mod inner<|> {
124 } 97 fn f() {}
125}
126fn main() {
127 println!("Hello, world!");
128} 98}
99fn g() {}
129"#, 100"#,
130 r#" 101 r#"
131//- /main.rs 102//- /submodule.rs
132mod foo; 103mod inner;
133fn main() { 104fn g() {}
134 println!("Hello, world!"); 105//- /submodule/inner.rs
135} 106fn f() {}
136//- /foo.rs 107"#,
137fn f() { 108 );
138
139}"#,
140 )
141 } 109 }
142 110
143 #[test] 111 #[test]
144 fn extract_module_to_file_with_lib_file() { 112 fn extract_from_mod_rs() {
145 check_assist( 113 check_assist(
146 extract_module_to_file, 114 extract_module_to_file,
147 r#" 115 r#"
148//- /lib.rs 116//- /main.rs
149mod foo {<|> 117mod submodule;
150 fn f() { 118//- /submodule/mod.rs
151 119mod inner<|> {
152 } 120 fn f() {}
153}
154fn main() {
155 println!("Hello, world!");
156} 121}
122fn g() {}
157"#, 123"#,
158 r#" 124 r#"
159//- /lib.rs 125//- /submodule/mod.rs
160mod foo; 126mod inner;
161fn main() { 127fn g() {}
162 println!("Hello, world!"); 128//- /submodule/inner.rs
163} 129fn f() {}
164//- /foo.rs 130"#,
165fn f() { 131 );
166
167}"#,
168 )
169 } 132 }
170} 133}
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 73ca6ba9f..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 }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1f4b5c24c..11cdae57f 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.
@@ -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/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/editors/code/package.json b/editors/code/package.json
index abcc84eda..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": {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 4b2d3c8a5..282240d84 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -131,7 +131,7 @@ async function tryActivate(context: vscode.ExtensionContext) {
131 ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config)); 131 ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config));
132 132
133 activateInlayHints(ctx); 133 activateInlayHints(ctx);
134 warnAboutRustLangExtensionConflict(); 134 warnAboutExtensionConflicts();
135 135
136 vscode.workspace.onDidChangeConfiguration( 136 vscode.workspace.onDidChangeConfiguration(
137 _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), 137 _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }),
@@ -287,12 +287,14 @@ async function getServer(config: Config, state: PersistentState): Promise<string
287 if (config.package.releaseTag === null) return "rust-analyzer"; 287 if (config.package.releaseTag === null) return "rust-analyzer";
288 288
289 let platform: string | undefined; 289 let platform: string | undefined;
290 if (process.arch === "x64" || process.arch === "ia32") { 290 if ((process.arch === "x64" || process.arch === "ia32") && process.platform === "win32") {
291 if (process.platform === "linux") platform = "linux"; 291 platform = "x86_64-pc-windows-msvc";
292 if (process.platform === "darwin") platform = "mac"; 292 } else if (process.arch === "x64" && process.platform === "linux") {
293 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";
294 } else if (process.arch === "arm64" && process.platform === "darwin") { 296 } else if (process.arch === "arm64" && process.platform === "darwin") {
295 platform = "mac"; 297 platform = "aarch64-apple-darwin";
296 } 298 }
297 if (platform === undefined) { 299 if (platform === undefined) {
298 vscode.window.showErrorMessage( 300 vscode.window.showErrorMessage(
@@ -305,7 +307,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
305 ); 307 );
306 return undefined; 308 return undefined;
307 } 309 }
308 const ext = platform === "windows" ? ".exe" : ""; 310 const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : "";
309 const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); 311 const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`);
310 const exists = await fs.stat(dest).then(() => true, () => false); 312 const exists = await fs.stat(dest).then(() => true, () => false);
311 if (!exists) { 313 if (!exists) {
@@ -411,11 +413,21 @@ async function queryForGithubToken(state: PersistentState): Promise<void> {
411 } 413 }
412} 414}
413 415
414function warnAboutRustLangExtensionConflict() { 416function warnAboutExtensionConflicts() {
415 const rustLangExt = vscode.extensions.getExtension("rust-lang.rust"); 417 const conflicting = [
416 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];
417 vscode.window.showWarningMessage( 429 vscode.window.showWarningMessage(
418 "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]}) ` +
419 "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 " +
420 "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");
421 }; 433 };
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index 9e15a5a4c..d07ad9420 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -58,30 +58,74 @@ 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
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));
79 cp(&src, &dst)?; 73 cp(&src, &dst)?;
80 gzip(&src, &dst.with_extension("gz"))?; 74 gzip(&src, &dst.with_extension("gz"))?;
81 75
76 // FIXME: the old names are temporarily kept for client compatibility, but they should be removed
77 // Remove this block after a couple of releases
78 match target.as_ref() {
79 "x86_64-unknown-linux-gnu" => {
80 cp(&src, "dist/rust-analyzer-linux")?;
81 gzip(&src, Path::new("dist/rust-analyzer-linux.gz"))?;
82 }
83 "x86_64-pc-windows-msvc" => {
84 cp(&src, "dist/rust-analyzer-windows.exe")?;
85 gzip(&src, Path::new("dist/rust-analyzer-windows.gz"))?;
86 }
87 "x86_64-apple-darwin" => {
88 cp(&src, "dist/rust-analyzer-mac")?;
89 gzip(&src, Path::new("dist/rust-analyzer-mac.gz"))?;
90 }
91 _ => {}
92 }
93
82 Ok(()) 94 Ok(())
83} 95}
84 96
97fn get_target() -> String {
98 match env::var("RA_TARGET") {
99 Ok(target) => target,
100 _ => {
101 if cfg!(target_os = "linux") {
102 "x86_64-unknown-linux-gnu".to_string()
103 } else if cfg!(target_os = "windows") {
104 "x86_64-pc-windows-msvc".to_string()
105 } else if cfg!(target_os = "macos") {
106 "x86_64-apple-darwin".to_string()
107 } else {
108 panic!("Unsupported OS, maybe try setting RA_TARGET")
109 }
110 }
111 }
112}
113
114fn exe_suffix(target: &str) -> String {
115 if target.contains("-windows-") {
116 ".exe".into()
117 } else {
118 "".into()
119 }
120}
121
122fn toolchain(target: &str) -> String {
123 match target {
124 "aarch64-apple-darwin" => "beta".to_string(),
125 _ => "stable".to_string(),
126 }
127}
128
85fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { 129fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
86 let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); 130 let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
87 let mut input = io::BufReader::new(File::open(src_path)?); 131 let mut input = io::BufReader::new(File::open(src_path)?);