Skip to content

Commit 182b474

Browse files
committed
Merge pull request godotengine#93479 from Repiteo/scons/better-colored-output
SCons: Improve colored output
2 parents d60c0e2 + d8761f2 commit 182b474

File tree

12 files changed

+150
-255
lines changed

12 files changed

+150
-255
lines changed

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ repos:
9898
name: doc-status
9999
language: python
100100
entry: python doc/tools/doc_status.py
101-
args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes]
101+
args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes, -c]
102102
pass_filenames: false
103103
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
104104

SConstruct

+4-22
Original file line numberDiff line numberDiff line change
@@ -58,31 +58,13 @@ import gles3_builders
5858
import glsl_builders
5959
import methods
6060
import scu_builders
61-
from methods import print_error, print_warning
61+
from methods import Ansi, print_error, print_info, print_warning
6262
from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases
6363

6464
if ARGUMENTS.get("target", "editor") == "editor":
6565
_helper_module("editor.editor_builders", "editor/editor_builders.py")
6666
_helper_module("editor.template_builders", "editor/template_builders.py")
6767

68-
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
69-
# <https://github.com/python/cpython/issues/73245>
70-
if sys.stdout.isatty() and sys.platform == "win32":
71-
try:
72-
from ctypes import WinError, byref, windll # type: ignore
73-
from ctypes.wintypes import DWORD # type: ignore
74-
75-
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
76-
mode = DWORD(0)
77-
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
78-
raise WinError()
79-
mode = DWORD(mode.value | 4)
80-
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
81-
raise WinError()
82-
except Exception as e:
83-
methods._colorize = False
84-
print_error(f"Failed to enable ANSI escape code support, disabling color output.\n{e}")
85-
8668
# Scan possible build platforms
8769

8870
platform_list = [] # list of platforms
@@ -635,7 +617,7 @@ detect.configure(env)
635617

636618
print(f'Building for platform "{env["platform"]}", architecture "{env["arch"]}", target "{env["target"]}".')
637619
if env.dev_build:
638-
print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).")
620+
print_info("Developer build, with debug optimization level and debug symbols (unless overridden).")
639621

640622
# Enforce our minimal compiler version requirements
641623
cc_version = methods.get_compiler_version(env)
@@ -1111,10 +1093,10 @@ def print_elapsed_time():
11111093
time_centiseconds = round((elapsed_time_sec % 1) * 100)
11121094
print(
11131095
"{}[Time elapsed: {}.{:02}]{}".format(
1114-
methods.ANSI.GRAY,
1096+
Ansi.GRAY,
11151097
time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
11161098
time_centiseconds,
1117-
methods.ANSI.RESET,
1099+
Ansi.RESET,
11181100
)
11191101
)
11201102

doc/tools/doc_status.py

+18-29
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,21 @@
33
import fnmatch
44
import math
55
import os
6-
import platform
76
import re
87
import sys
98
import xml.etree.ElementTree as ET
109
from typing import Dict, List, Set
1110

11+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
12+
13+
from methods import COLOR_SUPPORTED, Ansi, toggle_color
14+
1215
################################################################################
1316
# Config #
1417
################################################################################
1518

1619
flags = {
17-
"c": platform.platform() != "Windows", # Disable by default on windows, since we use ANSI escape codes
20+
"c": COLOR_SUPPORTED,
1821
"b": False,
1922
"g": False,
2023
"s": False,
@@ -85,16 +88,16 @@
8588
"Constructors",
8689
]
8790
colors = {
88-
"name": [36], # cyan
89-
"part_big_problem": [4, 31], # underline, red
90-
"part_problem": [31], # red
91-
"part_mostly_good": [33], # yellow
92-
"part_good": [32], # green
93-
"url": [4, 34], # underline, blue
94-
"section": [1, 4], # bold, underline
95-
"state_off": [36], # cyan
96-
"state_on": [1, 35], # bold, magenta/plum
97-
"bold": [1], # bold
91+
"name": [Ansi.CYAN], # cyan
92+
"part_big_problem": [Ansi.RED, Ansi.UNDERLINE], # underline, red
93+
"part_problem": [Ansi.RED], # red
94+
"part_mostly_good": [Ansi.YELLOW], # yellow
95+
"part_good": [Ansi.GREEN], # green
96+
"url": [Ansi.BLUE, Ansi.UNDERLINE], # underline, blue
97+
"section": [Ansi.BOLD, Ansi.UNDERLINE], # bold, underline
98+
"state_off": [Ansi.CYAN], # cyan
99+
"state_on": [Ansi.BOLD, Ansi.MAGENTA], # bold, magenta/plum
100+
"bold": [Ansi.BOLD], # bold
98101
}
99102
overall_progress_description_weight = 10
100103

@@ -111,13 +114,8 @@ def validate_tag(elem: ET.Element, tag: str) -> None:
111114

112115

113116
def color(color: str, string: str) -> str:
114-
if flags["c"] and terminal_supports_color():
115-
color_format = ""
116-
for code in colors[color]:
117-
color_format += "\033[" + str(code) + "m"
118-
return color_format + string + "\033[0m"
119-
else:
120-
return string
117+
color_format = "".join([str(x) for x in colors[color]])
118+
return f"{color_format}{string}{Ansi.RESET}"
121119

122120

123121
ansi_escape = re.compile(r"\x1b[^m]*m")
@@ -127,16 +125,6 @@ def nonescape_len(s: str) -> int:
127125
return len(ansi_escape.sub("", s))
128126

129127

130-
def terminal_supports_color():
131-
p = sys.platform
132-
supported_platform = p != "Pocket PC" and (p != "win32" or "ANSICON" in os.environ)
133-
134-
is_a_tty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty()
135-
if not supported_platform or not is_a_tty:
136-
return False
137-
return True
138-
139-
140128
################################################################################
141129
# Classes #
142130
################################################################################
@@ -342,6 +330,7 @@ def generate_for_class(c: ET.Element):
342330
table_column_names.append("Docs URL")
343331
table_columns.append("url")
344332

333+
toggle_color(flags["c"])
345334

346335
################################################################################
347336
# Help #

doc/tools/make_rst.py

+15-43
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
from collections import OrderedDict
1111
from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
1212

13-
# Import hardcoded version information from version.py
14-
root_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")
15-
sys.path.append(root_directory) # Include the root directory
16-
import version # noqa: E402
13+
sys.path.insert(0, root_directory := os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
14+
15+
import version
16+
from methods import Ansi, toggle_color
1717

1818
# $DOCS_URL/path/to/page.html(#fragment-tag)
1919
GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
@@ -90,8 +90,6 @@
9090
]
9191
strings_l10n: Dict[str, str] = {}
9292

93-
STYLES: Dict[str, str] = {}
94-
9593
CLASS_GROUPS: Dict[str, str] = {
9694
"global": "Globals",
9795
"node": "Nodes",
@@ -699,31 +697,7 @@ def main() -> None:
699697
)
700698
args = parser.parse_args()
701699

702-
should_color = bool(args.color or sys.stdout.isatty() or os.environ.get("CI"))
703-
704-
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
705-
# <https://github.com/python/cpython/issues/73245>
706-
if should_color and sys.stdout.isatty() and sys.platform == "win32":
707-
try:
708-
from ctypes import WinError, byref, windll # type: ignore
709-
from ctypes.wintypes import DWORD # type: ignore
710-
711-
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
712-
mode = DWORD(0)
713-
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
714-
raise WinError()
715-
mode = DWORD(mode.value | 4)
716-
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
717-
raise WinError()
718-
except Exception:
719-
should_color = False
720-
721-
STYLES["red"] = "\x1b[91m" if should_color else ""
722-
STYLES["green"] = "\x1b[92m" if should_color else ""
723-
STYLES["yellow"] = "\x1b[93m" if should_color else ""
724-
STYLES["bold"] = "\x1b[1m" if should_color else ""
725-
STYLES["regular"] = "\x1b[22m" if should_color else ""
726-
STYLES["reset"] = "\x1b[0m" if should_color else ""
700+
toggle_color(args.color)
727701

728702
# Retrieve heading translations for the given language.
729703
if not args.dry_run and args.lang != "en":
@@ -834,16 +808,16 @@ def main() -> None:
834808
if state.script_language_parity_check.hit_count > 0:
835809
if not args.verbose:
836810
print(
837-
f'{STYLES["yellow"]}{state.script_language_parity_check.hit_count} code samples failed parity check. Use --verbose to get more information.{STYLES["reset"]}'
811+
f"{Ansi.YELLOW}{state.script_language_parity_check.hit_count} code samples failed parity check. Use --verbose to get more information.{Ansi.RESET}"
838812
)
839813
else:
840814
print(
841-
f'{STYLES["yellow"]}{state.script_language_parity_check.hit_count} code samples failed parity check:{STYLES["reset"]}'
815+
f"{Ansi.YELLOW}{state.script_language_parity_check.hit_count} code samples failed parity check:{Ansi.RESET}"
842816
)
843817

844818
for class_name in state.script_language_parity_check.hit_map.keys():
845819
class_hits = state.script_language_parity_check.hit_map[class_name]
846-
print(f'{STYLES["yellow"]}- {len(class_hits)} hits in class "{class_name}"{STYLES["reset"]}')
820+
print(f'{Ansi.YELLOW}- {len(class_hits)} hits in class "{class_name}"{Ansi.RESET}')
847821

848822
for context, error in class_hits:
849823
print(f" - {error} in {format_context_name(context)}")
@@ -853,24 +827,22 @@ def main() -> None:
853827

854828
if state.num_warnings >= 2:
855829
print(
856-
f'{STYLES["yellow"]}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
830+
f"{Ansi.YELLOW}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{Ansi.RESET}"
857831
)
858832
elif state.num_warnings == 1:
859833
print(
860-
f'{STYLES["yellow"]}1 warning was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
834+
f"{Ansi.YELLOW}1 warning was found in the class reference XML. Please check the messages above.{Ansi.RESET}"
861835
)
862836

863837
if state.num_errors >= 2:
864838
print(
865-
f'{STYLES["red"]}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
839+
f"{Ansi.RED}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{Ansi.RESET}"
866840
)
867841
elif state.num_errors == 1:
868-
print(
869-
f'{STYLES["red"]}1 error was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
870-
)
842+
print(f"{Ansi.RED}1 error was found in the class reference XML. Please check the messages above.{Ansi.RESET}")
871843

872844
if state.num_warnings == 0 and state.num_errors == 0:
873-
print(f'{STYLES["green"]}No warnings or errors found in the class reference XML.{STYLES["reset"]}')
845+
print(f"{Ansi.GREEN}No warnings or errors found in the class reference XML.{Ansi.RESET}")
874846
if not args.dry_run:
875847
print(f"Wrote reStructuredText files for each class to: {args.output}")
876848
else:
@@ -881,12 +853,12 @@ def main() -> None:
881853

882854

883855
def print_error(error: str, state: State) -> None:
884-
print(f'{STYLES["red"]}{STYLES["bold"]}ERROR:{STYLES["regular"]} {error}{STYLES["reset"]}')
856+
print(f"{Ansi.RED}{Ansi.BOLD}ERROR:{Ansi.REGULAR} {error}{Ansi.RESET}")
885857
state.num_errors += 1
886858

887859

888860
def print_warning(warning: str, state: State) -> None:
889-
print(f'{STYLES["yellow"]}{STYLES["bold"]}WARNING:{STYLES["regular"]} {warning}{STYLES["reset"]}')
861+
print(f"{Ansi.YELLOW}{Ansi.BOLD}WARNING:{Ansi.REGULAR} {warning}{Ansi.RESET}")
890862
state.num_warnings += 1
891863

892864

0 commit comments

Comments
 (0)