diff options
21 files changed, 303 insertions, 157 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ff7a95ee1..eae4fbcb5 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -190,4 +190,4 @@ jobs: | |||
190 | - name: Publish Extension | 190 | - name: Publish Extension |
191 | working-directory: ./editors/code | 191 | working-directory: ./editors/code |
192 | # token from https://dev.azure.com/rust-analyzer/ | 192 | # token from https://dev.azure.com/rust-analyzer/ |
193 | run: ./node_modules/vsce/out/vsce publish 0.1.$(date +%Y%m%d) --pat ${{ secrets.MARKETPLACE_TOKEN }} | 193 | run: npx vsce publish 0.1.$(date +%Y%m%d) --pat ${{ secrets.MARKETPLACE_TOKEN }} |
diff --git a/.vscode/launch.json b/.vscode/launch.json index 55a2f10f2..b1bd98d4a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json | |||
@@ -2,39 +2,61 @@ | |||
2 | // Use IntelliSense to learn about possible attributes. | 2 | // Use IntelliSense to learn about possible attributes. |
3 | // Hover to view descriptions of existing attributes. | 3 | // Hover to view descriptions of existing attributes. |
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 |
5 | |||
6 | // NOTE: --disable-extensions | ||
7 | // Disable all installed extensions to increase performance of the debug instance | ||
8 | // and prevent potential conflicts with other installed extensions. | ||
9 | |||
5 | "version": "0.2.0", | 10 | "version": "0.2.0", |
6 | "configurations": [ | 11 | "configurations": [ |
7 | { | 12 | { |
13 | // Used for testing the extension with the installed LSP server. | ||
8 | "name": "Run Extension", | 14 | "name": "Run Extension", |
9 | "type": "extensionHost", | 15 | "type": "extensionHost", |
10 | "request": "launch", | 16 | "request": "launch", |
11 | "runtimeExecutable": "${execPath}", | 17 | "runtimeExecutable": "${execPath}", |
12 | "args": [ | 18 | "args": [ |
19 | "--disable-extensions", | ||
13 | "--extensionDevelopmentPath=${workspaceFolder}/editors/code" | 20 | "--extensionDevelopmentPath=${workspaceFolder}/editors/code" |
14 | ], | 21 | ], |
15 | "outFiles": [ | 22 | "outFiles": [ |
16 | "${workspaceFolder}/editors/code/out/**/*.js" | 23 | "${workspaceFolder}/editors/code/out/**/*.js" |
17 | ], | 24 | ], |
18 | "preLaunchTask": "Build Extension" | 25 | "preLaunchTask": "Build Extension", |
26 | "skipFiles": [ | ||
27 | "<node_internals>/**/*.js" | ||
28 | ] | ||
19 | }, | 29 | }, |
20 | { | 30 | { |
31 | // Used for testing the extension with a local build of the LSP server (in `target/debug`). | ||
21 | "name": "Run Extension (Dev Server)", | 32 | "name": "Run Extension (Dev Server)", |
22 | "type": "extensionHost", | 33 | "type": "extensionHost", |
23 | "request": "launch", | 34 | "request": "launch", |
24 | "runtimeExecutable": "${execPath}", | 35 | "runtimeExecutable": "${execPath}", |
25 | "args": [ | 36 | "args": [ |
37 | "--disable-extensions", | ||
26 | "--extensionDevelopmentPath=${workspaceFolder}/editors/code" | 38 | "--extensionDevelopmentPath=${workspaceFolder}/editors/code" |
27 | ], | 39 | ], |
28 | "outFiles": [ | 40 | "outFiles": [ |
29 | "${workspaceFolder}/editors/code/out/**/*.js" | 41 | "${workspaceFolder}/editors/code/out/**/*.js" |
30 | ], | 42 | ], |
31 | "preLaunchTask": "Build Extension", | 43 | "preLaunchTask": "Build Extension", |
44 | "skipFiles": [ | ||
45 | "<node_internals>/**/*.js" | ||
46 | ], | ||
32 | "env": { | 47 | "env": { |
33 | "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/ra_lsp_server" | 48 | "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/ra_lsp_server" |
34 | } | 49 | } |
35 | }, | 50 | }, |
36 | { | 51 | { |
37 | "name": "Debug Lsp Server", | 52 | // Used to attach LLDB to a running LSP server. |
53 | // NOTE: Might require root permissions. For this run: | ||
54 | // | ||
55 | // `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope` | ||
56 | // | ||
57 | // Don't forget to set `debug = 2` in `Cargo.toml` before building the server | ||
58 | |||
59 | "name": "Attach To Server", | ||
38 | "type": "lldb", | 60 | "type": "lldb", |
39 | "request": "attach", | 61 | "request": "attach", |
40 | "program": "${workspaceFolder}/target/debug/ra_lsp_server", | 62 | "program": "${workspaceFolder}/target/debug/ra_lsp_server", |
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs index 5485a38ff..4835a68ce 100644 --- a/crates/ra_cli/src/analysis_bench.rs +++ b/crates/ra_cli/src/analysis_bench.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | path::{Path, PathBuf}, | 4 | path::{Path, PathBuf}, |
5 | str::FromStr, | ||
5 | sync::Arc, | 6 | sync::Arc, |
6 | time::Instant, | 7 | time::Instant, |
7 | }; | 8 | }; |
@@ -14,12 +15,35 @@ use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol}; | |||
14 | 15 | ||
15 | use crate::Result; | 16 | use crate::Result; |
16 | 17 | ||
18 | pub(crate) struct Position { | ||
19 | path: PathBuf, | ||
20 | line: u32, | ||
21 | column: u32, | ||
22 | } | ||
23 | |||
24 | impl FromStr for Position { | ||
25 | type Err = Box<dyn std::error::Error + Send + Sync>; | ||
26 | fn from_str(s: &str) -> Result<Self> { | ||
27 | let (path_line, column) = rsplit_at_char(s, ':')?; | ||
28 | let (path, line) = rsplit_at_char(path_line, ':')?; | ||
29 | Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? }) | ||
30 | } | ||
31 | } | ||
32 | |||
33 | fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> { | ||
34 | let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?; | ||
35 | Ok((&s[..idx], &s[idx + 1..])) | ||
36 | } | ||
37 | |||
17 | pub(crate) enum Op { | 38 | pub(crate) enum Op { |
18 | Highlight { path: PathBuf }, | 39 | Highlight { path: PathBuf }, |
19 | Complete { path: PathBuf, line: u32, column: u32 }, | 40 | Complete(Position), |
41 | GotoDef(Position), | ||
20 | } | 42 | } |
21 | 43 | ||
22 | pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { | 44 | pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { |
45 | ra_prof::init(); | ||
46 | |||
23 | let start = Instant::now(); | 47 | let start = Instant::now(); |
24 | eprint!("loading: "); | 48 | eprint!("loading: "); |
25 | let (mut host, roots) = ra_batch::load_cargo(path)?; | 49 | let (mut host, roots) = ra_batch::load_cargo(path)?; |
@@ -29,7 +53,7 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { | |||
29 | let file_id = { | 53 | let file_id = { |
30 | let path = match &op { | 54 | let path = match &op { |
31 | Op::Highlight { path } => path, | 55 | Op::Highlight { path } => path, |
32 | Op::Complete { path, .. } => path, | 56 | Op::Complete(pos) | Op::GotoDef(pos) => &pos.path, |
33 | }; | 57 | }; |
34 | let path = std::env::current_dir()?.join(path).canonicalize()?; | 58 | let path = std::env::current_dir()?.join(path).canonicalize()?; |
35 | roots | 59 | roots |
@@ -49,7 +73,7 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { | |||
49 | .ok_or_else(|| format!("Can't find {:?}", path))? | 73 | .ok_or_else(|| format!("Can't find {:?}", path))? |
50 | }; | 74 | }; |
51 | 75 | ||
52 | match op { | 76 | match &op { |
53 | Op::Highlight { .. } => { | 77 | Op::Highlight { .. } => { |
54 | let res = do_work(&mut host, file_id, |analysis| { | 78 | let res = do_work(&mut host, file_id, |analysis| { |
55 | analysis.diagnostics(file_id).unwrap(); | 79 | analysis.diagnostics(file_id).unwrap(); |
@@ -59,16 +83,30 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { | |||
59 | println!("\n{}", res); | 83 | println!("\n{}", res); |
60 | } | 84 | } |
61 | } | 85 | } |
62 | Op::Complete { line, column, .. } => { | 86 | Op::Complete(pos) | Op::GotoDef(pos) => { |
87 | let is_completion = match op { | ||
88 | Op::Complete(..) => true, | ||
89 | _ => false, | ||
90 | }; | ||
91 | |||
63 | let offset = host | 92 | let offset = host |
64 | .analysis() | 93 | .analysis() |
65 | .file_line_index(file_id)? | 94 | .file_line_index(file_id)? |
66 | .offset(LineCol { line, col_utf16: column }); | 95 | .offset(LineCol { line: pos.line - 1, col_utf16: pos.column }); |
67 | let file_postion = FilePosition { file_id, offset }; | 96 | let file_postion = FilePosition { file_id, offset }; |
68 | 97 | ||
69 | let res = do_work(&mut host, file_id, |analysis| analysis.completions(file_postion)); | 98 | if is_completion { |
70 | if verbose { | 99 | let res = |
71 | println!("\n{:#?}", res); | 100 | do_work(&mut host, file_id, |analysis| analysis.completions(file_postion)); |
101 | if verbose { | ||
102 | println!("\n{:#?}", res); | ||
103 | } | ||
104 | } else { | ||
105 | let res = | ||
106 | do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion)); | ||
107 | if verbose { | ||
108 | println!("\n{:#?}", res); | ||
109 | } | ||
72 | } | 110 | } |
73 | } | 111 | } |
74 | } | 112 | } |
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index 6a0e447b9..750cbab86 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -132,25 +132,16 @@ fn main() -> Result<()> { | |||
132 | } | 132 | } |
133 | let verbose = matches.contains(["-v", "--verbose"]); | 133 | let verbose = matches.contains(["-v", "--verbose"]); |
134 | let path: String = matches.opt_value_from_str("--path")?.unwrap_or_default(); | 134 | let path: String = matches.opt_value_from_str("--path")?.unwrap_or_default(); |
135 | let highlight_path = matches.opt_value_from_str("--highlight")?; | 135 | let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?; |
136 | let complete_path = matches.opt_value_from_str("--complete")?; | 136 | let complete_path: Option<String> = matches.opt_value_from_str("--complete")?; |
137 | if highlight_path.is_some() && complete_path.is_some() { | 137 | let goto_def_path: Option<String> = matches.opt_value_from_str("--goto-def")?; |
138 | panic!("either --highlight or --complete must be set, not both") | 138 | let op = match (highlight_path, complete_path, goto_def_path) { |
139 | } | 139 | (Some(path), None, None) => analysis_bench::Op::Highlight { path: path.into() }, |
140 | let op = if let Some(path) = highlight_path { | 140 | (None, Some(position), None) => analysis_bench::Op::Complete(position.parse()?), |
141 | let path: String = path; | 141 | (None, None, Some(position)) => analysis_bench::Op::GotoDef(position.parse()?), |
142 | analysis_bench::Op::Highlight { path: path.into() } | 142 | _ => panic!( |
143 | } else if let Some(path_line_col) = complete_path { | 143 | "exactly one of `--highlight`, `--complete` or `--goto-def` must be set" |
144 | let path_line_col: String = path_line_col; | 144 | ), |
145 | let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?; | ||
146 | let (path, line) = rsplit_at_char(path_line, ':')?; | ||
147 | analysis_bench::Op::Complete { | ||
148 | path: path.into(), | ||
149 | line: line.parse()?, | ||
150 | column: column.parse()?, | ||
151 | } | ||
152 | } else { | ||
153 | panic!("either --highlight or --complete must be set") | ||
154 | }; | 145 | }; |
155 | matches.finish().or_else(handle_extra_flags)?; | 146 | matches.finish().or_else(handle_extra_flags)?; |
156 | analysis_bench::run(verbose, path.as_ref(), op)?; | 147 | analysis_bench::run(verbose, path.as_ref(), op)?; |
@@ -183,8 +174,3 @@ fn read_stdin() -> Result<String> { | |||
183 | std::io::stdin().read_to_string(&mut buff)?; | 174 | std::io::stdin().read_to_string(&mut buff)?; |
184 | Ok(buff) | 175 | Ok(buff) |
185 | } | 176 | } |
186 | |||
187 | fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> { | ||
188 | let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?; | ||
189 | Ok((&s[..idx], &s[idx + 1..])) | ||
190 | } | ||
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index fe05642ae..1dc842f40 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -249,6 +249,8 @@ impl InferenceTable { | |||
249 | match (ty1, ty2) { | 249 | match (ty1, ty2) { |
250 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, | 250 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, |
251 | 251 | ||
252 | (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, | ||
253 | |||
252 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | 254 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) |
253 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | 255 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) |
254 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) | 256 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index fc5ef36a5..42330b269 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -526,3 +526,25 @@ fn test() { | |||
526 | "### | 526 | "### |
527 | ); | 527 | ); |
528 | } | 528 | } |
529 | |||
530 | #[test] | ||
531 | fn coerce_placeholder_ref() { | ||
532 | // placeholders should unify, even behind references | ||
533 | assert_snapshot!( | ||
534 | infer_with_mismatches(r#" | ||
535 | struct S<T> { t: T } | ||
536 | impl<TT> S<TT> { | ||
537 | fn get(&self) -> &TT { | ||
538 | &self.t | ||
539 | } | ||
540 | } | ||
541 | "#, true), | ||
542 | @r###" | ||
543 | [51; 55) 'self': &S<TT> | ||
544 | [64; 87) '{ ... }': &TT | ||
545 | [74; 81) '&self.t': &TT | ||
546 | [75; 79) 'self': &S<TT> | ||
547 | [75; 81) 'self.t': TT | ||
548 | "### | ||
549 | ); | ||
550 | } | ||
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index 1cc55e78b..a02dbaf2f 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html | |||
@@ -16,6 +16,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
16 | .literal { color: #BFEBBF; } | 16 | .literal { color: #BFEBBF; } |
17 | .literal\.numeric { color: #6A8759; } | 17 | .literal\.numeric { color: #6A8759; } |
18 | .macro { color: #94BFF3; } | 18 | .macro { color: #94BFF3; } |
19 | .module { color: #AFD8AF; } | ||
19 | .variable { color: #DCDCCC; } | 20 | .variable { color: #DCDCCC; } |
20 | .variable\.mut { color: #DCDCCC; text-decoration: underline; } | 21 | .variable\.mut { color: #DCDCCC; text-decoration: underline; } |
21 | 22 | ||
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 918fd4b97..95f038f00 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html | |||
@@ -16,6 +16,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
16 | .literal { color: #BFEBBF; } | 16 | .literal { color: #BFEBBF; } |
17 | .literal\.numeric { color: #6A8759; } | 17 | .literal\.numeric { color: #6A8759; } |
18 | .macro { color: #94BFF3; } | 18 | .macro { color: #94BFF3; } |
19 | .module { color: #AFD8AF; } | ||
19 | .variable { color: #DCDCCC; } | 20 | .variable { color: #DCDCCC; } |
20 | .variable\.mut { color: #DCDCCC; text-decoration: underline; } | 21 | .variable\.mut { color: #DCDCCC; text-decoration: underline; } |
21 | 22 | ||
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 174e13595..20c414ca1 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -365,6 +365,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
365 | .literal { color: #BFEBBF; } | 365 | .literal { color: #BFEBBF; } |
366 | .literal\\.numeric { color: #6A8759; } | 366 | .literal\\.numeric { color: #6A8759; } |
367 | .macro { color: #94BFF3; } | 367 | .macro { color: #94BFF3; } |
368 | .module { color: #AFD8AF; } | ||
368 | .variable { color: #DCDCCC; } | 369 | .variable { color: #DCDCCC; } |
369 | .variable\\.mut { color: #DCDCCC; text-decoration: underline; } | 370 | .variable\\.mut { color: #DCDCCC; text-decoration: underline; } |
370 | 371 | ||
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index c8a017c5c..ed2eaabd4 100644 --- a/crates/ra_lsp_server/src/main.rs +++ b/crates/ra_lsp_server/src/main.rs | |||
@@ -15,13 +15,8 @@ fn main() -> Result<()> { | |||
15 | 15 | ||
16 | fn setup_logging() -> Result<()> { | 16 | fn setup_logging() -> Result<()> { |
17 | std::env::set_var("RUST_BACKTRACE", "short"); | 17 | std::env::set_var("RUST_BACKTRACE", "short"); |
18 | |||
19 | env_logger::try_init()?; | 18 | env_logger::try_init()?; |
20 | 19 | ra_prof::init(); | |
21 | ra_prof::set_filter(match std::env::var("RA_PROFILE") { | ||
22 | Ok(spec) => ra_prof::Filter::from_spec(&spec), | ||
23 | Err(_) => ra_prof::Filter::disabled(), | ||
24 | }); | ||
25 | Ok(()) | 20 | Ok(()) |
26 | } | 21 | } |
27 | 22 | ||
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs index d38ff397e..c0bfbc2ee 100644 --- a/crates/ra_prof/src/lib.rs +++ b/crates/ra_prof/src/lib.rs | |||
@@ -26,6 +26,13 @@ pub use crate::memory_usage::{Bytes, MemoryUsage}; | |||
26 | #[global_allocator] | 26 | #[global_allocator] |
27 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; | 27 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; |
28 | 28 | ||
29 | pub fn init() { | ||
30 | set_filter(match std::env::var("RA_PROFILE") { | ||
31 | Ok(spec) => Filter::from_spec(&spec), | ||
32 | Err(_) => Filter::disabled(), | ||
33 | }); | ||
34 | } | ||
35 | |||
29 | /// Set profiling filter. It specifies descriptions allowed to profile. | 36 | /// Set profiling filter. It specifies descriptions allowed to profile. |
30 | /// This is helpful when call stack has too many nested profiling scopes. | 37 | /// This is helpful when call stack has too many nested profiling scopes. |
31 | /// Additionally filter can specify maximum depth of profiling scopes nesting. | 38 | /// Additionally filter can specify maximum depth of profiling scopes nesting. |
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc index 867aae975..553687e78 100644 --- a/docs/user/readme.adoc +++ b/docs/user/readme.adoc | |||
@@ -27,8 +27,9 @@ https://github.com/rust-analyzer/rust-analyzer/tree/master/editors/code[in tree] | |||
27 | 27 | ||
28 | You can install the latest release of the plugin from | 28 | You can install the latest release of the plugin from |
29 | https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. | 29 | https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. |
30 | By default, the plugin will download the latest version of the server as well. | 30 | By default, the plugin will download the matching version of the server as well. |
31 | 31 | ||
32 | // FIXME: update the image (its text has changed) | ||
32 | image::https://user-images.githubusercontent.com/36276403/74103174-a40df100-4b52-11ea-81f4-372c70797924.png[] | 33 | image::https://user-images.githubusercontent.com/36276403/74103174-a40df100-4b52-11ea-81f4-372c70797924.png[] |
33 | 34 | ||
34 | The server binary is stored in `~/.config/Code/User/globalStorage/matklad.rust-analyzer`. | 35 | The server binary is stored in `~/.config/Code/User/globalStorage/matklad.rust-analyzer`. |
@@ -37,9 +38,7 @@ Note that we only support the latest version of VS Code. | |||
37 | 38 | ||
38 | ==== Updates | 39 | ==== Updates |
39 | 40 | ||
40 | The extension will be updated automatically as new versions become available. | 41 | The extension will be updated automatically as new versions become available. It will ask your permission to download the matching language server version binary if needed. |
41 | The server update functionality is in progress. | ||
42 | For the time being, the workaround is to remove the binary from `globalStorage` and to restart the extension. | ||
43 | 42 | ||
44 | ==== Building From Source | 43 | ==== Building From Source |
45 | 44 | ||
diff --git a/editors/code/package.json b/editors/code/package.json index a607c2148..ed1cae2ab 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -6,7 +6,7 @@ | |||
6 | "private": true, | 6 | "private": true, |
7 | "icon": "icon.png", | 7 | "icon": "icon.png", |
8 | "//": "The real version is in release.yaml, this one just needs to be bigger", | 8 | "//": "The real version is in release.yaml, this one just needs to be bigger", |
9 | "version": "0.2.0-dev", | 9 | "version": "0.2.20200211-dev", |
10 | "publisher": "matklad", | 10 | "publisher": "matklad", |
11 | "repository": { | 11 | "repository": { |
12 | "url": "https://github.com/rust-analyzer/rust-analyzer.git", | 12 | "url": "https://github.com/rust-analyzer/rust-analyzer.git", |
@@ -233,11 +233,10 @@ | |||
233 | "description": "Trace requests to the ra_lsp_server" | 233 | "description": "Trace requests to the ra_lsp_server" |
234 | }, | 234 | }, |
235 | "rust-analyzer.lruCapacity": { | 235 | "rust-analyzer.lruCapacity": { |
236 | "type": [ | 236 | "type": [ "null", "integer" ], |
237 | "number", | ||
238 | "null" | ||
239 | ], | ||
240 | "default": null, | 237 | "default": null, |
238 | "minimum": 0, | ||
239 | "exclusiveMinimum": true, | ||
241 | "description": "Number of syntax trees rust-analyzer keeps in memory" | 240 | "description": "Number of syntax trees rust-analyzer keeps in memory" |
242 | }, | 241 | }, |
243 | "rust-analyzer.displayInlayHints": { | 242 | "rust-analyzer.displayInlayHints": { |
@@ -246,9 +245,10 @@ | |||
246 | "description": "Display additional type and parameter information in the editor" | 245 | "description": "Display additional type and parameter information in the editor" |
247 | }, | 246 | }, |
248 | "rust-analyzer.maxInlayHintLength": { | 247 | "rust-analyzer.maxInlayHintLength": { |
249 | "type": "number", | 248 | "type": [ "null", "integer" ], |
250 | "default": 20, | 249 | "default": 20, |
251 | "exclusiveMinimum": 0, | 250 | "minimum": 0, |
251 | "exclusiveMinimum": true, | ||
252 | "description": "Maximum length for inlay hints" | 252 | "description": "Maximum length for inlay hints" |
253 | }, | 253 | }, |
254 | "rust-analyzer.cargoFeatures.noDefaultFeatures": { | 254 | "rust-analyzer.cargoFeatures.noDefaultFeatures": { |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 12c97be2f..efef820ab 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -11,7 +11,7 @@ export async function createClient(config: Config): Promise<null | lc.LanguageCl | |||
11 | // It might be a good idea to test if the uri points to a file. | 11 | // It might be a good idea to test if the uri points to a file. |
12 | const workspaceFolderPath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '.'; | 12 | const workspaceFolderPath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '.'; |
13 | 13 | ||
14 | const serverPath = await ensureServerBinary(config.serverBinarySource); | 14 | const serverPath = await ensureServerBinary(config.serverSource); |
15 | if (!serverPath) return null; | 15 | if (!serverPath) return null; |
16 | 16 | ||
17 | const run: lc.Executable = { | 17 | const run: lc.Executable = { |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 7866ed7e1..70cb0a612 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -24,6 +24,19 @@ export class Config { | |||
24 | ] | 24 | ] |
25 | .map(opt => `${Config.rootSection}.${opt}`); | 25 | .map(opt => `${Config.rootSection}.${opt}`); |
26 | 26 | ||
27 | private static readonly extensionVersion: string = (() => { | ||
28 | const packageJsonVersion = vscode | ||
29 | .extensions | ||
30 | .getExtension("matklad.rust-analyzer")! | ||
31 | .packageJSON | ||
32 | .version as string; // n.n.YYYYMMDD | ||
33 | |||
34 | const realVersionRegexp = /^\d+\.\d+\.(\d{4})(\d{2})(\d{2})/; | ||
35 | const [, yyyy, mm, dd] = packageJsonVersion.match(realVersionRegexp)!; | ||
36 | |||
37 | return `${yyyy}-${mm}-${dd}`; | ||
38 | })(); | ||
39 | |||
27 | private cfg!: vscode.WorkspaceConfiguration; | 40 | private cfg!: vscode.WorkspaceConfiguration; |
28 | 41 | ||
29 | constructor(private readonly ctx: vscode.ExtensionContext) { | 42 | constructor(private readonly ctx: vscode.ExtensionContext) { |
@@ -98,7 +111,7 @@ export class Config { | |||
98 | } | 111 | } |
99 | } | 112 | } |
100 | 113 | ||
101 | get serverBinarySource(): null | BinarySource { | 114 | get serverSource(): null | BinarySource { |
102 | const serverPath = RA_LSP_DEBUG ?? this.cfg.get<null | string>("raLspServerPath"); | 115 | const serverPath = RA_LSP_DEBUG ?? this.cfg.get<null | string>("raLspServerPath"); |
103 | 116 | ||
104 | if (serverPath) { | 117 | if (serverPath) { |
@@ -116,6 +129,8 @@ export class Config { | |||
116 | type: BinarySource.Type.GithubRelease, | 129 | type: BinarySource.Type.GithubRelease, |
117 | dir: this.ctx.globalStoragePath, | 130 | dir: this.ctx.globalStoragePath, |
118 | file: prebuiltBinaryName, | 131 | file: prebuiltBinaryName, |
132 | storage: this.ctx.globalState, | ||
133 | version: Config.extensionVersion, | ||
119 | repo: { | 134 | repo: { |
120 | name: "rust-analyzer", | 135 | name: "rust-analyzer", |
121 | owner: "rust-analyzer", | 136 | owner: "rust-analyzer", |
@@ -153,5 +168,5 @@ export class Config { | |||
153 | } | 168 | } |
154 | 169 | ||
155 | // for internal use | 170 | // for internal use |
156 | get withSysroot() { return this.cfg.get("withSysroot", false); } | 171 | get withSysroot() { return this.cfg.get("withSysroot", true) as boolean; } |
157 | } | 172 | } |
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 70042a479..9fcf2ec38 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts | |||
@@ -60,6 +60,10 @@ export class Ctx { | |||
60 | this.pushCleanup(d); | 60 | this.pushCleanup(d); |
61 | } | 61 | } |
62 | 62 | ||
63 | get globalState(): vscode.Memento { | ||
64 | return this.extCtx.globalState; | ||
65 | } | ||
66 | |||
63 | get subscriptions(): Disposable[] { | 67 | get subscriptions(): Disposable[] { |
64 | return this.extCtx.subscriptions; | 68 | return this.extCtx.subscriptions; |
65 | } | 69 | } |
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index 1c019a51b..c317a9213 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts | |||
@@ -13,7 +13,7 @@ export function activateInlayHints(ctx: Ctx) { | |||
13 | 13 | ||
14 | vscode.workspace.onDidChangeTextDocument( | 14 | vscode.workspace.onDidChangeTextDocument( |
15 | async event => { | 15 | async event => { |
16 | if (event.contentChanges.length !== 0) return; | 16 | if (event.contentChanges.length === 0) return; |
17 | if (event.document.languageId !== 'rust') return; | 17 | if (event.document.languageId !== 'rust') return; |
18 | await hintsUpdater.refresh(); | 18 | await hintsUpdater.refresh(); |
19 | }, | 19 | }, |
diff --git a/editors/code/src/installation/download_artifact.ts b/editors/code/src/installation/download_artifact.ts new file mode 100644 index 000000000..de655f8f4 --- /dev/null +++ b/editors/code/src/installation/download_artifact.ts | |||
@@ -0,0 +1,58 @@ | |||
1 | import * as vscode from "vscode"; | ||
2 | import * as path from "path"; | ||
3 | import { promises as fs } from "fs"; | ||
4 | import { strict as assert } from "assert"; | ||
5 | |||
6 | import { ArtifactReleaseInfo } from "./interfaces"; | ||
7 | import { downloadFile } from "./download_file"; | ||
8 | import { throttle } from "throttle-debounce"; | ||
9 | |||
10 | /** | ||
11 | * Downloads artifact from given `downloadUrl`. | ||
12 | * Creates `installationDir` if it is not yet created and put the artifact under | ||
13 | * `artifactFileName`. | ||
14 | * Displays info about the download progress in an info message printing the name | ||
15 | * of the artifact as `displayName`. | ||
16 | */ | ||
17 | export async function downloadArtifact( | ||
18 | {downloadUrl, releaseName}: ArtifactReleaseInfo, | ||
19 | artifactFileName: string, | ||
20 | installationDir: string, | ||
21 | displayName: string, | ||
22 | ) { | ||
23 | await fs.mkdir(installationDir).catch(err => assert.strictEqual( | ||
24 | err?.code, | ||
25 | "EEXIST", | ||
26 | `Couldn't create directory "${installationDir}" to download `+ | ||
27 | `${artifactFileName} artifact: ${err.message}` | ||
28 | )); | ||
29 | |||
30 | const installationPath = path.join(installationDir, artifactFileName); | ||
31 | |||
32 | console.time(`Downloading ${artifactFileName}`); | ||
33 | await vscode.window.withProgress( | ||
34 | { | ||
35 | location: vscode.ProgressLocation.Notification, | ||
36 | cancellable: false, // FIXME: add support for canceling download? | ||
37 | title: `Downloading ${displayName} (${releaseName})` | ||
38 | }, | ||
39 | async (progress, _cancellationToken) => { | ||
40 | let lastPrecentage = 0; | ||
41 | const filePermissions = 0o755; // (rwx, r_x, r_x) | ||
42 | await downloadFile(downloadUrl, installationPath, filePermissions, throttle( | ||
43 | 200, | ||
44 | /* noTrailing: */ true, | ||
45 | (readBytes, totalBytes) => { | ||
46 | const newPercentage = (readBytes / totalBytes) * 100; | ||
47 | progress.report({ | ||
48 | message: newPercentage.toFixed(0) + "%", | ||
49 | increment: newPercentage - lastPrecentage | ||
50 | }); | ||
51 | |||
52 | lastPrecentage = newPercentage; | ||
53 | }) | ||
54 | ); | ||
55 | } | ||
56 | ); | ||
57 | console.timeEnd(`Downloading ${artifactFileName}`); | ||
58 | } | ||
diff --git a/editors/code/src/installation/fetch_latest_artifact_release_info.ts b/editors/code/src/installation/fetch_artifact_release_info.ts index 29ee029a7..7d497057a 100644 --- a/editors/code/src/installation/fetch_latest_artifact_release_info.ts +++ b/editors/code/src/installation/fetch_artifact_release_info.ts | |||
@@ -3,24 +3,30 @@ import { GithubRepo, ArtifactReleaseInfo } from "./interfaces"; | |||
3 | 3 | ||
4 | const GITHUB_API_ENDPOINT_URL = "https://api.github.com"; | 4 | const GITHUB_API_ENDPOINT_URL = "https://api.github.com"; |
5 | 5 | ||
6 | |||
6 | /** | 7 | /** |
7 | * Fetches the latest release from GitHub `repo` and returns metadata about | 8 | * Fetches the release with `releaseTag` (or just latest release when not specified) |
8 | * `artifactFileName` shipped with this release or `null` if no such artifact was published. | 9 | * from GitHub `repo` and returns metadata about `artifactFileName` shipped with |
10 | * this release or `null` if no such artifact was published. | ||
9 | */ | 11 | */ |
10 | export async function fetchLatestArtifactReleaseInfo( | 12 | export async function fetchArtifactReleaseInfo( |
11 | repo: GithubRepo, artifactFileName: string | 13 | repo: GithubRepo, artifactFileName: string, releaseTag?: string |
12 | ): Promise<null | ArtifactReleaseInfo> { | 14 | ): Promise<null | ArtifactReleaseInfo> { |
13 | 15 | ||
14 | const repoOwner = encodeURIComponent(repo.owner); | 16 | const repoOwner = encodeURIComponent(repo.owner); |
15 | const repoName = encodeURIComponent(repo.name); | 17 | const repoName = encodeURIComponent(repo.name); |
16 | 18 | ||
17 | const apiEndpointPath = `/repos/${repoOwner}/${repoName}/releases/latest`; | 19 | const apiEndpointPath = releaseTag |
20 | ? `/repos/${repoOwner}/${repoName}/releases/tags/${releaseTag}` | ||
21 | : `/repos/${repoOwner}/${repoName}/releases/latest`; | ||
22 | |||
18 | const requestUrl = GITHUB_API_ENDPOINT_URL + apiEndpointPath; | 23 | const requestUrl = GITHUB_API_ENDPOINT_URL + apiEndpointPath; |
19 | 24 | ||
20 | // We skip runtime type checks for simplicity (here we cast from `any` to `GithubRelease`) | 25 | // We skip runtime type checks for simplicity (here we cast from `any` to `GithubRelease`) |
21 | 26 | ||
22 | console.log("Issuing request for released artifacts metadata to", requestUrl); | 27 | console.log("Issuing request for released artifacts metadata to", requestUrl); |
23 | 28 | ||
29 | // FIXME: handle non-ok response | ||
24 | const response: GithubRelease = await fetch(requestUrl, { | 30 | const response: GithubRelease = await fetch(requestUrl, { |
25 | headers: { Accept: "application/vnd.github.v3+json" } | 31 | headers: { Accept: "application/vnd.github.v3+json" } |
26 | }) | 32 | }) |
diff --git a/editors/code/src/installation/interfaces.ts b/editors/code/src/installation/interfaces.ts index 93ea577d4..e40839e4b 100644 --- a/editors/code/src/installation/interfaces.ts +++ b/editors/code/src/installation/interfaces.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | import * as vscode from "vscode"; | ||
2 | |||
1 | export interface GithubRepo { | 3 | export interface GithubRepo { |
2 | name: string; | 4 | name: string; |
3 | owner: string; | 5 | owner: string; |
@@ -50,6 +52,17 @@ export namespace BinarySource { | |||
50 | * and in local `.dir`. | 52 | * and in local `.dir`. |
51 | */ | 53 | */ |
52 | file: string; | 54 | file: string; |
55 | |||
56 | /** | ||
57 | * Tag of github release that denotes a version required by this extension. | ||
58 | */ | ||
59 | version: string; | ||
60 | |||
61 | /** | ||
62 | * Object that provides `get()/update()` operations to store metadata | ||
63 | * about the actual binary, e.g. its actual version. | ||
64 | */ | ||
65 | storage: vscode.Memento; | ||
53 | } | 66 | } |
54 | 67 | ||
55 | } | 68 | } |
diff --git a/editors/code/src/installation/server.ts b/editors/code/src/installation/server.ts index 406e2299c..80cb719e3 100644 --- a/editors/code/src/installation/server.ts +++ b/editors/code/src/installation/server.ts | |||
@@ -1,63 +1,15 @@ | |||
1 | import * as vscode from "vscode"; | 1 | import * as vscode from "vscode"; |
2 | import * as path from "path"; | 2 | import * as path from "path"; |
3 | import { strict as assert } from "assert"; | 3 | import { strict as assert } from "assert"; |
4 | import { promises as fs } from "fs"; | ||
5 | import { promises as dns } from "dns"; | 4 | import { promises as dns } from "dns"; |
6 | import { spawnSync } from "child_process"; | 5 | import { spawnSync } from "child_process"; |
7 | import { throttle } from "throttle-debounce"; | ||
8 | 6 | ||
9 | import { BinarySource } from "./interfaces"; | 7 | import { BinarySource } from "./interfaces"; |
10 | import { fetchLatestArtifactReleaseInfo } from "./fetch_latest_artifact_release_info"; | 8 | import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info"; |
11 | import { downloadFile } from "./download_file"; | 9 | import { downloadArtifact } from "./download_artifact"; |
12 | |||
13 | export async function downloadLatestServer( | ||
14 | {file: artifactFileName, dir: installationDir, repo}: BinarySource.GithubRelease | ||
15 | ) { | ||
16 | const { releaseName, downloadUrl } = (await fetchLatestArtifactReleaseInfo( | ||
17 | repo, artifactFileName | ||
18 | ))!; | ||
19 | |||
20 | await fs.mkdir(installationDir).catch(err => assert.strictEqual( | ||
21 | err?.code, | ||
22 | "EEXIST", | ||
23 | `Couldn't create directory "${installationDir}" to download `+ | ||
24 | `language server binary: ${err.message}` | ||
25 | )); | ||
26 | |||
27 | const installationPath = path.join(installationDir, artifactFileName); | ||
28 | |||
29 | console.time("Downloading ra_lsp_server"); | ||
30 | await vscode.window.withProgress( | ||
31 | { | ||
32 | location: vscode.ProgressLocation.Notification, | ||
33 | cancellable: false, // FIXME: add support for canceling download? | ||
34 | title: `Downloading language server (${releaseName})` | ||
35 | }, | ||
36 | async (progress, _cancellationToken) => { | ||
37 | let lastPrecentage = 0; | ||
38 | const filePermissions = 0o755; // (rwx, r_x, r_x) | ||
39 | await downloadFile(downloadUrl, installationPath, filePermissions, throttle( | ||
40 | 200, | ||
41 | /* noTrailing: */ true, | ||
42 | (readBytes, totalBytes) => { | ||
43 | const newPercentage = (readBytes / totalBytes) * 100; | ||
44 | progress.report({ | ||
45 | message: newPercentage.toFixed(0) + "%", | ||
46 | increment: newPercentage - lastPrecentage | ||
47 | }); | ||
48 | |||
49 | lastPrecentage = newPercentage; | ||
50 | }) | ||
51 | ); | ||
52 | } | ||
53 | ); | ||
54 | console.timeEnd("Downloading ra_lsp_server"); | ||
55 | } | ||
56 | export async function ensureServerBinary( | ||
57 | serverSource: null | BinarySource | ||
58 | ): Promise<null | string> { | ||
59 | 10 | ||
60 | if (!serverSource) { | 11 | export async function ensureServerBinary(source: null | BinarySource): Promise<null | string> { |
12 | if (!source) { | ||
61 | vscode.window.showErrorMessage( | 13 | vscode.window.showErrorMessage( |
62 | "Unfortunately we don't ship binaries for your platform yet. " + | 14 | "Unfortunately we don't ship binaries for your platform yet. " + |
63 | "You need to manually clone rust-analyzer repository and " + | 15 | "You need to manually clone rust-analyzer repository and " + |
@@ -69,80 +21,104 @@ export async function ensureServerBinary( | |||
69 | return null; | 21 | return null; |
70 | } | 22 | } |
71 | 23 | ||
72 | switch (serverSource.type) { | 24 | switch (source.type) { |
73 | case BinarySource.Type.ExplicitPath: { | 25 | case BinarySource.Type.ExplicitPath: { |
74 | if (isBinaryAvailable(serverSource.path)) { | 26 | if (isBinaryAvailable(source.path)) { |
75 | return serverSource.path; | 27 | return source.path; |
76 | } | 28 | } |
77 | 29 | ||
78 | vscode.window.showErrorMessage( | 30 | vscode.window.showErrorMessage( |
79 | `Unable to run ${serverSource.path} binary. ` + | 31 | `Unable to run ${source.path} binary. ` + |
80 | `To use the pre-built language server, set "rust-analyzer.raLspServerPath" ` + | 32 | `To use the pre-built language server, set "rust-analyzer.raLspServerPath" ` + |
81 | "value to `null` or remove it from the settings to use it by default." | 33 | "value to `null` or remove it from the settings to use it by default." |
82 | ); | 34 | ); |
83 | return null; | 35 | return null; |
84 | } | 36 | } |
85 | case BinarySource.Type.GithubRelease: { | 37 | case BinarySource.Type.GithubRelease: { |
86 | const prebuiltBinaryPath = path.join(serverSource.dir, serverSource.file); | 38 | const prebuiltBinaryPath = path.join(source.dir, source.file); |
39 | |||
40 | const installedVersion: null | string = getServerVersion(source.storage); | ||
41 | const requiredVersion: string = source.version; | ||
87 | 42 | ||
88 | if (isBinaryAvailable(prebuiltBinaryPath)) { | 43 | console.log("Installed version:", installedVersion, "required:", requiredVersion); |
44 | |||
45 | if (isBinaryAvailable(prebuiltBinaryPath) && installedVersion == requiredVersion) { | ||
46 | // FIXME: check for new releases and notify the user to update if possible | ||
89 | return prebuiltBinaryPath; | 47 | return prebuiltBinaryPath; |
90 | } | 48 | } |
91 | 49 | ||
92 | const userResponse = await vscode.window.showInformationMessage( | 50 | const userResponse = await vscode.window.showInformationMessage( |
93 | "Language server binary for rust-analyzer was not found. " + | 51 | `Language server version ${source.version} for rust-analyzer is not installed. ` + |
94 | "Do you want to download it now?", | 52 | "Do you want to download it now?", |
95 | "Download now", "Cancel" | 53 | "Download now", "Cancel" |
96 | ); | 54 | ); |
97 | if (userResponse !== "Download now") return null; | 55 | if (userResponse !== "Download now") return null; |
98 | 56 | ||
99 | try { | 57 | if (!await downloadServer(source)) return null; |
100 | await downloadLatestServer(serverSource); | ||
101 | } catch (err) { | ||
102 | vscode.window.showErrorMessage( | ||
103 | `Failed to download language server from ${serverSource.repo.name} ` + | ||
104 | `GitHub repository: ${err.message}` | ||
105 | ); | ||
106 | 58 | ||
107 | console.error(err); | 59 | return prebuiltBinaryPath; |
60 | } | ||
61 | } | ||
62 | } | ||
108 | 63 | ||
109 | dns.resolve('example.com').then( | 64 | async function downloadServer(source: BinarySource.GithubRelease): Promise<boolean> { |
110 | addrs => console.log("DNS resolution for example.com was successful", addrs), | 65 | try { |
111 | err => { | 66 | const releaseInfo = (await fetchArtifactReleaseInfo(source.repo, source.file, source.version))!; |
112 | console.error( | 67 | |
113 | "DNS resolution for example.com failed, " + | 68 | await downloadArtifact(releaseInfo, source.file, source.dir, "language server"); |
114 | "there might be an issue with Internet availability" | 69 | await setServerVersion(source.storage, releaseInfo.releaseName); |
115 | ); | 70 | } catch (err) { |
116 | console.error(err); | 71 | vscode.window.showErrorMessage( |
117 | } | 72 | `Failed to download language server from ${source.repo.name} ` + |
118 | ); | 73 | `GitHub repository: ${err.message}` |
74 | ); | ||
75 | |||
76 | console.error(err); | ||
119 | 77 | ||
120 | return null; | 78 | dns.resolve('example.com').then( |
79 | addrs => console.log("DNS resolution for example.com was successful", addrs), | ||
80 | err => { | ||
81 | console.error( | ||
82 | "DNS resolution for example.com failed, " + | ||
83 | "there might be an issue with Internet availability" | ||
84 | ); | ||
85 | console.error(err); | ||
121 | } | 86 | } |
87 | ); | ||
88 | return false; | ||
89 | } | ||
122 | 90 | ||
123 | if (!isBinaryAvailable(prebuiltBinaryPath)) assert(false, | 91 | if (!isBinaryAvailable(path.join(source.dir, source.file))) assert(false, |
124 | `Downloaded language server binary is not functional.` + | 92 | `Downloaded language server binary is not functional.` + |
125 | `Downloaded from: ${JSON.stringify(serverSource)}` | 93 | `Downloaded from: ${JSON.stringify(source, null, 4)}` |
126 | ); | 94 | ); |
127 | 95 | ||
96 | vscode.window.showInformationMessage( | ||
97 | "Rust analyzer language server was successfully installed 🦀" | ||
98 | ); | ||
128 | 99 | ||
129 | vscode.window.showInformationMessage( | 100 | return true; |
130 | "Rust analyzer language server was successfully installed 🦀" | 101 | } |
131 | ); | ||
132 | 102 | ||
133 | return prebuiltBinaryPath; | 103 | function isBinaryAvailable(binaryPath: string): boolean { |
134 | } | 104 | const res = spawnSync(binaryPath, ["--version"]); |
135 | } | ||
136 | 105 | ||
137 | function isBinaryAvailable(binaryPath: string) { | 106 | // ACHTUNG! `res` type declaration is inherently wrong, see |
138 | const res = spawnSync(binaryPath, ["--version"]); | 107 | // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42221 |
139 | 108 | ||
140 | // ACHTUNG! `res` type declaration is inherently wrong, see | 109 | console.log("Checked binary availablity via --version", res); |
141 | // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42221 | 110 | console.log(binaryPath, "--version output:", res.output?.map(String)); |
142 | 111 | ||
143 | console.log("Checked binary availablity via --version", res); | 112 | return res.status === 0; |
144 | console.log(binaryPath, "--version output:", res.output?.map(String)); | 113 | } |
145 | 114 | ||
146 | return res.status === 0; | 115 | function getServerVersion(storage: vscode.Memento): null | string { |
147 | } | 116 | const version = storage.get<null | string>("server-version", null); |
117 | console.log("Get server-version:", version); | ||
118 | return version; | ||
119 | } | ||
120 | |||
121 | async function setServerVersion(storage: vscode.Memento, version: string): Promise<void> { | ||
122 | console.log("Set server-version:", version); | ||
123 | await storage.update("server-version", version.toString()); | ||
148 | } | 124 | } |