From 23f04e4357230d1d707b034cfbb06cd40ad7b04a Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Tue, 24 Mar 2026 23:05:56 -0700 Subject: [PATCH] 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) --- Buffer.h | 47 + CMakeLists.txt | 5 +- CONFIG.md | 116 + Command.cc | 68 +- Command.h | 2 + GUIConfig.cc | 114 +- GUIConfig.h | 20 +- HelpText.cc | 25 +- ImGuiFrontend.cc | 27 + ImGuiRenderer.cc | 200 +- KKeymap.cc | 3 + docs/themes.md | 13 +- ext/tomlplusplus/toml.hpp | 17748 ++++++++++++++++++++++++++++++++++++ fonts/CrimsonPro.h | 1768 ++++ fonts/ETBook.h | 1203 +++ fonts/FontList.h | 3 + fonts/FontRegistry.cc | 15 + fonts/FontRegistry.h | 15 + fonts/Spectral.h | 3227 +++++++ kge.toml.example | 24 + make-release | 1 + 21 files changed, 24521 insertions(+), 123 deletions(-) create mode 100644 CONFIG.md create mode 100644 ext/tomlplusplus/toml.hpp create mode 100644 fonts/CrimsonPro.h create mode 100644 fonts/ETBook.h create mode 100644 fonts/Spectral.h create mode 100644 kge.toml.example diff --git a/Buffer.h b/Buffer.h index 816cf25..7b545ec 100644 --- a/Buffer.h +++ b/Buffer.h @@ -35,9 +35,12 @@ */ #pragma once +#include #include +#include #include #include +#include #include #include @@ -48,6 +51,26 @@ #include "Highlight.h" #include +// Edit mode determines which font class is used for a buffer. +enum class EditMode { Code, Writing }; + +// Detect edit mode from a filename's extension. +inline EditMode +DetectEditMode(const std::string &filename) +{ + std::string ext = std::filesystem::path(filename).extension().string(); + std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { + return static_cast(std::tolower(c)); + }); + static const std::unordered_set writing_exts = { + ".txt", ".md", ".markdown", ".rst", ".org", + ".tex", ".adoc", ".asciidoc", + }; + if (writing_exts.count(ext)) + return EditMode::Writing; + return EditMode::Code; +} + // Forward declaration for swap journal integration namespace kte { class SwapRecorder; @@ -484,6 +507,27 @@ public: } + // Edit mode (code vs writing) + [[nodiscard]] EditMode GetEditMode() const + { + return edit_mode_; + } + + + void SetEditMode(EditMode m) + { + edit_mode_ = m; + } + + + void ToggleEditMode() + { + edit_mode_ = (edit_mode_ == EditMode::Code) + ? EditMode::Writing + : EditMode::Code; + } + + void SetSyntaxEnabled(bool on) { syntax_enabled_ = on; @@ -614,6 +658,9 @@ private: std::unique_ptr undo_tree_; std::unique_ptr undo_sys_; + // Edit mode (code vs writing) + EditMode edit_mode_ = EditMode::Code; + // Syntax/highlighting state std::uint64_t version_ = 0; // increment on edits bool syntax_enabled_ = true; diff --git a/CMakeLists.txt b/CMakeLists.txt index c7afe2f..eb04d66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(kte) include(GNUInstallDirs) set(CMAKE_CXX_STANDARD 20) -set(KTE_VERSION "1.9.1") +set(KTE_VERSION "1.10.0") # Default to terminal-only build to avoid SDL/OpenGL dependency by default. # Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available. @@ -205,6 +205,8 @@ set(FONT_HEADERS fonts/FontList.h fonts/B612Mono.h fonts/BrassMono.h + fonts/CrimsonPro.h + fonts/ETBook.h fonts/BrassMonoCode.h fonts/FiraCode.h fonts/Go.h @@ -216,6 +218,7 @@ set(FONT_HEADERS fonts/IosevkaExtended.h fonts/ShareTech.h fonts/SpaceMono.h + fonts/Spectral.h fonts/Syne.h fonts/Triplicate.h fonts/Unispace.h diff --git a/CONFIG.md b/CONFIG.md new file mode 100644 index 0000000..f45a532 --- /dev/null +++ b/CONFIG.md @@ -0,0 +1,116 @@ +# kge Configuration + +kge loads configuration from `~/.config/kte/kge.toml`. If no TOML file is +found, it falls back to the legacy `kge.ini` format. + +## TOML Format + +```toml +[window] +fullscreen = false +columns = 80 +rows = 42 + +[font] +# Default font and size +name = "default" +size = 18.0 +# Font used in code mode (monospace) +code = "default" +# Font used in writing mode (proportional) +writing = "crimsonpro" + +[appearance] +theme = "nord" +# "dark" or "light" for themes with variants +background = "dark" + +[editor] +syntax = true +``` + +## Sections + +### `[window]` + +| Key | Type | Default | Description | +|--------------|------|---------|---------------------------------| +| `fullscreen` | bool | false | Start in fullscreen mode | +| `columns` | int | 80 | Initial window width in columns | +| `rows` | int | 42 | Initial window height in rows | + +### `[font]` + +| Key | Type | Default | Description | +|-----------|--------|--------------|------------------------------------------| +| `name` | string | "default" | Default font loaded at startup | +| `size` | float | 18.0 | Font size in pixels | +| `code` | string | "default" | Font for code mode (monospace) | +| `writing` | string | "crimsonpro" | Font for writing mode (proportional) | + +### `[appearance]` + +| Key | Type | Default | Description | +|--------------|--------|---------|-----------------------------------------| +| `theme` | string | "nord" | Color theme | +| `background` | string | "dark" | Background mode: "dark" or "light" | + +### `[editor]` + +| Key | Type | Default | Description | +|----------|------|---------|------------------------------| +| `syntax` | bool | true | Enable syntax highlighting | + +## Edit Modes + +kge has two edit modes that control which font is used: + +- **code** — Uses the monospace font (`font.code`). Default for source files. +- **writing** — Uses the proportional font (`font.writing`). Auto-detected + for `.txt`, `.md`, `.markdown`, `.rst`, `.org`, `.tex`, `.adoc`, and + `.asciidoc` files. + +Toggle with `C-k m` or `: mode [code|writing]`. + +## Available Fonts + +### Monospace + +b612, berkeley, berkeley-bold, brassmono, brassmono-bold, brassmonocode, +brassmonocode-bold, fira, go, ibm, idealist, inconsolata, inconsolataex, +iosevka, iosevkaex, sharetech, space, syne, triplicate, unispace + +### Proportional (Serif) + +crimsonpro, etbook, spectral + +## Available Themes + +amber, eink, everforest, gruvbox, kanagawa-paper, lcars, leuchtturm, nord, +old-book, orbital, plan9, solarized, tufte, weyland-yutani, zenburn + +Themes with light/dark variants: eink, gruvbox, leuchtturm, old-book, +solarized. Set `background = "light"` or use `: background light`. + +## Migrating from kge.ini + +If you have an existing `kge.ini`, kge will still read it but prints a +notice to stderr suggesting migration. To migrate, create `kge.toml` in the +same directory (`~/.config/kte/`) using the format above. The TOML file +takes priority when both exist. + +The INI keys map to TOML as follows: + +| INI key | TOML equivalent | +|---------------|--------------------------| +| `fullscreen` | `window.fullscreen` | +| `columns` | `window.columns` | +| `rows` | `window.rows` | +| `font` | `font.name` | +| `font_size` | `font.size` | +| `theme` | `appearance.theme` | +| `background` | `appearance.background` | +| `syntax` | `editor.syntax` | + +New keys `font.code` and `font.writing` have no INI equivalent (the INI +parser accepts `code_font` and `writing_font` if needed). diff --git a/Command.cc b/Command.cc index bc2dd1d..1cf5957 100644 --- a/Command.cc +++ b/Command.cc @@ -1335,6 +1335,40 @@ cmd_font_set_size(CommandContext &ctx) #endif +// Toggle edit mode (code/writing) for current buffer +static bool +cmd_toggle_edit_mode(const CommandContext &ctx) +{ + Buffer *b = ctx.editor.CurrentBuffer(); + if (!b) + return false; + + std::string arg = ctx.arg; + std::transform(arg.begin(), arg.end(), arg.begin(), [](unsigned char c) { + return static_cast(std::tolower(c)); + }); + // Trim whitespace + auto start = arg.find_first_not_of(" \t"); + if (start != std::string::npos) + arg = arg.substr(start); + auto end = arg.find_last_not_of(" \t"); + if (end != std::string::npos) + arg = arg.substr(0, end + 1); + + if (arg == "code") { + b->SetEditMode(EditMode::Code); + } else if (arg == "writing") { + b->SetEditMode(EditMode::Writing); + } else { + b->ToggleEditMode(); + } + + const char *mode_str = (b->GetEditMode() == EditMode::Writing) ? "writing" : "code"; + ctx.editor.SetStatus(std::string("Mode: ") + mode_str); + return true; +} + + // Background set command (GUI, ImGui-only for now) #if defined(KTE_BUILD_GUI) && !defined(KTE_USE_QT) static bool @@ -1888,15 +1922,15 @@ cmd_insert_text(CommandContext &ctx) #endif } if (cmd == "font") { -#if defined(KTE_BUILD_GUI) && defined(KTE_USE_QT) - // Complete against installed font families (case-insensitive prefix) std::vector cands; - QStringList fams = QFontDatabase::families(); std::string apfx_lower = argprefix; std::transform(apfx_lower.begin(), apfx_lower.end(), apfx_lower.begin(), [](unsigned char c) { return (char) std::tolower(c); }); +#if defined(KTE_BUILD_GUI) && defined(KTE_USE_QT) + // Qt: complete against system font families + QStringList fams = QFontDatabase::families(); for (const auto &fam: fams) { std::string n = fam.toStdString(); std::string nlower = n; @@ -1907,6 +1941,13 @@ cmd_insert_text(CommandContext &ctx) if (apfx_lower.empty() || nlower.rfind(apfx_lower, 0) == 0) cands.push_back(n); } +#elif defined(KTE_BUILD_GUI) + // ImGui: complete against embedded font registry + for (const auto &n : kte::Fonts::FontRegistry::Instance().FontNames()) { + if (apfx_lower.empty() || n.rfind(apfx_lower, 0) == 0) + cands.push_back(n); + } +#endif if (cands.empty()) { // no change } else if (cands.size() == 1) { @@ -1927,9 +1968,19 @@ cmd_insert_text(CommandContext &ctx) } ctx.editor.SetStatus(std::string(": ") + ctx.editor.PromptText()); return true; -#else - (void) argprefix; -#endif + } + if (cmd == "mode") { + std::vector modes = {"code", "writing"}; + std::vector cands; + for (const auto &m : modes) { + if (argprefix.empty() || m.rfind(argprefix, 0) == 0) + cands.push_back(m); + } + if (cands.size() == 1) { + ctx.editor.SetPromptText(cmd + std::string(" ") + cands[0]); + } + ctx.editor.SetStatus(std::string(": ") + ctx.editor.PromptText()); + return true; } // default: no special arg completion ctx.editor.SetStatus(std::string(": ") + ctx.editor.PromptText()); @@ -5025,6 +5076,11 @@ InstallDefaultCommands() CommandId::NewWindow, "new-window", "Open a new editor window (GUI only)", cmd_new_window, false, false }); + // Edit mode toggle (public) + CommandRegistry::Register({ + CommandId::ToggleEditMode, "mode", "Toggle or set edit mode: code|writing", + cmd_toggle_edit_mode, true, false + }); } diff --git a/Command.h b/Command.h index 778a1e9..f6af21c 100644 --- a/Command.h +++ b/Command.h @@ -117,6 +117,8 @@ enum class CommandId { FontZoomIn, FontZoomOut, FontZoomReset, + // Edit mode (code/writing) + ToggleEditMode, }; diff --git a/GUIConfig.cc b/GUIConfig.cc index 76ad99f..ac62dc7 100644 --- a/GUIConfig.cc +++ b/GUIConfig.cc @@ -3,9 +3,29 @@ #include #include #include +#include +#include #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()) + fullscreen = *v; + if (auto v = (*win)["columns"].value()) { + if (*v > 0) columns = static_cast(*v); + } + if (auto v = (*win)["rows"].value()) { + if (*v > 0) rows = static_cast(*v); + } + } + + // [font] + if (auto sec = tbl["font"].as_table()) { + if (auto v = (*sec)["name"].value()) + font = *v; + if (auto v = (*sec)["size"].value()) { + if (*v > 0.0) font_size = static_cast(*v); + } + if (auto v = (*sec)["code"].value()) + code_font = *v; + if (auto v = (*sec)["writing"].value()) + writing_font = *v; + } + + // [appearance] + if (auto sec = tbl["appearance"].as_table()) { + if (auto v = (*sec)["theme"].value()) + theme = *v; + if (auto v = (*sec)["background"].value()) { + 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()) + 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") { diff --git a/GUIConfig.h b/GUIConfig.h index 6c788b4..7e9a440 100644 --- a/GUIConfig.h +++ b/GUIConfig.h @@ -1,5 +1,7 @@ /* - * GUIConfig - loads simple GUI configuration from $HOME/.config/kte/kge.ini + * GUIConfig - loads GUI configuration from $HOME/.config/kte/kge.toml + * + * Falls back to legacy kge.ini if no TOML config is found. */ #pragma once @@ -22,12 +24,18 @@ public: std::string background = "dark"; // Default syntax highlighting state for GUI (kge): on/off - // Accepts: on/off/true/false/yes/no/1/0 in the ini file. - bool syntax = true; // default: enabled + bool syntax = true; - // Load from default path: $HOME/.config/kte/kge.ini + // Per-mode font defaults + std::string code_font = "default"; + std::string writing_font = "crimsonpro"; + + // Load from default paths: try kge.toml first, fall back to kge.ini static GUIConfig Load(); - // Load from explicit path. Returns true if file existed and was parsed. - bool LoadFromFile(const std::string &path); + // Load from explicit TOML path. Returns true if file existed and was parsed. + bool LoadFromTOML(const std::string &path); + + // Load from explicit INI path (legacy). Returns true if file existed and was parsed. + bool LoadFromINI(const std::string &path); }; diff --git a/HelpText.cc b/HelpText.cc index 7fa4877..c519af2 100644 --- a/HelpText.cc +++ b/HelpText.cc @@ -41,6 +41,7 @@ HelpText::Text() " C-k j Jump to mark\n" " C-k k Center viewport on cursor\n" " C-k l Reload buffer from disk\n" + " C-k m Toggle edit mode (code/writing)\n" " C-k n Previous buffer\n" " C-k o Change working directory (prompt)\n" " C-k p Next buffer\n" @@ -82,12 +83,24 @@ HelpText::Text() "\n" "Buffers:\n +HELP+ is read-only. Press C-k ' to toggle; C-k h restores it.\n" "\n" - "GUI appearance (command prompt):\n" - " : theme NAME Set GUI theme (amber, eink, everforest, gruvbox, kanagawa-paper, lcars, nord, old-book, plan9, solarized, weyland-yutani, zenburn)\n" - " : background MODE Set background: light | dark (affects eink, gruvbox, old-book, solarized)\n" + "Edit modes:\n" + " code Monospace font (default for source files)\n" + " writing Proportional font (auto for .txt, .md, .rst, .org, .tex)\n" + " C-k m or : mode [code|writing] to toggle\n" "\n" - "GUI config file options:\n" - " font_size=NUM Set font size in pixels (default: 16; e.g., font_size=18)\n" + "GUI commands (command prompt):\n" + " : theme NAME Set theme (amber, eink, everforest, gruvbox,\n" + " kanagawa-paper, lcars, leuchtturm, nord, old-book,\n" + " orbital, plan9, solarized, tufte, weyland-yutani,\n" + " zenburn)\n" + " : background MODE Background: light | dark\n" + " : font NAME Set font (tab completes)\n" + " : font-size NUM Set font size in pixels\n" + " : mode [code|writing] Toggle or set edit mode\n" + "\n" + "Configuration:\n" + " Config file: ~/.config/kte/kge.toml (see CONFIG.md)\n" + " Legacy kge.ini is also supported.\n" "\n" "GUI window management:\n" " Cmd+N (macOS) Open a new editor window sharing the same buffers\n" @@ -95,4 +108,4 @@ HelpText::Text() " Close window Secondary windows close independently; closing the\n" " primary window quits the editor\n" ); -} \ No newline at end of file +} diff --git a/ImGuiFrontend.cc b/ImGuiFrontend.cc index 940c7e6..d21175f 100644 --- a/ImGuiFrontend.cc +++ b/ImGuiFrontend.cc @@ -38,6 +38,11 @@ apply_syntax_to_buffer(Buffer *b, const GUIConfig &cfg) { if (!b) return; + + // Auto-detect edit mode from file extension + if (!b->Filename().empty()) + b->SetEditMode(DetectEditMode(b->Filename())); + if (cfg.syntax) { b->SetSyntaxEnabled(true); b->EnsureHighlighter(); @@ -518,6 +523,9 @@ GUIFrontend::Step(Editor &ed, bool &running) // Allow deferred opens wed.ProcessPendingOpens(); + // Ensure newly opened buffers get syntax + edit mode detection + apply_syntax_to_buffer(wed.CurrentBuffer(), config_); + // Drain input queue for (;;) { MappedInput mi; @@ -557,6 +565,25 @@ GUIFrontend::Step(Editor &ed, bool &running) running = false; } + // Switch font based on current buffer's edit mode + { + Buffer *cur = wed.CurrentBuffer(); + if (cur) { + auto &fr = kte::Fonts::FontRegistry::Instance(); + const std::string &expected = + (cur->GetEditMode() == EditMode::Writing) + ? config_.writing_font + : config_.code_font; + if (fr.CurrentFontName() != expected && fr.HasFont(expected)) { + float sz = fr.CurrentFontSize(); + if (sz <= 0.0f) sz = config_.font_size; + fr.LoadFont(expected, sz); + ImGui_ImplOpenGL3_DestroyFontsTexture(); + ImGui_ImplOpenGL3_CreateFontsTexture(); + } + } + } + // Draw ws.renderer.Draw(wed); diff --git a/ImGuiRenderer.cc b/ImGuiRenderer.cc index 062a443..2db364a 100644 --- a/ImGuiRenderer.cc +++ b/ImGuiRenderer.cc @@ -175,29 +175,54 @@ ImGuiRenderer::Draw(Editor &ed) if (by >= lines.size()) by = lines.empty() ? 0 : (lines.size() - 1); - // Convert mouse pos to rendered x + if (lines.empty()) + return {0, 0}; + + // Expand tabs for the clicked line + std::string line_clicked = static_cast(lines[by]); + const std::size_t tabw = 8; + std::string click_expanded; + click_expanded.reserve(line_clicked.size() + 16); + std::size_t click_rx = 0; + // Map: source column -> expanded column + std::vector src_to_exp; + src_to_exp.reserve(line_clicked.size() + 1); + for (std::size_t ci = 0; ci < line_clicked.size(); ++ci) { + src_to_exp.push_back(click_rx); + if (line_clicked[ci] == '\t') { + std::size_t adv = (tabw - (click_rx % tabw)); + click_expanded.append(adv, ' '); + click_rx += adv; + } else { + click_expanded.push_back(line_clicked[ci]); + click_rx += 1; + } + } + src_to_exp.push_back(click_rx); // past-end position + + // Pixel x relative to the line start (accounting for scroll) float visual_x = mp.x - child_window_pos.x; if (visual_x < 0.0f) visual_x = 0.0f; - std::size_t clicked_rx = static_cast(visual_x / space_w) + coloffs_now; + // Add scroll offset in pixels + visual_x += scroll_x; - // Convert rendered column to source column - if (lines.empty()) - return {0, 0}; - std::string line_clicked = static_cast(lines[by]); - const std::size_t tabw = 8; - std::size_t rx = 0; - std::size_t best_col = 0; - float best_dist = std::numeric_limits::infinity(); - float clicked_rx_f = static_cast(clicked_rx); - for (std::size_t i = 0; i <= line_clicked.size(); ++i) { - float dist = std::fabs(clicked_rx_f - static_cast(rx)); + // Find the source column whose expanded position is closest + // to the click pixel, using actual text measurement. + std::size_t best_col = 0; + float best_dist = std::numeric_limits::infinity(); + for (std::size_t ci = 0; ci <= line_clicked.size(); ++ci) { + std::size_t exp_col = src_to_exp[ci]; + float px = 0.0f; + if (exp_col > 0 && !click_expanded.empty()) { + std::size_t end = std::min(click_expanded.size(), exp_col); + px = ImGui::CalcTextSize(click_expanded.c_str(), + click_expanded.c_str() + end).x; + } + float dist = std::fabs(visual_x - px); if (dist < best_dist) { best_dist = dist; - best_col = i; - } - if (i < line_clicked.size()) { - rx += (line_clicked[i] == '\t') ? (tabw - (rx % tabw)) : 1; + best_col = ci; } } return {by, best_col}; @@ -244,11 +269,37 @@ ImGuiRenderer::Draw(Editor &ed) ImVec2 line_pos = ImGui::GetCursorScreenPos(); std::string line = static_cast(lines[i]); - // Expand tabs to spaces with width=8 and apply horizontal scroll offset + // Expand tabs to spaces with width=8 const std::size_t tabw = 8; std::string expanded; expanded.reserve(line.size() + 16); - std::size_t rx_abs_draw = 0; // rendered column for drawing + std::size_t rx_abs_draw = 0; + for (std::size_t src = 0; src < line.size(); ++src) { + char c = line[src]; + if (c == '\t') { + std::size_t adv = (tabw - (rx_abs_draw % tabw)); + expanded.append(adv, ' '); + rx_abs_draw += adv; + } else { + expanded.push_back(c); + rx_abs_draw += 1; + } + } + + // Helper: convert a rendered column position to pixel x offset + // relative to the visible line start, using actual text measurement + // so proportional fonts render correctly. + auto rx_to_px = [&](std::size_t rx_col) -> float { + if (rx_col <= coloffs_now) + return 0.0f; + std::size_t start = coloffs_now; + std::size_t end = std::min(expanded.size(), rx_col); + if (start >= expanded.size() || end <= start) + return 0.0f; + return ImGui::CalcTextSize(expanded.c_str() + start, + expanded.c_str() + end).x; + }; + // Compute search highlight ranges for this line in source indices bool search_mode = ed.SearchActive() && !ed.SearchQuery().empty(); std::vector > hl_src_ranges; @@ -303,10 +354,8 @@ ImGuiRenderer::Draw(Editor &ed) // Apply horizontal scroll offset if (rx_end <= coloffs_now) continue; // fully left of view - std::size_t vx0 = (rx_start > coloffs_now) ? (rx_start - coloffs_now) : 0; - std::size_t vx1 = rx_end - coloffs_now; - ImVec2 p0 = ImVec2(line_pos.x + static_cast(vx0) * space_w, line_pos.y); - ImVec2 p1 = ImVec2(line_pos.x + static_cast(vx1) * space_w, + ImVec2 p0 = ImVec2(line_pos.x + rx_to_px(rx_start), line_pos.y); + ImVec2 p1 = ImVec2(line_pos.x + rx_to_px(rx_end), line_pos.y + line_h); // Choose color: current match stronger bool is_current = has_current && sx == cur_x && ex == cur_end; @@ -344,13 +393,9 @@ ImGuiRenderer::Draw(Editor &ed) std::size_t rx_start = src_to_rx(sx); std::size_t rx_end = src_to_rx(ex); if (rx_end > coloffs_now) { - std::size_t vx0 = (rx_start > coloffs_now) - ? (rx_start - coloffs_now) - : 0; - std::size_t vx1 = rx_end - coloffs_now; - ImVec2 p0 = ImVec2(line_pos.x + static_cast(vx0) * space_w, - line_pos.y); - ImVec2 p1 = ImVec2(line_pos.x + static_cast(vx1) * space_w, + ImVec2 p0 = ImVec2(line_pos.x + rx_to_px(rx_start), + line_pos.y); + ImVec2 p1 = ImVec2(line_pos.x + rx_to_px(rx_end), line_pos.y + line_h); ImU32 col = ImGui::GetColorU32(ImGuiCol_TextSelectedBg); ImGui::GetWindowDrawList()->AddRectFilled(p0, p1, col); @@ -369,31 +414,14 @@ ImGuiRenderer::Draw(Editor &ed) rx_end = rx_start + 1; } if (rx_end > coloffs_now) { - std::size_t vx0 = (rx_start > coloffs_now) - ? (rx_start - coloffs_now) - : 0; - std::size_t vx1 = rx_end - coloffs_now; - ImVec2 p0 = ImVec2(line_pos.x + static_cast(vx0) * space_w, - line_pos.y); - ImVec2 p1 = ImVec2(line_pos.x + static_cast(vx1) * space_w, + ImVec2 p0 = ImVec2(line_pos.x + rx_to_px(rx_start), + line_pos.y); + ImVec2 p1 = ImVec2(line_pos.x + rx_to_px(rx_end), line_pos.y + line_h); ImU32 col = ImGui::GetColorU32(ImGuiCol_TextSelectedBg); ImGui::GetWindowDrawList()->AddRectFilled(p0, p1, col); } } - // Emit entire line to an expanded buffer (tabs -> spaces) - for (std::size_t src = 0; src < line.size(); ++src) { - char c = line[src]; - if (c == '\t') { - std::size_t adv = (tabw - (rx_abs_draw % tabw)); - expanded.append(adv, ' '); - rx_abs_draw += adv; - } else { - expanded.push_back(c); - rx_abs_draw += 1; - } - } - // Draw syntax-colored runs (text above background highlights) if (buf->SyntaxEnabled() && buf->Highlighter() && buf->Highlighter()->HasHighlighter()) { kte::LineHighlight lh = buf->Highlighter()->GetLine( @@ -445,10 +473,9 @@ ImGuiRenderer::Draw(Editor &ed) std::size_t draw_end = std::min(rx_e, expanded.size()); if (draw_end <= draw_start) continue; - // Screen position is relative to coloffs_now - std::size_t screen_x = draw_start - coloffs_now; + // Screen position via actual text measurement ImU32 col = ImGui::GetColorU32(kte::SyntaxInk(sp.k)); - ImVec2 p = ImVec2(line_pos.x + static_cast(screen_x) * space_w, + ImVec2 p = ImVec2(line_pos.x + rx_to_px(draw_start), line_pos.y); ImGui::GetWindowDrawList()->AddText( p, col, expanded.c_str() + draw_start, expanded.c_str() + draw_end); @@ -472,28 +499,8 @@ ImGuiRenderer::Draw(Editor &ed) // Draw a visible cursor indicator on the current line if (i == cy) { - // Compute rendered X (rx) from source column with tab expansion - std::size_t rx_abs = 0; - for (std::size_t k = 0; k < std::min(cx, line.size()); ++k) { - if (line[k] == '\t') - rx_abs += (tabw - (rx_abs % tabw)); - else - rx_abs += 1; - } - // Convert to viewport x by subtracting horizontal col offset - std::size_t rx_viewport = (rx_abs > coloffs_now) ? (rx_abs - coloffs_now) : 0; - // For proportional fonts (Linux GUI), avoid accumulating drift by computing - // the exact pixel width of the expanded substring up to the cursor. - // expanded contains the line with tabs expanded to spaces and is what we draw. - float cursor_px = 0.0f; - if (rx_viewport > 0 && coloffs_now < expanded.size()) { - std::size_t start = coloffs_now; - std::size_t end = std::min(expanded.size(), start + rx_viewport); - // Measure substring width in pixels - ImVec2 sz = ImGui::CalcTextSize(expanded.c_str() + start, - expanded.c_str() + end); - cursor_px = sz.x; - } + std::size_t rx_abs = src_to_rx(cx); + float cursor_px = rx_to_px(rx_abs); ImVec2 p0 = ImVec2(line_pos.x + cursor_px, line_pos.y); ImVec2 p1 = ImVec2(p0.x + space_w, p0.y + line_h); ImU32 col = IM_COL32(200, 200, 255, 128); // soft highlight @@ -539,29 +546,40 @@ ImGuiRenderer::Draw(Editor &ed) last_row = first_row + vis_rows - 1; } - // Horizontal scroll: ensure cursor column is visible - long vis_cols = static_cast(std::round(child_w_actual / space_w)); - if (vis_cols < 1) - vis_cols = 1; - long first_col = static_cast(scroll_x_now / space_w); - long last_col = first_col + vis_cols - 1; - - std::size_t cursor_rx = 0; + // Horizontal scroll: ensure cursor is visible (pixel-based for proportional fonts) + float cursor_px_abs = 0.0f; if (cy < lines.size()) { std::string cur_line = static_cast(lines[cy]); const std::size_t tabw = 8; - for (std::size_t i = 0; i < cx && i < cur_line.size(); ++i) { - if (cur_line[i] == '\t') { - cursor_rx += tabw - (cursor_rx % tabw); + // Expand tabs for cursor line to measure pixel position + std::string cur_expanded; + cur_expanded.reserve(cur_line.size() + 16); + std::size_t cur_rx = 0; + for (std::size_t ci = 0; ci < cur_line.size(); ++ci) { + if (cur_line[ci] == '\t') { + std::size_t adv = tabw - (cur_rx % tabw); + cur_expanded.append(adv, ' '); + cur_rx += adv; } else { - cursor_rx += 1; + cur_expanded.push_back(cur_line[ci]); + cur_rx += 1; } } + // Compute rendered column of cursor + std::size_t cursor_rx = 0; + for (std::size_t ci = 0; ci < cx && ci < cur_line.size(); ++ci) { + if (cur_line[ci] == '\t') + cursor_rx += tabw - (cursor_rx % tabw); + else + cursor_rx += 1; + } + std::size_t exp_end = std::min(cur_expanded.size(), cursor_rx); + if (exp_end > 0) + cursor_px_abs = ImGui::CalcTextSize(cur_expanded.c_str(), + cur_expanded.c_str() + exp_end).x; } - long cxr = static_cast(cursor_rx); - if (cxr < first_col || cxr > last_col) { - float target_x = static_cast(cxr) * space_w; - target_x -= (child_w_actual / 2.0f); + if (cursor_px_abs < scroll_x_now || cursor_px_abs > scroll_x_now + child_w_actual) { + float target_x = cursor_px_abs - (child_w_actual / 2.0f); if (target_x < 0.f) target_x = 0.f; float max_x = ImGui::GetScrollMaxX(); diff --git a/KKeymap.cc b/KKeymap.cc index cd1e83d..e0b6146 100644 --- a/KKeymap.cc +++ b/KKeymap.cc @@ -84,6 +84,9 @@ KLookupKCommand(const int ascii_key, const bool ctrl, CommandId &out) -> bool case 'l': out = CommandId::ReloadBuffer; return true; + case 'm': + out = CommandId::ToggleEditMode; + return true; case 'n': out = CommandId::BufferPrev; return true; diff --git a/docs/themes.md b/docs/themes.md index 41d540b..98406d3 100644 --- a/docs/themes.md +++ b/docs/themes.md @@ -23,29 +23,34 @@ Current themes (alphabetically): - **gruvbox** — Retro groove color scheme (light/dark variants) - **kanagawa-paper** — Inspired by traditional Japanese art - **lcars** — Star Trek LCARS interface style +- **leuchtturm** — Modern, clean theme (light/dark variants) - **nord** — Arctic, north-bluish color palette - **old-book** — Sepia-toned vintage book aesthetic (light/dark variants) - **orbital** — Space-themed dark palette - **plan9** — Minimalist Plan 9 from Bell Labs inspired - **solarized** — Ethan Schoonover's Solarized (light/dark variants) +- **tufte** — Edward Tufte-inspired minimalist theme (light/dark variants) - **weyland-yutani** — Alien franchise corporate aesthetic - **zenburn** — Low-contrast, easy-on-the-eyes theme Configuration ------------- -Themes are configured via `$HOME/.config/kte/kge.ini`: +Themes are configured via `$HOME/.config/kte/kge.toml`: -```ini -theme = nord -background = dark +```toml +[appearance] +theme = "nord" +background = "dark" ``` - `theme` — The theme name (e.g., "nord", "gruvbox", "solarized") - `background` — Either "dark" or "light" (for themes supporting both variants) +Legacy `kge.ini` format is also supported (see CONFIG.md). + Themes can also be switched at runtime using the `:theme ` command. diff --git a/ext/tomlplusplus/toml.hpp b/ext/tomlplusplus/toml.hpp new file mode 100644 index 0000000..0599bf5 --- /dev/null +++ b/ext/tomlplusplus/toml.hpp @@ -0,0 +1,17748 @@ +//---------------------------------------------------------------------------------------------------------------------- +// +// toml++ v3.4.0 +// https://github.com/marzer/tomlplusplus +// SPDX-License-Identifier: MIT +// +//---------------------------------------------------------------------------------------------------------------------- +// +// - THIS FILE WAS ASSEMBLED FROM MULTIPLE HEADER FILES BY A SCRIPT - PLEASE DON'T EDIT IT DIRECTLY - +// +// If you wish to submit a contribution to toml++, hooray and thanks! Before you crack on, please be aware that this +// file was assembled from a number of smaller files by a python script, and code contributions should not be made +// against it directly. You should instead make your changes in the relevant source file(s). The file names of the files +// that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file. +// +//---------------------------------------------------------------------------------------------------------------------- +// +// TOML Language Specifications: +// latest: https://github.com/toml-lang/toml/blob/master/README.md +// v1.0.0: https://toml.io/en/v1.0.0 +// v0.5.0: https://toml.io/en/v0.5.0 +// changelog: https://github.com/toml-lang/toml/blob/master/CHANGELOG.md +// +//---------------------------------------------------------------------------------------------------------------------- +// +// MIT License +// +// Copyright (c) Mark Gillard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +// Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//---------------------------------------------------------------------------------------------------------------------- +#ifndef TOMLPLUSPLUS_HPP +#define TOMLPLUSPLUS_HPP + +#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3 +#define TOMLPLUSPLUS_H // guard name used in the legacy toml.h + +//******** impl/preprocessor.hpp ************************************************************************************* + +#ifndef __cplusplus +#error toml++ is a C++ library. +#endif + +#ifndef TOML_CPP +#ifdef _MSVC_LANG +#if _MSVC_LANG > __cplusplus +#define TOML_CPP _MSVC_LANG +#endif +#endif +#ifndef TOML_CPP +#define TOML_CPP __cplusplus +#endif +#if TOML_CPP >= 202900L +#undef TOML_CPP +#define TOML_CPP 29 +#elif TOML_CPP >= 202600L +#undef TOML_CPP +#define TOML_CPP 26 +#elif TOML_CPP >= 202302L +#undef TOML_CPP +#define TOML_CPP 23 +#elif TOML_CPP >= 202002L +#undef TOML_CPP +#define TOML_CPP 20 +#elif TOML_CPP >= 201703L +#undef TOML_CPP +#define TOML_CPP 17 +#elif TOML_CPP >= 201402L +#undef TOML_CPP +#define TOML_CPP 14 +#elif TOML_CPP >= 201103L +#undef TOML_CPP +#define TOML_CPP 11 +#else +#undef TOML_CPP +#define TOML_CPP 0 +#endif +#endif + +#if !TOML_CPP +#error toml++ requires C++17 or higher. For a pre-C++11 TOML library see https://github.com/ToruNiina/Boost.toml +#elif TOML_CPP < 17 +#error toml++ requires C++17 or higher. For a C++11 TOML library see https://github.com/ToruNiina/toml11 +#endif + +#ifndef TOML_MAKE_VERSION +#define TOML_MAKE_VERSION(major, minor, patch) (((major)*10000) + ((minor)*100) + ((patch))) +#endif + +#ifndef TOML_INTELLISENSE +#ifdef __INTELLISENSE__ +#define TOML_INTELLISENSE 1 +#else +#define TOML_INTELLISENSE 0 +#endif +#endif + +#ifndef TOML_DOXYGEN +#if defined(DOXYGEN) || defined(__DOXYGEN) || defined(__DOXYGEN__) || defined(__doxygen__) || defined(__POXY__) \ + || defined(__poxy__) +#define TOML_DOXYGEN 1 +#else +#define TOML_DOXYGEN 0 +#endif +#endif + +#ifndef TOML_CLANG +#ifdef __clang__ +#define TOML_CLANG __clang_major__ +#else +#define TOML_CLANG 0 +#endif + +// special handling for apple clang; see: +// - https://github.com/marzer/tomlplusplus/issues/189 +// - https://en.wikipedia.org/wiki/Xcode +// - +// https://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time +#if TOML_CLANG && defined(__apple_build_version__) +#undef TOML_CLANG +#define TOML_CLANG_VERSION TOML_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#if TOML_CLANG_VERSION >= TOML_MAKE_VERSION(15, 0, 0) +#define TOML_CLANG 16 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 3, 0) +#define TOML_CLANG 15 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 0, 0) +#define TOML_CLANG 14 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 1, 6) +#define TOML_CLANG 13 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 0, 0) +#define TOML_CLANG 12 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 5) +#define TOML_CLANG 11 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 0) +#define TOML_CLANG 10 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 3) +#define TOML_CLANG 9 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 0) +#define TOML_CLANG 8 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(10, 0, 1) +#define TOML_CLANG 7 +#else +#define TOML_CLANG 6 // not strictly correct but doesn't matter below this +#endif +#undef TOML_CLANG_VERSION +#endif +#endif + +#ifndef TOML_ICC +#ifdef __INTEL_COMPILER +#define TOML_ICC __INTEL_COMPILER +#ifdef __ICL +#define TOML_ICC_CL TOML_ICC +#else +#define TOML_ICC_CL 0 +#endif +#else +#define TOML_ICC 0 +#define TOML_ICC_CL 0 +#endif +#endif + +#ifndef TOML_MSVC_LIKE +#ifdef _MSC_VER +#define TOML_MSVC_LIKE _MSC_VER +#else +#define TOML_MSVC_LIKE 0 +#endif +#endif + +#ifndef TOML_MSVC +#if TOML_MSVC_LIKE && !TOML_CLANG && !TOML_ICC +#define TOML_MSVC TOML_MSVC_LIKE +#else +#define TOML_MSVC 0 +#endif +#endif + +#ifndef TOML_GCC_LIKE +#ifdef __GNUC__ +#define TOML_GCC_LIKE __GNUC__ +#else +#define TOML_GCC_LIKE 0 +#endif +#endif + +#ifndef TOML_GCC +#if TOML_GCC_LIKE && !TOML_CLANG && !TOML_ICC +#define TOML_GCC TOML_GCC_LIKE +#else +#define TOML_GCC 0 +#endif +#endif + +#ifndef TOML_CUDA +#if defined(__CUDACC__) || defined(__CUDA_ARCH__) || defined(__CUDA_LIBDEVICE__) +#define TOML_CUDA 1 +#else +#define TOML_CUDA 0 +#endif +#endif + +#ifndef TOML_ARCH_ITANIUM +#if defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) +#define TOML_ARCH_ITANIUM 1 +#define TOML_ARCH_BITNESS 64 +#else +#define TOML_ARCH_ITANIUM 0 +#endif +#endif + +#ifndef TOML_ARCH_AMD64 +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) +#define TOML_ARCH_AMD64 1 +#define TOML_ARCH_BITNESS 64 +#else +#define TOML_ARCH_AMD64 0 +#endif +#endif + +#ifndef TOML_ARCH_X86 +#if defined(__i386__) || defined(_M_IX86) +#define TOML_ARCH_X86 1 +#define TOML_ARCH_BITNESS 32 +#else +#define TOML_ARCH_X86 0 +#endif +#endif + +#ifndef TOML_ARCH_ARM +#if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64) || defined(__ARM_64BIT_STATE) \ + || defined(_M_ARM64EC) +#define TOML_ARCH_ARM32 0 +#define TOML_ARCH_ARM64 1 +#define TOML_ARCH_ARM 1 +#define TOML_ARCH_BITNESS 64 +#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE) +#define TOML_ARCH_ARM32 1 +#define TOML_ARCH_ARM64 0 +#define TOML_ARCH_ARM 1 +#define TOML_ARCH_BITNESS 32 +#else +#define TOML_ARCH_ARM32 0 +#define TOML_ARCH_ARM64 0 +#define TOML_ARCH_ARM 0 +#endif +#endif + +#ifndef TOML_ARCH_BITNESS +#define TOML_ARCH_BITNESS 0 +#endif + +#ifndef TOML_ARCH_X64 +#if TOML_ARCH_BITNESS == 64 +#define TOML_ARCH_X64 1 +#else +#define TOML_ARCH_X64 0 +#endif +#endif + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__) +#define TOML_WINDOWS 1 +#else +#define TOML_WINDOWS 0 +#endif + +#ifdef __unix__ +#define TOML_UNIX 1 +#else +#define TOML_UNIX 0 +#endif + +#ifdef __linux__ +#define TOML_LINUX 1 +#else +#define TOML_LINUX 0 +#endif + +// TOML_HAS_INCLUDE +#ifndef TOML_HAS_INCLUDE +#ifdef __has_include +#define TOML_HAS_INCLUDE(header) __has_include(header) +#else +#define TOML_HAS_INCLUDE(header) 0 +#endif +#endif + +// TOML_HAS_BUILTIN +#ifndef TOML_HAS_BUILTIN +#ifdef __has_builtin +#define TOML_HAS_BUILTIN(name) __has_builtin(name) +#else +#define TOML_HAS_BUILTIN(name) 0 +#endif +#endif + +// TOML_HAS_FEATURE +#ifndef TOML_HAS_FEATURE +#ifdef __has_feature +#define TOML_HAS_FEATURE(name) __has_feature(name) +#else +#define TOML_HAS_FEATURE(name) 0 +#endif +#endif + +// TOML_HAS_ATTR +#ifndef TOML_HAS_ATTR +#ifdef __has_attribute +#define TOML_HAS_ATTR(attr) __has_attribute(attr) +#else +#define TOML_HAS_ATTR(attr) 0 +#endif +#endif + +// TOML_HAS_CPP_ATTR +#ifndef TOML_HAS_CPP_ATTR +#ifdef __has_cpp_attribute +#define TOML_HAS_CPP_ATTR(attr) __has_cpp_attribute(attr) +#else +#define TOML_HAS_CPP_ATTR(attr) 0 +#endif +#endif + +// TOML_ATTR (gnu attributes) +#ifndef TOML_ATTR +#if TOML_CLANG || TOML_GCC_LIKE +#define TOML_ATTR(...) __attribute__((__VA_ARGS__)) +#else +#define TOML_ATTR(...) +#endif +#endif + +// TOML_DECLSPEC (msvc attributes) +#ifndef TOML_DECLSPEC +#if TOML_MSVC_LIKE +#define TOML_DECLSPEC(...) __declspec(__VA_ARGS__) +#else +#define TOML_DECLSPEC(...) +#endif +#endif + +// TOML_COMPILER_HAS_EXCEPTIONS +#ifndef TOML_COMPILER_HAS_EXCEPTIONS +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions) +#define TOML_COMPILER_HAS_EXCEPTIONS 1 +#else +#define TOML_COMPILER_HAS_EXCEPTIONS 0 +#endif +#endif + +// TOML_COMPILER_HAS_RTTI +#ifndef TOML_COMPILER_HAS_RTTI +#if defined(_CPPRTTI) || defined(__GXX_RTTI) || TOML_HAS_FEATURE(cxx_rtti) +#define TOML_COMPILER_HAS_RTTI 1 +#else +#define TOML_COMPILER_HAS_RTTI 0 +#endif +#endif + +// TOML_CONCAT +#define TOML_CONCAT_1(x, y) x##y +#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y) + +// TOML_MAKE_STRING +#define TOML_MAKE_STRING_1(s) #s +#define TOML_MAKE_STRING(s) TOML_MAKE_STRING_1(s) + +// TOML_PRAGMA_XXXX (compiler-specific pragmas) +#if TOML_CLANG +#define TOML_PRAGMA_CLANG(decl) _Pragma(TOML_MAKE_STRING(clang decl)) +#else +#define TOML_PRAGMA_CLANG(decl) +#endif +#if TOML_CLANG >= 8 +#define TOML_PRAGMA_CLANG_GE_8(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_8(decl) +#endif +#if TOML_CLANG >= 9 +#define TOML_PRAGMA_CLANG_GE_9(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_9(decl) +#endif +#if TOML_CLANG >= 10 +#define TOML_PRAGMA_CLANG_GE_10(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_10(decl) +#endif +#if TOML_CLANG >= 11 +#define TOML_PRAGMA_CLANG_GE_11(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_11(decl) +#endif +#if TOML_GCC +#define TOML_PRAGMA_GCC(decl) _Pragma(TOML_MAKE_STRING(GCC decl)) +#else +#define TOML_PRAGMA_GCC(decl) +#endif +#if TOML_MSVC +#define TOML_PRAGMA_MSVC(...) __pragma(__VA_ARGS__) +#else +#define TOML_PRAGMA_MSVC(...) +#endif +#if TOML_ICC +#define TOML_PRAGMA_ICC(...) __pragma(__VA_ARGS__) +#else +#define TOML_PRAGMA_ICC(...) +#endif + +// TOML_ALWAYS_INLINE +#ifdef _MSC_VER +#define TOML_ALWAYS_INLINE __forceinline +#elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__always_inline__) +#define TOML_ALWAYS_INLINE \ + TOML_ATTR(__always_inline__) \ + inline +#else +#define TOML_ALWAYS_INLINE inline +#endif + +// TOML_NEVER_INLINE +#ifdef _MSC_VER +#define TOML_NEVER_INLINE TOML_DECLSPEC(noinline) +#elif TOML_CUDA // https://gitlab.gnome.org/GNOME/glib/-/issues/2555 +#define TOML_NEVER_INLINE TOML_ATTR(noinline) +#else +#if TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__noinline__) +#define TOML_NEVER_INLINE TOML_ATTR(__noinline__) +#endif +#endif +#ifndef TOML_NEVER_INLINE +#define TOML_NEVER_INLINE +#endif + +// MSVC attributes +#define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable) +#define TOML_EMPTY_BASES TOML_DECLSPEC(empty_bases) + +// TOML_TRIVIAL_ABI +#if TOML_CLANG || TOML_HAS_ATTR(__trivial_abi__) +#define TOML_TRIVIAL_ABI TOML_ATTR(__trivial_abi__) +#else +#define TOML_TRIVIAL_ABI +#endif + +// TOML_NODISCARD +#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201603 +#define TOML_NODISCARD [[nodiscard]] +#elif TOML_CLANG || TOML_GCC || TOML_HAS_ATTR(__warn_unused_result__) +#define TOML_NODISCARD TOML_ATTR(__warn_unused_result__) +#else +#define TOML_NODISCARD +#endif + +// TOML_NODISCARD_CTOR +#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907 +#define TOML_NODISCARD_CTOR [[nodiscard]] +#else +#define TOML_NODISCARD_CTOR +#endif + +// pure + const +#ifndef TOML_PURE +#ifdef NDEBUG +#define TOML_PURE \ + TOML_DECLSPEC(noalias) \ + TOML_ATTR(pure) +#else +#define TOML_PURE +#endif +#endif +#ifndef TOML_CONST +#ifdef NDEBUG +#define TOML_CONST \ + TOML_DECLSPEC(noalias) \ + TOML_ATTR(const) +#else +#define TOML_CONST +#endif +#endif +#ifndef TOML_INLINE_GETTER +#define TOML_INLINE_GETTER \ + TOML_NODISCARD \ + TOML_ALWAYS_INLINE +#endif +#ifndef TOML_PURE_GETTER +#define TOML_PURE_GETTER \ + TOML_NODISCARD \ + TOML_PURE +#endif +#ifndef TOML_PURE_INLINE_GETTER +#define TOML_PURE_INLINE_GETTER \ + TOML_NODISCARD \ + TOML_ALWAYS_INLINE \ + TOML_PURE +#endif +#ifndef TOML_CONST_GETTER +#define TOML_CONST_GETTER \ + TOML_NODISCARD \ + TOML_CONST +#endif +#ifndef TOML_CONST_INLINE_GETTER +#define TOML_CONST_INLINE_GETTER \ + TOML_NODISCARD \ + TOML_ALWAYS_INLINE \ + TOML_CONST +#endif + +// TOML_ASSUME +#ifdef _MSC_VER +#define TOML_ASSUME(expr) __assume(expr) +#elif TOML_ICC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_assume) +#define TOML_ASSUME(expr) __builtin_assume(expr) +#elif TOML_HAS_CPP_ATTR(assume) >= 202207 +#define TOML_ASSUME(expr) [[assume(expr)]] +#elif TOML_HAS_ATTR(__assume__) +#define TOML_ASSUME(expr) __attribute__((__assume__(expr))) +#else +#define TOML_ASSUME(expr) static_cast(0) +#endif + +// TOML_UNREACHABLE +#ifdef _MSC_VER +#define TOML_UNREACHABLE __assume(0) +#elif TOML_ICC || TOML_CLANG || TOML_GCC || TOML_HAS_BUILTIN(__builtin_unreachable) +#define TOML_UNREACHABLE __builtin_unreachable() +#else +#define TOML_UNREACHABLE static_cast(0) +#endif + +// TOML_LIKELY +#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(likely) >= 201803 +#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]] +#define TOML_LIKELY_CASE [[likely]] +#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect) +#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1)) +#else +#define TOML_LIKELY(...) (__VA_ARGS__) +#endif +#ifndef TOML_LIKELY_CASE +#define TOML_LIKELY_CASE +#endif + +// TOML_UNLIKELY +#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(unlikely) >= 201803 +#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]] +#define TOML_UNLIKELY_CASE [[unlikely]] +#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect) +#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0)) +#else +#define TOML_UNLIKELY(...) (__VA_ARGS__) +#endif +#ifndef TOML_UNLIKELY_CASE +#define TOML_UNLIKELY_CASE +#endif + +// TOML_FLAGS_ENUM +#if TOML_CLANG || TOML_HAS_ATTR(flag_enum) +#define TOML_FLAGS_ENUM __attribute__((flag_enum)) +#else +#define TOML_FLAGS_ENUM +#endif + +// TOML_OPEN_ENUM + TOML_CLOSED_ENUM +#if TOML_CLANG || TOML_HAS_ATTR(enum_extensibility) +#define TOML_OPEN_ENUM __attribute__((enum_extensibility(open))) +#define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed))) +#else +#define TOML_OPEN_ENUM +#define TOML_CLOSED_ENUM +#endif + +// TOML_OPEN_FLAGS_ENUM + TOML_CLOSED_FLAGS_ENUM +#define TOML_OPEN_FLAGS_ENUM TOML_OPEN_ENUM TOML_FLAGS_ENUM +#define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM + +// TOML_MAKE_FLAGS +#define TOML_MAKE_FLAGS_2(T, op, linkage) \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr T operator op(T lhs, T rhs) noexcept \ + { \ + using under = std::underlying_type_t; \ + return static_cast(static_cast(lhs) op static_cast(rhs)); \ + } \ + \ + linkage constexpr T& operator TOML_CONCAT(op, =)(T & lhs, T rhs) noexcept \ + { \ + return lhs = (lhs op rhs); \ + } \ + \ + static_assert(true) +#define TOML_MAKE_FLAGS_1(T, linkage) \ + static_assert(std::is_enum_v); \ + \ + TOML_MAKE_FLAGS_2(T, &, linkage); \ + TOML_MAKE_FLAGS_2(T, |, linkage); \ + TOML_MAKE_FLAGS_2(T, ^, linkage); \ + \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr T operator~(T val) noexcept \ + { \ + using under = std::underlying_type_t; \ + return static_cast(~static_cast(val)); \ + } \ + \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr bool operator!(T val) noexcept \ + { \ + using under = std::underlying_type_t; \ + return !static_cast(val); \ + } \ + \ + static_assert(true) +#define TOML_MAKE_FLAGS(T) TOML_MAKE_FLAGS_1(T, ) + +#define TOML_UNUSED(...) static_cast(__VA_ARGS__) + +#define TOML_DELETE_DEFAULTS(T) \ + T(const T&) = delete; \ + T(T&&) = delete; \ + T& operator=(const T&) = delete; \ + T& operator=(T&&) = delete + +#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator==(RHS rhs, LHS lhs) noexcept \ + { \ + return lhs == rhs; \ + } \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator!=(LHS lhs, RHS rhs) noexcept \ + { \ + return !(lhs == rhs); \ + } \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator!=(RHS rhs, LHS lhs) noexcept \ + { \ + return !(lhs == rhs); \ + } \ + static_assert(true) + +#define TOML_EVAL_BOOL_1(T, F) T +#define TOML_EVAL_BOOL_0(T, F) F + +#if !defined(__POXY__) && !defined(POXY_IMPLEMENTATION_DETAIL) +#define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__ +#endif + +// COMPILER-SPECIFIC WARNING MANAGEMENT + +#if TOML_CLANG + +#define TOML_PUSH_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic push) \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wunknown-warning-option") \ + static_assert(true) + +#define TOML_DISABLE_SWITCH_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wswitch") \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wimplicit-int-float-conversion") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wfloat-equal") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wshift-sign-overflow") \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + TOML_PRAGMA_CLANG_GE_8(diagnostic ignored "-Wdefaulted-function-deleted") \ + TOML_PRAGMA_CLANG_GE_9(diagnostic ignored "-Wctad-maybe-unsupported") \ + TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wzero-as-null-pointer-constant") \ + TOML_PRAGMA_CLANG_GE_11(diagnostic ignored "-Wsuggest-destructor-override") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-template-vtables") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wmissing-field-initializers") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wpadded") \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic pop) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic push) \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Weverything") \ + static_assert(true, "") + +#define TOML_ENABLE_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic pop) \ + static_assert(true) + +#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1 + +#elif TOML_MSVC + +#define TOML_PUSH_WARNINGS \ + __pragma(warning(push)) \ + static_assert(true) + +#if TOML_HAS_INCLUDE() +#pragma warning(push, 0) +#include +#pragma warning(pop) +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS \ + __pragma(warning(disable : ALL_CODE_ANALYSIS_WARNINGS)) \ + static_assert(true) +#else +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true) +#endif + +#define TOML_DISABLE_SWITCH_WARNINGS \ + __pragma(warning(disable : 4061)) \ + __pragma(warning(disable : 4062)) \ + __pragma(warning(disable : 4063)) \ + __pragma(warning(disable : 5262)) /* switch-case implicit fallthrough (false-positive) */ \ + __pragma(warning(disable : 26819)) /* cg: unannotated fallthrough */ \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + __pragma(warning(disable : 4127)) /* conditional expr is constant */ \ + __pragma(warning(disable : 4324)) /* structure was padded due to alignment specifier */ \ + __pragma(warning(disable : 4348)) \ + __pragma(warning(disable : 4464)) /* relative include path contains '..' */ \ + __pragma(warning(disable : 4505)) /* unreferenced local function removed */ \ + __pragma(warning(disable : 4514)) /* unreferenced inline function has been removed */ \ + __pragma(warning(disable : 4582)) /* constructor is not implicitly called */ \ + __pragma(warning(disable : 4619)) /* there is no warning number 'XXXX' */ \ + __pragma(warning(disable : 4623)) /* default constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 4625)) /* copy constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 4626)) /* assignment operator was implicitly defined as deleted */ \ + __pragma(warning(disable : 4710)) /* function not inlined */ \ + __pragma(warning(disable : 4711)) /* function selected for automatic expansion */ \ + __pragma(warning(disable : 4820)) /* N bytes padding added */ \ + __pragma(warning(disable : 4946)) /* reinterpret_cast used between related classes */ \ + __pragma(warning(disable : 5026)) /* move constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 5027)) /* move assignment operator was implicitly defined as deleted */ \ + __pragma(warning(disable : 5039)) /* potentially throwing function passed to 'extern "C"' function */ \ + __pragma(warning(disable : 5045)) /* Compiler will insert Spectre mitigation */ \ + __pragma(warning(disable : 5264)) /* const variable is not used (false-positive) */ \ + __pragma(warning(disable : 26451)) \ + __pragma(warning(disable : 26490)) \ + __pragma(warning(disable : 26495)) \ + __pragma(warning(disable : 26812)) \ + __pragma(warning(disable : 26819)) \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + __pragma(warning(disable : 4365)) /* argument signed/unsigned mismatch */ \ + __pragma(warning(disable : 4738)) /* storing 32-bit float result in memory */ \ + __pragma(warning(disable : 5219)) /* implicit conversion from integral to float */ \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + __pragma(warning(push, 0)) \ + __pragma(warning(disable : 4348)) \ + __pragma(warning(disable : 4668)) \ + __pragma(warning(disable : 5105)) \ + __pragma(warning(disable : 5264)) \ + TOML_DISABLE_CODE_ANALYSIS_WARNINGS; \ + TOML_DISABLE_SWITCH_WARNINGS; \ + TOML_DISABLE_SPAM_WARNINGS; \ + TOML_DISABLE_ARITHMETIC_WARNINGS; \ + static_assert(true) + +#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS + +#elif TOML_ICC + +#define TOML_PUSH_WARNINGS \ + __pragma(warning(push)) \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + __pragma(warning(disable : 82)) /* storage class is not first */ \ + __pragma(warning(disable : 111)) /* statement unreachable (false-positive) */ \ + __pragma(warning(disable : 869)) /* unreferenced parameter */ \ + __pragma(warning(disable : 1011)) /* missing return (false-positive) */ \ + __pragma(warning(disable : 2261)) /* assume expr side-effects discarded */ \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + __pragma(warning(push, 0)) \ + TOML_DISABLE_SPAM_WARNINGS + +#define TOML_ENABLE_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#elif TOML_GCC + +#define TOML_PUSH_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic push) \ + static_assert(true) + +#define TOML_DISABLE_SWITCH_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-enum") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-default") \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wfloat-equal") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsign-conversion") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \ + static_assert(true) + +#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=const") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=pure") \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wpadded") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wcast-align") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wcomment") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wtype-limits") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wuseless-cast") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsubobject-linkage") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wmissing-field-initializers") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wnoexcept") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wnull-dereference") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wduplicated-branches") \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic pop) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic push) \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wall") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wextra") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wpedantic") \ + TOML_DISABLE_SWITCH_WARNINGS; \ + TOML_DISABLE_ARITHMETIC_WARNINGS; \ + TOML_DISABLE_SUGGEST_ATTR_WARNINGS; \ + TOML_DISABLE_SPAM_WARNINGS; \ + static_assert(true) + +#define TOML_ENABLE_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic pop) \ + static_assert(true) + +#endif + +#ifndef TOML_PUSH_WARNINGS +#define TOML_PUSH_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SWITCH_WARNINGS +#define TOML_DISABLE_SWITCH_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS +#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SPAM_WARNINGS +#define TOML_DISABLE_SPAM_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS +#define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true) +#endif +#ifndef TOML_POP_WARNINGS +#define TOML_POP_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_WARNINGS +#define TOML_DISABLE_WARNINGS static_assert(true) +#endif +#ifndef TOML_ENABLE_WARNINGS +#define TOML_ENABLE_WARNINGS static_assert(true) +#endif +#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES +#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0 +#endif + +#ifdef TOML_CONFIG_HEADER +#include TOML_CONFIG_HEADER +#endif + +// is the library being built as a shared lib/dll using meson and friends? +#ifndef TOML_SHARED_LIB +#define TOML_SHARED_LIB 0 +#endif + +// header-only mode +#if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0 +#define TOML_HEADER_ONLY TOML_ALL_INLINE +#endif +#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE +#undef TOML_HEADER_ONLY +#define TOML_HEADER_ONLY 1 +#endif +#if TOML_DOXYGEN || TOML_SHARED_LIB +#undef TOML_HEADER_ONLY +#define TOML_HEADER_ONLY 0 +#endif + +// internal implementation switch +#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY +#undef TOML_IMPLEMENTATION +#define TOML_IMPLEMENTATION 1 +#else +#define TOML_IMPLEMENTATION 0 +#endif + +// dll/shared lib function exports (legacy - TOML_API was the old name for this setting) +#if !defined(TOML_EXPORTED_MEMBER_FUNCTION) && !defined(TOML_EXPORTED_STATIC_FUNCTION) \ + && !defined(TOML_EXPORTED_FREE_FUNCTION) && !defined(TOML_EXPORTED_CLASS) && defined(TOML_API) +#define TOML_EXPORTED_MEMBER_FUNCTION TOML_API +#define TOML_EXPORTED_STATIC_FUNCTION TOML_API +#define TOML_EXPORTED_FREE_FUNCTION TOML_API +#endif + +// dll/shared lib exports +#if TOML_SHARED_LIB +#undef TOML_API +#undef TOML_EXPORTED_CLASS +#undef TOML_EXPORTED_MEMBER_FUNCTION +#undef TOML_EXPORTED_STATIC_FUNCTION +#undef TOML_EXPORTED_FREE_FUNCTION +#if TOML_WINDOWS +#if TOML_IMPLEMENTATION +#define TOML_EXPORTED_CLASS __declspec(dllexport) +#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllexport) +#else +#define TOML_EXPORTED_CLASS __declspec(dllimport) +#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllimport) +#endif +#ifndef TOML_CALLCONV +#define TOML_CALLCONV __cdecl +#endif +#elif defined(__GNUC__) && __GNUC__ >= 4 +#define TOML_EXPORTED_CLASS __attribute__((visibility("default"))) +#define TOML_EXPORTED_MEMBER_FUNCTION __attribute__((visibility("default"))) +#define TOML_EXPORTED_STATIC_FUNCTION __attribute__((visibility("default"))) +#define TOML_EXPORTED_FREE_FUNCTION __attribute__((visibility("default"))) +#endif +#endif +#ifndef TOML_EXPORTED_CLASS +#define TOML_EXPORTED_CLASS +#endif +#ifndef TOML_EXPORTED_MEMBER_FUNCTION +#define TOML_EXPORTED_MEMBER_FUNCTION +#endif +#ifndef TOML_EXPORTED_STATIC_FUNCTION +#define TOML_EXPORTED_STATIC_FUNCTION +#endif +#ifndef TOML_EXPORTED_FREE_FUNCTION +#define TOML_EXPORTED_FREE_FUNCTION +#endif + +// experimental language features +#if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES + // pre-3.0 +#define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES +#endif +#if (defined(TOML_ENABLE_UNRELEASED_FEATURES) && TOML_ENABLE_UNRELEASED_FEATURES) || TOML_INTELLISENSE +#undef TOML_ENABLE_UNRELEASED_FEATURES +#define TOML_ENABLE_UNRELEASED_FEATURES 1 +#endif +#ifndef TOML_ENABLE_UNRELEASED_FEATURES +#define TOML_ENABLE_UNRELEASED_FEATURES 0 +#endif + +// parser +#if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER) // was TOML_PARSER pre-3.0 +#define TOML_ENABLE_PARSER TOML_PARSER +#endif +#if !defined(TOML_ENABLE_PARSER) || (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE +#undef TOML_ENABLE_PARSER +#define TOML_ENABLE_PARSER 1 +#endif + +// formatters +#if !defined(TOML_ENABLE_FORMATTERS) || (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) || TOML_INTELLISENSE +#undef TOML_ENABLE_FORMATTERS +#define TOML_ENABLE_FORMATTERS 1 +#endif + +// SIMD +#if !defined(TOML_ENABLE_SIMD) || (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) || TOML_INTELLISENSE +#undef TOML_ENABLE_SIMD +#define TOML_ENABLE_SIMD 1 +#endif + +// windows compat +#if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0 +#define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT +#endif +#if !defined(TOML_ENABLE_WINDOWS_COMPAT) || (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT) \ + || TOML_INTELLISENSE +#undef TOML_ENABLE_WINDOWS_COMPAT +#define TOML_ENABLE_WINDOWS_COMPAT 1 +#endif + +#if !TOML_WINDOWS +#undef TOML_ENABLE_WINDOWS_COMPAT +#define TOML_ENABLE_WINDOWS_COMPAT 0 +#endif + +#ifndef TOML_INCLUDE_WINDOWS_H +#define TOML_INCLUDE_WINDOWS_H 0 +#endif + +// custom optional +#ifdef TOML_OPTIONAL_TYPE +#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1 +#else +#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0 +#endif + +// exceptions (library use) +#if TOML_COMPILER_HAS_EXCEPTIONS +#if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS) +#undef TOML_EXCEPTIONS +#define TOML_EXCEPTIONS 1 +#endif +#else +#if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS +#error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler. +#endif +#undef TOML_EXCEPTIONS +#define TOML_EXCEPTIONS 0 +#endif + +// calling convention for static/free/friend functions +#ifndef TOML_CALLCONV +#define TOML_CALLCONV +#endif + +#ifndef TOML_UNDEF_MACROS +#define TOML_UNDEF_MACROS 1 +#endif + +#ifndef TOML_MAX_NESTED_VALUES +#define TOML_MAX_NESTED_VALUES 256 +// this refers to the depth of nested values, e.g. inline tables and arrays. +// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job... +#endif + +#ifdef TOML_CHAR_8_STRINGS +#if TOML_CHAR_8_STRINGS +#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly. +#endif +#endif + +#ifdef TOML_LARGE_FILES +#if !TOML_LARGE_FILES +#error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0. +#endif +#endif + +#ifndef TOML_LIFETIME_HOOKS +#define TOML_LIFETIME_HOOKS 0 +#endif + +#ifdef NDEBUG +#undef TOML_ASSERT +#define TOML_ASSERT(expr) static_assert(true) +#endif +#ifndef TOML_ASSERT +#ifndef assert +TOML_DISABLE_WARNINGS; +#include +TOML_ENABLE_WARNINGS; +#endif +#define TOML_ASSERT(expr) assert(expr) +#endif +#ifdef NDEBUG +#define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr) +#else +#define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr) +#endif + +#ifndef TOML_ENABLE_FLOAT16 +#define TOML_ENABLE_FLOAT16 0 +#endif + +#if !defined(TOML_FLOAT_CHARCONV) && (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL)) +// not supported by any version of GCC or Clang as of 26/11/2020 +// not supported by any version of ICC on Linux as of 11/01/2021 +#define TOML_FLOAT_CHARCONV 0 +#endif +#if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__)) +// causes link errors on emscripten +// causes Mac OS SDK version errors on some versions of Apple Clang +#define TOML_INT_CHARCONV 0 +#endif +#ifndef TOML_INT_CHARCONV +#define TOML_INT_CHARCONV 1 +#endif +#ifndef TOML_FLOAT_CHARCONV +#define TOML_FLOAT_CHARCONV 1 +#endif +#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE() +#undef TOML_INT_CHARCONV +#undef TOML_FLOAT_CHARCONV +#define TOML_INT_CHARCONV 0 +#define TOML_FLOAT_CHARCONV 0 +#endif + +#if defined(__cpp_concepts) && __cpp_concepts >= 201907 +#define TOML_REQUIRES(...) requires(__VA_ARGS__) +#else +#define TOML_REQUIRES(...) +#endif +#define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0 +#define TOML_CONSTRAINED_TEMPLATE(condition, ...) \ + template <__VA_ARGS__ TOML_ENABLE_IF(condition)> \ + TOML_REQUIRES(condition) +#define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__) + +#if defined(__SIZEOF_FLOAT128__) && defined(__FLT128_MANT_DIG__) && defined(__LDBL_MANT_DIG__) \ + && __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__ +#define TOML_FLOAT128 __float128 +#endif + +#ifdef __SIZEOF_INT128__ +#define TOML_INT128 __int128_t +#define TOML_UINT128 __uint128_t +#endif + +// clang-format off + +//******** impl/version.hpp ****************************************************************************************** + +#define TOML_LIB_MAJOR 3 +#define TOML_LIB_MINOR 4 +#define TOML_LIB_PATCH 0 + +#define TOML_LANG_MAJOR 1 +#define TOML_LANG_MINOR 0 +#define TOML_LANG_PATCH 0 + +//******** impl/preprocessor.hpp ************************************************************************************* + +#define TOML_LIB_SINGLE_HEADER 1 + +#if TOML_ENABLE_UNRELEASED_FEATURES + #define TOML_LANG_EFFECTIVE_VERSION \ + TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1) +#else + #define TOML_LANG_EFFECTIVE_VERSION \ + TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH) +#endif + +#define TOML_LANG_HIGHER_THAN(major, minor, patch) \ + (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch)) + +#define TOML_LANG_AT_LEAST(major, minor, patch) \ + (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch)) + +#define TOML_LANG_UNRELEASED \ + TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH) + +#ifndef TOML_ABI_NAMESPACES + #if TOML_DOXYGEN + #define TOML_ABI_NAMESPACES 0 + #else + #define TOML_ABI_NAMESPACES 1 + #endif +#endif +#if TOML_ABI_NAMESPACES + #define TOML_NAMESPACE_START namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR) + #define TOML_NAMESPACE_END } static_assert(true) + #define TOML_NAMESPACE ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR) + #define TOML_ABI_NAMESPACE_START(name) inline namespace name { static_assert(true) + #define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F)) + #define TOML_ABI_NAMESPACE_END } static_assert(true) +#else + #define TOML_NAMESPACE_START namespace toml + #define TOML_NAMESPACE_END static_assert(true) + #define TOML_NAMESPACE toml + #define TOML_ABI_NAMESPACE_START(...) static_assert(true) + #define TOML_ABI_NAMESPACE_BOOL(...) static_assert(true) + #define TOML_ABI_NAMESPACE_END static_assert(true) +#endif +#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl +#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END +#if TOML_HEADER_ONLY + #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START + #define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END + #define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl + #define TOML_EXTERNAL_LINKAGE inline + #define TOML_INTERNAL_LINKAGE inline +#else + #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); \ + using namespace toml; \ + namespace + #define TOML_ANON_NAMESPACE_END static_assert(true) + #define TOML_ANON_NAMESPACE + #define TOML_EXTERNAL_LINKAGE + #define TOML_INTERNAL_LINKAGE static +#endif + +// clang-format on + +// clang-format off + +#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES + + #define TOML_SA_NEWLINE " " + #define TOML_SA_LIST_SEP ", " + #define TOML_SA_LIST_BEG " (" + #define TOML_SA_LIST_END ")" + #define TOML_SA_LIST_NEW " " + #define TOML_SA_LIST_NXT ", " + +#else + + #define TOML_SA_NEWLINE "\n| " + #define TOML_SA_LIST_SEP TOML_SA_NEWLINE " - " + #define TOML_SA_LIST_BEG TOML_SA_LIST_SEP + #define TOML_SA_LIST_END + #define TOML_SA_LIST_NEW TOML_SA_NEWLINE TOML_SA_NEWLINE + #define TOML_SA_LIST_NXT TOML_SA_LIST_NEW + +#endif + +#define TOML_SA_NATIVE_VALUE_TYPE_LIST \ + TOML_SA_LIST_BEG "std::string" \ + TOML_SA_LIST_SEP "int64_t" \ + TOML_SA_LIST_SEP "double" \ + TOML_SA_LIST_SEP "bool" \ + TOML_SA_LIST_SEP "toml::date" \ + TOML_SA_LIST_SEP "toml::time" \ + TOML_SA_LIST_SEP "toml::date_time" \ + TOML_SA_LIST_END + +#define TOML_SA_NODE_TYPE_LIST \ + TOML_SA_LIST_BEG "toml::table" \ + TOML_SA_LIST_SEP "toml::array" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_END + +#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST \ + TOML_SA_LIST_NEW "A native TOML value type" \ + TOML_SA_NATIVE_VALUE_TYPE_LIST \ + \ + TOML_SA_LIST_NXT "A TOML node type" \ + TOML_SA_NODE_TYPE_LIST + +// clang-format on + +TOML_PUSH_WARNINGS; +TOML_DISABLE_SPAM_WARNINGS; +TOML_DISABLE_SWITCH_WARNINGS; +TOML_DISABLE_SUGGEST_ATTR_WARNINGS; + +// misc warning false-positives +#if TOML_MSVC +#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch +#if TOML_SHARED_LIB +#pragma warning(disable : 4251) // dll exports for std lib types +#endif +#elif TOML_CLANG +TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene") +#if TOML_CLANG >= 12 +TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions") +#endif +#if TOML_CLANG == 13 +TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier") +#endif +#endif + +//******** impl/std_new.hpp ****************************************************************************************** + +TOML_DISABLE_WARNINGS; +#include +TOML_ENABLE_WARNINGS; + +#if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914 +#define TOML_LAUNDER(x) __builtin_launder(x) +#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 +#define TOML_LAUNDER(x) std::launder(x) +#else +#define TOML_LAUNDER(x) x +#endif + +//******** impl/std_string.hpp *************************************************************************************** + +TOML_DISABLE_WARNINGS; +#include +#include +TOML_ENABLE_WARNINGS; + +#if TOML_DOXYGEN \ + || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t) \ + && __cpp_lib_char8_t >= 201907) +#define TOML_HAS_CHAR8 1 +#else +#define TOML_HAS_CHAR8 0 +#endif + +namespace toml // non-abi namespace; this is not an error +{ + using namespace std::string_literals; + using namespace std::string_view_literals; +} + +#if TOML_ENABLE_WINDOWS_COMPAT + +TOML_IMPL_NAMESPACE_START +{ + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::string narrow(std::wstring_view); + + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::wstring widen(std::string_view); + +#if TOML_HAS_CHAR8 + + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::wstring widen(std::u8string_view); + +#endif +} +TOML_IMPL_NAMESPACE_END; + +#endif // TOML_ENABLE_WINDOWS_COMPAT + +//******** impl/std_optional.hpp ************************************************************************************* + +TOML_DISABLE_WARNINGS; +#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE +#include +#endif +TOML_ENABLE_WARNINGS; + +TOML_NAMESPACE_START +{ +#if TOML_HAS_CUSTOM_OPTIONAL_TYPE + + template + using optional = TOML_OPTIONAL_TYPE; + +#else + + template + using optional = std::optional; + +#endif +} +TOML_NAMESPACE_END; + +//******** impl/forward_declarations.hpp ***************************************************************************** + +TOML_DISABLE_WARNINGS; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +TOML_ENABLE_WARNINGS; +TOML_PUSH_WARNINGS; +#ifdef _MSC_VER +#ifndef __clang__ +#pragma inline_recursion(on) +#endif +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef TOML_DISABLE_ENVIRONMENT_CHECKS +#define TOML_ENV_MESSAGE \ + "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to " \ + "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the " \ + "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining " \ + "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at " \ + "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. " \ + "Thanks!" + +static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE); +#ifdef FLT_RADIX +static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE); +#endif +static_assert('A' == 65, TOML_ENV_MESSAGE); +static_assert(sizeof(double) == 8, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::is_iec559, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::digits == 53, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::digits10 == 15, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::radix == 2, TOML_ENV_MESSAGE); + +#undef TOML_ENV_MESSAGE +#endif // !TOML_DISABLE_ENVIRONMENT_CHECKS + +// undocumented forward declarations are hidden from doxygen because they fuck it up =/ + +namespace toml // non-abi namespace; this is not an error +{ + using ::std::size_t; + using ::std::intptr_t; + using ::std::uintptr_t; + using ::std::ptrdiff_t; + using ::std::nullptr_t; + using ::std::int8_t; + using ::std::int16_t; + using ::std::int32_t; + using ::std::int64_t; + using ::std::uint8_t; + using ::std::uint16_t; + using ::std::uint32_t; + using ::std::uint64_t; + using ::std::uint_least32_t; + using ::std::uint_least64_t; +} + +TOML_NAMESPACE_START +{ + struct date; + struct time; + struct time_offset; + + TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt); + struct date_time; + TOML_ABI_NAMESPACE_END; + + struct source_position; + struct source_region; + + class node; + template + class node_view; + + class key; + class array; + class table; + template + class value; + + class path; + + class toml_formatter; + class json_formatter; + class yaml_formatter; + + TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex); +#if TOML_EXCEPTIONS + using parse_result = table; +#else + class parse_result; +#endif + TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS +} +TOML_NAMESPACE_END; + +TOML_IMPL_NAMESPACE_START +{ + using node_ptr = std::unique_ptr; + + TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex); + class parser; + TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS + + // clang-format off + + inline constexpr std::string_view control_char_escapes[] = + { + "\\u0000"sv, + "\\u0001"sv, + "\\u0002"sv, + "\\u0003"sv, + "\\u0004"sv, + "\\u0005"sv, + "\\u0006"sv, + "\\u0007"sv, + "\\b"sv, + "\\t"sv, + "\\n"sv, + "\\u000B"sv, + "\\f"sv, + "\\r"sv, + "\\u000E"sv, + "\\u000F"sv, + "\\u0010"sv, + "\\u0011"sv, + "\\u0012"sv, + "\\u0013"sv, + "\\u0014"sv, + "\\u0015"sv, + "\\u0016"sv, + "\\u0017"sv, + "\\u0018"sv, + "\\u0019"sv, + "\\u001A"sv, + "\\u001B"sv, + "\\u001C"sv, + "\\u001D"sv, + "\\u001E"sv, + "\\u001F"sv, + }; + + inline constexpr std::string_view node_type_friendly_names[] = + { + "none"sv, + "table"sv, + "array"sv, + "string"sv, + "integer"sv, + "floating-point"sv, + "boolean"sv, + "date"sv, + "time"sv, + "date-time"sv + }; + + // clang-format on +} +TOML_IMPL_NAMESPACE_END; + +#if TOML_ABI_NAMESPACES +#if TOML_EXCEPTIONS +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_ex::parser +#else +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_noex::parser +#endif +#else +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser +#endif + +namespace toml +{ +} + +TOML_NAMESPACE_START // abi namespace +{ + inline namespace literals + { + } + + enum class TOML_CLOSED_ENUM node_type : uint8_t + { + none, + table, + array, + string, + integer, + floating_point, + boolean, + date, + time, + date_time + }; + + template + inline std::basic_ostream& operator<<(std::basic_ostream& lhs, node_type rhs) + { + const auto str = impl::node_type_friendly_names[static_cast>(rhs)]; + using str_char_t = decltype(str)::value_type; + if constexpr (std::is_same_v) + return lhs << str; + else + { + if constexpr (sizeof(Char) == sizeof(str_char_t)) + return lhs << std::basic_string_view{ reinterpret_cast(str.data()), str.length() }; + else + return lhs << str.data(); + } + } + + enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error + { + none, + format_as_binary = 1, + format_as_octal = 2, + format_as_hexadecimal = 3, + }; + TOML_MAKE_FLAGS(value_flags); + + inline constexpr value_flags preserve_source_value_flags = + POXY_IMPLEMENTATION_DETAIL(value_flags{ static_cast>(-1) }); + + enum class TOML_CLOSED_FLAGS_ENUM format_flags : uint64_t + { + none, + quote_dates_and_times = (1ull << 0), + quote_infinities_and_nans = (1ull << 1), + allow_literal_strings = (1ull << 2), + allow_multi_line_strings = (1ull << 3), + allow_real_tabs_in_strings = (1ull << 4), + allow_unicode_strings = (1ull << 5), + allow_binary_integers = (1ull << 6), + allow_octal_integers = (1ull << 7), + allow_hexadecimal_integers = (1ull << 8), + indent_sub_tables = (1ull << 9), + indent_array_elements = (1ull << 10), + indentation = indent_sub_tables | indent_array_elements, + relaxed_float_precision = (1ull << 11), + terse_key_value_pairs = (1ull << 12), + }; + TOML_MAKE_FLAGS(format_flags); + + template + struct TOML_TRIVIAL_ABI inserter + { + static_assert(std::is_reference_v); + + T value; + }; + template + inserter(T&&) -> inserter; + template + inserter(T&) -> inserter; + + using default_formatter = toml_formatter; +} +TOML_NAMESPACE_END; + +TOML_IMPL_NAMESPACE_START +{ + template + using remove_cvref = std::remove_cv_t>; + + template + using common_signed_type = std::common_type_t...>; + + template + inline constexpr bool is_one_of = (false || ... || std::is_same_v); + + template + inline constexpr bool all_integral = (std::is_integral_v && ...); + + template + inline constexpr bool is_cvref = std::is_reference_v || std::is_const_v || std::is_volatile_v; + + template + inline constexpr bool is_wide_string = + is_one_of, const wchar_t*, wchar_t*, std::wstring_view, std::wstring>; + + template + inline constexpr bool value_retrieval_is_nothrow = !std::is_same_v, std::string> +#if TOML_HAS_CHAR8 + && !std::is_same_v, std::u8string> +#endif + + && !is_wide_string; + + template + struct copy_ref_; + template + using copy_ref = typename copy_ref_::type; + + template + struct copy_ref_ + { + using type = Dest; + }; + + template + struct copy_ref_ + { + using type = std::add_lvalue_reference_t; + }; + + template + struct copy_ref_ + { + using type = std::add_rvalue_reference_t; + }; + + template + struct copy_cv_; + template + using copy_cv = typename copy_cv_::type; + + template + struct copy_cv_ + { + using type = Dest; + }; + + template + struct copy_cv_ + { + using type = std::add_const_t; + }; + + template + struct copy_cv_ + { + using type = std::add_volatile_t; + }; + + template + struct copy_cv_ + { + using type = std::add_cv_t; + }; + + template + using copy_cvref = + copy_ref, std::remove_reference_t>, Dest>, Src>; + + template + inline constexpr bool always_false = false; + + template + inline constexpr bool first_is_same = false; + template + inline constexpr bool first_is_same = true; + + template > + struct underlying_type_ + { + using type = std::underlying_type_t; + }; + template + struct underlying_type_ + { + using type = T; + }; + template + using underlying_type = typename underlying_type_::type; + + // general value traits + // (as they relate to their equivalent native TOML type) + struct default_value_traits + { + using native_type = void; + static constexpr bool is_native = false; + static constexpr bool is_losslessly_convertible_to_native = false; + static constexpr bool can_represent_native = false; + static constexpr bool can_partially_represent_native = false; + static constexpr auto type = node_type::none; + }; + + template + struct value_traits; + + template > + struct value_traits_base_selector + { + static_assert(!is_cvref); + + using type = default_value_traits; + }; + template + struct value_traits_base_selector + { + static_assert(!is_cvref); + + using type = value_traits>; + }; + + template + struct value_traits : value_traits_base_selector::type + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + + // integer value_traits specializations - standard types + template + struct integer_limits + { + static constexpr T min = T{ (std::numeric_limits>::min)() }; + static constexpr T max = T{ (std::numeric_limits>::max)() }; + }; + template + struct integer_traits_base : integer_limits + { + using native_type = int64_t; + static constexpr bool is_native = std::is_same_v, native_type>; + static constexpr bool is_signed = static_cast>(-1) < underlying_type{}; + static constexpr auto type = node_type::integer; + static constexpr bool can_partially_represent_native = true; + }; + template + struct unsigned_integer_traits : integer_traits_base + { + static constexpr bool is_losslessly_convertible_to_native = + integer_limits>::max <= 9223372036854775807ULL; + static constexpr bool can_represent_native = false; + }; + template + struct signed_integer_traits : integer_traits_base + { + using native_type = int64_t; + static constexpr bool is_losslessly_convertible_to_native = + integer_limits>::min >= (-9223372036854775807LL - 1LL) + && integer_limits>::max <= 9223372036854775807LL; + static constexpr bool can_represent_native = + integer_limits>::min <= (-9223372036854775807LL - 1LL) + && integer_limits>::max >= 9223372036854775807LL; + }; + template ::is_signed> + struct integer_traits : signed_integer_traits + {}; + template + struct integer_traits : unsigned_integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + static_assert(value_traits::is_native); + static_assert(value_traits::is_signed); + static_assert(value_traits::is_losslessly_convertible_to_native); + static_assert(value_traits::can_represent_native); + static_assert(value_traits::can_partially_represent_native); + + // integer value_traits specializations - non-standard types +#ifdef TOML_INT128 + template <> + struct integer_limits + { + static constexpr TOML_INT128 max = + static_cast((TOML_UINT128{ 1u } << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1); + static constexpr TOML_INT128 min = -max - TOML_INT128{ 1 }; + }; + template <> + struct integer_limits + { + static constexpr TOML_UINT128 min = TOML_UINT128{}; + static constexpr TOML_UINT128 max = (2u * static_cast(integer_limits::max)) + 1u; + }; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; +#endif +#ifdef TOML_SMALL_INT_TYPE + template <> + struct value_traits : signed_integer_traits + {}; +#endif + + // floating-point traits base + template + struct float_traits_base + { + static constexpr auto type = node_type::floating_point; + using native_type = double; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_signed = true; + + static constexpr int bits = static_cast(sizeof(T) * CHAR_BIT); + static constexpr int digits = MantissaDigits; + static constexpr int digits10 = DecimalDigits; + + static constexpr bool is_losslessly_convertible_to_native = bits <= 64 // + && digits <= 53 // DBL_MANT_DIG + && digits10 <= 15; // DBL_DIG + + static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG + && digits10 >= 15; // DBL_DIG + + static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0; + }; + template + struct float_traits : float_traits_base::digits, std::numeric_limits::digits10> + {}; +#if TOML_ENABLE_FLOAT16 + template <> + struct float_traits<_Float16> : float_traits_base<_Float16, __FLT16_MANT_DIG__, __FLT16_DIG__> + {}; +#endif +#ifdef TOML_FLOAT128 + template <> + struct float_traits : float_traits_base + {}; +#endif + + // floating-point traits + template <> + struct value_traits : float_traits + {}; + template <> + struct value_traits : float_traits + {}; + template <> + struct value_traits : float_traits + {}; +#if TOML_ENABLE_FLOAT16 + template <> + struct value_traits<_Float16> : float_traits<_Float16> + {}; +#endif +#ifdef TOML_FLOAT128 + template <> + struct value_traits : float_traits + {}; +#endif +#ifdef TOML_SMALL_FLOAT_TYPE + template <> + struct value_traits : float_traits + {}; +#endif + static_assert(value_traits::is_native); + static_assert(value_traits::is_losslessly_convertible_to_native); + static_assert(value_traits::can_represent_native); + static_assert(value_traits::can_partially_represent_native); + + // string value_traits specializations - char-based strings + template + struct string_traits + { + using native_type = std::string; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_losslessly_convertible_to_native = true; + static constexpr bool can_represent_native = + !std::is_array_v && (!std::is_pointer_v || std::is_const_v>); + static constexpr bool can_partially_represent_native = can_represent_native; + static constexpr auto type = node_type::string; + }; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + + // string value_traits specializations - char8_t-based strings +#if TOML_HAS_CHAR8 + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; +#endif + + // string value_traits specializations - wchar_t-based strings on Windows +#if TOML_ENABLE_WINDOWS_COMPAT + template + struct wstring_traits + { + using native_type = std::string; + static constexpr bool is_native = false; + static constexpr bool is_losslessly_convertible_to_native = true; // narrow + static constexpr bool can_represent_native = std::is_same_v; // widen + static constexpr bool can_partially_represent_native = can_represent_native; + static constexpr auto type = node_type::string; + }; + template <> + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template + struct value_traits : wstring_traits + {}; +#endif + + // other 'native' value_traits specializations + template + struct native_value_traits + { + using native_type = T; + static constexpr bool is_native = true; + static constexpr bool is_losslessly_convertible_to_native = true; + static constexpr bool can_represent_native = true; + static constexpr bool can_partially_represent_native = true; + static constexpr auto type = NodeType; + }; + template <> + struct value_traits : native_value_traits + {}; + template <> + struct value_traits : native_value_traits + {}; + template <> + struct value_traits