Journal insert_row as one record; keep the cursor in the buffer; fix ENABLE_ASAN
- Buffer::insert_row recorded its text and newline as two swap records after inserting both. A checkpoint triggered by the first (1 MiB of edits, or the checkpoint timer) snapshotted the newline already, and the second added it again on replay: recovery after undoing C-k C-k silently gained a blank line. It is now one record. - Visual-line yank placed the cursor relative to its row assuming that row was inside the selection; after C-k a or Enter it was not, and the cursor ended past the end of a line or the buffer, where typed text was recorded for undo at a position it was not inserted at and could not be undone. The formula uses the nearest selected row, and run_handler now clamps the cursor to the buffer before and after every command. - ENABLE_ASAN added -fsanitize=address to CMAKE_C_FLAGS only; the project is C++, so nothing was instrumented. Add it to CMAKE_CXX_FLAGS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
@@ -929,10 +929,14 @@ Buffer::insert_row(int row, const std::string_view text)
|
||||
rows_cache_dirty_ = true;
|
||||
edited_at_(row);
|
||||
if (swap_rec_) {
|
||||
// Avoid allocation: emit the row text insertion (if any) and the newline insertion.
|
||||
if (!text.empty())
|
||||
swap_rec_->OnInsert(row, 0, text);
|
||||
swap_rec_->OnInsert(row, static_cast<int>(text.size()), std::string_view("\n", 1));
|
||||
// One record: the first of two could trigger a journal checkpoint,
|
||||
// whose snapshot already holds the newline the second then added
|
||||
// again on replay.
|
||||
std::string line;
|
||||
line.reserve(text.size() + 1);
|
||||
line.append(text);
|
||||
line.push_back('\n');
|
||||
swap_rec_->OnInsert(row, 0, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user