Skip to content

Commit 6b036ec

Browse files
committed
Refactor colors Class for Curses UI
1 parent e086625 commit 6b036ec

File tree

3 files changed

+167
-126
lines changed

3 files changed

+167
-126
lines changed

glances/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,10 @@ def init_ui_mode(self, args):
720720
args.time = 1
721721
args.disable_history = True
722722

723+
# Unicode => No separator
724+
if args.disable_unicode:
725+
args.enable_separator = False
726+
723727
def parse_args(self):
724728
"""Parse command line arguments."""
725729
args = self.init_args().parse_args()

glances/outputs/glances_colors.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#
2+
# This file is part of Glances.
3+
#
4+
# SPDX-FileCopyrightText: 2024 Nicolas Hennion <nicolas@nicolargo.com>
5+
#
6+
# SPDX-License-Identifier: LGPL-3.0-only
7+
#
8+
9+
"""Glances colors."""
10+
11+
import sys
12+
13+
from glances.logger import logger
14+
15+
try:
16+
import curses
17+
except ImportError:
18+
logger.critical("Curses module not found. Glances cannot start in standalone mode.")
19+
sys.exit(1)
20+
21+
22+
class GlancesColors:
23+
"""Class to manage colors in Glances UI
24+
For the moment limited to Curses interface.
25+
But will be used in the WebUI through the issue #2048"""
26+
27+
def __init__(self, args) -> None:
28+
self.args = args
29+
30+
# Define "home made" bold
31+
self.A_BOLD = 0 if args.disable_bold else curses.A_BOLD
32+
33+
# Set defaults curses colors
34+
try:
35+
if hasattr(curses, 'start_color'):
36+
curses.start_color()
37+
logger.debug(f'Curses interface compatible with {curses.COLORS} colors')
38+
if hasattr(curses, 'use_default_colors'):
39+
# Use -1 to use the default foregound/background color
40+
curses.use_default_colors()
41+
if hasattr(curses, 'assume_default_colors'):
42+
# Define the color index 0 with -1 and -1 for foregound/background
43+
# = curses.init_pair(0, -1, -1)
44+
curses.assume_default_colors(-1, -1)
45+
except Exception as e:
46+
logger.warning(f'Error initializing terminal color ({e})')
47+
48+
if curses.has_colors():
49+
# The screen is compatible with a colored design
50+
# ex: export TERM=xterm-256color
51+
# export TERM=xterm-color
52+
self.__define_colors()
53+
else:
54+
# The screen is NOT compatible with a colored design
55+
# switch to B&W text styles
56+
# ex: export TERM=xterm-mono
57+
self.__define_bw()
58+
59+
def __repr__(self) -> dict:
60+
return self.get()
61+
62+
def __define_colors(self) -> None:
63+
curses.init_pair(1, -1, -1)
64+
if self.args.disable_bg:
65+
curses.init_pair(2, curses.COLOR_RED, -1)
66+
curses.init_pair(3, curses.COLOR_GREEN, -1)
67+
curses.init_pair(5, curses.COLOR_MAGENTA, -1)
68+
else:
69+
curses.init_pair(2, -1, curses.COLOR_RED)
70+
curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_GREEN)
71+
curses.init_pair(5, -1, curses.COLOR_MAGENTA)
72+
curses.init_pair(4, curses.COLOR_BLUE, -1)
73+
curses.init_pair(6, curses.COLOR_RED, -1)
74+
curses.init_pair(7, curses.COLOR_GREEN, -1)
75+
curses.init_pair(8, curses.COLOR_MAGENTA, -1)
76+
77+
# Colors text styles
78+
self.DEFAULT = curses.color_pair(1)
79+
self.OK_LOG = curses.color_pair(3) | self.A_BOLD
80+
self.NICE = curses.color_pair(8)
81+
self.CPU_TIME = curses.color_pair(8)
82+
self.CAREFUL_LOG = curses.color_pair(4) | self.A_BOLD
83+
self.WARNING_LOG = curses.color_pair(5) | self.A_BOLD
84+
self.CRITICAL_LOG = curses.color_pair(2) | self.A_BOLD
85+
self.OK = curses.color_pair(7)
86+
self.CAREFUL = curses.color_pair(4)
87+
self.WARNING = curses.color_pair(8) | self.A_BOLD
88+
self.CRITICAL = curses.color_pair(6) | self.A_BOLD
89+
self.INFO = curses.color_pair(4)
90+
self.FILTER = self.A_BOLD
91+
self.SELECTED = self.A_BOLD
92+
self.SEPARATOR = curses.color_pair(1)
93+
94+
if curses.COLORS > 8:
95+
# ex: export TERM=xterm-256color
96+
try:
97+
curses.init_pair(9, curses.COLOR_CYAN, -1)
98+
curses.init_pair(10, curses.COLOR_YELLOW, -1)
99+
except Exception:
100+
curses.init_pair(9, -1, -1)
101+
curses.init_pair(10, -1, -1)
102+
self.FILTER = curses.color_pair(9) | self.A_BOLD
103+
self.SELECTED = curses.color_pair(10) | self.A_BOLD
104+
105+
# Define separator line style
106+
try:
107+
curses.init_color(11, 500, 500, 500)
108+
curses.init_pair(11, curses.COLOR_BLACK, -1)
109+
self.SEPARATOR = curses.color_pair(11)
110+
except Exception:
111+
# Catch exception in TMUX
112+
pass
113+
114+
def __define_bw(self) -> None:
115+
# The screen is NOT compatible with a colored design
116+
# switch to B&W text styles
117+
# ex: export TERM=xterm-mono
118+
self.DEFAULT = -1
119+
self.OK_LOG = -1
120+
self.NICE = self.A_BOLD
121+
self.CPU_TIME = self.A_BOLD
122+
self.CAREFUL_LOG = self.A_BOLD
123+
self.WARNING_LOG = curses.A_UNDERLINE
124+
self.CRITICAL_LOG = curses.A_REVERSE
125+
self.OK = -1
126+
self.CAREFUL = self.A_BOLD
127+
self.WARNING = curses.A_UNDERLINE
128+
self.CRITICAL = curses.A_REVERSE
129+
self.INFO = self.A_BOLD
130+
self.FILTER = self.A_BOLD
131+
self.SELECTED = self.A_BOLD
132+
self.SEPARATOR = -1
133+
134+
def get(self) -> dict:
135+
return {
136+
'DEFAULT': self.DEFAULT,
137+
'UNDERLINE': curses.A_UNDERLINE,
138+
'BOLD': self.A_BOLD,
139+
'SORT': curses.A_UNDERLINE | self.A_BOLD,
140+
'OK': self.OK,
141+
'MAX': self.OK | self.A_BOLD,
142+
'FILTER': self.FILTER,
143+
'TITLE': self.A_BOLD,
144+
'PROCESS': self.OK,
145+
'PROCESS_SELECTED': self.OK | curses.A_UNDERLINE,
146+
'STATUS': self.OK,
147+
'NICE': self.NICE,
148+
'CPU_TIME': self.CPU_TIME,
149+
'CAREFUL': self.CAREFUL,
150+
'WARNING': self.WARNING,
151+
'CRITICAL': self.CRITICAL,
152+
'OK_LOG': self.OK_LOG,
153+
'CAREFUL_LOG': self.CAREFUL_LOG,
154+
'WARNING_LOG': self.WARNING_LOG,
155+
'CRITICAL_LOG': self.CRITICAL_LOG,
156+
'PASSWORD': curses.A_PROTECT,
157+
'SELECTED': self.SELECTED,
158+
'INFO': self.INFO,
159+
'ERROR': self.SELECTED,
160+
'SEPARATOR': self.SEPARATOR,
161+
}

glances/outputs/glances_curses.py

Lines changed: 2 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from glances.events_list import glances_events
1515
from glances.globals import MACOS, WINDOWS, disable, enable, itervalues, nativestr, u
1616
from glances.logger import logger
17+
from glances.outputs.glances_colors import GlancesColors
1718
from glances.outputs.glances_unicode import unicode_message
1819
from glances.processes import glances_processes, sort_processes_key_list
1920
from glances.timer import Timer
@@ -162,7 +163,7 @@ def __init__(self, config=None, args=None):
162163
self._init_cursor()
163164

164165
# Init the colors
165-
self.colors_list = build_colors_list(args)
166+
self.colors_list = GlancesColors(args).get()
166167

167168
# Init main window
168169
self.term_window = self.screen.subwin(0, 0)
@@ -1179,128 +1180,3 @@ def __init__(self, *args, **kwargs):
11791180

11801181
def do_command(self, ch):
11811182
return super().do_command(ch)
1182-
1183-
1184-
def build_colors_list(args):
1185-
"""Init the Curses color layout."""
1186-
# Set curses options
1187-
try:
1188-
if hasattr(curses, 'start_color'):
1189-
curses.start_color()
1190-
logger.debug(f'Curses interface compatible with {curses.COLORS} colors')
1191-
if hasattr(curses, 'use_default_colors'):
1192-
curses.use_default_colors()
1193-
except Exception as e:
1194-
logger.warning(f'Error initializing terminal color ({e})')
1195-
1196-
# Init colors
1197-
if args.disable_bold:
1198-
A_BOLD = 0
1199-
args.disable_bg = True
1200-
else:
1201-
A_BOLD = curses.A_BOLD
1202-
1203-
title_color = A_BOLD
1204-
1205-
if curses.has_colors():
1206-
# The screen is compatible with a colored design
1207-
# ex: export TERM=xterm-256color
1208-
# export TERM=xterm-color
1209-
1210-
curses.init_pair(1, -1, -1)
1211-
if args.disable_bg:
1212-
curses.init_pair(2, curses.COLOR_RED, -1)
1213-
curses.init_pair(3, curses.COLOR_GREEN, -1)
1214-
curses.init_pair(5, curses.COLOR_MAGENTA, -1)
1215-
else:
1216-
curses.init_pair(2, -1, curses.COLOR_RED)
1217-
curses.init_pair(3, 0, curses.COLOR_GREEN)
1218-
curses.init_pair(5, -1, curses.COLOR_MAGENTA)
1219-
curses.init_pair(4, curses.COLOR_BLUE, -1)
1220-
curses.init_pair(6, curses.COLOR_RED, -1)
1221-
curses.init_pair(7, curses.COLOR_GREEN, -1)
1222-
curses.init_pair(8, curses.COLOR_MAGENTA, -1)
1223-
1224-
# Colors text styles
1225-
no_color = curses.color_pair(1)
1226-
default_color = curses.color_pair(3) | A_BOLD
1227-
nice_color = curses.color_pair(8)
1228-
cpu_time_color = curses.color_pair(8)
1229-
ifCAREFUL_color = curses.color_pair(4) | A_BOLD
1230-
ifWARNING_color = curses.color_pair(5) | A_BOLD
1231-
ifCRITICAL_color = curses.color_pair(2) | A_BOLD
1232-
default_color2 = curses.color_pair(7)
1233-
ifCAREFUL_color2 = curses.color_pair(4)
1234-
ifWARNING_color2 = curses.color_pair(8) | A_BOLD
1235-
ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD
1236-
ifINFO_color = curses.color_pair(4)
1237-
filter_color = A_BOLD
1238-
selected_color = A_BOLD
1239-
separator = curses.color_pair(1)
1240-
1241-
if curses.COLORS > 8:
1242-
# ex: export TERM=xterm-256color
1243-
colors_list = [curses.COLOR_CYAN, curses.COLOR_YELLOW]
1244-
for i in range(0, 3):
1245-
try:
1246-
curses.init_pair(i + 9, colors_list[i], -1)
1247-
except Exception:
1248-
curses.init_pair(i + 9, -1, -1)
1249-
filter_color = curses.color_pair(9) | A_BOLD
1250-
selected_color = curses.color_pair(10) | A_BOLD
1251-
# Define separator line style
1252-
try:
1253-
curses.init_color(11, 500, 500, 500)
1254-
curses.init_pair(11, curses.COLOR_BLACK, -1)
1255-
separator = curses.color_pair(11)
1256-
except Exception:
1257-
# Catch exception in TMUX
1258-
pass
1259-
else:
1260-
# The screen is NOT compatible with a colored design
1261-
# switch to B&W text styles
1262-
# ex: export TERM=xterm-mono
1263-
no_color = -1
1264-
default_color = -1
1265-
nice_color = A_BOLD
1266-
cpu_time_color = A_BOLD
1267-
ifCAREFUL_color = A_BOLD
1268-
ifWARNING_color = curses.A_UNDERLINE
1269-
ifCRITICAL_color = curses.A_REVERSE
1270-
default_color2 = -1
1271-
ifCAREFUL_color2 = A_BOLD
1272-
ifWARNING_color2 = curses.A_UNDERLINE
1273-
ifCRITICAL_color2 = curses.A_REVERSE
1274-
ifINFO_color = A_BOLD
1275-
filter_color = A_BOLD
1276-
selected_color = A_BOLD
1277-
separator = -1
1278-
1279-
# Define the colors list (hash table) for stats
1280-
return {
1281-
'DEFAULT': no_color,
1282-
'UNDERLINE': curses.A_UNDERLINE,
1283-
'BOLD': A_BOLD,
1284-
'SORT': curses.A_UNDERLINE | A_BOLD,
1285-
'OK': default_color2,
1286-
'MAX': default_color2 | A_BOLD,
1287-
'FILTER': filter_color,
1288-
'TITLE': title_color,
1289-
'PROCESS': default_color2,
1290-
'PROCESS_SELECTED': default_color2 | curses.A_UNDERLINE,
1291-
'STATUS': default_color2,
1292-
'NICE': nice_color,
1293-
'CPU_TIME': cpu_time_color,
1294-
'CAREFUL': ifCAREFUL_color2,
1295-
'WARNING': ifWARNING_color2,
1296-
'CRITICAL': ifCRITICAL_color2,
1297-
'OK_LOG': default_color,
1298-
'CAREFUL_LOG': ifCAREFUL_color,
1299-
'WARNING_LOG': ifWARNING_color,
1300-
'CRITICAL_LOG': ifCRITICAL_color,
1301-
'PASSWORD': curses.A_PROTECT,
1302-
'SELECTED': selected_color,
1303-
'INFO': ifINFO_color,
1304-
'ERROR': selected_color,
1305-
'SEPARATOR': separator,
1306-
}

0 commit comments

Comments
 (0)