aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-12 19:02:56 +0100
committerAleksey Kladov <[email protected]>2018-08-12 19:02:56 +0100
commit23c06db9c236db0f9c8ef5117fb1adefd6616c43 (patch)
tree8e265a79b7f8f62761c6ea2dd4fa0d6bc0c74204 /crates
parent66be735aa98c32fb062d1c756fa9303ff2d13002 (diff)
Half of code-actions
Diffstat (limited to 'crates')
-rw-r--r--crates/server/src/caps.rs2
-rw-r--r--crates/server/src/conv.rs81
-rw-r--r--crates/server/src/handlers.rs103
-rw-r--r--crates/server/src/main.rs7
-rw-r--r--crates/server/src/req.rs3
5 files changed, 139 insertions, 57 deletions
diff --git a/crates/server/src/caps.rs b/crates/server/src/caps.rs
index dca07ebc9..b502b0865 100644
--- a/crates/server/src/caps.rs
+++ b/crates/server/src/caps.rs
@@ -25,7 +25,7 @@ pub const SERVER_CAPABILITIES: ServerCapabilities = ServerCapabilities {
25 document_highlight_provider: None, 25 document_highlight_provider: None,
26 document_symbol_provider: Some(true), 26 document_symbol_provider: Some(true),
27 workspace_symbol_provider: None, 27 workspace_symbol_provider: None,
28 code_action_provider: None, 28 code_action_provider: Some(true),
29 code_lens_provider: None, 29 code_lens_provider: None,
30 document_formatting_provider: None, 30 document_formatting_provider: None,
31 document_range_formatting_provider: None, 31 document_range_formatting_provider: None,
diff --git a/crates/server/src/conv.rs b/crates/server/src/conv.rs
new file mode 100644
index 000000000..c7bea15df
--- /dev/null
+++ b/crates/server/src/conv.rs
@@ -0,0 +1,81 @@
1use languageserver_types::{Range, SymbolKind, Position};
2use libeditor::{LineIndex, LineCol};
3use libsyntax2::{SyntaxKind, TextUnit, TextRange};
4
5pub trait Conv {
6 type Output;
7 fn conv(&self) -> Self::Output;
8}
9
10pub trait ConvWith {
11 type Ctx;
12 type Output;
13 fn conv_with(&self, ctx: &Self::Ctx) -> Self::Output;
14}
15
16impl Conv for SyntaxKind {
17 type Output = SymbolKind;
18
19 fn conv(&self) -> <Self as Conv>::Output {
20 match *self {
21 SyntaxKind::FUNCTION => SymbolKind::Function,
22 SyntaxKind::STRUCT => SymbolKind::Struct,
23 SyntaxKind::ENUM => SymbolKind::Enum,
24 SyntaxKind::TRAIT => SymbolKind::Interface,
25 SyntaxKind::MODULE => SymbolKind::Module,
26 SyntaxKind::TYPE_ITEM => SymbolKind::TypeParameter,
27 SyntaxKind::STATIC_ITEM => SymbolKind::Constant,
28 SyntaxKind::CONST_ITEM => SymbolKind::Constant,
29 _ => SymbolKind::Variable,
30 }
31 }
32}
33
34impl ConvWith for Position {
35 type Ctx = LineIndex;
36 type Output = TextUnit;
37
38 fn conv_with(&self, line_index: &LineIndex) -> TextUnit {
39 // TODO: UTF-16
40 let line_col = LineCol {
41 line: self.line as u32,
42 col: (self.character as u32).into(),
43 };
44 line_index.offset(line_col)
45 }
46}
47
48impl ConvWith for TextUnit {
49 type Ctx = LineIndex;
50 type Output = Position;
51
52 fn conv_with(&self, line_index: &LineIndex) -> Position {
53 let line_col = line_index.line_col(*self);
54 // TODO: UTF-16
55 Position::new(line_col.line as u64, u32::from(line_col.col) as u64)
56 }
57}
58
59impl ConvWith for TextRange {
60 type Ctx = LineIndex;
61 type Output = Range;
62
63 fn conv_with(&self, line_index: &LineIndex) -> Range {
64 Range::new(
65 self.start().conv_with(line_index),
66 self.end().conv_with(line_index),
67 )
68 }
69}
70
71impl ConvWith for Range {
72 type Ctx = LineIndex;
73 type Output = TextRange;
74
75 fn conv_with(&self, line_index: &LineIndex) -> TextRange {
76 TextRange::from_to(
77 self.start.conv_with(line_index),
78 self.end.conv_with(line_index),
79 )
80 }
81}
diff --git a/crates/server/src/handlers.rs b/crates/server/src/handlers.rs
index f6f960d22..c6db22289 100644
--- a/crates/server/src/handlers.rs
+++ b/crates/server/src/handlers.rs
@@ -1,11 +1,15 @@
1use languageserver_types::{Range, Position, Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, SymbolKind}; 1use languageserver_types::{
2use libsyntax2::SyntaxKind; 2 Diagnostic, DiagnosticSeverity, Url, DocumentSymbol,
3 Command
4};
3use libanalysis::World; 5use libanalysis::World;
4use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit}; 6use libeditor;
7use serde_json::to_value;
5 8
6use ::{ 9use ::{
7 req::{self, Decoration}, Result, 10 req::{self, Decoration}, Result,
8 util::FilePath, 11 util::FilePath,
12 conv::{Conv, ConvWith},
9}; 13};
10 14
11pub fn handle_syntax_tree( 15pub fn handle_syntax_tree(
@@ -25,11 +29,9 @@ pub fn handle_extend_selection(
25 let file = world.file_syntax(&path)?; 29 let file = world.file_syntax(&path)?;
26 let line_index = world.file_line_index(&path)?; 30 let line_index = world.file_line_index(&path)?;
27 let selections = params.selections.into_iter() 31 let selections = params.selections.into_iter()
28 .map(|r| { 32 .map(|r| r.conv_with(&line_index))
29 let r = to_text_range(&line_index, r); 33 .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r))
30 let r = libeditor::extend_selection(&file, r).unwrap_or(r); 34 .map(|r| r.conv_with(&line_index))
31 to_vs_range(&line_index, r)
32 })
33 .collect(); 35 .collect();
34 Ok(req::ExtendSelectionResult { selections }) 36 Ok(req::ExtendSelectionResult { selections })
35} 37}
@@ -48,10 +50,10 @@ pub fn handle_document_symbol(
48 let doc_symbol = DocumentSymbol { 50 let doc_symbol = DocumentSymbol {
49 name: symbol.name.clone(), 51 name: symbol.name.clone(),
50 detail: Some(symbol.name), 52 detail: Some(symbol.name),
51 kind: to_symbol_kind(symbol.kind), 53 kind: symbol.kind.conv(),
52 deprecated: None, 54 deprecated: None,
53 range: to_vs_range(&line_index, symbol.node_range), 55 range: symbol.node_range.conv_with(&line_index),
54 selection_range: to_vs_range(&line_index, symbol.name_range), 56 selection_range: symbol.name_range.conv_with(&line_index),
55 children: None, 57 children: None,
56 }; 58 };
57 if let Some(idx) = symbol.parent { 59 if let Some(idx) = symbol.parent {
@@ -67,17 +69,40 @@ pub fn handle_document_symbol(
67 Ok(Some(req::DocumentSymbolResponse::Nested(res))) 69 Ok(Some(req::DocumentSymbolResponse::Nested(res)))
68} 70}
69 71
70fn to_symbol_kind(kind: SyntaxKind) -> SymbolKind { 72pub fn handle_code_action(
71 match kind { 73 world: World,
72 SyntaxKind::FUNCTION => SymbolKind::Function, 74 params: req::CodeActionParams,
73 SyntaxKind::STRUCT => SymbolKind::Struct, 75) -> Result<Option<Vec<Command>>> {
74 SyntaxKind::ENUM => SymbolKind::Enum, 76 let path = params.text_document.file_path()?;
75 SyntaxKind::TRAIT => SymbolKind::Interface, 77 let file = world.file_syntax(&path)?;
76 SyntaxKind::MODULE => SymbolKind::Module, 78 let line_index = world.file_line_index(&path)?;
77 SyntaxKind::TYPE_ITEM => SymbolKind::TypeParameter, 79 let offset = params.range.conv_with(&line_index).start();
78 SyntaxKind::STATIC_ITEM => SymbolKind::Constant, 80 let ret = if libeditor::flip_comma(&file, offset).is_some() {
79 SyntaxKind::CONST_ITEM => SymbolKind::Constant, 81 Some(vec![apply_code_action_cmd(ActionId::FlipComma)])
80 _ => SymbolKind::Variable, 82 } else {
83 None
84 };
85 Ok(ret)
86}
87
88fn apply_code_action_cmd(id: ActionId) -> Command {
89 Command {
90 title: id.title().to_string(),
91 command: "apply_code_action".to_string(),
92 arguments: Some(vec![to_value(id).unwrap()]),
93 }
94}
95
96#[derive(Serialize, Deserialize, Clone, Copy)]
97enum ActionId {
98 FlipComma
99}
100
101impl ActionId {
102 fn title(&self) -> &'static str {
103 match *self {
104 ActionId::FlipComma => "Flip `,`",
105 }
81 } 106 }
82} 107}
83 108
@@ -88,7 +113,7 @@ pub fn publish_diagnostics(world: World, uri: Url) -> Result<req::PublishDiagnos
88 let diagnostics = libeditor::diagnostics(&file) 113 let diagnostics = libeditor::diagnostics(&file)
89 .into_iter() 114 .into_iter()
90 .map(|d| Diagnostic { 115 .map(|d| Diagnostic {
91 range: to_vs_range(&line_index, d.range), 116 range: d.range.conv_with(&line_index),
92 severity: Some(DiagnosticSeverity::Error), 117 severity: Some(DiagnosticSeverity::Error),
93 code: None, 118 code: None,
94 source: Some("libsyntax2".to_string()), 119 source: Some("libsyntax2".to_string()),
@@ -105,38 +130,8 @@ pub fn publish_decorations(world: World, uri: Url) -> Result<req::PublishDecorat
105 let decorations = libeditor::highlight(&file) 130 let decorations = libeditor::highlight(&file)
106 .into_iter() 131 .into_iter()
107 .map(|h| Decoration { 132 .map(|h| Decoration {
108 range: to_vs_range(&line_index, h.range), 133 range: h.range.conv_with(&line_index),
109 tag: h.tag, 134 tag: h.tag,
110 }).collect(); 135 }).collect();
111 Ok(req::PublishDecorationsParams { uri, decorations }) 136 Ok(req::PublishDecorationsParams { uri, decorations })
112} 137}
113
114fn to_text_range(line_index: &LineIndex, range: Range) -> TextRange {
115 TextRange::from_to(
116 to_text_unit(line_index, range.start),
117 to_text_unit(line_index, range.end),
118 )
119}
120
121fn to_text_unit(line_index: &LineIndex, position: Position) -> TextUnit {
122 // TODO: UTF-16
123 let line_col = LineCol {
124 line: position.line as u32,
125 col: (position.character as u32).into(),
126 };
127 line_index.offset(line_col)
128}
129
130
131fn to_vs_range(line_index: &LineIndex, range: TextRange) -> Range {
132 Range::new(
133 to_vs_position(line_index, range.start()),
134 to_vs_position(line_index, range.end()),
135 )
136}
137
138fn to_vs_position(line_index: &LineIndex, offset: TextUnit) -> Position {
139 let line_col = line_index.line_col(offset);
140 // TODO: UTF-16
141 Position::new(line_col.line as u64, u32::from(line_col.col) as u64)
142}
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs
index 916638d49..3ff300e3d 100644
--- a/crates/server/src/main.rs
+++ b/crates/server/src/main.rs
@@ -23,6 +23,7 @@ mod req;
23mod dispatch; 23mod dispatch;
24mod handlers; 24mod handlers;
25mod util; 25mod util;
26mod conv;
26 27
27use threadpool::ThreadPool; 28use threadpool::ThreadPool;
28use crossbeam_channel::{bounded, Sender, Receiver}; 29use crossbeam_channel::{bounded, Sender, Receiver};
@@ -33,7 +34,7 @@ use libanalysis::{WorldState, World};
33use ::{ 34use ::{
34 io::{Io, RawMsg, RawRequest}, 35 io::{Io, RawMsg, RawRequest},
35 handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations, 36 handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations,
36 handle_document_symbol}, 37 handle_document_symbol, handle_code_action},
37 util::{FilePath, FnBox} 38 util::{FilePath, FnBox}
38}; 39};
39 40
@@ -182,6 +183,10 @@ fn main_loop(
182 handle_request_on_threadpool::<req::DocumentSymbolRequest>( 183 handle_request_on_threadpool::<req::DocumentSymbolRequest>(
183 &mut req, pool, world, &sender, handle_document_symbol 184 &mut req, pool, world, &sender, handle_document_symbol
184 )?; 185 )?;
186 handle_request_on_threadpool::<req::CodeActionRequest>(
187 &mut req, pool, world, &sender, handle_code_action
188 )?;
189
185 let mut shutdown = false; 190 let mut shutdown = false;
186 dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { 191 dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {
187 resp.result(io, ())?; 192 resp.result(io, ())?;
diff --git a/crates/server/src/req.rs b/crates/server/src/req.rs
index 6a0926084..e3b1cdf50 100644
--- a/crates/server/src/req.rs
+++ b/crates/server/src/req.rs
@@ -5,7 +5,8 @@ use url_serde;
5pub use languageserver_types::{ 5pub use languageserver_types::{
6 request::*, notification::*, 6 request::*, notification::*,
7 InitializeResult, PublishDiagnosticsParams, 7 InitializeResult, PublishDiagnosticsParams,
8 DocumentSymbolParams, DocumentSymbolResponse 8 DocumentSymbolParams, DocumentSymbolResponse,
9 CodeActionParams,
9}; 10};
10 11
11 12