Skip to content

Commit

Permalink
SCons: Improve colored output
Browse files Browse the repository at this point in the history
  • Loading branch information
Repiteo committed Dec 10, 2024
1 parent a372214 commit d8761f2
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 255 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ repos:
name: doc-status
language: python
entry: python doc/tools/doc_status.py
args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes]
args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes, -c]
pass_filenames: false
files: ^(doc/classes|.*/doc_classes)/.*\.xml$

Expand Down
26 changes: 4 additions & 22 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -58,31 +58,13 @@ import gles3_builders
import glsl_builders
import methods
import scu_builders
from methods import print_error, print_warning
from methods import Ansi, print_error, print_info, print_warning
from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases

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

# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if sys.stdout.isatty() and sys.platform == "win32":
try:
from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore

stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
mode = DWORD(0)
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
raise WinError()
mode = DWORD(mode.value | 4)
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
raise WinError()
except Exception as e:
methods._colorize = False
print_error(f"Failed to enable ANSI escape code support, disabling color output.\n{e}")

# Scan possible build platforms

platform_list = [] # list of platforms
Expand Down Expand Up @@ -630,7 +612,7 @@ detect.configure(env)

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

# Enforce our minimal compiler version requirements
cc_version = methods.get_compiler_version(env)
Expand Down Expand Up @@ -1095,10 +1077,10 @@ def print_elapsed_time():
time_centiseconds = round((elapsed_time_sec % 1) * 100)
print(
"{}[Time elapsed: {}.{:02}]{}".format(
methods.ANSI.GRAY,
Ansi.GRAY,
time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
time_centiseconds,
methods.ANSI.RESET,
Ansi.RESET,
)
)

Expand Down
47 changes: 18 additions & 29 deletions doc/tools/doc_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
import fnmatch
import math
import os
import platform
import re
import sys
import xml.etree.ElementTree as ET
from typing import Dict, List, Set

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))

from methods import COLOR_SUPPORTED, Ansi, toggle_color

################################################################################
# Config #
################################################################################

flags = {
"c": platform.platform() != "Windows", # Disable by default on windows, since we use ANSI escape codes
"c": COLOR_SUPPORTED,
"b": False,
"g": False,
"s": False,
Expand Down Expand Up @@ -85,16 +88,16 @@
"Constructors",
]
colors = {
"name": [36], # cyan
"part_big_problem": [4, 31], # underline, red
"part_problem": [31], # red
"part_mostly_good": [33], # yellow
"part_good": [32], # green
"url": [4, 34], # underline, blue
"section": [1, 4], # bold, underline
"state_off": [36], # cyan
"state_on": [1, 35], # bold, magenta/plum
"bold": [1], # bold
"name": [Ansi.CYAN], # cyan
"part_big_problem": [Ansi.RED, Ansi.UNDERLINE], # underline, red
"part_problem": [Ansi.RED], # red
"part_mostly_good": [Ansi.YELLOW], # yellow
"part_good": [Ansi.GREEN], # green
"url": [Ansi.BLUE, Ansi.UNDERLINE], # underline, blue
"section": [Ansi.BOLD, Ansi.UNDERLINE], # bold, underline
"state_off": [Ansi.CYAN], # cyan
"state_on": [Ansi.BOLD, Ansi.MAGENTA], # bold, magenta/plum
"bold": [Ansi.BOLD], # bold
}
overall_progress_description_weight = 10

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


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


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


def terminal_supports_color():
p = sys.platform
supported_platform = p != "Pocket PC" and (p != "win32" or "ANSICON" in os.environ)

is_a_tty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty()
if not supported_platform or not is_a_tty:
return False
return True


################################################################################
# Classes #
################################################################################
Expand Down Expand Up @@ -342,6 +330,7 @@ def generate_for_class(c: ET.Element):
table_column_names.append("Docs URL")
table_columns.append("url")

toggle_color(flags["c"])

################################################################################
# Help #
Expand Down
58 changes: 15 additions & 43 deletions doc/tools/make_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
from collections import OrderedDict
from typing import Any, Dict, List, Optional, TextIO, Tuple, Union

# Import hardcoded version information from version.py
root_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")
sys.path.append(root_directory) # Include the root directory
import version # noqa: E402
sys.path.insert(0, root_directory := os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))

import version
from methods import Ansi, toggle_color

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

STYLES: Dict[str, str] = {}

CLASS_GROUPS: Dict[str, str] = {
"global": "Globals",
"node": "Nodes",
Expand Down Expand Up @@ -699,31 +697,7 @@ def main() -> None:
)
args = parser.parse_args()

should_color = bool(args.color or sys.stdout.isatty() or os.environ.get("CI"))

# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if should_color and sys.stdout.isatty() and sys.platform == "win32":
try:
from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore

stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
mode = DWORD(0)
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
raise WinError()
mode = DWORD(mode.value | 4)
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
raise WinError()
except Exception:
should_color = False

STYLES["red"] = "\x1b[91m" if should_color else ""
STYLES["green"] = "\x1b[92m" if should_color else ""
STYLES["yellow"] = "\x1b[93m" 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 ""
toggle_color(args.color)

# Retrieve heading translations for the given language.
if not args.dry_run and args.lang != "en":
Expand Down Expand Up @@ -834,16 +808,16 @@ def main() -> None:
if state.script_language_parity_check.hit_count > 0:
if not args.verbose:
print(
f'{STYLES["yellow"]}{state.script_language_parity_check.hit_count} code samples failed parity check. Use --verbose to get more information.{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.script_language_parity_check.hit_count} code samples failed parity check. Use --verbose to get more information.{Ansi.RESET}"
)
else:
print(
f'{STYLES["yellow"]}{state.script_language_parity_check.hit_count} code samples failed parity check:{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.script_language_parity_check.hit_count} code samples failed parity check:{Ansi.RESET}"
)

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

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

if state.num_warnings >= 2:
print(
f'{STYLES["yellow"]}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)
elif state.num_warnings == 1:
print(
f'{STYLES["yellow"]}1 warning was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.YELLOW}1 warning was found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)

if state.num_errors >= 2:
print(
f'{STYLES["red"]}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.RED}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)
elif state.num_errors == 1:
print(
f'{STYLES["red"]}1 error was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
)
print(f"{Ansi.RED}1 error was found in the class reference XML. Please check the messages above.{Ansi.RESET}")

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


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


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


Expand Down
Loading

0 comments on commit d8761f2

Please sign in to comment.