chzyer/readline

repository·main·Indexed 25 days ago

https://github.com/chzyer/readline

A multi-platform Go library for terminal-based applications providing advanced line editing, history management, and auto-completion. It features a tree-based completion system via PrefixCompleter, custom segment-based completion through SegmentCompleter, and a robust history management system (opHistory) with file persistence. The library supports a wide array of standard keyboard shortcuts for navigation, editing, and history searching across different operating systems.

Tokens
8.2K
Snippets
6
Records
59
Agent score
81%

What's inside chzyer/readline

  1. Overview of readline features

    main

    The readline library is a multi-platform Go library designed for powerful line editing in terminal applications. It provides the following core capabilities:

    • Multi-platform support: Works across different operating systems.
    • Line editing: Supports common keyboard shortcut keys for navigating and editing text.
    • History support: Allows users to navigate through previous commands with customizable persistence (saving/loading history).
    • Completion support: Enables tab-completion for commands or inputs.
    • Custom prompts: Supports customizable prompt strings to guide user input.
  2. The readline remote protocol message format

    main

    The remote communication uses a custom message format defined by the Message struct. Every message is prefixed with a length and a type.

    Message Structure (BigEndian):

    1. length (int32): The total size of the message payload including the type field (length = 2 + len(Data)).
    2. type (int16): The MsgType identifier.
    3. data ([]byte): The raw payload.

    Supported MsgType values:

    • T_DATA (0): Contains raw data to be read or written.
    • T_WIDTH (1): Used for width reporting.
    • T_WIDTH_REPORT (2): Client reporting its terminal width to the server.
    • T_ISTTY_REPORT (3): Client reporting if it is a terminal to the server.
    • T_RAW (4): Command to enter raw mode.
    • T_ERAW (5): Command to exit raw mode.
    • T_EOF (6): Signal that the connection is closing/EOF reached.
  3. Use DynamicCompleteFunc for runtime command generation

    main

    If you need to provide completions that change based on the current state or input (like file paths or dynamic IDs), use PcItemDynamic. This requires a DynamicCompleteFunc, which is a function that takes a string and returns a slice of []string representing the available completions.

    When a PrefixCompleter is marked as Dynamic, the completion engine calls its Callback to retrieve the available names for the current line.

  4. Manage command history with opHistory

    main

    The opHistory type manages the lifecycle of command history, including in-memory storage, persistence to a file, and searching. It is typically initialized via newOpHistory(cfg *Config) and used to track user inputs.

    Key capabilities include:

    • Persistence: Automatically saves history to the path specified in Config.HistoryFile.
    • Navigation: Move through history using Prev() and Next().
    • Searching: Search backwards (FindBck) or forwards (FindFwd) through history items.
    • Lifecycle Management: Use New(current []rune) to commit a new command to history, Update(s []rune, commit bool) to modify the current item, and Revert() to return to the last known state.
  5. Quickstart: Create a basic readline loop

    main

    To use readline for a simple interactive command-line interface, use readline.New(prompt) to create an instance, then loop over rl.Readline() to capture user input. Always ensure you defer rl.Close() to clean up resources.

    rl, err := readline.New("> ")
    if err != nil {
    	panic(err)
    }
    defer rl.Close()
    
    for {
    	line, err := rl.Readline()
    	if err != nil { // io.EOF
    		break
    	}
    	println(line)
    }
  6. Implement tree-based command completion with PrefixCompleter

    main

    The readline package provides a tree-based completion system using PrefixCompleter. You can build a hierarchy of commands and subcommands by nesting PrefixCompleter instances.

    To build a static tree, use PcItem(name, children...). To build a dynamic tree where names are generated at runtime (e.g., based on current input), use PcItemDynamic(callback, children...).

    To perform the actual completion logic against a line of text, call Do(completer, line, pos).

  7. Configure input filtering with FuncFilterInputRune

    main

    You can restrict what characters the user is allowed to type by providing a function to Config.FuncFilterInputRune. This function is called for every rune read from the terminal.

    FuncFilterInputRune signature: func(r rune) (rune, bool)

    • If it returns false for the second value, the rune is ignored and the buffer is refreshed.
    • If it returns true, the (potentially modified) rune is processed.
  8. Configure readline.Config

    main

    The Config struct allows you to customize the behavior of the readline instance. Key configuration options include:

    • Prompt: The string displayed to the user (supports ANSI escape sequences for color).
    • HistoryFile: Path to the file where command history is persisted.
    • HistoryLimit: Maximum number of history entries (default is 500; set to -1 to disable).
    • HistorySearchFold: Enables case-insensitive history searching.
    • AutoComplete: An AutoCompleter implementation called when the user presses TAB.
    • Listener: A function triggered on every key press.
    • VimMode: If true, the instance defaults to Vim's insert mode.
    • InterruptPrompt: The prompt shown when an interrupt occurs (default ^C).
    • EOFPrompt: The prompt shown when EOF occurs (default ^D).
    • EnableMask: Enables character masking (e.g., for passwords).
    • MaskRune: The rune used for masking.
    • FuncFilterInputRune: A function to filter or translate input runes before processing.
  9. Readline shortcuts in Normal Mode

    main

    The following keyboard shortcuts are available when using readline in normal mode:

    ShortcutComment
    Ctrl+ABeginning of line
    Ctrl+B / Backward one character
    Meta+BBackward one word
    Ctrl+CSend io.EOF
    Ctrl+DDelete one character
    Meta+DDelete one word
    Ctrl+EEnd of line
    Ctrl+F / Forward one character
    Meta+FForward one word
    Ctrl+GCancel
    Ctrl+HDelete previous character
    Ctrl+I / TabCommand line completion
    Ctrl+JLine feed
    Ctrl+KCut text to the end of line
    Ctrl+LClear screen
    Ctrl+MSame as Enter key
    Ctrl+N / Next line (in history)
    Ctrl+P / Prev line (in history)
    Ctrl+RSearch backwards in history
    Ctrl+SSearch forwards in history
    Ctrl+TTranspose characters
    Meta+TTranspose words (TODO)
    Ctrl+UCut text to the beginning of line
    Ctrl+WCut previous word
    BackspaceDelete previous character
    Meta+BackspaceCut previous word
    EnterLine feed

    Note on Meta keys: Meta+B can be achieved by pressing Esc and B separately. In terminal simulators like iTerm2, you can configure Alt+B to act as Meta+B. On Windows, Meta+B is equivalent to Alt+B.

  10. Readline shortcuts in Search Mode

    main

    Enter Search Mode by pressing Ctrl+S or Ctrl+R. While in Search Mode, use the following shortcuts:

    ShortcutComment
    Ctrl+SSearch forwards in history
    Ctrl+RSearch backwards in history
    Ctrl+C / Ctrl+GExit Search Mode and revert the history
    BackspaceDelete previous character
    OtherExit Search Mode
  11. Readline shortcuts in Complete Select Mode

    main

    Enter Complete Select Mode by pressing Tab twice. While in this mode, use the following shortcuts to navigate and select candidates:

    ShortcutComment
    Ctrl+FMove Forward
    Ctrl+BMove Backward
    Ctrl+NMove to next line
    Ctrl+PMove to previous line
    Ctrl+AMove to the first candidate in current line
    Ctrl+EMove to the last candidate in current line
    Tab / EnterUse the word on cursor to complete
    Ctrl+C / Ctrl+GExit Complete Select Mode
    OtherExit Complete Select Mode
  12. Use SegmentAutoComplete to wrap a SegmentCompleter

    main
    If you have an implementation of the SegmentCompleter interface, you can wrap it in a SegmentComplete struct using the SegmentAutoComplete function. This struct implements the AutoCompleter interface required by readline to perform segment-based completion during user input.