0eba8499af0c7855929caf5d739a4389be9e14abd5672609386c46370ad518e6a17bb1efe96dd616dc75add28468941afa1d092699f36fdd5067d9a01da33d 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import { Disposable } from '../../../../base/common/lifecycle.js';
  6. import { EditorAction, registerEditorAction, registerEditorContribution } from '../../../browser/editorExtensions.js';
  7. import { EditorContextKeys } from '../../../common/editorContextKeys.js';
  8. import * as nls from '../../../../nls.js';
  9. class CursorState {
  10. constructor(selections) {
  11. this.selections = selections;
  12. }
  13. equals(other) {
  14. const thisLen = this.selections.length;
  15. const otherLen = other.selections.length;
  16. if (thisLen !== otherLen) {
  17. return false;
  18. }
  19. for (let i = 0; i < thisLen; i++) {
  20. if (!this.selections[i].equalsSelection(other.selections[i])) {
  21. return false;
  22. }
  23. }
  24. return true;
  25. }
  26. }
  27. class StackElement {
  28. constructor(cursorState, scrollTop, scrollLeft) {
  29. this.cursorState = cursorState;
  30. this.scrollTop = scrollTop;
  31. this.scrollLeft = scrollLeft;
  32. }
  33. }
  34. export class CursorUndoRedoController extends Disposable {
  35. constructor(editor) {
  36. super();
  37. this._editor = editor;
  38. this._isCursorUndoRedo = false;
  39. this._undoStack = [];
  40. this._redoStack = [];
  41. this._register(editor.onDidChangeModel((e) => {
  42. this._undoStack = [];
  43. this._redoStack = [];
  44. }));
  45. this._register(editor.onDidChangeModelContent((e) => {
  46. this._undoStack = [];
  47. this._redoStack = [];
  48. }));
  49. this._register(editor.onDidChangeCursorSelection((e) => {
  50. if (this._isCursorUndoRedo) {
  51. return;
  52. }
  53. if (!e.oldSelections) {
  54. return;
  55. }
  56. if (e.oldModelVersionId !== e.modelVersionId) {
  57. return;
  58. }
  59. const prevState = new CursorState(e.oldSelections);
  60. const isEqualToLastUndoStack = (this._undoStack.length > 0 && this._undoStack[this._undoStack.length - 1].cursorState.equals(prevState));
  61. if (!isEqualToLastUndoStack) {
  62. this._undoStack.push(new StackElement(prevState, editor.getScrollTop(), editor.getScrollLeft()));
  63. this._redoStack = [];
  64. if (this._undoStack.length > 50) {
  65. // keep the cursor undo stack bounded
  66. this._undoStack.shift();
  67. }
  68. }
  69. }));
  70. }
  71. static get(editor) {
  72. return editor.getContribution(CursorUndoRedoController.ID);
  73. }
  74. cursorUndo() {
  75. if (!this._editor.hasModel() || this._undoStack.length === 0) {
  76. return;
  77. }
  78. this._redoStack.push(new StackElement(new CursorState(this._editor.getSelections()), this._editor.getScrollTop(), this._editor.getScrollLeft()));
  79. this._applyState(this._undoStack.pop());
  80. }
  81. cursorRedo() {
  82. if (!this._editor.hasModel() || this._redoStack.length === 0) {
  83. return;
  84. }
  85. this._undoStack.push(new StackElement(new CursorState(this._editor.getSelections()), this._editor.getScrollTop(), this._editor.getScrollLeft()));
  86. this._applyState(this._redoStack.pop());
  87. }
  88. _applyState(stackElement) {
  89. this._isCursorUndoRedo = true;
  90. this._editor.setSelections(stackElement.cursorState.selections);
  91. this._editor.setScrollPosition({
  92. scrollTop: stackElement.scrollTop,
  93. scrollLeft: stackElement.scrollLeft
  94. });
  95. this._isCursorUndoRedo = false;
  96. }
  97. }
  98. CursorUndoRedoController.ID = 'editor.contrib.cursorUndoRedoController';
  99. export class CursorUndo extends EditorAction {
  100. constructor() {
  101. super({
  102. id: 'cursorUndo',
  103. label: nls.localize('cursor.undo', "Cursor Undo"),
  104. alias: 'Cursor Undo',
  105. precondition: undefined,
  106. kbOpts: {
  107. kbExpr: EditorContextKeys.textInputFocus,
  108. primary: 2048 /* KeyMod.CtrlCmd */ | 51 /* KeyCode.KeyU */,
  109. weight: 100 /* KeybindingWeight.EditorContrib */
  110. }
  111. });
  112. }
  113. run(accessor, editor, args) {
  114. var _a;
  115. (_a = CursorUndoRedoController.get(editor)) === null || _a === void 0 ? void 0 : _a.cursorUndo();
  116. }
  117. }
  118. export class CursorRedo extends EditorAction {
  119. constructor() {
  120. super({
  121. id: 'cursorRedo',
  122. label: nls.localize('cursor.redo', "Cursor Redo"),
  123. alias: 'Cursor Redo',
  124. precondition: undefined
  125. });
  126. }
  127. run(accessor, editor, args) {
  128. var _a;
  129. (_a = CursorUndoRedoController.get(editor)) === null || _a === void 0 ? void 0 : _a.cursorRedo();
  130. }
  131. }
  132. registerEditorContribution(CursorUndoRedoController.ID, CursorUndoRedoController);
  133. registerEditorAction(CursorUndo);
  134. registerEditorAction(CursorRedo);