Просмотр исходного кода

[cm6] Account for line shifts when updating the spelling line tracker (#13015)

* Use lineShift

* Use fromA instead of fromB

* Only check the update doc

* Always use oldDoc

* Copy tests

GitOrigin-RevId: 05e5516b09ee4a25d8ac2b5f2994a034f35c9e82
Alf Eaton 3 лет назад
Родитель
Сommit
466011df86

+ 18 - 14
services/web/frontend/js/features/source-editor/extensions/spelling/line-tracker.ts

@@ -58,14 +58,13 @@ export class LineTracker {
   applyUpdate(update: ViewUpdate) {
     for (const transaction of update.transactions) {
       if (transaction.docChanged) {
-        let positionShift = 0
+        let lineShift = 0
         transaction.changes.iterChanges(
           (fromA, toA, fromB, toB, insertedText) => {
             const insertedLength = insertedText.length
             const removedLength = toA - fromA
             const hasInserted = insertedLength > 0
             const hasRemoved = removedLength > 0
-            const doc = update.state.doc
             const oldDoc = transaction.startState.doc
             if (hasRemoved) {
               const startLine = oldDoc.lineAt(fromA).number
@@ -85,10 +84,15 @@ export class LineTracker {
                *   |2|bb|  => [false, true, false]
                *   |3|dddd|
                */
-              this._lines.splice(startLine - 1, endLine - startLine + 1, true)
+              this._lines.splice(
+                startLine - 1 + lineShift,
+                endLine - startLine + 1,
+                true
+              )
+              lineShift -= endLine - startLine
             }
             if (hasInserted) {
-              const startLine = doc.lineAt(fromB).number
+              const startLine = oldDoc.lineAt(fromA).number
               /* Mark start line as changed, and insert new (changed) lines after.
                * Example:
                *   with this text:
@@ -108,19 +112,19 @@ export class LineTracker {
                *   |4|cccc|
                */
               const changes = new Array(insertedText.lines).fill(true)
-              this._lines.splice(startLine - 1, 1, ...changes)
+              this._lines.splice(startLine - 1 + lineShift, 1, ...changes)
+              lineShift += changes.length - 1
             }
-            positionShift = positionShift - removedLength + insertedLength
           }
         )
-        if (update.state.doc.lines !== this._lines.length) {
-          throw new OError(
-            'LineTracker length does not match document line count'
-          ).withInfo({
-            documentLines: update.state.doc.lines,
-            trackerLines: this._lines.length,
-          })
-        }
+      }
+      if (update.state.doc.lines !== this._lines.length) {
+        throw new OError(
+          'LineTracker length does not match document line count'
+        ).withInfo({
+          documentLines: update.state.doc.lines,
+          trackerLines: this._lines.length,
+        })
       }
     }
   }

+ 24 - 0
services/web/test/frontend/features/source-editor/extensions/spelling/line-tracker.test.ts

@@ -178,5 +178,29 @@ describe('LineTracker', function () {
         [5, false],
       ])
     })
+
+    it('should handle multiple deletions', function () {
+      const transaction = view.state.update({
+        changes: [
+          { from: 0, to: 24, insert: '' },
+          { from: 39, to: 44, insert: '' },
+        ],
+      })
+      view.dispatch(transaction)
+      check([
+        [1, true],
+        [2, true],
+      ])
+    })
+
+    it('should handle multiple insertions', function () {
+      const transactionUndo = view.state.update({
+        changes: [
+          { from: 0, to: 0, insert: 'big change\n'.repeat(20) },
+          { from: 50, to: 50, insert: 'xxxx' },
+        ],
+      })
+      view.dispatch(transactionUndo)
+    })
   })
 })