33import * as vscode from 'vscode' ;
44
55import * as markdownitContainer from 'markdown-it-container' ;
6+ import * as S from 'string' ;
67
78function render ( tokens , idx , options , env , self ) : string {
89 tokens [ idx ] . attrJoin ( 'role' , 'alert' ) ;
@@ -11,6 +12,83 @@ function render( tokens, idx, options, env, self): string {
1112 return self . renderToken ( ...arguments ) ;
1213}
1314
15+ function parseFenceCodeParams ( lang ) {
16+ const attrMatch = lang . match ( / { ( .* ) } / )
17+ const params = { }
18+ if ( attrMatch && attrMatch . length >= 2 ) {
19+ const attrs = attrMatch [ 1 ]
20+ const paraMatch = attrs . match ( / ( [ # . ] ( \S + ?) \s ) | ( ( \S + ?) \s * = \s * ( " ( .+ ?) " | ' ( .+ ?) ' | \[ [ ^ \] ] * \] | \{ [ } ] * \} | ( \S + ) ) ) / g)
21+ paraMatch && paraMatch . forEach ( param => {
22+ param = param . trim ( )
23+ if ( param [ 0 ] === '#' ) {
24+ params [ 'id' ] = param . slice ( 1 )
25+ } else if ( param [ 0 ] === '.' ) {
26+ if ( params [ 'class' ] ) params [ 'class' ] = [ ]
27+ params [ 'class' ] = params [ 'class' ] . concat ( param . slice ( 1 ) )
28+ } else {
29+ const offset = param . indexOf ( '=' )
30+ const id = param . substring ( 0 , offset ) . trim ( ) . toLowerCase ( )
31+ let val = param . substring ( offset + 1 ) . trim ( )
32+ const valStart = val [ 0 ]
33+ const valEnd = val [ val . length - 1 ]
34+ if ( [ '"' , "'" ] . indexOf ( valStart ) !== - 1 && [ '"' , "'" ] . indexOf ( valEnd ) !== - 1 && valStart === valEnd ) {
35+ val = val . substring ( 1 , val . length - 1 )
36+ }
37+ if ( id === 'class' ) {
38+ if ( params [ 'class' ] ) params [ 'class' ] = [ ]
39+ params [ 'class' ] = params [ 'class' ] . concat ( val )
40+ } else {
41+ params [ id ] = val
42+ }
43+ }
44+ } )
45+ }
46+ return params
47+ }
48+
49+ function highlightRender ( code , lang ) {
50+ if ( ! lang || / n o ( - ? ) h i g h l i g h t | p l a i n | t e x t / . test ( lang ) ) { return }
51+ // support adding extra attributes for fence code block
52+ // ex: ```graphviz {engine="neato"}
53+ const params = parseFenceCodeParams ( lang ) as any ;
54+ lang = lang . split ( / \s + / g) [ 0 ]
55+ code = S ( code ) . escapeHTML ( ) . s
56+ if ( lang === 'sequence' ) {
57+ return `<span class="sequence-diagram raw">${ code } </span>`
58+ } else if ( lang === 'flow' ) {
59+ return `<span class="flow-chart raw">${ code } </span>`
60+ } else if ( lang === 'graphviz' ) {
61+ // support to specify layout engine of graphviz
62+ let dataAttrs = ''
63+ if ( params . hasOwnProperty ( 'engine' ) ) {
64+ dataAttrs = ' data-engine="' + params . engine + '"'
65+ }
66+ return `<span class="graphviz raw"${ dataAttrs } >${ code } </span>`
67+ } else if ( lang === 'mermaid' ) {
68+ return `<span class="mermaid raw">${ code } </span>`
69+ } else if ( lang === 'abc' ) {
70+ return `<span class="abc raw">${ code } </span>`
71+ }
72+ const result = {
73+ value : code
74+ }
75+ const showlinenumbers = / = $ | = \d + $ | = \+ $ / . test ( lang )
76+ if ( showlinenumbers ) {
77+ let startnumber = 1
78+ const matches = lang . match ( / = ( \d + ) $ / )
79+ if ( matches ) { startnumber = parseInt ( matches [ 1 ] ) }
80+ const lines = result . value . split ( '\n' )
81+ const linenumbers = [ ]
82+ for ( let i = 0 ; i < lines . length - 1 ; i ++ ) {
83+ linenumbers [ i ] = `<span data-linenumber='${ startnumber + i } '></span>`
84+ }
85+ const continuelinenumber = / = \+ $ / . test ( lang )
86+ const linegutter = `<div class='gutter linenumber${ continuelinenumber ? ' continue' : '' } '>${ linenumbers . join ( '\n' ) } </div>`
87+ result . value = `<div class='wrapper'>${ linegutter } <div class='code'>${ result . value } </div></div>`
88+ }
89+ return result . value
90+ }
91+
1492// this method is called when your extension is activated
1593// your extension is activated the very first time the command is executed
1694export function activate ( context : vscode . ExtensionContext ) {
@@ -41,6 +119,10 @@ export function activate(context: vscode.ExtensionContext) {
41119 md . use ( markdownitContainer , 'warning' , { render } ) ;
42120 md . use ( markdownitContainer , 'danger' , { render } ) ;
43121
122+ md . options . linkify = true ;
123+ md . options . typographer = true ;
124+ md . options . highlight = highlightRender ;
125+
44126 return md ;
45127 }
46128 } ;
0 commit comments