CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-simple-term-menu

A Python package which creates simple interactive menus on the command line.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

Simple Terminal Menu

A Python package which creates simple interactive menus on the command line. It provides customizable terminal menus with navigation, multi-selection, search functionality, and preview capabilities, supporting cross-platform terminal environments with automatic feature detection.

Package Information

  • Package Name: simple-term-menu
  • Language: Python
  • Installation: pip install simple-term-menu
  • Supported Platforms: Linux, macOS
  • Python Version: 3.5+

Core Imports

from simple_term_menu import TerminalMenu

For exceptions:

from simple_term_menu import (
    InvalidParameterCombinationError,
    InvalidStyleError,
    NoMenuEntriesError,
    PreviewCommandFailedError,
    UnknownMenuEntryError
)

For utility functions and constants:

from simple_term_menu import (
    get_locale, 
    wcswidth,
    BoxDrawingCharacters,
    # Default constants (optional, for customization)
    DEFAULT_MENU_CURSOR,
    DEFAULT_MENU_CURSOR_STYLE,
    DEFAULT_QUIT_KEYS
)

For CLI functions:

from simple_term_menu import main, parse_arguments, get_argumentparser

Basic Usage

from simple_term_menu import TerminalMenu

def main():
    options = ["entry 1", "entry 2", "entry 3"]
    terminal_menu = TerminalMenu(options)
    menu_entry_index = terminal_menu.show()
    
    if menu_entry_index is not None:
        print(f"You have selected {options[menu_entry_index]}!")
    else:
        print("Menu was cancelled")

if __name__ == "__main__":
    main()

Multi-selection example:

from simple_term_menu import TerminalMenu

options = ["Option 1", "Option 2", "Option 3", "Option 4"]
terminal_menu = TerminalMenu(
    options,
    multi_select=True,
    show_multi_select_hint=True
)
menu_entry_indices = terminal_menu.show()

if menu_entry_indices:
    selected_options = [options[i] for i in menu_entry_indices]
    print(f"Selected: {', '.join(selected_options)}")

Error handling example:

from simple_term_menu import (
    TerminalMenu,
    NoMenuEntriesError,
    InvalidParameterCombinationError,
    PreviewCommandFailedError
)

try:
    # Example of handling common errors
    options = []  # Empty list will raise NoMenuEntriesError
    terminal_menu = TerminalMenu(
        options,
        preview_command="invalid_command {}"  # May cause PreviewCommandFailedError
    )
    result = terminal_menu.show()
    
except NoMenuEntriesError as e:
    print(f"Error: No menu entries provided - {e}")
    
except InvalidParameterCombinationError as e:
    print(f"Error: Invalid parameter combination - {e}")
    
except PreviewCommandFailedError as e:
    print(f"Error: Preview command failed - {e}")
    
except KeyboardInterrupt:
    print("Menu cancelled by user")
    # Note: Set raise_error_on_interrupt=True to get this exception
    
except NotImplementedError as e:
    print(f"Error: Platform not supported - {e}")
    # Raised on Windows or when TERM environment variable is missing

Capabilities

Terminal Menu Creation

Creates interactive terminal menus with extensive customization options including cursor styles, keyboard shortcuts, multi-selection, search functionality, and preview windows.

class TerminalMenu:
    def __init__(
        self,
        menu_entries: Iterable[str],
        *,
        accept_keys: Iterable[str] = ("enter",),
        clear_menu_on_exit: bool = True,
        clear_screen: bool = False,
        cursor_index: Optional[int] = None,
        cycle_cursor: bool = True,
        exit_on_shortcut: bool = True,
        menu_cursor: Optional[str] = "> ",
        menu_cursor_style: Optional[Iterable[str]] = ("fg_red", "bold"),
        menu_highlight_style: Optional[Iterable[str]] = ("standout",),
        multi_select: bool = False,
        multi_select_cursor: str = "[*] ",
        multi_select_cursor_brackets_style: Optional[Iterable[str]] = ("fg_gray",),
        multi_select_cursor_style: Optional[Iterable[str]] = ("fg_yellow", "bold"),
        multi_select_empty_ok: bool = False,
        multi_select_keys: Optional[Iterable[str]] = (" ", "tab"),
        multi_select_select_on_accept: bool = True,
        preselected_entries: Optional[Iterable[Union[str, int]]] = None,
        preview_border: bool = True,
        preview_command: Optional[Union[str, Callable[[str], str]]] = None,
        preview_size: float = 0.25,
        preview_title: str = "preview",
        quit_keys: Iterable[str] = ("escape", "q", "ctrl-g"),
        raise_error_on_interrupt: bool = False,
        search_case_sensitive: bool = False,
        search_highlight_style: Optional[Iterable[str]] = ("fg_black", "bg_yellow", "bold"),
        search_key: Optional[str] = "/",
        shortcut_brackets_highlight_style: Optional[Iterable[str]] = ("fg_gray",),
        shortcut_key_highlight_style: Optional[Iterable[str]] = ("fg_blue",),
        show_multi_select_hint: bool = False,
        show_multi_select_hint_text: Optional[str] = None,
        show_search_hint: bool = False,
        show_search_hint_text: Optional[str] = None,
        show_shortcut_hints: bool = False,
        show_shortcut_hints_in_status_bar: bool = True,
        skip_empty_entries: bool = False,
        status_bar: Optional[Union[str, Iterable[str], Callable[[str], str]]] = None,
        status_bar_below_preview: bool = False,
        status_bar_style: Optional[Iterable[str]] = ("fg_yellow", "bg_black"),
        title: Optional[Union[str, Iterable[str]]] = None
    ):
        """
        Create a terminal menu.

        Parameters:
        - menu_entries: List of menu entry strings to display
        - accept_keys: Keys that accept the current selection
        - clear_menu_on_exit: Whether to clear the menu when exiting
        - clear_screen: Whether to clear the screen before showing the menu
        - cursor_index: Initial cursor position (0-based index)
        - cycle_cursor: Whether cursor wraps around at ends
        - exit_on_shortcut: Whether to exit immediately on shortcut key
        - menu_cursor: String to display as cursor
        - menu_cursor_style: Style tuple for cursor (e.g., ("fg_red", "bold"))
        - menu_highlight_style: Style tuple for highlighted entries
        - multi_select: Enable multi-selection mode
        - multi_select_cursor: Cursor for selected items in multi-select
        - multi_select_cursor_brackets_style: Style for selection brackets
        - multi_select_cursor_style: Style for multi-select cursor
        - multi_select_empty_ok: Allow empty selection in multi-select
        - multi_select_keys: Keys for toggling selection in multi-select
        - multi_select_select_on_accept: Select current item on accept in multi-select
        - preselected_entries: Pre-selected entries by string or index
        - preview_border: Show border around preview area
        - preview_command: Command or function to generate preview content
        - preview_size: Preview area size as fraction of screen (0.0-1.0)
        - preview_title: Title for preview area
        - quit_keys: Keys that quit the menu without selection
        - raise_error_on_interrupt: Raise exception on keyboard interrupt
        - search_case_sensitive: Whether search is case sensitive
        - search_highlight_style: Style for search highlighting
        - search_key: Key to activate search mode
        - shortcut_brackets_highlight_style: Style for shortcut brackets
        - shortcut_key_highlight_style: Style for shortcut keys
        - show_multi_select_hint: Show multi-select hint text
        - show_multi_select_hint_text: Custom multi-select hint text
        - show_search_hint: Show search hint text
        - show_search_hint_text: Custom search hint text
        - show_shortcut_hints: Show shortcut hints
        - show_shortcut_hints_in_status_bar: Show shortcuts in status bar
        - skip_empty_entries: Skip empty entries in navigation
        - status_bar: Status bar content (string, list, or callable)
        - status_bar_below_preview: Position status bar below preview
        - status_bar_style: Style for status bar
        - title: Menu title (string or list of strings)
        """

    def show(self) -> Optional[Union[int, Tuple[int, ...]]]:
        """
        Display the menu and wait for user interaction.

        Returns:
        - For single-select: Selected menu entry index (int) or None if cancelled
        - For multi-select: Tuple of selected indices or None if cancelled
        """

Menu Interaction Properties

Access information about the last menu interaction, including selected entries and the key used to accept the selection.

@property
def chosen_accept_key(self) -> Optional[str]:
    """Key used to accept the last selection."""

@property
def chosen_menu_entry(self) -> Optional[str]:
    """Text of the last chosen menu entry (single-select)."""

@property
def chosen_menu_entries(self) -> Optional[Tuple[str, ...]]:
    """Texts of the last chosen menu entries (multi-select)."""

@property
def chosen_menu_index(self) -> Optional[int]:
    """Index of the last chosen menu entry (single-select)."""

@property
def chosen_menu_indices(self) -> Optional[Tuple[int, ...]]:
    """Indices of the last chosen menu entries (multi-select)."""

Exception Handling

Custom exceptions for various error conditions that may occur during menu creation and operation.

class InvalidParameterCombinationError(Exception):
    """Raised when incompatible parameters are used together."""

class InvalidStyleError(Exception):
    """Raised when an invalid style is specified."""

class NoMenuEntriesError(Exception):
    """Raised when no menu entries are provided."""

class PreviewCommandFailedError(Exception):
    """Raised when a preview command fails to execute."""

class UnknownMenuEntryError(Exception):
    """Raised when referencing a non-existent menu entry."""

Box Drawing Characters

Provides platform-appropriate box drawing characters for terminal UIs. Automatically detects UTF-8 support and uses Unicode or ASCII characters accordingly.

class BoxDrawingCharacters:
    """
    Box drawing characters that adapt to terminal capabilities.
    
    Uses Unicode box characters (─│┌┐└┘) for UTF-8 locales,
    falls back to ASCII characters (-|+++) for other locales.
    """
    horizontal: str  # "─" or "-"
    vertical: str    # "│" or "|"
    upper_left: str  # "┌" or "+"
    upper_right: str # "┐" or "+"
    lower_left: str  # "└" or "+"
    lower_right: str # "┘" or "+"

Utility Functions

Helper functions for locale handling and text width calculation, useful for custom terminal applications.

def get_locale() -> str:
    """
    Get the current system locale.

    Returns:
    Current locale string
    """

def wcswidth(text: str) -> int:
    """
    Calculate the width of text considering wide characters.

    Parameters:
    - text: Text string to measure

    Returns:
    Width of the text in terminal columns
    """

Command Line Interface

Functions for using simple-term-menu as a command-line tool, allowing integration with shell scripts and other tools.

def main() -> None:
    """
    Main entry point for command-line usage.
    
    Parses command-line arguments and creates a terminal menu.
    Available as 'simple-term-menu' console script.
    
    Example usage:
    simple-term-menu "Option 1" "Option 2" "Option 3"
    simple-term-menu -m "Item 1" "Item 2" "Item 3"  # Multi-select
    echo -e "Choice A\\nChoice B\\nChoice C" | simple-term-menu
    """

def parse_arguments() -> AttributeDict:
    """
    Parse command-line arguments for the CLI interface.

    Returns:
    Parsed arguments as AttributeDict
    """

def get_argumentparser() -> argparse.ArgumentParser:
    """
    Create and return the argument parser for CLI usage.

    Returns:
    Configured ArgumentParser instance
    """

CLI Arguments

The command-line interface supports extensive configuration through these arguments:

Navigation and Display:

  • -s, --case-sensitive: Make searches case sensitive
  • -X, --no-clear-menu-on-exit: Do not clear the menu on exit
  • -l, --clear-screen: Clear the screen before showing menu
  • -C, --no-cycle: Do not cycle the menu selection
  • -E, --no-exit-on-shortcut: Do not exit on shortcut keys
  • -i, --cursor-index N: Initially selected item index (default: 0)
  • --cursor STR: Menu cursor string (default: "> ")

Styling:

  • --cursor-style STYLES: Cursor style as comma-separated list (default: "fg_red,bold")
  • --highlight-style STYLES: Selected entry style (default: "standout")
  • --search-highlight-style STYLES: Search highlight style (default: "fg_black,bg_yellow,bold")

Multi-Selection:

  • -m, --multi-select: Enable multi-selection mode (implies --stdout)
  • --multi-select-cursor STR: Multi-select cursor (default: "[*] ")
  • --multi-select-cursor-style STYLES: Multi-select cursor style (default: "fg_yellow,bold")
  • --multi-select-cursor-brackets-style STYLES: Bracket style (default: "fg_gray")
  • --multi-select-keys KEYS: Toggle keys (default: " ,tab")
  • --multi-select-no-select-on-accept: Don't select current item on accept
  • --multi-select-empty-ok: Allow empty multi-selection

Preview:

  • -p, --preview COMMAND: Preview command for entries
  • --preview-size FLOAT: Preview area size as fraction (default: 0.25)
  • --preview-title STR: Preview area title (default: "preview")
  • --no-preview-border: Disable preview border

Search:

  • --search-key KEY: Search activation key (default: "/")
  • --no-search-key: Activate search on any letter key

Shortcuts and Hints:

  • --shortcut-key-highlight-style STYLES: Shortcut key style (default: "fg_blue")
  • --shortcut-brackets-highlight-style STYLES: Shortcut bracket style (default: "fg_gray")
  • --show-shortcut-hints: Show shortcut hints
  • --show-multi-select-hint: Show multi-select hint
  • --show-search-hint: Show search hint

Status Bar:

  • --status-bar STR: Status bar content
  • --status-bar-below-preview: Position status bar below preview
  • --status-bar-style STYLES: Status bar style (default: "fg_yellow,bg_black")

Output:

  • --stdout: Output to stdout instead of stderr
  • --title STR: Menu title
  • -V, --version: Show version and exit

Styling Options

The package supports extensive styling through tuples of style keywords:

Color Options

  • Foreground colors: fg_black, fg_blue, fg_cyan, fg_gray, fg_green, fg_purple, fg_red, fg_yellow
  • Background colors: bg_black, bg_blue, bg_cyan, bg_gray, bg_green, bg_purple, bg_red, bg_yellow

Style Options

  • Text formatting: bold, dim, italic, underline, blink, reverse, strikethrough
  • Special: standout (platform-specific highlighting)

Example styling:

menu = TerminalMenu(
    options,
    menu_cursor_style=("fg_red", "bold"),
    menu_highlight_style=("bg_blue", "fg_white"),
    search_highlight_style=("bg_yellow", "fg_black", "bold")
)

Keyboard Navigation

Default Key Bindings

  • Navigation: Arrow keys, j/k (vim-style), Ctrl-n/Ctrl-p (emacs-style), Page Up/Down, Ctrl-f/Ctrl-b
  • Selection: Enter (accept), Space/Tab (multi-select toggle)
  • Search: / (activate search), Escape (exit search)
  • Exit: Escape, q, Ctrl-g, Ctrl-c

Shortcut Keys

Menu entries can include shortcut keys for quick selection. Enclose the shortcut character in brackets:

options = ["[a]pple", "[b]anana", "[c]herry"]
menu = TerminalMenu(options)

Search Feature

Built-in search functionality allows filtering menu entries:

  • Default search key: / (like vim, less)
  • Search supports regex patterns
  • Set search_key=None to activate search on any letter key
  • Case sensitivity controlled by search_case_sensitive parameter

Custom Key Configuration

Keys can be customized through the various *_keys parameters. Keys are specified as strings:

  • Single characters: "a", "/", " " (space)
  • Special keys: "enter", "escape", "tab", "space"
  • Control combinations: "ctrl-g", "ctrl-c"
  • Alt combinations: "alt-a", "alt-x"

Types

from typing import Iterable, Optional, Union, Tuple, Callable, Any, Dict

# Menu entry types
MenuEntry = str
MenuEntries = Iterable[MenuEntry]

# Selection result types
SingleSelection = Optional[int]
MultiSelection = Optional[Tuple[int, ...]]
Selection = Union[SingleSelection, MultiSelection]

# Style specification
StyleTuple = Tuple[str, ...]
Style = Optional[StyleTuple]

# Preview command types
PreviewCommand = Union[str, Callable[[str], str]]

# Status bar types
StatusBar = Union[str, Iterable[str], Callable[[str], str]]

# Title types
Title = Union[str, Iterable[str]]

# CLI argument dictionary
class AttributeDict(dict):
    """
    Dictionary that allows attribute-style access to keys.
    
    Used by parse_arguments() to return CLI arguments that can be 
    accessed as attributes (args.multi_select) or dict keys (args['multi_select']).
    """
    def __getattr__(self, attr: str) -> Any: ...
    def __setattr__(self, attr: str, value: Any) -> None: ...

# Key specification types
KeySpec = str  # Key names like "enter", "escape", "ctrl-g", "alt-x"
KeySequence = Iterable[KeySpec]

# Preselection types
PreselectedEntry = Union[str, int]  # Menu entry by text or index
PreselectedEntries = Iterable[PreselectedEntry]

Module Constants

Version and Package Information

__author__: str = "Ingo Meyer"
__email__: str = "i.meyer@fz-juelich.de"  
__copyright__: str = "Copyright © 2021 Forschungszentrum Jülich GmbH. All rights reserved."
__license__: str = "MIT"
__version_info__: Tuple[int, int, int] = (1, 6, 6)
__version__: str = "1.6.6"

Default Configuration Values

Default parameter values used by TerminalMenu constructor:

# Navigation and behavior defaults
DEFAULT_ACCEPT_KEYS: Tuple[str, ...] = ("enter",)
DEFAULT_QUIT_KEYS: Tuple[str, ...] = ("escape", "q", "ctrl-g")
DEFAULT_CYCLE_CURSOR: bool = True
DEFAULT_EXIT_ON_SHORTCUT: bool = True

# Display defaults
DEFAULT_CLEAR_MENU_ON_EXIT: bool = True
DEFAULT_CLEAR_SCREEN: bool = False
DEFAULT_MENU_CURSOR: str = "> "
DEFAULT_MENU_CURSOR_STYLE: Tuple[str, ...] = ("fg_red", "bold")
DEFAULT_MENU_HIGHLIGHT_STYLE: Tuple[str, ...] = ("standout",)

# Multi-selection defaults
DEFAULT_MULTI_SELECT: bool = False
DEFAULT_MULTI_SELECT_CURSOR: str = "[*] "
DEFAULT_MULTI_SELECT_CURSOR_BRACKETS_STYLE: Tuple[str, ...] = ("fg_gray",)
DEFAULT_MULTI_SELECT_CURSOR_STYLE: Tuple[str, ...] = ("fg_yellow", "bold")
DEFAULT_MULTI_SELECT_KEYS: Tuple[str, ...] = (" ", "tab")
DEFAULT_MULTI_SELECT_SELECT_ON_ACCEPT: bool = True

# Search defaults
DEFAULT_SEARCH_CASE_SENSITIVE: bool = False
DEFAULT_SEARCH_HIGHLIGHT_STYLE: Tuple[str, ...] = ("fg_black", "bg_yellow", "bold")
DEFAULT_SEARCH_KEY: str = "/"

# Preview defaults
DEFAULT_PREVIEW_BORDER: bool = True
DEFAULT_PREVIEW_SIZE: float = 0.25
DEFAULT_PREVIEW_TITLE: str = "preview"

# Shortcut and hint defaults
DEFAULT_SHORTCUT_BRACKETS_HIGHLIGHT_STYLE: Tuple[str, ...] = ("fg_gray",)
DEFAULT_SHORTCUT_KEY_HIGHLIGHT_STYLE: Tuple[str, ...] = ("fg_blue",)
DEFAULT_SHOW_MULTI_SELECT_HINT: bool = False
DEFAULT_SHOW_SEARCH_HINT: bool = False
DEFAULT_SHOW_SHORTCUT_HINTS: bool = False
DEFAULT_SHOW_SHORTCUT_HINTS_IN_STATUS_BAR: bool = True

# Status bar defaults
DEFAULT_STATUS_BAR_BELOW_PREVIEW: bool = False
DEFAULT_STATUS_BAR_STYLE: Tuple[str, ...] = ("fg_yellow", "bg_black")

# Layout constraints
MIN_VISIBLE_MENU_ENTRIES_COUNT: int = 3

docs

index.md

tile.json