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:
parent
778f77a458
commit
a655c2113c
4
edit.lua
4
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
|
||||
|
|
10
file.lua
10
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
|
||||
|
|
|
@ -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()
|
||||
|
|
16
search.lua
16
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
|
||||
|
|
32
select.lua
32
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
|
||||
|
|
86
text.lua
86
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)
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue