get rid of unnecessary tables around line strings

This commit is contained in:
Kartik K. Agaram 2024-07-28 22:06:18 -07:00
parent 4fb1667685
commit 7fbb866620
6 changed files with 70 additions and 73 deletions

View File

@ -23,10 +23,7 @@ function new_editor(top, left, right, bottom, font, font_height, line_height) -
-- The editor is for editing an array of lines.
-- The array of lines can never be empty; there must be at least one line for positioning a cursor at.
--
-- A line is a table with:
-- string data,
lines = {{data=''}}, -- array of lines
lines = {''}, -- array of strings
-- We need to track a couple of _locations_:
screen_top = nil, -- location at top of screen, to start drawing from
@ -107,10 +104,10 @@ function edit.draw(Editor)
initpos = Editor.screen_top.pos
end
--? print('screen line', line_index, initpos, y)
for pos,char in utf8chars(line.data, initpos) do
for pos,char in utf8chars(line, initpos) do
local w = Editor.font:getWidth(char)
if char:match('%s') then
if Text.line_wrap_at_word_boundary(Editor, x, line.data, pos) then
if Text.line_wrap_at_word_boundary(Editor, x, line, pos) then
do_it(x,y, w, line_index, pos, char)
x = Editor.left
y = y + Editor.line_height
@ -140,7 +137,7 @@ function edit.draw(Editor)
end
end
-- draw cursor if it's at end of line
do_it(x,y, 0, line_index, utf8.len(line.data)+1, '')
do_it(x,y, 0, line_index, utf8.len(line)+1, '')
y = y + Editor.line_height
if y + Editor.line_height > Editor.bottom then
break
@ -325,7 +322,7 @@ function edit.keychord_press(Editor, chord, key)
-- clipboard
elseif chord == 'C-a' then
Editor.selection1 = {line=1, pos=1}
Editor.cursor = {line=#Editor.lines, pos=utf8.len(Editor.lines[#Editor.lines].data)+1}
Editor.cursor = {line=#Editor.lines, pos=utf8.len(Editor.lines[#Editor.lines])+1}
elseif chord == 'C-c' then
local s = Text.selection(Editor)
if s then

View File

@ -24,11 +24,11 @@ function load_from_file(infile)
while true do
local line = infile_next_line()
if line == nil then break end
table.insert(result, {data=line})
table.insert(result, line)
end
end
if #result == 0 then
table.insert(result, {data=''})
table.insert(result, '')
end
return result
end
@ -40,7 +40,7 @@ function save_to_disk(Editor)
error('failed to write to "'..Editor.filename..'"')
end
for _,line in ipairs(Editor.lines) do
outfile:write(line.data)
outfile:write(line)
outfile:write('\n')
end
outfile:close()
@ -50,10 +50,10 @@ end
function load_array(a)
local result = {}
for _,line in ipairs(a) do
table.insert(result, {data=line})
table.insert(result, line)
end
if #result == 0 then
table.insert(result, {data=''})
table.insert(result, '')
end
return result
end

View File

@ -93,7 +93,7 @@ function Text.right(Editor)
end -- 0-5 scans
function Text.right_without_scroll(Editor)
if Editor.cursor.pos and Editor.cursor.pos <= utf8.len(Editor.lines[Editor.cursor.line].data) then
if Editor.cursor.pos and Editor.cursor.pos <= utf8.len(Editor.lines[Editor.cursor.line]) then
Editor.cursor.pos = Editor.cursor.pos+1
else
local _, y = edit.to_coord(Editor, Editor.cursor) -- scan
@ -127,7 +127,7 @@ function Text.start_of_line(Editor)
end -- 0-1 scan
function Text.end_of_line(Editor)
Editor.cursor.pos = utf8.len(Editor.lines[Editor.cursor.line].data) + 1
Editor.cursor.pos = utf8.len(Editor.lines[Editor.cursor.line]) + 1
maybe_snap_cursor_to_bottom_of_screen(Editor) -- 0-1 scan
end -- 0-1 scan
@ -137,7 +137,7 @@ function Text.word_left(Editor)
if Editor.cursor.pos == nil or Editor.cursor.pos == 1 then
break -- line boundary is always whitespace
end
if Text.match(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos-1, '%S') then
if Text.match(Editor.lines[Editor.cursor.line], Editor.cursor.pos-1, '%S') then
break
end
Text.left_without_scroll(Editor)
@ -149,7 +149,7 @@ function Text.word_left(Editor)
break
end
assert(Editor.cursor.pos > 1, 'bumped up against start of line')
if Text.match(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos-1, '%s') then
if Text.match(Editor.lines[Editor.cursor.line], Editor.cursor.pos-1, '%s') then
break
end
end
@ -159,20 +159,20 @@ end
function Text.word_right(Editor)
-- skip some whitespace
while true do
if Editor.cursor.pos == nil or Editor.cursor.pos > utf8.len(Editor.lines[Editor.cursor.line].data) then
if Editor.cursor.pos == nil or Editor.cursor.pos > utf8.len(Editor.lines[Editor.cursor.line]) then
break
end
if Text.match(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos, '%S') then
if Text.match(Editor.lines[Editor.cursor.line], Editor.cursor.pos, '%S') then
break
end
Text.right_without_scroll(Editor)
end
while true do
Text.right_without_scroll(Editor)
if Editor.cursor.pos == nil or Editor.cursor.pos > utf8.len(Editor.lines[Editor.cursor.line].data) then
if Editor.cursor.pos == nil or Editor.cursor.pos > utf8.len(Editor.lines[Editor.cursor.line]) then
break
end
if Text.match(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos, '%s') then
if Text.match(Editor.lines[Editor.cursor.line], Editor.cursor.pos, '%s') then
break
end
end
@ -224,11 +224,11 @@ function edit.to_loc(Editor, mx,my)
if line_index == Editor.screen_top.line then
initpos = Editor.screen_top.pos
end
for pos, char in utf8chars(line.data, initpos) do
for pos, char in utf8chars(line, initpos) do
prevloc.pos = pos
local w = Editor.font:getWidth(char) -- width of char
if char:match('%s') then
if Text.line_wrap_at_word_boundary(Editor, x, line.data, pos) then
if Text.line_wrap_at_word_boundary(Editor, x, line, pos) then
if my < y+Editor.line_height then
return {line=line_index, pos=pos}
end
@ -258,9 +258,9 @@ function edit.to_loc(Editor, mx,my)
x = x+w
end
end
prevloc.pos = utf8.len(line.data)+1
prevloc.pos = utf8.len(line)+1
if my < y+Editor.line_height then
return {line=line_index, pos=utf8.len(line.data)+1}
return {line=line_index, pos=utf8.len(line)+1}
end
y = y + Editor.line_height
if y + Editor.line_height > Editor.bottom then
@ -280,10 +280,10 @@ function edit.to_coord(Editor, loc) -- scans
if line_index == Editor.screen_top.line then
initpos = Editor.screen_top.pos
end
for pos,char in utf8chars(line.data, initpos) do
for pos,char in utf8chars(line, initpos) do
local w = Editor.font:getWidth(char)
if char:match('%s') then
if Text.line_wrap_at_word_boundary(Editor, x, line.data, pos) then
if Text.line_wrap_at_word_boundary(Editor, x, line, pos) then
if loc.line == line_index and loc.pos == pos then
return x, y
end
@ -310,7 +310,7 @@ function edit.to_coord(Editor, loc) -- scans
x = x + w
end
end
if loc.line == line_index and loc.pos == utf8.len(line.data)+1 then
if loc.line == line_index and loc.pos == utf8.len(line)+1 then
return x, y
end
y = y + Editor.line_height
@ -413,10 +413,10 @@ function edit.hor(Editor, loc, x0) -- scans line
-- look within the screen line
local x = Editor.left
local prevx = nil
for pos,char in utf8chars(line.data, start_pos_of_screen_line) do
for pos,char in utf8chars(line, start_pos_of_screen_line) do
local w = Editor.font:getWidth(char)
if char:match('%s') then
if Text.line_wrap_at_word_boundary(Editor, x, line.data, pos) then
if Text.line_wrap_at_word_boundary(Editor, x, line, pos) then
return {line=loc.line, pos=pos+1}
else
if (prevx == nil or x0 >= (prevx+x)/2) and x0 < x+w/2 then
@ -438,7 +438,7 @@ function edit.hor(Editor, loc, x0) -- scans line
x = x + w
end
end
return {line=loc.line, pos=utf8.len(line.data)+1}
return {line=loc.line, pos=utf8.len(line)+1}
end -- 0-1 scans
function Text.start_of_screen_line(Editor, loc) -- scans line
@ -458,10 +458,10 @@ function Text.screen_line_starts(Editor, line_index) -- scans line
local result = {1}
local line = Editor.lines[line_index]
local x = Editor.left
for pos,char in utf8chars(line.data) do
for pos,char in utf8chars(line) do
local w = Editor.font:getWidth(char)
if char:match('%s') then
if Text.line_wrap_at_word_boundary(Editor, x, line.data, pos) then
if Text.line_wrap_at_word_boundary(Editor, x, line, pos) then
x = Editor.left
table.insert(result, pos+1)
else
@ -553,11 +553,11 @@ function Text.get_wrap(Editor, line_index) -- scans line
local curr_screen_line = {}
local line = Editor.lines[line_index]
local x = Editor.left
for pos,char in utf8chars(line.data) do
for pos,char in utf8chars(line) do
local w = Editor.font:getWidth(char)
if char:match('%s') then
table.insert(curr_screen_line, char)
if Text.line_wrap_at_word_boundary(Editor, x, line.data, pos) then
if Text.line_wrap_at_word_boundary(Editor, x, line, pos) then
table.insert(right_margins, x+w)
table.insert(result, table.concat(curr_screen_line))
curr_screen_line = {}

View File

@ -20,7 +20,7 @@ function Text.search_next(Editor)
local offset
-- search current line from cursor
local curr_pos = Editor.cursor.pos
local curr_line = Editor.lines[Editor.cursor.line].data
local curr_line = Editor.lines[Editor.cursor.line]
local curr_offset = Text.offset(curr_line, curr_pos)
offset = find(curr_line, Editor.search_term, curr_offset, --[[literal]] true)
if offset then
@ -29,7 +29,7 @@ function Text.search_next(Editor)
if offset == nil then
-- search lines below cursor
for i=Editor.cursor.line+1,#Editor.lines do
local curr_line = Editor.lines[i].data
local curr_line = Editor.lines[i]
offset = find(curr_line, Editor.search_term, --[[from start]] nil, --[[literal]] true)
if offset then
Editor.cursor = {line=i, pos=utf8.len(curr_line, 1, offset)}
@ -40,7 +40,7 @@ function Text.search_next(Editor)
if offset == nil then
-- wrap around
for i=1,Editor.cursor.line-1 do
local curr_line = Editor.lines[i].data
local curr_line = Editor.lines[i]
offset = find(curr_line, Editor.search_term, --[[from start]] nil, --[[literal]] true)
if offset then
Editor.cursor = {line=i, pos=utf8.len(curr_line, 1, offset)}
@ -50,7 +50,7 @@ function Text.search_next(Editor)
end
if offset == nil then
-- search current line until cursor
local curr_line = Editor.lines[Editor.cursor.line].data
local curr_line = Editor.lines[Editor.cursor.line]
offset = find(curr_line, Editor.search_term, --[[from start]] nil, --[[literal]] true)
local pos = utf8.len(curr_line, 1, offset)
if pos and pos < Editor.cursor.pos then
@ -70,7 +70,7 @@ function Text.search_previous(Editor)
local offset
-- search current line before cursor
local curr_pos = Editor.cursor.pos
local curr_line = Editor.lines[Editor.cursor.line].data
local curr_line = Editor.lines[Editor.cursor.line]
local curr_offset = Text.offset(curr_line, curr_pos)
offset = rfind(curr_line, Editor.search_term, curr_offset-1, --[[literal]] true)
if offset then
@ -79,7 +79,7 @@ function Text.search_previous(Editor)
if offset == nil then
-- search lines above cursor
for i=Editor.cursor.line-1,1,-1 do
local curr_line = Editor.lines[i].data
local curr_line = Editor.lines[i]
offset = rfind(curr_line, Editor.search_term, --[[from end]] nil, --[[literal]] true)
if offset then
Editor.cursor = {line=i, pos=utf8.len(curr_line, 1, offset)}
@ -90,7 +90,7 @@ function Text.search_previous(Editor)
if offset == nil then
-- wrap around
for i=#Editor.lines,Editor.cursor.line+1,-1 do
local curr_line = Editor.lines[i].data
local curr_line = Editor.lines[i]
offset = rfind(curr_line, Editor.search_term, --[[from end]] nil, --[[literal]] true)
if offset then
Editor.cursor = {line=i, pos=utf8.len(curr_line, 1, offset)}
@ -100,7 +100,7 @@ function Text.search_previous(Editor)
end
if offset == nil then
-- search current line after cursor
local curr_line = Editor.lines[Editor.cursor.line].data
local curr_line = Editor.lines[Editor.cursor.line]
offset = rfind(curr_line, Editor.search_term, --[[from end]] nil, --[[literal]] true)
local pos = utf8.len(curr_line, 1, offset)
if pos and pos > Editor.cursor.pos then
@ -121,7 +121,7 @@ function in_search(Editor, line_index, pos)
if Editor.search_term == nil then return false end
if #Editor.search_term == 0 then return false end
if line_index ~= Editor.cursor.line then return false end
return find_at(Editor.lines[line_index].data, Editor.search_term, Editor.cursor.pos)
return find_at(Editor.lines[line_index], Editor.search_term, Editor.cursor.pos)
and Editor.cursor.pos <= pos and pos <= Editor.cursor.pos+utf8.len(Editor.search_term)-1
end

View File

@ -41,18 +41,18 @@ function Text.delete_selection_without_undo(Editor)
end
Editor.selection1 = {}
-- delete everything between min (inclusive) and max (exclusive)
local min_offset = Text.offset(Editor.lines[minl].data, minp)
local max_offset = Text.offset(Editor.lines[maxl].data, maxp)
local min_offset = Text.offset(Editor.lines[minl], minp)
local max_offset = Text.offset(Editor.lines[maxl], maxp)
if minl == maxl then
Editor.lines[minl].data = Editor.lines[minl].data:sub(1, min_offset-1)..Editor.lines[minl].data:sub(max_offset)
Editor.lines[minl] = Editor.lines[minl]:sub(1, min_offset-1)..Editor.lines[minl]:sub(max_offset)
return
end
assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
local rhs = Editor.lines[maxl].data:sub(max_offset)
local rhs = Editor.lines[maxl]:sub(max_offset)
for i=maxl,minl+1,-1 do
table.remove(Editor.lines, i)
end
Editor.lines[minl].data = Editor.lines[minl].data:sub(1, min_offset-1)..rhs
Editor.lines[minl] = Editor.lines[minl]:sub(1, min_offset-1)..rhs
end
function Text.selection(Editor)
@ -68,17 +68,17 @@ function Text.selection(Editor)
minp,maxp = maxp,minp
end
end
local min_offset = Text.offset(Editor.lines[minl].data, minp)
local max_offset = Text.offset(Editor.lines[maxl].data, maxp)
local min_offset = Text.offset(Editor.lines[minl], minp)
local max_offset = Text.offset(Editor.lines[maxl], maxp)
if minl == maxl then
return Editor.lines[minl].data:sub(min_offset, max_offset-1)
return Editor.lines[minl]:sub(min_offset, max_offset-1)
end
assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
local result = {Editor.lines[minl].data:sub(min_offset)}
local result = {Editor.lines[minl]:sub(min_offset)}
for i=minl+1,maxl-1 do
table.insert(result, Editor.lines[i].data)
table.insert(result, Editor.lines[i])
end
table.insert(result, Editor.lines[maxl].data:sub(1, max_offset-1))
table.insert(result, Editor.lines[maxl]:sub(1, max_offset-1))
return table.concat(result, '\n')
end

View File

@ -26,8 +26,8 @@ function Text.text_input(Editor, t)
end
function Text.insert_at_cursor(Editor, t)
local byte_offset = Text.offset(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos)
Editor.lines[Editor.cursor.line].data = string.sub(Editor.lines[Editor.cursor.line].data, 1, byte_offset-1)..t..string.sub(Editor.lines[Editor.cursor.line].data, byte_offset)
local byte_offset = Text.offset(Editor.lines[Editor.cursor.line], Editor.cursor.pos)
Editor.lines[Editor.cursor.line] = string.sub(Editor.lines[Editor.cursor.line], 1, byte_offset-1)..t..string.sub(Editor.lines[Editor.cursor.line], byte_offset)
Editor.cursor.pos = Editor.cursor.pos+1
end
@ -56,21 +56,21 @@ function Text.keychord_press(Editor, chord)
local before
if Editor.cursor.pos > 1 then
before = snapshot(Editor, Editor.cursor.line)
local byte_start = utf8.offset(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos-1)
local byte_end = utf8.offset(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos)
local byte_start = utf8.offset(Editor.lines[Editor.cursor.line], Editor.cursor.pos-1)
local byte_end = utf8.offset(Editor.lines[Editor.cursor.line], Editor.cursor.pos)
if byte_start then
if byte_end then
Editor.lines[Editor.cursor.line].data = string.sub(Editor.lines[Editor.cursor.line].data, 1, byte_start-1)..string.sub(Editor.lines[Editor.cursor.line].data, byte_end)
Editor.lines[Editor.cursor.line] = string.sub(Editor.lines[Editor.cursor.line], 1, byte_start-1)..string.sub(Editor.lines[Editor.cursor.line], byte_end)
else
Editor.lines[Editor.cursor.line].data = string.sub(Editor.lines[Editor.cursor.line].data, 1, byte_start-1)
Editor.lines[Editor.cursor.line] = string.sub(Editor.lines[Editor.cursor.line], 1, byte_start-1)
end
Editor.cursor.pos = Editor.cursor.pos-1
end
elseif Editor.cursor.line > 1 then
before = snapshot(Editor, Editor.cursor.line-1, Editor.cursor.line)
-- join lines
Editor.cursor.pos = utf8.len(Editor.lines[Editor.cursor.line-1].data)+1
Editor.lines[Editor.cursor.line-1].data = Editor.lines[Editor.cursor.line-1].data..Editor.lines[Editor.cursor.line].data
Editor.cursor.pos = utf8.len(Editor.lines[Editor.cursor.line-1])+1
Editor.lines[Editor.cursor.line-1] = Editor.lines[Editor.cursor.line-1]..Editor.lines[Editor.cursor.line]
table.remove(Editor.lines, Editor.cursor.line)
Editor.cursor.line = Editor.cursor.line-1
end
@ -90,25 +90,25 @@ function Text.keychord_press(Editor, chord)
return
end
local before
if Editor.cursor.pos <= utf8.len(Editor.lines[Editor.cursor.line].data) then
if Editor.cursor.pos <= utf8.len(Editor.lines[Editor.cursor.line]) then
before = snapshot(Editor, Editor.cursor.line)
else
before = snapshot(Editor, Editor.cursor.line, Editor.cursor.line+1)
end
if Editor.cursor.pos <= utf8.len(Editor.lines[Editor.cursor.line].data) then
local byte_start = utf8.offset(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos)
local byte_end = utf8.offset(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos+1)
if Editor.cursor.pos <= utf8.len(Editor.lines[Editor.cursor.line]) then
local byte_start = utf8.offset(Editor.lines[Editor.cursor.line], Editor.cursor.pos)
local byte_end = utf8.offset(Editor.lines[Editor.cursor.line], Editor.cursor.pos+1)
if byte_start then
if byte_end then
Editor.lines[Editor.cursor.line].data = string.sub(Editor.lines[Editor.cursor.line].data, 1, byte_start-1)..string.sub(Editor.lines[Editor.cursor.line].data, byte_end)
Editor.lines[Editor.cursor.line] = string.sub(Editor.lines[Editor.cursor.line], 1, byte_start-1)..string.sub(Editor.lines[Editor.cursor.line], byte_end)
else
Editor.lines[Editor.cursor.line].data = string.sub(Editor.lines[Editor.cursor.line].data, 1, byte_start-1)
Editor.lines[Editor.cursor.line] = string.sub(Editor.lines[Editor.cursor.line], 1, byte_start-1)
end
-- no change to Editor.cursor.pos
end
elseif Editor.cursor.line < #Editor.lines then
-- join lines
Editor.lines[Editor.cursor.line].data = Editor.lines[Editor.cursor.line].data..Editor.lines[Editor.cursor.line+1].data
Editor.lines[Editor.cursor.line] = Editor.lines[Editor.cursor.line]..Editor.lines[Editor.cursor.line+1]
table.remove(Editor.lines, Editor.cursor.line+1)
end
record_undo_event(Editor, {before=before, after=snapshot(Editor, Editor.cursor.line)})
@ -199,9 +199,9 @@ function Text.keychord_press(Editor, chord)
end
function Text.insert_return(Editor)
local byte_offset = Text.offset(Editor.lines[Editor.cursor.line].data, Editor.cursor.pos)
table.insert(Editor.lines, Editor.cursor.line+1, {data=string.sub(Editor.lines[Editor.cursor.line].data, byte_offset)})
Editor.lines[Editor.cursor.line].data = string.sub(Editor.lines[Editor.cursor.line].data, 1, byte_offset-1)
local byte_offset = Text.offset(Editor.lines[Editor.cursor.line], Editor.cursor.pos)
table.insert(Editor.lines, Editor.cursor.line+1, string.sub(Editor.lines[Editor.cursor.line], byte_offset))
Editor.lines[Editor.cursor.line] = string.sub(Editor.lines[Editor.cursor.line], 1, byte_offset-1)
Editor.cursor = {line=Editor.cursor.line+1, pos=1}
maybe_snap_cursor_to_bottom_of_screen(Editor)
end