|
1 | 1 | import type * as vscode from 'vscode'; |
2 | | -import diff = require('fast-diff'); |
3 | 2 |
|
4 | 3 | /** for test unit */ |
5 | 4 | export type FormatableTextDocument = Pick<vscode.TextDocument, 'getText' | 'offsetAt' | 'positionAt'>; |
@@ -61,72 +60,41 @@ function getTrimmedNewText( |
61 | 60 | return; |
62 | 61 | } |
63 | 62 |
|
64 | | - const map = createOffsetMap(oldText, edit.newText); |
65 | | - const newStart = map[overlapStart]; |
66 | | - const newEnd = map[overlapEnd]; |
67 | | - return { |
68 | | - start: editStart + overlapStart, |
69 | | - end: editStart + overlapEnd, |
70 | | - newText: edit.newText.slice(newStart, newEnd), |
71 | | - }; |
72 | | -} |
| 63 | + let oldTextIndex = 0; |
| 64 | + let newTextIndex = 0; |
| 65 | + let newStart = overlapStart; |
| 66 | + let newEnd = overlapEnd; |
73 | 67 |
|
74 | | -function createOffsetMap(oldText: string, newText: string) { |
75 | | - const length = oldText.length; |
76 | | - const map = new Array<number>(length + 1); |
77 | | - let oldIndex = 0; |
78 | | - let newIndex = 0; |
79 | | - map[0] = 0; |
80 | | - |
81 | | - for (const [op, text] of diff(oldText, newText)) { |
82 | | - if (op === diff.EQUAL) { |
83 | | - for (let i = 0; i < text.length; i++) { |
84 | | - oldIndex++; |
85 | | - newIndex++; |
86 | | - map[oldIndex] = newIndex; |
87 | | - } |
88 | | - } |
89 | | - else if (op === diff.DELETE) { |
90 | | - for (let i = 0; i < text.length; i++) { |
91 | | - oldIndex++; |
92 | | - map[oldIndex] = Number.NaN; |
93 | | - } |
| 68 | + while (true) { |
| 69 | + if (oldTextIndex === overlapStart) { |
| 70 | + newStart = newTextIndex; |
94 | 71 | } |
95 | | - else { |
96 | | - newIndex += text.length; |
| 72 | + if (oldTextIndex === overlapEnd) { |
| 73 | + newEnd = newTextIndex; |
| 74 | + break; |
97 | 75 | } |
98 | | - } |
99 | | - |
100 | | - map[length] = newIndex; |
101 | | - |
102 | | - let lastDefinedIndex = 0; |
103 | | - for (let i = 1; i <= length; i++) { |
104 | | - if (map[i] === undefined || Number.isNaN(map[i])) { |
| 76 | + const oldCharCode = oldText.charCodeAt(oldTextIndex); |
| 77 | + const newCharCode = edit.newText.charCodeAt(newTextIndex); |
| 78 | + if (oldCharCode === newCharCode || (!isWhitespaceChar(oldCharCode) && !isWhitespaceChar(newCharCode))) { |
| 79 | + oldTextIndex++; |
| 80 | + newTextIndex++; |
105 | 81 | continue; |
106 | 82 | } |
107 | | - interpolate(map, lastDefinedIndex, i); |
108 | | - lastDefinedIndex = i; |
109 | | - } |
110 | | - if (lastDefinedIndex < length) { |
111 | | - interpolate(map, lastDefinedIndex, length); |
| 83 | + if (isWhitespaceChar(oldCharCode)) { |
| 84 | + oldTextIndex++; |
| 85 | + } |
| 86 | + if (isWhitespaceChar(newCharCode)) { |
| 87 | + newTextIndex++; |
| 88 | + } |
112 | 89 | } |
113 | 90 |
|
114 | | - return map; |
| 91 | + return { |
| 92 | + start: editStart + overlapStart, |
| 93 | + end: editStart + overlapEnd, |
| 94 | + newText: edit.newText.slice(newStart, newEnd), |
| 95 | + }; |
115 | 96 | } |
116 | 97 |
|
117 | | -function interpolate(map: number[], startIndex: number, endIndex: number) { |
118 | | - const startValue = map[startIndex] ?? 0; |
119 | | - const endValue = map[endIndex] ?? startValue; |
120 | | - const gap = endIndex - startIndex; |
121 | | - if (gap <= 1) { |
122 | | - return; |
123 | | - } |
124 | | - const delta = (endValue - startValue) / gap; |
125 | | - for (let i = 1; i < gap; i++) { |
126 | | - const index = startIndex + i; |
127 | | - if (map[index] !== undefined && !Number.isNaN(map[index])) { |
128 | | - continue; |
129 | | - } |
130 | | - map[index] = Math.floor(startValue + delta * i); |
131 | | - } |
| 98 | +function isWhitespaceChar(charCode: number) { |
| 99 | + return charCode === 32 || charCode === 9 || charCode === 10 || charCode === 13; |
132 | 100 | } |
0 commit comments