summaryrefslogtreecommitdiffstats
path: root/src/htmlgen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/htmlgen.cpp')
-rw-r--r--src/htmlgen.cpp185
1 files changed, 184 insertions, 1 deletions
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index 52ffecc..41f0500 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -49,6 +49,7 @@
#include "bufstr.h"
#include "resourcemgr.h"
#include "tooltip.h"
+#include "growbuf.h"
//#define DBG_HTML(x) x;
#define DBG_HTML(x)
@@ -56,6 +57,7 @@
static QCString g_header;
static QCString g_footer;
static QCString g_mathjax_code;
+static QCString g_latex_macro;
static bool DoxyCodeLineOpen = FALSE;
@@ -112,6 +114,174 @@ static void writeServerSearchBox(FTextStream &t,const char *relPath,bool highlig
}
//------------------------------------------------------------------------
+/// Convert a set of LaTeX `\(re)newcommand` to a form readable by MathJax
+/// LaTeX syntax:
+/// \newcommand{\cmd}{replacement}
+/// or
+/// \renewcommand{\cmd}{replacement}
+/// MathJax syntax:
+/// cmd: "{replacement}"
+///
+/// LaTeX syntax:
+/// \newcommand{\cmd}[nr]{replacement}
+/// or
+/// \renewcommand{\cmd}[nr]{replacement}
+/// MathJax syntax:
+/// cmd: ["{replacement}",nr]
+static QCString getConvertLatexMacro()
+{
+ QCString macrofile = Config_getString(FORMULA_MACROFILE);
+ if (macrofile.isEmpty()) return "";
+ QCString s = fileToString(macrofile);
+ macrofile = QFileInfo(macrofile).absFilePath().utf8();
+ int size = s.length();
+ GrowBuf out(size);
+ const char *data = s.data();
+ int line = 1;
+ int cnt = 0;
+ int i = 0;
+ QCString nr;
+ while (i < size)
+ {
+ nr = "";
+ // skip initial white space, but count lines
+ while (i < size && (data[i] == ' ' || data[i] == '\t' || data[i] == '\n'))
+ {
+ if (data[i] == '\n') line++;
+ i++;
+ }
+ if (i >= size) break;
+ // check for \newcommand or \renewcommand
+ if (data[i] != '\\')
+ {
+ warn(macrofile,line, "file contains non valid code, expected '\\' got '%c'\n",data[i]);
+ return "";
+ }
+ i++;
+ if (!qstrncmp(data + i, "newcommand", strlen("newcommand"))) i += strlen("newcommand");
+ else if (!qstrncmp(data + i, "renewcommand", strlen("renewcommand"))) i += strlen("renewcommand");
+ else
+ {
+ warn(macrofile,line, "file contains non valid code, expected 'newcommand' or 'renewcommand'");
+ return "";
+ }
+ // handle {cmd}
+ if (data[i] != '{')
+ {
+ warn(macrofile,line, "file contains non valid code, expected '{' got '%c'\n",data[i]);
+ return "";
+ }
+ i++;
+ if (data[i] != '\\')
+ {
+ warn(macrofile,line, "file contains non valid code, expected '\\' got '%c'\n",data[i]);
+ return "";
+ }
+ i++;
+ // run till }, i.e. cmd
+ out.addStr(" ");
+ while (i < size && (data[i] != '}')) out.addChar(data[i++]);
+ if (i >= size)
+ {
+ warn(macrofile,line, "file contains non valid code, no closing '}' for command");
+ return "";
+ }
+ out.addChar(':');
+ out.addChar(' ');
+ i++;
+
+ if (data[i] == '[')
+ {
+ // handle [nr]
+ // run till ]
+ out.addChar('[');
+ i++;
+ while (i < size && (data[i] != ']')) nr += data[i++];
+ if (i >= size)
+ {
+ warn(macrofile,line, "file contains non valid code, no closing ']'");
+ return "";
+ }
+ i++;
+ }
+ else if (data[i] != '{')
+ {
+ warn(macrofile,line, "file contains non valid code, expected '[' or '{' got '%c'\n",data[i]);
+ return "";
+ }
+ // handle {replacement}
+ // retest as the '[' part might have advanced so we can have a new '{'
+ if (data[i] != '{')
+ {
+ warn(macrofile,line, "file contains non valid code, expected '{' got '%c'\n",data[i]);
+ return "";
+ }
+ out.addChar('"');
+ out.addChar('{');
+ i++;
+ // run till }
+ cnt = 1;
+ while (i < size && cnt)
+ {
+ switch(data[i])
+ {
+ case '\\':
+ out.addChar('\\'); // need to escape it for MathJax js code
+ out.addChar('\\');
+ i++;
+ if (data[i] == '\\') // we have an escaped backslash
+ {
+ out.addChar('\\');
+ out.addChar('\\');
+ i++;
+ }
+ else if (data[i] != '"') out.addChar(data[i++]); // double quote handled separately
+ break;
+ case '{':
+ cnt++;
+ out.addChar(data[i++]);
+ break;
+ case '}':
+ cnt--;
+ if (cnt) out.addChar(data[i]);
+ i++;
+ break;
+ case '"':
+ out.addChar('\\'); // need to escape it for MathJax js code
+ out.addChar(data[i++]);
+ break;
+ case '\n':
+ line++;
+ out.addChar(data[i++]);
+ break;
+ default:
+ out.addChar(data[i++]);
+ break;
+ }
+ }
+ if (i > size)
+ {
+ warn(macrofile,line, "file contains non valid code, no closing '}' for replacement");
+ return "";
+ }
+ out.addChar('}');
+ out.addChar('"');
+ if (!nr.isEmpty())
+ {
+ out.addChar(',');
+ out.addStr(nr);
+ }
+ if (!nr.isEmpty())
+ {
+ out.addChar(']');
+ }
+ out.addChar(',');
+ out.addChar('\n');
+ }
+ out.addChar(0);
+ return out.get();
+}
+//------------------------------------------------------------------------
/// Clear a text block \a s from \a begin to \a end markers
QCString clearBlock(const char *s,const char *begin,const char *end)
@@ -376,7 +546,18 @@ static QCString substituteHtmlKeywords(const QCString &s,
mathJaxJs += g_mathjax_code;
mathJaxJs += "\n";
}
- mathJaxJs += "</script>";
+ mathJaxJs += "</script>\n";
+ if (!g_latex_macro.isEmpty())
+ {
+ mathJaxJs += "<script type=\"text/x-mathjax-config\">\n"
+ " MathJax.Hub.Config({\n"
+ " TeX: { Macros: {\n";
+ mathJaxJs += g_latex_macro;
+ mathJaxJs += "\n"
+ " } }\n"
+ "});\n"
+ "</script>\n";
+ }
mathJaxJs += "<script type=\"text/javascript\" async=\"async\" src=\"" + path + "MathJax.js\"></script>\n";
}
@@ -758,6 +939,8 @@ void HtmlGenerator::init()
g_mathjax_code=fileToString(Config_getString(MATHJAX_CODEFILE));
//printf("g_mathjax_code='%s'\n",g_mathjax_code.data());
}
+ g_latex_macro=getConvertLatexMacro();
+ //printf("converted g_latex_macro='%s'\n",g_latex_macro.data());
}
createSubDirs(d);