From a655c2113cdc80095402243ce41e1322dea535ab Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Mon, 15 Aug 2022 10:31:56 -0700 Subject: [PATCH] bring back a level of wrapping Many projects will require the ability to add metadata to lines, so let's not drop that. --- edit.lua | 4 +-- file.lua | 10 +++--- main_tests.lua | 6 ++-- search.lua | 16 +++++----- select.lua | 32 +++++++++---------- text.lua | 86 +++++++++++++++++++++++++------------------------- text_tests.lua | 36 ++++++++++----------- undo.lua | 3 +- 8 files changed, 97 insertions(+), 96 deletions(-) diff --git a/edit.lua b/edit.lua index 1b888a8..2b23769 100644 --- a/edit.lua +++ b/edit.lua @@ -18,7 +18,7 @@ edit = {} -- run in both tests and a real run function edit.initialize_state(top, left, right, font_height, line_height) -- currently always draws to bottom of screen local result = { - lines = {''}, -- array of strings + lines = {{data=''}}, -- array of strings -- Lines can be too long to fit on screen, in which case they _wrap_ into -- multiple _screen lines_. @@ -106,7 +106,7 @@ function edit.draw(State) if State.cursor_y == -1 then State.cursor_y = App.screen.height end ---? print('screen bottom: '..tostring(State.screen_bottom1.pos)..' in '..tostring(State.lines[State.screen_bottom1.line])) +--? print('screen bottom: '..tostring(State.screen_bottom1.pos)..' in '..tostring(State.lines[State.screen_bottom1.line].data)) if State.search_term then Text.draw_search_bar(State) end diff --git a/file.lua b/file.lua index 84cc74c..94514b2 100644 --- a/file.lua +++ b/file.lua @@ -12,11 +12,11 @@ function load_from_file(infile) while true do local line = infile_next_line() if line == nil then break end - table.insert(result, line) + table.insert(result, {data=line}) end end if #result == 0 then - table.insert(result, '') + table.insert(result, {data=''}) end return result end @@ -27,7 +27,7 @@ function save_to_disk(State) error('failed to write to "'..State.filename..'"') end for _,line in ipairs(State.lines) do - outfile:write(line, '\n') + outfile:write(line.data, '\n') end outfile:close() end @@ -40,10 +40,10 @@ function load_array(a) while true do i,line = next_line(a, i) if i == nil then break end - table.insert(result, line) + table.insert(result, {data=line}) end if #result == 0 then - table.insert(result, '') + table.insert(result, {data=''}) end return result end diff --git a/main_tests.lua b/main_tests.lua index 9993d99..b89c634 100644 --- a/main_tests.lua +++ b/main_tests.lua @@ -38,9 +38,9 @@ function test_drop_file() } App.filedropped(fake_dropped_file) check_eq(#Editor_state.lines, 3, 'F - test_drop_file/#lines') - check_eq(Editor_state.lines[1], 'abc', 'F - test_drop_file/lines:1') - check_eq(Editor_state.lines[2], 'def', 'F - test_drop_file/lines:2') - check_eq(Editor_state.lines[3], 'ghi', 'F - test_drop_file/lines:3') + check_eq(Editor_state.lines[1].data, 'abc', 'F - test_drop_file/lines:1') + check_eq(Editor_state.lines[2].data, 'def', 'F - test_drop_file/lines:2') + check_eq(Editor_state.lines[3].data, 'ghi', 'F - test_drop_file/lines:3') end function test_drop_file_saves_previous() diff --git a/search.lua b/search.lua index ce089d3..1872b9e 100644 --- a/search.lua +++ b/search.lua @@ -21,14 +21,14 @@ end function Text.search_next(State) -- search current line from cursor - local pos = find(State.lines[State.cursor1.line], State.search_term, State.cursor1.pos) + local pos = find(State.lines[State.cursor1.line].data, State.search_term, State.cursor1.pos) if pos then State.cursor1.pos = pos end if pos == nil then -- search lines below cursor for i=State.cursor1.line+1,#State.lines do - pos = find(State.lines[i], State.search_term) + pos = find(State.lines[i].data, State.search_term) if pos then State.cursor1.line = i State.cursor1.pos = pos @@ -39,7 +39,7 @@ function Text.search_next(State) if pos == nil then -- wrap around for i=1,State.cursor1.line-1 do - pos = find(State.lines[i], State.search_term) + pos = find(State.lines[i].data, State.search_term) if pos then State.cursor1.line = i State.cursor1.pos = pos @@ -49,7 +49,7 @@ function Text.search_next(State) end if pos == nil then -- search current line until cursor - pos = find(State.lines[State.cursor1.line], State.search_term) + pos = find(State.lines[State.cursor1.line].data, State.search_term) if pos and pos < State.cursor1.pos then State.cursor1.pos = pos end @@ -69,14 +69,14 @@ end function Text.search_previous(State) -- search current line before cursor - local pos = rfind(State.lines[State.cursor1.line], State.search_term, State.cursor1.pos-1) + local pos = rfind(State.lines[State.cursor1.line].data, State.search_term, State.cursor1.pos-1) if pos then State.cursor1.pos = pos end if pos == nil then -- search lines above cursor for i=State.cursor1.line-1,1,-1 do - pos = rfind(State.lines[i], State.search_term) + pos = rfind(State.lines[i].data, State.search_term) if pos then State.cursor1.line = i State.cursor1.pos = pos @@ -87,7 +87,7 @@ function Text.search_previous(State) if pos == nil then -- wrap around for i=#State.lines,State.cursor1.line+1,-1 do - pos = rfind(State.lines[i], State.search_term) + pos = rfind(State.lines[i].data, State.search_term) if pos then State.cursor1.line = i State.cursor1.pos = pos @@ -97,7 +97,7 @@ function Text.search_previous(State) end if pos == nil then -- search current line after cursor - pos = rfind(State.lines[State.cursor1.line], State.search_term) + pos = rfind(State.lines[State.cursor1.line].data, State.search_term) if pos and pos > State.cursor1.pos then State.cursor1.pos = pos end diff --git a/select.lua b/select.lua index b89ea33..147d60a 100644 --- a/select.lua +++ b/select.lua @@ -53,19 +53,19 @@ end -- Returns some intermediate computation useful elsewhere. function Text.draw_highlight(State, line, x,y, pos, lo,hi) if lo then - local lo_offset = Text.offset(line, lo) - local hi_offset = Text.offset(line, hi) - local pos_offset = Text.offset(line, pos) + local lo_offset = Text.offset(line.data, lo) + local hi_offset = Text.offset(line.data, hi) + local pos_offset = Text.offset(line.data, pos) local lo_px if pos == lo then lo_px = 0 else - local before = line:sub(pos_offset, lo_offset-1) + local before = line.data:sub(pos_offset, lo_offset-1) local before_text = App.newText(love.graphics.getFont(), before) lo_px = App.width(before_text) end --? print(lo,pos,hi, '--', lo_offset,pos_offset,hi_offset, '--', lo_px) - local s = line:sub(lo_offset, hi_offset-1) + local s = line.data:sub(lo_offset, hi_offset-1) local text = App.newText(love.graphics.getFont(), s) local text_width = App.width(text) App.color(Highlight_color) @@ -136,20 +136,20 @@ function Text.delete_selection_without_undo(State) State.selection1 = {} -- delete everything between min (inclusive) and max (exclusive) Text.clear_screen_line_cache(State, minl) - local min_offset = Text.offset(State.lines[minl], minp) - local max_offset = Text.offset(State.lines[maxl], maxp) + local min_offset = Text.offset(State.lines[minl].data, minp) + local max_offset = Text.offset(State.lines[maxl].data, maxp) if minl == maxl then --? print('minl == maxl') - State.lines[minl] = State.lines[minl]:sub(1, min_offset-1)..State.lines[minl]:sub(max_offset) + State.lines[minl].data = State.lines[minl].data:sub(1, min_offset-1)..State.lines[minl].data:sub(max_offset) return end assert(minl < maxl) - local rhs = State.lines[maxl]:sub(max_offset) + local rhs = State.lines[maxl].data:sub(max_offset) for i=maxl,minl+1,-1 do table.remove(State.lines, i) table.remove(State.line_cache, i) end - State.lines[minl] = State.lines[minl]:sub(1, min_offset-1)..rhs + State.lines[minl].data = State.lines[minl].data:sub(1, min_offset-1)..rhs end function Text.selection(State) @@ -165,16 +165,16 @@ function Text.selection(State) minp,maxp = maxp,minp end end - local min_offset = Text.offset(State.lines[minl], minp) - local max_offset = Text.offset(State.lines[maxl], maxp) + local min_offset = Text.offset(State.lines[minl].data, minp) + local max_offset = Text.offset(State.lines[maxl].data, maxp) if minl == maxl then - return State.lines[minl]:sub(min_offset, max_offset-1) + return State.lines[minl].data:sub(min_offset, max_offset-1) end assert(minl < maxl) - local result = {State.lines[minl]:sub(min_offset)} + local result = {State.lines[minl].data:sub(min_offset)} for i=minl+1,maxl-1 do - table.insert(result, State.lines[i]) + table.insert(result, State.lines[i].data) end - table.insert(result, State.lines[maxl]:sub(1, max_offset-1)) + table.insert(result, State.lines[maxl].data:sub(1, max_offset-1)) return table.concat(result, '\n') end diff --git a/text.lua b/text.lua index 014f77c..d46b6d4 100644 --- a/text.lua +++ b/text.lua @@ -50,7 +50,7 @@ function Text.draw(State, line_index, y, startpos) if line_index == State.cursor1.line then if pos <= State.cursor1.pos and pos + frag_len > State.cursor1.pos then if State.search_term then - if State.lines[State.cursor1.line]:sub(State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term)-1) == State.search_term then + if State.lines[State.cursor1.line].data:sub(State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term)-1) == State.search_term then local lo_px = Text.draw_highlight(State, line, x,y, pos, State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term)) App.color(Text_color) love.graphics.print(State.search_term, x+lo_px,y) @@ -92,7 +92,7 @@ function Text.compute_fragments(State, line_index) line_cache.fragments = {} local x = State.left -- try to wrap at word boundaries - for frag in line:gmatch('%S*%s*') do + for frag in line.data:gmatch('%S*%s*') do local frag_text = App.newText(love.graphics.getFont(), frag) local frag_width = App.width(frag_text) --? print('x: '..tostring(x)..'; '..tostring(State.right-x)..'px to go') @@ -142,8 +142,8 @@ function Text.textinput(State, t) end function Text.insert_at_cursor(State, t) - local byte_offset = Text.offset(State.lines[State.cursor1.line], State.cursor1.pos) - State.lines[State.cursor1.line] = string.sub(State.lines[State.cursor1.line], 1, byte_offset-1)..t..string.sub(State.lines[State.cursor1.line], byte_offset) + 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) State.cursor1.pos = State.cursor1.pos+1 end @@ -182,21 +182,21 @@ function Text.keychord_pressed(State, chord) local before if State.cursor1.pos > 1 then before = snapshot(State, State.cursor1.line) - local byte_start = utf8.offset(State.lines[State.cursor1.line], State.cursor1.pos-1) - local byte_end = utf8.offset(State.lines[State.cursor1.line], State.cursor1.pos) + 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 then if byte_end then - State.lines[State.cursor1.line] = string.sub(State.lines[State.cursor1.line], 1, byte_start-1)..string.sub(State.lines[State.cursor1.line], byte_end) + State.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) else - State.lines[State.cursor1.line] = string.sub(State.lines[State.cursor1.line], 1, byte_start-1) + State.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_start-1) end State.cursor1.pos = State.cursor1.pos-1 end elseif State.cursor1.line > 1 then before = snapshot(State, State.cursor1.line-1, State.cursor1.line) -- join lines - State.cursor1.pos = utf8.len(State.lines[State.cursor1.line-1])+1 - State.lines[State.cursor1.line-1] = State.lines[State.cursor1.line-1]..State.lines[State.cursor1.line] + 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 @@ -222,25 +222,25 @@ function Text.keychord_pressed(State, chord) return end local before - if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line]) then + if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) then before = snapshot(State, State.cursor1.line) else before = snapshot(State, State.cursor1.line, State.cursor1.line+1) end - if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line]) then - local byte_start = utf8.offset(State.lines[State.cursor1.line], State.cursor1.pos) - local byte_end = utf8.offset(State.lines[State.cursor1.line], State.cursor1.pos+1) + if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) then + local 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 then if byte_end then - State.lines[State.cursor1.line] = string.sub(State.lines[State.cursor1.line], 1, byte_start-1)..string.sub(State.lines[State.cursor1.line], byte_end) + State.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) else - State.lines[State.cursor1.line] = string.sub(State.lines[State.cursor1.line], 1, byte_start-1) + State.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_start-1) end -- no change to State.cursor1.pos end elseif State.cursor1.line < #State.lines then -- join lines - State.lines[State.cursor1.line] = State.lines[State.cursor1.line]..State.lines[State.cursor1.line+1] + 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 @@ -333,10 +333,10 @@ function Text.keychord_pressed(State, chord) end function Text.insert_return(State) - local byte_offset = Text.offset(State.lines[State.cursor1.line], State.cursor1.pos) - table.insert(State.lines, State.cursor1.line+1, string.sub(State.lines[State.cursor1.line], byte_offset)) + local byte_offset = Text.offset(State.lines[State.cursor1.line].data, State.cursor1.pos) + 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] = string.sub(State.lines[State.cursor1.line], 1, byte_offset-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) State.cursor1.line = State.cursor1.line+1 State.cursor1.pos = 1 @@ -409,8 +409,8 @@ function Text.up(State) State.screen_top1.pos = screen_line_starting_pos --? print('pos of top of screen is also '..tostring(State.screen_top1.pos)..' of the same line') end - local screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line], screen_line_starting_pos) - local s = string.sub(State.lines[State.cursor1.line], screen_line_starting_byte_offset) + 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(s, State.cursor_x, State.left) - 1 end if State.cursor1.line < State.screen_top1.line then @@ -426,8 +426,8 @@ function Text.up(State) State.screen_top1.pos = new_screen_line_starting_pos --? print('also setting pos of top of screen to '..tostring(State.screen_top1.pos)) end - local new_screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line], new_screen_line_starting_pos) - local s = string.sub(State.lines[State.cursor1.line], new_screen_line_starting_byte_offset) + local new_screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line].data, new_screen_line_starting_pos) + local s = string.sub(State.lines[State.cursor1.line].data, new_screen_line_starting_byte_offset) State.cursor1.pos = new_screen_line_starting_pos + Text.nearest_cursor_pos(s, State.cursor_x, State.left) - 1 --? print('cursor pos is now '..tostring(State.cursor1.pos)) end @@ -441,7 +441,7 @@ function Text.down(State) 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.lines[State.cursor1.line], State.cursor_x, State.left) + State.cursor1.pos = Text.nearest_cursor_pos(State.lines[State.cursor1.line].data, State.cursor_x, State.left) --? print(State.cursor1.pos) end if State.cursor1.line > State.screen_bottom1.line then @@ -460,8 +460,8 @@ function Text.down(State) local screen_line_index, screen_line_starting_pos = Text.pos_at_start_of_cursor_screen_line(State) new_screen_line_starting_pos = State.line_cache[State.cursor1.line].screen_line_starting_pos[screen_line_index+1] --? print('switching pos of screen line at cursor from '..tostring(screen_line_starting_pos)..' to '..tostring(new_screen_line_starting_pos)) - local new_screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line], new_screen_line_starting_pos) - local s = string.sub(State.lines[State.cursor1.line], new_screen_line_starting_byte_offset) + local new_screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line].data, new_screen_line_starting_pos) + local s = string.sub(State.lines[State.cursor1.line].data, new_screen_line_starting_byte_offset) State.cursor1.pos = new_screen_line_starting_pos + Text.nearest_cursor_pos(s, State.cursor_x, State.left) - 1 --? print('cursor pos is now', State.cursor1.line, State.cursor1.pos) if scroll_down then @@ -481,7 +481,7 @@ function Text.start_of_line(State) end function Text.end_of_line(State) - State.cursor1.pos = utf8.len(State.lines[State.cursor1.line]) + 1 + State.cursor1.pos = utf8.len(State.lines[State.cursor1.line].data) + 1 local _,botpos = Text.pos_at_start_of_cursor_screen_line(State) local botline1 = {line=State.cursor1.line, pos=botpos} if Text.cursor_past_screen_bottom(State) then @@ -495,7 +495,7 @@ function Text.word_left(State) if State.cursor1.pos == 1 then break end - if Text.match(State.lines[State.cursor1.line], State.cursor1.pos-1, '%S') then + if Text.match(State.lines[State.cursor1.line].data, State.cursor1.pos-1, '%S') then break end Text.left(State) @@ -507,7 +507,7 @@ function Text.word_left(State) break end assert(State.cursor1.pos > 1) - if Text.match(State.lines[State.cursor1.line], State.cursor1.pos-1, '%s') then + if Text.match(State.lines[State.cursor1.line].data, State.cursor1.pos-1, '%s') then break end end @@ -516,20 +516,20 @@ end function Text.word_right(State) -- skip some whitespace while true do - if State.cursor1.pos > utf8.len(State.lines[State.cursor1.line]) then + if State.cursor1.pos > utf8.len(State.lines[State.cursor1.line].data) then break end - if Text.match(State.lines[State.cursor1.line], State.cursor1.pos, '%S') then + if Text.match(State.lines[State.cursor1.line].data, State.cursor1.pos, '%S') then break end Text.right_without_scroll(State) end while true do Text.right_without_scroll(State) - if State.cursor1.pos > utf8.len(State.lines[State.cursor1.line]) then + if State.cursor1.pos > utf8.len(State.lines[State.cursor1.line].data) then break end - if Text.match(State.lines[State.cursor1.line], State.cursor1.pos, '%s') then + if Text.match(State.lines[State.cursor1.line].data, State.cursor1.pos, '%s') then break end end @@ -552,7 +552,7 @@ function Text.left(State) State.cursor1.pos = State.cursor1.pos-1 elseif State.cursor1.line > 1 then State.cursor1.line = State.cursor1.line-1 - State.cursor1.pos = utf8.len(State.lines[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 local top2 = Text.to2(State, State.screen_top1) @@ -569,7 +569,7 @@ function Text.right(State) end function Text.right_without_scroll(State) - if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line]) then + if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) then State.cursor1.pos = State.cursor1.pos+1 elseif State.cursor1.line <= #State.lines-1 then State.cursor1.line = State.cursor1.line+1 @@ -647,8 +647,8 @@ function Text.to_pos_on_line(State, line_index, mx, my) local start_screen_line_index = Text.screen_line_index(line_cache.screen_line_starting_pos, line_cache.startpos) for screen_line_index = start_screen_line_index,#line_cache.screen_line_starting_pos do local screen_line_starting_pos = line_cache.screen_line_starting_pos[screen_line_index] - local screen_line_starting_byte_offset = Text.offset(line, screen_line_starting_pos) ---? print('iter', y, screen_line_index, screen_line_starting_pos, string.sub(line, screen_line_starting_byte_offset)) + local screen_line_starting_byte_offset = Text.offset(line.data, screen_line_starting_pos) +--? print('iter', y, screen_line_index, screen_line_starting_pos, string.sub(line.data, screen_line_starting_byte_offset)) local nexty = y + State.line_height if my < nexty then -- On all wrapped screen lines but the final one, clicks past end of @@ -658,7 +658,7 @@ function Text.to_pos_on_line(State, line_index, mx, my) --? print('past end of non-final line; return') return line_cache.screen_line_starting_pos[screen_line_index+1]-1 end - local s = string.sub(line, screen_line_starting_byte_offset) + local s = string.sub(line.data, screen_line_starting_byte_offset) --? print('return', mx, Text.nearest_cursor_pos(s, mx, State.left), '=>', screen_line_starting_pos + Text.nearest_cursor_pos(s, mx, State.left) - 1) return screen_line_starting_pos + Text.nearest_cursor_pos(s, mx, State.left) - 1 end @@ -671,14 +671,14 @@ function Text.screen_line_width(State, line_index, i) local line = State.lines[line_index] local line_cache = State.line_cache[line_index] local start_pos = line_cache.screen_line_starting_pos[i] - local start_offset = Text.offset(line, start_pos) + local start_offset = Text.offset(line.data, start_pos) local screen_line if i < #line_cache.screen_line_starting_pos then local past_end_pos = line_cache.screen_line_starting_pos[i+1] - local past_end_offset = Text.offset(line, past_end_pos) - screen_line = string.sub(line, start_offset, past_end_offset-1) + local past_end_offset = Text.offset(line.data, past_end_pos) + screen_line = string.sub(line.data, start_offset, past_end_offset-1) else - screen_line = string.sub(line, start_pos) + screen_line = string.sub(line.data, start_pos) end local screen_line_text = App.newText(love.graphics.getFont(), screen_line) return App.width(screen_line_text) diff --git a/text_tests.lua b/text_tests.lua index 5de9ea8..7f9b2e4 100644 --- a/text_tests.lua +++ b/text_tests.lua @@ -601,7 +601,7 @@ function test_cursor_movement_without_shift_resets_selection() edit.run_after_keychord(Editor_state, 'right') -- no change to data, selection is reset check_nil(Editor_state.selection1.line, 'F - test_cursor_movement_without_shift_resets_selection') - check_eq(Editor_state.lines[1], 'abc', 'F - test_cursor_movement_without_shift_resets_selection/data') + check_eq(Editor_state.lines[1].data, 'abc', 'F - test_cursor_movement_without_shift_resets_selection/data') end function test_edit_deletes_selection() @@ -619,7 +619,7 @@ function test_edit_deletes_selection() -- press a key edit.run_after_textinput(Editor_state, 'x') -- selected text is deleted and replaced with the key - check_eq(Editor_state.lines[1], 'xbc', 'F - test_edit_deletes_selection') + check_eq(Editor_state.lines[1].data, 'xbc', 'F - test_edit_deletes_selection') end function test_edit_with_shift_key_deletes_selection() @@ -642,7 +642,7 @@ function test_edit_with_shift_key_deletes_selection() App.fake_key_release('lshift') -- selected text is deleted and replaced with the key check_nil(Editor_state.selection1.line, 'F - test_edit_with_shift_key_deletes_selection') - check_eq(Editor_state.lines[1], 'Dbc', 'F - test_edit_with_shift_key_deletes_selection/data') + check_eq(Editor_state.lines[1].data, 'Dbc', 'F - test_edit_with_shift_key_deletes_selection/data') end function test_copy_does_not_reset_selection() @@ -680,7 +680,7 @@ function test_cut() edit.run_after_keychord(Editor_state, 'C-x') check_eq(App.clipboard, 'a', 'F - test_cut/clipboard') -- selected text is deleted - check_eq(Editor_state.lines[1], 'bc', 'F - test_cut/data') + check_eq(Editor_state.lines[1].data, 'bc', 'F - test_cut/data') end function test_paste_replaces_selection() @@ -701,7 +701,7 @@ function test_paste_replaces_selection() edit.run_after_keychord(Editor_state, 'C-v') -- selection is reset since shift key is not pressed -- selection includes the newline, so it's also deleted - check_eq(Editor_state.lines[1], 'xyzdef', 'F - test_paste_replaces_selection') + check_eq(Editor_state.lines[1].data, 'xyzdef', 'F - test_paste_replaces_selection') end function test_deleting_selection_may_scroll() @@ -727,7 +727,7 @@ function test_deleting_selection_may_scroll() edit.run_after_keychord(Editor_state, 'backspace') -- page scrolls up check_eq(Editor_state.screen_top1.line, 1, 'F - test_deleting_selection_may_scroll') - check_eq(Editor_state.lines[1], 'ahi', 'F - test_deleting_selection_may_scroll/data') + check_eq(Editor_state.lines[1].data, 'ahi', 'F - test_deleting_selection_may_scroll/data') end function test_edit_wrapping_text() @@ -793,8 +793,8 @@ function test_insert_newline_at_start_of_line() edit.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], '', 'F - test_insert_newline_at_start_of_line/data:1') - check_eq(Editor_state.lines[2], 'abc', 'F - test_insert_newline_at_start_of_line/data:2') + 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') end function test_insert_from_clipboard() @@ -1758,7 +1758,7 @@ function test_backspace_past_line_boundary() Editor_state.cursor1 = {line=2, pos=1} -- backspace joins with previous line edit.run_after_keychord(Editor_state, 'backspace') - check_eq(Editor_state.lines[1], 'abcdef', "F - test_backspace_past_line_boundary") + check_eq(Editor_state.lines[1].data, 'abcdef', "F - test_backspace_past_line_boundary") end -- some tests for operating over selections created using Shift- chords @@ -1775,7 +1775,7 @@ function test_backspace_over_selection() Editor_state.selection1 = {line=1, pos=2} -- backspace deletes the selected character, even though it's after the cursor edit.run_after_keychord(Editor_state, 'backspace') - check_eq(Editor_state.lines[1], 'bc', "F - test_backspace_over_selection/data") + check_eq(Editor_state.lines[1].data, 'bc', "F - test_backspace_over_selection/data") -- cursor (remains) at start of selection check_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") @@ -1794,7 +1794,7 @@ function test_backspace_over_selection_reverse() Editor_state.selection1 = {line=1, pos=1} -- backspace deletes the selected character edit.run_after_keychord(Editor_state, 'backspace') - check_eq(Editor_state.lines[1], 'bc', "F - test_backspace_over_selection_reverse/data") + check_eq(Editor_state.lines[1].data, 'bc', "F - test_backspace_over_selection_reverse/data") -- cursor moves to start of selection check_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") @@ -1813,8 +1813,8 @@ function test_backspace_over_multiple_lines() Editor_state.selection1 = {line=4, pos=2} -- backspace deletes the region and joins the remaining portions of lines on either side edit.run_after_keychord(Editor_state, 'backspace') - check_eq(Editor_state.lines[1], 'akl', "F - test_backspace_over_multiple_lines/data:1") - check_eq(Editor_state.lines[2], 'mno', "F - test_backspace_over_multiple_lines/data:2") + 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 selection check_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") @@ -1833,8 +1833,8 @@ function test_backspace_to_end_of_line() Editor_state.selection1 = {line=1, pos=4} -- backspace deletes rest of line without joining to any other line edit.run_after_keychord(Editor_state, 'backspace') - check_eq(Editor_state.lines[1], 'a', "F - test_backspace_to_start_of_line/data:1") - check_eq(Editor_state.lines[2], 'def', "F - test_backspace_to_start_of_line/data:2") + 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 selection check_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") @@ -1853,8 +1853,8 @@ function test_backspace_to_start_of_line() Editor_state.selection1 = {line=2, pos=3} -- backspace deletes beginning of line without joining to any other line edit.run_after_keychord(Editor_state, 'backspace') - check_eq(Editor_state.lines[1], 'abc', "F - test_backspace_to_start_of_line/data:1") - check_eq(Editor_state.lines[2], 'f', "F - test_backspace_to_start_of_line/data:2") + 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 selection check_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") @@ -1950,7 +1950,7 @@ function test_undo_restores_selection() edit.draw(Editor_state) -- delete selected text edit.run_after_textinput(Editor_state, 'x') - check_eq(Editor_state.lines[1], 'xbc', 'F - test_undo_restores_selection/baseline') + 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') -- undo edit.run_after_keychord(Editor_state, 'C-z') diff --git a/undo.lua b/undo.lua index 9e55fe8..912c949 100644 --- a/undo.lua +++ b/undo.lua @@ -57,7 +57,8 @@ function snapshot(State, s,e) } -- deep copy lines without cached stuff like text fragments for i=s,e do - table.insert(event.lines, State.lines[i]) + local line = State.lines[i] + table.insert(event.lines, {data=line.data}) end return event end