Skip to content

Commit aef6481

Browse files
committed
feat: add optional colorized output support
Add ros2cli/color.py with an extensible colorizer framework that wraps sys.stdout and applies ANSI colors line-by-line. Colorizers are registered per (command, verb) pair; unregistered commands fall back to DefaultColorizer. Colorized output is activated when ROS_COLORIZED_OUTPUT=1 and stdout is a TTY, or via the new --color CLI flag. Signed-off-by: Peng Wang <penwang@qti.qualcomm.com>
1 parent 3b57dd3 commit aef6481

2 files changed

Lines changed: 382 additions & 0 deletions

File tree

ros2cli/ros2cli/cli.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616
import argparse
1717
import builtins
1818
import functools
19+
import os
1920
import signal
2021
import sys
2122

2223
from rclpy.executors import ExternalShutdownException
2324

25+
from ros2cli.color import ColoringStdout
26+
from ros2cli.color import get_colorizer
27+
from ros2cli.color import is_color_enabled
2428
from ros2cli.command import add_subparsers_on_demand
2529

2630

@@ -42,6 +46,11 @@ def main(*, script_name='ros2', argv=None, description=None, extension=None):
4246
'Do not force line buffering in stdout and instead use the python default buffering, '
4347
'which might be affected by PYTHONUNBUFFERED/-u and depends on whatever stdout is '
4448
'interactive or not'))
49+
parser.add_argument(
50+
'--color',
51+
action='store_true',
52+
default=False,
53+
help='Force colorized output (also enabled by ROS_COLORIZED_OUTPUT=1)')
4554

4655
# add arguments for command extension(s)
4756
if extension:
@@ -81,6 +90,15 @@ def main(*, script_name='ros2', argv=None, description=None, extension=None):
8190
# get extension identified by the passed command (if available)
8291
extension = getattr(args, selected_extension_key, None)
8392

93+
# activate colorized output if requested
94+
if args.color:
95+
os.environ['ROS_COLORIZED_OUTPUT'] = '1'
96+
if is_color_enabled():
97+
command_name = getattr(extension, 'NAME', '') if extension else ''
98+
verb_name = getattr(getattr(args, '_verb', None), 'NAME', '') or ''
99+
colorizer = get_colorizer(command_name, verb_name)
100+
sys.stdout = ColoringStdout(sys.stdout, colorizer)
101+
84102
# handle the case that no command was passed
85103
if extension is None:
86104
parser.print_help()

0 commit comments

Comments
 (0)