diff options
author | Aleksey Kladov <[email protected]> | 2020-05-21 18:50:23 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-05-21 19:05:33 +0100 |
commit | 5b5ebec440841ee98a0aa70b71a135d94f5ca077 (patch) | |
tree | 5accb5fce10496334b49ed5a823d321572b375b4 /crates | |
parent | ba6cf638fbf3d0a025e804f2d354d91abc8afd28 (diff) |
Formalize JoinLines protocol extension
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide/src/lib.rs | 9 | ||||
-rw-r--r-- | crates/ra_text_edit/src/lib.rs | 33 | ||||
-rw-r--r-- | crates/rust-analyzer/src/caps.rs | 9 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lsp_ext.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 30 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 7 |
6 files changed, 60 insertions, 34 deletions
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index d0aeb3ba7..97ff67ee8 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -89,6 +89,7 @@ pub use ra_ide_db::{ | |||
89 | symbol_index::Query, | 89 | symbol_index::Query, |
90 | RootDatabase, | 90 | RootDatabase, |
91 | }; | 91 | }; |
92 | pub use ra_text_edit::{Indel, TextEdit}; | ||
92 | 93 | ||
93 | pub type Cancelable<T> = Result<T, Canceled>; | 94 | pub type Cancelable<T> = Result<T, Canceled>; |
94 | 95 | ||
@@ -285,14 +286,10 @@ impl Analysis { | |||
285 | 286 | ||
286 | /// Returns an edit to remove all newlines in the range, cleaning up minor | 287 | /// Returns an edit to remove all newlines in the range, cleaning up minor |
287 | /// stuff like trailing commas. | 288 | /// stuff like trailing commas. |
288 | pub fn join_lines(&self, frange: FileRange) -> Cancelable<SourceChange> { | 289 | pub fn join_lines(&self, frange: FileRange) -> Cancelable<TextEdit> { |
289 | self.with_db(|db| { | 290 | self.with_db(|db| { |
290 | let parse = db.parse(frange.file_id); | 291 | let parse = db.parse(frange.file_id); |
291 | let file_edit = SourceFileEdit { | 292 | join_lines::join_lines(&parse.tree(), frange.range) |
292 | file_id: frange.file_id, | ||
293 | edit: join_lines::join_lines(&parse.tree(), frange.range), | ||
294 | }; | ||
295 | SourceChange::source_file_edit("Join lines", file_edit) | ||
296 | }) | 293 | }) |
297 | } | 294 | } |
298 | 295 | ||
diff --git a/crates/ra_text_edit/src/lib.rs b/crates/ra_text_edit/src/lib.rs index 199fd1096..25554f583 100644 --- a/crates/ra_text_edit/src/lib.rs +++ b/crates/ra_text_edit/src/lib.rs | |||
@@ -17,7 +17,7 @@ pub struct Indel { | |||
17 | pub delete: TextRange, | 17 | pub delete: TextRange, |
18 | } | 18 | } |
19 | 19 | ||
20 | #[derive(Debug, Clone)] | 20 | #[derive(Default, Debug, Clone)] |
21 | pub struct TextEdit { | 21 | pub struct TextEdit { |
22 | indels: Vec<Indel>, | 22 | indels: Vec<Indel>, |
23 | } | 23 | } |
@@ -64,14 +64,6 @@ impl TextEdit { | |||
64 | builder.finish() | 64 | builder.finish() |
65 | } | 65 | } |
66 | 66 | ||
67 | pub(crate) fn from_indels(mut indels: Vec<Indel>) -> TextEdit { | ||
68 | indels.sort_by_key(|a| (a.delete.start(), a.delete.end())); | ||
69 | for (a1, a2) in indels.iter().zip(indels.iter().skip(1)) { | ||
70 | assert!(a1.delete.end() <= a2.delete.start()) | ||
71 | } | ||
72 | TextEdit { indels } | ||
73 | } | ||
74 | |||
75 | pub fn len(&self) -> usize { | 67 | pub fn len(&self) -> usize { |
76 | self.indels.len() | 68 | self.indels.len() |
77 | } | 69 | } |
@@ -122,6 +114,17 @@ impl TextEdit { | |||
122 | *text = buf | 114 | *text = buf |
123 | } | 115 | } |
124 | 116 | ||
117 | pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> { | ||
118 | // FIXME: can be done without allocating intermediate vector | ||
119 | let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>(); | ||
120 | if !check_disjoint(&mut all) { | ||
121 | return Err(other); | ||
122 | } | ||
123 | self.indels.extend(other.indels); | ||
124 | assert!(check_disjoint(&mut self.indels)); | ||
125 | Ok(()) | ||
126 | } | ||
127 | |||
125 | pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> { | 128 | pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> { |
126 | let mut res = offset; | 129 | let mut res = offset; |
127 | for indel in self.indels.iter() { | 130 | for indel in self.indels.iter() { |
@@ -149,9 +152,19 @@ impl TextEditBuilder { | |||
149 | self.indels.push(Indel::insert(offset, text)) | 152 | self.indels.push(Indel::insert(offset, text)) |
150 | } | 153 | } |
151 | pub fn finish(self) -> TextEdit { | 154 | pub fn finish(self) -> TextEdit { |
152 | TextEdit::from_indels(self.indels) | 155 | let mut indels = self.indels; |
156 | assert!(check_disjoint(&mut indels)); | ||
157 | TextEdit { indels } | ||
153 | } | 158 | } |
154 | pub fn invalidates_offset(&self, offset: TextSize) -> bool { | 159 | pub fn invalidates_offset(&self, offset: TextSize) -> bool { |
155 | self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) | 160 | self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) |
156 | } | 161 | } |
157 | } | 162 | } |
163 | |||
164 | fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool { | ||
165 | indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end())); | ||
166 | indels | ||
167 | .iter() | ||
168 | .zip(indels.iter().skip(1)) | ||
169 | .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start()) | ||
170 | } | ||
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 110c9a442..4c417c270 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | //! Advertizes the capabilities of the LSP Server. | 1 | //! Advertizes the capabilities of the LSP Server. |
2 | use std::env; | 2 | use std::env; |
3 | 3 | ||
4 | use crate::semantic_tokens; | ||
5 | |||
6 | use lsp_types::{ | 4 | use lsp_types::{ |
7 | CallHierarchyServerCapability, CodeActionOptions, CodeActionProviderCapability, | 5 | CallHierarchyServerCapability, CodeActionOptions, CodeActionProviderCapability, |
8 | CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, | 6 | CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, |
@@ -12,6 +10,9 @@ use lsp_types::{ | |||
12 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, | 10 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, |
13 | TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, | 11 | TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, |
14 | }; | 12 | }; |
13 | use serde_json::json; | ||
14 | |||
15 | use crate::semantic_tokens; | ||
15 | 16 | ||
16 | pub fn server_capabilities() -> ServerCapabilities { | 17 | pub fn server_capabilities() -> ServerCapabilities { |
17 | ServerCapabilities { | 18 | ServerCapabilities { |
@@ -91,6 +92,8 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
91 | } | 92 | } |
92 | .into(), | 93 | .into(), |
93 | ), | 94 | ), |
94 | experimental: Default::default(), | 95 | experimental: Some(json!({ |
96 | "joinLines": true, | ||
97 | })), | ||
95 | } | 98 | } |
96 | } | 99 | } |
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 3c7bd609d..1bb1b02ab 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -87,15 +87,15 @@ pub enum JoinLines {} | |||
87 | 87 | ||
88 | impl Request for JoinLines { | 88 | impl Request for JoinLines { |
89 | type Params = JoinLinesParams; | 89 | type Params = JoinLinesParams; |
90 | type Result = SourceChange; | 90 | type Result = Vec<lsp_types::TextEdit>; |
91 | const METHOD: &'static str = "rust-analyzer/joinLines"; | 91 | const METHOD: &'static str = "experimental/joinLines"; |
92 | } | 92 | } |
93 | 93 | ||
94 | #[derive(Deserialize, Serialize, Debug)] | 94 | #[derive(Deserialize, Serialize, Debug)] |
95 | #[serde(rename_all = "camelCase")] | 95 | #[serde(rename_all = "camelCase")] |
96 | pub struct JoinLinesParams { | 96 | pub struct JoinLinesParams { |
97 | pub text_document: TextDocumentIdentifier, | 97 | pub text_document: TextDocumentIdentifier, |
98 | pub range: Range, | 98 | pub ranges: Vec<Range>, |
99 | } | 99 | } |
100 | 100 | ||
101 | pub enum OnEnter {} | 101 | pub enum OnEnter {} |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index fcf08cd79..121964718 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -15,10 +15,11 @@ use lsp_types::{ | |||
15 | DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, | 15 | DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, |
16 | MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, | 16 | MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, |
17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, | 17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, |
18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, TextEdit, Url, WorkspaceEdit, | 18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, |
19 | }; | 19 | }; |
20 | use ra_ide::{ | 20 | use ra_ide::{ |
21 | Assist, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, | 21 | Assist, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, |
22 | TextEdit, | ||
22 | }; | 23 | }; |
23 | use ra_prof::profile; | 24 | use ra_prof::profile; |
24 | use ra_project_model::TargetKind; | 25 | use ra_project_model::TargetKind; |
@@ -149,11 +150,24 @@ pub fn handle_find_matching_brace( | |||
149 | pub fn handle_join_lines( | 150 | pub fn handle_join_lines( |
150 | world: WorldSnapshot, | 151 | world: WorldSnapshot, |
151 | params: lsp_ext::JoinLinesParams, | 152 | params: lsp_ext::JoinLinesParams, |
152 | ) -> Result<lsp_ext::SourceChange> { | 153 | ) -> Result<Vec<lsp_types::TextEdit>> { |
153 | let _p = profile("handle_join_lines"); | 154 | let _p = profile("handle_join_lines"); |
154 | let frange = from_proto::file_range(&world, params.text_document, params.range)?; | 155 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
155 | let source_change = world.analysis().join_lines(frange)?; | 156 | let line_index = world.analysis().file_line_index(file_id)?; |
156 | to_proto::source_change(&world, source_change) | 157 | let line_endings = world.file_line_endings(file_id); |
158 | let mut res = TextEdit::default(); | ||
159 | for range in params.ranges { | ||
160 | let range = from_proto::text_range(&line_index, range); | ||
161 | let edit = world.analysis().join_lines(FileRange { file_id, range })?; | ||
162 | match res.union(edit) { | ||
163 | Ok(()) => (), | ||
164 | Err(_edit) => { | ||
165 | // just ignore overlapping edits | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | let res = to_proto::text_edit_vec(&line_index, line_endings, res); | ||
170 | Ok(res) | ||
157 | } | 171 | } |
158 | 172 | ||
159 | pub fn handle_on_enter( | 173 | pub fn handle_on_enter( |
@@ -172,7 +186,7 @@ pub fn handle_on_enter( | |||
172 | pub fn handle_on_type_formatting( | 186 | pub fn handle_on_type_formatting( |
173 | world: WorldSnapshot, | 187 | world: WorldSnapshot, |
174 | params: lsp_types::DocumentOnTypeFormattingParams, | 188 | params: lsp_types::DocumentOnTypeFormattingParams, |
175 | ) -> Result<Option<Vec<TextEdit>>> { | 189 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { |
176 | let _p = profile("handle_on_type_formatting"); | 190 | let _p = profile("handle_on_type_formatting"); |
177 | let mut position = from_proto::file_position(&world, params.text_document_position)?; | 191 | let mut position = from_proto::file_position(&world, params.text_document_position)?; |
178 | let line_index = world.analysis().file_line_index(position.file_id)?; | 192 | let line_index = world.analysis().file_line_index(position.file_id)?; |
@@ -618,7 +632,7 @@ pub fn handle_references( | |||
618 | pub fn handle_formatting( | 632 | pub fn handle_formatting( |
619 | world: WorldSnapshot, | 633 | world: WorldSnapshot, |
620 | params: DocumentFormattingParams, | 634 | params: DocumentFormattingParams, |
621 | ) -> Result<Option<Vec<TextEdit>>> { | 635 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { |
622 | let _p = profile("handle_formatting"); | 636 | let _p = profile("handle_formatting"); |
623 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 637 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
624 | let file = world.analysis().file_text(file_id)?; | 638 | let file = world.analysis().file_text(file_id)?; |
@@ -685,7 +699,7 @@ pub fn handle_formatting( | |||
685 | } | 699 | } |
686 | } | 700 | } |
687 | 701 | ||
688 | Ok(Some(vec![TextEdit { | 702 | Ok(Some(vec![lsp_types::TextEdit { |
689 | range: Range::new(Position::new(0, 0), end_position), | 703 | range: Range::new(Position::new(0, 0), end_position), |
690 | new_text: captured_stdout, | 704 | new_text: captured_stdout, |
691 | }])) | 705 | }])) |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 617197963..f6f4bb134 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -2,12 +2,11 @@ | |||
2 | use ra_db::{FileId, FileRange}; | 2 | use ra_db::{FileId, FileRange}; |
3 | use ra_ide::{ | 3 | use ra_ide::{ |
4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, | 4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, |
5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, InlayHint, | 5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, |
6 | InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity, | 6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity, |
7 | SourceChange, SourceFileEdit, | 7 | SourceChange, SourceFileEdit, TextEdit, |
8 | }; | 8 | }; |
9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; | 9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; |
10 | use ra_text_edit::{Indel, TextEdit}; | ||
11 | use ra_vfs::LineEndings; | 10 | use ra_vfs::LineEndings; |
12 | 11 | ||
13 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; | 12 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; |