Post by Chris GreenAre there any packages that offer this sort of thing? I'd prefer ones
from the Debian repositories but that's not absolutely necessary.
So, in my humble opinion, it's a no-brainer to split this into two
camps and draw a line between Linux and Windows.
On Linux, you're going to wanna roll with curses. See [1] below.
For Windows, whip up your own terminal using tkinter (Yeah,
tkinter's a GUI library, no doubt! But in this case, it's just
being used to mimic a terminal.) as your secret sauce. See [2].
If that's too tied to specific systems for your taste,
why not cook up a library that smooths out those wrinkles?
The following drafts still contain bugs, but might convey
the idea.
[1]
import curses
def main(stdscr):
# Clear screen and hide cursor
stdscr.clear()
curses.curs_set(1)
# Display prompt
stdscr.addstr(0, 0, "Color? ")
# Pre-fill with "red"
default_text = "red"
stdscr.addstr(0, 7, default_text)
curses.echo() # Enable echo of characters
curses.cbreak() # React to keys instantly without Enter key
# Initialize cursor position
cursor_x = 7 + len(default_text)
current_text = default_text
while True:
stdscr.move(0, cursor_x)
ch = stdscr.getch()
if ch == ord('\n'): # Enter key
break
elif ch in (curses.KEY_BACKSPACE, 127): # Backspace
if cursor_x > 7:
cursor_x -= 1
current_text = current_text[:cursor_x-7] + current_text[cursor_x-6:]
stdscr.delch(0, cursor_x)
elif ch == curses.KEY_LEFT:
if cursor_x > 7:
cursor_x -= 1
elif ch == curses.KEY_RIGHT:
if cursor_x < 7 + len(current_text):
cursor_x += 1
elif 32 <= ch <= 126: # Printable characters
current_text = current_text[:cursor_x-7] + chr(ch) + current_text[cursor_x-7:]
stdscr.insch(0, cursor_x, ch)
cursor_x += 1
stdscr.refresh()
# Clear screen
stdscr.clear()
# Display result
stdscr.addstr(0, 0, f"You entered: {current_text}")
stdscr.refresh()
stdscr.getch()
if __name__ == "__main__":
curses.wrapper(main)
[2]
import tkinter as tk
from tkinter import simpledialog
class ColorQueryApp:
def __init__(self, master):
self.master = master
master.title("Color Query")
# Create the Text widget
self.text_field = tk.Text(master, height=10, width=40)
self.text_field.pack(padx=10, pady=10)
# Create a button to add new color queries
self.add_button = tk.Button(master, text="Add Color Query", command=self.add_color_query)
self.add_button.pack(pady=5)
# Bind the Return key event
self.text_field.bind('<Return>', self.show_color_dialog)
def add_color_query(self):
# Insert a new line if the Text widget is not empty
if self.text_field.index('end-1c') != '1.0':
self.text_field.insert('end', '\n')
# Insert the new color query line
query_line = "Color? red"
self.text_field.insert('end', query_line)
# Move the cursor to the end of the new line
self.text_field.mark_set('insert', f'{self.text_field.index("end-1c")}')
# Bind the key events
self.text_field.bind('<Key>', self.check_editing)
def check_editing(self, event):
# Allow all keystrokes if cursor is in editable area
if self.text_field.compare('insert', '>=', 'insert linestart+7c'):
return
# Prevent editing in the "Color? " area
if event.keysym in ['BackSpace', 'Delete'] or len(event.char) > 0:
return 'break'
def show_color_dialog(self, event):
# Get the current line
current_line = self.text_field.get("insert linestart", "insert lineend")
# Extract the color
color = current_line[7:].strip()
# Show a dialog with the entered color
simpledialog.messagebox.showinfo("Entered Color", f"You entered: {color}")
# Prevent the default newline behavior
return 'break'
root = tk.Tk()
app = ColorQueryApp(root)
root.mainloop()