diff options
-rw-r--r-- | doc/doxygen_manual.css | 80 | ||||
-rw-r--r-- | doc/markdown.doc | 34 | ||||
-rw-r--r-- | src/markdown.cpp | 181 | ||||
-rw-r--r-- | templates/html/doxygen.css | 79 |
4 files changed, 366 insertions, 8 deletions
diff --git a/doc/doxygen_manual.css b/doc/doxygen_manual.css index e7271b2..51cc8b0 100644 --- a/doc/doxygen_manual.css +++ b/doc/doxygen_manual.css @@ -1503,3 +1503,83 @@ tr.heading h2 { } } + +/* @group Markdown */ + +/* +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid ##37; + padding: 3px 7px 2px; +} + +table.markdownTableHead tr { +} + +table.markdownTableBodyLeft td, table.markdownTable th { + border: 1px solid ##37; + padding: 3px 7px 2px; +} + +th.markdownTableHeadLeft th.markdownTableHeadRight th.markdownTableHeadCenter th.markdownTableHeadNone { + background-color: ##47; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft { + text-align: left +} + +th.markdownTableHeadRight { + text-align: right +} + +th.markdownTableHeadCenter { + text-align: center +} +*/ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid ##37; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + + +/* @end */ diff --git a/doc/markdown.doc b/doc/markdown.doc index b525fe9..300d7fc 100644 --- a/doc/markdown.doc +++ b/doc/markdown.doc @@ -337,6 +337,40 @@ which will look as follows: | 10 | 10 | 10 | | 1000 | 1000 | 1000 | +Additionally, column and row spans are supported. Using a caret ("^") +in a cell indicates that the cell above should span rows. Sequences +of carets may be used for any number of row spans. For example: + + | Right | Center | Left | + | ----: | :----: | :---- | + | 10 | 10 | 10 | + | ^ | 1000 | 1000 | + +which will look as follows: + +| Right | Center | Left | +| ----: | :----: | :---- | +| 10 | 10 | 10 | +| ^ | 1000 | 1000 | + +Column spans are supported by means of directly adjacent vertical bars +("|"). Each additional vertical bar indicates an additional column to +be spanned. To put it another way, a single vertical bar indicates a +single column span, two vertical bars indicates a 2 columns span, and +so on. For example: + + | Right | Center | Left | + | ----: | :----: | :---- | + | 10 | 10 | 10 | + | 1000 ||| + +which will look as follows: + +| Right | Center | Left | +| ----: | :----: | :---- | +| 10 | 10 | 10 | +| 1000 ||| + For more complex tables in doxygen please have a look at: \ref tables \subsection md_fenced Fenced Code Blocks diff --git a/src/markdown.cpp b/src/markdown.cpp index d63e149..919fc6e 100644 --- a/src/markdown.cpp +++ b/src/markdown.cpp @@ -36,6 +36,8 @@ #include <qregexp.h> #include <qfileinfo.h> #include <qdict.h> +#include <qvector.h> +//#define USE_ORIGINAL_TABLES #include "markdown.h" #include "growbuf.h" @@ -81,6 +83,13 @@ struct LinkRef QCString title; }; +struct TableCell +{ + TableCell() : colSpan(false) {} + QCString cellText; + bool colSpan; +}; + typedef int (*action_t)(GrowBuf &out,const char *data,int offset,int size); enum Alignment { AlignNone, AlignLeft, AlignCenter, AlignRight }; @@ -1578,14 +1587,6 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) i = findTableColumns(data,size,start,end,columns); - out.addStr("<table>"); - - // write table header, in range [start..end] - out.addStr("<tr>"); - - int headerStart = start; - int headerEnd = end; - // read cell alignments int ret = findTableColumns(data+i,size-i,start,end,cc); k=0; @@ -1626,6 +1627,15 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) // proceed to next line i+=ret; +#ifdef USE_ORIGINAL_TABLES + out.addStr("<table>"); + + // write table header, in range [start..end] + out.addStr("<tr>"); + + int headerStart = start; + int headerEnd = end; + int m=headerStart; for (k=0;k<columns;k++) { @@ -1689,6 +1699,161 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) } out.addStr("</table> "); +#else + // Store the table cell information by row then column. This + // allows us to handle row spanning. + QVector<QVector<TableCell> > tableContents; + tableContents.setAutoDelete(TRUE); + + int headerStart = start; + int headerEnd = end; + + int m=headerStart; + QVector<TableCell> *headerContents = new QVector<TableCell>(columns); + headerContents->setAutoDelete(TRUE); + for (k=0;k<columns;k++) + { + headerContents->insert(k, new TableCell); + while (m<=headerEnd && (data[m]!='|' || (m>0 && data[m-1]=='\\'))) + { + headerContents->at(k)->cellText += data[m++]; + } + m++; + // do the column span test before stripping white space + // || is spanning columns, | | is not + headerContents->at(k)->colSpan = headerContents->at(k)->cellText.isEmpty(); + headerContents->at(k)->cellText = headerContents->at(k)->cellText.stripWhiteSpace(); + } + // qvector doesn't have an append like std::vector, so we gotta do + // extra work + tableContents.resize(1); + tableContents.insert(0, headerContents); + + // write table cells + int rowNum = 1; + while (i<size) + { + int ret = findTableColumns(data+i,size-i,start,end,cc); + if (cc!=columns) break; // end of table + + j=start+i; + k=0; + QVector<TableCell> *rowContents = new QVector<TableCell>(columns); + rowContents->setAutoDelete(TRUE); + rowContents->insert(k, new TableCell); + while (j<=end+i) + { + if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) + { + // do the column span test before stripping white space + // || is spanning columns, | | is not + rowContents->at(k)->colSpan = rowContents->at(k)->cellText.isEmpty(); + rowContents->at(k)->cellText = rowContents->at(k)->cellText.stripWhiteSpace(); + k++; + rowContents->insert(k, new TableCell); + } // if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) + else + { + rowContents->at(k)->cellText += data[j]; + } // else { if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) } + j++; + } // while (j<=end+i) + // do the column span test before stripping white space + // || is spanning columns, | | is not + rowContents->at(k)->colSpan = rowContents->at(k)->cellText.isEmpty(); + rowContents->at(k)->cellText = rowContents->at(k)->cellText.stripWhiteSpace(); + // qvector doesn't have an append like std::vector, so we gotta do + // extra work + tableContents.resize(tableContents.size()+1); + tableContents.insert(rowNum++, rowContents); + + // proceed to next line + i+=ret; + } + + + out.addStr("<table class=\"markdownTable\">\n"); + QCString cellTag("th"), cellClass("class=\"markdownTableHead"); + for (unsigned row = 0; row < tableContents.size(); row++) + { + out.addStr(" <tr class=\"markdownTable"); + if (row) + { + out.addStr("Body\""); + if (row % 2) + { + out.addStr(" class=\"markdownTableRowOdd\">\n"); + } + else + { + out.addStr(" class=\"markdownTableRowEven\">\n"); + } + } + else + { + out.addStr("Head\">\n"); + } + for (int c = 0; c < columns; c++) + { + // save the cell text for use after column span computation + QCString cellText(tableContents[row]->at(c)->cellText); + + // Row span handling. Spanning rows will contain a caret ('^'). + // If the current cell contains just a caret, this is part of an + // earlier row's span and the cell should not be added to the + // output. + if (tableContents[row]->at(c)->cellText == "^") + continue; + unsigned rowSpan = 1, spanRow = row+1; + while ((spanRow < tableContents.size()) && + (tableContents[spanRow]->at(c)->cellText == "^")) + { + spanRow++; + rowSpan++; + } + + out.addStr(" <" + cellTag + " " + cellClass); + // use appropriate alignment style + switch (columnAlignment[c]) + { + case AlignLeft: out.addStr("Left\""); break; + case AlignRight: out.addStr("Right\""); break; + case AlignCenter: out.addStr("Center\""); break; + case AlignNone: out.addStr("None\""); break; + } + + if (rowSpan > 1) + { + QCString spanStr; + spanStr.setNum(rowSpan); + out.addStr(" rowspan=\"" + spanStr + "\""); + } + // Column span handling, assumes that column spans will have + // empty strings, which would indicate the sequence "||", used + // to signify spanning columns. + unsigned colSpan = 1; + while ((c < columns-1) && + tableContents[row]->at(c+1)->colSpan) + { + c++; + colSpan++; + } + if (colSpan > 1) + { + QCString spanStr; + spanStr.setNum(colSpan); + out.addStr(" colspan=\"" + spanStr + "\""); + } + // need at least one space on either side of the cell text in + // order for doxygen to do other formatting + out.addStr("> " + cellText + " </" + cellTag + ">\n"); + } + cellTag = "td"; + cellClass = "class=\"markdownTableBody"; + out.addStr(" </tr>\n"); + } + out.addStr("</table>\n"); +#endif delete[] columnAlignment; return i; diff --git a/templates/html/doxygen.css b/templates/html/doxygen.css index 6a6f1c8..db80bc8 100644 --- a/templates/html/doxygen.css +++ b/templates/html/doxygen.css @@ -1511,3 +1511,82 @@ tr.heading h2 { } } +/* @group Markdown */ + +/* +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid ##37; + padding: 3px 7px 2px; +} + +table.markdownTableHead tr { +} + +table.markdownTableBodyLeft td, table.markdownTable th { + border: 1px solid ##37; + padding: 3px 7px 2px; +} + +th.markdownTableHeadLeft th.markdownTableHeadRight th.markdownTableHeadCenter th.markdownTableHeadNone { + background-color: ##47; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft { + text-align: left +} + +th.markdownTableHeadRight { + text-align: right +} + +th.markdownTableHeadCenter { + text-align: center +} +*/ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid ##37; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + + +/* @end */ |