summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDimitri van Heesch <doxygen@gmail.com>2019-12-25 09:04:23 (GMT)
committerGitHub <noreply@github.com>2019-12-25 09:04:23 (GMT)
commitff3fdb3ac14a1f90334ca6c40eac46c772b5af63 (patch)
tree9fc8728c52e91e673137b631ef2f8bd613dfe164 /src
parentfabc8146c8bdbdedcb2d2d8630a5eb60de3f5dc0 (diff)
parentfd3b60caa8bb99bec81b74d74f394c6043091c76 (diff)
downloadDoxygen-ff3fdb3ac14a1f90334ca6c40eac46c772b5af63.zip
Doxygen-ff3fdb3ac14a1f90334ca6c40eac46c772b5af63.tar.gz
Doxygen-ff3fdb3ac14a1f90334ca6c40eac46c772b5af63.tar.bz2
Merge pull request #7230 from albert-github/feature/bug_formula_macrofile
Create possibility to define LaTeX commands for formulas
Diffstat (limited to 'src')
-rw-r--r--src/config.xml10
-rwxr-xr-xsrc/configgen.py2
-rw-r--r--src/formula.cpp14
-rw-r--r--src/htmlgen.cpp185
-rw-r--r--src/latexgen.cpp10
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);