1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
#!/usr/bin/python
# Part of Latex-Suite
#
# Copyright: Srinath Avadhanula
# Description:
# This file implements a simple outline creation for latex documents.
import re
import os
import sys
import StringIO
# getFileContents {{{
def getFileContents(argin, ext=''):
if type(argin) is str:
fname = argin + ext
else:
fname = argin.group(3) + ext
# This longish thing is to make sure that all files are converted into
# \n seperated lines.
contents = '\n'.join(open(fname).read().splitlines())
# TODO what are all the ways in which a tex file can include another?
pat = re.compile(r'^\\(@?)(include|input){(.*?)}', re.M)
contents = re.sub(pat, lambda input: getFileContents(input, ext), contents)
return ('%%==== FILENAME: %s' % fname) + '\n' + contents
# }}}
# stripComments {{{
def stripComments(contents):
# remove all comments except those of the form
# %%==== FILENAME: <filename.tex>
uncomm = [re.sub('%(?!==== FILENAME: ).*', '', line) for line in contents.splitlines()]
# also remove all only-whitespace lines.
nonempty = [line for line in uncomm if line.strip()]
return nonempty
# }}}
# addFileNameAndNumber {{{
def addFileNameAndNumber(lines):
filename = ''
retval = ''
for line in lines:
if re.match('%==== FILENAME: ', line):
filename = line.split('%==== FILENAME: ')[1]
else:
retval += '<%s>%s\n' % (filename, line)
return retval
# }}}
# getSectionLabels_Root {{{
def getSectionLabels_Root(lineinfo, section_prefix, label_prefix):
prev_txt = ''
inside_env = 0
prev_env = ''
outstr = StringIO.StringIO('')
pres_depth = len(section_prefix)
#print '+getSectionLabels_Root: lineinfo = [%s]' % lineinfo
for line in lineinfo.splitlines():
if not line:
continue
# throw away leading white-space
m = re.search('<(.*?)>(.*)', line)
fname = m.group(1)
line = m.group(2).lstrip()
# we found a label!
m = re.search(r'\\label{(%s.*?)}' % label_prefix, line)
if m:
# add the current line (except the \label command) to the text
# which will be displayed below this label
prev_txt += re.search(r'(^.*?)\\label{', line).group(1)
# for the figure environment however, just display the caption.
# instead of everything since the \begin command.
if prev_env == 'figure':
cm = re.search(r'\caption(\[.*?\]\s*)?{(.*?)}', prev_txt)
if cm:
prev_txt = cm.group(2)
# print a nice formatted text entry like so
#
# > eqn:label
# : e^{i\pi} + 1 = 0
#
# Use the current "section depth" for the leading indentation.
print >>outstr, '>%s%s\t\t<%s>' % (' '*(2*pres_depth+2),
m.group(1), fname)
print >>outstr, ':%s%s' % (' '*(2*pres_depth+4), prev_txt)
prev_txt = ''
# If we just encoutered the start or end of an environment or a
# label, then do not remember this line.
# NOTE: This assumes that there is no equation text on the same
# line as the \begin or \end command. The text on the same line as
# the \label was already handled.
if re.search(r'\\begin{(equation|eqnarray|align|figure)', line):
prev_txt = ''
prev_env = re.search(r'\\begin{(.*?)}', line).group(1)
inside_env = 1
elif re.search(r'\\label', line):
prev_txt = ''
elif re.search(r'\\end{(equation|eqnarray|align|figure)', line):
inside_env = 0
prev_env = ''
else:
# If we are inside an environment, then the text displayed with
# the label is the complete text within the environment,
# otherwise its just the previous line.
if inside_env:
prev_txt += line
else:
prev_txt = line
return outstr.getvalue()
# }}}
# getSectionLabels {{{
def getSectionLabels(lineinfo,
sectypes=['chapter', 'section', 'subsection', 'subsubsection'],
section_prefix='', label_prefix=''):
if not sectypes:
return getSectionLabels_Root(lineinfo, section_prefix, label_prefix)
##print 'sectypes[0] = %s, section_prefix = [%s], lineinfo = [%s]' % (
## sectypes[0], section_prefix, lineinfo)
sections = re.split(r'(<.*?>\\%s{.*})' % sectypes[0], lineinfo)
# there will 1+2n sections, the first containing the "preamble" and the
# others containing the child sections as paris of [section_name,
# section_text]
rettext = getSectionLabels(sections[0], sectypes[1:], section_prefix, label_prefix)
for i in range(1,len(sections),2):
sec_num = (i+1)/2
section_name = re.search(r'\\%s{(.*?)}' % sectypes[0], sections[i]).group(1)
section_label_text = getSectionLabels(sections[i] + sections[i+1], sectypes[1:],
section_prefix+('%d.' % sec_num), label_prefix)
if section_label_text:
sec_heading = 2*' '*len(section_prefix) + section_prefix
sec_heading += '%d. %s' % (sec_num, section_name)
sec_heading += '<<<%d\n' % (len(section_prefix)/2+1)
rettext += sec_heading + section_label_text
return rettext
# }}}
# main {{{
def main(fname, label_prefix):
[head, tail] = os.path.split(fname)
if head:
os.chdir(head)
[root, ext] = os.path.splitext(tail)
contents = getFileContents(root, ext)
nonempty = stripComments(contents)
lineinfo = addFileNameAndNumber(nonempty)
return getSectionLabels(lineinfo, label_prefix=label_prefix)
# }}}
if __name__ == "__main__":
if len(sys.argv) > 2:
prefix = sys.argv[2]
else:
prefix = ''
print main(sys.argv[1], prefix)
# vim: fdm=marker
|