Skip to content

Instantly share code, notes, and snippets.

@darktrojan
Created May 3, 2023 00:00
Show Gist options
  • Save darktrojan/e3d3074db01f7404359c0de04e287e44 to your computer and use it in GitHub Desktop.
Save darktrojan/e3d3074db01f7404359c0de04e287e44 to your computer and use it in GitHub Desktop.
Uses the mozilla IDL parser to write Restructured Text files for interfaces. It's pretty rough and I don't really remember how to invoke it.
import os
import os.path
import re
import sys
from xpidl import xpidl
def _get_xpidl_interface_docs(i):
# This function is horrible. We probably need full docblock parsing
# support to extract @param.
def format_comments(c):
l = []
for entry in c:
for line in entry.splitlines():
line = line.strip()
if line == '/**' or line == '/*' or line == '/*' or line == '*/':
continue
elif line.startswith('/**'):
line = line[3:]
elif line.startswith('/*'):
line = line[2:]
elif line.startswith('*'):
line = line[1:]
elif line.startswith('*/'):
line = line[2:]
elif line.endswith('*/'):
line = line[:-2]
line = line.strip()
if line == '/':
continue
l.append(line)
return l
def pad_line(l):
if l.startswith("*"):
return l
if l:
return " " + l
return ""
def pad_lines(lines):
return [pad_line(l) for l in lines]
lines = []
lines.extend([
'=' * len(i.name),
i.name,
'=' * len(i.name),
'',
])
lines.extend([
'`%s <https://hg.mozilla.org/comm-central/file/tip/%s>`_' % (source_path, source_path),
'',
])
lines.extend(format_comments(i.doccomments))
lines.append('')
members = {}
for m in i.members:
k = members.setdefault(m.kind, [])
# if isinstance(m, XPIDLCDATA):
# continue
k.append(m)
if 'const' in members:
lines.extend([
'Constants',
'=========',
'',
])
for member in members.get('const', {}):
lines.extend([
member.name,
'-' * len(member.name),
'',
])
lines.append('**Type**: ``%s``' % (member.type,))
lines.append('')
lines.append('**Value**: ``%s``' % (member.valueFn(i),))
lines.append('')
lines.extend(format_comments(member.doccomments))
lines.append('')
if 'attribute' in members:
lines.extend([
'Properties',
'==========',
'',
])
for attribute in members.get('attribute', {}):
lines.extend([
attribute.name,
'-' * len(attribute.name),
'',
])
lines.append('``%s``' % (str(attribute).strip()))
lines.append('')
if attribute.doccomments:
lines.extend(format_comments(attribute.doccomments))
lines.append('')
if 'method' in members:
lines.extend([
'Methods',
'=======',
'',
])
for method in members.get('method', {}):
# method.name = method.name + '(' + ', '.join([p.name for p in method.params]) + ')'
lines.extend([
method.name,
'-' * len(method.name),
'',
])
lines.append('``%s``' % (str(method).strip()))
lines.append('')
# if method.deprecated:
# lines.extend([
# '.. warning:: This method is deprecated.',
# '',
# ])
param_comments = {}
in_param = None
return_comments = []
in_return = False
exception_comments = []
in_exception = False
warning_comments = []
in_warning = False
empty_comment = True
for line in format_comments(method.doccomments):
line = line.strip()
if line.startswith("@return") or line.startswith("@result"):
line = re.sub(r'^(@returns?|@result)\s+(\{.*\}\s+)?', '', line)
return_comments.append(line)
in_return = True
in_param = None
in_exception = False
in_warning = False
continue
elif line.startswith("@param"):
line = re.sub(r'^@param\s+(\{.*\})?\s+', '', line)
[p, c] = line.split(' ', 1)
c = re.sub(r'^-\s+', '', c)
comment = param_comments.setdefault(p, [])
comment.append(c.strip())
in_return = False
in_param = p
in_exception = False
in_warning = False
continue
elif line.startswith("@exception") or line.startswith("@throws"):
line = re.sub(r'^@(exception|throws)\s+', '* ', line)
exception_comments.append(line)
in_return = False
in_param = None
in_exception = True
in_warning = False
continue
elif line.startswith("@warning"):
line = re.sub(r'^@warning\s+', '', line)
warning_comments.append(line)
in_return = False
in_param = None
in_exception = False
in_warning = True
continue
elif line.startswith("@"):
in_return = False
in_param = None
in_exception = False
in_warning = False
if in_return:
return_comments.append(line)
elif in_param is not None:
param_comments.get(in_param).append(line)
elif in_exception:
exception_comments.append(line)
elif in_warning:
warning_comments.append(line)
elif line or lines[-1]:
lines.append(line)
empty_comment = False
if not empty_comment and lines[-1]:
lines.append('')
if len(warning_comments) > 0:
lines.extend([
'.. warning::',
'',
])
lines.extend(pad_lines(warning_comments))
if lines[-1]:
lines.append('')
def format_type(type):
if type.params is None:
if type.name.startswith("nsI") or type.name.startswith("calI"):
return ':doc:`%s`' % (str(type))
else:
return str(type)
return '%s<%s>' % (type.name, ", ".join(format_type(p) for p in type.params))
if len(method.params) > 0:
lines.extend([
'Parameters',
'^^^^^^^^^^',
'',
])
for p in method.params:
lines.append('* %s %s %s' % (p.paramtype, format_type(p.type), p.name))
comment = param_comments.get(p.name, None)
if comment is not None:
lines.append("")
lines.extend(pad_lines(comment))
if lines[-1]:
lines.append('')
if method.type.name != "void":
lines.extend([
'Return value',
'^^^^^^^^^^^^',
'',
'* %s' % (format_type(method.type))
])
if len(return_comments) > 0:
lines.append('')
lines.extend(pad_lines(return_comments))
if lines[-1]:
lines.append('')
if len(exception_comments) > 0:
lines.extend([
'Throws',
'^^^^^^',
'',
])
lines.extend(pad_lines(exception_comments))
if lines[-1]:
lines.append('')
return lines
path = os.path.join(os.getcwd(), sys.argv[1])
source_path = path[path.rfind("comm/") + 5:]
p = xpidl.IDLParser()
idl_data = open(path).read()
idl = p.parse(data=idl_data, filename='nsIAbManager.idl')
for p in idl.productions:
if p.kind != "interface":
continue
print(os.path.dirname(source_path), p.name)
docs = '\n'.join(_get_xpidl_interface_docs(p))
# print(docs)
with open(os.path.join("/home/geoff/mozilla/interfaces/source", p.name + ".rst"), "w") as f:
f.write(docs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment