aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_lsp_server/src')
-rw-r--r--crates/ra_lsp_server/src/conv.rs78
-rw-r--r--crates/ra_lsp_server/src/main.rs4
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs58
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs39
-rw-r--r--crates/ra_lsp_server/src/req.rs2
-rw-r--r--crates/ra_lsp_server/src/server_world.rs11
6 files changed, 139 insertions, 53 deletions
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 7467f472c..051f1f995 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -1,8 +1,8 @@
1use languageserver_types::{ 1use languageserver_types::{
2 self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, 2 self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
3 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, 3 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, InsertTextFormat,
4}; 4};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileNodeEdit, FilePosition}; 5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition, CompletionItem, CompletionItemKind, InsertText};
6use ra_editor::{LineCol, LineIndex}; 6use ra_editor::{LineCol, LineIndex};
7use ra_text_edit::{AtomTextEdit, TextEdit}; 7use ra_text_edit::{AtomTextEdit, TextEdit};
8use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 8use ra_syntax::{SyntaxKind, TextRange, TextUnit};
@@ -45,6 +45,46 @@ impl Conv for SyntaxKind {
45 } 45 }
46} 46}
47 47
48impl Conv for CompletionItemKind {
49 type Output = ::languageserver_types::CompletionItemKind;
50
51 fn conv(self) -> <Self as Conv>::Output {
52 use ::languageserver_types::CompletionItemKind::*;
53 match self {
54 CompletionItemKind::Keyword => Keyword,
55 CompletionItemKind::Snippet => Snippet,
56 CompletionItemKind::Module => Module,
57 CompletionItemKind::Function => Function,
58 CompletionItemKind::Binding => Variable,
59 }
60 }
61}
62
63impl Conv for CompletionItem {
64 type Output = ::languageserver_types::CompletionItem;
65
66 fn conv(self) -> <Self as Conv>::Output {
67 let mut res = ::languageserver_types::CompletionItem {
68 label: self.label().to_string(),
69 filter_text: Some(self.lookup().to_string()),
70 kind: self.kind().map(|it| it.conv()),
71 ..Default::default()
72 };
73 match self.insert_text() {
74 InsertText::PlainText { text } => {
75 res.insert_text = Some(text);
76 res.insert_text_format = Some(InsertTextFormat::PlainText);
77 }
78 InsertText::Snippet { text } => {
79 res.insert_text = Some(text);
80 res.insert_text_format = Some(InsertTextFormat::Snippet);
81 res.kind = Some(languageserver_types::CompletionItemKind::Keyword);
82 }
83 }
84 res
85 }
86}
87
48impl ConvWith for Position { 88impl ConvWith for Position {
49 type Ctx = LineIndex; 89 type Ctx = LineIndex;
50 type Output = TextUnit; 90 type Output = TextUnit;
@@ -97,21 +137,21 @@ impl ConvWith for TextEdit {
97 type Output = Vec<languageserver_types::TextEdit>; 137 type Output = Vec<languageserver_types::TextEdit>;
98 138
99 fn conv_with(self, line_index: &LineIndex) -> Vec<languageserver_types::TextEdit> { 139 fn conv_with(self, line_index: &LineIndex) -> Vec<languageserver_types::TextEdit> {
100 self.into_atoms() 140 self.as_atoms()
101 .into_iter() 141 .into_iter()
102 .map_conv_with(line_index) 142 .map_conv_with(line_index)
103 .collect() 143 .collect()
104 } 144 }
105} 145}
106 146
107impl ConvWith for AtomTextEdit { 147impl<'a> ConvWith for &'a AtomTextEdit {
108 type Ctx = LineIndex; 148 type Ctx = LineIndex;
109 type Output = languageserver_types::TextEdit; 149 type Output = languageserver_types::TextEdit;
110 150
111 fn conv_with(self, line_index: &LineIndex) -> languageserver_types::TextEdit { 151 fn conv_with(self, line_index: &LineIndex) -> languageserver_types::TextEdit {
112 languageserver_types::TextEdit { 152 languageserver_types::TextEdit {
113 range: self.delete.conv_with(line_index), 153 range: self.delete.conv_with(line_index),
114 new_text: self.insert, 154 new_text: self.insert.clone(),
115 } 155 }
116 } 156 }
117} 157}
@@ -199,7 +239,7 @@ impl TryConvWith for SourceChange {
199 .source_file_edits 239 .source_file_edits
200 .iter() 240 .iter()
201 .find(|it| it.file_id == pos.file_id) 241 .find(|it| it.file_id == pos.file_id)
202 .map(|it| it.edits.as_slice()) 242 .map(|it| it.edit.as_atoms())
203 .unwrap_or(&[]); 243 .unwrap_or(&[]);
204 let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits); 244 let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits);
205 let position = 245 let position =
@@ -256,7 +296,7 @@ fn translate_offset_with_edit(
256 } 296 }
257} 297}
258 298
259impl TryConvWith for SourceFileNodeEdit { 299impl TryConvWith for SourceFileEdit {
260 type Ctx = ServerWorld; 300 type Ctx = ServerWorld;
261 type Output = TextDocumentEdit; 301 type Output = TextDocumentEdit;
262 fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> { 302 fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> {
@@ -265,7 +305,12 @@ impl TryConvWith for SourceFileNodeEdit {
265 version: None, 305 version: None,
266 }; 306 };
267 let line_index = world.analysis().file_line_index(self.file_id); 307 let line_index = world.analysis().file_line_index(self.file_id);
268 let edits = self.edits.into_iter().map_conv_with(&line_index).collect(); 308 let edits = self
309 .edit
310 .as_atoms()
311 .iter()
312 .map_conv_with(&line_index)
313 .collect();
269 Ok(TextDocumentEdit { 314 Ok(TextDocumentEdit {
270 text_document, 315 text_document,
271 edits, 316 edits,
@@ -278,16 +323,17 @@ impl TryConvWith for FileSystemEdit {
278 type Output = req::FileSystemEdit; 323 type Output = req::FileSystemEdit;
279 fn try_conv_with(self, world: &ServerWorld) -> Result<req::FileSystemEdit> { 324 fn try_conv_with(self, world: &ServerWorld) -> Result<req::FileSystemEdit> {
280 let res = match self { 325 let res = match self {
281 FileSystemEdit::CreateFile { anchor, path } => { 326 FileSystemEdit::CreateFile { source_root, path } => {
282 let uri = world.file_id_to_uri(anchor)?; 327 let uri = world.path_to_uri(source_root, &path)?;
283 let path = &path.as_str()[3..]; // strip `../` b/c url is weird
284 let uri = uri.join(path)?;
285 req::FileSystemEdit::CreateFile { uri } 328 req::FileSystemEdit::CreateFile { uri }
286 } 329 }
287 FileSystemEdit::MoveFile { file, path } => { 330 FileSystemEdit::MoveFile {
288 let src = world.file_id_to_uri(file)?; 331 src,
289 let path = &path.as_str()[3..]; // strip `../` b/c url is weird 332 dst_source_root,
290 let dst = src.join(path)?; 333 dst_path,
334 } => {
335 let src = world.file_id_to_uri(src)?;
336 let dst = world.path_to_uri(dst_source_root, &dst_path)?;
291 req::FileSystemEdit::MoveFile { src, dst } 337 req::FileSystemEdit::MoveFile { src, dst }
292 } 338 }
293 }; 339 };
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index 721665eed..33aa30d70 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -1,7 +1,7 @@
1use serde_derive::Deserialize; 1use serde::Deserialize;
2use serde::Deserialize as _D;
3use flexi_logger::{Duplicate, Logger}; 2use flexi_logger::{Duplicate, Logger};
4use gen_lsp_server::{run_server, stdio_transport}; 3use gen_lsp_server::{run_server, stdio_transport};
4
5use ra_lsp_server::Result; 5use ra_lsp_server::Result;
6 6
7fn main() -> Result<()> { 7fn main() -> Result<()> {
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 8b787c329..a5a2b5eec 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -2,6 +2,7 @@ mod handlers;
2mod subscriptions; 2mod subscriptions;
3 3
4use std::{ 4use std::{
5 fmt,
5 path::PathBuf, 6 path::PathBuf,
6 sync::Arc, 7 sync::Arc,
7}; 8};
@@ -109,6 +110,50 @@ pub fn main_loop(
109 Ok(()) 110 Ok(())
110} 111}
111 112
113enum Event {
114 Msg(RawMessage),
115 Task(Task),
116 Vfs(VfsTask),
117 Lib(LibraryData),
118}
119
120impl fmt::Debug for Event {
121 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122 let debug_verbose_not = |not: &RawNotification, f: &mut fmt::Formatter| {
123 f.debug_struct("RawNotification")
124 .field("method", &not.method)
125 .finish()
126 };
127
128 match self {
129 Event::Msg(RawMessage::Notification(not)) => {
130 if not.is::<req::DidOpenTextDocument>() || not.is::<req::DidChangeTextDocument>() {
131 return debug_verbose_not(not, f);
132 }
133 }
134 Event::Task(Task::Notify(not)) => {
135 if not.is::<req::PublishDecorations>() || not.is::<req::PublishDiagnostics>() {
136 return debug_verbose_not(not, f);
137 }
138 }
139 Event::Task(Task::Respond(resp)) => {
140 return f
141 .debug_struct("RawResponse")
142 .field("id", &resp.id)
143 .field("error", &resp.error)
144 .finish();
145 }
146 _ => (),
147 }
148 match self {
149 Event::Msg(it) => fmt::Debug::fmt(it, f),
150 Event::Task(it) => fmt::Debug::fmt(it, f),
151 Event::Vfs(it) => fmt::Debug::fmt(it, f),
152 Event::Lib(it) => fmt::Debug::fmt(it, f),
153 }
154 }
155}
156
112fn main_loop_inner( 157fn main_loop_inner(
113 internal_mode: bool, 158 internal_mode: bool,
114 supports_decorations: bool, 159 supports_decorations: bool,
@@ -123,13 +168,6 @@ fn main_loop_inner(
123) -> Result<()> { 168) -> Result<()> {
124 let (libdata_sender, libdata_receiver) = unbounded(); 169 let (libdata_sender, libdata_receiver) = unbounded();
125 loop { 170 loop {
126 #[derive(Debug)]
127 enum Event {
128 Msg(RawMessage),
129 Task(Task),
130 Vfs(VfsTask),
131 Lib(LibraryData),
132 }
133 log::trace!("selecting"); 171 log::trace!("selecting");
134 let event = select! { 172 let event = select! {
135 recv(msg_receiver, msg) => match msg { 173 recv(msg_receiver, msg) => match msg {
@@ -143,7 +181,8 @@ fn main_loop_inner(
143 } 181 }
144 recv(libdata_receiver, data) => Event::Lib(data.unwrap()) 182 recv(libdata_receiver, data) => Event::Lib(data.unwrap())
145 }; 183 };
146 log::info!("{:?}", event); 184 log::info!("loop_turn = {:?}", event);
185 let start = std::time::Instant::now();
147 let mut state_changed = false; 186 let mut state_changed = false;
148 match event { 187 match event {
149 Event::Task(task) => on_task(task, msg_sender, pending_requests), 188 Event::Task(task) => on_task(task, msg_sender, pending_requests),
@@ -206,6 +245,7 @@ fn main_loop_inner(
206 subs.subscriptions(), 245 subs.subscriptions(),
207 ) 246 )
208 } 247 }
248 log::info!("loop_turn = {:?}", start.elapsed());
209 } 249 }
210} 250}
211 251
@@ -387,7 +427,7 @@ impl<'a> PoolDispatcher<'a> {
387 RawResponse::err( 427 RawResponse::err(
388 id, 428 id,
389 ErrorCode::ContentModified as i32, 429 ErrorCode::ContentModified as i32,
390 e.to_string(), 430 format!("content modified: {}", e),
391 ) 431 )
392 } else { 432 } else {
393 RawResponse::err( 433 RawResponse::err(
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 572ae7fb5..252d1ba3e 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -2,9 +2,9 @@ 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, CompletionItem, CompletionItemKind, Diagnostic, 5 CodeActionResponse, Command, Diagnostic,
6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, 6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
7 FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, MarkedString, Position, 7 FoldingRangeParams, Location, MarkupContent, MarkupKind, MarkedString, Position,
8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, 8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
9 WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents, 9 WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents,
10}; 10};
@@ -107,9 +107,16 @@ pub fn handle_on_type_formatting(
107 }; 107 };
108 let edits = match world.analysis().on_eq_typed(position) { 108 let edits = match world.analysis().on_eq_typed(position) {
109 None => return Ok(None), 109 None => return Ok(None),
110 Some(mut action) => action.source_file_edits.pop().unwrap().edits, 110 Some(mut action) => action
111 .source_file_edits
112 .pop()
113 .unwrap()
114 .edit
115 .as_atoms()
116 .iter()
117 .map_conv_with(&line_index)
118 .collect(),
111 }; 119 };
112 let edits = edits.into_iter().map_conv_with(&line_index).collect();
113 Ok(Some(edits)) 120 Ok(Some(edits))
114} 121}
115 122
@@ -412,22 +419,7 @@ pub fn handle_completion(
412 None => return Ok(None), 419 None => return Ok(None),
413 Some(items) => items, 420 Some(items) => items,
414 }; 421 };
415 let items = items 422 let items = items.into_iter().map(|item| item.conv()).collect();
416 .into_iter()
417 .map(|item| {
418 let mut res = CompletionItem {
419 label: item.label,
420 filter_text: item.lookup,
421 ..Default::default()
422 };
423 if let Some(snip) = item.snippet {
424 res.insert_text = Some(snip);
425 res.insert_text_format = Some(InsertTextFormat::Snippet);
426 res.kind = Some(CompletionItemKind::Keyword);
427 };
428 res
429 })
430 .collect();
431 423
432 Ok(Some(req::CompletionResponse::Array(items))) 424 Ok(Some(req::CompletionResponse::Array(items)))
433} 425}
@@ -446,8 +438,9 @@ pub fn handle_folding_range(
446 .into_iter() 438 .into_iter()
447 .map(|fold| { 439 .map(|fold| {
448 let kind = match fold.kind { 440 let kind = match fold.kind {
449 FoldKind::Comment => FoldingRangeKind::Comment, 441 FoldKind::Comment => Some(FoldingRangeKind::Comment),
450 FoldKind::Imports => FoldingRangeKind::Imports, 442 FoldKind::Imports => Some(FoldingRangeKind::Imports),
443 FoldKind::Block => None,
451 }; 444 };
452 let range = fold.range.conv_with(&line_index); 445 let range = fold.range.conv_with(&line_index);
453 FoldingRange { 446 FoldingRange {
@@ -455,7 +448,7 @@ pub fn handle_folding_range(
455 start_character: Some(range.start.character), 448 start_character: Some(range.start.character),
456 end_line: range.end.line, 449 end_line: range.end.line,
457 end_character: Some(range.start.character), 450 end_character: Some(range.start.character),
458 kind: Some(kind), 451 kind,
459 } 452 }
460 }) 453 })
461 .collect(), 454 .collect(),
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index 999792ecb..747ab8a8c 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -1,4 +1,4 @@
1use serde_derive::{Serialize, Deserialize}; 1use serde::{Serialize, Deserialize};
2use languageserver_types::{Location, Position, Range, TextDocumentIdentifier, Url}; 2use languageserver_types::{Location, Position, Range, TextDocumentIdentifier, Url};
3use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
4use url_serde; 4use url_serde;
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs
index 785877c4b..c183c25af 100644
--- a/crates/ra_lsp_server/src/server_world.rs
+++ b/crates/ra_lsp_server/src/server_world.rs
@@ -8,7 +8,7 @@ use ra_analysis::{
8 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, 8 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData,
9 SourceRootId 9 SourceRootId
10}; 10};
11use ra_vfs::{Vfs, VfsChange, VfsFile}; 11use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot};
12use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
13use relative_path::RelativePathBuf; 13use relative_path::RelativePathBuf;
14use parking_lot::RwLock; 14use parking_lot::RwLock;
@@ -107,7 +107,6 @@ impl ServerWorldState {
107 let mut libs = Vec::new(); 107 let mut libs = Vec::new();
108 let mut change = AnalysisChange::new(); 108 let mut change = AnalysisChange::new();
109 for c in changes { 109 for c in changes {
110 log::info!("vfs change {:?}", c);
111 match c { 110 match c {
112 VfsChange::AddRoot { root, files } => { 111 VfsChange::AddRoot { root, files } => {
113 let root_path = self.vfs.read().root2path(root); 112 let root_path = self.vfs.read().root2path(root);
@@ -183,4 +182,12 @@ impl ServerWorld {
183 .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; 182 .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
184 Ok(url) 183 Ok(url)
185 } 184 }
185
186 pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
187 let base = self.vfs.read().root2path(VfsRoot(root.0));
188 let path = path.to_path(base);
189 let url = Url::from_file_path(&path)
190 .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
191 Ok(url)
192 }
186} 193}