Fix round-four regressions: save fallback, replace memory, regex skip

- Save's in-place fallbacks (no temp file; no hard-link copy) now apply
  only when the directory refuses a new name (EACCES, EPERM,
  ENAMETOOLONG). On ENOSPC, EDQUOT or EIO the in-place write truncated
  the file and then failed, leaving it corrupt; now the save fails and
  the file is untouched (checked on a full tmpfs).
- replace_rows_text/replace_buffer_text delete and insert only the span
  between the old and new text's common prefix and suffix (kept on
  UTF-8 boundaries). Replace-all recorded the whole buffer twice in the
  undo tree per run.
- Regex search skips long lines only while typing (limit lowered to
  2,000 bytes, as for renderer highlighting; '.*q' on a 20 KB line took
  12 s), reports how many were skipped, and next/previous match search
  every line. Previously matches on long lines could not be found.

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 ca3a6e675b
commit b1b0b3de57
5 changed files with 230 additions and 58 deletions
+15
View File
@@ -410,6 +410,21 @@ before the fix (unless noted).
after a close; a reload confirmation survived other commands; a swap
recovery prompt from a deferred open was not drawn until a key.
**Fifth round (review of the fourth round's changes)**
- The save fallbacks added in round four (write in place when no temp
file or hard-link copy can be made) also fired on ENOSPC/EDQUOT/EIO,
truncating the file and then failing: the file on disk was left
corrupt. They now apply only when the directory refuses a new name
(EACCES, EPERM, ENAMETOOLONG); otherwise the save fails and the file
is untouched.
- Whole-buffer replace recorded the entire old and new text for undo on
every run (about 150 MB more per replace-all on a 50 MB file); only
the span between the common prefix and suffix is now recorded.
- Regex search silently never found matches on lines over 20,000 bytes;
the skip now applies only to search-as-you-type (at 2,000 bytes, where
the worst case is well under a second), says so in the status line,
and moving to the next/previous match searches every line.
**Known limitations (not fixed)**
- Catastrophic regex backtracking (e.g. `(a*)*b`) can still take very
long; std::regex has no time limit.