Skip to content

Instantly share code, notes, and snippets.

@Pinacolada64
Last active March 15, 2023 06:31
Show Gist options
  • Save Pinacolada64/62415d4a4216976685f4ae3f0955fbf9 to your computer and use it in GitHub Desktop.
Save Pinacolada64/62415d4a4216976685f4ae3f0955fbf9 to your computer and use it in GitHub Desktop.
Beginning a simple line-based text editor.
try:
import getch
except ImportError as e:
print(f"Can't import getch: {e}.")
def get_character():
"""
Wait for a character to be typed
return tuple: 'in_char': character, 'asc': ascii value
"""
in_char = None
while in_char is None:
# getch.getch() does not echo input
in_char = getch.getch()
asc = ord(in_char)
return (in_char, asc)
def out_backspace(count):
"""
Output <count> backspaces, character used depends on terminal
"""
backspace = "\b \b" # Linux terminal
# if Character.terminal['translation'] == "PetSCII" then:
# backspace = chr(20)
output = backspace * count
return output
def yes_or_no(prompt="Are you sure", default=False):
"""
Ask a yes-or-no question, with default answer.
the response is yes (True), or no (False).
prompt: configurable string
default: unless any other key but 'y' for True or 'n' for False is typed
returns: response: yes = True, no = False
"""
if default is True:
chars = "Y/n"
if default is False:
chars = "y/N"
print(f"{prompt} [{chars}]: ", end="", flush=True)
key, asc = get_character()
command_char = key.lower()
if default is True and command_char != "n":
response = True
print("Yes.\n")
if default is False and command_char != "y":
response = False
print("No.\n")
return response
def dot_cmd_list():
"""
list text with line numbers
"""
for k, v in enumerate(buffer, start=1):
print(f"{k}:\n{v}")
print("Using getch:")
# init:
editing = True
buffer = ['', ''] # empty buffer, but 1-indexed
char_pos = 0
line = '' # init empty line
line_num = 0
char_pos = 0
KEY_BACKSPACE = 127
KEY_RETURN = 10 # last char of CR/LF pair
prompt = "Command: "
debug = True
"""
editing: Boolean whether we're in the editor
char_pos: character position within line
line: the string input so far
line_num: the line number being edited (1-based)
char: character typed
asc: ascii value of char
"""
while editing is True:
char, asc = get_character()
# asc = ord(char) # ascii value
# handle column 0 dot/slash commands:
if char_pos == 0:
# print(char, asc)
if char in ("/", "."):
print(prompt, end="", flush=True)
key, asc = get_character()
command_char = key.lower()
if command_char == "a":
print("Abort")
response = yes_or_no(default=False)
if response is True:
editing = False
continue
if command_char == "l":
print("List")
dot_cmd_list()
continue
if command_char == "n":
print("Erase Text")
response = yes_or_no(default=False)
if response is True:
buffer = ['', '']
print("Erased text.")
continue
if asc == KEY_BACKSPACE or asc == KEY_RETURN or command_char in ("/", "."):
print(out_backspace(len(prompt)), end='', flush=True)
continue
else:
print(f"{command_char} ({asc}) not implemented yet.")
# handle backspace/delete:
if asc == KEY_BACKSPACE and char_pos > 0:
# print("BS/DEL", end='')
char_pos -= 1
line = line[:char_pos]
print(out_backspace(1), end='', flush=True)
elif asc == 10:
# print(" [Return/Enter hit]\n")
print()
# if line_num > len(buffer):
# buffer.append(x for x in [line_num - len(buffer)]
# TODO: fill in blank lines
buffer[line_num] = line
line_num += 1
line = ''
char_pos = 0
else:
# filter out control chars for now:
if asc > 31 and asc < 197:
# print(f"{asc if debug else ''}{char}", end='', flush=True)
print(f"{char}", end='', flush=True)
char_pos += 1
line = line + char
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment