PrettyPrompt

repository·main·Indexed 41 days ago

https://github.com/waf/prettyprompt

A cross-platform command-line prompt library for .NET 10 that enhances Console.ReadLine() with syntax highlighting, autocompletion, and history navigation. It utilizes a pane-based UI system and an incremental renderer using ANSI Escape Sequences for efficient terminal updates.

Tokens
988
Snippets
2
Records
6
Agent score
3%

What's inside PrettyPrompt

  1. How PrettyPrompt handles cross-platform input and output

    main

    PrettyPrompt uses a hybrid approach to ensure cross-platform compatibility between Windows, Linux, and macOS:

    • Output (ANSI Escape Sequences): Uses ANSI sequences for syntax highlighting, cursor positioning, and clearing the screen (defined in AnsiEscapeCodes.cs). This approach is thread-safe and allows for efficient incremental screen updates via character streams.
    • Input (System.Console APIs): Uses standard Console APIs for reading characters from STDIN (via SystemConsole.cs).

    Why this hybrid approach? While ANSI sequences are used for output, the library avoids using ANSI sequences for input because:

    1. Standard Console APIs allow for detecting the <kbd>Shift</kbd> modifier (e.g., for Shift + Enter soft newlines).
    2. ANSI input sequences are cryptic and require complex custom parsing.
    3. To handle Bracketed Paste (pasting large blocks of text) without the performance hit of processing every single character as a keypress, PrettyPrompt uses Console.KeyAvailable to detect a "full buffer" and batches them into a single paste event.
  2. How PrettyPrompt's architecture works

    main

    PrettyPrompt is built around a central key-press loop and a pane-based UI system.

    Core Components

    • Prompt.cs: The root entry point. It configures the terminal and manages the main KeyPress loop. It intercepts key presses and dispatches them to IKeyPressHandler implementations.
    • Panes: UI components that implement IKeyPressHandler to react to input.
      • CodePane: The primary text area. It uses a StringBuilder as a backing store and tracks the Caret (index) and Cursor (2D row/column) for word-wrapped text.
      • CompletionPane: The intellisense/autocomplete window, which uses a SlidingArrayWindow to manage scrolling.

    Input and Rendering Lifecycle

    1. Input: KeyDown events are processed by all registered handlers.
    2. Processing: Text is word-wrapped.
    3. Output: KeyUp handlers fire.
    4. Rendering:
      • User-provided callbacks are used for syntax highlighting.
      • Models (CodePane, CompletionPane) are converted into a grid of Cell objects.
      • An incremental renderer compares the new grid to the current screen grid and calculates the minimal ANSI Escape Sequence string (including cursor movements) required to update the screen. This is emitted in a single Console.Write call for efficiency.
  3. Configure the Prompt instance

    main

    The Prompt constructor accepts a PromptConfiguration object. This configuration allows you to enable or disable features such as:

    • Syntax highlighting
    • Autocompletion
    • Soft-newline configuration

    You can also customize the prompt string (e.g., prompt: "> ") via the configuration.

  4. Implement a basic REPL loop with Prompt

    main

    To use PrettyPrompt, instantiate a Prompt object with a PromptConfiguration. Use await prompt.ReadLineAsync() to capture user input. The returned response object contains an IsSuccess property, which is false if the user cancels the operation (e.g., via Ctrl-C).

    var prompt = new Prompt(
        configuration: new PromptConfiguration(prompt: "> "));
    
    while (true)
    {
        var response = await prompt.ReadLineAsync();
        if (response.IsSuccess) // false if user cancels, i.e. ctrl-c
        {
            if (response.Text == "exit") break;
    
            Console.WriteLine("You wrote " + response.Text);
        }
    }