diff --git a/doc/utils/converters/lammpsdoc/eqImg2mathjaxInline.py b/doc/utils/converters/lammpsdoc/eqImg2mathjaxInline.py
new file mode 100644
index 0000000000..6db83da7fd
--- /dev/null
+++ b/doc/utils/converters/lammpsdoc/eqImg2mathjaxInline.py
@@ -0,0 +1,238 @@
+#! /usr/bin/env python3
+# LAMMPS Documentation Utilities
+#
+# Scan for duplicate anchor labels in documentation files
+#
+# Copyright (C) 2019 E. Anne Gunn
+# Based largely on doc_anchor_check.py by Richard Berger
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+import argparse
+import os
+import re
+import sys
+
+
+# We only want to replace image lines where image is
+# pulled from Eqs subfolder
+image_pattern = re.compile(r'.*image:: Eqs/(.*)\.jpg')
+tex_eq_pattern = re.compile(r'\$\$')
+latex_begin_eq_pattern = re.compile(r'\\begin{equation}')
+latex_end_eq_pattern = re.compile(r'\\end{equation}')
+latex_begin_eqArray_pattern = re.compile(r'\\begin{eqnarray\*}')
+latex_end_eqArray_pattern = re.compile(r'\\end{eqnarray\*}')
+
+imageMarker = ">>>image was here"
+image_marker_pattern = re.compile(r'>>>image was here')
+align_pattern = re.compile(r'.*:align: center')
+
+modifiedFileFolder = "src/modifiedRst/"
+# Since this is a proof of concept implementation,
+# skip any rst files that are known to cause problems
+skipFileList = ["pair_tersoff_zbl.rst"]
+
+runReport = {
+}
+
+
+def checkForEquationStart(texLine):
+ eqType = None
+ texMatch = tex_eq_pattern.match(texLine)
+ if texMatch:
+ eqType = "texMatch"
+ else:
+ eqMatch = latex_begin_eq_pattern.match(texLine)
+ if eqMatch:
+ eqType = "eqMatch"
+ else:
+ eqArrayMatch = latex_begin_eqArray_pattern.match(texLine)
+ if eqArrayMatch:
+ eqType = "eqArrayMatch"
+ return eqType
+
+
+def checkForEquationEnd(texLine, eqType):
+ endPattern = tex_eq_pattern
+ if eqType == "texMatch":
+ endPattern = tex_eq_pattern
+ elif eqType == "eqMatch":
+ endPattern = latex_end_eq_pattern
+ elif eqType == "eqArrayMatch":
+ endPattern = latex_end_eqArray_pattern
+ else:
+ print("***error: unexpected eqType %s, will look for tex delimiter" % eqType)
+
+ endMatch = endPattern.match(texLine)
+ endFound = endMatch is not None
+ if endFound:
+ print("found pattern end, line: %s" % texLine)
+ return endFound
+
+
+def startMathjax():
+ mathjaxLines = []
+ mathjaxLines.append(".. math::\n\n")
+ return mathjaxLines
+
+
+def endMathjax(mathjaxLines):
+ mathjaxLines.append("\n")
+ mathjaxLines.append("%s\n" % imageMarker)
+ return mathjaxLines
+
+
+def processFile(filename):
+ print("in processFile for filename: %s" % filename)
+ imageCount = 0
+
+ modifiedFileLines = []
+ doWriteModifiedFile = False
+ with open(filename, 'rt') as f:
+ for line_number, line in enumerate(f):
+ m = image_pattern.match(line)
+ if m:
+ fileroot = m.group(1)
+ print("fileroot: {0}".format(fileroot))
+ imageCount += 1
+ texFilename = "src/Eqs/{0}.tex".format(fileroot)
+ print("will try to open %s" % texFilename)
+ eqType = None
+ eqLines = []
+ try:
+ with open(texFilename, 'rt', encoding='utf-8') as t:
+ print("%s file opened ok" % texFilename)
+ eqLines = startMathjax()
+ try:
+ for dummy, texLine in enumerate(t):
+ #print(texLine)
+ if eqType == None:
+ eqType = checkForEquationStart(texLine)
+ if eqType != None:
+ print("equation type: {0}".format(eqType))
+ else:
+ endFound = checkForEquationEnd(texLine, eqType)
+ if endFound != True:
+ eqLines.append(texLine)
+ else:
+ eqType = None
+ eqLines = endMathjax(eqLines)
+ print("Equation lines will be:")
+ print("-----------------------------")
+ print(*eqLines, sep="\n")
+ print("-----------------------------")
+ except UnicodeDecodeError:
+ print("UnicodeDecodeError reading file file %s, image markup will be left in place" % texFilename)
+ break
+ except EnvironmentError:
+ error = "could not open source tex file {0}, line: {1}".format(texFilename, line)
+ print(error)
+ print("image markup will be left in place")
+ if filename not in runReport:
+ runReport[filename] = []
+ runReport[filename].append(error)
+ # put the image line we could not replace back into the output
+ eqLines.append(line)
+ if len(eqLines) > 0:
+ modifiedFileLines.extend(eqLines)
+ doWriteModifiedFile = True
+ eqLines = []
+ else:
+ # not an equation line, so simply queue it up for output as is
+ modifiedFileLines.append(line)
+ if doWriteModifiedFile:
+ #print(*modifiedFileLines, sep="\n")
+ print("modifiedFileLines has %d lines before align center cleanup" % len(modifiedFileLines))
+ # First, go through the file and pull out the lines where there is
+ # now an image file marker followed by an align center directive
+ deleteLines = []
+ for lineNumber, line in enumerate(modifiedFileLines):
+ m = image_marker_pattern.match(line)
+ if m:
+ print("found image marker in line %d" % lineNumber)
+ n = align_pattern.match(modifiedFileLines[lineNumber+1])
+ if n:
+ print("found align center")
+ deleteLines.append(lineNumber)
+ deleteLines.append(lineNumber+1)
+ #When deleting, always work from the back of the list to the front
+ for lineNumber in reversed(deleteLines):
+ print(lineNumber)
+ del modifiedFileLines[lineNumber]
+ print("modifiedFileLines has %d lines after align center cleanup" % len(modifiedFileLines))
+ # Now we can actually write out the new contents
+ try:
+ if not os.path.exists(modifiedFileFolder):
+ os.makedirs(modifiedFileFolder)
+ nameParts = filename.split("/")
+ filenamePos = len(nameParts) - 1
+ modFilePath = "{0}{1}".format(modifiedFileFolder, nameParts[filenamePos])
+ modRst = open(modFilePath, "w")
+ for rstLine in modifiedFileLines:
+ modRst.write(rstLine)
+ modRst.close()
+ except OSError:
+ print('Error: Creating directory. ' + modifiedFileFolder)
+ return imageCount
+
+
+def main():
+ fileCount = 0
+ totalImageCount = 0
+
+ parser = argparse.ArgumentParser(description='replace image markup in rst files with inline mathjax markup from .txt source of images')
+ parser.add_argument('files', metavar='file', nargs='+', help='one or more files to scan')
+ parsed_args = parser.parse_args()
+
+ # TODO: make originalRst folder and copy src/*.rst files into it
+
+ # Because we may decide to add files to the skip list between runs,
+ # if we have more than one file to process,
+ # remove the modified file folder so we don't end up with
+ # zombie modifications
+ if len(parsed_args.files) > 1:
+ for outputFile in os.listdir(modifiedFileFolder):
+ filePath = os.path.join(modifiedFileFolder, outputFile)
+ try:
+ if os.path.isfile(filePath):
+ os.unlink(filePath)
+ except Exception as e:
+ print(e)
+ sys.exit(1)
+
+ for filename in parsed_args.files:
+ doSkip = False
+ for skipName in skipFileList:
+ if filename.find(skipName) != -1:
+ print("skipping file: %s" % filename)
+ doSkip = True
+ runReport[filename] = ["skipped based on skipFileList"]
+ break
+ if not doSkip:
+ fileCount += 1
+ ic = processFile(filename)
+ totalImageCount += ic
+
+ print("============================================")
+ print("Processed %d rst files." % fileCount)
+ print("Found %d image lines." % totalImageCount)
+
+ for fileKey in runReport:
+ print("--------------------------------------------")
+ print("run report for %s:" % fileKey)
+ print(*runReport[fileKey], sep="\n")
+
+ print("============================================")
+
+if __name__ == "__main__":
+ main()
diff --git a/doc/utils/converters/lammpsdoc/rst_anchor_check.py b/doc/utils/converters/lammpsdoc/rst_anchor_check.py
new file mode 100644
index 0000000000..9c097e7d0e
--- /dev/null
+++ b/doc/utils/converters/lammpsdoc/rst_anchor_check.py
@@ -0,0 +1,64 @@
+#! /usr/bin/env python3
+# LAMMPS Documentation Utilities
+#
+# Scan for duplicate anchor labels in documentation files
+#
+# Copyright (C) 2017 Richard Berger
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+import re
+import sys
+import argparse
+
+def main():
+ parser = argparse.ArgumentParser(description='scan for duplicate anchor labels in documentation files')
+ parser.add_argument('files', metavar='file', nargs='+', help='one or more files to scan')
+ parsed_args = parser.parse_args()
+
+ anchor_pattern = re.compile(r'^\.\. _(.*):$')
+ anchors = {}
+
+ for filename in parsed_args.files:
+ #print("filename: %s" % filename)
+ with open(filename, 'rt') as f:
+ for line_number, line in enumerate(f):
+ m = anchor_pattern.match(line)
+ if m:
+ label = m.group(1)
+ #print("found label: %s" % label)
+ if label in anchors:
+ anchors[label].append((filename, line_number+1))
+ else:
+ anchors[label] = [(filename, line_number+1)]
+
+ print("found %d anchor labels" % len(anchors))
+
+ count = 0
+
+ for label in sorted(anchors.keys()):
+ if len(anchors[label]) > 1:
+ print(label)
+ count += 1
+ for filename, line_number in anchors[label]:
+ print(" - %s:%d" % (filename, line_number))
+
+
+ if count > 0:
+ print("Found %d anchor label errors." % count)
+ sys.exit(1)
+ else:
+ print("No anchor label errors.")
+
+if __name__ == "__main__":
+ main()
diff --git a/doc/utils/converters/setup.py b/doc/utils/converters/setup.py
index f4656a7f69..d85669bcc1 100644
--- a/doc/utils/converters/setup.py
+++ b/doc/utils/converters/setup.py
@@ -13,6 +13,6 @@ setup(name='LAMMPS Documentation Utilities',
entry_points = {
"console_scripts": ['txt2html = lammpsdoc.txt2html:main',
'txt2rst = lammpsdoc.txt2rst:main',
- 'doc_anchor_check = lammpsdoc.doc_anchor_check:main ']
+ 'rst_anchor_check = lammpsdoc.rst_anchor_check:main ']
},
)