From bfe7dedd6f6c12f4357ae20c02d172045d37a5fb Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Fri, 13 Oct 2023 09:51:16 -0500 Subject: [PATCH] update --- .gitignore | 3 + jlog/__init__.py | 157 ++++++++++++++++++++-- jlog/__pycache__/__init__.cpython-311.pyc | Bin 11352 -> 0 bytes 3 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 .gitignore delete mode 100644 jlog/__pycache__/__init__.cpython-311.pyc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f33237 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/result* +/.venv +__pycache__ diff --git a/jlog/__init__.py b/jlog/__init__.py index c90cbd9..f4f916e 100644 --- a/jlog/__init__.py +++ b/jlog/__init__.py @@ -1,6 +1,9 @@ """Configure logging.""" +import base64 +from enum import Enum from enum import IntEnum +from enum import auto import logging import pathlib import re @@ -23,7 +26,65 @@ class ANSIColor(IntEnum): WHITE = 8 +class Mode(Enum): + C0 = auto() + C1 = auto() + + class ANSI: + mode: Mode + + SOH = "\u0001" + STX = "\u0002" + BEL = "\u0007" + BS = "\u0008" + HT = "\u0009" + LF = "\u000a" + VT = "\u000b" + FF = "\u000c" + CR = "\u000d" + ESC = "\u001b" + DEL = "\u007f" + + def __init__(self, mode: Mode = Mode.C0): + self.mode = mode + + @property + def DCS(self: Self) -> str: + """Device Control String""" + match self.mode: + case Mode.C1: + return "\u008d" + case Mode.C0 | _: + return f"{self.ESC}P" + + @property + def CSI(self: Self) -> str: + """Control Sequence Introducer""" + match self.mode: + case Mode.C1: + return "\u009b" + case Mode.C0 | _: + return f"{self.ESC}[" + + @property + def ST(self: Self) -> str: + """String Terminator""" + match self.mode: + case Mode.C1: + return "\u009c" + case Mode.C0 | _: + return f"{self.ESC}\\" + + @property + def OSC(self: Self) -> str: + """Operating System Command""" + match self.mode: + case Mode.C1: + return "\u009d" + case Mode.C0 | _: + return f"{self.ESC}]" + def __getattr__(self: Self, item: str) -> str: return self.color(item) @@ -42,7 +103,7 @@ class ANSI: try: color = ANSIColor[item] - return f"\u001b[1;{color+offset:d}{extra}m" + return f"{self.CSI}1;{color+offset:d}{extra}m" except KeyError: return self.fg24bitrgb(*(getrgb(item)[:3])) @@ -54,6 +115,10 @@ class ANSI: def white(self: Self) -> str: return self.color("white") + @property + def green(self: Self) -> str: + return self.color("green") + @property def blue(self: Self) -> str: return self.color("blue") @@ -64,37 +129,76 @@ class ANSI: @property def reset(self: Self) -> str: - return "\u001b[0m" + return f"{self.CSI}0m" @property def bold(self: Self) -> str: - return "\u001b[1m" + return f"{self.CSI}1m" @property def faint(self: Self) -> str: - return "\u001b[2m" + return f"{self.CSI}2m" @property def italic(self: Self) -> str: - return "\u001b[3m" + return f"{self.CSI}3m" @property def underline(self: Self) -> str: - return "\u001b[4m" + return f"{self.CSI}4m" @property def reversed(self: Self) -> str: - return "\u001b[7m" + return f"{self.CSI}7m" + + def icon_name_and_window_title(self: Self, text: str) -> str: + return f"{self.OSC}0;{text}{self.ST}" + + def icon_name(self: Self, text: str) -> str: + return f"{self.OSC}1;{text}{self.ST}" + + def window_title(self: Self, text: str) -> str: + return f"{self.OSC}2;{text}{self.ST}" + + def hyperlink(self: Self, link: str, text: str) -> str: + return f"{self.OSC}8;;{link}{self.ST}{text}{self.OSC}8;;{self.ST}" + + def post_notification(self: Self, message: str) -> str: + return f"{self.OSC}9;{message}{self.ST}" + + def write_to_pastboard(self: Self, pasteboard: str, data: str) -> str: + return f"{self.OSC}52;{pasteboard};{base64.b64encode(data).decode()}{self.ST}" + + def query_pasteboard(self: Self, pasteboard: str) -> str: + return f"{self.OSC}52;{pasteboard};?{self.ST}" + + def copy_to_clipboard(self: Self, clipboard_name: str) -> str: + return f"{self.OSC}1337;CopyToClipboard={clipboard_name}{self.ST}" + + def end_copy(self: Self) -> str: + return f"{self.OSC}1337;EndCopy{self.ST}" + + def clear_scrollback_history(self: Self) -> str: + return f"{self.OSC}1337;ClearScrollback{self.ST}" + + def set_current_directory(self: Self, dir: str) -> str: + return f"{self.OSC}1337;CurrentDir={dir}{self.ST}" + + def change_profile(self: Self, new_profile_name: str) -> str: + return f"{self.OSC}1337;SetProfile={new_profile_name}{self.ST}" + + def steal_focus(self: Self) -> str: + return f"{self.OSC}1337;StealFocus{self.ST}" def fg8bit(self: Self, code: int) -> str: assert code >= 0 assert code < 256 - code = f"\u001b[38;5;{code}m" + code = f"{self.CSI}38;5;{code}m" def bg8bit(self: Self, code: int) -> str: assert code >= 0 assert code < 256 - return f"\u001b[48;5;{code}m" + return f"{self.CSI}48;5;{code}m" def fg24bitrgb(self: Self, red: int, green: int, blue: int) -> str: assert red >= 0 @@ -103,7 +207,7 @@ class ANSI: assert green < 256 assert blue >= 0 assert blue < 256 - return f"\u001b[38;2;{red};{green};{blue}m" + return f"{self.CSI}38;2;{red};{green};{blue}m" def bg24bitrgb(self: Self, red: int, green: int, blue: int) -> str: assert red >= 0 @@ -112,7 +216,7 @@ class ANSI: assert green < 256 assert blue >= 0 assert blue < 256 - return f"\u001b[48;2;{red};{green};{blue}m" + return f"{self.CSI}48;2;{red};{green};{blue}m" # def fg24bitcmy(self, cyan: int, magenta: int, yellow: int) -> str: # assert cyan >= 0 @@ -121,12 +225,41 @@ class ANSI: # assert magenta < 256 # assert yellow >= 0 # assert yellow < 256 - # return f"\u001b[38:2::{cyan};{magenta};{yellow}:::m" + # return f"{self.OSC}38:2::{cyan};{magenta};{yellow}:::m" ansi = ANSI() +class BashPromptBuilder: + ansi: ANSI + + ESC = "\\e" + BEL = "\\a" + prompt = "\\$" + current_working_directory = "\\w" + username = "\\u" + hostname_short = "\\h" + hostname_long = "\\H" + + @property + def RL_PROMPT_START_IGNORE(self: Self) -> str: + return self.ansi.SOH + + @property + def RL_PROMPT_END_IGNORE(self: Self) -> str: + return self.ansi.STX + + def __init__(self: Self, ansi: ANSI = ansi) -> None: + self.ansi = ansi + + def wrap_nonprinting(self: Self, text: str) -> str: + return f"{self.RL_PROMPT_START_IGNORE}{text}{self.RL_PROMPT_END_IGNORE}" + + def title_bar(self: Self, text: str) -> str: + return self.wrap_nonprinting(self.ansi.icon_name_and_window_title(text)) + + class JLogFormatter(logging.Formatter): """Format time the way it SHOULD be done.""" diff --git a/jlog/__pycache__/__init__.cpython-311.pyc b/jlog/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 9ae2f2fc4ff20823ab9ddad5d5b525cb0bbadf8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11352 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 TD2-P+$2wP|r4=>-sviFX+U9^~