From f36aa9f456d0c91d6cd7884b824b565862edb9d8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 03:16:59 +0000 Subject: [PATCH] Buffer: bump version on every content change SetDirty(false) did not bump the version, so undo back to the saved state (and reload, and replace_all_bytes) left the highlighter serving spans for the old text. Reloading a file deleted on disk now also clears undo history recorded against the old content. Audit finding D9. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB --- Buffer.cc | 6 ++++++ Buffer.h | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Buffer.cc b/Buffer.cc index 99c8d9e..ebec980 100644 --- a/Buffer.cc +++ b/Buffer.cc @@ -455,6 +455,10 @@ Buffer::OpenFromFile(const std::string &path, std::string &err) // Empty PieceTable content_.Clear(); rows_cache_dirty_ = true; + // History recorded against the previous content no longer applies. + if (undo_sys_) + undo_sys_->clear(); + MarkContentChanged(); return true; } @@ -520,6 +524,7 @@ Buffer::OpenFromFile(const std::string &path, std::string &err) undo_sys_ = std::make_unique(*this, *undo_tree_); // Clear any existing history for a fresh load undo_sys_->clear(); + MarkContentChanged(); // Reset cursor/viewport state curx_ = cury_ = rx_ = 0; @@ -829,6 +834,7 @@ Buffer::replace_all_bytes(const std::string_view bytes) if (!bytes.empty()) content_.Append(bytes.data(), bytes.size()); rows_cache_dirty_ = true; + MarkContentChanged(); } diff --git a/Buffer.h b/Buffer.h index 51fd17b..c6f177e 100644 --- a/Buffer.h +++ b/Buffer.h @@ -391,11 +391,19 @@ public: void SetDirty(bool d) { dirty_ = d; - if (d) { - ++version_; - if (highlighter_) { - highlighter_->InvalidateFrom(0); - } + // Bump even when clearing: undo/redo back to the saved state changes the + // text and then calls SetDirty(false). Without a bump the highlighter + // keeps serving spans for the pre-undo text. + MarkContentChanged(); + } + + + // Invalidate version-keyed caches (syntax highlighting) after a content change. + void MarkContentChanged() + { + ++version_; + if (highlighter_) { + highlighter_->InvalidateFrom(0); } }