Public Access
Notes: edit a text file of any size (#47)
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:
+10
-1
@@ -25,6 +25,10 @@ bool endsWith(const std::string& s, const char* tail) {
|
||||
size_t n = std::strlen(tail);
|
||||
return s.size() >= n && s.compare(s.size() - n, n, tail) == 0;
|
||||
}
|
||||
|
||||
// Beside a note, and not one: a save cut short (.tmp), a long note's unsaved edits (.edit), and
|
||||
// edits that no longer fit their file, kept for whoever wants to look (.edit.lost).
|
||||
bool notANote(const std::string& name) { return endsWith(name, ".tmp") || endsWith(name, ".edit") || endsWith(name, ".edit.lost"); }
|
||||
} // namespace
|
||||
|
||||
void NotesApp::onEnter() {
|
||||
@@ -125,6 +129,7 @@ void NotesApp::onFinished(const FileOps::Status& s) {
|
||||
if (list_.find(name.substr(0, name.size() - 4)) < 0) orphans.push_back(name);
|
||||
continue;
|
||||
}
|
||||
if (notANote(name)) continue;
|
||||
notes_.push_back(static_cast<uint16_t>(i));
|
||||
}
|
||||
if (!orphans.empty() && !mended_) {
|
||||
@@ -202,6 +207,8 @@ bool NotesApp::onKey(const KeyEvent& e) {
|
||||
selectIndex_ = rows_.selected();
|
||||
selectAfter_.clear();
|
||||
std::string why = ops_.remove(target_, false);
|
||||
std::string side = target_ + ".edit"; // a long note's unsaved edits go with it (issue #47)
|
||||
if (why.empty()) storage_.runJob([side]() { SD.remove(side.c_str()); });
|
||||
if (why.empty()) wait_ = Wait::Work;
|
||||
else say(why);
|
||||
}
|
||||
@@ -225,6 +232,8 @@ bool NotesApp::onNameKey(const KeyEvent& e) {
|
||||
if (why.empty() && name != baseName(target_)) {
|
||||
why = ops_.move(target_, false, joinPath(kFolder, name));
|
||||
if (why.empty()) {
|
||||
std::string side = target_ + ".edit", sideTo = joinPath(kFolder, name) + ".edit";
|
||||
storage_.runJob([side, sideTo]() { SD.rename(side.c_str(), sideTo.c_str()); });
|
||||
wait_ = Wait::Work;
|
||||
selectAfter_ = name;
|
||||
}
|
||||
@@ -268,7 +277,7 @@ bool NotesApp::onListKey(const KeyEvent& e) {
|
||||
list_.sort(sort_);
|
||||
notes_.clear();
|
||||
for (size_t i = 0; i < list_.count(); i++)
|
||||
if (!list_.folder(i) && !endsWith(list_.name(i), ".tmp")) notes_.push_back(static_cast<uint16_t>(i));
|
||||
if (!list_.folder(i) && !notANote(list_.name(i))) notes_.push_back(static_cast<uint16_t>(i));
|
||||
for (size_t i = 0; i < notes_.size(); i++)
|
||||
if (keep == list_.name(notes_[i])) rows_.select(static_cast<int>(i));
|
||||
titlesFrom_ = -1;
|
||||
|
||||
Reference in New Issue
Block a user