Skip to content

Commit e49c754

Browse files
authored
Merge pull request #7 from adafruit/more_stuff
Working on more things
2 parents b1930c7 + 45bd92d commit e49c754

File tree

9 files changed

+296
-147
lines changed

9 files changed

+296
-147
lines changed

build.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import shutil
55
from pathlib import Path
66
import requests
7+
from circup.commands import main as circup_cli
78

89
LEARN_PROJECT_URLS = [
910
"https://cdn-learn.adafruit.com/downloads/zip/3194974/Metro/Metro_RP2350_Snake.zip?timestamp={}",
@@ -102,7 +103,11 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
102103

103104
# copy builtin apps
104105
shutil.copytree("builtin_apps", apps_dir, dirs_exist_ok=True)
105-
106+
shutil.copyfile("mock_boot_out.txt", temp_dir / "boot_out.txt")
107+
for builtin_app_dir in os.listdir("builtin_apps"):
108+
circup_cli(["--path", temp_dir, "install", "--auto", "--auto-file", f"apps/{builtin_app_dir}/code.py"],
109+
standalone_mode=False)
110+
os.remove(temp_dir / "boot_out.txt")
106111
# Create the final zip file
107112
with zipfile.ZipFile(output_zip, 'w', zipfile.ZIP_DEFLATED) as zf:
108113
for file_path in temp_dir.rglob("*"):

builtin_apps/editor/adafruit_editor/dang.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ def getkey(self):
113113
self._pending = pending[1:]
114114
return pending[0]
115115
else:
116-
c = self._terminal_read_blocking()
116+
c = self._terminal_read_timeout(50)
117+
if c is None:
118+
return None
117119
c = pending + c
118120

119121
code = special_keys.get(c)

builtin_apps/editor/adafruit_editor/editor.py

Lines changed: 185 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ def clamp(x, lower, upper):
116116
return x
117117

118118

119+
def _count_leading_characters(text, char):
120+
count = 0
121+
for c in text:
122+
if c == char:
123+
count += 1
124+
else:
125+
break
126+
return count
127+
128+
119129
class Cursor:
120130
def __init__(self, row=0, col=0, col_hint=None):
121131
self.row = row
@@ -219,19 +229,40 @@ def end(window, buffer, cursor):
219229
window.horizontal_scroll(cursor)
220230

221231

222-
def editor(stdscr, filename, visible_cursor): # pylint: disable=too-many-branches,too-many-statements
232+
def editor(stdscr, filename, mouse=None, terminal_tilegrid=None): # pylint: disable=too-many-branches,too-many-statements
233+
234+
def _only_spaces_before(cursor):
235+
i = cursor.col - 1
236+
while i >= 0:
237+
print(f"i: {i} chr: '{buffer.lines[cursor.row][i]}'")
238+
if buffer.lines[cursor.row][i] != " ":
239+
return False
240+
i -= 1
241+
return True
223242
if os_exists(filename):
224243
with open(filename, "r", encoding="utf-8") as f:
225244
buffer = Buffer(f.read().splitlines())
226245
else:
227246
buffer = Buffer([""])
247+
print(f"cwd: {os.getcwd()} | {os.getcwd() == "/apps/editor"}")
248+
if os.getcwd() != "/apps/editor" and os.getcwd() != "/":
249+
absolute_filepath = os.getcwd() + "/" + filename
250+
else:
251+
absolute_filepath = filename
228252

229253
user_message = None
254+
user_message_shown_time = -1
255+
256+
clicked_tile_coords = [None, None]
230257

231258
window = Window(curses.LINES - 1, curses.COLS - 1)
232259
cursor = Cursor()
233-
visible_cursor.text = buffer[0][0]
234-
last_refresh_time = -1
260+
terminal_tilegrid.pixel_shader[cursor.col,cursor.row] = [1, 0]
261+
old_cursor_pos = (cursor.col, cursor.row)
262+
# try:
263+
# visible_cursor.text = buffer[0][0]
264+
# except IndexError:
265+
# visible_cursor.text = " "
235266

236267
stdscr.erase()
237268

@@ -244,6 +275,7 @@ def setline(row, line):
244275
line += " " * (window.n_cols - len(line))
245276
stdscr.addstr(row, 0, line)
246277

278+
print(f"cwd: {os.getcwd()} | abs path: {absolute_filepath} | filename: {filename}")
247279
while True:
248280
lastrow = 0
249281
for row, line in enumerate(buffer[window.row: window.row + window.n_rows]):
@@ -258,133 +290,183 @@ def setline(row, line):
258290
row = curses.LINES - 1
259291

260292
if user_message is None:
261-
if util.readonly():
262-
line = f"{filename:12} (mnt RO ^W) | ^R run | ^C: quit{gc_mem_free_hint()}"
293+
if (not absolute_filepath.startswith("/saves/") and
294+
not absolute_filepath.startswith("/sd/") and
295+
util.readonly()):
296+
297+
line = f"{absolute_filepath:12} (mnt RO ^W) | ^R run | ^O Open | ^C: quit{gc_mem_free_hint()}"
263298
else:
264-
line = f"{filename:12} (mnt RW ^W) | ^R run | ^S save | ^X: save & exit | ^C: exit no save{gc_mem_free_hint()}"
299+
line = f"{absolute_filepath:12} (mnt RW ^W) | ^R run | ^O Open | ^S save | ^X: save & exit | ^C: exit no save{gc_mem_free_hint()}"
265300
else:
266301
line = user_message
267-
user_message = None
302+
if user_message_shown_time + 3.0 < time.monotonic():
303+
user_message = None
268304
setline(row, line)
269305

270306
stdscr.move(*window.translate(cursor))
271-
old_cursor_pos = (cursor.col, cursor.row)
307+
272308
# display.refresh(minimum_frames_per_second=20)
273309
k = stdscr.getkey()
274-
# print(repr(k))
275-
if len(k) == 1 and " " <= k <= "~":
276-
buffer.insert(cursor, k)
277-
for _ in k:
278-
right(window, buffer, cursor)
279-
elif k == "\x18": # ctrl-x
280-
if not util.readonly():
281-
with open(filename, "w", encoding="utf-8") as f:
310+
if k is not None:
311+
# print(repr(k))
312+
if len(k) == 1 and " " <= k <= "~":
313+
buffer.insert(cursor, k)
314+
for _ in k:
315+
right(window, buffer, cursor)
316+
elif k == "\x18": # ctrl-x
317+
if not util.readonly():
318+
with open(filename, "w", encoding="utf-8") as f:
319+
for row in buffer:
320+
f.write(f"{row}\n")
321+
return
322+
else:
323+
print("Unable to Save due to readonly mode! File Contents:")
324+
print("---- begin file contents ----")
282325
for row in buffer:
283-
f.write(f"{row}\n")
284-
return
285-
else:
286-
print("Unable to Save due to readonly mode! File Contents:")
287-
print("---- begin file contents ----")
326+
print(row)
327+
print("---- end file contents ----")
328+
elif k == "\x13": # Ctrl-S
329+
print(absolute_filepath)
330+
print(f"starts with saves: {absolute_filepath.startswith("/saves/")}")
331+
print(f"stars saves: {absolute_filepath.startswith("/saves/")}")
332+
print(f"stars sd: {absolute_filepath.startswith("/sd/")}")
333+
print(f"readonly: {util.readonly()}")
334+
if (absolute_filepath.startswith("/saves/") or
335+
absolute_filepath.startswith("/sd/") or
336+
not util.readonly()):
337+
338+
with open(absolute_filepath, "w", encoding="utf-8") as f:
339+
for row in buffer:
340+
f.write(f"{row}\n")
341+
user_message = "Saved"
342+
user_message_shown_time = time.monotonic()
343+
else:
344+
user_message = "Unable to Save due to readonly mode!"
345+
user_message_shown_time = time.monotonic()
346+
elif k == "\x11": # Ctrl-Q
347+
print("ctrl-Q")
288348
for row in buffer:
289349
print(row)
290-
print("---- end file contents ----")
291-
elif k == "\x13": # Ctrl-S
292-
if not util.readonly():
293-
with open(filename, "w", encoding="utf-8") as f:
294-
for row in buffer:
295-
f.write(f"{row}\n")
296-
user_message = "Saved"
297-
else:
298-
print("Unable to Save due to readonly mode!")
299-
elif k == "\x11": # Ctrl-Q
300-
print("ctrl-Q")
301-
for row in buffer:
302-
print(row)
303-
elif k == "\x17": # Ctrl-W
304-
boot_args_file = argv_filename("/boot.py")
305-
with open(boot_args_file, "w") as f:
306-
f.write(json.dumps([not util.readonly(), "/apps/editor/code.py", Path(filename).absolute()]))
307-
microcontroller.reset()
308-
elif k == "\x12": # Ctrl-R
309-
print(f"Run: {filename}")
310-
311-
launcher_code_args_file = argv_filename("/code.py")
312-
with open(launcher_code_args_file, "w") as f:
313-
f.write(json.dumps(["/apps/editor/code.py", Path(filename).absolute()]))
314-
315-
supervisor.set_next_code_file(filename, sticky_on_reload=False, reload_on_error=True,
316-
working_directory=Path(filename).parent.absolute())
317-
supervisor.reload()
318-
elif k == "KEY_HOME":
319-
home(window, buffer, cursor)
320-
elif k == "KEY_END":
321-
end(window, buffer, cursor)
322-
elif k == "KEY_LEFT":
323-
left(window, buffer, cursor)
324-
elif k == "KEY_DOWN":
325-
326-
cursor.down(buffer)
327-
window.down(buffer, cursor)
328-
window.horizontal_scroll(cursor)
329-
print(f"scroll pos: {window.row}")
330-
elif k == "KEY_PGDN":
331-
for _ in range(window.n_rows):
350+
elif k == "\x17": # Ctrl-W
351+
boot_args_file = argv_filename("/boot.py")
352+
with open(boot_args_file, "w") as f:
353+
f.write(json.dumps([not util.readonly(), "/apps/editor/code.py", Path(filename).absolute()]))
354+
microcontroller.reset()
355+
elif k == "\x12": # Ctrl-R
356+
print(f"Run: {filename}")
357+
358+
launcher_code_args_file = argv_filename("/code.py")
359+
with open(launcher_code_args_file, "w") as f:
360+
f.write(json.dumps(["/apps/editor/code.py", Path(filename).absolute()]))
361+
362+
supervisor.set_next_code_file(filename, sticky_on_reload=False, reload_on_error=True,
363+
working_directory=Path(filename).parent.absolute())
364+
supervisor.reload()
365+
elif k == "\x0f": # Ctrl-O
366+
367+
supervisor.set_next_code_file("/apps/editor/code.py", sticky_on_reload=False, reload_on_error=True,
368+
working_directory="/apps/editor")
369+
supervisor.reload()
370+
371+
372+
elif k == "KEY_HOME":
373+
home(window, buffer, cursor)
374+
elif k == "KEY_END":
375+
end(window, buffer, cursor)
376+
elif k == "KEY_LEFT":
377+
left(window, buffer, cursor)
378+
elif k == "KEY_DOWN":
379+
332380
cursor.down(buffer)
333381
window.down(buffer, cursor)
334382
window.horizontal_scroll(cursor)
335-
elif k == "KEY_UP":
336-
cursor.up(buffer)
337-
window.up(cursor)
338-
window.horizontal_scroll(cursor)
339-
elif k == "KEY_PGUP":
340-
for _ in range(window.n_rows):
383+
print(f"scroll pos: {window.row}")
384+
elif k == "KEY_PGDN":
385+
for _ in range(window.n_rows):
386+
cursor.down(buffer)
387+
window.down(buffer, cursor)
388+
window.horizontal_scroll(cursor)
389+
elif k == "KEY_UP":
341390
cursor.up(buffer)
342391
window.up(cursor)
343392
window.horizontal_scroll(cursor)
344-
elif k == "KEY_RIGHT":
345-
right(window, buffer, cursor)
346-
elif k == "\n":
347-
buffer.split(cursor)
348-
right(window, buffer, cursor)
349-
elif k in ("KEY_DELETE", "\x04"):
350-
print("delete")
351-
if cursor.row < len(buffer.lines) - 1 or \
352-
cursor.col < len(buffer.lines[cursor.row]):
353-
buffer.delete(cursor)
354-
try:
355-
visible_cursor.text = buffer.lines[cursor.row][cursor.col]
356-
except IndexError:
357-
visible_cursor.text = " "
358-
359-
elif k in ("KEY_BACKSPACE", "\x7f", "\x08"):
360-
print(f"backspace {bytes(k, 'utf-8')}")
361-
if (cursor.row, cursor.col) > (0, 0):
362-
left(window, buffer, cursor)
363-
buffer.delete(cursor)
393+
elif k == "KEY_PGUP":
394+
for _ in range(window.n_rows):
395+
cursor.up(buffer)
396+
window.up(cursor)
397+
window.horizontal_scroll(cursor)
398+
elif k == "KEY_RIGHT":
399+
right(window, buffer, cursor)
400+
elif k == "\n":
401+
leading_spaces = _count_leading_characters(buffer.lines[cursor.row], " ")
402+
buffer.split(cursor)
403+
right(window, buffer, cursor)
404+
for i in range(leading_spaces):
405+
buffer.insert(cursor, " ")
406+
right(window, buffer, cursor)
407+
elif k in ("KEY_DELETE", "\x04"):
408+
print("delete")
409+
if cursor.row < len(buffer.lines) - 1 or \
410+
cursor.col < len(buffer.lines[cursor.row]):
411+
buffer.delete(cursor)
412+
# try:
413+
# visible_cursor.text = buffer.lines[cursor.row][cursor.col]
414+
# except IndexError:
415+
# visible_cursor.text = " "
416+
417+
elif k in ("KEY_BACKSPACE", "\x7f", "\x08"):
418+
print(f"backspace {bytes(k, 'utf-8')}")
419+
if (cursor.row, cursor.col) > (0, 0):
420+
if cursor.col > 0 and buffer.lines[cursor.row][cursor.col-1] == " " and _only_spaces_before(cursor):
421+
for i in range(4):
422+
left(window, buffer, cursor)
423+
buffer.delete(cursor)
424+
else:
425+
left(window, buffer, cursor)
426+
buffer.delete(cursor)
427+
428+
else:
429+
print(f"unhandled k: {k}")
430+
print(f"unhandled K: {ord(k)}")
431+
print(f"unhandled k: {bytes(k, 'utf-8')}")
432+
433+
434+
if mouse is not None:
435+
pressed_btns = mouse.update()
436+
if pressed_btns is not None and "left" in pressed_btns:
437+
clicked_tile_coords[0] = mouse.x // 6
438+
clicked_tile_coords[1] = mouse.y // 12
439+
440+
if clicked_tile_coords[0] > len(buffer.lines[clicked_tile_coords[1]]):
441+
clicked_tile_coords[0] = len(buffer.lines[clicked_tile_coords[1]])
442+
cursor.row = clicked_tile_coords[1]
443+
cursor.col = clicked_tile_coords[0]
444+
364445

365-
else:
366-
print(f"unhandled k: {k}")
367-
print(f"unhandled K: {ord(k)}")
368-
print(f"unhandled k: {bytes(k, 'utf-8')}")
369446
# print("updating visible cursor")
370447
# print(f"anchored pos: {((cursor.col * 6) - 1, (cursor.row * 12) + 20)}")
371-
if old_cursor_pos != (cursor.col, cursor.row):
372448

373-
# terminal_tilegrid.pixel_shader[old_cursor_pos[0], old_cursor_pos[1]] = [0,1]
374-
# terminal_tilegrid.pixel_shader[cursor.col, cursor.row] = [1,0]
449+
if old_cursor_pos != (cursor.col, cursor.row):
450+
# print(f"old cursor: {old_cursor_pos}, new: {(cursor.col, cursor.row)}")
451+
terminal_tilegrid.pixel_shader[old_cursor_pos[0], old_cursor_pos[1]] = [0,1]
452+
terminal_tilegrid.pixel_shader[cursor.col, cursor.row] = [1,0]
453+
# print(f"old: {terminal_tilegrid.pixel_shader[old_cursor_pos[0], old_cursor_pos[1]]} new: {terminal_tilegrid.pixel_shader[cursor.col, cursor.row]}")
375454

376455
# visible_cursor.anchored_position = ((cursor.col * 6) - 1, (cursor.row * 12) + 20)
377-
visible_cursor.anchored_position = ((cursor.col * 6), ((cursor.row - window.row) * 12))
378456

379-
try:
380-
visible_cursor.text = buffer.lines[cursor.row][cursor.col]
381-
except IndexError:
382-
visible_cursor.text = " "
457+
# visible_cursor.anchored_position = ((cursor.col * 6), ((cursor.row - window.row) * 12))
458+
#
459+
# try:
460+
# visible_cursor.text = buffer.lines[cursor.row][cursor.col]
461+
# except IndexError:
462+
# visible_cursor.text = " "
463+
383464

465+
old_cursor_pos = (cursor.col, cursor.row)
384466

385-
def edit(filename, terminal=None, visible_cursor=None):
467+
def edit(filename, terminal=None, mouse=None, terminal_tilegrid=None):
386468
with MaybeDisableReload():
387469
if terminal is None:
388470
return curses.wrapper(editor, filename)
389471
else:
390-
return curses.custom_terminal_wrapper(terminal, editor, filename, visible_cursor)
472+
return curses.custom_terminal_wrapper(terminal, editor, filename, mouse, terminal_tilegrid)

0 commit comments

Comments
 (0)