Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # QAPI texi generator |
| 3 | # |
| 4 | # This work is licensed under the terms of the GNU LGPL, version 2+. |
| 5 | # See the COPYING file in the top-level directory. |
| 6 | """This script produces the documentation of a qapi schema in texinfo format""" |
Markus Armbruster | fb0bc83 | 2018-02-26 13:48:58 -0600 | [diff] [blame] | 7 | |
Daniel P. Berrange | ef9d910 | 2018-01-16 13:42:04 +0000 | [diff] [blame] | 8 | from __future__ import print_function |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 9 | import re |
Markus Armbruster | fb0bc83 | 2018-02-26 13:48:58 -0600 | [diff] [blame] | 10 | import qapi.common |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 11 | |
Marc-André Lureau | 597494a | 2017-01-25 17:03:07 +0400 | [diff] [blame] | 12 | MSG_FMT = """ |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 13 | @deftypefn {type} {{}} {name} |
| 14 | |
| 15 | {body} |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 16 | @end deftypefn |
| 17 | |
| 18 | """.format |
| 19 | |
Marc-André Lureau | 597494a | 2017-01-25 17:03:07 +0400 | [diff] [blame] | 20 | TYPE_FMT = """ |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 21 | @deftp {{{type}}} {name} |
| 22 | |
| 23 | {body} |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 24 | @end deftp |
| 25 | |
| 26 | """.format |
| 27 | |
| 28 | EXAMPLE_FMT = """@example |
| 29 | {code} |
| 30 | @end example |
| 31 | """.format |
| 32 | |
| 33 | |
| 34 | def subst_strong(doc): |
| 35 | """Replaces *foo* by @strong{foo}""" |
Markus Armbruster | c32617a | 2017-03-20 14:11:55 +0100 | [diff] [blame] | 36 | return re.sub(r'\*([^*\n]+)\*', r'@strong{\1}', doc) |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 37 | |
| 38 | |
| 39 | def subst_emph(doc): |
| 40 | """Replaces _foo_ by @emph{foo}""" |
Markus Armbruster | c32617a | 2017-03-20 14:11:55 +0100 | [diff] [blame] | 41 | return re.sub(r'\b_([^_\n]+)_\b', r'@emph{\1}', doc) |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 42 | |
| 43 | |
| 44 | def subst_vars(doc): |
| 45 | """Replaces @var by @code{var}""" |
| 46 | return re.sub(r'@([\w-]+)', r'@code{\1}', doc) |
| 47 | |
| 48 | |
| 49 | def subst_braces(doc): |
| 50 | """Replaces {} with @{ @}""" |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 51 | return doc.replace('{', '@{').replace('}', '@}') |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 52 | |
| 53 | |
| 54 | def texi_example(doc): |
| 55 | """Format @example""" |
| 56 | # TODO: Neglects to escape @ characters. |
| 57 | # We should probably escape them in subst_braces(), and rename the |
| 58 | # function to subst_special() or subs_texi_special(). If we do that, we |
| 59 | # need to delay it until after subst_vars() in texi_format(). |
| 60 | doc = subst_braces(doc).strip('\n') |
| 61 | return EXAMPLE_FMT(code=doc) |
| 62 | |
| 63 | |
| 64 | def texi_format(doc): |
| 65 | """ |
| 66 | Format documentation |
| 67 | |
| 68 | Lines starting with: |
| 69 | - |: generates an @example |
| 70 | - =: generates @section |
| 71 | - ==: generates @subsection |
| 72 | - 1. or 1): generates an @enumerate @item |
| 73 | - */-: generates an @itemize list |
| 74 | """ |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 75 | ret = '' |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 76 | doc = subst_braces(doc) |
| 77 | doc = subst_vars(doc) |
| 78 | doc = subst_emph(doc) |
| 79 | doc = subst_strong(doc) |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 80 | inlist = '' |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 81 | lastempty = False |
| 82 | for line in doc.split('\n'): |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 83 | empty = line == '' |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 84 | |
| 85 | # FIXME: Doing this in a single if / elif chain is |
| 86 | # problematic. For instance, a line without markup terminates |
| 87 | # a list if it follows a blank line (reaches the final elif), |
| 88 | # but a line with some *other* markup, such as a = title |
| 89 | # doesn't. |
| 90 | # |
| 91 | # Make sure to update section "Documentation markup" in |
Philippe Mathieu-Daudé | b3125e7 | 2017-07-28 19:46:03 -0300 | [diff] [blame] | 92 | # docs/devel/qapi-code-gen.txt when fixing this. |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 93 | if line.startswith('| '): |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 94 | line = EXAMPLE_FMT(code=line[2:]) |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 95 | elif line.startswith('= '): |
| 96 | line = '@section ' + line[2:] |
| 97 | elif line.startswith('== '): |
| 98 | line = '@subsection ' + line[3:] |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 99 | elif re.match(r'^([0-9]*\.) ', line): |
| 100 | if not inlist: |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 101 | ret += '@enumerate\n' |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 102 | inlist = 'enumerate' |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 103 | ret += '@item\n' |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 104 | line = line[line.find(' ')+1:] |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 105 | elif re.match(r'^[*-] ', line): |
| 106 | if not inlist: |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 107 | ret += '@itemize %s\n' % {'*': '@bullet', |
| 108 | '-': '@minus'}[line[0]] |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 109 | inlist = 'itemize' |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 110 | ret += '@item\n' |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 111 | line = line[2:] |
| 112 | elif lastempty and inlist: |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 113 | ret += '@end %s\n\n' % inlist |
Markus Armbruster | ef801a9 | 2017-03-15 13:57:08 +0100 | [diff] [blame] | 114 | inlist = '' |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 115 | |
| 116 | lastempty = empty |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 117 | ret += line + '\n' |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 118 | |
| 119 | if inlist: |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 120 | ret += '@end %s\n\n' % inlist |
| 121 | return ret |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 122 | |
| 123 | |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 124 | def texi_body(doc): |
| 125 | """Format the main documentation body""" |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 126 | return texi_format(doc.body.text) |
Markus Armbruster | 860e877 | 2017-03-15 13:57:04 +0100 | [diff] [blame] | 127 | |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 128 | |
Marc-André Lureau | a35c9bf | 2018-12-13 16:37:20 +0400 | [diff] [blame] | 129 | def texi_if(ifcond, prefix='\n', suffix='\n'): |
| 130 | """Format the #if condition""" |
| 131 | if not ifcond: |
| 132 | return '' |
| 133 | return '%s@b{If:} @code{%s}%s' % (prefix, ', '.join(ifcond), suffix) |
| 134 | |
| 135 | |
| 136 | def texi_enum_value(value, desc, suffix): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 137 | """Format a table of members item for an enumeration value""" |
Marc-André Lureau | a35c9bf | 2018-12-13 16:37:20 +0400 | [diff] [blame] | 138 | return '@item @code{%s}\n%s%s' % ( |
| 139 | value.name, desc, texi_if(value.ifcond, prefix='@*')) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 140 | |
| 141 | |
Marc-André Lureau | a35c9bf | 2018-12-13 16:37:20 +0400 | [diff] [blame] | 142 | def texi_member(member, desc, suffix): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 143 | """Format a table of members item for an object type member""" |
Markus Armbruster | 691e031 | 2017-03-15 13:57:14 +0100 | [diff] [blame] | 144 | typ = member.type.doc_type() |
Marc-André Lureau | 26ee12a | 2018-03-05 18:29:48 +0100 | [diff] [blame] | 145 | membertype = ': ' + typ if typ else '' |
Marc-André Lureau | 8867bf0 | 2018-12-13 16:37:21 +0400 | [diff] [blame] | 146 | return '@item @code{%s%s}%s%s\n%s%s' % ( |
Marc-André Lureau | 26ee12a | 2018-03-05 18:29:48 +0100 | [diff] [blame] | 147 | member.name, membertype, |
Markus Armbruster | 5169cd8 | 2017-03-15 13:57:16 +0100 | [diff] [blame] | 148 | ' (optional)' if member.optional else '', |
Marc-André Lureau | 8867bf0 | 2018-12-13 16:37:21 +0400 | [diff] [blame] | 149 | suffix, desc, texi_if(member.ifcond, prefix='@*')) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 150 | |
| 151 | |
Markus Armbruster | 5169cd8 | 2017-03-15 13:57:16 +0100 | [diff] [blame] | 152 | def texi_members(doc, what, base, variants, member_func): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 153 | """Format the table of members""" |
| 154 | items = '' |
Daniel P. Berrange | 2f84804 | 2018-01-16 13:42:05 +0000 | [diff] [blame] | 155 | for section in doc.args.values(): |
Markus Armbruster | c19eaa6 | 2017-03-15 13:57:17 +0100 | [diff] [blame] | 156 | # TODO Drop fallbacks when undocumented members are outlawed |
Markus Armbruster | 09331fc | 2017-10-02 16:13:38 +0200 | [diff] [blame] | 157 | if section.text: |
| 158 | desc = texi_format(section.text) |
Markus Armbruster | c19eaa6 | 2017-03-15 13:57:17 +0100 | [diff] [blame] | 159 | elif (variants and variants.tag_member == section.member |
| 160 | and not section.member.type.doc_type()): |
| 161 | values = section.member.type.member_names() |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 162 | members_text = ', '.join(['@t{"%s"}' % v for v in values]) |
| 163 | desc = 'One of ' + members_text + '\n' |
Markus Armbruster | 5da19f1 | 2017-03-15 13:57:11 +0100 | [diff] [blame] | 164 | else: |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 165 | desc = 'Not documented\n' |
Marc-André Lureau | a35c9bf | 2018-12-13 16:37:20 +0400 | [diff] [blame] | 166 | items += member_func(section.member, desc, suffix='') |
Markus Armbruster | 88f6346 | 2017-03-15 13:57:15 +0100 | [diff] [blame] | 167 | if base: |
| 168 | items += '@item The members of @code{%s}\n' % base.doc_type() |
Markus Armbruster | 5169cd8 | 2017-03-15 13:57:16 +0100 | [diff] [blame] | 169 | if variants: |
| 170 | for v in variants.variants: |
Marc-André Lureau | 01ae9cc | 2018-12-13 16:37:22 +0400 | [diff] [blame] | 171 | when = ' when @code{%s} is @t{"%s"}%s' % ( |
| 172 | variants.tag_member.name, v.name, texi_if(v.ifcond, " (", ")")) |
Markus Armbruster | 5169cd8 | 2017-03-15 13:57:16 +0100 | [diff] [blame] | 173 | if v.type.is_implicit(): |
| 174 | assert not v.type.base and not v.type.variants |
| 175 | for m in v.type.local_members: |
Marc-André Lureau | a35c9bf | 2018-12-13 16:37:20 +0400 | [diff] [blame] | 176 | items += member_func(m, desc='', suffix=when) |
Markus Armbruster | 5169cd8 | 2017-03-15 13:57:16 +0100 | [diff] [blame] | 177 | else: |
| 178 | items += '@item The members of @code{%s}%s\n' % ( |
| 179 | v.type.doc_type(), when) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 180 | if not items: |
| 181 | return '' |
Markus Armbruster | 2a1183c | 2017-03-15 13:57:10 +0100 | [diff] [blame] | 182 | return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 183 | |
| 184 | |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 185 | def texi_sections(doc, ifcond): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 186 | """Format additional sections following arguments""" |
| 187 | body = '' |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 188 | for section in doc.sections: |
Markus Armbruster | 0968dc9 | 2017-10-02 16:13:36 +0200 | [diff] [blame] | 189 | if section.name: |
Marc-André Lureau | 1ede77d | 2017-02-17 13:34:16 +0400 | [diff] [blame] | 190 | # prefer @b over @strong, so txt doesn't translate it to *Foo:* |
Markus Armbruster | 76eb6b6 | 2017-10-02 16:13:39 +0200 | [diff] [blame] | 191 | body += '\n@b{%s:}\n' % section.name |
Markus Armbruster | fc3f0df | 2017-10-02 16:13:37 +0200 | [diff] [blame] | 192 | if section.name and section.name.startswith('Example'): |
Markus Armbruster | 09331fc | 2017-10-02 16:13:38 +0200 | [diff] [blame] | 193 | body += texi_example(section.text) |
Markus Armbruster | 0968dc9 | 2017-10-02 16:13:36 +0200 | [diff] [blame] | 194 | else: |
Markus Armbruster | 09331fc | 2017-10-02 16:13:38 +0200 | [diff] [blame] | 195 | body += texi_format(section.text) |
Marc-André Lureau | a35c9bf | 2018-12-13 16:37:20 +0400 | [diff] [blame] | 196 | body += texi_if(ifcond, suffix='') |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 197 | return body |
| 198 | |
| 199 | |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 200 | def texi_entity(doc, what, ifcond, base=None, variants=None, |
Markus Armbruster | 5169cd8 | 2017-03-15 13:57:16 +0100 | [diff] [blame] | 201 | member_func=texi_member): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 202 | return (texi_body(doc) |
Markus Armbruster | 5169cd8 | 2017-03-15 13:57:16 +0100 | [diff] [blame] | 203 | + texi_members(doc, what, base, variants, member_func) |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 204 | + texi_sections(doc, ifcond)) |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 205 | |
| 206 | |
Markus Armbruster | fb0bc83 | 2018-02-26 13:48:58 -0600 | [diff] [blame] | 207 | class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor): |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 208 | def __init__(self, prefix): |
| 209 | self._prefix = prefix |
Markus Armbruster | dddee4d | 2019-03-01 16:40:47 +0100 | [diff] [blame] | 210 | self._gen = qapi.common.QAPIGenDoc(self._prefix + 'qapi-doc.texi') |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 211 | self.cur_doc = None |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 212 | |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 213 | def write(self, output_dir): |
Markus Armbruster | dddee4d | 2019-03-01 16:40:47 +0100 | [diff] [blame] | 214 | self._gen.write(output_dir) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 215 | |
Marc-André Lureau | 1962bd3 | 2018-12-13 16:37:04 +0400 | [diff] [blame] | 216 | def visit_enum_type(self, name, info, ifcond, members, prefix): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 217 | doc = self.cur_doc |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 218 | self._gen.add(TYPE_FMT(type='Enum', |
| 219 | name=doc.symbol, |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 220 | body=texi_entity(doc, 'Values', ifcond, |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 221 | member_func=texi_enum_value))) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 222 | |
Marc-André Lureau | fbf09a2 | 2018-07-03 17:56:38 +0200 | [diff] [blame] | 223 | def visit_object_type(self, name, info, ifcond, base, members, variants): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 224 | doc = self.cur_doc |
Markus Armbruster | 88f6346 | 2017-03-15 13:57:15 +0100 | [diff] [blame] | 225 | if base and base.is_implicit(): |
| 226 | base = None |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 227 | self._gen.add(TYPE_FMT(type='Object', |
| 228 | name=doc.symbol, |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 229 | body=texi_entity(doc, 'Members', ifcond, |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 230 | base, variants))) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 231 | |
Marc-André Lureau | fbf09a2 | 2018-07-03 17:56:38 +0200 | [diff] [blame] | 232 | def visit_alternate_type(self, name, info, ifcond, variants): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 233 | doc = self.cur_doc |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 234 | self._gen.add(TYPE_FMT(type='Alternate', |
| 235 | name=doc.symbol, |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 236 | body=texi_entity(doc, 'Members', ifcond))) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 237 | |
Marc-André Lureau | fbf09a2 | 2018-07-03 17:56:38 +0200 | [diff] [blame] | 238 | def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, |
Igor Mammedov | d6fe3d0 | 2018-05-11 18:51:43 +0200 | [diff] [blame] | 239 | success_response, boxed, allow_oob, allow_preconfig): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 240 | doc = self.cur_doc |
Markus Armbruster | c2dd311 | 2017-03-15 13:57:13 +0100 | [diff] [blame] | 241 | if boxed: |
| 242 | body = texi_body(doc) |
Markus Armbruster | 09331fc | 2017-10-02 16:13:38 +0200 | [diff] [blame] | 243 | body += ('\n@b{Arguments:} the members of @code{%s}\n' |
| 244 | % arg_type.name) |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 245 | body += texi_sections(doc, ifcond) |
Markus Armbruster | c2dd311 | 2017-03-15 13:57:13 +0100 | [diff] [blame] | 246 | else: |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 247 | body = texi_entity(doc, 'Arguments', ifcond) |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 248 | self._gen.add(MSG_FMT(type='Command', |
| 249 | name=doc.symbol, |
| 250 | body=body)) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 251 | |
Marc-André Lureau | fbf09a2 | 2018-07-03 17:56:38 +0200 | [diff] [blame] | 252 | def visit_event(self, name, info, ifcond, arg_type, boxed): |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 253 | doc = self.cur_doc |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 254 | self._gen.add(MSG_FMT(type='Event', |
| 255 | name=doc.symbol, |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 256 | body=texi_entity(doc, 'Arguments', ifcond))) |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 257 | |
| 258 | def symbol(self, doc, entity): |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 259 | if self._gen._body: |
| 260 | self._gen.add('\n') |
Markus Armbruster | aa964b7 | 2017-03-15 13:57:05 +0100 | [diff] [blame] | 261 | self.cur_doc = doc |
| 262 | entity.visit(self) |
| 263 | self.cur_doc = None |
| 264 | |
| 265 | def freeform(self, doc): |
| 266 | assert not doc.args |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 267 | if self._gen._body: |
| 268 | self._gen.add('\n') |
Marc-André Lureau | 901a34a | 2018-07-03 17:56:46 +0200 | [diff] [blame] | 269 | self._gen.add(texi_body(doc) + texi_sections(doc, None)) |
Marc-André Lureau | 3313b61 | 2017-01-13 15:41:29 +0100 | [diff] [blame] | 270 | |
| 271 | |
Markus Armbruster | fb0bc83 | 2018-02-26 13:48:58 -0600 | [diff] [blame] | 272 | def gen_doc(schema, output_dir, prefix): |
Markus Armbruster | 71b3f04 | 2018-02-26 13:50:08 -0600 | [diff] [blame] | 273 | if not qapi.common.doc_required: |
| 274 | return |
| 275 | vis = QAPISchemaGenDocVisitor(prefix) |
| 276 | vis.visit_begin(schema) |
| 277 | for doc in schema.docs: |
| 278 | if doc.symbol: |
| 279 | vis.symbol(doc, schema.lookup_entity(doc.symbol)) |
| 280 | else: |
| 281 | vis.freeform(doc) |
| 282 | vis.write(output_dir) |