bring back a level of wrapping

Many projects will require the ability to add metadata to lines, so
let's not drop that.
This commit is contained in:
Kartik K. Agaram 2022-08-15 10:31:56 -07:00
parent 778f77a458
commit a655c2113c
8 changed files with 97 additions and 96 deletions

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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')

View File

@ -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