86 lines
2.8 KiB
Python
86 lines
2.8 KiB
Python
|
#!/usr/bin/env -S uv run python3
|
||
|
import tkinter as tk
|
||
|
from tkinter import N, S, E, W, ttk
|
||
|
import textwrap
|
||
|
|
||
|
|
||
|
# Complex transforms go here,
|
||
|
# Simple transforms are just lambdas
|
||
|
def _wordcount(s: str):
|
||
|
"Returns a tuple of linecount, wordcount, charcount"
|
||
|
return (len(s.splitlines()), len(s.split()), len(s))
|
||
|
|
||
|
|
||
|
def _markdown_quote(s: str):
|
||
|
"Returns every line prefixed with >"
|
||
|
return "\n".join(["> " + line for line in s.splitlines()])
|
||
|
|
||
|
transforms = [
|
||
|
# Transforms go here, for example
|
||
|
{"name": "One line", "transform": lambda x: " ".join(x.splitlines())}
|
||
|
,{"name": "Line/Word/Char", "transform": _wordcount}
|
||
|
,{"name": "Dedent", "transform": textwrap.dedent}
|
||
|
,{"name": "Markdown Quote", "transform": _markdown_quote}
|
||
|
]
|
||
|
|
||
|
class GUI():
|
||
|
def __init__(self) -> None:
|
||
|
self.root = tk.Tk()
|
||
|
self.active_transform = lambda x: x # start with no transform
|
||
|
self.layout_gui()
|
||
|
|
||
|
|
||
|
def layout_gui(self) -> None:
|
||
|
self.mainframe = ttk.Frame(self.root, padding="3 3 12 12")
|
||
|
|
||
|
self.root.title("Text Tools")
|
||
|
self.mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
|
||
|
self.root.columnconfigure(0, weight=1)
|
||
|
self.root.rowconfigure(0, weight=1)
|
||
|
self.content_box = tk.Text(self.mainframe, undo=True)
|
||
|
self.content_box.grid(column=2, row=2)
|
||
|
|
||
|
self.output_box = tk.Text(self.mainframe, undo=True)
|
||
|
self.output_box.grid(column=2, row=3)
|
||
|
|
||
|
self.transform_box = tk.Listbox(self.mainframe)
|
||
|
self.transform_box.grid(column=1, row=2, rowspan=2)
|
||
|
for t in transforms:
|
||
|
self.transform_box.insert(tk.END, t["name"])
|
||
|
|
||
|
# Keyboard bindings
|
||
|
self.root.bind("<Escape>", lambda _: self.root.quit())
|
||
|
self.content_box.bind("<Tab>", lambda _: self.transform_box.focus())
|
||
|
|
||
|
# vvv makes clicking or pressing enter change the transform
|
||
|
self.transform_box.bind("<Button-1>", self.select_transform)
|
||
|
self.transform_box.bind("<Return>", self.select_transform)
|
||
|
|
||
|
# vvv makes anything typed in update the output
|
||
|
self.content_box.bind("<Key>",
|
||
|
lambda _: self.root.after(1, self.update))
|
||
|
|
||
|
self.content_box.focus()
|
||
|
|
||
|
def update(self):
|
||
|
content = self.content_box.get('1.0', tk.END)
|
||
|
content = self.active_transform(content)
|
||
|
self.output_box.delete('1.0', tk.END)
|
||
|
self.output_box.insert('1.0', content)
|
||
|
|
||
|
def select_transform(self, _):
|
||
|
try:
|
||
|
selection = self.transform_box.curselection()[0]
|
||
|
self.active_transform = transforms[selection]["transform"]
|
||
|
self.update()
|
||
|
except (ValueError, IndexError):
|
||
|
pass
|
||
|
|
||
|
def main(): # Entry point for pyproject.toml
|
||
|
gui = GUI()
|
||
|
gui.root.mainloop()
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|
||
|
|