@@ -16,6 +16,7 @@ class MicronParser {
1616 this . DEFAULT_FG_DARK = "ddd" ;
1717 this . DEFAULT_FG_LIGHT = "222" ;
1818 this . DEFAULT_BG = "default" ;
19+ this . MAX_TABLE_WIDTH = 100 ;
1920
2021 if ( this . enableForceMonospace ) {
2122 this . injectMonospaceStyles ( ) ;
@@ -142,7 +143,11 @@ class MicronParser {
142143 align : "left" ,
143144 default_fg : defaultFg ,
144145 default_bg : defaultBg ,
145- radio_groups : { }
146+ radio_groups : { } ,
147+ table_mode : false ,
148+ table_buffer : [ ] ,
149+ table_align : null ,
150+ table_maxwidth : this . MAX_TABLE_WIDTH
146151 } ;
147152
148153 const lines = markup . split ( "\n" ) ;
@@ -205,7 +210,11 @@ class MicronParser {
205210 align : "left" ,
206211 default_fg : defaultFg ,
207212 default_bg : defaultBg ,
208- radio_groups : { }
213+ radio_groups : { } ,
214+ table_mode : false ,
215+ table_buffer : [ ] ,
216+ table_align : null ,
217+ table_maxwidth : this . MAX_TABLE_WIDTH
209218 } ;
210219
211220 // create container div for page-level colors
@@ -245,6 +254,39 @@ class MicronParser {
245254 return [ ] ;
246255 }
247256
257+ if ( line . startsWith ( "`t" ) ) {
258+ let rest = line . slice ( 2 ) ;
259+ let align = null ;
260+ if ( rest . length > 0 && ( rest [ 0 ] === 'l' || rest [ 0 ] === 'c' || rest [ 0 ] === 'r' ) ) {
261+ align = rest [ 0 ] ;
262+ rest = rest . slice ( 1 ) ;
263+ }
264+ let maxWidth = null ;
265+ if ( rest . length > 0 ) {
266+ const w = parseInt ( rest , 10 ) ;
267+ if ( ! isNaN ( w ) ) maxWidth = w ;
268+ }
269+ if ( state . table_mode ) {
270+ const widgets = this . renderTable ( state . table_buffer , state ) ;
271+ state . table_mode = false ;
272+ state . table_buffer = [ ] ;
273+ state . table_align = null ;
274+ state . table_maxwidth = this . MAX_TABLE_WIDTH ;
275+ return widgets || [ ] ;
276+ } else {
277+ state . table_mode = true ;
278+ state . table_buffer = [ ] ;
279+ state . table_align = align ;
280+ state . table_maxwidth = maxWidth ;
281+ return [ ] ;
282+ }
283+ }
284+
285+ if ( state . table_mode ) {
286+ state . table_buffer . push ( line ) ;
287+ return [ ] ;
288+ }
289+
248290 let preEscape = false ;
249291
250292 if ( ! state . literal ) {
@@ -1299,6 +1341,114 @@ applyStyleToElement(el, style, defaultBg = "default") {
12991341 return cleanup ;
13001342 }
13011343
1344+ renderTable ( lines , state ) {
1345+ if ( lines . length < 2 ) return null ;
1346+
1347+ const headerCells = this . _parseTableRow ( lines [ 0 ] ) ;
1348+ const alignments = this . _parseTableAlignments ( lines [ 1 ] ) ;
1349+ while ( alignments . length < headerCells . length ) alignments . push ( 'left' ) ;
1350+
1351+ const dataRows = [ ] ;
1352+ for ( let i = 2 ; i < lines . length ; i ++ ) {
1353+ let cells = this . _parseTableRow ( lines [ i ] ) ;
1354+ while ( cells . length < headerCells . length ) cells . push ( "" ) ;
1355+ cells = cells . slice ( 0 , headerCells . length ) ;
1356+ dataRows . push ( cells ) ;
1357+ }
1358+
1359+ const borderColor = this . colorToCss ( state . fg_color ) || "currentColor" ;
1360+ const cellBorder = "1px solid " + borderColor ;
1361+ const cellPadding = "0.2em 0.5em" ;
1362+
1363+ const table = document . createElement ( "table" ) ;
1364+ table . style . borderCollapse = "collapse" ;
1365+ table . style . display = "inline-table" ;
1366+ if ( state . table_maxwidth ) {
1367+ table . style . maxWidth = ( state . table_maxwidth * 0.6 ) + "em" ;
1368+ }
1369+
1370+ const thead = document . createElement ( "thead" ) ;
1371+ const headerRow = document . createElement ( "tr" ) ;
1372+ for ( let i = 0 ; i < headerCells . length ; i ++ ) {
1373+ const th = document . createElement ( "th" ) ;
1374+ th . style . border = cellBorder ;
1375+ th . style . padding = cellPadding ;
1376+ th . style . textAlign = alignments [ i ] || 'left' ;
1377+ this . _renderTableCell ( th , headerCells [ i ] , state ) ;
1378+ headerRow . appendChild ( th ) ;
1379+ }
1380+ thead . appendChild ( headerRow ) ;
1381+ table . appendChild ( thead ) ;
1382+
1383+ const tbody = document . createElement ( "tbody" ) ;
1384+ for ( const row of dataRows ) {
1385+ const tr = document . createElement ( "tr" ) ;
1386+ for ( let i = 0 ; i < row . length ; i ++ ) {
1387+ const td = document . createElement ( "td" ) ;
1388+ td . style . border = cellBorder ;
1389+ td . style . padding = cellPadding ;
1390+ td . style . textAlign = alignments [ i ] || 'left' ;
1391+ this . _renderTableCell ( td , row [ i ] , state ) ;
1392+ tr . appendChild ( td ) ;
1393+ }
1394+ tbody . appendChild ( tr ) ;
1395+ }
1396+ table . appendChild ( tbody ) ;
1397+
1398+ const wrapper = document . createElement ( "div" ) ;
1399+ this . applySectionIndent ( wrapper , state ) ;
1400+ if ( state . table_align === 'c' ) wrapper . style . textAlign = "center" ;
1401+ else if ( state . table_align === 'r' ) wrapper . style . textAlign = "right" ;
1402+ else if ( state . table_align === 'l' ) wrapper . style . textAlign = "left" ;
1403+ wrapper . appendChild ( table ) ;
1404+
1405+ return [ wrapper ] ;
1406+ }
1407+
1408+ _renderTableCell ( el , text , state ) {
1409+ const snap = {
1410+ fg_color : state . fg_color ,
1411+ bg_color : state . bg_color ,
1412+ align : state . align ,
1413+ formatting : { ...state . formatting }
1414+ } ;
1415+ const parts = this . makeOutput ( state , text ) ;
1416+ if ( parts && parts . length > 0 ) {
1417+ this . appendOutput ( el , parts , state ) ;
1418+ }
1419+ state . fg_color = snap . fg_color ;
1420+ state . bg_color = snap . bg_color ;
1421+ state . align = snap . align ;
1422+ state . formatting = snap . formatting ;
1423+ }
1424+
1425+ _parseTableRow ( line ) {
1426+ line = line . trim ( ) ;
1427+ if ( line . startsWith ( '|' ) ) line = line . slice ( 1 ) ;
1428+ if ( line . endsWith ( '|' ) ) line = line . slice ( 0 , - 1 ) ;
1429+ const cells = [ ] ;
1430+ let current = "" ;
1431+ let escaped = false ;
1432+ for ( const ch of line ) {
1433+ if ( escaped ) { current += ch ; escaped = false ; }
1434+ else if ( ch === '\\' ) escaped = true ;
1435+ else if ( ch === '|' ) { cells . push ( current . trim ( ) ) ; current = "" ; }
1436+ else current += ch ;
1437+ }
1438+ cells . push ( current . trim ( ) ) ;
1439+ return cells ;
1440+ }
1441+
1442+ _parseTableAlignments ( line ) {
1443+ const cells = this . _parseTableRow ( line ) ;
1444+ return cells . map ( c => {
1445+ c = c . trim ( ) ;
1446+ if ( c . startsWith ( ':' ) && c . endsWith ( ':' ) ) return 'center' ;
1447+ if ( c . endsWith ( ':' ) ) return 'right' ;
1448+ return 'left' ;
1449+ } ) ;
1450+ }
1451+
13021452 splitAtSpaces ( line ) {
13031453 let out = "" ;
13041454 const wordArr = line . split ( / (?< = ) / g) ;
0 commit comments