From af97140596371bb6566b999b85cb631afe96d82d Mon Sep 17 00:00:00 2001 From: Andreas Grapentin Date: Sun, 6 Mar 2022 14:45:35 +0100 Subject: [PATCH] implemented all output_format settings supported by i3status --- py3status/constants.py | 14 ++++++- py3status/core.py | 93 +++++++++++++++++++++++++++++++----------- py3status/module.py | 16 +++++--- 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/py3status/constants.py b/py3status/constants.py index 1febcd8d05..f2fcd5ff25 100644 --- a/py3status/constants.py +++ b/py3status/constants.py @@ -10,8 +10,18 @@ "output_format": "i3bar", } -DEFAULT_SEPARATORS = { - "tmux": "#[fg={color_separator}]|#[default]", +OUTPUT_FORMAT_NEEDS_SEPARATOR = [ + "dzen2", + "xmobar", + "lemonbar", + "tmux", + "term", + "none", +] + +DEFAULT_SEPARATOR = { + "dzen2": "^p(5;-2)^ro(2)^p()^p(5)", + # if it's not listed here, it defaults to " | " } MAX_NESTING_LEVELS = 4 diff --git a/py3status/core.py b/py3status/core.py index 00a8c2f23c..ff24c66413 100644 --- a/py3status/core.py +++ b/py3status/core.py @@ -13,7 +13,7 @@ from traceback import extract_tb, format_tb, format_stack from py3status.command import CommandServer -from py3status.constants import DEFAULT_SEPARATORS +from py3status.constants import OUTPUT_FORMAT_NEEDS_SEPARATOR, DEFAULT_SEPARATOR from py3status.events import Events from py3status.formatter import expand_color from py3status.helpers import print_stderr @@ -681,17 +681,18 @@ def setup(self): # determine the target output format self.output_format = self.config["py3_config"]["general"]["output_format"] - # determine the separator between status entries, if needed - default_separator = DEFAULT_SEPARATORS.get(self.output_format, None) - self.output_format_separator = self.config["py3_config"]["py3status"].get( - "output_format_separator", default_separator - ) - - # inject the value of color_separator into the separator string - if self.output_format_separator is not None: - self.output_format_separator = self.output_format_separator.format( - color_separator=self.config["py3_config"]["general"]["color_separator"] + # determine the output separator, if needed + self.separator = None + if self.output_format in OUTPUT_FORMAT_NEEDS_SEPARATOR: + default_separator = DEFAULT_SEPARATOR.get(self.output_format, " | ") + self.separator = self.config["py3_config"]["general"].get( + "separator", default_separator ) + if self.config["py3_config"]["general"]["colors"]: + self.separator = self.format_separator( + self.separator, + self.config["py3_config"]["general"]["color_separator"], + ) def notify_user( self, @@ -970,6 +971,53 @@ def create_mappings(self, config): # Store mappings for later use. self.mappings_color = mappings + def format_color(self, output): + """ + Format the output of a module according to the value of output_format. + """ + full_text = output["full_text"] + if "color" in output: + if self.output_format == "dzen2": + full_text = f"^fg({output['color']})" + output["full_text"] + if self.output_format == "xmobar": + full_text = f"{output['full_text']}" + if self.output_format == "lemonbar": + full_text = f"%{{F{output['color']}}}" + output["full_text"] + if self.output_format == "tmux": + full_text = f"#[fg={output['color'].lower()}]" + output["full_text"] + if self.output_format == "term": + col = int(output["color"][1:], 16) + r = (col & (0xFF << 0)) // 0x80 + g = (col & (0xFF << 8)) // 0x8000 + b = (col & (0xFF << 16)) // 0x800000 + col = (r << 2) | (g << 1) | b + full_text = f"\033[3{col};1m" + output["full_text"] + if self.output_format == "none": + pass # colors are ignored + return full_text + + def format_separator(self, separator, color_separator): + """ + Format the output separator according to the value of output_format. + """ + if self.output_format == "dzen2": + return f"^fg({color_separator}){separator}^fg()" + if self.output_format == "xmobar": + return f"{separator}" + if self.output_format == "lemonbar": + return f"%{{F{color_separator}}}{separator}%{{F-}}" + if self.output_format == "tmux": + return f"#[fg={color_separator}]{separator}#[default]" + if self.output_format == "term": + col = int(color_separator[1:], 16) + r = (col & (0xFF << 0)) // 0x80 + g = (col & (0xFF << 8)) // 0x8000 + b = (col & (0xFF << 16)) // 0x800000 + col = (r << 2) | (g << 1) | b + return f"\033[3{col};1m{separator}\033[0m" + else: # output_format == "none" + return separator # color_separator is ignored + def process_module_output(self, module): """ Process the output for a module and return a json string representing it. @@ -986,15 +1034,13 @@ def process_module_output(self, module): # Color: substitute the config defined color if "color" not in output: output["color"] = color - # Create the tmux string output. - if self.output_format == "tmux": - for output in outputs: - if "color" in output: - output[ - "full_text" - ] = f"#[fg={output['color'].lower()}]{output['full_text']}#[default]" - return "".join(x["full_text"] for x in outputs) - # Create the json string output. + # concatenate string output, if needed. + if self.output_format in OUTPUT_FORMAT_NEEDS_SEPARATOR: + # FIXME: `output_format = none` in config will default to i3bar. + # `output_format = "none"` is required instead. this is different + # in i3status, which behaves correctly for `output_status = none` + return "".join(self.format_color(x) for x in outputs) + # otherwise create the json string output. else: return ",".join(dumps(x) for x in outputs) @@ -1066,7 +1112,7 @@ def run(self): "click_events": self.config["click_events"], "stop_signal": self.stop_signal or 0, } - if self.output_format != "tmux": + if self.output_format not in OUTPUT_FORMAT_NEEDS_SEPARATOR: write(dumps(header)) write("\n[[]\n") @@ -1096,9 +1142,8 @@ def run(self): output[index] = out # build output string and dump to stdout - out = "" - if self.output_format == "tmux": - out = self.output_format_separator.join(x for x in output if x) + if self.output_format in OUTPUT_FORMAT_NEEDS_SEPARATOR: + out = self.separator.join(x for x in output if x) write(f"{out}\n") else: out = ",".join(x for x in output if x) diff --git a/py3status/module.py b/py3status/module.py index f76083af7a..1170572b15 100644 --- a/py3status/module.py +++ b/py3status/module.py @@ -337,11 +337,17 @@ def set_module_options(self, module): separator = fn(self.module_full_name, "separator") if not hasattr(separator, "none_setting"): - if not isinstance(separator, bool): - err = "Invalid `separator` attribute, should be a boolean. " - err += f"Got `{separator}`." - raise TypeError(err) - self.i3bar_module_options["separator"] = separator + # HACK: separator is a valid setting in the general section + # of the configuration. but it's a string, not a boolean. + # revisit how i3status and py3status differ in this regard. + # if not isinstance(separator, bool): + + # err = "Invalid `separator` attribute, should be a boolean. " + # err += f"Got `{separator}`." + # raise TypeError(err) + # self.i3bar_module_options["separator"] = separator + if isinstance(separator, bool): + self.i3bar_module_options["separator"] = separator separator_block_width = fn(self.module_full_name, "separator_block_width") if not hasattr(separator_block_width, "none_setting"):