A lightweight terminal UI library for high-frequency dynamic refresh scenarios.
Project description
Prosperous - Terminal UI Library / 终端 UI 库
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 thelive.frame()context, it calls componentdraw()methods, writing to thescreen_preparebuffer. - Render Thread: Runs at the target FPS. It performs an O(1) pointer swap between
screen_prepareandscreen_buffer, compares the new frame withscreen_dumpto 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_prepare与screen_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 bymarkup.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 / 样式:
Styleobjects, TrueColor / 256-color support, style inheritance, and a Theme system (default values by component type). - Animation / 动画:
Tween(start, end, duration, easing)interpolators with built-inlinear,ease_in,ease_out,ease_in_out, and support for custom easing functions. - Query / 查询: Deep-first search via
component.find(id)orlive.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
Release history Release notifications | RSS feed
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6b11823fe0f7706681396d1ddab4d2abb4cf0f773be374901c5a4bd7ff170c1
|
|
| MD5 |
9f9d4dd3e089e8fac6bcde1acddbb861
|
|
| BLAKE2b-256 |
2c4850ed7d42d4e715c7d5a6b0ccf4e7fb46b727e49874ee1b5b706100cf9429
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58dff43862cb285200577bd6e9424c888865f153c2da73ba1819ec398435efbc
|
|
| MD5 |
17d77f8e7be5bf2b6a4811d031674cd7
|
|
| BLAKE2b-256 |
a3678cf7bca50523b987a575925bc96c1c382130e9bd5414ae05553224d4833e
|