From fbfa0257a76d26fcbdb46babe2dc6292fbd137ef Mon Sep 17 00:00:00 2001 From: Minecon724 Date: Mon, 1 Jul 2024 15:25:23 +0200 Subject: [PATCH] commit --- writer/__main__.py | 150 +++++++++++++++++++++++++++++++++++++-------- writer/keys.py | 3 +- 2 files changed, 128 insertions(+), 25 deletions(-) diff --git a/writer/__main__.py b/writer/__main__.py index 95a5ed0..96aa0bc 100644 --- a/writer/__main__.py +++ b/writer/__main__.py @@ -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) diff --git a/writer/keys.py b/writer/keys.py index 1a5bd58..d9a4229 100644 --- a/writer/keys.py +++ b/writer/keys.py @@ -1,3 +1,4 @@ KEY_ESCAPE = '\x1b' KEY_BACKSPACE = '\x7f' -KEY_ENTER = '\n' \ No newline at end of file +KEY_ENTER = '\n' +KEY_BELL = '\x07' \ No newline at end of file