turbodesk¶
Terminal user interfaces as pure functions from state to an immutable view tree.
from turbodesk import UI, View, run
def app(ui: UI) -> View:
count, set_count = ui.state(0)
ui.on_event(lambda e: set_count(count + 1))
return View.text(f"pressed {count} times").center(within=ui.size)
run(app)
Your app is a function. It runs again whenever something changes, and returns a picture of what should be on screen. There is no widget tree to keep in sync, because there is nothing kept between frames except the values you asked for by name.
Here's what you can do with it¶
Two complete programs are built on turbodesk and published on PyPI: Turbo Python and TurboVI. Both are one command away and neither needs a checkout.
They are fully worked examples, developed alongside the library and meant to be used rather than demonstrated. That is the point of them: an example nobody runs proves nothing, and these two are where several parts of turbodesk were first shown to be missing.
Turbo Python — an IDE in the shape of Turbo Pascal 7.0¶
File Edit Search Run Compile Debug Tools Options Window Help
╔[■]════════════════════════════ GREET.PY ═════════════════════════════ 1 [↑]╗
║ 1 def greet(name): ║
║ 2 """Say hello.""" ║
║ 3 return f"hello {name}" ║
║ 4 ║
║ 5 ║
║ 6 for who in ['world', 'turbodesk']: ║
║ 7 print(greet(who)) ║
║ 8 ║
║ ║
╚ 1:1 ══════════════════════════════════════════════════════════════════════◢
F1 Help F2 Save F3 Open Alt+F9 Compile F9 Make F10 Menu
A desktop of overlapping windows you can drag, resize, zoom and tile. A menu bar with hot letters, an editor with syntax colouring, a debugger that steps and breaks and watches, a class browser over the whole project, and a language-server client. Three key schemes, because the Borland one asks for chords a stock macOS terminal never delivers.
The install is turbopython-ide and the command is tp or turbopython. uvx turbopython on its own gets somebody else's project — the bare name belongs to an unrelated compiled-Python dialect, which is why the --from is there.
TurboVI — a vi clone that uses no widgets at all¶
1 def greet(name):
2 """Say hello."""
3 return f"hello {name}"
4
5
6 for who in ['world', 'turbovi']:
7 print(greet(who))
~
~
NORMAL greet.py 5:1 71%
Modes, counts, the ["x] [count] operator [count] motion grammar, registers, marks, macros, . repeat, :s with ranges and flags, several buffers, split windows, syntax colouring, crash recovery, .editorconfig, and find-in-project with a quickfix list — in about 4,800 lines.
It draws every one of those cells from View combinators directly, with no widget anywhere. That is what makes it the library's real test: a text editor is an application rather than a component, and if the core carries one then the core is doing its job.
More to come¶
That is two. The list is meant to grow, and what it takes to join it is a program somebody uses rather than a demo somebody runs.
Why you might want this¶
Rendering is a pure function. app(ui) -> View has no side effects on the screen. You can call it in a test, at any size, and assert on what came out. There is no event loop to start and no snapshot to approve.
from turbodesk.testing import render, to_text
from turbodesk.view import Size
assert "pressed 0 times" in to_text(render(app, size=Size(40, 10)))
A View is a value. It is an immutable grid of styled cells that composes with hcat, vcat and zcat. Two views side by side is a function call.
State is local and explicit. ui.state is a hook keyed by call order, like React's. A widget that needs to remember something asks for it; a widget that does not, does not.
No stylesheet. Styles are Style values in Python. Layout is arithmetic. Two real applications were ported to turbodesk without wanting a layout engine. See the comparison for what that cost and where it hurt.
Why you might not¶
turbodesk is small on purpose, and that is a real constraint:
- POSIX only. It uses
termiosandtty; there is no Windows support. - Far fewer widgets than Textual. About twenty, against Textual's several dozen. No tree-with-checkboxes, no tabbed content, no data table with sorting.
- No CSS, devtools, or web target. To restyle an app without touching Python, or serve it over HTTP, use Textual.
- Young. Two applications have been ported to it. That is enough to have found real bugs, and not enough to have found all of them.
If you want the largest, most featureful terminal framework in Python, use Textual. turbodesk is for people who want a small core they can hold in their head, and whose UI code is testable without a harness.
Where to go next¶
The four tabs across the top, in the order most people want them:
- Getting started: install it and build something.
- Guides: views, state and input are the model; widgets, modals, Rich, passthrough and testing are the parts.
- Developers: how the render loop works inside, how to write a component, and what a change has to pass.
- About: what is stable, and how it compares with Textual, Rich, urwid and prompt_toolkit.