import * as vscode from 'vscode' ; import * as vscel from '@wraith13/vscel' ; import packageJson from "../package.json" ; import localeEn from "../package.nls.json" ; import localeJa from "../package.nls.ja.json" ; const locale = vscel . locale . make ( localeEn , { "ja" : localeJa } ) ; const profile = vscel . profiler . profile ; interface ScopeTerms { opening : string ; closing : string ; } type HeaderMode = "before" | "smart" | "inner" ; interface BracketTrait extends ScopeTerms { headerMode ? : HeaderMode ; inters ? : string [ ] ; } interface StringTrait extends ScopeTerms { escape : string [ ] ; } interface LanguageConfiguration { ignoreCase : boolean ; comments ? : { block ? : ScopeTerms [ ] ; line ? : string [ ] ; } ; brackets ? : { symbol ? : BracketTrait [ ] ; word ? : BracketTrait [ ] ; } ; strings ? : { inline ? : StringTrait [ ] ; multiline ? : StringTrait [ ] ; } ; terminators ? : string [ ] ; ignoreSymbols ? : string [ ] ; } const modeObject = Object . freeze ( { "none" : "none" , "manual" : "manual" , "auto" : "auto" , } ) ; module Config { export const root = vscel . config . makeRoot ( packageJson ) ; export const mode = root . makeMapEntry ( "bracketLens.mode" , "active-text-editor" , modeObject ) ; export const debug = root . makeEntry < boolean > ( "bracketLens.debug" , "root-workspace" ) ; export const color = root . makeEntry < string > ( "bracketLens.color" , "active-text-editor" ) ; export const prefix = root . makeEntry < string > ( "bracketLens.prefix" , "active-text-editor" ) ; export const unmatchBracketsPrefix = root . makeEntry < string > ( "bracketLens.unmatchBracketsPrefix" , "active-text-editor" ) ; export const maxBracketHeaderLength = root . makeEntry < number > ( "bracketLens.maxBracketHeaderLength" , "active-text-editor" ) ; export const minBracketScopeLines = root . makeEntry < number > ( "bracketLens.minBracketScopeLines" , "active-text-editor" ) ; export const languageConfiguration = root . makeEntry < LanguageConfiguration > ( "bracketLens.languageConfiguration" , "active-text-editor" ) ; } let isMutedAll = undefined ; const debug = ( output ) => { if ( Config . debug . get ( ) ) { console . debug ( output ) ; } } ; let profilerOutputChannel = undefined ; const getProfilerOutputChannel = ( ) => profilerOutputChannel ? profilerOutputChannel : ( profilerOutputChannel = vscode . window . createOutputChannel ( "Bracket Lens Profiler" ) ) ; interface TokenEntry { position : vscode . Position ; token : string ; } interface BracketEntry { start : TokenEntry ; end : TokenEntry ; headerMode : HeaderMode ; isUnmatchBrackets : boolean ; items : BracketEntry [ ] ; } interface BracketContext { parentEntry : BracketEntry | undefined ; previousEntry : BracketEntry | undefined ; entry : BracketEntry ; nextEntry : BracketEntry | undefined ; } interface BracketDecorationSource { range : vscode . Range ; bracketHeader : string ; } class DocumentDecorationCacheEntry { brackets : BracketEntry [ ] ; decorationSource : BracketDecorationSource [ ] = [ ] ; public constructor ( document ) { this . brackets = parseBrackets ( document ) ; this . decorationSource = getBracketDecorationSource ( document , this . brackets ) ; documentDecorationCache . set ( document , this ) ; } } class EditorDecorationCacheEntry { isMuted : boolean | undefined ; private isDirtyValue : boolean = false ; private bracketHeaderInformationDecoration ? : vscode . TextEditorDecorationType ; public constructor ( editor ) { editorDecorationCache . set ( editor , this ) ; } public isDirty = ( ) => this . isDirtyValue ; public setDirty = ( ) => { this . isDirtyValue = true ; } ; public setBracketHeaderInformationDecoration = ( bracketHeaderInformationDecoration ? ) => { this . dispose ( ) ; this . bracketHeaderInformationDecoration = bracketHeaderInformationDecoration ; } ; public dispose = ( ) => { this . bracketHeaderInformationDecoration ?. dispose ( ) ; this . bracketHeaderInformationDecoration = undefined ; this . isDirtyValue = false ; } ; } const documentDecorationCache = new Map < vscode . TextDocument , DocumentDecorationCacheEntry > ( ) ; const makeSureDocumentDecorationCache = ( document ) => documentDecorationCache . get ( document ) ?? new DocumentDecorationCacheEntry ( document ) ; const editorDecorationCache = new Map < vscode . TextEditor , EditorDecorationCacheEntry > ( ) ; const makeSureEditorDecorationCache = ( textEditor ) => editorDecorationCache . get ( textEditor ) ?? new EditorDecorationCacheEntry ( textEditor ) ; export const regExpExecToArray = ( regexp , text ) => profile ( `regExpExecToArray(/${ regexp . source }/${ regexp . flags })` , ( ) => { const result = [ ] ; while ( true ) { const match = regexp . exec ( text ) ; if ( null === match ) { break ; } result . push ( match ) ; } return result ; } ) ; const makeRegExpPart = ( text ) => text . replace ( /([\\\/\*\[\]\(\)\{\}\|])/gmu , "\\$1" ) . replace ( /\s+/ , "\\s" ) ; const isInlineScope = ( bracket ) => bracket . end . position . line <= bracket . start . position . line ; const parseBrackets = ( document ) => profile ( "parseBrackets" , ( ) : BracketEntry [ ] => { const result = [ ] ; const languageConfiguration = Config . languageConfiguration . get ( document ) ; const regulate = languageConfiguration . ignoreCase ? ( text ) => text . replace ( /\s+/ , " " ) . toLowerCase ( ) : ( text ) => text . replace ( /\s+/ , " " ) ; const openingBlockComments = languageConfiguration . comments ?. block ?. map ( i => regulate ( i . opening ) ) ?? [ ] ; const closingBlockComments = languageConfiguration . comments ?. block ?. map ( i => regulate ( i . closing ) ) ?? [ ] ; const lineComments = languageConfiguration . comments ?. line ?. map ( regulate ) ?? [ ] ; const openingSymbolBrackets = languageConfiguration . brackets ?. symbol ?. map ( i => regulate ( i . opening ) ) ?? [ ] ; const symbolBracketInters = languageConfiguration . brackets ?. symbol ?. map ( i => i . inters ?. map ( regulate ) ?? [ ] ) ?. reduce ( ( a , b ) => a . concat ( b ) , [ ] ) ?? [ ] ; const closingSymbolBrackets = languageConfiguration . brackets ?. symbol ?. map ( i => regulate ( i . closing ) ) ?? [ ] ; const symbolBracketsHeader = languageConfiguration . brackets ?. symbol ?. map ( i => i . headerMode ?? "smart" ) ?? [ ] ; const openingWordBrackets = languageConfiguration . brackets ?. word ?. map ( i => regulate ( i . opening ) ) ?? [ ] ; const wordBracketInters = languageConfiguration . brackets ?. word ?. map ( i => i . inters ?. map ( regulate ) ?? [ ] ) ?. reduce ( ( a , b ) => a . concat ( b ) , [ ] ) ?? [ ] ; const closingWordBrackets = languageConfiguration . brackets ?. word ?. map ( i => regulate ( i . closing ) ) ?? [ ] ; const wordBracketsHeader = languageConfiguration . brackets ?. word ?. map ( i => i . headerMode ?? "inner" ) ?? [ ] ; const openingInlineStrings = languageConfiguration . strings ?. inline ?. map ( i => regulate ( i . opening ) ) ?? [ ] ; const escapeInlineStrings = languageConfiguration . strings ?. inline ?. map ( i => i . escape . map ( regulate ) ) ?. reduce ( ( a , b ) => a . concat ( b ) , [ ] ) ?? [ ] ; const closingInlineStrings = languageConfiguration . strings ?. inline ?. map ( i => regulate ( i . closing ) ) ?? [ ] ; const openingMultilineStrings = languageConfiguration . strings ?. multiline ?. map ( i => regulate ( i . opening ) ) ?? [ ] ; const escapeMultilineStrings = languageConfiguration . strings ?. multiline ?. map ( i => i . escape . map ( regulate ) ) ?. reduce ( ( a , b ) => a . concat ( b ) , [ ] ) ?? [ ] ; const closingMultilineStrings = languageConfiguration . strings ?. multiline ?. map ( i => regulate ( i . closing ) ) ?? [ ] ; const ignoreSymbols = languageConfiguration . ignoreSymbols ?. map ( i => regulate ( i ) ) ?? [ ] ; const pattern = ( < string [ ] > [ ] ) . concat ( ignoreSymbols ) . concat ( openingBlockComments ) . concat ( closingBlockComments ) . concat ( lineComments ) . concat ( openingSymbolBrackets ) . concat ( symbolBracketInters ) . concat ( closingSymbolBrackets ) . concat ( openingWordBrackets ) . concat ( wordBracketInters ) . concat ( closingWordBrackets ) . concat ( openingInlineStrings ) . concat ( escapeInlineStrings ) . concat ( closingInlineStrings ) . concat ( openingMultilineStrings ) . concat ( escapeMultilineStrings ) . concat ( closingMultilineStrings ) . filter ( ( entry , index , array ) => "" !== entry && index === array . indexOf ( entry ) ) . map ( i => `${ makeRegExpPart ( i ) }` ) . join ( "|" ) ; const text = document . getText ( ) ; const tokens = regExpExecToArray ( new RegExp ( pattern , languageConfiguration . ignoreCase ? "gui" : "gu" ) , text ) . map ( match => ( { index : match . index , token : match [ 0 ] , } ) ) ; const getCharactoer = ( index ) => index < 0 ? "" : document . getText ( new vscode . Range ( document . positionAt ( index ) , document . positionAt ( index + 1 ) ) ) ; const isIncludeWord = ( text ) => text . replace ( /\w/ , "" ) . length < text . length ; const isSureMatchWord = ( match ) => ! isIncludeWord ( getCharactoer ( match . index - 1 ) ) && ! isIncludeWord ( getCharactoer ( match . index + match . token . length ) ) ; profile ( "parseBrackets.scan" , ( ) => { let scopeStack = [ ] ; let i = 0 ; const writeCore = ( entry ) => profile ( "parseBrackets.scan.writeCore" , ( ) => { if ( ! isInlineScope ( entry ) || entry . isUnmatchBrackets ) { const parent = scopeStack [ scopeStack . length - 1 ] ; if ( parent ) { parent . items . push ( entry ) ; } else { result . push ( entry ) ; } } } ) ; const write = ( closingToken ) => profile ( "parseBrackets.scan.write" , ( ) => { const scope = scopeStack . pop ( ) ; if ( scope ) { writeCore ( { start : scope . start , end : { position : document . positionAt ( closingToken . index + closingToken . token . length ) , token : closingToken . token , } , headerMode : scope . headerMode , isUnmatchBrackets : scope . closing !== regulate ( closingToken . token ) , items : scope . items , } ) ; } else { writeCore ( { start : { position : document . positionAt ( closingToken . index ) , token : closingToken . token , } , end : { position : document . positionAt ( closingToken . index + closingToken . token . length ) , token : closingToken . token , } , headerMode : "smart" , isUnmatchBrackets : true , items : [ ] , } ) ; } } ) ; while ( i < tokens . length ) { const token = regulate ( tokens [ i ] . token ) ; if ( 0 <= openingBlockComments . indexOf ( token ) ) { profile ( "parseBrackets.scan.blockComment" , ( ) => { const closing = closingBlockComments [ openingBlockComments . indexOf ( token ) ] ; while ( ++ i < tokens . length ) { if ( closing === regulate ( tokens [ i ] . token ) ) { ++ i ; break ; } } } ) ; } else if ( 0 <= lineComments . indexOf ( token ) ) { profile ( "parseBrackets.scan.lineComment" , ( ) => { const line = document . positionAt ( tokens [ i ] . index ) . line ; while ( ++ i < tokens . length ) { if ( line !== document . positionAt ( tokens [ i ] . index ) . line ) { break ; } } } ) ; } else if ( 0 <= openingSymbolBrackets . indexOf ( token ) ) { profile ( "parseBrackets.scan.openingSymbolBracket" , ( ) => { const index = openingSymbolBrackets . indexOf ( token ) ; scopeStack . push ( { start : { position : document . positionAt ( tokens [ i ] . index ) , token : tokens [ i ] . token , } , closing : closingSymbolBrackets [ index ] , headerMode : symbolBracketsHeader [ index ] , items : [ ] , } ) ; ++ i ; } ) ; } else if ( 0 <= openingWordBrackets . indexOf ( token ) && isSureMatchWord ( tokens [ i ] ) ) { profile ( "parseBrackets.scan.openingWordBracket" , ( ) => { const index = openingWordBrackets . indexOf ( token ) ; scopeStack . push ( { start : { position : document . positionAt ( tokens [ i ] . index ) , token : tokens [ i ] . token , } , closing : closingWordBrackets [ index ] , headerMode : wordBracketsHeader [ index ] , items : [ ] , } ) ; ++ i ; } ) ; } else if ( 0 <= closingSymbolBrackets . indexOf ( token ) || ( 0 <= closingWordBrackets . indexOf ( token ) && isSureMatchWord ( tokens [ i ] ) ) ) { profile ( "parseBrackets.scan.closingBracket" , ( ) => { write ( tokens [ i ] ) ; ++ i ; } ) ; } else if ( 0 <= openingInlineStrings . indexOf ( token ) ) { profile ( "parseBrackets.scan.inlineString" , ( ) => { const line = document . positionAt ( tokens [ i ] . index ) . line ; const closing = closingInlineStrings [ openingInlineStrings . indexOf ( token ) ] ; while ( ++ i < tokens . length ) { if ( line !== document . positionAt ( tokens [ i ] . index ) . line ) { break ; } if ( closing === regulate ( tokens [ i ] . token ) ) { ++ i ; break ; } } } ) ; } else if ( 0 <= openingMultilineStrings . indexOf ( token ) ) { profile ( "parseBrackets.scan.multilineString" , ( ) => { const closing = closingMultilineStrings [ openingMultilineStrings . indexOf ( token ) ] ; while ( ++ i < tokens . length ) { if ( closing === regulate ( tokens [ i ] . token ) ) { ++ i ; break ; } } } ) ; } else { debug ( `unmatch-token: ${ JSON . stringify ( tokens [ i ] ) }` ) ; ++ i ; } } ; profile ( "parseBrackets.scan.rest" , ( ) => { while ( 0 < scopeStack . length ) { write ( { index : text . length , token : "" } ) ; } } ) ; } ) ; return result ; } ) ; module position { export const nextLine = ( position , increment = 1 ) => new vscode . Position ( position . line + increment , 0 ) ; export const nextCharacter = ( position , increment = 1 ) => new vscode . Position ( position . line , position . character + increment ) ; export const min = ( positions ) => positions . reduce ( ( a , b ) => a . isBefore ( b ) ? a : b , positions [ 0 ] ) ; export const max = ( positions ) => positions . reduce ( ( a , b ) => a . isAfter ( b ) ? a : b , positions [ 0 ] ) ; } const getBracketHeader = ( document , context ) => profile ( "getBracketHeader" , ( ) : string => { const maxBracketHeaderLength = Config . maxBracketHeaderLength . get ( document ) ; const regulateHeader = ( text ) => { let result = text . replace ( /\s+/gu , " " ) . trim ( ) ; if ( maxBracketHeaderLength < result . length ) { return result . substring ( 0 , maxBracketHeaderLength - 3 ) + "..." ; } return result ; } ; const isValidHeader = ( text ) => 0 < text . replace ( /,/gmu , "" ) . trim ( ) . length ; if ( "inner" !== context . entry . headerMode ) { const languageConfiguration = Config . languageConfiguration . get ( document ) ; const terminators = languageConfiguration . terminators ?? [ ] ; const topLimit = context . previousEntry ?. end . position ?? ( undefined !== context . parentEntry ? position . nextCharacter ( context . parentEntry . start . position , context . parentEntry . start . token . length ) : new vscode . Position ( 0 , 0 ) ) ; const lineHead = position . max ( [ topLimit , position . nextLine ( context . entry . start . position , 0 ) , ] ) ; const currnetLineHeader = regulateHeader ( document . getText ( new vscode . Range ( lineHead , context . entry . start . position ) ) ) ; if ( isValidHeader ( currnetLineHeader ) && ! terminators . some ( i => currnetLineHeader . endsWith ( i ) ) ) { return currnetLineHeader ; } if ( topLimit . line < context . entry . start . position . line ) { const previousLineHead = position . max ( [ topLimit , position . nextLine ( context . entry . start . position , - 1 ) , ] ) ; const previousLineHeader = regulateHeader ( document . getText ( new vscode . Range ( previousLineHead , lineHead ) ) ) ; if ( isValidHeader ( previousLineHeader ) && ! terminators . some ( i => previousLineHeader . endsWith ( i ) ) ) { return previousLineHeader ; } } } if ( "before" !== context . entry . headerMode ) { const currnetLineInnerHeader = regulateHeader ( document . getText ( new vscode . Range ( context . entry . start . position , position . nextLine ( context . entry . start . position , + 1 ) ) ) ) ; if ( isValidHeader ( currnetLineInnerHeader ) && currnetLineInnerHeader !== regulateHeader ( context . entry . start . token ) ) { return currnetLineInnerHeader ; } const innerHeader = regulateHeader ( document . getText ( new vscode . Range ( context . entry . start . position , position . min ( [ position . nextLine ( context . entry . start . position , + 16 ) , context . entry . end . position , ] ) ) ) ) ; if ( isValidHeader ( innerHeader ) ) { return innerHeader ; } } return "" ; } ) ; export const getBracketDecorationSource = ( document , brackets ) => profile ( "getBracketDecorationSource" , ( ) => { const prefix = Config . prefix . get ( document ) ; const unmatchBracketsPrefix = Config . unmatchBracketsPrefix . get ( document ) ; const minBracketScopeLines = Config . minBracketScopeLines . get ( document ) ; const result = [ ] ; const scanner = ( context ) => { if ( minBracketScopeLines <= ( context . entry . end . position . line - context . entry . start . position . line ) + 1 ) { if ( context . entry . end . position . line < ( context . nextEntry ?. start . position . line ?? document . lineCount + 1 ) && context . entry . end . position . line < ( context . parentEntry ?. end . position . line ?? document . lineCount + 1 ) ) { const bracketHeader = getBracketHeader ( document , context ) ; if ( 0 < bracketHeader . length ) { result . push ( { range : new vscode . Range ( position . nextCharacter ( context . entry . end . position , - context . entry . end . token . length ) , context . entry . end . position ) , bracketHeader : `${ context . entry . isUnmatchBrackets ? unmatchBracketsPrefix : prefix }${ bracketHeader }` , } ) ; } } context . entry . items . map ( ( entry , index , array ) => scanner ( { parentEntry : context . entry , previousEntry : array [ index - 1 ] , entry , nextEntry : array [ index + 1 ] , } ) ) ; } } ; brackets . map ( ( entry , index , array ) => scanner ( { parentEntry : undefined , previousEntry : array [ index - 1 ] , entry , nextEntry : array [ index + 1 ] , } ) ) ; return result ; } ) ; export const updateDecoration = ( textEditor ) => profile ( "updateDecoration" , ( ) => { const editorCache = editorDecorationCache . get ( textEditor ) ; if ( "none" !== Config . mode . getKey ( textEditor . document ) ) { const isMuted = undefined !== editorCache ?. isMuted ? editorCache . isMuted : isMutedAll ; if ( isMuted ) { editorCache ?. dispose ( ) ; editorCache ?. setDirty ( ) ; } else if ( undefined === editorCache || editorCache . isDirty ( ) ) { const bracketHeaderInformationDecoration = vscode . window . createTextEditorDecorationType ( { isWholeLine : true , } ) ; const options = [ ] ; const color = Config . color . get ( textEditor . document ) ; makeSureDocumentDecorationCache ( textEditor . document ) . decorationSource . forEach ( i => options . push ( { range : i . range , renderOptions : { after : { contentText : i . bracketHeader , color , } } } ) ) ; makeSureEditorDecorationCache ( textEditor ) . setBracketHeaderInformationDecoration ( bracketHeaderInformationDecoration ) ; profile ( "textEditor.setDecorations" , ( ) => textEditor . setDecorations ( bracketHeaderInformationDecoration , options ) ) ; } } else { editorCache ?. dispose ( ) ; editorDecorationCache . delete ( textEditor ) ; } } ) ; export const onDidChangeConfiguration = ( ) => { clearAllDecorationCache ( ) ; updateAllDecoration ( ) ; } ; const valueThen = < ValueT , ResultT > ( value , f ) => { if ( value ) { return f ( value ) ; } return undefined ; } ; const activeTextEditor = < T > ( f ) => valueThen ( vscode . window . activeTextEditor , f ) ; export const clearAllDecorationCache = ( ) : void => { documentDecorationCache . clear ( ) ; for ( const textEditor of editorDecorationCache . keys ( ) ) { editorDecorationCache . get ( textEditor ) ?. setDirty ( ) ; } } ; export const clearDecorationCache = ( document ? ) : void => { if ( document ) { documentDecorationCache . delete ( document ) ; for ( const textEditor of editorDecorationCache . keys ( ) ) { if ( document === textEditor . document ) { editorDecorationCache . get ( textEditor ) ?. setDirty ( ) ; } } } for ( const textEditor of editorDecorationCache . keys ( ) ) { if ( vscode . window . visibleTextEditors . indexOf ( textEditor ) < 0 ) { editorDecorationCache . get ( textEditor ) ?. dispose ( ) ; editorDecorationCache . delete ( textEditor ) ; } } } ; const getDocumentTextLength = ( document ) => document . offsetAt ( document . lineAt ( document . lineCount - 1 ) . range . end ) ; const lastUpdateStamp = new Map < vscode . TextEditor , number > ( ) ; export const delayUpdateDecoration = ( textEditor ) : void => { if ( undefined !== textEditor . viewColumn && "auto" === Config . mode . getKey ( textEditor . document ) ) { const updateStamp = vscel . profiler . getTicks ( ) ; lastUpdateStamp . set ( textEditor , updateStamp ) ; const textLength = getDocumentTextLength ( textEditor . document ) ; const logUnit = 16 * 1024 ; const logRate = Math . pow ( Math . max ( textLength , logUnit ) / logUnit , 1.0 / 2.0 ) ; const activeEditorDelay = false ? 30 : logRate * ( 100 + ( undefined === documentDecorationCache . get ( textEditor . document ) ? 100 : 0 ) ) ; const delay = vscode . window . activeTextEditor === textEditor ? activeEditorDelay : ( ( 2 * activeEditorDelay ) + 500 ) * ( 1.0 + ( 0.2 * ( textEditor . viewColumn ?? 0 ) ) ) ; setTimeout ( ( ) => { if ( lastUpdateStamp . get ( textEditor ) === updateStamp ) { lastUpdateStamp . delete ( textEditor ) ; updateDecoration ( textEditor ) ; } } , delay * 3 + 3000 ) ; } } ; export const delayUpdateDecorationByDocument = ( document ) : void => { vscode . window . visibleTextEditors . filter ( i => i . document === document ) . forEach ( i => delayUpdateDecoration ( i ) ) ; } ; export const updateAllDecoration = ( ) => vscode . window . visibleTextEditors . forEach ( i => updateDecoration ( i ) ) ; export const onDidChangeWorkspaceFolders = onDidChangeConfiguration ; export const onDidChangeActiveTextEditor = ( ) : void => { clearDecorationCache ( ) ; activeTextEditor ( delayUpdateDecoration ) ; } ; export const onDidOpenTextDocument = ( document ) : void => delayUpdateDecorationByDocument ( document ) ; export const onDidCloseTextDocument = clearDecorationCache ; export const onDidChangeTextDocument = ( document ) : void => { clearDecorationCache ( document ) ; delayUpdateDecorationByDocument ( document ) ; } ; export let extensionContext ; export const toggleMute = ( textEditor ) => { const currentEditorDecorationCache = makeSureEditorDecorationCache ( textEditor ) ; currentEditorDecorationCache . isMuted = undefined === currentEditorDecorationCache . isMuted ? ! isMutedAll : ! currentEditorDecorationCache . isMuted ; updateDecoration ( textEditor ) ; } ; export const activate = async ( context ) => { extensionContext = context ; vscel . profiler . start ( ) ; context . subscriptions . push ( vscode . commands . registerCommand ( `bracketLens.toggleMute` , ( ) => activeTextEditor ( toggleMute ) ) , vscode . commands . registerCommand ( `bracketLens.toggleMuteAll` , ( ) => { isMutedAll = ! isMutedAll ; editorDecorationCache . forEach ( i => i . isMuted = undefined ) ; updateAllDecoration ( ) ; } ) , vscode . commands . registerCommand ( `bracketLens.updateBrackets` , ( ) => activeTextEditor ( updateDecoration ) ) , vscode . commands . registerCommand ( `bracketLens.reportProfile` , ( ) => { const outputChannel = getProfilerOutputChannel ( ) ; outputChannel . show ( ) ; if ( vscel . profiler . getIsProfiling ( ) ) { outputChannel . appendLine ( `${ locale . map ( "📊 Profile Report" ) } - ${ new Date ( ) }` ) ; const overall = vscel . profiler . getOverall ( ) ; const total = vscel . profiler . getReport ( ) . map ( i => i . ticks ) . reduce ( ( p , c ) => p + c ) ; outputChannel . appendLine ( locale . map ( "⚖ Overview" ) ) ; outputChannel . appendLine ( `- Overall: ${ overall . toLocaleString ( ) }ms ( ${ vscel . profiler . percentToDisplayString ( 1 ) } )` ) ; outputChannel . appendLine ( `- Busy: ${ total . toLocaleString ( ) }ms ( ${ vscel . profiler . percentToDisplayString ( total / overall ) } )` ) ; outputChannel . appendLine ( locale . map ( "🔬 Busy Details" ) ) ; outputChannel . appendLine ( `- Total: ${ total . toLocaleString ( ) }ms ( ${ vscel . profiler . percentToDisplayString ( 1 ) } )` ) ; vscel . profiler . getReport ( ) . forEach ( i => outputChannel . appendLine ( `- ${ i . name }: ${ i . ticks . toLocaleString ( ) }ms ( ${ vscel . profiler . percentToDisplayString ( i . ticks / total ) } )` ) ) ; outputChannel . appendLine ( "" ) ; } else { outputChannel . appendLine ( locale . map ( "🚫 Profile has not been started." ) ) ; } } ) , vscode . workspace . onDidChangeConfiguration ( async ( event ) => { if ( event . affectsConfiguration ( "bracketLens" ) ) { onDidChangeConfiguration ( ) ; } } ) , vscode . workspace . onDidChangeWorkspaceFolders ( ( ) => onDidChangeWorkspaceFolders ( ) ) , vscode . workspace . onDidChangeTextDocument ( event => onDidChangeTextDocument ( event . document ) ) , vscode . workspace . onDidOpenTextDocument ( ( document ) => onDidOpenTextDocument ( document ) ) , vscode . workspace . onDidCloseTextDocument ( ( document ) => onDidCloseTextDocument ( document ) ) , vscode . window . onDidChangeActiveTextEditor ( ( ) => onDidChangeActiveTextEditor ( ) ) ) ; vscode . window . visibleTextEditors . forEach ( i => delayUpdateDecoration ( i ) ) ; } ; export const deactivate = ( ) => { } ;