Notes: edit a text file of any size (#47)
CI / build (pull_request) Successful in 1m52s
Site / build (pull_request) Successful in 12s

The editor held the whole note in memory and stopped at 16 KB. It now keeps
a window of the file around the cursor, and the rest on the card as a list
of pieces (notes::NoteDocument). Memory with a note open is what it was.

Up to 64 KB a save rewrites the file, as before. Above, the five-second
save appends what changed to <note>.edit, and the file is rewritten on
leaving the note, with a progress bar. After a power cut, opening the note
picks the edit up where it was saved; a rewrite cut short is finished or
dropped, never half applied.

Also: Ctrl with Fn+Up/Down go to the start and end of the note; the
consoles' `key` command takes ctrl-, alt- and shift-; the Storage App's
`e` no longer refuses a big file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-07 15:39:45 +02:00
co-authored by Claude Opus 5.5
parent 10c5291e15
commit de8af6ed92
21 changed files with 1681 additions and 111 deletions
+13 -3
View File
@@ -7,8 +7,9 @@
namespace roro::notes {
// The text of a note while it's edited (F1, Q144, Q145): UTF-8 held whole in memory, a cursor, and
// the part of it on screen. Lines wrap at spaces, `cols` characters wide; a line owns the space or
// The text of a note while it's edited (F1, Q144, Q145): UTF-8 held in memory, a cursor, and the
// part of it on screen. Up to 16 KB: a longer note is edited through NoteDocument (note_document.h),
// which keeps this as its window on the file. Lines wrap at spaces, `cols` characters wide; a line owns the space or
// the newline it ends with, so every byte of the text belongs to exactly one line. No index of
// lines is kept (a note of newlines alone would need twice its size): where a line starts is
// worked out from the start of its paragraph, which is never far.
@@ -27,8 +28,17 @@ class NoteText {
bool setText(const std::string& text);
const std::string& text() const { return text_; }
size_t cursor() const { return cursor_; }
size_t size() const { return text_.size(); }
uint32_t revision() const { return revision_; } // changes with every edit: is it saved?
// For a window on a longer text (issue #47): the caller refills the buffer, then says where
// the cursor is in it and which row of the screen it should be on. CRLF becomes LF as in
// setText; returns how many CRs went. The revision doesn't change: nothing was edited.
std::string& buffer() { return text_; }
size_t refilled(size_t cursor, int row);
size_t startOfLine(size_t pos) const { return lineOf(pos); }
size_t top() const { return top_; }
bool insert(uint32_t codePoint); // false: the note is full
bool insertText(const std::string& s); // all of it or nothing
void backspace();
@@ -61,7 +71,7 @@ class NoteText {
bool hasLineAfter(size_t start) const;
void moved(bool keepGoal = false);
void follow(); // scrolls so the cursor is on screen
void dropCarriageReturns();
size_t dropCarriageReturns(size_t* follow = nullptr); // how many; `follow` is a place in the text, kept on its character
int cols_, rows_;
std::string text_;