diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-11-09 11:54:42 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-11-09 11:54:42 +0000 |
commit | 2d3b0571bb02aa85e3aae390e5cfb10b0ada5c38 (patch) | |
tree | 8aebf9a517eef712cc704cd983677183be898010 | |
parent | 2f247140817c9cbd9009085c9f9ccedb4f6a718f (diff) | |
parent | be00b6b8fa03f9b578ca5f736e745d4d99ffd649 (diff) |
Merge #6465
6465: Support multiple file edits in AssistBuilder r=matklad a=Veykril
Fixes #6459
Co-authored-by: Lukas Wirth <[email protected]>
-rw-r--r-- | crates/assists/src/assist_context.rs | 25 | ||||
-rw-r--r-- | editors/code/src/snippets.ts | 23 |
2 files changed, 34 insertions, 14 deletions
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs index 51a160f40..a17e592b0 100644 --- a/crates/assists/src/assist_context.rs +++ b/crates/assists/src/assist_context.rs | |||
@@ -208,7 +208,7 @@ pub(crate) struct AssistBuilder { | |||
208 | edit: TextEditBuilder, | 208 | edit: TextEditBuilder, |
209 | file_id: FileId, | 209 | file_id: FileId, |
210 | is_snippet: bool, | 210 | is_snippet: bool, |
211 | change: SourceChange, | 211 | source_file_edits: Vec<SourceFileEdit>, |
212 | } | 212 | } |
213 | 213 | ||
214 | impl AssistBuilder { | 214 | impl AssistBuilder { |
@@ -217,20 +217,27 @@ impl AssistBuilder { | |||
217 | edit: TextEdit::builder(), | 217 | edit: TextEdit::builder(), |
218 | file_id, | 218 | file_id, |
219 | is_snippet: false, | 219 | is_snippet: false, |
220 | change: SourceChange::default(), | 220 | source_file_edits: Vec::default(), |
221 | } | 221 | } |
222 | } | 222 | } |
223 | 223 | ||
224 | pub(crate) fn edit_file(&mut self, file_id: FileId) { | 224 | pub(crate) fn edit_file(&mut self, file_id: FileId) { |
225 | self.commit(); | ||
225 | self.file_id = file_id; | 226 | self.file_id = file_id; |
226 | } | 227 | } |
227 | 228 | ||
228 | fn commit(&mut self) { | 229 | fn commit(&mut self) { |
229 | let edit = mem::take(&mut self.edit).finish(); | 230 | let edit = mem::take(&mut self.edit).finish(); |
230 | if !edit.is_empty() { | 231 | if !edit.is_empty() { |
231 | let new_edit = SourceFileEdit { file_id: self.file_id, edit }; | 232 | match self.source_file_edits.binary_search_by_key(&self.file_id, |edit| edit.file_id) { |
232 | assert!(!self.change.source_file_edits.iter().any(|it| it.file_id == new_edit.file_id)); | 233 | Ok(idx) => self.source_file_edits[idx] |
233 | self.change.source_file_edits.push(new_edit); | 234 | .edit |
235 | .union(edit) | ||
236 | .expect("overlapping edits for same file"), | ||
237 | Err(idx) => self | ||
238 | .source_file_edits | ||
239 | .insert(idx, SourceFileEdit { file_id: self.file_id, edit }), | ||
240 | } | ||
234 | } | 241 | } |
235 | } | 242 | } |
236 | 243 | ||
@@ -277,10 +284,10 @@ impl AssistBuilder { | |||
277 | 284 | ||
278 | fn finish(mut self) -> SourceChange { | 285 | fn finish(mut self) -> SourceChange { |
279 | self.commit(); | 286 | self.commit(); |
280 | let mut change = mem::take(&mut self.change); | 287 | SourceChange { |
281 | if self.is_snippet { | 288 | source_file_edits: mem::take(&mut self.source_file_edits), |
282 | change.is_snippet = true; | 289 | file_system_edits: Default::default(), |
290 | is_snippet: self.is_snippet, | ||
283 | } | 291 | } |
284 | change | ||
285 | } | 292 | } |
286 | } | 293 | } |
diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts index 258b49982..fee736e7d 100644 --- a/editors/code/src/snippets.ts +++ b/editors/code/src/snippets.ts | |||
@@ -3,16 +3,29 @@ import * as vscode from 'vscode'; | |||
3 | import { assert } from './util'; | 3 | import { assert } from './util'; |
4 | 4 | ||
5 | export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { | 5 | export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { |
6 | assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`); | 6 | if (edit.entries().length === 1) { |
7 | const [uri, edits] = edit.entries()[0]; | 7 | const [uri, edits] = edit.entries()[0]; |
8 | const editor = await editorFromUri(uri); | ||
9 | if (editor) await applySnippetTextEdits(editor, edits); | ||
10 | return; | ||
11 | } | ||
12 | for (const [uri, edits] of edit.entries()) { | ||
13 | const editor = await editorFromUri(uri); | ||
14 | if (editor) await editor.edit((builder) => { | ||
15 | for (const indel of edits) { | ||
16 | assert(!parseSnippet(indel.newText), `bad ws edit: snippet received with multiple edits: ${JSON.stringify(edit)}`); | ||
17 | builder.replace(indel.range, indel.newText); | ||
18 | } | ||
19 | }); | ||
20 | } | ||
21 | } | ||
8 | 22 | ||
23 | async function editorFromUri(uri: vscode.Uri): Promise<vscode.TextEditor | undefined> { | ||
9 | if (vscode.window.activeTextEditor?.document.uri !== uri) { | 24 | if (vscode.window.activeTextEditor?.document.uri !== uri) { |
10 | // `vscode.window.visibleTextEditors` only contains editors whose contents are being displayed | 25 | // `vscode.window.visibleTextEditors` only contains editors whose contents are being displayed |
11 | await vscode.window.showTextDocument(uri, {}); | 26 | await vscode.window.showTextDocument(uri, {}); |
12 | } | 27 | } |
13 | const editor = vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString()); | 28 | return vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString()); |
14 | if (!editor) return; | ||
15 | await applySnippetTextEdits(editor, edits); | ||
16 | } | 29 | } |
17 | 30 | ||
18 | export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) { | 31 | export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) { |