Add syntax highlighting infrastructure

- Introduced `HighlighterRegistry` with support for multiple language highlighters (e.g., JSON, Markdown, Python).
- Added `JsonHighlighter` implementation for basic JSON syntax highlighting.
This commit is contained in:
2025-12-01 18:20:36 -08:00
parent 4d84b352eb
commit 1a77f28ce4
38 changed files with 1701 additions and 590 deletions

View File

@@ -1,57 +1,48 @@
// GUITheme.h - ImGui theme configuration for kte GUI
// Provides theme palettes and style settings (Nord + Gruvbox variants).
// GUITheme.h ImGui theming helpers and background mode
#pragma once
#include <imgui.h>
#include <algorithm>
#include <memory>
#include <vector>
#include <memory>
#include <string>
#include <cstddef>
#include <algorithm>
#include <cctype>
namespace kte {
// Theme identifiers (legacy API kept for compatibility)
enum class ThemeId {
Nord,
GruvboxDarkMedium,
GruvboxLightMedium,
EInk, // monochrome e-ink style
Solarized, // solarized (light/dark via background)
Plan9, // plan9-inspired minimal theme (single acme-like palette)
};
// Background mode for themes that support light/dark variants
enum class BackgroundMode {
Dark,
Light,
};
// Forward declaration of registry helpers
class Theme;
static inline const std::vector<std::unique_ptr<Theme> > &ThemeRegistry();
static inline size_t ThemeIndexFromId(ThemeId id);
static inline ThemeId ThemeIdFromIndex(size_t idx);
// Keep track of current theme (program-wide)
static inline ThemeId gCurrentTheme = ThemeId::Nord;
// Background preference (defaults to Dark)
static inline BackgroundMode gBackgroundMode = BackgroundMode::Dark;
// Mirror index of current theme in the registry; keep it consistent with gCurrentTheme
// Current alphabetical order: 0=eink, 1=gruvbox, 2=nord, 3=solarized
static inline size_t gCurrentThemeIndex = ThemeIndexFromId(gCurrentTheme);
// Convert RGB hex (0xRRGGBB) to ImVec4 with optional alpha
static inline ImVec4
RGBA(unsigned int rgb, float a = 1.0f)
// Small helper to convert packed RGB (0xRRGGBB) + optional alpha to ImVec4
static inline ImVec4 RGBA(unsigned int rgb, float a = 1.0f)
{
float r = ((rgb >> 16) & 0xFF) / 255.0f;
float g = ((rgb >> 8) & 0xFF) / 255.0f;
float b = ((rgb) & 0xFF) / 255.0f;
return ImVec4(r, g, b, a);
const float r = static_cast<float>((rgb >> 16) & 0xFF) / 255.0f;
const float g = static_cast<float>((rgb >> 8) & 0xFF) / 255.0f;
const float b = static_cast<float>(rgb & 0xFF) / 255.0f;
return ImVec4(r, g, b, a);
}
namespace kte {
// Background mode selection for light/dark palettes
enum class BackgroundMode { Light, Dark };
// Global background mode; default to Dark to match prior defaults
static inline BackgroundMode gBackgroundMode = BackgroundMode::Dark;
// Basic theme identifier (kept minimal; some ids are aliases)
enum class ThemeId {
EInk = 0,
GruvboxDarkMedium = 1,
GruvboxLightMedium = 1, // alias to unified gruvbox index
Nord = 2,
Plan9 = 3,
Solarized = 4,
};
// Current theme tracking
static inline ThemeId gCurrentTheme = ThemeId::Nord;
static inline std::size_t gCurrentThemeIndex = 0;
// Forward declarations for helpers used below
static inline size_t ThemeIndexFromId(ThemeId id);
static inline ThemeId ThemeIdFromIndex(size_t idx);
// Helpers to set/query background mode
static inline void
@@ -1107,20 +1098,18 @@ CurrentThemeName()
static inline size_t
ThemeIndexFromId(ThemeId id)
{
switch (id) {
case ThemeId::EInk:
return 0;
case ThemeId::GruvboxDarkMedium:
return 1;
case ThemeId::GruvboxLightMedium: // legacy alias maps to unified gruvbox index
return 1;
case ThemeId::Nord:
return 2;
case ThemeId::Plan9:
return 3;
case ThemeId::Solarized:
return 4;
}
switch (id) {
case ThemeId::EInk:
return 0;
case ThemeId::GruvboxDarkMedium:
return 1;
case ThemeId::Nord:
return 2;
case ThemeId::Plan9:
return 3;
case ThemeId::Solarized:
return 4;
}
return 0;
}
@@ -1142,4 +1131,30 @@ ThemeIdFromIndex(size_t idx)
return ThemeId::Solarized;
}
}
// --- Syntax palette (v1): map TokenKind to ink color per current theme/background ---
static inline ImVec4 SyntaxInk(TokenKind k)
{
// Basic palettes for dark/light backgrounds; tuned for Nord-ish defaults
const bool dark = (GetBackgroundMode() == BackgroundMode::Dark);
// Base text
ImVec4 def = dark ? RGBA(0xD8DEE9) : RGBA(0x2E3440);
switch (k) {
case TokenKind::Keyword: return dark ? RGBA(0x81A1C1) : RGBA(0x5E81AC);
case TokenKind::Type: return dark ? RGBA(0x8FBCBB) : RGBA(0x4C566A);
case TokenKind::String: return dark ? RGBA(0xA3BE8C) : RGBA(0x6C8E5E);
case TokenKind::Char: return dark ? RGBA(0xA3BE8C) : RGBA(0x6C8E5E);
case TokenKind::Comment: return dark ? RGBA(0x616E88) : RGBA(0x7A869A);
case TokenKind::Number: return dark ? RGBA(0xEBCB8B) : RGBA(0xB58900);
case TokenKind::Preproc: return dark ? RGBA(0xD08770) : RGBA(0xAF3A03);
case TokenKind::Constant: return dark ? RGBA(0xB48EAD) : RGBA(0x7B4B7F);
case TokenKind::Function: return dark ? RGBA(0x88C0D0) : RGBA(0x3465A4);
case TokenKind::Operator: return dark ? RGBA(0xECEFF4) : RGBA(0x2E3440);
case TokenKind::Punctuation: return dark ? RGBA(0xECEFF4) : RGBA(0x2E3440);
case TokenKind::Identifier: return def;
case TokenKind::Whitespace: return def;
case TokenKind::Error: return dark ? RGBA(0xBF616A) : RGBA(0xCC0000);
case TokenKind::Default: default: return def;
}
}
} // namespace kte