Safe Unicode and Colors

Highlight Every Match

Each matching line is printed once. The stored byte ranges divide it into unmatched and matched slices, and the matched slices use a bright, bold style. An empty regular-expression match has no text to color, so elgrep inserts a narrow marker at its position.

ElGrepApp.cpp — highlighted matching lines
void ElGrepApp::printMatchingLine(const MatchingLine &line) const {
    terminal()->print(ct::fg::BrightBlack, "    "_el, el::String::fromInteger(line.number), ": "_el, ct::fg::Default);

    auto lastEnd = std::size_t{0};
    for (const auto &range : line.ranges) {
        printText(
            line.text.slice(el::ByteRange{el::ByteIndex::fromSizeT(lastEnd), el::ByteIndex::fromSizeT(range.begin())}));
        terminal()->print(ct::fg::BrightYellow, ct::BlockAttributes{ct::BlockAttributes::Bold});
        if (range.isEmpty()) {
            terminal()->print("▏"_el);
        } else {
            printText(line.text.slice(
                el::ByteRange{el::ByteIndex::fromSizeT(range.begin()), el::ByteIndex::fromSizeT(range.end())}));
        }
        terminal()->print(ct::Color::reset(), ct::BlockAttributes::reset());
        lastEnd = range.end();
    }
    printText(line.text.slice(el::StringSide::Back, el::ByteIndex::fromSizeT(lastEnd)));
    terminal()->writeLineBreak();
}

Before writing any source text, printText() applies the display escaping format. Invisible and control characters become readable escape sequences instead of changing the terminal state.

ElGrepApp.cpp — display-safe text
void ElGrepApp::printText(const el::String &text) const {
    terminal()->print(text.toEscaped(el::EscapeFormat::Display));

The terminal representation also preserves valid Unicode characters and combining sequences. Malformed UTF-8 is decoded using deterministic replacement characters.

Interactive and Redirected Output

The program entry point enables terminal support before it calls run().

<project>/elgrep/src/main.cpp
 1// Copyright (c) 2026 Tobias Erbsland - https://erbsland.dev
 2// SPDX-License-Identifier: Apache-2.0
 3
 4#include "ElGrepApp.hpp"
 5
 6#include <erbsland/cterm/Terminal.hpp>
 7
 8
 9auto main(const int argc, char *argv[]) -> int {
10    auto app = elgrep::ElGrepApp{argc, argv};
11    app.enableTerminal();
12    if (!app.terminal()->isInteractive()) {
13        app.terminal()->setOutputMode(el::cterm::Terminal::OutputMode::BlockText);
14    }
15    return app.run();
16}

On an interactive terminal, Core renders the selected colors. For redirected output or a platform without terminal control, the entry point selects the terminal’s plain block-text mode. It omits ANSI control sequences while the search and output code remain unchanged.

Build and Run elgrep →