|
1 |
| -import type * as atomIde from 'atom-ide-base'; |
2 |
| -import Convert from '../convert'; |
3 |
| -import { LanguageClientConnection, ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse } from '../languageclient'; |
4 |
| -import { TextBuffer, TextEditor } from 'atom'; |
| 1 | +import type * as atomIde from "atom-ide-base" |
| 2 | +import Convert from "../convert" |
| 3 | +import { LanguageClientConnection, ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse } from "../languageclient" |
| 4 | +import { TextBuffer, TextEditor } from "atom" |
5 | 5 |
|
6 | 6 | /** Public: Adapts workspace/applyEdit commands to editors. */
|
7 | 7 | export default class ApplyEditAdapter {
|
8 | 8 | /** Public: Attach to a {LanguageClientConnection} to receive edit events. */
|
9 | 9 | public static attach(connection: LanguageClientConnection): void {
|
10 |
| - connection.onApplyEdit((m) => ApplyEditAdapter.onApplyEdit(m)); |
| 10 | + connection.onApplyEdit((m) => ApplyEditAdapter.onApplyEdit(m)) |
11 | 11 | }
|
12 | 12 |
|
13 | 13 | /**
|
14 | 14 | * Tries to apply edits and reverts if anything goes wrong.
|
15 | 15 | * Returns the checkpoint, so the caller can revert changes if needed.
|
16 | 16 | */
|
17 | 17 | public static applyEdits(buffer: TextBuffer, edits: atomIde.TextEdit[]): number {
|
18 |
| - const checkpoint = buffer.createCheckpoint(); |
| 18 | + const checkpoint = buffer.createCheckpoint() |
19 | 19 | try {
|
20 | 20 | // Sort edits in reverse order to prevent edit conflicts.
|
21 |
| - edits.sort((edit1, edit2) => -edit1.oldRange.compare(edit2.oldRange)); |
| 21 | + edits.sort((edit1, edit2) => -edit1.oldRange.compare(edit2.oldRange)) |
22 | 22 | edits.reduce((previous: atomIde.TextEdit | null, current) => {
|
23 |
| - ApplyEditAdapter.validateEdit(buffer, current, previous); |
24 |
| - buffer.setTextInRange(current.oldRange, current.newText); |
25 |
| - return current; |
26 |
| - }, null); |
27 |
| - buffer.groupChangesSinceCheckpoint(checkpoint); |
28 |
| - return checkpoint; |
| 23 | + ApplyEditAdapter.validateEdit(buffer, current, previous) |
| 24 | + buffer.setTextInRange(current.oldRange, current.newText) |
| 25 | + return current |
| 26 | + }, null) |
| 27 | + buffer.groupChangesSinceCheckpoint(checkpoint) |
| 28 | + return checkpoint |
29 | 29 | } catch (err) {
|
30 |
| - buffer.revertToCheckpoint(checkpoint); |
31 |
| - throw err; |
| 30 | + buffer.revertToCheckpoint(checkpoint) |
| 31 | + throw err |
32 | 32 | }
|
33 | 33 | }
|
34 | 34 |
|
35 | 35 | public static async onApplyEdit(params: ApplyWorkspaceEditParams): Promise<ApplyWorkspaceEditResponse> {
|
36 |
| - let changes = params.edit.changes || {}; |
| 36 | + let changes = params.edit.changes || {} |
37 | 37 |
|
38 | 38 | if (params.edit.documentChanges) {
|
39 |
| - changes = {}; |
| 39 | + changes = {} |
40 | 40 | params.edit.documentChanges.forEach((change) => {
|
41 |
| - if (change && 'textDocument' in change && change.textDocument) { |
42 |
| - changes[change.textDocument.uri] = change.edits; |
| 41 | + if (change && "textDocument" in change && change.textDocument) { |
| 42 | + changes[change.textDocument.uri] = change.edits |
43 | 43 | }
|
44 |
| - }); |
| 44 | + }) |
45 | 45 | }
|
46 | 46 |
|
47 |
| - const uris = Object.keys(changes); |
| 47 | + const uris = Object.keys(changes) |
48 | 48 |
|
49 | 49 | // Keep checkpoints from all successful buffer edits
|
50 |
| - const checkpoints: Array<{ buffer: TextBuffer; checkpoint: number }> = []; |
| 50 | + const checkpoints: Array<{ buffer: TextBuffer; checkpoint: number }> = [] |
51 | 51 |
|
52 | 52 | const promises = uris.map(async (uri) => {
|
53 |
| - const path = Convert.uriToPath(uri); |
| 53 | + const path = Convert.uriToPath(uri) |
54 | 54 | const editor = (await atom.workspace.open(path, {
|
55 | 55 | searchAllPanes: true,
|
56 | 56 | // Open new editors in the background.
|
57 | 57 | activatePane: false,
|
58 | 58 | activateItem: false,
|
59 |
| - })) as TextEditor; |
60 |
| - const buffer = editor.getBuffer(); |
| 59 | + })) as TextEditor |
| 60 | + const buffer = editor.getBuffer() |
61 | 61 | // Get an existing editor for the file, or open a new one if it doesn't exist.
|
62 |
| - const edits = Convert.convertLsTextEdits(changes[uri]); |
63 |
| - const checkpoint = ApplyEditAdapter.applyEdits(buffer, edits); |
64 |
| - checkpoints.push({ buffer, checkpoint }); |
65 |
| - }); |
| 62 | + const edits = Convert.convertLsTextEdits(changes[uri]) |
| 63 | + const checkpoint = ApplyEditAdapter.applyEdits(buffer, edits) |
| 64 | + checkpoints.push({ buffer, checkpoint }) |
| 65 | + }) |
66 | 66 |
|
67 | 67 | // Apply all edits or fail and revert everything
|
68 | 68 | const applied = await Promise.all(promises)
|
69 | 69 | .then(() => true)
|
70 | 70 | .catch((err) => {
|
71 |
| - atom.notifications.addError('workspace/applyEdits failed', { |
72 |
| - description: 'Failed to apply edits.', |
| 71 | + atom.notifications.addError("workspace/applyEdits failed", { |
| 72 | + description: "Failed to apply edits.", |
73 | 73 | detail: err.message,
|
74 |
| - }); |
| 74 | + }) |
75 | 75 | checkpoints.forEach(({ buffer, checkpoint }) => {
|
76 |
| - buffer.revertToCheckpoint(checkpoint); |
77 |
| - }); |
78 |
| - return false; |
79 |
| - }); |
| 76 | + buffer.revertToCheckpoint(checkpoint) |
| 77 | + }) |
| 78 | + return false |
| 79 | + }) |
80 | 80 |
|
81 |
| - return { applied }; |
| 81 | + return { applied } |
82 | 82 | }
|
83 | 83 |
|
84 | 84 | /** Private: Do some basic sanity checking on the edit ranges. */
|
85 | 85 | private static validateEdit(buffer: TextBuffer, edit: atomIde.TextEdit, prevEdit: atomIde.TextEdit | null): void {
|
86 |
| - const path = buffer.getPath() || ''; |
| 86 | + const path = buffer.getPath() || "" |
87 | 87 | if (prevEdit && edit.oldRange.end.compare(prevEdit.oldRange.start) > 0) {
|
88 |
| - throw Error(`Found overlapping edit ranges in ${path}`); |
| 88 | + throw Error(`Found overlapping edit ranges in ${path}`) |
89 | 89 | }
|
90 |
| - const startRow = edit.oldRange.start.row; |
91 |
| - const startCol = edit.oldRange.start.column; |
92 |
| - const lineLength = buffer.lineLengthForRow(startRow); |
| 90 | + const startRow = edit.oldRange.start.row |
| 91 | + const startCol = edit.oldRange.start.column |
| 92 | + const lineLength = buffer.lineLengthForRow(startRow) |
93 | 93 | if (lineLength == null || startCol > lineLength) {
|
94 |
| - throw Error(`Out of range edit on ${path}:${startRow + 1}:${startCol + 1}`); |
| 94 | + throw Error(`Out of range edit on ${path}:${startRow + 1}:${startCol + 1}`) |
95 | 95 | }
|
96 | 96 | }
|
97 | 97 | }
|
0 commit comments