commit
This commit is contained in:
parent
885fc45751
commit
fbfa0257a7
2 changed files with 128 additions and 25 deletions
|
@ -1,5 +1,6 @@
|
|||
from os import get_terminal_size, O_NONBLOCK
|
||||
from sys import stdin
|
||||
from termios import tcgetattr, tcsetattr, TCSADRAIN
|
||||
from tty import setcbreak
|
||||
from fcntl import fcntl, F_GETFL, F_SETFL
|
||||
|
||||
|
@ -8,14 +9,20 @@ from keys import *
|
|||
def wrapper(f: callable, *args: any):
|
||||
try:
|
||||
fd = stdin.fileno()
|
||||
orig_fl = fcntl(fd, F_GETFL)
|
||||
old_fl = fcntl(fd, F_GETFL)
|
||||
old_tc = tcgetattr(fd)
|
||||
|
||||
setcbreak(fd)
|
||||
fcntl(fd, F_SETFL, orig_fl | O_NONBLOCK)
|
||||
fcntl(fd, F_SETFL, old_fl | O_NONBLOCK)
|
||||
|
||||
f(*args)
|
||||
except KeyboardInterrupt:
|
||||
cprint('2J')
|
||||
move(0, 0)
|
||||
pass
|
||||
finally:
|
||||
fcntl(fd, F_SETFL, orig_fl)
|
||||
fcntl(fd, F_SETFL, old_fl)
|
||||
tcsetattr(fd, TCSADRAIN, old_tc)
|
||||
|
||||
|
||||
def rprint(*text: str):
|
||||
|
@ -24,29 +31,88 @@ def rprint(*text: str):
|
|||
def cprint(*code: str):
|
||||
rprint(*['\033[' + c for c in code])
|
||||
|
||||
def refresh(lines: list[str], ncols: int) -> tuple[int, int]:
|
||||
cprint('2J', '0;0H')
|
||||
y = 0
|
||||
cl = -1
|
||||
def move(y: int, x: int):
|
||||
cprint(f'{y+1};{x+1}H')
|
||||
|
||||
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:
|
||||
_ = 0
|
||||
if ln == cur_line: # if this line is the focused line
|
||||
y = my
|
||||
while _ == 0 or l != '':
|
||||
cl = l[:ncols]
|
||||
print(cl)
|
||||
_ += 1
|
||||
l = l[ncols:]
|
||||
y += _
|
||||
my += _
|
||||
ln += 1
|
||||
|
||||
x = len(cl) + 1
|
||||
if x - 1 == ncols:
|
||||
x = 0
|
||||
y += 1
|
||||
cprint(f'{y};{x}H')
|
||||
x = line_pos % ncols
|
||||
if line_pos / ncols >= 1:
|
||||
y += line_pos // ncols
|
||||
move(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():
|
||||
cprint('2J', '0;0H')
|
||||
terminal_size = None
|
||||
|
||||
y = 0
|
||||
|
@ -60,27 +126,63 @@ def main():
|
|||
new_terminal_size = get_terminal_size()
|
||||
if new_terminal_size != terminal_size:
|
||||
terminal_size = new_terminal_size
|
||||
|
||||
y, x = refresh(lines, terminal_size.columns)
|
||||
y, x = refresh(line_pos, cur_line, lines, terminal_size.columns)
|
||||
|
||||
key = stdin.read(1)
|
||||
|
||||
if key == '':
|
||||
continue
|
||||
elif key == KEY_ESCAPE:
|
||||
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:
|
||||
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:
|
||||
print('')
|
||||
y, x = nl(y, x)
|
||||
|
||||
cur_line += 1
|
||||
if cur_line >= len(lines):
|
||||
line_pos = 0
|
||||
if len(lines) == cur_line:
|
||||
lines.append('')
|
||||
elif 31 < ord(key) < 127:
|
||||
lines[cur_line] += key
|
||||
rprint(key)
|
||||
elif 31 < ord(key) < 127: # keystroke
|
||||
line_pos += 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__":
|
||||
wrapper(main)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
KEY_ESCAPE = '\x1b'
|
||||
KEY_BACKSPACE = '\x7f'
|
||||
KEY_ENTER = '\n'
|
||||
KEY_ENTER = '\n'
|
||||
KEY_BELL = '\x07'
|
Loading…
Reference in a new issue