@@ -34,7 +34,6 @@ import { withUndefinedAsNull } from 'vs/base/common/types';
3434import { VSBufferReadableStream , VSBuffer } from 'vs/base/common/buffer' ;
3535import { TokensStore , MultilineTokens , countEOL , MultilineTokens2 , TokensStore2 } from 'vs/editor/common/model/tokensStore' ;
3636import { Color } from 'vs/base/common/color' ;
37- import { Constants } from 'vs/base/common/uint' ;
3837import { EditorTheme } from 'vs/editor/common/view/viewContext' ;
3938import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo' ;
4039import { TextChange } from 'vs/editor/common/model/textChange' ;
@@ -172,6 +171,21 @@ const enum StringOffsetValidationType {
172171 SurrogatePairs = 1 ,
173172}
174173
174+ type ContinueBracketSearchPredicate = null | ( ( ) => boolean ) ;
175+
176+ class BracketSearchCanceled {
177+ public static INSTANCE = new BracketSearchCanceled ( ) ;
178+ _searchCanceledBrand = undefined ;
179+ private constructor ( ) { }
180+ }
181+
182+ function stripBracketSearchCanceled < T > ( result : T | null | BracketSearchCanceled ) : T | null {
183+ if ( result instanceof BracketSearchCanceled ) {
184+ return null ;
185+ }
186+ return result ;
187+ }
188+
175189export class TextModel extends Disposable implements model . ITextModel {
176190
177191 private static readonly MODEL_SYNC_LIMIT = 50 * 1024 * 1024 ; // 50 MB
@@ -2014,7 +2028,7 @@ export class TextModel extends Disposable implements model.ITextModel {
20142028 return null ;
20152029 }
20162030
2017- return this . _findMatchingBracketUp ( data , position ) ;
2031+ return stripBracketSearchCanceled ( this . _findMatchingBracketUp ( data , position , null ) ) ;
20182032 }
20192033
20202034 public matchBracket ( position : IPosition ) : [ Range , Range ] | null {
@@ -2062,8 +2076,11 @@ export class TextModel extends Disposable implements model.ITextModel {
20622076 // check that we didn't hit a bracket too far away from position
20632077 if ( foundBracket . startColumn <= position . column && position . column <= foundBracket . endColumn ) {
20642078 const foundBracketText = lineText . substring ( foundBracket . startColumn - 1 , foundBracket . endColumn - 1 ) . toLowerCase ( ) ;
2065- const r = this . _matchFoundBracket ( foundBracket , currentModeBrackets . textIsBracket [ foundBracketText ] , currentModeBrackets . textIsOpenBracket [ foundBracketText ] ) ;
2079+ const r = this . _matchFoundBracket ( foundBracket , currentModeBrackets . textIsBracket [ foundBracketText ] , currentModeBrackets . textIsOpenBracket [ foundBracketText ] , null ) ;
20662080 if ( r ) {
2081+ if ( r instanceof BracketSearchCanceled ) {
2082+ return null ;
2083+ }
20672084 bestResult = r ;
20682085 }
20692086 }
@@ -2100,8 +2117,11 @@ export class TextModel extends Disposable implements model.ITextModel {
21002117 // check that we didn't hit a bracket too far away from position
21012118 if ( foundBracket && foundBracket . startColumn <= position . column && position . column <= foundBracket . endColumn ) {
21022119 const foundBracketText = lineText . substring ( foundBracket . startColumn - 1 , foundBracket . endColumn - 1 ) . toLowerCase ( ) ;
2103- const r = this . _matchFoundBracket ( foundBracket , prevModeBrackets . textIsBracket [ foundBracketText ] , prevModeBrackets . textIsOpenBracket [ foundBracketText ] ) ;
2120+ const r = this . _matchFoundBracket ( foundBracket , prevModeBrackets . textIsBracket [ foundBracketText ] , prevModeBrackets . textIsOpenBracket [ foundBracketText ] , null ) ;
21042121 if ( r ) {
2122+ if ( r instanceof BracketSearchCanceled ) {
2123+ return null ;
2124+ }
21052125 return r ;
21062126 }
21072127 }
@@ -2111,35 +2131,41 @@ export class TextModel extends Disposable implements model.ITextModel {
21112131 return null ;
21122132 }
21132133
2114- private _matchFoundBracket ( foundBracket : Range , data : RichEditBracket , isOpen : boolean ) : [ Range , Range ] | null {
2134+ private _matchFoundBracket ( foundBracket : Range , data : RichEditBracket , isOpen : boolean , continueSearchPredicate : ContinueBracketSearchPredicate ) : [ Range , Range ] | null | BracketSearchCanceled {
21152135 if ( ! data ) {
21162136 return null ;
21172137 }
21182138
2119- if ( isOpen ) {
2120- let matched = this . _findMatchingBracketDown ( data , foundBracket . getEndPosition ( ) ) ;
2121- if ( matched ) {
2122- return [ foundBracket , matched ] ;
2123- }
2124- } else {
2125- let matched = this . _findMatchingBracketUp ( data , foundBracket . getStartPosition ( ) ) ;
2126- if ( matched ) {
2127- return [ foundBracket , matched ] ;
2128- }
2139+ const matched = (
2140+ isOpen
2141+ ? this . _findMatchingBracketDown ( data , foundBracket . getEndPosition ( ) , continueSearchPredicate )
2142+ : this . _findMatchingBracketUp ( data , foundBracket . getStartPosition ( ) , continueSearchPredicate )
2143+ ) ;
2144+
2145+ if ( ! matched ) {
2146+ return null ;
21292147 }
21302148
2131- return null ;
2149+ if ( matched instanceof BracketSearchCanceled ) {
2150+ return matched ;
2151+ }
2152+
2153+ return [ foundBracket , matched ] ;
21322154 }
21332155
2134- private _findMatchingBracketUp ( bracket : RichEditBracket , position : Position ) : Range | null {
2156+ private _findMatchingBracketUp ( bracket : RichEditBracket , position : Position , continueSearchPredicate : ContinueBracketSearchPredicate ) : Range | null | BracketSearchCanceled {
21352157 // console.log('_findMatchingBracketUp: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
21362158
21372159 const languageId = bracket . languageIdentifier . id ;
21382160 const reversedBracketRegex = bracket . reversedRegex ;
21392161 let count = - 1 ;
21402162
2141- const searchPrevMatchingBracketInRange = ( lineNumber : number , lineText : string , searchStartOffset : number , searchEndOffset : number ) : Range | null => {
2163+ let totalCallCount = 0 ;
2164+ const searchPrevMatchingBracketInRange = ( lineNumber : number , lineText : string , searchStartOffset : number , searchEndOffset : number ) : Range | null | BracketSearchCanceled => {
21422165 while ( true ) {
2166+ if ( continueSearchPredicate && ( ++ totalCallCount ) % 100 === 0 && ! continueSearchPredicate ( ) ) {
2167+ return BracketSearchCanceled . INSTANCE ;
2168+ }
21432169 const r = BracketsUtils . findPrevBracketInRange ( reversedBracketRegex , lineNumber , lineText , searchStartOffset , searchEndOffset ) ;
21442170 if ( ! r ) {
21452171 break ;
@@ -2214,15 +2240,19 @@ export class TextModel extends Disposable implements model.ITextModel {
22142240 return null ;
22152241 }
22162242
2217- private _findMatchingBracketDown ( bracket : RichEditBracket , position : Position ) : Range | null {
2243+ private _findMatchingBracketDown ( bracket : RichEditBracket , position : Position , continueSearchPredicate : ContinueBracketSearchPredicate ) : Range | null | BracketSearchCanceled {
22182244 // console.log('_findMatchingBracketDown: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
22192245
22202246 const languageId = bracket . languageIdentifier . id ;
22212247 const bracketRegex = bracket . forwardRegex ;
22222248 let count = 1 ;
22232249
2224- const searchNextMatchingBracketInRange = ( lineNumber : number , lineText : string , searchStartOffset : number , searchEndOffset : number ) : Range | null => {
2250+ let totalCallCount = 0 ;
2251+ const searchNextMatchingBracketInRange = ( lineNumber : number , lineText : string , searchStartOffset : number , searchEndOffset : number ) : Range | null | BracketSearchCanceled => {
22252252 while ( true ) {
2253+ if ( continueSearchPredicate && ( ++ totalCallCount ) % 100 === 0 && ! continueSearchPredicate ( ) ) {
2254+ return BracketSearchCanceled . INSTANCE ;
2255+ }
22262256 const r = BracketsUtils . findNextBracketInRange ( bracketRegex , lineNumber , lineText , searchStartOffset , searchEndOffset ) ;
22272257 if ( ! r ) {
22282258 break ;
@@ -2452,7 +2482,16 @@ export class TextModel extends Disposable implements model.ITextModel {
24522482 return null ;
24532483 }
24542484
2455- public findEnclosingBrackets ( _position : IPosition , maxDuration = Constants . MAX_SAFE_SMALL_INTEGER ) : [ Range , Range ] | null {
2485+ public findEnclosingBrackets ( _position : IPosition , maxDuration ?: number ) : [ Range , Range ] | null {
2486+ let continueSearchPredicate : ContinueBracketSearchPredicate ;
2487+ if ( typeof maxDuration === 'undefined' ) {
2488+ continueSearchPredicate = null ;
2489+ } else {
2490+ const startTime = Date . now ( ) ;
2491+ continueSearchPredicate = ( ) => {
2492+ return ( Date . now ( ) - startTime <= maxDuration ) ;
2493+ } ;
2494+ }
24562495 const position = this . validatePosition ( _position ) ;
24572496 const lineCount = this . getLineCount ( ) ;
24582497 const savedCounts = new Map < number , number [ ] > ( ) ;
@@ -2468,8 +2507,13 @@ export class TextModel extends Disposable implements model.ITextModel {
24682507 }
24692508 counts = savedCounts . get ( languageId ) ! ;
24702509 } ;
2471- const searchInRange = ( modeBrackets : RichEditBrackets , lineNumber : number , lineText : string , searchStartOffset : number , searchEndOffset : number ) : [ Range , Range ] | null => {
2510+
2511+ let totalCallCount = 0 ;
2512+ const searchInRange = ( modeBrackets : RichEditBrackets , lineNumber : number , lineText : string , searchStartOffset : number , searchEndOffset : number ) : [ Range , Range ] | null | BracketSearchCanceled => {
24722513 while ( true ) {
2514+ if ( continueSearchPredicate && ( ++ totalCallCount ) % 100 === 0 && ! continueSearchPredicate ( ) ) {
2515+ return BracketSearchCanceled . INSTANCE ;
2516+ }
24732517 const r = BracketsUtils . findNextBracketInRange ( modeBrackets . forwardRegex , lineNumber , lineText , searchStartOffset , searchEndOffset ) ;
24742518 if ( ! r ) {
24752519 break ;
@@ -2485,7 +2529,7 @@ export class TextModel extends Disposable implements model.ITextModel {
24852529 }
24862530
24872531 if ( counts [ bracket . index ] === - 1 ) {
2488- return this . _matchFoundBracket ( r , bracket , false ) ;
2532+ return this . _matchFoundBracket ( r , bracket , false , continueSearchPredicate ) ;
24892533 }
24902534 }
24912535
@@ -2496,12 +2540,7 @@ export class TextModel extends Disposable implements model.ITextModel {
24962540
24972541 let languageId : LanguageId = - 1 ;
24982542 let modeBrackets : RichEditBrackets | null = null ;
2499- const startTime = Date . now ( ) ;
25002543 for ( let lineNumber = position . lineNumber ; lineNumber <= lineCount ; lineNumber ++ ) {
2501- const elapsedTime = Date . now ( ) - startTime ;
2502- if ( elapsedTime > maxDuration ) {
2503- return null ;
2504- }
25052544 const lineTokens = this . _getLineTokens ( lineNumber ) ;
25062545 const tokenCount = lineTokens . getCount ( ) ;
25072546 const lineText = this . _buffer . getLineContent ( lineNumber ) ;
@@ -2530,7 +2569,7 @@ export class TextModel extends Disposable implements model.ITextModel {
25302569 if ( modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset ) {
25312570 const r = searchInRange ( modeBrackets , lineNumber , lineText , searchStartOffset , searchEndOffset ) ;
25322571 if ( r ) {
2533- return r ;
2572+ return stripBracketSearchCanceled ( r ) ;
25342573 }
25352574 prevSearchInToken = false ;
25362575 }
@@ -2555,7 +2594,7 @@ export class TextModel extends Disposable implements model.ITextModel {
25552594 if ( modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset ) {
25562595 const r = searchInRange ( modeBrackets , lineNumber , lineText , searchStartOffset , searchEndOffset ) ;
25572596 if ( r ) {
2558- return r ;
2597+ return stripBracketSearchCanceled ( r ) ;
25592598 }
25602599 }
25612600 }
@@ -2566,7 +2605,7 @@ export class TextModel extends Disposable implements model.ITextModel {
25662605 if ( modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset ) {
25672606 const r = searchInRange ( modeBrackets , lineNumber , lineText , searchStartOffset , searchEndOffset ) ;
25682607 if ( r ) {
2569- return r ;
2608+ return stripBracketSearchCanceled ( r ) ;
25702609 }
25712610 }
25722611 }
0 commit comments