06322cf3f49ffb8df87816a3b3e76e7d3dea493d692ee4d64e06f769dca6c4df2219467c0af9386649a256aab3d20bc3bf6cf46700d4c42d7b9a744efb6a60 4.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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 { lengthAdd, lengthDiffNonNegative, lengthLessThanEqual, lengthToObj, toLength } from './length.js';
  6. export class TextEditInfo {
  7. constructor(startOffset, endOffset, newLength) {
  8. this.startOffset = startOffset;
  9. this.endOffset = endOffset;
  10. this.newLength = newLength;
  11. }
  12. }
  13. export class BeforeEditPositionMapper {
  14. /**
  15. * @param edits Must be sorted by offset in ascending order.
  16. */
  17. constructor(edits, documentLength) {
  18. this.documentLength = documentLength;
  19. this.nextEditIdx = 0;
  20. this.deltaOldToNewLineCount = 0;
  21. this.deltaOldToNewColumnCount = 0;
  22. this.deltaLineIdxInOld = -1;
  23. this.edits = edits.map(edit => TextEditInfoCache.from(edit));
  24. }
  25. /**
  26. * @param offset Must be equal to or greater than the last offset this method has been called with.
  27. */
  28. getOffsetBeforeChange(offset) {
  29. this.adjustNextEdit(offset);
  30. return this.translateCurToOld(offset);
  31. }
  32. /**
  33. * @param offset Must be equal to or greater than the last offset this method has been called with.
  34. */
  35. getDistanceToNextChange(offset) {
  36. this.adjustNextEdit(offset);
  37. const nextEdit = this.edits[this.nextEditIdx];
  38. const nextChangeOffset = nextEdit ? this.translateOldToCur(nextEdit.offsetObj) : this.documentLength;
  39. return lengthDiffNonNegative(offset, nextChangeOffset);
  40. }
  41. translateOldToCur(oldOffsetObj) {
  42. if (oldOffsetObj.lineCount === this.deltaLineIdxInOld) {
  43. return toLength(oldOffsetObj.lineCount + this.deltaOldToNewLineCount, oldOffsetObj.columnCount + this.deltaOldToNewColumnCount);
  44. }
  45. else {
  46. return toLength(oldOffsetObj.lineCount + this.deltaOldToNewLineCount, oldOffsetObj.columnCount);
  47. }
  48. }
  49. translateCurToOld(newOffset) {
  50. const offsetObj = lengthToObj(newOffset);
  51. if (offsetObj.lineCount - this.deltaOldToNewLineCount === this.deltaLineIdxInOld) {
  52. return toLength(offsetObj.lineCount - this.deltaOldToNewLineCount, offsetObj.columnCount - this.deltaOldToNewColumnCount);
  53. }
  54. else {
  55. return toLength(offsetObj.lineCount - this.deltaOldToNewLineCount, offsetObj.columnCount);
  56. }
  57. }
  58. adjustNextEdit(offset) {
  59. while (this.nextEditIdx < this.edits.length) {
  60. const nextEdit = this.edits[this.nextEditIdx];
  61. // After applying the edit, what is its end offset (considering all previous edits)?
  62. const nextEditEndOffsetInCur = this.translateOldToCur(nextEdit.endOffsetAfterObj);
  63. if (lengthLessThanEqual(nextEditEndOffsetInCur, offset)) {
  64. // We are after the edit, skip it
  65. this.nextEditIdx++;
  66. const nextEditEndOffsetInCurObj = lengthToObj(nextEditEndOffsetInCur);
  67. // Before applying the edit, what is its end offset (considering all previous edits)?
  68. const nextEditEndOffsetBeforeInCurObj = lengthToObj(this.translateOldToCur(nextEdit.endOffsetBeforeObj));
  69. const lineDelta = nextEditEndOffsetInCurObj.lineCount - nextEditEndOffsetBeforeInCurObj.lineCount;
  70. this.deltaOldToNewLineCount += lineDelta;
  71. const previousColumnDelta = this.deltaLineIdxInOld === nextEdit.endOffsetBeforeObj.lineCount ? this.deltaOldToNewColumnCount : 0;
  72. const columnDelta = nextEditEndOffsetInCurObj.columnCount - nextEditEndOffsetBeforeInCurObj.columnCount;
  73. this.deltaOldToNewColumnCount = previousColumnDelta + columnDelta;
  74. this.deltaLineIdxInOld = nextEdit.endOffsetBeforeObj.lineCount;
  75. }
  76. else {
  77. // We are in or before the edit.
  78. break;
  79. }
  80. }
  81. }
  82. }
  83. class TextEditInfoCache {
  84. constructor(startOffset, endOffset, textLength) {
  85. this.endOffsetBeforeObj = lengthToObj(endOffset);
  86. this.endOffsetAfterObj = lengthToObj(lengthAdd(startOffset, textLength));
  87. this.offsetObj = lengthToObj(startOffset);
  88. }
  89. static from(edit) {
  90. return new TextEditInfoCache(edit.startOffset, edit.endOffset, edit.newLength);
  91. }
  92. }