@@ -35,34 +35,41 @@ const BI = new Set([
3535] ) ;
3636const LIT = new Set ( [ 'True' , 'False' , 'None' ] ) ;
3737
38+ const WORD_CLS = [
39+ [ KW , 'tk-kw' ] ,
40+ [ LIT , 'tk-lit' ] ,
41+ [ BI , 'tk-bi' ] ,
42+ ] ;
43+
3844const TOKEN_RE = / ( # [ ^ \n ] * ) | ( (?: \b [ f F r R b B u U ] { 1 , 2 } ) ? (?: " " " [ \s \S ] * ?" " " | ' ' ' [ \s \S ] * ?' ' ' | " (?: \\ .| [ ^ " \\ \n ] ) * " | ' (?: \\ .| [ ^ ' \\ \n ] ) * ' ) ) | ( 0 [ x X ] [ \d a - f A - F _ ] + | 0 [ o O ] [ 0 - 7 _ ] + | 0 [ b B ] [ 0 1 _ ] + | \d [ \d _ ] * (?: \. [ \d _ ] * ) ? (?: [ e E ] [ + - ] ? \d + ) ? [ j J ] ? | \. \d [ \d _ ] * (?: [ e E ] [ + - ] ? \d + ) ? [ j J ] ? ) | ( [ A - Z a - z _ ] \w * ) / g;
3945
4046const esc = ( s ) => s . replace ( / [ & < > ] / g, ( c ) => ( { '&' : '&' , '<' : '<' , '>' : '>' } [ c ] ) ) ;
41-
42- const highlight = ( src ) => {
43- const escaped = esc ( src ) ;
44- return escaped . replace ( TOKEN_RE , ( m , com , str , num , word , offset , fullStr ) => {
45- if ( com ) return `<span class="tk-com">${ com } </span>` ;
46- if ( str ) return `<span class="tk-str">${ str } </span>` ;
47- if ( num ) return `<span class="tk-num">${ num } </span>` ;
48- if ( word ) {
49- const isEntity = fullStr [ offset - 1 ] === '&' && fullStr [ offset + word . length ] === ';' ;
50- if ( isEntity ) return word ;
51-
52- if ( KW . has ( word ) ) return `<span class="tk-kw">${ word } </span>` ;
53- if ( LIT . has ( word ) ) return `<span class="tk-lit">${ word } </span>` ;
54- if ( BI . has ( word ) ) return `<span class="tk-bi">${ word } </span>` ;
55-
56- const isFunction = / ^ \s * \( / . test ( fullStr . slice ( offset + word . length ) ) ;
57- if ( isFunction ) {
58- return `<span class="tk-func">${ word } </span>` ;
59- } else {
60- return `<span class="tk-var">${ word } </span>` ;
61- }
47+ const span = ( cls , s ) => `<span class="${ cls } ">${ s } </span>` ;
48+
49+ const tokenize = ( m , com , str , num , word , offset , fullStr ) => {
50+ if ( com ) return span ( 'tk-com' , com ) ;
51+ if ( str ) {
52+ if ( / ^ [ f F r R b B u U ] * [ f F ] / i. test ( str ) ) {
53+ const body = str . replace ( / \{ \{ | \} \} | \{ ( [ ^ { } ] * ) \} / g, ( m , expr ) =>
54+ expr != null
55+ ? `{${ expr . replace ( new RegExp ( TOKEN_RE . source , TOKEN_RE . flags ) , tokenize ) } }`
56+ : m
57+ ) ;
58+ return span ( 'tk-str' , body ) ;
6259 }
63- return m ;
64- } ) ;
60+ return span ( 'tk-str' , str ) ;
61+ }
62+ if ( num ) return span ( 'tk-num' , num ) ;
63+ if ( word ) {
64+ if ( fullStr [ offset - 1 ] === '&' && fullStr [ offset + word . length ] === ';' ) return word ;
65+ for ( const [ set , cls ] of WORD_CLS ) if ( set . has ( word ) ) return span ( cls , word ) ;
66+ return span ( / ^ \s * \( / . test ( fullStr . slice ( offset + word . length ) ) ? 'tk-func' : 'tk-var' , word ) ;
67+ }
68+ return m ;
6569} ;
70+
71+ const highlight = ( src ) => esc ( src ) . replace ( TOKEN_RE , tokenize ) ;
72+
6673const jar = CodeJar ( ed , ( editor ) => {
6774 editor . innerHTML = highlight ( editor . textContent ) ;
6875} , {
@@ -125,7 +132,7 @@ const runCode = async () => {
125132const sync = ( ) => {
126133 const text = jar . toString ( ) . replace ( / \n $ / , '' ) ;
127134 const n = Math . max ( 1 , Math . min ( text . split ( '\n' ) . length , MAX_LINES ) ) ;
128- ln . textContent = Array . from ( { length : n } , ( _ , i ) => String ( i + 1 ) . padStart ( 2 , '0 ' ) ) . join ( '\n' ) ;
135+ ln . textContent = Array . from ( { length : n } , ( _ , i ) => String ( i + 1 ) . padStart ( 2 , '00 ' ) ) . join ( '\n' ) ;
129136 ln . scrollTop = ed . scrollTop ;
130137} ;
131138
0 commit comments