Round-seven fixes: swap name room for .tmp; input and notice details

- The shortened fallback swap name was capped at exactly NAME_MAX, so
  compaction's '<journal>.tmp' failed with ENAMETOOLONG on every
  checkpoint and the journal grew by a full copy of the buffer each
  time. Cap it at NAME_MAX - 4.
- A lone UTF-8 lead byte (8-bit Meta terminals) waited a second for
  continuation bytes on every key; wait 250 ms. An invalid byte now ends
  a pending ESC/C-k prefix instead of leaving it for the next key.
- Journal notices are shown after a deferred open's own status (which
  used to overwrite them), all pending ones at once, and the lock-out
  notice is not repeated after every save while the lock is still held.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
Claude
2026-09-24 09:16:04 -07:00
committed by Kyle Isom
parent 78d78f6f54
commit b9f91b0ed2
6 changed files with 65 additions and 20 deletions
+17 -9
View File
@@ -489,25 +489,33 @@ Editor::ResolveRecoveryPrompt(const bool yes)
bool
Editor::ProcessPendingOpens()
{
// Opening can throw (bad_alloc on a huge file, filesystem errors). This
// runs from every frontend's loop, outside command dispatch: report the
// failure instead of letting it end the editor.
bool opened = false;
// Opening can throw (bad_alloc on a huge file, filesystem errors), and so
// can the checkpoint snapshot below. This runs from every frontend's
// loop, outside command dispatch: report the failure instead of letting
// it end the editor.
try {
// Also the once-per-frame hook for the journal: retry the
// checkpoint of a journal that lost a record.
if (kte::SwapManager *sm = Swap()) {
if (kte::SwapManager *sm = Swap())
sm->RetryGapCheckpoints();
if (std::string notice = sm->TakeUserNotice(); !notice.empty())
SetStatus(notice);
}
return process_pending_opens_();
opened = process_pending_opens_();
} catch (const std::exception &e) {
kte::ErrorHandler::Instance().Error("Editor", std::string("open failed: ") + e.what(), "");
SetStatus(std::string("Open failed: ") + e.what());
} catch (...) {
SetStatus("Open failed");
}
return false;
// Journal problems for the user, after the open's own status so it does
// not hide them; all pending ones at once (one per frame flashed by).
if (kte::SwapManager *sm = Swap()) {
std::string notices;
for (std::string n = sm->TakeUserNotice(); !n.empty(); n = sm->TakeUserNotice())
notices += (notices.empty() ? "" : "; ") + n;
if (!notices.empty())
SetStatus(notices);
}
return opened;
}