From 927accbca44d792aa9f36a96f9ef76ffcdaa6dd1 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 16:52:38 +0000 Subject: [PATCH] One place to pick a buffer's highlighter Filetype detection (extension or shebang) was written out three times (two open paths in Editor and the ImGui frontend's per-frame check) and "highlighter for this filetype, else the null one" five times (Buffer's copy constructor and assignment, Editor::SwitchTo, :set filetype). Buffer::ApplyDetectedFiletype and InstallFiletypeHighlighter replace them. The InvalidateFrom(0) calls after SetHighlighter are dropped: SetHighlighter already clears the caches. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB --- Buffer.cc | 57 +++++++++++++++++++-------------------- Buffer.h | 9 +++++++ Command.cc | 30 +++++---------------- Editor.cc | 69 +++++------------------------------------------- ImGuiFrontend.cc | 20 ++------------ 5 files changed, 50 insertions(+), 135 deletions(-) diff --git a/Buffer.cc b/Buffer.cc index 60afa03..9ba4aa3 100644 --- a/Buffer.cc +++ b/Buffer.cc @@ -377,23 +377,8 @@ Buffer::Buffer(const Buffer &other) undo_sys_ = std::make_unique(*this, *undo_tree_); // Recreate a highlighter engine for this copy based on filetype/syntax state - if (syntax_enabled_) { - // Allocate engine and install an appropriate highlighter - highlighter_ = std::make_unique(); - if (!filetype_.empty()) { - auto hl = kte::HighlighterRegistry::CreateFor(filetype_); - if (hl) { - highlighter_->SetHighlighter(std::move(hl)); - } else { - // Unsupported filetype -> NullHighlighter keeps syntax pipeline active - highlighter_->SetHighlighter(std::make_unique()); - } - } else { - // No filetype -> keep syntax enabled but use NullHighlighter - highlighter_->SetHighlighter(std::make_unique()); - } - // Fresh engine has empty caches; nothing to invalidate - } + if (syntax_enabled_) + InstallFiletypeHighlighter(); } @@ -428,19 +413,8 @@ Buffer::operator=(const Buffer &other) // Recreate highlighter engine consistent with syntax settings highlighter_.reset(); - if (syntax_enabled_) { - highlighter_ = std::make_unique(); - if (!filetype_.empty()) { - auto hl = kte::HighlighterRegistry::CreateFor(filetype_); - if (hl) { - highlighter_->SetHighlighter(std::move(hl)); - } else { - highlighter_->SetHighlighter(std::make_unique()); - } - } else { - highlighter_->SetHighlighter(std::make_unique()); - } - } + if (syntax_enabled_) + InstallFiletypeHighlighter(); return *this; } @@ -768,6 +742,29 @@ Buffer::insert_text(int row, int col, std::string_view text) } +void +Buffer::ApplyDetectedFiletype() +{ + EnsureHighlighter(); + const std::string first = Nrows() > 0 ? GetLineString(0) : std::string(); + const std::string ft = kte::HighlighterRegistry::DetectForPath(filename_, first); + SetFiletype(ft); + SetSyntaxEnabled(true); + InstallFiletypeHighlighter(); +} + + +void +Buffer::InstallFiletypeHighlighter() +{ + EnsureHighlighter(); + auto hl = filetype_.empty() ? nullptr : kte::HighlighterRegistry::CreateFor(filetype_); + if (!hl) + hl = std::make_unique(); + highlighter_->SetHighlighter(std::move(hl)); +} + + // ===== Adapter helpers for PieceTable-backed Buffer ===== std::string Buffer::Bytes() const diff --git a/Buffer.h b/Buffer.h index 6da64e8..faca09b 100644 --- a/Buffer.h +++ b/Buffer.h @@ -472,6 +472,15 @@ public: } + // Enable syntax with the highlighter the filename (or a shebang on the + // first line) calls for, or none for an unknown type. + void ApplyDetectedFiletype(); + + // Install the highlighter for Filetype() (the null highlighter for an + // empty or unsupported one), creating the engine if needed. + void InstallFiletypeHighlighter(); + + // Swap journal integration (set by Editor) void SetSwapRecorder(kte::SwapRecorder *rec) { diff --git a/Command.cc b/Command.cc index ab8e90f..e159ffc 100644 --- a/Command.cc +++ b/Command.cc @@ -15,7 +15,6 @@ #include "RegexEngine.h" #include "TermWidth.h" #include "syntax/HighlighterRegistry.h" -#include "syntax/NullHighlighter.h" #include "Editor.h" #include "Buffer.h" #include "UndoSystem.h" @@ -1641,29 +1640,12 @@ apply_filetype(Buffer &buf, const std::string &ft) buf.SetSyntaxEnabled(false); return; } - if (val.empty()) { - // Empty means unknown/unspecified -> use NullHighlighter but keep syntax enabled - buf.SetFiletype(""); - buf.SetSyntaxEnabled(true); - eng->SetHighlighter(std::make_unique()); - eng->InvalidateFrom(0); - return; - } - // Normalize and create via registry - std::string norm = kte::HighlighterRegistry::Normalize(val); - auto hl = kte::HighlighterRegistry::CreateFor(norm); - if (hl) { - eng->SetHighlighter(std::move(hl)); - buf.SetFiletype(norm); - buf.SetSyntaxEnabled(true); - eng->InvalidateFrom(0); - } else { - // Unknown -> install NullHighlighter and keep syntax enabled - eng->SetHighlighter(std::make_unique()); - buf.SetFiletype(val); // record what user asked even if unsupported - buf.SetSyntaxEnabled(true); - eng->InvalidateFrom(0); - } + // Empty means unspecified (no highlighting, syntax stays on); an + // unsupported type is recorded as asked, without highlighting. + const std::string norm = val.empty() ? val : kte::HighlighterRegistry::Normalize(val); + buf.SetFiletype(kte::HighlighterRegistry::CreateFor(norm) ? norm : val); + buf.SetSyntaxEnabled(true); + buf.InstallFiletypeHighlighter(); } diff --git a/Editor.cc b/Editor.cc index 1ad0133..a98563c 100644 --- a/Editor.cc +++ b/Editor.cc @@ -6,9 +6,7 @@ #include "Editor.h" #include "ErrorHandler.h" -#include "syntax/HighlighterRegistry.h" #include "syntax/CppHighlighter.h" -#include "syntax/NullHighlighter.h" namespace { @@ -285,27 +283,8 @@ Editor::OpenFile(const std::string &path, std::string &err) cur.SetSwapRecorder(Swap()->RecorderFor(&cur)); Swap()->NotifyFilenameChanged(cur); } - // Setup highlighting using registry (extension + shebang) - cur.EnsureHighlighter(); - std::string first = ""; - if (cur.Nrows() > 0) - first = cur.GetLineString(0); - std::string ft = kte::HighlighterRegistry::DetectForPath(path, first); - if (!ft.empty()) { - cur.SetFiletype(ft); - cur.SetSyntaxEnabled(true); - if (auto *eng = cur.Highlighter()) { - eng->SetHighlighter(kte::HighlighterRegistry::CreateFor(ft)); - eng->InvalidateFrom(0); - } - } else { - cur.SetFiletype(""); - cur.SetSyntaxEnabled(true); - if (auto *eng = cur.Highlighter()) { - eng->SetHighlighter(std::make_unique()); - eng->InvalidateFrom(0); - } - } + // Highlighting by extension or shebang + cur.ApplyDetectedFiletype(); // Defensive: ensure any active prompt is closed after a successful open CancelPrompt(); return true; @@ -318,27 +297,8 @@ Editor::OpenFile(const std::string &path, std::string &err) } // NOTE: swap recorder/attach must happen after the buffer is stored in its // final location (vector) because swap manager keys off Buffer*. - // Initialize syntax highlighting by extension + shebang via registry (v2) - b.EnsureHighlighter(); - std::string first = ""; - if (b.Nrows() > 0) - first = b.GetLineString(0); - std::string ft = kte::HighlighterRegistry::DetectForPath(path, first); - if (!ft.empty()) { - b.SetFiletype(ft); - b.SetSyntaxEnabled(true); - if (auto *eng = b.Highlighter()) { - eng->SetHighlighter(kte::HighlighterRegistry::CreateFor(ft)); - eng->InvalidateFrom(0); - } - } else { - b.SetFiletype(""); - b.SetSyntaxEnabled(true); - if (auto *eng = b.Highlighter()) { - eng->SetHighlighter(std::make_unique()); - eng->InvalidateFrom(0); - } - } + // Highlighting by extension or shebang + b.ApplyDetectedFiletype(); // Add as a new buffer and switch to it std::size_t idx = AddBuffer(std::move(b)); if (Swap()) { @@ -650,25 +610,8 @@ Editor::SwitchTo(std::size_t index) curbuf_ = index; // Robustness: ensure a valid highlighter is installed when switching buffers Buffer &b = bufs[curbuf_]; - if (b.SyntaxEnabled()) { - b.EnsureHighlighter(); - if (auto *eng = b.Highlighter()) { - if (!eng->HasHighlighter()) { - // Try to set based on existing filetype; fall back to NullHighlighter - if (!b.Filetype().empty()) { - auto hl = kte::HighlighterRegistry::CreateFor(b.Filetype()); - if (hl) { - eng->SetHighlighter(std::move(hl)); - } else { - eng->SetHighlighter(std::make_unique()); - } - } else { - eng->SetHighlighter(std::make_unique()); - } - eng->InvalidateFrom(0); - } - } - } + if (b.SyntaxEnabled() && !(b.Highlighter() && b.Highlighter()->HasHighlighter())) + b.InstallFiletypeHighlighter(); return true; } diff --git a/ImGuiFrontend.cc b/ImGuiFrontend.cc index 4076c8e..e873aa1 100644 --- a/ImGuiFrontend.cc +++ b/ImGuiFrontend.cc @@ -19,8 +19,6 @@ #include "fonts/Font.h" // embedded default font (DefaultFont) #include "fonts/FontRegistry.h" #include "fonts/IosevkaExtended.h" -#include "syntax/HighlighterRegistry.h" -#include "syntax/NullHighlighter.h" #ifndef KTE_FONT_SIZE @@ -54,22 +52,8 @@ apply_syntax_to_buffer(Buffer *b, const GUIConfig &cfg) if (cfg.syntax && b->GetEditMode() != EditMode::Writing) { b->SetSyntaxEnabled(true); b->EnsureHighlighter(); - if (auto *eng = b->Highlighter()) { - if (!eng->HasHighlighter()) { - const std::string first_line = b->Nrows() > 0 ? b->GetLineString(0) : std::string(); - std::string ft = kte::HighlighterRegistry::DetectForPath( - b->Filename(), first_line); - if (!ft.empty()) { - eng->SetHighlighter(kte::HighlighterRegistry::CreateFor(ft)); - b->SetFiletype(ft); - eng->InvalidateFrom(0); - } else { - eng->SetHighlighter(std::make_unique()); - b->SetFiletype(""); - eng->InvalidateFrom(0); - } - } - } + if (!b->Highlighter()->HasHighlighter()) + b->ApplyDetectedFiletype(); } else { b->SetSyntaxEnabled(false); }