summaryrefslogtreecommitdiff
path: root/doc/tools/make_rst.py
diff options
context:
space:
mode:
Diffstat (limited to 'doc/tools/make_rst.py')
-rwxr-xr-xdoc/tools/make_rst.py79
1 files changed, 67 insertions, 12 deletions
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index eba4cee33a..ce09361dfa 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -4,7 +4,9 @@
import argparse
import os
+import platform
import re
+import sys
import xml.etree.ElementTree as ET
from collections import OrderedDict
@@ -55,9 +57,11 @@ BASE_STRINGS = [
]
strings_l10n = {}
+STYLES = {}
+
def print_error(error, state): # type: (str, State) -> None
- print("ERROR: {}".format(error))
+ print("{}{}ERROR:{} {}{}".format(STYLES["red"], STYLES["bold"], STYLES["regular"], error, STYLES["reset"]))
state.num_errors += 1
@@ -399,10 +403,26 @@ def parse_arguments(root): # type: (ET.Element) -> List[ParameterDef]
def main(): # type: () -> None
+ # Enable ANSI escape code support on Windows 10 and later (for colored console output).
+ # <https://bugs.python.org/issue29059>
+ if platform.system().lower() == "windows":
+ from ctypes import windll, c_int, byref
+
+ stdout_handle = windll.kernel32.GetStdHandle(c_int(-11))
+ mode = c_int(0)
+ windll.kernel32.GetConsoleMode(c_int(stdout_handle), byref(mode))
+ mode = c_int(mode.value | 4)
+ windll.kernel32.SetConsoleMode(c_int(stdout_handle), mode)
+
parser = argparse.ArgumentParser()
parser.add_argument("path", nargs="+", help="A path to an XML file or a directory containing XML files to parse.")
parser.add_argument("--filter", default="", help="The filepath pattern for XML files to filter.")
parser.add_argument("--lang", "-l", default="en", help="Language to use for section headings.")
+ parser.add_argument(
+ "--color",
+ action="store_true",
+ help="If passed, force colored output even if stdout is not a TTY (useful for continuous integration).",
+ )
group = parser.add_mutually_exclusive_group()
group.add_argument("--output", "-o", default=".", help="The directory to save output .rst files in.")
group.add_argument(
@@ -412,6 +432,13 @@ def main(): # type: () -> None
)
args = parser.parse_args()
+ should_color = args.color or (hasattr(sys.stdout, "isatty") and sys.stdout.isatty())
+ STYLES["red"] = "\x1b[91m" if should_color else ""
+ STYLES["green"] = "\x1b[92m" if should_color else ""
+ STYLES["bold"] = "\x1b[1m" if should_color else ""
+ STYLES["regular"] = "\x1b[22m" if should_color else ""
+ STYLES["reset"] = "\x1b[0m" if should_color else ""
+
# Retrieve heading translations for the given language.
if not args.dry_run and args.lang != "en":
lang_file = os.path.join(
@@ -464,17 +491,17 @@ def main(): # type: () -> None
try:
tree = ET.parse(cur_file)
except ET.ParseError as e:
- print_error("{}.xml: Parse error while reading the file: {}".format(cur_file, e), state)
+ print_error("{}: Parse error while reading the file: {}".format(cur_file, e), state)
continue
doc = tree.getroot()
if "version" not in doc.attrib:
- print_error('{}.xml: "version" attribute missing from "doc".'.format(cur_file), state)
+ print_error('{}: "version" attribute missing from "doc".'.format(cur_file), state)
continue
name = doc.attrib["name"]
if name in classes:
- print_error('{}.xml: Duplicate class "{}".'.format(cur_file, name), state)
+ print_error('{}: Duplicate class "{}".'.format(cur_file, name), state)
continue
classes[name] = (doc, cur_file)
@@ -499,16 +526,22 @@ def main(): # type: () -> None
make_rst_class(class_def, state, args.dry_run, args.output)
if state.num_errors == 0:
- print("No errors found in the class reference XML.")
+ print("{}No errors found in the class reference XML.{}".format(STYLES["green"], STYLES["reset"]))
if not args.dry_run:
print("Wrote reStructuredText files for each class to: %s" % args.output)
else:
if state.num_errors >= 2:
print(
- "%d errors were found in the class reference XML. Please check the messages above." % state.num_errors
+ "{}{} errors were found in the class reference XML. Please check the messages above.{}".format(
+ STYLES["red"], state.num_errors, STYLES["reset"]
+ )
)
else:
- print("1 error was found in the class reference XML. Please check the messages above.")
+ print(
+ "{}1 error was found in the class reference XML. Please check the messages above.{}".format(
+ STYLES["red"], STYLES["reset"]
+ )
+ )
exit(1)
@@ -677,7 +710,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
for value in e.values.values():
f.write("- **{}** = **{}**".format(value.name, value.value))
if value.text is not None and value.text.strip() != "":
- f.write(" --- " + rstize_text(value.text.strip(), state))
+ # If value.text contains a bullet point list, each entry needs additional indentation
+ f.write(" --- " + indent_bullets(rstize_text(value.text.strip(), state)))
f.write("\n\n")
@@ -879,9 +913,9 @@ def format_codeblock(code_type, post_text, indent_level, state): # types: str,
if to_skip > indent_level:
print_error(
- "{}.xml: Four spaces should be used for indentation within ["
- + code_type
- + "].".format(state.current_class),
+ "{}.xml: Four spaces should be used for indentation within [{}].".format(
+ state.current_class, code_type
+ ),
state,
)
@@ -904,7 +938,7 @@ def rstize_text(text, state): # type: (str, State) -> str
pre_text = text[:pos]
indent_level = 0
- while text[pos + 1] == "\t":
+ while pos + 1 < len(text) and text[pos + 1] == "\t":
pos += 1
indent_level += 1
post_text = text[pos + 1 :]
@@ -1409,6 +1443,8 @@ def sanitize_operator_name(dirty_name, state): # type: (str, State) -> str
clear_name = "div"
elif clear_name == "%":
clear_name = "mod"
+ elif clear_name == "**":
+ clear_name = "pow"
elif clear_name == "unary+":
clear_name = "unplus"
@@ -1438,5 +1474,24 @@ def sanitize_operator_name(dirty_name, state): # type: (str, State) -> str
return clear_name
+def indent_bullets(text): # type: (str) -> str
+ # Take the text and check each line for a bullet point represented by "-".
+ # Where found, indent the given line by a further "\t".
+ # Used to properly indent bullet points contained in the description for enum values.
+ # Ignore the first line - text will be prepended to it so bullet points wouldn't work anyway.
+ bullet_points = "-"
+
+ lines = text.splitlines(keepends=True)
+ for line_index, line in enumerate(lines[1:], start=1):
+ pos = 0
+ while pos < len(line) and line[pos] == "\t":
+ pos += 1
+
+ if pos < len(line) and line[pos] in bullet_points:
+ lines[line_index] = line[:pos] + "\t" + line[pos:]
+
+ return "".join(lines)
+
+
if __name__ == "__main__":
main()