Merge lines.love

[?]
Nov 4, 2022, 4:08 AM
VP5KC4XZBKD536KCBFO47UKH74RNONENDCFJAHUMVUTPVPGJWD4AC

Dependencies

  • [2] VBU5YHLR Merge lines.love
  • [3] APX2PY6G stop tracking wallclock time
  • [4] OGUV4HSA remove some memory leaks from rendered fragments
  • [5] XX7G2FFJ intermingle freehand line drawings with text
  • [6] 6VXO3ZL3 just keep the cursor visible after any input events
  • [7] 6DE7RBZ6 move mouse_released events to Drawing
  • [8] YT5P6TO6 bugfix: save previous file when dropping a new one on
  • [9] KKMFQDR4 editing source code from within the app
  • [10] D2GCFTTT clean up repl functionality
  • [11] BJ5X5O4A let's prevent the text cursor from ever getting on a drawing
  • [12] KVHUFUFV reorg
  • [13] VHUNJHXB Merge lines.love
  • [14] T7SJSJIH test: undo naming a point
  • [15] 4VQGE7RA new test
  • [16] ENENSZLK bugfix: source margins when toggling log browser
  • [17] BULPIBEG beginnings of a module for the text editor
  • [18] 3PSFWAIL Merge lines.love
  • [19] TO6Y2G3U more decoupling editor tests from App
  • [20] R5QXEHUI somebody stop me
  • [21] 2CTN2IEF Merge lines.love
  • [22] JRLBUB6L more intuitive point delete from polygons
  • [23] JCSLDGAH beginnings of support for multiple shapes
  • [24] TLOAPLBJ add a license
  • [25] 3QNOKBFM beginnings of a test harness
  • [26] Z4XRNDTR find text
  • [27] LXTTOB33 extract a couple of files
  • [28] 7DYUAOI6 test: undo moving point
  • [29] 32V6ZHQB Merge lines.love
  • [30] RSZD5A7G forgot to add json.lua
  • [31] 6SMGKYDR .
  • [32] IFGAJAF7 add a level of indirection to vertices of shapes
  • [33] 4AXV2HG4 all pending manual tests done!
  • [34] 5FW7YOFT highlight selection while dragging
  • [35] CIQN2MDE bugfix: typing a capital letter deletes selection
  • [36] PX7DDEMO autosave slightly less aggressively
  • [37] FS2ITYYH record a known issue
  • [38] 42LVB4DE test: naming a point
  • [39] GUOQRUL7 Merge lines.love
  • [40] JOPVPUSA editing source code from within the app
  • [41] HRWN5V6J Devine's suggestion to try to live with just freehand
  • [42] EMHRPJ3R no, that's not right
  • [43] VHQCNMAR several more modules
  • [44] D4B52CQ2 Merge lines.love
  • [45] 6LJZN727 handle chords
  • [46] EF6MFB46 assume we always have a filename
  • [47] OTIBCAUJ love2d scaffold
  • [48] VXORMHME delete experimental REPL
  • [49] DCO5BQWV Merge lines.love
  • [50] LNUHQOGH start passing in Editor_state explicitly
  • [51] 66X36NZN a little more prose describing manual_tests
  • [52] BLWAYPKV extract a module
  • [53] AVTNUQYR basic test-enabled framework
  • [54] Z4KNS42N to open a file without a terminal, drag it on!
  • [55] AVLAYODP much simpler
  • [56] YGCT2D2O start loading settings as applicable
  • [57] KMSL74GA support selections in the source editor
  • [58] ATQO62TF Merge lines.love
  • [59] ETXNVRPT Merge lines.love
  • [60] T4FRZSYL delete an ancient, unused file
  • [61] TVCPXAAU rename
  • [62] 3QQZ7W4E bring couple more globals back to the app level
  • [63] MD3W5IRA new fork: rip out drawing support
  • [64] FYS7TCDW bugfix
  • [65] TXDMRA5J bugfix: alt-tab shouldn't emit keypress events
  • [66] CE4LZV4T drop last couple of manual tests
  • [67] 4YDBYBA4 clean up memory leak experiments
  • [68] L6XA5EY2 test: moving a point
  • [69] 2L5MEZV3 experiment: new edit namespace
  • [70] S7ZZA3YE ugh, handle absolute as well as relative paths
  • [71] BYG5CEMV support for naming points
  • [72] 73OCE2MC after much struggle, a brute-force undo
  • [73] AYX33NBC Merge lines.love
  • [74] K2X6G75Z start writing some tests for drawings
  • [75] KAUD3YIK tests: deleting points/shapes
  • [76] OI4FPFIN support drawings in the source editor
  • [*] 2Y7YH7UP infrastructure for caching LÖVE text objects
  • [*] SPNMXTYR have file API operate on state object

Change contents

  • file deletion: drawing_tests.lua (----------)
    [4.2][4.81419:81460](),[4.81460][4.37333:37333]()
    -- major tests for drawings
    -- We minimize assumptions about specific pixels, and try to test at the level
    -- of specific shapes. In particular, no tests of freehand drawings.
    function test_creating_drawing_saves()
    io.write('\ntest_creating_drawing_saves')
    App.screen.init{width=120, height=60}
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    -- click on button to create drawing
    edit.run_after_mouse_click(Editor_state, 8,Editor_state.top+8, 1)
    -- file not immediately saved
    edit.update(Editor_state, 0.01)
    check_nil(App.filesystem['foo'], 'F - test_creating_drawing_saves/early')
    -- wait until save
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- filesystem contains drawing and an empty line of text
    check_eq(App.filesystem['foo'], '```lines\n```\n\n', 'F - test_creating_drawing_saves')
    end
    function test_draw_line()
    io.write('\ntest_draw_line')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_line/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_line/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_line/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_line/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_line/baseline/#shapes')
    -- draw a line
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_line/#shapes')
    check_eq(#drawing.points, 2, 'F - test_draw_line/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_draw_line/p1:x')
    check_eq(p1.y, 6, 'F - test_draw_line/p1:y')
    check_eq(p2.x, 35, 'F - test_draw_line/p2:x')
    check_eq(p2.y, 36, 'F - test_draw_line/p2:y')
    -- wait until save
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- The format on disk isn't perfectly stable. Table fields can be reordered.
    -- So just reload from disk to verify.
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_line/save/#shapes')
    check_eq(#drawing.points, 2, 'F - test_draw_line/save/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/save/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_draw_line/save/p1:x')
    check_eq(p1.y, 6, 'F - test_draw_line/save/p1:y')
    check_eq(p2.x, 35, 'F - test_draw_line/save/p2:x')
    check_eq(p2.y, 36, 'F - test_draw_line/save/p2:y')
    end
    function test_draw_horizontal_line()
    io.write('\ntest_draw_horizontal_line')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'manhattan'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_horizontal_line/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_horizontal_line/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_horizontal_line/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_horizontal_line/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_horizontal_line/baseline/#shapes')
    -- draw a line that is more horizontal than vertical
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_horizontal_line/#shapes')
    check_eq(#drawing.points, 2, 'F - test_draw_horizontal_line/#points')
    check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_draw_horizontal_line/shape_mode')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_draw_horizontal_line/p1:x')
    check_eq(p1.y, 6, 'F - test_draw_horizontal_line/p1:y')
    check_eq(p2.x, 35, 'F - test_draw_horizontal_line/p2:x')
    check_eq(p2.y, p1.y, 'F - test_draw_horizontal_line/p2:y')
    end
    function test_draw_circle()
    io.write('\ntest_draw_circle')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_circle/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_circle/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_circle/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_circle/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_circle/baseline/#shapes')
    -- draw a circle
    App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
    edit.run_after_keychord(Editor_state, 'C-o')
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_circle/#shapes')
    check_eq(#drawing.points, 1, 'F - test_draw_circle/#points')
    check_eq(drawing.shapes[1].mode, 'circle', 'F - test_draw_horizontal_line/shape_mode')
    check_eq(drawing.shapes[1].radius, 30, 'F - test_draw_circle/radius')
    local center = drawing.points[drawing.shapes[1].center]
    check_eq(center.x, 35, 'F - test_draw_circle/center:x')
    check_eq(center.y, 36, 'F - test_draw_circle/center:y')
    end
    function test_cancel_stroke()
    io.write('\ntest_cancel_stroke')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_cancel_stroke/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_cancel_stroke/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_cancel_stroke/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_cancel_stroke/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_cancel_stroke/baseline/#shapes')
    -- start drawing a line
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    -- cancel
    edit.run_after_keychord(Editor_state, 'escape')
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 0, 'F - test_cancel_stroke/#shapes')
    end
    function test_keys_do_not_affect_shape_when_mouse_up()
    io.write('\ntest_keys_do_not_affect_shape_when_mouse_up')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- hover over drawing and press 'o' without holding mouse
    App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
    edit.run_after_keychord(Editor_state, 'o')
    -- no change to drawing mode
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_keys_do_not_affect_shape_when_mouse_up/drawing_mode')
    -- no change to text either because we didn't run the textinput event
    end
    function test_draw_circle_mid_stroke()
    io.write('\ntest_draw_circle_mid_stroke')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_circle_mid_stroke/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_circle_mid_stroke/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_circle_mid_stroke/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_circle_mid_stroke/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_circle_mid_stroke/baseline/#shapes')
    -- draw a circle
    App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_keychord(Editor_state, 'o')
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_circle_mid_stroke/#shapes')
    check_eq(#drawing.points, 1, 'F - test_draw_circle_mid_stroke/#points')
    check_eq(drawing.shapes[1].mode, 'circle', 'F - test_draw_horizontal_line/shape_mode')
    check_eq(drawing.shapes[1].radius, 30, 'F - test_draw_circle_mid_stroke/radius')
    local center = drawing.points[drawing.shapes[1].center]
    check_eq(center.x, 35, 'F - test_draw_circle_mid_stroke/center:x')
    check_eq(center.y, 36, 'F - test_draw_circle_mid_stroke/center:y')
    end
    function test_draw_arc()
    io.write('\ntest_draw_arc')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'circle'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_arc/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_arc/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_arc/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_arc/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_arc/baseline/#shapes')
    -- draw an arc
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    App.mouse_move(Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'a') -- arc mode
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35+50, Editor_state.top+Drawing_padding_top+36+50, 1) -- 45°
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_arc/#shapes')
    check_eq(#drawing.points, 1, 'F - test_draw_arc/#points')
    check_eq(drawing.shapes[1].mode, 'arc', 'F - test_draw_horizontal_line/shape_mode')
    local arc = drawing.shapes[1]
    check_eq(arc.radius, 30, 'F - test_draw_arc/radius')
    local center = drawing.points[arc.center]
    check_eq(center.x, 35, 'F - test_draw_arc/center:x')
    check_eq(center.y, 36, 'F - test_draw_arc/center:y')
    check_eq(arc.start_angle, 0, 'F - test_draw_arc/start:angle')
    check_eq(arc.end_angle, math.pi/4, 'F - test_draw_arc/end:angle')
    end
    function test_draw_polygon()
    io.write('\ntest_draw_polygon')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_polygon/baseline/drawing_mode')
    check_eq(#Editor_state.lines, 2, 'F - test_draw_polygon/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_polygon/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_polygon/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_polygon/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_polygon/baseline/#shapes')
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_keychord(Editor_state, 'g') -- polygon mode
    -- second point
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'p') -- add point
    -- final point
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_polygon/#shapes')
    check_eq(#drawing.points, 3, 'F - test_draw_polygon/vertices')
    local shape = drawing.shapes[1]
    check_eq(shape.mode, 'polygon', 'F - test_draw_polygon/shape_mode')
    check_eq(#shape.vertices, 3, 'F - test_draw_polygon/vertices')
    local p = drawing.points[shape.vertices[1]]
    check_eq(p.x, 5, 'F - test_draw_polygon/p1:x')
    check_eq(p.y, 6, 'F - test_draw_polygon/p1:y')
    local p = drawing.points[shape.vertices[2]]
    check_eq(p.x, 65, 'F - test_draw_polygon/p2:x')
    check_eq(p.y, 36, 'F - test_draw_polygon/p2:y')
    local p = drawing.points[shape.vertices[3]]
    check_eq(p.x, 35, 'F - test_draw_polygon/p3:x')
    check_eq(p.y, 26, 'F - test_draw_polygon/p3:y')
    end
    function test_draw_rectangle()
    io.write('\ntest_draw_rectangle')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_rectangle/baseline/drawing_mode')
    check_eq(#Editor_state.lines, 2, 'F - test_draw_rectangle/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_rectangle/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_rectangle/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_rectangle/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_rectangle/baseline/#shapes')
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_keychord(Editor_state, 'r') -- rectangle mode
    -- second point/first edge
    App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
    edit.run_after_keychord(Editor_state, 'p')
    -- override second point/first edge
    App.mouse_move(Editor_state.left+75, Editor_state.top+Drawing_padding_top+76)
    edit.run_after_keychord(Editor_state, 'p')
    -- release (decides 'thickness' of rectangle perpendicular to first edge)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+15, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_rectangle/#shapes')
    check_eq(#drawing.points, 5, 'F - test_draw_rectangle/#points') -- currently includes every point added
    local shape = drawing.shapes[1]
    check_eq(shape.mode, 'rectangle', 'F - test_draw_rectangle/shape_mode')
    check_eq(#shape.vertices, 4, 'F - test_draw_rectangle/vertices')
    local p = drawing.points[shape.vertices[1]]
    check_eq(p.x, 35, 'F - test_draw_rectangle/p1:x')
    check_eq(p.y, 36, 'F - test_draw_rectangle/p1:y')
    local p = drawing.points[shape.vertices[2]]
    check_eq(p.x, 75, 'F - test_draw_rectangle/p2:x')
    check_eq(p.y, 76, 'F - test_draw_rectangle/p2:y')
    local p = drawing.points[shape.vertices[3]]
    check_eq(p.x, 70, 'F - test_draw_rectangle/p3:x')
    check_eq(p.y, 81, 'F - test_draw_rectangle/p3:y')
    local p = drawing.points[shape.vertices[4]]
    check_eq(p.x, 30, 'F - test_draw_rectangle/p4:x')
    check_eq(p.y, 41, 'F - test_draw_rectangle/p4:y')
    end
    function test_draw_rectangle_intermediate()
    io.write('\ntest_draw_rectangle_intermediate')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_rectangle_intermediate/baseline/drawing_mode')
    check_eq(#Editor_state.lines, 2, 'F - test_draw_rectangle_intermediate/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_rectangle_intermediate/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_rectangle_intermediate/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_rectangle_intermediate/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_rectangle_intermediate/baseline/#shapes')
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_keychord(Editor_state, 'r') -- rectangle mode
    -- second point/first edge
    App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
    edit.run_after_keychord(Editor_state, 'p')
    -- override second point/first edge
    App.mouse_move(Editor_state.left+75, Editor_state.top+Drawing_padding_top+76)
    edit.run_after_keychord(Editor_state, 'p')
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.points, 3, 'F - test_draw_rectangle_intermediate/#points') -- currently includes every point added
    local pending = drawing.pending
    check_eq(pending.mode, 'rectangle', 'F - test_draw_rectangle_intermediate/shape_mode')
    check_eq(#pending.vertices, 2, 'F - test_draw_rectangle_intermediate/vertices')
    local p = drawing.points[pending.vertices[1]]
    check_eq(p.x, 35, 'F - test_draw_rectangle_intermediate/p1:x')
    check_eq(p.y, 36, 'F - test_draw_rectangle_intermediate/p1:y')
    local p = drawing.points[pending.vertices[2]]
    check_eq(p.x, 75, 'F - test_draw_rectangle_intermediate/p2:x')
    check_eq(p.y, 76, 'F - test_draw_rectangle_intermediate/p2:y')
    -- outline of rectangle is drawn based on where the mouse is, but we can't check that so far
    end
    function test_draw_square()
    io.write('\ntest_draw_square')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_square/baseline/drawing_mode')
    check_eq(#Editor_state.lines, 2, 'F - test_draw_square/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_square/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_square/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_square/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_square/baseline/#shapes')
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_keychord(Editor_state, 's') -- square mode
    -- second point/first edge
    App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
    edit.run_after_keychord(Editor_state, 'p')
    -- override second point/first edge
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+66)
    edit.run_after_keychord(Editor_state, 'p')
    -- release (decides which side of first edge to draw square on)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+15, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_square/#shapes')
    check_eq(#drawing.points, 5, 'F - test_draw_square/#points') -- currently includes every point added
    check_eq(drawing.shapes[1].mode, 'square', 'F - test_draw_square/shape_mode')
    check_eq(#drawing.shapes[1].vertices, 4, 'F - test_draw_square/vertices')
    local p = drawing.points[drawing.shapes[1].vertices[1]]
    check_eq(p.x, 35, 'F - test_draw_square/p1:x')
    check_eq(p.y, 36, 'F - test_draw_square/p1:y')
    local p = drawing.points[drawing.shapes[1].vertices[2]]
    check_eq(p.x, 65, 'F - test_draw_square/p2:x')
    check_eq(p.y, 66, 'F - test_draw_square/p2:y')
    local p = drawing.points[drawing.shapes[1].vertices[3]]
    check_eq(p.x, 35, 'F - test_draw_square/p3:x')
    check_eq(p.y, 96, 'F - test_draw_square/p3:y')
    local p = drawing.points[drawing.shapes[1].vertices[4]]
    check_eq(p.x, 5, 'F - test_draw_square/p4:x')
    check_eq(p.y, 66, 'F - test_draw_square/p4:y')
    end
    function test_name_point()
    io.write('\ntest_name_point')
    -- create a drawing with a line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- draw a line
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_name_point/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_name_point/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_name_point/baseline/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_name_point/baseline/p1:x')
    check_eq(p1.y, 6, 'F - test_name_point/baseline/p1:y')
    check_eq(p2.x, 35, 'F - test_name_point/baseline/p2:x')
    check_eq(p2.y, 36, 'F - test_name_point/baseline/p2:y')
    check_nil(p2.name, 'F - test_name_point/baseline/p2:name')
    -- enter 'name' mode without moving the mouse
    edit.run_after_keychord(Editor_state, 'C-n')
    check_eq(Editor_state.current_drawing_mode, 'name', 'F - test_name_point/mode:1')
    edit.run_after_textinput(Editor_state, 'A')
    check_eq(p2.name, 'A', 'F - test_name_point')
    -- still in 'name' mode
    check_eq(Editor_state.current_drawing_mode, 'name', 'F - test_name_point/mode:2')
    -- exit 'name' mode
    edit.run_after_keychord(Editor_state, 'return')
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_name_point/mode:3')
    check_eq(p2.name, 'A', 'F - test_name_point')
    -- wait until save
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- change is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.name, 'A', 'F - test_name_point/save')
    end
    function test_move_point()
    io.write('\ntest_move_point')
    -- create a drawing with a line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_move_point/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_move_point/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point/baseline/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_move_point/baseline/p1:x')
    check_eq(p1.y, 6, 'F - test_move_point/baseline/p1:y')
    check_eq(p2.x, 35, 'F - test_move_point/baseline/p2:x')
    check_eq(p2.y, 36, 'F - test_move_point/baseline/p2:y')
    -- wait until save
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- line is saved to disk
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local drawing = Editor_state.lines[1]
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.x, 35, 'F - test_move_point/save/x')
    check_eq(p2.y, 36, 'F - test_move_point/save/y')
    edit.draw(Editor_state)
    -- enter 'move' mode without moving the mouse
    edit.run_after_keychord(Editor_state, 'C-u')
    check_eq(Editor_state.current_drawing_mode, 'move', 'F - test_move_point/mode:1')
    -- point is lifted
    check_eq(drawing.pending.mode, 'move', 'F - test_move_point/mode:2')
    check_eq(drawing.pending.target_point, p2, 'F - test_move_point/target')
    -- move point
    App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
    edit.update(Editor_state, 0.05)
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p2.x, 26, 'F - test_move_point/x')
    check_eq(p2.y, 44, 'F - test_move_point/y')
    -- exit 'move' mode
    edit.run_after_mouse_click(Editor_state, Editor_state.left+26, Editor_state.top+Drawing_padding_top+44, 1)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_move_point/mode:3')
    check_eq(drawing.pending, {}, 'F - test_move_point/pending')
    -- wait until save
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- change is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.x, 26, 'F - test_move_point/save/x')
    check_eq(p2.y, 44, 'F - test_move_point/save/y')
    end
    function test_move_point_on_manhattan_line()
    io.write('\ntest_move_point_on_manhattan_line')
    -- create a drawing with a manhattan line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'manhattan'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+46, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_move_point_on_manhattan_line/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_move_point_on_manhattan_line/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_move_point_on_manhattan_line/baseline/shape:1')
    edit.draw(Editor_state)
    -- enter 'move' mode
    edit.run_after_keychord(Editor_state, 'C-u')
    check_eq(Editor_state.current_drawing_mode, 'move', 'F - test_move_point_on_manhattan_line/mode:1')
    -- move point
    App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
    edit.update(Editor_state, 0.05)
    -- line is no longer manhattan
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point_on_manhattan_line/baseline/shape:1')
    end
    function test_delete_lines_at_point()
    io.write('\ntest_delete_lines_at_point')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 2, 'F - test_delete_lines_at_point/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_delete_lines_at_point/baseline/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_lines_at_point/baseline/shape:2')
    -- hover on the common point and delete
    App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'C-d')
    check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_lines_at_point/shape:1')
    check_eq(drawing.shapes[2].mode, 'deleted', 'F - test_delete_lines_at_point/shape:2')
    -- wait for some time
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- deleted points disappear after file is reloaded
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_delete_lines_at_point/save')
    end
    function test_delete_line_under_mouse_pointer()
    io.write('\ntest_delete_line_under_mouse_pointer')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 2, 'F - test_delete_line_under_mouse_pointer/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_delete_line_under_mouse_pointer/baseline/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_line_under_mouse_pointer/baseline/shape:2')
    -- hover on one of the lines and delete
    App.mouse_move(Editor_state.left+25, Editor_state.top+Drawing_padding_top+26)
    edit.run_after_keychord(Editor_state, 'C-d')
    -- only that line is deleted
    check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_line_under_mouse_pointer/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_line_under_mouse_pointer/shape:2')
    end
    function test_delete_point_from_polygon()
    io.write('\ntest_delete_point_from_polygon')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_keychord(Editor_state, 'g') -- polygon mode
    -- second point
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'p') -- add point
    -- third point
    App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+26)
    edit.run_after_keychord(Editor_state, 'p') -- add point
    -- fourth point
    edit.run_after_mouse_release(Editor_state, Editor_state.left+14, Editor_state.top+Drawing_padding_top+16, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_delete_point_from_polygon/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/baseline/mode')
    check_eq(#drawing.shapes[1].vertices, 4, 'F - test_delete_point_from_polygon/baseline/vertices')
    -- hover on a point and delete
    App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+26)
    edit.run_after_keychord(Editor_state, 'C-d')
    -- just the one point is deleted
    check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/shape')
    check_eq(#drawing.shapes[1].vertices, 3, 'F - test_delete_point_from_polygon/vertices')
    end
    function test_delete_point_from_polygon()
    io.write('\ntest_delete_point_from_polygon')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_keychord(Editor_state, 'g') -- polygon mode
    -- second point
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'p') -- add point
    -- third point
    edit.run_after_mouse_release(Editor_state, Editor_state.left+14, Editor_state.top+Drawing_padding_top+16, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_delete_point_from_polygon/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/baseline/mode')
    check_eq(#drawing.shapes[1].vertices, 3, 'F - test_delete_point_from_polygon/baseline/vertices')
    -- hover on a point and delete
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'C-d')
    -- there's < 3 points left, so the whole polygon is deleted
    check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_point_from_polygon')
    end
    function test_undo_name_point()
    io.write('\ntest_undo_name_point')
    -- create a drawing with a line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- draw a line
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_undo_name_point/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_undo_name_point/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_name_point/baseline/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_undo_name_point/baseline/p1:x')
    check_eq(p1.y, 6, 'F - test_undo_name_point/baseline/p1:y')
    check_eq(p2.x, 35, 'F - test_undo_name_point/baseline/p2:x')
    check_eq(p2.y, 36, 'F - test_undo_name_point/baseline/p2:y')
    check_nil(p2.name, 'F - test_undo_name_point/baseline/p2:name')
    check_eq(#Editor_state.history, 1, 'F - test_undo_name_point/baseline/history:1')
    --? print('a', Editor_state.lines.current_drawing)
    -- enter 'name' mode without moving the mouse
    edit.run_after_keychord(Editor_state, 'C-n')
    edit.run_after_textinput(Editor_state, 'A')
    edit.run_after_keychord(Editor_state, 'return')
    check_eq(p2.name, 'A', 'F - test_undo_name_point/baseline')
    check_eq(#Editor_state.history, 3, 'F - test_undo_name_point/baseline/history:2')
    check_eq(Editor_state.next_history, 4, 'F - test_undo_name_point/baseline/next_history')
    --? print('b', Editor_state.lines.current_drawing)
    -- undo
    edit.run_after_keychord(Editor_state, 'C-z')
    local drawing = Editor_state.lines[1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(Editor_state.next_history, 3, 'F - test_undo_name_point/next_history')
    check_eq(p2.name, '', 'F - test_undo_name_point') -- not quite what it was before, but close enough
    -- wait until save
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- undo is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.name, '', 'F - test_undo_name_point/save')
    end
    function test_undo_move_point()
    io.write('\ntest_undo_move_point')
    -- create a drawing with a line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_undo_move_point/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_undo_move_point/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_move_point/baseline/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_undo_move_point/baseline/p1:x')
    check_eq(p1.y, 6, 'F - test_undo_move_point/baseline/p1:y')
    check_eq(p2.x, 35, 'F - test_undo_move_point/baseline/p2:x')
    check_eq(p2.y, 36, 'F - test_undo_move_point/baseline/p2:y')
    check_nil(p2.name, 'F - test_undo_move_point/baseline/p2:name')
    -- move p2
    edit.run_after_keychord(Editor_state, 'C-u')
    App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
    edit.update(Editor_state, 0.05)
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p2.x, 26, 'F - test_undo_move_point/x')
    check_eq(p2.y, 44, 'F - test_undo_move_point/y')
    -- exit 'move' mode
    edit.run_after_mouse_click(Editor_state, Editor_state.left+26, Editor_state.top+Drawing_padding_top+44, 1)
    check_eq(Editor_state.next_history, 4, 'F - test_undo_move_point/next_history')
    -- undo
    edit.run_after_keychord(Editor_state, 'C-z')
    edit.run_after_keychord(Editor_state, 'C-z') -- bug: need to undo twice
    local drawing = Editor_state.lines[1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(Editor_state.next_history, 2, 'F - test_undo_move_point/next_history')
    check_eq(p2.x, 35, 'F - test_undo_move_point/x')
    check_eq(p2.y, 36, 'F - test_undo_move_point/y')
    -- wait until save
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- undo is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.x, 35, 'F - test_undo_move_point/save/x')
    check_eq(p2.y, 36, 'F - test_undo_move_point/save/y')
    end
    function test_undo_delete_point()
    io.write('\ntest_undo_delete_point')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 2, 'F - test_undo_delete_point/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_delete_point/baseline/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/baseline/shape:2')
    -- hover on the common point and delete
    App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'C-d')
    check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_undo_delete_point/shape:1')
    check_eq(drawing.shapes[2].mode, 'deleted', 'F - test_undo_delete_point/shape:2')
    -- undo
    edit.run_after_keychord(Editor_state, 'C-z')
    local drawing = Editor_state.lines[1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(Editor_state.next_history, 3, 'F - test_undo_move_point/next_history')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_delete_point/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/shape:2')
    -- wait until save
    App.wait_fake_time(3.1)
    edit.update(Editor_state, 0)
    -- undo is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    check_eq(#Editor_state.lines[1].shapes, 2, 'F - test_undo_delete_point/save')
    end
  • file deletion: source_tests.lua (----------)source_tests.lua (----------)
    [4.2][4.150199:150239](),[4.2][4.150199:150239](),[4.150239][4.147103:147103]()
    Current_time = Current_time + 0.1
    App.run_after_keychord('C-l')
    -- margins are now adjusted
    check_eq(Editor_state.left, Margin_left, 'F - test_show_log_browser_side_resizes_both_sides_if_cannot_double_window_width/edit:left')
    check_eq(Editor_state.right, App.screen.width/2 - Margin_right, 'F - test_show_log_browser_side_resizes_both_sides_if_cannot_double_window_width/edit:right')
    check_eq(Log_browser_state.left, App.screen.width/2 + Margin_left, 'F - test_show_log_browser_side_resizes_both_sides_if_cannot_double_window_width/log:left')
    check_eq(Log_browser_state.right, App.screen.width - Margin_right, 'F - test_show_log_browser_side_resizes_both_sides_if_cannot_double_window_width/log:right')
    end
    Current_time = Current_time + 0.1
    App.run_after_keychord('C-l')
    -- window width is doubled
    check_eq(App.screen.width, 600, 'F - test_show_log_browser_side_doubles_window_width_if_possible/display:width')
    -- left side margins are unchanged
    check_eq(Editor_state.left, Margin_left, 'F - test_show_log_browser_side_doubles_window_width_if_possible/edit:left')
    check_eq(Editor_state.right, old_editor_right, 'F - test_show_log_browser_side_doubles_window_width_if_possible/edit:right')
    -- log browser margins are adjusted
    check_eq(Log_browser_state.left, App.screen.width/2 + Margin_left, 'F - test_show_log_browser_side_doubles_window_width_if_possible/log:left')
    check_eq(Log_browser_state.right, App.screen.width - Margin_right, 'F - test_show_log_browser_side_doubles_window_width_if_possible/log:right')
    end
    function test_show_log_browser_side_resizes_both_sides_if_cannot_double_window_width()
    io.write('\ntest_show_log_browser_side_resizes_both_sides_if_cannot_double_window_width')
    -- initialize screen dimensions and indicate that it is maximized
    App.screen.init{width=300, height=300}
    Display_width = 300
    -- initialize source app with left side occupying more than half the display
    Current_app = 'source'
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.left = Margin_left
    Editor_state.right = 200
    Text.redraw_all(Editor_state)
    Log_browser_state = edit.initialize_test_state()
    -- log browser has some arbitrary margins
    Log_browser_state.left = 200 + Margin_left
    Log_browser_state.right = 400
    Text.redraw_all(Log_browser_state)
    log_browser.parse(Log_browser_state)
    -- display log browser
    Current_time = Current_time + 0.1
    App.run_after_keychord('C-l')
    check(Show_log_browser_side, 'F - test_show_log_browser_side')
  • file deletion: source_edit.lua (----------)source_edit.lua (----------)
    [4.2][4.165725:165764](),[4.2][4.165725:165764](),[4.165764][4.152440:152440]()
    State.next_save = Current_time + 3 -- short enough that you're likely to still remember what you did
    end
    end
    function edit.quit(State)
    -- make sure to save before quitting
    if State.next_save then
    save_to_disk(State)
    end
    end
    function edit.mouse_pressed(State, x,y, mouse_button)
    if State.search_term then return end
    if State.next_save and State.next_save < Current_time then
    save_to_disk(State)
    State.next_save = nil
    end
    end
    function schedule_save(State)
    if State.next_save == nil then
  • replacement in source_tests.lua at line 34
    [4.659][4.659:685]()
    App.wait_fake_time(0.1)
    [4.659]
    [4.685]
    Current_time = Current_time + 0.1
  • replacement in source_tests.lua at line 59
    [4.1688][4.1688:1714]()
    App.wait_fake_time(0.1)
    [4.1688]
    [4.1714]
    Current_time = Current_time + 0.1
  • replacement in source_tests.lua at line 90
    [4.3366][4.3366:3392]()
    App.wait_fake_time(0.1)
    [4.3366]
    [4.3392]
    Current_time = Current_time + 0.1
  • replacement in source_edit.lua at line 192
    [4.20090][4.156691:156753](),[4.156691][4.156691:156753]()
    if State.next_save and State.next_save < App.getTime() then
    [4.20090]
    [4.156753]
    if State.next_save and State.next_save < Current_time then
  • replacement in source_edit.lua at line 200
    [4.156877][4.156877:156984]()
    State.next_save = App.getTime() + 3 -- short enough that you're likely to still remember what you did
    [4.156877]
    [4.156984]
    State.next_save = Current_time + 3 -- short enough that you're likely to still remember what you did
  • edit in main.lua at line 82
    [4.186991][4.186991:187113](),[4.186991][4.186991:187113]()
    Last_focus_time = App.getTime() -- https://love2d.org/forums/viewtopic.php?p=249700
    Last_resize_time = App.getTime()
  • resurrect zombie in main.lua at line 82
    [4.187113][4.38:42](),[4.187113][4.38:42]()
    end
  • edit in main.lua at line 82
    [4.186991]
    [4.38]
    Current_time = 0
    Last_focus_time = 0 -- https://love2d.org/forums/viewtopic.php?p=249700
    Last_resize_time = 0
  • edit in main.lua at line 120
    [4.187512][4.187512:187548](),[4.187548][4.44:44]()
    Last_focus_time = App.getTime()
  • resurrect zombie in main.lua at line 120
    [4.188051][3.450:485](),[4.188051][3.450:485]()
    Last_focus_time = Current_time
  • resolve order conflict in main.lua at line 120
    [4.187512]
    [3.450]
  • replacement in main.lua at line 159
    [4.188248][4.188248:188297]()
    if App.getTime() < Last_focus_time + 0.01 then
    [4.188248]
    [4.188297]
    if Current_time < Last_focus_time + 0.01 then
  • edit in main.lua at line 161
    [4.188308][4.50:50](),[4.188787][3.571:619](),[4.188787][3.571:619]()
    if Current_time < Last_focus_time + 0.01 then
  • resolve order conflict in main.lua at line 161
    [4.188308]
    [4.188847]
  • resurrect zombie in main.lua at line 196
    [4.1512][4.189334:189406](),[4.1512][4.189334:189406]()
    -- ignore events for some time after window in focus (mostly alt-tab)
  • edit in main.lua at line 197
    [4.189406][4.54:54](),[4.189406][4.54:54]()
  • resurrect zombie in main.lua at line 197
    [4.189945][3.620:668](),[4.189945][3.620:668]()
    if Current_time < Last_focus_time + 0.01 then
  • resolve order conflict in main.lua at line 197
    [4.189406]
    [3.620]
  • resurrect zombie in main.lua at line 210
    [4.3121][4.189648:189757](),[4.3121][4.189648:189757]()
    function App.keyreleased(chord, key)
    -- ignore events for some time after window in focus (mostly alt-tab)
  • edit in main.lua at line 212
    [4.189757][4.58:58](),[4.189757][4.58:58]()
  • resurrect zombie in main.lua at line 212
    [4.190296][3.669:717](),[4.190296][3.669:717]()
    if Current_time < Last_focus_time + 0.01 then
  • resolve order conflict in main.lua at line 212
    [4.189757]
    [3.669]
  • edit in main.lua at line 264
    [4.186991][3.297:414](),[4.186991][3.297:414]()
    Current_time = 0
    Last_focus_time = 0 -- https://love2d.org/forums/viewtopic.php?p=249700
    Last_resize_time = 0
  • resolve order conflict in main.lua at line 264
    [78.268]
  • edit in edit.lua at line 109
    [4.4252]
    [79.421]
    if State.next_save and State.next_save < Current_time then
  • file un-deletion: drawing_tests.lua (----------)drawing_tests.lua (----------)
    [4.1575][4.15:15](),[4.2][4.1534:1575](),[4.2][4.1534:1575]()
  • resurrect zombie in drawing_tests.lua at line 1
    [4.937][3.897:933](),[4.937][3.897:933](),[4.1001][3.934:970](),[4.1001][3.934:970](),[4.1065][3.971:1007](),[4.1065][3.971:1007](),[4.1129][3.1008:1044](),[4.1129][3.1008:1044](),[4.1193][3.1045:1081](),[4.1193][3.1045:1081](),[4.1260][3.1082:1118](),[4.1260][3.1082:1118](),[4.1324][3.1119:1155](),[4.1324][3.1119:1155](),[4.1388][3.1156:1192](),[4.1388][3.1156:1192](),[4.1452][3.1193:1229](),[4.1452][3.1193:1229]()
    Current_time = Current_time + 3.1
    Current_time = Current_time + 3.1
    Current_time = Current_time + 3.1
    Current_time = Current_time + 3.1
    Current_time = Current_time + 3.1
    Current_time = Current_time + 3.1
    Current_time = Current_time + 3.1
    Current_time = Current_time + 3.1
    Current_time = Current_time + 3.1
  • edit in drawing_tests.lua at line 1
    [4.15]
    [3.897]
    -- major tests for drawings
    -- We minimize assumptions about specific pixels, and try to test at the level
    -- of specific shapes. In particular, no tests of freehand drawings.
    function test_creating_drawing_saves()
    io.write('\ntest_creating_drawing_saves')
    App.screen.init{width=120, height=60}
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    -- click on button to create drawing
    edit.run_after_mouse_click(Editor_state, 8,Editor_state.top+8, 1)
    -- file not immediately saved
    edit.update(Editor_state, 0.01)
    check_nil(App.filesystem['foo'], 'F - test_creating_drawing_saves/early')
    -- wait until save
  • edit in drawing_tests.lua at line 20
    [3.933]
    [3.934]
    edit.update(Editor_state, 0)
    -- filesystem contains drawing and an empty line of text
    check_eq(App.filesystem['foo'], '```lines\n```\n\n', 'F - test_creating_drawing_saves')
    end
    function test_draw_line()
    io.write('\ntest_draw_line')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_line/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_line/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_line/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_line/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_line/baseline/#shapes')
    -- draw a line
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_line/#shapes')
    check_eq(#drawing.points, 2, 'F - test_draw_line/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_draw_line/p1:x')
    check_eq(p1.y, 6, 'F - test_draw_line/p1:y')
    check_eq(p2.x, 35, 'F - test_draw_line/p2:x')
    check_eq(p2.y, 36, 'F - test_draw_line/p2:y')
    -- wait until save
  • edit in drawing_tests.lua at line 55
    [3.970]
    [3.971]
    edit.update(Editor_state, 0)
    -- The format on disk isn't perfectly stable. Table fields can be reordered.
    -- So just reload from disk to verify.
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_line/save/#shapes')
    check_eq(#drawing.points, 2, 'F - test_draw_line/save/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/save/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_draw_line/save/p1:x')
    check_eq(p1.y, 6, 'F - test_draw_line/save/p1:y')
    check_eq(p2.x, 35, 'F - test_draw_line/save/p2:x')
    check_eq(p2.y, 36, 'F - test_draw_line/save/p2:y')
    end
    function test_draw_horizontal_line()
    io.write('\ntest_draw_horizontal_line')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'manhattan'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_horizontal_line/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_horizontal_line/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_horizontal_line/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_horizontal_line/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_horizontal_line/baseline/#shapes')
    -- draw a line that is more horizontal than vertical
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_horizontal_line/#shapes')
    check_eq(#drawing.points, 2, 'F - test_draw_horizontal_line/#points')
    check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_draw_horizontal_line/shape_mode')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_draw_horizontal_line/p1:x')
    check_eq(p1.y, 6, 'F - test_draw_horizontal_line/p1:y')
    check_eq(p2.x, 35, 'F - test_draw_horizontal_line/p2:x')
    check_eq(p2.y, p1.y, 'F - test_draw_horizontal_line/p2:y')
    end
    function test_draw_circle()
    io.write('\ntest_draw_circle')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_circle/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_circle/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_circle/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_circle/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_circle/baseline/#shapes')
    -- draw a circle
    App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
    edit.run_after_keychord(Editor_state, 'C-o')
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_circle/#shapes')
    check_eq(#drawing.points, 1, 'F - test_draw_circle/#points')
    check_eq(drawing.shapes[1].mode, 'circle', 'F - test_draw_horizontal_line/shape_mode')
    check_eq(drawing.shapes[1].radius, 30, 'F - test_draw_circle/radius')
    local center = drawing.points[drawing.shapes[1].center]
    check_eq(center.x, 35, 'F - test_draw_circle/center:x')
    check_eq(center.y, 36, 'F - test_draw_circle/center:y')
    end
    function test_cancel_stroke()
    io.write('\ntest_cancel_stroke')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_cancel_stroke/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_cancel_stroke/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_cancel_stroke/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_cancel_stroke/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_cancel_stroke/baseline/#shapes')
    -- start drawing a line
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    -- cancel
    edit.run_after_keychord(Editor_state, 'escape')
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 0, 'F - test_cancel_stroke/#shapes')
    end
    function test_keys_do_not_affect_shape_when_mouse_up()
    io.write('\ntest_keys_do_not_affect_shape_when_mouse_up')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- hover over drawing and press 'o' without holding mouse
    App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
    edit.run_after_keychord(Editor_state, 'o')
    -- no change to drawing mode
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_keys_do_not_affect_shape_when_mouse_up/drawing_mode')
    -- no change to text either because we didn't run the textinput event
    end
    function test_draw_circle_mid_stroke()
    io.write('\ntest_draw_circle_mid_stroke')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_circle_mid_stroke/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_circle_mid_stroke/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_circle_mid_stroke/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_circle_mid_stroke/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_circle_mid_stroke/baseline/#shapes')
    -- draw a circle
    App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_keychord(Editor_state, 'o')
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_circle_mid_stroke/#shapes')
    check_eq(#drawing.points, 1, 'F - test_draw_circle_mid_stroke/#points')
    check_eq(drawing.shapes[1].mode, 'circle', 'F - test_draw_horizontal_line/shape_mode')
    check_eq(drawing.shapes[1].radius, 30, 'F - test_draw_circle_mid_stroke/radius')
    local center = drawing.points[drawing.shapes[1].center]
    check_eq(center.x, 35, 'F - test_draw_circle_mid_stroke/center:x')
    check_eq(center.y, 36, 'F - test_draw_circle_mid_stroke/center:y')
    end
    function test_draw_arc()
    io.write('\ntest_draw_arc')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'circle'
    edit.draw(Editor_state)
    check_eq(#Editor_state.lines, 2, 'F - test_draw_arc/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_arc/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_arc/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_arc/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_arc/baseline/#shapes')
    -- draw an arc
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    App.mouse_move(Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'a') -- arc mode
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35+50, Editor_state.top+Drawing_padding_top+36+50, 1) -- 45°
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_arc/#shapes')
    check_eq(#drawing.points, 1, 'F - test_draw_arc/#points')
    check_eq(drawing.shapes[1].mode, 'arc', 'F - test_draw_horizontal_line/shape_mode')
    local arc = drawing.shapes[1]
    check_eq(arc.radius, 30, 'F - test_draw_arc/radius')
    local center = drawing.points[arc.center]
    check_eq(center.x, 35, 'F - test_draw_arc/center:x')
    check_eq(center.y, 36, 'F - test_draw_arc/center:y')
    check_eq(arc.start_angle, 0, 'F - test_draw_arc/start:angle')
    check_eq(arc.end_angle, math.pi/4, 'F - test_draw_arc/end:angle')
    end
    function test_draw_polygon()
    io.write('\ntest_draw_polygon')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_polygon/baseline/drawing_mode')
    check_eq(#Editor_state.lines, 2, 'F - test_draw_polygon/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_polygon/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_polygon/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_polygon/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_polygon/baseline/#shapes')
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_keychord(Editor_state, 'g') -- polygon mode
    -- second point
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'p') -- add point
    -- final point
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_polygon/#shapes')
    check_eq(#drawing.points, 3, 'F - test_draw_polygon/vertices')
    local shape = drawing.shapes[1]
    check_eq(shape.mode, 'polygon', 'F - test_draw_polygon/shape_mode')
    check_eq(#shape.vertices, 3, 'F - test_draw_polygon/vertices')
    local p = drawing.points[shape.vertices[1]]
    check_eq(p.x, 5, 'F - test_draw_polygon/p1:x')
    check_eq(p.y, 6, 'F - test_draw_polygon/p1:y')
    local p = drawing.points[shape.vertices[2]]
    check_eq(p.x, 65, 'F - test_draw_polygon/p2:x')
    check_eq(p.y, 36, 'F - test_draw_polygon/p2:y')
    local p = drawing.points[shape.vertices[3]]
    check_eq(p.x, 35, 'F - test_draw_polygon/p3:x')
    check_eq(p.y, 26, 'F - test_draw_polygon/p3:y')
    end
    function test_draw_rectangle()
    io.write('\ntest_draw_rectangle')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_rectangle/baseline/drawing_mode')
    check_eq(#Editor_state.lines, 2, 'F - test_draw_rectangle/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_rectangle/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_rectangle/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_rectangle/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_rectangle/baseline/#shapes')
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_keychord(Editor_state, 'r') -- rectangle mode
    -- second point/first edge
    App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
    edit.run_after_keychord(Editor_state, 'p')
    -- override second point/first edge
    App.mouse_move(Editor_state.left+75, Editor_state.top+Drawing_padding_top+76)
    edit.run_after_keychord(Editor_state, 'p')
    -- release (decides 'thickness' of rectangle perpendicular to first edge)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+15, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_rectangle/#shapes')
    check_eq(#drawing.points, 5, 'F - test_draw_rectangle/#points') -- currently includes every point added
    local shape = drawing.shapes[1]
    check_eq(shape.mode, 'rectangle', 'F - test_draw_rectangle/shape_mode')
    check_eq(#shape.vertices, 4, 'F - test_draw_rectangle/vertices')
    local p = drawing.points[shape.vertices[1]]
    check_eq(p.x, 35, 'F - test_draw_rectangle/p1:x')
    check_eq(p.y, 36, 'F - test_draw_rectangle/p1:y')
    local p = drawing.points[shape.vertices[2]]
    check_eq(p.x, 75, 'F - test_draw_rectangle/p2:x')
    check_eq(p.y, 76, 'F - test_draw_rectangle/p2:y')
    local p = drawing.points[shape.vertices[3]]
    check_eq(p.x, 70, 'F - test_draw_rectangle/p3:x')
    check_eq(p.y, 81, 'F - test_draw_rectangle/p3:y')
    local p = drawing.points[shape.vertices[4]]
    check_eq(p.x, 30, 'F - test_draw_rectangle/p4:x')
    check_eq(p.y, 41, 'F - test_draw_rectangle/p4:y')
    end
    function test_draw_rectangle_intermediate()
    io.write('\ntest_draw_rectangle_intermediate')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_rectangle_intermediate/baseline/drawing_mode')
    check_eq(#Editor_state.lines, 2, 'F - test_draw_rectangle_intermediate/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_rectangle_intermediate/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_rectangle_intermediate/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_rectangle_intermediate/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_rectangle_intermediate/baseline/#shapes')
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_keychord(Editor_state, 'r') -- rectangle mode
    -- second point/first edge
    App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
    edit.run_after_keychord(Editor_state, 'p')
    -- override second point/first edge
    App.mouse_move(Editor_state.left+75, Editor_state.top+Drawing_padding_top+76)
    edit.run_after_keychord(Editor_state, 'p')
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.points, 3, 'F - test_draw_rectangle_intermediate/#points') -- currently includes every point added
    local pending = drawing.pending
    check_eq(pending.mode, 'rectangle', 'F - test_draw_rectangle_intermediate/shape_mode')
    check_eq(#pending.vertices, 2, 'F - test_draw_rectangle_intermediate/vertices')
    local p = drawing.points[pending.vertices[1]]
    check_eq(p.x, 35, 'F - test_draw_rectangle_intermediate/p1:x')
    check_eq(p.y, 36, 'F - test_draw_rectangle_intermediate/p1:y')
    local p = drawing.points[pending.vertices[2]]
    check_eq(p.x, 75, 'F - test_draw_rectangle_intermediate/p2:x')
    check_eq(p.y, 76, 'F - test_draw_rectangle_intermediate/p2:y')
    -- outline of rectangle is drawn based on where the mouse is, but we can't check that so far
    end
    function test_draw_square()
    io.write('\ntest_draw_square')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_square/baseline/drawing_mode')
    check_eq(#Editor_state.lines, 2, 'F - test_draw_square/baseline/#lines')
    check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_draw_square/baseline/mode')
    check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'F - test_draw_square/baseline/y')
    check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_square/baseline/y')
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_square/baseline/#shapes')
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_keychord(Editor_state, 's') -- square mode
    -- second point/first edge
    App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
    edit.run_after_keychord(Editor_state, 'p')
    -- override second point/first edge
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+66)
    edit.run_after_keychord(Editor_state, 'p')
    -- release (decides which side of first edge to draw square on)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+15, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_draw_square/#shapes')
    check_eq(#drawing.points, 5, 'F - test_draw_square/#points') -- currently includes every point added
    check_eq(drawing.shapes[1].mode, 'square', 'F - test_draw_square/shape_mode')
    check_eq(#drawing.shapes[1].vertices, 4, 'F - test_draw_square/vertices')
    local p = drawing.points[drawing.shapes[1].vertices[1]]
    check_eq(p.x, 35, 'F - test_draw_square/p1:x')
    check_eq(p.y, 36, 'F - test_draw_square/p1:y')
    local p = drawing.points[drawing.shapes[1].vertices[2]]
    check_eq(p.x, 65, 'F - test_draw_square/p2:x')
    check_eq(p.y, 66, 'F - test_draw_square/p2:y')
    local p = drawing.points[drawing.shapes[1].vertices[3]]
    check_eq(p.x, 35, 'F - test_draw_square/p3:x')
    check_eq(p.y, 96, 'F - test_draw_square/p3:y')
    local p = drawing.points[drawing.shapes[1].vertices[4]]
    check_eq(p.x, 5, 'F - test_draw_square/p4:x')
    check_eq(p.y, 66, 'F - test_draw_square/p4:y')
    end
    function test_name_point()
    io.write('\ntest_name_point')
    -- create a drawing with a line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- draw a line
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_name_point/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_name_point/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_name_point/baseline/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_name_point/baseline/p1:x')
    check_eq(p1.y, 6, 'F - test_name_point/baseline/p1:y')
    check_eq(p2.x, 35, 'F - test_name_point/baseline/p2:x')
    check_eq(p2.y, 36, 'F - test_name_point/baseline/p2:y')
    check_nil(p2.name, 'F - test_name_point/baseline/p2:name')
    -- enter 'name' mode without moving the mouse
    edit.run_after_keychord(Editor_state, 'C-n')
    check_eq(Editor_state.current_drawing_mode, 'name', 'F - test_name_point/mode:1')
    edit.run_after_textinput(Editor_state, 'A')
    check_eq(p2.name, 'A', 'F - test_name_point')
    -- still in 'name' mode
    check_eq(Editor_state.current_drawing_mode, 'name', 'F - test_name_point/mode:2')
    -- exit 'name' mode
    edit.run_after_keychord(Editor_state, 'return')
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_name_point/mode:3')
    check_eq(p2.name, 'A', 'F - test_name_point')
    -- wait until save
  • edit in drawing_tests.lua at line 434
    [3.1007]
    [3.1008]
    edit.update(Editor_state, 0)
    -- change is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.name, 'A', 'F - test_name_point/save')
    end
    function test_move_point()
    io.write('\ntest_move_point')
    -- create a drawing with a line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_move_point/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_move_point/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point/baseline/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_move_point/baseline/p1:x')
    check_eq(p1.y, 6, 'F - test_move_point/baseline/p1:y')
    check_eq(p2.x, 35, 'F - test_move_point/baseline/p2:x')
    check_eq(p2.y, 36, 'F - test_move_point/baseline/p2:y')
    -- wait until save
  • edit in drawing_tests.lua at line 466
    [3.1044]
    [3.1045]
    edit.update(Editor_state, 0)
    -- line is saved to disk
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local drawing = Editor_state.lines[1]
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.x, 35, 'F - test_move_point/save/x')
    check_eq(p2.y, 36, 'F - test_move_point/save/y')
    edit.draw(Editor_state)
    -- enter 'move' mode without moving the mouse
    edit.run_after_keychord(Editor_state, 'C-u')
    check_eq(Editor_state.current_drawing_mode, 'move', 'F - test_move_point/mode:1')
    -- point is lifted
    check_eq(drawing.pending.mode, 'move', 'F - test_move_point/mode:2')
    check_eq(drawing.pending.target_point, p2, 'F - test_move_point/target')
    -- move point
    App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
    edit.update(Editor_state, 0.05)
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p2.x, 26, 'F - test_move_point/x')
    check_eq(p2.y, 44, 'F - test_move_point/y')
    -- exit 'move' mode
    edit.run_after_mouse_click(Editor_state, Editor_state.left+26, Editor_state.top+Drawing_padding_top+44, 1)
    check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_move_point/mode:3')
    check_eq(drawing.pending, {}, 'F - test_move_point/pending')
    -- wait until save
  • edit in drawing_tests.lua at line 493
    [3.1081]
    [3.1082]
    edit.update(Editor_state, 0)
    -- change is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.x, 26, 'F - test_move_point/save/x')
    check_eq(p2.y, 44, 'F - test_move_point/save/y')
    end
    function test_move_point_on_manhattan_line()
    io.write('\ntest_move_point_on_manhattan_line')
    -- create a drawing with a manhattan line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'manhattan'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+46, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_move_point_on_manhattan_line/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_move_point_on_manhattan_line/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_move_point_on_manhattan_line/baseline/shape:1')
    edit.draw(Editor_state)
    -- enter 'move' mode
    edit.run_after_keychord(Editor_state, 'C-u')
    check_eq(Editor_state.current_drawing_mode, 'move', 'F - test_move_point_on_manhattan_line/mode:1')
    -- move point
    App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
    edit.update(Editor_state, 0.05)
    -- line is no longer manhattan
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point_on_manhattan_line/baseline/shape:1')
    end
    function test_delete_lines_at_point()
    io.write('\ntest_delete_lines_at_point')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 2, 'F - test_delete_lines_at_point/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_delete_lines_at_point/baseline/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_lines_at_point/baseline/shape:2')
    -- hover on the common point and delete
    App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'C-d')
    check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_lines_at_point/shape:1')
    check_eq(drawing.shapes[2].mode, 'deleted', 'F - test_delete_lines_at_point/shape:2')
    -- wait for some time
  • edit in drawing_tests.lua at line 554
    [3.1118]
    [3.1119]
    edit.update(Editor_state, 0)
    -- deleted points disappear after file is reloaded
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_delete_lines_at_point/save')
    end
    function test_delete_line_under_mouse_pointer()
    io.write('\ntest_delete_line_under_mouse_pointer')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 2, 'F - test_delete_line_under_mouse_pointer/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_delete_line_under_mouse_pointer/baseline/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_line_under_mouse_pointer/baseline/shape:2')
    -- hover on one of the lines and delete
    App.mouse_move(Editor_state.left+25, Editor_state.top+Drawing_padding_top+26)
    edit.run_after_keychord(Editor_state, 'C-d')
    -- only that line is deleted
    check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_line_under_mouse_pointer/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_line_under_mouse_pointer/shape:2')
    end
    function test_delete_point_from_polygon()
    io.write('\ntest_delete_point_from_polygon')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_keychord(Editor_state, 'g') -- polygon mode
    -- second point
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'p') -- add point
    -- third point
    App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+26)
    edit.run_after_keychord(Editor_state, 'p') -- add point
    -- fourth point
    edit.run_after_mouse_release(Editor_state, Editor_state.left+14, Editor_state.top+Drawing_padding_top+16, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_delete_point_from_polygon/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/baseline/mode')
    check_eq(#drawing.shapes[1].vertices, 4, 'F - test_delete_point_from_polygon/baseline/vertices')
    -- hover on a point and delete
    App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+26)
    edit.run_after_keychord(Editor_state, 'C-d')
    -- just the one point is deleted
    check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/shape')
    check_eq(#drawing.shapes[1].vertices, 3, 'F - test_delete_point_from_polygon/vertices')
    end
    function test_delete_point_from_polygon()
    io.write('\ntest_delete_point_from_polygon')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- first point
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_keychord(Editor_state, 'g') -- polygon mode
    -- second point
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'p') -- add point
    -- third point
    edit.run_after_mouse_release(Editor_state, Editor_state.left+14, Editor_state.top+Drawing_padding_top+16, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_delete_point_from_polygon/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/baseline/mode')
    check_eq(#drawing.shapes[1].vertices, 3, 'F - test_delete_point_from_polygon/baseline/vertices')
    -- hover on a point and delete
    App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'C-d')
    -- there's < 3 points left, so the whole polygon is deleted
    check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_point_from_polygon')
    end
    function test_undo_name_point()
    io.write('\ntest_undo_name_point')
    -- create a drawing with a line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    -- draw a line
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_undo_name_point/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_undo_name_point/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_name_point/baseline/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_undo_name_point/baseline/p1:x')
    check_eq(p1.y, 6, 'F - test_undo_name_point/baseline/p1:y')
    check_eq(p2.x, 35, 'F - test_undo_name_point/baseline/p2:x')
    check_eq(p2.y, 36, 'F - test_undo_name_point/baseline/p2:y')
    check_nil(p2.name, 'F - test_undo_name_point/baseline/p2:name')
    check_eq(#Editor_state.history, 1, 'F - test_undo_name_point/baseline/history:1')
    --? print('a', Editor_state.lines.current_drawing)
    -- enter 'name' mode without moving the mouse
    edit.run_after_keychord(Editor_state, 'C-n')
    edit.run_after_textinput(Editor_state, 'A')
    edit.run_after_keychord(Editor_state, 'return')
    check_eq(p2.name, 'A', 'F - test_undo_name_point/baseline')
    check_eq(#Editor_state.history, 3, 'F - test_undo_name_point/baseline/history:2')
    check_eq(Editor_state.next_history, 4, 'F - test_undo_name_point/baseline/next_history')
    --? print('b', Editor_state.lines.current_drawing)
    -- undo
    edit.run_after_keychord(Editor_state, 'C-z')
    local drawing = Editor_state.lines[1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(Editor_state.next_history, 3, 'F - test_undo_name_point/next_history')
    check_eq(p2.name, '', 'F - test_undo_name_point') -- not quite what it was before, but close enough
    -- wait until save
  • edit in drawing_tests.lua at line 688
    [3.1155]
    [3.1156]
    edit.update(Editor_state, 0)
    -- undo is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.name, '', 'F - test_undo_name_point/save')
    end
    function test_undo_move_point()
    io.write('\ntest_undo_move_point')
    -- create a drawing with a line
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 1, 'F - test_undo_move_point/baseline/#shapes')
    check_eq(#drawing.points, 2, 'F - test_undo_move_point/baseline/#points')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_move_point/baseline/shape:1')
    local p1 = drawing.points[drawing.shapes[1].p1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p1.x, 5, 'F - test_undo_move_point/baseline/p1:x')
    check_eq(p1.y, 6, 'F - test_undo_move_point/baseline/p1:y')
    check_eq(p2.x, 35, 'F - test_undo_move_point/baseline/p2:x')
    check_eq(p2.y, 36, 'F - test_undo_move_point/baseline/p2:y')
    check_nil(p2.name, 'F - test_undo_move_point/baseline/p2:name')
    -- move p2
    edit.run_after_keychord(Editor_state, 'C-u')
    App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
    edit.update(Editor_state, 0.05)
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(p2.x, 26, 'F - test_undo_move_point/x')
    check_eq(p2.y, 44, 'F - test_undo_move_point/y')
    -- exit 'move' mode
    edit.run_after_mouse_click(Editor_state, Editor_state.left+26, Editor_state.top+Drawing_padding_top+44, 1)
    check_eq(Editor_state.next_history, 4, 'F - test_undo_move_point/next_history')
    -- undo
    edit.run_after_keychord(Editor_state, 'C-z')
    edit.run_after_keychord(Editor_state, 'C-z') -- bug: need to undo twice
    local drawing = Editor_state.lines[1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(Editor_state.next_history, 2, 'F - test_undo_move_point/next_history')
    check_eq(p2.x, 35, 'F - test_undo_move_point/x')
    check_eq(p2.y, 36, 'F - test_undo_move_point/y')
    -- wait until save
  • edit in drawing_tests.lua at line 739
    [3.1192]
    [3.1193]
    edit.update(Editor_state, 0)
    -- undo is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
    check_eq(p2.x, 35, 'F - test_undo_move_point/save/x')
    check_eq(p2.y, 36, 'F - test_undo_move_point/save/y')
    end
    function test_undo_delete_point()
    io.write('\ntest_undo_delete_point')
    -- create a drawing with two lines connected at a point
    App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
    Editor_state = edit.initialize_test_state()
    Editor_state.filename = 'foo'
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    Editor_state.current_drawing_mode = 'line'
    edit.draw(Editor_state)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
    edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
    local drawing = Editor_state.lines[1]
    check_eq(#drawing.shapes, 2, 'F - test_undo_delete_point/baseline/#shapes')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_delete_point/baseline/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/baseline/shape:2')
    -- hover on the common point and delete
    App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+36)
    edit.run_after_keychord(Editor_state, 'C-d')
    check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_undo_delete_point/shape:1')
    check_eq(drawing.shapes[2].mode, 'deleted', 'F - test_undo_delete_point/shape:2')
    -- undo
    edit.run_after_keychord(Editor_state, 'C-z')
    local drawing = Editor_state.lines[1]
    local p2 = drawing.points[drawing.shapes[1].p2]
    check_eq(Editor_state.next_history, 3, 'F - test_undo_move_point/next_history')
    check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_delete_point/shape:1')
    check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/shape:2')
    -- wait until save
  • edit in drawing_tests.lua at line 780
    [3.1229]
    edit.update(Editor_state, 0)
    -- undo is saved
    load_from_disk(Editor_state)
    Text.redraw_all(Editor_state)
    check_eq(#Editor_state.lines[1].shapes, 2, 'F - test_undo_delete_point/save')
    end