aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-03 13:54:43 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-03 13:54:43 +0000
commit5443205fdd9f4886cc88ad15c3a6061ffa90ca19 (patch)
tree380084b87b5b6b9174f0a8eb6a7652942e862e23
parentaea2183799e7975d3d9000cec9bb9a3c001a3d4e (diff)
parent7d9e02e5a201fe997f98b6908daadd820d4a6593 (diff)
Merge #415
415: use LSP file system operations r=matklad a=vemoo implements #131 I've replaced `source_file_edits` and `file_system_edits` with `workspace_edit` because [`WorkspacEdit`](https://docs.rs/languageserver-types/0.53.1/languageserver_types/struct.WorkspaceEdit.html) can represent both. I only use `document_changes` because `changes` cannot represent file system operations. But if the client doesn't have the `workspace.workspaceEdit.resourceOperations` capability `WorkspaceEdit` cannot replace the current `FileSystemEdit`. Can we assume that the client will support it? I also adapted the extension code to make use of the new response type, but only for vscode, i don't know if changes have to be made for the emacs part. Co-authored-by: Bernardo <[email protected]>
-rw-r--r--crates/ra_lsp_server/src/conv.rs51
-rw-r--r--crates/ra_lsp_server/src/req.rs22
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs23
-rw-r--r--editors/code/src/commands/apply_source_change.ts43
4 files changed, 61 insertions, 78 deletions
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 1107ffc8b..7230fb101 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -1,11 +1,16 @@
1use languageserver_types::{ 1use languageserver_types::{
2 self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, 2 self, CreateFile, DocumentChangeOperation, DocumentChanges, InsertTextFormat, Location,
3 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, InsertTextFormat, 3 Position, Range, RenameFile, ResourceOp, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
4 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier,
5 WorkspaceEdit,
4}; 6};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition,FileRange, CompletionItem, CompletionItemKind, InsertText, NavigationTarget}; 7use ra_analysis::{
6use ra_editor::{LineCol, LineIndex, translate_offset_with_edit}; 8 CompletionItem, CompletionItemKind, FileId, FilePosition, FileRange, FileSystemEdit,
7use ra_text_edit::{AtomTextEdit, TextEdit}; 9 InsertText, NavigationTarget, SourceChange, SourceFileEdit,
10};
11use ra_editor::{translate_offset_with_edit, LineCol, LineIndex};
8use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 12use ra_syntax::{SyntaxKind, TextRange, TextUnit};
13use ra_text_edit::{AtomTextEdit, TextEdit};
9 14
10use crate::{req, server_world::ServerWorld, Result}; 15use crate::{req, server_world::ServerWorld, Result};
11 16
@@ -49,7 +54,7 @@ impl Conv for CompletionItemKind {
49 type Output = ::languageserver_types::CompletionItemKind; 54 type Output = ::languageserver_types::CompletionItemKind;
50 55
51 fn conv(self) -> <Self as Conv>::Output { 56 fn conv(self) -> <Self as Conv>::Output {
52 use ::languageserver_types::CompletionItemKind::*; 57 use languageserver_types::CompletionItemKind::*;
53 match self { 58 match self {
54 CompletionItemKind::Keyword => Keyword, 59 CompletionItemKind::Keyword => Keyword,
55 CompletionItemKind::Snippet => Snippet, 60 CompletionItemKind::Snippet => Snippet,
@@ -266,12 +271,20 @@ impl TryConvWith for SourceChange {
266 }) 271 })
267 } 272 }
268 }; 273 };
269 let source_file_edits = self.source_file_edits.try_conv_with(world)?; 274 let mut document_changes: Vec<DocumentChangeOperation> = Vec::new();
270 let file_system_edits = self.file_system_edits.try_conv_with(world)?; 275 for resource_op in self.file_system_edits.try_conv_with(world)? {
276 document_changes.push(DocumentChangeOperation::Op(resource_op));
277 }
278 for text_document_edit in self.source_file_edits.try_conv_with(world)? {
279 document_changes.push(DocumentChangeOperation::Edit(text_document_edit));
280 }
281 let workspace_edit = WorkspaceEdit {
282 changes: None,
283 document_changes: Some(DocumentChanges::Operations(document_changes)),
284 };
271 Ok(req::SourceChange { 285 Ok(req::SourceChange {
272 label: self.label, 286 label: self.label,
273 source_file_edits, 287 workspace_edit,
274 file_system_edits,
275 cursor_position, 288 cursor_position,
276 }) 289 })
277 } 290 }
@@ -301,21 +314,25 @@ impl TryConvWith for SourceFileEdit {
301 314
302impl TryConvWith for FileSystemEdit { 315impl TryConvWith for FileSystemEdit {
303 type Ctx = ServerWorld; 316 type Ctx = ServerWorld;
304 type Output = req::FileSystemEdit; 317 type Output = ResourceOp;
305 fn try_conv_with(self, world: &ServerWorld) -> Result<req::FileSystemEdit> { 318 fn try_conv_with(self, world: &ServerWorld) -> Result<ResourceOp> {
306 let res = match self { 319 let res = match self {
307 FileSystemEdit::CreateFile { source_root, path } => { 320 FileSystemEdit::CreateFile { source_root, path } => {
308 let uri = world.path_to_uri(source_root, &path)?; 321 let uri = world.path_to_uri(source_root, &path)?.to_string();
309 req::FileSystemEdit::CreateFile { uri } 322 ResourceOp::Create(CreateFile { uri, options: None })
310 } 323 }
311 FileSystemEdit::MoveFile { 324 FileSystemEdit::MoveFile {
312 src, 325 src,
313 dst_source_root, 326 dst_source_root,
314 dst_path, 327 dst_path,
315 } => { 328 } => {
316 let src = world.file_id_to_uri(src)?; 329 let old_uri = world.file_id_to_uri(src)?.to_string();
317 let dst = world.path_to_uri(dst_source_root, &dst_path)?; 330 let new_uri = world.path_to_uri(dst_source_root, &dst_path)?.to_string();
318 req::FileSystemEdit::MoveFile { src, dst } 331 ResourceOp::Rename(RenameFile {
332 old_uri,
333 new_uri,
334 options: None,
335 })
319 } 336 }
320 }; 337 };
321 Ok(res) 338 Ok(res)
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index 747ab8a8c..b41e90328 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -1,6 +1,6 @@
1use serde::{Serialize, Deserialize};
2use languageserver_types::{Location, Position, Range, TextDocumentIdentifier, Url}; 1use languageserver_types::{Location, Position, Range, TextDocumentIdentifier, Url};
3use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3use serde::{Deserialize, Serialize};
4use url_serde; 4use url_serde;
5 5
6pub use languageserver_types::{ 6pub use languageserver_types::{
@@ -8,7 +8,7 @@ pub use languageserver_types::{
8 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, 8 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, WorkspaceSymbolParams, 11 TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams,
12}; 12};
13 13
14pub enum SyntaxTree {} 14pub enum SyntaxTree {}
@@ -151,26 +151,10 @@ pub struct Runnable {
151#[serde(rename_all = "camelCase")] 151#[serde(rename_all = "camelCase")]
152pub struct SourceChange { 152pub struct SourceChange {
153 pub label: String, 153 pub label: String,
154 pub source_file_edits: Vec<TextDocumentEdit>, 154 pub workspace_edit: WorkspaceEdit,
155 pub file_system_edits: Vec<FileSystemEdit>,
156 pub cursor_position: Option<TextDocumentPositionParams>, 155 pub cursor_position: Option<TextDocumentPositionParams>,
157} 156}
158 157
159#[derive(Serialize, Debug)]
160#[serde(tag = "type", rename_all = "camelCase")]
161pub enum FileSystemEdit {
162 CreateFile {
163 #[serde(with = "url_serde")]
164 uri: Url,
165 },
166 MoveFile {
167 #[serde(with = "url_serde")]
168 src: Url,
169 #[serde(with = "url_serde")]
170 dst: Url,
171 },
172}
173
174pub enum InternalFeedback {} 158pub enum InternalFeedback {}
175 159
176impl Notification for InternalFeedback { 160impl Notification for InternalFeedback {
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index b0e1e65b6..4cae44eab 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -1,8 +1,12 @@
1mod support; 1mod support;
2 2
3use languageserver_types::{
4 CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range,
5};
6use ra_lsp_server::req::{
7 CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams,
8};
3use serde_json::json; 9use serde_json::json;
4use ra_lsp_server::req::{Runnables, RunnablesParams, CodeActionRequest, CodeActionParams, Formatting};
5use languageserver_types::{Position, Range, CodeActionContext, DocumentFormattingParams, FormattingOptions};
6 10
7use crate::support::project; 11use crate::support::project;
8 12
@@ -203,14 +207,15 @@ fn main() {}
203 "arguments": [ 207 "arguments": [
204 { 208 {
205 "cursorPosition": null, 209 "cursorPosition": null,
206 "fileSystemEdits": [ 210 "workspaceEdit": {
207 { 211 "documentChanges": [
208 "type": "createFile", 212 {
213 "kind": "create",
209 "uri": "file:///[..]/src/bar.rs" 214 "uri": "file:///[..]/src/bar.rs"
210 } 215 }
211 ], 216 ]
212 "label": "create module", 217 },
213 "sourceFileEdits": [] 218 "label": "create module"
214 } 219 }
215 ], 220 ],
216 "command": "ra-lsp.applySourceChange", 221 "command": "ra-lsp.applySourceChange",
diff --git a/editors/code/src/commands/apply_source_change.ts b/editors/code/src/commands/apply_source_change.ts
index cf921e3ac..10dbf72c0 100644
--- a/editors/code/src/commands/apply_source_change.ts
+++ b/editors/code/src/commands/apply_source_change.ts
@@ -3,46 +3,23 @@ import * as lc from 'vscode-languageclient';
3 3
4import { Server } from '../server'; 4import { Server } from '../server';
5 5
6interface FileSystemEdit {
7 type: string;
8 uri?: string;
9 src?: string;
10 dst?: string;
11}
12
13export interface SourceChange { 6export interface SourceChange {
14 label: string; 7 label: string;
15 sourceFileEdits: lc.TextDocumentEdit[]; 8 workspaceEdit: lc.WorkspaceEdit;
16 fileSystemEdits: FileSystemEdit[];
17 cursorPosition?: lc.TextDocumentPositionParams; 9 cursorPosition?: lc.TextDocumentPositionParams;
18} 10}
19 11
20export async function handle(change: SourceChange) { 12export async function handle(change: SourceChange) {
21 const wsEdit = new vscode.WorkspaceEdit(); 13 const wsEdit = Server.client.protocol2CodeConverter.asWorkspaceEdit(change.workspaceEdit);
22 for (const sourceEdit of change.sourceFileEdits) {
23 const uri = Server.client.protocol2CodeConverter.asUri(
24 sourceEdit.textDocument.uri
25 );
26 const edits = Server.client.protocol2CodeConverter.asTextEdits(
27 sourceEdit.edits
28 );
29 wsEdit.set(uri, edits);
30 }
31 let created; 14 let created;
32 let moved; 15 let moved;
33 for (const fsEdit of change.fileSystemEdits) { 16 if (change.workspaceEdit.documentChanges) {
34 switch (fsEdit.type) { 17 for (const docChange of change.workspaceEdit.documentChanges) {
35 case 'createFile': 18 if (lc.CreateFile.is(docChange)) {
36 const uri = vscode.Uri.parse(fsEdit.uri!); 19 created = docChange.uri;
37 wsEdit.createFile(uri); 20 } else if (lc.RenameFile.is(docChange)) {
38 created = uri; 21 moved = docChange.newUri;
39 break; 22 }
40 case 'moveFile':
41 const src = vscode.Uri.parse(fsEdit.src!);
42 const dst = vscode.Uri.parse(fsEdit.dst!);
43 wsEdit.renameFile(src, dst);
44 moved = dst;
45 break;
46 } 23 }
47 } 24 }
48 const toOpen = created || moved; 25 const toOpen = created || moved;
@@ -65,6 +42,6 @@ export async function handle(change: SourceChange) {
65 if (!editor.selection.isEmpty) { 42 if (!editor.selection.isEmpty) {
66 return; 43 return;
67 } 44 }
68 editor!.selection = new vscode.Selection(position, position); 45 editor.selection = new vscode.Selection(position, position);
69 } 46 }
70} 47}