H073.ConsoleKit 1.0.0

Prefix Reserved
dotnet add package H073.ConsoleKit --version 1.0.0
                    
NuGet\Install-Package H073.ConsoleKit -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="H073.ConsoleKit" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="H073.ConsoleKit" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="H073.ConsoleKit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add H073.ConsoleKit --version 1.0.0
                    
#r "nuget: H073.ConsoleKit, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package H073.ConsoleKit@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=H073.ConsoleKit&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=H073.ConsoleKit&version=1.0.0
                    
Install as a Cake Tool

Note: This project was written entirely without AI-generated code. Only this README was created with the help of AI.

ConsoleKit

A generic, extensible virtual console framework for .NET 8. ConsoleKit provides everything needed to embed an interactive command-line interface into any application -- attribute-based command definitions, hierarchical command routing via a trie structure, argument parsing and binding, tab completion, input history, undo/redo, and output management.

ConsoleKit is state-only -- it delivers structured state (ConsoleState) but performs no rendering. The host application reads the state and draws the console however it wants.

ConsoleKit has zero external dependencies. It targets pure .NET 8 and can be integrated into any host application (games, desktop tools, editors, etc.).

Package ID: H073.ConsoleKit

Table of Contents

Installation

Add a project reference to ConsoleKit.csproj or install the NuGet package:

dotnet add package H073.ConsoleKit

Quick Start

using ConsoleKit.Attributes;
using ConsoleKit.Core;
using ConsoleKit.State;

// 1. Define a command
[Command("greet", Help = "Greet someone by name")]
public class GreetCommand : ICommand
{
    [Argument(0, Name = "name", Help = "The person to greet")]
    public string? Name { get; set; }

    [Option("uppercase", "u", Help = "Print the greeting in uppercase")]
    public bool Uppercase { get; set; }

    public CommandResult Execute(CommandContext context)
    {
        var greeting = $"Hello, {Name ?? "World"}!";
        if (Uppercase) greeting = greeting.ToUpper();
        context.Output.WriteLine(greeting);
        return CommandResult.Ok;
    }
}

// 2. Set up the console provider
var console = new ConsoleProvider();
console.Registry.Register<GreetCommand>();

// 3. Execute a command
console.SetInput("greet Alice --uppercase");
var result = console.Submit();
// Output: "HELLO, ALICE!"

Architecture Overview

ConsoleKit/
├── Attributes/              Declarative command metadata
│   ├── CommandAttribute         [Command] on classes
│   ├── ArgumentAttribute        [Argument] on properties
│   ├── OptionAttribute          [Option] on properties
│   └── Validation/
│       ├── IValidationAttribute Custom validation interface
│       ├── RequiredAttribute    Required value validation
│       └── RangeAttribute       Numeric range validation
├── Commands/                Built-in commands
│   └── HelpCommand              Auto-registered "help" command
├── Completion/              Tab-completion engine
│   ├── CompletionEngine         Generates suggestions
│   ├── CompletionItem           Single suggestion
│   ├── CompletionResult         Suggestion set with replacement info
│   └── ICompletionProvider      Custom completion source
├── Core/                    Command abstractions
│   ├── ICommand                 The single command interface
│   ├── IUndoAction              Reversible action
│   ├── UndoAction               Delegate-based IUndoAction
│   ├── CommandContext            Execution context (output + services)
│   └── CommandResult            Execution result (exit code + error + optional undo)
├── History/                 History management
│   ├── InputHistory             Command input history with navigation
│   └── UndoStack                Undo/redo action stack
├── Output/
│   └── IConsoleOutput           Output abstraction
├── Parsing/                 Input parsing and binding
│   ├── CommandParser            Tokenizer and parser
│   ├── ParsedInput              Parsed command path, args, options
│   └── ArgumentBinder           Maps parsed tokens to command properties
├── Registry/                Command registration and lookup
│   ├── CommandRegistry          Central registry with trie-based routing
│   └── CommandDescriptor        Reflected metadata for a command
└── State/                   Console UI state
    ├── ConsoleState             Observable state snapshot
    └── ConsoleProvider          Main orchestrator

The data flow is:

User Input
    │
    ▼
CommandParser.Parse()        → ParsedInput (path, args, options, token spans)
    │
    ▼
CommandRegistry.FindCommand() → CommandDescriptor (via trie lookup)
    │
    ▼
--help interception?         → If --help is present, output help text and return Ok
    │
    ▼
CommandDescriptor.CreateInstance() → ICommand instance
    │
    ▼
ArgumentBinder.Bind()        → Sets properties, validates, returns BindingResult
    │
    ▼
ICommand.Execute()           → CommandResult (with optional UndoAction)
    │
    ▼
ConsoleProvider.Submit()     → Pushes UndoAction to stack if present, fires CommandExecuted event

Defining Commands

Basic Commands

Decorate a class with [Command] and implement ICommand. The Path string defines the command name and supports hierarchical paths separated by spaces.

[Command("clear", Help = "Clear the console output")]
public class ClearCommand : ICommand
{
    public CommandResult Execute(CommandContext context)
    {
        context.Output.Clear();
        return CommandResult.Ok;
    }
}

Hierarchical (multi-word) command paths create subcommand trees:

[Command("scene load", Help = "Load a scene by name")]
public class SceneLoadCommand : ICommand
{
    [Argument(0, Name = "name", Help = "Scene file name")]
    public string? Name { get; set; }

    public CommandResult Execute(CommandContext context)
    {
        if (Name == null)
            return CommandResult.Fail("Scene name is required");

        context.Output.WriteLine($"Loading scene: {Name}");
        return CommandResult.Ok;
    }
}

[Command("scene list", Help = "List all available scenes")]
public class SceneListCommand : ICommand
{
    public CommandResult Execute(CommandContext context)
    {
        context.Output.WriteLine("main_menu");
        context.Output.WriteLine("level_01");
        context.Output.WriteLine("level_02");
        return CommandResult.Ok;
    }
}

Both scene load forest and scene list work as separate commands sharing the scene prefix.

Positional Arguments

Use [Argument(index)] on public properties to bind positional arguments. The Index parameter is zero-based.

[Command("teleport", Help = "Teleport to coordinates")]
public class TeleportCommand : ICommand
{
    [Argument(0, Name = "x", Help = "X coordinate")]
    public float X { get; set; }

    [Argument(1, Name = "y", Help = "Y coordinate")]
    public float Y { get; set; }

    [Argument(2, Name = "z", Help = "Z coordinate")]
    public float Z { get; set; }

    public CommandResult Execute(CommandContext context)
    {
        context.Output.WriteLine($"Teleported to ({X}, {Y}, {Z})");
        return CommandResult.Ok;
    }
}
// Usage: teleport 10.5 0 -3.2

Supported property types for automatic conversion:

Type Example Input
string hello, "hello world"
int 42, -7
float 3.14
double 2.718281828
bool true, false
byte 255
long 9999999999
enum North (case-insensitive)
Nullable<T> Any of the above, or omitted for null

Named Options

Use [Option(longName, shortName)] on public properties for named options. Options are parsed as --longname value, -s value, --longname=value, or -s=value.

[Command("spawn", Help = "Spawn an entity")]
public class SpawnCommand : ICommand
{
    [Argument(0, Name = "entity", Help = "Entity type to spawn")]
    public string? Entity { get; set; }

    [Option("count", "c", Help = "Number of entities to spawn")]
    public int Count { get; set; } = 1;

    [Option("hostile", "h", Help = "Spawn as hostile")]
    public bool Hostile { get; set; }

    [Option("level", "l", Help = "Entity level")]
    public int Level { get; set; } = 1;

    public CommandResult Execute(CommandContext context)
    {
        var disposition = Hostile ? "hostile" : "friendly";
        context.Output.WriteLine(
            $"Spawning {Count}x {Entity} (level {Level}, {disposition})");
        return CommandResult.Ok;
    }
}
// Usage: spawn goblin --count 5 --hostile -l 3
// Usage: spawn goblin -c=5 -h --level=3

Boolean options act as flags: their mere presence sets the property to true. No value argument is needed.

Validation

Apply validation attributes to argument or option properties. ConsoleKit ships with two built-in validators.

[Required] -- Fails if the value is null or whitespace.

[Command("rename", Help = "Rename an entity")]
public class RenameCommand : ICommand
{
    [Argument(0, Name = "target", Help = "Entity to rename")]
    [Required(ErrorMessage = "You must specify a target entity")]
    public string? Target { get; set; }

    [Argument(1, Name = "newname", Help = "New name")]
    [Required]
    public string? NewName { get; set; }

    public CommandResult Execute(CommandContext context)
    {
        context.Output.WriteLine($"Renamed '{Target}' to '{NewName}'");
        return CommandResult.Ok;
    }
}

[Range(min, max)] -- Fails if a numeric value is outside the given bounds.

[Command("volume", Help = "Set audio volume")]
public class VolumeCommand : ICommand
{
    [Argument(0, Name = "level", Help = "Volume level (0-100)")]
    [Range(0, 100, ErrorMessage = "Volume must be between 0 and 100")]
    public int Level { get; set; }

    public CommandResult Execute(CommandContext context)
    {
        context.Output.WriteLine($"Volume set to {Level}");
        return CommandResult.Ok;
    }
}
// "volume 150" → Error: "Volume must be between 0 and 100"

Undoable Commands

To support undo/redo, a command returns CommandResult.WithUndo(...) instead of CommandResult.Ok. The WithUndo factory wraps an IUndoAction into the result. There is only one command interface (ICommand) -- undo support is determined by the return value, not the type.

[Command("set gravity", Help = "Set the gravity value")]
public class SetGravityCommand : ICommand
{
    [Argument(0, Name = "value", Help = "New gravity value")]
    [Required]
    public float Value { get; set; }

    public CommandResult Execute(CommandContext context)
    {
        var physics = context.GetService<PhysicsEngine>()!;
        float oldGravity = physics.Gravity;
        physics.Gravity = Value;
        context.Output.WriteLine($"Gravity changed from {oldGravity} to {Value}");

        return CommandResult.WithUndo(new UndoAction(
            $"Set gravity to {Value}",
            ctx =>
            {
                physics.Gravity = oldGravity;
                ctx.Output.WriteLine($"Gravity reverted to {oldGravity}");
            },
            ctx =>
            {
                physics.Gravity = Value;
                ctx.Output.WriteLine($"Gravity re-applied: {Value}");
            }
        ));
    }
}

When the user runs set gravity 20, the UndoAction is automatically pushed onto the undo stack by ConsoleProvider.Submit(). Calling console.Undo() restores the previous gravity, and console.Redo() re-applies it.

UndoAction is a delegate-based convenience class. For more complex undo logic, implement IUndoAction directly:

public interface IUndoAction
{
    void Undo(CommandContext context);
    void Redo(CommandContext context);
    string Description { get; }
}

Registering Commands

Commands can be registered individually or discovered from an entire assembly.

var console = new ConsoleProvider();

// Register individual command types
console.Registry.Register<GreetCommand>();
console.Registry.Register<TeleportCommand>();
console.Registry.Register<SpawnCommand>();

// Or discover all [Command]-attributed ICommand types in an assembly
console.Registry.DiscoverCommands(typeof(Program).Assembly);

You can also bring your own CommandRegistry:

var registry = new CommandRegistry();
registry.Register<GreetCommand>();
registry.Register<SpawnCommand>();

var console = new ConsoleProvider(registry);

A built-in help command is auto-registered by CommandRegistry on construction. See Built-in Help System.

Executing Commands

There are two execution paths.

Via ConsoleProvider (typical usage): Set the input text, then call Submit().

console.SetInput("spawn goblin --count 3");
CommandResult result = console.Submit();

if (!result.Success)
    Console.WriteLine($"Error (exit code {result.ExitCode}): {result.Error}");

Submit() automatically:

  1. Adds the input to history
  2. Clears the input line
  3. Executes the command via CommandRegistry.Execute()
  4. Pushes result.UndoAction to the undo stack if present
  5. Updates the ExecutionState (Idle on success, Error on failure)
  6. Fires the CommandExecuted event

Via CommandRegistry directly (lower-level):

var registry = new CommandRegistry();
registry.Register<GreetCommand>();

var output = new MyConsoleOutput(); // your IConsoleOutput impl
var context = new CommandContext(output);

CommandResult result = registry.Execute("greet Alice -u", context);

CommandResult

CommandResult is a readonly struct with four static factories:

CommandResult.Ok                             // ExitCode = 0, Success = true
CommandResult.WithUndo(undoAction)           // ExitCode = 0, carries an IUndoAction
CommandResult.Fail("something broke")        // ExitCode = 1
CommandResult.Fail(127, "not found")         // Custom exit code

Properties:

Property Type Description
ExitCode int 0 = success, non-zero = failure
Success bool true when ExitCode == 0
Error string? Error message, null on success
UndoAction IUndoAction? Undo action, null if command is not undoable

Built-in Help System

ConsoleKit has automatic help support. Every CommandRegistry auto-registers a built-in help command on construction, and every command can be queried with --help.

The help command

help                    Lists all registered commands
help <command>          Shows detailed help for a specific command

Examples:

> help
Available commands:

  bone attach              Attaches a bone
  echo                     Echoes the input
  help                     Shows available commands or help for a specific command

> help echo
echo - Echoes the input

Arguments:
  <text> (required)  Text to echo

Options:
  --uppercase, -u          Convert to uppercase

The --help flag

Any command supports --help automatically. When --help is present in the parsed options, the registry intercepts execution, prints the command's help text, and returns CommandResult.Ok without running the command.

> echo --help
echo - Echoes the input

Arguments:
  <text> (required)  Text to echo

Options:
  --uppercase, -u          Convert to uppercase

This works for every registered command -- no per-command setup needed.

The ConsoleProvider

ConsoleProvider is the central orchestrator. It owns the registry, completion engine, input history, undo stack, and console state. It also implements IConsoleOutput, so command output is captured into the state's output lines.

var console = new ConsoleProvider();

// Access sub-systems
CommandRegistry   registry   = console.Registry;
CompletionEngine  completion = console.Completion;
InputHistory      history    = console.InputHistory;
UndoStack         undoStack  = console.UndoStack;
ConsoleState      state      = console.State;

Input Manipulation

console.SetInput("hello");          // Replace entire input
console.SetCursor(3);               // Move cursor to position 3
console.MoveCursor(-1);             // Move cursor left by 1
console.InsertChar('!');            // Insert character at cursor
console.InsertText(" world");       // Insert string at cursor
console.Backspace();                // Delete character before cursor
console.Delete();                   // Delete character at cursor
console.ClearInput();               // Clear input to ""

All input methods automatically clear any active completion popup.

Visibility

console.Open();                     // state.IsOpen = true
console.Close();                    // state.IsOpen = false
console.Toggle();                   // Flips state.IsOpen

History Navigation

// After several Submit() calls:
console.HistoryUp();                // Load previous command into input
console.HistoryUp();                // Go further back
console.HistoryDown();              // Go forward
console.HistoryDown();              // Return to original input

InputHistory saves the current input before navigating and restores it when the user navigates past the most recent entry. Consecutive duplicate entries are not stored. The default capacity is 100 entries.

Tab Completion

// User types "sp" and presses Tab
console.SetInput("sp");
console.SetCursor(2);
console.RequestCompletion();

// Read completions from state
IReadOnlyList<string>? items = console.State.CompletionItems;
int selected = console.State.CompletionSelectedIndex;

// Navigate the completion list
console.SelectCompletionDelta(1);   // Move selection down
console.SelectCompletionDelta(-1);  // Move selection up

// Apply the selected completion
console.ApplyCompletion();          // Replaces the token in-place

// Or dismiss
console.ClearCompletion();

The completion engine automatically completes:

  • Command names and subcommands based on the trie structure
  • Option names (--long and -s forms) from the matched command's descriptor
  • Argument values if a custom ICompletionProvider is registered for that argument name

Undo and Redo

// After executing commands that return CommandResult.WithUndo(...):
bool undone = console.Undo();       // Undo the last undoable command
bool redone = console.Redo();       // Redo the last undone command

// Inspect the stacks
IUndoAction? nextUndo = console.UndoStack.PeekUndo();
IUndoAction? nextRedo = console.UndoStack.PeekRedo();

if (nextUndo != null)
    Console.WriteLine($"Next undo: {nextUndo.Description}");

The undo stack capacity defaults to 50. Pushing a new action clears the redo stack.

Output and Scrolling

// Write output (these are also called by commands via CommandContext)
console.WriteLine("Normal output");
console.WriteError("Error output");
console.Clear();

// Scroll through output
console.ScrollOutput(-1);           // Scroll up
console.ScrollOutput(3);            // Scroll down 3 lines

// Read output lines from state
foreach (OutputLine line in console.State.OutputLines)
{
    Console.ForegroundColor = line.Type switch
    {
        OutputType.Error   => ConsoleColor.Red,
        OutputType.Warning => ConsoleColor.Yellow,
        OutputType.Info    => ConsoleColor.Cyan,
        _                  => ConsoleColor.White
    };
    Console.WriteLine($"[{line.Timestamp:HH:mm:ss}] {line.Text}");
}

Output is trimmed to 1000 lines by default (ConsoleState.MaxOutputLines).

Events

ConsoleProvider exposes two C# events for reactive integration:

// Fired after Submit() completes (after state update, after undo stack push)
console.CommandExecuted += (CommandResult result) =>
{
    if (!result.Success)
        Logger.Warn($"Command failed: {result.Error}");
};

// Fired whenever a line is written (via WriteLine or WriteError)
console.OutputWritten += (OutputLine line) =>
{
    if (line.Type == OutputType.Error)
        ErrorOverlay.Flash(line.Text);
};
Event Signature When it fires
CommandExecuted Action<CommandResult> After Submit() completes, after state has been updated
OutputWritten Action<OutputLine> After each WriteLine() or WriteError() call

Dependency Injection

Inject an IServiceProvider to make services available to commands via CommandContext.GetService<T>().

var services = new ServiceCollection()
    .AddSingleton<PhysicsEngine>()
    .AddSingleton<AudioManager>()
    .BuildServiceProvider();

var console = new ConsoleProvider();
console.SetServices(services);

// Inside a command:
public CommandResult Execute(CommandContext context)
{
    var audio = context.GetService<AudioManager>();
    audio?.PlaySound("click");
    return CommandResult.Ok;
}

Custom Completion Providers

Register an ICompletionProvider for a specific argument name to provide domain-specific completions.

public class SceneCompletionProvider : ICompletionProvider
{
    private readonly List<string> _scenes = ["main_menu", "level_01", "level_02", "boss_arena"];

    public IEnumerable<CompletionItem> GetCompletions(
        CommandDescriptor? command,
        string argumentName,
        string currentValue)
    {
        return _scenes
            .Where(s => s.StartsWith(currentValue, StringComparison.OrdinalIgnoreCase))
            .Select(s => new CompletionItem(s, s, "Scene file", CompletionKind.Argument));
    }
}

// Register the provider for the argument named "name"
console.Completion.RegisterProvider("name", new SceneCompletionProvider());

// Now typing "scene load l" + Tab will suggest "level_01", "level_02"

The argument name passed to RegisterProvider must match the Name in the [Argument] attribute (or the property name if Name is not set).

Custom Validation Attributes

Implement IValidationAttribute to create your own validators.

[AttributeUsage(AttributeTargets.Property)]
public class FileExistsAttribute : Attribute, IValidationAttribute
{
    public string? ErrorMessage { get; set; }

    public bool Validate(object? value, out string? errorMessage)
    {
        if (value is string path && !File.Exists(path))
        {
            errorMessage = ErrorMessage ?? $"File not found: {path}";
            return false;
        }

        errorMessage = null;
        return true;
    }
}

// Usage:
[Command("load", Help = "Load a configuration file")]
public class LoadCommand : ICommand
{
    [Argument(0, Name = "path", Help = "File path")]
    [Required]
    [FileExists(ErrorMessage = "Config file does not exist")]
    public string? Path { get; set; }

    public CommandResult Execute(CommandContext context)
    {
        context.Output.WriteLine($"Loaded: {Path}");
        return CommandResult.Ok;
    }
}

Multiple validators can be stacked on the same property. All validators are evaluated during binding, and all errors are collected before execution is aborted.

Parsing Rules

The CommandParser follows these rules:

Syntax Meaning
help Single command
scene load Hierarchical command path
greet Alice Positional argument
greet "Alice Smith" Quoted argument (preserves spaces)
--verbose Long option (boolean flag)
--count 5 Long option with value
--count=5 Long option with inline value
-v Short option (boolean flag)
-c 5 Short option with value
-c=5 Short option with inline value
teleport 10 -3.2 Negative numbers are treated as arguments, not options

Option names are case-insensitive. The parser uses a trie walk to determine where the command path ends and arguments begin, so scene load forest.json correctly identifies scene load as the command and forest.json as an argument.

Token Spans

The parser tracks the exact character position of every token via TokenSpan. This enables features like syntax highlighting, inline error markers, or cursor-aware completion in a UI:

var (tokens, spans) = CommandParser.Tokenize("spawn goblin --count 5");

// spans[0] = TokenSpan { Start=0, Length=5, Value="spawn",   Type=Argument }
// spans[1] = TokenSpan { Start=6, Length=6, Value="goblin",  Type=Argument }
// spans[2] = TokenSpan { Start=13, Length=7, Value="--count", Type=Argument }
// spans[3] = TokenSpan { Start=21, Length=1, Value="5",       Type=Argument }

Note: Tokenize assigns all tokens a default TokenType.Argument. The full Parse() method reassigns types to Command, OptionName, and OptionValue based on the registry lookup.

Console State

ConsoleState provides a read-only view of all UI-relevant data. A rendering layer can observe this state to draw the console overlay.

ConsoleState state = console.State;

state.InputText              // Current input line (string)
state.CursorPosition         // Cursor offset in input (int)
state.IsOpen                 // Whether the console is visible (bool)
state.ExecutionState         // Idle, Running, or Error
state.CompletionItems        // Active completion suggestions, or null
state.CompletionSelectedIndex // Selected completion index (-1 if none)
state.OutputLines            // All output lines (IReadOnlyList<OutputLine>)
state.OutputScrollOffset     // Scroll position (int)
state.MaxOutputLines         // Output line cap (int, default 1000)

Each OutputLine contains:

  • Text -- the output string
  • Type -- Normal, Error, Warning, or Info
  • Timestamp -- DateTime when the line was written

Integration Example: Game Loop

Here is how ConsoleKit can be integrated into a MonoGame update/draw loop:

public class Game1 : Game
{
    private ConsoleProvider _console;

    protected override void Initialize()
    {
        _console = new ConsoleProvider();
        _console.Registry.DiscoverCommands(GetType().Assembly);
        _console.SetServices(Services);

        // React to events
        _console.CommandExecuted += result =>
        {
            if (!result.Success)
                System.Diagnostics.Debug.WriteLine($"Command failed: {result.Error}");
        };

        base.Initialize();
    }

    protected override void Update(GameTime gameTime)
    {
        var kb = Keyboard.GetState();

        // Toggle console with tilde key
        if (WasKeyPressed(Keys.OemTilde))
            _console.Toggle();

        if (_console.State.IsOpen)
        {
            // Handle text input (subscribe to Window.TextInput for full support)
            foreach (char c in _typedCharacters)
                _console.InsertChar(c);

            if (WasKeyPressed(Keys.Back))
                _console.Backspace();

            if (WasKeyPressed(Keys.Delete))
                _console.Delete();

            if (WasKeyPressed(Keys.Left))
                _console.MoveCursor(-1);

            if (WasKeyPressed(Keys.Right))
                _console.MoveCursor(1);

            if (WasKeyPressed(Keys.Up))
                _console.HistoryUp();

            if (WasKeyPressed(Keys.Down))
                _console.HistoryDown();

            if (WasKeyPressed(Keys.Tab))
            {
                if (_console.State.CompletionItems != null)
                    _console.ApplyCompletion();
                else
                    _console.RequestCompletion();
            }

            if (WasKeyPressed(Keys.Escape))
            {
                if (_console.State.CompletionItems != null)
                    _console.ClearCompletion();
                else
                    _console.Close();
            }

            if (WasKeyPressed(Keys.Enter))
                _console.Submit();
        }

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        if (_console.State.IsOpen)
        {
            // Draw a background overlay
            // Draw output lines from _console.State.OutputLines
            // Draw the input line with cursor from _console.State.InputText
            // Draw completion popup from _console.State.CompletionItems
        }

        base.Draw(gameTime);
    }
}

API Reference

Interfaces

Interface Namespace Description
ICommand ConsoleKit.Core CommandResult Execute(CommandContext context) -- the single command interface
IUndoAction ConsoleKit.Core void Undo(CommandContext), void Redo(CommandContext), string Description
IConsoleOutput ConsoleKit.Output WriteLine, Write, WriteError, Clear
ICompletionProvider ConsoleKit.Completion IEnumerable<CompletionItem> GetCompletions(...)
IValidationAttribute ConsoleKit.Attributes.Validation bool Validate(object? value, out string? errorMessage)

Classes

Class Namespace Description
CommandAttribute ConsoleKit.Attributes [Command(path, Help = "...")]
ArgumentAttribute ConsoleKit.Attributes [Argument(index, Name = "...", Help = "...")]
OptionAttribute ConsoleKit.Attributes [Option(longName, shortName, Help = "...")]
RequiredAttribute ConsoleKit.Attributes.Validation [Required(ErrorMessage = "...")]
RangeAttribute ConsoleKit.Attributes.Validation [Range(min, max, ErrorMessage = "...")]
CommandContext ConsoleKit.Core Provides Output and Services to commands
UndoAction ConsoleKit.Core Delegate-based IUndoAction: new UndoAction(description, undoFn, redoFn)
HelpCommand ConsoleKit.Commands Built-in help command, auto-registered by CommandRegistry
CommandParser ConsoleKit.Parsing Tokenizes and parses raw input strings
ParsedInput ConsoleKit.Parsing Result of parsing: CommandPath, PositionalArguments, Options, TokenSpans
ArgumentBinder ConsoleKit.Parsing Binds parsed input to command properties via reflection
CommandRegistry ConsoleKit.Registry Trie-based command registration, lookup, execution, help generation
CommandDescriptor ConsoleKit.Registry Metadata for a registered command (type, path, arguments, options)
ArgumentDescriptor ConsoleKit.Registry Metadata for a positional argument
OptionDescriptor ConsoleKit.Registry Metadata for a named option
CompletionEngine ConsoleKit.Completion Generates context-aware completions
CompletionItem ConsoleKit.Completion Single completion suggestion (Label, InsertText, Detail, Kind)
CompletionResult ConsoleKit.Completion Completion result set with replacement span info
ConsoleProvider ConsoleKit.State Main orchestrator, implements IConsoleOutput
ConsoleState ConsoleKit.State Observable console UI state
InputHistory ConsoleKit.History Command history buffer (default max 100)
UndoStack ConsoleKit.History Undo/redo stack (default max 50)

Structs

Struct Namespace Description
CommandResult ConsoleKit.Core ExitCode, Error, Success, UndoAction -- factories: Ok, WithUndo(action), Fail(...)
BindingResult ConsoleKit.Parsing Success, Errors -- factories: Ok(), Fail(errors)
TokenSpan ConsoleKit.Parsing Start, Length, Value, Type, End
OutputLine ConsoleKit.State Text, Type, Timestamp

Enums

Enum Namespace Values
TokenType ConsoleKit.Parsing Command, Argument, OptionName, OptionValue
CompletionKind ConsoleKit.Completion Command, Argument, Option
ExecutionState ConsoleKit.State Idle, Running, Error
OutputType ConsoleKit.State Normal, Error, Warning, Info

Events (on ConsoleProvider)

Event Signature Description
CommandExecuted Action<CommandResult>? Fires after Submit() completes
OutputWritten Action<OutputLine>? Fires after each WriteLine / WriteError call
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 100 2/5/2026