Generated reference › API — ICoreEssentials/UI/Backends/Gtk4/Text
kind: generated#api#icoreessentials-ui-backends-gtk4-text

API — ICoreEssentials/UI/Backends/Gtk4/Text

The public contract of 2 header(s) under ICoreEssentials/UI/Backends/Gtk4/Text — 2 class/struct definition(s), 19 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.

ICoreGtk4SyntaxHighlighter.h#

ICoreEssentials/UI/Backends/Gtk4/Text/ICoreGtk4SyntaxHighlighter.h

The GTK4 text tier's syntax-highlighting engine (the planning row is named in the .cpp, not here): the per-paragraph callback, the block-state machine that lets a construct span paragraphs, and the run formatting a highlighter paints with. The peer of ../../AppKit/Text/ICoreAppKitSyntaxHighlighter.h and ../../WinUI/Text/ICoreWinUISyntaxHighlighter.h, and deliberately the same surface -- the seam one layer up is identical on the three backends, so the halves it joins should be too.

NO GTK IN THIS HEADER -- the document arrives as an opaque void* that the .cpp casts to GtkTextBuffer*. Same rule, and the same reason, as ./ICoreGtk4TextDocument.h beside it: a verify rig includes this without gtk4 on its compile line.

⚠ IT SPEAKS PLAIN NUMBERS AND std::u16string, NOT THE ICore VALUE CLASSES,

ICoreGtk4TextRunFormat#

ICoreGtk4SyntaxHighlighter.h:64 · struct · 1 declaration(s)

One run's worth of formatting: the four properties a GtkTextTag carries for this vocabulary, plus the flag that says whether the fifth was asked for.

struct ICoreGtk4TextRunFormat {
public:
    bool hasForeground = false;
    int foregroundRed = 0;
    int foregroundGreen = 0;
    int foregroundBlue = 0;
    int foregroundAlpha = 255;

    bool bold = false;
    bool italic = false;

    bool underline = false;

    // ⚠ THE SEPARATE FLAG IS THE WinUI RECORD'S SHAPE AND NOT THE APPKIT ONE'S,
    // and the WinUI header says why: `setUnderlineStyle(Wave)` without
    // `setUnderlineColor(...)` is a legal thing for a highlighter to ask for,
    // and a record that could not say so would invent a colour -- which would
    // then come back out of formatAt() and make a format the caller never wrote
    // compare unequal to the one it did. The script highlighter's error
    // squiggle is exactly that call pair, one of them omitted.
    bool hasUnderlineColor = false;
    int underlineRed = 0;
    int underlineGreen = 0;
    int underlineBlue = 0;
    int underlineAlpha = 255;

    // A format that asks for nothing: no colour, no weight, no slant, no
    // squiggle. Painting one is not an error -- it CLEARS the run, which is
    // what "replace, not merge" means when the replacement is empty.
    [[nodiscard]] bool isEmpty() const;
};
};

ICoreGtk4SyntaxHighlighter#

ICoreGtk4SyntaxHighlighter.h:133 · class · pImpl · 18 declaration(s)

⚠⚠ THE DOCUMENT IS NOT MODIFIED BY HIGHLIGHTING, AND ON THIS TOOLKIT THAT IS A MEASUREMENT RATHER THAN A DESIGN.

class ICoreGtk4SyntaxHighlighter {
public:
    ICoreGtk4SyntaxHighlighter();
    virtual ~ICoreGtk4SyntaxHighlighter();

    ICoreGtk4SyntaxHighlighter(const ICoreGtk4SyntaxHighlighter&) = delete;
    ICoreGtk4SyntaxHighlighter& operator=(const ICoreGtk4SyntaxHighlighter&) = delete;

    // `textBuffer` is a `GtkTextBuffer*` -- the model a `GtkTextView` sits on,
    // and the same object ICoreTextDocumentHandle carries on this backend.
    // nullptr detaches.
    void setDocument(void* textBuffer);
    [[nodiscard]] void* document() const;

    // Reapply the highlighting to every paragraph.
    void rehighlight();

    // Reapply it to one paragraph, and to as many after it as the block state
    // requires -- a paragraph whose end state changes forces the next one to be
    // re-read, which is what lets a comment opened on one line reach the lines
    // below it.
    void rehighlightBlock(int blockNumber);

    // Paragraphs in the attached document. An empty document still has one:
    // gtk_text_buffer_get_line_count() never answers 0, which L5.1 measured
    // against the oracle on all three edge cases.
    [[nodiscard]] int blockCount() const;

    // =========================
    // ⚠ THE SUBSCRIPTION -- WHERE THIS BACKEND DIFFERS FROM THE OTHER TWO
    // =========================
    //
    // This engine is SUBSCRIBED, not driven: it connects to the buffer's
    // "changed" signal and re-highlights the paragraphs whose text actually
    // moved, plus the cascade. The WinUI engine's own header explains why it
    // could not -- "TOM has no change notification, so attaching cannot start a
    // pass by itself" -- and defers live highlighting to its editor row. GTK
    // has the notification, and, measured above, applying a tag does NOT emit
    // it, so the pass cannot re-enter itself. That closes the gap without a
    // re-entrancy flag doing the work.
    //
    // ⚠ IT MATTERS BECAUSE THE PUBLIC SEAM HAS NO OTHER DOOR. One layer up,
    // ICoreSyntaxHighlighter publishes `rehighlight()` and nothing narrower --
    // no rehighlightBlock, no attach. An editor that wanted live highlighting
    // through that surface could only call rehighlight() per keystroke, which
    // is a whole-file regex pass per character typed. Qt's seat never does
    // that, so neither does this one.
    //
    // Turn it off for a batch pass or a test with setAutoRehighlight(false);
    // rehighlight() and rehighlightBlock() are unaffected either way.
    void setAutoRehighlight(bool on);
    [[nodiscard]] bool autoRehighlight() const;

    // =========================
    // THE RUN SURFACE
    // =========================
    //
    // ⚠ PUBLIC, NOT PROTECTED, AND THAT IS DELIBERATE -- the same sentence both
    // sibling engines and the component above them carry. These are what a
    // highlighter CALLS while it works, not what it overrides, and the header
    // surface rule bans protected non-virtual helpers precisely because a thing
    // called from a subclass is public API written down as an inheritance
    // detail.

    // Paint a run of the paragraph being highlighted. `start` is relative to
    // that paragraph, not to the document; a run reaching past the paragraph's
    // last character is clipped to it, and the newline that ends the paragraph
    // is never painted.
    //
    // ⚠ A LATER CALL REPLACES AN EARLIER ONE over the same characters. A
    // `GtkTextTag` MERGES by nature -- applying a colour tag over a weight tag
    // leaves the weight, and the toolkit's own priority rule decides which of
    // two conflicting tags wins by the order they entered the TAG TABLE rather
    // than the order they were applied (measured: a tag created later outranks
    // one applied later). So this seat removes its own tags from the range
    // before it applies the new one. Replace is what a live QSyntaxHighlighter
    // was measured to do on the Windows board, and it is what the two sibling
    // seats pin; a merging setFormat would leave the previous pass's weight
    // under a comment.
    void setFormat(int start, int count, const ICoreGtk4TextRunFormat& format);

    // What the run at `position` -- again relative to the current paragraph --
    // is painted with, including whatever this pass has already applied.
    //
    // ⚠ IT ANSWERS THIS ENGINE'S OVERLAY, NOT THE DOCUMENT'S OWN FORMATTING,
    // which is the same scope the AppKit seat's formatAt has and for the same
    // reason: a tag somebody else put on the buffer is not something this
    // record can express. Its one caller in the product is the script
    // highlighter's error squiggle, which reads back the colour the pass just
    // painted and adds a wave to it.
    //
    // ⚠ PASS-SCOPED. Outside a highlight pass this answers an empty format,
    // because the Qt seat does: QSyntaxHighlighter::format() reads the block
    // being highlighted right now and there is no such block once the pass has
    // returned. GTK would happily answer at any time, and answering would let a
    // caller write code that works here and silently returns defaults on Qt.
    [[nodiscard]] ICoreGtk4TextRunFormat formatAt(int position) const;

    // The end state of the paragraph before this one, or -1 for the first
    // paragraph and for one whose predecessor never set a state.
    [[nodiscard]] int previousBlockState() const;

    // The state of the paragraph being highlighted. -1 until something sets it;
    // a state set in a previous pass survives into this one.
    [[nodiscard]] int currentBlockState() const;
    void setCurrentBlockState(int state);

    // Which paragraph is being highlighted, counting from zero. -1 outside a
    // pass.
    [[nodiscard]] int currentBlockNumber() const;

protected:
    // Implemented by the highlighter. `text` is one paragraph WITHOUT the
    // newline that separates it from the next -- which is what QTextBlock::text()
    // hands over, measured by L5.1 against both toolkits.
    virtual void highlightBlock(const std::u16string& text) = 0;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreGtk4TextDocument.h#

ICoreEssentials/UI/Backends/Gtk4/Text/ICoreGtk4TextDocument.h

The GTK4 text tier's shared vocabulary and its in-zone seam. (The planning row is named in the .cpp, not here.)

NO GTK IN THIS HEADER -- the document is passed as an opaque void* that each .cpp casts to GtkTextBuffer*, so a verify test can include this without gtk4 on its compile line. Same rule as ../Widgets/ICoreGtk4TextSeat.h and ../Graphics/ICoreGtk4ItemScene.h.

⚠ THE DOCUMENT IS A GtkTextBuffer, WHICH IS THE MODEL AND NOT A VIEW. It is a plain GObject: gtk_text_buffer_new(NULL) works with no display, no gtk_init() and no GtkTextView -- measured on this machine, not assumed. That is what makes this row provable headlessly, and it is why the model tier lands before L5.3's text view.

Declares no class of its own — see the file.