src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts

555 LOC · 527 covered · 28 uncovered · 82 ranges · 38 concepts · 28 introducers · 18 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filemonospaceLineBreaksComputer.ts ×4 · 13 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×2 · 7 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×2 · 8 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×2 · 8 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 2 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×15 · 206 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #75494: surrogate pairs overrun 1|occurrence=1 · 0 introduced LOCmonospaceLineBreaksCompu…Korean (CJK) text when setting normal|occurrence=1 · 0 introduced LOCKorean (CJK) text when s…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #75494: surrogate pairs overrun 2|occurrence=1 · 0 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 6 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #16332: Scroll bar overlaying on top of text|occurrence=1 · 0 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #33366: Word wrap algorithm behaves differently around punctuation|occurrence=1, monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #152773: Word wrap algorithm behaves differently with bracket followed by comma|occurrence=1 · 0 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #35162: wrappingIndent not consistently working|occurrence=1, monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - WrappingIndent.DeepIndent|occurrence=1 · 0 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 2 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - WrappingIndent.Same|occurrence=1 · 0 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 3 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 3 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 4 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 3 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 3 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×2 · 6 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - CJK and Kinsoku Shori|occurrence=1 · 0 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×3 · 16 introduced LOCmonospaceLineBreaksCompu…Korean (CJK) text when setting keepAll|occurrence=1 · 0 introduced LOCKorean (CJK) text when s…monospaceLineBreaksComputer.ts ×1 · 2 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 3 introduced LOCmonospaceLineBreaksCompu…modelLineProjectionData.ts ×1 · 1 introduced LOCmodelLineProjectionData.…monospaceLineBreaksComputer.ts ×1 · 4 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×3 · 17 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×2 · 4 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×4 · 14 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 2 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×2 · 10 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 2 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×2 · 4 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 3 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×1 · 2 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.ts ×24 · 170 introduced LOCmonospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - CJK and Kinsoku Shori|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - CJK and Kinsoku Shori|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - WrappingIndent.DeepIndent|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - WrappingIndent.DeepIndent|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - WrappingIndent.Same|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer - WrappingIndent.Same|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer incremental 1|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer incremental 1|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer MonospaceLineBreaksComputer|occurrence=1monospaceLineBreaksCompu…Korean (CJK) text when setting keepAll|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer Word break work well with Chinese/Japanese/Korean (CJK) text when setting keepAll|occurrence=1Korean (CJK) text when s…Korean (CJK) text when setting normal|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer Word break work well with Chinese/Japanese/Korean (CJK) text when setting normal|occurrence=1Korean (CJK) text when s…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #110392: Occasional crash when resize with panel on the right|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #110392: Occasional crash when resize with panel on the right|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #112382: Word wrap doesn't work well with control characters|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #112382: Word wrap doesn't work well with control characters|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #152773: Word wrap algorithm behaves differently with bracket followed by comma|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #152773: Word wrap algorithm behaves differently with bracket followed by comma|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #16332: Scroll bar overlaying on top of text|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #16332: Scroll bar overlaying on top of text|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #258022: wrapOnEscapedLineFeeds: should work correctly after editor resize|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #258022: wrapOnEscapedLineFeeds: should work correctly after editor resize|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #33366: Word wrap algorithm behaves differently around punctuation|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #33366: Word wrap algorithm behaves differently around punctuation|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #35162: wrappingIndent not consistently working|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #35162: wrappingIndent not consistently working|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #75494: surrogate pairs overrun 1|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #75494: surrogate pairs overrun 1|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #75494: surrogate pairs overrun 2|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #75494: surrogate pairs overrun 2|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #75494: surrogate pairs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #75494: surrogate pairs|occurrence=1monospaceLineBreaksCompu…monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #95686: CRITICAL: loop forever on the monospaceLineBreaksComputer|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test|title=Editor ViewModel - MonospaceLineBreaksComputer issue #95686: CRITICAL: loop forever on the monospaceLineBreaksComputer|occurrence=1monospaceLineBreaksCompu…Focused file · src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts · 555 LOCviewModel/monospaceLineB…

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- monospaceLineBreaksComputer.ts ×24
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 { CharCode } from '../../../base/common/charCode.js';
7 > import * as strings from '../../../base/common/strings.js';
8 > import { WrappingIndent, IComputedEditorOptions, EditorOption } from '../config/editorOptions.js';
9 > import { CharacterClassifier } from '../core/characterClassifier.js';
10 > import { FontInfo } from '../config/fontInfo.js';
11 > import { LineInjectedText } from '../textModelEvents.js';
12 > import { InjectedTextOptions } from '../model.js';
13 > import { ILineBreaksComputerFactory, ILineBreaksComputer, ModelLineProjectionData, ILineBreaksComputerContext } from '../modelLineProjectionData.js';
14 >
15 > export class MonospaceLineBreaksComputerFactory implements ILineBreaksComputerFactory {
16 > public static create(options: IComputedEditorOptions): MonospaceLineBreaksComputerFactory {
17 return new MonospaceLineBreaksComputerFactory(
18 options.get(EditorOption.wordWrapBreakBeforeCharacters),
19 options.get(EditorOption.wordWrapBreakAfterCharacters)
20 );
21 }
23 > private readonly classifier: WrappingCharacterClassifier;
24 >
25 > constructor(breakBeforeChars: string, breakAfterChars: string) {
26 > this.classifier = new WrappingCharacterClassifier(breakBeforeChars, breakAfterChars);
27 > }
28 >
29 > public createLineBreaksComputer(context: ILineBreaksComputerContext, fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll', wrapOnEscapedLineFeeds: boolean): ILineBreaksComputer {
30 > const lineNumbers: number[] = [];
31 > const previousBreakingData: (ModelLineProjectionData | null)[] = [];
32 > return {
33 > addRequest: (lineNumber: number, previousLineBreakData: ModelLineProjectionData | null) => {
34 > lineNumbers.push(lineNumber);
35 > previousBreakingData.push(previousLineBreakData);
36 > },
37 > finalize: () => {
38 > const columnsForFullWidthChar = fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth;
39 > const result: (ModelLineProjectionData | null)[] = [];
40 > for (let i = 0, len = lineNumbers.length; i < len; i++) {
41 > const lineNumber = lineNumbers[i];
42 > const injectedText = context.getLineInjectedText(lineNumber);
43 > const lineText = context.getLineContent(lineNumber);
44 > const previousLineBreakData = previousBreakingData[i];
45 > const isLineFeedWrappingEnabled = wrapOnEscapedLineFeeds && lineText.includes('"') && lineText.includes('\\n');
46 > if (previousLineBreakData && !previousLineBreakData.injectionOptions && !injectedText && !isLineFeedWrappingEnabled) {
47 > result[i] = createLineBreaksFromPreviousLineBreaks(this.classifier, previousLineBreakData, lineText, tabSize, wrappingColumn, columnsForFullWidthChar, wrappingIndent, wordBreak); monospaceLineBreaksComputer.ts ×15
49 > result[i] = createLineBreaks(this.classifier, lineText, injectedText, tabSize, wrappingColumn, columnsForFullWidthChar, wrappingIndent, wordBreak, isLineFeedWrappingEnabled);
50 > }
51 > }
52 > arrPool1.length = 0;
53 > arrPool2.length = 0;
54 > return result;
55 > }
56 > };
57 > }
58 > }
59 >
60 > const enum CharacterClass {
61 > NONE = 0,
62 > BREAK_BEFORE = 1,
63 > BREAK_AFTER = 2,
64 > BREAK_IDEOGRAPHIC = 3 // for Han and Kana.
65 > }
66 >
67 > class WrappingCharacterClassifier extends CharacterClassifier<CharacterClass> {
68 >
69 > constructor(BREAK_BEFORE: string, BREAK_AFTER: string) {
70 > super(CharacterClass.NONE);
71 >
72 > for (let i = 0; i < BREAK_BEFORE.length; i++) {
73 > this.set(BREAK_BEFORE.charCodeAt(i), CharacterClass.BREAK_BEFORE); monospaceLineBreaksComputer.ts ×1
74 > }
76 > for (let i = 0; i < BREAK_AFTER.length; i++) {
77 > this.set(BREAK_AFTER.charCodeAt(i), CharacterClass.BREAK_AFTER);
78 > }
79 > }
80 >
81 > public override get(charCode: number): CharacterClass {
82 > if (charCode >= 0 && charCode < 256) {
83 > return <CharacterClass>this._asciiMap[charCode]; monospaceLineBreaksComputer.ts ×2
85 > // Initialize CharacterClass.BREAK_IDEOGRAPHIC for these Unicode ranges: monospaceLineBreaksComputer.ts ×2
86 > // 1. CJK Unified Ideographs (0x4E00 -- 0x9FFF)
87 > // 2. CJK Unified Ideographs Extension A (0x3400 -- 0x4DBF)
88 > // 3. Hiragana and Katakana (0x3040 -- 0x30FF)
89 > if (
90 > (charCode >= 0x3040 && charCode <= 0x30FF)
91 > || (charCode >= 0x3400 && charCode <= 0x4DBF)
92 > || (charCode >= 0x4E00 && charCode <= 0x9FFF)
93 > ) {
94 > return CharacterClass.BREAK_IDEOGRAPHIC; monospaceLineBreaksComputer.ts ×2
95 > }
97 > return <CharacterClass>(this._map.get(charCode) || this._defaultValue);
100 > }
101 >
102 > let arrPool1: number[] = [];
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 ×15
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; monospaceLineBreaksComputer.ts ×2
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 monospaceLineBreaksComputer.ts ×4
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 monospaceLineBreaksComputer.ts ×2
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 monospaceLineBreaksComputer.ts ×2
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 monospaceLineBreaksComputer.ts ×4
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 monospaceLineBreaksComputer.ts ×4
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! monospaceLineBreaksComputer.ts ×4
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 monospaceLineBreaksComputer.ts ×2
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) monospaceLineBreaksComputer.ts ×2
311 > const charCode = lineText.charCodeAt(lastBreakingOffset);
312 > if (strings.isHighSurrogate(charCode)) {
313 // A surrogate pair must always be considered as a single unit, so it is never to be broken
314 breakOffset = lastBreakingOffset + 2;
315 breakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn + 2;
317 > breakOffset = lastBreakingOffset + 1;
318 > breakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn + computeCharWidth(charCode, lastBreakingOffsetVisibleColumn, tabSize, columnsForFullWidthChar);
319 > }
320 > }
322 > lastBreakingOffset = breakOffset;
323 > breakingOffsets[breakingOffsetsCount] = breakOffset;
324 > lastBreakingOffsetVisibleColumn = breakOffsetVisibleColumn;
325 > breakingOffsetsVisibleColumn[breakingOffsetsCount] = breakOffsetVisibleColumn;
326 > breakingOffsetsCount++;
327 > breakingColumn = breakOffsetVisibleColumn + wrappedLineBreakColumn;
328 >
329 > while (prevIndex < 0 || (prevIndex < prevLen && prevBreakingOffsetsVisibleColumn[prevIndex] < breakOffsetVisibleColumn)) {
330 > prevIndex++;
331 > }
332 >
333 > let bestDistance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex] - breakingColumn);
334 > while (prevIndex + 1 < prevLen) {
335 > const distance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex + 1] - breakingColumn);
336 > if (distance >= bestDistance) {
337 > break;
338 > }
339 > bestDistance = distance;
340 > prevIndex++;
341 > }
342 > }
343 >
344 > if (breakingOffsetsCount === 0) {
345 return null;
346 }
348 > // Doing here some object reuse which ends up helping a huge deal with GC pauses!
349 > breakingOffsets.length = breakingOffsetsCount;
350 > breakingOffsetsVisibleColumn.length = breakingOffsetsCount;
351 > arrPool1 = previousBreakingData.breakOffsets;
352 > arrPool2 = previousBreakingData.breakOffsetsVisibleColumn;
353 > previousBreakingData.breakOffsets = breakingOffsets;
354 > previousBreakingData.breakOffsetsVisibleColumn = breakingOffsetsVisibleColumn;
355 > previousBreakingData.wrappedTextIndentLength = wrappedTextIndentLength;
356 > return previousBreakingData;
357 > }
359 > function createLineBreaks(classifier: WrappingCharacterClassifier, _lineText: string, injectedTexts: LineInjectedText[] | null, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll', wrapOnEscapedLineFeeds: boolean): ModelLineProjectionData | null {
360 > const lineText = LineInjectedText.applyInjectedText(_lineText, injectedTexts);
361 >
362 > let injectionOptions: InjectedTextOptions[] | null;
363 > let injectionOffsets: number[] | null;
364 > if (injectedTexts && injectedTexts.length > 0) {
365 injectionOptions = injectedTexts.map(t => t.options);
366 injectionOffsets = injectedTexts.map(text => text.column - 1);
368 > injectionOptions = null;
369 > injectionOffsets = null;
370 > }
371 >
372 > if (firstLineBreakColumn === -1) {
373 > if (!injectionOptions) { monospaceLineBreaksComputer.ts ×2
374 > return null;
375 > }
376 // creating a `LineBreakData` with an invalid `breakOffsetsVisibleColumn` is OK
377 // because `breakOffsetsVisibleColumn` will never be used because it contains injected text
378 return new ModelLineProjectionData(injectionOffsets, injectionOptions, [lineText.length], [], 0);
379 }
381 > const len = lineText.length;
382 > if (len <= 1) {
383 > if (!injectionOptions) { monospaceLineBreaksComputer.ts ×2
384 > return null;
385 > }
386 // creating a `LineBreakData` with an invalid `breakOffsetsVisibleColumn` is OK
387 // because `breakOffsetsVisibleColumn` will never be used because it contains injected text
388 return new ModelLineProjectionData(injectionOffsets, injectionOptions, [lineText.length], [], 0);
389 }
391 > const isKeepAll = (wordBreak === 'keepAll');
392 > const wrappedTextIndentLength = computeWrappedTextIndentLength(lineText, tabSize, firstLineBreakColumn, columnsForFullWidthChar, wrappingIndent);
393 > const wrappedLineBreakColumn = firstLineBreakColumn - wrappedTextIndentLength;
394 >
395 > const breakingOffsets: number[] = [];
396 > const breakingOffsetsVisibleColumn: number[] = [];
397 > let breakingOffsetsCount: number = 0;
398 > let breakOffset = 0;
399 > let breakOffsetVisibleColumn = 0;
400 >
401 > let breakingColumn = firstLineBreakColumn;
402 > let prevCharCode = lineText.charCodeAt(0);
403 > let prevCharCodeClass = classifier.get(prevCharCode);
404 > let visibleColumn = computeCharWidth(prevCharCode, 0, tabSize, columnsForFullWidthChar);
405 >
406 > let startOffset = 1;
407 > if (strings.isHighSurrogate(prevCharCode)) {
408 > // A surrogate pair must always be considered as a single unit, so it is never to be broken monospaceLineBreaksComputer.ts ×1
409 > visibleColumn += 1;
410 > prevCharCode = lineText.charCodeAt(1);
411 > prevCharCodeClass = classifier.get(prevCharCode);
412 > startOffset++;
413 > }
415 > for (let i = startOffset; i < len; i++) {
416 > const charStartOffset = i;
417 > const charCode = lineText.charCodeAt(i);
418 > let charCodeClass: CharacterClass;
419 > let charWidth: number;
420 > let wrapEscapedLineFeed = false;
421 >
422 > if (strings.isHighSurrogate(charCode)) {
423 > // A surrogate pair must always be considered as a single unit, so it is never to be broken monospaceLineBreaksComputer.ts ×1
424 > i++;
425 > charCodeClass = CharacterClass.NONE;
426 > charWidth = 2;
428 > charCodeClass = classifier.get(charCode); monospaceLineBreaksComputer.ts ×2
429 > charWidth = computeCharWidth(charCode, visibleColumn, tabSize, columnsForFullWidthChar);
430 > }
432 > // literal \n shall trigger a softwrap
433 > if (wrapOnEscapedLineFeeds && isEscapedLineBreakAtPosition(lineText, i)) {
434 > breakOffset = charStartOffset; monospaceLineBreaksComputer.ts ×3
435 > breakOffsetVisibleColumn = visibleColumn;
436 > wrapEscapedLineFeed = true;
437 > } else if (canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass, isKeepAll)) { monospaceLineBreaksComputer.ts ×24
438 > breakOffset = charStartOffset; monospaceLineBreaksComputer.ts ×1
439 > breakOffsetVisibleColumn = visibleColumn;
440 > }
442 > visibleColumn += charWidth;
443 >
444 > // check if adding character at `i` will go over the breaking column
445 > if (visibleColumn > breakingColumn || wrapEscapedLineFeed) {
446 > // We need to break at least before character at `i`: monospaceLineBreaksComputer.ts ×3
447 >
448 > if (breakOffset === 0 || visibleColumn - breakOffsetVisibleColumn > wrappedLineBreakColumn) {
449 > // Cannot break at `breakOffset`, must break at `i` monospaceLineBreaksComputer.ts ×1
450 > breakOffset = charStartOffset;
451 > breakOffsetVisibleColumn = visibleColumn - charWidth;
452 > }
454 > breakingOffsets[breakingOffsetsCount] = breakOffset;
455 > breakingOffsetsVisibleColumn[breakingOffsetsCount] = breakOffsetVisibleColumn;
456 > breakingOffsetsCount++;
457 > breakingColumn = breakOffsetVisibleColumn + wrappedLineBreakColumn;
458 > breakOffset = 0;
459 > }
461 > prevCharCode = charCode;
462 > prevCharCodeClass = charCodeClass;
463 > }
464 >
465 > if (breakingOffsetsCount === 0 && (!injectedTexts || injectedTexts.length === 0)) {
467 > }
469 > // Add last segment
470 > breakingOffsets[breakingOffsetsCount] = len;
471 > breakingOffsetsVisibleColumn[breakingOffsetsCount] = visibleColumn;
472 >
473 > return new ModelLineProjectionData(injectionOffsets, injectionOptions, breakingOffsets, breakingOffsetsVisibleColumn, wrappedTextIndentLength);
474 > }
476 > function computeCharWidth(charCode: number, visibleColumn: number, tabSize: number, columnsForFullWidthChar: number): number {
477 > if (charCode === CharCode.Tab) {
478 > return (tabSize - (visibleColumn % tabSize)); monospaceLineBreaksComputer.ts ×1
479 > }
480 > if (strings.isFullWidthCharacter(charCode)) { monospaceLineBreaksComputer.ts ×24
481 > return columnsForFullWidthChar; monospaceLineBreaksComputer.ts ×2
482 > }
483 > if (charCode < 32) { monospaceLineBreaksComputer.ts ×24
484 > // when using `editor.renderControlCharacters`, the substitutions are often wide monospaceLineBreaksComputer.ts ×1
485 > return columnsForFullWidthChar;
486 > }
488 > }
490 > function tabCharacterWidth(visibleColumn: number, tabSize: number): number { monospaceLineBreaksComputer.ts ×1
491 > return (tabSize - (visibleColumn % tabSize));
492 > }
494 > /**
495 > * Checks if the current position in the text should trigger a soft wrap due to escaped line feeds.
496 > * This handles the wrapOnEscapedLineFeeds feature which allows \n sequences in strings to trigger wrapping.
497 > */
498 > function isEscapedLineBreakAtPosition(lineText: string, i: number): boolean { monospaceLineBreaksComputer.ts ×3
499 > if (i >= 2 && lineText.charAt(i - 1) === 'n') {
500 > // Check if there's an odd number of backslashes
501 > let escapeCount = 0;
502 > for (let j = i - 2; j >= 0; j--) {
503 > if (lineText.charAt(j) === '\\') {
504 > escapeCount++;
505 > } else {
506 > return escapeCount % 2 === 1;
507 > }
508 > }
509 }
511 > }
513 > /**
514 > * Kinsoku Shori : Don't break after a leading character, like an open bracket
515 > * Kinsoku Shori : Don't break before a trailing character, like a period
516 > */
517 > function canBreak(prevCharCode: number, prevCharCodeClass: CharacterClass, charCode: number, charCodeClass: CharacterClass, isKeepAll: boolean): boolean {
518 > return (
519 > charCode !== CharCode.Space
520 > && (
521 > (prevCharCodeClass === CharacterClass.BREAK_AFTER && charCodeClass !== CharacterClass.BREAK_AFTER) // break at the end of multiple BREAK_AFTER
522 > || (prevCharCodeClass !== CharacterClass.BREAK_BEFORE && charCodeClass === CharacterClass.BREAK_BEFORE) // break at the start of multiple BREAK_BEFORE monospaceLineBreaksComputer.ts ×1
523 > || (!isKeepAll && prevCharCodeClass === CharacterClass.BREAK_IDEOGRAPHIC && charCodeClass !== CharacterClass.BREAK_AFTER)
524 > || (!isKeepAll && charCodeClass === CharacterClass.BREAK_IDEOGRAPHIC && prevCharCodeClass !== CharacterClass.BREAK_BEFORE)
526 > );
527 > }
528 >
529 > function computeWrappedTextIndentLength(lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): number {
530 > let wrappedTextIndentLength = 0;
531 > if (wrappingIndent !== WrappingIndent.None) {
532 > const firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineText); monospaceLineBreaksComputer.ts ×4
533 > if (firstNonWhitespaceIndex !== -1) {
534 > // Track existing indent
535 >
536 > for (let i = 0; i < firstNonWhitespaceIndex; i++) {
537 > const charWidth = (lineText.charCodeAt(i) === CharCode.Tab ? tabCharacterWidth(wrappedTextIndentLength, tabSize) : 1); monospaceLineBreaksComputer.ts ×1
538 > wrappedTextIndentLength += charWidth;
539 > }
541 > // Increase indent of continuation lines, if desired
542 > const numberOfAdditionalTabs = (wrappingIndent === WrappingIndent.DeepIndent ? 2 : wrappingIndent === WrappingIndent.Indent ? 1 : 0);
543 > for (let i = 0; i < numberOfAdditionalTabs; i++) {
544 > const charWidth = tabCharacterWidth(wrappedTextIndentLength, tabSize); monospaceLineBreaksComputer.ts ×1
545 > wrappedTextIndentLength += charWidth;
546 > }
548 > // Force sticking to beginning of line if no character would fit except for the indentation
549 > if (wrappedTextIndentLength + columnsForFullWidthChar > firstLineBreakColumn) {
550 > wrappedTextIndentLength = 0; monospaceLineBreaksComputer.ts ×1
551 > }
553 > }
554 > return wrappedTextIndentLength; monospaceLineBreaksComputer.ts ×24
555 > }