rougail-output-display/src/rougail/output_display/output/console.py
2025-12-04 21:21:54 +01:00

197 lines
6.9 KiB
Python

"""
Silique (https://www.silique.fr)
Copyright (C) 2022-2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from rich.console import Console
from rich.tree import Tree
from rich.table import Table
from rich.panel import Panel
from ..i18n import _
from ..util import CommonOutput
class OutputFamily(CommonOutput):
level = 10
name = "console"
variable_hidden_color = "orange1"
variable_normal_color = None
value_unmodified_color = "gold1"
value_modified_color = "green"
value_default_color = None
error_color = 'bright_red'
def run(self):
max_width = self.root.rougailconfig["display.console.max_width"]
self.console = Console(force_terminal=True, width=max_width)
with self.console.capture() as capture:
ret = self.root.print()
return ret, capture.get()
def print(self) -> None:
ret = self.root.exporter()
for out in self.out:
self.console.print(out)
return ret
def header(self):
caption_line = ""
if self.root_family.variable_default_enable:
caption_line += _("Variable") + "\n"
if self.root_family.variable_hidden_enable:
caption_line += f'[{self.variable_hidden_color}]{_("Unmodifiable variable")}[/{self.variable_hidden_color}]\n'
header_value = ""
if self.root_family.value_unmodified_enable:
header_value += f'[{self.value_unmodified_color}]{_("Default value")}[/{self.value_unmodified_color}]\n'
if self.root_family.value_modified_enable:
header_value += f'[{self.value_modified_color}]{_("Modified value")}[/{self.value_modified_color}]\n'
if self.root_family.value_default_enable:
header_value += f'(:hourglass_flowing_sand: {_("Original default value")})\n'
caption = Table.grid(padding=1, collapse_padding=True)
caption.pad_edge = False
caption.add_row(caption_line[:-1], header_value[:-1])
self.out.append(Panel.fit(caption, title=_("Caption")))
#
layers = Table.grid(padding=1, collapse_padding=True)
caption.pad_edge = False
if self.root.layer_datas:
max_len = 0
for datas in self.root.layer_datas.values():
for data in datas.values():
max_len = max(max_len, len(data))
display_layers = ["" for i in range(max_len)]
for datas in self.root.layer_datas.values():
for data in datas.values():
last_index = len(data) - 1
for idx in range(max_len):
if last_index < idx:
display_layers[idx] += "\n"
else:
display_layers[idx] += data[idx] + "\n"
layers.add_row(*[layer[:-1] for layer in display_layers])
self.out.append(Panel.fit(layers, title=_("Layers")))
def error_header(self):
tree = Tree(
f"[bold][{self.error_color}]:stop_sign: {_('ERRORS')}[/{self.error_color}][/bold]",
guide_style=f"bold {self.error_color}",
)
self.out.append(tree)
return tree
def display_error(self, tree, error, level):
return tree.add(error)
def display_warnings(
self,
warnings: list,
) -> None:
tree = Tree(
f"[bold][bright_yellow]:bell: {_('WARNINGS')}[/bright_yellow][/bold]",
guide_style="bold bright_yellow",
)
for warning in warnings:
tree.add(warning)
self.out.append(tree)
def add_variable(
self, *args, **kwargs,
):
key, value = super().add_variable(*args, **kwargs)
if isinstance(value, list):
subtree = self.get_tree().add(
":notebook: " + _("{0}:").format(key),
guide_style="bold bright_blue",
)
for val in value:
subtree.add(str(val))
else:
self.get_tree().add(":notebook: " + _("{0}: {1}").format(key, value))
def colorize(
self,
values,
option=None,
) -> str:
multi = False
ret = []
default = []
for idx, data in enumerate(values):
value = data["value"]
if isinstance(value, list):
multi = True
else:
value = [value]
for vidx, val in enumerate(value):
if len(ret) == vidx:
ret.append("")
default.append(False)
if idx:
if not default[vidx]:
if ret[vidx]:
ret[vidx] += " "
ret[vidx] += "("
default[vidx] = True
else:
ret[vidx] += " "
ret[vidx] += ":hourglass_flowing_sand: "
if option:
val = self.convert_value(
option,
val,
)
color = data["color"]
if color is not None:
ret[vidx] += f"[{color}]{val}[/{color}]"
else:
ret[vidx] += val
loaded_from = data["loaded_from"]
if loaded_from:
ret[vidx] += f" :arrow_backward: {loaded_from}"
for idx in range(len(ret)):
if default[idx]:
ret[idx] += ")"
if not multi:
if not ret:
return ""
return ret[0]
return ret
def get_tree(self):
if self.tree is None:
if self.parent is None:
tree = Tree
else:
tree = self.parent.add
# if self.is_leader:
# self.tree = tree(
# ":notebook: " + _("{0}:").format(self.family),
# guide_style="bold bright_blue",
# )
# elif self.no_icon:
if self.no_icon:
self.tree = tree(
self.family,
guide_style="bold bright_blue",
)
else:
self.tree = tree(
f":open_file_folder: {self.family}",
guide_style="bold bright_blue",
)
return self.tree