A markup language for UI layouts — define panels once, render anywhere.
Project description
panelmark
panelmark is a zero-dependency Python library for defining terminal UI layouts using a readable ASCII-art shell language, and for implementing the interaction logic that runs inside them.
panelmark is the core library in the panelmark ecosystem. It has no runtime dependencies on any terminal library. It defines:
What is real today
| Feature | Status |
|---|---|
| Shell definition language (ASCII-art DSL) | ✅ Fully working |
# line comments and /* */ block comments |
✅ Fully working |
Horizontal splits (= / - border rows) |
✅ Fully working |
Vertical splits — single-line divider (|) |
✅ Fully working |
Vertical splits — double-line divider (||) |
✅ Fully working |
| Equal-width fill splits (all columns fill-width) | ✅ Columns share space equally (differ by at most 1 char) |
Panel headings (__text__ syntax) |
⚠️ Parsed and stored; renderers must implement display |
Shell state machine (focus, dirty tracking, key dispatch, on_change, bind) |
✅ Fully working |
Draw command abstraction (DrawCommand, RenderContext, WriteCmd, FillCmd, CursorCmd) |
✅ Fully working |
Interaction base class |
✅ Fully working |
See panelmark-tui limitations for the combined limitations list.
- The shell definition language — an ASCII-art syntax for describing layouts
- The layout model — resolved geometry (row, col, width, height) for each named region
- The draw command abstraction — renderer-agnostic
DrawCommandtypes returned by interactions - The
Interactionbase class — the protocol all interactive widgets implement - The
Shellstate machine — focus, dirty tracking, key dispatch, and value observation
To actually display a shell in a terminal, pair panelmark with panelmark-tui, which wraps blessed and provides a full event loop, built-in interactions, and renderer-specific convenience widgets.
Installation
pip install panelmark
Quick start
from panelmark import Shell, Interaction
from panelmark.draw import DrawCommand, RenderContext, WriteCmd, FillCmd
# 1. Define a layout
LAYOUT = """
|=== <bold>My App</> ===|
|{10R $sidebar$ }|{$main$ }|
|==================|
|{2R $status$ }|
|==================|
"""
# 2. Implement an interaction
class Label(Interaction):
def __init__(self, text: str):
self._text = text
@property
def is_focusable(self) -> bool:
return False
def render(self, context: RenderContext, focused: bool = False) -> list[DrawCommand]:
line = self._text[:context.width].ljust(context.width)
return [WriteCmd(row=0, col=0, text=line)]
def handle_key(self, key) -> tuple:
return False, self.get_value()
def get_value(self):
return self._text
def set_value(self, value) -> None:
self._text = str(value)
# 3. Assign interactions to regions
shell = Shell(LAYOUT)
shell.assign("sidebar", Label("Navigation"))
shell.assign("main", Label("Content area"))
shell.assign("status", Label("Ready"))
# 4. Drive with a renderer (e.g. panelmark-tui)
# result = shell.run() ← panelmark_tui.Shell adds run()
Documentation
| Document | Description |
|---|---|
| Shell Language | Shell, region, and panel concepts; state machine methods |
| Shell Language Syntax | Full grammar reference for the ASCII-art layout DSL |
| Shell Language Examples | Annotated examples; custom interactions; portable rendering patterns |
| Draw Commands | DrawCommand types, RenderContext, and the style dict |
| Custom Interactions | Implementing the Interaction ABC |
| Renderer Spec | Renderer compatibility contract, portable library layer, and extension policy |
| Ecosystem Overview | Layered design; package responsibilities; dependency direction |
| Choosing a Renderer | Decision tree for selecting the right package |
Ecosystem
panelmark follows a layered design. The core library is renderer-agnostic; renderer-specific packages extend it.
| Package | Role |
|---|---|
| panelmark (this package) | Zero-dependency core: shell language, layout, draw commands, interaction protocol |
| panelmark-tui | Terminal renderer (blessed); portable-library-compatible |
| panelmark-html | Static HTML/CSS renderer; pre-alpha; foundation for panelmark-web |
| panelmark-web | Live web runtime via WebSockets; portable-library-compatible |
See ecosystem overview for the full design rationale and dependency diagram.
License
MIT
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 panelmark-0.1.0.tar.gz.
File metadata
- Download URL: panelmark-0.1.0.tar.gz
- Upload date:
- Size: 27.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34c75eaafce1301a79638627e3d111ab8f591c0d52e11c81e86f9bc2384bba2d
|
|
| MD5 |
7d6dc53d3d9413dc24e5cae9242ee7ba
|
|
| BLAKE2b-256 |
3fee35f78a12ed1d49aea23e0ef0674eac03e5db6c4125b7d628520a465422dc
|
File details
Details for the file panelmark-0.1.0-py3-none-any.whl.
File metadata
- Download URL: panelmark-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
532d4aee96feea769b20739f65517ae1e966eb85633e9df52c0f677bd568f2e8
|
|
| MD5 |
22d10292f8382eb5ed991586167cf6b4
|
|
| BLAKE2b-256 |
7cad93028e10add8f9bfe660758e0ec5828b7abe2d6a6f9b70c5e5a02bad109a
|