diff --git a/text.lua b/text.lua index 383d762..6fd47cd 100644 --- a/text.lua +++ b/text.lua @@ -294,21 +294,21 @@ function Text.keychord_pressed(chord) end Text.word_right() elseif chord == 'home' then - Cursor1.pos = 1 + Text.start_of_line() Selection1 = {} elseif chord == 'end' then - Cursor1.pos = utf8.len(Lines[Cursor1.line].data) + 1 + Text.end_of_line() Selection1 = {} elseif chord == 'S-home' then if Selection1.line == nil then Selection1 = {line=Cursor1.line, pos=Cursor1.pos} end - Cursor1.pos = 1 + Text.start_of_line() elseif chord == 'S-end' then if Selection1.line == nil then Selection1 = {line=Cursor1.line, pos=Cursor1.pos} end - Cursor1.pos = utf8.len(Lines[Cursor1.line].data) + 1 + Text.end_of_line() elseif chord == 'up' then Text.up() Selection1 = {} @@ -499,6 +499,22 @@ function Text.down() --? print('=>', Cursor1.line, Cursor1.pos, Screen_top1.line, Screen_top1.pos, Screen_bottom1.line, Screen_bottom1.pos) end +function Text.start_of_line() + Cursor1.pos = 1 + if Text.lt1(Cursor1, Screen_top1) then + Screen_top1 = {line=Cursor1.line, pos=Cursor1.pos} -- copy + end +end + +function Text.end_of_line() + Cursor1.pos = utf8.len(Lines[Cursor1.line].data) + 1 + local _,botpos = Text.pos_at_start_of_cursor_screen_line() + local botline1 = {line=Cursor1.line, pos=botpos} + if Text.lt1(Screen_bottom1, botline1) then + Text.snap_cursor_to_bottom_of_screen() + end +end + function Text.word_left() while true do Text.left() @@ -537,9 +553,11 @@ function Text.left() break end end - if Cursor1.line < Screen_top1.line then - Screen_top1.line = Cursor1.line - end + end + if Text.lt1(Cursor1, Screen_top1) then + local top2 = Text.to2(Screen_top1) + top2 = Text.previous_screen_line(top2) + Screen_top1 = Text.to1(top2) end end @@ -557,9 +575,11 @@ function Text.right() break end end - if Cursor1.line > Screen_bottom1.line then - Screen_top1.line = Cursor1.line - end + end + local _,botpos = Text.pos_at_start_of_cursor_screen_line() + local botline1 = {line=Cursor1.line, pos=botpos} + if Text.lt1(Screen_bottom1, botline1) then + Text.snap_cursor_to_bottom_of_screen() end end diff --git a/text_tests.lua b/text_tests.lua index 698c186..3fcb5aa 100644 --- a/text_tests.lua +++ b/text_tests.lua @@ -1152,6 +1152,124 @@ function test_typing_on_bottom_line_scrolls_down() App.screen.check(y, 'l', 'F - test_typing_on_bottom_line_scrolls_down/screen:3') end +function test_left_arrow_scrolls_up_in_wrapped_line() + io.write('\ntest_left_arrow_scrolls_up_in_wrapped_line') + -- display lines starting from second screen line of a line + App.screen.init{width=Margin_left+30, height=60} + Lines = load_array{'abc', 'def', 'ghi jkl', 'mno'} + Line_width = App.screen.width + Screen_top1 = {line=3, pos=5} + Screen_bottom1 = {} + -- cursor is at top of screen + Cursor1 = {line=3, pos=5} + App.draw() + local y = Margin_top + App.screen.check(y, 'jkl', 'F - test_left_arrow_scrolls_up_in_wrapped_line/baseline/screen:1') + y = y + Line_height + App.screen.check(y, 'mno', 'F - test_left_arrow_scrolls_up_in_wrapped_line/baseline/screen:2') + -- after hitting the left arrow the screen scrolls up to first screen line + App.run_after_keychord('left') + y = Margin_top + App.screen.check(y, 'ghi ', 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen:1') + y = y + Line_height + App.screen.check(y, 'jkl', 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen:2') + y = y + Line_height + App.screen.check(y, 'mno', 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen:3') + check_eq(Screen_top1.line, 3, 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen_top') + check_eq(Screen_top1.pos, 1, 'F - test_left_arrow_scrolls_up_in_wrapped_line/screen_top') + check_eq(Cursor1.line, 3, 'F - test_left_arrow_scrolls_up_in_wrapped_line/cursor:line') + check_eq(Cursor1.pos, 4, 'F - test_left_arrow_scrolls_up_in_wrapped_line/cursor:pos') +end + +function test_right_arrow_scrolls_down_in_wrapped_line() + io.write('\ntest_right_arrow_scrolls_down_in_wrapped_line') + -- display the first three lines with the cursor on the bottom line + App.screen.init{width=Margin_left+30, height=60} + Lines = load_array{'abc', 'def', 'ghi jkl', 'mno'} + Line_width = App.screen.width + Screen_top1 = {line=1, pos=1} + Screen_bottom1 = {} + -- cursor is at bottom right of screen + Cursor1 = {line=3, pos=5} + App.draw() + local y = Margin_top + App.screen.check(y, 'abc', 'F - test_right_arrow_scrolls_down_in_wrapped_line/baseline/screen:1') + y = y + Line_height + App.screen.check(y, 'def', 'F - test_right_arrow_scrolls_down_in_wrapped_line/baseline/screen:2') + y = y + Line_height + App.screen.check(y, 'ghi ', 'F - test_right_arrow_scrolls_down_in_wrapped_line/baseline/screen:3') -- line wrapping includes trailing whitespace + -- after hitting the right arrow the screen scrolls down by one line + App.run_after_keychord('right') + check_eq(Screen_top1.line, 2, 'F - test_right_arrow_scrolls_down_in_wrapped_line/screen_top') + check_eq(Cursor1.line, 3, 'F - test_right_arrow_scrolls_down_in_wrapped_line/cursor:line') + check_eq(Cursor1.pos, 6, 'F - test_right_arrow_scrolls_down_in_wrapped_line/cursor:pos') + y = Margin_top + App.screen.check(y, 'def', 'F - test_right_arrow_scrolls_down_in_wrapped_line/screen:1') + y = y + Line_height + App.screen.check(y, 'ghi ', 'F - test_right_arrow_scrolls_down_in_wrapped_line/screen:2') + y = y + Line_height + App.screen.check(y, 'jkl', 'F - test_right_arrow_scrolls_down_in_wrapped_line/screen:3') +end + +function test_home_scrolls_up_in_wrapped_line() + io.write('\ntest_home_scrolls_up_in_wrapped_line') + -- display lines starting from second screen line of a line + App.screen.init{width=Margin_left+30, height=60} + Lines = load_array{'abc', 'def', 'ghi jkl', 'mno'} + Line_width = App.screen.width + Screen_top1 = {line=3, pos=5} + Screen_bottom1 = {} + -- cursor is at top of screen + Cursor1 = {line=3, pos=5} + App.draw() + local y = Margin_top + App.screen.check(y, 'jkl', 'F - test_home_scrolls_up_in_wrapped_line/baseline/screen:1') + y = y + Line_height + App.screen.check(y, 'mno', 'F - test_home_scrolls_up_in_wrapped_line/baseline/screen:2') + -- after hitting home the screen scrolls up to first screen line + App.run_after_keychord('home') + y = Margin_top + App.screen.check(y, 'ghi ', 'F - test_home_scrolls_up_in_wrapped_line/screen:1') + y = y + Line_height + App.screen.check(y, 'jkl', 'F - test_home_scrolls_up_in_wrapped_line/screen:2') + y = y + Line_height + App.screen.check(y, 'mno', 'F - test_home_scrolls_up_in_wrapped_line/screen:3') + check_eq(Screen_top1.line, 3, 'F - test_home_scrolls_up_in_wrapped_line/screen_top') + check_eq(Screen_top1.pos, 1, 'F - test_home_scrolls_up_in_wrapped_line/screen_top') + check_eq(Cursor1.line, 3, 'F - test_home_scrolls_up_in_wrapped_line/cursor:line') + check_eq(Cursor1.pos, 1, 'F - test_home_scrolls_up_in_wrapped_line/cursor:pos') +end + +function test_end_scrolls_down_in_wrapped_line() + io.write('\ntest_end_scrolls_down_in_wrapped_line') + -- display the first three lines with the cursor on the bottom line + App.screen.init{width=Margin_left+30, height=60} + Lines = load_array{'abc', 'def', 'ghi jkl', 'mno'} + Line_width = App.screen.width + Screen_top1 = {line=1, pos=1} + Screen_bottom1 = {} + -- cursor is at bottom right of screen + Cursor1 = {line=3, pos=5} + App.draw() + local y = Margin_top + App.screen.check(y, 'abc', 'F - test_end_scrolls_down_in_wrapped_line/baseline/screen:1') + y = y + Line_height + App.screen.check(y, 'def', 'F - test_end_scrolls_down_in_wrapped_line/baseline/screen:2') + y = y + Line_height + App.screen.check(y, 'ghi ', 'F - test_end_scrolls_down_in_wrapped_line/baseline/screen:3') -- line wrapping includes trailing whitespace + -- after hitting end the screen scrolls down by one line + App.run_after_keychord('end') + check_eq(Screen_top1.line, 2, 'F - test_end_scrolls_down_in_wrapped_line/screen_top') + check_eq(Cursor1.line, 3, 'F - test_end_scrolls_down_in_wrapped_line/cursor:line') + check_eq(Cursor1.pos, 8, 'F - test_end_scrolls_down_in_wrapped_line/cursor:pos') + y = Margin_top + App.screen.check(y, 'def', 'F - test_end_scrolls_down_in_wrapped_line/screen:1') + y = y + Line_height + App.screen.check(y, 'ghi ', 'F - test_end_scrolls_down_in_wrapped_line/screen:2') + y = y + Line_height + App.screen.check(y, 'jkl', 'F - test_end_scrolls_down_in_wrapped_line/screen:3') +end + function test_position_cursor_on_recently_edited_wrapping_line() -- draw a line wrapping over 2 screen lines io.write('\ntest_position_cursor_on_recently_edited_wrapping_line')