summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/hybrid-latex/python
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/hybrid-latex/python
Initial commit
Diffstat (limited to 'macros/latex/contrib/hybrid-latex/python')
-rwxr-xr-xmacros/latex/contrib/hybrid-latex/python/merge-tex.py115
-rwxr-xr-xmacros/latex/contrib/hybrid-latex/python/pypostproc.py239
-rwxr-xr-xmacros/latex/contrib/hybrid-latex/python/pypreproc.py414
3 files changed, 768 insertions, 0 deletions
diff --git a/macros/latex/contrib/hybrid-latex/python/merge-tex.py b/macros/latex/contrib/hybrid-latex/python/merge-tex.py
new file mode 100755
index 0000000000..de5fd157c2
--- /dev/null
+++ b/macros/latex/contrib/hybrid-latex/python/merge-tex.py
@@ -0,0 +1,115 @@
+#!/usr/local/bin/python3
+
+import re
+import sys
+import os.path
+
+max_recurse_depth = 10 # limit depth of nested \Input statements
+
+re_comment = re.compile (r"^\s*%")
+re_file_name = re.compile (r"^\s*\\Input\{([_a-zA-Z0-9./-]+)\}") # use \Input to avoid confusion with \input
+
+def make_str (num,digits):
+ return '{number:0{width}d}'.format(number=num,width=digits)
+
+def include_files (txt, file_name, recurse_depth):
+
+ def grep (this_line, regex, the_group):
+ result = regex.search (this_line)
+ if result:
+ found = True
+ group = result.group (the_group)
+ else:
+ found = False
+ group = "<none>"
+ return group, found
+
+ def not_comment (the_line):
+ return not re_comment.search (the_line)
+
+ def read_include_name (the_line):
+ file_name, found = grep (the_line,re_file_name,1)
+ return file_name, found
+
+ recurse_depth = recurse_depth + 1
+
+ if recurse_depth > max_recurse_depth:
+ print ("> merge-tex.py: Recursion limit for \\Input{...} reached (max = "+str(max_recurse_depth)+"), exit")
+ sys.exit(1)
+
+ with open (file_name,'r') as src:
+
+ for the_line in src:
+
+ if not_comment (the_line):
+ inc_file, found = read_include_name (the_line)
+ if found:
+ if not os.path.isfile (inc_file):
+ print ("> merge-tex.py: Include file " + inc_file + " not found, exit.\n")
+ sys.exit(1)
+ if markup:
+ txt.write (comment + " beg" + make_str(recurse_depth,2) + ": " + inc_file + "\n")
+ recurse_depth = include_files (txt, inc_file, recurse_depth)
+ txt.write (comment + " end" + make_str(recurse_depth,2) + ": " + inc_file + "\n")
+ else:
+ recurse_depth = include_files (txt, inc_file, recurse_depth)
+ else:
+ txt.write (the_line)
+ else:
+ txt.write (the_line)
+
+ recurse_depth = recurse_depth - 1
+
+ return recurse_depth
+
+# -----------------------------------------------------------------------------
+# the main code
+
+comment = "%%" # standard comment marker for LaTeX source
+
+import argparse
+
+parser = argparse.ArgumentParser(description="Merge a sequence of LaTeX files into a single LaTeX file")
+parser.add_argument("-i", dest="input", metavar="foo.tex", help="source file", required=True)
+parser.add_argument("-o", dest="output", metavar="bah.tex", help="output file", required=True)
+parser.add_argument("-S", dest="silent", default="False", action='store_true', help="suppress markup lines for each \\Input{foo.tex}", required=False)
+
+src_file_name = parser.parse_args().input
+out_file_name = parser.parse_args().output
+
+silent = parser.parse_args().silent
+
+if silent == "False":
+ markup = True
+else:
+ markup = False
+
+if src_file_name == out_file_name:
+ print ("> merge-tex.py: Indentical files names for input and output, exit.")
+ sys.exit (1)
+
+if not os.path.isfile (src_file_name):
+ print ("> merge-tex.py: Source file " + src_file_name + " not found, exit.")
+ sys.exit (1)
+
+with open (out_file_name,"w") as txt:
+
+ recurse_depth = 0
+
+ if markup:
+
+ txt.write (comment + " --------------------------------------------------------------\n")
+ txt.write (comment + " Do not edit this file, it was created by merge-tex.py using:\n")
+ txt.write (comment + " merge-tex.py -i " + src_file_name + " -o " + out_file_name + "\n")
+ txt.write (comment + " --------------------------------------------------------------\n")
+
+ txt.write (comment + " beg" + make_str(recurse_depth,2) + ": ./" + src_file_name + "\n")
+ recurse_depth = include_files (txt, "./" + src_file_name, recurse_depth)
+ txt.write (comment + " end" + make_str(recurse_depth,2) + ": ./" + src_file_name + "\n")
+
+ else:
+ recurse_depth = include_files (txt, "./" + src_file_name, recurse_depth)
+
+if not recurse_depth == 0:
+ print("> merge-tex.py: error during merger")
+ print("> recursion depth should be zero, actual value: "+str(recurse_depth))
diff --git a/macros/latex/contrib/hybrid-latex/python/pypostproc.py b/macros/latex/contrib/hybrid-latex/python/pypostproc.py
new file mode 100755
index 0000000000..11b4ae3382
--- /dev/null
+++ b/macros/latex/contrib/hybrid-latex/python/pypostproc.py
@@ -0,0 +1,239 @@
+#!/usr/local/bin/python3
+
+import re
+import sys
+import os.path
+
+import enum
+
+class Type (enum.Enum):
+ BegTag = 1
+ EndTag = 2
+ PlainText = 3
+ Unknown = 4
+
+def empty_line (this_line):
+ if len(this_line) == 0:
+ return True
+ else:
+ return re.search ("(^ *$)",this_line)
+
+def get_index (this_line):
+ result = re.search ("tag([0-9]+)",this_line)
+ if result:
+ return int(result.group (1))
+ else:
+ print ("> Error reading tag index on: " + this_line)
+ sys.exit (1)
+
+def get_text (this_line):
+ result = re.search ("tag([0-9]+)=(.*)",this_line)
+ if result:
+ return result.group (2)
+ else:
+ print ("> Error reading tag text on: " + this_line)
+ sys.exit (1)
+
+def has_tag (this_line):
+ return re.search (r"(tag[0-9]+=)",this_line)
+
+def is_beg_tag (this_line):
+ return re.search (r"(^beg_tag[0-9]+$)",this_line)
+
+def is_end_tag (this_line):
+ return re.search (r"(^end_tag[0-9]+$)",this_line)
+
+# -------------------------------------------------------------------------
+# stack operations
+
+stack = []
+stack_index = 0
+max_stack_index = 5
+for i in range (0,max_stack_index): # create an empty stack
+ stack.append(0) # using zero forces any non-tagged output to be stored in tag_output[0]
+
+def read_stack (index):
+ return stack [index]
+
+def push_stack (index, stack_index):
+ if stack_index < max_stack_index:
+ stack_index = stack_index + 1
+ stack [stack_index] = index
+ return stack_index
+ else:
+ print ("> Depth of nested pyBeg/pyEnd pairs exceeded, max = "+str(max_stack_index)+", exit\n")
+ sys.exit (1)
+
+def pop_stack (index, stack_index):
+ if stack_index > 0:
+ if index == read_stack (stack_index):
+ stack [stack_index] = 0
+ return stack_index - 1
+ else:
+ print ("> Error with pyBeg/pyEnd pairs for tag index: "+str(index)+", exit\n")
+ sys.exit (1)
+ else:
+ print ("> Error with pyBeg/pyEnd pairs, check for missing pyBeg or pyEnd, exit\n")
+ sys.exit (1)
+
+def parse (this_line):
+ if is_beg_tag (this_line):
+ return Type.BegTag
+ elif is_end_tag (this_line):
+ return Type.EndTag
+ else:
+ return Type.PlainText
+
+def append_text (this_line, index):
+ tag_output[index].append(this_line.rstrip("\n"))
+
+def tex_macro (tex, index):
+ the_lines = tag_output [index]
+ tex.write ("\pytag{"+tag_name[index]+"}{%\n")
+ for i in range (0,len(the_lines)):
+ if not empty_line (the_lines[i]):
+ tex.write (the_lines[i]+"%\n")
+ tex.write("}\n")
+
+# -----------------------------------------------------------------------------
+# the main code
+
+import argparse
+
+parser = argparse.ArgumentParser(description="Post-process Python output")
+parser.add_argument("-i", dest="input", metavar="source", help="LaTeX-Python source file (without .tex file extension)", required=True)
+parser.add_argument("-I", dest="sty", metavar="include", help="Full path to LaTeX-Python pymacros.sty file")
+
+the_file_name = parser.parse_args().input
+sty_file_name = parser.parse_args().sty
+
+# ----------------------------------------------------------------------------
+# include the Python macros in the .cdbtex file?
+
+if sty_file_name:
+ include_macros_header = True
+ if not os.path.isfile (sty_file_name):
+ print ("> could not find "+sty_file_name)
+ print ("> will not include Python macros")
+ include_macros_header = False
+else:
+ include_macros_header = False
+
+# ----------------------------------------------------------------------------
+# file names
+
+idx_file_name = the_file_name + ".pyidx"
+tex_file_name = the_file_name + ".pytex"
+src_file_name = the_file_name + ".pytxt"
+
+# ----------------------------------------------------------------------------
+# any tag index/name pairs to read?
+
+if not os.path.isfile (idx_file_name):
+ with open(tex_file_name,"w") as tex:
+ tex.write ("% no Python output")
+ sys.exit (0)
+
+# ----------------------------------------------------------------------------
+# read tag index/name pairs
+
+tag_name = [""] # dummy entry at index = 0
+tag_done = [False] # ditto
+tag_found = [False] # ditto
+tag_output = [[]] # ditto
+num_tag = 0
+tag_index = 0
+
+with open(idx_file_name, "r") as idx:
+ for this_line in idx:
+ if has_tag (this_line): # skip any non-tag text (e.g., comments)
+ num_tag = num_tag + 1 # the tag index
+ tag_name.append (get_text (this_line)) # the tag name
+ tag_done.append (False)
+ tag_found.append (False)
+ tag_output.append ([])
+
+# note: num_tag = number of tags declared in the Python/LaTeX source
+# these tags are stored in locations 1,2,3 ... num_tag in the various arrays
+# tag_output[0] will contain all non-tagged Python output.
+
+# ----------------------------------------------------------------------------
+# read Python output and create LaTeX macros for each tag
+
+if num_tag == 0:
+ with open(tex_file_name,"w") as tex:
+ tex.write ("% no Python output")
+else:
+
+ if not os.path.isfile (src_file_name):
+ with open(tex_file_name,"w") as tex:
+ tex.write ("% no Python output")
+ print ("> post-process: Source file " + src_file_name + " not found, exit.")
+ print ("> possible error during execution of Python.")
+ sys.exit (1)
+
+ # -------------------------------------------------------------------------
+ # read Python output
+
+ with open(src_file_name,"r") as src:
+ for this_line in src:
+
+ line_type = parse (this_line)
+ if line_type == Type.BegTag:
+
+ tag_index = get_index (this_line)
+ tag_done [tag_index] = False
+ tag_found [tag_index] = True
+ stack_index = push_stack (tag_index,stack_index)
+
+ elif line_type == Type.EndTag:
+
+ tag_index = get_index (this_line)
+ tag_done [tag_index] = True
+ tag_found [tag_index] = True
+ stack_index = pop_stack (tag_index,stack_index)
+ tag_index = read_stack (stack_index)
+
+ elif line_type == Type.PlainText:
+
+ append_text (this_line,tag_index)
+
+ else:
+ pass # should never get here
+
+ # -----------------------------------------------------------------------
+ # create the latex macros, one for each tag
+
+ with open(tex_file_name,"w") as tex:
+
+ if include_macros_header:
+ tex.write(r'% ====================================================================='+'\n')
+ tex.write(r'% Define Python macros so that this file may be used by other LaTeX sources.'+'\n')
+ tex.write(r'% To include this file in some other LaTeX source be sure to add the following'+'\n')
+ tex.write(r'% lines in the LaTeX preamble.'+'\n')
+ tex.write(r'% \input{foo.mattex}% change foo to match the name of this file.'+'\n')
+ tex.write(r'% ---------------------------------------------------------------------'+'\n')
+ tex.write(r'\makeatletter'+'\n')
+ with open(sty_file_name,"r") as sty:
+ for this_line in sty:
+ tex.write (this_line)
+ tex.write(r'\makeatother'+'\n')
+ tex.write(r'% ====================================================================='+'\n')
+
+ for i in range (1,num_tag+1):
+
+ tex_macro (tex, i)
+
+ # -------------------------------------------------------------------------
+ # report tags that didn't have matching Python output
+
+ for i in range (1,num_tag+1):
+ if not tag_found [i]:
+ print ("> post-process: Failed to find output for tag: "+tag_name[i])
+
+ # -------------------------------------------------------------------------
+ # report problems with un-matched beg/end pairs
+
+ for i in range (1,num_tag+1):
+ if not tag_done [i]:
+ print ("> post-process: Something is missing for tag: "+tag_name[i])
diff --git a/macros/latex/contrib/hybrid-latex/python/pypreproc.py b/macros/latex/contrib/hybrid-latex/python/pypreproc.py
new file mode 100755
index 0000000000..613153013a
--- /dev/null
+++ b/macros/latex/contrib/hybrid-latex/python/pypreproc.py
@@ -0,0 +1,414 @@
+#!/usr/local/bin/python3
+
+import re
+import sys
+import os.path
+
+re_beg_python_environ = re.compile (r'^\s*\\begin{python}')
+re_end_python_environ = re.compile (r'^\s*\\end{python}')
+
+re_beg_python_verbatim = re.compile (r'^\s*\\PySetup{(.*?)action=verbatim')
+re_end_python_verbatim = re.compile (r'^\s*\\PySetup{(.*?)action=(show|hide)')
+
+re_beg_latex_document = re.compile (r'^\s*\\begin{document}')
+re_end_latex_document = re.compile (r'^\s*\\end{document}')
+
+re_indent = re.compile (r'(^\s*)')
+re_empty_line = re.compile (r'(^\s*$)')
+re_latex_comment = re.compile (r'(^\s*%)')
+re_python_comment = re.compile (r'(^\s*#)')
+re_python_markup = re.compile (r'(#\s*(py\s*\(|pyBeg\s*\(|pyEnd))')
+re_hidden_markup = re.compile (r'(^\s*#.*#\s*(py\s*\(|pyBeg\s*\(|pyEnd))')
+re_capture = re.compile (r'(#\s*((pyBeg|pyEnd)\s*\(\s*([a-zA-Z0-9_.]+)\)))')
+re_beg_capture = re.compile (r'(#\s*(pyBeg\s*\(\s*([a-zA-Z0-9_.]+)\)))')
+re_end_capture = re.compile (r'(#\s*(pyEnd\s*(\(\s*([a-zA-Z0-9_.]+)\))?))')
+re_py_tag = re.compile (r'(#\s*(py\s*\(\s*([a-zA-Z0-9_.]+)\s*(,\s*([a-zA-Z0-9_]+)\s*)?\)))')
+ # Allow two forms of tag, py(foo,bah) and py(bah).
+ # In both cases bah must be a valid python expression.
+
+def make_str (num,digits):
+ return '{number:0{width}d}'.format(number=num,width=digits)
+
+def grep (this_line, regex, the_group):
+ result = regex.search (this_line)
+ if result:
+ found = True
+ the_beg = result.start (the_group)
+ the_end = result.end (the_group)
+ else:
+ found = False
+ the_beg = -1
+ the_end = -1
+ return the_beg, the_end, found
+
+def not_latex_comment (this_line):
+ return not re_latex_comment.search (this_line)
+
+def not_python_comment (this_line):
+ return not re_python_comment.search (this_line)
+
+def is_beg_latex_document (this_line):
+ return re_beg_latex_document.search (this_line)
+
+def is_end_latex_document (this_line):
+ return re_end_latex_document.search (this_line)
+
+def is_beg_python_environ (this_line):
+ return re_beg_python_environ.search (this_line)
+
+def is_end_python_environ (this_line):
+ return re_end_python_environ.search (this_line)
+
+def is_beg_python_verbatim (this_line):
+ return re_beg_python_verbatim.search (this_line)
+
+def is_end_python_verbatim (this_line):
+ return re_end_python_verbatim.search (this_line)
+
+def has_beg_python_capture (this_line):
+ return re_beg_capture.search (this_line)
+
+def has_end_python_capture (this_line):
+ return re_end_capture.search (this_line)
+
+def has_python_tag (this_line):
+ return re_py_tag.search (this_line)
+
+def has_python_markup (this_line):
+ return re_python_markup.search (this_line)
+
+def not_hidden_markup (this_line):
+ return not re_hidden_markup.search (this_line)
+
+def filter_python_markup (this_line):
+ if len(this_line) == 0:
+ return ""
+ else:
+ if has_python_markup (this_line):
+ the_beg,the_end,found = grep (this_line,re_python_markup,1)
+ if the_beg > 0 :
+ return this_line[0:the_beg-1].rstrip(" ")
+ else:
+ return this_line.rstrip("\n")
+ else:
+ return this_line.rstrip("\n")
+
+# -----------------------------------------------------------------------------
+# 1st pass: copy Python source from source.tex to source.py file
+# leave in-line comments in place, these will be removed in pass2
+
+def pass1 (src_file_name, out_file_name, the_file_name):
+
+ in_latex_document = False
+ in_python_environ = False
+ in_python_verbatim = False
+
+ # --------------------------------------------------------------------------
+ # find the first non-empty, non-comment line in the Python blocks
+ # record the indent of that line
+
+ indent_num = 0 # number of leading spaces of first non-trivial Python line
+
+ with open(src_file_name, "r") as src:
+ for this_line in src:
+ if not_latex_comment (this_line):
+ if in_latex_document:
+ if is_end_latex_document (this_line):
+ in_latex_document = False
+ break
+ else:
+ if is_beg_python_verbatim (this_line):
+ in_python_verbatim = True
+ elif is_end_python_verbatim (this_line):
+ in_python_verbatim = False
+ if in_python_environ:
+ if is_end_python_environ (this_line):
+ in_python_environ = False
+ else:
+ if not in_python_verbatim:
+ if len(this_line) > 1:
+ if not_python_comment (this_line):
+ the_beg,the_end,found = grep (this_line,re_indent,1)
+ if not found:
+ print ("> read error in preproc/pass1")
+ print ("> line: "&this_line)
+ sys.exit (1)
+ else:
+ indent_num = the_end - the_beg # number of leading spaces
+ break
+ else:
+ if is_beg_python_environ (this_line):
+ in_python_environ = True
+ else:
+ if is_beg_latex_document (this_line):
+ in_latex_document = True
+
+ # --------------------------------------------------------------------------
+ # collect the Python begin/end blocks and write to a single file
+
+ in_latex_document = False
+ in_python_environ = False
+ in_python_verbatim = False
+
+ with open (src_file_name,"r") as src:
+ with open (out_file_name,"w") as out:
+
+ out.write ("# ----------------------------------------------\n")
+ out.write ("# auto-generated from " + src_file_name + "\n")
+ out.write ("# ----------------------------------------------\n")
+
+ out.write ("def Print (obj):\n")
+ out.write (" try:\n")
+ out.write (" print(latex(obj))\n")
+ out.write (" except:\n")
+ out.write (" print(obj)\n")
+ out.write ("# ----------------------------------------------\n\n")
+
+ for this_line in src:
+
+ if not_latex_comment (this_line):
+ if in_latex_document:
+ if is_end_latex_document (this_line):
+ in_latex_document = False
+ break
+ else:
+ if is_beg_python_verbatim (this_line):
+ in_python_verbatim = True
+ elif is_end_python_verbatim (this_line):
+ in_python_verbatim = False
+
+ if in_python_environ:
+ if is_end_python_environ (this_line):
+ in_python_environ = False
+ else:
+ if not in_python_verbatim:
+ if len(this_line) > 0:
+ the_beg,the_end,found = grep (this_line,re_indent,1)
+ start = min(indent_num,the_end-the_beg)
+ out.write (this_line[start:len(this_line)-1]+"\n") # use 0: to retain indent
+ else:
+ out.write("\n")
+
+ else:
+ if is_beg_python_environ (this_line):
+ in_python_environ = True
+
+ else:
+ if is_beg_latex_document (this_line):
+ in_latex_document = True
+
+# -----------------------------------------------------------------------------
+# 2nd pass: use the source.py (from pass1) file to build the following files
+
+# source_.py : annotated file, contains extra lines to generate output for later capture
+# source.pyidx : a list of tags, one line per tag, written as: tag index = tag name
+
+def pass2 (src_file_name, out_file_name, idx_file_name):
+
+ # -----------------------------------------------------------
+ # read functions, extract tag and expressions names
+
+ def get_tag (this_line):
+ the_beg,the_end,found = grep (this_line,re_py_tag,3)
+ if found:
+ return this_line[the_beg:the_end].strip(" ")
+ else:
+ return this_line.strip(" ")
+
+ def get_exp (this_line):
+ the_beg,the_end,found = grep (this_line,re_py_tag,5)
+ if found and (the_beg > 0) and (the_end > 0):
+ return this_line[the_beg:the_end].strip(" ") # returns foo given py (foo,bah)
+ else:
+ return get_tag (this_line) # returns bah given py (bah)
+
+ def get_src (this_line):
+ the_beg,the_end,found = grep (this_line,re_py_tag,1)
+ if found:
+ if the_beg == 0:
+ return ""
+ else:
+ return this_line [0:the_beg-1].rstrip(" ")
+ else:
+ return this_line.rstrip(" ")
+
+ def get_capture (this_line):
+ the_beg,the_end,found = grep (this_line,re_capture,4)
+ if found:
+ return this_line[the_beg:the_end].strip(" ")
+ else:
+ return this_line.strip(" ")
+
+ def beg_capture_src (this_line):
+ the_beg,the_end,found = grep (this_line,re_beg_capture,1)
+ if found:
+ if the_beg > 0:
+ return this_line [0:the_beg-1].rstrip(" ")
+ else:
+ return ""
+ else:
+ return this_line.rstrip(" ")
+
+ def end_capture_src (this_line):
+ the_beg,the_end,found = grep (this_line,re_end_capture,1)
+ if found:
+ if the_beg > 0:
+ return this_line [0:the_beg-1].rstrip(" ")
+ else:
+ return ""
+ else:
+ return this_line.rstrip(" ")
+
+ # ----------------------------------------------------------
+ # output functions, writes to index file, temp py file etc.
+
+ def beg_tag (num):
+ return 'print("beg_tag'+make_str(num,4)+'")'
+
+ def end_tag (num):
+ return 'print("end_tag'+make_str(num,4)+'")'
+
+ def beg_capture (num):
+ return beg_tag (num)
+
+ def end_capture (num):
+ return end_tag (num)
+
+ def wrt_latex (this_line):
+ this_text = get_exp (this_line)
+ return "Print("+this_text+")"
+
+ # -------------------------------------------------------------------------
+ # stack operations
+
+ stack = []
+ tag_name = []
+ stack_index = 0
+ max_stack_index = 5
+ for i in range (0,max_stack_index+1): # create an empty stack
+ stack.append(-1)
+ tag_name.append("")
+
+ def read_stack (index):
+ return stack [index]
+
+ def push_stack (index, this_line, stack_index):
+ if stack_index < max_stack_index:
+ stack_index = stack_index + 1
+ stack [stack_index] = index
+ tag_name [stack_index] = get_capture (this_line)
+ return stack_index
+ else:
+ print ("> Depth of nested pyBeg/pyEnd pairs exceeded, max = "+str(max_stack_index)+", exit")
+ sys.exit (1)
+
+ def pop_stack (index, this_line, stack_index):
+ if stack_index > 0:
+ tmp_name = get_capture (this_line)
+ if tmp_name == tag_name [stack_index]:
+ stack [stack_index] = -1
+ return stack_index - 1
+ else:
+ print ("> Error in pyBeg/pyEnd pair for tag: "+str(tag_name[index])+", exit")
+ sys.exit (1)
+ else:
+ print ("> Error with pyBeg/pyEnd pairs, check for missing pyBeg or pyEnd, exit")
+ sys.exit (1)
+
+ # create a temporary copy of the Python source
+
+ from shutil import copyfile
+ from uuid import uuid4
+
+ tmp_file_name = "/tmp/"+str(uuid4())
+ copyfile (src_file_name,tmp_file_name)
+
+ # create an annotated _.py and .pyidx files using the temporary file as source
+
+ with open (out_file_name,"w") as out:
+ with open (idx_file_name,"w") as idx:
+ with open (tmp_file_name,"r") as src:
+
+ tag_index = 0
+
+ for this_line in src:
+
+ if has_python_markup (this_line) and not_hidden_markup (this_line):
+
+ if has_beg_python_capture (this_line):
+
+ tag_index = tag_index + 1
+
+ out.write ( beg_capture_src (this_line) + "\n")
+ out.write ( beg_capture (tag_index) + "\n" )
+
+ idx.write ("tag"+make_str(tag_index,4)+"=")
+ idx.write ( get_capture (this_line) + "\n")
+
+ stack_index = push_stack (tag_index,this_line,stack_index)
+
+ elif has_end_python_capture (this_line):
+
+ out.write ( end_capture_src (this_line) + "\n" )
+ out.write ( end_capture (read_stack (stack_index)) + "\n")
+
+ stack_index = pop_stack (read_stack (stack_index),this_line,stack_index)
+
+ elif has_python_tag (this_line):
+
+ tag_index = tag_index + 1
+
+ out.write (get_src (this_line) + "\n")
+ out.write (beg_tag (tag_index) + "\n")
+ out.write (wrt_latex (this_line) + "\n")
+ out.write (end_tag (tag_index) + "\n")
+
+ idx.write ("tag"+make_str(tag_index,4) + "=")
+ idx.write ( get_tag (this_line) + "\n")
+
+ else:
+
+ out.write (filter_python_markup (this_line)+"\n")
+
+ else:
+
+ out.write (filter_python_markup (this_line)+"\n")
+
+ # copy the temporary file back to the source with in-line comments removed
+ # note: this clean copy is just for reference, it's never used
+
+ with open (tmp_file_name,"r") as tmp:
+ with open (src_file_name,"w") as src:
+ for this_line in tmp:
+ src.write (filter_python_markup(this_line)+"\n") # note: could choose to retain in-line comments
+ # just drop the filter_python_markup
+
+# -----------------------------------------------------------------------------
+# the main code
+
+import argparse
+
+parser = argparse.ArgumentParser(description="Pre-process LaTeX-Python source")
+parser.add_argument("-i", dest="input", metavar="input", help="LaTeX-Python source file (without file extension)", required=True)
+parser.add_argument("-m", dest="name", metavar="name", help="Merged LaTeX-Python source file (without file extension)")
+
+src_file_name = parser.parse_args().input
+mrg_file_name = parser.parse_args().name
+
+if not mrg_file_name:
+
+ if not os.path.isfile (src_file_name + ".tex"):
+ print ("> pre-process: Source file " + src_file_name + ".tex" + " not found, exit.")
+ sys.exit (1)
+
+ pass1 (src_file_name + ".tex", src_file_name + ".py", src_file_name)
+ pass2 (src_file_name + ".py", src_file_name + "_.py", src_file_name + ".pyidx")
+
+else:
+
+ if not os.path.isfile (mrg_file_name + ".tex"):
+ print ("> pre-process: Source file " + mrg_file_name + ".tex" + " not found, exit.")
+ sys.exit (1)
+
+ pass1 (mrg_file_name + ".tex", src_file_name + ".py", src_file_name)
+ pass2 (src_file_name + ".py", src_file_name + "_.py", src_file_name + ".pyidx")