Source code for lynguine.util.tex

import os
import re

from ..config.interface import Interface

interface = Interface.from_file(raise_error_if_not_found=False)

# Using list comprehensions and set for avoiding duplicate directories.
TEX_DIRECTORIES = list(set(["."] + interface.get("bibinputs", "").split(":") + interface.get("texinputs", "").split(":")))
if "TEXINPUTS" in os.environ:
    TEX_DIRECTORIES += os.environ["TEXINPUTS"].split(":")
if "BIBINPUTS" in os.environ:
    TEX_DIRECTORIES += os.environ["BIBINPUTS"].split(":")
TEX_DIRECTORIES = [os.path.expandvars(directory) for directory in TEX_DIRECTORIES]

[docs] def extract_bib_files(text): """ Extract all the bib files listed in the file lines. :param text: The text of the file to be parsed. :type text: str :return: The list of bib files. :rtype: list """ if isinstance(text, list): text = "\n".join(text) # Regular expressions for matching bibliography definitions patterns = [r'\\bibliography{([^}]*)}', r'\\begin{btSect}.*{([^}]*)}'] # Extract the bib files bib_files = set() for pattern in patterns: for match in re.findall(pattern, text): bib_files.update(match.split(',')) return list(bib_files)
[docs] def substitute_inputs(filename, directories=None): """ Take the base file and substitute in any input and include files. :param filename: The filename to be substituted. :type filename: str :param directories: The directories to search for the input files. :type directories: list :return: The substituted file. :rtype: str """ file_dir = os.path.dirname(filename) if directories == None: directories = [file_dir] filename = os.path.basename(filename) elif len(file_dir) > 0: if file_dir not in directories: directories.append(file_dir) for directory in TEX_DIRECTORIES: if directory not in directories: directories.append(directory) if filename[0] == "#": # it's a macro return None tex_file_handle = None for directory in directories: full_filename = os.path.join(directory, filename) if os.path.exists(full_filename): tex_file_handle = open(full_filename, "r") dirname = directory break if not tex_file_handle: return None lines = tex_file_handle.readlines() new_lines = "" # Avoid parsing defined commands in notation def. for line in lines: if not line[0] == "%": match_inp = re.compile(r"""\\newsection *{([^}]*)} *{([^}]*)}""") for match in match_inp.finditer(line): subs = substitute_inputs(input_file_name(match.group(2)), directories) if subs: replace_string = ( "\\section{" + match.group(1) + "}" + "\n" * 2 + subs ) line = line.replace(match.group(0), replace_string) match_inp = re.compile(r"""\\newsubsection *{([^}]*)} *{([^}]*)}""") for match in match_inp.finditer(line): subs = substitute_inputs(input_file_name(match.group(2)), directories) if subs: replace_string = ( "\\subsection{" + match.group(1) + "}" + "\n" * 2 + subs ) line = line.replace(match.group(0), replace_string) match_inp = re.compile(r"""\\inputdiagram{([^}]*)}""") for match in match_inp.finditer(line): subs = substitute_inputs(input_file_name(match.group(1)), directories) if subs: replace_string = "\\small" + subs + "\\vspace{0.5cm}" line = line.replace(match.group(0), replace_string) match_inp = re.compile(r"""\\input{([^}]*)}""") for match in match_inp.finditer(line): subs = substitute_inputs(input_file_name(match.group(1)), directories) if subs: line = line.replace(match.group(0), subs) match_inp = re.compile(r"""\\include{([^}]*)}""") for match in match_inp.finditer(line): subs = substitute_inputs(input_file_name(match.group(1)), directories) if subs: line = line.replace(match.group(0), subs) match_inp = re.compile(r"""\\includetalkfile{([^}]*)}""") for match in match_inp.finditer(line): subs = substitute_inputs(input_file_name(match.group(1)), directories) if subs: line = line.replace(match.group(0), subs) new_lines += line return new_lines
[docs] def input_file_name(filename, extension=".tex"): """ Return the filename with the extension if it exists. :param filename: The filename to be checked. :type filename: str :param extension: The extension to be checked. :type extension: str :return: The filename with the extension if it exists. :rtype: str """ ext_list = ["md", "tex"] if os.path.exists(filename): return filename else: for ext in ext_list: if os.path.exists(filename + "." + ext): return filename + "." + ext
[docs] def process_file(filename, extension=".tex"): """ Process a file and return the lines. :param filename: The filename to be processed. :type filename: str :param extension: The extension to be processed. :type extension: str :return: The lines of the processed file. :rtype: list """ tex_file_handle = open(filename, "r") lines = tex_file_handle.readlines() inp_list = extract_inputs(lines) for inp in inp_list: if not inp[0] == "#": if inp[-len(extension) :] == extension: lines += process_file(inp, extension) else: lines += process_file(inp + extension, extension) return lines
[docs] def extract_inputs(text): """ Extract latex file dependencies. :param text: The text of the file to be processed. :type text: str or list of str (for backwards compatability) :return: The list of files. :rtype: list """ if isinstance(text, str): lines = text.split("\n") else: lines = text def extract_input(line, matchstr): line_inp = re.compile(matchstr).findall(line) inp_list = [] if line_inp: for inp in line_inp: inp_list = inp_list + inp.split(",") return inp_list inp_list = [] for line in lines: inp_list += extract_input(line, r"""\\newsection *{[^}]*} *{([^}]*)}""") inp_list += extract_input(line, r"""\\newsubsection *{[^}]*} *{([^}]*)}""") inp_list += extract_input(line, r"""\\includetalkfile{([^}]*)}""") inp_list += extract_input(line, r"""\\input *{([^}]*)}""") inp_list += extract_input(line, r"""\\include *{([^}]*)}""") return inp_list
[docs] def extract_diagrams(lines, type="all"): """ Extract all the diagrams listed in the file. :param lines: The lines of the file to be processed. :type lines: list :param type: The type of diagrams to be extracted. :type type: str :return: The list of diagrams. :rtype: list """ diagram_list = [] rebases = {} rebases["diagram"] = [ r"\\includediagram", r"\\includediagramclass", r"\\inlinediagram", r"\\inputdiagram", ] rebases["img"] = [r"\\includeimg"] rebases["png"] = [r"\\includepng"] rebases["gif"] = [r"\\includegif"] rebases["jpg"] = [r"\\includejpg"] all_val = [] for key in rebases: all_val += rebases[key] rebases["all"] = all_val retails = [ r" *\[[^\]]*\] *{([^}]*)}", r"<[^>]*>{([^}]*)}", r"<[^>]*>\[[^\]]*\]{([^}]*)}", r"{([^}]*)}", ] for rebase in rebases[type]: for retail in retails: match_diagram = re.compile(rebase + retail) for line in lines: line_diagram = match_diagram.findall(line) if line_diagram: for diagram in line_diagram: diagram_list += diagram.split(",") return diagram_list
[docs] def extract_citations(lines): """ Extract all the citations listed in the file lines. :param lines: The lines of the file to be processed. :type lines: list :return: The list of citations. :rtype: list """ citations_list = [] match_cite = re.compile(r"""\\cite[^\{]*{([^}\\#]+)}""") full_text = "" for line in lines: full_text += line line_cite = match_cite.findall(full_text) if line_cite: for cite in line_cite: citations_list = citations_list + cite.split(",") for i in range(len(citations_list)): for j in range(i + 1, len(citations_list)): if citations_list[i] == citations_list[j]: citations_list[j] = [] return citations_list
[docs] def make_bib_file(citations_list, bib_files): """ Create a new bibliography file for a given list of citations. :param citations_list: The list of citations. :type citations_list: list :param bib_files: The list of bib files. :type bib_files: list :return: The new bibliography file. :rtype: str """ if citations_list: citations_list.sort() cross_ref_list = [] string_list = [] out = "" # Get the location of the bibfiles bib_dir = TEX_DIRECTORIES # Regular expressions match_bib_field = re.compile(r"""(\@\w+{)""") match_cross_ref = re.compile( r"""\bcrossref\s*=\s*[\"|{](.*)[}|\"]""", re.IGNORECASE ) match_string = re.compile(r"""\b\w*\s*=\s*(\w[^0-9]\w*),""") for dir in bib_dir: if not dir: dir = "." for filename in bib_files: if os.access(os.path.join(dir, filename) + ".bib", os.R_OK): bib_file_handle = open(os.path.join(dir, filename) + ".bib", "r") bib_file = bib_file_handle.read() # Split the bib file at the entries. bib_comp = match_bib_field.split(bib_file) for i in range(len(citations_list)): if citations_list[i]: if i > 0 and citations_list[i] == citations_list[i - 1]: citations_list[i] = [] continue for j in range(2, len(bib_comp)): entry = bib_comp[j].split(",") entry = entry[0].split("=") if not entry[0].find(citations_list[i]) == -1: # print entry[0] # Adds the entry to output out = out + bib_comp[j - 1] + bib_comp[j] # Removes the citation from the list citations_list[i] = [] cross_refs = match_cross_ref.findall(bib_comp[j]) if cross_refs: cross_ref_list = cross_ref_list + cross_refs else: strings = match_string.findall(bib_comp[j]) if strings: for string in strings: if not string_list.count(string): string_list.append(string) break return ( get_bib_strings(string_list, bib_files) + out + get_bib_cross_refs(cross_ref_list, bib_files) ) else: return ""
[docs] def get_bib_strings(string_list, bib_files): """ Create a new bibliography file for a given list of bibtex strings. :param string_list: The list of bibtex strings. :type string_list: list :param bib_files: The list of bib files. :type bib_files: list :return: The new bibliography file. :rtype: str """ if string_list: return make_bib_file(string_list, bib_files) else: return ""
[docs] def get_bib_cross_refs(string_list, bib_files): """ Create a new bibliography file for a given list of cross references. :param string_list: The list of cross references. :type string_list: list :param bib_files: The list of bib files. :type bib_files: list :return: The new bibliography file. :rtype: str """ if string_list: return make_bib_file(string_list, bib_files) else: return ""
[docs] def create_bib_file_given_tex(lines): """ Create a new bibliography file for a given latex file. :param lines: The lines of the file to be processed. :type lines: list :return: The new bibliography file. :rtype: str """ bib_files = extract_bib_files(lines) citations_list = extract_citations(lines) return make_bib_file(citations_list, bib_files)