Commands: second-pass fixes from the follow-up review

- Motion and delete commands read rows through RowsView (on-demand,
  version-cached) instead of Buffer::Rows(), which rebuilt every line of
  the file after each edit. On a 500k-line buffer after an edit:
  backspace/delete/motions 80-90 ms -> ~0.1 ms; C-u 3000 C-d 273 s ->
  0.25 s. Whole-buffer search scans keep Rows() (cached between edits).
- While a prompt is open only prompt-aware and view-only commands run.
  Others edited the buffer behind the prompt (bypassing the read-only
  check) or switched/closed buffers under a pending confirmation, which
  then acted on the wrong buffer. The ':' command path now applies the
  read-only check too.
- Pasting into a prompt (ImGui) flattens line breaks to spaces instead
  of emitting Newline, which accepted the prompt and sent the rest of
  the paste to the buffer (or ran replace-all).
- The mark region clamps both ends; a stale mark past the end of the
  buffer is treated as end of buffer. This fixes kill-region deleting
  the wrong text and leaving the cursor past end-of-line.
- Kill-line with a count stops at end of buffer instead of killing
  lines above the cursor (regression from the D3 change).
- Undo groups nest, so SmartNewline in visual-line mode is one step.
- Word motions and word deletion treat non-ASCII bytes as word
  characters and so never split a UTF-8 character.
- The universal-argument count saturates at 1,000,000 instead of
  overflowing int.

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 0075c7aa86
commit 812cde090f
8 changed files with 355 additions and 51 deletions
+8 -2
View File
@@ -9,6 +9,12 @@
#include "syntax/NullHighlighter.h"
namespace {
// Universal-argument repeat counts are capped here (well below INT_MAX).
constexpr int kMaxUArgCount = 1000000;
} // namespace
namespace {
static std::string
buffer_bytes_via_views(const Buffer &b)
@@ -594,7 +600,7 @@ Editor::UArgStart()
if (ucount_ == 0) {
ucount_ = 1;
}
ucount_ *= 4;
ucount_ = std::min(ucount_ * 4, kMaxUArgCount); // no int overflow
}
uarg_ = 1;
char buf[64];
@@ -614,7 +620,7 @@ Editor::UArgDigit(int d)
uarg_ = 1;
ucount_ = 0;
}
ucount_ = ucount_ * 10 + d;
ucount_ = (ucount_ > (kMaxUArgCount - d) / 10) ? kMaxUArgCount : ucount_ * 10 + d;
char buf[64];
std::snprintf(buf, sizeof(buf), "C-u %d", ucount_);
SetStatus(buf);