summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/doxygen_manual.css80
-rw-r--r--doc/markdown.doc34
-rw-r--r--src/markdown.cpp181
-rw-r--r--templates/html/doxygen.css79
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 22e0d50..dee0045 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"
@@ -86,6 +88,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 };
@@ -1583,14 +1592,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;
@@ -1631,6 +1632,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++)
{
@@ -1694,6 +1704,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 */