update
This commit is contained in:
parent
f1efca7ea8
commit
bfe7dedd6f
3 changed files with 148 additions and 12 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/result*
|
||||||
|
/.venv
|
||||||
|
__pycache__
|
157
jlog/__init__.py
157
jlog/__init__.py
|
@ -1,6 +1,9 @@
|
||||||
"""Configure logging."""
|
"""Configure logging."""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
from enum import Enum
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
from enum import auto
|
||||||
import logging
|
import logging
|
||||||
import pathlib
|
import pathlib
|
||||||
import re
|
import re
|
||||||
|
@ -23,7 +26,65 @@ class ANSIColor(IntEnum):
|
||||||
WHITE = 8
|
WHITE = 8
|
||||||
|
|
||||||
|
|
||||||
|
class Mode(Enum):
|
||||||
|
C0 = auto()
|
||||||
|
C1 = auto()
|
||||||
|
|
||||||
|
|
||||||
class ANSI:
|
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:
|
def __getattr__(self: Self, item: str) -> str:
|
||||||
return self.color(item)
|
return self.color(item)
|
||||||
|
|
||||||
|
@ -42,7 +103,7 @@ class ANSI:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
color = ANSIColor[item]
|
color = ANSIColor[item]
|
||||||
return f"\u001b[1;{color+offset:d}{extra}m"
|
return f"{self.CSI}1;{color+offset:d}{extra}m"
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return self.fg24bitrgb(*(getrgb(item)[:3]))
|
return self.fg24bitrgb(*(getrgb(item)[:3]))
|
||||||
|
|
||||||
|
@ -54,6 +115,10 @@ class ANSI:
|
||||||
def white(self: Self) -> str:
|
def white(self: Self) -> str:
|
||||||
return self.color("white")
|
return self.color("white")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def green(self: Self) -> str:
|
||||||
|
return self.color("green")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def blue(self: Self) -> str:
|
def blue(self: Self) -> str:
|
||||||
return self.color("blue")
|
return self.color("blue")
|
||||||
|
@ -64,37 +129,76 @@ class ANSI:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reset(self: Self) -> str:
|
def reset(self: Self) -> str:
|
||||||
return "\u001b[0m"
|
return f"{self.CSI}0m"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bold(self: Self) -> str:
|
def bold(self: Self) -> str:
|
||||||
return "\u001b[1m"
|
return f"{self.CSI}1m"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def faint(self: Self) -> str:
|
def faint(self: Self) -> str:
|
||||||
return "\u001b[2m"
|
return f"{self.CSI}2m"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def italic(self: Self) -> str:
|
def italic(self: Self) -> str:
|
||||||
return "\u001b[3m"
|
return f"{self.CSI}3m"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def underline(self: Self) -> str:
|
def underline(self: Self) -> str:
|
||||||
return "\u001b[4m"
|
return f"{self.CSI}4m"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reversed(self: Self) -> str:
|
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:
|
def fg8bit(self: Self, code: int) -> str:
|
||||||
assert code >= 0
|
assert code >= 0
|
||||||
assert code < 256
|
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:
|
def bg8bit(self: Self, code: int) -> str:
|
||||||
assert code >= 0
|
assert code >= 0
|
||||||
assert code < 256
|
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:
|
def fg24bitrgb(self: Self, red: int, green: int, blue: int) -> str:
|
||||||
assert red >= 0
|
assert red >= 0
|
||||||
|
@ -103,7 +207,7 @@ class ANSI:
|
||||||
assert green < 256
|
assert green < 256
|
||||||
assert blue >= 0
|
assert blue >= 0
|
||||||
assert blue < 256
|
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:
|
def bg24bitrgb(self: Self, red: int, green: int, blue: int) -> str:
|
||||||
assert red >= 0
|
assert red >= 0
|
||||||
|
@ -112,7 +216,7 @@ class ANSI:
|
||||||
assert green < 256
|
assert green < 256
|
||||||
assert blue >= 0
|
assert blue >= 0
|
||||||
assert blue < 256
|
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:
|
# def fg24bitcmy(self, cyan: int, magenta: int, yellow: int) -> str:
|
||||||
# assert cyan >= 0
|
# assert cyan >= 0
|
||||||
|
@ -121,12 +225,41 @@ class ANSI:
|
||||||
# assert magenta < 256
|
# assert magenta < 256
|
||||||
# assert yellow >= 0
|
# assert yellow >= 0
|
||||||
# assert yellow < 256
|
# assert yellow < 256
|
||||||
# return f"\u001b[38:2::{cyan};{magenta};{yellow}:::m"
|
# return f"{self.OSC}38:2::{cyan};{magenta};{yellow}:::m"
|
||||||
|
|
||||||
|
|
||||||
ansi = ANSI()
|
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):
|
class JLogFormatter(logging.Formatter):
|
||||||
"""Format time the way it SHOULD be done."""
|
"""Format time the way it SHOULD be done."""
|
||||||
|
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue