update boot.py to use adafruit_argv_file, fix new file functionality, allow saving files in /saves/ and /sd/ when main storage is readonly, ctrl-p hotkey to open picker from editor
This commit is contained in:
parent
b1930c7231
commit
e41c7e56c4
4 changed files with 105 additions and 39 deletions
|
|
@ -116,6 +116,16 @@ def clamp(x, lower, upper):
|
|||
return x
|
||||
|
||||
|
||||
def _count_leading_characters(text, char):
|
||||
count = 0
|
||||
for c in text:
|
||||
if c == char:
|
||||
count += 1
|
||||
else:
|
||||
break
|
||||
return count
|
||||
|
||||
|
||||
class Cursor:
|
||||
def __init__(self, row=0, col=0, col_hint=None):
|
||||
self.row = row
|
||||
|
|
@ -220,18 +230,31 @@ def end(window, buffer, cursor):
|
|||
|
||||
|
||||
def editor(stdscr, filename, visible_cursor): # pylint: disable=too-many-branches,too-many-statements
|
||||
|
||||
def _only_spaces_before(cursor):
|
||||
i = cursor.col - 1
|
||||
while i >= 0:
|
||||
print(f"i: {i} chr: '{buffer.lines[cursor.row][i]}'")
|
||||
if buffer.lines[cursor.row][i] != " ":
|
||||
return False
|
||||
i -= 1
|
||||
return True
|
||||
if os_exists(filename):
|
||||
with open(filename, "r", encoding="utf-8") as f:
|
||||
buffer = Buffer(f.read().splitlines())
|
||||
else:
|
||||
buffer = Buffer([""])
|
||||
|
||||
absolute_filepath = os.getcwd() + "/" + filename
|
||||
|
||||
user_message = None
|
||||
|
||||
window = Window(curses.LINES - 1, curses.COLS - 1)
|
||||
cursor = Cursor()
|
||||
visible_cursor.text = buffer[0][0]
|
||||
last_refresh_time = -1
|
||||
try:
|
||||
visible_cursor.text = buffer[0][0]
|
||||
except IndexError:
|
||||
visible_cursor.text = " "
|
||||
|
||||
stdscr.erase()
|
||||
|
||||
|
|
@ -258,10 +281,13 @@ def editor(stdscr, filename, visible_cursor): # pylint: disable=too-many-branch
|
|||
row = curses.LINES - 1
|
||||
|
||||
if user_message is None:
|
||||
if util.readonly():
|
||||
line = f"{filename:12} (mnt RO ^W) | ^R run | ^C: quit{gc_mem_free_hint()}"
|
||||
if (not absolute_filepath.startswith("/saves/") and
|
||||
not absolute_filepath.startswith("/sd/") and
|
||||
util.readonly()):
|
||||
|
||||
line = f"{filename:12} (mnt RO ^W) | ^R run | ^P exit & picker | ^C: quit{gc_mem_free_hint()}"
|
||||
else:
|
||||
line = f"{filename:12} (mnt RW ^W) | ^R run | ^S save | ^X: save & exit | ^C: exit no save{gc_mem_free_hint()}"
|
||||
line = f"{filename:12} (mnt RW ^W) | ^R run | ^S save | ^X: save & exit | ^P exit & picker | ^C: exit no save{gc_mem_free_hint()}"
|
||||
else:
|
||||
line = user_message
|
||||
user_message = None
|
||||
|
|
@ -289,13 +315,16 @@ def editor(stdscr, filename, visible_cursor): # pylint: disable=too-many-branch
|
|||
print(row)
|
||||
print("---- end file contents ----")
|
||||
elif k == "\x13": # Ctrl-S
|
||||
if not util.readonly():
|
||||
if (absolute_filepath.startswith("/saves/") or
|
||||
absolute_filepath.startswith("/sd/") or
|
||||
util.readonly()):
|
||||
|
||||
with open(filename, "w", encoding="utf-8") as f:
|
||||
for row in buffer:
|
||||
f.write(f"{row}\n")
|
||||
user_message = "Saved"
|
||||
else:
|
||||
print("Unable to Save due to readonly mode!")
|
||||
user_message = "Unable to Save due to readonly mode!"
|
||||
elif k == "\x11": # Ctrl-Q
|
||||
print("ctrl-Q")
|
||||
for row in buffer:
|
||||
|
|
@ -315,6 +344,10 @@ def editor(stdscr, filename, visible_cursor): # pylint: disable=too-many-branch
|
|||
supervisor.set_next_code_file(filename, sticky_on_reload=False, reload_on_error=True,
|
||||
working_directory=Path(filename).parent.absolute())
|
||||
supervisor.reload()
|
||||
elif k == "\x10": # Ctrl-P
|
||||
supervisor.set_next_code_file("/apps/editor/code.py", sticky_on_reload=False, reload_on_error=True,
|
||||
working_directory="/apps/editor")
|
||||
supervisor.reload()
|
||||
elif k == "KEY_HOME":
|
||||
home(window, buffer, cursor)
|
||||
elif k == "KEY_END":
|
||||
|
|
@ -344,8 +377,12 @@ def editor(stdscr, filename, visible_cursor): # pylint: disable=too-many-branch
|
|||
elif k == "KEY_RIGHT":
|
||||
right(window, buffer, cursor)
|
||||
elif k == "\n":
|
||||
leading_spaces = _count_leading_characters(buffer.lines[cursor.row], " ")
|
||||
buffer.split(cursor)
|
||||
right(window, buffer, cursor)
|
||||
for i in range(leading_spaces):
|
||||
buffer.insert(cursor, " ")
|
||||
right(window, buffer, cursor)
|
||||
elif k in ("KEY_DELETE", "\x04"):
|
||||
print("delete")
|
||||
if cursor.row < len(buffer.lines) - 1 or \
|
||||
|
|
@ -359,8 +396,13 @@ def editor(stdscr, filename, visible_cursor): # pylint: disable=too-many-branch
|
|||
elif k in ("KEY_BACKSPACE", "\x7f", "\x08"):
|
||||
print(f"backspace {bytes(k, 'utf-8')}")
|
||||
if (cursor.row, cursor.col) > (0, 0):
|
||||
left(window, buffer, cursor)
|
||||
buffer.delete(cursor)
|
||||
if cursor.col > 0 and buffer.lines[cursor.row][cursor.col-1] == " " and _only_spaces_before(cursor):
|
||||
for i in range(4):
|
||||
left(window, buffer, cursor)
|
||||
buffer.delete(cursor)
|
||||
else:
|
||||
left(window, buffer, cursor)
|
||||
buffer.delete(cursor)
|
||||
|
||||
else:
|
||||
print(f"unhandled k: {k}")
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
import usb_cdc
|
||||
from . import dang as curses
|
||||
from . import util
|
||||
|
|
@ -115,23 +117,55 @@ def picker(stdscr, options, notes=(), start_idx=0):
|
|||
|
||||
# ctrl-N
|
||||
elif k == "\x0E":
|
||||
if not util.readonly():
|
||||
# if not util.readonly():
|
||||
new_file_name = new_file(stdscr)
|
||||
if new_file_name is not None:
|
||||
return new_file_name
|
||||
else:
|
||||
time.sleep(2)
|
||||
stdscr.erase()
|
||||
old_idx = None
|
||||
_draw_file_list()
|
||||
|
||||
|
||||
|
||||
def terminal_input(stdscr, message):
|
||||
stdscr.erase()
|
||||
stdscr.addstr(0, 0, message)
|
||||
input_str_list = []
|
||||
k = stdscr.getkey()
|
||||
while k != "\n":
|
||||
if len(k) == 1 and " " <= k <= "~":
|
||||
input_str_list.append(k)
|
||||
stdscr.addstr(0, len(message) + len(input_str_list) - 1, k)
|
||||
elif k == "\x08":
|
||||
input_str_list.pop(len(input_str_list) - 1)
|
||||
stdscr.addstr(0, len(message) + len(input_str_list) - 1, k)
|
||||
k = stdscr.getkey()
|
||||
# submit after enter pressed
|
||||
return "".join(input_str_list)
|
||||
|
||||
|
||||
# pylint: disable=inconsistent-return-statements
|
||||
def new_file(stdscr):
|
||||
stdscr.erase()
|
||||
new_file_name = input("New File Name: ")
|
||||
new_file_name = terminal_input(stdscr, "New File Name: ")
|
||||
if os_exists(new_file_name):
|
||||
print("Error: File Already Exists")
|
||||
stdscr.addstr(1,0, "Error: File Already Exists")
|
||||
return
|
||||
with open(new_file_name, "w") as f:
|
||||
f.write("")
|
||||
print(f"new filename: {new_file_name}")
|
||||
if not new_file_name.startswith("/saves/") and not new_file_name.startswith("/sd/"):
|
||||
if not util.readonly():
|
||||
with open(new_file_name, "w") as f:
|
||||
f.write("")
|
||||
|
||||
return new_file_name
|
||||
return new_file_name
|
||||
else:
|
||||
stdscr.addstr(1, 0, "Error: Cannot create file in readonly storage")
|
||||
else:
|
||||
with open(new_file_name, "w") as f:
|
||||
f.write("")
|
||||
return new_file_name
|
||||
|
||||
|
||||
def _files_list():
|
||||
|
|
|
|||
33
src/boot.py
33
src/boot.py
|
|
@ -1,7 +1,9 @@
|
|||
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
import os
|
||||
|
||||
import supervisor
|
||||
from argv_file_helper import argv_filename
|
||||
from adafruit_argv_file import read_argv, write_argv
|
||||
import json
|
||||
import storage
|
||||
|
||||
|
|
@ -15,15 +17,10 @@ boot.py arguments
|
|||
2-N: args to pass to next code file
|
||||
|
||||
"""
|
||||
try:
|
||||
arg_file = argv_filename(__file__)
|
||||
print(f"arg files: {arg_file}")
|
||||
with open(arg_file, "r") as f:
|
||||
args = json.load(f)
|
||||
|
||||
print("args file found and loaded")
|
||||
os.remove(arg_file)
|
||||
print("args file removed")
|
||||
|
||||
args = read_argv(__file__)
|
||||
if args is not None and len(args) > 0:
|
||||
|
||||
readonly = args[0]
|
||||
next_code_file = None
|
||||
|
|
@ -35,20 +32,14 @@ try:
|
|||
remaining_args = args[2:]
|
||||
|
||||
if remaining_args is not None:
|
||||
next_code_argv_filename = argv_filename(next_code_file)
|
||||
with open(next_code_argv_filename, "w") as f:
|
||||
f.write(json.dumps(remaining_args))
|
||||
print("next code args written")
|
||||
write_argv(next_code_file, remaining_args)
|
||||
|
||||
print(f"setting storage readonly to: {readonly}")
|
||||
# print(f"setting storage readonly to: {readonly}")
|
||||
storage.remount("/", readonly=readonly)
|
||||
|
||||
next_code_file = next_code_file
|
||||
supervisor.set_next_code_file(next_code_file)
|
||||
print(f"launching: {next_code_file}")
|
||||
# os.rename("/saves/.boot_py_argv", "/saves/.not_boot_py_argv")
|
||||
supervisor.set_next_code_file(next_code_file, sticky_on_reload=False, reload_on_error=True,
|
||||
working_directory="/".join(next_code_file.split("/")[:-1]))
|
||||
|
||||
|
||||
except OSError:
|
||||
print("launching boot animation")
|
||||
supervisor.set_next_code_file("boot_animation.py")
|
||||
else:
|
||||
supervisor.set_next_code_file("boot_animation.py")
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
|
||||
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""
|
||||
This example uses adafruit_display_text.label to display text using a custom font
|
||||
loaded by adafruit_bitmap_font
|
||||
Fruit Jam OS Launcher
|
||||
"""
|
||||
import array
|
||||
import atexit
|
||||
|
|
|
|||
Loading…
Reference in a new issue