3 __version__ = '$Revision: 1.1.1.1 $'
12 __rmjunk = re.compile("<#\d+#>")
16 def __init__(self, link, str, seqno):
19 # remove <#\d+#> left in by moving the data out of LaTeX2HTML
20 str = self.__rmjunk.sub('', str)
22 self.text = split_entry_text(str)
23 self.key = split_entry_key(str)
25 def __cmp__(self, other):
26 """Comparison operator includes sequence number, for use with
28 return self.cmp_entry(other) or cmp(self.seqno, other.seqno)
30 def cmp_entry(self, other):
31 """Comparison 'operator' that ignores sequence number."""
33 for i in range(min(len(self.key), len(other.key))):
34 c = (cmp_part(self.key[i], other.key[i])
35 or cmp_part(self.text[i], other.text[i]))
38 return c or cmp(self.key, other.key) or cmp(self.text, other.text)
41 return "<Node for %s (%s)>" % (string.join(self.text, '!'), self.seqno)
44 return string.join(self.key, '!')
47 return "%s\1%s###%s\n" \
48 % (string.join(self.links, "\1"),
49 string.join(self.text, '!'),
59 minlen = min(len(s1), len(s2))
60 if len(s1) < len(s2) and l1 == l2[:len(s1)]:
62 elif len(s2) < len(s1) and l2 == l1[:len(s2)]:
65 result = cmp(l1, l2) or cmp(s1, s2)
69 def split_entry(str, which):
71 parts = string.split(str, '!')
72 parts = map(string.split, parts, ['@'] * len(parts))
82 _rmtt = re.compile(r"""(.*)<tt(?: class=['"][a-z0-9]+["'])?>(.*)</tt>(.*)$""",
84 _rmparens = re.compile(r"\(\)")
86 def split_entry_key(str):
87 parts = split_entry(str, 1)
88 for i in range(len(parts)):
89 m = _rmtt.match(parts[i])
91 parts[i] = string.join(m.group(1, 2, 3), '')
93 parts[i] = string.lower(parts[i])
94 # remove '()' from the key:
95 parts[i] = _rmparens.sub('', parts[i])
96 return map(trim_ignored_letters, parts)
99 def split_entry_text(str):
103 str = string.join(m.group(1, 2, 3), '')
104 return split_entry(str, 1)
109 rx = re.compile("(.*)\1(.*)###(.*)$")
116 link, str, seqno = m.group(1, 2, 3)
117 nodes.append(Node(link, str, seqno))
121 def trim_ignored_letters(s):
122 # ignore $ to keep environment variables with the
123 # leading letter from the name
130 def get_first_letter(s):
131 return string.lower(trim_ignored_letters(s)[0])
134 def split_letters(nodes):
138 append = group.append
139 letter = get_first_letter(nodes[0].text[0])
140 letter_groups.append((letter, group))
142 nletter = get_first_letter(node.text[0])
143 if letter != nletter:
146 letter_groups.append((letter, group))
147 append = group.append
152 # need a function to separate the nodes into columns...
153 def split_columns(nodes, columns=1):
156 # This is a rough height; we may have to increase to avoid breaks before
158 colheight = len(nodes) / columns
159 numlong = len(nodes) % columns
161 colheight = colheight + 1
165 for i in range(numlong):
166 start = i * colheight
167 end = start + colheight
168 cols.append(nodes[start:end])
170 colheight = colheight - 1
172 numshort = len(nodes) / colheight
173 except ZeroDivisionError:
174 cols = cols + (columns - len(cols)) * [[]]
176 for i in range(numshort):
177 start = i * colheight
178 end = start + colheight
179 cols.append(nodes[start:end])
181 # If items continue across columns, make sure they are marked
182 # as continuations so the user knows to look at the previous column.
184 for i in range(len(cols) - 1):
187 next = cols[i + 1][0]
191 n = min(len(prev.key), len(next.key))
193 if prev.key[j] != next.key[j]:
195 next.continuation = j + 1
199 DL_LEVEL_INDENT = " "
201 def format_column(nodes):
202 strings = ["<dl compact>"]
203 append = strings.append
209 for i in range(min(len(current), len(previous))):
210 if previous[i] != current[i]:
214 append("<dl compact>" * (count - level) + "\n")
218 append(level * DL_LEVEL_INDENT)
219 append("</dl>" * (level - count))
221 # else: level == count
222 for i in range(count, len(current) - 1):
225 if node.continuation > i:
226 extra = " (continued)"
229 append("\n<dt>%s%s\n<dd>\n%s<dl compact>"
230 % (term, extra, level * DL_LEVEL_INDENT))
231 append("\n%s<dt>%s%s</a>"
232 % (level * DL_LEVEL_INDENT, node.links[0], node.text[-1]))
233 for link in node.links[1:]:
234 append(",\n%s %s[Link]</a>" % (level * DL_LEVEL_INDENT, link))
237 append("</dl>" * (level + 1))
238 return string.join(strings, '')
241 def format_nodes(nodes, columns=1):
243 append = strings.append
245 colnos = range(columns)
246 colheight = len(nodes) / columns
247 if len(nodes) % columns:
248 colheight = colheight + 1
249 colwidth = 100 / columns
250 append('<table width="100%"><tr valign="top">')
251 for col in split_columns(nodes, columns):
252 append('<td width="%d%%">\n' % colwidth)
253 append(format_column(col))
255 append("\n</tr></table>")
257 append(format_column(nodes))
259 return string.join(strings, '')
262 def format_letter(letter):
264 lettername = ". (dot)"
266 lettername = "_ (underscore)"
268 lettername = string.upper(letter)
269 return "\n<hr>\n<h2><a name=\"letter-%s\">%s</a></h2>\n\n" \
270 % (letter, lettername)
273 def format_html_letters(nodes, columns=1):
274 letter_groups = split_letters(nodes)
276 for letter, nodes in letter_groups:
277 s = "<b><a href=\"#letter-%s\">%s</a></b>" % (letter, letter)
279 s = ["<hr><center>\n%s</center>\n" % string.join(items, " |\n")]
280 for letter, nodes in letter_groups:
281 s.append(format_letter(letter))
282 s.append(format_nodes(nodes, columns))
283 return string.join(s, '')
285 def format_html(nodes, columns):
286 return format_nodes(nodes, columns)
290 """Collapse sequences of nodes with matching keys into a single node.
296 while i < len(nodes):
298 if not node.cmp_entry(prev):
299 prev.links.append(node.links[0])
308 fp.write(node.dump())
311 def process_nodes(nodes, columns, letters):
315 return format_html_letters(nodes, columns)
317 return format_html(nodes, columns)
326 opts, args = getopt.getopt(sys.argv[1:], "c:lo:",
327 ["columns=", "letters", "output="])
328 for opt, val in opts:
329 if opt in ("-o", "--output"):
331 elif opt in ("-c", "--columns"):
332 columns = string.atoi(val)
333 elif opt in ("-l", "--letters"):
339 nodes = nodes + load(open(fn))
340 num_nodes = len(nodes)
341 html = process_nodes(nodes, columns, letters)
342 program = os.path.basename(sys.argv[0])
344 sys.stdout.write(html)
345 sys.stderr.write("\n%s: %d index nodes" % (program, num_nodes))
347 open(ofn, "w").write(html)
349 print "%s: %d index nodes" % (program, num_nodes)
352 if __name__ == "__main__":