Skip to content

Commit 1a92798

Browse files
committed
more words, remove superfluous code
1 parent 72f92e2 commit 1a92798

File tree

2 files changed

+45
-23
lines changed

2 files changed

+45
-23
lines changed

docs/blog/posts/release1.0.0.md

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,42 @@ authors:
88
- willmcgugan
99
---
1010

11-
Version 1.0 announcements often come with a happy hour and merch.
12-
Well we haven't got any merch.
1311

12+
I've had the fortune of being able to work fulltime on a FOSS project for the last three plus years.
1413

15-
## The Compositor
1614

15+
!!! tip inline end "Textual Demo"
16+
17+
[![Textual Demo](../images/textual-demo.svg)](https://github.com/textualize/textual-demo)
18+
19+
20+
Textual has been a constant source of programming challenges, often frustrating but never boring.
21+
The challenges arise because the terminal "specification" says nothing about how to build a modern User Interface on top of it.
22+
The building blocks are there.
23+
After some effort you can move the cursor, write colored text, read keys and mouse coordinates, but that's about it.
24+
Everything else we had to build from scratch: from the most basic [button](https://textual.textualize.io/widget_gallery/#button) to a syntax highlighted [TextArea](https://textual.textualize.io/widget_gallery/#textarea), and everything along the way.
25+
26+
I wanted to write-up some of the more interesting solutions we came up with.
27+
The 1.0 milestone we just passed makes this the perfect time.
28+
29+
If you haven't followed along with Textual's development, here is a demo of what it can do.
30+
This is a Textual app, running remotely, served by your browser:
31+
32+
??? textualize "Try in Textual-web"
33+
34+
<div class="textual-web-demo" data-app="demo"></div>
35+
36+
I cheaped out on the VMs &mdash; so if the demo is down, you could run it locally (with [uv](https://docs.astral.sh/uv/)):
1737

38+
```
39+
uvx --python 3.12 textual-demo
40+
```
41+
42+
43+
44+
## The Compositor
45+
46+
The first component of Textual I want to cover is the *compositor*.
1847
The job of the compositor is to combine widgets in to a single view.
1948

2049
We do this because the terminal itself has no notion of overlapping windows in the way a desktop does.
@@ -39,18 +68,18 @@ Textual's way of handling this is inherited from [Rich](https://github.com/Textu
3968
Anything you print in Rich, first generates a list of [Segments](https://github.com/Textualize/rich/blob/master/rich/segment.py) which consist of a string and associated style.
4069
These Segments are only converted into text with [ansi escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) at the very last moment.
4170

71+
4272
Textual works with same Segment object.
43-
Widgets all produce a list of segments, which are further processed by the compositor.
73+
Widgets all produce a list of segments, which is further processed by the compositor.
4474

4575
!!! tip "Switch the Primitive"
46-
47-
I hope I've earned the opertunity to dispense unsolicited pearls of wisdom.
76+
4877
If a problem is intractable, it can often be simplified by changing what you consider to be the fundamental atomic data and operations you are working with.
4978
I call this "switching the primitive".
5079

5180
### Thinking in Segments
5281

53-
In the following illustration we have an app with three widgets; the "screen" (in blue) plus two floating widgets (in red and green).
82+
In the following illustration we have an app with three widgets; the background "screen" (in blue) plus two floating widgets (in red and green).
5483
There will be many more widgets in a typical app, but this is enough to show how it works.
5584

5685

@@ -73,10 +102,9 @@ It would appear something like the following:
73102
--8<-- "docs/blog/images/compositor/cuts0.excalidraw.svg"
74103
</div>
75104

76-
Those lines are produced when the widget is rendered and consist of a list of segments.
105+
We can't yet display the output as it would require writing each "layer" independantly, potentially making the terminal flicker, and certainly writing more data than neccesary.
77106

78-
We want to combine these lists into a single list that covers the width of the terminal.
79-
That way we can update everything in a single write.
107+
We need a few more steps to combine these lines in to a single line.
80108

81109

82110
### Step 1. Finding the cuts.
@@ -96,25 +124,28 @@ This will produce smaller lists of segments, which in the compositor code we ref
96124
--8<-- "docs/blog/images/compositor/cuts2.excalidraw.svg"
97125
</div>
98126

127+
These chops have the property that nothing overlaps, which is important for the next step.
99128

100129
### Step 3. Discard chops.
101130

102-
Only the top-most chops will actually be visible to the viewer, so we can discard any chop that isn't at the top.
131+
Only the top-most chops will actually be visible to the viewer.
132+
Anything not at the top can simply be thrown away.
103133

104134
<div class="excalidraw">
105135
--8<-- "docs/blog/images/compositor/cuts3.excalidraw.svg"
106136
</div>
107137

108138
### Step 4. Combine.
109139

110-
Now all that's left is to combine the top-most chops in to a single list of Segments.
111-
112-
It is this list of segments that becomes a line in the terminal.
140+
Now all that's left is to combine the top-most chops in to a single list of Segments. It is this list of segments that becomes a line in the terminal.
113141

114142
<div class="excalidraw">
115143
--8<-- "docs/blog/images/compositor/cuts4.excalidraw.svg"
116144
</div>
117145

146+
this is done for ever line in the output.
147+
At the end of it we have a list of segments for each line, ready to be converted in to escape sequences and written to the terminal.
148+
118149
### What I omitted
119150

120151
There is more going on than this explanation may suggest.
@@ -124,4 +155,3 @@ Additionally, the compositor can do partial updates.
124155
In other words, if you click a button and it changes color the compositor can update just that button.
125156

126157
The compositor does all of this fast enough to enable smooth scrolling, even with a metric tonne of widgets on screen.
127-
Surprising fast, given it is essentially number crunching, which isn't considered Python's forté.

src/textual/_layout_resolve.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
from dataclasses import dataclass
43
from fractions import Fraction
54
from typing import Sequence, cast
65

@@ -18,13 +17,6 @@ class EdgeProtocol(Protocol):
1817
min_size: int
1918

2019

21-
@dataclass
22-
class Edge:
23-
size: int | None = None
24-
fraction: int | None = 1
25-
min_size: int = 1
26-
27-
2820
def layout_resolve(total: int, edges: Sequence[EdgeProtocol]) -> list[int]:
2921
"""Divide total space to satisfy size, fraction, and min_size, constraints.
3022

0 commit comments

Comments
 (0)