8a99ff792f737526d44a9d02596e9936f3a75aa4e46270b311f2fb18783e507346ec19ccf648810f117fb538e785f14a0f37da9ef0f5212c520dc4f230f1a9 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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 { splitLines } from '../../../../../base/common/strings.js';
  6. import { Range } from '../../../core/range.js';
  7. /**
  8. * Represents a non-negative length in terms of line and column count.
  9. * Prefer using {@link Length} for performance reasons.
  10. */
  11. export class LengthObj {
  12. constructor(lineCount, columnCount) {
  13. this.lineCount = lineCount;
  14. this.columnCount = columnCount;
  15. }
  16. toString() {
  17. return `${this.lineCount},${this.columnCount}`;
  18. }
  19. }
  20. LengthObj.zero = new LengthObj(0, 0);
  21. /**
  22. * The end must be greater than or equal to the start.
  23. */
  24. export function lengthDiff(startLineCount, startColumnCount, endLineCount, endColumnCount) {
  25. return (startLineCount !== endLineCount)
  26. ? toLength(endLineCount - startLineCount, endColumnCount)
  27. : toLength(0, endColumnCount - startColumnCount);
  28. }
  29. export const lengthZero = 0;
  30. export function lengthIsZero(length) {
  31. return length === 0;
  32. }
  33. /*
  34. * We have 52 bits available in a JS number.
  35. * We use the upper 26 bits to store the line and the lower 26 bits to store the column.
  36. *
  37. * Set boolean to `true` when debugging, so that debugging is easier.
  38. */
  39. const factor = /* is debug: */ false ? 100000 : Math.pow(2, 26);
  40. export function toLength(lineCount, columnCount) {
  41. // llllllllllllllllllllllllllcccccccccccccccccccccccccc (52 bits)
  42. // line count (26 bits) column count (26 bits)
  43. // If there is no overflow (all values/sums below 2^26 = 67108864),
  44. // we have `toLength(lns1, cols1) + toLength(lns2, cols2) = toLength(lns1 + lns2, cols1 + cols2)`.
  45. return (lineCount * factor + columnCount);
  46. }
  47. export function lengthToObj(length) {
  48. const l = length;
  49. const lineCount = Math.floor(l / factor);
  50. const columnCount = l - lineCount * factor;
  51. return new LengthObj(lineCount, columnCount);
  52. }
  53. export function lengthGetLineCount(length) {
  54. return Math.floor(length / factor);
  55. }
  56. /**
  57. * Returns the amount of columns of the given length, assuming that it does not span any line.
  58. */
  59. export function lengthGetColumnCountIfZeroLineCount(length) {
  60. return length;
  61. }
  62. export function lengthAdd(l1, l2) {
  63. return ((l2 < factor)
  64. ? (l1 + l2) // l2 is the amount of columns (zero line count). Keep the column count from l1.
  65. : (l1 - (l1 % factor) + l2)); // l1 - (l1 % factor) equals toLength(l1.lineCount, 0)
  66. }
  67. /**
  68. * Returns a non negative length `result` such that `lengthAdd(length1, result) = length2`, or zero if such length does not exist.
  69. */
  70. export function lengthDiffNonNegative(length1, length2) {
  71. const l1 = length1;
  72. const l2 = length2;
  73. const diff = l2 - l1;
  74. if (diff <= 0) {
  75. // line-count of length1 is higher than line-count of length2
  76. // or they are equal and column-count of length1 is higher than column-count of length2
  77. return lengthZero;
  78. }
  79. const lineCount1 = Math.floor(l1 / factor);
  80. const lineCount2 = Math.floor(l2 / factor);
  81. const colCount2 = l2 - lineCount2 * factor;
  82. if (lineCount1 === lineCount2) {
  83. const colCount1 = l1 - lineCount1 * factor;
  84. return toLength(0, colCount2 - colCount1);
  85. }
  86. else {
  87. return toLength(lineCount2 - lineCount1, colCount2);
  88. }
  89. }
  90. export function lengthLessThan(length1, length2) {
  91. // First, compare line counts, then column counts.
  92. return length1 < length2;
  93. }
  94. export function lengthLessThanEqual(length1, length2) {
  95. return length1 <= length2;
  96. }
  97. export function lengthGreaterThanEqual(length1, length2) {
  98. return length1 >= length2;
  99. }
  100. export function positionToLength(position) {
  101. return toLength(position.lineNumber - 1, position.column - 1);
  102. }
  103. export function lengthsToRange(lengthStart, lengthEnd) {
  104. const l = lengthStart;
  105. const lineCount = Math.floor(l / factor);
  106. const colCount = l - lineCount * factor;
  107. const l2 = lengthEnd;
  108. const lineCount2 = Math.floor(l2 / factor);
  109. const colCount2 = l2 - lineCount2 * factor;
  110. return new Range(lineCount + 1, colCount + 1, lineCount2 + 1, colCount2 + 1);
  111. }
  112. export function lengthOfString(str) {
  113. const lines = splitLines(str);
  114. return toLength(lines.length - 1, lines[lines.length - 1].length);
  115. }