diff options
Diffstat (limited to 'src/markdown.cpp')
-rw-r--r-- | src/markdown.cpp | 179 |
1 files changed, 176 insertions, 3 deletions
diff --git a/src/markdown.cpp b/src/markdown.cpp index d63e149..67ceba2 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" @@ -59,6 +61,11 @@ (data[i]>='0' && data[i]<='9') || \ (((unsigned char)data[i])>=0x80)) // unicode characters +#define extraChar(i) \ + (data[i]=='-' || data[i]=='+' || data[i]=='!' || \ + data[i]=='?' || data[i]=='$' || data[i]=='@' || \ + data[i]=='&' || data[i]=='*' || data[i]=='%') + // is character at position i in data allowed before an emphasis section #define isOpenEmphChar(i) \ (data[i]=='\n' || data[i]==' ' || data[i]=='\'' || data[i]=='<' || \ @@ -81,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 }; @@ -592,8 +606,8 @@ static int processHtmlTag(GrowBuf &out,const char *data,int offset,int size) static int processEmphasis(GrowBuf &out,const char *data,int offset,int size) { if ((offset>0 && !isOpenEmphChar(-1)) || // invalid char before * or _ - (size>1 && data[0]!=data[1] && !(isIdChar(1) || data[1]=='[')) || // invalid char after * or _ - (size>2 && data[0]==data[1] && !(isIdChar(2) || data[2]=='['))) // invalid char after ** or __ + (size>1 && data[0]!=data[1] && !(isIdChar(1) || extraChar(1) || data[1]=='[')) || // invalid char after * or _ + (size>2 && data[0]==data[1] && !(isIdChar(2) || extraChar(2) || data[2]=='['))) // invalid char after ** or __ { return 0; } @@ -1578,6 +1592,7 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) i = findTableColumns(data,size,start,end,columns); +#ifdef USE_ORIGINAL_TABLES out.addStr("<table>"); // write table header, in range [start..end] @@ -1585,7 +1600,8 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) int headerStart = start; int headerEnd = end; - +#endif + // read cell alignments int ret = findTableColumns(data+i,size-i,start,end,cc); k=0; @@ -1626,6 +1642,8 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) // proceed to next line i+=ret; +#ifdef USE_ORIGINAL_TABLES + int m=headerStart; for (k=0;k<columns;k++) { @@ -1689,6 +1707,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; |