source: doc/user-guide/genhelp.py @ c720890

Last change on this file since c720890 was ad678a4, checked in by dequis <dx@…>, at 2015-05-17T03:41:31Z

genhelp.py: take input/output parameters

  • Property mode set to 100644
File size: 6.5 KB
Line 
1#!/usr/bin/env python
2
3# Usage: python genhelp.py input.xml output.txt
4# (Both python2 (>=2.5) or python3 work)
5
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License
8# as published by the Free Software Foundation; either version 2
9# of the License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor,
19# Boston, MA  02110-1301, USA.
20
21
22import re
23import sys
24import xml.etree.ElementTree as ET
25
26NORMALIZE_RE = re.compile(r"([^<>\s\t])[\s\t]+([^<>\s\t])")
27
28# Helpers
29
30def normalize(x):
31    """Normalize whitespace of a string.
32
33    The regexp turns any sequence of whitespace into a single space if it's in
34    the middle of the tag text, and then all newlines and tabs are removed,
35    keeping spaces.
36    """
37
38    x = NORMALIZE_RE.sub(r"\1 \2", x or '')
39    return x.replace("\n", "").replace("\t", "")
40
41def join(list):
42    """Turns any iterator into a string"""
43    return ''.join([str(x) for x in list])
44
45def fix_tree(tag, debug=False, lvl=''):
46    """Walks the XML tree and modifies it in-place fixing various details"""
47
48    # The include tags have an ugly namespace in the tag name. Simplify that.
49    if tag.tag.count("XInclude"):
50        tag.tag = 'include'
51
52    # Print a pretty tree-like representation of the processed tags
53    if debug:
54        print("%s<%s>%r" % (lvl, tag.tag, [tag.text, normalize(tag.text)]))
55
56    for subtag in tag:
57        fix_tree(subtag, debug, lvl + "  ")
58
59    if debug:
60        print("%s</%s>%r" % (lvl, tag.tag, [tag.tail, normalize(tag.tail)]))
61
62    # Actually normalize whitespace
63    tag.text = normalize(tag.text)
64    tag.tail = normalize(tag.tail)
65
66
67# Main logic
68
69def process_file(filename, parent=None):
70    tree = ET.parse(open(filename)).getroot()
71    fix_tree(tree)
72    return parse_tag(tree, parent)
73
74def parse_tag(tag, parent):
75    """Calls a tag_... function based on the tag name"""
76
77    fun = globals()["tag_%s" % tag.tag.replace("-", "_")]
78    return join(fun(tag, parent))
79
80def parse_subtags(tag, parent=None):
81    yield tag.text
82
83    for subtag in tag:
84        yield parse_tag(subtag, tag)
85
86    yield tag.tail
87
88
89# Main tag handlers
90
91def handle_subject(tag, parent):
92    """Tag handler for preface, chapter, sect1 and sect2 (aliased below)"""
93
94    yield '?%s\n' % tag.attrib['id']
95
96    first = True
97    for element in tag:
98        if element.tag in ["para", "variablelist", "simplelist",
99                           "command-list", "ircexample"]:
100            if not first:
101                # Spaces between paragraphs
102                yield "\n"
103            first = False
104
105            if element.attrib.get('title', ''):
106                yield element.attrib['title']
107                yield "\n"
108            yield join(parse_tag(element, tag)).rstrip("\n")
109            yield "\n"
110
111    yield "%\n"
112
113    for element in tag:
114        if element.tag in ["sect1", "sect2"]:
115            yield join(handle_subject(element, tag))
116
117    for element in tag.findall("bitlbee-command"):
118        yield join(handle_command(element))
119
120    for element in tag.findall("bitlbee-setting"):
121        yield join(handle_setting(element))
122
123def handle_command(tag, prefix=''):
124    """Tag handler for <bitlbee-command> (called from handle_subject)"""
125
126    this_cmd = prefix + tag.attrib['name']
127
128    yield "?%s\n" % this_cmd
129    for syntax in tag.findall("syntax"):
130        yield '\x02Syntax:\x02 %s\n' % syntax.text
131
132    yield "\n"
133    yield join(parse_subtags(tag.find("description"))).rstrip()
134    yield "\n"
135
136    for example in tag.findall("ircexample"):
137        yield "\n\x02Example:\x02\n"
138        yield join(parse_subtags(example)).rstrip()
139        yield "\n"
140
141    yield "%\n"
142
143    for element in tag.findall("bitlbee-command"):
144        yield join(handle_command(element, this_cmd + " "))
145
146def handle_setting(tag):
147    """Tag handler for <bitlbee-setting> (called from handle_subject)"""
148
149    yield "?set %s\n" % tag.attrib['name']
150    yield "\x02Type:\x02 %s\n" % tag.attrib["type"]
151    yield "\x02Scope:\x02 %s\n" % tag.attrib["scope"]
152
153    if tag.find("default") is not None:
154        yield "\x02Default:\x02 %s\n" % tag.findtext("default")
155
156    if tag.find("possible-values") is not None:
157        yield "\x02Possible Values:\x02 %s\n" % tag.findtext("possible-values")
158
159    yield "\n"
160    yield join(parse_subtags(tag.find("description"))).rstrip()
161    yield "\n%\n"
162
163
164# Aliases for tags that behave like subjects
165tag_preface = handle_subject
166tag_chapter = handle_subject
167tag_sect1 = handle_subject
168tag_sect2 = handle_subject
169
170# Aliases for tags that don't have any special behavior
171tag_ulink = parse_subtags
172tag_note = parse_subtags
173tag_book = parse_subtags
174tag_ircexample = parse_subtags
175
176
177# Handlers for specific tags
178
179def tag_include(tag, parent):
180    return process_file(tag.attrib['href'], tag)
181
182def tag_para(tag, parent):
183    return join(parse_subtags(tag)) + "\n\n"
184
185def tag_emphasis(tag, parent):
186    return "\x02%s\x02%s" % (tag.text, tag.tail)
187
188def tag_ircline(tag, parent):
189    return "\x02<%s>\x02 %s\n" % (tag.attrib['nick'], join(parse_subtags(tag)))
190
191def tag_ircaction(tag, parent):
192    return "\x02* %s\x02 %s\n" % (tag.attrib['nick'], join(parse_subtags(tag)))
193
194def tag_command_list(tag, parent):
195    yield "These are all root commands. See \x02help <command name>\x02 " \
196          "for more details on each command.\n\n"
197
198    for subtag in parent.findall("bitlbee-command"):
199        yield " * \x02%s\x02 - %s\n" % \
200            (subtag.attrib['name'],
201             subtag.findtext("short-description"))
202
203    yield "\nMost commands can be shortened. For example instead of " \
204          "\x02account list\x02, try \x02ac l\x02.\n\n"
205
206def tag_variablelist(tag, parent):
207    for subtag in tag:
208        yield " \x02%s\x02 - %s\n" % \
209            (subtag.findtext("term"),
210             join(parse_subtags(subtag.find("listitem/para"))))
211    yield '\n'
212
213def tag_simplelist(tag, parent):
214    for subtag in tag:
215        yield " - %s\n" % join(parse_subtags(subtag))
216    yield '\n'
217
218
219def main():
220    if len(sys.argv) != 3:
221        print("Usage: python genhelp.py input.xml output.txt")
222        return
223
224    txt = process_file(sys.argv[1])
225    open(sys.argv[2], "w").write(txt)
226
227if __name__ == '__main__':
228    main()
Note: See TracBrowser for help on using the repository browser.