From 388c59aefd4a5f97dbd2d37eb12917a9b9668d75 Mon Sep 17 00:00:00 2001 From: Andrew Hamilton Date: Wed, 11 May 2022 11:11:37 +1000 Subject: [PATCH] Coding style - Moved path_colored into lscolors. - Made lscolors a package. - Moved LS_COLORS.sh and LSCOLORS into lscolors. - Moved fill3.join into termstr so that lscolors can depend on termstr only. --- eris/eris/__main__.py | 23 +++++---- eris/eris/tools.py | 50 ++++--------------- eris/eris/webserver.py | 2 +- eris/setup.py | 4 +- eris/tests/__main___test.py | 3 +- eris/tests/tools_test.py | 4 +- fill3/fill3/__init__.py | 11 +--- fill3/tests/fill3_test.py | 3 +- {eris => lscolors}/LS_COLORS | 0 {eris/eris => lscolors/lscolors}/LS_COLORS.sh | 0 .../{lscolors.py => lscolors/__init__.py} | 40 +++++++++++++++ lscolors/setup.py | 6 ++- termstr/termstr.py | 9 ++++ 13 files changed, 85 insertions(+), 70 deletions(-) rename {eris => lscolors}/LS_COLORS (100%) rename {eris/eris => lscolors/lscolors}/LS_COLORS.sh (100%) rename lscolors/{lscolors.py => lscolors/__init__.py} (77%) diff --git a/eris/eris/__main__.py b/eris/eris/__main__.py index b405a0d..6283c06 100755 --- a/eris/eris/__main__.py +++ b/eris/eris/__main__.py @@ -35,6 +35,7 @@ import time import docopt import fill3 import fill3.terminal as terminal +import lscolors import pygments.styles import pyinotify import termstr @@ -122,7 +123,7 @@ class Entry: if self.highlighted is not None: self.results[self.highlighted].is_highlighted = True row_appearance = self.widget.appearance() - path = tools.path_colored(self.path) + path = lscolors.path_colored(self.path) padding = " " * (self.last_width - len(self.results) + 1) self.appearance_cache = [row_appearance[0] + padding + path] if self.highlighted is not None: @@ -136,7 +137,7 @@ class Entry: result_html, result_styles = result.as_html() html_parts.append(result_html) styles.update(result_styles) - path = tools.path_colored(self.path) + path = lscolors.path_colored(self.path) padding = " " * (Entry.MAX_WIDTH - len(self.widget.widgets) + 1) path_html, path_styles = termstr.TermStr(padding + path).as_html() return "".join(html_parts) + path_html, styles.union(path_styles) @@ -560,7 +561,7 @@ class Log: def log_message(self, message, timestamp=None, char_style=None): if isinstance(message, list): message = [part[1] if isinstance(part, tuple) else part for part in message] - message = fill3.join("", message) + message = termstr.join("", message) if char_style is not None: message = termstr.TermStr(message, char_style) timestamp = time.strftime("%H:%M:%S", time.localtime()) if timestamp is None else timestamp @@ -587,12 +588,12 @@ def highlight_chars(str_, style, marker="*"): parts = str_.split(marker) highlighted_parts = [termstr.TermStr(part[0], style) + part[1:] for part in parts[1:] if part != ""] - return fill3.join("", [parts[0]] + highlighted_parts) + return termstr.join("", [parts[0]] + highlighted_parts) def get_status_help(): - return fill3.join("\n", ["Statuses:"] + [" " + tools.STATUS_TO_TERMSTR[status] + " " + meaning - for status, meaning in tools.STATUS_MEANINGS]) + return termstr.join("\n", ["Statuses:"] + [" " + tools.STATUS_TO_TERMSTR[status] + " " + meaning + for status, meaning in tools.STATUS_MEANINGS]) class Help: @@ -600,7 +601,7 @@ class Help: def __init__(self, summary, screen): self.summary = summary self.screen = screen - help_text = fill3.join("\n", [__doc__, KEYS_DOC, get_status_help()]) + help_text = termstr.join("\n", [__doc__, KEYS_DOC, get_status_help()]) self.view = fill3.View.from_widget(fill3.Text(help_text)) self.widget = fill3.Border(self.view, title="Help") portal = self.view.portal @@ -777,7 +778,7 @@ class Screen: "See option -e.") else: path = self._summary.get_selection().path - path_colored = tools.path_colored(path) + path_colored = lscolors.path_colored(path) line_num = self._summary.get_selection().entry[0].scroll_position[1] + 1 self._log.log_message([in_green("Editing "), path_colored, in_green(f" at line {line_num}…")]) @@ -801,7 +802,7 @@ class Screen: def refresh(self): selection = self._summary.get_selection() tool_name = tools.tool_name_colored(selection.tool, selection.path) - path_colored = tools.path_colored(selection.path) + path_colored = lscolors.path_colored(selection.path) self._log.log_message([in_green("Refreshing "), tool_name, in_green(" result of "), path_colored, in_green("…")]) self._summary.refresh_result(selection) @@ -829,7 +830,7 @@ class Screen: def xdg_open(self): path = self._summary.get_selection().path - path_colored = tools.path_colored(path) + path_colored = lscolors.path_colored(path) self._log.log_message([in_green("Opening "), path_colored, in_green("…")]) subprocess.Popen(["xdg-open", path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -908,7 +909,7 @@ class Screen: view.widget = widget.result tool_name = tools.tool_name_colored(widget.tool, widget.path) divider = " " + self._listing.top * 2 + " " - self._listing.title = (tools.path_colored(widget.path) + divider + tool_name + " " + + self._listing.title = (lscolors.path_colored(widget.path) + divider + tool_name + " " + tools.STATUS_TO_TERMSTR[widget.status] + divider + "line " + str(y+1)) _STATUS_BAR = highlight_chars(" *help *quit *t*a*b:focus *turn *log *edit *next *sort" diff --git a/eris/eris/tools.py b/eris/eris/tools.py index 91e87d2..2d01d15 100755 --- a/eris/eris/tools.py +++ b/eris/eris/tools.py @@ -67,13 +67,6 @@ STATUS_TO_TERMSTR = {status: termstr.TermStr(" ", termstr.CharStyle(bg_color=col STATUS_TO_TERMSTR[Status.pending] = termstr.TermStr(".").fg_color(termstr.Color.grey_100) -def get_ls_color_codes(): - with importlib.resources.open_text(eris, "LS_COLORS.sh") as lscolors_file: - codes = lscolors_file.readline().strip()[len("LS_COLORS='"):-len("';")] - return lscolors._parse_ls_colors(codes) - - -_LS_COLOR_CODES = get_ls_color_codes() TIMEOUT = 60 @@ -134,11 +127,11 @@ def _syntax_highlight(text, lexer, style): token_style["underline"]) default_bg_color = _parse_rgb(style.background_color) default_style = termstr.CharStyle(bg_color=default_bg_color) - text = fill3.join("", [termstr.TermStr(text, _char_style_for_token_type( + text = termstr.join("", [termstr.TermStr(text, _char_style_for_token_type( token_type, default_bg_color, default_style)) for token_type, text in pygments.lex(text, lexer)]) text_widget = fill3.Text(text, pad_char=termstr.TermStr(" ").bg_color(default_bg_color)) - return fill3.join("\n", text_widget.text) + return termstr.join("\n", text_widget.text) def _syntax_highlight_using_path(text, path): @@ -205,8 +198,8 @@ def metadata(path): else: name, value = line name = termstr.TermStr(name + ":").fg_color(termstr.Color.blue).ljust(16) - text.append(name + fill3.join("", value) + "\n") - return Status.ok, fill3.join("", text) + text.append(name + termstr.join("", value) + "\n") + return Status.ok, termstr.join("", text) @deps(deps={"python3-pygments"}, url="http://pygments.org/") @@ -275,7 +268,7 @@ def mypy(path): def _colorize_coverage_report(lines): line_color = {"> ": termstr.Color.green, "! ": termstr.Color.grey_150, " ": None} - return fill3.join("", [termstr.TermStr(line).fg_color(line_color[line[:2]]) for line in lines]) + return termstr.join("", [termstr.TermStr(line).fg_color(line_color[line[:2]]) for line in lines]) @deps(deps={"python3-coverage"}, url="https://coverage.readthedocs.io/") @@ -335,7 +328,7 @@ def _get_mccabe_line_score(line): def _colorize_mccabe(text): - return fill3.join("", [ + return termstr.join("", [ termstr.TermStr(line).fg_color(termstr.Color.yellow) if _get_mccabe_line_score(line) > 10 else line for line in text.splitlines(keepends=True)]) @@ -398,7 +391,7 @@ def _image_to_text(image): rows = [data[row_index*width:(row_index+1)*width] for row_index in range(image.height)] if image.height % 2 == 1: rows.append([None] * image.width) - return fill3.join("\n", [ + return termstr.join("\n", [ termstr.TermStr(text, tuple(termstr.CharStyle(fg_color=top_pixel, bg_color=bottom_pixel) for top_pixel, bottom_pixel in zip(rows[index], rows[index+1]))) for index in range(0, image.height, 2)]) @@ -568,7 +561,7 @@ class Result: async def run(self, log, runner): tool_name = tool_name_colored(self.tool, self.path) - path = path_colored(self.path) + path = lscolors.path_colored(self.path) log.log_message(["Running ", tool_name, " on ", path, "…"]) self.set_status(Status.running) fill3.APPEARANCE_CHANGED_EVENT.set() @@ -695,35 +688,10 @@ def run_tool_no_error(path, tool): pygments.styles.get_style_by_name(os.environ["PYGMENT_STYLE"])) -def _charstyle_of_path(path): - color_code = lscolors.color_code_for_path(path, _LS_COLOR_CODES) - if color_code is None: - return termstr.CharStyle() - term_text = termstr.ESC + "[" + color_code + "m-" - return termstr.TermStr.from_term(term_text).style[0] - - -@functools.lru_cache(maxsize=100) -def path_colored(path): - char_style = _charstyle_of_path(path) - if path.startswith("./"): - path = path[2:] - dirname, basename = os.path.split(path) - if dirname == "": - return termstr.TermStr(basename, char_style) - else: - dirname = dirname + os.path.sep - dir_style = _charstyle_of_path(os.path.sep) - parts = [termstr.TermStr(part, dir_style) for part in dirname.split(os.path.sep)] - path_sep = termstr.TermStr(os.path.sep).fg_color(termstr.Color.grey_100) - dir_name = fill3.join(path_sep, parts) - return dir_name + termstr.TermStr(basename, char_style) - - @functools.lru_cache(maxsize=100) def tool_name_colored(tool, path): char_style = (termstr.CharStyle(is_bold=True) if tool in generic_tools() - else _charstyle_of_path(path)) + else lscolors._charstyle_of_path(path)) return termstr.TermStr(tool.__name__, char_style) diff --git a/eris/eris/webserver.py b/eris/eris/webserver.py index 57f7810..984a1e5 100755 --- a/eris/eris/webserver.py +++ b/eris/eris/webserver.py @@ -47,7 +47,7 @@ def make_listing_page(url_path): result = index[(path, tool_name)] tool = getattr(tools, tool_name) tool_name_colored = tools.tool_name_colored(tool, path) - header = fill3.appearance_as_html([tools.path_colored(path) + " - " + tool_name_colored, + header = fill3.appearance_as_html([lscolors.path_colored(path) + " - " + tool_name_colored, termstr.TermStr(" ").underline() * 100]) body = fill3.appearance_as_html(result.appearance()) return make_page(header + body, f"{path} - {tool_name}") diff --git a/eris/setup.py b/eris/setup.py index 0d2387a..cc9966d 100755 --- a/eris/setup.py +++ b/eris/setup.py @@ -18,8 +18,8 @@ setup(name="eris", license="Artistic 2.0", python_requires=">=3.10.0", packages=["eris"], - py_modules=["lscolors", "sorted_collection"], - package_data={"eris": ["LS_COLORS.sh", "tools.toml"]}, + py_modules=["sorted_collection"], + package_data={"eris": ["tools.toml"]}, entry_points={"console_scripts": ["eris=eris.__main__:entry_point", "eris-worker=eris.worker:main", "eris-webserver=eris.webserver:main", "pydoc_color=eris.pydoc_color:main"]}, diff --git a/eris/tests/__main___test.py b/eris/tests/__main___test.py index 07e45e8..d0656ec 100755 --- a/eris/tests/__main___test.py +++ b/eris/tests/__main___test.py @@ -10,6 +10,7 @@ import tempfile import unittest import fill3 +import termstr import golden import eris.__main__ as __main__ @@ -24,7 +25,7 @@ _DIMENSIONS = (100, 60) def _widget_to_string(widget, dimensions=_DIMENSIONS): appearance = (widget.appearance() if dimensions is None else widget.appearance_for(dimensions)) - return str(fill3.join("\n", appearance)) + return str(termstr.join("\n", appearance)) def _touch(path): diff --git a/eris/tests/tools_test.py b/eris/tests/tools_test.py index a81e61c..0a779cf 100755 --- a/eris/tests/tools_test.py +++ b/eris/tests/tools_test.py @@ -7,7 +7,7 @@ import shutil import unittest import unittest.mock -import fill3 +import termstr import golden import eris.tools as tools @@ -31,7 +31,7 @@ class ExecutablesTestCase(unittest.TestCase): def widget_to_string(widget): - return str(fill3.join("\n", widget.appearance())) + return str(termstr.join("\n", widget.appearance())) @contextlib.contextmanager diff --git a/fill3/fill3/__init__.py b/fill3/fill3/__init__.py index 3fad78f..28a0d43 100755 --- a/fill3/fill3/__init__.py +++ b/fill3/fill3/__init__.py @@ -40,19 +40,10 @@ def appearance_dimensions(appearance): return 0, 0 -def join(seperator, parts): - if parts == []: - return "" - try: - return seperator.join(parts) - except TypeError: - return termstr.TermStr(seperator).join(parts) - - def join_horizontal(appearances): heights = set(len(appearance) for appearance in appearances) assert len(heights) == 1, heights - return [join("", parts) for parts in zip(*appearances)] + return [termstr.join("", parts) for parts in zip(*appearances)] def even_widths(column_widgets, width): diff --git a/fill3/tests/fill3_test.py b/fill3/tests/fill3_test.py index d9814ec..c375b49 100755 --- a/fill3/tests/fill3_test.py +++ b/fill3/tests/fill3_test.py @@ -6,6 +6,7 @@ import unittest import fill3 import fill3.terminal as terminal +import termstr class WidgetTests(unittest.TestCase): @@ -14,7 +15,7 @@ class WidgetTests(unittest.TestCase): TEXT_B = fill3.Text("B") def assert_string(self, appearance, expected_string): - self.assertEqual(str(fill3.join("\n", appearance)), expected_string) + self.assertEqual(str(termstr.join("\n", appearance)), expected_string) def test_rows_widget(self): rows = fill3.Row([self.TEXT_A, self.TEXT_B]) diff --git a/eris/LS_COLORS b/lscolors/LS_COLORS similarity index 100% rename from eris/LS_COLORS rename to lscolors/LS_COLORS diff --git a/eris/eris/LS_COLORS.sh b/lscolors/lscolors/LS_COLORS.sh similarity index 100% rename from eris/eris/LS_COLORS.sh rename to lscolors/lscolors/LS_COLORS.sh diff --git a/lscolors/lscolors.py b/lscolors/lscolors/__init__.py similarity index 77% rename from lscolors/lscolors.py rename to lscolors/lscolors/__init__.py index 048e018..b462116 100644 --- a/lscolors/lscolors.py +++ b/lscolors/lscolors/__init__.py @@ -3,11 +3,17 @@ """Give coloring for file types as in the ls command.""" +import functools +import importlib +import importlib.resources import os import os.path import stat import syslog +import lscolors +import termstr + __version__ = "v2022.04.30" @@ -127,3 +133,37 @@ def color_code_for_path(path, color_codes): if extension is not None: color_key = extension return color_codes.get(color_key, None) + + +def get_ls_color_codes(): + with importlib.resources.open_text(lscolors, "LS_COLORS.sh") as lscolors_file: + codes = lscolors_file.readline().strip()[len("LS_COLORS='"):-len("';")] + return _parse_ls_colors(codes) + + +_LS_COLOR_CODES = get_ls_color_codes() + + +def _charstyle_of_path(path): + color_code = color_code_for_path(path, _LS_COLOR_CODES) + if color_code is None: + return termstr.CharStyle() + term_text = termstr.ESC + "[" + color_code + "m-" + return termstr.TermStr.from_term(term_text).style[0] + + +@functools.lru_cache(maxsize=100) +def path_colored(path): + char_style = _charstyle_of_path(path) + if path.startswith("./"): + path = path[2:] + dirname, basename = os.path.split(path) + if dirname == "": + return termstr.TermStr(basename, char_style) + else: + dirname = dirname + os.path.sep + dir_style = _charstyle_of_path(os.path.sep) + parts = [termstr.TermStr(part, dir_style) for part in dirname.split(os.path.sep)] + path_sep = termstr.TermStr(os.path.sep).fg_color(termstr.Color.grey_100) + dir_name = termstr.join(path_sep, parts) + return dir_name + termstr.TermStr(basename, char_style) diff --git a/lscolors/setup.py b/lscolors/setup.py index 8a57915..a6df585 100755 --- a/lscolors/setup.py +++ b/lscolors/setup.py @@ -1,12 +1,14 @@ #!/usr/bin/env python3.10 +import os try: from setuptools import setup except ImportError: from distutils.core import setup +REPO_PATH = os.path.dirname(os.getcwd()) setup(name="lscolors", version="v2022.04.30", description=("Give coloring for file types as in the ls command."), @@ -14,4 +16,6 @@ setup(name="lscolors", author="Andrew Hamilton", author_email="and_hamilton@yahoo.com", license="Artistic 2.0", - py_modules=["lscolors"]) + packages=["lscolors"], + package_data={"lscolors": ["LS_COLORS.sh"]}, + install_requires=[f"termstr @ file://{REPO_PATH}/termstr"]) diff --git a/termstr/termstr.py b/termstr/termstr.py index b67734f..725653f 100644 --- a/termstr/termstr.py +++ b/termstr/termstr.py @@ -177,6 +177,15 @@ def _pad_wide_chars(str_): return str_ if len(padded_str) == len(str_) else padded_str +def join(seperator, parts): + if parts == []: + return "" + try: + return seperator.join(parts) + except TypeError: + return TermStr(seperator).join(parts) + + class TermStr(collections.UserString): def __init__(self, data, style=CharStyle()):