Skip to main content

A lightweight terminal UI library for high-frequency dynamic refresh scenarios.

Project description

Prosperous - Terminal UI Library / 终端 UI 库

coverage

English | 中文


Introduction

Prosperous is a lightweight terminal UI library designed for dynamic high-frequency refresh scenarios. It serves as a lightweight alternative to Rich.Live, bypassing document-flow or constraint-based layouts in favor of a frame-loop driven canvas. This approach empowers developers to build high-performance, responsive terminal applications with ease.

The only external dependency is Pillow (required only for image rendering).

简介

Prosperous 是一个轻量的终端 UI 库,专为动态高频刷新场景设计,是 Rich.Live 的轻量替代方向。它不引入文档流或约束布局,直接面向帧循环画布,帮助开发者快速搭建高性能、交互灵敏的终端应用。

唯一的外部依赖是 Pillow(仅图像渲染需要)。


Core Architecture / 底层架构

Rendering Engine / 渲染引擎

Prosperous uses double-buffered differential rendering, driven by three collaborative threads:

  • Logic Thread: Runs the user's main loop. It's rate-limited by live.poll(). Within the live.frame() context, it calls component draw() methods, writing to the screen_prepare buffer.
  • Render Thread: Runs at the target FPS. It performs an O(1) pointer swap between screen_prepare and screen_buffer, compares the new frame with screen_dump to calculate the difference, and sends only the changed cells to the terminal.
  • Input Thread: A byte-stream state machine that parses raw input in real-time. Events are queued and consumed by the Logic thread via live.poll().

ANSI output is handled by an incremental state machine (_RenderContext), which tracks the terminal's current style state and emits only changed attribute codes, avoiding full resets. This is highly efficient for high-latency environments like SSH.

采用双缓冲差分渲染,由三个线程协同驱动:

  • Logic 线程:用户的主循环,通过 live.poll() 限速,在 live.frame() 上下文内调用组件 draw(),结果写入 screen_prepare 缓冲区。
  • Render 线程:以目标 fps 运行,通过 O(1) 指针交换将 screen_preparescreen_buffer 互换,然后对比 screen_dump 计算差分,只向终端发送变化的格子。
  • Input 线程:字节流状态机,实时解析原始输入并入队,Logic 线程通过 live.poll() 取出。

ANSI 输出采用增量状态机_RenderContext):追踪终端当前样式状态,只发送变化的属性码,不发全量 reset。对 SSH 等高延迟环境友好。

Coordinate System / 坐标系

Coordinates use the format pos=(row, col), starting from 0. Child component coordinates are relative to the content origin of their parent container (get_child_origin()), rather than absolute screen coordinates. Top-level components (added directly via live.add()) have pos equal to screen coordinates.

VStack and HStack achieve automatic arrangement by overriding get_child_origin(child).

pos=(row, col),从 0 开始。子组件坐标相对于父容器的内容区原点get_child_origin()),而非屏幕绝对坐标。顶层组件(直接 live.add() 的)pos 等于屏幕坐标。

VStack / HStack 通过覆盖 get_child_origin(child) 实现自动排列。

Focus System / 焦点系统

The FocusManager features a built-in focus stack. When live.add() is called, all focusable=True components are automatically registered in declaration order (skipping visible=False subtrees). Modals and similar scenarios are handled by push_group() / pop_group(), which temporarily hijack focus and automatically restore it once popped.

FocusManager 内置焦点栈live.add() 时自动按声明顺序注册所有 focusable=True 的组件(跳过 visible=False 子树)。Modal 等场景通过 push_group() / pop_group() 临时接管焦点,关闭后自动恢复。


Quick Start / 快速上手

from prosperous import Live, Panel, InputBox, Button, Style

def handle_cmd(text):
    # Your logic here
    pass

with Live(fps=30, logic_fps=60) as live:
    cmd = InputBox(id="cmd", width=30, label="INPUT",
                   on_enter=lambda: handle_cmd(cmd.text))

    panel = Panel(pos=(1, 2), width=50, height=5, title="DEMO",
                  children=[cmd, Button(label="OK", on_enter=lambda: handle_cmd(cmd.text))])

    live.add(panel)  # focusable children are automatically registered

    while live.running:
        for key in live.poll():
            if key == "ESC": live.stop()
            live.focus.handle_input(key)
        with live.frame():
            # Add dynamic drawing logic here if needed
            pass

Features / 功能一览

  • Components / 组件: Panel, Box (custom borders/backgrounds), VStack, HStack, Label (high-performance single-line), Text (multi-line/alignment/rich text markup), Button, InputBox, ProgressBar, LogView.
  • Layout / 布局: padding, gap, align (cross-axis alignment), reverse, layer (rendering order).
  • Rich Text / 富文本: Supports HTML-like <tag>content</> markup (parsed by markup.py). Supports themed semantic tags <#id>, color names, HEX colors, and nested ANSI attributes.
  • Interaction / 交互: Declarative callbacks (on_enter, on_key, on_focus, on_blur), focus stack (modal isolation), and CJK input support.
  • Styles / 样式: Style objects, TrueColor / 256-color support, style inheritance, and a Theme system (default values by component type).
  • Animation / 动画: Tween(start, end, duration, easing) interpolators with built-in linear, ease_in, ease_out, ease_in_out, and support for custom easing functions.
  • Query / 查询: Deep-first search via component.find(id) or live.find(id).

Theme System / 主题系统

from prosperous import set_theme, DEFAULT_THEME, Style

set_theme({
    **DEFAULT_THEME,
    "Panel": {"padding": 2, "style": Style(fg=240)},
})

Theme defaults are automatically applied when style parameters are omitted. Call set_theme once before entering with Live(...).

如果不传样式参数,组件会自动使用 Theme 默认值。在进入 with Live(...) 前调用一次 set_theme 即可。


Code Style / 代码风格

Prosperous follows the ruff format --line-length 100 standard.

It is recommended to declare top-level containers as named variables and pass references to live.add(), rather than inlining the entire component tree, to avoid excessive nesting depth:

使用 ruff format --line-length 100。建议顶层容器用命名变量声明,live.add() 只传引用,避免整个组件树内联导致缩进过深。

# Recommended / 推荐
panel = Panel(pos=(1, 2), width=76, height=7, title="METRICS", children=[...])
live.add(panel)

# Not Recommended / 不推荐
live.add(Panel(pos=(1, 2), width=76, height=7, title="METRICS", children=[...]))

License / 开源协议

MIT License.

Acknowledgments / 致谢

Welcome bug reports and contributions! If you're interested in building a terminal application with Prosperous, we'd love to see what you create.

非常欢迎您指正代码中的错误,或者参与到共同开发中。如果您有兴趣尝试用这个小工具开发一个简单的终端应用,那将是对本项目最大的支持。

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

prosperous-0.1.0.tar.gz (51.8 kB view details)

Uploaded Source

Built Distribution

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

prosperous-0.1.0-py3-none-any.whl (51.3 kB view details)

Uploaded Python 3

File details

Details for the file prosperous-0.1.0.tar.gz.

File metadata

  • Download URL: prosperous-0.1.0.tar.gz
  • Upload date:
  • Size: 51.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for prosperous-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b6b11823fe0f7706681396d1ddab4d2abb4cf0f773be374901c5a4bd7ff170c1
MD5 9f9d4dd3e089e8fac6bcde1acddbb861
BLAKE2b-256 2c4850ed7d42d4e715c7d5a6b0ccf4e7fb46b727e49874ee1b5b706100cf9429

See more details on using hashes here.

File details

Details for the file prosperous-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: prosperous-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 51.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for prosperous-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 58dff43862cb285200577bd6e9424c888865f153c2da73ba1819ec398435efbc
MD5 17d77f8e7be5bf2b6a4811d031674cd7
BLAKE2b-256 a3678cf7bca50523b987a575925bc96c1c382130e9bd5414ae05553224d4833e

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