Browse Source

Backport PR #10647: Fix #10391 - incorrect cursor position after autocomplete (#10689)

Co-authored-by: Kevin Jahns <kevin.jahns@protonmail.com>
MeeseeksMachine 3 years ago
parent
commit
3cba08d476
2 changed files with 40 additions and 1 deletions
  1. 4 0
      packages/completer/src/handler.ts
  2. 36 1
      packages/completer/test/handler.spec.ts

+ 4 - 0
packages/completer/src/handler.ts

@@ -186,8 +186,12 @@ export class CompletionHandler implements IDisposable {
     }
 
     const { start, end, value } = patch;
+    const cursorBeforeChange = editor.getOffsetAt(editor.getCursorPosition());
     // we need to update the shared model in a single transaction so that the undo manager works as expected
     editor.model.sharedModel.updateSource(start, end, value);
+    if (cursorBeforeChange <= end && cursorBeforeChange >= start) {
+      editor.setCursorPosition(editor.getPositionAt(start + value.length)!);
+    }
   }
 
   /**

+ 36 - 1
packages/completer/test/handler.spec.ts

@@ -246,7 +246,7 @@ describe('@jupyterlab/completer', () => {
         const text = 'eggs\nfoo # comment\nbaz';
         const want = 'eggs\nfoobar # comment\nbaz';
         const line = 1;
-        const column = 5;
+        const column = 5; // this sets the cursor after the "#" sign - not in the mid of the replaced word
         const request: Completer.ITextState = {
           column,
           line,
@@ -320,5 +320,40 @@ describe('@jupyterlab/completer', () => {
         console.warn(editor.getCursorPosition());
       });
     });
+
+    it('should update cursor position after autocomplete on empty word', () => {
+      const model = new CompleterModel();
+      const patch = 'foobar';
+      const completer = new Completer({ editor: null, model });
+      const handler = new TestCompletionHandler({ completer, connector });
+      const editor = createEditorWidget().editor;
+      const text = 'eggs\n  # comment\nbaz';
+      const want = 'eggs\n foobar # comment\nbaz';
+      const line = 1;
+      const column = 1;
+      const request: Completer.ITextState = {
+        column: column,
+        line,
+        lineHeight: 0,
+        charWidth: 0,
+        coords: null,
+        text
+      };
+
+      handler.editor = editor;
+      handler.editor.model.value.text = text;
+      handler.editor.model.sharedModel.clearUndoHistory();
+      handler.editor.setCursorPosition({ line, column });
+      model.original = request;
+      const offset = handler.editor.getOffsetAt({ line, column });
+      model.cursor = { start: offset, end: offset };
+      // Make the completion, check its value and cursor position.
+      (completer.selected as any).emit(patch);
+      expect(editor.model.value.text).toBe(want);
+      expect(editor.getCursorPosition()).toEqual({
+        line,
+        column: column + 6
+      });
+    });
   });
 });