Customizing Help Output

The option system builds help, version, and error output as neutral TextDocument trees. This page explains how Application renders these documents, how to render them manually, and how to customize generated wording and terminal style.

Detailed Option Help

The built-in --help=<name> form displays one visible option in detail. The name may be a case-insensitive long or internal alias, or a case-sensitive short alias. For a root request, global options are searched before modules in registration order. For a module request, that module is searched first, then global options, then the remaining modules. When the same exact alias exists in another scope, the document adds a See Also command for that scope.

Detailed documents generate one usage line for each dashed alias and use attached value syntax. They show the option title, description, an optional example configured with setHelpExample(), and any related scope commands. Use OptionManager::detailedHelpDocument() or displayDetailedHelp() when routing display requests manually. An unresolved direct request throws OptionError with an UnknownName context and fuzzy suggestions.

Plain Output Is the Default

Without terminal support, Application renders generated help as plain text. This is predictable for redirected output, build logs, tests, and simple command-line tools.

option/HelpCustomization/main.cpp

/// `Application::enableTerminal()` switches generated help from plain text to styled terminal output.
///
/// This application checks for `--terminal` before parsing and enables terminal rendering early enough for `--help`.
/// It also sets a predefined terminal document style for system output.
class HelpCustomizationApp final : public el::Application {
public:
    using Application::Application;

protected:
    void initialize() override {
        info().setApplicationName("Night Watch Help"_el);
        info().setApplicationVersion(el::Version{0, 8, 0});
        for (const auto &arg : commandLineArguments()) {
            if (arg == "--terminal"_el) {
                enableTerminal();
                setSystemOutputStyle(el::cterm::TerminalDocumentStyle::defaultStyled());
                break;
            }
        }
    }
    void registerCommandLineOptions(const el::OptionsPtr &options) override {
        addSharedOptions(options);
        options->addOption({"--terminal"_el, "terminal"_el})
            .setHelpTitle("Renders help with terminal colors."_el)
            .setHelpVisibility(el::OptionHelpVisibility::Hidden);
    }
};

/// `OptionManager` exposes neutral help documents and compiled display-text layers for manual rendering and wording
/// changes.
///
/// The manager can build a `TextDocument` without owning the application lifecycle.
/// Change compiled display-text layers when generated labels such as `Usage`, `Options`, placeholders, or built-in
/// option descriptions need application-specific wording.
auto manualHelpRendering() -> el::ExitCode {
    auto options = el::Options::create();
    auto info = el::ApplicationInfo{};
    info.setApplicationName("Manual Help"_el);
    info.setApplicationVersion(el::Version{0, 8, 0});
    options->setApplicationInfo(info);
    options->setExecutablePath("manual-help"_el);
    addSharedOptions(options);

    el::application().displayText()->addData(DisplayTextDemo::create());

    auto manager = el::OptionManager{options};
    el::io::printLine(manager.helpDocument({}).toString());
    return el::ExitCode::success();
}
$ option/option_help_customization --help
Shows how option help can be rendered as a document.
Usage:
option_help_customization [options]
Options:
-g, --area <area>       Area for which to view help.
-f, --format <choice>   Output detail level. Choices: short, full.
-h, --help[=<keyword>]  Display this help.
    --version           Display version information.
$ option/option_help_customization --terminal --help


      Shows how option help can be rendered as a document.


   -◆ Usage ◆-──────────────────────────────────────────────────────────────────────────

option_help_customization options


   -◆ Options ◆-────────────────────────────────────────────────────────────────────────

-g, --area area       Area for which to view help.
-f, --format choice   Output detail level. Choices: short, full.
-h, --help[=keyword]  Display this help.
    --version         Display version information.
$ option/option_help_customization manual
Shows how option help can be rendered as a document.
Usage:
manual-help [options]
Settings:
-g, --area <area>       Area for which to view help.
-f, --format <choice>   Output detail level. Choices: short, full.
-h, --help[=<keyword>]  Display this help.
    --version           Display version information.

Enable Terminal Rendering in Application

Call enableTerminal() before command-line parsing when help should use terminal styling. The usual place is at the start of initialize(). If styling should depend on an early command-line switch, inspect commandLineArguments() in initialize() and enable the terminal before parsing begins.

When terminal support is enabled, Application renders help, version, errors, and other system output through its terminal document renderer. Use setSystemOutputStyle() to choose a predefined or custom TerminalDocumentStyle.

Render Help Manually

Use OptionManager directly when help or diagnostics are part of a larger workflow. The manager can build neutral documents without displaying them:

The document can be converted to plain text with toString() or passed to a terminal document renderer. Manual rendering is useful for tests, embedded command interpreters, graphical shells, and tools that collect diagnostics before printing them.

Customize Display Text

DisplayText controls generated words such as labels, headings, placeholders, built-in option descriptions, and diagnostic labels. It does not change parser behavior.

Define the labels you want to replace in an ELCL catalog, compile it with erbsland_core_display_text(), and register its generated data with application().displayText()->addData(...). The application registry supplies wording to existing managers and diagnostic renderers. See Internationalization for catalog generation, layer precedence, and translator integration.

This is the right tool for localization, house style, or embedding option help into an application that already has its own vocabulary. Use option and set help metadata for user-facing descriptions of your own options. Use DisplayText for generated framework wording.

Complete demo sources

option/HelpCustomization/main.cpp

// Copyright (c) 2026 Tobias Erbsland - https://erbsland.dev
// SPDX-License-Identifier: Apache-2.0

#include <DemoTerminal.hpp>
#include <DisplayTextDemo.hpp>
#include <erbsland/Application.hpp>
#include <erbsland/ApplicationInfo.hpp>
#include <erbsland/cterm/TerminalDocumentStyle.hpp>
#include <erbsland/DisplayText.hpp>
#include <erbsland/ExitCode.hpp>
#include <erbsland/Literals.hpp>
#include <erbsland/OptionHelpVisibility.hpp>
#include <erbsland/OptionManager.hpp>
#include <erbsland/Options.hpp>
#include <erbsland/OptionType.hpp>
#include <erbsland/pattern/Text.hpp>
#include <erbsland/StandardStreams.hpp>
#include <erbsland/TextDocument.hpp>
#include <erbsland/Version.hpp>

#include <string_view>

namespace demo {

using namespace el::text::literals;

void addSharedOptions(const el::OptionsPtr &options) {
    options->setHelpTitle("Night Watch Help"_el);
    options->setHelpDescription("Shows how option help can be rendered as a document."_el);
    options->addOption({"-g"_el, "--area"_el, "area"_el})
        .setType(el::OptionType::Text)
        .setValueName("area"_el)
        .setHelpTitle("Area for which to view help."_el);
    options->addOption({"-f"_el, "--format"_el, "format"_el})
        .addChoice("short"_el)
        .addChoice("full"_el)
        .setDefaultValue("short"_el)
        .setHelpTitle("Output detail level."_el);
}

/// `Application::enableTerminal()` switches generated help from plain text to styled terminal output.
///
/// This application checks for `--terminal` before parsing and enables terminal rendering early enough for `--help`.
/// It also sets a predefined terminal document style for system output.
class HelpCustomizationApp final : public el::Application {
public:
    using Application::Application;

protected:
    void initialize() override {
        info().setApplicationName("Night Watch Help"_el);
        info().setApplicationVersion(el::Version{0, 8, 0});
        for (const auto &arg : commandLineArguments()) {
            if (arg == "--terminal"_el) {
                DemoTerminal::enable(*this);
                setSystemOutputStyle(el::cterm::TerminalDocumentStyle::defaultStyled());
                break;
            }
        }
    }
    void registerCommandLineOptions(const el::OptionsPtr &options) override {
        addSharedOptions(options);
        options->addOption({"--terminal"_el, "terminal"_el})
            .setHelpTitle("Renders help with terminal colors."_el)
            .setHelpVisibility(el::OptionHelpVisibility::Hidden);
    }
};

/// `OptionManager` exposes neutral help documents and compiled display-text layers for manual rendering and wording
/// changes.
///
/// The manager can build a `TextDocument` without owning the application lifecycle.
/// Change compiled display-text layers when generated labels such as `Usage`, `Options`, placeholders, or built-in
/// option descriptions need application-specific wording.
auto manualHelpRendering() -> el::ExitCode {
    auto options = el::Options::create();
    auto info = el::ApplicationInfo{};
    info.setApplicationName("Manual Help"_el);
    info.setApplicationVersion(el::Version{0, 8, 0});
    options->setApplicationInfo(info);
    options->setExecutablePath("manual-help"_el);
    addSharedOptions(options);

    el::application().displayText()->addData(DisplayTextDemo::create());

    auto manager = el::OptionManager{options};
    el::io::printLine(manager.helpDocument({}).toString());
    return el::ExitCode::success();
}

}

auto main(const int argc, char *argv[]) -> int {
    if (argc > 1 && std::string_view{argv[1]} == std::string_view{"manual"}) {
        auto app = el::Application{};
        app.setMainFn(demo::manualHelpRendering);
        return app.run();
    }
    auto app = demo::HelpCustomizationApp{argc, argv};
    return app.run();
}