Last active
July 2, 2021 09:49
-
-
Save secemp9/ffa7e8eb7704dadc690e7732ec05505e to your computer and use it in GitHub Desktop.
Text editor used as Text viewer (Prototype 0)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import curses | |
import io | |
import locale | |
import os | |
import binascii | |
class Editor: | |
def __init__(self, win, file_name): | |
self.win = win | |
self.file_name = file_name | |
self.cur_x, self.cur_y = 0, 0 # cursor position | |
self.win_x, self.win_y = 0, 0 # window top left position | |
self.bar_msg = f'{self.cur_x}, {self.cur_y}' | |
self.read_file() | |
self.screen = curses.initscr() | |
def guess_encoding(self, file_name): | |
csv_file = file_name | |
with io.open(csv_file, "rb") as f: | |
self.data = f.read(5) | |
if self.data.startswith(b"\xEF\xBB\xBF"): # UTF-8 with a "BOM" | |
return "utf-8-sig" | |
elif self.data.startswith(b"\xFF\xFE") or self.data.startswith(b"\xFE\xFF"): | |
return "utf-16" | |
else: # in Windows, guessing utf-8 doesn't work, so we have to try | |
try: | |
with io.open(csv_file, encoding="utf-8") as f: | |
self.preview = f.read(222222) | |
return "utf-8" | |
except: | |
return locale.getdefaultlocale()[1] | |
def read_file(self): | |
with open(self.file_name, 'rb') as f: | |
f.seek(-1, os.SEEK_END) | |
self.last_char = f.read(1) | |
if bytes.hex(self.last_char) == '0a': | |
with open(self.file_name, 'a+', encoding=self.guess_encoding(self.file_name)) as f: | |
f.seek(0) | |
self.buff = f.readlines() | |
if not self.buff: | |
self.buff.append('\n') | |
else: | |
self.chunk_size = 1024 | |
with open(self.file_name, 'rb') as f: | |
while True: | |
self.data = f.read(self.chunk_size) | |
if not self.data: | |
break | |
self.buff = binascii.hexlify(self.data) | |
self.buff = self.buff.decode('ascii') | |
def draw(self): | |
def show_bar(): | |
msg = self.bar_msg[:self.win_w-1] | |
self.win.addstr(self.win_h - 1, 0, msg) | |
def show_text(): | |
for i in range(self.win_x, min(len(self.buff), self.win_x + self.win_h - 1)): | |
line = self.buff[i] | |
line = line[self.win_y : self.win_y + self.win_w] | |
self.win.addstr(line if line else '\n') | |
def update_cursor_position(): | |
self.win.move(self.cur_x - self.win_x, self.cur_y - self.win_y) | |
def update_window_position(): | |
self.win_h, self.win_w = self.win.getmaxyx() # window height, width | |
if self.cur_x < self.win_x: | |
self.win_x = self.cur_x | |
if self.cur_y < self.win_y: | |
self.win_y = self.cur_y | |
if self.cur_x > self.win_x + self.win_h - 2: | |
self.win_x = self.cur_x - self.win_h + 2 | |
if self.cur_y > self.win_x + self.win_w- 2: | |
self.win_y = self.cur_y - self.win_w + 2 | |
self.win.erase() | |
update_window_position() | |
show_text() | |
show_bar() | |
update_cursor_position() | |
def read_key(self): | |
def move_up(): | |
self.cur_x = max(self.cur_x - 1, 0) | |
self.cur_y = min(self.cur_y, len(self.buff[self.cur_x]) - 1) | |
def move_down(): | |
self.cur_x = min(self.cur_x + 1, len(self.buff) - 1) | |
self.cur_y = min(self.cur_y, len(self.buff[self.cur_x]) - 1) | |
def move_left(): | |
self.cur_y = max(self.cur_y - 1, 0) | |
def move_right(): | |
self.cur_y = min(self.cur_y + 1, len(self.buff[self.cur_x]) - 1) | |
key = self.win.getch() | |
if key == curses.KEY_UP: | |
move_up() | |
elif key == curses.KEY_DOWN: | |
move_down() | |
elif key == curses.KEY_LEFT: | |
move_left() | |
elif key == curses.KEY_RIGHT: | |
move_right() | |
elif key == ord('q'): | |
raise SystemExit | |
def run(self): | |
self.draw() | |
while True: | |
self.bar_msg = f'{self.cur_x}, {self.cur_y}' | |
self.read_key() | |
self.draw() | |
def main(win): | |
editor = Editor(win, sys.argv[1]) | |
editor.run() | |
curses.wrapper(main) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment