Merge text.love

[?]
Apr 3, 2023, 4:28 PM
2CFLXLIERFBJDB6WXTNPKWRSJBAFYY2C4VRMWXFKGGA3DCJQIJWAC

Dependencies

  • [2] OWPI7Y4Q Merge text.love
  • [3] 5YXILO7X Merge text.love
  • [4] QD4LOFQR Merge text.love
  • [5] KWIVKQQ7 Merge lines.love
  • [6] R5QXEHUI somebody stop me
  • [7] BULPIBEG beginnings of a module for the text editor
  • [8] 2L5MEZV3 experiment: new edit namespace
  • [9] MD3W5IRA new fork: rip out drawing support
  • [10] UN7GKYV5 support hyperlinks in the source editor
  • [11] EX43CDDI Merge text.love
  • [12] ZTZOO2OQ Merge lines.love
  • [13] ZWDTEUH7 clean up some absolute coordinates
  • [14] 4YDBYBA4 clean up memory leak experiments
  • [15] 2CTN2IEF Merge lines.love
  • [16] XX7G2FFJ intermingle freehand line drawings with text
  • [17] VHUNJHXB Merge lines.love
  • [18] 2TQUKHBC Merge lines.love
  • [19] ZLJYLPOT Merge lines.love
  • [20] Q6RXCILQ Merge text.love
  • [21] KKMFQDR4 editing source code from within the app
  • [22] 3G723RV5 Merge text.love
  • [23] 6LJZN727 handle chords
  • [24] K2X6G75Z start writing some tests for drawings
  • [25] T4FRZSYL delete an ancient, unused file
  • [26] VXORMHME delete experimental REPL
  • [27] 73OCE2MC after much struggle, a brute-force undo
  • [28] OGUV4HSA remove some memory leaks from rendered fragments
  • [29] 3PSFWAIL Merge lines.love
  • [30] D2GCFTTT clean up repl functionality
  • [31] AVTNUQYR basic test-enabled framework
  • [32] JOPVPUSA editing source code from within the app
  • [33] 3QNOKBFM beginnings of a test harness
  • [34] D4B52CQ2 Merge lines.love
  • [35] A4BSGS2C Merge lines.love
  • [36] LXTTOB33 extract a couple of files
  • [37] ECBDENZ4 Merge text.love
  • [38] 66X36NZN a little more prose describing manual_tests
  • [39] 4SR3Z4Y3 document the version of LÖVE I've been using
  • [40] RSZD5A7G forgot to add json.lua
  • [41] TLOAPLBJ add a license
  • [42] BJ5X5O4A let's prevent the text cursor from ever getting on a drawing
  • [43] BLWAYPKV extract a module
  • [44] 36Z442IV back to commit 8123959e52f without code editing
  • [45] K74U4BAU Merge lines.love
  • [46] FS2ITYYH record a known issue
  • [47] TVCPXAAU rename
  • [48] KMSL74GA support selections in the source editor
  • [49] GZ5WULJV switch source side to new screen-line-based render
  • [50] OTIBCAUJ love2d scaffold
  • [51] VP5KC4XZ Merge lines.love
  • [52] ORKN6EOB Merge lines.love
  • [53] CE4LZV4T drop last couple of manual tests
  • [54] UAYCSFSK Merge text.love
  • [55] VHQCNMAR several more modules

Change contents

  • file deletion: icons.lua (----------)icons.lua (----------)
    [6.2][6.6587:6620](),[6.2][6.6587:6620](),[6.6620][6.5323:5323]()
    -- hack: set the hyperlink color so that caller can draw the text of the
    -- hyperlink in the same color
    App.color(Hyperlink_decoration_color)
    love.graphics.line(x,y+Editor_state.line_height, x+button_params.w,y+Editor_state.line_height)
  • file deletion: source_text_tests.lua (----------)source_text_tests.lua (----------)
    [6.2][6.83739:83784](),[6.2][6.83739:83784](),[6.83784][6.3561:3561]()
    App.screen.check(y, 'mn', 'screen:3')
    end
    function test_pagedown_never_moves_up()
  • file deletion: source_text.lua (----------)source_text.lua (----------)
    [6.2][6.147125:147164](),[6.2][6.147125:147164](),[6.147164][6.83786:83786]()
    State.line_cache[line_index].link_offsets = nil
    end
    function trim(s)
    return s:gsub('^%s+', ''):gsub('%s+$', '')
    end
    function ltrim(s)
    return s:gsub('^%s+', '')
    end
    function rtrim(s)
    return s:gsub('%s+$', '')
    edit.draw(State)
    return State.cursor_y == nil
    -- this approach is cheaper and almost works, except on the final screen
    -- where file ends above bottom of screen
    --? local botpos = Text.pos_at_start_of_screen_line(State, State.cursor1)
    --? local botline1 = {line=State.cursor1.line, pos=botpos}
    --? return Text.lt1(State.screen_bottom1, botline1)
    end
    --? print(s, e, soff, eoff, loff, hoff)
    return App.width(line.data:sub(1, loff-1)), App.width(line.data:sub(1, hoff))
    end
    end
    local loff = math.max(s, soff)
    local hoff
    if eoff then
    hoff = math.min(e, eoff)
    else
    hoff = e
    end
    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
    end
    line_cache.link_offsets = {}
    local pos = 1
    -- try to wrap at word boundaries
    if line_cache.link_offsets then
    return
    end
    function Text.populate_link_offsets(State, line_index)
    local line = State.lines[line_index]
    pos = pos + utf8.len(frag)
    end
    end
    x = 0 -- new screen line
    end
    x = x + frag_width
    -- 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)
    table.insert(line_cache.screen_line_starting_pos, pos)
    local x = 0
    local pos = 1
    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)
    end
    function Text.draw_cursor(State, x, y)
    -- blink every 0.5s
    if math.floor(Cursor_time*2)%2 == 0 then
    App.color(Cursor_color)
    love.graphics.rectangle('fill', x,y, 3,State.line_height)
    end
    State.cursor_x = x
    State.cursor_y = y+State.line_height
    end
    function Text.populate_screen_line_starting_pos(State, line_index)
    local line = State.lines[line_index]
    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)
    end
    y = y + State.line_height
    if y >= App.screen.height then
    break
    end
    end
    Text.draw_cursor(State, State.left+Text.x(f, State.cursor1.pos-pos+1), y)
    end
    end
    end
    love.graphics.print(State.search_term, State.left+lo_px,y)
    end
    elseif Focus == 'edit' then
    local lo_px = Text.draw_highlight(State, line, State.left,y, pos, State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term))
    App.color(Text_color)
    if not hide_cursor and line_index == State.cursor1.line then
    if pos <= State.cursor1.pos and pos + frag_len >= State.cursor1.pos then
    if State.search_term then
    if State.lines[State.cursor1.line].data:sub(State.cursor1.pos, State.cursor1.pos+utf8.len(State.search_term)-1) == State.search_term then
    select_color(f)
    App.screen.print(f, State.left,y)
    -- render cursor if necessary
    Text.draw_highlight(State, line, State.left,y, pos, lo,hi)
    end
    -- render fragment
    if State.selection1.line then
    local lo, hi = Text.clip_selection(State, line_index, pos, pos+frag_len)
    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,
    })
    end
    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]
    if pos < startpos then
    -- render nothing
    Text.populate_link_offsets(State, line_index)
    initialize_color()
    local final_screen_line_starting_pos = startpos -- track value to return
    Text.populate_screen_line_starting_pos(State, line_index)
    -- return y for the next line, and position of start of final screen line drawn
    function Text.draw(State, line_index, y, startpos, hide_cursor)
  • file deletion: log_browser.lua (----------)log_browser.lua (----------)
    [6.2][6.202684:202723](),[6.2][6.202684:202723](),[6.202723][6.191243:191243]()
    Text.draw(State, line_index, y, --[[startpos]] 1)
    State.left,State.right = old_left,old_right
    else
    height = log_render[line.data.name](line.data, xleft, y, xright-xleft)
    end
    end
    if App.mouse_x() > Log_browser_state.left and line_index == mouse_line_index then
    App.color(Cursor_line_background_color)
    love.graphics.rectangle('fill', xleft,y, xright-xleft, height)
    end
    y = y + height
    end
    end
    end
    function render_stack_left_margin(State, line_index, line, y)
    if line.section_stack == nil then
    -- assertion message
    for k,v in pairs(line) do
    print(k)
    end
    end
    App.color(Section_border_color)
    for i=1,#line.section_stack do
    local x = State.left + (i-1)*Section_border_padding_horizontal
    love.graphics.line(x,y, x,y+log_browser.height(State, line_index))
    if y < 30 then
    love.graphics.print(line.section_stack[i].name, x+State.font_height+5, y+5, --[[vertically]] math.pi/2)
    end
    if y > App.screen.height-log_browser.height(State, line_index) then