5cc984ebc2932677100ba6836e6e0ed89f16814a68756555970de452bb280caba6d2bc9acd1bf4d6b9367d1e300e4a96873d91ed06ebe439025b35fd2cf209 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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 { findFirstInSorted } from '../../../../base/common/arrays.js';
  6. import { Emitter } from '../../../../base/common/event.js';
  7. import { Range } from '../../../common/core/range.js';
  8. import { countEOL } from '../../../common/core/eolCounter.js';
  9. export class HiddenRangeModel {
  10. constructor(model) {
  11. this._updateEventEmitter = new Emitter();
  12. this._hasLineChanges = false;
  13. this._foldingModel = model;
  14. this._foldingModelListener = model.onDidChange(_ => this.updateHiddenRanges());
  15. this._hiddenRanges = [];
  16. if (model.regions.length) {
  17. this.updateHiddenRanges();
  18. }
  19. }
  20. get onDidChange() { return this._updateEventEmitter.event; }
  21. get hiddenRanges() { return this._hiddenRanges; }
  22. notifyChangeModelContent(e) {
  23. if (this._hiddenRanges.length && !this._hasLineChanges) {
  24. this._hasLineChanges = e.changes.some(change => {
  25. return change.range.endLineNumber !== change.range.startLineNumber || countEOL(change.text)[0] !== 0;
  26. });
  27. }
  28. }
  29. updateHiddenRanges() {
  30. let updateHiddenAreas = false;
  31. const newHiddenAreas = [];
  32. let i = 0; // index into hidden
  33. let k = 0;
  34. let lastCollapsedStart = Number.MAX_VALUE;
  35. let lastCollapsedEnd = -1;
  36. const ranges = this._foldingModel.regions;
  37. for (; i < ranges.length; i++) {
  38. if (!ranges.isCollapsed(i)) {
  39. continue;
  40. }
  41. const startLineNumber = ranges.getStartLineNumber(i) + 1; // the first line is not hidden
  42. const endLineNumber = ranges.getEndLineNumber(i);
  43. if (lastCollapsedStart <= startLineNumber && endLineNumber <= lastCollapsedEnd) {
  44. // ignore ranges contained in collapsed regions
  45. continue;
  46. }
  47. if (!updateHiddenAreas && k < this._hiddenRanges.length && this._hiddenRanges[k].startLineNumber === startLineNumber && this._hiddenRanges[k].endLineNumber === endLineNumber) {
  48. // reuse the old ranges
  49. newHiddenAreas.push(this._hiddenRanges[k]);
  50. k++;
  51. }
  52. else {
  53. updateHiddenAreas = true;
  54. newHiddenAreas.push(new Range(startLineNumber, 1, endLineNumber, 1));
  55. }
  56. lastCollapsedStart = startLineNumber;
  57. lastCollapsedEnd = endLineNumber;
  58. }
  59. if (this._hasLineChanges || updateHiddenAreas || k < this._hiddenRanges.length) {
  60. this.applyHiddenRanges(newHiddenAreas);
  61. }
  62. }
  63. applyHiddenRanges(newHiddenAreas) {
  64. this._hiddenRanges = newHiddenAreas;
  65. this._hasLineChanges = false;
  66. this._updateEventEmitter.fire(newHiddenAreas);
  67. }
  68. hasRanges() {
  69. return this._hiddenRanges.length > 0;
  70. }
  71. isHidden(line) {
  72. return findRange(this._hiddenRanges, line) !== null;
  73. }
  74. adjustSelections(selections) {
  75. let hasChanges = false;
  76. const editorModel = this._foldingModel.textModel;
  77. let lastRange = null;
  78. const adjustLine = (line) => {
  79. if (!lastRange || !isInside(line, lastRange)) {
  80. lastRange = findRange(this._hiddenRanges, line);
  81. }
  82. if (lastRange) {
  83. return lastRange.startLineNumber - 1;
  84. }
  85. return null;
  86. };
  87. for (let i = 0, len = selections.length; i < len; i++) {
  88. let selection = selections[i];
  89. const adjustedStartLine = adjustLine(selection.startLineNumber);
  90. if (adjustedStartLine) {
  91. selection = selection.setStartPosition(adjustedStartLine, editorModel.getLineMaxColumn(adjustedStartLine));
  92. hasChanges = true;
  93. }
  94. const adjustedEndLine = adjustLine(selection.endLineNumber);
  95. if (adjustedEndLine) {
  96. selection = selection.setEndPosition(adjustedEndLine, editorModel.getLineMaxColumn(adjustedEndLine));
  97. hasChanges = true;
  98. }
  99. selections[i] = selection;
  100. }
  101. return hasChanges;
  102. }
  103. dispose() {
  104. if (this.hiddenRanges.length > 0) {
  105. this._hiddenRanges = [];
  106. this._updateEventEmitter.fire(this._hiddenRanges);
  107. }
  108. if (this._foldingModelListener) {
  109. this._foldingModelListener.dispose();
  110. this._foldingModelListener = null;
  111. }
  112. }
  113. }
  114. function isInside(line, range) {
  115. return line >= range.startLineNumber && line <= range.endLineNumber;
  116. }
  117. function findRange(ranges, line) {
  118. const i = findFirstInSorted(ranges, r => line < r.startLineNumber) - 1;
  119. if (i >= 0 && ranges[i].endLineNumber >= line) {
  120. return ranges[i];
  121. }
  122. return null;
  123. }