Skip to main content

Vibe-TUI

A TUI library based in pure python that uses weighting to align your program perfectly.

Version Creator

Why should I use this?

  • No asyncio: Do what you want and manage as you like and display when you're finished; no rush here!
  • Weight based alignment: Remove the hassle of calculating widths and heights to the weight system! (I don't see hackers need to be game devs to make good TUIs)

What Nodes (or widgets) can I use?

  • UIBox(Node): A basic container box.
  • UIImage(Node): Displays an image as block characters (requires term-image and Pillow).
  • PythonCode(UIBox): Python text editor widget.
  • UILabel(UIBox): A box without edges, used for text display.
  • UIBar(UIBox): Loading bar, requires vibe_loadbar to be installed.
  • ColorPicker(Node): A color selection widget.
  • UICheckbox(UIBox): A checkbox widget.
  • UIButton(UIBox): A clickable button.
  • UIInput(Node): A text input field.
  • UISelect(UIBox): A selection/list manager.
  • TabManagerH(UiContainerHorizontal): A horizontal tab manager.
  • UIScrollText(Node): A scrollable text view.
  • UIEditor(UIBox): A full-featured text editor.
  • UITerminal(UiContainerVertical): A terminal emulator widget.
  • UITree(UIBox): A tree view widget.
  • UIToast(Node): A toast notification overlay.
  • UIModal(Node): A basic modal overlay.
  • UIModalNode(UIModal): A modal that can contain another widget.
  • CanvasNode(Node): A canvas for custom drawing. and more...

What layouts can I use?

  • UiContainerHorizontal(Node): Horizontal layout.
  • UiContainerVertical(Node): Vertical layout.

You can also use FocusManager to manage Node focus.

File Structure:

.
├── architecture.svg
├── pyproject.toml
├── README.md
├── vibe_browser.py
├── example.py
└── vibe_tui
    ├── UI
    │   ├── __init__.py
    │   ├── base_widgets.py
    │   ├── interactive
    │   │   ├── __init__.py
    │   │   ├── clickable.py
    │   │   ├── images
    │   │   │   ├── __init__.py
    │   │   │   └── image.py
    │   │   └── textinput.py
    │   └── widgets.py
    ├── __init__.py
    ├── base
    │   ├── __init__.py
    │   ├── basic.py
    │   ├── colors.py
    │   └── theme.py
    ├── event
    │   └── eventmanager.py
    ├── keyinput
    │   ├── __init__.py
    │   └── key.py
    ├── layouts
    │   ├── __init__.py
    │   └── baselayouts.py
    ├── managers
    │   ├── __init__.py
    │   ├── app.py
    │   └── manager.py
    ├── node
    │   ├── __init__.py
    │   └── basenode.py
    └── statements.py

Class structure:

class

New:

  • VibeApp() class makes a custom app for you without having to manage the event loop.

Example code:

Click to view the code
from vibe_tui import (
    VibeApp,
    UiContainerVertical,
    UiContainerHorizontal,
    UISelect,
    UIScrollText,
    UIInput,
    UILabel,
    Colors,
    Theme
)
import random
import string
from vibe_tui.base.colors import LIGHT_BLUE_THEME

Theme.set_color_theme(LIGHT_BLUE_THEME)

class SimpleApp:
    def __init__(self):
        # Sample data for demonstration
        self.all_items = items = [
            f"root/{'sys' if i % 3 == 0 else 'usr'}/{i:02d}/{''.join(random.choices(string.ascii_lowercase, k=12))}.cfg"
            for i in range(123)
        ]
        
        # 2. Define Layout
        self.root = UiContainerVertical()
        
        # Header with bold colors
        self.header = UILabel(weight=1, text=f" {Colors.BOLD}{Colors.BLUE}VIBE-TUI ENHANCED DEMO{Colors.RESET}")
        
        # Interactive Search/Filter bar
        self.search_bar = UIInput(weight=1, label="   Filter: ")
        
        # Main content area using weights (1:2 ratio)
        self.main_layout = UiContainerHorizontal(weight=8)
        self.list_box = UISelect(weight=1, title=" SELECTOR ")
        self.preview_box = UIScrollText(weight=2, title=" PREVIEW ", show_line_numbers=True)
        
        self.main_layout.add(self.list_box).add(self.preview_box)
        
        # Informative Footer
        self.footer = UILabel(weight=1, text=f" {Colors.DIM}Press 'q' to Quit | Tab: Switch Focus | Arrows: Navigate{Colors.RESET}")

        # Assemble the UI tree
        self.root.add(self.header).add(self.search_bar).add(self.main_layout).add(self.footer)

        # 3. Setup Logic & Events
        self.list_box.options = self.all_items
        
        # Bind events: Update preview on selection, and filter on search change
        self.list_box.on("change", self.on_selection_change)
        self.search_bar.on("change", self.on_search_change)

        # 4. Initialize the App Engine
        self.app = VibeApp(self.root)
        self.on_selection_change(None) # Initial preview load

    def on_selection_change(self, _):
        """Updates the preview pane based on the current selection."""
        if not self.list_box.options:
            self.preview_box.set_text("\n   No matches found.")
            return
            
        selected = self.list_box.options[self.list_box.selection]
        details = f"{Colors.BOLD}Details for:{Colors.RESET} {Colors.CYAN}{selected}{Colors.RESET}\n"
        details += "═" * 40 + "\n\n"
        details += "This UI is built using weight-based alignment,\n"
        details += "ensuring it scales perfectly with your terminal size.\n\n"
        details += f"Current Index: {Colors.YELLOW}{self.list_box.selection}{Colors.RESET}\n"
        details += f"Status: {Colors.GREEN}Active{Colors.RESET}" if self.list_box.selection % random.choice([i for i in range(1, 16)]) != 0 else f"Status: {Colors.RED}DISABLED{Colors.RESET}"
        
        self.preview_box.set_text(details)

    def on_search_change(self, query):
        """Filters the list selection as you type."""
        filtered = [item for item in self.all_items if query.lower() in item.lower()]
        self.list_box.options = filtered
        
        # Ensure selection index remains valid
        if self.list_box.selection >= len(filtered):
            self.list_box.selection = max(0, len(filtered) - 1)
        self.on_selection_change(None)

    def run(self):
        """Extends the input handler to support global shortcuts."""
        original_handle = self.app.fm.handle_input
        
        def custom_handle(key):
            # Global quit shortcut (when not typing in the search bar)
            if key == 'q' and self.app.fm.current != self.search_bar:
                self.app.stop()
                return
            original_handle(key)
        
        self.app.fm.handle_input = custom_handle
        self.app.run()

if __name__ == "__main__":
    try:
        SimpleApp().run()
    except Exception as e:
        print(f"Error starting app: {e}")

Read the Documentation

Made with time and code by Adam Hany

Metadata

Release files for vibe-tui 0.8.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vibe-tui 0.8.6
File Size Uploaded Provenance
vibe_tui-0.8.6.tar.gz 37.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for vibe-tui 0.8.6
File Interpreter ABI Platform
vibe_tui-0.8.6-cp315-cp315-macosx_10_15_universal2.whl CPython 3.15 CPython 3.15 macOS 10.15+ universal2 (ARM64, x86-64) Details

Total release size: 85.2 kB

Release files / vibe_tui-0.8.6.tar.gz

Download URL vibe_tui-0.8.6.tar.gz
Size 37.6 kB
Tags Source
SHA-256 checksum
How to use checksums
43197077633086f2f9c7825fb8dd9010337c662fc7ba24b1fb089c5217e9e8f9
BLAKE2b-256 checksum
How to use checksums
b613d54143ee4bf018b259c8d7cb400d07ed4bba1fd11d5270410ed6d16596b2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.15.0a7

Release files / vibe_tui-0.8.6-cp315-cp315-macosx_10_15_universal2.whl

Download URL vibe_tui-0.8.6-cp315-cp315-macosx_10_15_universal2.whl
Size 47.6 kB
Tags CPython 3.15 macOS 10.15+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
eb0c68be4ad8cad9a64ba35fbf9485019d4aa255a2c07a1f970008c1051f52e0
BLAKE2b-256 checksum
How to use checksums
97c37f98198c231e59826a87f016d740335300566a1662d17af54d404555b99c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.15.0a7

Security for vibe-tui 0.8.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page