SharpConsoleUI

repository·master·Indexed 42 days ago

https://github.com/nickprotop/consoleex

A Terminal Application Framework for .NET that treats the terminal as a full application surface. It enables building complex TUIs with overlapping windows, a real compositor, alpha blending, and reactive UI components. Requires .NET 8.0 or later.

Tokens
283.8K
Snippets
707
Records
1K
Agent score
54%

What's inside SharpConsoleUI

  1. Explore the SharpConsoleUI API

    master

    The SharpConsoleUI API provides the core building blocks for creating terminal-based user interfaces. The API is organized into several key functional areas:

    • Core Namespace (SharpConsoleUI): Contains the fundamental classes and logic required to initialize and manage a console application.
    • Window Management (Window): The primary abstraction for defining a UI area or container within the terminal.
    • UI Controls (Controls): A collection of pre-built components (widgets) used to build interactive interfaces.
    • Fluent Builders (Builders): A set of builder patterns used to construct complex UI hierarchies and configurations using a fluent API style.
  2. Explore SharpConsoleUI built applications

    master

    SharpConsoleUI is used to power a wide variety of complex TUI (Terminal User Interface) applications. Examples include:

    • cxagent: A terminal AI coding agent with permission-gated tools and live session panels.
    • cxshell: A full terminal desktop environment with a start menu, taskbar, and window management, optimized for SSH.
    • LazyCaddy: A Caddy server dashboard for managing routes, TLS, and upstreams via the admin API.
    • CXPost: A multi-account IMAP/SMTP email client.
    • cxtop / cxnet / cxgpu: System, network, and GPU monitoring tools with advanced visualizations like Braille waveforms and sparklines.
    • LazyDotIDE: An LSP-powered .NET IDE for the terminal.
    • CXFiles: A three-pane terminal file manager with image previews.
    • LazyNuGet: A NuGet package manager TUI.
  3. Explore real-world applications built with SharpConsoleUI

    master

    SharpConsoleUI is used to power a variety of complex terminal applications, ranging from AI agents and desktop environments to system monitors and IDEs. Key examples include:

    • cxagent: A terminal AI coding agent with sub-agents, live session panels, and permission-gated tool calls.
    • cxshell: A complete terminal-based desktop environment with a Start menu, taskbar, and window manager capable of hosting multiple TUI apps in draggable windows.
    • cxnet: A real-time network throughput monitor using Braille waveforms and alpha-blended backgrounds.
    • cxgpu: A multi-vendor GPU monitor (NVIDIA/AMD) featuring gauges, sparkline history, and process trees.
    • cxtop: A system monitor for CPU, memory, network, and storage metrics.
    • CXFiles: A three-pane terminal file manager with folder trees and image previews via the Kitty graphics protocol.
    • CXPost: A multi-account IMAP/SMTP email client with conversation threading.
    • ServerHub: A Linux server control panel with a widget-based architecture for monitoring system vitals.
    • LazyNuGet: A TUI for managing NuGet packages across .NET solutions.
    • LazyDotIDE: A lightweight .NET IDE featuring LSP IntelliSense and a built-in terminal emulator.
  4. Compare .NET Console UI Libraries

    master

    When choosing a library for your .NET console application, consider the primary goal of your UI:

    • Spectre.Console: Best for rich, beautiful, formatted output that scrolls away (a "printer").
    • Terminal.Gui: Best for single-screen, forms-based TUI applications (a "dialog box").
    • XenoAtom.Terminal.UI: A reactive UI framework for the terminal with alpha blending (like "WPF for the terminal").
    • SharpConsoleUI: Best for multi-window applications with overlapping windows, window management (drag, resize, minimize, maximize), and visual effects like blur and gradients (a "desktop").

    Note on SharpConsoleUI and Spectre.Console: SharpConsoleUI is not built on top of Spectre.Console. It has its own rendering engine, compositor, and layout engine. It is compatible with Spectre.Console markup syntax by design, and it provides a SpectreRenderableControl to host Spectre renderables inside SharpConsoleUI windows.

  5. Understand the Code Quality Enforcement status

    master

    The project uses a staged enforcement plan to transition from advisory CI to blocking gates. Currently, the following signals are enforced as blocking (will fail a PR if not met), while others are advisory or planned:

    Blocking Gates

    • Formatting: Enforced via dotnet format. The codebase is normalized to use tabs per .editorconfig.
    • License-header banner: All source files must carry the required license banner.
    • Analyzer/compiler warnings: Library builds must be warning-clean. Note that AnalysisMode=None is used to disable the broad CA catalog, allowing the library to enforce only its own targeted rules.

    Advisory/Planned

    • Oversized files (>800 lines): Currently Advisory. The goal is to split these into Model/Renderer/InputHandler partials to make this a blocking gate.
    • Multi-TFM PR matrix: Planned (Phase 5). This will involve building and testing across net8.0, net9.0, and net10.0 on PRs.
  6. What is FlowControl and when to use it

    master

    Overview

    FlowControl is an embeddable, focusable control that renders flow steps (like wizards or confirmation dialogs) inline within an existing window layout (e.g., inside a pane or a stack section) instead of opening a separate modal popup.

    It is the third implementation of IFlowHost, providing a different user experience compared to other hosts:

    HostWhere steps appear
    ModalWindowHost (default)A new modal window per step
    SwapContentHostOne shared modal window, content swapped per step
    FlowControlInside an existing layout region, no window opened

    Key Characteristics

    • Composition: It is a three-band GridControl (Auto top / Star body / Auto bottom). It inherits the full container surface, meaning child controls participate in the layout tree, take focus, and route mouse clicks.
    • Lifecycle: Moves through Idle (shows Placeholder), Running (shows the three-band flow), and Done (returns to Placeholder).
    • Focus: Uses normal focus scope. The surrounding window UI remains fully interactive while the flow runs.
    • Sizing: The top and bottom bands are Auto-height; the body row is Star (fills remaining height) and includes a scroll viewport for tall content.
    • Cancellation: Cancelling via the Cancel button or a cancellation token resolves the flow as FlowResult.Cancelled without closing any windows.
  7. How the SharpConsoleUI plugin architecture works

    master

    SharpConsoleUI uses an extensible plugin architecture to add custom themes, controls, windows, and services. Plugins are registered in-process and must be explicitly loaded.

    Plugin Capabilities:

    1. Themes: Custom color schemes and visual styles.
    2. Controls: Reusable UI components.
    3. Windows: Pre-configured window templates and dialogs.
    4. Services: Application-level services and functionality.

    Plugin Lifecycle:

    1. Plugin instance is created.
    2. windowSystem.PluginStateService.LoadPlugin<T>() is called.
    3. Plugin.Initialize(ConsoleWindowSystem) is called.
    4. GetThemes(), GetControls(), GetWindows(), and GetServicePlugins() are called to register content.
    5. Plugin is ready for use.
    6. When windowSystem.Dispose() is called, Plugin.Dispose() is triggered.
    windowSystem.PluginStateService.LoadPlugin<MyPlugin>();
  8. Probe plugin kinds with `plugin_kind`

    master

    The plugin_kind() export acts as a 'pre-load probe'. It returns a newline-separated list of all unique kind strings declared by the services within that library.

    Purpose: It allows a host to decide whether to admit a plugin before performing a full load/handshake. This prevents the host from accidentally registering a plugin that it doesn't recognize, which is important because unloading is not supported.

    Requirements:

    • The probe must return the union of all kinds declared in the manifest.
    • For a file to be considered a valid plugin during probing, it must export both plugin_kind and plugin_free.
    • Consistency Check: The values returned by plugin_kind() must match the kind values in the plugin_describe manifest. A mismatch results in a load error.

    Security Note: Probing is not a sandbox. Calling plugin_kind via dlopen will execute the library's initializers. Do not probe untrusted files.

    // Example of using the probe to filter plugins in a directory
    foreach (var file in Directory.EnumerateFiles(dir, "*.so"))
    {
        if (!NativePluginProbe.TryReadKinds(file, out var kinds)) continue;  // not ours
        if (!kinds.Contains("scm")) continue;                                 // not wanted
        windowSystem.PluginStateService.LoadPlugin(new NativePluginContainer(file));
    }
  9. Configure Panels using the fluent builder pattern

    master

    Panels (top and bottom bars) are configured using a fluent builder pattern within the ConsoleWindowSystemOptions. You can place elements in Left, Center, or Right positions.

    Available Elements

    • Elements.StatusText(text): Displays static or markup text.
    • Elements.Separator(): A vertical separator.
    • Elements.TaskBar(): A window list with Alt+N shortcuts.
    • Elements.Clock(): A live clock display.
    • Elements.Performance(): Displays real-time FPS and dirty character metrics.
    • Elements.StartMenu(): A start button and menu.
    • Elements.Custom(name): A custom render callback.

    Runtime Panel Control

    Use windowSystem.PanelStateService to modify panels while the application is running:

    • Update Status Text: windowSystem.PanelStateService.TopStatus = "[green]Text[/]" (updates the first StatusTextElement).
    • Toggle Visibility: windowSystem.PanelStateService.ShowTopPanel = false.
    using SharpConsoleUI.Panel;
    
    var options = new ConsoleWindowSystemOptions(
        TopPanelConfig: panel => panel
            .Left(Elements.StatusText("[bold cyan]App Title[/]"))
            .Left(Elements.Separator())
            .Right(Elements.Performance()),
        BottomPanelConfig: panel => panel
            .Left(Elements.StartMenu().WithText("☰ Start"))
            .Center(Elements.TaskBar())
            .Right(Elements.Clock().WithFormat("HH:mm:ss"))
    );
  10. Keyboard and Mouse interaction for TimePickerControl

    master

    Keyboard Shortcuts

    • Left / Right: Move between time segments.
    • Tab / Shift+Tab: Move between segments (passes focus if at first/last segment).
    • Up: Increment the focused segment by 1.
    • Down: Decrement the focused segment by 1.
    • Page Up: Increment the focused segment by a large step.
    • Page Down: Decrement the focused segment by a large step.
    • Home: Set the focused segment to its minimum value.
    • End: Set the focused segment to its maximum value.
    • 0-9: Type digits directly into the focused segment (uses a two-keystroke model).
    • A: Set to AM (when AM/PM segment is focused).
    • P: Set to PM (when AM/PM segment is focused).

    Note: Digit entry uses a two-keystroke model. The first digit is held as a pending value; the second digit completes the entry. After a complete two-digit entry, focus auto-advances to the next segment.

    Mouse Interaction

    • Click on a segment: Focuses that segment for editing.
    • Mouse wheel: Increments/decrements the focused segment.
  11. Native Plugin Execution Protocol (The Call/Return Cycle)

    master

    The interaction between the managed host and native plugin during an operation execution follows a strict synchronous JSON-based protocol designed for NativeAOT compatibility.

    The Execution Flow

    1. Validation: The NativeServiceShim validates the input Dictionary<string, object> against the operation's manifest requirements before crossing the ABI. This prevents malformed calls from reaching native code.
    2. Marshalling: Arguments are written to a JSON buffer using a Utf8JsonWriter. The writer uses the declared type from the manifest rather than the runtime type of the boxed object. This ensures the process is AOT-friendly and avoids reflection.
    3. Invocation: The host performs a single P/Invoke: plugin_invoke(op, argsJson).
    4. Return: The native side returns a UTF-8 JSON envelope. The shim:
      • Copies the bytes into a managed string.
      • Immediately calls plugin_free(ptr) to release native memory.
      • Parses the envelope to check for success (ok:true) or failure (ok:false).
      • Returns the value field cast to the operation's declared ReturnType.

    Critical Constraints

    • Concurrency: plugin_invoke is not serialized. Multiple threads can call the same plugin concurrently. If your native plugin is not thread-safe, you must handle synchronization internally or ensure callers do not call it concurrently.
    • Synchronous Only: There is no async support in the ABI. A long-running native operation will block the calling thread. To avoid UI freezes, the host should call the service from a background thread.
    • No Streaming: Communication is strictly one call, one envelope. There is no support for partial results or streaming.
    • Memory Ownership: Every string/buffer crossing the boundary is owned by the producer. The host must call plugin_free on any pointer provided by the native side.
    // Example of the single P/Invoke call on the hot path
    plugin_invoke(op, argsJson);
  12. How MenuControl works: Orientation, Submenus, and Overlays

    master

    A MenuControl serves two primary layout roles:

    • Horizontal: A menu bar (e.g., File, Edit, View) typically placed at the top.
    • Vertical: A sidebar of menu items.

    Key Concepts:

    • Submenus: Each top-level item can host an unlimited hierarchy of child items. Submenus are configured using a nested MenuItemBuilder passed to .AddItem(string text, Action<MenuItemBuilder> configure).
    • Dropdown Rendering: Dropdowns and submenus are rendered as portal overlays. They float above other content and are automatically positioned and clamped to the available screen space (e.g., opening below/above for horizontal bars, or right/left for submenus).
    • Sticky Behavior: Using .Sticky() ensures the menu maintains focus while a dropdown is open, preventing accidental unfocusing.
    • MenuItem Model: Items are instances of the MenuItem class. They support display text, shortcut hints, foreground colors, and an Action. Because MenuItem implements INotifyPropertyChanged, properties like Text, Shortcut, ForegroundColor, and IsEnabled can be data-bound to view models.