autosave slightly less aggressively

It might reduce wear and tear on disk, and losing 3 seconds of data
doesn't feel catastrophic (short of a C-z rampage).

Thanks to the love2d.org community for the suggestion:
  https://love2d.org/forums/viewtopic.php?f=14&t=93173
This commit is contained in:
Kartik K. Agaram 2022-06-17 15:42:53 -07:00
parent 482d07778d
commit 856c51212a
4 changed files with 72 additions and 18 deletions

13
app.lua
View File

@ -157,6 +157,14 @@ function App.screen.print(msg, x,y)
end
end
App.time = 1
function App.getTime()
return App.time
end
function App.wait_fake_time(t)
App.time = App.time + t
end
-- LÖVE's Text primitive retains no trace of the string it was created from,
-- so we'll wrap it for our tests.
--
@ -329,10 +337,14 @@ function App.disable_tests()
-- test methods are disallowed outside tests
App.screen.init = nil
App.filesystem = nil
App.time = nil
App.run_after_textinput = nil
App.run_after_keychord = nil
App.keypress = nil
App.keyrelease = nil
App.run_after_mouse_click = nil
App.run_after_mouse_press = nil
App.run_after_mouse_release = nil
App.fake_key_pressed = nil
App.fake_key_press = nil
App.fake_key_release = nil
@ -346,6 +358,7 @@ function App.disable_tests()
App.width = function(text) return text:getWidth() end
App.open_for_reading = function(filename) return io.open(filename, 'r') end
App.open_for_writing = function(filename) return io.open(filename, 'w') end
App.getTime = love.timer.getTime
App.getClipboardText = love.system.getClipboardText
App.setClipboardText = love.system.setClipboardText
App.modifier_down = love.keyboard.isDown

View File

@ -10,6 +10,12 @@ function test_creating_drawing_saves()
App.draw()
-- click on button to create drawing
App.run_after_mouse_click(8,Margin_top+8, 1)
-- file not immediately saved
App.update(0.01)
check_nil(App.filesystem['foo'], 'F - test_creating_drawing_saves/early')
-- wait until save
App.wait_fake_time(3.1)
App.update(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
@ -41,6 +47,9 @@ function test_draw_line()
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)
App.update(0)
-- The format on disk isn't perfectly stable. Table fields can be reordered.
-- So just reload from disk to verify.
Lines = load_from_disk(Filename)
@ -382,6 +391,9 @@ function test_name_point()
App.run_after_keychord('return')
check_eq(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)
App.update(0)
-- change is saved
Lines = load_from_disk(Filename)
local p2 = Lines[1].points[drawing.shapes[1].p2]
@ -410,6 +422,9 @@ function test_move_point()
check_eq(p2.x, 35, 'F - test_move_point/baseline/p2:x')
check_eq(p2.y, 36, 'F - test_move_point/baseline/p2:y')
check_nil(p2.name, 'F - test_move_point/baseline/p2:name')
-- wait until save
App.wait_fake_time(3.1)
App.update(0)
-- line is saved to disk
Lines = load_from_disk(Filename)
local drawing = Lines[1]
@ -433,6 +448,9 @@ function test_move_point()
App.run_after_mouse_click(Margin_left+26, Margin_top+Drawing_padding_top+44, 1)
check_eq(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)
App.update(0)
-- change is saved
Lines = load_from_disk(Filename)
local p2 = Lines[1].points[drawing.shapes[1].p2]
@ -462,6 +480,9 @@ function test_delete_lines_at_point()
App.run_after_keychord('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)
App.update(0)
-- deleted points disappear after file is reloaded
Lines = load_from_disk(Filename)
check_eq(#Lines[1].shapes, 0, 'F - test_delete_lines_at_point/save')
@ -586,6 +607,9 @@ function test_undo_name_point()
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(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)
App.update(0)
-- undo is saved
Lines = load_from_disk(Filename)
local p2 = Lines[1].points[drawing.shapes[1].p2]
@ -632,6 +656,9 @@ function test_undo_move_point()
check_eq(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)
App.update(0)
-- undo is saved
Lines = load_from_disk(Filename)
local p2 = Lines[1].points[drawing.shapes[1].p2]
@ -668,6 +695,9 @@ function test_undo_delete_point()
check_eq(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)
App.update(0)
-- undo is saved
Lines = load_from_disk(Filename)
check_eq(#Lines[1].shapes, 2, 'F - test_undo_delete_point/save')

View File

@ -76,6 +76,7 @@ Drawing_padding_bottom = 10
Drawing_padding_height = Drawing_padding_top + Drawing_padding_bottom
Filename = love.filesystem.getUserDirectory()..'/lines.txt'
Next_save = nil
-- undo
History = {}
@ -168,7 +169,7 @@ function love.resize(w, h)
App.screen.width, App.screen.height = w, h
Line_width = math.min(40*App.width(Em), App.screen.width-50)
Text.redraw_all()
Last_resize_time = love.timer.getTime()
Last_resize_time = App.getTime()
end
function initialize_font_settings(font_height)
@ -208,7 +209,7 @@ function App.draw()
-- some hysteresis while resizing
if Last_resize_time then
if love.timer.getTime() - Last_resize_time < 0.1 then
if App.getTime() - Last_resize_time < 0.1 then
return
else
Last_resize_time = nil
@ -235,7 +236,7 @@ function App.draw()
if Cursor1.line >= line_index then
Cursor1.line = Cursor1.line+1
end
save_to_disk(Lines, Filename)
schedule_save()
record_undo_event({before=Drawing.before, after=snapshot(line_index-1, line_index+1)})
end})
if Search_term == nil then
@ -272,13 +273,23 @@ function App.update(dt)
Cursor_time = Cursor_time + dt
-- some hysteresis while resizing
if Last_resize_time then
if love.timer.getTime() - Last_resize_time < 0.1 then
if App.getTime() - Last_resize_time < 0.1 then
return
else
Last_resize_time = nil
end
end
Drawing.update(dt)
if Next_save and Next_save < App.getTime() then
save_to_disk(Lines, Filename)
Next_save = nil
end
end
function schedule_save()
if Next_save == nil then
Next_save = App.getTime() + 3 -- short enough that you're likely to still remember what you did
end
end
function App.mousepressed(x,y, mouse_button)
@ -317,7 +328,7 @@ function App.mousereleased(x,y, button)
if Search_term then return end
if Lines.current_drawing then
Drawing.mouse_released(x,y, button)
save_to_disk(Lines, Filename)
schedule_save()
if Drawing.before then
record_undo_event({before=Drawing.before, after=snapshot(Lines.current_drawing_index)})
Drawing.before = nil
@ -358,7 +369,7 @@ function App.textinput(t)
else
Text.textinput(t)
end
save_to_disk(Lines, Filename)
schedule_save()
end
function App.keychord_pressed(chord)
@ -409,7 +420,7 @@ function App.keychord_pressed(chord)
Selection1 = deepcopy(src.selection)
patch(Lines, event.after, event.before)
Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks
save_to_disk(Lines, Filename)
schedule_save()
end
elseif chord == 'C-y' then
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll
@ -421,7 +432,7 @@ function App.keychord_pressed(chord)
Selection1 = deepcopy(src.selection)
patch(Lines, event.before, event.after)
Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks
save_to_disk(Lines, Filename)
schedule_save()
end
-- clipboard
elseif chord == 'C-c' then
@ -436,7 +447,7 @@ function App.keychord_pressed(chord)
if s then
App.setClipboardText(s)
end
save_to_disk(Lines, Filename)
schedule_save()
elseif chord == 'C-v' then
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll
-- We don't have a good sense of when to scroll, so we'll be conservative
@ -456,7 +467,7 @@ function App.keychord_pressed(chord)
if Cursor_y >= App.screen.height - Line_height then
Text.snap_cursor_to_bottom_of_screen()
end
save_to_disk(Lines, Filename)
schedule_save()
record_undo_event({before=before, after=snapshot(before_line, Cursor1.line)})
-- dispatch to drawing or text
elseif App.mouse_down(1) or chord:sub(1,2) == 'C-' then
@ -466,7 +477,7 @@ function App.keychord_pressed(chord)
local before = snapshot(drawing_index)
Drawing.keychord_pressed(chord)
record_undo_event({before=before, after=snapshot(drawing_index)})
save_to_disk(Lines, Filename)
schedule_save()
end
elseif chord == 'escape' and App.mouse_down(1) then
local _,drawing = Drawing.current_drawing()
@ -496,7 +507,7 @@ function App.keychord_pressed(chord)
end
record_undo_event({before=before, after=snapshot(Lines.current_drawing_index)})
end
save_to_disk(Lines, Filename)
schedule_save()
else
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll
Text.keychord_pressed(chord)

View File

@ -182,7 +182,7 @@ function Text.keychord_pressed(chord)
if (Cursor_y + Line_height) > App.screen.height then
Text.snap_cursor_to_bottom_of_screen()
end
save_to_disk(Lines, Filename)
schedule_save()
record_undo_event({before=before, after=snapshot(before_line, Cursor1.line)})
elseif chord == 'tab' then
local before = snapshot(Cursor1.line)
@ -193,12 +193,12 @@ function Text.keychord_pressed(chord)
Text.snap_cursor_to_bottom_of_screen()
--? print('=>', Screen_top1.line, Screen_top1.pos, Cursor1.line, Cursor1.pos, Screen_bottom1.line, Screen_bottom1.pos)
end
save_to_disk(Lines, Filename)
schedule_save()
record_undo_event({before=before, after=snapshot(Cursor1.line)})
elseif chord == 'backspace' then
if Selection1.line then
Text.delete_selection()
save_to_disk(Lines, Filename)
schedule_save()
return
end
local before
@ -235,12 +235,12 @@ function Text.keychord_pressed(chord)
Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks
end
assert(Text.le1(Screen_top1, Cursor1))
save_to_disk(Lines, Filename)
schedule_save()
record_undo_event({before=before, after=snapshot(Cursor1.line)})
elseif chord == 'delete' then
if Selection1.line then
Text.delete_selection()
save_to_disk(Lines, Filename)
schedule_save()
return
end
local before
@ -271,7 +271,7 @@ function Text.keychord_pressed(chord)
table.remove(Lines, Cursor1.line+1)
end
end
save_to_disk(Lines, Filename)
schedule_save()
record_undo_event({before=before, after=snapshot(Cursor1.line)})
--== shortcuts that move the cursor
elseif chord == 'left' then