This commit is contained in:
Minecon724 2024-07-01 15:25:23 +02:00
parent 885fc45751
commit fbfa0257a7
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
2 changed files with 128 additions and 25 deletions

View file

@ -1,5 +1,6 @@
from os import get_terminal_size, O_NONBLOCK from os import get_terminal_size, O_NONBLOCK
from sys import stdin from sys import stdin
from termios import tcgetattr, tcsetattr, TCSADRAIN
from tty import setcbreak from tty import setcbreak
from fcntl import fcntl, F_GETFL, F_SETFL from fcntl import fcntl, F_GETFL, F_SETFL
@ -8,14 +9,20 @@ from keys import *
def wrapper(f: callable, *args: any): def wrapper(f: callable, *args: any):
try: try:
fd = stdin.fileno() fd = stdin.fileno()
orig_fl = fcntl(fd, F_GETFL) old_fl = fcntl(fd, F_GETFL)
old_tc = tcgetattr(fd)
setcbreak(fd) setcbreak(fd)
fcntl(fd, F_SETFL, orig_fl | O_NONBLOCK) fcntl(fd, F_SETFL, old_fl | O_NONBLOCK)
f(*args) f(*args)
except KeyboardInterrupt:
cprint('2J')
move(0, 0)
pass
finally: finally:
fcntl(fd, F_SETFL, orig_fl) fcntl(fd, F_SETFL, old_fl)
tcsetattr(fd, TCSADRAIN, old_tc)
def rprint(*text: str): def rprint(*text: str):
@ -24,29 +31,88 @@ def rprint(*text: str):
def cprint(*code: str): def cprint(*code: str):
rprint(*['\033[' + c for c in code]) rprint(*['\033[' + c for c in code])
def refresh(lines: list[str], ncols: int) -> tuple[int, int]: def move(y: int, x: int):
cprint('2J', '0;0H') cprint(f'{y+1};{x+1}H')
y = 0
cl = -1 def refresh(line_pos: int, cur_line: int, lines: list[str], ncols: int) -> tuple[int, int]:
cprint('2J') # clear screen
move(0, 0)
my = 0 # max y
cl = '' # current screen line
ln = 0 # line number
y = 0 # output pos
x = 0
for l in lines: for l in lines:
_ = 0 _ = 0
if ln == cur_line: # if this line is the focused line
y = my
while _ == 0 or l != '': while _ == 0 or l != '':
cl = l[:ncols] cl = l[:ncols]
print(cl) print(cl)
_ += 1 _ += 1
l = l[ncols:] l = l[ncols:]
y += _ my += _
ln += 1
x = len(cl) + 1 x = line_pos % ncols
if x - 1 == ncols: if line_pos / ncols >= 1:
x = 0 y += line_pos // ncols
y += 1 move(y, x)
cprint(f'{y};{x}H')
return (y, x) return (y, x)
def insert_str(text: str, to_insert: str, index: int) -> str:
return text[:index] + to_insert + text[index:]
def remove_str(text: str, index: int) -> str:
return text[:index] + text[index + 1:]
def nl(y: int, x: int) -> tuple[int]:
cprint('E')
return (y + 1, 0)
def move_back(y: int, x: int, line_pos: int, cur_line: int, lines: list[str], ncols: int) -> tuple[int]:
if x != 0:
line_pos -= 1
x -= 1
elif y != 0:
if line_pos == 0:
cur_line -= 1
line_pos = len(lines[cur_line])
x = line_pos % ncols
y -= 1
else:
rprint(KEY_BELL)
return (y, x, line_pos, cur_line)
def move_forward(y: int, x: int, line_pos: int, cur_line: int, lines: list[str], ncols: int) -> tuple[int]:
lines_count = len(lines) - 1
line_len = len(lines[cur_line])
if line_pos == line_len: # if the cursor is on the last char of line
if cur_line == lines_count: # if the line is the last line
rprint(KEY_BELL)
else: # if not then switch to next line
x = 0
y += 1
line_pos = 0
cur_line += 1
else:
line_pos += 1
if x - 1 == ncols: # if cursor is at the right edge of screen
x = 0
y += 1
return (y, x, line_pos, cur_line)
def main(): def main():
cprint('2J', '0;0H')
terminal_size = None terminal_size = None
y = 0 y = 0
@ -60,27 +126,63 @@ def main():
new_terminal_size = get_terminal_size() new_terminal_size = get_terminal_size()
if new_terminal_size != terminal_size: if new_terminal_size != terminal_size:
terminal_size = new_terminal_size terminal_size = new_terminal_size
y, x = refresh(line_pos, cur_line, lines, terminal_size.columns)
y, x = refresh(lines, terminal_size.columns)
key = stdin.read(1) key = stdin.read(1)
if key == '': if key == '':
continue continue
elif key == KEY_ESCAPE: elif key == KEY_ESCAPE:
next = stdin.read(1) next = stdin.read(1)
pass if next == '[':
next = stdin.read(1)
if next == 'A':
cprint('A')
elif next == 'B':
cprint('B')
elif next == 'C':
y, x, line_pos, cur_line = move_forward(y, x, line_pos, cur_line, lines, terminal_size.columns)
move(y, x)
elif next == 'D':
y, x, line_pos, cur_line = move_back(y, x, line_pos, cur_line, lines, terminal_size.columns)
move(y, x)
elif key == KEY_BACKSPACE: elif key == KEY_BACKSPACE:
pass """if x != 0:
line_pos -= 1
x -= 1
else:
if y == 0:
rprint(KEY_BELL)
continue
if line_pos == 0:
cur_line -= 1
line_pos = len(lines[cur_line])
x = line_pos % terminal_size.columns
y -= 1"""
y, x, line_pos, cur_line = move_back(y, x, line_pos, cur_line, lines, terminal_size.columns)
move(y, x)
rprint(' ')
move(y, x)
lines[cur_line] = remove_str(lines[cur_line], line_pos)
elif key == KEY_ENTER: elif key == KEY_ENTER:
print('') y, x = nl(y, x)
cur_line += 1 cur_line += 1
if cur_line >= len(lines): line_pos = 0
if len(lines) == cur_line:
lines.append('') lines.append('')
elif 31 < ord(key) < 127: elif 31 < ord(key) < 127: # keystroke
lines[cur_line] += key line_pos += 1
rprint(key)
x += 1 x += 1
#print(key.encode())
if x - 1 == terminal_size.columns:
y, x = nl(y, x)
rprint(key)
lines[cur_line] = insert_str(lines[cur_line], key, line_pos)
y, x = refresh(line_pos, cur_line, lines, terminal_size.columns) # TODO make this not needed
if __name__ == "__main__": if __name__ == "__main__":
wrapper(main) wrapper(main)

View file

@ -1,3 +1,4 @@
KEY_ESCAPE = '\x1b' KEY_ESCAPE = '\x1b'
KEY_BACKSPACE = '\x7f' KEY_BACKSPACE = '\x7f'
KEY_ENTER = '\n' KEY_ENTER = '\n'
KEY_BELL = '\x07'