Skip to main content

A simple yet powerful Python library for creating interactive CLI menus

Project description

pymenu-cli

PyPI PyPI - Downloads Python License: MIT

A Python library for creating interactive terminal user interface (TUI) menus from JSON configuration files. Define your menu structure in JSON, write your actions in Python, and get a full-featured TUI application with keyboard navigation, mouse support, global search, theming, and more.

v2.0 — Complete rewrite with a modern TUI powered by Textual. The classic numbered-menu mode is still available via --classic.

pymenu-cli dark theme

Features

  • Full TUI Application — Sidebar navigation, breadcrumb trail, action output panel, footer with keybinding hints
  • Keyboard & Mouse Navigation — Arrow keys, vim keys (j/k), Enter to select, mouse click support
  • Global Search — Press / to search across all menus and submenus instantly
  • Dark & Light Themes — Toggle with T at runtime, or start with --theme light
  • 5 Banner Styles — Rich text, box-drawing, FIGlet, gradient, and emoji
  • Classic Mode — Original v1 numbered-menu experience via --classic flag
  • JSON-Driven — Define menus, submenus, colors, and banners in simple JSON
  • Backward Compatible — Existing v1 JSON files and action modules work unchanged
  • Python 3.9+ — Modern Python with pyproject.toml packaging

Screenshots

Submenu Navigation

Submenu navigation

Action Output

Action output panel

Global Search

Global search

Light Theme

Light theme

Installation

pip install pymenu-cli

Quick Start

1. Create a menu JSON file (menu.json)

{
  "banner": {
    "title": "My App",
    "style": "gradient",
    "colors": ["red", "magenta"],
    "subtitle": "v1.0"
  },
  "title": "Main Menu",
  "items": [
    {
      "title": "Say Hello",
      "action": "say_hello"
    },
    {
      "title": "Settings",
      "submenu": {
        "title": "Settings",
        "items": [
          {
            "title": "Show Config",
            "action": "show_config"
          }
        ]
      }
    }
  ]
}

2. Create an actions file (actions.py)

import platform

def say_hello():
    print("Hello from pymenu-cli!")
    print(f"Running on {platform.system()} {platform.machine()}")

def show_config():
    print("Config: default settings loaded")

3. Run it

# Launch the TUI (default)
pymenu-cli --menu menu.json --actions actions.py

# Classic numbered-menu mode
pymenu-cli --menu menu.json --actions actions.py --classic

# Start with light theme
pymenu-cli --menu menu.json --actions actions.py --theme light

Or use the Python API

from pymenu_cli.pymenu import load_menu

menu = load_menu("menu.json", "actions.py")
menu.display()                          # TUI mode (default)
menu.display(classic=True)              # Classic mode
menu.display(theme="light")             # Light theme

Keyboard Shortcuts

Key Action
/ k Move cursor up
/ j Move cursor down
Enter Select item (enter submenu or run action)
Esc Go back / clear search
Backspace Go back to parent menu
/ Focus global search bar
T Toggle dark/light theme
Q Quit application

Mouse: Click menu items, sidebar nodes, or scroll the output panel.

Menu JSON Format

Full Structure

{
  "banner": {
    "title": "App Name",
    "style": "gradient",
    "colors": ["red", "blue"],
    "subtitle": "Optional subtitle"
  },
  "title": "Main Menu",
  "color": {
    "text": "yellow",
    "background": "light_blue"
  },
  "items": [
    {
      "title": "Action Item",
      "action": "function_name",
      "color": { "text": "green", "background": "black" }
    },
    {
      "title": "Submenu Item",
      "submenu": {
        "title": "Submenu Title",
        "items": [ ... ]
      }
    }
  ]
}

Properties

Property Required Description
title Yes Menu or item title
items Yes Array of menu items
banner No Header banner configuration
color No Text and background color for the title
action No Name of the Python function to execute
submenu No Nested submenu (same structure as root)

Banner Styles

All banner styles are rendered using Rich/Textual — no extra dependencies needed (except pyfiglet for FIGlet style).

Rich Text ("style": "rich")

Clean, bold title with optional subtitle.

"banner": { "title": "My App", "style": "rich", "subtitle": "v1.0" }

Box Drawing ("style": "box")

Unicode box frame around the title.

"banner": { "title": "My App", "style": "box" }
╔════════════════╗
║    My App      ║
╚════════════════╝

FIGlet ("style": "figlet")

Large ASCII art text. Supports font selection via the font parameter. See pyfiglet fonts.

"banner": { "title": "My App", "style": "figlet", "font": "slant" }
    __  ___         ___                
   /  |/  /__  __  /   |  ____   ____ 
  / /|_/ / / / / / / /| | / __ \ / __ \
 / /  / / /_/ / / ___ |/ /_/ // /_/ /
/_/  /_/\__, / /_/  |_/ .___// .___/ 
       /____/        /_/    /_/      

Gradient ("style": "gradient")

Color gradient across the title text.

"banner": { "title": "My App", "style": "gradient", "colors": ["red", "blue"] }

Emoji ("style": "emoji")

Emoji icon paired with styled text.

"banner": { "title": "My App", "style": "emoji", "icon": "🚀" }

Backward Compatibility

Existing v1 format with "font" (no "style") automatically maps to FIGlet:

"banner": { "title": "My App", "font": "standard" }

Color Options

Colors work in classic mode for text and background styling. In TUI mode, they act as overrides on top of the active theme.

Available colors: RED, LIGHT_RED, BLUE, LIGHT_BLUE, YELLOW, LIGHT_YELLOW, GREEN, LIGHT_GREEN, CYAN, LIGHT_CYAN, MAGENTA, LIGHT_MAGENTA, BLACK, LIGHT_BLACK, WHITE, LIGHT_WHITE

{
  "title": "Highlighted Item",
  "color": { "text": "yellow", "background": "blue" },
  "action": "my_function"
}

Actions File

The actions file is a plain Python module. Each function name corresponds to an "action" value in the JSON. Functions receive no arguments. In TUI mode, print() output is captured and displayed in the output panel.

import os
import platform

def show_system_info():
    print(f"OS: {platform.system()} {platform.release()}")
    print(f"Python: {platform.python_version()}")
    print(f"CWD: {os.getcwd()}")

def create_file():
    with open("output.txt", "w") as f:
        f.write("Hello from pymenu-cli!\n")
    print("✓ Created output.txt")

def risky_action():
    # Exceptions are caught and shown in the output panel
    raise ValueError("Something went wrong!")

Global Search

Press / to activate the search bar. It searches across all menus and submenus, not just the current view. Results show the full path to each matching item:

❯ General Settings  ⚡ (Main Menu › Tools › Settings)
  Advanced Settings  ⚡ (Main Menu › Tools › Settings)
  Generate Password  ⚡ (Main Menu › Tools)

Press Enter to navigate to the item and execute it. Press Esc to clear the search.

Theming

Two built-in themes: dark (default) and light.

  • Toggle at runtime: press T
  • Start with a theme: --theme light
  • Via API: menu.display(theme="light")

Themes are implemented as Textual CSS files in pymenu_cli/themes/. Custom themes can be added by creating new .tcss files.

Classic Mode

The original v1 numbered-menu experience is preserved:

pymenu-cli --menu menu.json --actions actions.py --classic
Main Menu

1. File
2. Edit
3. Tools
4. Help

B. Back
X. Exit

Enter your choice:

CLI Reference

pymenu-cli [-h] [-m MENU] [-a ACTIONS] [--classic] [--theme {dark,light}]

Options:
  -m, --menu MENU          Path to the menu JSON file
  -a, --actions ACTIONS    Path to the actions Python file
  --classic                Use classic numbered-menu mode
  --theme {dark,light}     Color theme for TUI mode (default: dark)
  -h, --help               Show help message

Examples

The examples/ directory contains a full working example with real actions:

# Clone and run
git clone https://github.com/moraneus/pymenu-cli.git
cd pymenu-cli

# Install
pip install -e ".[dev]"

# Run the TUI example
pymenu-cli --menu examples/menus/colored_menu.json --actions examples/actions/actions.py

# Run in classic mode
pymenu-cli --menu examples/menus/colored_menu.json --actions examples/actions/actions.py --classic

# Run with light theme
pymenu-cli --menu examples/menus/colored_menu.json --actions examples/actions/actions.py --theme light

The example includes:

  • File operations — Create files, list workspace, export as text/JSON/XML
  • Edit operations — Clipboard cut/copy/paste, workspace stats
  • Tools — System info, password generator, plugin manager, backup/restore
  • Help — User guide with keybindings, FAQ, about page

Migration from v1

pymenu-cli v2.0 is fully backward compatible. Your existing JSON files and action modules work without changes:

What v1 v2
Default display Numbered menu (input()) Full TUI (Textual)
Old display mode --classic flag
Dependencies colorama, art textual, pyfiglet, colorama
Python 3.8+ 3.9+
Packaging setup.py pyproject.toml
Banner format "font": "standard" Still works (auto-detected as FIGlet)
New banner styles rich, box, gradient, emoji
Theming dark / light with T toggle
Search Global search with /

Breaking changes: Python 3.8 is no longer supported (EOL since Oct 2024).

Development

# Clone
git clone https://github.com/moraneus/pymenu-cli.git
cd pymenu-cli

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run linter
pylint pymenu_cli/

# Run with Textual dev console (live CSS reload)
textual run --dev pymenu_cli.app:MenuApp

Project Structure

pymenu_cli/
├── __init__.py          # Public API exports
├── app.py               # MenuApp — main Textual TUI application
├── banner.py            # Banner rendering (5 styles)
├── classic.py           # Classic v1 numbered-menu mode
├── pymenu.py            # CLI entry point, JSON/module loading
├── models/
│   ├── menu.py          # Menu class
│   └── menu_item.py     # MenuItem class
├── widgets/
│   ├── sidebar.py       # Menu tree sidebar
│   ├── menu_list.py     # Navigable menu items panel
│   ├── breadcrumb.py    # Breadcrumb navigation bar
│   ├── search_bar.py    # Global search/filter bar
│   └── output_panel.py  # Action stdout/stderr panel
└── themes/
    ├── dark.tcss        # Dark theme (default)
    └── light.tcss       # Light theme

License

This project is licensed under the MIT License.

Author

Created by Moraneus.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymenu_cli-2.0.0.tar.gz (160.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pymenu_cli-2.0.0-py3-none-any.whl (22.3 kB view details)

Uploaded Python 3

File details

Details for the file pymenu_cli-2.0.0.tar.gz.

File metadata

  • Download URL: pymenu_cli-2.0.0.tar.gz
  • Upload date:
  • Size: 160.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for pymenu_cli-2.0.0.tar.gz
Algorithm Hash digest
SHA256 4f340757aa6cb0cc0274e2df251ae92000451ae870f23c83d6b3d3cd9c8db32b
MD5 2f167a7abf34c37ddba71a15779fb5fc
BLAKE2b-256 dd0accc8140af9034a2c47e2796eaff3bfcb0ab2908825decf1f8b4b86eba912

See more details on using hashes here.

File details

Details for the file pymenu_cli-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: pymenu_cli-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 22.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for pymenu_cli-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 36ce45ac5a3fc65259b0dc607e5e5aed12c60ec8433f93cb78032b7a6ac42fa7
MD5 0ffe7dec5b07172137ec5e0b85cc9a24
BLAKE2b-256 a88e1281ec47458a2dae89ef40eaf0cc05e4473c14348ecd18e1a8ac93a38564

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page