Skip to content

Commit 083a595

Browse files
committed
Improves performance of bracket pair colorization.
1 parent 2259b00 commit 083a595

File tree

5 files changed

+44
-24
lines changed

5 files changed

+44
-24
lines changed

src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/ast.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { BugIndicatingError } from 'vs/base/common/errors';
67
import { CursorColumns } from 'vs/editor/common/core/cursorColumns';
78
import { BracketKind } from 'vs/editor/common/languages/supports/languageBracketsConfiguration';
89
import { ITextModel } from 'vs/editor/common/model';
@@ -125,7 +126,7 @@ export class PairAstNode extends BaseAstNode {
125126
* Avoid using this property, it allocates an array!
126127
*/
127128
public get children() {
128-
const result = new Array<AstNode>();
129+
const result: AstNode[] = [];
129130
result.push(this.openingBracket);
130131
if (this.child) {
131132
result.push(this.child);
@@ -295,10 +296,19 @@ export abstract class ListAstNode extends BaseAstNode {
295296
return false;
296297
}
297298

299+
if (this.childrenLength === 0) {
300+
// Don't reuse empty lists.
301+
return false;
302+
}
303+
298304
let lastChild: ListAstNode = this;
299-
let lastLength: number;
300-
while (lastChild.kind === AstNodeKind.List && (lastLength = lastChild.childrenLength) > 0) {
301-
lastChild = lastChild.getChild(lastLength! - 1) as ListAstNode;
305+
while (lastChild.kind === AstNodeKind.List) {
306+
const lastLength = lastChild.childrenLength;
307+
if (lastLength === 0) {
308+
// Empty lists should never be contained in other lists.
309+
throw new BugIndicatingError();
310+
}
311+
lastChild = lastChild.getChild(lastLength - 1) as ListAstNode;
302312
}
303313

304314
return lastChild.canBeReused(openBracketIds);
@@ -324,7 +334,7 @@ export abstract class ListAstNode extends BaseAstNode {
324334
}
325335

326336
public flattenLists(): ListAstNode {
327-
const items = new Array<AstNode>();
337+
const items: AstNode[] = [];
328338
for (const c of this.children) {
329339
const normalized = c.flattenLists();
330340
if (normalized.kind === AstNodeKind.List) {

src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/concat23Trees.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ function concat(node1: AstNode, node2: AstNode): AstNode {
108108
function append(list: ListAstNode, nodeToAppend: AstNode): AstNode {
109109
list = list.toMutable() as ListAstNode;
110110
let curNode: AstNode = list;
111-
const parents = new Array<ListAstNode>();
111+
const parents: ListAstNode[] = [];
112112
let nodeToAppendOfCorrectHeight: AstNode | undefined;
113113
while (true) {
114114
// assert nodeToInsert.listHeight <= curNode.listHeight
@@ -157,7 +157,7 @@ function append(list: ListAstNode, nodeToAppend: AstNode): AstNode {
157157
function prepend(list: ListAstNode, nodeToAppend: AstNode): AstNode {
158158
list = list.toMutable() as ListAstNode;
159159
let curNode: AstNode = list;
160-
const parents = new Array<ListAstNode>();
160+
const parents: ListAstNode[] = [];
161161
// assert nodeToInsert.listHeight <= curNode.listHeight
162162
while (nodeToAppend.listHeight !== curNode.listHeight) {
163163
// assert 0 <= nodeToInsert.listHeight < curNode.listHeight

src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/parser.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,24 @@ class Parser {
7171
private parseList(
7272
openedBracketIds: SmallImmutableSet<OpeningBracketId>,
7373
): AstNode | null {
74-
const items = new Array<AstNode>();
74+
const items: AstNode[] = [];
7575

7676
while (true) {
77-
const token = this.tokenizer.peek();
78-
if (
79-
!token ||
80-
(token.kind === TokenKind.ClosingBracket &&
81-
token.bracketIds.intersects(openedBracketIds))
82-
) {
83-
break;
77+
let child = this.tryReadChildFromCache(openedBracketIds);
78+
79+
if (!child) {
80+
const token = this.tokenizer.peek();
81+
if (
82+
!token ||
83+
(token.kind === TokenKind.ClosingBracket &&
84+
token.bracketIds.intersects(openedBracketIds))
85+
) {
86+
break;
87+
}
88+
89+
child = this.parseChild(openedBracketIds);
8490
}
8591

86-
const child = this.parseChild(openedBracketIds);
8792
if (child.kind === AstNodeKind.List && child.childrenLength === 0) {
8893
continue;
8994
}
@@ -96,9 +101,7 @@ class Parser {
96101
return result;
97102
}
98103

99-
private parseChild(
100-
openedBracketIds: SmallImmutableSet<number>,
101-
): AstNode {
104+
private tryReadChildFromCache(openedBracketIds: SmallImmutableSet<number>): AstNode | undefined {
102105
if (this.oldNodeReader) {
103106
const maxCacheableLength = this.positionMapper.getDistanceToNextChange(this.tokenizer.offset);
104107
if (!lengthIsZero(maxCacheableLength)) {
@@ -119,7 +122,12 @@ class Parser {
119122
}
120123
}
121124
}
125+
return undefined;
126+
}
122127

128+
private parseChild(
129+
openedBracketIds: SmallImmutableSet<number>,
130+
): AstNode {
123131
this._itemsConstructed++;
124132

125133
const token = this.tokenizer.read()!;

src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/smallImmutableSet.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
const emptyArr = new Array<number>();
6+
const emptyArr: number[] = [];
77

88
/**
99
* Represents an immutable set that works best for a small number of elements (less than 32).
@@ -86,7 +86,7 @@ export class SmallImmutableSet<T> {
8686
}
8787

8888
// This can be optimized, but it's not a common case
89-
const newItems = new Array<number>();
89+
const newItems: number[] = [];
9090
for (let i = 0; i < Math.max(this.additionalItems.length, other.additionalItems.length); i++) {
9191
const item1 = this.additionalItems[i] || 0;
9292
const item2 = other.additionalItems[i] || 0;

src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ class NonPeekableTextBufferTokenizer {
143143
// We must not jump into a token!
144144
if (lineIdx === this.lineIdx) {
145145
this.lineCharOffset = column;
146-
this.lineTokenOffset = this.lineCharOffset === 0 ? 0 : this.lineTokens!.findTokenIndexAtOffset(this.lineCharOffset);
146+
if (this.line !== null) {
147+
this.lineTokenOffset = this.lineCharOffset === 0 ? 0 : this.lineTokens!.findTokenIndexAtOffset(this.lineCharOffset);
148+
}
147149
} else {
148150
this.lineIdx = lineIdx;
149151
this.lineCharOffset = column;
@@ -291,7 +293,7 @@ export class FastTokenizer implements Tokenizer {
291293
let lastTokenEndOffset = 0;
292294
let lastTokenEndLine = 0;
293295

294-
const smallTextTokens0Line = new Array<Token>();
296+
const smallTextTokens0Line: Token[] = [];
295297
for (let i = 0; i < 60; i++) {
296298
smallTextTokens0Line.push(
297299
new Token(
@@ -301,7 +303,7 @@ export class FastTokenizer implements Tokenizer {
301303
);
302304
}
303305

304-
const smallTextTokens1Line = new Array<Token>();
306+
const smallTextTokens1Line: Token[] = [];
305307
for (let i = 0; i < 60; i++) {
306308
smallTextTokens1Line.push(
307309
new Token(

0 commit comments

Comments
 (0)