From 1609d79516b2e8f790648fd67614d9edb9c2e24c Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Mon, 28 Oct 2024 21:49:24 -0700 Subject: bugfix: restart search on backspace Ported from bugfix of 2024-06-23. --- source_edit.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source_edit.lua b/source_edit.lua index 53bd16a..3c0f794 100644 --- a/source_edit.lua +++ b/source_edit.lua @@ -407,6 +407,9 @@ function edit.keychord_press(State, chord, key) local 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.cursor = deepcopy(State.search_backup.cursor) + State.screen_top = deepcopy(State.search_backup.screen_top) + Text.search_next(State) elseif chord == 'down' then State.cursor1.pos = State.cursor1.pos+1 Text.search_next(State) -- cgit 1.4.1-2-gfad0 From c1a3616964bfdeb11144c0e7289fc16ba563e84a Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 29 Oct 2024 15:43:35 -0700 Subject: bugfix in search UI This one is ancient and it affects every single one of my forks, including the whole lines2 lineage. The corner case: searching for empty string. In the process I've also cleaned up edit.check_locs on initialization to only modify cursor if it can find a legal place for it. In general I should be more careful about mutating the cursor. Just adding 1 to it is irresponsible. --- app.lua | 2 +- edit.lua | 33 +++++++++++++++++++++++++++------ source_edit.lua | 33 +++++++++++++++++++++++++++------ source_text_tests.lua | 14 ++++++++++++++ text_tests.lua | 14 ++++++++++++++ 5 files changed, 83 insertions(+), 13 deletions(-) diff --git a/app.lua b/app.lua index 263518c..1bec1f0 100644 --- a/app.lua +++ b/app.lua @@ -131,7 +131,7 @@ function App.run_tests() end table.sort(sorted_names) --? App.initialize_for_test() -- debug: run a single test at a time like these 2 lines ---? test_click_below_all_lines() +--? test_search() for _,name in ipairs(sorted_names) do App.initialize_for_test() --? print('=== '..name) diff --git a/edit.lua b/edit.lua index 551db10..9e80cc3 100644 --- a/edit.lua +++ b/edit.lua @@ -140,15 +140,36 @@ function edit.cursor_on_text(State) end function edit.put_cursor_on_next_text_line(State) - while true do - if State.cursor1.line >= #State.lines then + local line = State.cursor1.line + while line < #State.lines do + line = line+1 + if State.lines[line].mode == 'text' then + State.cursor1.line = line + State.cursor1.pos = 1 break end - if State.lines[State.cursor1.line].mode == 'text' then + end +end + +function edit.put_cursor_on_next_text_line_wrapping_around_if_necessary(State) + local line = State.cursor1.line + local max = #State.lines + for _ = 1, max-1 do + line = (line+1) % max + if State.lines[line].mode == 'text' then + State.cursor1.line = line + State.cursor1.pos = 1 break end - State.cursor1.line = State.cursor1.line+1 - State.cursor1.pos = 1 + end +end + +function edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) + local cursor_line = State.lines[State.cursor1.line].data + if State.cursor1.pos <= utf8.len(cursor_line) then + State.cursor1.pos = State.cursor1.pos + 1 + else + edit.put_cursor_on_next_text_line_wrapping_around_if_necessary(State) end end @@ -405,7 +426,7 @@ function edit.keychord_press(State, chord, key) State.screen_top = deepcopy(State.search_backup.screen_top) Text.search_next(State) elseif chord == 'down' then - State.cursor1.pos = State.cursor1.pos+1 + edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) Text.search_next(State) elseif chord == 'up' then Text.search_previous(State) diff --git a/source_edit.lua b/source_edit.lua index 3c0f794..90c1171 100644 --- a/source_edit.lua +++ b/source_edit.lua @@ -142,15 +142,36 @@ function edit.cursor_on_text(State) end function edit.put_cursor_on_next_text_line(State) - while true do - if State.cursor1.line >= #State.lines then + local line = State.cursor1.line + while line < #State.lines do + line = line+1 + if State.lines[line].mode == 'text' then + State.cursor1.line = line + State.cursor1.pos = 1 break end - if State.lines[State.cursor1.line].mode == 'text' then + end +end + +function edit.put_cursor_on_next_text_line_wrapping_around_if_necessary(State) + local line = State.cursor1.line + local max = #State.lines + for _ = 1, max-1 do + line = (line+1) % max + if State.lines[line].mode == 'text' then + State.cursor1.line = line + State.cursor1.pos = 1 break end - State.cursor1.line = State.cursor1.line+1 - State.cursor1.pos = 1 + end +end + +function edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) + local cursor_line = State.lines[State.cursor1.line].data + if State.cursor1.pos <= utf8.len(cursor_line) then + State.cursor1.pos = State.cursor1.pos + 1 + else + edit.put_cursor_on_next_text_line_wrapping_around_if_necessary(State) end end @@ -411,7 +432,7 @@ function edit.keychord_press(State, chord, key) State.screen_top = deepcopy(State.search_backup.screen_top) Text.search_next(State) elseif chord == 'down' then - State.cursor1.pos = State.cursor1.pos+1 + edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) Text.search_next(State) elseif chord == 'up' then Text.search_previous(State) diff --git a/source_text_tests.lua b/source_text_tests.lua index 11cc823..db3ae44 100644 --- a/source_text_tests.lua +++ b/source_text_tests.lua @@ -2073,3 +2073,17 @@ function test_search_wrap_upwards() check_eq(Editor_state.cursor1.line, 1, '1/cursor:line') check_eq(Editor_state.cursor1.pos, 6, '1/cursor:pos') end + +function test_search_downwards_from_end_of_line() + 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=4} + Editor_state.screen_top1 = {line=1, pos=1} + edit.draw(Editor_state) + -- search for empty string + edit.run_after_keychord(Editor_state, 'C-f', 'f') + edit.run_after_keychord(Editor_state, 'down', 'down') + -- no crash +end diff --git a/text_tests.lua b/text_tests.lua index 9b34a24..aebade8 100644 --- a/text_tests.lua +++ b/text_tests.lua @@ -2073,3 +2073,17 @@ function test_search_wrap_upwards() check_eq(Editor_state.cursor1.line, 1, '1/cursor:line') check_eq(Editor_state.cursor1.pos, 6, '1/cursor:pos') end + +function test_search_downwards_from_end_of_line() + 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=4} + Editor_state.screen_top1 = {line=1, pos=1} + edit.draw(Editor_state) + -- search for empty string + edit.run_after_keychord(Editor_state, 'C-f', 'f') + edit.run_after_keychord(Editor_state, 'down', 'down') + -- no crash +end -- cgit 1.4.1-2-gfad0 From 1693f1f160e0567cf0bf1f26d3d61f577082cdfb Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 29 Oct 2024 16:04:14 -0700 Subject: bugfix #2 in search UI --- edit.lua | 10 +++++++--- search.lua | 2 ++ source_edit.lua | 10 +++++++--- source_text_tests.lua | 14 ++++++++++++++ text_tests.lua | 14 ++++++++++++++ 5 files changed, 44 insertions(+), 6 deletions(-) diff --git a/edit.lua b/edit.lua index 9e80cc3..91ea8e0 100644 --- a/edit.lua +++ b/edit.lua @@ -426,10 +426,14 @@ function edit.keychord_press(State, chord, key) State.screen_top = deepcopy(State.search_backup.screen_top) Text.search_next(State) elseif chord == 'down' then - edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) - Text.search_next(State) + if #State.search_term > 0 then + edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) + Text.search_next(State) + end elseif chord == 'up' then - Text.search_previous(State) + if #State.search_term > 0 then + Text.search_previous(State) + end end return elseif chord == 'C-f' then diff --git a/search.lua b/search.lua index d3a5fea..2b4ea99 100644 --- a/search.lua +++ b/search.lua @@ -17,6 +17,7 @@ function Text.draw_search_bar(State) end function Text.search_next(State) + assert(#State.search_term > 0) -- search current line from cursor local curr_pos = State.cursor1.pos local curr_line = State.lines[State.cursor1.line].data @@ -71,6 +72,7 @@ function Text.search_next(State) end function Text.search_previous(State) + assert(#State.search_term > 0) -- search current line before cursor local curr_pos = State.cursor1.pos local curr_line = State.lines[State.cursor1.line].data diff --git a/source_edit.lua b/source_edit.lua index 90c1171..733ca61 100644 --- a/source_edit.lua +++ b/source_edit.lua @@ -432,10 +432,14 @@ function edit.keychord_press(State, chord, key) State.screen_top = deepcopy(State.search_backup.screen_top) Text.search_next(State) elseif chord == 'down' then - edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) - Text.search_next(State) + if #State.search_term > 0 then + edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) + Text.search_next(State) + end elseif chord == 'up' then - Text.search_previous(State) + if #State.search_term > 0 then + Text.search_previous(State) + end end return elseif chord == 'C-f' then diff --git a/source_text_tests.lua b/source_text_tests.lua index db3ae44..7ed4caa 100644 --- a/source_text_tests.lua +++ b/source_text_tests.lua @@ -2087,3 +2087,17 @@ function test_search_downwards_from_end_of_line() edit.run_after_keychord(Editor_state, 'down', 'down') -- no crash end + +function test_search_downwards_from_final_pos_of_line() + 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=3} + Editor_state.screen_top1 = {line=1, pos=1} + edit.draw(Editor_state) + -- search for empty string + edit.run_after_keychord(Editor_state, 'C-f', 'f') + edit.run_after_keychord(Editor_state, 'down', 'down') + -- no crash +end diff --git a/text_tests.lua b/text_tests.lua index aebade8..7168daf 100644 --- a/text_tests.lua +++ b/text_tests.lua @@ -2087,3 +2087,17 @@ function test_search_downwards_from_end_of_line() edit.run_after_keychord(Editor_state, 'down', 'down') -- no crash end + +function test_search_downwards_from_final_pos_of_line() + 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=3} + Editor_state.screen_top1 = {line=1, pos=1} + edit.draw(Editor_state) + -- search for empty string + edit.run_after_keychord(Editor_state, 'C-f', 'f') + edit.run_after_keychord(Editor_state, 'down', 'down') + -- no crash +end -- cgit 1.4.1-2-gfad0 From 0940e7276100c4a368d12e03522aea45bb42b8ed Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 29 Oct 2024 16:27:23 -0700 Subject: bugfix #3 in search UI This is a regression. Scenario: search for a string, then backspace until it goes empty. --- edit.lua | 10 +++------- search.lua | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/edit.lua b/edit.lua index 91ea8e0..9e80cc3 100644 --- a/edit.lua +++ b/edit.lua @@ -426,14 +426,10 @@ function edit.keychord_press(State, chord, key) State.screen_top = deepcopy(State.search_backup.screen_top) Text.search_next(State) elseif chord == 'down' then - if #State.search_term > 0 then - edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) - Text.search_next(State) - end + edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) + Text.search_next(State) elseif chord == 'up' then - if #State.search_term > 0 then - Text.search_previous(State) - end + Text.search_previous(State) end return elseif chord == 'C-f' then diff --git a/search.lua b/search.lua index 2b4ea99..4aa1f02 100644 --- a/search.lua +++ b/search.lua @@ -17,7 +17,7 @@ function Text.draw_search_bar(State) end function Text.search_next(State) - assert(#State.search_term > 0) + if #State.search_term == 0 then return end -- search current line from cursor local curr_pos = State.cursor1.pos local curr_line = State.lines[State.cursor1.line].data @@ -72,7 +72,7 @@ function Text.search_next(State) end function Text.search_previous(State) - assert(#State.search_term > 0) + if #State.search_term == 0 then return end -- search current line before cursor local curr_pos = State.cursor1.pos local curr_line = State.lines[State.cursor1.line].data -- cgit 1.4.1-2-gfad0 From 6975b8b7210296da1280a56c29f279eac39cdbda Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 29 Oct 2024 17:47:38 -0700 Subject: bugfix #3, attempt #2 in search UI Avoid accidental side-effects. --- edit.lua | 6 ++++-- source_edit.lua | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/edit.lua b/edit.lua index 9e80cc3..44e58ab 100644 --- a/edit.lua +++ b/edit.lua @@ -426,8 +426,10 @@ function edit.keychord_press(State, chord, key) State.screen_top = deepcopy(State.search_backup.screen_top) Text.search_next(State) elseif chord == 'down' then - edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) - Text.search_next(State) + if #State.search_term > 0 then + edit.put_cursor_on_next_text_loc_wrapping_around_if_necessary(State) + Text.search_next(State) + end elseif chord == 'up' then Text.search_previous(State) end diff --git a/source_edit.lua b/source_edit.lua index 733ca61..7599a4a 100644 --- a/source_edit.lua +++ b/source_edit.lua @@ -437,9 +437,7 @@ function edit.keychord_press(State, chord, key) Text.search_next(State) end elseif chord == 'up' then - if #State.search_term > 0 then - Text.search_previous(State) - end + Text.search_previous(State) end return elseif chord == 'C-f' then -- cgit 1.4.1-2-gfad0