diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config.xml | 10 | ||||
-rwxr-xr-x | src/configgen.py | 2 | ||||
-rw-r--r-- | src/formula.cpp | 14 | ||||
-rw-r--r-- | src/htmlgen.cpp | 185 | ||||
-rw-r--r-- | src/latexgen.cpp | 10 |
5 files changed, 220 insertions, 1 deletions
diff --git a/src/config.xml b/src/config.xml index 7dc95b4..f40744d 100644 --- a/src/config.xml +++ b/src/config.xml @@ -2379,6 +2379,16 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. ]]> </docs> </option> + <option type='string' id='FORMULA_MACROFILE' format='file' defval=''> + <docs> +<![CDATA[ + The \c FORMULA_MACROFILE can contain \f$\mbox{\LaTeX}\f$ `\newcommand` and + `\renewcommand` commands to create new \f$\mbox{\LaTeX}\f$ commands to be used + in formulas as building blocks. + See the section \ref formulas for details. +]]> + </docs> + </option> <option type='bool' id='USE_MATHJAX' defval='0' depends='GENERATE_HTML'> <docs> <![CDATA[ diff --git a/src/configgen.py b/src/configgen.py index dbba264..6720116 100755 --- a/src/configgen.py +++ b/src/configgen.py @@ -21,6 +21,7 @@ from xml.dom import minidom, Node def transformDocs(doc): # join lines, unless it is an empty line # remove doxygen layout constructs + # Note: also look at expert.cpp of doxywizard for doxywizard parts doc = doc.strip() doc = doc.replace("\n", " ") doc = doc.replace("\r", " ") @@ -57,6 +58,7 @@ def transformDocs(doc): doc) doc = re.sub('\\\\ref +external', '"Linking to external documentation"', doc) + doc = re.sub('\\\\ref +formulas', '"Including formulas"', doc) # fallback for not handled doc = re.sub('\\\\ref', '', doc) #<a href="address">description</a> -> description (see: address) diff --git a/src/formula.cpp b/src/formula.cpp index 77085f8..63323db 100644 --- a/src/formula.cpp +++ b/src/formula.cpp @@ -56,6 +56,15 @@ void FormulaList::generateBitmaps(const char *path) term("Output dir %s does not exist!\n",path); } QCString oldDir = QDir::currentDirPath().utf8(); + QCString macroFile = Config_getString(FORMULA_MACROFILE); + QCString stripMacroFile; + if (!macroFile.isEmpty()) + { + QFileInfo fi(macroFile); + macroFile=fi.absFilePath().utf8(); + stripMacroFile = fi.fileName().data(); + } + // go to the html output directory (i.e. path) QDir::setCurrent(d.absPath()); QDir thisDir; @@ -77,6 +86,11 @@ void FormulaList::generateBitmaps(const char *path) t << "\\usepackage[utf8]{inputenc}" << endl; // looks like some older distributions with newunicode package 1.1 need this option. writeExtraLatexPackages(t); writeLatexSpecialFormulaChars(t); + if (!macroFile.isEmpty()) + { + copyFile(macroFile,stripMacroFile); + t << "\\input{" << stripMacroFile << "}" << endl; + } t << "\\pagestyle{empty}" << endl; t << "\\begin{document}" << endl; int page=0; 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); diff --git a/src/latexgen.cpp b/src/latexgen.cpp index 7d54f7a..5c2beae 100644 --- a/src/latexgen.cpp +++ b/src/latexgen.cpp @@ -691,6 +691,16 @@ static void writeDefaultHeaderPart1(FTextStream &t) writeExtraLatexPackages(t); writeLatexSpecialFormulaChars(t); + QCString macroFile = Config_getString(FORMULA_MACROFILE); + if (!macroFile.isEmpty()) + { + QCString dir=Config_getString(LATEX_OUTPUT); + QFileInfo fi(macroFile); + macroFile=fi.absFilePath().utf8(); + QCString stripMacroFile = fi.fileName().data(); + copyFile(macroFile,dir + "/" + stripMacroFile); + t << "\\input{" << stripMacroFile << "}" << endl; + } // Hyperlinks bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); |