support drawings in the source editor

[?]
Sep 5, 2022, 6:28 PM
OI4FPFINEROK6GNDEMOBTGSPYIULCLRGGT5W3H7VLM7VFH22GMWQC

Dependencies

  • [2] UN7L3DNN avoid some string concatenations
  • [3] UPCIYZEU drop an unnecessary level of indent
  • [4] E4HEHLRT extract a variable
  • [5] KV7GGVER couple of accidental globals
  • [6] KKMFQDR4 editing source code from within the app
  • [7] 5DOTWNVM right margin
  • [8] QCPXQ2E3 add state arg to a few functions
  • [9] V5MJRFOZ bugfix: down arrow doesn't scroll up unnecessarily
  • [10] VSBSWTE4 bugfix: where cursor is drawn
  • [11] PX3736DX better error message
  • [12] PFT5Y2ZY move
  • [13] PV2YA7KS subsection headings in a long switch
  • [14] SVJZZDC3 snapshot - no, that's all wrong
  • [15] ZPUQSPQP extract a few methods
  • [16] WQOSZSUE warn on unused commandline args
  • [17] KZ5GAYRP this fixes the immediate regression
  • [18] VHQCNMAR several more modules
  • [19] EGH7XDBK support non-text lines in Text.to2
  • [20] M6TH7VSZ rip out notion of Line_width
  • [21] LF7BWEG4 group all editor globals
  • [22] WJBZZQE4 fold together two largely similar cases
  • [23] NDHQN23G done passing left/right margins everywhere
  • [24] MXA3RZYK deduce left/right from state where possible
  • [25] ODLKHO7B switch to line index in a function
  • [26] HGC5RGJP switch to line index in a function
  • [27] ILOA5BYF separate data structure for each line's cache data
  • [28] KURLAXXI clean up some prints
  • [29] 2RXZ3PGO beginning of a new approach to scroll+wrap
  • [30] EAEGCJV5 rename
  • [31] KOYAJWE4 extract a couple more methods
  • [32] X3F7ECSL add state arg to some functions
  • [33] X3CQLBTR set window title within each app
  • [34] IMEJA43L snapshot
  • [35] KECEMMMR extract couple of functions
  • [36] 2L5MEZV3 experiment: new edit namespace
  • [37] CVSRHMJ2 experiment: slightly adaptive scrolling
  • [38] 2LOQ5ALJ add args to some functions
  • [39] LNUHQOGH start passing in Editor_state explicitly
  • [40] QYIFOHW3 first test!
  • [41] Z5HLXU4P add state arg to a few functions
  • [42] F65ADDGL add state arg to a few functions
  • [43] LSYLEVBD drop some redundant args when clearing the cache
  • [44] HOSPP2AN crisp font rendering
  • [45] SPNMXTYR have file API operate on state object
  • [46] 5USLYLBV duplicate
  • [*] BULPIBEG beginnings of a module for the text editor
  • [*] GNQC72UX generalize a function
  • [*] KOTI3MFG bugfix in previous commit
  • [*] OTIBCAUJ love2d scaffold
  • [*] K464QQR4 more defensive resize handling

Change contents

  • replacement in text.lua at line 118
    [7.2940][7.211:288]()
    --? print('x: '..tostring(x)..'; '..tostring(State.right-x)..'px to go')
    [7.2940]
    [3.3]
    --? print('x: '..tostring(x)..'; frag_width: '..tostring(frag_width)..'; '..tostring(State.right-x)..'px to go')
  • replacement in text.lua at line 368
    [7.302][7.2495:2563](),[7.2495][7.2495:2563]()
    State.cursor1.line = State.cursor1.line+1
    State.cursor1.pos = 1
    [7.242]
    [7.46]
    State.cursor1 = {line=State.cursor1.line+1, pos=1}
  • replacement in text.lua at line 388
    [7.858][7.3130:3220](),[7.3130][7.3130:3220]()
    State.cursor1.line = State.screen_top1.line
    State.cursor1.pos = State.screen_top1.pos
    [7.858]
    [7.537]
    State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
  • replacement in text.lua at line 407
    [7.3234][7.3506:3614]()
    State.screen_top1.line = State.screen_bottom1.line
    State.screen_top1.pos = State.screen_bottom1.pos
    [7.3234]
    [7.3318]
    State.screen_top1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos}
  • replacement in text.lua at line 410
    [7.3692][7.3692:3782]()
    State.cursor1.line = State.screen_top1.line
    State.cursor1.pos = State.screen_top1.pos
    [7.3692]
    [7.707]
    State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
  • replacement in text.lua at line 429
    [7.657][7.4137:4182]()
    State.cursor1.line = new_cursor_line
    [7.657]
    [7.208]
    State.cursor1 = {line=State.cursor1.line-1, pos=nil}
  • replacement in text.lua at line 468
    [7.6283][7.6283:6328](),[7.6328][7.1332:1450]()
    State.cursor1.line = new_cursor_line
    State.cursor1.pos = Text.nearest_cursor_pos(State.lines[State.cursor1.line].data, State.cursor_x, State.left)
    [7.6283]
    [7.6440]
    State.cursor1 = {
    line = new_cursor_line,
    pos = Text.nearest_cursor_pos(State.lines[new_cursor_line].data, State.cursor_x, State.left),
    }
  • edit in text.lua at line 487
    [49.224]
    [5.128]
    Text.populate_screen_line_starting_pos(State, State.cursor1.line)
  • replacement in text.lua at line 584
    [7.428][7.428:552]()
    State.cursor1.line = new_cursor_line
    State.cursor1.pos = utf8.len(State.lines[State.cursor1.line].data) + 1
    [7.428]
    [7.446]
    State.cursor1 = {
    line = new_cursor_line,
    pos = utf8.len(State.lines[new_cursor_line].data) + 1,
    }
  • replacement in text.lua at line 615
    [7.1156][7.1156:1231]()
    State.cursor1.line = new_cursor_line
    State.cursor1.pos = 1
    [7.1156]
    [7.984]
    State.cursor1 = {line=new_cursor_line, pos=1}
  • edit in text.lua at line 666
    [7.2786]
    [7.2786]
    --? print('to2:', State.cursor1.line, State.cursor1.pos)
  • edit in text.lua at line 668
    [7.2832]
    [50.533]
    --? print('to2: =>', top2.line, top2.screen_line, top2.screen_pos)
    -- slide to start of screen line
  • edit in text.lua at line 671
    [50.580]
    [7.3087]
    --? print('snap', State.screen_top1.line, State.screen_top1.pos, State.screen_top1.posB, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
  • edit in text.lua at line 701
    [7.3781]
    [7.3781]
    --? print('snap =>', State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos, State.screen_bottom1.line, State.screen_bottom1.pos)
  • replacement in text.lua at line 861
    [7.109][7.143:192]()
    local result = {line=loc1.line, screen_line=1}
    [7.109]
    [4.3]
    local result = {line=loc1.line}
  • edit in source_undo.lua at line 53
    [6.1787]
    [6.1787]
    current_drawing_mode=Drawing_mode,
    previous_drawing_mode=State.previous_drawing_mode,
  • replacement in source_undo.lua at line 63
    [6.2014][6.2014:2080]()
    table.insert(event.lines, {data=line.data, dataB=line.dataB})
    [6.2014]
    [6.2080]
    if line.mode == 'text' then
    table.insert(event.lines, {mode='text', data=line.data, dataB=line.dataB})
    elseif line.mode == 'drawing' then
    local points=deepcopy(line.points)
    --? print('copying', line.points, 'with', #line.points, 'points into', points)
    local shapes=deepcopy(line.shapes)
    --? print('copying', line.shapes, 'with', #line.shapes, 'shapes into', shapes)
    table.insert(event.lines, {mode='drawing', h=line.h, points=points, shapes=shapes, pending={}})
    --? table.insert(event.lines, {mode='drawing', h=line.h, points=deepcopy(line.points), shapes=deepcopy(line.shapes), pending={}})
    else
    print(line.mode)
    assert(false)
    end
  • edit in source_text_tests.lua at line 15
    [6.4179]
    [6.4179]
    end
    function test_click_to_create_drawing()
    io.write('\ntest_click_to_create_drawing')
    App.screen.init{width=120, height=60}
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{}
    Text.redraw_all(Editor_state)
    edit.draw(Editor_state)
    edit.run_after_mouse_click(Editor_state, 8,Editor_state.top+8, 1)
    -- cursor skips drawing to always remain on text
    check_eq(#Editor_state.lines, 2, 'F - test_click_to_create_drawing/#lines')
    check_eq(Editor_state.cursor1.line, 2, 'F - test_click_to_create_drawing/cursor')
    end
    function test_backspace_to_delete_drawing()
    io.write('\ntest_backspace_to_delete_drawing')
    -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
    App.screen.init{width=120, height=60}
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'```lines', '```', ''}
    Text.redraw_all(Editor_state)
    -- cursor is on text as always (outside tests this will get initialized correctly)
    Editor_state.cursor1.line = 2
    -- backspacing deletes the drawing
    edit.run_after_keychord(Editor_state, 'backspace')
    check_eq(#Editor_state.lines, 1, 'F - test_backspace_to_delete_drawing/#lines')
    check_eq(Editor_state.cursor1.line, 1, 'F - test_backspace_to_delete_drawing/cursor')
  • edit in source_text_tests.lua at line 724
    [6.34188]
    [6.34188]
    end
    function test_pagedown_skips_drawings()
    io.write('\ntest_pagedown_skips_drawings')
    -- some lines of text with a drawing intermixed
    local drawing_width = 50
    App.screen.init{width=Editor_state.left+drawing_width, height=80}
    Editor_state = edit.initialize_test_state()
    Editor_state.lines = load_array{'abc', -- height 15
    '```lines', '```', -- height 25
    'def', -- height 15
    'ghi'} -- height 15
    Text.redraw_all(Editor_state)
    check_eq(Editor_state.lines[2].mode, 'drawing', 'F - test_pagedown_skips_drawings/baseline/lines')
    Editor_state.cursor1 = {line=1, pos=1}
    Editor_state.screen_top1 = {line=1, pos=1}
    Editor_state.screen_bottom1 = {}
    local drawing_height = Drawing_padding_height + drawing_width/2 -- default
    -- initially the screen displays the first line and the drawing
    -- 15px margin + 15px line1 + 10px margin + 25px drawing + 10px margin = 75px < screen height 80px
    edit.draw(Editor_state)
    local y = Editor_state.top
    App.screen.check(y, 'abc', 'F - test_pagedown_skips_drawings/baseline/screen:1')
    -- after pagedown the screen draws the drawing up top
    -- 15px margin + 10px margin + 25px drawing + 10px margin + 15px line3 = 75px < screen height 80px
    edit.run_after_keychord(Editor_state, 'pagedown')
    check_eq(Editor_state.screen_top1.line, 2, 'F - test_pagedown_skips_drawings/screen_top')
    check_eq(Editor_state.cursor1.line, 3, 'F - test_pagedown_skips_drawings/cursor')
    y = Editor_state.top + drawing_height
    App.screen.check(y, 'def', 'F - test_pagedown_skips_drawings/screen:1')
  • replacement in source_text_tests.lua at line 1588
    [6.80428][6.80428:80490]()
    Editor_state.lines = load_array{'abc', 'def', 'ghi', 'deg'}
    [6.80428]
    [6.80490]
    Editor_state.lines = load_array{'```lines', '```', 'def', 'ghi', 'deg'}
  • edit in source_text.lua at line 56
    [6.85853][6.85853:86007]()
    --? if Foo then
    --? print('draw:', State.lines[line_index].data, "=====", State.lines[line_index].dataB, 'starting from x', x+AB_padding)
    --? end
  • edit in source_text.lua at line 196
    [6.91485]
    [6.91485]
    if line.mode ~= 'text' then return end
  • edit in source_text.lua at line 223
    [6.92319]
    [6.92319]
    if line.mode ~= 'text' then return end
  • replacement in source_text.lua at line 418
    [6.101765][6.101765:102095]()
    -- join lines
    State.cursor1.pos = utf8.len(State.lines[State.cursor1.line-1].data)+1
    State.lines[State.cursor1.line-1].data = State.lines[State.cursor1.line-1].data..State.lines[State.cursor1.line].data
    table.remove(State.lines, State.cursor1.line)
    table.remove(State.line_cache, State.cursor1.line)
    [6.101765]
    [6.102095]
    if State.lines[State.cursor1.line-1].mode == 'drawing' then
    table.remove(State.lines, State.cursor1.line-1)
    table.remove(State.line_cache, State.cursor1.line-1)
    else
    -- join lines
    State.cursor1.pos = utf8.len(State.lines[State.cursor1.line-1].data)+1
    State.lines[State.cursor1.line-1].data = State.lines[State.cursor1.line-1].data..State.lines[State.cursor1.line].data
    table.remove(State.lines, State.cursor1.line)
    table.remove(State.line_cache, State.cursor1.line)
    end
  • replacement in source_text.lua at line 478
    [6.104895][6.104895:105160]()
    -- join lines
    State.lines[State.cursor1.line].data = State.lines[State.cursor1.line].data..State.lines[State.cursor1.line+1].data
    -- delete side B on first line
    State.lines[State.cursor1.line].dataB = State.lines[State.cursor1.line+1].dataB
    [6.104895]
    [6.105160]
    if State.lines[State.cursor1.line+1].mode == 'text' then
    -- join lines
    State.lines[State.cursor1.line].data = State.lines[State.cursor1.line].data..State.lines[State.cursor1.line+1].data
    -- delete side B on first line
    State.lines[State.cursor1.line].dataB = State.lines[State.cursor1.line+1].dataB
    end
  • replacement in source_text.lua at line 539
    [6.106902][6.106902:107069]()
    table.insert(State.lines, State.cursor1.line+1, {data=string.sub(State.lines[State.cursor1.line].data, byte_offset), dataB=State.lines[State.cursor1.line].dataB})
    [6.106902]
    [6.107069]
    table.insert(State.lines, State.cursor1.line+1, {mode='text', data=string.sub(State.lines[State.cursor1.line].data, byte_offset), dataB=State.lines[State.cursor1.line].dataB})
  • replacement in source_text.lua at line 559
    [6.107889][6.107889:107919]()
    y = y - State.line_height
    [6.107889]
    [6.107919]
    if State.lines[State.screen_top1.line].mode == 'text' then
    y = y - State.line_height
    elseif State.lines[State.screen_top1.line].mode == 'drawing' then
    y = y - Drawing_padding_height - Drawing.pixels(State.lines[State.screen_top1.line].h, State.width)
    end
  • replacement in source_text.lua at line 580
    [6.108572][6.108572:108659]()
    State.screen_top1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos}
    [6.108572]
    [6.108659]
    State.screen_top1 = {line=State.screen_bottom1.line, pos=State.screen_bottom1.pos, posB=State.screen_bottom1.posB}
  • edit in source_text.lua at line 591
    [6.109127]
    [6.109127]
    assert(State.lines[State.cursor1.line].mode == 'text')
  • replacement in source_text.lua at line 605
    [6.109599][6.109599:110479]()
    if State.cursor1.line > 1 then
    --? print('found previous text line')
    State.cursor1 = {line=State.cursor1.line-1, pos=nil}
    Text.populate_screen_line_starting_pos(State, State.cursor1.line)
    -- previous text line found, pick its final screen line
    --? print('has multiple screen lines')
    local screen_line_starting_pos = State.line_cache[State.cursor1.line].screen_line_starting_pos
    --? print(#screen_line_starting_pos)
    screen_line_starting_pos = screen_line_starting_pos[#screen_line_starting_pos]
    local screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line].data, screen_line_starting_pos)
    local s = string.sub(State.lines[State.cursor1.line].data, screen_line_starting_byte_offset)
    State.cursor1.pos = screen_line_starting_pos + Text.nearest_cursor_pos(s, State.cursor_x, State.left) - 1
    [6.109599]
    [6.110479]
    local new_cursor_line = State.cursor1.line
    while new_cursor_line > 1 do
    new_cursor_line = new_cursor_line-1
    if State.lines[new_cursor_line].mode == 'text' then
    --? print('found previous text line')
    State.cursor1 = {line=State.cursor1.line-1, pos=nil}
    Text.populate_screen_line_starting_pos(State, State.cursor1.line)
    -- previous text line found, pick its final screen line
    --? print('has multiple screen lines')
    local screen_line_starting_pos = State.line_cache[State.cursor1.line].screen_line_starting_pos
    --? print(#screen_line_starting_pos)
    screen_line_starting_pos = screen_line_starting_pos[#screen_line_starting_pos]
    local screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line].data, screen_line_starting_pos)
    local s = string.sub(State.lines[State.cursor1.line].data, screen_line_starting_byte_offset)
    State.cursor1.pos = screen_line_starting_pos + Text.nearest_cursor_pos(s, State.cursor_x, State.left) - 1
    break
    end
  • replacement in source_text.lua at line 645
    [6.111628][6.111628:112363]()
    if State.cursor1.line > 1 then
    State.cursor1.line = State.cursor1.line-1
    State.cursor1.posB = nil
    Text.populate_screen_line_starting_pos(State, State.cursor1.line)
    local prev_line_cache = State.line_cache[State.cursor1.line]
    local prev_screen_line_starting_pos = prev_line_cache.screen_line_starting_pos[#prev_line_cache.screen_line_starting_pos]
    local prev_screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line].data, prev_screen_line_starting_pos)
    local s = string.sub(State.lines[State.cursor1.line].data, prev_screen_line_starting_byte_offset)
    State.cursor1.pos = prev_screen_line_starting_pos + Text.nearest_cursor_pos(s, State.cursor_x, State.left) - 1
    [6.111628]
    [6.112363]
    local new_cursor_line = State.cursor1.line
    while new_cursor_line > 1 do
    new_cursor_line = new_cursor_line-1
    if State.lines[new_cursor_line].mode == 'text' then
    State.cursor1 = {line=State.cursor1.line-1, posB=nil}
    Text.populate_screen_line_starting_pos(State, State.cursor1.line)
    local prev_line_cache = State.line_cache[State.cursor1.line]
    local prev_screen_line_starting_pos = prev_line_cache.screen_line_starting_pos[#prev_line_cache.screen_line_starting_pos]
    local prev_screen_line_starting_byte_offset = Text.offset(State.lines[State.cursor1.line].data, prev_screen_line_starting_pos)
    local s = string.sub(State.lines[State.cursor1.line].data, prev_screen_line_starting_byte_offset)
    State.cursor1.pos = prev_screen_line_starting_pos + Text.nearest_cursor_pos(s, State.cursor_x, State.left) - 1
    break
    end
  • edit in source_text.lua at line 696
    [6.114836]
    [6.114836]
    assert(State.lines[State.cursor1.line].mode == 'text')
  • replacement in source_text.lua at line 701
    [6.115146][6.115146:115402]()
    if State.cursor1.line < #State.lines then
    State.cursor1 = {
    line = State.cursor1.line+1,
    pos = Text.nearest_cursor_pos(State.lines[State.cursor1.line+1].data, State.cursor_x, State.left)
    }
    --? print(State.cursor1.pos)
    [6.115146]
    [6.115402]
    local new_cursor_line = State.cursor1.line
    while new_cursor_line < #State.lines do
    new_cursor_line = new_cursor_line+1
    if State.lines[new_cursor_line].mode == 'text' then
    State.cursor1 = {
    line = new_cursor_line,
    pos = Text.nearest_cursor_pos(State.lines[new_cursor_line].data, State.cursor_x, State.left),
    }
    --? print(State.cursor1.pos)
    break
    end
  • replacement in source_text.lua at line 766
    [6.118525][6.118525:118591]()
    State.screen_top1 = {line=State.cursor1.line, pos=1} -- copy
    [6.118525]
    [6.118591]
    State.screen_top1 = {line=State.cursor1.line, pos=State.cursor1.pos, posB=State.cursor1.posB} -- copy
  • replacement in source_text.lua at line 948
    [6.122940][6.122940:123106]()
    elseif State.cursor1.line > 1 then
    State.cursor1 = {
    line = State.cursor1.line-1,
    pos = utf8.len(State.lines[State.cursor1.line-1].data) + 1,
    }
    [6.122940]
    [6.123106]
    else
    local new_cursor_line = State.cursor1.line
    while new_cursor_line > 1 do
    new_cursor_line = new_cursor_line-1
    if State.lines[new_cursor_line].mode == 'text' then
    State.cursor1 = {
    line = new_cursor_line,
    pos = utf8.len(State.lines[new_cursor_line].data) + 1,
    }
    break
    end
    end
  • edit in source_text.lua at line 991
    [6.123998]
    [6.123998]
    assert(State.lines[State.cursor1.line].mode == 'text')
  • replacement in source_text.lua at line 1002
    [6.124285][6.124285:124391]()
    elseif State.cursor1.line <= #State.lines-1 then
    State.cursor1 = {line=State.cursor1.line+1, pos=1}
    [6.124285]
    [6.124391]
    else
    local new_cursor_line = State.cursor1.line
    while new_cursor_line <= #State.lines-1 do
    new_cursor_line = new_cursor_line+1
    if State.lines[new_cursor_line].mode == 'text' then
    State.cursor1 = {line=new_cursor_line, pos=1}
    break
    end
    end
  • replacement in source_text.lua at line 1017
    [6.124571][6.124571:124622]()
    elseif State.cursor1.line <= #State.lines-1 then
    [6.124571]
    [6.124622]
    else
  • replacement in source_text.lua at line 1019
    [6.124655][6.124655:124710]()
    State.cursor1 = {line=State.cursor1.line+1, pos=1}
    [6.124655]
    [6.124710]
    local new_cursor_line = State.cursor1.line
    while new_cursor_line <= #State.lines-1 do
    new_cursor_line = new_cursor_line+1
    if State.lines[new_cursor_line].mode == 'text' then
    State.cursor1 = {line=new_cursor_line, pos=1}
    break
    end
    end
  • replacement in source_text.lua at line 1078
    [6.126718][6.126718:126778]()
    if State.top > App.screen.height - State.line_height then
    [6.126718]
    [6.126778]
    local y = State.top
    while State.cursor1.line <= #State.lines do
    if State.lines[State.cursor1.line].mode == 'text' then
    break
    end
    --? print('cursor skips', State.cursor1.line)
    y = y + Drawing_padding_height + Drawing.pixels(State.lines[State.cursor1.line].h, State.width)
    State.cursor1.line = State.cursor1.line + 1
    end
    -- hack: insert a text line at bottom of file if necessary
    if State.cursor1.line > #State.lines then
    assert(State.cursor1.line == #State.lines+1)
    table.insert(State.lines, {mode='text', data=''})
    table.insert(State.line_cache, {})
    end
    --? print(y, App.screen.height, App.screen.height-State.line_height)
    if y > App.screen.height - State.line_height then
  • replacement in source_text.lua at line 1119
    [6.127996][6.127996:128070]()
    local h = State.line_height
    if y - h < State.top then
    break
    [6.127996]
    [6.128070]
    if top2.screen_line > 1 or State.lines[top2.line-1].mode == 'text' then
    local h = State.line_height
    if y - h < State.top then
    break
    end
    y = y - h
    else
    assert(top2.line > 1)
    assert(State.lines[top2.line-1].mode == 'drawing')
    -- We currently can't draw partial drawings, so either skip it entirely
    -- or not at all.
    local h = Drawing_padding_height + Drawing.pixels(State.lines[top2.line-1].h, State.width)
    if y - h < State.top then
    break
    end
    --? print('skipping drawing of height', h)
    y = y - h
  • edit in source_text.lua at line 1137
    [6.128078][6.128078:128092]()
    y = y - h
  • edit in source_text.lua at line 1144
    [6.128669][6.128669:128682]()
    Foo = true
  • edit in source_text.lua at line 1417
    [6.139891]
    [6.139891]
    if State.lines[loc1.line].mode == 'drawing' then
    return {line=loc1.line, screen_line=1, screen_pos=1}
    end
  • edit in source_text.lua at line 1530
    [6.142635][6.142635:142654]()
    --? print('a')
  • edit in source_text.lua at line 1532
    [6.142757][6.142757:142776]()
    --? print('b')
  • replacement in source_file.lua at line 28
    [6.150962][6.150962:151123]()
    local line_info = {}
    if line:find(Fold) then
    _, _, line_info.data, line_info.dataB = line:find('([^'..Fold..']*)'..Fold..'([^'..Fold..']*)')
    [6.150962]
    [6.151123]
    if line == '```lines' then -- inflexible with whitespace since these files are always autogenerated
    table.insert(result, load_drawing(infile_next_line))
  • replacement in source_file.lua at line 31
    [6.151134][6.151134:151164]()
    line_info.data = line
    [6.151134]
    [6.151164]
    local line_info = {mode='text'}
    if line:find(Fold) then
    _, _, line_info.data, line_info.dataB = line:find('([^'..Fold..']*)'..Fold..'([^'..Fold..']*)')
    else
    line_info.data = line
    end
    table.insert(result, line_info)
  • edit in source_file.lua at line 39
    [6.151174][6.151174:151212]()
    table.insert(result, line_info)
  • replacement in source_file.lua at line 42
    [6.151249][6.151249:151285]()
    table.insert(result, {data=''})
    [6.151249]
    [6.151285]
    table.insert(result, {mode='text', data=''})
  • replacement in source_file.lua at line 53
    [6.151521][6.151521:151651]()
    outfile:write(line.data)
    if line.dataB and #line.dataB > 0 then
    outfile:write(Fold)
    outfile:write(line.dataB)
    [6.151521]
    [6.151651]
    if line.mode == 'drawing' then
    store_drawing(outfile, line)
    else
    outfile:write(line.data)
    if line.dataB and #line.dataB > 0 then
    outfile:write(Fold)
    outfile:write(line.dataB)
    end
    outfile:write('\n')
  • edit in source_file.lua at line 63
    [6.151659][6.151659:151683]()
    outfile:write('\n')
  • edit in source_file.lua at line 65
    [6.151707]
    [6.151873]
    end
    function load_drawing(infile_next_line)
    local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
    while true do
    local line = infile_next_line()
    assert(line)
    if line == '```' then break end
    local shape = json.decode(line)
    if shape.mode == 'freehand' then
    -- no changes needed
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local name = shape.p1.name
    shape.p1 = Drawing.find_or_insert_point(drawing.points, shape.p1.x, shape.p1.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.p1].name = name
    name = shape.p2.name
    shape.p2 = Drawing.find_or_insert_point(drawing.points, shape.p2.x, shape.p2.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.p2].name = name
    elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
    for i,p in ipairs(shape.vertices) do
    local name = p.name
    shape.vertices[i] = Drawing.find_or_insert_point(drawing.points, p.x,p.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.vertices[i]].name = name
    end
    elseif shape.mode == 'circle' or shape.mode == 'arc' then
    local name = shape.center.name
    shape.center = Drawing.find_or_insert_point(drawing.points, shape.center.x,shape.center.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.center].name = name
    elseif shape.mode == 'deleted' then
    -- ignore
    else
    print(shape.mode)
    assert(false)
    end
    table.insert(drawing.shapes, shape)
    end
    return drawing
    end
    function store_drawing(outfile, drawing)
    outfile:write('```lines\n')
    for _,shape in ipairs(drawing.shapes) do
    if shape.mode == 'freehand' then
    outfile:write(json.encode(shape), '\n')
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local line = json.encode({mode=shape.mode, p1=drawing.points[shape.p1], p2=drawing.points[shape.p2]})
    outfile:write(line, '\n')
    elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
    local obj = {mode=shape.mode, vertices={}}
    for _,p in ipairs(shape.vertices) do
    table.insert(obj.vertices, drawing.points[p])
    end
    local line = json.encode(obj)
    outfile:write(line, '\n')
    elseif shape.mode == 'circle' then
    outfile:write(json.encode({mode=shape.mode, center=drawing.points[shape.center], radius=shape.radius}), '\n')
    elseif shape.mode == 'arc' then
    outfile:write(json.encode({mode=shape.mode, center=drawing.points[shape.center], radius=shape.radius, start_angle=shape.start_angle, end_angle=shape.end_angle}), '\n')
    elseif shape.mode == 'deleted' then
    -- ignore
    else
    print(shape.mode)
    assert(false)
    end
    end
    outfile:write('```\n')
  • replacement in source_file.lua at line 141
    [6.152071][6.152071:152226]()
    local line_info = {}
    if line:find(Fold) then
    _, _, line_info.data, line_info.dataB = line:find('([^'..Fold..']*)'..Fold..'([^'..Fold..']*)')
    [6.152071]
    [6.152226]
    --? print(line)
    if line == '```lines' then -- inflexible with whitespace since these files are always autogenerated
    --? print('inserting drawing')
    i, drawing = load_drawing_from_array(next_line, a, i)
    --? print('i now', i)
    table.insert(result, drawing)
  • replacement in source_file.lua at line 148
    [6.152235][6.152235:152263]()
    line_info.data = line
    [6.152235]
    [6.152263]
    --? print('inserting text')
    local line_info = {mode='text'}
    if line:find(Fold) then
    _, _, line_info.data, line_info.dataB = line:find('([^'..Fold..']*)'..Fold..'([^'..Fold..']*)')
    else
    line_info.data = line
    end
    table.insert(result, line_info)
  • edit in source_file.lua at line 157
    [6.152271][6.152271:152307]()
    table.insert(result, line_info)
  • replacement in source_file.lua at line 159
    [6.152336][6.152336:152372]()
    table.insert(result, {data=''})
    [6.152336]
    [6.152372]
    table.insert(result, {mode='text', data=''})
  • edit in source_file.lua at line 163
    [6.152398]
    function load_drawing_from_array(iter, a, i)
    local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
    local line
    while true do
    i, line = iter(a, i)
    assert(i)
    --? print(i)
    if line == '```' then break end
    local shape = json.decode(line)
    if shape.mode == 'freehand' then
    -- no changes needed
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local name = shape.p1.name
    shape.p1 = Drawing.find_or_insert_point(drawing.points, shape.p1.x, shape.p1.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.p1].name = name
    name = shape.p2.name
    shape.p2 = Drawing.find_or_insert_point(drawing.points, shape.p2.x, shape.p2.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.p2].name = name
    elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
    for i,p in ipairs(shape.vertices) do
    local name = p.name
    shape.vertices[i] = Drawing.find_or_insert_point(drawing.points, p.x,p.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.vertices[i]].name = name
    end
    elseif shape.mode == 'circle' or shape.mode == 'arc' then
    local name = shape.center.name
    shape.center = Drawing.find_or_insert_point(drawing.points, shape.center.x,shape.center.y, --[[large width to minimize overlap]] 1600)
    drawing.points[shape.center].name = name
    elseif shape.mode == 'deleted' then
    -- ignore
    else
    print(shape.mode)
    assert(false)
    end
    table.insert(drawing.shapes, shape)
    end
    return i, drawing
    end
  • edit in source_edit.lua at line 4
    [6.152546]
    [6.152546]
    Stroke_color = {r=0, g=0, b=0}
    Current_stroke_color = {r=0.7, g=0.7, b=0.7} -- in process of being drawn
    Current_name_background_color = {r=1, g=0, b=0, a=0.1} -- name currently being edited
  • edit in source_edit.lua at line 9
    [6.152673]
    [6.152673]
    Icon_color = {r=0.7, g=0.7, b=0.7} -- color of current mode icon in drawings
    Help_color = {r=0, g=0.5, b=0}
    Help_background_color = {r=0, g=0.5, b=0, a=0.1}
  • edit in source_edit.lua at line 18
    [6.152798]
    [6.152798]
    Drawing_padding_top = 10
    Drawing_padding_bottom = 10
    Drawing_padding_height = Drawing_padding_top + Drawing_padding_bottom
  • edit in source_edit.lua at line 23
    [6.152799]
    [6.152799]
    Same_point_distance = 4 -- pixel distance at which two points are considered the same
  • replacement in source_edit.lua at line 30
    [6.152987][6.152987:153197]()
    -- a line of bifold text consists of an A side and an optional B side, each of which is a string
    -- expanded: whether to show B side
    lines = {{data='', dataB=nil, expanded=nil}}, -- array of lines
    [6.152987]
    [6.153197]
    -- a line is either bifold text or a drawing
    -- a line of bifold text consists of an A side and an optional B side
    -- mode = 'text',
    -- string data,
    -- string dataB,
    -- expanded: whether to show B side
    -- a drawing is a table with:
    -- mode = 'drawing'
    -- a (y) coord in pixels (updated while painting screen),
    -- a (h)eight,
    -- an array of points, and
    -- an array of shapes
    -- a shape is a table containing:
    -- a mode
    -- an array points for mode 'freehand' (raw x,y coords; freehand drawings don't pollute the points array of a drawing)
    -- an array vertices for mode 'polygon', 'rectangle', 'square'
    -- p1, p2 for mode 'line'
    -- center, radius for mode 'circle'
    -- center, radius, start_angle, end_angle for mode 'arc'
    -- Unless otherwise specified, coord fields are normalized; a drawing is always 256 units wide
    -- The field names are carefully chosen so that switching modes in midstream
    -- remembers previously entered points where that makes sense.
    lines = {{mode='text', data='', dataB=nil, expanded=nil}}, -- array of lines
  • edit in source_edit.lua at line 82
    [6.154804]
    [6.154804]
    current_drawing_mode = 'line',
    previous_drawing_mode = nil, -- extra state for some ephemeral modes like moving/deleting/naming points
  • edit in source_edit.lua at line 109
    [6.155350]
    [6.155350]
    function edit.fixup_cursor(State)
    for i,line in ipairs(State.lines) do
    if line.mode == 'text' then
    State.cursor1.line = i
    break
    end
    end
    end
  • replacement in source_edit.lua at line 132
    [6.155884][6.155884:155928]()
    --? print('draw:', y, line_index, line)
    [6.155884]
    [6.155928]
    --? print('draw:', y, line_index, line, line.mode)
  • edit in source_edit.lua at line 135
    [6.156056]
    [6.156056]
    if line.mode == 'text' then
  • replacement in source_edit.lua at line 137
    [6.156098][6.156098:156332]()
    local startpos, startposB = 1, nil
    if line_index == State.screen_top1.line then
    if State.screen_top1.pos then
    startpos = State.screen_top1.pos
    else
    startpos, startposB = nil, State.screen_top1.posB
    [6.156098]
    [6.156332]
    local startpos, startposB = 1, nil
    if line_index == State.screen_top1.line then
    if State.screen_top1.pos then
    startpos = State.screen_top1.pos
    else
    startpos, startposB = nil, State.screen_top1.posB
    end
    end
    if line.data == '' then
    -- button to insert new drawing
    button(State, 'draw', {x=4,y=y+4, w=12,h=12, color={1,1,0},
    icon = icon.insert_drawing,
    onpress1 = function()
    Drawing.before = snapshot(State, line_index-1, line_index)
    table.insert(State.lines, line_index, {mode='drawing', y=y, h=256/2, points={}, shapes={}, pending={}})
    table.insert(State.line_cache, line_index, {})
    if State.cursor1.line >= line_index then
    State.cursor1.line = State.cursor1.line+1
    end
    schedule_save(State)
    record_undo_event(State, {before=Drawing.before, after=snapshot(State, line_index-1, line_index+1)})
    end,
    })
  • edit in source_edit.lua at line 161
    [6.156342]
    [6.156342]
    y, State.screen_bottom1.pos, State.screen_bottom1.posB = Text.draw(State, line_index, y, startpos, startposB)
    y = y + State.line_height
    --? print('=> y', y)
    elseif line.mode == 'drawing' then
    y = y+Drawing_padding_top
    Drawing.draw(State, line_index, y)
    y = y + Drawing.pixels(line.h, State.width) + Drawing_padding_bottom
    else
    print(line.mode)
    assert(false)
  • edit in source_edit.lua at line 172
    [6.156350][6.156350:156519]()
    y, State.screen_bottom1.pos, State.screen_bottom1.posB = Text.draw(State, line_index, y, startpos, startposB)
    y = y + State.line_height
    --? print('=> y', y)
  • edit in source_edit.lua at line 179
    [6.156628]
    [6.156628]
    Drawing.update(State, dt)
  • replacement in source_edit.lua at line 201
    [6.157151][6.157151:157217]()
    --? print('press', State.selection1.line, State.selection1.pos)
    [6.157151]
    [6.157217]
    --? print('press')
  • replacement in source_edit.lua at line 208
    [6.157427][6.157427:157679]()
    if Text.in_line(State, line_index, x,y) then
    local pos,posB = Text.to_pos_on_line(State, line_index, x, y)
    --? print(x,y, 'setting cursor:', line_index, pos, posB)
    State.cursor1 = {line=line_index, pos=pos, posB=posB}
    break
    [6.157427]
    [6.157679]
    if line.mode == 'text' then
    if Text.in_line(State, line_index, x,y) then
    local pos,posB = Text.to_pos_on_line(State, line_index, x, y)
    --? print(x,y, 'setting cursor:', line_index, pos, posB)
    State.cursor1 = {line=line_index, pos=pos, posB=posB}
    break
    end
    elseif line.mode == 'drawing' then
    local line_cache = State.line_cache[line_index]
    if Drawing.in_drawing(line, line_cache, x, y, State.left,State.right) then
    State.lines.current_drawing_index = line_index
    State.lines.current_drawing = line
    Drawing.before = snapshot(State, line_index)
    Drawing.mouse_pressed(State, line_index, x,y, mouse_button)
    break
    end
  • edit in source_edit.lua at line 229
    [6.157753]
    [6.157753]
    if State.search_term then return end
    --? print('release')
    if State.lines.current_drawing then
    Drawing.mouse_released(State, x,y, mouse_button)
    schedule_save(State)
    if Drawing.before then
    record_undo_event(State, {before=Drawing.before, after=snapshot(State, State.lines.current_drawing_index)})
    Drawing.before = nil
    end
    end
  • edit in source_edit.lua at line 247
    [6.158026]
    [6.158026]
    elseif State.current_drawing_mode == 'name' then
    local before = snapshot(State, State.lines.current_drawing_index)
    local drawing = State.lines.current_drawing
    local p = drawing.points[drawing.pending.target_point]
    p.name = p.name..t
    record_undo_event(State, {before=before, after=snapshot(State, State.lines.current_drawing_index)})
  • replacement in source_edit.lua at line 305
    [6.159775][6.159775:159804]()
    elseif chord == 'C-d' then
    [6.159775]
    [6.159804]
    elseif chord == 'C-i' then
  • edit in source_edit.lua at line 340
    [6.161174]
    [6.161174]
    -- invalidate various cached bits of lines
    State.lines.current_drawing = nil
  • edit in source_edit.lua at line 354
    [6.161677]
    [6.161677]
    -- invalidate various cached bits of lines
    State.lines.current_drawing = nil
  • replacement in source_edit.lua at line 393
    [6.163099][6.163099:163121]()
    -- dispatch to text
    [6.163099]
    [6.163121]
    -- dispatch to drawing or text
    elseif App.mouse_down(1) or chord:sub(1,2) == 'C-' then
    -- DON'T reset line_cache.starty here
    local drawing_index, drawing = Drawing.current_drawing(State)
    if drawing_index then
    local before = snapshot(State, drawing_index)
    Drawing.keychord_pressed(State, chord)
    record_undo_event(State, {before=before, after=snapshot(State, drawing_index)})
    schedule_save(State)
    end
    elseif chord == 'escape' and not App.mouse_down(1) then
    for _,line in ipairs(State.lines) do
    if line.mode == 'drawing' then
    line.show_help = false
    end
    end
    elseif State.current_drawing_mode == 'name' then
    if chord == 'return' then
    State.current_drawing_mode = State.previous_drawing_mode
    State.previous_drawing_mode = nil
    else
    local before = snapshot(State, State.lines.current_drawing_index)
    local drawing = State.lines.current_drawing
    local p = drawing.points[drawing.pending.target_point]
    if chord == 'escape' then
    p.name = nil
    record_undo_event(State, {before=before, after=snapshot(State, State.lines.current_drawing_index)})
    elseif chord == 'backspace' then
    local len = utf8.len(p.name)
    local byte_offset = Text.offset(p.name, len-1)
    if len == 1 then byte_offset = 0 end
    p.name = string.sub(p.name, 1, byte_offset)
    record_undo_event(State, {before=before, after=snapshot(State, State.lines.current_drawing_index)})
    end
    end
    schedule_save(State)
  • replacement in source.lua at line 280
    [6.174838][6.174838:174898]()
    if Editor_state.left <= x and x < Editor_state.right then
    [6.174838]
    [6.174898]
    if x < Editor_state.right + Margin_right then
  • edit in main.lua at line 26
    [6.184859]
    [52.162]
    -- both sides use drawings
    load_file_from_source_or_save_directory('icons.lua')
    load_file_from_source_or_save_directory('drawing.lua')
    load_file_from_source_or_save_directory('geom.lua')
    load_file_from_source_or_save_directory('help.lua')
    load_file_from_source_or_save_directory('drawing_tests.lua')
  • edit in main.lua at line 53
    [6.185525][6.185525:185584]()
    load_file_from_source_or_save_directory('icons.lua')
  • edit in main.lua at line 55
    [6.185709][6.185709:185949]()
    load_file_from_source_or_save_directory('drawing.lua')
    load_file_from_source_or_save_directory('geom.lua')
    load_file_from_source_or_save_directory('help.lua')
    load_file_from_source_or_save_directory('drawing_tests.lua')
  • replacement in file.lua at line 47
    [7.16169][2.14:51]()
    outfile:write(line.data, '\n')
    [7.16169]
    [7.16206]
    outfile:write(line.data)
    outfile:write('\n')
  • replacement in edit.lua at line 137
    [7.3095][7.3095:3138]()
    State.screen_bottom1.line = line_index
    [7.3095]
    [7.15]
    State.screen_bottom1 = {line=line_index, pos=nil}
  • edit in edit.lua at line 172
    [7.5923][7.4061:4191]()
    --? print('screen bottom: '..tostring(State.screen_bottom1.pos)..' in '..tostring(State.lines[State.screen_bottom1.line].data))
  • replacement in edit.lua at line 333
    [7.7565][7.7565:7718]()
    State.search_backup = {cursor={line=State.cursor1.line, pos=State.cursor1.pos}, screen_top={line=State.screen_top1.line, pos=State.screen_top1.pos}}
    [7.7565]
    [7.7718]
    State.search_backup = {
    cursor={line=State.cursor1.line, pos=State.cursor1.pos},
    screen_top={line=State.screen_top1.line, pos=State.screen_top1.pos},
    }
  • replacement in commands.lua at line 31
    [6.205424][6.205424:205482]()
    add_hotkey_to_menu('ctrl+d: create/edit debug print')
    [6.205424]
    [6.205482]
    add_hotkey_to_menu('ctrl+i: create/edit debug print')