audit all asserts
Each one should provide a message that will show up within LÖVE. Stop relying on nearby prints to the terminal. I also found some unnecessary ones. There is some potential here for performance regressions: the format() calls will trigger whether or not the assertion fails, and cause allocations. So far Lua's GC seems good enough to manage the load even with Moby Dick, even in some situations that caused issues in the past like undo.
This commit is contained in:
parent
5cce511550
commit
007b965b11
|
@ -136,7 +136,7 @@ end
|
|||
|
||||
function move_candidate_to_front(s)
|
||||
local index = array.find(File_navigation.all_candidates, s)
|
||||
assert(index)
|
||||
assert(index, 'file missing from manifest')
|
||||
table.remove(File_navigation.all_candidates, index)
|
||||
table.insert(File_navigation.all_candidates, 1, s)
|
||||
end
|
||||
|
|
28
drawing.lua
28
drawing.lua
|
@ -33,7 +33,6 @@ function Drawing.draw(State, line_index, y)
|
|||
local my = Drawing.coord(pmy-line_cache.starty, State.width)
|
||||
|
||||
for _,shape in ipairs(line.shapes) do
|
||||
assert(shape)
|
||||
if geom.on_shape(mx,my, line, shape) then
|
||||
App.color(Focus_stroke_color)
|
||||
else
|
||||
|
@ -113,8 +112,7 @@ function Drawing.draw_shape(drawing, shape, top, left,right)
|
|||
elseif shape.mode == 'deleted' then
|
||||
-- ignore
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -207,8 +205,7 @@ function Drawing.draw_pending_shape(drawing, top, left,right)
|
|||
elseif shape.mode == 'name' then
|
||||
-- nothing pending; changes are immediately committed
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -239,8 +236,7 @@ function Drawing.mouse_press(State, drawing_index, x,y, mouse_button)
|
|||
elseif State.current_drawing_mode == 'name' then
|
||||
-- nothing
|
||||
else
|
||||
print(State.current_drawing_mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(State.current_drawing_mode))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -255,7 +251,7 @@ function Drawing.update(State)
|
|||
-- just skip this frame
|
||||
return
|
||||
end
|
||||
assert(drawing.mode == 'drawing')
|
||||
assert(drawing.mode == 'drawing', 'Drawing.update: line is not a drawing')
|
||||
local pmx, pmy = App.mouse_x(), App.mouse_y()
|
||||
local mx = Drawing.coord(pmx-State.left, State.width)
|
||||
local my = Drawing.coord(pmy-line_cache.starty, State.width)
|
||||
|
@ -342,7 +338,7 @@ function Drawing.mouse_release(State, x,y, mouse_button)
|
|||
table.insert(drawing.shapes, drawing.pending)
|
||||
end
|
||||
elseif drawing.pending.mode == 'rectangle' then
|
||||
assert(#drawing.pending.vertices <= 2)
|
||||
assert(#drawing.pending.vertices <= 2, 'Drawing.mouse_release: rectangle has too many pending vertices')
|
||||
if #drawing.pending.vertices == 2 then
|
||||
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-line_cache.starty, State.width)
|
||||
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
|
||||
|
@ -357,7 +353,7 @@ function Drawing.mouse_release(State, x,y, mouse_button)
|
|||
-- too few points; draw nothing
|
||||
end
|
||||
elseif drawing.pending.mode == 'square' then
|
||||
assert(#drawing.pending.vertices <= 2)
|
||||
assert(#drawing.pending.vertices <= 2, 'Drawing.mouse_release: square has too many pending vertices')
|
||||
if #drawing.pending.vertices == 2 then
|
||||
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-line_cache.starty, State.width)
|
||||
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
|
||||
|
@ -386,8 +382,7 @@ function Drawing.mouse_release(State, x,y, mouse_button)
|
|||
elseif drawing.pending.mode == 'name' then
|
||||
-- drop it
|
||||
else
|
||||
print(drawing.pending.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(drawing.pending.mode))
|
||||
end
|
||||
State.lines.current_drawing.pending = {}
|
||||
State.lines.current_drawing = nil
|
||||
|
@ -545,7 +540,7 @@ function Drawing.keychord_press(State, chord)
|
|||
if Drawing.contains_point(shape, i) then
|
||||
if shape.mode == 'polygon' then
|
||||
local idx = table.find(shape.vertices, i)
|
||||
assert(idx)
|
||||
assert(idx, 'point to delete is not in vertices')
|
||||
table.remove(shape.vertices, idx)
|
||||
if #shape.vertices < 3 then
|
||||
shape.mode = 'deleted'
|
||||
|
@ -641,7 +636,6 @@ function Drawing.select_shape_at_mouse(State)
|
|||
if Drawing.in_drawing(drawing, line_cache, x,y, State.left,State.right) then
|
||||
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-line_cache.starty, State.width)
|
||||
for i,shape in ipairs(drawing.shapes) do
|
||||
assert(shape)
|
||||
if geom.on_shape(mx,my, drawing, shape) then
|
||||
return drawing,line_cache,i,shape
|
||||
end
|
||||
|
@ -659,7 +653,6 @@ function Drawing.select_point_at_mouse(State)
|
|||
if Drawing.in_drawing(drawing, line_cache, x,y, State.left,State.right) then
|
||||
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-line_cache.starty, State.width)
|
||||
for i,point in ipairs(drawing.points) do
|
||||
assert(point)
|
||||
if Drawing.near(point, mx,my, State.width) then
|
||||
return drawing_index,drawing,line_cache,i,point
|
||||
end
|
||||
|
@ -696,13 +689,12 @@ function Drawing.contains_point(shape, p)
|
|||
elseif shape.mode == 'deleted' then
|
||||
-- already done
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
end
|
||||
|
||||
function Drawing.smoothen(shape)
|
||||
assert(shape.mode == 'freehand')
|
||||
assert(shape.mode == 'freehand', 'can only smoothen freehand shapes')
|
||||
for _=1,7 do
|
||||
for i=2,#shape.points-1 do
|
||||
local a = shape.points[i-1]
|
||||
|
|
15
edit.lua
15
edit.lua
|
@ -80,7 +80,7 @@ function edit.initialize_state(top, left, right, font_height, line_height) -- c
|
|||
cursor_x = 0,
|
||||
cursor_y = 0,
|
||||
|
||||
current_drawing_mode = 'line',
|
||||
current_drawing_mode = 'line', -- one of the available shape modes
|
||||
previous_drawing_mode = nil, -- extra state for some ephemeral modes like moving/deleting/naming points
|
||||
|
||||
font_height = font_height,
|
||||
|
@ -157,14 +157,8 @@ end
|
|||
function edit.draw(State)
|
||||
State.button_handlers = {}
|
||||
App.color(Text_color)
|
||||
if #State.lines ~= #State.line_cache then
|
||||
print(('line_cache is out of date; %d when it should be %d'):format(#State.line_cache, #State.lines))
|
||||
assert(false)
|
||||
end
|
||||
if not Text.le1(State.screen_top1, State.cursor1) then
|
||||
print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
|
||||
assert(false)
|
||||
end
|
||||
assert(#State.lines == #State.line_cache, ('line_cache is out of date; %d elements when it should be %d'):format(#State.line_cache, #State.lines))
|
||||
assert(Text.le1(State.screen_top1, State.cursor1), ('screen_top (line=%d,pos=%d) is below cursor (line=%d,pos=%d)'):format(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos))
|
||||
State.cursor_x = nil
|
||||
State.cursor_y = nil
|
||||
local y = State.top
|
||||
|
@ -204,8 +198,7 @@ function edit.draw(State)
|
|||
Drawing.draw(State, line_index, y)
|
||||
y = y + Drawing.pixels(line.h, State.width) + Drawing_padding_bottom
|
||||
else
|
||||
print(line.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown line mode %s'):format(line.mode))
|
||||
end
|
||||
end
|
||||
State.screen_bottom1 = screen_bottom1
|
||||
|
|
13
file.lua
13
file.lua
|
@ -55,7 +55,7 @@ function load_drawing(infile_next_line)
|
|||
local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
|
||||
while true do
|
||||
local line = infile_next_line()
|
||||
assert(line)
|
||||
assert(line, 'drawing in file is incomplete')
|
||||
if line == '```' then break end
|
||||
local shape = json.decode(line)
|
||||
if shape.mode == 'freehand' then
|
||||
|
@ -80,8 +80,7 @@ function load_drawing(infile_next_line)
|
|||
elseif shape.mode == 'deleted' then
|
||||
-- ignore
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
table.insert(drawing.shapes, shape)
|
||||
end
|
||||
|
@ -115,8 +114,7 @@ function store_drawing(outfile, drawing)
|
|||
elseif shape.mode == 'deleted' then
|
||||
-- ignore
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
end
|
||||
outfile:write('```\n')
|
||||
|
@ -152,7 +150,7 @@ function load_drawing_from_array(iter, a, i)
|
|||
local line
|
||||
while true do
|
||||
i, line = iter(a, i)
|
||||
assert(i)
|
||||
assert(i, 'drawing in array is incomplete')
|
||||
--? print(i)
|
||||
if line == '```' then break end
|
||||
local shape = json.decode(line)
|
||||
|
@ -178,8 +176,7 @@ function load_drawing_from_array(iter, a, i)
|
|||
elseif shape.mode == 'deleted' then
|
||||
-- ignore
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
table.insert(drawing.shapes, shape)
|
||||
end
|
||||
|
|
3
geom.lua
3
geom.lua
|
@ -38,8 +38,7 @@ function geom.on_shape(x,y, drawing, shape)
|
|||
return geom.angle_between(center.x,center.y, x,y, shape.start_angle,shape.end_angle)
|
||||
elseif shape.mode == 'deleted' then
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ function table.shallowcopy(x)
|
|||
end
|
||||
|
||||
function log_browser.draw(State, hide_cursor)
|
||||
assert(#State.lines == #State.line_cache)
|
||||
assert(#State.lines == #State.line_cache, ('line_cache is out of date; %d elements when it should be %d'):format(#State.line_cache, #State.lines))
|
||||
local mouse_line_index = log_browser.line_index(State, App.mouse_x(), App.mouse_y())
|
||||
local y = State.top
|
||||
for line_index = State.screen_top1.line,#State.lines do
|
||||
|
@ -95,7 +95,7 @@ function log_browser.draw(State, hide_cursor)
|
|||
love.graphics.line(xleft,sectiony, xleft+50-2,sectiony)
|
||||
love.graphics.print(line.section_name, xleft+50,y)
|
||||
love.graphics.line(xleft+50+App.width(line.section_name)+2,sectiony, xright,sectiony)
|
||||
else assert(line.section_end)
|
||||
else assert(line.section_end, "log line has a section name, but it's neither the start nor end of a section")
|
||||
local sectiony = y+State.line_height-Section_border_padding_vertical
|
||||
love.graphics.line(xleft,y, xleft,sectiony)
|
||||
love.graphics.line(xright,y, xright,sectiony)
|
||||
|
|
|
@ -139,7 +139,7 @@ function rfind(s, pat, i, plain)
|
|||
local rendpos = rs:find(rpat, ri, plain)
|
||||
if rendpos == nil then return nil end
|
||||
local endpos = #s - rendpos + 1
|
||||
assert (endpos >= #pat)
|
||||
assert (endpos >= #pat, ('rfind: endpos %d should be >= #pat %d at this point'):format(endpos, #pat))
|
||||
return endpos-#pat+1
|
||||
end
|
||||
|
||||
|
|
10
select.lua
10
select.lua
|
@ -33,13 +33,13 @@ function Text.clip_selection(State, line_index, apos, bpos)
|
|||
-- fully contained
|
||||
return apos,bpos
|
||||
elseif a_ge then
|
||||
assert(maxl == line_index)
|
||||
assert(maxl == line_index, ('maxl %d not equal to line_index %d'):format(maxl, line_index))
|
||||
return apos,maxp
|
||||
elseif b_lt then
|
||||
assert(minl == line_index)
|
||||
assert(minl == line_index, ('minl %d not equal to line_index %d'):format(minl, line_index))
|
||||
return minp,bpos
|
||||
else
|
||||
assert(minl == maxl and minl == line_index)
|
||||
assert(minl == maxl and minl == line_index, ('minl %d, maxl %d and line_index %d are not all equal'):format(minl, maxl, line_index))
|
||||
return minp,maxp
|
||||
end
|
||||
end
|
||||
|
@ -127,7 +127,7 @@ function Text.delete_selection_without_undo(State)
|
|||
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)
|
||||
assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
|
||||
local rhs = State.lines[maxl].data:sub(max_offset)
|
||||
for i=maxl,minl+1,-1 do
|
||||
table.remove(State.lines, i)
|
||||
|
@ -154,7 +154,7 @@ function Text.selection(State)
|
|||
if minl == maxl then
|
||||
return State.lines[minl].data:sub(min_offset, max_offset-1)
|
||||
end
|
||||
assert(minl < maxl)
|
||||
assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
|
||||
local result = {State.lines[minl].data:sub(min_offset)}
|
||||
for i=minl+1,maxl-1 do
|
||||
if State.lines[i].mode == 'text' then
|
||||
|
|
|
@ -158,14 +158,8 @@ end
|
|||
function edit.draw(State, hide_cursor, show_line_numbers)
|
||||
State.button_handlers = {}
|
||||
App.color(Text_color)
|
||||
if #State.lines ~= #State.line_cache then
|
||||
print(('line_cache is out of date; %d when it should be %d'):format(#State.line_cache, #State.lines))
|
||||
assert(false)
|
||||
end
|
||||
if not Text.le1(State.screen_top1, State.cursor1) then
|
||||
print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
|
||||
assert(false)
|
||||
end
|
||||
assert(#State.lines == #State.line_cache, ('line_cache is out of date; %d elements when it should be %d'):format(#State.line_cache, #State.lines))
|
||||
assert(Text.le1(State.screen_top1, State.cursor1), ('screen_top (line=%d,pos=%d) is below cursor (line=%d,pos=%d)'):format(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos))
|
||||
State.cursor_x = nil
|
||||
State.cursor_y = nil
|
||||
local y = State.top
|
||||
|
@ -209,8 +203,7 @@ function edit.draw(State, hide_cursor, show_line_numbers)
|
|||
Drawing.draw(State, line_index, y)
|
||||
y = y + Drawing.pixels(line.h, State.width) + Drawing_padding_bottom
|
||||
else
|
||||
print(line.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown line mode %s'):format(line.mode))
|
||||
end
|
||||
end
|
||||
State.screen_bottom1 = screen_bottom1
|
||||
|
|
|
@ -63,7 +63,7 @@ function load_drawing(infile_next_line)
|
|||
local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
|
||||
while true do
|
||||
local line = infile_next_line()
|
||||
assert(line)
|
||||
assert(line, 'drawing in file is incomplete')
|
||||
if line == '```' then break end
|
||||
local shape = json.decode(line)
|
||||
if shape.mode == 'freehand' then
|
||||
|
@ -88,8 +88,7 @@ function load_drawing(infile_next_line)
|
|||
elseif shape.mode == 'deleted' then
|
||||
-- ignore
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
table.insert(drawing.shapes, shape)
|
||||
end
|
||||
|
@ -123,8 +122,7 @@ function store_drawing(outfile, drawing)
|
|||
elseif shape.mode == 'deleted' then
|
||||
-- ignore
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
end
|
||||
outfile:write('```\n')
|
||||
|
@ -162,7 +160,7 @@ function load_drawing_from_array(iter, a, i)
|
|||
local line
|
||||
while true do
|
||||
i, line = iter(a, i)
|
||||
assert(i)
|
||||
assert(i, 'drawing in array is incomplete')
|
||||
--? print(i)
|
||||
if line == '```' then break end
|
||||
local shape = json.decode(line)
|
||||
|
@ -188,8 +186,7 @@ function load_drawing_from_array(iter, a, i)
|
|||
elseif shape.mode == 'deleted' then
|
||||
-- ignore
|
||||
else
|
||||
print(shape.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown drawing mode %s'):format(shape.mode))
|
||||
end
|
||||
table.insert(drawing.shapes, shape)
|
||||
end
|
||||
|
|
|
@ -33,13 +33,13 @@ function Text.clip_selection(State, line_index, apos, bpos)
|
|||
-- fully contained
|
||||
return apos,bpos
|
||||
elseif a_ge then
|
||||
assert(maxl == line_index)
|
||||
assert(maxl == line_index, ('maxl %d not equal to line_index %d'):format(maxl, line_index))
|
||||
return apos,maxp
|
||||
elseif b_lt then
|
||||
assert(minl == line_index)
|
||||
assert(minl == line_index, ('minl %d not equal to line_index %d'):format(minl, line_index))
|
||||
return minp,bpos
|
||||
else
|
||||
assert(minl == maxl and minl == line_index)
|
||||
assert(minl == maxl and minl == line_index, ('minl %d, maxl %d and line_index %d are not all equal'):format(minl, maxl, line_index))
|
||||
return minp,maxp
|
||||
end
|
||||
end
|
||||
|
@ -127,7 +127,7 @@ function Text.delete_selection_without_undo(State)
|
|||
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)
|
||||
assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
|
||||
local rhs = State.lines[maxl].data:sub(max_offset)
|
||||
for i=maxl,minl+1,-1 do
|
||||
table.remove(State.lines, i)
|
||||
|
@ -154,7 +154,7 @@ function Text.selection(State)
|
|||
if minl == maxl then
|
||||
return State.lines[minl].data:sub(min_offset, max_offset-1)
|
||||
end
|
||||
assert(minl < maxl)
|
||||
assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
|
||||
local result = {State.lines[minl].data:sub(min_offset)}
|
||||
for i=minl+1,maxl-1 do
|
||||
if State.lines[i].mode == 'text' then
|
||||
|
|
|
@ -17,7 +17,7 @@ function Text.draw(State, line_index, y, startpos, hide_cursor, show_line_number
|
|||
love.graphics.print(line_index, State.left-Line_number_width*App.width('m')+10,y)
|
||||
end
|
||||
initialize_color()
|
||||
assert(#line_cache.screen_line_starting_pos >= 1)
|
||||
assert(#line_cache.screen_line_starting_pos >= 1, 'line cache missing screen line info')
|
||||
for i=1,#line_cache.screen_line_starting_pos do
|
||||
local pos = line_cache.screen_line_starting_pos[i]
|
||||
if pos < startpos then
|
||||
|
@ -209,7 +209,7 @@ function Text.text_input(State, t)
|
|||
end
|
||||
|
||||
function Text.insert_at_cursor(State, t)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
local byte_offset = Text.offset(State.lines[State.cursor1.line].data, State.cursor1.pos)
|
||||
State.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_offset-1)..t..string.sub(State.lines[State.cursor1.line].data, byte_offset)
|
||||
Text.clear_screen_line_cache(State, State.cursor1.line)
|
||||
|
@ -286,7 +286,7 @@ function Text.keychord_press(State, chord)
|
|||
Text.redraw_all(State) -- if we're scrolling, reclaim all fragments to avoid memory leaks
|
||||
end
|
||||
Text.clear_screen_line_cache(State, State.cursor1.line)
|
||||
assert(Text.le1(State.screen_top1, State.cursor1))
|
||||
assert(Text.le1(State.screen_top1, State.cursor1), ('screen_top (line=%d,pos=%d) is below cursor (line=%d,pos=%d)'):format(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos))
|
||||
schedule_save(State)
|
||||
record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})
|
||||
elseif chord == 'delete' then
|
||||
|
@ -452,7 +452,7 @@ function Text.pagedown(State)
|
|||
end
|
||||
|
||||
function Text.up(State)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
--? print('up', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos)
|
||||
local screen_line_starting_pos, screen_line_index = Text.pos_at_start_of_screen_line(State, State.cursor1)
|
||||
if screen_line_starting_pos == 1 then
|
||||
|
@ -478,7 +478,7 @@ function Text.up(State)
|
|||
end
|
||||
else
|
||||
-- move up one screen line in current line
|
||||
assert(screen_line_index > 1)
|
||||
assert(screen_line_index > 1, 'bumped up against top screen line in line')
|
||||
local new_screen_line_starting_pos = State.line_cache[State.cursor1.line].screen_line_starting_pos[screen_line_index-1]
|
||||
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)
|
||||
|
@ -495,9 +495,9 @@ function Text.up(State)
|
|||
end
|
||||
|
||||
function Text.down(State)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
--? print('down', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
|
||||
assert(State.cursor1.pos)
|
||||
assert(State.cursor1.pos, 'cursor has no pos')
|
||||
if Text.cursor_at_final_screen_line(State) then
|
||||
-- line is done, skip to next text line
|
||||
--? print('cursor at final screen line of its line')
|
||||
|
@ -571,7 +571,7 @@ function Text.word_left(State)
|
|||
if State.cursor1.pos == 1 then
|
||||
break
|
||||
end
|
||||
assert(State.cursor1.pos > 1)
|
||||
assert(State.cursor1.pos > 1, 'bumped up against start of line')
|
||||
if Text.match(State.lines[State.cursor1.line].data, State.cursor1.pos-1, '%s') then
|
||||
break
|
||||
end
|
||||
|
@ -605,15 +605,14 @@ end
|
|||
|
||||
function Text.match(s, pos, pat)
|
||||
local start_offset = Text.offset(s, pos)
|
||||
assert(start_offset)
|
||||
local end_offset = Text.offset(s, pos+1)
|
||||
assert(end_offset > start_offset)
|
||||
assert(end_offset > start_offset, ('end_offset %d not > start_offset %d'):format(end_offset, start_offset))
|
||||
local curr = s:sub(start_offset, end_offset-1)
|
||||
return curr:match(pat)
|
||||
end
|
||||
|
||||
function Text.left(State)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
if State.cursor1.pos > 1 then
|
||||
State.cursor1.pos = State.cursor1.pos-1
|
||||
else
|
||||
|
@ -646,7 +645,7 @@ function Text.right(State)
|
|||
end
|
||||
|
||||
function Text.right_without_scroll(State)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) then
|
||||
State.cursor1.pos = State.cursor1.pos+1
|
||||
else
|
||||
|
@ -671,7 +670,7 @@ function Text.pos_at_start_of_screen_line(State, loc1)
|
|||
return spos,i
|
||||
end
|
||||
end
|
||||
assert(false)
|
||||
assert(false, ('invalid pos %d'):format(loc1.pos))
|
||||
end
|
||||
|
||||
function Text.pos_at_end_of_screen_line(State, loc1)
|
||||
|
@ -685,7 +684,7 @@ function Text.pos_at_end_of_screen_line(State, loc1)
|
|||
end
|
||||
most_recent_final_pos = spos-1
|
||||
end
|
||||
assert(false)
|
||||
assert(false, ('invalid pos %d'):format(loc1.pos))
|
||||
end
|
||||
|
||||
function Text.cursor_at_final_screen_line(State)
|
||||
|
@ -710,7 +709,7 @@ function Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necess
|
|||
end
|
||||
-- hack: insert a text line at bottom of file if necessary
|
||||
if State.cursor1.line > #State.lines then
|
||||
assert(State.cursor1.line == #State.lines+1)
|
||||
assert(State.cursor1.line == #State.lines+1, 'tried to ensure bottom line of file is text, but failed')
|
||||
table.insert(State.lines, {mode='text', data=''})
|
||||
table.insert(State.line_cache, {})
|
||||
end
|
||||
|
@ -742,8 +741,8 @@ function Text.snap_cursor_to_bottom_of_screen(State)
|
|||
end
|
||||
y = y - h
|
||||
else
|
||||
assert(top2.line > 1)
|
||||
assert(State.lines[top2.line-1].mode == 'drawing')
|
||||
assert(top2.line > 1, 'tried to snap cursor to buttom of screen but failed')
|
||||
assert(State.lines[top2.line-1].mode == 'drawing', "expected a drawing but it's not")
|
||||
-- We currently can't draw partial drawings, so either skip it entirely
|
||||
-- or not at all.
|
||||
local h = Drawing_padding_height + Drawing.pixels(State.lines[top2.line-1].h, State.width)
|
||||
|
@ -775,7 +774,7 @@ end
|
|||
function Text.to_pos_on_line(State, line_index, mx, my)
|
||||
local line = State.lines[line_index]
|
||||
local line_cache = State.line_cache[line_index]
|
||||
assert(my >= line_cache.starty)
|
||||
assert(my >= line_cache.starty, 'failed to map y pixel to line')
|
||||
-- duplicate some logic from Text.draw
|
||||
local y = line_cache.starty
|
||||
local start_screen_line_index = Text.screen_line_index(line_cache.screen_line_starting_pos, line_cache.startpos)
|
||||
|
@ -798,7 +797,7 @@ function Text.to_pos_on_line(State, line_index, mx, my)
|
|||
end
|
||||
y = nexty
|
||||
end
|
||||
assert(false)
|
||||
assert(false, 'failed to map y pixel to line')
|
||||
end
|
||||
|
||||
function Text.screen_line_width(State, line_index, i)
|
||||
|
@ -864,7 +863,7 @@ function Text.nearest_cursor_pos(line, x, left)
|
|||
leftpos = curr
|
||||
end
|
||||
end
|
||||
assert(false)
|
||||
assert(false, 'failed to map x pixel to pos')
|
||||
end
|
||||
|
||||
-- return the nearest index of line (in utf8 code points) which lies entirely
|
||||
|
@ -895,7 +894,7 @@ function Text.nearest_pos_less_than(line, x)
|
|||
left = curr
|
||||
end
|
||||
end
|
||||
assert(false)
|
||||
assert(false, 'failed to map x pixel to pos')
|
||||
end
|
||||
|
||||
function Text.x_after(s, pos)
|
||||
|
@ -926,7 +925,7 @@ function Text.to2(State, loc1)
|
|||
break
|
||||
end
|
||||
end
|
||||
assert(result.screen_pos)
|
||||
assert(result.screen_pos, 'failed to convert schema-1 coordinate to schema-2')
|
||||
return result
|
||||
end
|
||||
|
||||
|
@ -968,7 +967,7 @@ function Text.offset(s, pos1)
|
|||
if result == nil then
|
||||
print(pos1, #s, s)
|
||||
end
|
||||
assert(result)
|
||||
assert(result, "Text.offset returned nil; this is likely a failure to handle utf8")
|
||||
return result
|
||||
end
|
||||
|
||||
|
|
|
@ -36,11 +36,11 @@ end
|
|||
-- Make copies of objects; the rest of the app may mutate them in place, but undo requires immutable histories.
|
||||
function snapshot(State, s,e)
|
||||
-- Snapshot everything by default, but subset if requested.
|
||||
assert(s)
|
||||
assert(s, 'failed to snapshot operation for undo history')
|
||||
if e == nil then
|
||||
e = s
|
||||
end
|
||||
assert(#State.lines > 0)
|
||||
assert(#State.lines > 0, 'failed to snapshot operation for undo history')
|
||||
if s < 1 then s = 1 end
|
||||
if s > #State.lines then s = #State.lines end
|
||||
if e < 1 then e = 1 end
|
||||
|
@ -65,8 +65,7 @@ function snapshot(State, s,e)
|
|||
elseif line.mode == 'drawing' then
|
||||
table.insert(event.lines, {mode='drawing', h=line.h, points=deepcopy(line.points), shapes=deepcopy(line.shapes), pending={}})
|
||||
else
|
||||
print(line.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown line mode %s'):format(line.mode))
|
||||
end
|
||||
end
|
||||
return event
|
||||
|
@ -80,22 +79,22 @@ function patch(lines, from, to)
|
|||
--? lines[from.start_line] = to.lines[1]
|
||||
--? return
|
||||
--? end
|
||||
assert(from.start_line == to.start_line)
|
||||
assert(from.start_line == to.start_line, 'failed to patch undo operation')
|
||||
for i=from.end_line,from.start_line,-1 do
|
||||
table.remove(lines, i)
|
||||
end
|
||||
assert(#to.lines == to.end_line-to.start_line+1)
|
||||
assert(#to.lines == to.end_line-to.start_line+1, 'failed to patch undo operation')
|
||||
for i=1,#to.lines do
|
||||
table.insert(lines, to.start_line+i-1, to.lines[i])
|
||||
end
|
||||
end
|
||||
|
||||
function patch_placeholders(line_cache, from, to)
|
||||
assert(from.start_line == to.start_line)
|
||||
assert(from.start_line == to.start_line, 'failed to patch undo operation')
|
||||
for i=from.end_line,from.start_line,-1 do
|
||||
table.remove(line_cache, i)
|
||||
end
|
||||
assert(#to.lines == to.end_line-to.start_line+1)
|
||||
assert(#to.lines == to.end_line-to.start_line+1, 'failed to patch undo operation')
|
||||
for i=1,#to.lines do
|
||||
table.insert(line_cache, to.start_line+i-1, {})
|
||||
end
|
||||
|
|
45
text.lua
45
text.lua
|
@ -12,7 +12,7 @@ function Text.draw(State, line_index, y, startpos)
|
|||
-- wrap long lines
|
||||
local final_screen_line_starting_pos = startpos -- track value to return
|
||||
Text.populate_screen_line_starting_pos(State, line_index)
|
||||
assert(#line_cache.screen_line_starting_pos >= 1)
|
||||
assert(#line_cache.screen_line_starting_pos >= 1, 'line cache missing screen line info')
|
||||
for i=1,#line_cache.screen_line_starting_pos do
|
||||
local pos = line_cache.screen_line_starting_pos[i]
|
||||
if pos < startpos then
|
||||
|
@ -135,7 +135,7 @@ function Text.text_input(State, t)
|
|||
end
|
||||
|
||||
function Text.insert_at_cursor(State, t)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
local byte_offset = Text.offset(State.lines[State.cursor1.line].data, State.cursor1.pos)
|
||||
State.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_offset-1)..t..string.sub(State.lines[State.cursor1.line].data, byte_offset)
|
||||
Text.clear_screen_line_cache(State, State.cursor1.line)
|
||||
|
@ -212,7 +212,7 @@ function Text.keychord_press(State, chord)
|
|||
Text.redraw_all(State) -- if we're scrolling, reclaim all fragments to avoid memory leaks
|
||||
end
|
||||
Text.clear_screen_line_cache(State, State.cursor1.line)
|
||||
assert(Text.le1(State.screen_top1, State.cursor1))
|
||||
assert(Text.le1(State.screen_top1, State.cursor1), ('screen_top (line=%d,pos=%d) is below cursor (line=%d,pos=%d)'):format(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos))
|
||||
schedule_save(State)
|
||||
record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})
|
||||
elseif chord == 'delete' then
|
||||
|
@ -390,7 +390,7 @@ function Text.pagedown(State)
|
|||
end
|
||||
|
||||
function Text.up(State)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
--? print('up', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos)
|
||||
local screen_line_starting_pos, screen_line_index = Text.pos_at_start_of_screen_line(State, State.cursor1)
|
||||
if screen_line_starting_pos == 1 then
|
||||
|
@ -416,7 +416,7 @@ function Text.up(State)
|
|||
end
|
||||
else
|
||||
-- move up one screen line in current line
|
||||
assert(screen_line_index > 1)
|
||||
assert(screen_line_index > 1, 'bumped up against top screen line in line')
|
||||
local new_screen_line_starting_pos = State.line_cache[State.cursor1.line].screen_line_starting_pos[screen_line_index-1]
|
||||
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)
|
||||
|
@ -433,9 +433,9 @@ function Text.up(State)
|
|||
end
|
||||
|
||||
function Text.down(State)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
--? print('down', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
|
||||
assert(State.cursor1.pos)
|
||||
assert(State.cursor1.pos, 'cursor has no pos')
|
||||
if Text.cursor_at_final_screen_line(State) then
|
||||
-- line is done, skip to next text line
|
||||
--? print('cursor at final screen line of its line')
|
||||
|
@ -509,7 +509,7 @@ function Text.word_left(State)
|
|||
if State.cursor1.pos == 1 then
|
||||
break
|
||||
end
|
||||
assert(State.cursor1.pos > 1)
|
||||
assert(State.cursor1.pos > 1, 'bumped up against start of line')
|
||||
if Text.match(State.lines[State.cursor1.line].data, State.cursor1.pos-1, '%s') then
|
||||
break
|
||||
end
|
||||
|
@ -543,15 +543,14 @@ end
|
|||
|
||||
function Text.match(s, pos, pat)
|
||||
local start_offset = Text.offset(s, pos)
|
||||
assert(start_offset)
|
||||
local end_offset = Text.offset(s, pos+1)
|
||||
assert(end_offset > start_offset)
|
||||
assert(end_offset > start_offset, ('end_offset %d not > start_offset %d'):format(end_offset, start_offset))
|
||||
local curr = s:sub(start_offset, end_offset-1)
|
||||
return curr:match(pat)
|
||||
end
|
||||
|
||||
function Text.left(State)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
if State.cursor1.pos > 1 then
|
||||
State.cursor1.pos = State.cursor1.pos-1
|
||||
else
|
||||
|
@ -584,7 +583,7 @@ function Text.right(State)
|
|||
end
|
||||
|
||||
function Text.right_without_scroll(State)
|
||||
assert(State.lines[State.cursor1.line].mode == 'text')
|
||||
assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
|
||||
if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) then
|
||||
State.cursor1.pos = State.cursor1.pos+1
|
||||
else
|
||||
|
@ -609,7 +608,7 @@ function Text.pos_at_start_of_screen_line(State, loc1)
|
|||
return spos,i
|
||||
end
|
||||
end
|
||||
assert(false)
|
||||
assert(false, ('invalid pos %d'):format(loc1.pos))
|
||||
end
|
||||
|
||||
function Text.pos_at_end_of_screen_line(State, loc1)
|
||||
|
@ -623,7 +622,7 @@ function Text.pos_at_end_of_screen_line(State, loc1)
|
|||
end
|
||||
most_recent_final_pos = spos-1
|
||||
end
|
||||
assert(false)
|
||||
assert(false, ('invalid pos %d'):format(loc1.pos))
|
||||
end
|
||||
|
||||
function Text.cursor_at_final_screen_line(State)
|
||||
|
@ -648,7 +647,7 @@ function Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necess
|
|||
end
|
||||
-- hack: insert a text line at bottom of file if necessary
|
||||
if State.cursor1.line > #State.lines then
|
||||
assert(State.cursor1.line == #State.lines+1)
|
||||
assert(State.cursor1.line == #State.lines+1, 'tried to ensure bottom line of file is text, but failed')
|
||||
table.insert(State.lines, {mode='text', data=''})
|
||||
table.insert(State.line_cache, {})
|
||||
end
|
||||
|
@ -680,8 +679,8 @@ function Text.snap_cursor_to_bottom_of_screen(State)
|
|||
end
|
||||
y = y - h
|
||||
else
|
||||
assert(top2.line > 1)
|
||||
assert(State.lines[top2.line-1].mode == 'drawing')
|
||||
assert(top2.line > 1, 'tried to snap cursor to buttom of screen but failed')
|
||||
assert(State.lines[top2.line-1].mode == 'drawing', "expected a drawing but it's not")
|
||||
-- We currently can't draw partial drawings, so either skip it entirely
|
||||
-- or not at all.
|
||||
local h = Drawing_padding_height + Drawing.pixels(State.lines[top2.line-1].h, State.width)
|
||||
|
@ -713,7 +712,7 @@ end
|
|||
function Text.to_pos_on_line(State, line_index, mx, my)
|
||||
local line = State.lines[line_index]
|
||||
local line_cache = State.line_cache[line_index]
|
||||
assert(my >= line_cache.starty)
|
||||
assert(my >= line_cache.starty, 'failed to map y pixel to line')
|
||||
-- duplicate some logic from Text.draw
|
||||
local y = line_cache.starty
|
||||
local start_screen_line_index = Text.screen_line_index(line_cache.screen_line_starting_pos, line_cache.startpos)
|
||||
|
@ -736,7 +735,7 @@ function Text.to_pos_on_line(State, line_index, mx, my)
|
|||
end
|
||||
y = nexty
|
||||
end
|
||||
assert(false)
|
||||
assert(false, 'failed to map y pixel to line')
|
||||
end
|
||||
|
||||
function Text.screen_line_width(State, line_index, i)
|
||||
|
@ -802,7 +801,7 @@ function Text.nearest_cursor_pos(line, x, left)
|
|||
leftpos = curr
|
||||
end
|
||||
end
|
||||
assert(false)
|
||||
assert(false, 'failed to map x pixel to pos')
|
||||
end
|
||||
|
||||
-- return the nearest index of line (in utf8 code points) which lies entirely
|
||||
|
@ -833,7 +832,7 @@ function Text.nearest_pos_less_than(line, x)
|
|||
left = curr
|
||||
end
|
||||
end
|
||||
assert(false)
|
||||
assert(false, 'failed to map x pixel to pos')
|
||||
end
|
||||
|
||||
function Text.x_after(s, pos)
|
||||
|
@ -864,7 +863,7 @@ function Text.to2(State, loc1)
|
|||
break
|
||||
end
|
||||
end
|
||||
assert(result.screen_pos)
|
||||
assert(result.screen_pos, 'failed to convert schema-1 coordinate to schema-2')
|
||||
return result
|
||||
end
|
||||
|
||||
|
@ -906,7 +905,7 @@ function Text.offset(s, pos1)
|
|||
if result == nil then
|
||||
print(pos1, #s, s)
|
||||
end
|
||||
assert(result)
|
||||
assert(result, "Text.offset returned nil; this is likely a failure to handle utf8")
|
||||
return result
|
||||
end
|
||||
|
||||
|
|
14
undo.lua
14
undo.lua
|
@ -36,11 +36,11 @@ end
|
|||
-- Make copies of objects; the rest of the app may mutate them in place, but undo requires immutable histories.
|
||||
function snapshot(State, s,e)
|
||||
-- Snapshot everything by default, but subset if requested.
|
||||
assert(s)
|
||||
assert(s, 'failed to snapshot operation for undo history')
|
||||
if e == nil then
|
||||
e = s
|
||||
end
|
||||
assert(#State.lines > 0)
|
||||
assert(#State.lines > 0, 'failed to snapshot operation for undo history')
|
||||
if s < 1 then s = 1 end
|
||||
if s > #State.lines then s = #State.lines end
|
||||
if e < 1 then e = 1 end
|
||||
|
@ -66,7 +66,7 @@ function snapshot(State, s,e)
|
|||
table.insert(event.lines, {mode='drawing', h=line.h, points=deepcopy(line.points), shapes=deepcopy(line.shapes), pending={}})
|
||||
else
|
||||
print(line.mode)
|
||||
assert(false)
|
||||
assert(false, ('unknown line mode %s'):format(line.mode))
|
||||
end
|
||||
end
|
||||
return event
|
||||
|
@ -80,22 +80,22 @@ function patch(lines, from, to)
|
|||
--? lines[from.start_line] = to.lines[1]
|
||||
--? return
|
||||
--? end
|
||||
assert(from.start_line == to.start_line)
|
||||
assert(from.start_line == to.start_line, 'failed to patch undo operation')
|
||||
for i=from.end_line,from.start_line,-1 do
|
||||
table.remove(lines, i)
|
||||
end
|
||||
assert(#to.lines == to.end_line-to.start_line+1)
|
||||
assert(#to.lines == to.end_line-to.start_line+1, 'failed to patch undo operation')
|
||||
for i=1,#to.lines do
|
||||
table.insert(lines, to.start_line+i-1, to.lines[i])
|
||||
end
|
||||
end
|
||||
|
||||
function patch_placeholders(line_cache, from, to)
|
||||
assert(from.start_line == to.start_line)
|
||||
assert(from.start_line == to.start_line, 'failed to patch undo operation')
|
||||
for i=from.end_line,from.start_line,-1 do
|
||||
table.remove(line_cache, i)
|
||||
end
|
||||
assert(#to.lines == to.end_line-to.start_line+1)
|
||||
assert(#to.lines == to.end_line-to.start_line+1, 'failed to patch undo operation')
|
||||
for i=1,#to.lines do
|
||||
table.insert(line_cache, to.start_line+i-1, {})
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue