more efficient undo/redo

[?]
Jun 3, 2022, 12:46 AM
VJ77YABHVJZWJKLHAGIPC562GYM73AUGRLCP4JLKP5JPWPT2RIHAC

Dependencies

  • [2] 4QQBMWLL regression: typing uppercase letters in text
  • [3] N6V6UJ3P this implementation undo load-tests quite poorly
  • [4] SQLVYKVJ rename
  • [5] XNFTJHC4 split keyboard handling between Text and Drawing
  • [6] 2ZYV7D3W handle tab characters
  • [7] CG3264MM move
  • [8] HMODUNJE scroll on backspace
  • [9] 2RXZ3PGO beginning of a new approach to scroll+wrap
  • [10] PHFWIFYK scroll on enter
  • [11] A2TQYJ6J .
  • [12] 2POFQQLW keep cursor on screen when pressing 'down'
  • [13] DAENUOGV eliminate assumptions that line length == size in bytes
  • [14] DHI6IJCN selecting text and deleting selections
  • [15] 73OCE2MC after much struggle, a brute-force undo
  • [16] G6OYAYHU paste in text with M-v
  • [17] WY3JD6W6 bugfix
  • [18] 537TQ2QN some more logging
  • [19] SLLR6KKI bugfix for non-ASCII
  • [20] QVDQMJXV avoid scrolling down if possible
  • [21] AYE2VEGJ extract a couple of methods
  • [22] JY4VK7L2 rename
  • [23] IDGP4BJZ new known issue with drawings
  • [*] BULPIBEG beginnings of a module for the text editor
  • [*] FS2ITYYH record a known issue

Change contents

  • edit in undo.lua at line 35
    [5.1004]
    [5.1004]
    -- Copy all relevant global state.
  • replacement in undo.lua at line 37
    [5.1116][4.1:21]()
    function snapshot()
    [5.1116]
    [5.1147]
    function snapshot(s,e)
    -- Snapshot everything by default, but subset if requested.
    if s == nil and e == nil then
    s = 1
    e = #Lines
    elseif e == nil then
    e = s
    end
  • edit in undo.lua at line 54
    [5.1427]
    [5.1427]
    start_line=s,
    end_line=e,
  • replacement in undo.lua at line 59
    [5.1559][5.1559:1592]()
    for _,line in ipairs(Lines) do
    [5.1559]
    [5.1592]
    for i=s,e do
    local line = Lines[i]
  • edit in undo.lua at line 78
    [5.2322]
    [5.2322]
    function patch(lines, from, to)
    --? if #from.lines == 1 and #to.lines == 1 then
    --? assert(from.start_line == from.end_line)
    --? assert(to.start_line == to.end_line)
    --? assert(from.start_line == to.start_line)
    --? lines[from.start_line] = to.lines[1]
    --? return
    --? end
    assert(from.start_line == to.start_line)
    for i=from.end_line,from.start_line,-1 do
    table.remove(lines, i)
    end
    assert(#to.lines == to.end_line-to.start_line+1)
    for i=1,#to.lines do
    table.insert(lines, to.start_line+i-1, to.lines[i])
    end
    end
  • edit in undo.lua at line 108
    [5.2739]
    function minmax(a, b)
    return math.min(a,b), math.max(a,b)
    end
  • edit in text.lua at line 135
    [5.2657]
    [5.2657]
    local minl,maxl = minmax(Selection1.line, Cursor1.line)
    local before = snapshot(minl, maxl)
    Text.delete_selection_without_undo()
    record_undo_event({before=before, after=snapshot(Cursor1.line)})
    end
    function Text.delete_selection_without_undo()
  • edit in text.lua at line 1178
    [5.6254][3.2:614]()
    end
    function test_zzz_undo_load_test()
    print('\n\nTesting a 10KB file')
    -- create a large list of lines
    local lines = {}
    -- 10k characters, hundred lines, 2k words
    for i=1,100 do
    local line = ''
    for c=1,20 do
    line = line..'abcd '
    end
    end
    Lines = load_array(lines)
    -- perform 1000 mutations
    print('are the dots printing quickly and without any pauses?')
    for i=1,1000 do
    if i%50 == 0 then
    App.run_after_keychord('return')
    else
    App.run_after_textinput('a')
    end
    if i%10 == 0 then
    io.write(i)
    io.write(' ')
    io.flush()
    end
    end
  • replacement in text.lua at line 1225
    [2.74][5.42:78](),[5.42][5.42:78]()
    local down = love.keyboard.isDown
    [2.74]
    [5.1]
    if Selection1.line then
    Text.delete_selection()
    end
    local before = snapshot(Cursor1.line)
  • edit in text.lua at line 1230
    [5.28]
    [5.60]
    record_undo_event({before=before, after=snapshot(Cursor1.line)})
  • edit in text.lua at line 1234
    [5.99][5.1:55](),[5.55][5.6260:6318](),[5.6318][4.23:51]()
    if Selection1.line then Text.delete_selection() end
    -- Collect what you did in an event that can be undone.
    local before = snapshot()
  • edit in text.lua at line 1244
    [5.763][5.6358:6383](),[5.6383][4.52:107]()
    -- finalize undo event
    record_undo_event({before=before, after=snapshot()})
  • replacement in text.lua at line 1251
    [5.655][4.108:138]()
    local before = snapshot()
    [5.655]
    [5.764]
    local before_line = Cursor1.line
    local before = snapshot(before_line)
  • replacement in text.lua at line 1265
    [5.1648][4.139:196]()
    record_undo_event({before=before, after=snapshot()})
    [5.1648]
    [5.134]
    record_undo_event({before=before, after=snapshot(before_line, Cursor1.line)})
  • replacement in text.lua at line 1267
    [5.163][4.197:227]()
    local before = snapshot()
    [5.163]
    [5.163]
    local before = snapshot(Cursor1.line)
  • replacement in text.lua at line 1270
    [5.1006][4.228:285]()
    record_undo_event({before=before, after=snapshot()})
    [5.1006]
    [5.2046]
    record_undo_event({before=before, after=snapshot(Cursor1.line)})
  • edit in text.lua at line 1272
    [5.2081][4.286:316]()
    local before = snapshot()
  • edit in text.lua at line 1275
    [5.6750][4.317:376]()
    record_undo_event({before=before, after=snapshot()})
  • edit in text.lua at line 1277
    [5.8474]
    [5.1902]
    local before
  • edit in text.lua at line 1279
    [5.1930]
    [5.1930]
    before = snapshot(Cursor1.line)
    else
    before = snapshot(Cursor1.line-1, Cursor1.line)
    end
    if Cursor1.pos > 1 then
  • replacement in text.lua at line 1314
    [5.3034][4.377:434]()
    record_undo_event({before=before, after=snapshot()})
    [5.3034]
    [5.3034]
    record_undo_event({before=before, after=snapshot(Cursor1.line)})
  • edit in text.lua at line 1316
    [5.3066][4.435:465]()
    local before = snapshot()
  • edit in text.lua at line 1319
    [5.6968][4.466:525]()
    record_undo_event({before=before, after=snapshot()})
  • edit in text.lua at line 1320
    [5.8546]
    [5.8546]
    end
    local before
    if Cursor1.pos <= utf8.len(Lines[Cursor1.line].data) then
    before = snapshot(Cursor1.line)
    else
    before = snapshot(Cursor1.line, Cursor1.line+1)
  • replacement in text.lua at line 1350
    [5.3956][4.526:583]()
    record_undo_event({before=before, after=snapshot()})
    [5.3956]
    [5.7107]
    record_undo_event({before=before, after=snapshot(Cursor1.line)})
  • replacement in text.lua at line 1360
    [5.7450][5.7450:7520]()
    if src.lines then
    Lines = deepcopy(src.lines)
    end
    [5.7450]
    [5.7520]
    patch(Lines, event.after, event.before)
  • replacement in text.lua at line 1369
    [5.7761][5.7761:8113]()
    if src.lines then
    Lines = deepcopy(src.lines)
    --? for _,line in ipairs(Lines) do
    --? if line.mode == 'drawing' then
    --? print('restoring', line.points, 'with', #line.points, 'points')
    --? print('restoring', line.shapes, 'with', #line.shapes, 'shapes')
    --? end
    --? end
    end
    [5.7761]
    [5.8113]
    patch(Lines, event.before, event.after)
  • edit in text.lua at line 1383
    [5.76]
    [5.76]
    local before_line = Cursor1.line
    local before = snapshot(before_line)
  • edit in text.lua at line 1389
    [5.209]
    [5.209]
    record_undo_event({before=before, after=snapshot(before_line, Cursor1.line)})
  • replacement in README.md at line 9
    [5.8364][5.8364:8558]()
    * Undo is extremely inefficient in space. While this app is extremely unlikely
    to lose the current state of a file at any moment, undo history is volatile
    and should be considered unstable.
    [5.8364]
    [5.14]
    * Undo/redo can be sluggish in large files. If things get sluggish, killing
    the process can lose data.