import { isFileTooLarge , isInFencedCodeBlock , isRmarkdownEditor , mathEnvCheck } from "../utils" ; import { ExtensionContext , Position , Range , TextEditor , window , workspace , TextEditorDecorationType } from "vscode" ; let decorTypes = { baseColor : window . createTextEditorDecorationType ( { dark : { color : "#EEFFFF" } , light : { color : "000000" } , } ) , gray : window . createTextEditorDecorationType ( { rangeBehavior : 1 , dark : { color : "#636363" } , light : { color : "#CCC" } , } ) , lightBlue : window . createTextEditorDecorationType ( { color : "#4080D0" , } ) , orange : window . createTextEditorDecorationType ( { color : "#D2B640" , } ) , strikethrough : window . createTextEditorDecorationType ( { rangeBehavior : 1 , textDecoration : "line-through" , } ) , codeSpan : window . createTextEditorDecorationType ( { rangeBehavior : 1 , border : "1px solid #454D51" , borderRadius : "3px" , } ) , } ; let decors = { } ; for ( const decorTypeName of Object . keys ( decorTypes ) ) { decors [ decorTypeName ] = [ ] ; } type RegexDecorTypeMapping = { [ reText ] : string [ ] ; } ; let regexDecorTypeMapping = { "(~~.+?~~)" : [ "strikethrough" ] , "(?<!`)(`+)(?!`)(.*?)(?<!`)(\\1)(?!`)" : [ "codeSpan" ] , } ; let regexDecorTypeMappingPlainTheme = { "(^|[^!])(\\[)([^\\]\\n]*(?!\\].*\\[)[^\\[\\n]*)(\\]\\(.+?\\))" : [ "" , "gray" , "lightBlue" , "gray" ] , "(\\!\\[)([^\\]\\n]*(?!\\].*\\[)[^\\[\\n]*)(\\]\\(.+?\\))" : [ "gray" , "orange" , "gray" ] , "(?<!`)(`+)(?!`)(.*?)(?<!`)(\\1)(?!`)" : [ "gray" , "baseColor" , "gray" ] , "(\\*)([^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s].*?[^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s])(\\*)" : [ "gray" , "baseColor" , "gray" ] , "(_)([^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s].*?[^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s])(_)" : [ "gray" , "baseColor" , "gray" ] , "(\\*\\*)([^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s].*?[^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s])(\\*\\*)" : [ "gray" , "baseColor" , "gray" ] , } ; export function activate ( context ) { window . onDidChangeActiveTextEditor ( updateDecorations , null , context . subscriptions ) ; workspace . onDidChangeTextDocument ( ( event ) => { let editor = window . activeTextEditor ; if ( editor !== undefined && event . document === editor . document ) { triggerUpdateDecorations ( editor ) ; } } , null , context . subscriptions ) ; var timeout = null ; function triggerUpdateDecorations ( editor ) { if ( timeout ) { clearTimeout ( timeout ) ; } timeout = setTimeout ( ( ) => updateDecorations ( editor ) , 200 ) ; } let editor = window . activeTextEditor ; if ( editor ) { updateDecorations ( editor ) ; } } function updateDecorations ( editor ? ) { if ( editor === undefined ) { editor = window . activeTextEditor ! ; } const doc = editor . document ; for ( const decorTypeName of Object . keys ( decorTypes ) ) { decors [ decorTypeName ] = [ ] ; } let appliedMappings = { ... regexDecorTypeMappingPlainTheme , ... regexDecorTypeMapping } ; doc . getText ( ) . split ( /\r?\n/g ) . forEach ( ( lineText , lineNum ) => { let noDecorRanges = [ ] ; for ( const reText of Object . keys ( appliedMappings ) ) { const decorTypeNames = appliedMappings [ reText ] ; const regex = new RegExp ( reText , "g" ) ; let match ; while ( ( match = regex . exec ( lineText ) ) !== null ) { let startIndex = match . index ; if ( noDecorRanges . some ( ( r ) => ( startIndex > r [ 0 ] && startIndex < r [ 1 ] ) || ( startIndex + match ! [ 0 ] . length > r [ 0 ] && startIndex + match ! [ 0 ] . length < r [ 1 ] ) ) ) { continue ; } for ( let i = 0 ; i < decorTypeNames . length ; i ++ ) { const decorTypeName = decorTypeNames [ i ] ; const caughtGroup = decorTypeName === "codeSpan" ? match [ 0 ] : match [ i + 1 ] ; if ( decorTypeName === "gray" && caughtGroup . length > 2 ) { noDecorRanges . push ( [ startIndex , startIndex + caughtGroup . length ] ) ; } const range = new Range ( lineNum , startIndex , lineNum , startIndex + caughtGroup . length ) ; startIndex += caughtGroup . length ; if ( decorTypeName . length === 0 ) { continue ; } decors [ decorTypeName ] . push ( range ) ; } } } } ) ; for ( const decorTypeName of Object . keys ( decors ) ) { editor . setDecorations ( decorTypes [ decorTypeName ] , decors [ decorTypeName ] ) ; } }