switch source side to new screen-line-based render

[?]
Apr 3, 2023, 3:33 PM
GZ5WULJVEZJJQPQPSQZE7CEPIYPJ2BJDYUJBMZRA5HLOO7TE3DOQC

Dependencies

  • [2] G54H3YG2 get rid of all bifold text
  • [3] S2QMLRXL stop creating a singleton table for every word
  • [4] V5SYDHPQ start thinking of compute_fragments as a detail
  • [5] H6QZ7GRR more precise name
  • [6] FBVUNLS4 clean up some debug prints
  • [7] ORRSP7FV deduce test names on failures
  • [8] H4R5BHVY no more Text allocations
  • [9] KMSL74GA support selections in the source editor
  • [10] OI4FPFIN support drawings in the source editor
  • [11] QZ2SXLHF some debug prints
  • [12] 4KC7I3E2 make colors easier to edit
  • [13] 2WGHUWE6 self-documenting 0 Test_right_margin
  • [14] 2CK5QI7W make love event names consistent
  • [15] KKMFQDR4 editing source code from within the app
  • [16] X3F7ECSL add state arg to some functions
  • [17] 2Y7YH7UP infrastructure for caching LÖVE text objects
  • [18] EKJUHVHB hoist out some common settings
  • [19] B4JEWKWI hide editor cursor while in file navigator
  • [20] ISOFHXB2 App.width can no longer take a Text
  • [21] UN7GKYV5 support hyperlinks in the source editor
  • [22] 4VQGE7RA new test
  • [23] LF7BWEG4 group all editor globals
  • [24] R3KXFRZN get rid of to_text
  • [25] J2SVGR2E experiment: blinking cursor
  • [*] BULPIBEG beginnings of a module for the text editor
  • [*] VHQCNMAR several more modules
  • [*] 2L5MEZV3 experiment: new edit namespace

Change contents

  • edit in text.lua at line 72
    [5.1490][5.92:118](),[5.55644][5.92:118](),[5.158][5.92:118]()
    App.color(Text_color)
  • replacement in source_text_tests.lua at line 980
    [5.35876][5.31723:31765]()
    App.screen.check(y, 'mno ', 'screen:3')
    [5.35876]
    [5.35980]
    App.screen.check(y, 'mn', 'screen:3')
  • replacement in source_text.lua at line 5
    [5.83964][2.7:79]()
    -- return the final y, and position of start of final screen line drawn
    [5.83964]
    [2.79]
    -- return y for the next line, and position of start of final screen line drawn
  • replacement in source_text.lua at line 12
    [2.165][2.165:204](),[2.204][5.87305:87349](),[5.87305][5.87305:87349]()
    local x = State.left
    local pos = 1
    local screen_line_starting_pos = startpos
    [2.165]
    [4.68]
    local final_screen_line_starting_pos = startpos -- track value to return
  • replacement in source_text.lua at line 14
    [4.128][5.87393:87409](),[5.87393][5.87393:87409]()
    local pos = 1
    [4.128]
    [5.87409]
    Text.populate_link_offsets(State, line_index)
  • replacement in source_text.lua at line 16
    [5.87430][5.87430:87502](),[5.87502][3.454:574]()
    for _, f in ipairs(line_cache.fragments) do
    App.color(Text_color)
    select_color(f)
    local frag_len = utf8.len(f)
    --? print('text.draw:', f, 'at', line_index,pos, 'after', x,y)
    [5.87430]
    [5.87674]
    assert(#line_cache.screen_line_starting_pos >= 1)
    for i=1,#line_cache.screen_line_starting_pos do
    local pos = line_cache.screen_line_starting_pos[i]
  • replacement in source_text.lua at line 23
    [5.87768][5.87768:87793](),[5.87793][3.607:645](),[5.353][5.87839:88027](),[3.645][5.87839:88027](),[5.87839][5.87839:88027](),[5.88027][2.205:250]()
    -- render fragment
    local frag_width = App.width(f)
    if x + frag_width > State.right then
    assert(x > State.left) -- no overfull lines
    y = y + State.line_height
    if y + State.line_height > App.screen.height then
    return y, screen_line_starting_pos
    [5.87768]
    [5.88105]
    final_screen_line_starting_pos = pos
    local f = Text.screen_line(line, line_cache, i)
    --? print('text.draw:', f, 'at', line_index,pos, 'after', x,y)
    local frag_len = utf8.len(f)
    -- render any link decorations
    for _,link_offsets in ipairs(line_cache.link_offsets) do
    local s,e,filename = unpack(link_offsets)
    local lo, hi = Text.clip_wikiword_with_screen_line(line, line_cache, i, s, e)
    if lo then
    button(State, 'link', {x=State.left+lo, y=y, w=hi-lo, h=State.line_height, color={1,1,1},
    icon = icon.hyperlink_decoration,
    onpress1 = function()
    if file_exists(filename) then
    source.switch_to_file(filename)
    end
    end,
    })
  • edit in source_text.lua at line 41
    [5.88117][5.88117:88179]()
    screen_line_starting_pos = pos
    x = State.left
  • edit in source_text.lua at line 42
    [5.20777]
    [5.20777]
    -- render fragment
  • replacement in source_text.lua at line 45
    [5.20894][5.20894:20952]()
    Text.draw_highlight(State, line, x,y, pos, lo,hi)
    [5.20894]
    [5.88179]
    Text.draw_highlight(State, line, State.left,y, pos, lo,hi)
  • replacement in source_text.lua at line 47
    [5.88189][5.7:84](),[5.84][3.646:731](),[5.685][5.172:367](),[3.731][5.172:367](),[5.172][5.172:367](),[5.367][5.7:125](),[5.125][5.578:779](),[5.578][5.578:779](),[5.779][3.732:763]()
    -- Make [[WikiWords]] (single word, all in one screen line) clickable.
    local trimmed_word = rtrim(f) -- compute_fragments puts whitespace at the end
    if starts_with(trimmed_word, '[[') and ends_with(trimmed_word, ']]') then
    local filename = trimmed_word:gsub('^..(.*)..$', '%1')
    if source.link_exists(State, filename) then
    button(State, 'link', {x=x+App.width('[['), y=y, w=App.width(filename), h=State.line_height, color={1,1,1},
    icon = icon.hyperlink_decoration,
    onpress1 = function()
    source.switch_to_file(filename)
    end,
    })
    end
    end
    App.screen.print(f, x,y)
    [5.88189]
    [5.88227]
    select_color(f)
    App.screen.print(f, State.left,y)
  • replacement in source_text.lua at line 50
    [5.88263][2.251:298](),[2.298][5.88332:88412](),[5.88332][5.88332:88412]()
    if line_index == State.cursor1.line then
    if pos <= State.cursor1.pos and pos + frag_len > State.cursor1.pos then
    [5.88263]
    [5.88412]
    if not hide_cursor and line_index == State.cursor1.line then
    if pos <= State.cursor1.pos and pos + frag_len >= State.cursor1.pos then
  • replacement in source_text.lua at line 54
    [5.88598][5.88598:88735]()
    local lo_px = Text.draw_highlight(State, line, x,y, pos, State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term))
    [5.88598]
    [5.88735]
    local lo_px = Text.draw_highlight(State, line, State.left,y, pos, State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term))
  • replacement in source_text.lua at line 56
    [5.88771][5.88771:88835]()
    love.graphics.print(State.search_term, x+lo_px,y)
    [5.88771]
    [5.88835]
    love.graphics.print(State.search_term, State.left+lo_px,y)
  • replacement in source_text.lua at line 59
    [5.88889][3.764:841](),[5.805][5.88969:89003](),[3.841][5.88969:89003](),[5.88969][5.88969:89003]()
    Text.draw_cursor(State, x+Text.x(f, State.cursor1.pos-pos+1), y)
    App.color(Text_color)
    [5.88889]
    [5.89003]
    Text.draw_cursor(State, State.left+Text.x(f, State.cursor1.pos-pos+1), y)
  • replacement in source_text.lua at line 63
    [5.89039][5.89039:89064]()
    x = x + frag_width
    [5.89039]
    [5.89064]
    y = y + State.line_height
    if y >= App.screen.height then
    break
    end
  • edit in source_text.lua at line 68
    [5.89072][5.89072:89097]()
    pos = pos + frag_len
  • replacement in source_text.lua at line 69
    [5.89103][2.299:484](),[2.484][5.91019:91027](),[5.91019][5.91019:91027]()
    if Focus == 'edit' and not hide_cursor and State.search_term == nil then
    if line_index == State.cursor1.line and State.cursor1.pos == pos then
    Text.draw_cursor(State, x, y)
    end
    [5.89103]
    [5.91052]
    return y, final_screen_line_starting_pos
    end
    function Text.screen_line(line, line_cache, i)
    local pos = line_cache.screen_line_starting_pos[i]
    local offset = Text.offset(line.data, pos)
    if i >= #line_cache.screen_line_starting_pos then
    return line.data:sub(offset)
  • replacement in source_text.lua at line 78
    [5.91058][2.485:522]()
    return y, screen_line_starting_pos
    [5.91058]
    [5.91109]
    local endpos = line_cache.screen_line_starting_pos[i+1]-1
    local end_offset = Text.offset(line.data, endpos)
    return line.data:sub(offset, end_offset)
  • edit in source_text.lua at line 100
    [5.91598][5.91598:91683]()
    -- duplicate some logic from Text.draw
    Text.compute_fragments(State, line_index)
  • replacement in source_text.lua at line 101
    [5.91727][5.91727:91750]()
    local x = State.left
    [5.91727]
    [5.91750]
    local x = 0
  • replacement in source_text.lua at line 103
    [5.91766][5.91766:91812](),[5.91855][5.91855:91878](),[5.91878][3.842:878](),[5.395][5.91922:91984](),[3.878][5.91922:91984](),[5.91922][5.91922:91984]()
    for _, f in ipairs(line_cache.fragments) do
    -- render fragment
    local frag_width = App.width(f)
    if x + frag_width > State.right then
    x = State.left
    [5.91766]
    [5.91984]
    -- try to wrap at word boundaries
    for frag in line.data:gmatch('%S*%s*') do
    local frag_width = App.width(frag)
    --? print('-- frag:', frag, pos, x, frag_width, State.width)
    while x + frag_width > State.width do
    --? print('frag:', frag, pos, x, frag_width, State.width)
    if x < 0.8 * State.width then
    -- long word; chop it at some letter
    -- We're not going to reimplement TeX here.
    local bpos = Text.nearest_pos_less_than(frag, State.width - x)
    -- everything works if bpos == 0, but is a little inefficient
    pos = pos + bpos
    local boffset = Text.offset(frag, bpos+1) -- byte _after_ bpos
    frag = string.sub(frag, boffset)
    --? if bpos > 0 then
    --? print('after chop:', frag)
    --? end
    frag_width = App.width(frag)
    end
    --? print('screen line:', pos)
  • edit in source_text.lua at line 124
    [5.92045]
    [5.92045]
    x = 0 -- new screen line
  • replacement in source_text.lua at line 127
    [5.92076][3.879:907]()
    pos = pos + utf8.len(f)
    [5.92076]
    [5.92137]
    pos = pos + utf8.len(frag)
  • replacement in source_text.lua at line 131
    [5.92148][5.92148:92199]()
    function Text.compute_fragments(State, line_index)
    [5.92148]
    [5.92280]
    function Text.populate_link_offsets(State, line_index)
  • replacement in source_text.lua at line 135
    [5.92369][5.92369:92400]()
    if line_cache.fragments then
    [5.92369]
    [5.92400]
    if line_cache.link_offsets then
  • replacement in source_text.lua at line 138
    [5.92417][5.92417:92468]()
    line_cache.fragments = {}
    local x = State.left
    [5.92417]
    [5.92468]
    line_cache.link_offsets = {}
    local pos = 1
  • replacement in source_text.lua at line 141
    [5.92504][5.92504:92548](),[5.92613][5.396:435](),[5.92774][5.92774:92816](),[5.92940][5.92940:93002](),[5.93033][5.93033:93201](),[5.93233][5.93233:93391](),[5.93486][5.93486:93539](),[5.93610][5.436:481](),[5.93745][5.93745:93792](),[5.93792][3.908:958](),[5.897][5.93866:93907](),[3.958][5.93866:93907](),[5.93866][5.93866:93907](),[5.93970][5.482:519](),[5.519][5.94012:94086](),[5.94012][5.94012:94086](),[5.94086][3.959:1006]()
    for frag in line.data:gmatch('%S*%s*') do
    local frag_width = App.width(frag)
    while x + frag_width > State.right do
    if (x-State.left) < 0.8 * (State.right-State.left) then
    -- long word; chop it at some letter
    -- We're not going to reimplement TeX here.
    local bpos = Text.nearest_pos_less_than(frag, State.right - x)
    if bpos == 0 then break end -- avoid infinite loop when window is too narrow
    local boffset = Text.offset(frag, bpos+1) -- byte _after_ bpos
    local frag1 = string.sub(frag, 1, boffset-1)
    local frag1_width = App.width(frag1)
    assert(x + frag1_width <= State.right)
    table.insert(line_cache.fragments, frag1)
    frag = string.sub(frag, boffset)
    frag_width = App.width(frag)
    end
    x = State.left -- new line
    end
    if #frag > 0 then
    table.insert(line_cache.fragments, frag)
    [5.92504]
    [5.94236]
    local s, e = 1, 0
    while s <= #line.data do
    s, e = line.data:find('%[%[%S+%]%]', s)
    if s == nil then break end
    local word = line.data:sub(s+2, e-2) -- strip out surrounding '[[..]]'
    --? print('wikiword:', s, e, word)
    table.insert(line_cache.link_offsets, {s, e, word})
    s = e + 1
    end
    end
    -- Intersect the filename between byte offsets s,e with the bounds of screen line i.
    -- Return the left/right pixel coordinates of of the intersection,
    -- or nil if it doesn't intersect with screen line i.
    function Text.clip_wikiword_with_screen_line(line, line_cache, i, s, e)
    local spos = line_cache.screen_line_starting_pos[i]
    local soff = Text.offset(line.data, spos)
    if e < soff then
    return
    end
    local eoff
    if i < #line_cache.screen_line_starting_pos then
    local epos = line_cache.screen_line_starting_pos[i+1]
    eoff = Text.offset(line.data, epos)
    if s > eoff then
    return
  • replacement in source_text.lua at line 168
    [5.94244][5.94244:94267]()
    x = x + frag_width
    [5.94244]
    [5.94267]
    end
    local loff = math.max(s, soff)
    local hoff
    if eoff then
    hoff = math.min(e, eoff)
    else
    hoff = e
  • edit in source_text.lua at line 176
    [5.94273]
    [5.94273]
    --? print(s, e, soff, eoff, loff, hoff)
    return App.width(line.data:sub(1, loff-1)), App.width(line.data:sub(1, hoff))
  • replacement in source_text.lua at line 1003
    [5.146096][5.146096:146109]()
    App.draw()
    [5.146096]
    [5.146109]
    edit.draw(State)
  • edit in source_text.lua at line 1012
    [5.146455][5.780:1037]()
    function source.link_exists(State, filename)
    if State.link_cache == nil then
    State.link_cache = {}
    end
    if State.link_cache[filename] == nil then
    State.link_cache[filename] = file_exists(filename)
    end
    return State.link_cache[filename]
    end
  • edit in source_text.lua at line 1018
    [5.146606][5.1038:1062]()
    State.link_cache = {}
  • edit in source_text.lua at line 1021
    [5.146668][5.146668:146715]()
    State.line_cache[line_index].fragments = nil
  • edit in source_text.lua at line 1022
    [5.146825]
    [5.146888]
    State.line_cache[line_index].link_offsets = nil
  • edit in source_edit.lua at line 187
    [5.368][5.21213:21245](),[2.6810][5.21213:21245](),[5.21213][5.21213:21245]()
    y = y + State.line_height
  • edit in source_edit.lua at line 510
    [5.164170][5.164170:164188]()
    Text_cache = {}
  • edit in source.lua at line 53
    [5.166573][5.166573:166665]()
    -- a few text objects we can avoid recomputing unless the font changes
    Text_cache = {}
  • edit in run.lua at line 9
    [5.178196][5.178196:178288]()
    -- a few text objects we can avoid recomputing unless the font changes
    Text_cache = {}
  • replacement in log_browser.lua at line 120
    [5.196574][5.196574:196638]()
    y = Text.draw(State, line_index, y, --[[startpos]] 1)
    [5.196574]
    [5.196638]
    Text.draw(State, line_index, y, --[[startpos]] 1)
  • edit in icons.lua at line 13
    [5.1420]
    [5.1420]
    -- hack: set the hyperlink color so that caller can draw the text of the
    -- hyperlink in the same color
  • edit in edit.lua at line 509
    [5.442][5.311:329]()
    Text_cache = {}