Skip to content

Commit dfe3eec

Browse files
committed
add mouse support to editor, make getkey() non-blocking, swap visible cursor to use TilePaletteMapper, use ctrl-O for open, fix saving files, highlight bottom row
1 parent e41c7e5 commit dfe3eec

File tree

4 files changed

+208
-136
lines changed

4 files changed

+208
-136
lines changed

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: 158 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ def end(window, buffer, cursor):
229229
window.horizontal_scroll(cursor)
230230

231231

232-
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
233233

234234
def _only_spaces_before(cursor):
235235
i = cursor.col - 1
@@ -244,17 +244,25 @@ def _only_spaces_before(cursor):
244244
buffer = Buffer(f.read().splitlines())
245245
else:
246246
buffer = Buffer([""])
247-
248-
absolute_filepath = os.getcwd() + "/" + filename
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
249252

250253
user_message = None
254+
user_message_shown_time = -1
255+
256+
clicked_tile_coords = [None, None]
251257

252258
window = Window(curses.LINES - 1, curses.COLS - 1)
253259
cursor = Cursor()
254-
try:
255-
visible_cursor.text = buffer[0][0]
256-
except IndexError:
257-
visible_cursor.text = " "
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 = " "
258266

259267
stdscr.erase()
260268

@@ -267,6 +275,7 @@ def setline(row, line):
267275
line += " " * (window.n_cols - len(line))
268276
stdscr.addstr(row, 0, line)
269277

278+
print(f"cwd: {os.getcwd()} | abs path: {absolute_filepath} | filename: {filename}")
270279
while True:
271280
lastrow = 0
272281
for row, line in enumerate(buffer[window.row: window.row + window.n_rows]):
@@ -285,148 +294,179 @@ def setline(row, line):
285294
not absolute_filepath.startswith("/sd/") and
286295
util.readonly()):
287296

288-
line = f"{filename:12} (mnt RO ^W) | ^R run | ^P exit & picker | ^C: quit{gc_mem_free_hint()}"
297+
line = f"{absolute_filepath:12} (mnt RO ^W) | ^R run | ^O Open | ^C: quit{gc_mem_free_hint()}"
289298
else:
290-
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()}"
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()}"
291300
else:
292301
line = user_message
293-
user_message = None
302+
if user_message_shown_time + 3.0 < time.monotonic():
303+
user_message = None
294304
setline(row, line)
295305

296306
stdscr.move(*window.translate(cursor))
297-
old_cursor_pos = (cursor.col, cursor.row)
307+
298308
# display.refresh(minimum_frames_per_second=20)
299309
k = stdscr.getkey()
300-
# print(repr(k))
301-
if len(k) == 1 and " " <= k <= "~":
302-
buffer.insert(cursor, k)
303-
for _ in k:
304-
right(window, buffer, cursor)
305-
elif k == "\x18": # ctrl-x
306-
if not util.readonly():
307-
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 ----")
308325
for row in buffer:
309-
f.write(f"{row}\n")
310-
return
311-
else:
312-
print("Unable to Save due to readonly mode! File Contents:")
313-
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")
314348
for row in buffer:
315349
print(row)
316-
print("---- end file contents ----")
317-
elif k == "\x13": # Ctrl-S
318-
if (absolute_filepath.startswith("/saves/") or
319-
absolute_filepath.startswith("/sd/") or
320-
util.readonly()):
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":
321379

322-
with open(filename, "w", encoding="utf-8") as f:
323-
for row in buffer:
324-
f.write(f"{row}\n")
325-
user_message = "Saved"
326-
else:
327-
user_message = "Unable to Save due to readonly mode!"
328-
elif k == "\x11": # Ctrl-Q
329-
print("ctrl-Q")
330-
for row in buffer:
331-
print(row)
332-
elif k == "\x17": # Ctrl-W
333-
boot_args_file = argv_filename("/boot.py")
334-
with open(boot_args_file, "w") as f:
335-
f.write(json.dumps([not util.readonly(), "/apps/editor/code.py", Path(filename).absolute()]))
336-
microcontroller.reset()
337-
elif k == "\x12": # Ctrl-R
338-
print(f"Run: {filename}")
339-
340-
launcher_code_args_file = argv_filename("/code.py")
341-
with open(launcher_code_args_file, "w") as f:
342-
f.write(json.dumps(["/apps/editor/code.py", Path(filename).absolute()]))
343-
344-
supervisor.set_next_code_file(filename, sticky_on_reload=False, reload_on_error=True,
345-
working_directory=Path(filename).parent.absolute())
346-
supervisor.reload()
347-
elif k == "\x10": # Ctrl-P
348-
supervisor.set_next_code_file("/apps/editor/code.py", sticky_on_reload=False, reload_on_error=True,
349-
working_directory="/apps/editor")
350-
supervisor.reload()
351-
elif k == "KEY_HOME":
352-
home(window, buffer, cursor)
353-
elif k == "KEY_END":
354-
end(window, buffer, cursor)
355-
elif k == "KEY_LEFT":
356-
left(window, buffer, cursor)
357-
elif k == "KEY_DOWN":
358-
359-
cursor.down(buffer)
360-
window.down(buffer, cursor)
361-
window.horizontal_scroll(cursor)
362-
print(f"scroll pos: {window.row}")
363-
elif k == "KEY_PGDN":
364-
for _ in range(window.n_rows):
365380
cursor.down(buffer)
366381
window.down(buffer, cursor)
367382
window.horizontal_scroll(cursor)
368-
elif k == "KEY_UP":
369-
cursor.up(buffer)
370-
window.up(cursor)
371-
window.horizontal_scroll(cursor)
372-
elif k == "KEY_PGUP":
373-
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":
374390
cursor.up(buffer)
375391
window.up(cursor)
376392
window.horizontal_scroll(cursor)
377-
elif k == "KEY_RIGHT":
378-
right(window, buffer, cursor)
379-
elif k == "\n":
380-
leading_spaces = _count_leading_characters(buffer.lines[cursor.row], " ")
381-
buffer.split(cursor)
382-
right(window, buffer, cursor)
383-
for i in range(leading_spaces):
384-
buffer.insert(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)
385403
right(window, buffer, cursor)
386-
elif k in ("KEY_DELETE", "\x04"):
387-
print("delete")
388-
if cursor.row < len(buffer.lines) - 1 or \
389-
cursor.col < len(buffer.lines[cursor.row]):
390-
buffer.delete(cursor)
391-
try:
392-
visible_cursor.text = buffer.lines[cursor.row][cursor.col]
393-
except IndexError:
394-
visible_cursor.text = " "
395-
396-
elif k in ("KEY_BACKSPACE", "\x7f", "\x08"):
397-
print(f"backspace {bytes(k, 'utf-8')}")
398-
if (cursor.row, cursor.col) > (0, 0):
399-
if cursor.col > 0 and buffer.lines[cursor.row][cursor.col-1] == " " and _only_spaces_before(cursor):
400-
for i in range(4):
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:
401425
left(window, buffer, cursor)
402426
buffer.delete(cursor)
403-
else:
404-
left(window, buffer, cursor)
405-
buffer.delete(cursor)
406427

407-
else:
408-
print(f"unhandled k: {k}")
409-
print(f"unhandled K: {ord(k)}")
410-
print(f"unhandled k: {bytes(k, 'utf-8')}")
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+
445+
411446
# print("updating visible cursor")
412447
# print(f"anchored pos: {((cursor.col * 6) - 1, (cursor.row * 12) + 20)}")
413-
if old_cursor_pos != (cursor.col, cursor.row):
414448

415-
# terminal_tilegrid.pixel_shader[old_cursor_pos[0], old_cursor_pos[1]] = [0,1]
416-
# 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]}")
417454

418455
# visible_cursor.anchored_position = ((cursor.col * 6) - 1, (cursor.row * 12) + 20)
419-
visible_cursor.anchored_position = ((cursor.col * 6), ((cursor.row - window.row) * 12))
420456

421-
try:
422-
visible_cursor.text = buffer.lines[cursor.row][cursor.col]
423-
except IndexError:
424-
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+
425464

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

427-
def edit(filename, terminal=None, visible_cursor=None):
467+
def edit(filename, terminal=None, mouse=None, terminal_tilegrid=None):
428468
with MaybeDisableReload():
429469
if terminal is None:
430470
return curses.wrapper(editor, filename)
431471
else:
432-
return curses.custom_terminal_wrapper(terminal, editor, filename, visible_cursor)
472+
return curses.custom_terminal_wrapper(terminal, editor, filename, mouse, terminal_tilegrid)

builtin_apps/editor/adafruit_editor/picker.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,13 @@ def terminal_input(stdscr, message):
135135
input_str_list = []
136136
k = stdscr.getkey()
137137
while k != "\n":
138-
if len(k) == 1 and " " <= k <= "~":
139-
input_str_list.append(k)
140-
stdscr.addstr(0, len(message) + len(input_str_list) - 1, k)
141-
elif k == "\x08":
142-
input_str_list.pop(len(input_str_list) - 1)
143-
stdscr.addstr(0, len(message) + len(input_str_list) - 1, k)
138+
if k is not None:
139+
if len(k) == 1 and " " <= k <= "~":
140+
input_str_list.append(k)
141+
stdscr.addstr(0, len(message) + len(input_str_list) - 1, k)
142+
elif k == "\x08":
143+
input_str_list.pop(len(input_str_list) - 1)
144+
stdscr.addstr(0, len(message) + len(input_str_list) - 1, k)
144145
k = stdscr.getkey()
145146
# submit after enter pressed
146147
return "".join(input_str_list)
@@ -149,6 +150,7 @@ def terminal_input(stdscr, message):
149150
# pylint: disable=inconsistent-return-statements
150151
def new_file(stdscr):
151152
stdscr.erase()
153+
print(f"cwd inside new_file(): {os.getcwd()}")
152154
new_file_name = terminal_input(stdscr, "New File Name: ")
153155
if os_exists(new_file_name):
154156
stdscr.addstr(1,0, "Error: File Already Exists")

0 commit comments

Comments
 (0)