103
let arrPool2: number[] = [];
104
105
>
function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterClassifier, previousBreakingData: ModelLineProjectionData, lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll'): ModelLineProjectionData | null {
monospaceLineBreaksComputer.ts
106
>
if (firstLineBreakColumn === -1) {
107
return null;
108
}
110
>
const len = lineText.length;
111
>
if (len <= 1) {
112
return null;
113
}
115
>
const isKeepAll = (wordBreak === 'keepAll');
116
>
117
>
const prevBreakingOffsets = previousBreakingData.breakOffsets;
118
>
const prevBreakingOffsetsVisibleColumn = previousBreakingData.breakOffsetsVisibleColumn;
119
>
120
>
const wrappedTextIndentLength = computeWrappedTextIndentLength(lineText, tabSize, firstLineBreakColumn, columnsForFullWidthChar, wrappingIndent);
121
>
const wrappedLineBreakColumn = firstLineBreakColumn - wrappedTextIndentLength;
122
>
123
>
const breakingOffsets: number[] = arrPool1;
124
>
const breakingOffsetsVisibleColumn: number[] = arrPool2;
125
>
let breakingOffsetsCount = 0;
126
>
let lastBreakingOffset = 0;
127
>
let lastBreakingOffsetVisibleColumn = 0;
128
>
129
>
let breakingColumn = firstLineBreakColumn;
130
>
const prevLen = prevBreakingOffsets.length;
131
>
let prevIndex = 0;
132
>
133
>
if (prevIndex >= 0) {
134
>
let bestDistance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex] - breakingColumn);
135
>
while (prevIndex + 1 < prevLen) {
136
>
const distance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex + 1] - breakingColumn);
137
>
if (distance >= bestDistance) {
138
>
break;
139
>
}
140
>
bestDistance = distance;
141
>
prevIndex++;
142
>
}
143
>
}
144
>
145
>
while (prevIndex < prevLen) {
146
>
// Allow for prevIndex to be -1 (for the case where we hit a tab when walking backwards from the first break)
147
>
let prevBreakOffset = prevIndex < 0 ? 0 : prevBreakingOffsets[prevIndex];
148
>
let prevBreakOffsetVisibleColumn = prevIndex < 0 ? 0 : prevBreakingOffsetsVisibleColumn[prevIndex];
149
>
if (lastBreakingOffset > prevBreakOffset) {
150
prevBreakOffset = lastBreakingOffset;
151
prevBreakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn;
152
}
154
>
let breakOffset = 0;
155
>
let breakOffsetVisibleColumn = 0;
156
>
157
>
let forcedBreakOffset = 0;
158
>
let forcedBreakOffsetVisibleColumn = 0;
159
>
160
>
// initially, we search as much as possible to the right (if it fits)
161
>
if (prevBreakOffsetVisibleColumn <= breakingColumn) {
162
>
let visibleColumn = prevBreakOffsetVisibleColumn;
163
>
let prevCharCode = prevBreakOffset === 0 ? CharCode.Null : lineText.charCodeAt(prevBreakOffset - 1);
164
>
let prevCharCodeClass = prevBreakOffset === 0 ? CharacterClass.NONE : classifier.get(prevCharCode);
165
>
let entireLineFits = true;
166
>
for (let i = prevBreakOffset; i < len; i++) {
167
>
const charStartOffset = i;
168
>
const charCode = lineText.charCodeAt(i);
169
>
let charCodeClass: number;
170
>
let charWidth: number;
171
>
172
>
if (strings.isHighSurrogate(charCode)) {
173
// A surrogate pair must always be considered as a single unit, so it is never to be broken
174
i++;
175
charCodeClass = CharacterClass.NONE;
176
charWidth = 2;
178
>
charCodeClass = classifier.get(charCode);
179
>
charWidth = computeCharWidth(charCode, visibleColumn, tabSize, columnsForFullWidthChar);
180
>
}
181
>
182
>
if (charStartOffset > lastBreakingOffset && canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass, isKeepAll)) {
183
>
breakOffset = charStartOffset;
184
>
breakOffsetVisibleColumn = visibleColumn;
185
>
}
186
>
187
>
visibleColumn += charWidth;
188
>
189
>
// check if adding character at `i` will go over the breaking column
190
>
if (visibleColumn > breakingColumn) {
191
>
// We need to break at least before character at `i`:
192
>
if (charStartOffset > lastBreakingOffset) {
193
>
forcedBreakOffset = charStartOffset;
194
>
forcedBreakOffsetVisibleColumn = visibleColumn - charWidth;
195
>
} else {
196
// we need to advance at least by one character
197
forcedBreakOffset = i + 1;
198
forcedBreakOffsetVisibleColumn = visibleColumn;
199
}
201
>
if (visibleColumn - breakOffsetVisibleColumn > wrappedLineBreakColumn) {
202
>
// Cannot break at `breakOffset` => reset it if it was set
203
>
breakOffset = 0;
204
>
}
205
>
206
>
entireLineFits = false;
207
>
break;
208
>
}
209
>
210
>
prevCharCode = charCode;
211
>
prevCharCodeClass = charCodeClass;
212
>
}
213
>
214
>
if (entireLineFits) {
215
>
// there is no more need to break => stop the outer loop!
216
>
if (breakingOffsetsCount > 0) {
217
>
// Add last segment, no need to assign to `lastBreakingOffset` and `lastBreakingOffsetVisibleColumn`
218
>
breakingOffsets[breakingOffsetsCount] = prevBreakingOffsets[prevBreakingOffsets.length - 1];
219
>
breakingOffsetsVisibleColumn[breakingOffsetsCount] = prevBreakingOffsetsVisibleColumn[prevBreakingOffsets.length - 1];
220
>
breakingOffsetsCount++;
221
>
}
222
>
break;
223
>
}
224
>
}
225
>
226
>
if (breakOffset === 0) {
227
>
// must search left
228
>
let visibleColumn = prevBreakOffsetVisibleColumn;
229
>
let charCode = lineText.charCodeAt(prevBreakOffset);
230
>
let charCodeClass = classifier.get(charCode);
231
>
let hitATabCharacter = false;
232
>
for (let i = prevBreakOffset - 1; i >= lastBreakingOffset; i--) {
233
>
const charStartOffset = i + 1;
234
>
const prevCharCode = lineText.charCodeAt(i);
235
>
236
>
if (prevCharCode === CharCode.Tab) {
237
// cannot determine the width of a tab when going backwards, so we must go forwards
238
hitATabCharacter = true;
239
break;
240
}
242
>
let prevCharCodeClass: number;
243
>
let prevCharWidth: number;
244
>
245
>
if (strings.isLowSurrogate(prevCharCode)) {
246
// A surrogate pair must always be considered as a single unit, so it is never to be broken
247
i--;
248
prevCharCodeClass = CharacterClass.NONE;
249
prevCharWidth = 2;
251
>
prevCharCodeClass = classifier.get(prevCharCode);
252
>
prevCharWidth = (strings.isFullWidthCharacter(prevCharCode) ? columnsForFullWidthChar : 1);
253
>
}
254
>
255
>
if (visibleColumn <= breakingColumn) {
256
>
if (forcedBreakOffset === 0) {
257
>
forcedBreakOffset = charStartOffset;
258
>
forcedBreakOffsetVisibleColumn = visibleColumn;
259
>
}
260
>
261
>
if (visibleColumn <= breakingColumn - wrappedLineBreakColumn) {
262
// went too far!
263
break;
264
}
266
>
if (canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass, isKeepAll)) {
267
>
breakOffset = charStartOffset;
268
>
breakOffsetVisibleColumn = visibleColumn;
269
>
break;
270
>
}
271
>
}
272
>
273
>
visibleColumn -= prevCharWidth;
274
>
charCode = prevCharCode;
275
>
charCodeClass = prevCharCodeClass;
276
>
}
277
>
278
>
if (breakOffset !== 0) {
279
>
const remainingWidthOfNextLine = wrappedLineBreakColumn - (forcedBreakOffsetVisibleColumn - breakOffsetVisibleColumn);
280
>
if (remainingWidthOfNextLine <= tabSize) {
281
>
const charCodeAtForcedBreakOffset = lineText.charCodeAt(forcedBreakOffset);
282
>
let charWidth: number;
283
>
if (strings.isHighSurrogate(charCodeAtForcedBreakOffset)) {
284
// A surrogate pair must always be considered as a single unit, so it is never to be broken
285
charWidth = 2;
287
>
charWidth = computeCharWidth(charCodeAtForcedBreakOffset, forcedBreakOffsetVisibleColumn, tabSize, columnsForFullWidthChar);
288
>
}
289
>
if (remainingWidthOfNextLine - charWidth < 0) {
290
// it is not worth it to break at breakOffset, it just introduces an extra needless line!
291
breakOffset = 0;
292
}
294
>
}
295
>
296
>
if (hitATabCharacter) {
297
// cannot determine the width of a tab when going backwards, so we must go forwards from the previous break
298
prevIndex--;
299
continue;
300
}
302
>
303
>
if (breakOffset === 0) {
304
>
// Could not find a good breaking point
305
>
breakOffset = forcedBreakOffset;
306
>
breakOffsetVisibleColumn = forcedBreakOffsetVisibleColumn;
307
>
}
308
>
309
>
if (breakOffset <= lastBreakingOffset) {
310
// Make sure that we are advancing (at least one character)
311
const charCode = lineText.charCodeAt(lastBreakingOffset);