Auto-save to ~ files

This commit is contained in:
Isaiah Odhner 2023-04-26 21:59:21 -04:00
parent a792b7a132
commit 2af9f4fd53
2 changed files with 19 additions and 1 deletions

View File

@ -21,6 +21,7 @@ This is a TUI (Text User Interface) image editor, inspired by MS Paint, built wi
- [x] Fancy file dialogs
- [x] Drag and drop files to open
- [x] Warnings when overwriting an existing file, or closing with unsaved changes
- [x] Auto-saves to `<filename>~` alongside the file you're editing, so you can recover your work if the program crashes
- File formats, chosen by typing a file extension in the Save As dialog:
- [x] ANSI (.ans) — Note that while it can load the files that it saves, you may have limited success loading other ANSI files that you find on the web, or create with other tools. ANSI files can vary a lot and even encode animations!
- [x] Plain Text (.txt) — discards color information
@ -141,7 +142,6 @@ cat samples/ship.ans
- The canvas flickers when zooming in with the Magnifier tool.
- Some languages don't display correctly.
- Large files can make the program very slow, as can magnifying the canvas.
- The program may crash or freeze up randomly, and there's no auto-save feature.
- Saved ANSI files are unnecessarily large, because they include escape sequences for every cell, even if the colors match the previous cell.
- Free-Form Select stamping/finalizing is incorrect when the selection is off-screen to the left or top.
- Moving the selection with the arrow keys does not cut out the selection from the canvas, it only moves the selection box.

View File

@ -1516,6 +1516,8 @@ class PaintApp(App[None]):
"""A temporary undo state for tool previews"""
saved_undo_count = 0
"""Used to determine if the document has been modified since the last save, in is_document_modified()"""
auto_saved_undo_count = 0
"""Used to determine if the document has been modified since the last auto-save"""
mouse_gesture_cancelled = False
"""For Undo/Redo, to interrupt the current action"""
@ -1840,6 +1842,19 @@ class PaintApp(App[None]):
assert isinstance(window, Window), f"Expected a Window for query '{selector}', but got {window.css_identifier}"
window.close()
def start_auto_save_interval(self) -> None:
"""Auto-save periodically."""
self.auto_save_interval = 10
self.set_interval(self.auto_save_interval, self.auto_save)
def auto_save(self) -> None:
"""Auto-save the image if it has been modified since the last save."""
if self.auto_saved_undo_count != len(self.undos):
auto_save_file_path = (self.file_path or _("Untitled")) + "~"
ansi = self.image.get_ansi()
self.write_file_path(auto_save_file_path, ansi, _("Auto-Save Failed"))
self.auto_saved_undo_count = len(self.undos)
def action_save(self) -> None:
"""Start the save action, but don't wait for the Save As dialog to close if it's a new file."""
task = asyncio.create_task(self.save())
@ -2142,6 +2157,7 @@ class PaintApp(App[None]):
self.canvas.refresh(layout=True)
self.file_path = None
self.saved_undo_count = 0
self.auto_saved_undo_count = 0
self.undos = []
self.redos = []
self.preview_action = None
@ -3540,5 +3556,7 @@ if args.clear_screen:
app.dark = args.theme == "dark"
app.call_later(app.start_auto_save_interval)
if __name__ == "__main__":
app.run()