mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 08:22:16 +01:00 
			
		
		
		
	Remove unused imports and reorder other imports so that the standard ones are coming first. Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
		
			
				
	
	
		
			347 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			347 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # SPDX-FileCopyrightText: 2022 Emmanuele Bassi
 | |
| #
 | |
| # SPDX-License-Identifier: LGPL-2.1-or-later
 | |
| 
 | |
| import os
 | |
| import re
 | |
| 
 | |
| import textwrap
 | |
| 
 | |
| # Disable line length warnings as wrapping the templates would be hard
 | |
| # flake8: noqa: E501
 | |
| 
 | |
| 
 | |
| class RstCodeGenerator:
 | |
|     """Generates documentation in reStructuredText format."""
 | |
| 
 | |
|     def __init__(self, ifaces):
 | |
|         self.ifaces = ifaces
 | |
|         self._generate_expand_dicts()
 | |
| 
 | |
|     def _expand(self, s, expandParamsAndConstants):
 | |
|         """Expands parameters and constant literals."""
 | |
|         res = []
 | |
|         for line in textwrap.dedent(s).split("\n"):
 | |
|             line = line.rstrip()
 | |
|             if line == "":
 | |
|                 res.append("")
 | |
|                 continue
 | |
|             for key in self._expand_member_dict_keys:
 | |
|                 line = line.replace(key, self._expand_member_dict[key])
 | |
|             for key in self._expand_iface_dict_keys:
 | |
|                 line = line.replace(key, self._expand_iface_dict[key])
 | |
|             if expandParamsAndConstants:
 | |
|                 # replace @foo with ``foo``
 | |
|                 line = re.sub(
 | |
|                     "@[a-zA-Z0-9_]*",
 | |
|                     lambda m: "``" + m.group(0)[1:] + "``",
 | |
|                     line,
 | |
|                 )
 | |
|                 # replace e.g. %TRUE with ``TRUE``
 | |
|                 line = re.sub(
 | |
|                     "%[a-zA-Z0-9_]*",
 | |
|                     lambda m: "``" + m.group(0)[1:] + "``",
 | |
|                     line,
 | |
|                 )
 | |
|             res.append(line)
 | |
|         return "\n".join(res)
 | |
| 
 | |
|     def _generate_expand_dicts(self):
 | |
|         """Generates the dictionaries used to expand gtk-doc sigils."""
 | |
|         self._expand_member_dict = {}
 | |
|         self._expand_iface_dict = {}
 | |
|         for i in self.ifaces:
 | |
|             key = f"#{i.name}"
 | |
|             value = f"`{i.name}`_"
 | |
|             self._expand_iface_dict[key] = value
 | |
| 
 | |
|             for m in i.methods:
 | |
|                 key = "%s.%s()" % (i.name, m.name)
 | |
|                 value = f"`{i.name}.{m.name}`_"
 | |
|                 self._expand_member_dict[key] = value
 | |
| 
 | |
|             for s in i.signals:
 | |
|                 key = "#%s::%s" % (i.name, s.name)
 | |
|                 value = f"`{i.name}::{s.name}`_"
 | |
|                 self._expand_member_dict[key] = value
 | |
| 
 | |
|             for p in i.properties:
 | |
|                 key = "#%s:%s" % (i.name, p.name)
 | |
|                 value = f"`{i.name}:{p.name}`_"
 | |
|                 self._expand_member_dict[key] = value
 | |
| 
 | |
|         # Make sure to expand the keys in reverse order so e.g. #org.foo.Iface:MediaCompat
 | |
|         # is evaluated before #org.foo.Iface:Media ...
 | |
|         self._expand_member_dict_keys = sorted(
 | |
|             self._expand_member_dict.keys(), reverse=True
 | |
|         )
 | |
|         self._expand_iface_dict_keys = sorted(
 | |
|             self._expand_iface_dict.keys(), reverse=True
 | |
|         )
 | |
| 
 | |
|     def _generate_header(self, iface):
 | |
|         """Generates the header and preamble of the document."""
 | |
|         iface_name = iface.name_without_prefix
 | |
|         header_len = len(iface_name)
 | |
|         res = [
 | |
|             f".. _{iface.name}:",
 | |
|             "",
 | |
|             "=" * header_len,
 | |
|             iface_name,
 | |
|             "=" * header_len,
 | |
|             "",
 | |
|             "-----------",
 | |
|             "Description",
 | |
|             "-----------",
 | |
|             "",
 | |
|             f".. _{iface.name} Description:",
 | |
|             "",
 | |
|             iface.doc_string_brief.strip(),
 | |
|             "",
 | |
|             self._expand(iface.doc_string, True),
 | |
|             "",
 | |
|         ]
 | |
|         if iface.since:
 | |
|             res += [
 | |
|                 f"Interface available since: {iface.since}.",
 | |
|                 "",
 | |
|             ]
 | |
|         if iface.deprecated:
 | |
|             res += [
 | |
|                 ".. warning::",
 | |
|                 "",
 | |
|                 "   This interface is deprecated.",
 | |
|                 "",
 | |
|                 "",
 | |
|             ]
 | |
|         res += [""]
 | |
|         return "\n".join(res)
 | |
| 
 | |
|     def _generate_section(self, title, name):
 | |
|         """Generates a section with the given title."""
 | |
|         res = [
 | |
|             f".. _{name} {title}:",
 | |
|             "",
 | |
|             "-" * len(title),
 | |
|             title,
 | |
|             "-" * len(title),
 | |
|             "",
 | |
|             "",
 | |
|         ]
 | |
|         return "\n".join(res)
 | |
| 
 | |
|     def _generate_properties(self, iface):
 | |
|         """Generates the properties section."""
 | |
|         res = []
 | |
|         for p in iface.properties:
 | |
|             title = f"{iface.name}:{p.name}"
 | |
|             if p.readable and p.writable:
 | |
|                 access = "readwrite"
 | |
|             elif p.writable:
 | |
|                 access = "writable"
 | |
|             else:
 | |
|                 access = "readable"
 | |
|             res += [
 | |
|                 f".. _{title}:",
 | |
|                 "",
 | |
|                 title,
 | |
|                 "^" * len(title),
 | |
|                 "",
 | |
|                 "::",
 | |
|                 "",
 | |
|                 f"    {p.name} {access} {p.signature}",
 | |
|                 "",
 | |
|                 "",
 | |
|                 self._expand(p.doc_string, True),
 | |
|                 "",
 | |
|             ]
 | |
|             if p.since:
 | |
|                 res += [
 | |
|                     f"Property available since: {p.since}.",
 | |
|                     "",
 | |
|                 ]
 | |
|             if p.deprecated:
 | |
|                 res += [
 | |
|                     ".. warning::",
 | |
|                     "",
 | |
|                     "   This property is deprecated.",
 | |
|                     "",
 | |
|                     "",
 | |
|                 ]
 | |
|             res += [""]
 | |
|         return "\n".join(res)
 | |
| 
 | |
|     def _generate_method_signature(self, method):
 | |
|         """Generates the method signature as a code block."""
 | |
|         res = [
 | |
|             "::",
 | |
|             "",
 | |
|         ]
 | |
|         n_in_args = len(method.in_args)
 | |
|         n_out_args = len(method.out_args)
 | |
|         if n_in_args == 0 and n_out_args == 0:
 | |
|             res += [
 | |
|                 f"    {method.name} ()",
 | |
|             ]
 | |
|         else:
 | |
|             res += [
 | |
|                 f"    {method.name} (",
 | |
|             ]
 | |
|             for idx, arg in enumerate(method.in_args):
 | |
|                 if idx == n_in_args - 1 and n_out_args == 0:
 | |
|                     res += [
 | |
|                         f"      IN {arg.name} {arg.signature}",
 | |
|                     ]
 | |
|                 else:
 | |
|                     res += [
 | |
|                         f"      IN {arg.name} {arg.signature},",
 | |
|                     ]
 | |
|             for idx, arg in enumerate(method.out_args):
 | |
|                 if idx == n_out_args - 1:
 | |
|                     res += [
 | |
|                         f"      OUT {arg.name} {arg.signature}",
 | |
|                     ]
 | |
|                 else:
 | |
|                     res += [
 | |
|                         f"      OUT {arg.name} {arg.signature},",
 | |
|                     ]
 | |
|             res += [
 | |
|                 "    )",
 | |
|                 "",
 | |
|             ]
 | |
|         res += [""]
 | |
|         return "\n".join(res)
 | |
| 
 | |
|     def _generate_methods(self, iface):
 | |
|         """Generates the methods section."""
 | |
|         res = []
 | |
|         for m in iface.methods:
 | |
|             title = f"{iface.name}.{m.name}"
 | |
|             res += [
 | |
|                 f".. _{title}:",
 | |
|                 "",
 | |
|                 title,
 | |
|                 "^" * len(title),
 | |
|                 "",
 | |
|                 self._generate_method_signature(m),
 | |
|                 "",
 | |
|                 self._expand(m.doc_string, True),
 | |
|                 "",
 | |
|             ]
 | |
|             for a in m.in_args:
 | |
|                 arg_desc = self._expand(a.doc_string, True)
 | |
|                 res += [
 | |
|                     f"{a.name}",
 | |
|                     f"  {arg_desc}",
 | |
|                     "",
 | |
|                 ]
 | |
|             for a in m.out_args:
 | |
|                 arg_desc = self._expand(a.doc_string, True)
 | |
|                 res += [
 | |
|                     f"{a.name}",
 | |
|                     f"  {arg_desc}",
 | |
|                     "",
 | |
|                 ]
 | |
|             res += [""]
 | |
|             if m.since:
 | |
|                 res += [
 | |
|                     f"Method available since: {m.since}.",
 | |
|                     "",
 | |
|                 ]
 | |
|             if m.deprecated:
 | |
|                 res += [
 | |
|                     ".. warning::",
 | |
|                     "",
 | |
|                     "   This method is deprecated.",
 | |
|                     "",
 | |
|                     "",
 | |
|                 ]
 | |
|             res += [""]
 | |
|         return "\n".join(res)
 | |
| 
 | |
|     def _generate_signal_signature(self, signal):
 | |
|         """Generates the signal signature."""
 | |
|         res = [
 | |
|             "::",
 | |
|             "",
 | |
|         ]
 | |
|         n_args = len(signal.args)
 | |
|         if n_args == 0:
 | |
|             res += [
 | |
|                 f"    {signal.name} ()",
 | |
|             ]
 | |
|         else:
 | |
|             res += [
 | |
|                 f"    {signal.name} (",
 | |
|             ]
 | |
|             for idx, arg in enumerate(signal.args):
 | |
|                 if idx == n_args - 1:
 | |
|                     res += [
 | |
|                         f"      {arg.name} {arg.signature}",
 | |
|                     ]
 | |
|                 else:
 | |
|                     res += [
 | |
|                         f"      {arg.name} {arg.signature},",
 | |
|                     ]
 | |
|             res += [
 | |
|                 "    )",
 | |
|                 "",
 | |
|             ]
 | |
|         res += [""]
 | |
|         return "\n".join(res)
 | |
| 
 | |
|     def _generate_signals(self, iface):
 | |
|         """Generates the signals section."""
 | |
|         res = []
 | |
|         for s in iface.signals:
 | |
|             title = f"{iface.name}::{s.name}"
 | |
|             res += [
 | |
|                 f".. _{title}:",
 | |
|                 "",
 | |
|                 title,
 | |
|                 "^" * len(title),
 | |
|                 "",
 | |
|                 self._generate_signal_signature(s),
 | |
|                 "",
 | |
|                 self._expand(s.doc_string, True),
 | |
|                 "",
 | |
|             ]
 | |
|             for a in s.args:
 | |
|                 arg_desc = self._expand(a.doc_string, True)
 | |
|                 res += [
 | |
|                     f"{a.name}",
 | |
|                     f"  {arg_desc}",
 | |
|                     "",
 | |
|                 ]
 | |
|             res += [""]
 | |
|             if s.since:
 | |
|                 res += [
 | |
|                     f"Signal available since: {s.since}.",
 | |
|                     "",
 | |
|                 ]
 | |
|             if s.deprecated:
 | |
|                 res += [
 | |
|                     ".. warning::",
 | |
|                     "",
 | |
|                     "   This signal is deprecated.",
 | |
|                     "",
 | |
|                     "",
 | |
|                 ]
 | |
|             res += [""]
 | |
|         return "\n".join(res)
 | |
| 
 | |
|     def generate(self, rst, outdir):
 | |
|         """Generates the reStructuredText file for each interface."""
 | |
|         for i in self.ifaces:
 | |
|             with open(os.path.join(outdir, f"{rst}-{i.name}.rst"), "w") as outfile:
 | |
|                 outfile.write(self._generate_header(i))
 | |
|                 if len(i.properties) > 0:
 | |
|                     outfile.write(self._generate_section("Properties", i.name))
 | |
|                     outfile.write(self._generate_properties(i))
 | |
|                 if len(i.methods) > 0:
 | |
|                     outfile.write(self._generate_section("Methods", i.name))
 | |
|                     outfile.write(self._generate_methods(i))
 | |
|                 if len(i.signals) > 0:
 | |
|                     outfile.write(self._generate_section("Signals", i.name))
 | |
|                     outfile.write(self._generate_signals(i))
 |