22
33import com .jtdev .website .model .BlogMetadata ;
44import com .jtdev .website .model .PortfolioMetadata ;
5+ import com .vladsch .flexmark .ext .tables .TablesExtension ;
56import com .vladsch .flexmark .html .HtmlRenderer ;
67import com .vladsch .flexmark .parser .Parser ;
78import com .vladsch .flexmark .util .ast .Node ;
@@ -72,6 +73,7 @@ public String getMarkdownContent(String path) throws IOException {
7273
7374 // Parse markdown and convert to ASCII-friendly format
7475 MutableDataSet options = new MutableDataSet ();
76+ options .set (Parser .EXTENSIONS , java .util .Arrays .asList (TablesExtension .create ()));
7577 Parser parser = Parser .builder (options ).build ();
7678 HtmlRenderer renderer = HtmlRenderer .builder (options ).build ();
7779
@@ -88,9 +90,12 @@ public String getMarkdownContent(String path) throws IOException {
8890 private String convertHtmlToAscii (String html , String dir ) {
8991 // First pass: Convert headers with dynamic borders
9092 html = convertDynamicHeaders (html );
91-
93+
9294 html = formatNestedLists (html );
9395
96+ // Convert tables before the general regex pass
97+ html = convertTablesToAscii (html );
98+
9499 // Convert HTML elements to ASCII formatting
95100 String text = html
96101 // Headers already converted above
@@ -124,17 +129,7 @@ private String convertHtmlToAscii(String html, String dir) {
124129
125130 // Bold and italic
126131 .replaceAll ("<strong[^>]*>([^<]*)</strong>" , "**$1**" )
127- .replaceAll ("<em[^>]*>([^<]*)</em>" , "*$1*" )
128-
129- // Tables (simplified ASCII representation)
130- .replaceAll ("<table[^>]*>" , "\n ┌" )
131- .replaceAll ("</table>" , "┘\n " )
132- .replaceAll ("<tr[^>]*>" , "" )
133- .replaceAll ("</tr>" , "\n ├" )
134- .replaceAll ("<th[^>]*>" , "─ " )
135- .replaceAll ("</th>" , " ─" )
136- .replaceAll ("<td[^>]*>" , "│ " )
137- .replaceAll ("</td>" , " │" );
132+ .replaceAll ("<em[^>]*>([^<]*)</em>" , "*$1*" );
138133
139134 // Handle images with ASCII art
140135 Pattern imgPattern = Pattern .compile ("<img[^>]*src=\" ([^\" ]*)\" [^>]*>" );
@@ -150,8 +145,8 @@ private String convertHtmlToAscii(String html, String dir) {
150145
151146 // Handle images without src
152147 text = text .replaceAll ("<img[^>]*>" , "[Image]" );
153- text
154148
149+ text = text
155150 // Remove any remaining HTML tags
156151 .replaceAll ("<[^>]+>" , "" )
157152
@@ -162,8 +157,7 @@ private String convertHtmlToAscii(String html, String dir) {
162157 .replaceAll ("\\ n{3,}" , "\n \n " )
163158 .trim ();
164159
165- // The formatting is already handled in the regex replacements above
166- return text .trim ();
160+ return text ;
167161 }
168162
169163 private String formatNestedLists (String html ) {
@@ -250,6 +244,90 @@ int nextIndex() {
250244 }
251245 }
252246
247+ private String convertTablesToAscii (String html ) {
248+ Pattern tablePattern = Pattern .compile ("<table[^>]*>(.*?)</table>" , Pattern .DOTALL | Pattern .CASE_INSENSITIVE );
249+ Matcher tableMatcher = tablePattern .matcher (html );
250+ StringBuffer sb = new StringBuffer ();
251+ while (tableMatcher .find ()) {
252+ String asciiTable = renderTableAsAscii (tableMatcher .group (1 ));
253+ tableMatcher .appendReplacement (sb , Matcher .quoteReplacement (asciiTable ));
254+ }
255+ tableMatcher .appendTail (sb );
256+ return sb .toString ();
257+ }
258+
259+ private String renderTableAsAscii (String tableHtml ) {
260+ List <List <String >> rows = new ArrayList <>();
261+
262+ Pattern rowPattern = Pattern .compile ("<tr[^>]*>(.*?)</tr>" , Pattern .DOTALL | Pattern .CASE_INSENSITIVE );
263+ Matcher rowMatcher = rowPattern .matcher (tableHtml );
264+ while (rowMatcher .find ()) {
265+ List <String > cells = new ArrayList <>();
266+ Pattern cellPattern = Pattern .compile ("<t[hd][^>]*>(.*?)</t[hd]>" , Pattern .DOTALL | Pattern .CASE_INSENSITIVE );
267+ Matcher cellMatcher = cellPattern .matcher (rowMatcher .group (1 ));
268+ while (cellMatcher .find ()) {
269+ String cell = cellMatcher .group (1 )
270+ .replaceAll ("<[^>]+>" , "" )
271+ .replaceAll ("&" , "&" ).replaceAll ("<" , "<" )
272+ .replaceAll (">" , ">" ).replaceAll (""" , "\" " )
273+ .replaceAll ("'" , "'" ).replaceAll (" " , " " )
274+ .trim ();
275+ cells .add (cell );
276+ }
277+ if (!cells .isEmpty ()) rows .add (cells );
278+ }
279+
280+ if (rows .isEmpty ()) return "" ;
281+
282+ int numCols = rows .stream ().mapToInt (List ::size ).max ().orElse (0 );
283+ int [] colWidths = new int [numCols ];
284+ for (List <String > row : rows ) {
285+ for (int i = 0 ; i < row .size (); i ++) {
286+ colWidths [i ] = Math .max (colWidths [i ], row .get (i ).length ());
287+ }
288+ }
289+
290+ StringBuilder ascii = new StringBuilder ("\n " );
291+
292+ // Top border
293+ ascii .append ("┌" );
294+ for (int i = 0 ; i < numCols ; i ++) {
295+ ascii .append ("─" .repeat (colWidths [i ] + 2 ));
296+ ascii .append (i < numCols - 1 ? "┬" : "┐" );
297+ }
298+ ascii .append ("\n " );
299+
300+ for (int r = 0 ; r < rows .size (); r ++) {
301+ List <String > row = rows .get (r );
302+ ascii .append ("│" );
303+ for (int i = 0 ; i < numCols ; i ++) {
304+ String cell = i < row .size () ? row .get (i ) : "" ;
305+ ascii .append (" " ).append (cell ).append (" " .repeat (colWidths [i ] - cell .length () + 1 )).append ("│" );
306+ }
307+ ascii .append ("\n " );
308+
309+ if (r == 0 && rows .size () > 1 ) {
310+ // Header separator
311+ ascii .append ("├" );
312+ for (int i = 0 ; i < numCols ; i ++) {
313+ ascii .append ("─" .repeat (colWidths [i ] + 2 ));
314+ ascii .append (i < numCols - 1 ? "┼" : "┤" );
315+ }
316+ ascii .append ("\n " );
317+ } else if (r == rows .size () - 1 ) {
318+ // Bottom border
319+ ascii .append ("└" );
320+ for (int i = 0 ; i < numCols ; i ++) {
321+ ascii .append ("─" .repeat (colWidths [i ] + 2 ));
322+ ascii .append (i < numCols - 1 ? "┴" : "┘" );
323+ }
324+ ascii .append ("\n " );
325+ }
326+ }
327+
328+ return ascii .toString ();
329+ }
330+
253331 private String convertDynamicHeaders (String html ) {
254332 // Convert H1 headers with dynamic borders
255333 Pattern h1Pattern = Pattern .compile ("<h1[^>]*>(.*?)</h1>" , Pattern .DOTALL );
0 commit comments