resolve conflicts

akkartik
Nov 18, 2023, 8:26 PM
KKQKPGCIHAG2JESQAWEMCBTAKBDC5AVIQ6LCZ2ORQM2AUCFQYLSQC

Dependencies

  • [2] 44BTGR7U Merge lines.love
  • [3] WB6SIB7H Merge lines.love
  • [4] 7YGYHOEO Merge lines.love
  • [5] TBTRYEBP Merge lines.love
  • [6] G3DLS5OU audit all asserts
  • [7] 6K5PFF6X helper: trimming whitespace from strings
  • [8] 4EGQRXDA bugfix: naming points
  • [9] W6XUYQKP source: show files in MRU order
  • [10] MGJZHZC4 Merge lines.love
  • [11] 2XLZCWZC bugfix: rectangles and squares are now saved
  • [12] WJBZZQE4 fold together two largely similar cases
  • [13] NFI42KGX more correct absolute path detection
  • [14] 2344TV56 Merge lines.love
  • [15] ED4Z6ORC cleaner API for file-system access
  • [16] KWIVKQQ7 Merge lines.love
  • [17] QYIFOHW3 first test!
  • [18] 3PSFWAIL Merge lines.love
  • [19] AIBA4RWQ hide cursor in log browser window
  • [20] BYG5CEMV support for naming points
  • [21] ZTK4QTZT extract a couple of functions
  • [22] MDXGMZU2 disable all debug prints
  • [23] ONHKBLLC Merge lines.love
  • [24] IFTYOERM line.y -> line_cache.starty in a few more places
  • [25] ZLJYLPOT Merge lines.love
  • [26] 62PZGSUC optimization: moving cursor to next word
  • [27] KECEMMMR extract couple of functions
  • [28] 4KC7I3E2 make colors easier to edit
  • [29] ATQO62TF Merge lines.love
  • [30] R3KXFRZN get rid of to_text
  • [31] MD3W5IRA new fork: rip out drawing support
  • [32] 2WGRQI5E missing shape modes in a couple more places
  • [33] K2X6G75Z start writing some tests for drawings
  • [34] 2CK5QI7W make love event names consistent
  • [35] LSYLEVBD drop some redundant args when clearing the cache
  • [36] 65HNIAOS make freehand drawings smoother
  • [37] 3HVBAZPA add state arg to a few functions
  • [38] KKMFQDR4 editing source code from within the app
  • [39] LDFXFRUO bring a few things in sync between run and source
  • [40] C3NYQP57 Merge lines.love
  • [41] OGUV4HSA remove some memory leaks from rendered fragments
  • [42] LWPFEZBI Merge lines.love
  • [43] ORKN6EOB Merge lines.love
  • [44] VHUNJHXB Merge lines.love
  • [45] MUJTM6RE bring back a level of wrapping
  • [46] KTZQ57HV replace globals with args in a few functions
  • [47] KKHSOUW4 bugfix: drawings in source editor
  • [48] TGZAJUEF bring back a set of constants
  • [49] OI4FPFIN support drawings in the source editor
  • [50] TLOAPLBJ add a license
  • [51] VJ77YABH more efficient undo/redo
  • [52] RT6EV6OP delegate update events to drawings
  • [53] 242L3OQX bugfix: ensure Cursor_line is always on a text line
  • [54] BJ5X5O4A let's prevent the text cursor from ever getting on a drawing
  • [55] ILOA5BYF separate data structure for each line's cache data
  • [56] CE4LZV4T drop last couple of manual tests
  • [57] 3OTESDW6 move drawing.starty into line cache
  • [58] F65ADDGL add state arg to a few functions
  • [59] 4VQGE7RA new test
  • [60] LK4ZW4BB bugfix
  • [61] 2TQUKHBC Merge lines.love
  • [62] BULPIBEG beginnings of a module for the text editor
  • [63] QCPXQ2E3 add state arg to a few functions
  • [64] G54H3YG2 get rid of all bifold text
  • [65] 5SM6DRHK port inscript's bugfix to source editor
  • [66] LIKTH6HM update stale source X-(
  • [67] JDZVBFEI Merge lines.love
  • [68] KOYAJWE4 extract a couple more methods
  • [69] YXQOITYS Merge lines.love
  • [70] KV7GGVER couple of accidental globals
  • [71] MXSAHZN4 Merge lines.love
  • [72] 4YDBYBA4 clean up memory leak experiments
  • [73] 2LEXWUW3 get rid of some ridiculous code
  • [74] O7QH4N4W speeding up copy, attempt 1
  • [75] KMSL74GA support selections in the source editor
  • [76] VDJSUX2Q typos
  • [77] S2MISTTM add state arg to a few functions
  • [78] R5QXEHUI somebody stop me
  • [79] CNCYMM6A make test initializations a little more obvious
  • [80] VP5KC4XZ Merge lines.love
  • [81] BLWAYPKV extract a module
  • [82] GGWAHCLE minor cleanup and a todo for later
  • [83] JOPVPUSA editing source code from within the app
  • [84] TVCPXAAU rename
  • [85] YF2ATH2Q Merge lines.love
  • [86] 5BMR5HRT click to the left of a line
  • [87] PLKNHYZ4 extract a function
  • [88] KYNGDE2C consistent names in a few more places
  • [89] DLQAEAC7 add state arg to Drawing.mouse_pressed
  • [90] BJ2C6F2B ignore 'name' mode in a few places
  • [91] LXTTOB33 extract a couple of files
  • [92] 3OKKTUT4 up and down arrow now moving by screen line where possible
  • [93] REAIVN7W Merge lines.love
  • [94] ISOFHXB2 App.width can no longer take a Text
  • [95] EHSUSZMK more idiomatic variable names
  • [96] D4B52CQ2 Merge lines.love
  • [97] AYX33NBC Merge lines.love
  • [98] RU4HIK43 Merge lines.love
  • [99] B4JEWKWI hide editor cursor while in file navigator
  • [100] VDFARWQX remove some support for long lines from source editor
  • [101] YCDYGEZU include drawing index in a few places
  • [102] VXORMHME delete experimental REPL
  • [103] SGMA5JLE save the list of tests in repo
  • [104] T4FRZSYL delete an ancient, unused file
  • [105] YTSPVDZH first successful pagedown test, first bug found by test
  • [106] LF7BWEG4 group all editor globals
  • [107] 3XNFQDDN Merge lines.love
  • [108] NYQ7HD4D move
  • [109] 4CTZOJPC stop pretending globals are local
  • [110] HYEAFRZ2 split mouse_pressed events between Text and Drawing
  • [111] OTIBCAUJ love2d scaffold
  • [112] 2RXZ3PGO beginning of a new approach to scroll+wrap
  • [113] AVTNUQYR basic test-enabled framework
  • [114] TGHAJBES use line cache for drawings as well
  • [115] N2NUGNN4 include a brief reference enabling many useful apps
  • [116] MU2HIRR6 Merge lines.love
  • [117] 2ZYV7D3W handle tab characters
  • [118] Z5HLXU4P add state arg to a few functions
  • [119] 3QNOKBFM beginnings of a test harness
  • [120] ZPUQSPQP extract a few methods
  • [121] PXSQR2AD hide line numbers from log browser
  • [122] 6DE7RBZ6 move mouse_released events to Drawing
  • [123] 66X36NZN a little more prose describing manual_tests
  • [124] 4SR3Z4Y3 document the version of LÖVE I've been using
  • [125] 2K2YDMFH ignore 'deleted' shapes when saving to disk
  • [126] TRNWIQN6 more precise height calculation when scrolling up as much as possible while keeping cursor on screen
  • [127] RSZD5A7G forgot to add json.lua
  • [128] WTDKUACN rectangle and square shapes
  • [129] VBU5YHLR Merge lines.love
  • [130] UZVWYRTY missing temporary modes in a couple more places
  • [131] SRVDX4I5 local var
  • [132] 6LJZN727 handle chords
  • [133] GZ5WULJV switch source side to new screen-line-based render
  • [134] FS2ITYYH record a known issue
  • [135] MXA3RZYK deduce left/right from state where possible
  • [136] LNUHQOGH start passing in Editor_state explicitly
  • [137] CWQIPU7U always show line numbers in source editor
  • [138] SR4C3ZYZ add an assert
  • [139] 2CTN2IEF Merge lines.love
  • [140] XX7G2FFJ intermingle freehand line drawings with text
  • [141] 4PHGNJN6 assume starty can be nil in update
  • [142] F63Q4OV7 several bugfixes
  • [143] 6VJTQKW7 start supporting LÖVE v12
  • [144] TACI4LU6 Merge lines.love
  • [145] XNFTJHC4 split keyboard handling between Text and Drawing
  • [146] 2L5MEZV3 experiment: new edit namespace
  • [147] ELJNEPW2 simplify cursor-on-screen check
  • [148] NQM25OZV reduce use of rfind
  • [149] VHQCNMAR several more modules
  • [150] 34BZ5ZKN Merge lines.love
  • [151] PP2IIHL6 stop putting button state in a global
  • [152] B4FAIVRA Merge lines.love
  • [153] D2GCFTTT clean up repl functionality
  • [154] V3EABA35 skip multiple consecutive whitespace
  • [155] R2ASHK5C fix a bad merge
  • [156] 73OCE2MC after much struggle, a brute-force undo

Change contents

  • file deletion: geom.lua (----------)
    [7.2][7.37186:37218](),[7.37218][7.32720:32720]()
    geom = {}
    function geom.on_shape(x,y, drawing, shape)
    if shape.mode == 'freehand' then
    return geom.on_freehand(x,y, drawing, shape)
    elseif shape.mode == 'line' then
    return geom.on_line(x,y, drawing, shape)
    elseif shape.mode == 'manhattan' then
    local p1 = drawing.points[shape.p1]
    local p2 = drawing.points[shape.p2]
    if p1.x == p2.x then
    if x ~= p1.x then return false end
    local y1,y2 = p1.y, p2.y
    if y1 > y2 then
    y1,y2 = y2,y1
    end
    return y >= y1-2 and y <= y2+2
    elseif p1.y == p2.y then
    if y ~= p1.y then return false end
    local x1,x2 = p1.x, p2.x
    if x1 > x2 then
    x1,x2 = x2,x1
    end
    return x >= x1-2 and x <= x2+2
    end
    elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
    return geom.on_polygon(x,y, drawing, shape)
    elseif shape.mode == 'circle' then
    local center = drawing.points[shape.center]
    local dist = geom.dist(center.x,center.y, x,y)
    return dist > shape.radius*0.95 and dist < shape.radius*1.05
    elseif shape.mode == 'arc' then
    local center = drawing.points[shape.center]
    local dist = geom.dist(center.x,center.y, x,y)
    if dist < shape.radius*0.95 or dist > shape.radius*1.05 then
    return false
    end
    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)
    end
    end
    function geom.on_freehand(x,y, drawing, shape)
    local prev
    for _,p in ipairs(shape.points) do
    if prev then
    if geom.on_line(x,y, drawing, {p1=prev, p2=p}) then
    return true
    end
    end
    prev = p
    end
    return false
    end
    function geom.on_line(x,y, drawing, shape)
    local p1,p2
    if type(shape.p1) == 'number' then
    p1 = drawing.points[shape.p1]
    p2 = drawing.points[shape.p2]
    else
    p1 = shape.p1
    p2 = shape.p2
    end
    if p1.x == p2.x then
    if math.abs(p1.x-x) > 2 then
    return false
    end
    local y1,y2 = p1.y,p2.y
    if y1 > y2 then
    y1,y2 = y2,y1
    end
    return y >= y1-2 and y <= y2+2
    end
    -- has the right slope and intercept
    local m = (p2.y - p1.y) / (p2.x - p1.x)
    local yp = p1.y + m*(x-p1.x)
    if yp < y-2 or yp > y+2 then
    return false
    end
    -- between endpoints
    local k = (x-p1.x) / (p2.x-p1.x)
    return k > -0.005 and k < 1.005
    end
    function geom.on_polygon(x,y, drawing, shape)
    local prev
    for _,p in ipairs(shape.vertices) do
    if prev then
    if geom.on_line(x,y, drawing, {p1=prev, p2=p}) then
    return true
    end
    end
    prev = p
    end
    return geom.on_line(x,y, drawing, {p1=shape.vertices[1], p2=shape.vertices[#shape.vertices]})
    end
    -- are (x3,y3) and (x4,y4) on the same side of the line between (x1,y1) and (x2,y2)
    function geom.same_side(x1,y1, x2,y2, x3,y3, x4,y4)
    if x1 == x2 then
    return math.sign(x3-x1) == math.sign(x4-x1)
    end
    if y1 == y2 then
    return math.sign(y3-y1) == math.sign(y4-y1)
    end
    local m = (y2-y1)/(x2-x1)
    return math.sign(m*(x3-x1) + y1-y3) == math.sign(m*(x4-x1) + y1-y4)
    end
    function math.sign(x)
    if x > 0 then
    return 1
    elseif x == 0 then
    return 0
    elseif x < 0 then
    return -1
    end
    end
    function geom.angle_with_hint(x1, y1, x2, y2, hint)
    local result = geom.angle(x1,y1, x2,y2)
    if hint then
    -- Smooth the discontinuity where angle goes from positive to negative.
    -- The hint is a memory of which way we drew it last time.
    while result > hint+math.pi/10 do
    result = result-math.pi*2
    end
    while result < hint-math.pi/10 do
    result = result+math.pi*2
    end
    end
    return result
    end
    -- result is from -π/2 to 3π/2, approximately adding math.atan2 from Lua 5.3
    -- (LÖVE is Lua 5.1)
    function geom.angle(x1,y1, x2,y2)
    local result = math.atan((y2-y1)/(x2-x1))
    if x2 < x1 then
    result = result+math.pi
    end
    return result
    end
    -- is the line between x,y and cx,cy at an angle between s and e?
    function geom.angle_between(ox,oy, x,y, s,e)
    local angle = geom.angle(ox,oy, x,y)
    if s > e then
    s,e = e,s
    end
    -- I'm not sure this is right or ideal..
    angle = angle-math.pi*2
    if s <= angle and angle <= e then
    return true
    end
    angle = angle+math.pi*2
    if s <= angle and angle <= e then
    return true
    end
    angle = angle+math.pi*2
    return s <= angle and angle <= e
    end
    function geom.dist(x1,y1, x2,y2) return ((x2-x1)^2+(y2-y1)^2)^0.5 end
  • file deletion: source_undo.lua (----------)source_undo.lua (----------)
    [7.2][7.3457:3496](),[7.2][7.3457:3496](),[7.3496][7.5:5]()
    assert(s, 'failed to snapshot operation for undo history')
    assert(#State.lines > 0, 'failed to snapshot operation for undo history')
    assert(false, ('unknown line mode %s'):format(line.mode))
    assert(from.start_line == to.start_line, 'failed to patch undo operation')
    assert(#to.lines == to.end_line-to.start_line+1, 'failed to patch undo operation')
    assert(from.start_line == to.start_line, 'failed to patch undo operation')
    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
    end
    -- https://stackoverflow.com/questions/640642/how-do-you-copy-a-lua-table-by-value/26367080#26367080
    function deepcopy(obj, seen)
    if type(obj) ~= 'table' then return obj end
    if seen and seen[obj] then return seen[obj] end
    local s = seen or {}
    local result = setmetatable({}, getmetatable(obj))
    s[obj] = result
    for k,v in pairs(obj) do
    result[deepcopy(k, s)] = deepcopy(v, s)
    end
    return result
    end
    function minmax(a, b)
    return math.min(a,b), math.max(a,b)
    end
    for i=from.end_line,from.start_line,-1 do
    table.remove(line_cache, i)
    end
    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)
    for i=from.end_line,from.start_line,-1 do
    table.remove(lines, i)
    end
    end
    if s < 1 then s = 1 end
    if s > #State.lines then s = #State.lines end
    if e < 1 then e = 1 end
    if e > #State.lines then e = #State.lines end
    -- compare with App.initialize_globals
    local event = {
    screen_top=deepcopy(State.screen_top1),
    selection=deepcopy(State.selection1),
    cursor=deepcopy(State.cursor1),
    if e == nil then
    e = s
    end
  • file deletion: source_text.lua (----------)source_text.lua (----------)
    [7.2][7.147062:147101](),[7.2][7.147062:147101](),[7.147101][7.83723:83723]()
    assert(#line_cache.screen_line_starting_pos >= 1, 'line cache missing screen line info')
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
    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))
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
    assert(screen_line_index > 1, 'bumped up against top screen line in line')
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
    assert(State.cursor1.pos, 'cursor has no pos')
    assert(State.cursor1.pos > 1, 'bumped up against start of line')
    assert(end_offset > start_offset, ('end_offset %d not > start_offset %d'):format(end_offset, start_offset))
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
    assert(false, ('invalid pos %d'):format(loc1.pos))
    assert(false, ('invalid pos %d'):format(loc1.pos))
    assert(State.cursor1.line == #State.lines+1, 'tried to ensure bottom line of file is text, but failed')
    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")
    assert(my >= line_cache.starty, 'failed to map y pixel to line')
    assert(false, 'failed to map y pixel to line')
    assert(false, 'failed to map x pixel to pos')
    assert(false, 'failed to map x pixel to pos')
    assert(result.screen_pos, 'failed to convert schema-1 coordinate to schema-2')
    assert(result, "Text.offset returned nil; this is likely a failure to handle utf8")
    return result
    end
    function Text.previous_screen_line(State, loc2)
    return result
    end
    function Text.to1(State, loc2)
    end
    function Text.x_after(s, pos)
    local offset = Text.offset(s, math.min(pos+1, #s+1))
    local s_before = s:sub(1, offset-1)
    --? print('^'..s_before..'$')
    end
    -- return the nearest index of line (in utf8 code points) which lies entirely
    -- within x pixels of the left margin
    -- result: 0 to len+1
    function Text.nearest_pos_less_than(line, x)
    --? print('', '-- nearest_pos_less_than', line, x)
    local len = utf8.len(line)
    local max_x = Text.x_after(line, len)
    if x > max_x then
    return len+1
    end
    local left, right = 0, len+1
    while true do
    local curr = math.floor((left+right)/2)
    local currxmin = Text.x_after(line, curr+1)
    local currxmax = Text.x_after(line, curr+2)
    --? print('', x, left, right, curr, currxmin, currxmax)
    if currxmin <= x and x < currxmax then
    return curr
    end
    if left >= right-1 then
    return left
    end
    if currxmin > x then
    right = curr
    else
    left = curr
    end
    end
    end
    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.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.data, past_end_pos)
    screen_line = string.sub(line.data, start_offset, past_end_offset-1)
    else
    screen_line = string.sub(line.data, start_pos)
    end
    -- duplicate some logic from Text.draw
    local y = line_cache.starty
    -- 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)
    if y - h < State.top then
    break
    end
    --? print('skipping drawing of height', h)
    y = y - h
    table.insert(State.lines, {mode='text', data=''})
    table.insert(State.line_cache, {})
    end
    --? print(y, App.screen.height, App.screen.height-State.line_height)
    if y > App.screen.height - State.line_height then
    end
    end
    if State.cursor1.pos <= utf8.len(State.lines[State.cursor1.line].data) then
    State.cursor1.pos = State.cursor1.pos+1
    if State.cursor1.pos > 1 then
    State.cursor1.pos = State.cursor1.pos-1
    local curr = s:sub(start_offset, end_offset-1)
    return curr:match(pat)
    end
    function Text.left(State)
    if Text.match(State.lines[State.cursor1.line].data, State.cursor1.pos-1, '%s') then
    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')
    --? print('down', State.cursor1.line, State.cursor1.pos, State.screen_top1.line, State.screen_top1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
    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)
    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
    if Text.lt1(State.cursor1, State.screen_top1) then
    --? 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
    --? print('cursor is at first screen line of its line')
    -- line is done; skip to previous text line
    schedule_save(State)
    record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})
    elseif chord == 'delete' then
    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
    for i=1,#line_cache.screen_line_starting_pos do
    local pos = line_cache.screen_line_starting_pos[i]
  • file deletion: source_file.lua (----------)source_file.lua (----------)
    [7.2][7.152399:152438](),[7.2][7.152399:152438](),[7.152438][7.150241:150241]()
    assert(line, 'drawing in file is incomplete')
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
    assert(i, 'drawing in array is incomplete')
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
    end
    table.insert(drawing.shapes, shape)
    end
    return i, drawing
    end
    --? print(i)
    if line == '```' then break end
    local shape = json.decode(line)
    if shape.mode == 'freehand' then
    -- no changes needed
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local name = shape.p1.name
    shape.p1 = Drawing.find_or_insert_point(drawing.points, shape.p1.x, shape.p1.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.p1].name = name
    name = shape.p2.name
    shape.p2 = Drawing.find_or_insert_point(drawing.points, shape.p2.x, shape.p2.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.p2].name = name
    elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
    for i,p in ipairs(shape.vertices) do
    local name = p.name
    shape.vertices[i] = Drawing.find_or_insert_point(drawing.points, p.x,p.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.vertices[i]].name = name
    end
    elseif shape.mode == 'circle' or shape.mode == 'arc' then
    local name = shape.center.name
    shape.center = Drawing.find_or_insert_point(drawing.points, shape.center.x,shape.center.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.center].name = name
    elseif shape.mode == 'deleted' then
    -- ignore
    else
    end
    end
    outfile:write('```\n')
    end
    table.insert(drawing.shapes, shape)
    end
    return drawing
    end
    function store_drawing(outfile, drawing)
    outfile:write('```lines\n')
    for _,shape in ipairs(drawing.shapes) do
    if shape.mode == 'freehand' then
    if line == '```' then break end
    local shape = json.decode(line)
    if shape.mode == 'freehand' then
    -- no changes needed
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local name = shape.p1.name
    shape.p1 = Drawing.find_or_insert_point(drawing.points, shape.p1.x, shape.p1.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.p1].name = name
    name = shape.p2.name
    shape.p2 = Drawing.find_or_insert_point(drawing.points, shape.p2.x, shape.p2.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.p2].name = name
    elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
    for i,p in ipairs(shape.vertices) do
    local name = p.name
    shape.vertices[i] = Drawing.find_or_insert_point(drawing.points, p.x,p.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.vertices[i]].name = name
    end
    elseif shape.mode == 'circle' or shape.mode == 'arc' then
    local name = shape.center.name
    shape.center = Drawing.find_or_insert_point(drawing.points, shape.center.x,shape.center.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.center].name = name
    elseif shape.mode == 'deleted' then
    -- ignore
    else
  • file deletion: source_edit.lua (----------)source_edit.lua (----------)
    [7.2][7.165725:165764](),[7.2][7.165725:165764](),[7.165764][7.152440:152440]()
    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))
    assert(false, ('unknown line mode %s'):format(line.mode))
    end
    State.cursor_x = nil
    State.cursor_y = nil
    local y = State.top
  • file deletion: log_browser.lua (----------)log_browser.lua (----------)
    [7.2][7.203223:203262](),[7.2][7.203223:203262](),[7.203262][7.191782:191782]()
    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))
    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)
    love.graphics.line(xleft,sectiony, xleft+50-2,sectiony)
    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
    App.color(Text_color)
    local line = State.lines[line_index]
    if y + State.line_height > App.screen.height then break end
    local height = State.line_height
    if should_show(line) then
    local xleft = render_stack_left_margin(State, line_index, line, y)
    local xright = render_stack_right_margin(State, line_index, line, y)
    if line.section_name then
    App.color(Section_border_color)
  • file deletion: commands.lua (----------)commands.lua (----------)
    [7.2][7.207726:207762](),[7.2][7.207726:207762](),[7.207762][7.204370:204370]()
    assert(index, 'file missing from manifest')
    table.remove(File_navigation.all_candidates, index)
    table.insert(File_navigation.all_candidates, 1, s)
  • edit in undo.lua at line 62
    [7.2268][6.139:203](),[7.2268][6.139:203]()
    assert(false, ('unknown line mode %s'):format(line.mode))
  • resolve order conflict in undo.lua at line 62
    [7.102]
    [7.2296]
  • edit in text.lua at line 380
    [7.816][6.917:994]()
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • resurrect zombie in text.lua at line 401
    [7.1956][2.3:127](),[7.1956][2.3:127]()
    local new_screen_line_starting_pos = State.line_cache[State.cursor1.line].screen_line_starting_pos[screen_line_index-1]
  • edit in text.lua at line 401
    [7.1858]
    [2.3]
    assert(screen_line_index > 1, 'bumped up against top screen line in line')
  • edit in text.lua at line 405
    [7.4427][2.129:129](),[7.1858][6.995:1074](),[7.1858][6.995:1074]()
    assert(screen_line_index > 1, 'bumped up against top screen line in line')
  • resolve order conflict in text.lua at line 405
    [7.4427]
    [7.1139]
  • edit in text.lua at line 418
    [7.1280][6.1075:1152]()
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • resurrect zombie in text.lua at line 487
    [7.8150][7.4939:5027](),[7.8150][7.4939:5027]()
    if Text.match(State.lines[State.cursor1.line].data, State.cursor1.pos-1, '%s') then
  • edit in text.lua at line 487
    [7.1135]
    [7.4939]
    assert(State.cursor1.pos > 1, 'bumped up against start of line')
  • edit in text.lua at line 489
    [7.1135][6.1203:1272](),[7.1135][6.1203:1272]()
    assert(State.cursor1.pos > 1, 'bumped up against start of line')
  • resolve order conflict in text.lua at line 489
    [7.5027]
    [7.5221]
  • edit in text.lua at line 528
    [7.2106][6.1384:1461]()
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • edit in text.lua at line 552
    [7.823][6.1462:1539](),[7.823][6.1462:1539]()
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • resolve order conflict in text.lua at line 552
    [7.5516]
    [7.958]
  • edit in text.lua at line 595
    [7.6899][7.4:4](),[7.2634][6.1648:1756](),[7.2634][6.1648:1756]()
    assert(State.cursor1.line == #State.lines+1, 'tried to ensure bottom line of file is text, but failed')
  • resolve order conflict in text.lua at line 595
    [7.6899]
    [7.1554]
  • edit in text.lua at line 617
    [7.776][6.1757:1932](),[7.776][6.1757:1932]()
    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")
  • resolve order conflict in text.lua at line 617
    [7.6974]
    [7.875]
  • edit in text.lua at line 942
    [7.442][7.59:59](),[7.79][6.624:701](),[7.79][6.624:701]()
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • resolve order conflict in text.lua at line 942
    [7.442]
  • replacement in source_undo.lua at line 39
    [7.1447][7.1447:1459]()
    assert(s)
    [7.1447]
    [7.1459]
    assert(s, 'failed to snapshot operation for undo history')
  • replacement in source_undo.lua at line 43
    [7.1494][7.1494:1521]()
    assert(#State.lines > 0)
    [7.1494]
    [7.1521]
    assert(#State.lines > 0, 'failed to snapshot operation for undo history')
  • replacement in source_undo.lua at line 68
    [7.759][7.759:802]()
    print(line.mode)
    assert(false)
    [7.759]
    [7.802]
    assert(false, ('unknown line mode %s'):format(line.mode))
  • replacement in source_undo.lua at line 82
    [7.2464][7.2464:2507]()
    assert(from.start_line == to.start_line)
    [7.2464]
    [7.2507]
    assert(from.start_line == to.start_line, 'failed to patch undo operation')
  • replacement in source_undo.lua at line 86
    [7.2584][7.2584:2635]()
    assert(#to.lines == to.end_line-to.start_line+1)
    [7.2584]
    [7.2635]
    assert(#to.lines == to.end_line-to.start_line+1, 'failed to patch undo operation')
  • replacement in source_undo.lua at line 93
    [7.2775][7.2775:2818]()
    assert(from.start_line == to.start_line)
    [7.2775]
    [7.2818]
    assert(from.start_line == to.start_line, 'failed to patch undo operation')
  • replacement in source_undo.lua at line 97
    [7.2900][7.2900:2951]()
    assert(#to.lines == to.end_line-to.start_line+1)
    [7.2900]
    [7.2951]
    assert(#to.lines == to.end_line-to.start_line+1, 'failed to patch undo operation')
  • replacement in source_text.lua at line 20
    [7.87493][7.255:307]()
    assert(#line_cache.screen_line_starting_pos >= 1)
    [7.87493]
    [7.307]
    assert(#line_cache.screen_line_starting_pos >= 1, 'line cache missing screen line info')
  • replacement in source_text.lua at line 212
    [7.97898][7.7:64]()
    assert(State.lines[State.cursor1.line].mode == 'text')
    [7.97898]
    [7.1487]
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • replacement in source_text.lua at line 289
    [7.102919][7.102919:102974]()
    assert(Text.le1(State.screen_top1, State.cursor1))
    [7.102919]
    [7.102974]
    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))
  • replacement in source_text.lua at line 455
    [7.109190][7.5440:5497]()
    assert(State.lines[State.cursor1.line].mode == 'text')
    [7.109190]
    [7.109301]
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • replacement in source_text.lua at line 481
    [7.110604][7.110604:110638]()
    assert(screen_line_index > 1)
    [7.110604]
    [7.110638]
    assert(screen_line_index > 1, 'bumped up against top screen line in line')
  • replacement in source_text.lua at line 498
    [7.114899][7.7470:7527]()
    assert(State.lines[State.cursor1.line].mode == 'text')
    [7.114899]
    [7.114899]
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • replacement in source_text.lua at line 500
    [7.115058][7.7:35]()
    assert(State.cursor1.pos)
    [7.115058]
    [7.115058]
    assert(State.cursor1.pos, 'cursor has no pos')
  • replacement in source_text.lua at line 574
    [7.120443][7.120443:120477]()
    assert(State.cursor1.pos > 1)
    [7.120443]
    [7.120477]
    assert(State.cursor1.pos > 1, 'bumped up against start of line')
  • edit in source_text.lua at line 608
    [7.122603][7.122603:122626]()
    assert(start_offset)
  • replacement in source_text.lua at line 609
    [7.122669][7.122669:122705]()
    assert(end_offset > start_offset)
    [7.122669]
    [7.122705]
    assert(end_offset > start_offset, ('end_offset %d not > start_offset %d'):format(end_offset, start_offset))
  • replacement in source_text.lua at line 615
    [7.122810][7.4694:4751]()
    assert(State.lines[State.cursor1.line].mode == 'text')
    [7.122810]
    [7.122927]
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • replacement in source_text.lua at line 648
    [7.124061][7.8418:8475]()
    assert(State.lines[State.cursor1.line].mode == 'text')
    [7.124061]
    [7.124226]
    assert(State.lines[State.cursor1.line].mode == 'text', 'line is not text')
  • replacement in source_text.lua at line 673
    [7.125663][7.125663:125679]()
    assert(false)
    [7.125663]
    [7.125679]
    assert(false, ('invalid pos %d'):format(loc1.pos))
  • replacement in source_text.lua at line 687
    [7.4230][7.4230:4246]()
    assert(false)
    [7.4230]
    [7.4246]
    assert(false, ('invalid pos %d'):format(loc1.pos))
  • replacement in source_text.lua at line 712
    [7.9509][7.9509:9558]()
    assert(State.cursor1.line == #State.lines+1)
    [7.9509]
    [7.9558]
    assert(State.cursor1.line == #State.lines+1, 'tried to ensure bottom line of file is text, but failed')
  • replacement in source_text.lua at line 744
    [7.9972][7.9972:10057]()
    assert(top2.line > 1)
    assert(State.lines[top2.line-1].mode == 'drawing')
    [7.9972]
    [7.10057]
    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")
  • replacement in source_text.lua at line 777
    [7.130948][7.130948:130982]()
    assert(my >= line_cache.starty)
    [7.130948]
    [7.130982]
    assert(my >= line_cache.starty, 'failed to map y pixel to line')
  • replacement in source_text.lua at line 800
    [7.135420][7.135420:135436]()
    assert(false)
    [7.135420]
    [7.135436]
    assert(false, 'failed to map y pixel to line')
  • replacement in source_text.lua at line 866
    [7.138612][7.138612:138628]()
    assert(false)
    [7.138612]
    [7.138628]
    assert(false, 'failed to map x pixel to pos')
  • replacement in source_text.lua at line 897
    [7.139436][7.139436:139452]()
    assert(false)
    [7.139436]
    [7.139452]
    assert(false, 'failed to map x pixel to pos')
  • replacement in source_text.lua at line 928
    [7.140472][7.140472:140500]()
    assert(result.screen_pos)
    [7.140472]
    [7.141153]
    assert(result.screen_pos, 'failed to convert schema-1 coordinate to schema-2')
  • replacement in source_text.lua at line 970
    [7.142386][7.142386:142403]()
    assert(result)
    [7.142386]
    [7.142403]
    assert(result, "Text.offset returned nil; this is likely a failure to handle utf8")
  • replacement in source_file.lua at line 66
    [7.11419][7.11419:11436]()
    assert(line)
    [7.11419]
    [7.11436]
    assert(line, 'drawing in file is incomplete')
  • replacement in source_file.lua at line 91
    [7.12752][7.12752:12796]()
    print(shape.mode)
    assert(false)
    [7.12752]
    [7.12796]
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • replacement in source_file.lua at line 125
    [7.14024][7.14024:14068]()
    print(shape.mode)
    assert(false)
    [7.14024]
    [7.14068]
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • replacement in source_file.lua at line 163
    [7.14919][7.14919:14933]()
    assert(i)
    [7.14919]
    [7.14933]
    assert(i, 'drawing in array is incomplete')
  • replacement in source_file.lua at line 189
    [7.16266][7.16266:16310]()
    print(shape.mode)
    assert(false)
    [7.16266]
    [7.16310]
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • replacement in source_edit.lua at line 161
    [7.155492][7.4077:4251](),[7.4251][7.155536:155593](),[7.155536][7.155536:155593](),[7.155593][7.8399:8495](),[7.8495][7.155733:155757](),[7.155733][7.155733:155757]()
    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
    [7.155492]
    [7.155757]
    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))
  • replacement in source_edit.lua at line 206
    [7.20018][7.20018:20061]()
    print(line.mode)
    assert(false)
    [7.20018]
    [7.156405]
    assert(false, ('unknown line mode %s'):format(line.mode))
  • resurrect zombie in select.lua at line 128
    [7.47674][7.6568:6621](),[7.47674][7.6568:6621]()
    local rhs = State.lines[maxl].data:sub(max_offset)
  • edit in select.lua at line 128
    [7.47652]
    [7.6568]
    assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
  • edit in select.lua at line 130
    [7.47652][6.6172:6240](),[7.47652][6.6172:6240]()
    assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
  • resolve order conflict in select.lua at line 130
    [7.6621]
    [7.47721]
  • resurrect zombie in select.lua at line 155
    [7.48447][7.6891:6949](),[7.48447][7.6891:6949]()
    local result = {State.lines[minl].data:sub(min_offset)}
  • edit in select.lua at line 155
    [7.48425]
    [7.6891]
    assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
  • edit in select.lua at line 157
    [7.48425][6.6241:6309](),[7.48425][6.6241:6309]()
    assert(minl < maxl, ('minl %d not < maxl %d'):format(minl, maxl))
  • resolve order conflict in select.lua at line 157
    [7.6949]
    [7.48503]
  • replacement in log_browser.lua at line 78
    [7.177][7.194281:194325](),[7.194281][7.194281:194325]()
    assert(#State.lines == #State.line_cache)
    [7.177]
    [7.194325]
    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))
  • replacement in log_browser.lua at line 98
    [7.1813][7.195420:195458](),[7.195420][7.195420:195458]()
    else assert(line.section_end)
    [7.1813]
    [7.195458]
    else assert(line.section_end, "log line has a section name, but it's neither the start nor end of a section")
  • file un-deletion: geom.lua (----------)geom.lua (----------)
    [7.15081][7.11579:11579](),[7.2][7.15049:15081](),[7.2][7.15049:15081]()
  • resurrect zombie in geom.lua at line 1
    [7.12514][6.6684:6750](),[7.12514][6.6684:6750]()
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • edit in geom.lua at line 1
    [7.11579]
    [6.6684]
    geom = {}
    function geom.on_shape(x,y, drawing, shape)
    if shape.mode == 'freehand' then
    return geom.on_freehand(x,y, drawing, shape)
    elseif shape.mode == 'line' then
    return geom.on_line(x,y, drawing, shape)
    elseif shape.mode == 'manhattan' then
    local p1 = drawing.points[shape.p1]
    local p2 = drawing.points[shape.p2]
    if p1.x == p2.x then
    if x ~= p1.x then return false end
    local y1,y2 = p1.y, p2.y
    if y1 > y2 then
    y1,y2 = y2,y1
    end
    return y >= y1-2 and y <= y2+2
    elseif p1.y == p2.y then
    if y ~= p1.y then return false end
    local x1,x2 = p1.x, p2.x
    if x1 > x2 then
    x1,x2 = x2,x1
    end
    return x >= x1-2 and x <= x2+2
    end
    elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
    return geom.on_polygon(x,y, drawing, shape)
    elseif shape.mode == 'circle' then
    local center = drawing.points[shape.center]
    local dist = geom.dist(center.x,center.y, x,y)
    return dist > shape.radius*0.95 and dist < shape.radius*1.05
    elseif shape.mode == 'arc' then
    local center = drawing.points[shape.center]
    local dist = geom.dist(center.x,center.y, x,y)
    if dist < shape.radius*0.95 or dist > shape.radius*1.05 then
    return false
    end
    return geom.angle_between(center.x,center.y, x,y, shape.start_angle,shape.end_angle)
    elseif shape.mode == 'deleted' then
    else
  • edit in geom.lua at line 42
    [6.6750]
    end
    end
    function geom.on_freehand(x,y, drawing, shape)
    local prev
    for _,p in ipairs(shape.points) do
    if prev then
    if geom.on_line(x,y, drawing, {p1=prev, p2=p}) then
    return true
    end
    end
    prev = p
    end
    return false
    end
    function geom.on_line(x,y, drawing, shape)
    local p1,p2
    if type(shape.p1) == 'number' then
    p1 = drawing.points[shape.p1]
    p2 = drawing.points[shape.p2]
    else
    p1 = shape.p1
    p2 = shape.p2
    end
    if p1.x == p2.x then
    if math.abs(p1.x-x) > 2 then
    return false
    end
    local y1,y2 = p1.y,p2.y
    if y1 > y2 then
    y1,y2 = y2,y1
    end
    return y >= y1-2 and y <= y2+2
    end
    -- has the right slope and intercept
    local m = (p2.y - p1.y) / (p2.x - p1.x)
    local yp = p1.y + m*(x-p1.x)
    if yp < y-2 or yp > y+2 then
    return false
    end
    -- between endpoints
    local k = (x-p1.x) / (p2.x-p1.x)
    return k > -0.005 and k < 1.005
    end
    function geom.on_polygon(x,y, drawing, shape)
    local prev
    for _,p in ipairs(shape.vertices) do
    if prev then
    if geom.on_line(x,y, drawing, {p1=prev, p2=p}) then
    return true
    end
    end
    prev = p
    end
    return geom.on_line(x,y, drawing, {p1=shape.vertices[1], p2=shape.vertices[#shape.vertices]})
    end
    -- are (x3,y3) and (x4,y4) on the same side of the line between (x1,y1) and (x2,y2)
    function geom.same_side(x1,y1, x2,y2, x3,y3, x4,y4)
    if x1 == x2 then
    return math.sign(x3-x1) == math.sign(x4-x1)
    end
    if y1 == y2 then
    return math.sign(y3-y1) == math.sign(y4-y1)
    end
    local m = (y2-y1)/(x2-x1)
    return math.sign(m*(x3-x1) + y1-y3) == math.sign(m*(x4-x1) + y1-y4)
    end
    function math.sign(x)
    if x > 0 then
    return 1
    elseif x == 0 then
    return 0
    elseif x < 0 then
    return -1
    end
    end
    function geom.angle_with_hint(x1, y1, x2, y2, hint)
    local result = geom.angle(x1,y1, x2,y2)
    if hint then
    -- Smooth the discontinuity where angle goes from positive to negative.
    -- The hint is a memory of which way we drew it last time.
    while result > hint+math.pi/10 do
    result = result-math.pi*2
    end
    while result < hint-math.pi/10 do
    result = result+math.pi*2
    end
    end
    return result
    end
    -- result is from -π/2 to 3π/2, approximately adding math.atan2 from Lua 5.3
    -- (LÖVE is Lua 5.1)
    function geom.angle(x1,y1, x2,y2)
    local result = math.atan((y2-y1)/(x2-x1))
    if x2 < x1 then
    result = result+math.pi
    end
    return result
    end
    -- is the line between x,y and cx,cy at an angle between s and e?
    function geom.angle_between(ox,oy, x,y, s,e)
    local angle = geom.angle(ox,oy, x,y)
    if s > e then
    s,e = e,s
    end
    -- I'm not sure this is right or ideal..
    angle = angle-math.pi*2
    if s <= angle and angle <= e then
    return true
    end
    angle = angle+math.pi*2
    if s <= angle and angle <= e then
    return true
    end
    angle = angle+math.pi*2
    return s <= angle and angle <= e
    end
    function geom.dist(x1,y1, x2,y2) return ((x2-x1)^2+(y2-y1)^2)^0.5 end
  • replacement in file.lua at line 46
    [7.16435][6.6751:6801](),[7.16435][6.6751:6801](),[7.244][6.6802:6870](),[7.244][6.6802:6870](),[7.394][6.6871:6939](),[7.394][6.6871:6939]()
    assert(line, 'drawing in file is incomplete')
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
    [7.16243]
    [7.18207]
    -- for tests
    function load_array(a)
    local result = {}
    local next_line = ipairs(a)
    local i,line,drawing = 0, ''
    while true do
    i,line = next_line(a, i)
    if i == nil then break end
    table.insert(result, {data=line})
    end
    if #result == 0 then
    table.insert(result, {data=''})
    end
    return result
  • edit in file.lua at line 79
    [7.1381][7.1381:1467](),[7.1467][7.2551:2582](),[7.2582][7.1490:1566](),[7.1490][7.1490:1566](),[7.1566][7.7991:8029](),[7.8029][7.1810:1839](),[7.9433][7.1810:1839](),[7.1810][7.1810:1839](),[7.1839][7.8030:8066](),[7.8066][7.1888:1910](),[7.9463][7.1888:1910](),[7.1888][7.1888:1910](),[7.1910][7.532:532](),[7.2092][6.6940:6988](),[7.2092][6.6940:6988](),[7.3157][6.6989:7057](),[7.3157][6.6989:7057]()
    -- for tests
    function load_array(a)
    local result = {}
    local next_line = ipairs(a)
    local i,line,drawing = 0, ''
    while true do
    i,line = next_line(a, i)
    if i == nil then break end
    table.insert(result, {data=line})
    end
    if #result == 0 then
    table.insert(result, {data=''})
    end
    return result
    assert(i, 'drawing in array is incomplete')
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • resolve order conflict in file.lua at line 79
    [7.1296]
  • edit in edit.lua at line 50
    [7.3184][6.7058:7130](),[7.3184][6.7058:7130]()
    current_drawing_mode = 'line', -- one of the available shape modes
  • replacement in edit.lua at line 103
    [7.108][7.108:459]()
    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
    [7.108]
    [7.459]
    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))
  • edit in edit.lua at line 456
    [7.12430][4.213:213](),[7.5492][6.7493:7557](),[7.5492][6.7493:7557](),[7.5492][6.7493:7557](),[7.1023][6.7131:7492](),[7.1023][6.7131:7492]()
    assert(false, ('unknown line mode %s'):format(line.mode))
    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))
  • resolve order conflict in edit.lua at line 456
    [7.12430]
  • edit in drawing.lua at line 36
    [7.11261][7.11261:11279]()
    assert(shape)
  • replacement in drawing.lua at line 115
    [7.14400][7.14400:14440]()
    print(shape.mode)
    assert(false)
    [7.14400]
    [7.14440]
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • edit in drawing.lua at line 127
    [7.14879][7.9688:9688](),[7.1687][6.7558:7624](),[7.1687][6.7558:7624]()
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • resolve order conflict in drawing.lua at line 127
    [7.14879]
    [7.7397]
  • replacement in drawing.lua at line 208
    [7.18327][7.18327:18367]()
    print(shape.mode)
    assert(false)
    [7.18327]
    [7.18367]
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • edit in drawing.lua at line 218
    [7.18674][7.1479:1479](),[7.4021][6.7625:7691](),[7.4021][6.7625:7691]()
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • resolve order conflict in drawing.lua at line 218
    [7.18674]
    [7.883]
  • replacement in drawing.lua at line 239
    [7.19871][7.19871:19927]()
    print(State.current_drawing_mode)
    assert(false)
    [7.19871]
    [7.19927]
    assert(false, ('unknown drawing mode %s'):format(State.current_drawing_mode))
  • replacement in drawing.lua at line 254
    [7.1656][7.20230:20266](),[7.20230][7.20230:20266]()
    assert(drawing.mode == 'drawing')
    [7.1656]
    [7.20266]
    assert(drawing.mode == 'drawing', 'Drawing.update: line is not a drawing')
  • edit in drawing.lua at line 297
    [7.21692][7.1658:1658](),[7.4193][6.7692:7774](),[7.4193][6.7692:7774]()
    assert(false, ('unknown drawing mode %s'):format(State.current_drawing_mode))
  • resolve order conflict in drawing.lua at line 297
    [7.21692]
    [7.7466]
  • replacement in drawing.lua at line 341
    [7.24131][7.24131:24178]()
    assert(#drawing.pending.vertices <= 2)
    [7.24131]
    [7.24178]
    assert(#drawing.pending.vertices <= 2, 'Drawing.mouse_release: rectangle has too many pending vertices')
  • replacement in drawing.lua at line 356
    [7.25113][7.25113:25160]()
    assert(#drawing.pending.vertices <= 2)
    [7.25113]
    [7.25160]
    assert(#drawing.pending.vertices <= 2, 'Drawing.mouse_release: square has too many pending vertices')
  • replacement in drawing.lua at line 385
    [7.26978][7.26978:27036]()
    print(drawing.pending.mode)
    assert(false)
    [7.26978]
    [7.27036]
    assert(false, ('unknown drawing mode %s'):format(drawing.pending.mode))
  • edit in drawing.lua at line 393
    [7.207][6.7775:7852](),[7.207][6.7775:7852](),[7.207][6.7775:7852](),[7.1574][6.7853:7966](),[7.1574][6.7853:7966](),[7.2272][6.7967:8077](),[7.2272][6.7967:8077](),[7.6342][6.8078:8158](),[7.6342][6.8078:8158]()
    assert(drawing.mode == 'drawing', 'Drawing.update: line is not a drawing')
    assert(#drawing.pending.vertices <= 2, 'Drawing.mouse_release: rectangle has too many pending vertices')
    assert(#drawing.pending.vertices <= 2, 'Drawing.mouse_release: square has too many pending vertices')
    assert(false, ('unknown drawing mode %s'):format(drawing.pending.mode))
  • resolve order conflict in drawing.lua at line 393
    [7.27152]
    [7.7524]
  • replacement in drawing.lua at line 543
    [7.35589][7.35589:35613]()
    assert(idx)
    [7.35589]
    [7.35613]
    assert(idx, 'point to delete is not in vertices')
  • edit in drawing.lua at line 639
    [7.39139][7.39139:39163]()
    assert(shape)
  • edit in drawing.lua at line 656
    [7.39806][7.39806:39830]()
    assert(point)
  • replacement in drawing.lua at line 692
    [7.40949][7.40949:40989]()
    print(shape.mode)
    assert(false)
    [7.40949]
    [7.40989]
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
  • replacement in drawing.lua at line 697
    [7.41033][7.41033:41068]()
    assert(shape.mode == 'freehand')
    [7.41033]
    [7.41068]
    assert(shape.mode == 'freehand', 'can only smoothen freehand shapes')
  • edit in drawing.lua at line 744
    [7.11016][6.8159:8221](),[7.11016][6.8159:8221](),[7.21459][6.8222:8288](),[7.21459][6.8222:8288](),[7.230][6.8289:8361](),[7.230][6.8289:8361]()
    assert(idx, 'point to delete is not in vertices')
    assert(false, ('unknown drawing mode %s'):format(shape.mode))
    assert(shape.mode == 'freehand', 'can only smoothen freehand shapes')
  • resolve order conflict in drawing.lua at line 744
    [7.42200]
  • replacement in commands.lua at line 139
    [7.3209][7.3209:3225]()
    assert(index)
    [7.3209]
    [7.3225]
    assert(index, 'file missing from manifest')