aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_lsp_server/src/caps.rs6
-rw-r--r--crates/ra_lsp_server/src/cargo_target_spec.rs100
-rw-r--r--crates/ra_lsp_server/src/lib.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs141
-rw-r--r--crates/ra_lsp_server/src/req.rs4
-rw-r--r--crates/ra_syntax/src/grammar/items/nominal.rs10
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.rs4
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.txt39
-rw-r--r--crates/tools/src/main.rs4
-rw-r--r--editors/README.md2
-rw-r--r--editors/code/src/commands/runnables.ts16
-rw-r--r--editors/code/src/extension.ts3
13 files changed, 229 insertions, 102 deletions
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 2599a4ca6..be6a6ead6 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -1,5 +1,5 @@
1use languageserver_types::{ 1use languageserver_types::{
2 CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions, 2 CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions,
3 ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, 3 ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability,
4 ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, 4 ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
5 TextDocumentSyncOptions, 5 TextDocumentSyncOptions,
@@ -32,7 +32,9 @@ pub fn server_capabilities() -> ServerCapabilities {
32 document_symbol_provider: Some(true), 32 document_symbol_provider: Some(true),
33 workspace_symbol_provider: Some(true), 33 workspace_symbol_provider: Some(true),
34 code_action_provider: Some(CodeActionProviderCapability::Simple(true)), 34 code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
35 code_lens_provider: None, 35 code_lens_provider: Some(CodeLensOptions {
36 resolve_provider: None,
37 }),
36 document_formatting_provider: Some(true), 38 document_formatting_provider: Some(true),
37 document_range_formatting_provider: None, 39 document_range_formatting_provider: None,
38 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { 40 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
diff --git a/crates/ra_lsp_server/src/cargo_target_spec.rs b/crates/ra_lsp_server/src/cargo_target_spec.rs
new file mode 100644
index 000000000..a66f14b82
--- /dev/null
+++ b/crates/ra_lsp_server/src/cargo_target_spec.rs
@@ -0,0 +1,100 @@
1use crate::{
2 project_model::TargetKind,
3 server_world::ServerWorld,
4 Result
5};
6
7use ra_ide_api::{FileId, RunnableKind};
8
9pub(crate) fn runnable_args(
10 world: &ServerWorld,
11 file_id: FileId,
12 kind: &RunnableKind,
13) -> Result<Vec<String>> {
14 let spec = CargoTargetSpec::for_file(world, file_id)?;
15 let mut res = Vec::new();
16 match kind {
17 RunnableKind::Test { name } => {
18 res.push("test".to_string());
19 if let Some(spec) = spec {
20 spec.push_to(&mut res);
21 }
22 res.push("--".to_string());
23 res.push(name.to_string());
24 res.push("--nocapture".to_string());
25 }
26 RunnableKind::TestMod { path } => {
27 res.push("test".to_string());
28 if let Some(spec) = spec {
29 spec.push_to(&mut res);
30 }
31 res.push("--".to_string());
32 res.push(path.to_string());
33 res.push("--nocapture".to_string());
34 }
35 RunnableKind::Bin => {
36 res.push("run".to_string());
37 if let Some(spec) = spec {
38 spec.push_to(&mut res);
39 }
40 }
41 }
42 Ok(res)
43}
44
45pub struct CargoTargetSpec {
46 pub package: String,
47 pub target: String,
48 pub target_kind: TargetKind,
49}
50
51impl CargoTargetSpec {
52 pub fn for_file(world: &ServerWorld, file_id: FileId) -> Result<Option<CargoTargetSpec>> {
53 let &crate_id = match world.analysis().crate_for(file_id)?.first() {
54 Some(crate_id) => crate_id,
55 None => return Ok(None),
56 };
57 let file_id = world.analysis().crate_root(crate_id)?;
58 let path = world
59 .vfs
60 .read()
61 .file2path(ra_vfs::VfsFile(file_id.0.into()));
62 let res = world.workspaces.iter().find_map(|ws| {
63 let tgt = ws.cargo.target_by_root(&path)?;
64 let res = CargoTargetSpec {
65 package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(),
66 target: tgt.name(&ws.cargo).to_string(),
67 target_kind: tgt.kind(&ws.cargo),
68 };
69 Some(res)
70 });
71 Ok(res)
72 }
73
74 pub fn push_to(self, buf: &mut Vec<String>) {
75 buf.push("--package".to_string());
76 buf.push(self.package);
77 match self.target_kind {
78 TargetKind::Bin => {
79 buf.push("--bin".to_string());
80 buf.push(self.target);
81 }
82 TargetKind::Test => {
83 buf.push("--test".to_string());
84 buf.push(self.target);
85 }
86 TargetKind::Bench => {
87 buf.push("--bench".to_string());
88 buf.push(self.target);
89 }
90 TargetKind::Example => {
91 buf.push("--example".to_string());
92 buf.push(self.target);
93 }
94 TargetKind::Lib => {
95 buf.push("--lib".to_string());
96 }
97 TargetKind::Other => (),
98 }
99 }
100}
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs
index 725b1258a..f93d4b37d 100644
--- a/crates/ra_lsp_server/src/lib.rs
+++ b/crates/ra_lsp_server/src/lib.rs
@@ -1,4 +1,5 @@
1mod caps; 1mod caps;
2mod cargo_target_spec;
2mod conv; 3mod conv;
3mod main_loop; 4mod main_loop;
4mod project_model; 5mod project_model;
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 6b9f6a988..03c834dbc 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -300,6 +300,7 @@ fn on_request(
300 .on::<req::DecorationsRequest>(handlers::handle_decorations)? 300 .on::<req::DecorationsRequest>(handlers::handle_decorations)?
301 .on::<req::Completion>(handlers::handle_completion)? 301 .on::<req::Completion>(handlers::handle_completion)?
302 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 302 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
303 .on::<req::CodeLensRequest>(handlers::handle_code_lens)?
303 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? 304 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
304 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? 305 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
305 .on::<req::HoverRequest>(handlers::handle_hover)? 306 .on::<req::HoverRequest>(handlers::handle_hover)?
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 5ab13542c..a781df181 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -2,7 +2,7 @@ use std::collections::HashMap;
2 2
3use gen_lsp_server::ErrorCode; 3use gen_lsp_server::ErrorCode;
4use languageserver_types::{ 4use languageserver_types::{
5 CodeActionResponse, Command, Diagnostic, DiagnosticSeverity, DocumentFormattingParams, 5 CodeActionResponse, Command, CodeLens, Diagnostic, DiagnosticSeverity, DocumentFormattingParams,
6 DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, 6 DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
7 FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, 7 FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind,
8 ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, 8 ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams,
@@ -17,8 +17,8 @@ use serde_json::to_value;
17use std::io::Write; 17use std::io::Write;
18 18
19use crate::{ 19use crate::{
20 cargo_target_spec::{CargoTargetSpec, runnable_args},
20 conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith}, 21 conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith},
21 project_model::TargetKind,
22 req::{self, Decoration}, 22 req::{self, Decoration},
23 server_world::ServerWorld, 23 server_world::ServerWorld,
24 LspError, Result, 24 LspError, Result,
@@ -291,99 +291,6 @@ pub fn handle_runnables(
291 env: FxHashMap::default(), 291 env: FxHashMap::default(),
292 }); 292 });
293 return Ok(res); 293 return Ok(res);
294
295 fn runnable_args(
296 world: &ServerWorld,
297 file_id: FileId,
298 kind: &RunnableKind,
299 ) -> Result<Vec<String>> {
300 let spec = CargoTargetSpec::for_file(world, file_id)?;
301 let mut res = Vec::new();
302 match kind {
303 RunnableKind::Test { name } => {
304 res.push("test".to_string());
305 if let Some(spec) = spec {
306 spec.push_to(&mut res);
307 }
308 res.push("--".to_string());
309 res.push(name.to_string());
310 res.push("--nocapture".to_string());
311 }
312 RunnableKind::TestMod { path } => {
313 res.push("test".to_string());
314 if let Some(spec) = spec {
315 spec.push_to(&mut res);
316 }
317 res.push("--".to_string());
318 res.push(path.to_string());
319 res.push("--nocapture".to_string());
320 }
321 RunnableKind::Bin => {
322 res.push("run".to_string());
323 if let Some(spec) = spec {
324 spec.push_to(&mut res);
325 }
326 }
327 }
328 Ok(res)
329 }
330
331 struct CargoTargetSpec {
332 package: String,
333 target: String,
334 target_kind: TargetKind,
335 }
336
337 impl CargoTargetSpec {
338 fn for_file(world: &ServerWorld, file_id: FileId) -> Result<Option<CargoTargetSpec>> {
339 let &crate_id = match world.analysis().crate_for(file_id)?.first() {
340 Some(crate_id) => crate_id,
341 None => return Ok(None),
342 };
343 let file_id = world.analysis().crate_root(crate_id)?;
344 let path = world
345 .vfs
346 .read()
347 .file2path(ra_vfs::VfsFile(file_id.0.into()));
348 let res = world.workspaces.iter().find_map(|ws| {
349 let tgt = ws.cargo.target_by_root(&path)?;
350 let res = CargoTargetSpec {
351 package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(),
352 target: tgt.name(&ws.cargo).to_string(),
353 target_kind: tgt.kind(&ws.cargo),
354 };
355 Some(res)
356 });
357 Ok(res)
358 }
359
360 fn push_to(self, buf: &mut Vec<String>) {
361 buf.push("--package".to_string());
362 buf.push(self.package);
363 match self.target_kind {
364 TargetKind::Bin => {
365 buf.push("--bin".to_string());
366 buf.push(self.target);
367 }
368 TargetKind::Test => {
369 buf.push("--test".to_string());
370 buf.push(self.target);
371 }
372 TargetKind::Bench => {
373 buf.push("--bench".to_string());
374 buf.push(self.target);
375 }
376 TargetKind::Example => {
377 buf.push("--example".to_string());
378 buf.push(self.target);
379 }
380 TargetKind::Lib => {
381 buf.push("--lib".to_string());
382 }
383 TargetKind::Other => (),
384 }
385 }
386 }
387} 294}
388 295
389pub fn handle_decorations( 296pub fn handle_decorations(
@@ -669,6 +576,50 @@ pub fn handle_code_action(
669 Ok(Some(CodeActionResponse::Commands(res))) 576 Ok(Some(CodeActionResponse::Commands(res)))
670} 577}
671 578
579pub fn handle_code_lens(
580 world: ServerWorld,
581 params: req::CodeLensParams,
582) -> Result<Option<Vec<CodeLens>>> {
583 let file_id = params.text_document.try_conv_with(&world)?;
584 let line_index = world.analysis().file_line_index(file_id);
585
586 let mut lenses: Vec<CodeLens> = Default::default();
587
588 for runnable in world.analysis().runnables(file_id)? {
589 match &runnable.kind {
590 RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => {
591 let args = runnable_args(&world, file_id, &runnable.kind)?;
592
593 let range = runnable.range.conv_with(&line_index);
594
595 // This represents the actual command that will be run.
596 let r: req::Runnable = req::Runnable {
597 range,
598 label: Default::default(),
599 bin: "cargo".into(),
600 args,
601 env: Default::default(),
602 };
603
604 let lens = CodeLens {
605 range,
606 command: Some(Command {
607 title: "Run Test".into(),
608 command: "ra-lsp.run-single".into(),
609 arguments: Some(vec![to_value(r).unwrap()]),
610 }),
611 data: None,
612 };
613
614 lenses.push(lens);
615 }
616 _ => continue,
617 };
618 }
619
620 return Ok(Some(lenses));
621}
622
672pub fn handle_document_highlight( 623pub fn handle_document_highlight(
673 world: ServerWorld, 624 world: ServerWorld,
674 params: req::TextDocumentPositionParams, 625 params: req::TextDocumentPositionParams,
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index b41e90328..c2b16725b 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
4use url_serde; 4use url_serde;
5 5
6pub use languageserver_types::{ 6pub use languageserver_types::{
7 notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CompletionParams, 7 notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, CodeLensParams,
8 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, 8 CompletionParams, CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams,
9 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, 9 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult,
10 PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit, 10 PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit,
11 TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, 11 TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams,
diff --git a/crates/ra_syntax/src/grammar/items/nominal.rs b/crates/ra_syntax/src/grammar/items/nominal.rs
index 495462ca7..0784fb7b1 100644
--- a/crates/ra_syntax/src/grammar/items/nominal.rs
+++ b/crates/ra_syntax/src/grammar/items/nominal.rs
@@ -140,6 +140,16 @@ fn pos_field_list(p: &mut Parser) {
140 } 140 }
141 while !p.at(R_PAREN) && !p.at(EOF) { 141 while !p.at(R_PAREN) && !p.at(EOF) {
142 let m = p.start(); 142 let m = p.start();
143 // test pos_field_attrs
144 // struct S (
145 // #[serde(with = "url_serde")]
146 // pub Uri,
147 // );
148 //
149 // enum S {
150 // Uri(#[serde(with = "url_serde")] Uri),
151 // }
152 attributes::outer_attributes(p);
143 opt_visibility(p); 153 opt_visibility(p);
144 if !p.at_ts(types::TYPE_FIRST) { 154 if !p.at_ts(types::TYPE_FIRST) {
145 p.error("expected a type"); 155 p.error("expected a type");
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.rs b/crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.rs
new file mode 100644
index 000000000..635b9ac21
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.rs
@@ -0,0 +1,4 @@
1struct S (
2 #[serde(with = "url_serde")]
3 pub Uri,
4);
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.txt
new file mode 100644
index 000000000..99ec0755b
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.txt
@@ -0,0 +1,39 @@
1SOURCE_FILE@[0; 60)
2 STRUCT_DEF@[0; 59)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 WHITESPACE@[8; 9)
8 POS_FIELD_LIST@[9; 58)
9 L_PAREN@[9; 10)
10 WHITESPACE@[10; 15)
11 POS_FIELD@[15; 55)
12 ATTR@[15; 43)
13 POUND@[15; 16)
14 TOKEN_TREE@[16; 43)
15 L_BRACK@[16; 17)
16 IDENT@[17; 22) "serde"
17 TOKEN_TREE@[22; 42)
18 L_PAREN@[22; 23)
19 IDENT@[23; 27) "with"
20 WHITESPACE@[27; 28)
21 EQ@[28; 29)
22 WHITESPACE@[29; 30)
23 STRING@[30; 41)
24 R_PAREN@[41; 42)
25 R_BRACK@[42; 43)
26 WHITESPACE@[43; 48)
27 VISIBILITY@[48; 51)
28 PUB_KW@[48; 51)
29 WHITESPACE@[51; 52)
30 PATH_TYPE@[52; 55)
31 PATH@[52; 55)
32 PATH_SEGMENT@[52; 55)
33 NAME_REF@[52; 55)
34 IDENT@[52; 55) "Uri"
35 COMMA@[55; 56)
36 WHITESPACE@[56; 57)
37 R_PAREN@[57; 58)
38 SEMI@[58; 59)
39 WHITESPACE@[59; 60)
diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs
index 9d73d57c4..5597aae5a 100644
--- a/crates/tools/src/main.rs
+++ b/crates/tools/src/main.rs
@@ -158,12 +158,12 @@ fn install_code_extension() -> Result<()> {
158 } 158 }
159 if cfg!(windows) { 159 if cfg!(windows) {
160 run( 160 run(
161 r"cmd.exe /c code.cmd --install-extension ./ra-lsp-0.0.1.vsix", 161 r"cmd.exe /c code.cmd --install-extension ./ra-lsp-0.0.1.vsix --force",
162 "./editors/code", 162 "./editors/code",
163 )?; 163 )?;
164 } else { 164 } else {
165 run( 165 run(
166 r"code --install-extension ./ra-lsp-0.0.1.vsix", 166 r"code --install-extension ./ra-lsp-0.0.1.vsix --force",
167 "./editors/code", 167 "./editors/code",
168 )?; 168 )?;
169 } 169 }
diff --git a/editors/README.md b/editors/README.md
index a63ced725..5b09750e6 100644
--- a/editors/README.md
+++ b/editors/README.md
@@ -1,7 +1,7 @@
1To install experimental VS Code plugin: 1To install experimental VS Code plugin:
2 2
3``` 3```
4$ git clone https://github.com/rust-analyzer/rust-analyzer.git 4$ git clone https://github.com/rust-analyzer/rust-analyzer.git --depth 1
5$ cd rust-analyzer 5$ cd rust-analyzer
6$ cargo install-code 6$ cargo install-code
7``` 7```
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index be17c8944..f9a4e2fc9 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -103,3 +103,19 @@ export async function handle() {
103 return await vscode.tasks.executeTask(task); 103 return await vscode.tasks.executeTask(task);
104 } 104 }
105} 105}
106
107export async function handleSingle(runnable: Runnable) {
108 const editor = vscode.window.activeTextEditor;
109 if (editor == null || editor.document.languageId !== 'rust') {
110 return;
111 }
112
113 const task = createTask(runnable);
114 task.group = vscode.TaskGroup.Build;
115 task.presentationOptions = {
116 reveal: vscode.TaskRevealKind.Always,
117 panel: vscode.TaskPanelKind.Dedicated,
118 };
119
120 return vscode.tasks.executeTask(task);
121} \ No newline at end of file
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts
index 4acd54d90..9edfb13b5 100644
--- a/editors/code/src/extension.ts
+++ b/editors/code/src/extension.ts
@@ -55,6 +55,9 @@ export function activate(context: vscode.ExtensionContext) {
55 ); 55 );
56 overrideCommand('type', commands.onEnter.handle); 56 overrideCommand('type', commands.onEnter.handle);
57 57
58 // Unlike the above this does not send requests to the language server
59 registerCommand('ra-lsp.run-single', commands.runnables.handleSingle);
60
58 // Notifications are events triggered by the language server 61 // Notifications are events triggered by the language server
59 const allNotifications: Iterable< 62 const allNotifications: Iterable<
60 [string, lc.GenericNotificationHandler] 63 [string, lc.GenericNotificationHandler]