3 __version__
= '$Revision$'
12 __rmjunk
= re
.compile("<#\d+#>")
14 def __init__(self
, link
, str, seqno
):
17 # remove <#\d+#> left in by moving the data out of LaTeX2HTML
18 str = self
.__rmjunk
.sub('', str)
20 self
.text
= split_entry_text(str)
21 self
.key
= split_entry_key(str)
23 def __cmp__(self
, other
):
24 """Comparison operator includes sequence number, for use with
26 return self
.cmp_entry(other
) or cmp(self
.seqno
, other
.seqno
)
28 def cmp_entry(self
, other
):
29 """Comparison 'operator' that ignores sequence number."""
31 for i
in range(min(len(self
.key
), len(other
.key
))):
32 c
= (cmp_part(self
.key
[i
], other
.key
[i
])
33 or cmp_part(self
.text
[i
], other
.text
[i
]))
36 return c
or cmp(self
.key
, other
.key
) or cmp(self
.text
, other
.text
)
39 return "<Node for %s (%s)>" % (string
.join(self
.text
, '!'), self
.seqno
)
42 return string
.join(self
.key
, '!')
45 return "%s\1%s###%s\n" \
46 % (string
.join(self
.links
, "\1"),
47 string
.join(self
.text
, '!'),
57 minlen
= min(len(s1
), len(s2
))
58 if len(s1
) < len(s2
) and l1
== l2
[:len(s1
)]:
60 elif len(s2
) < len(s1
) and l2
== l1
[:len(s2
)]:
63 result
= cmp(l1
, l2
) or cmp(s1
, s2
)
67 def split_entry(str, which
):
69 parts
= string
.split(str, '!')
70 parts
= map(string
.split
, parts
, ['@'] * len(parts
))
80 _rmtt
= re
.compile(r
"(.*)<tt(?: class=[a-z0-9]+)?>(.*)</tt>(.*)$",
82 _rmparens
= re
.compile(r
"\(\)")
84 def split_entry_key(str):
85 parts
= split_entry(str, 1)
86 for i
in range(len(parts
)):
87 m
= _rmtt
.match(parts
[i
])
89 parts
[i
] = string
.join(m
.group(1, 2, 3), '')
91 parts
[i
] = string
.lower(parts
[i
])
92 # remove '()' from the key:
93 parts
[i
] = _rmparens
.sub('', parts
[i
])
94 return map(trim_ignored_letters
, parts
)
97 def split_entry_text(str):
101 str = string
.join(m
.group(1, 2, 3), '')
102 return split_entry(str, 1)
107 rx
= re
.compile("(.*)\1(.*)###(.*)$")
114 link
, str, seqno
= m
.group(1, 2, 3)
115 nodes
.append(Node(link
, str, seqno
))
119 def trim_ignored_letters(s
):
120 # ignore $ to keep environment variables with the
121 # leading letter from the name
128 def get_first_letter(s
):
129 return string
.lower(trim_ignored_letters(s
)[0])
132 def split_letters(nodes
):
136 append
= group
.append
137 letter
= get_first_letter(nodes
[0].text
[0])
138 letter_groups
.append((letter
, group
))
140 nletter
= get_first_letter(node
.text
[0])
141 if letter
!= nletter
:
144 letter_groups
.append((letter
, group
))
145 append
= group
.append
150 # need a function to separate the nodes into columns...
151 def split_columns(nodes
, columns
=1):
154 # This is a rough height; we may have to increase to avoid breaks before
156 colheight
= len(nodes
) / columns
157 numlong
= len(nodes
) % columns
159 colheight
= colheight
+ 1
163 for i
in range(numlong
):
164 start
= i
* colheight
165 end
= start
+ colheight
166 cols
.append(nodes
[start
:end
])
168 colheight
= colheight
- 1
170 numshort
= len(nodes
) / colheight
171 except ZeroDivisionError:
172 cols
= cols
+ (columns
- len(cols
)) * [[]]
174 for i
in range(numshort
):
175 start
= i
* colheight
176 end
= start
+ colheight
177 cols
.append(nodes
[start
:end
])
181 DL_LEVEL_INDENT
= " "
183 def format_column(nodes
):
184 strings
= ["<dl compact>"]
185 append
= strings
.append
191 for i
in range(min(len(current
), len(previous
))):
192 if previous
[i
] != current
[i
]:
196 append("<dl compact>" * (count
- level
) + "\n")
200 append(level
* DL_LEVEL_INDENT
)
201 append("</dl>" * (level
- count
))
203 # else: level == count
204 for i
in range(count
, len(current
) - 1):
207 append("\n<dt>%s\n<dd>\n%s<dl compact>"
208 % (term
, level
* DL_LEVEL_INDENT
))
209 append("\n%s<dt>%s%s</a>"
210 % (level
* DL_LEVEL_INDENT
, node
.links
[0], node
.text
[-1]))
211 for link
in node
.links
[1:]:
212 append(",\n%s %s[Link]</a>" % (level
* DL_LEVEL_INDENT
, link
))
215 append("</dl>" * (level
+ 1))
216 return string
.join(strings
, '')
219 def format_nodes(nodes
, columns
=1):
221 append
= strings
.append
223 colnos
= range(columns
)
224 colheight
= len(nodes
) / columns
225 if len(nodes
) % columns
:
226 colheight
= colheight
+ 1
227 colwidth
= 100 / columns
228 append('<table width="100%"><tr valign="top">')
229 for col
in split_columns(nodes
, columns
):
230 append('<td width="%d%%">\n' % colwidth
)
231 append(format_column(col
))
233 append("\n</tr></table>")
235 append(format_column(nodes
))
237 return string
.join(strings
, '')
240 def format_letter(letter
):
242 lettername
= ". (dot)"
244 lettername
= "_ (underscore)"
246 lettername
= string
.upper(letter
)
247 return "\n<hr>\n<h2><a name=\"letter-%s\">%s</a></h2>\n\n" \
248 % (letter
, lettername
)
251 def format_html_letters(nodes
, columns
=1):
252 letter_groups
= split_letters(nodes
)
254 for letter
, nodes
in letter_groups
:
255 s
= "<b><a href=\"#letter-%s\">%s</a></b>" % (letter
, letter
)
257 s
= ["<hr><center>\n%s</center>\n" % string
.join(items
, " |\n")]
258 for letter
, nodes
in letter_groups
:
259 s
.append(format_letter(letter
))
260 s
.append(format_nodes(nodes
, columns
))
261 return string
.join(s
, '')
263 def format_html(nodes
, columns
):
264 return format_nodes(nodes
, columns
)
268 """Collapse sequences of nodes with matching keys into a single node.
274 while i
< len(nodes
):
276 if not node
.cmp_entry(prev
):
277 prev
.links
.append(node
.links
[0])
286 fp
.write(node
.dump())
289 def process_nodes(nodes
, columns
, letters
):
293 return format_html_letters(nodes
, columns
)
295 return format_html(nodes
, columns
)
304 opts
, args
= getopt
.getopt(sys
.argv
[1:], "c:lo:",
305 ["columns=", "letters", "output="])
306 for opt
, val
in opts
:
307 if opt
in ("-o", "--output"):
309 elif opt
in ("-c", "--columns"):
310 columns
= string
.atoi(val
)
311 elif opt
in ("-l", "--letters"):
317 nodes
= nodes
+ load(open(fn
))
318 num_nodes
= len(nodes
)
319 html
= process_nodes(nodes
, columns
, letters
)
320 program
= os
.path
.basename(sys
.argv
[0])
322 sys
.stdout
.write(html
)
323 sys
.stderr
.write("\n%s: %d index nodes" % (program
, num_nodes
))
325 open(ofn
, "w").write(html
)
327 print "%s: %d index nodes" % (program
, num_nodes
)
330 if __name__
== "__main__":