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