95 lines
No EOL
3.6 KiB
Python
95 lines
No EOL
3.6 KiB
Python
import os
|
||
import sys
|
||
|
||
DEFAULT_CAT = r""" ╱|、
|
||
(˚ˎ 。7 {{HBAR}}{{HBAR}}
|
||
|、˜〵
|
||
じしˍ,)ノ"""
|
||
|
||
BOXES = {
|
||
"rounded": {
|
||
"hbar": "─",
|
||
"vbar": "│",
|
||
"corner_tl": "╭",
|
||
"corner_tr": "╮",
|
||
"corner_bl": "╰",
|
||
"corner_br": "╯",
|
||
"joiner": "┤",
|
||
}
|
||
|
||
}
|
||
|
||
def main():
|
||
parser = False
|
||
args = False
|
||
isatty = sys.stdin.isatty()
|
||
message = ""
|
||
if not isatty:
|
||
message = sys.stdin.read().strip()
|
||
if len(sys.argv) > 1:
|
||
import argparse
|
||
parser = argparse.ArgumentParser(description="Display a message in a speech bubble next to a kittycat.")
|
||
parser.add_argument("--box", type=str, choices=BOXES.keys(), default="rounded", help="The style of the speech bubble.")
|
||
parser.add_argument("-W", type=int, default=0, help="The maximum width of the message before wrapping. Defaults to terminal width minus kittycat width.")
|
||
parser.add_argument("-f", "--file", type=str, default="./kittycats/default.cat", help="The path to the kittycat file to use.")
|
||
if isatty:
|
||
parser.add_argument("message", type=str, help="The message to display.")
|
||
args = parser.parse_args()
|
||
message = args.message
|
||
else:
|
||
args = parser.parse_args()
|
||
if len(message) == 0:
|
||
message = [
|
||
"Meow.",
|
||
"We still don't support multi-line input.",
|
||
"Try a pipe why don't you?",
|
||
"Wi wi wi wi.",
|
||
"Weh weh weh.",
|
||
][int((int.from_bytes(open("/dev/urandom", "rb").read(1), "big") / 256) * 5)]
|
||
kittycat = DEFAULT_CAT
|
||
box_style = "rounded"
|
||
wrapping = 0
|
||
if args:
|
||
if os.path.isfile(args.file):
|
||
kittycat = open(args.file).read()
|
||
box_style = args.box
|
||
wrapping = args.W
|
||
outcat = get_kittycat(kittycat, message, BOXES[box_style], wrap=wrapping)
|
||
print(outcat)
|
||
|
||
def get_kittycat(cat: str, msg: str, box: dict[str, str], wrap = 0):
|
||
for kw in box.keys():
|
||
cat = cat.replace(r"{{" + kw.upper() + r"}}", box[kw])
|
||
cat_lines = cat.splitlines()
|
||
cat_width = max(len(line) for line in cat_lines)
|
||
max_msg_height = len(cat_lines) - 2
|
||
max_msg_width = os.get_terminal_size()[0] - cat_width - 2
|
||
if not wrap < max_msg_width:
|
||
raise ValueError("Wrap width exceeds maximum message width")
|
||
wrap = wrap if wrap else max_msg_width
|
||
msg = msg.replace("\n", " ")
|
||
msg_lines = []
|
||
msg_words = msg.split(" ")
|
||
while msg_words:
|
||
line = ""
|
||
while msg_words and len(line) + len(msg_words[0]) + 1 <= wrap:
|
||
line += (msg_words.pop(0) + " ")
|
||
msg_lines.append(line.rstrip())
|
||
if len(msg_lines) > max_msg_height:
|
||
raise ValueError(f"Message exceeds maximum height of {max_msg_height} given {wrap} character wrap")
|
||
longest_msg_line = max(len(line) for line in msg_lines)
|
||
msg_lines = [line.ljust(longest_msg_line) for line in msg_lines]
|
||
msg_lines = [box["joiner"] + " " + msg_lines.pop(0) + " " + box["vbar"]] + [box["vbar"] + " " + line + " " + box["vbar"] for line in msg_lines]
|
||
top_bar = box["corner_tl"] + box["hbar"] * (longest_msg_line + 2) + box["corner_tr"]
|
||
bottom_bar = box["corner_bl"] + box["hbar"] * (longest_msg_line + 2) + box["corner_br"]
|
||
msg_lines = [top_bar, *msg_lines, bottom_bar]
|
||
outcat_lines = []
|
||
for i, line in enumerate(cat_lines):
|
||
box_line = ""
|
||
if i < len(msg_lines):
|
||
box_line = msg_lines[i]
|
||
outcat_lines.append(line + box_line)
|
||
return "\n".join(outcat_lines)
|
||
|
||
if __name__ == "__main__":
|
||
main() |