2 # -*- coding: utf-8 -*-
4 # script to produce rst file from program's help output.
6 from __future__ import unicode_literals
14 # We assume that first line is usage line like this:
16 # Usage: nghttp [OPTIONS]... URI...
18 # The second line is description of the command. Multiple lines
19 # are permitted. The blank line signals the end of this section.
20 # After that, we parses positional and optional arguments.
22 # The positional argument is enclosed with < and >:
26 # We may describe default behavior without any options by encoding
31 # "Options:" is treated specially and produces "OPTIONS" section.
32 # We allow subsection under OPTIONS. Lines not starting with (, <
33 # and Options: are treated as subsection name and produces section
38 # The above is an example of subsection.
40 # The description of arguments must be indented by len(arg_indent)
41 # characters. The default value should be placed in separate line
42 # and should be start with "Default: " after indentation.
44 line = infile.readline().strip()
45 m = re.match(r'^Usage: (.*)', line)
47 print 'usage line is invalid. Expected following lines:'
48 print 'Usage: cmdname ...'
50 synopsis = m.group(1).split(' ', 1)
51 if len(synopsis) == 2:
52 cmdname, args = synopsis
54 cmdname, args = synopsis[0], ''
61 description.append(line)
76 '''.format(cmdname=cmdname, args=args,
77 cmdnameunderline='=' * (len(cmdname) + 3),
78 synopsis=synopsis, description=format_text('\n'.join(description)))
85 if not line.strip() and in_arg:
88 if line.startswith(' ') and in_arg:
89 if not line.startswith(arg_indent):
90 sys.stderr.write('warning: argument description is not indented correctly. We need {} spaces as indentation.\n'.format(len(arg_indent)))
91 print '{}'.format(format_arg_text(line[len(arg_indent):]))
98 if line == 'Options:':
104 if line.startswith(' <'):
105 # positional argument
106 m = re.match(r'^(?:\s+)([a-zA-Z0-9-_<>]+)(.*)', line)
107 argname, rest = m.group(1), m.group(2)
108 print '.. describe:: {}'.format(argname)
110 print '{}'.format(format_arg_text(rest.strip()))
114 if line.startswith(' ('):
115 # positional argument
116 m = re.match(r'^(?:\s+)(\([a-zA-Z0-9-_<> ]+\))(.*)', line)
117 argname, rest = m.group(1), m.group(2)
118 print '.. describe:: {}'.format(argname)
120 print '{}'.format(format_arg_text(rest.strip()))
124 if line.startswith(' -'):
127 r'^(?:\s+)(-\S+?(?:, -\S+?)*)($| .*)',
129 argname, rest = m.group(1), m.group(2)
130 print '.. option:: {}'.format(argname)
134 print '{}'.format(format_arg_text(rest))
138 if not line.startswith(' ') and line.endswith(':'):
140 subsec = line.strip()[:-1]
141 print '{}'.format(subsec)
142 print '{}'.format('~' * len(subsec))
148 def format_text(text):
150 if len(text) > len(arg_indent):
151 text = text[:len(arg_indent) + 1] + re.sub(r'\*', r'\*', text[len(arg_indent) + 1:])
153 text = re.sub(r'\*', r'\*', text)
154 # markup option reference
155 text = re.sub(r'(^|\s)(-[a-zA-Z0-9-]+)', r'\1:option:`\2`', text)
156 # sphinx does not like markup like ':option:`-f`='. We need
157 # backslash between ` and =.
158 text = re.sub(r'(:option:`.*?`)(\S)', r'\1\\\2', text)
159 # file path should be italic
160 text = re.sub(r'(^|\s|\'|")(/[^\s\'"]*)', r'\1*\2*', text)
163 def format_arg_text(text):
164 if text.strip().startswith('Default: '):
165 return '\n ' + re.sub(r'^(\s*Default: )(.*)$', r'\1``\2``', text)
166 return ' {}'.format(format_text(text))
168 if __name__ == '__main__':
169 parser = argparse.ArgumentParser(
170 description='Produces rst document from help output.')
171 parser.add_argument('-i', '--include', metavar='FILE',
172 help='include content of <FILE> as verbatim. It should be ReST formatted text.')
173 args = parser.parse_args()
177 with open(args.include) as f:
178 sys.stdout.write(f.read())