Composable tmux popup system with gum UI components
Project description
tmux-popup
Composable tmux popup system with gum UI components.
Features
🎨 Rich Display - Canvas with Markdown and flexible layouts
🔧 Hybrid Approach - Python data handling + full gum passthrough
📦 Zero Dependencies - Pure Python, only needs tmux and gum
🎯 Type-Safe - Full type hints with proper base classes
🔍 Fuzzy Search - Multi-select filtering with dict support
Installation
# Prerequisites
sudo pacman -S tmux gum # Arch
brew install tmux gum # macOS
# Install package
uv add tmux-popup # Recommended
pip install tmux-popup # Alternative
Quick Start
from tmux_popup import Popup, Canvas, Text, Input, Choose
# Display text
popup = Popup(width="60%", height="30%")
canvas = Canvas(border="rounded", padding="1")
canvas.add(Text("Welcome to tmux-popup!"))
popup.add(canvas).show()
# Get input
name = Popup().add(Input(prompt="Name: ")).show()
# Display then choose
popup = Popup()
popup.add(Canvas().add(Text("Continue?")))
result = popup.add(Choose(options=["Yes", "No"])).show()
Core Concepts
Three Patterns
# 1. Display only
Popup().add(Canvas().add(content)).show()
# 2. Input only
Popup().add(interactive_element).show()
# 3. Display + Input
popup = Popup()
popup.add(Canvas().add(content))
result = popup.add(interactive_element).show()
Content & Layout
from tmux_popup import Popup, Canvas, Markdown, Text, Row, Column
# Rich content with Markdown
canvas = Canvas(border="rounded", padding="1")
canvas.add(Markdown("""# Title
**Bold**, *italic*, `code`
\```python
def hello():
print("Hi!")
\```
"""))
# Two-column layout
left = Column(width="50%", border="normal", padding="1")
left.add(Markdown("## Left"))
right = Column(width="50%", border="normal", padding="1")
right.add(Text("Right content"))
canvas.add(Row(left, right))
popup.add(canvas).show()
Interactive Elements
from tmux_popup import Input, Choose, Filter, Confirm, Table
# Text input
email = Popup().add(
Input(prompt="Email: ", placeholder="user@example.com")
).show()
# Single choice (dict shows labels, returns values)
actions = {
"📝 New File": "new",
"📂 Open": "open",
"❌ Quit": "quit"
}
result = Popup().add(Choose(options=actions)).show() # Returns: "new", "open", or "quit"
# Multi-select with fuzzy search
packages = ["numpy", "pandas", "fastapi", "django"]
selected = Popup().add(
Filter(options=packages, no_limit=True, fuzzy=True)
).show() # Returns: ["numpy", "pandas"]
# Confirmation
if Popup().add(Confirm(prompt="Delete all?")).show():
print("Deleting...")
# Table selection
data = [
{"name": "Alice", "role": "Admin"},
{"name": "Bob", "role": "User"}
]
row = Popup().add(Table(data=data)).show() # Returns selected row dict
Advanced Features
Complete Example
from tmux_popup import Popup, Canvas, Row, Column, Markdown, Text, Filter
# Build interface
popup = Popup(width="80%", height="60%")
canvas = Canvas(border="rounded", padding="1")
# Two columns
left = Column(width="50%", padding="1")
left.add(Markdown("## Instructions\n\n• Type to filter\n• Space to select"))
right = Column(width="50%", padding="1")
right.add(Markdown("## Example\n\n packages = ['numpy', 'pandas']"))
canvas.add(Row(left, right))
popup.add(canvas)
# Add interactive filter
packages = {"NumPy": "numpy", "Pandas": "pandas"}
selected = popup.add(
Filter(options=packages, no_limit=True, fuzzy=True)
).show()
Gum Passthrough
All gum flags work via kwargs:
Choose(
options=["A", "B", "C"],
cursor_foreground="212", # gum styling
height=10, # gum display option
select_if_one=True, # gum behavior
header="Select:" # gum text
)
Debug Mode
# See generated shell script
Popup(debug=True).add(Canvas().add("Test")).show()
Components Reference
Core
Popup- Main container (width, height, border, debug)Canvas- Content area (border, padding, margin, align)
Content
Text- Plain textMarkdown- Formatted markdown with code blocks
Layout
Row- Horizontal containerColumn- Vertical container (width, border, padding)
Interactive
Input- Single-line input (prompt, placeholder, header)Write- Multi-line editor (width, height)Confirm- Yes/no dialog (prompt, affirmative, negative)Choose- Single/multi selection (options, limit, header)Filter- Fuzzy search (options, no_limit, fuzzy)Table- Tabular selection (data, border)FilePicker- File browser (path, file, all)Pager- Scrollable viewer (content)Spin- Loading spinner (command, title)Format- Text formatter (content, format_type)
Types
TimeoutResult,CancelledResult- Special return values
Development
git clone https://github.com/angelsen/tap-tools
cd tap-tools/packages/tmux-popup
uv sync
# Run examples
python examples/demo.py
📄 License
MIT - see LICENSE for details.
👤 Author
Fredrik Angelsen
🙏 Acknowledgments
Built on top of:
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tmux_popup-0.2.1.tar.gz.
File metadata
- Download URL: tmux_popup-0.2.1.tar.gz
- Upload date:
- Size: 19.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec62d0c678555e7048a5647a1c84f319c22fdfb8e50a85826250443916a995ec
|
|
| MD5 |
ef7fc22f6061868f1d9d21a794e280ef
|
|
| BLAKE2b-256 |
4f73027e15c72bb1131befff53f25fb2f8fdedfa7fa36cb95801902256838084
|
File details
Details for the file tmux_popup-0.2.1-py3-none-any.whl.
File metadata
- Download URL: tmux_popup-0.2.1-py3-none-any.whl
- Upload date:
- Size: 30.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1959cd8691d4f477fa5b29945e936fda09da8618c5cf5a5793d6a76302c3f72e
|
|
| MD5 |
4901add2cd92820b87cb20f724ba8ff8
|
|
| BLAKE2b-256 |
3f48849cf9d4832e6662a508f4c0c763c67eb194d9426ab1b9b75844d5b22083
|