diff options
Diffstat (limited to 'text.lua')
-rw-r--r-- | text.lua | 197 |
1 files changed, 46 insertions, 151 deletions
diff --git a/text.lua b/text.lua index 4c87ad8..da4d2a1 100644 --- a/text.lua +++ b/text.lua @@ -82,7 +82,6 @@ end function Text.populate_screen_line_starting_pos(State, line_index) local line = State.lines[line_index] - if line.mode ~= 'text' then return end local line_cache = State.line_cache[line_index] if line_cache.screen_line_starting_pos then return @@ -141,7 +140,6 @@ function Text.text_input(State, t) end function Text.insert_at_cursor(State, t) - assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text') local byte_offset = Text.offset(State.lines[State.cursor1.line].data, State.cursor1.pos) State.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_offset-1)..t..string.sub(State.lines[State.cursor1.line].data, byte_offset) Text.clear_screen_line_cache(State, State.cursor1.line) @@ -193,16 +191,11 @@ function Text.keychord_press(State, chord) end elseif State.cursor1.line > 1 then before = snapshot(State, State.cursor1.line-1, State.cursor1.line) - if State.lines[State.cursor1.line-1].mode == 'drawing' then - table.remove(State.lines, State.cursor1.line-1) - table.remove(State.line_cache, State.cursor1.line-1) - else - -- join lines - State.cursor1.pos = utf8.len(State.lines[State.cursor1.line-1].data)+1 - State.lines[State.cursor1.line-1].data = State.lines[State.cursor1.line-1].data..State.lines[State.cursor1.line].data - table.remove(State.lines, State.cursor1.line) - table.remove(State.line_cache, State.cursor1.line) - end + -- join lines + State.cursor1.pos = utf8.len(State.lines[State.cursor1.line-1].data)+1 + State.lines[State.cursor1.line-1].data = State.lines[State.cursor1.line-1].data..State.lines[State.cursor1.line].data + table.remove(State.lines, State.cursor1.line) + table.remove(State.line_cache, State.cursor1.line) State.cursor1.line = State.cursor1.line-1 end if State.screen_top1.line > #State.lines then @@ -244,10 +237,8 @@ function Text.keychord_press(State, chord) -- no change to State.cursor1.pos end elseif State.cursor1.line < #State.lines then - if State.lines[State.cursor1.line+1].mode == 'text' then - -- join lines - State.lines[State.cursor1.line].data = State.lines[State.cursor1.line].data..State.lines[State.cursor1.line+1].data - end + -- join lines + State.lines[State.cursor1.line].data = State.lines[State.cursor1.line].data..State.lines[State.cursor1.line+1].data table.remove(State.lines, State.cursor1.line+1) table.remove(State.line_cache, State.cursor1.line+1) end @@ -341,7 +332,7 @@ end function Text.insert_return(State) local byte_offset = Text.offset(State.lines[State.cursor1.line].data, State.cursor1.pos) - table.insert(State.lines, State.cursor1.line+1, {mode='text', data=string.sub(State.lines[State.cursor1.line].data, byte_offset)}) + table.insert(State.lines, State.cursor1.line+1, {data=string.sub(State.lines[State.cursor1.line].data, byte_offset)}) table.insert(State.line_cache, State.cursor1.line+1, {}) State.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_offset-1) Text.clear_screen_line_cache(State, State.cursor1.line) @@ -364,15 +355,8 @@ function Text.starty(State, line_index) local loc2 = Text.to2(State, State.screen_top1) local y = State.top while true do - if State.lines[loc2.line].mode == 'drawing' then - y = y + Drawing_padding_top - end if loc2.line == line_index then return y end - if State.lines[loc2.line].mode == 'text' then - y = y + State.line_height - elseif State.lines[loc2.line].mode == 'drawing' then - y = y + Drawing.pixels(State.lines[loc2.line].h, State.width) + Drawing_padding_bottom - end + y = y + State.line_height if y + State.line_height > App.screen.height then break end local next_loc2 = Text.next_screen_line(State, loc2) if Text.eq2(next_loc2, loc2) then break end -- end of file @@ -387,11 +371,7 @@ function Text.previous_screen_top1(State) local y = App.screen.height - State.line_height while y >= State.top do if loc2.line == 1 and loc2.screen_line == 1 and loc2.screen_pos == 1 then break end - if State.lines[loc2.line].mode == 'text' then - y = y - State.line_height - elseif State.lines[loc2.line].mode == 'drawing' then - y = y - Drawing_padding_height - Drawing.pixels(State.lines[loc2.line].h, State.width) - end + y = y - State.line_height loc2 = Text.previous_screen_line(State, loc2) end return Text.to1(State, loc2) @@ -411,11 +391,7 @@ function Text.screen_bottom1(State) local loc2 = Text.to2(State, State.screen_top1) local y = State.top while true do - if State.lines[loc2.line].mode == 'text' then - y = y + State.line_height - elseif State.lines[loc2.line].mode == 'drawing' then - y = y + Drawing_padding_height + Drawing.pixels(State.lines[loc2.line].h, State.width) - end + y = y + State.line_height if y + State.line_height > App.screen.height then break end local next_loc2 = Text.next_screen_line(State, loc2) if Text.eq2(next_loc2, loc2) then break end @@ -425,29 +401,24 @@ function Text.screen_bottom1(State) end function Text.up(State) - assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text') --? print('up', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos) local screen_line_starting_pos, screen_line_index = Text.pos_at_start_of_screen_line(State, State.cursor1) if screen_line_starting_pos == 1 then --? print('cursor is at first screen line of its line') -- line is done; skip to previous text line - local new_cursor_line = State.cursor1.line - while new_cursor_line > 1 do - new_cursor_line = new_cursor_line-1 - if State.lines[new_cursor_line].mode == 'text' then ---? print('found previous text line') - State.cursor1 = {line=new_cursor_line, pos=nil} - Text.populate_screen_line_starting_pos(State, State.cursor1.line) - -- previous text line found, pick its final screen line ---? print('has multiple screen lines') - local screen_line_starting_pos = State.line_cache[State.cursor1.line].screen_line_starting_pos ---? print(#screen_line_starting_pos) - screen_line_starting_pos = screen_line_starting_pos[#screen_line_starting_pos] - local screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line].data, screen_line_starting_pos) - local s = string.sub(State.lines[State.cursor1.line].data, screen_line_starting_byte_offset) - State.cursor1.pos = screen_line_starting_pos + Text.nearest_cursor_pos(State.font, s, State.cursor_x, State.left) - 1 - break - end + if State.cursor1.line > 1 then + local new_cursor_line = State.cursor1.line-1 +--? print('found previous text line') + State.cursor1 = {line=new_cursor_line, pos=nil} + Text.populate_screen_line_starting_pos(State, State.cursor1.line) + -- previous text line found, pick its final screen line +--? print('has multiple screen lines') + local screen_line_starting_pos = State.line_cache[State.cursor1.line].screen_line_starting_pos +--? print(#screen_line_starting_pos) + screen_line_starting_pos = screen_line_starting_pos[#screen_line_starting_pos] + local screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line].data, screen_line_starting_pos) + local s = string.sub(State.lines[State.cursor1.line].data, screen_line_starting_byte_offset) + State.cursor1.pos = screen_line_starting_pos + Text.nearest_cursor_pos(State.font, s, State.cursor_x, State.left) - 1 end else -- move up one screen line in current line @@ -468,23 +439,16 @@ function Text.up(State) end function Text.down(State) - assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text') --? print('down', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos) assert(State.cursor1.pos, 'cursor has no pos') if Text.cursor_at_final_screen_line(State) then -- line is done, skip to next text line --? print('cursor at final screen line of its line') - local new_cursor_line = State.cursor1.line - while new_cursor_line < #State.lines do - new_cursor_line = new_cursor_line+1 - if State.lines[new_cursor_line].mode == 'text' then - State.cursor1 = { - line = new_cursor_line, - pos = Text.nearest_cursor_pos(State.font, State.lines[new_cursor_line].data, State.cursor_x, State.left), - } ---? print(State.cursor1.pos) - break - end + if State.cursor1.line < #State.lines then + local new_cursor_line = State.cursor1.line+1 + State.cursor1.line = new_cursor_line + State.cursor1.pos = Text.nearest_cursor_pos(State.font, State.lines[State.cursor1.line].data, State.cursor_x, State.left) +--? print(State.cursor1.pos) end local screen_bottom1 = Text.screen_bottom1(State) --? print('down 2', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, screen_bottom1.line, screen_bottom1.pos) @@ -588,21 +552,11 @@ function Text.match(s, pos, pat) end function Text.left(State) - assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text') if State.cursor1.pos > 1 then State.cursor1.pos = State.cursor1.pos-1 - else - local new_cursor_line = State.cursor1.line - while new_cursor_line > 1 do - new_cursor_line = new_cursor_line-1 - if State.lines[new_cursor_line].mode == 'text' then - State.cursor1 = { - line = new_cursor_line, - pos = utf8.len(State.lines[new_cursor_line].data) + 1, - } - break - end - end + elseif State.cursor1.line > 1 then + State.cursor1.line = State.cursor1.line-1 + State.cursor1.pos = utf8.len(State.lines[State.cursor1.line].data) + 1 end if Text.lt1(State.cursor1, State.screen_top1) then State.screen_top1 = { @@ -621,18 +575,11 @@ function Text.right(State) end function Text.right_without_scroll(State) - assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text') if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) then State.cursor1.pos = State.cursor1.pos+1 - else - local new_cursor_line = State.cursor1.line - while new_cursor_line <= #State.lines-1 do - new_cursor_line = new_cursor_line+1 - if State.lines[new_cursor_line].mode == 'text' then - State.cursor1 = {line=new_cursor_line, pos=1} - break - end - end + elseif State.cursor1.line <= #State.lines-1 then + State.cursor1.line = State.cursor1.line+1 + State.cursor1.pos = 1 end end @@ -650,7 +597,6 @@ function Text.pos_at_start_of_screen_line(State, loc1) end function Text.pos_at_end_of_screen_line(State, loc1) - assert(State.lines[loc1.line].mode == 'text') Text.populate_screen_line_starting_pos(State, loc1.line) local line_cache = State.line_cache[loc1.line] local most_recent_final_pos = utf8.len(State.lines[loc1.line].data)+1 @@ -664,23 +610,12 @@ function Text.pos_at_end_of_screen_line(State, loc1) assert(false, ('invalid pos %d'):format(loc1.pos)) end -function Text.final_text_loc_on_screen(State) +function Text.final_loc_on_screen(State) local screen_bottom1 = Text.screen_bottom1(State) - if State.lines[screen_bottom1.line].mode == 'text' then - return { - line=screen_bottom1.line, - pos=Text.pos_at_end_of_screen_line(State, screen_bottom1), - } - end - local loc2 = Text.to2(State, screen_bottom1) - while true do - if State.lines[loc2.line].mode == 'text' then break end - assert(loc2.line > 1 or loc2.screen_line > 1 and loc2.screen_pos > 1) -- elsewhere we're making sure there's always at least one text line on screen - loc2 = Text.previous_screen_line(State, loc2) - end - local result = Text.to1(State, loc2) - result.pos = Text.pos_at_end_of_screen_line(State, result) - return result + return { + line=screen_bottom1.line, + pos=Text.pos_at_end_of_screen_line(State, screen_bottom1), + } end function Text.cursor_at_final_screen_line(State) @@ -691,26 +626,7 @@ function Text.cursor_at_final_screen_line(State) end function Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State) - local y = State.top - while State.cursor1.line <= #State.lines do - if State.lines[State.cursor1.line].mode == 'text' then - break - end ---? print('cursor skips', State.cursor1.line) - y = y + Drawing_padding_height + Drawing.pixels(State.lines[State.cursor1.line].h, State.width) - State.cursor1.line = State.cursor1.line + 1 - end - if State.cursor1.pos == nil then - State.cursor1.pos = 1 - end - -- hack: insert a text line at bottom of file if necessary - if State.cursor1.line > #State.lines then - assert(State.cursor1.line == #State.lines+1, 'tried to ensure bottom line of file is text, but failed') - table.insert(State.lines, {mode='text', data=''}) - table.insert(State.line_cache, {}) - end ---? print(y, App.screen.height, App.screen.height-State.line_height) - if y > App.screen.height - State.line_height then + if State.top > App.screen.height - State.line_height then --? print('scroll up') Text.snap_cursor_to_bottom_of_screen(State) end @@ -730,24 +646,11 @@ function Text.snap_cursor_to_bottom_of_screen(State) while true do --? print(y, 'top2:', top2.line, top2.screen_line, top2.screen_pos) if top2.line == 1 and top2.screen_line == 1 then break end - if top2.screen_line > 1 or State.lines[top2.line-1].mode == 'text' then - local h = State.line_height - if y - h < State.top then - break - end - y = y - h - else - assert(top2.line > 1, 'tried to snap cursor to buttom of screen but failed') - assert(State.lines[top2.line-1].mode == 'drawing', "expected a drawing but it's not") - -- We currently can't draw partial drawings, so either skip it entirely - -- or not at all. - local h = Drawing_padding_height + Drawing.pixels(State.lines[top2.line-1].h, State.width) - if y - h < State.top then - break - end ---? print('skipping drawing of height', h) - y = y - h + local h = State.line_height + if y - h < State.top then + break end + y = y - h top2 = Text.previous_screen_line(State, top2) end --? print('top2 finally:', top2.line, top2.screen_line, top2.screen_pos) @@ -910,9 +813,6 @@ function Text.x(font, s, pos) end function Text.to2(State, loc1) - if State.lines[loc1.line].mode == 'drawing' then - return {line=loc1.line, screen_line=1, screen_pos=1} - end local result = {line=loc1.line} local line_cache = State.line_cache[loc1.line] Text.populate_screen_line_starting_pos(State, loc1.line) @@ -978,8 +878,6 @@ function Text.previous_screen_line(State, loc2) return {line=loc2.line, screen_line=loc2.screen_line-1, screen_pos=1} elseif loc2.line == 1 then return loc2 - elseif State.lines[loc2.line-1].mode == 'drawing' then - return {line=loc2.line-1, screen_line=1, screen_pos=1} else local l = State.lines[loc2.line-1] Text.populate_screen_line_starting_pos(State, loc2.line-1) @@ -988,9 +886,6 @@ function Text.previous_screen_line(State, loc2) end function Text.next_screen_line(State, loc2) - if State.lines[loc2.line].mode == 'drawing' then - return {line=loc2.line+1, screen_line=1, screen_pos=1} - end Text.populate_screen_line_starting_pos(State, loc2.line) if loc2.screen_line >= #State.line_cache[loc2.line].screen_line_starting_pos then if loc2.line < #State.lines then @@ -1031,7 +926,7 @@ function Text.tweak_screen_top_and_cursor(State) State.cursor1 = deepcopy(State.screen_top1) elseif State.cursor1.line >= screen_bottom1.line then if Text.cursor_out_of_screen(State) then - State.cursor1 = Text.final_text_loc_on_screen(State) + State.cursor1 = Text.final_loc_on_screen(State) end end end |