未验证 提交 0204c009 编写于 作者: A Alex Dima

Fixes #93370: Add ContinueBracketSearchPredicate and invoke it every 100th search

上级 18d381b7
......@@ -34,7 +34,6 @@ import { withUndefinedAsNull } from 'vs/base/common/types';
import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';
import { Color } from 'vs/base/common/color';
import { Constants } from 'vs/base/common/uint';
import { EditorTheme } from 'vs/editor/common/view/viewContext';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { TextChange } from 'vs/editor/common/model/textChange';
......@@ -172,6 +171,21 @@ const enum StringOffsetValidationType {
SurrogatePairs = 1,
}
type ContinueBracketSearchPredicate = null | (() => boolean);
class BracketSearchCanceled {
public static INSTANCE = new BracketSearchCanceled();
_searchCanceledBrand = undefined;
private constructor() { }
}
function stripBracketSearchCanceled<T>(result: T | null | BracketSearchCanceled): T | null {
if (result instanceof BracketSearchCanceled) {
return null;
}
return result;
}
export class TextModel extends Disposable implements model.ITextModel {
private static readonly MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB
......@@ -2014,7 +2028,7 @@ export class TextModel extends Disposable implements model.ITextModel {
return null;
}
return this._findMatchingBracketUp(data, position);
return stripBracketSearchCanceled(this._findMatchingBracketUp(data, position, null));
}
public matchBracket(position: IPosition): [Range, Range] | null {
......@@ -2062,8 +2076,11 @@ export class TextModel extends Disposable implements model.ITextModel {
// check that we didn't hit a bracket too far away from position
if (foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
const foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase();
const r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText]);
const r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText], null);
if (r) {
if (r instanceof BracketSearchCanceled) {
return null;
}
bestResult = r;
}
}
......@@ -2100,8 +2117,11 @@ export class TextModel extends Disposable implements model.ITextModel {
// check that we didn't hit a bracket too far away from position
if (foundBracket && foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
const foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase();
const r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText]);
const r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText], null);
if (r) {
if (r instanceof BracketSearchCanceled) {
return null;
}
return r;
}
}
......@@ -2111,35 +2131,41 @@ export class TextModel extends Disposable implements model.ITextModel {
return null;
}
private _matchFoundBracket(foundBracket: Range, data: RichEditBracket, isOpen: boolean): [Range, Range] | null {
private _matchFoundBracket(foundBracket: Range, data: RichEditBracket, isOpen: boolean, continueSearchPredicate: ContinueBracketSearchPredicate): [Range, Range] | null | BracketSearchCanceled {
if (!data) {
return null;
}
if (isOpen) {
let matched = this._findMatchingBracketDown(data, foundBracket.getEndPosition());
if (matched) {
return [foundBracket, matched];
}
} else {
let matched = this._findMatchingBracketUp(data, foundBracket.getStartPosition());
if (matched) {
return [foundBracket, matched];
const matched = (
isOpen
? this._findMatchingBracketDown(data, foundBracket.getEndPosition(), continueSearchPredicate)
: this._findMatchingBracketUp(data, foundBracket.getStartPosition(), continueSearchPredicate)
);
if (!matched) {
return null;
}
if (matched instanceof BracketSearchCanceled) {
return matched;
}
return null;
return [foundBracket, matched];
}
private _findMatchingBracketUp(bracket: RichEditBracket, position: Position): Range | null {
private _findMatchingBracketUp(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {
// console.log('_findMatchingBracketUp: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
const languageId = bracket.languageIdentifier.id;
const reversedBracketRegex = bracket.reversedRegex;
let count = -1;
const searchPrevMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null => {
let totalCallCount = 0;
const searchPrevMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null | BracketSearchCanceled => {
while (true) {
if (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {
return BracketSearchCanceled.INSTANCE;
}
const r = BracketsUtils.findPrevBracketInRange(reversedBracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (!r) {
break;
......@@ -2214,15 +2240,19 @@ export class TextModel extends Disposable implements model.ITextModel {
return null;
}
private _findMatchingBracketDown(bracket: RichEditBracket, position: Position): Range | null {
private _findMatchingBracketDown(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {
// console.log('_findMatchingBracketDown: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
const languageId = bracket.languageIdentifier.id;
const bracketRegex = bracket.forwardRegex;
let count = 1;
const searchNextMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null => {
let totalCallCount = 0;
const searchNextMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null | BracketSearchCanceled => {
while (true) {
if (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {
return BracketSearchCanceled.INSTANCE;
}
const r = BracketsUtils.findNextBracketInRange(bracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (!r) {
break;
......@@ -2452,7 +2482,16 @@ export class TextModel extends Disposable implements model.ITextModel {
return null;
}
public findEnclosingBrackets(_position: IPosition, maxDuration = Constants.MAX_SAFE_SMALL_INTEGER): [Range, Range] | null {
public findEnclosingBrackets(_position: IPosition, maxDuration?: number): [Range, Range] | null {
let continueSearchPredicate: ContinueBracketSearchPredicate;
if (typeof maxDuration === 'undefined') {
continueSearchPredicate = null;
} else {
const startTime = Date.now();
continueSearchPredicate = () => {
return (Date.now() - startTime <= maxDuration);
};
}
const position = this.validatePosition(_position);
const lineCount = this.getLineCount();
const savedCounts = new Map<number, number[]>();
......@@ -2468,8 +2507,13 @@ export class TextModel extends Disposable implements model.ITextModel {
}
counts = savedCounts.get(languageId)!;
};
const searchInRange = (modeBrackets: RichEditBrackets, lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): [Range, Range] | null => {
let totalCallCount = 0;
const searchInRange = (modeBrackets: RichEditBrackets, lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): [Range, Range] | null | BracketSearchCanceled => {
while (true) {
if (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {
return BracketSearchCanceled.INSTANCE;
}
const r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (!r) {
break;
......@@ -2485,7 +2529,7 @@ export class TextModel extends Disposable implements model.ITextModel {
}
if (counts[bracket.index] === -1) {
return this._matchFoundBracket(r, bracket, false);
return this._matchFoundBracket(r, bracket, false, continueSearchPredicate);
}
}
......@@ -2496,12 +2540,7 @@ export class TextModel extends Disposable implements model.ITextModel {
let languageId: LanguageId = -1;
let modeBrackets: RichEditBrackets | null = null;
const startTime = Date.now();
for (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {
const elapsedTime = Date.now() - startTime;
if (elapsedTime > maxDuration) {
return null;
}
const lineTokens = this._getLineTokens(lineNumber);
const tokenCount = lineTokens.getCount();
const lineText = this._buffer.getLineContent(lineNumber);
......@@ -2530,7 +2569,7 @@ export class TextModel extends Disposable implements model.ITextModel {
if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {
const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (r) {
return r;
return stripBracketSearchCanceled(r);
}
prevSearchInToken = false;
}
......@@ -2555,7 +2594,7 @@ export class TextModel extends Disposable implements model.ITextModel {
if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {
const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (r) {
return r;
return stripBracketSearchCanceled(r);
}
}
}
......@@ -2566,7 +2605,7 @@ export class TextModel extends Disposable implements model.ITextModel {
if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {
const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (r) {
return r;
return stripBracketSearchCanceled(r);
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册