265a72e24009b1f8a40ecfed746cc7b3f53e5a2d282e7e8ea1378354712d63807eca67b0add9c34d94b9caf553bfd8a4e7634f714df145a957ccf95d68098b 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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 { CursorState, SingleCursorState } from '../cursorCommon.js';
  6. import { Position } from '../core/position.js';
  7. import { Range } from '../core/range.js';
  8. import { Selection } from '../core/selection.js';
  9. /**
  10. * Represents a single cursor.
  11. */
  12. export class Cursor {
  13. constructor(context) {
  14. this._selTrackedRange = null;
  15. this._trackSelection = true;
  16. this._setState(context, new SingleCursorState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0), new SingleCursorState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0));
  17. }
  18. dispose(context) {
  19. this._removeTrackedRange(context);
  20. }
  21. startTrackingSelection(context) {
  22. this._trackSelection = true;
  23. this._updateTrackedRange(context);
  24. }
  25. stopTrackingSelection(context) {
  26. this._trackSelection = false;
  27. this._removeTrackedRange(context);
  28. }
  29. _updateTrackedRange(context) {
  30. if (!this._trackSelection) {
  31. // don't track the selection
  32. return;
  33. }
  34. this._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, this.modelState.selection, 0 /* TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges */);
  35. }
  36. _removeTrackedRange(context) {
  37. this._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, null, 0 /* TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges */);
  38. }
  39. asCursorState() {
  40. return new CursorState(this.modelState, this.viewState);
  41. }
  42. readSelectionFromMarkers(context) {
  43. const range = context.model._getTrackedRange(this._selTrackedRange);
  44. return Selection.fromRange(range, this.modelState.selection.getDirection());
  45. }
  46. ensureValidState(context) {
  47. this._setState(context, this.modelState, this.viewState);
  48. }
  49. setState(context, modelState, viewState) {
  50. this._setState(context, modelState, viewState);
  51. }
  52. static _validatePositionWithCache(viewModel, position, cacheInput, cacheOutput) {
  53. if (position.equals(cacheInput)) {
  54. return cacheOutput;
  55. }
  56. return viewModel.normalizePosition(position, 2 /* PositionAffinity.None */);
  57. }
  58. static _validateViewState(viewModel, viewState) {
  59. const position = viewState.position;
  60. const sStartPosition = viewState.selectionStart.getStartPosition();
  61. const sEndPosition = viewState.selectionStart.getEndPosition();
  62. const validPosition = viewModel.normalizePosition(position, 2 /* PositionAffinity.None */);
  63. const validSStartPosition = this._validatePositionWithCache(viewModel, sStartPosition, position, validPosition);
  64. const validSEndPosition = this._validatePositionWithCache(viewModel, sEndPosition, sStartPosition, validSStartPosition);
  65. if (position.equals(validPosition) && sStartPosition.equals(validSStartPosition) && sEndPosition.equals(validSEndPosition)) {
  66. // fast path: the state is valid
  67. return viewState;
  68. }
  69. return new SingleCursorState(Range.fromPositions(validSStartPosition, validSEndPosition), viewState.selectionStartLeftoverVisibleColumns + sStartPosition.column - validSStartPosition.column, validPosition, viewState.leftoverVisibleColumns + position.column - validPosition.column);
  70. }
  71. _setState(context, modelState, viewState) {
  72. if (viewState) {
  73. viewState = Cursor._validateViewState(context.viewModel, viewState);
  74. }
  75. if (!modelState) {
  76. if (!viewState) {
  77. return;
  78. }
  79. // We only have the view state => compute the model state
  80. const selectionStart = context.model.validateRange(context.coordinatesConverter.convertViewRangeToModelRange(viewState.selectionStart));
  81. const position = context.model.validatePosition(context.coordinatesConverter.convertViewPositionToModelPosition(viewState.position));
  82. modelState = new SingleCursorState(selectionStart, viewState.selectionStartLeftoverVisibleColumns, position, viewState.leftoverVisibleColumns);
  83. }
  84. else {
  85. // Validate new model state
  86. const selectionStart = context.model.validateRange(modelState.selectionStart);
  87. const selectionStartLeftoverVisibleColumns = modelState.selectionStart.equalsRange(selectionStart) ? modelState.selectionStartLeftoverVisibleColumns : 0;
  88. const position = context.model.validatePosition(modelState.position);
  89. const leftoverVisibleColumns = modelState.position.equals(position) ? modelState.leftoverVisibleColumns : 0;
  90. modelState = new SingleCursorState(selectionStart, selectionStartLeftoverVisibleColumns, position, leftoverVisibleColumns);
  91. }
  92. if (!viewState) {
  93. // We only have the model state => compute the view state
  94. const viewSelectionStart1 = context.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelState.selectionStart.startLineNumber, modelState.selectionStart.startColumn));
  95. const viewSelectionStart2 = context.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelState.selectionStart.endLineNumber, modelState.selectionStart.endColumn));
  96. const viewSelectionStart = new Range(viewSelectionStart1.lineNumber, viewSelectionStart1.column, viewSelectionStart2.lineNumber, viewSelectionStart2.column);
  97. const viewPosition = context.coordinatesConverter.convertModelPositionToViewPosition(modelState.position);
  98. viewState = new SingleCursorState(viewSelectionStart, modelState.selectionStartLeftoverVisibleColumns, viewPosition, modelState.leftoverVisibleColumns);
  99. }
  100. else {
  101. // Validate new view state
  102. const viewSelectionStart = context.coordinatesConverter.validateViewRange(viewState.selectionStart, modelState.selectionStart);
  103. const viewPosition = context.coordinatesConverter.validateViewPosition(viewState.position, modelState.position);
  104. viewState = new SingleCursorState(viewSelectionStart, modelState.selectionStartLeftoverVisibleColumns, viewPosition, modelState.leftoverVisibleColumns);
  105. }
  106. this.modelState = modelState;
  107. this.viewState = viewState;
  108. this._updateTrackedRange(context);
  109. }
  110. }