aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_ide_api/Cargo.toml3
-rw-r--r--crates/ra_ide_api/src/change.rs20
-rw-r--r--crates/ra_ide_api/src/db.rs10
-rw-r--r--crates/ra_ide_api/src/lib.rs1
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs37
-rw-r--r--crates/ra_ide_api/src/wasm_shims.rs17
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs1
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs15
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rs4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.txt75
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.txt59
-rw-r--r--crates/ra_tools/src/main.rs2
13 files changed, 233 insertions, 16 deletions
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml
index 000694620..6bbf9d5dd 100644
--- a/crates/ra_ide_api/Cargo.toml
+++ b/crates/ra_ide_api/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_ide_api"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[features]
8wasm = []
9
7[dependencies] 10[dependencies]
8format-buf = "1.0.0" 11format-buf = "1.0.0"
9itertools = "0.8.0" 12itertools = "0.8.0"
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 0d52f5ffb..cc476a237 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -6,6 +6,7 @@ use ra_db::{
6}; 6};
7use ra_prof::{memory_usage, profile, Bytes}; 7use ra_prof::{memory_usage, profile, Bytes};
8use ra_syntax::SourceFile; 8use ra_syntax::SourceFile;
9#[cfg(not(feature = "wasm"))]
9use rayon::prelude::*; 10use rayon::prelude::*;
10use relative_path::RelativePathBuf; 11use relative_path::RelativePathBuf;
11use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
@@ -143,7 +144,12 @@ impl LibraryData {
143 root_id: SourceRootId, 144 root_id: SourceRootId,
144 files: Vec<(FileId, RelativePathBuf, Arc<String>)>, 145 files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
145 ) -> LibraryData { 146 ) -> LibraryData {
146 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, _, text)| { 147 #[cfg(not(feature = "wasm"))]
148 let iter = files.par_iter();
149 #[cfg(feature = "wasm")]
150 let iter = files.iter();
151
152 let symbol_index = SymbolIndex::for_files(iter.map(|(file_id, _, text)| {
147 let parse = SourceFile::parse(text); 153 let parse = SourceFile::parse(text);
148 (*file_id, parse) 154 (*file_id, parse)
149 })); 155 }));
@@ -234,8 +240,12 @@ impl RootDatabase {
234 } 240 }
235 241
236 pub(crate) fn maybe_collect_garbage(&mut self) { 242 pub(crate) fn maybe_collect_garbage(&mut self) {
243 if cfg!(feature = "wasm") {
244 return;
245 }
246
237 if self.last_gc_check.elapsed() > GC_COOLDOWN { 247 if self.last_gc_check.elapsed() > GC_COOLDOWN {
238 self.last_gc_check = time::Instant::now(); 248 self.last_gc_check = crate::wasm_shims::Instant::now();
239 let retained_trees = syntax_tree_stats(self).retained; 249 let retained_trees = syntax_tree_stats(self).retained;
240 if retained_trees > 100 { 250 if retained_trees > 100 {
241 log::info!("automatic garbadge collection, {} retained trees", retained_trees); 251 log::info!("automatic garbadge collection, {} retained trees", retained_trees);
@@ -245,8 +255,12 @@ impl RootDatabase {
245 } 255 }
246 256
247 pub(crate) fn collect_garbage(&mut self) { 257 pub(crate) fn collect_garbage(&mut self) {
258 if cfg!(feature = "wasm") {
259 return;
260 }
261
248 let _p = profile("RootDatabase::collect_garbage"); 262 let _p = profile("RootDatabase::collect_garbage");
249 self.last_gc = time::Instant::now(); 263 self.last_gc = crate::wasm_shims::Instant::now();
250 264
251 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); 265 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
252 266
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index 4c5159d61..afd9022ce 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -1,4 +1,4 @@
1use std::{sync::Arc, time}; 1use std::sync::Arc;
2 2
3use ra_db::{ 3use ra_db::{
4 salsa::{self, Database, Durability}, 4 salsa::{self, Database, Durability},
@@ -25,8 +25,8 @@ pub(crate) struct RootDatabase {
25 runtime: salsa::Runtime<RootDatabase>, 25 runtime: salsa::Runtime<RootDatabase>,
26 pub(crate) feature_flags: Arc<FeatureFlags>, 26 pub(crate) feature_flags: Arc<FeatureFlags>,
27 pub(crate) debug_data: Arc<DebugData>, 27 pub(crate) debug_data: Arc<DebugData>,
28 pub(crate) last_gc: time::Instant, 28 pub(crate) last_gc: crate::wasm_shims::Instant,
29 pub(crate) last_gc_check: time::Instant, 29 pub(crate) last_gc_check: crate::wasm_shims::Instant,
30} 30}
31 31
32impl hir::debug::HirDebugHelper for RootDatabase { 32impl hir::debug::HirDebugHelper for RootDatabase {
@@ -69,8 +69,8 @@ impl RootDatabase {
69 pub fn new(lru_capacity: Option<usize>, feature_flags: FeatureFlags) -> RootDatabase { 69 pub fn new(lru_capacity: Option<usize>, feature_flags: FeatureFlags) -> RootDatabase {
70 let mut db = RootDatabase { 70 let mut db = RootDatabase {
71 runtime: salsa::Runtime::default(), 71 runtime: salsa::Runtime::default(),
72 last_gc: time::Instant::now(), 72 last_gc: crate::wasm_shims::Instant::now(),
73 last_gc_check: time::Instant::now(), 73 last_gc_check: crate::wasm_shims::Instant::now(),
74 feature_flags: Arc::new(feature_flags), 74 feature_flags: Arc::new(feature_flags),
75 debug_data: Default::default(), 75 debug_data: Default::default(),
76 }; 76 };
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 412dc4d71..44d1ec77b 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -40,6 +40,7 @@ mod typing;
40mod matching_brace; 40mod matching_brace;
41mod display; 41mod display;
42mod inlay_hints; 42mod inlay_hints;
43mod wasm_shims;
43 44
44#[cfg(test)] 45#[cfg(test)]
45mod marks; 46mod marks;
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index a5729c368..02cdfbc60 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -38,6 +38,7 @@ use ra_syntax::{
38 SyntaxKind::{self, *}, 38 SyntaxKind::{self, *},
39 SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent, 39 SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent,
40}; 40};
41#[cfg(not(feature = "wasm"))]
41use rayon::prelude::*; 42use rayon::prelude::*;
42 43
43use crate::{db::RootDatabase, FileId, Query}; 44use crate::{db::RootDatabase, FileId, Query};
@@ -79,10 +80,17 @@ pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol>
79 80
80 let buf: Vec<Arc<SymbolIndex>> = if query.libs { 81 let buf: Vec<Arc<SymbolIndex>> = if query.libs {
81 let snap = Snap(db.snapshot()); 82 let snap = Snap(db.snapshot());
82 db.library_roots() 83 #[cfg(not(feature = "wasm"))]
84 let buf = db
85 .library_roots()
83 .par_iter() 86 .par_iter()
84 .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id)) 87 .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id))
85 .collect() 88 .collect();
89
90 #[cfg(feature = "wasm")]
91 let buf = db.library_roots().iter().map(|&lib_id| snap.0.library_symbols(lib_id)).collect();
92
93 buf
86 } else { 94 } else {
87 let mut files = Vec::new(); 95 let mut files = Vec::new();
88 for &root in db.local_roots().iter() { 96 for &root in db.local_roots().iter() {
@@ -91,7 +99,14 @@ pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol>
91 } 99 }
92 100
93 let snap = Snap(db.snapshot()); 101 let snap = Snap(db.snapshot());
94 files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect() 102 #[cfg(not(feature = "wasm"))]
103 let buf =
104 files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect();
105
106 #[cfg(feature = "wasm")]
107 let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect();
108
109 buf
95 }; 110 };
96 query.search(&buf) 111 query.search(&buf)
97} 112}
@@ -135,9 +150,12 @@ impl SymbolIndex {
135 fn cmp_key<'a>(s1: &'a FileSymbol) -> impl Ord + 'a { 150 fn cmp_key<'a>(s1: &'a FileSymbol) -> impl Ord + 'a {
136 unicase::Ascii::new(s1.name.as_str()) 151 unicase::Ascii::new(s1.name.as_str())
137 } 152 }
138 153 #[cfg(not(feature = "wasm"))]
139 symbols.par_sort_by(|s1, s2| cmp_key(s1).cmp(&cmp_key(s2))); 154 symbols.par_sort_by(|s1, s2| cmp_key(s1).cmp(&cmp_key(s2)));
140 155
156 #[cfg(feature = "wasm")]
157 symbols.sort_by(|s1, s2| cmp_key(s1).cmp(&cmp_key(s2)));
158
141 let mut builder = fst::MapBuilder::memory(); 159 let mut builder = fst::MapBuilder::memory();
142 160
143 let mut last_batch_start = 0; 161 let mut last_batch_start = 0;
@@ -169,6 +187,7 @@ impl SymbolIndex {
169 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>() 187 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
170 } 188 }
171 189
190 #[cfg(not(feature = "wasm"))]
172 pub(crate) fn for_files( 191 pub(crate) fn for_files(
173 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>, 192 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>,
174 ) -> SymbolIndex { 193 ) -> SymbolIndex {
@@ -178,6 +197,16 @@ impl SymbolIndex {
178 SymbolIndex::new(symbols) 197 SymbolIndex::new(symbols)
179 } 198 }
180 199
200 #[cfg(feature = "wasm")]
201 pub(crate) fn for_files(
202 files: impl Iterator<Item = (FileId, Parse<ast::SourceFile>)>,
203 ) -> SymbolIndex {
204 let symbols = files
205 .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
206 .collect::<Vec<_>>();
207 SymbolIndex::new(symbols)
208 }
209
181 fn range_to_map_value(start: usize, end: usize) -> u64 { 210 fn range_to_map_value(start: usize, end: usize) -> u64 {
182 debug_assert![start <= (std::u32::MAX as usize)]; 211 debug_assert![start <= (std::u32::MAX as usize)];
183 debug_assert![end <= (std::u32::MAX as usize)]; 212 debug_assert![end <= (std::u32::MAX as usize)];
diff --git a/crates/ra_ide_api/src/wasm_shims.rs b/crates/ra_ide_api/src/wasm_shims.rs
new file mode 100644
index 000000000..592dddf44
--- /dev/null
+++ b/crates/ra_ide_api/src/wasm_shims.rs
@@ -0,0 +1,17 @@
1#[cfg(not(feature = "wasm"))]
2pub use std::time::Instant;
3
4#[cfg(feature = "wasm")]
5#[derive(Clone, Copy, Debug)]
6pub struct Instant;
7
8#[cfg(feature = "wasm")]
9impl Instant {
10 pub fn now() -> Self {
11 Self
12 }
13
14 pub fn elapsed(&self) -> std::time::Duration {
15 std::time::Duration::new(0, 0)
16 }
17}
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index 6c7fdc2cd..457f42a26 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -54,6 +54,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
54 LIFETIME, 54 LIFETIME,
55 ASYNC_KW, 55 ASYNC_KW,
56 TRY_KW, 56 TRY_KW,
57 LOOP_KW
57 ]); 58 ]);
58 59
59const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; 60const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index a4ffd6960..aa9a6d18e 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -167,7 +167,7 @@ fn record_field_pat_list(p: &mut Parser) {
167 // A trailing `..` is *not* treated as a DOT_DOT_PAT. 167 // A trailing `..` is *not* treated as a DOT_DOT_PAT.
168 T![.] if p.at(T![..]) => p.bump(T![..]), 168 T![.] if p.at(T![..]) => p.bump(T![..]),
169 169
170 IDENT if p.nth(1) == T![:] => record_field_pat(p), 170 IDENT | INT_NUMBER if p.nth(1) == T![:] => record_field_pat(p),
171 T!['{'] => error_block(p, "expected ident"), 171 T!['{'] => error_block(p, "expected ident"),
172 T![box] => { 172 T![box] => {
173 box_pat(p); 173 box_pat(p);
@@ -184,12 +184,21 @@ fn record_field_pat_list(p: &mut Parser) {
184 m.complete(p, RECORD_FIELD_PAT_LIST); 184 m.complete(p, RECORD_FIELD_PAT_LIST);
185} 185}
186 186
187// test record_field_pat
188// fn foo() {
189// let S { 0: 1 } = ();
190// let S { x: 1 } = ();
191// }
187fn record_field_pat(p: &mut Parser) { 192fn record_field_pat(p: &mut Parser) {
188 assert!(p.at(IDENT)); 193 assert!(p.at(IDENT) || p.at(INT_NUMBER));
189 assert!(p.nth(1) == T![:]); 194 assert!(p.nth(1) == T![:]);
190 195
191 let m = p.start(); 196 let m = p.start();
192 name(p); 197
198 if !p.eat(INT_NUMBER) {
199 name(p)
200 }
201
193 p.bump_any(); 202 p.bump_any();
194 pattern(p); 203 pattern(p);
195 m.complete(p, RECORD_FIELD_PAT); 204 m.complete(p, RECORD_FIELD_PAT);
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rs b/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rs
new file mode 100644
index 000000000..26b1d5f89
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 let S { 0: 1 } = ();
3 let S { x: 1 } = ();
4}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.txt b/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.txt
new file mode 100644
index 000000000..06fbdfabf
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.txt
@@ -0,0 +1,75 @@
1SOURCE_FILE@[0; 63)
2 FN_DEF@[0; 62)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " "
11 BLOCK_EXPR@[9; 62)
12 BLOCK@[9; 62)
13 L_CURLY@[9; 10) "{"
14 WHITESPACE@[10; 15) "\n "
15 LET_STMT@[15; 35)
16 LET_KW@[15; 18) "let"
17 WHITESPACE@[18; 19) " "
18 RECORD_PAT@[19; 29)
19 PATH@[19; 20)
20 PATH_SEGMENT@[19; 20)
21 NAME_REF@[19; 20)
22 IDENT@[19; 20) "S"
23 WHITESPACE@[20; 21) " "
24 RECORD_FIELD_PAT_LIST@[21; 29)
25 L_CURLY@[21; 22) "{"
26 WHITESPACE@[22; 23) " "
27 RECORD_FIELD_PAT@[23; 27)
28 INT_NUMBER@[23; 24) "0"
29 COLON@[24; 25) ":"
30 WHITESPACE@[25; 26) " "
31 LITERAL_PAT@[26; 27)
32 LITERAL@[26; 27)
33 INT_NUMBER@[26; 27) "1"
34 WHITESPACE@[27; 28) " "
35 R_CURLY@[28; 29) "}"
36 WHITESPACE@[29; 30) " "
37 EQ@[30; 31) "="
38 WHITESPACE@[31; 32) " "
39 TUPLE_EXPR@[32; 34)
40 L_PAREN@[32; 33) "("
41 R_PAREN@[33; 34) ")"
42 SEMI@[34; 35) ";"
43 WHITESPACE@[35; 40) "\n "
44 LET_STMT@[40; 60)
45 LET_KW@[40; 43) "let"
46 WHITESPACE@[43; 44) " "
47 RECORD_PAT@[44; 54)
48 PATH@[44; 45)
49 PATH_SEGMENT@[44; 45)
50 NAME_REF@[44; 45)
51 IDENT@[44; 45) "S"
52 WHITESPACE@[45; 46) " "
53 RECORD_FIELD_PAT_LIST@[46; 54)
54 L_CURLY@[46; 47) "{"
55 WHITESPACE@[47; 48) " "
56 RECORD_FIELD_PAT@[48; 52)
57 NAME@[48; 49)
58 IDENT@[48; 49) "x"
59 COLON@[49; 50) ":"
60 WHITESPACE@[50; 51) " "
61 LITERAL_PAT@[51; 52)
62 LITERAL@[51; 52)
63 INT_NUMBER@[51; 52) "1"
64 WHITESPACE@[52; 53) " "
65 R_CURLY@[53; 54) "}"
66 WHITESPACE@[54; 55) " "
67 EQ@[55; 56) "="
68 WHITESPACE@[56; 57) " "
69 TUPLE_EXPR@[57; 59)
70 L_PAREN@[57; 58) "("
71 R_PAREN@[58; 59) ")"
72 SEMI@[59; 60) ";"
73 WHITESPACE@[60; 61) "\n"
74 R_CURLY@[61; 62) "}"
75 WHITESPACE@[62; 63) "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rs b/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rs
new file mode 100644
index 000000000..31c12522f
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rs
@@ -0,0 +1,5 @@
1fn foo(x: i32) {}
2
3fn main() {
4 foo(loop {});
5} \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.txt b/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.txt
new file mode 100644
index 000000000..cc8c3f7ec
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.txt
@@ -0,0 +1,59 @@
1SOURCE_FILE@[0; 50)
2 FN_DEF@[0; 17)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 14)
8 L_PAREN@[6; 7) "("
9 PARAM@[7; 13)
10 BIND_PAT@[7; 8)
11 NAME@[7; 8)
12 IDENT@[7; 8) "x"
13 COLON@[8; 9) ":"
14 WHITESPACE@[9; 10) " "
15 PATH_TYPE@[10; 13)
16 PATH@[10; 13)
17 PATH_SEGMENT@[10; 13)
18 NAME_REF@[10; 13)
19 IDENT@[10; 13) "i32"
20 R_PAREN@[13; 14) ")"
21 WHITESPACE@[14; 15) " "
22 BLOCK_EXPR@[15; 17)
23 BLOCK@[15; 17)
24 L_CURLY@[15; 16) "{"
25 R_CURLY@[16; 17) "}"
26 WHITESPACE@[17; 19) "\n\n"
27 FN_DEF@[19; 50)
28 FN_KW@[19; 21) "fn"
29 WHITESPACE@[21; 22) " "
30 NAME@[22; 26)
31 IDENT@[22; 26) "main"
32 PARAM_LIST@[26; 28)
33 L_PAREN@[26; 27) "("
34 R_PAREN@[27; 28) ")"
35 WHITESPACE@[28; 29) " "
36 BLOCK_EXPR@[29; 50)
37 BLOCK@[29; 50)
38 L_CURLY@[29; 30) "{"
39 WHITESPACE@[30; 35) "\n "
40 EXPR_STMT@[35; 48)
41 CALL_EXPR@[35; 47)
42 PATH_EXPR@[35; 38)
43 PATH@[35; 38)
44 PATH_SEGMENT@[35; 38)
45 NAME_REF@[35; 38)
46 IDENT@[35; 38) "foo"
47 ARG_LIST@[38; 47)
48 L_PAREN@[38; 39) "("
49 LOOP_EXPR@[39; 46)
50 LOOP_KW@[39; 43) "loop"
51 WHITESPACE@[43; 44) " "
52 BLOCK_EXPR@[44; 46)
53 BLOCK@[44; 46)
54 L_CURLY@[44; 45) "{"
55 R_CURLY@[45; 46) "}"
56 R_PAREN@[46; 47) ")"
57 SEMI@[47; 48) ";"
58 WHITESPACE@[48; 49) "\n"
59 R_CURLY@[49; 50) "}"
diff --git a/crates/ra_tools/src/main.rs b/crates/ra_tools/src/main.rs
index 65d211b44..a951ce427 100644
--- a/crates/ra_tools/src/main.rs
+++ b/crates/ra_tools/src/main.rs
@@ -167,7 +167,7 @@ fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
167 } 167 }
168 .run()?; 168 .run()?;
169 169
170 let code_binary = ["code", "code-insiders"].iter().find(|bin| { 170 let code_binary = ["code", "code-insiders", "codium"].iter().find(|bin| {
171 Cmd { 171 Cmd {
172 unix: &format!("{} --version", bin), 172 unix: &format!("{} --version", bin),
173 windows: &format!("cmd.exe /c {}.cmd --version", bin), 173 windows: &format!("cmd.exe /c {}.cmd --version", bin),