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
3296 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
export const lengthZero = 0 as any as Length;
27
28
export function lengthIsZero(length: Length): boolean {
29
return length as any as number === 0;
30
}
31
32
/*
33
* We have 52 bits available in a JS number.
34
* We use the upper 26 bits to store the line and the lower 26 bits to store the column.
35
*/
36
///*
37
const factor = 2 ** 26;
38
/*/
39
const factor = 1000000;
40
// */
41
42
export function toLength(lineCount: number, columnCount: number): Length {
43
// llllllllllllllllllllllllllcccccccccccccccccccccccccc (52 bits)
44
// line count (26 bits) column count (26 bits)
45
46
// If there is no overflow (all values/sums below 2^26 = 67108864),
47
// we have `toLength(lns1, cols1) + toLength(lns2, cols2) = toLength(lns1 + lns2, cols1 + cols2)`.
48
49
return (lineCount * factor + columnCount) as any as Length;
50
}
51
52
export function lengthToObj(length: Length): TextLength {
53
const l = length as any as number;
54
const lineCount = Math.floor(l / factor);
55
const columnCount = l - lineCount * factor;
56
return new TextLength(lineCount, columnCount);
57
}
58
59
export function lengthGetLineCount(length: Length): number {
60
return Math.floor(length as any as number / factor);
61
}
62
63
/**
64
* Returns the amount of columns of the given length, assuming that it does not span any line.
65
*/
66
export function lengthGetColumnCountIfZeroLineCount(length: Length): number {
67
return length as any as number;
68
}
69
70
71
// [10 lines, 5 cols] + [ 0 lines, 3 cols] = [10 lines, 8 cols]
72
// [10 lines, 5 cols] + [20 lines, 3 cols] = [30 lines, 3 cols]
73
export function lengthAdd(length1: Length, length2: Length): Length;
74
export function lengthAdd(l1: any, l2: any): Length {
75
let r = l1 + l2;
76
if (l2 >= factor) { r = r - (l1 % factor); }
77
return r;
78
}
79
80
export function sumLengths<T>(items: readonly T[], lengthFn: (item: T) => Length): Length {
81
return items.reduce((a, b) => lengthAdd(a, lengthFn(b)), lengthZero);
82
}
83
84
export function lengthEquals(length1: Length, length2: Length): boolean {
85
return length1 === length2;
86
}
87
88
/**
89
* Returns a non negative length `result` such that `lengthAdd(length1, result) = length2`, or zero if such length does not exist.
90
*/
91
export function lengthDiffNonNegative(length1: Length, length2: Length): Length {
92
const l1 = length1 as any as number;
93
const l2 = length2 as any as number;
94
95
const diff = l2 - l1;
96
if (diff <= 0) {
97
// line-count of length1 is higher than line-count of length2
98
// or they are equal and column-count of length1 is higher than column-count of length2
99
return lengthZero;
100
}
101
102
const lineCount1 = Math.floor(l1 / factor);
103
const lineCount2 = Math.floor(l2 / factor);
104
105
const colCount2 = l2 - lineCount2 * factor;
106
107
if (lineCount1 === lineCount2) {
108
const colCount1 = l1 - lineCount1 * factor;
109
return toLength(0, colCount2 - colCount1);
110
} else {
111
return toLength(lineCount2 - lineCount1, colCount2);
112
}
113
}
114
115
export function lengthLessThan(length1: Length, length2: Length): boolean {
116
// First, compare line counts, then column counts.
117
return (length1 as any as number) < (length2 as any as number);
118
}
119
120
export function lengthLessThanEqual(length1: Length, length2: Length): boolean {
121
return (length1 as any as number) <= (length2 as any as number);
122
}
123
124
export function lengthGreaterThanEqual(length1: Length, length2: Length): boolean {
125
return (length1 as any as number) >= (length2 as any as number);
126
}
127
128
export function lengthToPosition(length: Length): Position {
129
const l = length as any as number;
130
const lineCount = Math.floor(l / factor);
131
const colCount = l - lineCount * factor;
132
return new Position(lineCount + 1, colCount + 1);
133
}
134
135
export function positionToLength(position: Position): Length {
136
return toLength(position.lineNumber - 1, position.column - 1);
137
}
138
139
export function lengthsToRange(lengthStart: Length, lengthEnd: Length): Range {
140
const l = lengthStart as any as number;
141
const lineCount = Math.floor(l / factor);
142
const colCount = l - lineCount * factor;
143
144
const l2 = lengthEnd as any as number;
145
const lineCount2 = Math.floor(l2 / factor);
146
const colCount2 = l2 - lineCount2 * factor;
147
148
return new Range(lineCount + 1, colCount + 1, lineCount2 + 1, colCount2 + 1);
149
}
150
151
export function lengthOfRange(range: Range): TextLength {
152
if (range.startLineNumber === range.endLineNumber) {
153
return new TextLength(0, range.endColumn - range.startColumn);
154
} else {
155
return new TextLength(range.endLineNumber - range.startLineNumber, range.endColumn - 1);
156
}
157
}
158
159
export function lengthCompare(length1: Length, length2: Length): number {
160
const l1 = length1 as any as number;
161
const l2 = length2 as any as number;
162
return l1 - l2;
163
}
164
165
export function lengthOfString(str: string): Length {
166
const lines = splitLines(str);
167
return toLength(lines.length - 1, lines[lines.length - 1].length);
168
}
169
170
export function lengthOfStringObj(str: string): TextLength {
171
const lines = splitLines(str);
172
return new TextLength(lines.length - 1, lines[lines.length - 1].length);
173
}
174
175
/**
176
* Computes a numeric hash of the given length.
177
*/
178
export function lengthHash(length: Length): number {
179
return length as any;
180
}
181
182
export function lengthMax(length1: Length, length2: Length): Length {
183
return length1 > length2 ? length1 : length2;
184
}
185
186