diff --git a/code.py b/code.py index 8460699..c4bfe90 100644 --- a/code.py +++ b/code.py @@ -1,5 +1,6 @@ -import editor +import picker, editor try: - editor.edit("code.py") + filename = picker.pick_file() + editor.edit(filename) except KeyboardInterrupt: pass diff --git a/dang.py b/dang.py index 2d3bb1e..7342678 100644 --- a/dang.py +++ b/dang.py @@ -98,7 +98,7 @@ def wrapper(func, *args, **kwds): stdscr = Screen() try: _nonblocking() - func(stdscr, *args, **kwds) + return func(stdscr, *args, **kwds) finally: _blocking() stdscr.move(LINES-1, 0) diff --git a/editor.py b/editor.py index 174c83b..effc006 100644 --- a/editor.py +++ b/editor.py @@ -1,4 +1,5 @@ import dang as curses +import os import sys import gc @@ -20,6 +21,13 @@ class MaybeDisableReload: runtime.autoreload = self._old_autoreload +def os_exists(filename): + try: + os.stat(filename) + return True + except OSError: + return False + def gc_mem_free_hint(): if hasattr(gc, 'mem_free'): gc.collect() @@ -172,15 +180,18 @@ def end(window, buffer, cursor): window.horizontal_scroll(cursor) def editor(stdscr, filename): - with open(filename) as f: - buffer = Buffer(f.read().splitlines()) + if os_exists(filename): + with open(filename) as f: + buffer = Buffer(f.read().splitlines()) + else: + buffer = Buffer([]) window = Window(curses.LINES - 1, curses.COLS - 1) cursor = Cursor() stdscr.erase() - img = [''] * window.n_rows + img = [''] * curses.LINES def setline(row, line): if img[row] == line: return @@ -188,7 +199,7 @@ def editor(stdscr, filename): stdscr.addstr(row, 0, line) while True: - for row, line in enumerate(buffer[window.row:window.row + window.n_rows-1]): + for row, line in enumerate(buffer[window.row:window.row + window.n_rows]): if row == cursor.row - window.row and window.col > 0: line = "«" + line[window.col + 1:] if len(line) > window.n_cols: @@ -196,7 +207,7 @@ def editor(stdscr, filename): line += ' ' * (window.n_cols - len(line)) setline(row, line) - row = window.n_rows - 1 + row = curses.LINES - 1 if readonly(): line = f"{filename:12} (readonly) | ^C: quit{gc_mem_free_hint()}" else: @@ -243,7 +254,7 @@ def editor(stdscr, filename): def edit(filename): with MaybeDisableReload(): - curses.wrapper(editor, filename) + return curses.wrapper(editor, filename) if __name__ == "__main__": import argparse diff --git a/picker.py b/picker.py new file mode 100644 index 0000000..1a68592 --- /dev/null +++ b/picker.py @@ -0,0 +1,57 @@ +import os +import dang as curses + +always = ["code.py", "boot.py", "settings.toml", "boot_out.txt"] +good_extensions = [".py", ".toml", ".txt", ".json"] + +def os_exists(filename): + try: + os.stat(filename) + return True + except OSError: + return False + +def isdir(filename): + return os.stat(filename)[0] & 0o40_000 + +def has_good_extension(filename): + for g in good_extensions: + if filename.endswith(g): + return True + return False + +def picker(stdscr, options, notes=[], start_idx=0): + stdscr.erase() + stdscr.addstr(curses.LINES-1, 0, "Enter: select | ^C: quit") + del options[curses.LINES-1:] + for row, option in enumerate(options): + if row < len(notes) and (note := notes[row]): + option = f"{option} {note}" + + stdscr.addstr(row, 3, option) + + old_idx = None + idx = start_idx + while True: + if idx != old_idx: + if old_idx is not None: + stdscr.addstr(old_idx, 0, " ") + stdscr.addstr(idx, 0, "=>") + old_idx = idx + + k = stdscr.getkey() + + if k == 'KEY_DOWN': + idx = min(idx + 1, len(options) - 1) + elif k == 'KEY_UP': + idx = max(idx - 1, 0) + elif k == '\n': + return options[idx] + +def pick_file(): + options = always[:] + sorted( + (g for g in os.listdir('.') if g not in always and not isdir(g) and not g.startswith('.')), + key=lambda filename: (not has_good_extension(filename), filename), + ) + notes = [None if os_exists(filename) else "(NEW)" for filename in options] + return curses.wrapper(picker, options, notes)