Edit a text file where you are already reading it

v2 of the viewer: Edit, on text and Markdown, in the dialog and on the
row menu. Save is explicit -- every save mints a new blob, so autosave
would burn quota and multiply the conflicts it cannot see.

Two people editing one file is the case worth getting right. `saveText`
re-reads the node and compares the blob the editor started from: if
somebody else saved in the meantime it refuses, says so, and leaves the
work in the box to copy out. `ifInState` is the obvious tool and the
wrong one -- it is the state of every FileNode in the account, so an
unrelated upload in another folder would fail the save, and a warning
that cries wolf is a warning people click through.

Editing is not offered where saving would lose something: a file
truncated for display would have its tail written away, and one that did
not decode as UTF-8 would have mojibake written over whatever encoding it
really is. Both open read-only and say which. Nor is it offered without
mayModifyContent -- a read-only share just has no Edit.

Closing or cancelling with unsaved changes asks first, Ctrl+S saves, and
mail attachments are unaffected: they pass no onSave, because a message
part is not a thing that can be written back.
This commit is contained in:
2026-09-01 20:51:51 -07:00
parent 8d562628ff
commit a4c0e04ab9
4 changed files with 320 additions and 54 deletions
+2
View File
@@ -320,6 +320,8 @@ a.menu-item:hover { color: var(--fg); }
.segmented button.active { background: var(--accent-soft); color: var(--accent-soft-fg); font-weight: 600; }
.segmented button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.segmented.left { margin-right: auto; }
.dialog-foot .hint.left { margin-right: auto; }
.dialog-foot textarea.code, .dialog-body > textarea.code { font-family: var(--font-mono); }
/* Rendered Markdown in the file viewer. Deliberately plain: this is somebody's
notes, not a web page, and the point is to read it. */