Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length.ts
5221 views
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
6
import { splitLines } from '../../../../../base/common/strings.js';
7
import { Position } from '../../../core/position.js';
8
import { Range } from '../../../core/range.js';
9
import { TextLength } from '../../../core/text/textLength.js';
10
11
/**
12
* The end must be greater than or equal to the start.
13
*/
14
export function lengthDiff(startLineCount: number, startColumnCount: number, endLineCount: number, endColumnCount: number): Length {
15
return (startLineCount !== endLineCount)
16
? toLength(endLineCount - startLineCount, endColumnCount)
17
: toLength(0, endColumnCount - startColumnCount);
18
}
19
20
/**
21
* Represents a non-negative length in terms of line and column count.
22
* Does not allocate.
23
*/
24
export type Length = { _brand: 'Length' };
25
26
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
27
export const lengthZero = 0 as any as Length;
28
29
export function lengthIsZero(length: Length): boolean {
30
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
31
return length as any as number === 0;
32
}
33
34
/*
35
* We have 52 bits available in a JS number.
36
* We use the upper 26 bits to store the line and the lower 26 bits to store the column.
37
*/
38
///*
39
const factor = 2 ** 26;
40
/*/
41
const factor = 1000000;
42
// */
43
44
export function toLength(lineCount: number, columnCount: number): Length {
45
// llllllllllllllllllllllllllcccccccccccccccccccccccccc (52 bits)
46
// line count (26 bits) column count (26 bits)
47
48
// If there is no overflow (all values/sums below 2^26 = 67108864),
49
// we have `toLength(lns1, cols1) + toLength(lns2, cols2) = toLength(lns1 + lns2, cols1 + cols2)`.
50
51
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
52
return (lineCount * factor + columnCount) as any as Length;
53
}
54
55
export function lengthToObj(length: Length): TextLength {
56
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
57
const l = length as any as number;
58
const lineCount = Math.floor(l / factor);
59
const columnCount = l - lineCount * factor;
60
return new TextLength(lineCount, columnCount);
61
}
62
63
export function lengthGetLineCount(length: Length): number {
64
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
65
return Math.floor(length as any as number / factor);
66
}
67
68
/**
69
* Returns the amount of columns of the given length, assuming that it does not span any line.
70
*/
71
export function lengthGetColumnCountIfZeroLineCount(length: Length): number {
72
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
73
return length as any as number;
74
}
75
76
77
// [10 lines, 5 cols] + [ 0 lines, 3 cols] = [10 lines, 8 cols]
78
// [10 lines, 5 cols] + [20 lines, 3 cols] = [30 lines, 3 cols]
79
export function lengthAdd(length1: Length, length2: Length): Length;
80
// eslint-disable-next-line @typescript-eslint/no-explicit-any
81
export function lengthAdd(l1: any, l2: any): Length {
82
let r = l1 + l2;
83
if (l2 >= factor) { r = r - (l1 % factor); }
84
return r;
85
}
86
87
export function sumLengths<T>(items: readonly T[], lengthFn: (item: T) => Length): Length {
88
return items.reduce((a, b) => lengthAdd(a, lengthFn(b)), lengthZero);
89
}
90
91
export function lengthEquals(length1: Length, length2: Length): boolean {
92
return length1 === length2;
93
}
94
95
/**
96
* Returns a non negative length `result` such that `lengthAdd(length1, result) = length2`, or zero if such length does not exist.
97
*/
98
export function lengthDiffNonNegative(length1: Length, length2: Length): Length {
99
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
100
const l1 = length1 as any as number;
101
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
102
const l2 = length2 as any as number;
103
104
const diff = l2 - l1;
105
if (diff <= 0) {
106
// line-count of length1 is higher than line-count of length2
107
// or they are equal and column-count of length1 is higher than column-count of length2
108
return lengthZero;
109
}
110
111
const lineCount1 = Math.floor(l1 / factor);
112
const lineCount2 = Math.floor(l2 / factor);
113
114
const colCount2 = l2 - lineCount2 * factor;
115
116
if (lineCount1 === lineCount2) {
117
const colCount1 = l1 - lineCount1 * factor;
118
return toLength(0, colCount2 - colCount1);
119
} else {
120
return toLength(lineCount2 - lineCount1, colCount2);
121
}
122
}
123
124
export function lengthLessThan(length1: Length, length2: Length): boolean {
125
// First, compare line counts, then column counts.
126
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
127
return (length1 as any as number) < (length2 as any as number);
128
}
129
130
export function lengthLessThanEqual(length1: Length, length2: Length): boolean {
131
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
132
return (length1 as any as number) <= (length2 as any as number);
133
}
134
135
export function lengthGreaterThanEqual(length1: Length, length2: Length): boolean {
136
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
137
return (length1 as any as number) >= (length2 as any as number);
138
}
139
140
export function lengthToPosition(length: Length): Position {
141
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
142
const l = length as any as number;
143
const lineCount = Math.floor(l / factor);
144
const colCount = l - lineCount * factor;
145
return new Position(lineCount + 1, colCount + 1);
146
}
147
148
export function positionToLength(position: Position): Length {
149
return toLength(position.lineNumber - 1, position.column - 1);
150
}
151
152
export function lengthsToRange(lengthStart: Length, lengthEnd: Length): Range {
153
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
154
const l = lengthStart as any as number;
155
const lineCount = Math.floor(l / factor);
156
const colCount = l - lineCount * factor;
157
158
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
159
const l2 = lengthEnd as any as number;
160
const lineCount2 = Math.floor(l2 / factor);
161
const colCount2 = l2 - lineCount2 * factor;
162
163
return new Range(lineCount + 1, colCount + 1, lineCount2 + 1, colCount2 + 1);
164
}
165
166
export function lengthOfRange(range: Range): TextLength {
167
if (range.startLineNumber === range.endLineNumber) {
168
return new TextLength(0, range.endColumn - range.startColumn);
169
} else {
170
return new TextLength(range.endLineNumber - range.startLineNumber, range.endColumn - 1);
171
}
172
}
173
174
export function lengthCompare(length1: Length, length2: Length): number {
175
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
176
const l1 = length1 as any as number;
177
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
178
const l2 = length2 as any as number;
179
return l1 - l2;
180
}
181
182
export function lengthOfString(str: string): Length {
183
const lines = splitLines(str);
184
return toLength(lines.length - 1, lines[lines.length - 1].length);
185
}
186
187
export function lengthOfStringObj(str: string): TextLength {
188
const lines = splitLines(str);
189
return new TextLength(lines.length - 1, lines[lines.length - 1].length);
190
}
191
192
/**
193
* Computes a numeric hash of the given length.
194
*/
195
export function lengthHash(length: Length): number {
196
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
197
return length as any;
198
}
199
200
export function lengthMax(length1: Length, length2: Length): Length {
201
return length1 > length2 ? length1 : length2;
202
}
203
204