Merge lines.love
[?]
Sep 7, 2022, 1:46 AM
D4B52CQ2QKG2HQKFUQOO5S2ME325DTW3PH2D7SBXCW4BPQFYG7CACDependencies
- [2]
VHUNJHXBMerge lines.love - [3]
KMSL74GAsupport selections in the source editor - [4]
XW7ANEJXswitch shortcuts for bifold text - [5]
VHQCNMARseveral more modules - [6]
CE4LZV4Tdrop last couple of manual tests - [7]
RSZD5A7Gforgot to add json.lua - [8]
T4FRZSYLdelete an ancient, unused file - [9]
R5QXEHUIsomebody stop me - [10]
XX7G2FFJintermingle freehand line drawings with text - [11]
BLWAYPKVextract a module - [12]
73OCE2MCafter much struggle, a brute-force undo - [13]
MD3W5IRAnew fork: rip out drawing support - [14]
QS3YLNKZMerge lines.love - [15]
6LJZN727handle chords - [16]
BJ5X5O4Alet's prevent the text cursor from ever getting on a drawing - [17]
3QNOKBFMbeginnings of a test harness - [18]
OI4FPFINsupport drawings in the source editor - [19]
D2GCFTTTclean up repl functionality - [20]
VXORMHMEdelete experimental REPL - [21]
2CTN2IEFMerge lines.love - [22]
JOPVPUSAediting source code from within the app - [23]
TLOAPLBJadd a license - [24]
BULPIBEGbeginnings of a module for the text editor - [25]
66X36NZNa little more prose describing manual_tests - [26]
OTIBCAUJlove2d scaffold - [27]
32V6ZHQBMerge lines.love - [28]
UN7GKYV5support hyperlinks in the source editor - [29]
AVTNUQYRbasic test-enabled framework - [30]
4YDBYBA4clean up memory leak experiments - [31]
K2X6G75Zstart writing some tests for drawings - [32]
2L5MEZV3experiment: new edit namespace - [33]
3PSFWAILMerge lines.love - [34]
GUOQRUL7Merge lines.love - [35]
LXTTOB33extract a couple of files - [36]
OGUV4HSAremove some memory leaks from rendered fragments - [37]
FS2ITYYHrecord a known issue - [38]
TVCPXAAUrename - [39]
KKMFQDR4editing source code from within the app
Change contents
- file deletion: source_text_tests.lua source_text_tests.lua
function test_undo_restores_selection()io.write('\ntest_undo_restores_selection')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- delete selected textedit.run_after_textinput(Editor_state, 'x')check_eq(Editor_state.lines[1].data, 'xbc', 'F - test_undo_restores_selection/baseline')check_nil(Editor_state.selection1.line, 'F - test_undo_restores_selection/baseline:selection')-- undoedit.run_after_keychord(Editor_state, 'C-z')edit.run_after_keychord(Editor_state, 'C-z')-- selection is restoredcheck_eq(Editor_state.selection1.line, 1, 'F - test_undo_restores_selection/line')check_eq(Editor_state.selection1.pos, 2, 'F - test_undo_restores_selection/pos')endfunction test_search()io.write('\ntest_search')App.screen.init{width=120, height=60}Editor_state = edit.initialize_test_state()check_nil(Editor_state.selection1.line, 'F - test_undo_delete_text/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_undo_delete_text/selection:pos')--? check_eq(Editor_state.selection1.line, 2, 'F - test_undo_delete_text/selection:line')--? check_eq(Editor_state.selection1.pos, 4, 'F - test_undo_delete_text/selection:pos')y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_undo_delete_text/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'defg', 'F - test_undo_delete_text/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'xyz', 'F - test_undo_delete_text/screen:3')endcheck_nil(Editor_state.selection1.line, 'F - test_undo_delete_text/baseline/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_undo_delete_text/baseline/selection:pos')local y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_undo_delete_text/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'def', 'F - test_undo_delete_text/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'xyz', 'F - test_undo_delete_text/baseline/screen:3')-- undo--? -- after undo, the backspaced key is selectededit.run_after_keychord(Editor_state, 'C-z')check_eq(Editor_state.cursor1.line, 2, 'F - test_undo_delete_text/cursor:line')check_eq(Editor_state.cursor1.pos, 5, 'F - test_undo_delete_text/cursor:pos')check_nil(Editor_state.selection1.line, 'F - test_undo_insert_text/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_undo_insert_text/selection:pos')y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_undo_insert_text/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'def', 'F - test_undo_insert_text/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'xyz', 'F - test_undo_insert_text/screen:3')endfunction test_undo_delete_text()io.write('\ntest_undo_delete_text')App.screen.init{width=120, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'defg', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=5}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- delete a characteredit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.cursor1.line, 2, 'F - test_undo_delete_text/baseline/cursor:line')check_eq(Editor_state.cursor1.pos, 4, 'F - test_undo_delete_text/baseline/cursor:pos')check_nil(Editor_state.selection1.line, 'F - test_undo_insert_text/baseline/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_undo_insert_text/baseline/selection:pos')local y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_undo_insert_text/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'defg', 'F - test_undo_insert_text/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'xyz', 'F - test_undo_insert_text/baseline/screen:3')-- undoedit.run_after_keychord(Editor_state, 'C-z')check_eq(Editor_state.cursor1.line, 2, 'F - test_undo_insert_text/cursor:line')check_eq(Editor_state.cursor1.pos, 4, 'F - test_undo_insert_text/cursor:pos')-- some tests for operating over selections created using Shift- chords-- we're just testing delete_selection, and it works the same for all keysfunction test_backspace_over_selection()io.write('\ntest_backspace_over_selection')-- select just one character within a line with cursor before selectionApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}-- backspace deletes the selected character, even though it's after the cursoredit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'bc', "F - test_backspace_over_selection/data")-- cursor (remains) at start of selectioncheck_eq(Editor_state.cursor1.line, 1, "F - test_backspace_over_selection/cursor:line")check_eq(Editor_state.cursor1.pos, 1, "F - test_backspace_over_selection/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_over_selection/selection")endfunction test_backspace_over_selection_reverse()io.write('\ntest_backspace_over_selection_reverse')-- select just one character within a line with cursor after selectionApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.selection1 = {line=1, pos=1}-- backspace deletes the selected characteredit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'bc', "F - test_backspace_over_selection_reverse/data")-- cursor moves to start of selectioncheck_eq(Editor_state.cursor1.line, 1, "F - test_backspace_over_selection_reverse/cursor:line")check_eq(Editor_state.cursor1.pos, 1, "F - test_backspace_over_selection_reverse/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_over_selection_reverse/selection")endfunction test_backspace_over_multiple_lines()io.write('\ntest_backspace_over_multiple_lines')-- select just one character within a line with cursor after selectionApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.selection1 = {line=4, pos=2}-- backspace deletes the region and joins the remaining portions of lines on either sideedit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'akl', "F - test_backspace_over_multiple_lines/data:1")check_eq(Editor_state.lines[2].data, 'mno', "F - test_backspace_over_multiple_lines/data:2")-- cursor remains at start of selectioncheck_eq(Editor_state.cursor1.line, 1, "F - test_backspace_over_multiple_lines/cursor:line")check_eq(Editor_state.cursor1.pos, 2, "F - test_backspace_over_multiple_lines/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_over_multiple_lines/selection")endfunction test_backspace_to_end_of_line()io.write('\ntest_backspace_to_end_of_line')-- select region from cursor to end of lineApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.selection1 = {line=1, pos=4}-- backspace deletes rest of line without joining to any other lineedit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'a', "F - test_backspace_to_start_of_line/data:1")check_eq(Editor_state.lines[2].data, 'def', "F - test_backspace_to_start_of_line/data:2")-- cursor remains at start of selectioncheck_eq(Editor_state.cursor1.line, 1, "F - test_backspace_to_start_of_line/cursor:line")check_eq(Editor_state.cursor1.pos, 2, "F - test_backspace_to_start_of_line/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_to_start_of_line/selection")endfunction test_backspace_to_start_of_line()io.write('\ntest_backspace_to_start_of_line')-- select region from cursor to start of lineApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=1}Editor_state.selection1 = {line=2, pos=3}-- backspace deletes beginning of line without joining to any other lineedit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'abc', "F - test_backspace_to_start_of_line/data:1")check_eq(Editor_state.lines[2].data, 'f', "F - test_backspace_to_start_of_line/data:2")-- cursor remains at start of selectioncheck_eq(Editor_state.cursor1.line, 2, "F - test_backspace_to_start_of_line/cursor:line")check_eq(Editor_state.cursor1.pos, 1, "F - test_backspace_to_start_of_line/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_to_start_of_line/selection")endfunction test_undo_insert_text()io.write('\ntest_undo_insert_text')App.screen.init{width=120, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=4}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- insert a characteredit.draw(Editor_state)edit.run_after_textinput(Editor_state, 'g')check_eq(Editor_state.cursor1.line, 2, 'F - test_undo_insert_text/baseline/cursor:line')check_eq(Editor_state.cursor1.pos, 5, 'F - test_undo_insert_text/baseline/cursor:pos')edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+Editor_state.line_height*2+5, 1)-- cursor should movecheck_eq(Editor_state.cursor1.line, 1, 'F - test_position_cursor_on_recently_edited_wrapping_line/cursor:line')check_eq(Editor_state.cursor1.pos, 26, 'F - test_position_cursor_on_recently_edited_wrapping_line/cursor:pos')endfunction test_backspace_can_scroll_up()io.write('\ntest_backspace_can_scroll_up')-- display the lines 2/3/4 with the cursor on line 2App.screen.init{width=120, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=1}Editor_state.screen_top1 = {line=2, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'def', 'F - test_backspace_can_scroll_up/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_backspace_can_scroll_up/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'jkl', 'F - test_backspace_can_scroll_up/baseline/screen:3')-- after hitting backspace the screen scrolls up by one lineedit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.screen_top1.line, 1, 'F - test_backspace_can_scroll_up/screen_top')check_eq(Editor_state.cursor1.line, 1, 'F - test_backspace_can_scroll_up/cursor')y = Editor_state.topApp.screen.check(y, 'abcdef', 'F - test_backspace_can_scroll_up/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_backspace_can_scroll_up/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'jkl', 'F - test_backspace_can_scroll_up/screen:3')endfunction test_backspace_can_scroll_up_screen_line()io.write('\ntest_backspace_can_scroll_up_screen_line')-- display lines starting from second screen line of a lineApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=3, pos=5}Editor_state.screen_top1 = {line=3, pos=5}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'jkl', 'F - test_backspace_can_scroll_up_screen_line/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'mno', 'F - test_backspace_can_scroll_up_screen_line/baseline/screen:2')-- after hitting backspace the screen scrolls up by one screen lineedit.run_after_keychord(Editor_state, 'backspace')y = Editor_state.topApp.screen.check(y, 'ghij', 'F - test_backspace_can_scroll_up_screen_line/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'kl', 'F - test_backspace_can_scroll_up_screen_line/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'mno', 'F - test_backspace_can_scroll_up_screen_line/screen:3')check_eq(Editor_state.screen_top1.line, 3, 'F - test_backspace_can_scroll_up_screen_line/screen_top')check_eq(Editor_state.screen_top1.pos, 1, 'F - test_backspace_can_scroll_up_screen_line/screen_top')check_eq(Editor_state.cursor1.line, 3, 'F - test_backspace_can_scroll_up_screen_line/cursor:line')check_eq(Editor_state.cursor1.pos, 4, 'F - test_backspace_can_scroll_up_screen_line/cursor:pos')endfunction test_backspace_past_line_boundary()io.write('\ntest_backspace_past_line_boundary')-- position cursor at start of a (non-first) lineApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=1}-- backspace joins with previous lineedit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'abcdef', "F - test_backspace_past_line_boundary")endfunction test_cut_without_selection()io.write('\ntest_cut_without_selection')-- display a few linesApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}Editor_state.selection1 = {}edit.draw(Editor_state)-- try to cut without selecting textedit.run_after_keychord(Editor_state, 'C-x')-- no crashcheck_nil(Editor_state.selection1.line, 'F - test_cut_without_selection')endfunction test_pagedown()io.write('\ntest_pagedown')App.screen.init{width=120, height=45}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- initially the first two lines are displayededit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_pagedown/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'def', 'F - test_pagedown/baseline/screen:2')-- after pagedown the bottom line becomes the topedit.run_after_keychord(Editor_state, 'pagedown')check_eq(Editor_state.screen_top1.line, 2, 'F - test_pagedown/screen_top')check_eq(Editor_state.cursor1.line, 2, 'F - test_pagedown/cursor')y = Editor_state.topApp.screen.check(y, 'def', 'F - test_pagedown/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_pagedown/screen:2')check_nil(Editor_state.selection1.line, 'F - test_move_cursor_using_mouse/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_move_cursor_using_mouse/selection:pos')endfunction test_select_text_using_mouse()io.write('\ntest_select_text_using_mouse')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}Editor_state.selection1 = {}edit.draw(Editor_state) -- populate line_cache.starty for each line Editor_state.line_cache-- press and hold on first locationedit.run_after_mouse_press(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- drag and release somewhere elseedit.run_after_mouse_release(Editor_state, Editor_state.left+20,Editor_state.top+Editor_state.line_height+5, 1)check_eq(Editor_state.selection1.line, 1, 'F - test_select_text_using_mouse/selection:line')check_eq(Editor_state.selection1.pos, 2, 'F - test_select_text_using_mouse/selection:pos')check_eq(Editor_state.cursor1.line, 2, 'F - test_select_text_using_mouse/cursor:line')check_eq(Editor_state.cursor1.pos, 4, 'F - test_select_text_using_mouse/cursor:pos')endfunction test_select_text_using_mouse_and_shift()io.write('\ntest_select_text_using_mouse_and_shift')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}Editor_state.selection1 = {}edit.draw(Editor_state) -- populate line_cache.starty for each line Editor_state.line_cache-- click on first locationedit.run_after_mouse_press(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- hold down shift and click somewhere elseApp.fake_key_press('lshift')edit.run_after_mouse_press(Editor_state, Editor_state.left+20,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+20,Editor_state.top+Editor_state.line_height+5, 1)App.fake_key_release('lshift')check_eq(Editor_state.selection1.line, 1, 'F - test_select_text_using_mouse_and_shift/selection:line')check_eq(Editor_state.selection1.pos, 2, 'F - test_select_text_using_mouse_and_shift/selection:pos')check_eq(Editor_state.cursor1.line, 2, 'F - test_select_text_using_mouse_and_shift/cursor:line')check_eq(Editor_state.cursor1.pos, 4, 'F - test_select_text_using_mouse_and_shift/cursor:pos')endfunction test_select_text_repeatedly_using_mouse_and_shift()io.write('\ntest_select_text_repeatedly_using_mouse_and_shift')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}Editor_state.selection1 = {}edit.draw(Editor_state) -- populate line_cache.starty for each line Editor_state.line_cache-- click on first locationedit.run_after_mouse_press(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- hold down shift and click on a second locationApp.fake_key_press('lshift')edit.run_after_mouse_press(Editor_state, Editor_state.left+20,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+20,Editor_state.top+Editor_state.line_height+5, 1)-- hold down shift and click at a third locationApp.fake_key_press('lshift')edit.run_after_mouse_press(Editor_state, Editor_state.left+20,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+Editor_state.line_height+5, 1)App.fake_key_release('lshift')-- selection is between first and third location. forget the second location, not the first.check_eq(Editor_state.selection1.line, 1, 'F - test_select_text_repeatedly_using_mouse_and_shift/selection:line')check_eq(Editor_state.selection1.pos, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/selection:pos')check_eq(Editor_state.cursor1.line, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/cursor:pos')endedit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)check_eq(Editor_state.cursor1.line, 1, 'F - test_move_cursor_using_mouse/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_move_cursor_using_mouse/cursor:pos')Editor_state.selection1 = {}edit.draw(Editor_state) -- populate line_cache.starty for each line Editor_state.line_cachefunction test_edit_deletes_selection()io.write('\ntest_edit_deletes_selection')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- press a keyedit.run_after_textinput(Editor_state, 'x')-- selected text is deleted and replaced with the keycheck_eq(Editor_state.lines[1].data, 'xbc', 'F - test_edit_deletes_selection')endfunction test_edit_with_shift_key_deletes_selection()io.write('\ntest_edit_with_shift_key_deletes_selection')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- mimic precise keypresses for a capital letterApp.fake_key_press('lshift')edit.keychord_pressed(Editor_state, 'd', 'd')edit.textinput(Editor_state, 'D')edit.key_released(Editor_state, 'd')App.fake_key_release('lshift')-- selected text is deleted and replaced with the keycheck_nil(Editor_state.selection1.line, 'F - test_edit_with_shift_key_deletes_selection')check_eq(Editor_state.lines[1].data, 'Dbc', 'F - test_edit_with_shift_key_deletes_selection/data')endfunction test_copy_does_not_reset_selection()io.write('\ntest_copy_does_not_reset_selection')-- display a line of text with a selectionApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- copy selectionedit.run_after_keychord(Editor_state, 'C-c')check_eq(App.clipboard, 'a', 'F - test_copy_does_not_reset_selection/clipboard')-- selection is reset since shift key is not pressedcheck(Editor_state.selection1.line, 'F - test_copy_does_not_reset_selection')endfunction test_cut()io.write('\ntest_cut')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- press a keyedit.run_after_keychord(Editor_state, 'C-x')check_eq(App.clipboard, 'a', 'F - test_cut/clipboard')-- selected text is deletedcheck_eq(Editor_state.lines[1].data, 'bc', 'F - test_cut/data')endfunction test_paste_replaces_selection()io.write('\ntest_paste_replaces_selection')-- display a line of text with a selectionApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=1}Editor_state.selection1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- set clipboardApp.clipboard = 'xyz'-- paste selectionedit.run_after_keychord(Editor_state, 'C-v')-- selection is reset since shift key is not pressed-- selection includes the newline, so it's also deletedcheck_eq(Editor_state.lines[1].data, 'xyzdef', 'F - test_paste_replaces_selection')endfunction test_deleting_selection_may_scroll()io.write('\ntest_deleting_selection_may_scroll')-- display lines 2/3/4App.screen.init{width=120, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=3, pos=2}Editor_state.screen_top1 = {line=2, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'def', 'F - test_deleting_selection_may_scroll/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_deleting_selection_may_scroll/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'jkl', 'F - test_deleting_selection_may_scroll/baseline/screen:3')-- set up a selection starting above the currently displayed pageEditor_state.selection1 = {line=1, pos=2}-- delete selectionedit.run_after_keychord(Editor_state, 'backspace')-- page scrolls upcheck_eq(Editor_state.screen_top1.line, 1, 'F - test_deleting_selection_may_scroll')check_eq(Editor_state.lines[1].data, 'ahi', 'F - test_deleting_selection_may_scroll/data')endfunction test_edit_wrapping_text()io.write('\ntest_edit_wrapping_text')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=4}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)edit.run_after_textinput(Editor_state, 'g')local y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_edit_wrapping_text/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'de', 'F - test_edit_wrapping_text/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'fg', 'F - test_edit_wrapping_text/screen:3')endfunction test_insert_newline()io.write('\ntest_insert_newline')-- display a few linesApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_insert_newline/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'def', 'F - test_insert_newline/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_insert_newline/baseline/screen:3')-- hitting the enter key splits the lineedit.run_after_keychord(Editor_state, 'return')check_eq(Editor_state.screen_top1.line, 1, 'F - test_insert_newline/screen_top')check_eq(Editor_state.cursor1.line, 2, 'F - test_insert_newline/cursor:line')check_eq(Editor_state.cursor1.pos, 1, 'F - test_insert_newline/cursor:pos')y = Editor_state.topApp.screen.check(y, 'a', 'F - test_insert_newline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'bc', 'F - test_insert_newline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'def', 'F - test_insert_newline/screen:3')endfunction test_insert_newline_at_start_of_line()io.write('\ntest_insert_newline_at_start_of_line')-- display a lineApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- hitting the enter key splits the lineedit.run_after_keychord(Editor_state, 'return')check_eq(Editor_state.cursor1.line, 2, 'F - test_insert_newline_at_start_of_line/cursor:line')check_eq(Editor_state.cursor1.pos, 1, 'F - test_insert_newline_at_start_of_line/cursor:pos')check_eq(Editor_state.lines[1].data, '', 'F - test_insert_newline_at_start_of_line/data:1')check_eq(Editor_state.lines[2].data, 'abc', 'F - test_insert_newline_at_start_of_line/data:2')endfunction test_insert_from_clipboard()io.write('\ntest_insert_from_clipboard')-- display a few linesApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_insert_from_clipboard/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'def', 'F - test_insert_from_clipboard/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_insert_from_clipboard/baseline/screen:3')-- paste some text including a newline, check that new line is createdApp.clipboard = 'xy\nz'edit.run_after_keychord(Editor_state, 'C-v')check_eq(Editor_state.screen_top1.line, 1, 'F - test_insert_from_clipboard/screen_top')check_eq(Editor_state.cursor1.line, 2, 'F - test_insert_from_clipboard/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_insert_from_clipboard/cursor:pos')y = Editor_state.topApp.screen.check(y, 'axy', 'F - test_insert_from_clipboard/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'zbc', 'F - test_insert_from_clipboard/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'def', 'F - test_insert_from_clipboard/screen:3')endfunction test_move_cursor_using_mouse()io.write('\ntest_move_cursor_using_mouse')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}endfunction test_select_text()io.write('\ntest_select_text')-- display a line of textApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc def'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- select a letterApp.fake_key_press('lshift')edit.run_after_keychord(Editor_state, 'S-right')App.fake_key_release('lshift')edit.key_released(Editor_state, 'lshift')-- selection persists even after shift is releasedcheck_eq(Editor_state.selection1.line, 1, 'F - test_select_text/selection:line')check_eq(Editor_state.selection1.pos, 1, 'F - test_select_text/selection:pos')check_eq(Editor_state.cursor1.line, 1, 'F - test_select_text/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_select_text/cursor:pos')endfunction test_cursor_movement_without_shift_resets_selection()io.write('\ntest_cursor_movement_without_shift_resets_selection')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- press an arrow key without shiftedit.run_after_keychord(Editor_state, 'right')-- no change to data, selection is resetcheck_nil(Editor_state.selection1.line, 'F - test_cursor_movement_without_shift_resets_selection')check_eq(Editor_state.lines[1].data, 'abc', 'F - test_cursor_movement_without_shift_resets_selection/data')endcheck_nil(Editor_state.selection1.line, 'F - test_click_with_mouse_on_wrapping_line_takes_margins_into_account/selection is empty to avoid perturbing future edits')endfunction test_draw_text_wrapping_within_word()-- arrange a screen line that needs to be split within a wordio.write('\ntest_draw_text_wrapping_within_word')App.screen.init{width=60, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abcd e fghijk', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'abcd ', 'F - test_draw_text_wrapping_within_word/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'e fgh', 'F - test_draw_text_wrapping_within_word/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'ijk', 'F - test_draw_text_wrapping_within_word/screen:3')endfunction test_draw_wrapping_text_containing_non_ascii()-- draw a long line containing non-ASCIIio.write('\ntest_draw_wrapping_text_containing_non_ascii')App.screen.init{width=60, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'madam I’m adam', 'xyz'} -- notice the non-ASCII apostropheText.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'mad', 'F - test_draw_wrapping_text_containing_non_ascii/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'am I', 'F - test_draw_wrapping_text_containing_non_ascii/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, '’m a', 'F - test_draw_wrapping_text_containing_non_ascii/screen:3')endfunction test_click_on_wrapping_line()io.write('\ntest_click_on_wrapping_line')-- display a wrapping lineApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()-- 12345678901234Editor_state.lines = load_array{"madam I'm adam"}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'madam ', 'F - test_click_on_wrapping_line/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, "I'm ad", 'F - test_click_on_wrapping_line/baseline/screen:2')y = y + Editor_state.line_height-- click past end of second screen lineedit.run_after_mouse_click(Editor_state, App.screen.width-2,y-2, 1)-- cursor moves to end of screen linecheck_eq(Editor_state.cursor1.line, 1, 'F - test_click_on_wrapping_line/cursor:line')check_eq(Editor_state.cursor1.pos, 12, 'F - test_click_on_wrapping_line/cursor:pos')endfunction test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen()io.write('\ntest_click_on_wrapping_line_rendered_from_partway_at_top_of_screen')-- display a wrapping line from its second screen lineApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()-- 12345678901234Editor_state.lines = load_array{"madam I'm adam"}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=8}Editor_state.screen_top1 = {line=1, pos=7}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, "I'm ad", 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/baseline/screen:2')y = y + Editor_state.line_height-- click past end of second screen lineedit.run_after_mouse_click(Editor_state, App.screen.width-2,y-2, 1)-- cursor moves to end of screen linecheck_eq(Editor_state.cursor1.line, 1, 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/cursor:line')check_eq(Editor_state.cursor1.pos, 12, 'F - test_click_on_wrapping_line_rendered_from_partway_at_top_of_screen/cursor:pos')endfunction test_click_past_end_of_wrapping_line()io.write('\ntest_click_past_end_of_wrapping_line')-- display a wrapping lineApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()-- 12345678901234Editor_state.lines = load_array{"madam I'm adam"}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'madam ', 'F - test_click_past_end_of_wrapping_line/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, "I'm ad", 'F - test_click_past_end_of_wrapping_line/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'am', 'F - test_click_past_end_of_wrapping_line/baseline/screen:3')y = y + Editor_state.line_height-- click past the end of itedit.run_after_mouse_click(Editor_state, App.screen.width-2,y-2, 1)-- cursor moves to end of linecheck_eq(Editor_state.cursor1.pos, 15, 'F - test_click_past_end_of_wrapping_line/cursor') -- one more than the number of UTF-8 code-pointsendfunction test_click_past_end_of_wrapping_line_containing_non_ascii()io.write('\ntest_click_past_end_of_wrapping_line_containing_non_ascii')-- display a wrapping line containing non-ASCIIApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()-- 12345678901234Editor_state.lines = load_array{'madam I’m adam'} -- notice the non-ASCII apostropheText.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'madam ', 'F - test_click_past_end_of_wrapping_line_containing_non_ascii/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'I’m ad', 'F - test_click_past_end_of_wrapping_line_containing_non_ascii/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'am', 'F - test_click_past_end_of_wrapping_line_containing_non_ascii/baseline/screen:3')y = y + Editor_state.line_height-- click past the end of itedit.run_after_mouse_click(Editor_state, App.screen.width-2,y-2, 1)-- cursor moves to end of linecheck_eq(Editor_state.cursor1.pos, 15, 'F - test_click_past_end_of_wrapping_line_containing_non_ascii/cursor') -- one more than the number of UTF-8 code-pointsendfunction test_click_past_end_of_word_wrapping_line()io.write('\ntest_click_past_end_of_word_wrapping_line')-- display a long line wrapping at a word boundary on a screen of more realistic lengthApp.screen.init{width=160, height=80}Editor_state = edit.initialize_test_state()-- 0 1 2-- 123456789012345678901Editor_state.lines = load_array{'the quick brown fox jumped over the lazy dog'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'the quick brown fox ', 'F - test_click_past_end_of_word_wrapping_line/baseline/screen:1')y = y + Editor_state.line_height-- click past the end of the screen lineedit.run_after_mouse_click(Editor_state, App.screen.width-2,y-2, 1)-- cursor moves to end of screen linecheck_eq(Editor_state.cursor1.pos, 20, 'F - test_click_past_end_of_word_wrapping_line/cursor')check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse_on_wrapping_line/selection is empty to avoid perturbing future edits')endfunction test_click_with_mouse_on_wrapping_line_takes_margins_into_account()io.write('\ntest_click_with_mouse_on_wrapping_line_takes_margins_into_account')-- display two lines with cursor on one of themApp.screen.init{width=100, height=80}Editor_state = edit.initialize_test_state()Editor_state.left = 50 -- occupy only right side of screenEditor_state.lines = load_array{'abc def ghi jkl mno pqr stu'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=20}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- click on the other lineedit.draw(Editor_state)edit.run_after_mouse_click(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- cursor movescheck_eq(Editor_state.cursor1.line, 1, 'F - test_click_with_mouse_on_wrapping_line_takes_margins_into_account/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_click_with_mouse_on_wrapping_line_takes_margins_into_account/cursor:pos')check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse_takes_margins_into_account/selection is empty to avoid perturbing future edits')endfunction test_click_with_mouse_on_empty_line()io.write('\ntest_click_with_mouse_on_empty_line')-- display two lines with the first one emptyApp.screen.init{width=50, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'', 'def'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- click on the empty lineedit.draw(Editor_state)edit.run_after_mouse_click(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- cursor movescheck_eq(Editor_state.cursor1.line, 1, 'F - test_click_with_mouse_on_empty_line/cursor')endfunction test_draw_text()io.write('\ntest_draw_text')App.screen.init{width=120, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_draw_text/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'def', 'F - test_draw_text/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_draw_text/screen:3')endfunction test_draw_wrapping_text()io.write('\ntest_draw_wrapping_text')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'defgh', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'abc', 'F - test_draw_wrapping_text/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'de', 'F - test_draw_wrapping_text/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'fgh', 'F - test_draw_wrapping_text/screen:3')endfunction test_draw_word_wrapping_text()io.write('\ntest_draw_word_wrapping_text')App.screen.init{width=60, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc def ghi', 'jkl'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'abc ', 'F - test_draw_word_wrapping_text/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'def ', 'F - test_draw_word_wrapping_text/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_draw_word_wrapping_text/screen:3')endfunction test_click_with_mouse_on_wrapping_line()io.write('\ntest_click_with_mouse_on_wrapping_line')-- display two lines with cursor on one of themApp.screen.init{width=50, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc def ghi jkl mno pqr stu'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=20}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- click on the other lineedit.draw(Editor_state)edit.run_after_mouse_click(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- cursor movescheck_eq(Editor_state.cursor1.line, 1, 'F - test_click_with_mouse_on_wrapping_line/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_click_with_mouse_on_wrapping_line/cursor:pos')check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse_to_left_of_line/selection is empty to avoid perturbing future edits')endfunction test_click_with_mouse_takes_margins_into_account()io.write('\ntest_click_with_mouse_takes_margins_into_account')-- display two lines with cursor on one of themApp.screen.init{width=100, height=80}Editor_state = edit.initialize_test_state()Editor_state.left = 50 -- occupy only right side of screenEditor_state.lines = load_array{'abc', 'def'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- click on the other lineedit.draw(Editor_state)edit.run_after_mouse_click(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- cursor movescheck_eq(Editor_state.cursor1.line, 1, 'F - test_click_with_mouse_takes_margins_into_account/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_click_with_mouse_takes_margins_into_account/cursor:pos')check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse/selection is empty to avoid perturbing future edits')endfunction test_click_with_mouse_to_left_of_line()io.write('\ntest_click_with_mouse_to_left_of_line')-- display a line with the cursor in the middleApp.screen.init{width=50, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=3}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}-- click to the left of the lineedit.draw(Editor_state)edit.run_after_mouse_click(Editor_state, Editor_state.left-4,Editor_state.top+5, 1)-- cursor moves to start of linecheck_eq(Editor_state.cursor1.line, 1, 'F - test_click_with_mouse_to_left_of_line/cursor:line')check_eq(Editor_state.cursor1.pos, 1, 'F - test_click_with_mouse_to_left_of_line/cursor:pos') - file deletion: source_text.lua source_text.lua
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.pagedown(State)endendfunction Text.insert_return(State)if State.cursor1.pos then-- when inserting a newline, move any B side to the new linelocal byte_offset = Text.offset(State.lines[State.cursor1.line].data, State.cursor1.pos)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.pageup(State)elseif chord == 'S-pagedown' thenState.selection1 = {}elseif chord == 'S-pageup' thenState.selection1 = {}elseif chord == 'pagedown' thenText.pagedown(State)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.down(State)elseif chord == 'pageup' thenText.pageup(State)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.up(State)elseif chord == 'S-down' thenState.selection1 = {}elseif chord == 'S-up' thenState.selection1 = {}elseif chord == 'down' thenText.down(State)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.end_of_line(State)elseif chord == 'up' thenText.up(State)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.start_of_line(State)elseif chord == 'S-end' thenState.selection1 = {}elseif chord == 'S-home' thenState.selection1 = {}elseif chord == 'end' thenText.end_of_line(State)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.word_right(State)elseif chord == 'home' thenText.start_of_line(State)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.word_left(State)elseif chord == 'M-S-right' thenState.selection1 = {}elseif chord == 'M-S-left' thenState.selection1 = {}elseif chord == 'M-right' thenText.word_right(State)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.right(State)-- C- hotkeys reserved for drawings, so we'll use M-elseif chord == 'M-left' thenText.word_left(State)if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}endText.left(State)elseif chord == 'S-right' thenState.selection1 = {}elseif chord == 'S-left' thenState.selection1 = {}elseif chord == 'right' thenText.right(State)if State.selection1.line thenText.delete_selection(State, State.left, State.right)schedule_save(State)returnendlocal beforeif State.cursor1.posB or State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) thenbefore = snapshot(State, State.cursor1.line)elsebefore = snapshot(State, State.cursor1.line, State.cursor1.line+1)endif State.cursor1.pos and State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) thenlocal byte_start = utf8.offset(State.lines[State.cursor1.line].data, State.cursor1.pos)local byte_end = utf8.offset(State.lines[State.cursor1.line].data, State.cursor1.pos+1)if byte_start thenif byte_end thenState.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_start-1)..string.sub(State.lines[State.cursor1.line].data, byte_end)elseState.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_start-1)end-- no change to State.cursor1.posendelseif State.cursor1.posB thenif State.cursor1.posB <= utf8.len(State.lines[State.cursor1.line].dataB) thenlocal byte_start = utf8.offset(State.lines[State.cursor1.line].dataB, State.cursor1.posB)local byte_end = utf8.offset(State.lines[State.cursor1.line].dataB, State.cursor1.posB+1)if byte_start thenif byte_end thenState.lines[State.cursor1.line].dataB = string.sub(State.lines[State.cursor1.line].dataB, 1, byte_start-1)..string.sub(State.lines[State.cursor1.line].dataB, byte_end)elseState.lines[State.cursor1.line].dataB = string.sub(State.lines[State.cursor1.line].dataB, 1, byte_start-1)end-- no change to State.cursor1.posendelse-- refuse to delete past end of side Bendelseif State.cursor1.line < #State.lines thenif State.selection1.line thenText.delete_selection(State, State.left, State.right)schedule_save(State)returnendlocal beforeif State.cursor1.pos and State.cursor1.pos > 1 thenbefore = snapshot(State, State.cursor1.line)local byte_start = utf8.offset(State.lines[State.cursor1.line].data, State.cursor1.pos-1)local byte_end = utf8.offset(State.lines[State.cursor1.line].data, State.cursor1.pos)if byte_start thenif byte_end thenState.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_start-1)..string.sub(State.lines[State.cursor1.line].data, byte_end)elseState.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_start-1)endState.cursor1.pos = State.cursor1.pos-1endelseif State.cursor1.posB thenif State.cursor1.posB > 1 thenbefore = snapshot(State, State.cursor1.line)local byte_start = utf8.offset(State.lines[State.cursor1.line].dataB, State.cursor1.posB-1)local byte_end = utf8.offset(State.lines[State.cursor1.line].dataB, State.cursor1.posB)if byte_start thenif byte_end thenState.lines[State.cursor1.line].dataB = string.sub(State.lines[State.cursor1.line].dataB, 1, byte_start-1)..string.sub(State.lines[State.cursor1.line].dataB, byte_end)elseState.lines[State.cursor1.line].dataB = string.sub(State.lines[State.cursor1.line].dataB, 1, byte_start-1)endState.cursor1.posB = State.cursor1.posB-1endelse-- refuse to delete past beginning of side Bendelseif State.cursor1.line > 1 thenbefore = snapshot(State, State.cursor1.line-1, State.cursor1.line)State.selection1 = {}if State.cursor_y > App.screen.height - State.line_height thenText.snap_cursor_to_bottom_of_screen(State, State.left, State.right)endschedule_save(State)record_undo_event(State, {before=before, after=snapshot(State, before_line, State.cursor1.line)})elseif chord == 'tab' thenlocal before = snapshot(State, State.cursor1.line)--? print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)Text.insert_at_cursor(State, '\t')if State.cursor_y > App.screen.height - State.line_height thenText.populate_screen_line_starting_pos(State, State.cursor1.line)Text.snap_cursor_to_bottom_of_screen(State, State.left, State.right)--? print('=>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)endschedule_save(State)record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})elseif chord == 'backspace' then--? print('chord', chord, State.selection1.line, State.selection1.pos)--== shortcuts that mutate textif chord == 'return' thenlocal before_line = State.cursor1.linelocal before = snapshot(State, before_line)Text.insert_return(State)endif State.selection1.line thenlocal lo, hi = Text.clip_selection(State, line_index, pos, pos+frag_len)Text.draw_highlight(State, line, x,y, pos, lo,hi)endApp.screen.draw(frag_text, x,y)-- render cursor if necessaryif State.cursor1.posB and line_index == State.cursor1.line thenif pos <= State.cursor1.posB and pos + frag_len > State.cursor1.posB thenif State.search_term thenif State.lines[State.cursor1.line].dataB:sub(State.cursor1.posB, State.cursor1.posB+utf8.len(State.search_term)-1) == State.search_term thenlocal lo_px = Text.draw_highlight(State, line, x,y, pos, State.cursor1.posB, State.cursor1.posB+utf8.len(State.search_term))App.color(Fold_color)love.graphics.print(State.search_term, x+lo_px,y)endelseif Focus == 'edit' thenText.draw_cursor(State, x+Text.x(frag, State.cursor1.posB-pos+1), y)App.color(Fold_color)endendendx = x + frag_widthendpos = pos + frag_lenendreturn false, x,y, pos, screen_line_starting_posendfunction Text.draw_cursor(State, x, y)-- blink every 0.5sif math.floor(Cursor_time*2)%2 == 0 thenApp.color(Cursor_color)love.graphics.rectangle('fill', x,y, 3,State.line_height)endState.cursor_x = xState.cursor_y = y+State.line_heightendfunction Text.populate_screen_line_starting_pos(State, line_index)local line = State.lines[line_index]endif State.selection1.line thenlocal lo, hi = Text.clip_selection(State, line_index, pos, pos+frag_len)Text.draw_highlight(State, line, x,y, pos, lo,hi)end - file deletion: source_edit.lua source_edit.lua
State.selection1 = deepcopy(src.selection)patch(State.lines, event.before, event.after)State.selection1 = deepcopy(src.selection)patch(State.lines, event.after, event.before)patch_placeholders(State.line_cache, event.after, event.before)if State.selection1.line andnot State.lines.current_drawing and-- printable character created using shift key => delete selection-- (we're not creating any ctrl-shift- or alt-shift- combinations using regular/printable keys)(not App.shift_down() or utf8.len(key) == 1) andchord ~= 'C-c' and chord ~= 'C-x' and chord ~= 'backspace' and backspace ~= 'delete' and not App.is_cursor_movement(chord) thenText.delete_selection(State, State.left, State.right)endelseif chord == 'M-d' thenif State.cursor1.posB == nil thenlocal before = snapshot(State, State.cursor1.line)if State.lines[State.cursor1.line].dataB == nil thenState.lines[State.cursor1.line].dataB = ''endState.lines[State.cursor1.line].expanded = trueState.cursor1.pos = nilState.cursor1.posB = 1if Text.cursor_out_of_screen(State) thenText.snap_cursor_to_bottom_of_screen(State, State.left, State.right)endschedule_save(State)record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})end-- zoomelseif chord == 'C-=' thenedit.update_font_settings(State, State.font_height+2)Text.redraw_all(State)elseif chord == 'C--' thenedit.update_font_settings(State, State.font_height-2)Text.redraw_all(State)elseif chord == 'C-0' thenedit.update_font_settings(State, 20)Text.redraw_all(State)-- undoelseif chord == 'C-z' thenfor _,line_cache in ipairs(State.line_cache) do line_cache.starty = nil end -- just in case we scrolllocal event = undo_event(State)if event thenlocal src = event.beforeState.screen_top1 = deepcopy(src.screen_top)State.cursor1 = deepcopy(src.cursor)elseif chord == 'M-b' thenState.expanded = not State.expandedText.redraw_all(State)if not State.expanded thenfor _,line in ipairs(State.lines) doline.expanded = nilendedit.eradicate_locations_after_the_fold(State)endif State.search_term thenif chord == 'escape' thenState.search_term = nilState.search_text = nilState.cursor1 = State.search_backup.cursorState.screen_top1 = State.search_backup.screen_topState.search_backup = nilText.redraw_all(State) -- if we're scrolling, reclaim all fragments to avoid memory leakselseif chord == 'return' thenState.search_term = nilState.search_text = nilState.search_backup = nilelseif chord == 'backspace' thenlocal len = utf8.len(State.search_term)local byte_offset = Text.offset(State.search_term, len)State.search_term = string.sub(State.search_term, 1, byte_offset-1)State.search_text = nilelseif chord == 'down' thenif State.cursor1.pos thenState.cursor1.pos = State.cursor1.pos+1elseState.cursor1.posB = State.cursor1.posB+1endText.search_next(State)elseif chord == 'up' thenText.search_previous(State)endreturnelseif chord == 'C-f' thenState.search_term = ''State.search_backup = {cursor={line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB},screen_top={line=State.screen_top1.line, pos=State.screen_top1.pos, posB=State.screen_top1.posB},}assert(State.search_text == nil)-- bifold textelsefor line_index,line in ipairs(State.lines) doif line.mode == 'text' thenif Text.in_line(State, line_index, x,y) then--? print('reset selection')local pos,posB = Text.to_pos_on_line(State, line_index, x, y)State.cursor1 = {line=line_index, pos=pos, posB=posB}--? print('cursor', State.cursor1.line, State.cursor1.pos, State.cursor1.posB)if State.mousepress_shift thenif State.old_selection1.line == nil thenState.selection1 = State.old_cursor1elseState.selection1 = State.old_selection1endendState.old_cursor1, State.old_selection1, State.mousepress_shift = nilif eq(State.cursor1, State.selection1) thenState.selection1 = {}endbreakendendend--? print('selection:', State.selection1.line, State.selection1.pos)endState.selection1 = {line=line_index, pos=pos, posB=posB}--? print('selection', State.selection1.line, State.selection1.pos, State.selection1.posB)breakendelseif line.mode == 'drawing' thenlocal line_cache = State.line_cache[line_index]if Drawing.in_drawing(line, line_cache, x, y, State.left,State.right) thenState.lines.current_drawing_index = line_indexState.lines.current_drawing = lineDrawing.before = snapshot(State, line_index)Drawing.mouse_pressed(State, line_index, x,y, mouse_button)breakend-- delicate dance between cursor, selection and old cursor/selection-- scenarios:-- regular press+release: sets cursor, clears selection-- shift press+release:-- sets selection to old cursor if not set otherwise leaves it untouched-- sets cursor-- press and hold to start a selection: sets selection on press, cursor on release-- press and hold, then press shift: ignore shift-- i.e. mouse_released should never look at shift stateState.old_cursor1 = State.cursor1State.old_selection1 = State.selection1State.mousepress_shift = App.shift_down()local pos,posB = Text.to_pos_on_line(State, line_index, x, y)--? print(x,y, 'setting cursor:', line_index, pos, posB)selection1 = {},-- some extra state to compute selection between mouse press and releaseold_cursor1 = nil,old_selection1 = nil,mousepress_shift = nil,-- when selecting text, avoid recomputing some state on every single framerecent_mouse = {},-- cursor coordinates in pixelscursor_x = 0,cursor_y = 0, - file deletion: commands.lua commands.lua
add_hotkey_to_menu('alt+d: create/edit debug print')add_hotkey_to_menu('ctrl+f: find in file')add_hotkey_to_menu('alt+left alt+right: prev/next word')elseif Focus == 'log_browser' then-- nothing yetelseassert(false, 'unknown focus "'..Focus..'"')endadd_hotkey_to_menu('ctrl+z ctrl+y: undo/redo')add_hotkey_to_menu('ctrl+x ctrl+c ctrl+v: cut/copy/paste')add_hotkey_to_menu('ctrl+= ctrl+- ctrl+0: zoom')endfunction add_hotkey_to_menu(s)if Text_cache[s] == nil thenText_cache[s] = App.newText(love.graphics.getFont(), s)endlocal width = App.width(Text_cache[s])if Menu_cursor + width > App.screen.width - 5 thenreturnendApp.color(Menu_command_color)App.screen.draw(Text_cache[s], Menu_cursor,5)Menu_cursor = Menu_cursor + width + 30endfunction source.draw_file_navigator()for i,file in ipairs(File_navigation.candidates) doif file == 'source' thenApp.color(Menu_border_color)love.graphics.line(Menu_cursor-10,2, Menu_cursor-10,Menu_status_bar_height-2)endadd_file_to_menu(file, i == File_navigation.index)endendfunction add_file_to_menu(s, cursor_highlight)if Text_cache[s] == nil thenText_cache[s] = App.newText(love.graphics.getFont(), s)endlocal width = App.width(Text_cache[s])if Menu_cursor + width > App.screen.width - 5 thenreturnendif cursor_highlight thenApp.color(Menu_highlight_color)love.graphics.rectangle('fill', Menu_cursor-5,5-2, App.width(Text_cache[s])+5*2,Editor_state.line_height+2*2)endApp.color(Menu_command_color)App.screen.draw(Text_cache[s], Menu_cursor,5)Menu_cursor = Menu_cursor + width + 30endfunction keychord_pressed_on_file_navigator(chord, key)if chord == 'escape' thenShow_file_navigator = falseelseif chord == 'return' thenlocal candidate = guess_source(File_navigation.candidates[File_navigation.index]..'.lua')source.switch_to_file(candidate)Show_file_navigator = falseelseif chord == 'left' thenif File_navigation.index > 1 thenFile_navigation.index = File_navigation.index-1endelseif chord == 'right' thenif File_navigation.index < #File_navigation.candidates thenFile_navigation.index = File_navigation.index+1endendendadd_hotkey_to_menu('alt+b: expand debug prints')endadd_hotkey_to_menu('alt+b: collapse debug prints')else - edit in source_text_tests.lua at line 285
check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse/selection is empty to avoid perturbing future edits') - edit in source_text_tests.lua at line 304
check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse_to_left_of_line/selection is empty to avoid perturbing future edits') - edit in source_text_tests.lua at line 324
check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse_takes_margins_into_account/selection is empty to avoid perturbing future edits') - edit in source_text_tests.lua at line 414
check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse_on_wrapping_line/selection is empty to avoid perturbing future edits') - edit in source_text_tests.lua at line 434
check_nil(Editor_state.selection1.line, 'F - test_click_with_mouse_on_wrapping_line_takes_margins_into_account/selection is empty to avoid perturbing future edits') - edit in source_text_tests.lua at line 591
endfunction test_select_text()io.write('\ntest_select_text')-- display a line of textApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc def'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- select a letterApp.fake_key_press('lshift')edit.run_after_keychord(Editor_state, 'S-right')App.fake_key_release('lshift')edit.key_released(Editor_state, 'lshift')-- selection persists even after shift is releasedcheck_eq(Editor_state.selection1.line, 1, 'F - test_select_text/selection:line')check_eq(Editor_state.selection1.pos, 1, 'F - test_select_text/selection:pos')check_eq(Editor_state.cursor1.line, 1, 'F - test_select_text/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_select_text/cursor:pos')endfunction test_cursor_movement_without_shift_resets_selection()io.write('\ntest_cursor_movement_without_shift_resets_selection')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- press an arrow key without shiftedit.run_after_keychord(Editor_state, 'right')-- no change to data, selection is resetcheck_nil(Editor_state.selection1.line, 'F - test_cursor_movement_without_shift_resets_selection')check_eq(Editor_state.lines[1].data, 'abc', 'F - test_cursor_movement_without_shift_resets_selection/data') - edit in source_text_tests.lua at line 635
function test_edit_deletes_selection()io.write('\ntest_edit_deletes_selection')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- press a keyedit.run_after_textinput(Editor_state, 'x')-- selected text is deleted and replaced with the keycheck_eq(Editor_state.lines[1].data, 'xbc', 'F - test_edit_deletes_selection')endfunction test_edit_with_shift_key_deletes_selection()io.write('\ntest_edit_with_shift_key_deletes_selection')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- mimic precise keypresses for a capital letterApp.fake_key_press('lshift')edit.keychord_pressed(Editor_state, 'd', 'd')edit.textinput(Editor_state, 'D')edit.key_released(Editor_state, 'd')App.fake_key_release('lshift')-- selected text is deleted and replaced with the keycheck_nil(Editor_state.selection1.line, 'F - test_edit_with_shift_key_deletes_selection')check_eq(Editor_state.lines[1].data, 'Dbc', 'F - test_edit_with_shift_key_deletes_selection/data')endfunction test_copy_does_not_reset_selection()io.write('\ntest_copy_does_not_reset_selection')-- display a line of text with a selectionApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- copy selectionedit.run_after_keychord(Editor_state, 'C-c')check_eq(App.clipboard, 'a', 'F - test_copy_does_not_reset_selection/clipboard')-- selection is reset since shift key is not pressedcheck(Editor_state.selection1.line, 'F - test_copy_does_not_reset_selection')endfunction test_cut()io.write('\ntest_cut')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- press a keyedit.run_after_keychord(Editor_state, 'C-x')check_eq(App.clipboard, 'a', 'F - test_cut/clipboard')-- selected text is deletedcheck_eq(Editor_state.lines[1].data, 'bc', 'F - test_cut/data')endfunction test_paste_replaces_selection()io.write('\ntest_paste_replaces_selection')-- display a line of text with a selectionApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=1}Editor_state.selection1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- set clipboardApp.clipboard = 'xyz'-- paste selectionedit.run_after_keychord(Editor_state, 'C-v')-- selection is reset since shift key is not pressed-- selection includes the newline, so it's also deletedcheck_eq(Editor_state.lines[1].data, 'xyzdef', 'F - test_paste_replaces_selection')endfunction test_deleting_selection_may_scroll()io.write('\ntest_deleting_selection_may_scroll')-- display lines 2/3/4App.screen.init{width=120, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=3, pos=2}Editor_state.screen_top1 = {line=2, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)local y = Editor_state.topApp.screen.check(y, 'def', 'F - test_deleting_selection_may_scroll/baseline/screen:1')y = y + Editor_state.line_heightApp.screen.check(y, 'ghi', 'F - test_deleting_selection_may_scroll/baseline/screen:2')y = y + Editor_state.line_heightApp.screen.check(y, 'jkl', 'F - test_deleting_selection_may_scroll/baseline/screen:3')-- set up a selection starting above the currently displayed pageEditor_state.selection1 = {line=1, pos=2}-- delete selectionedit.run_after_keychord(Editor_state, 'backspace')-- page scrolls upcheck_eq(Editor_state.screen_top1.line, 1, 'F - test_deleting_selection_may_scroll')check_eq(Editor_state.lines[1].data, 'ahi', 'F - test_deleting_selection_may_scroll/data')end - edit in source_text_tests.lua at line 868
Editor_state.selection1 = {} - replacement in source_text_tests.lua at line 870
edit.run_after_mouse_press(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+5, 1) - edit in source_text_tests.lua at line 873
check_nil(Editor_state.selection1.line, 'F - test_move_cursor_using_mouse/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_move_cursor_using_mouse/selection:pos')endfunction test_select_text_using_mouse()io.write('\ntest_select_text_using_mouse')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}Editor_state.selection1 = {}edit.draw(Editor_state) -- populate line_cache.starty for each line Editor_state.line_cache-- press and hold on first locationedit.run_after_mouse_press(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- drag and release somewhere elseedit.run_after_mouse_release(Editor_state, Editor_state.left+20,Editor_state.top+Editor_state.line_height+5, 1)check_eq(Editor_state.selection1.line, 1, 'F - test_select_text_using_mouse/selection:line')check_eq(Editor_state.selection1.pos, 2, 'F - test_select_text_using_mouse/selection:pos')check_eq(Editor_state.cursor1.line, 2, 'F - test_select_text_using_mouse/cursor:line')check_eq(Editor_state.cursor1.pos, 4, 'F - test_select_text_using_mouse/cursor:pos')endfunction test_select_text_using_mouse_and_shift()io.write('\ntest_select_text_using_mouse_and_shift')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}Editor_state.selection1 = {}edit.draw(Editor_state) -- populate line_cache.starty for each line Editor_state.line_cache-- click on first locationedit.run_after_mouse_press(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- hold down shift and click somewhere elseApp.fake_key_press('lshift')edit.run_after_mouse_press(Editor_state, Editor_state.left+20,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+20,Editor_state.top+Editor_state.line_height+5, 1)App.fake_key_release('lshift')check_eq(Editor_state.selection1.line, 1, 'F - test_select_text_using_mouse_and_shift/selection:line')check_eq(Editor_state.selection1.pos, 2, 'F - test_select_text_using_mouse_and_shift/selection:pos')check_eq(Editor_state.cursor1.line, 2, 'F - test_select_text_using_mouse_and_shift/cursor:line')check_eq(Editor_state.cursor1.pos, 4, 'F - test_select_text_using_mouse_and_shift/cursor:pos')endfunction test_select_text_repeatedly_using_mouse_and_shift()io.write('\ntest_select_text_repeatedly_using_mouse_and_shift')App.screen.init{width=50, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'xyz'}Text.redraw_all(Editor_state)Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}Editor_state.selection1 = {}edit.draw(Editor_state) -- populate line_cache.starty for each line Editor_state.line_cache-- click on first locationedit.run_after_mouse_press(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+5, 1)-- hold down shift and click on a second locationApp.fake_key_press('lshift')edit.run_after_mouse_press(Editor_state, Editor_state.left+20,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+20,Editor_state.top+Editor_state.line_height+5, 1)-- hold down shift and click at a third locationApp.fake_key_press('lshift')edit.run_after_mouse_press(Editor_state, Editor_state.left+20,Editor_state.top+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+Editor_state.line_height+5, 1)App.fake_key_release('lshift')-- selection is between first and third location. forget the second location, not the first.check_eq(Editor_state.selection1.line, 1, 'F - test_select_text_repeatedly_using_mouse_and_shift/selection:line')check_eq(Editor_state.selection1.pos, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/selection:pos')check_eq(Editor_state.cursor1.line, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/cursor:line')check_eq(Editor_state.cursor1.pos, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/cursor:pos') - edit in source_text_tests.lua at line 954
function test_cut_without_selection()io.write('\ntest_cut_without_selection')-- display a few linesApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}Editor_state.selection1 = {}edit.draw(Editor_state)-- try to cut without selecting textedit.run_after_keychord(Editor_state, 'C-x')-- no crashcheck_nil(Editor_state.selection1.line, 'F - test_cut_without_selection')end - replacement in source_text_tests.lua at line 1714
edit.run_after_mouse_press(Editor_state, Editor_state.left+8,Editor_state.top+Editor_state.line_height*2+5, 1)edit.run_after_mouse_release(Editor_state, Editor_state.left+8,Editor_state.top+Editor_state.line_height*2+5, 1) - edit in source_text_tests.lua at line 1791
-- some tests for operating over selections created using Shift- chords-- we're just testing delete_selection, and it works the same for all keysfunction test_backspace_over_selection()io.write('\ntest_backspace_over_selection')-- select just one character within a line with cursor before selectionApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}-- backspace deletes the selected character, even though it's after the cursoredit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'bc', "F - test_backspace_over_selection/data")-- cursor (remains) at start of selectioncheck_eq(Editor_state.cursor1.line, 1, "F - test_backspace_over_selection/cursor:line")check_eq(Editor_state.cursor1.pos, 1, "F - test_backspace_over_selection/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_over_selection/selection")endfunction test_backspace_over_selection_reverse()io.write('\ntest_backspace_over_selection_reverse')-- select just one character within a line with cursor after selectionApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.selection1 = {line=1, pos=1}-- backspace deletes the selected characteredit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'bc', "F - test_backspace_over_selection_reverse/data")-- cursor moves to start of selectioncheck_eq(Editor_state.cursor1.line, 1, "F - test_backspace_over_selection_reverse/cursor:line")check_eq(Editor_state.cursor1.pos, 1, "F - test_backspace_over_selection_reverse/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_over_selection_reverse/selection")endfunction test_backspace_over_multiple_lines()io.write('\ntest_backspace_over_multiple_lines')-- select just one character within a line with cursor after selectionApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.selection1 = {line=4, pos=2}-- backspace deletes the region and joins the remaining portions of lines on either sideedit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'akl', "F - test_backspace_over_multiple_lines/data:1")check_eq(Editor_state.lines[2].data, 'mno', "F - test_backspace_over_multiple_lines/data:2")-- cursor remains at start of selectioncheck_eq(Editor_state.cursor1.line, 1, "F - test_backspace_over_multiple_lines/cursor:line")check_eq(Editor_state.cursor1.pos, 2, "F - test_backspace_over_multiple_lines/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_over_multiple_lines/selection")endfunction test_backspace_to_end_of_line()io.write('\ntest_backspace_to_end_of_line')-- select region from cursor to end of lineApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=2}Editor_state.selection1 = {line=1, pos=4}-- backspace deletes rest of line without joining to any other lineedit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'a', "F - test_backspace_to_start_of_line/data:1")check_eq(Editor_state.lines[2].data, 'def', "F - test_backspace_to_start_of_line/data:2")-- cursor remains at start of selectioncheck_eq(Editor_state.cursor1.line, 1, "F - test_backspace_to_start_of_line/cursor:line")check_eq(Editor_state.cursor1.pos, 2, "F - test_backspace_to_start_of_line/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_to_start_of_line/selection")endfunction test_backspace_to_start_of_line()io.write('\ntest_backspace_to_start_of_line')-- select region from cursor to start of lineApp.screen.init{width=Editor_state.left+30, height=60}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc', 'def', 'ghi', 'jkl', 'mno'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=2, pos=1}Editor_state.selection1 = {line=2, pos=3}-- backspace deletes beginning of line without joining to any other lineedit.run_after_keychord(Editor_state, 'backspace')check_eq(Editor_state.lines[1].data, 'abc', "F - test_backspace_to_start_of_line/data:1")check_eq(Editor_state.lines[2].data, 'f', "F - test_backspace_to_start_of_line/data:2")-- cursor remains at start of selectioncheck_eq(Editor_state.cursor1.line, 2, "F - test_backspace_to_start_of_line/cursor:line")check_eq(Editor_state.cursor1.pos, 1, "F - test_backspace_to_start_of_line/cursor:pos")-- selection is clearedcheck_nil(Editor_state.selection1.line, "F - test_backspace_to_start_of_line/selection")end - edit in source_text_tests.lua at line 1906
check_nil(Editor_state.selection1.line, 'F - test_undo_insert_text/baseline/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_undo_insert_text/baseline/selection:pos') - edit in source_text_tests.lua at line 1918
check_nil(Editor_state.selection1.line, 'F - test_undo_insert_text/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_undo_insert_text/selection:pos') - edit in source_text_tests.lua at line 1941
check_nil(Editor_state.selection1.line, 'F - test_undo_delete_text/baseline/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_undo_delete_text/baseline/selection:pos') - edit in source_text_tests.lua at line 1954
check_nil(Editor_state.selection1.line, 'F - test_undo_delete_text/selection:line')check_nil(Editor_state.selection1.pos, 'F - test_undo_delete_text/selection:pos')--? check_eq(Editor_state.selection1.line, 2, 'F - test_undo_delete_text/selection:line')--? check_eq(Editor_state.selection1.pos, 4, 'F - test_undo_delete_text/selection:pos') - edit in source_text_tests.lua at line 1966
function test_undo_restores_selection()io.write('\ntest_undo_restores_selection')-- display a line of text with some part selectedApp.screen.init{width=75, height=80}Editor_state = edit.initialize_test_state()Editor_state.lines = load_array{'abc'}Text.redraw_all(Editor_state)Editor_state.cursor1 = {line=1, pos=1}Editor_state.selection1 = {line=1, pos=2}Editor_state.screen_top1 = {line=1, pos=1}Editor_state.screen_bottom1 = {}edit.draw(Editor_state)-- delete selected textedit.run_after_textinput(Editor_state, 'x')check_eq(Editor_state.lines[1].data, 'xbc', 'F - test_undo_restores_selection/baseline')check_nil(Editor_state.selection1.line, 'F - test_undo_restores_selection/baseline:selection')-- undoedit.run_after_keychord(Editor_state, 'C-z')edit.run_after_keychord(Editor_state, 'C-z')-- selection is restoredcheck_eq(Editor_state.selection1.line, 1, 'F - test_undo_restores_selection/line')check_eq(Editor_state.selection1.pos, 2, 'F - test_undo_restores_selection/pos')end - edit in source_text.lua at line 112
endif State.selection1.line thenlocal lo, hi = Text.clip_selection(State, line_index, pos, pos+frag_len)Text.draw_highlight(State, line, x,y, pos, lo,hi) - edit in source_text.lua at line 178
endif State.selection1.line thenlocal lo, hi = Text.clip_selection(State, line_index, pos, pos+frag_len)Text.draw_highlight(State, line, x,y, pos, lo,hi) - replacement in source_text.lua at line 386
--? print('chord', chord)--? print('chord', chord, State.selection1.line, State.selection1.pos) - edit in source_text.lua at line 392
State.selection1 = {} - edit in source_text.lua at line 410
if State.selection1.line thenText.delete_selection(State, State.left, State.right)schedule_save(State)returnend - edit in source_text.lua at line 473
if State.selection1.line thenText.delete_selection(State, State.left, State.right)schedule_save(State)returnend - edit in source_text.lua at line 526
State.selection1 = {} - edit in source_text.lua at line 529
State.selection1 = {} - edit in source_text.lua at line 531
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 536
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 543
State.selection1 = {} - edit in source_text.lua at line 546
State.selection1 = {} - edit in source_text.lua at line 548
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 553
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 559
State.selection1 = {} - edit in source_text.lua at line 562
State.selection1 = {} - edit in source_text.lua at line 564
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 569
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 575
State.selection1 = {} - edit in source_text.lua at line 578
State.selection1 = {} - edit in source_text.lua at line 580
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 585
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 591
State.selection1 = {} - edit in source_text.lua at line 594
State.selection1 = {} - edit in source_text.lua at line 596
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_text.lua at line 601
if State.selection1.line == nil thenState.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB}end - edit in source_edit.lua at line 78
selection1 = {},-- some extra state to compute selection between mouse press and releaseold_cursor1 = nil,old_selection1 = nil,mousepress_shift = nil,-- when selecting text, avoid recomputing some state on every single framerecent_mouse = {}, - edit in source_edit.lua at line 219
-- delicate dance between cursor, selection and old cursor/selection-- scenarios:-- regular press+release: sets cursor, clears selection-- shift press+release:-- sets selection to old cursor if not set otherwise leaves it untouched-- sets cursor-- press and hold to start a selection: sets selection on press, cursor on release-- press and hold, then press shift: ignore shift-- i.e. mouse_released should never look at shift stateState.old_cursor1 = State.cursor1State.old_selection1 = State.selection1State.mousepress_shift = App.shift_down() - replacement in source_edit.lua at line 233
State.cursor1 = {line=line_index, pos=pos, posB=posB}State.selection1 = {line=line_index, pos=pos, posB=posB}--? print('selection', State.selection1.line, State.selection1.pos, State.selection1.posB) - edit in source_edit.lua at line 260
elsefor line_index,line in ipairs(State.lines) doif line.mode == 'text' thenif Text.in_line(State, line_index, x,y) then--? print('reset selection')local pos,posB = Text.to_pos_on_line(State, line_index, x, y)State.cursor1 = {line=line_index, pos=pos, posB=posB}--? print('cursor', State.cursor1.line, State.cursor1.pos, State.cursor1.posB)if State.mousepress_shift thenif State.old_selection1.line == nil thenState.selection1 = State.old_cursor1elseState.selection1 = State.old_selection1endendState.old_cursor1, State.old_selection1, State.mousepress_shift = nilif eq(State.cursor1, State.selection1) thenState.selection1 = {}endbreakendendend--? print('selection:', State.selection1.line, State.selection1.pos) - edit in source_edit.lua at line 306
if State.selection1.line andnot State.lines.current_drawing and-- printable character created using shift key => delete selection-- (we're not creating any ctrl-shift- or alt-shift- combinations using regular/printable keys)(not App.shift_down() or utf8.len(key) == 1) andchord ~= 'C-c' and chord ~= 'C-x' and chord ~= 'backspace' and backspace ~= 'delete' and not App.is_cursor_movement(chord) thenText.delete_selection(State, State.left, State.right)end - replacement in source_edit.lua at line 350
elseif chord == 'C-b' thenelseif chord == 'M-b' then - replacement in source_edit.lua at line 359
elseif chord == 'C-i' thenelseif chord == 'M-d' then - edit in source_edit.lua at line 392
State.selection1 = deepcopy(src.selection) - edit in source_edit.lua at line 408
State.selection1 = deepcopy(src.selection) - replacement in commands.lua at line 27
add_hotkey_to_menu('ctrl+b: collapse debug prints')add_hotkey_to_menu('alt+b: collapse debug prints') - replacement in commands.lua at line 29
add_hotkey_to_menu('ctrl+b: expand debug prints')add_hotkey_to_menu('alt+b: expand debug prints') - replacement in commands.lua at line 31
add_hotkey_to_menu('ctrl+i: create/edit debug print')add_hotkey_to_menu('alt+d: create/edit debug print')