Add proportional fonts, edit modes, and TOML config

- Add three proportional serif fonts: Crimson Pro, ET Book, Spectral
- Fix text rendering for variable-width fonts: selection, cursor,
  mouse click mapping, search highlights, and syntax-colored text
  now use pixel-accurate measurement via ImGui::CalcTextSize()
- Add per-buffer edit mode (code/writing) with auto-detection from
  file extension (.txt, .md, .rst, .org, .tex default to writing)
- Add C-k m keybinding and :mode command to toggle edit modes
- Switch config format from INI to TOML (kge.toml), with legacy
  INI fallback; vendor toml++ v3.4.0
- New config keys: font.code and font.writing for per-mode defaults
- Add font tab completion for ImGui builds
- Add tab completion for :mode command
- Update help text, themes.md, and add CONFIG.md
- Bump version to 1.10.0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 23:05:56 -07:00
parent 0585edad9e
commit 23f04e4357
21 changed files with 24521 additions and 123 deletions

View File

@@ -3,9 +3,29 @@
#include <fstream>
#include <sstream>
#include <algorithm>
#include <filesystem>
#include <iostream>
#include "GUIConfig.h"
// toml++ for TOML config parsing
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Weverything"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wall"
# pragma GCC diagnostic ignored "-Wextra"
#endif
#include "ext/tomlplusplus/toml.hpp"
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
static void
trim(std::string &s)
@@ -19,32 +39,104 @@ trim(std::string &s)
static std::string
default_config_path()
config_dir()
{
const char *home = std::getenv("HOME");
if (!home || !*home)
return {};
std::string path(home);
path += "/.config/kte/kge.ini";
return path;
return std::string(home) + "/.config/kte";
}
GUIConfig
GUIConfig::Load()
{
GUIConfig cfg; // defaults already set
const std::string path = default_config_path();
GUIConfig cfg;
std::string dir = config_dir();
if (dir.empty())
return cfg;
if (!path.empty()) {
cfg.LoadFromFile(path);
// Try TOML first
std::string toml_path = dir + "/kge.toml";
if (cfg.LoadFromTOML(toml_path))
return cfg;
// Fall back to legacy INI
std::string ini_path = dir + "/kge.ini";
if (cfg.LoadFromINI(ini_path)) {
std::cerr << "kge: loaded legacy kge.ini; consider migrating to kge.toml\n";
return cfg;
}
return cfg;
}
bool
GUIConfig::LoadFromFile(const std::string &path)
GUIConfig::LoadFromTOML(const std::string &path)
{
if (!std::filesystem::exists(path))
return false;
toml::table tbl;
try {
tbl = toml::parse_file(path);
} catch (const toml::parse_error &err) {
std::cerr << "kge: TOML parse error in " << path << ": " << err.what() << "\n";
return false;
}
// [window]
if (auto win = tbl["window"].as_table()) {
if (auto v = (*win)["fullscreen"].value<bool>())
fullscreen = *v;
if (auto v = (*win)["columns"].value<int64_t>()) {
if (*v > 0) columns = static_cast<int>(*v);
}
if (auto v = (*win)["rows"].value<int64_t>()) {
if (*v > 0) rows = static_cast<int>(*v);
}
}
// [font]
if (auto sec = tbl["font"].as_table()) {
if (auto v = (*sec)["name"].value<std::string>())
font = *v;
if (auto v = (*sec)["size"].value<double>()) {
if (*v > 0.0) font_size = static_cast<float>(*v);
}
if (auto v = (*sec)["code"].value<std::string>())
code_font = *v;
if (auto v = (*sec)["writing"].value<std::string>())
writing_font = *v;
}
// [appearance]
if (auto sec = tbl["appearance"].as_table()) {
if (auto v = (*sec)["theme"].value<std::string>())
theme = *v;
if (auto v = (*sec)["background"].value<std::string>()) {
std::string bg = *v;
std::transform(bg.begin(), bg.end(), bg.begin(), [](unsigned char c) {
return (char) std::tolower(c);
});
if (bg == "light" || bg == "dark")
background = bg;
}
}
// [editor]
if (auto sec = tbl["editor"].as_table()) {
if (auto v = (*sec)["syntax"].value<bool>())
syntax = *v;
}
return true;
}
bool
GUIConfig::LoadFromINI(const std::string &path)
{
std::ifstream in(path);
if (!in.good())
@@ -104,6 +196,10 @@ GUIConfig::LoadFromFile(const std::string &path)
}
} else if (key == "font") {
font = val;
} else if (key == "code_font") {
code_font = val;
} else if (key == "writing_font") {
writing_font = val;
} else if (key == "theme") {
theme = val;
} else if (key == "background" || key == "bg") {