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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
@@ -377,23 +377,8 @@ Buffer::Buffer(const Buffer &other)
|
|||||||
undo_sys_ = std::make_unique<UndoSystem>(*this, *undo_tree_);
|
undo_sys_ = std::make_unique<UndoSystem>(*this, *undo_tree_);
|
||||||
|
|
||||||
// Recreate a highlighter engine for this copy based on filetype/syntax state
|
// Recreate a highlighter engine for this copy based on filetype/syntax state
|
||||||
if (syntax_enabled_) {
|
if (syntax_enabled_)
|
||||||
// Allocate engine and install an appropriate highlighter
|
InstallFiletypeHighlighter();
|
||||||
highlighter_ = std::make_unique<kte::HighlighterEngine>();
|
|
||||||
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<kte::NullHighlighter>());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No filetype -> keep syntax enabled but use NullHighlighter
|
|
||||||
highlighter_->SetHighlighter(std::make_unique<kte::NullHighlighter>());
|
|
||||||
}
|
|
||||||
// Fresh engine has empty caches; nothing to invalidate
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -428,19 +413,8 @@ Buffer::operator=(const Buffer &other)
|
|||||||
|
|
||||||
// Recreate highlighter engine consistent with syntax settings
|
// Recreate highlighter engine consistent with syntax settings
|
||||||
highlighter_.reset();
|
highlighter_.reset();
|
||||||
if (syntax_enabled_) {
|
if (syntax_enabled_)
|
||||||
highlighter_ = std::make_unique<kte::HighlighterEngine>();
|
InstallFiletypeHighlighter();
|
||||||
if (!filetype_.empty()) {
|
|
||||||
auto hl = kte::HighlighterRegistry::CreateFor(filetype_);
|
|
||||||
if (hl) {
|
|
||||||
highlighter_->SetHighlighter(std::move(hl));
|
|
||||||
} else {
|
|
||||||
highlighter_->SetHighlighter(std::make_unique<kte::NullHighlighter>());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
highlighter_->SetHighlighter(std::make_unique<kte::NullHighlighter>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
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<kte::NullHighlighter>();
|
||||||
|
highlighter_->SetHighlighter(std::move(hl));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ===== Adapter helpers for PieceTable-backed Buffer =====
|
// ===== Adapter helpers for PieceTable-backed Buffer =====
|
||||||
std::string
|
std::string
|
||||||
Buffer::Bytes() const
|
Buffer::Bytes() const
|
||||||
|
|||||||
@@ -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)
|
// Swap journal integration (set by Editor)
|
||||||
void SetSwapRecorder(kte::SwapRecorder *rec)
|
void SetSwapRecorder(kte::SwapRecorder *rec)
|
||||||
{
|
{
|
||||||
|
|||||||
+6
-24
@@ -15,7 +15,6 @@
|
|||||||
#include "RegexEngine.h"
|
#include "RegexEngine.h"
|
||||||
#include "TermWidth.h"
|
#include "TermWidth.h"
|
||||||
#include "syntax/HighlighterRegistry.h"
|
#include "syntax/HighlighterRegistry.h"
|
||||||
#include "syntax/NullHighlighter.h"
|
|
||||||
#include "Editor.h"
|
#include "Editor.h"
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "UndoSystem.h"
|
#include "UndoSystem.h"
|
||||||
@@ -1641,29 +1640,12 @@ apply_filetype(Buffer &buf, const std::string &ft)
|
|||||||
buf.SetSyntaxEnabled(false);
|
buf.SetSyntaxEnabled(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (val.empty()) {
|
// Empty means unspecified (no highlighting, syntax stays on); an
|
||||||
// Empty means unknown/unspecified -> use NullHighlighter but keep syntax enabled
|
// unsupported type is recorded as asked, without highlighting.
|
||||||
buf.SetFiletype("");
|
const std::string norm = val.empty() ? val : kte::HighlighterRegistry::Normalize(val);
|
||||||
buf.SetSyntaxEnabled(true);
|
buf.SetFiletype(kte::HighlighterRegistry::CreateFor(norm) ? norm : val);
|
||||||
eng->SetHighlighter(std::make_unique<kte::NullHighlighter>());
|
buf.SetSyntaxEnabled(true);
|
||||||
eng->InvalidateFrom(0);
|
buf.InstallFiletypeHighlighter();
|
||||||
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<kte::NullHighlighter>());
|
|
||||||
buf.SetFiletype(val); // record what user asked even if unsupported
|
|
||||||
buf.SetSyntaxEnabled(true);
|
|
||||||
eng->InvalidateFrom(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,7 @@
|
|||||||
|
|
||||||
#include "Editor.h"
|
#include "Editor.h"
|
||||||
#include "ErrorHandler.h"
|
#include "ErrorHandler.h"
|
||||||
#include "syntax/HighlighterRegistry.h"
|
|
||||||
#include "syntax/CppHighlighter.h"
|
#include "syntax/CppHighlighter.h"
|
||||||
#include "syntax/NullHighlighter.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -285,27 +283,8 @@ Editor::OpenFile(const std::string &path, std::string &err)
|
|||||||
cur.SetSwapRecorder(Swap()->RecorderFor(&cur));
|
cur.SetSwapRecorder(Swap()->RecorderFor(&cur));
|
||||||
Swap()->NotifyFilenameChanged(cur);
|
Swap()->NotifyFilenameChanged(cur);
|
||||||
}
|
}
|
||||||
// Setup highlighting using registry (extension + shebang)
|
// Highlighting by extension or shebang
|
||||||
cur.EnsureHighlighter();
|
cur.ApplyDetectedFiletype();
|
||||||
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<kte::NullHighlighter>());
|
|
||||||
eng->InvalidateFrom(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Defensive: ensure any active prompt is closed after a successful open
|
// Defensive: ensure any active prompt is closed after a successful open
|
||||||
CancelPrompt();
|
CancelPrompt();
|
||||||
return true;
|
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
|
// NOTE: swap recorder/attach must happen after the buffer is stored in its
|
||||||
// final location (vector) because swap manager keys off Buffer*.
|
// final location (vector) because swap manager keys off Buffer*.
|
||||||
// Initialize syntax highlighting by extension + shebang via registry (v2)
|
// Highlighting by extension or shebang
|
||||||
b.EnsureHighlighter();
|
b.ApplyDetectedFiletype();
|
||||||
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<kte::NullHighlighter>());
|
|
||||||
eng->InvalidateFrom(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add as a new buffer and switch to it
|
// Add as a new buffer and switch to it
|
||||||
std::size_t idx = AddBuffer(std::move(b));
|
std::size_t idx = AddBuffer(std::move(b));
|
||||||
if (Swap()) {
|
if (Swap()) {
|
||||||
@@ -650,25 +610,8 @@ Editor::SwitchTo(std::size_t index)
|
|||||||
curbuf_ = index;
|
curbuf_ = index;
|
||||||
// Robustness: ensure a valid highlighter is installed when switching buffers
|
// Robustness: ensure a valid highlighter is installed when switching buffers
|
||||||
Buffer &b = bufs[curbuf_];
|
Buffer &b = bufs[curbuf_];
|
||||||
if (b.SyntaxEnabled()) {
|
if (b.SyntaxEnabled() && !(b.Highlighter() && b.Highlighter()->HasHighlighter()))
|
||||||
b.EnsureHighlighter();
|
b.InstallFiletypeHighlighter();
|
||||||
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<kte::NullHighlighter>());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eng->SetHighlighter(std::make_unique<kte::NullHighlighter>());
|
|
||||||
}
|
|
||||||
eng->InvalidateFrom(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-18
@@ -19,8 +19,6 @@
|
|||||||
#include "fonts/Font.h" // embedded default font (DefaultFont)
|
#include "fonts/Font.h" // embedded default font (DefaultFont)
|
||||||
#include "fonts/FontRegistry.h"
|
#include "fonts/FontRegistry.h"
|
||||||
#include "fonts/IosevkaExtended.h"
|
#include "fonts/IosevkaExtended.h"
|
||||||
#include "syntax/HighlighterRegistry.h"
|
|
||||||
#include "syntax/NullHighlighter.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef KTE_FONT_SIZE
|
#ifndef KTE_FONT_SIZE
|
||||||
@@ -54,22 +52,8 @@ apply_syntax_to_buffer(Buffer *b, const GUIConfig &cfg)
|
|||||||
if (cfg.syntax && b->GetEditMode() != EditMode::Writing) {
|
if (cfg.syntax && b->GetEditMode() != EditMode::Writing) {
|
||||||
b->SetSyntaxEnabled(true);
|
b->SetSyntaxEnabled(true);
|
||||||
b->EnsureHighlighter();
|
b->EnsureHighlighter();
|
||||||
if (auto *eng = b->Highlighter()) {
|
if (!b->Highlighter()->HasHighlighter())
|
||||||
if (!eng->HasHighlighter()) {
|
b->ApplyDetectedFiletype();
|
||||||
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<kte::NullHighlighter>());
|
|
||||||
b->SetFiletype("");
|
|
||||||
eng->InvalidateFrom(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
b->SetSyntaxEnabled(false);
|
b->SetSyntaxEnabled(false);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user