|
Packit |
0f19cf |
# This file is part of Rubber and thus covered by the GPL
|
|
Packit |
0f19cf |
# (c) Emmanuel Beffara, 2004--2006
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Indexing support with package 'index'.
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
This module handles the processing of the document's indices using a tool like
|
|
Packit |
0f19cf |
makeindex or xindy. It stores an MD5 sum of the source (.idx) file between two
|
|
Packit |
0f19cf |
runs, in order to detect modifications.
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
The following directives are provided to specify options for makeindex:
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
tool <tool> =
|
|
Packit |
0f19cf |
Choose which indexing tool should be used. Currently this can be either
|
|
Packit |
0f19cf |
"makeindex" (by default) or "xindy".
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
language <lang> =
|
|
Packit |
0f19cf |
Choose the language used for sorting the index (xindy only).
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
modules <mod> <mod> ... =
|
|
Packit |
0f19cf |
Specify which modules xindy should use for the index.
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
order <ordering> =
|
|
Packit |
0f19cf |
Modify the ordering to be used (makeindex only, supported by xindy with
|
|
Packit |
0f19cf |
warnings). The argument must be a space separated list of:
|
|
Packit |
0f19cf |
- standard = use default ordering (no options, this is the default)
|
|
Packit |
0f19cf |
- german = use German ordering (option "-g")
|
|
Packit |
0f19cf |
- letter = use letter instead of word ordering (option "-l")
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
path <directory> =
|
|
Packit |
0f19cf |
Add the specified directory to the search path for styles.
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
style <name> =
|
|
Packit |
0f19cf |
Use the specified style file.
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
They all accept an optional argument first, enclosed in parentheses as in
|
|
Packit |
0f19cf |
"index.path (foo,bar) here/", to specify which index they apply to. Without
|
|
Packit |
0f19cf |
this argument, they apply to all indices declared at the point where they
|
|
Packit |
0f19cf |
occur.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
import os
|
|
Packit |
0f19cf |
from os.path import *
|
|
Packit |
0f19cf |
import re, string
|
|
Packit |
0f19cf |
import subprocess
|
|
Packit |
0f19cf |
import xml.dom.minidom
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
from subprocess import Popen, PIPE
|
|
Packit |
0f19cf |
from msg import _, msg
|
|
Packit |
0f19cf |
from plugins import TexModule
|
|
Packit |
0f19cf |
from util import md5_file
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
class Xindy:
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Xindy command wrapper
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
def __init__(self, doc, idxfile, target, transcript="",
|
|
Packit |
0f19cf |
opts=None, modules=None,
|
|
Packit |
0f19cf |
index_lang="", style=""):
|
|
Packit |
0f19cf |
self.doc = doc
|
|
Packit |
0f19cf |
self.idxfile = idxfile
|
|
Packit |
0f19cf |
self.target = target
|
|
Packit |
0f19cf |
self.transcript = transcript
|
|
Packit |
0f19cf |
self.opts = opts or []
|
|
Packit |
0f19cf |
self.modules = modules or []
|
|
Packit |
0f19cf |
self.index_lang = index_lang
|
|
Packit |
0f19cf |
self.path_var = "XINDY_SEARCHPATH"
|
|
Packit |
0f19cf |
mapfile = os.path.join(os.path.dirname(__file__), "xindylang.xml")
|
|
Packit |
0f19cf |
self.languages = self.map_languages(mapfile)
|
|
Packit |
0f19cf |
self._re_hyperindex = re.compile(r"hyperindexformat{\\(.*?)}}{",
|
|
Packit |
0f19cf |
re.M|re.DOTALL)
|
|
Packit |
0f19cf |
self.invalid_index_ranges = []
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def map_languages(self, mapfile):
|
|
Packit |
0f19cf |
languages = {}
|
|
Packit |
0f19cf |
dom_document = xml.dom.minidom.parse(mapfile)
|
|
Packit |
0f19cf |
for dom_fontspec in dom_document.getElementsByTagName('map'):
|
|
Packit |
0f19cf |
lang = dom_fontspec.getAttribute('lang')
|
|
Packit |
0f19cf |
xindylang = dom_fontspec.getAttribute('xindylang')
|
|
Packit |
0f19cf |
if xindylang:
|
|
Packit |
0f19cf |
languages[lang] = xindylang
|
|
Packit |
0f19cf |
dom_document.unlink()
|
|
Packit |
0f19cf |
return languages
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def command(self):
|
|
Packit |
0f19cf |
cmd = []
|
|
Packit |
0f19cf |
if self.doc.program == "xelatex":
|
|
Packit |
0f19cf |
# If raw index is in UTF-8 the texindy command cannot be used
|
|
Packit |
0f19cf |
cmd.extend(["xindy", "-M", "texindy", "-C", self.doc.encoding])
|
|
Packit |
0f19cf |
# To behave even more like texindy
|
|
Packit |
0f19cf |
cmd.extend(["-q", "-M", "page-ranges"])
|
|
Packit |
0f19cf |
else:
|
|
Packit |
0f19cf |
# Call texindy to handle LICR encoded raw index
|
|
Packit |
0f19cf |
# Equivalent to xindy arguments (beware of module order):
|
|
Packit |
0f19cf |
# "xindy", "-M", "tex/inputenc/latin",
|
|
Packit |
0f19cf |
# "-M", "texindy", "-C", "latin",
|
|
Packit |
0f19cf |
# "-I", "latex"
|
|
Packit |
0f19cf |
cmd.extend(["texindy"])
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Specific output files?
|
|
Packit |
0f19cf |
if self.target:
|
|
Packit |
0f19cf |
cmd.extend(["-o", self.target])
|
|
Packit |
0f19cf |
if self.transcript:
|
|
Packit |
0f19cf |
cmd.extend(["-t", self.transcript])
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Find out which language to use
|
|
Packit |
0f19cf |
if self.index_lang:
|
|
Packit |
0f19cf |
lang = self.index_lang
|
|
Packit |
0f19cf |
elif self.doc.lang:
|
|
Packit |
0f19cf |
lang = self.languages.get(self.doc.lang)
|
|
Packit |
0f19cf |
if not(lang):
|
|
Packit |
0f19cf |
msg.warn(_("xindy: lang '%s' not found" % \
|
|
Packit |
0f19cf |
self.doc.lang), pkg="index")
|
|
Packit |
0f19cf |
else:
|
|
Packit |
0f19cf |
msg.log(_("xindy: lang '%s' mapped to '%s'" % \
|
|
Packit |
0f19cf |
(self.doc.lang, lang)), pkg="index")
|
|
Packit |
0f19cf |
else:
|
|
Packit |
0f19cf |
lang = None
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
if lang:
|
|
Packit |
0f19cf |
cmd.extend(["-L", lang])
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
for mod in self.modules:
|
|
Packit |
0f19cf |
cmd.extend(["-M", mod])
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
if self.opts:
|
|
Packit |
0f19cf |
cmd.extend(self.opts)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
cmd.append(self.idxfile)
|
|
Packit |
0f19cf |
return cmd
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def _find_index_encoding(self, logname):
|
|
Packit |
0f19cf |
# Texindy produces latin-* indexes. Try to find out which one from
|
|
Packit |
0f19cf |
# the modules loaded by the script (language dependent)
|
|
Packit |
0f19cf |
re_lang = re.compile("loading module \"lang/.*/(latin[^.-]*)")
|
|
Packit |
0f19cf |
logfile = open(logname)
|
|
Packit |
0f19cf |
encoding = ""
|
|
Packit |
0f19cf |
for line in logfile:
|
|
Packit |
0f19cf |
m = re_lang.search(line)
|
|
Packit |
0f19cf |
if m:
|
|
Packit |
0f19cf |
encoding = m.group(1)
|
|
Packit |
0f19cf |
break
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
logfile.close()
|
|
Packit |
0f19cf |
return encoding
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def _index_is_unicode(self):
|
|
Packit |
0f19cf |
f = file(self.target, "r")
|
|
Packit |
0f19cf |
is_unicode = True
|
|
Packit |
0f19cf |
for line in f:
|
|
Packit |
0f19cf |
try:
|
|
Packit |
0f19cf |
line.decode("utf8")
|
|
Packit |
0f19cf |
except:
|
|
Packit |
0f19cf |
is_unicode = False
|
|
Packit |
0f19cf |
break
|
|
Packit |
0f19cf |
f.close()
|
|
Packit |
0f19cf |
return is_unicode
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def _sanitize_idxfile(self):
|
|
Packit |
0f19cf |
#
|
|
Packit |
0f19cf |
# Remove the 'hyperindexformat' of the new hyperref that makes a mess
|
|
Packit |
0f19cf |
# with Xindy. If not, the following error is raised by Xindy:
|
|
Packit |
0f19cf |
# "WARNING: unknown cross-reference-class `hyperindexformat'! (ignored)"
|
|
Packit |
0f19cf |
#
|
|
Packit |
0f19cf |
f = file(self.idxfile, "r")
|
|
Packit |
0f19cf |
data = f.read()
|
|
Packit |
0f19cf |
f.close()
|
|
Packit |
0f19cf |
data, nsub = self._re_hyperindex.subn(r"\1}{", data)
|
|
Packit |
0f19cf |
if not(nsub):
|
|
Packit |
0f19cf |
return
|
|
Packit |
0f19cf |
msg.debug("Remove %d unsupported 'hyperindexformat' calls" % nsub)
|
|
Packit |
0f19cf |
f = file(self.idxfile, "w")
|
|
Packit |
0f19cf |
f.write(data)
|
|
Packit |
0f19cf |
f.close()
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def _fix_invalid_ranges(self):
|
|
Packit |
0f19cf |
if not(self.invalid_index_ranges): return
|
|
Packit |
0f19cf |
f = open(self.idxfile)
|
|
Packit |
0f19cf |
lines = f.readlines()
|
|
Packit |
0f19cf |
f.close()
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Track the lines with the wrong index ranges
|
|
Packit |
0f19cf |
for i, line in enumerate(lines):
|
|
Packit |
0f19cf |
for entry in self.invalid_index_ranges:
|
|
Packit |
0f19cf |
if entry.index_key in line:
|
|
Packit |
0f19cf |
entry.add_line(i, line)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Summary of the lines to remove in order to fix the ranges
|
|
Packit |
0f19cf |
skip_lines = []
|
|
Packit |
0f19cf |
for entry in self.invalid_index_ranges:
|
|
Packit |
0f19cf |
skip_lines.extend(entry.skip_lines)
|
|
Packit |
0f19cf |
entry.reinit()
|
|
Packit |
0f19cf |
if not(skip_lines): return
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Remove the lines starting from the end to always have valid line num
|
|
Packit |
0f19cf |
msg.debug("xindy: lines to remove from %s to fix ranges: %s" %\
|
|
Packit |
0f19cf |
(self.idxfile, skip_lines))
|
|
Packit |
0f19cf |
skip_lines.sort()
|
|
Packit |
0f19cf |
skip_lines.reverse()
|
|
Packit |
0f19cf |
for line_num in skip_lines:
|
|
Packit |
0f19cf |
del lines[line_num]
|
|
Packit |
0f19cf |
f = open(self.idxfile, "w")
|
|
Packit |
0f19cf |
f.writelines(lines)
|
|
Packit |
0f19cf |
f.close()
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def _detect_invalid_ranges(self, data):
|
|
Packit |
0f19cf |
# Look for warnings like this:
|
|
Packit |
0f19cf |
#
|
|
Packit |
0f19cf |
# WARNING: Found a :close-range in the index that wasn't opened before!
|
|
Packit |
0f19cf |
# Location-reference is 76 in keyword (Statute of Anne (1710))
|
|
Packit |
0f19cf |
# I'll continue and ignore this.
|
|
Packit |
0f19cf |
#
|
|
Packit |
0f19cf |
# Do it only once on the first run to find wrong indexes.
|
|
Packit |
0f19cf |
if (self.invalid_index_ranges): return
|
|
Packit |
0f19cf |
blocks = re.split("(WARNING:|ERROR:)", data, re.M)
|
|
Packit |
0f19cf |
check_next_block = False
|
|
Packit |
0f19cf |
for block in blocks:
|
|
Packit |
0f19cf |
if "WARNING" in block:
|
|
Packit |
0f19cf |
check_next_block = True
|
|
Packit |
0f19cf |
elif check_next_block:
|
|
Packit |
0f19cf |
m = re.search("Found.*?-range .*"\
|
|
Packit |
0f19cf |
"Location-reference is \d+ in keyword \((.*)\)",
|
|
Packit |
0f19cf |
block, re.M|re.DOTALL)
|
|
Packit |
0f19cf |
if m: self.invalid_index_ranges.append(Indexentry(m.group(1)))
|
|
Packit |
0f19cf |
check_next_block = False
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def run(self):
|
|
Packit |
0f19cf |
self._sanitize_idxfile()
|
|
Packit |
0f19cf |
self._fix_invalid_ranges()
|
|
Packit |
0f19cf |
cmd = self.command()
|
|
Packit |
0f19cf |
msg.debug(" ".join(cmd))
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Collect the script output, and errors
|
|
Packit |
0f19cf |
logname = join(dirname(self.target), "xindy.log")
|
|
Packit |
0f19cf |
logfile = open(logname, "w")
|
|
Packit |
0f19cf |
p = Popen(cmd, stdout=logfile, stderr=PIPE)
|
|
Packit |
0f19cf |
errdata = p.communicate()[1]
|
|
Packit |
0f19cf |
rc = p.wait()
|
|
Packit |
0f19cf |
if msg.stdout:
|
|
Packit |
0f19cf |
msg.stdout.write(errdata)
|
|
Packit |
0f19cf |
else:
|
|
Packit |
0f19cf |
msg.warn(_(errdata.strip()))
|
|
Packit |
0f19cf |
logfile.close()
|
|
Packit |
0f19cf |
if (rc != 0):
|
|
Packit |
0f19cf |
msg.error(_("could not make index %s") % self.target)
|
|
Packit |
0f19cf |
return 1
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
self._detect_invalid_ranges(errdata)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Now convert the built index to UTF-8 if required
|
|
Packit |
0f19cf |
if cmd[0] == "texindy" and self.doc.encoding == "utf8":
|
|
Packit |
0f19cf |
if not(self._index_is_unicode()):
|
|
Packit |
0f19cf |
encoding = self._find_index_encoding(logname)
|
|
Packit |
0f19cf |
tmpindex = join(dirname(self.target), "new.ind")
|
|
Packit |
0f19cf |
cmd = ["iconv", "-f", encoding, "-t", "utf8",
|
|
Packit |
0f19cf |
"-o", tmpindex, self.target]
|
|
Packit |
0f19cf |
msg.debug(" ".join(cmd))
|
|
Packit |
0f19cf |
rc = subprocess.call(cmd)
|
|
Packit |
0f19cf |
if rc == 0: os.rename(tmpindex, self.target)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
return rc
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
class Indexentry:
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Index entry wrapper from idxfile. Its role is to detect range anomalies
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
_re_entry = re.compile("\indexentry{(.*)\|([\(\)]?).*}{(\d+)}", re.DOTALL)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def __init__(self, index_key):
|
|
Packit |
0f19cf |
self.index_key = index_key
|
|
Packit |
0f19cf |
self.skip_lines = []
|
|
Packit |
0f19cf |
self.last_range_page = 0
|
|
Packit |
0f19cf |
self.last_range_line = -1
|
|
Packit |
0f19cf |
self.last_range_open = False
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def reinit(self):
|
|
Packit |
0f19cf |
self.__init__(self.index_key)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def add_line(self, line_num, indexentry):
|
|
Packit |
0f19cf |
m = self._re_entry.search(indexentry)
|
|
Packit |
0f19cf |
if not(m):
|
|
Packit |
0f19cf |
return
|
|
Packit |
0f19cf |
index_key = m.group(1).split("!")[-1]
|
|
Packit |
0f19cf |
if index_key != self.index_key:
|
|
Packit |
0f19cf |
return
|
|
Packit |
0f19cf |
range_state = m.group(2)
|
|
Packit |
0f19cf |
page = int(m.group(3))
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
#print "Found %s at %d" % (index_key, page)
|
|
Packit |
0f19cf |
if range_state == "(":
|
|
Packit |
0f19cf |
# If a starting range overlap the previous range remove
|
|
Packit |
0f19cf |
# this intermediate useless range close/open
|
|
Packit |
0f19cf |
if page <= self.last_range_page:
|
|
Packit |
0f19cf |
self.skip_lines += [self.last_range_line, line_num]
|
|
Packit |
0f19cf |
self.last_range_page = page
|
|
Packit |
0f19cf |
self.last_range_line = line_num
|
|
Packit |
0f19cf |
self.last_range_open = True
|
|
Packit |
0f19cf |
elif range_state == ")":
|
|
Packit |
0f19cf |
self.last_range_page = page
|
|
Packit |
0f19cf |
self.last_range_line = line_num
|
|
Packit |
0f19cf |
self.last_range_open = False
|
|
Packit |
0f19cf |
elif range_state == "":
|
|
Packit |
0f19cf |
# If a single indexentry is within a range, skip it
|
|
Packit |
0f19cf |
if self.last_range_open == True:
|
|
Packit |
0f19cf |
self.skip_lines += [line_num]
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
class Makeindex:
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Makeindex command wrapper
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
def __init__(self, doc, idxfile, target, transcript="",
|
|
Packit |
0f19cf |
opts=None, modules=None,
|
|
Packit |
0f19cf |
index_lang="", style=""):
|
|
Packit |
0f19cf |
self.doc = doc
|
|
Packit |
0f19cf |
self.idxfile = idxfile
|
|
Packit |
0f19cf |
self.target = target
|
|
Packit |
0f19cf |
self.transcript = transcript
|
|
Packit |
0f19cf |
self.opts = opts or []
|
|
Packit |
0f19cf |
self.path_var = "INDEXSTYLE"
|
|
Packit |
0f19cf |
self.style = style
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def command(self):
|
|
Packit |
0f19cf |
cmd = ["makeindex", "-o", self.target] + self.opts
|
|
Packit |
0f19cf |
if self.transcript:
|
|
Packit |
0f19cf |
cmd.extend(["-t", self.transcript])
|
|
Packit |
0f19cf |
if self.style:
|
|
Packit |
0f19cf |
cmd.extend(["-s", self.style])
|
|
Packit |
0f19cf |
cmd.append(self.idxfile)
|
|
Packit |
0f19cf |
return cmd
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def _index_is_unicode(self):
|
|
Packit |
0f19cf |
f = file(self.target, "r")
|
|
Packit |
0f19cf |
is_unicode = True
|
|
Packit |
0f19cf |
for line in f:
|
|
Packit |
0f19cf |
try:
|
|
Packit |
0f19cf |
line.decode("utf8")
|
|
Packit |
0f19cf |
except:
|
|
Packit |
0f19cf |
is_unicode = False
|
|
Packit |
0f19cf |
break
|
|
Packit |
0f19cf |
f.close()
|
|
Packit |
0f19cf |
return is_unicode
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def run(self):
|
|
Packit |
0f19cf |
cmd = self.command()
|
|
Packit |
0f19cf |
msg.debug(" ".join(cmd))
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Makeindex outputs everything to stderr, even progress messages
|
|
Packit |
0f19cf |
rc = subprocess.call(cmd, stderr=msg.stdout)
|
|
Packit |
0f19cf |
if (rc != 0):
|
|
Packit |
0f19cf |
msg.error(_("could not make index %s") % self.target)
|
|
Packit |
0f19cf |
return 1
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# Beware with UTF-8 encoding, makeindex with headings can be messy
|
|
Packit |
0f19cf |
# because it puts in the headings the first 8bits char of the words
|
|
Packit |
0f19cf |
# under the heading which can be an invalid character in UTF-8
|
|
Packit |
0f19cf |
if (self.style and self.doc.encoding == "utf8"):
|
|
Packit |
0f19cf |
if not(self._index_is_unicode()):
|
|
Packit |
0f19cf |
# Retry without style to avoid headings
|
|
Packit |
0f19cf |
msg.warn(_("makeindex on UTF8 failed. Retry..."))
|
|
Packit |
0f19cf |
self.style = ""
|
|
Packit |
0f19cf |
return self.run()
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
return rc
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
class Index(TexModule):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
This class represents a single index.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
def __init__ (self, doc, source, target, transcript):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Initialize the index, by specifying the source file (generated by
|
|
Packit |
0f19cf |
LaTeX), the target file (the output of makeindex) and the transcript
|
|
Packit |
0f19cf |
(e.g. .ilg) file. Transcript is used by glosstex.py.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
self.paranoid = True
|
|
Packit |
0f19cf |
self.doc = doc
|
|
Packit |
0f19cf |
self.pbase = doc.src_base
|
|
Packit |
0f19cf |
self.source = doc.src_base + "." + source
|
|
Packit |
0f19cf |
self.target = doc.src_base + "." + target
|
|
Packit |
0f19cf |
self.transcript = doc.src_base + "." + transcript
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
# In paranoid mode, can output only in current working dir
|
|
Packit |
0f19cf |
if self.paranoid and (os.path.dirname(self.target) == os.getcwd()):
|
|
Packit |
0f19cf |
self.target = os.path.basename(self.target)
|
|
Packit |
0f19cf |
self.transcript = os.path.basename(self.transcript)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
if os.path.exists(self.source):
|
|
Packit |
0f19cf |
self.md5 = md5_file(self.source)
|
|
Packit |
0f19cf |
else:
|
|
Packit |
0f19cf |
self.md5 = None
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
self.tool = "makeindex"
|
|
Packit |
0f19cf |
self.tool_obj = None
|
|
Packit |
0f19cf |
self.lang = None # only for xindy
|
|
Packit |
0f19cf |
self.modules = [] # only for xindy
|
|
Packit |
0f19cf |
self.opts = []
|
|
Packit |
0f19cf |
self.path = []
|
|
Packit |
0f19cf |
self.style = None # only for makeindex
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def do_language (self, lang):
|
|
Packit |
0f19cf |
self.lang = lang
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def do_modules (self, *args):
|
|
Packit |
0f19cf |
self.modules.extend(args)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def do_order (self, *args):
|
|
Packit |
0f19cf |
for opt in args:
|
|
Packit |
0f19cf |
if opt == "standard": self.opts = []
|
|
Packit |
0f19cf |
elif opt == "german": self.opts.append("-g")
|
|
Packit |
0f19cf |
elif opt == "letter": self.opts.append("-l")
|
|
Packit |
0f19cf |
else: msg.warn(
|
|
Packit |
0f19cf |
_("unknown option '%s' for 'makeidx.order'") % opt)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def do_path (self, path):
|
|
Packit |
0f19cf |
self.path.append(self.doc.abspath(path))
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def do_style (self, style):
|
|
Packit |
0f19cf |
self.style = style
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def do_tool (self, tool):
|
|
Packit |
0f19cf |
if tool not in ("makeindex", "xindy"):
|
|
Packit |
0f19cf |
msg.error(_("unknown indexing tool '%s'") % tool)
|
|
Packit |
0f19cf |
self.tool = tool
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def post_compile (self):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Run the indexer tool
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
if not os.path.exists(self.source):
|
|
Packit |
0f19cf |
msg.log(_("strange, there is no %s") % self.source, pkg="index")
|
|
Packit |
0f19cf |
return 0
|
|
Packit |
0f19cf |
if not self.run_needed():
|
|
Packit |
0f19cf |
return 0
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
msg.progress(_("processing index %s") % self.source)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
if not(self.tool_obj):
|
|
Packit |
0f19cf |
if self.tool == "makeindex":
|
|
Packit |
0f19cf |
index_cls = Makeindex
|
|
Packit |
0f19cf |
elif self.tool == "xindy":
|
|
Packit |
0f19cf |
index_cls = Xindy
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
self.tool_obj = index_cls(self.doc,
|
|
Packit |
0f19cf |
self.source,
|
|
Packit |
0f19cf |
self.target,
|
|
Packit |
0f19cf |
transcript=self.transcript,
|
|
Packit |
0f19cf |
opts=self.opts,
|
|
Packit |
0f19cf |
modules=self.modules,
|
|
Packit |
0f19cf |
index_lang=self.lang,
|
|
Packit |
0f19cf |
style=self.style)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
rc = self.tool_obj.run()
|
|
Packit |
0f19cf |
if rc != 0:
|
|
Packit |
0f19cf |
return rc
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
self.doc.must_compile = 1
|
|
Packit |
0f19cf |
return 0
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def run_needed (self):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Check if makeindex has to be run. This is the case either if the
|
|
Packit |
0f19cf |
target file does not exist or if the source file has changed.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
if os.path.getsize(self.source) == 0:
|
|
Packit |
0f19cf |
msg.log(_("the index file %s is empty") % self.source, pkg="index")
|
|
Packit |
0f19cf |
return 0
|
|
Packit |
0f19cf |
new = md5_file(self.source)
|
|
Packit |
0f19cf |
if not os.path.exists(self.target):
|
|
Packit |
0f19cf |
self.md5 = new
|
|
Packit |
0f19cf |
return 1
|
|
Packit |
0f19cf |
if not self.md5:
|
|
Packit |
0f19cf |
self.md5 = new
|
|
Packit |
0f19cf |
msg.log(_("the index file %s is new") % self.source, pkg="index")
|
|
Packit |
0f19cf |
return 1
|
|
Packit |
0f19cf |
if self.md5 == new:
|
|
Packit |
0f19cf |
msg.log(_("the index %s did not change") % self.source, pkg="index")
|
|
Packit |
0f19cf |
return 0
|
|
Packit |
0f19cf |
self.md5 = new
|
|
Packit |
0f19cf |
msg.log(_("the index %s has changed") % self.source, pkg="index")
|
|
Packit |
0f19cf |
return 1
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def clean (self):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Remove all generated files related to the index.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
for file in self.source, self.target, self.transcript:
|
|
Packit |
0f19cf |
if exists(file):
|
|
Packit |
0f19cf |
msg.log(_("removing %s") % file, pkg="index")
|
|
Packit |
0f19cf |
os.unlink(file)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
re_newindex = re.compile(" *{(?P<idx>[^{}]*)} *{(?P<ind>[^{}]*)}")
|
|
Packit |
0f19cf |
re_optarg = re.compile("\((?P<list>[^()]*)\) *")
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
class Module (TexModule):
|
|
Packit |
0f19cf |
def __init__ (self, doc, dict):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Initialize the module with no index.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
self.doc = doc
|
|
Packit |
0f19cf |
self.indices = {}
|
|
Packit |
0f19cf |
self.defaults = []
|
|
Packit |
0f19cf |
self.commands = {}
|
|
Packit |
0f19cf |
doc.parser.add_hook("makeindex", self.makeindex)
|
|
Packit |
0f19cf |
doc.parser.add_hook("newindex", self.newindex)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def register (self, name, idx, ind, ilg):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Register a new index.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
index = self.indices[name] = Index(self.doc, idx, ind, ilg)
|
|
Packit |
0f19cf |
for cmd in self.defaults:
|
|
Packit |
0f19cf |
index.command(*cmd)
|
|
Packit |
0f19cf |
if self.commands.has_key(name):
|
|
Packit |
0f19cf |
for cmd in self.commands[name]:
|
|
Packit |
0f19cf |
index.command(*cmd)
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def makeindex (self, dict):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Register the standard index.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
self.register("default", "idx", "ind", "ilg")
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def newindex (self, dict):
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
Register a new index.
|
|
Packit |
0f19cf |
"""
|
|
Packit |
0f19cf |
m = re_newindex.match(dict["line"])
|
|
Packit |
0f19cf |
if not m:
|
|
Packit |
0f19cf |
return
|
|
Packit |
0f19cf |
index = dict["arg"]
|
|
Packit |
0f19cf |
d = m.groupdict()
|
|
Packit |
0f19cf |
self.register(index, d["idx"], d["ind"], "ilg")
|
|
Packit |
0f19cf |
msg.log(_("index %s registered") % index, pkg="index")
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def command (self, cmd, args):
|
|
Packit |
0f19cf |
indices = self.indices
|
|
Packit |
0f19cf |
names = None
|
|
Packit |
0f19cf |
if len(args) > 0:
|
|
Packit |
0f19cf |
m = re_optarg.match(args[0])
|
|
Packit |
0f19cf |
if m:
|
|
Packit |
0f19cf |
names = m.group("list").split(",")
|
|
Packit |
0f19cf |
args = args[1:]
|
|
Packit |
0f19cf |
if names is None:
|
|
Packit |
0f19cf |
self.defaults.append([cmd, args])
|
|
Packit |
0f19cf |
names = indices.keys()
|
|
Packit |
0f19cf |
for index in names:
|
|
Packit |
0f19cf |
if indices.has_key(index):
|
|
Packit |
0f19cf |
indices[index].command(cmd, args[1:])
|
|
Packit |
0f19cf |
elif self.commands.has_key(index):
|
|
Packit |
0f19cf |
self.commands[index].append([cmd, args])
|
|
Packit |
0f19cf |
else:
|
|
Packit |
0f19cf |
self.commands[index] = [[cmd, args]]
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def post_compile (self):
|
|
Packit |
0f19cf |
for index in self.indices.values():
|
|
Packit |
0f19cf |
if index.post_compile():
|
|
Packit |
0f19cf |
return 1
|
|
Packit |
0f19cf |
return 0
|
|
Packit |
0f19cf |
|
|
Packit |
0f19cf |
def clean (self):
|
|
Packit |
0f19cf |
for index in self.indices.values():
|
|
Packit |
0f19cf |
index.clean()
|
|
Packit |
0f19cf |
return 0
|
|
Packit |
0f19cf |
|