Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / src/systems/carry_lex.cpp

sdl_runtime_compiler git · main

SDL3 game for running and compiling code at runtime

sdl3 c++ compiler dlopen cmake · first commit 2026-04-19 · last commit 2026-07-03 (3 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-runtime-compiler

C++ 72.3% C 26.2%
git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gz
src/systems/carry_lex.cpp 2.5 KB · 75 lines raw
#include "carry_lex.hpp"

#include <SDL3/SDL.h>
#include <string>

#include "systems/carry_system.hpp"
#include "text/text.hpp"
#include "text/token.hpp"

namespace
Nimbin
{

// Re-lex the entire carried line as ONE source string, then assign each word a
// context colour by mapping highlight spans onto its byte range. Mirrors
// Handler::apply_Highlight, but synchronous and scoped to a single joined line.
void
CarryLex::lex_CarriedLine(CarriedLine& carry)
{
    // 1) Build the joined source + per-token byte spans, in reading order.
    //    NOTE: nodes() is front->back. If the carried line reads right-to-left
    //    on screen (get_SlotPosition lays out from `last` with decreasing
    //    offset), switch this to reverse_nodes() so "int x" lexes as "int x"
    //    and not "x int". Verify against the on-screen order once.
    std::string                   src;
    DynArray<Text::Token::Data*>  toks;

    for (CarriedWordNode* n : carry.nodes()) {
        if (!n->word) continue;
        Text::Token::Data* t = n->word.get();
        if (!src.empty()) src += ' ';
        t->byte_begin = src.size();
        src += t->text;
        t->byte_end   = src.size();
        toks.push_back(t);
    }
    if (toks.empty()) return;

    // 2) Classify the whole line as one context.
    DynArray<Text::HiSpan> spans = Text::CppHighlight::classify(src);

    // 3) Map spans -> tokens by maximum byte overlap.
    for (Text::Token::Data* t : toks) {
        size_t            best  = 0;
        Text::Token::Type type  = Text::Token::Type::Identifier;
        bool              found = false;

        for (const Text::HiSpan& s : spans) {
            size_t lo = (t->byte_begin > s.byte_begin) ? t->byte_begin : s.byte_begin;
            size_t hi = (t->byte_end   < s.byte_end)   ? t->byte_end   : s.byte_end;
            if (lo < hi) {
                size_t ov = hi - lo;
                if (ov > best) { best = ov; type = s.type; found = true; }
            }
        }

        t->set_ColorSource(Text::ColorSource::Lexed);   // carried line is a context
        if (found) t->set_Context(Text::Token::get_Color(type));
        else       t->clear_Context();                  // no span -> single fallback
    }
}


// A word that leaves the carried line is no longer in a context: drop the
// context flag and select its lone (single) colour, the same colour it shows on
// the floor or as a projectile.
void
CarryLex::revert_ToSingle(Text::Token::Data* word)
{
    if (!word) return;
    word->clear_Context();
    word->set_ColorSource(Text::ColorSource::Lint);
}

} // namespace Nimbin