From 91a13406e66a5f4e715118be3aa9f0b9484d0d96 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 13:41:10 +0100 Subject: [PATCH 01/89] Remove trailing whitespace Including one instance that I wouldn't have, but the pre-commit hooks have, and it seems fine. --- docs/tutorial.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index c9e03c89e..b41a7365b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -1,18 +1,18 @@ --- hide: - - navigation + - navigation --- # Tutorial Welcome to the Textual Tutorial! -By the end of this page you should have a solid understanding of app development with Textual. +By the end of this page you should have a solid understanding of app development with Textual. !!! quote If you want people to build things, make it fun. - + — **Will McGugan** (creator of Rich and Textual) @@ -83,7 +83,7 @@ Return types follow `->`. So `-> str:` indicates this method returns a string. The first step in building a Textual app is to import and extend the `App` class. Here's a basic app class we will use as a starting point for the stopwatch app. -```python title="stopwatch01.py" +```python title="stopwatch01.py" --8<-- "docs/examples/tutorial/stopwatch01.py" ``` @@ -134,7 +134,7 @@ The final three lines create an instance of the app and calls the [run()][textua ## Designing a UI with widgets -Textual comes with a number of builtin widgets, like Header and Footer, which are versatile and re-usable. We will need to build some custom widgets for the stopwatch. Before we dive in to that, let's first sketch a design for the app — so we know what we're aiming for. +Textual comes with a number of builtin widgets, like Header and Footer, which are versatile and re-usable. We will need to build some custom widgets for the stopwatch. Before we dive in to that, let's first sketch a design for the app — so we know what we're aiming for.
--8<-- "docs/images/stopwatch.excalidraw.svg" @@ -157,9 +157,9 @@ Let's add those to the app. Just a skeleton for now, we will add the rest of the --8<-- "docs/examples/tutorial/stopwatch02.py" ``` -We've imported two new widgets in this code: `Button`, which creates a clickable button, and `Static` which is a base class for a simple control. We've also imported `Container` from `textual.containers` which (as the name suggests) is a Widget which contains other widgets. +We've imported two new widgets in this code: `Button`, which creates a clickable button, and `Static` which is a base class for a simple control. We've also imported `Container` from `textual.containers` which (as the name suggests) is a Widget which contains other widgets. -We've defined an empty `TimeDisplay` widget by extending `Static`. We will flesh this out later. +We've defined an empty `TimeDisplay` widget by extending `Static`. We will flesh this out later. The Stopwatch widget class also extends `Static`. This class has a `compose()` method which yields child widgets, consisting of three `Button` objects and a single `TimeDisplay` object. These widgets will form the stopwatch in our sketch. @@ -168,7 +168,7 @@ The Stopwatch widget class also extends `Static`. This class has a `compose()` m The Button constructor takes a label to be displayed in the button (`"Start"`, `"Stop"`, or `"Reset"`). Additionally some of the buttons set the following parameters: - `id` is an identifier we can use to tell the buttons apart in code and apply styles. More on that later. -- `variant` is a string which selects a default style. The "success" variant makes the button green, and the "error" variant makes it red. +- `variant` is a string which selects a default style. The "success" variant makes the button green, and the "error" variant makes it red. ### Composing the widgets @@ -194,8 +194,8 @@ Every widget has a `styles` object with a number of attributes that impact how t self.styles.background = "blue" self.styles.color = "white" ``` - -While it's possible to set all styles for an app this way, it is rarely necessary. Textual has support for CSS (Cascading Style Sheets), a technology used by web browsers. CSS files are data files loaded by your app which contain information about styles to apply to your widgets. + +While it's possible to set all styles for an app this way, it is rarely necessary. Textual has support for CSS (Cascading Style Sheets), a technology used by web browsers. CSS files are data files loaded by your app which contain information about styles to apply to your widgets. !!! info @@ -213,7 +213,7 @@ Let's add a CSS file to our application. Adding the `CSS_PATH` class variable tells Textual to load the following file when the app starts: -```sass title="stopwatch03.css" +```sass title="stopwatch03.css" --8<-- "docs/examples/tutorial/stopwatch03.css" ``` @@ -228,7 +228,7 @@ This app looks much more like our sketch. let's look at how the Textual uses `st CSS files contain a number of _declaration blocks_. Here's the first such block from `stopwatch03.css` again: -```sass +```sass Stopwatch { layout: horizontal; background: $boost; @@ -263,7 +263,7 @@ TimeDisplay { } Button { - width: 16; + width: 16; } #start { @@ -354,7 +354,7 @@ We have added two reactive attributes: `start_time` will contain the time in sec Both attributes will be available on `self` as if you had assigned them in `__init__`. If you write to either of these attributes the widget will update automatically. -!!! info +!!! info The `monotonic` function in this example is imported from the standard library `time` module. It is similar to `time.time` but won't go backwards if the system clock is changed. From a90a2fd72879f98090ea17217b1981a2905fc03a Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 13:45:34 +0100 Subject: [PATCH 02/89] Correct the name of mypy It seems that mypy's preference for its name is mypy (or even my[py]), but not Mypy. --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index b41a7365b..e73088655 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -64,7 +64,7 @@ python stopwatch.py Type hints are entirely optional in Textual. We've included them in the example code but it's up to you whether you add them to your own projects. -We're a big fan of Python type hints at Textualize. If you haven't encountered type hinting, it's a way to express the types of your data, parameters, and return values. Type hinting allows tools like [Mypy](https://mypy.readthedocs.io/en/stable/) to catch bugs before your code runs. +We're a big fan of Python type hints at Textualize. If you haven't encountered type hinting, it's a way to express the types of your data, parameters, and return values. Type hinting allows tools like [mypy](https://mypy.readthedocs.io/en/stable/) to catch bugs before your code runs. The following function contains type hints: From 93e403c8dc7d5738aaf94e3f7231dfb937a19391 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:11:12 +0100 Subject: [PATCH 03/89] Mark mention of Widget as a class as code --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index e73088655..0324a4ed0 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -157,7 +157,7 @@ Let's add those to the app. Just a skeleton for now, we will add the rest of the --8<-- "docs/examples/tutorial/stopwatch02.py" ``` -We've imported two new widgets in this code: `Button`, which creates a clickable button, and `Static` which is a base class for a simple control. We've also imported `Container` from `textual.containers` which (as the name suggests) is a Widget which contains other widgets. +We've imported two new widgets in this code: `Button`, which creates a clickable button, and `Static` which is a base class for a simple control. We've also imported `Container` from `textual.containers` which (as the name suggests) is a `Widget` which contains other widgets. We've defined an empty `TimeDisplay` widget by extending `Static`. We will flesh this out later. From 82499c31e789c856568de97e72e6653415e4529f Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:16:24 +0100 Subject: [PATCH 04/89] Capital at the start of a sentence --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 0324a4ed0..5a4eeceb7 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -222,7 +222,7 @@ If we run the app now, it will look *very* different. ```{.textual path="docs/examples/tutorial/stopwatch03.py" title="stopwatch03.py"} ``` -This app looks much more like our sketch. let's look at how the Textual uses `stopwatch03.css` to apply styles. +This app looks much more like our sketch. Let's look at how the Textual uses `stopwatch03.css` to apply styles. ### CSS basics From 2e25c894e3d97c4b9a65ae3341b936e91b3d65d6 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:18:23 +0100 Subject: [PATCH 05/89] Add code markup to the mention of a class name --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 5a4eeceb7..ea9cb749e 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -250,7 +250,7 @@ Here's how this CSS code changes how the `Stopwatch` widget is displayed. - `background: $boost` sets the background color to `$boost`. The `$` prefix picks a pre-defined color from the builtin theme. There are other ways to specify colors such as `"blue"` or `rgb(20,46,210)`. - `height: 5` sets the height of our widget to 5 lines of text. - `padding: 1` sets a padding of 1 cell around the child widgets. -- `margin: 1` sets a margin of 1 cell around the Stopwatch widget to create a little space between widgets in the list. +- `margin: 1` sets a margin of 1 cell around the `Stopwatch` widget to create a little space between widgets in the list. Here's the rest of `stopwatch03.css` which contains further declaration blocks: From 50fb72396599edf9df9e59abe52fa1a57e5e08f8 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:19:50 +0100 Subject: [PATCH 06/89] Add code markup to the mention of a class name --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index ea9cb749e..0dab08caa 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -284,7 +284,7 @@ The `TimeDisplay` block aligns text to the center (`content-align`), fades it sl The `Button` block sets the width (`width`) of buttons to 16 cells (character widths). -The last 3 blocks have a slightly different format. When the declaration begins with a `#` then the styles will be applied to widgets with a matching "id" attribute. We've set an ID on the Button widgets we yielded in compose. For instance the first button has `id="start"` which matches `#start` in the CSS. +The last 3 blocks have a slightly different format. When the declaration begins with a `#` then the styles will be applied to widgets with a matching "id" attribute. We've set an ID on the `Button` widgets we yielded in compose. For instance the first button has `id="start"` which matches `#start` in the CSS. The buttons have a `dock` style which aligns the widget to a given edge. The start and stop buttons are docked to the left edge, while the reset button is docked to the right edge. From 758ddfa86f9a93f63a4eea73e41624f65ff04ffb Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:20:41 +0100 Subject: [PATCH 07/89] Add code markup to the mention of a method name --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 0dab08caa..b67ff3ac3 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -284,7 +284,7 @@ The `TimeDisplay` block aligns text to the center (`content-align`), fades it sl The `Button` block sets the width (`width`) of buttons to 16 cells (character widths). -The last 3 blocks have a slightly different format. When the declaration begins with a `#` then the styles will be applied to widgets with a matching "id" attribute. We've set an ID on the `Button` widgets we yielded in compose. For instance the first button has `id="start"` which matches `#start` in the CSS. +The last 3 blocks have a slightly different format. When the declaration begins with a `#` then the styles will be applied to widgets with a matching "id" attribute. We've set an ID on the `Button` widgets we yielded in `compose`. For instance the first button has `id="start"` which matches `#start` in the CSS. The buttons have a `dock` style which aligns the widget to a given edge. The start and stop buttons are docked to the left edge, while the reset button is docked to the right edge. From e109599a97391f5b14b35de24e6c5109f1b22ca2 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:21:39 +0100 Subject: [PATCH 08/89] Add code markup to the mention of a class name --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index b67ff3ac3..edd46d18f 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -292,7 +292,7 @@ You may have noticed that the stop button (`#stop` in the CSS) has `display: non ### Dynamic CSS -We want our Stopwatch widget to have two states: a default state with a Start and Reset button; and a _started_ state with a Stop button. When a stopwatch is started it should also have a green background and bold text. +We want our `Stopwatch` widget to have two states: a default state with a Start and Reset button; and a _started_ state with a Stop button. When a stopwatch is started it should also have a green background and bold text.
--8<-- "docs/images/css_stopwatch.excalidraw.svg" From ed20f4a8e68c90864b9860d18ea4b8e284942dca Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:23:26 +0100 Subject: [PATCH 09/89] Add code markup a string that is a widget ID Elsewhere in the docs we see `"something"` for a class, so I feel it follows that "#something" should really be `"#something"` too. --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index edd46d18f..97704a9d1 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -317,7 +317,7 @@ Some of the new styles have more than one selector separated by a space. The spa } ``` -The `.started` selector matches any widget with a `"started"` CSS class. While `#start` matches a child widget with an ID of "start". So it matches the Start button only for Stopwatches in a started state. +The `.started` selector matches any widget with a `"started"` CSS class. While `#start` matches a child widget with an ID of `"start"`. So it matches the Start button only for Stopwatches in a started state. The rule is `"display: none"` which tells Textual to hide the button. From be36c55d37b9fa6b29f56e2fef6c443acaf67551 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:26:44 +0100 Subject: [PATCH 10/89] Add code markup to the mention of a class name --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 97704a9d1..221765557 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -350,7 +350,7 @@ You can declare a reactive attribute with [reactive][textual.reactive.reactive]. --8<-- "docs/examples/tutorial/stopwatch05.py" ``` -We have added two reactive attributes: `start_time` will contain the time in seconds when the stopwatch was started, and `time` will contain the time to be displayed on the Stopwatch. +We have added two reactive attributes: `start_time` will contain the time in seconds when the stopwatch was started, and `time` will contain the time to be displayed on the `Stopwatch`. Both attributes will be available on `self` as if you had assigned them in `__init__`. If you write to either of these attributes the widget will update automatically. From 86b5612c9f590ef1708cd5ec62219bc0173b9bd2 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:28:04 +0100 Subject: [PATCH 11/89] Lower-case mention of stopwatches This looks more like it's been used as a normal word, rather than as a plural for the class. --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 221765557..f60c0576b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -374,7 +374,7 @@ The end result is that the `Stopwatch` widgets show the time elapsed since the w ```{.textual path="docs/examples/tutorial/stopwatch05.py" title="stopwatch05.py"} ``` -We've seen how we can update widgets with a timer, but we still need to wire up the buttons so we can operate Stopwatches independently. +We've seen how we can update widgets with a timer, but we still need to wire up the buttons so we can operate stopwatches independently. ### Wiring buttons From 1dbde34b40eae4a66377e3ea885d24a45c9a6a14 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:31:32 +0100 Subject: [PATCH 12/89] Add code markup a string that is a class Elsewhere a string that is a class is marked up this way, so let's follow that earlier standard. --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index f60c0576b..62894d36b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -414,7 +414,7 @@ This code supplies missing features and makes our app useful. We've made the fol - The first line retrieves `id` attribute of the button that was pressed. We can use this to decide what to do in response. - The second line calls `query_one` to get a reference to the `TimeDisplay` widget. - We call the method on `TimeDisplay` that matches the pressed button. -- We add the "started" class when the Stopwatch is started (`self.add_class("started)`), and remove it (`self.remove_class("started")`) when it is stopped. This will update the Stopwatch visuals via CSS. +- We add the `"started"` class when the Stopwatch is started (`self.add_class("started)`), and remove it (`self.remove_class("started")`) when it is stopped. This will update the Stopwatch visuals via CSS. If you run stopwatch06.py you will be able to use the stopwatches independently. From 45db071bb5d7100993f5eca3555329b6c05cc989 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:32:20 +0100 Subject: [PATCH 13/89] Add missing end quote to a string --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 62894d36b..35e85053b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -414,7 +414,7 @@ This code supplies missing features and makes our app useful. We've made the fol - The first line retrieves `id` attribute of the button that was pressed. We can use this to decide what to do in response. - The second line calls `query_one` to get a reference to the `TimeDisplay` widget. - We call the method on `TimeDisplay` that matches the pressed button. -- We add the `"started"` class when the Stopwatch is started (`self.add_class("started)`), and remove it (`self.remove_class("started")`) when it is stopped. This will update the Stopwatch visuals via CSS. +- We add the `"started"` class when the Stopwatch is started (`self.add_class("started")`), and remove it (`self.remove_class("started")`) when it is stopped. This will update the Stopwatch visuals via CSS. If you run stopwatch06.py you will be able to use the stopwatches independently. From d6a2c88713fb7fa47ca7e5ff8f35d2e7a8fb26e7 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:35:39 +0100 Subject: [PATCH 14/89] Add code markup to a number of code-oriented things in a line --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 35e85053b..9376b787e 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -435,7 +435,7 @@ Let's use these methods to implement adding and removing stopwatches to our app. Here's a summary of the changes: -- The Container object in StopWatchApp grew a "timers" ID. +- The `Container` object in `StopWatchApp` grew a `"timers"` ID. - Added `action_add_stopwatch` to add a new stopwatch. - Added `action_remove_stopwatch` to remove a stopwatch. - Added keybindings for the actions. From a342a2cb530e9cf6910bd70e5c795cd6ca7dcdf1 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:37:03 +0100 Subject: [PATCH 15/89] Add code markup to the mention of a class name --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 9376b787e..866738a15 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -440,7 +440,7 @@ Here's a summary of the changes: - Added `action_remove_stopwatch` to remove a stopwatch. - Added keybindings for the actions. -The `action_add_stopwatch` method creates and mounts a new stopwatch. Note the call to [query_one()][textual.dom.DOMNode.query_one] with a CSS selector of `"#timers"` which gets the timer's container via its ID. Once mounted, the new Stopwatch will appear in the terminal. That last line in `action_add_stopwatch` calls [scroll_visible()][textual.widget.Widget.scroll_visible] which will scroll the container to make the new Stopwatch visible (if required). +The `action_add_stopwatch` method creates and mounts a new stopwatch. Note the call to [query_one()][textual.dom.DOMNode.query_one] with a CSS selector of `"#timers"` which gets the timer's container via its ID. Once mounted, the new Stopwatch will appear in the terminal. That last line in `action_add_stopwatch` calls [scroll_visible()][textual.widget.Widget.scroll_visible] which will scroll the container to make the new `Stopwatch` visible (if required). The `action_remove_stopwatch` function calls [query()][textual.dom.DOMNode.query] with a CSS selector of `"Stopwatch"` which gets all the `Stopwatch` widgets. If there are stopwatches then the action calls [last()][textual.css.query.DOMQuery.last] to get the last stopwatch, and [remove()][textual.css.query.DOMQuery.remove] to remove it. From bd43f0466ab28b7c34315804a9d21e35fddc7a28 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:41:10 +0100 Subject: [PATCH 16/89] Harmonise the tutorial's markup of filenames In some cases filenames where `marked-up.py`, in other cases they were "marked-up.py", and in some cases they were just mentioned with no-markup.py. This commit seeks to make all filename mentions, in text, the same. --- docs/tutorial.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 866738a15..52d12df70 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -102,7 +102,7 @@ Hit ++ctrl+c++ to exit the app and return to the command prompt. ### A closer look at the App class -Let's examine stopwatch01.py in more detail. +Let's examine `stopwatch01.py` in more detail. ```python title="stopwatch01.py" hl_lines="1 2" --8<-- "docs/examples/tutorial/stopwatch01.py" @@ -179,7 +179,7 @@ The new line in `Stopwatch.compose()` yields a single `Container` object which w ### The unstyled app -Let's see what happens when we run "stopwatch02.py". +Let's see what happens when we run `stopwatch02.py`. ```{.textual path="docs/examples/tutorial/stopwatch02.py" title="stopwatch02.py"} ``` @@ -335,7 +335,7 @@ The following code will start or stop the stopwatches in response to clicking a The `on_button_pressed` method is an *event handler*. Event handlers are methods called by Textual in response to an *event* such as a key press, mouse click, etc. Event handlers begin with `on_` followed by the name of the event they will handler. Hence `on_button_pressed` will handle the button pressed event. -If you run "stopwatch04.py" now you will be able to toggle between the two states by clicking the first button: +If you run `stopwatch04.py` now you will be able to toggle between the two states by clicking the first button: ```{.textual path="docs/examples/tutorial/stopwatch04.py" title="stopwatch04.py" press="tab,tab,tab,_,enter,_,_,_"} ``` @@ -416,7 +416,7 @@ This code supplies missing features and makes our app useful. We've made the fol - We call the method on `TimeDisplay` that matches the pressed button. - We add the `"started"` class when the Stopwatch is started (`self.add_class("started")`), and remove it (`self.remove_class("started")`) when it is stopped. This will update the Stopwatch visuals via CSS. -If you run stopwatch06.py you will be able to use the stopwatches independently. +If you run `stopwatch06.py` you will be able to use the stopwatches independently. ```{.textual path="docs/examples/tutorial/stopwatch06.py" title="stopwatch06.py" press="tab,enter,_,_,tab,enter,_,tab"} ``` @@ -451,6 +451,6 @@ If you run `stopwatch.py` now you can add a new stopwatch with the ++a++ key and ## What next? -Congratulations on building your first Textual application! This tutorial has covered a lot of ground. If you are the type that prefers to learn a framework by coding, feel free. You could tweak stopwatch.py or look through the examples. +Congratulations on building your first Textual application! This tutorial has covered a lot of ground. If you are the type that prefers to learn a framework by coding, feel free. You could tweak `stopwatch.py` or look through the examples. Read the guide for the full details on how to build sophisticated TUI applications with Textual. From 7676a6cf4c8fade5237e96758482245946fd52bc Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:45:54 +0100 Subject: [PATCH 17/89] Trailing whitespace cleanup --- docs/guide/devtools.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/guide/devtools.md b/docs/guide/devtools.md index fa835bba3..9b60dbd4c 100644 --- a/docs/guide/devtools.md +++ b/docs/guide/devtools.md @@ -3,7 +3,7 @@ !!! note inline end If you don't have the `textual` command on your path, you may have forgotten so install with the `dev` switch. - + See [getting started](../getting_started.md#installation) for details. Textual comes with a command line application of the same name. The `textual` command is a super useful tool that will help you to build apps. @@ -44,7 +44,7 @@ textual run --dev my_app.py One of the the features of *dev* mode is live editing of CSS files: any changes to your CSS will be reflected in the terminal a few milliseconds later. -This is a great feature for iterating on your app's look and feel. Open the CSS in your editor and have your app running in a terminal. Edits to your CSS will appear almost immediately after you save. +This is a great feature for iterating on your app's look and feel. Open the CSS in your editor and have your app running in a terminal. Edits to your CSS will appear almost immediately after you save. ## Console @@ -120,4 +120,3 @@ if __name__ == "__main__": LogApp.run() ``` - From ceb531e5354b3f5c2d4bf1b0083ab0717e79d361 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 14:46:39 +0100 Subject: [PATCH 18/89] Add code markup to the mention of a class name --- docs/guide/devtools.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/devtools.md b/docs/guide/devtools.md index 9b60dbd4c..970b8f768 100644 --- a/docs/guide/devtools.md +++ b/docs/guide/devtools.md @@ -23,7 +23,7 @@ You can run Textual apps with the `run` subcommand. If you supply a path to a Py textual run my_app.py ``` -The `run` sub-command assumes you have an App instance called `app` in the global scope of your Python file. If the application is called something different, you can specify it with a colon following the filename: +The `run` sub-command assumes you have an `App` instance called `app` in the global scope of your Python file. If the application is called something different, you can specify it with a colon following the filename: ```bash textual run my_app.py:alternative_app From 4a6e4ff02589ddb85f93b24c07d5ba67d913fb5a Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 15:26:54 +0100 Subject: [PATCH 19/89] Reword the details of how `textual run` finds an app It seems the docs are lagging behind the code here, so this commit attempts to update them so they're more in line with how `textual run` works. --- docs/guide/devtools.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/devtools.md b/docs/guide/devtools.md index 970b8f768..316471eba 100644 --- a/docs/guide/devtools.md +++ b/docs/guide/devtools.md @@ -23,7 +23,7 @@ You can run Textual apps with the `run` subcommand. If you supply a path to a Py textual run my_app.py ``` -The `run` sub-command assumes you have an `App` instance called `app` in the global scope of your Python file. If the application is called something different, you can specify it with a colon following the filename: +The `run` sub-command will look to see if you have an `App` instance called `app` in the global scope of your Python file and will use that if it does. If not it will then look to see if there is a class that inherits from `App` and it will create and `run` an instance of that. Finally, you can specify the application instance to run with a colon following the filename: ```bash textual run my_app.py:alternative_app From 25fcf26a30b79a1920094eeecf2ead3f8ff551f8 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 15:31:34 +0100 Subject: [PATCH 20/89] Add code markup to the mention of a class names --- docs/guide/devtools.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/devtools.md b/docs/guide/devtools.md index 316471eba..2809446a7 100644 --- a/docs/guide/devtools.md +++ b/docs/guide/devtools.md @@ -103,7 +103,7 @@ log("[bold red]DANGER![/] We're having too much fun") ### Log method -There's a convenient shortcut to `log` available on the App and Widget objects. This is useful in event handlers. Here's an example: +There's a convenient shortcut to `log` available on the `App` and `Widget` objects. This is useful in event handlers. Here's an example: ```python from textual.app import App From e736611b55f5deedfe1f77ebddf95c846cbc28fd Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 15:34:10 +0100 Subject: [PATCH 21/89] Remove trailing whitespace --- docs/guide/app.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/app.md b/docs/guide/app.md index 1689895ef..4cdc653e6 100644 --- a/docs/guide/app.md +++ b/docs/guide/app.md @@ -76,7 +76,7 @@ Textual knows to *await* your event handlers if they are coroutines (i.e. prefix !!! tip For a friendly introduction to async programming in Python, see FastAPI's [concurrent burgers](https://fastapi.tiangolo.com/async/) article. - + ## Widgets @@ -172,7 +172,7 @@ When `"question02.py"` runs it will load `"question02.css"` and update the app a ### Classvar CSS -While external CSS files are recommended for most applications, and enable some cool features like *live editing*, you can also specify the CSS directly within the Python code. +While external CSS files are recommended for most applications, and enable some cool features like *live editing*, you can also specify the CSS directly within the Python code. To do this set a `CSS` class variable on the app to a string containing your CSS. From da49d19cb70cc9596254aa94eeaa7db6987d6acb Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 15:40:03 +0100 Subject: [PATCH 22/89] s/fledge/fledged/ --- docs/guide/app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/app.md b/docs/guide/app.md index 4cdc653e6..f1585a5a3 100644 --- a/docs/guide/app.md +++ b/docs/guide/app.md @@ -82,7 +82,7 @@ Textual knows to *await* your event handlers if they are coroutines (i.e. prefix Widgets are self-contained components responsible for generating the output for a portion of the screen. Widgets respond to events in much the same way as the App. Most apps that do anything interesting will contain at least one (and probably many) widgets which together form a User Interface. -Widgets can be as simple as a piece of text, a button, or a fully-fledge component like a text editor or file browser (which may contain widgets of their own). +Widgets can be as simple as a piece of text, a button, or a fully-fledged component like a text editor or file browser (which may contain widgets of their own). ### Composing From 4569a77d54ee5de50871528a786b9ea2140b1086 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 15:40:55 +0100 Subject: [PATCH 23/89] Add code markup to the mention of a class name --- docs/guide/app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/app.md b/docs/guide/app.md index f1585a5a3..1e8b5bff7 100644 --- a/docs/guide/app.md +++ b/docs/guide/app.md @@ -86,7 +86,7 @@ Widgets can be as simple as a piece of text, a button, or a fully-fledged compon ### Composing -To add widgets to your app implement a [`compose()`][textual.app.App.compose] method which should return an iterable of Widget instances. A list would work, but it is convenient to yield widgets, making the method a *generator*. +To add widgets to your app implement a [`compose()`][textual.app.App.compose] method which should return an iterable of `Widget` instances. A list would work, but it is convenient to yield widgets, making the method a *generator*. The following example imports a builtin Welcome widget and yields it from `App.compose()`. From ffbccd5d5d107f123b8910d087388a721668e1a1 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 15:42:01 +0100 Subject: [PATCH 24/89] Add code markup to the mention of class names --- docs/guide/app.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guide/app.md b/docs/guide/app.md index 1e8b5bff7..3ed44fae2 100644 --- a/docs/guide/app.md +++ b/docs/guide/app.md @@ -88,18 +88,18 @@ Widgets can be as simple as a piece of text, a button, or a fully-fledged compon To add widgets to your app implement a [`compose()`][textual.app.App.compose] method which should return an iterable of `Widget` instances. A list would work, but it is convenient to yield widgets, making the method a *generator*. -The following example imports a builtin Welcome widget and yields it from `App.compose()`. +The following example imports a builtin `Welcome` widget and yields it from `App.compose()`. ```python title="widgets01.py" --8<-- "docs/examples/app/widgets01.py" ``` -When you run this code, Textual will *mount* the Welcome widget which contains Markdown content and a button: +When you run this code, Textual will *mount* the `Welcome` widget which contains Markdown content and a button: ```{.textual path="docs/examples/app/widgets01.py"} ``` -Notice the `on_button_pressed` method which handles the [Button.Pressed][textual.widgets.Button] event sent by a button contained in the Welcome widget. The handler calls [App.exit()][textual.app.App.exit] to exit the app. +Notice the `on_button_pressed` method which handles the [Button.Pressed][textual.widgets.Button] event sent by a button contained in the `Welcome` widget. The handler calls [App.exit()][textual.app.App.exit] to exit the app. ### Mounting From c4a43c3f527a61e78c4cff2c32e6e171ff610fd3 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 15:44:46 +0100 Subject: [PATCH 25/89] s/Mypy/mypy/ --- docs/guide/app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/app.md b/docs/guide/app.md index 3ed44fae2..9cea67855 100644 --- a/docs/guide/app.md +++ b/docs/guide/app.md @@ -141,7 +141,7 @@ You may have noticed that we subclassed `App[str]` rather than the usual `App`. --8<-- "docs/examples/app/question01.py" ``` -The addition of `[str]` tells Mypy that `run()` is expected to return a string. It may also return `None` if [App.exit()][textual.app.App.exit] is called without a return value, so the return type of `run` will be `str | None`. Replace the `str` in `[str]` with the type of the value you intend to call the exit method with. +The addition of `[str]` tells mypy that `run()` is expected to return a string. It may also return `None` if [App.exit()][textual.app.App.exit] is called without a return value, so the return type of `run` will be `str | None`. Replace the `str` in `[str]` with the type of the value you intend to call the exit method with. !!! note From 7182c7981419bbf0712440dbef9b298722f218c1 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 15:46:17 +0100 Subject: [PATCH 26/89] Lets to let's --- docs/guide/app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/app.md b/docs/guide/app.md index 9cea67855..14e5c79cb 100644 --- a/docs/guide/app.md +++ b/docs/guide/app.md @@ -151,7 +151,7 @@ The addition of `[str]` tells mypy that `run()` is expected to return a string. Textual apps can reference [CSS](CSS.md) files which define how your app and widgets will look, while keeping your Python code free of display related code (which tends to be messy). -The chapter on [Textual CSS](CSS.md) describes how to use CSS in detail. For now lets look at how your app references external CSS files. +The chapter on [Textual CSS](CSS.md) describes how to use CSS in detail. For now let's look at how your app references external CSS files. The following example enables loading of CSS by adding a `CSS_PATH` class variable: From 31a1ebbe8fd1b17d32b10ea2c2f124d6d3981430 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 16:36:30 +0100 Subject: [PATCH 27/89] s/you/your/ --- docs/guide/app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/app.md b/docs/guide/app.md index 14e5c79cb..3f8b3dd46 100644 --- a/docs/guide/app.md +++ b/docs/guide/app.md @@ -184,4 +184,4 @@ Here's the question app with classvar CSS: ## What's next -In the following chapter we will learn more about how to apply styles to you widgets and app. +In the following chapter we will learn more about how to apply styles to your widgets and app. From 8b45cd5324803fb481d2a2be24f3dbf8238e5426 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 21:49:46 +0100 Subject: [PATCH 28/89] Remove trailing whitespace --- docs/guide/styles.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/guide/styles.md b/docs/guide/styles.md index ac7a32e79..c8269560d 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -88,7 +88,7 @@ There are a few ways you can set alpha on a color in Textual. - You can set the alpha value of a color by adding a fourth digit or pair of digits to a hex color. The extra digits form an alpha component which ranges from 0 for completely transparent to 255 (completely opaque). Any value between 0 and 255 will be translucent. For example `"#9932CC7f"` is a dark orchid which is roughly 50% translucent. - You can also set alpha with the `rgba` format, which is identical to `rgb` with the additional of a fourth value that should be between 0 and 1, where 0 is invisible and 1 is opaque. For example `"rgba(192,78,96,0.5)"`. -- You can add the `a` parameter on a [Color][textual.color.Color] object. For example `Color(192, 78, 96, a=0.5)` creates a translucent dark orchid. +- You can add the `a` parameter on a [Color][textual.color.Color] object. For example `Color(192, 78, 96, a=0.5)` creates a translucent dark orchid. The following examples shows what happens when you set alpha on background colors: @@ -96,7 +96,7 @@ The following examples shows what happens when you set alpha on background color --8<-- "docs/examples/guide/styles/colors02.py" ``` -Notice that an alpha of 0.1 the background almost matches the screen, but at 1.0 it is a solid color. +Notice that an alpha of 0.1 the background almost matches the screen, but at 1.0 it is a solid color. ```{.textual path="docs/examples/guide/styles/colors02.py"} ``` @@ -110,7 +110,7 @@ Widgets occupy a rectangular region of the screen, which may be as small as a si The following styles influence the dimensions of a widget. - [width](../styles/width.md) and [height](../styles/width.md) define the size of the widget. -- [padding](../styles/padding.md) adds optional space around the content area. +- [padding](../styles/padding.md) adds optional space around the content area. - [border](../styles/border.md) draws an optional rectangular border around the padding and the content area. Additionally, the [margin](../styles/margin.md) style adds space around a widget's border, which isn't technically part of the widget, but provides visual separation between widgets. @@ -235,7 +235,7 @@ Compare the output of this example to the previous example: You can also set padding to a tuple of *four* values which applies padding to each edge individually. The first value is the padding for the top of the widget, followed by the right of the widget, then bottom, then left. -### Border +### Border The [border](../styles/border.md) style draws a border around a widget. To add a border set `styles.border` to a tuple of two values. The first value is the border type, which should be a string. The second value is the border color which will accept any value that works with [color](../styles/color.md) and [background](../styles/background.md). @@ -301,7 +301,7 @@ The second widget sets `box_sizing` to `"content-box"`. --8<-- "docs/examples/guide/styles/box_sizing01.py" ``` -The padding and border of the first widget is subtracted from the height leaving only 2 lines in the content area. The second widget also has a height of 6, but the padding and border adds additional height so that the content area remains 6 lines. +The padding and border of the first widget is subtracted from the height leaving only 2 lines in the content area. The second widget also has a height of 6, but the padding and border adds additional height so that the content area remains 6 lines. ```{.textual path="docs/examples/guide/styles/box_sizing01.py"} ``` From bd21a255ad2032db4edbeb61b392364b851a9227 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 21:53:16 +0100 Subject: [PATCH 29/89] Add missing "we" --- docs/guide/styles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/styles.md b/docs/guide/styles.md index c8269560d..0e0840b6c 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -1,6 +1,6 @@ # Styles -In this chapter will explore how you can apply styles to your application to create beautiful user interfaces. +In this chapter we will explore how you can apply styles to your application to create beautiful user interfaces. ## Styles object From 279b043c8188a59a16cf8b175866777a1f42696d Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 21:55:49 +0100 Subject: [PATCH 30/89] Add missing plural --- docs/guide/styles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/styles.md b/docs/guide/styles.md index 0e0840b6c..191e333af 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -48,7 +48,7 @@ Note how the combined height of the widget is three rows in the terminal. This i ## Colors -There are a number of style attribute which accept colors. The most commonly used are [color](../styles/color.md) which sets the default color of text on a widget, and [background](..styles/background/md) which sets the background color (beneath the text). +There are a number of style attributes which accept colors. The most commonly used are [color](../styles/color.md) which sets the default color of text on a widget, and [background](..styles/background/md) which sets the background color (beneath the text). You can set a color value to one of a number of pre-defined color constants, such as "crimson", "lime", and "palegreen". You can find a full list in the [Color reference](../reference/color.md#textual.color--named-colors). From 19c29bdb11e68ef2243c435762bb91c462839efd Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 21:57:08 +0100 Subject: [PATCH 31/89] Add code markup to string constants Elsewhere in the document colour names as strings have been marked up as text, so this is in keeping with that. --- docs/guide/styles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/styles.md b/docs/guide/styles.md index 191e333af..f8772ee09 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -50,7 +50,7 @@ Note how the combined height of the widget is three rows in the terminal. This i There are a number of style attributes which accept colors. The most commonly used are [color](../styles/color.md) which sets the default color of text on a widget, and [background](..styles/background/md) which sets the background color (beneath the text). -You can set a color value to one of a number of pre-defined color constants, such as "crimson", "lime", and "palegreen". You can find a full list in the [Color reference](../reference/color.md#textual.color--named-colors). +You can set a color value to one of a number of pre-defined color constants, such as `"crimson"`, `"lime"`, and `"palegreen"`. You can find a full list in the [Color reference](../reference/color.md#textual.color--named-colors). Here's how you would set the screen background to lime: From bfed4a6bf9ed8d55aafde98300ae9f9cc5e9984f Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 22:00:17 +0100 Subject: [PATCH 32/89] Fix the mention of an example to be singular --- docs/guide/styles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/styles.md b/docs/guide/styles.md index f8772ee09..8720cba9a 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -90,7 +90,7 @@ There are a few ways you can set alpha on a color in Textual. - You can also set alpha with the `rgba` format, which is identical to `rgb` with the additional of a fourth value that should be between 0 and 1, where 0 is invisible and 1 is opaque. For example `"rgba(192,78,96,0.5)"`. - You can add the `a` parameter on a [Color][textual.color.Color] object. For example `Color(192, 78, 96, a=0.5)` creates a translucent dark orchid. -The following examples shows what happens when you set alpha on background colors: +The following example shows what happens when you set alpha on background colors: ```python title="colors01.py" hl_lines="12-15" --8<-- "docs/examples/guide/styles/colors02.py" From c37c5569d7599e8e96dab19a6fe93c9c351be138 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 22:01:16 +0100 Subject: [PATCH 33/89] Add what appears to be a missing "at" --- docs/guide/styles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/styles.md b/docs/guide/styles.md index 8720cba9a..3f4ca7948 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -96,7 +96,7 @@ The following example shows what happens when you set alpha on background colors --8<-- "docs/examples/guide/styles/colors02.py" ``` -Notice that an alpha of 0.1 the background almost matches the screen, but at 1.0 it is a solid color. +Notice that at an alpha of 0.1 the background almost matches the screen, but at 1.0 it is a solid color. ```{.textual path="docs/examples/guide/styles/colors02.py"} ``` From e583d21165005b0c0aa15f143beccda7fb59fbfc Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 22:10:46 +0100 Subject: [PATCH 34/89] it's -> its --- docs/guide/styles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/styles.md b/docs/guide/styles.md index 3f4ca7948..7b868f86a 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -138,7 +138,7 @@ Note how the text wraps in the widget, and is cropped because it doesn't fit in #### Auto dimensions -In practice, we generally want the size of a widget to adapt to it's content, which we can do by setting a dimension to `"auto"`. +In practice, we generally want the size of a widget to adapt to its content, which we can do by setting a dimension to `"auto"`. Let's set the height to auto and see what happens. From e280719816a0d56aa70e8ebd024133afb1625382 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 13 Oct 2022 22:14:14 +0100 Subject: [PATCH 35/89] Singular style --- docs/guide/styles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/styles.md b/docs/guide/styles.md index 7b868f86a..95dff6435 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -195,7 +195,7 @@ Let's look at an example. We will create two widgets, one with a height of `"2fr --8<-- "docs/examples/guide/styles/dimensions04.py" ``` -The total `fr` units for height is 3. The first widget will have a screen height of two thirds because its height style is set to `2fr`. The second widget's height styles is `1fr` so its screen height will be one third. Here's what that looks like. +The total `fr` units for height is 3. The first widget will have a screen height of two thirds because its height style is set to `2fr`. The second widget's height style is `1fr` so its screen height will be one third. Here's what that looks like. ```{.textual path="docs/examples/guide/styles/dimensions04.py"} ``` From e46c51d61c21d6cf51d6e3e6f04e3ae66e419574 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 08:41:02 +0100 Subject: [PATCH 36/89] Fix whitespace Includes pre-commit hook changes. --- docs/guide/CSS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/guide/CSS.md b/docs/guide/CSS.md index bfac0d098..d7af28995 100644 --- a/docs/guide/CSS.md +++ b/docs/guide/CSS.md @@ -82,7 +82,7 @@ With the above example, the DOM will look like the following: This doesn't look much like a tree yet. Let's add a header and a footer to this application, which will create more _branches_ of the tree: === "dom2.py" - + ```python hl_lines="7 8" --8<-- "docs/examples/guide/dom2.py" ``` @@ -427,4 +427,3 @@ Variables can refer to other variables. Let's say we define a variable `$success: lime;`. Our `$border` variable could then be updated to `$border: wide $success;`, which will be translated to `$border: wide lime;`. - From d324f1cd56c092de7ee6471c97b4201cbd246f05 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 08:42:11 +0100 Subject: [PATCH 37/89] Add a missing word --- docs/guide/CSS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/CSS.md b/docs/guide/CSS.md index d7af28995..49508cc48 100644 --- a/docs/guide/CSS.md +++ b/docs/guide/CSS.md @@ -105,7 +105,7 @@ With a header and a footer widget the DOM looks the this: Both Header and Footer are children of the Screen object. -To further explore the DOM, we're going to build a simple dialog with a question and two buttons. To do this we're going import and use a few more builtin widgets: +To further explore the DOM, we're going to build a simple dialog with a question and two buttons. To do this we're going to import and use a few more builtin widgets: - `textual.layout.Container` For our top-level dialog. - `textual.layout.Horizontal` To arrange widgets left to right. From 34e5d53cb3b66314a555917aa102be395d5740f7 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 08:48:06 +0100 Subject: [PATCH 38/89] Correct what is imported in an example The main code in the example creates a `Button` from a `Static`, but the import is importing a `Widget`. This commit makes the example code make more sense. --- docs/guide/CSS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/CSS.md b/docs/guide/CSS.md index 49508cc48..b1b2c9f92 100644 --- a/docs/guide/CSS.md +++ b/docs/guide/CSS.md @@ -187,7 +187,7 @@ Let's look at the selectors supported by Textual CSS. The _type_ selector matches the name of the (Python) class. For example, the following widget can be matched with a `Button` selector: ```python -from textual.widgets import Widget +from textual.widgets import Static class Button(Static): pass From ad5fb455c131d569aee9cbb6063e24358e0caf51 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 08:52:29 +0100 Subject: [PATCH 39/89] it's -> its --- docs/guide/CSS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/CSS.md b/docs/guide/CSS.md index b1b2c9f92..7e6ea0f86 100644 --- a/docs/guide/CSS.md +++ b/docs/guide/CSS.md @@ -218,7 +218,7 @@ You may have noticed that the `border` rule exists in both Static and Button. Wh ### ID selector -Every Widget can have a single `id` attribute, which is set via the constructor. The ID should be unique to it's container. +Every Widget can have a single `id` attribute, which is set via the constructor. The ID should be unique to its container. Here's an example of a widget with an ID: From 185a817a302c57bb1b15a3c9b5b64a7c5f9786e7 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 08:56:59 +0100 Subject: [PATCH 40/89] Improve the description of has_class --- docs/guide/CSS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/CSS.md b/docs/guide/CSS.md index 7e6ea0f86..9c0332bfc 100644 --- a/docs/guide/CSS.md +++ b/docs/guide/CSS.md @@ -280,7 +280,7 @@ Unlike the `id` attribute, a widget's classes can be changed after the widget wa - [add_class()][textual.dom.DOMNode.add_class] Adds one or more classes to a widget. - [remove_class()][textual.dom.DOMNode.remove_class] Removes class name(s) from a widget. - [toggle_class()][textual.dom.DOMNode.toggle_class] Removes a class name if it is present, or adds the name if it's not already present. -- [has_class()][textual.dom.DOMNode.has_class] Checks if a class(es) is set on a widget. +- [has_class()][textual.dom.DOMNode.has_class] Checks if one or more classes are set on a widget. - [classes][textual.dom.DOMNode.classes] Is a frozen set of the class(es) set on a widget. From c10e172151d3e8ec508cf1fee7666c8b9d13e2c9 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 09:00:52 +0100 Subject: [PATCH 41/89] Markup pseudo-selector as code Other similar items in the surrounding text use code markup, so this feels like it should do too. --- docs/guide/CSS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/CSS.md b/docs/guide/CSS.md index 9c0332bfc..4ca7785c3 100644 --- a/docs/guide/CSS.md +++ b/docs/guide/CSS.md @@ -369,7 +369,7 @@ It is possible that several selectors match a given widget. If the same style is - The selector with the most IDs wins. For instance `#next` beats `.button` and `#dialog #next` beats `#next`. If the selectors have the same number of IDs then move to the next rule. -- The selector with the most class names wins. For instance `.button.success` beats `.success`. For the purposes of specificity, pseudo classes are treated the same as regular class names, so ".button:hover" counts as _2_ class names. If the selectors have the same number of class names then move to the next rule. +- The selector with the most class names wins. For instance `.button.success` beats `.success`. For the purposes of specificity, pseudo classes are treated the same as regular class names, so `.button:hover` counts as _2_ class names. If the selectors have the same number of class names then move to the next rule. - The selector with the most types wins. For instance `Container Button` beats `Button`. From 26dc103f6df6f25df637cbb3066294660cb5d2f3 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 09:27:48 +0100 Subject: [PATCH 42/89] Add password as a Input keyword argument Via https://github.com/Textualize/textual/discussions/905 -- I feel it's reasonable to expect the password reactive to be set via a keyword argument of the same name -- many folk will likely come at this expecting some similarity to how similar elements work on the web. --- src/textual/widgets/_input.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/textual/widgets/_input.py b/src/textual/widgets/_input.py index 616844bf2..e5e72ab9a 100644 --- a/src/textual/widgets/_input.py +++ b/src/textual/widgets/_input.py @@ -107,6 +107,7 @@ class Input(Widget, can_focus=True): value: str = "", placeholder: str = "", highlighter: Highlighter | None = None, + password: bool = False, name: str | None = None, id: str | None = None, classes: str | None = None, @@ -115,6 +116,7 @@ class Input(Widget, can_focus=True): self.value = value self.placeholder = placeholder self.highlighter = highlighter + self.password = password def _position_to_cell(self, position: int) -> int: """Convert an index within the value to cell position.""" From 7bad3c37ce861825595bdcd532893f758f8932b2 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 14:38:29 +0100 Subject: [PATCH 43/89] place -> placed --- docs/guide/layout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/layout.md b/docs/guide/layout.md index 76f21be4c..b48925365 100644 --- a/docs/guide/layout.md +++ b/docs/guide/layout.md @@ -468,7 +468,7 @@ If we wished for the sidebar to appear below the header, it'd simply be a case o ## Layers -Textual has a concept of _layers_ which gives you finely grained control over the order widgets are place. +Textual has a concept of _layers_ which gives you finely grained control over the order widgets are placed. When drawing widgets, Textual will first draw on _lower_ layers, working its way up to higher layers. As such, widgets on higher layers will be drawn on top of those on lower layers. From 1354270e6c97d107b0a96d887d4dedd024c334df Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 14:42:17 +0100 Subject: [PATCH 44/89] Make the final paragraph flow a wee bit better --- docs/guide/layout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/layout.md b/docs/guide/layout.md index b48925365..495cb6f86 100644 --- a/docs/guide/layout.md +++ b/docs/guide/layout.md @@ -548,4 +548,4 @@ The example below shows how an advanced layout can be built by combining the var --8<-- "docs/examples/guide/layout/combining_layouts.css" ``` -Textual layouts make it easy design build real-life applications with relatively little code. +Textual layouts make it easy to design and build real-life applications with relatively little code. From 8c5749898fb577fd9fae4974184c096756e377c8 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 18:16:30 +0100 Subject: [PATCH 45/89] Clean up trailing whitespace --- docs/guide/events.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guide/events.md b/docs/guide/events.md index d5fb2fe69..f11289442 100644 --- a/docs/guide/events.md +++ b/docs/guide/events.md @@ -12,7 +12,7 @@ More on that later, but for now keep in mind that events are also messages, and Every [App][textual.app.App] and [Widget][textual.widget.Widget] object contains a *message queue*. You can think of a message queue as orders at a restaurant. The chef takes an order and makes the dish. Orders that arrive while the chef is cooking are placed in a line. When the chef has finished a dish they pick up the next order in the line. -Textual processes messages in the same way. Messages are picked off a queue and processed (cooked) by a handler method. This guarantees messages and events are processed even if your code can not handle them right way. +Textual processes messages in the same way. Messages are picked off a queue and processed (cooked) by a handler method. This guarantees messages and events are processed even if your code can not handle them right way. This processing of messages is done within an asyncio Task which is started when you mount the widget. The task monitors a queue for new messages and dispatches them to the appropriate handler when they arrive. @@ -20,7 +20,7 @@ This processing of messages is done within an asyncio Task which is started when The FastAPI docs have an [excellent introduction](https://fastapi.tiangolo.com/async/) to Python async programming. -By way of an example, let's consider what happens if you were to type "Text" in to a `Input` widget. When you hit the ++t++ key, Textual creates a [key][textual.events.Key] event and sends it to the widget's message queue. Ditto for ++e++, ++x++, and ++t++. +By way of an example, let's consider what happens if you were to type "Text" in to a `Input` widget. When you hit the ++t++ key, Textual creates a [key][textual.events.Key] event and sends it to the widget's message queue. Ditto for ++e++, ++x++, and ++t++. The widget's task will pick the first message from the queue (a key event for the ++t++ key) and call the `on_key` method with the event as the first argument. In other words it will call `Input.on_key(event)`, which updates the display to show the new letter. @@ -177,7 +177,7 @@ Let's look at an example which looks up word definitions from an [api](https://d ``` === "dictionary.css" - ```python title="dictionary.css" + ```python title="dictionary.css" --8<-- "docs/examples/events/dictionary.css" ``` From 72c99e69fb189e994dc743d257cc86b0d0383f16 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 18:35:18 +0100 Subject: [PATCH 46/89] it's -> its --- docs/guide/events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/events.md b/docs/guide/events.md index f11289442..da58de8b6 100644 --- a/docs/guide/events.md +++ b/docs/guide/events.md @@ -69,7 +69,7 @@ After Textual calls `Button.on_key` the event _bubbles_ to the button's parent a --8<-- "docs/images/events/bubble2.excalidraw.svg"
-As before, the event bubbles to it's parent (the App class). +As before, the event bubbles to its parent (the App class).
--8<-- "docs/images/events/bubble3.excalidraw.svg" From acc5e72775d5f53b3717ca4e409539bfd9a2ebfc Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 18:46:43 +0100 Subject: [PATCH 47/89] Add 'a' --- docs/guide/events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/events.md b/docs/guide/events.md index da58de8b6..9cdfb3259 100644 --- a/docs/guide/events.md +++ b/docs/guide/events.md @@ -186,4 +186,4 @@ Let's look at an example which looks up word definitions from an [api](https://d ```{.textual path="docs/examples/events/dictionary.py" press="tab,t,e,x,t,_,_,_,_,_,_,_,_,_,_,_"} ``` -Note the highlighted line in the above code which calls `asyncio.create_task` to run coroutine in the background. Without this you would find typing in to the text box to be unresponsive. +Note the highlighted line in the above code which calls `asyncio.create_task` to run a coroutine in the background. Without this you would find typing in to the text box to be unresponsive. From 248b12c23458387cd81d9c9296458e1ac820b1d1 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Fri, 14 Oct 2022 18:55:13 +0100 Subject: [PATCH 48/89] Update docs/guide/devtools.md Co-authored-by: Will McGugan --- docs/guide/devtools.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/guide/devtools.md b/docs/guide/devtools.md index 2809446a7..887315ebc 100644 --- a/docs/guide/devtools.md +++ b/docs/guide/devtools.md @@ -23,7 +23,9 @@ You can run Textual apps with the `run` subcommand. If you supply a path to a Py textual run my_app.py ``` -The `run` sub-command will look to see if you have an `App` instance called `app` in the global scope of your Python file and will use that if it does. If not it will then look to see if there is a class that inherits from `App` and it will create and `run` an instance of that. Finally, you can specify the application instance to run with a colon following the filename: +The `run` sub-command will first look for a `App` instance called `app` in the global scope of your Python file. If there is no `app`, it will create an instance of the first `App` class it finds and run that. + +Alternatively, you can add the name of an `App` instance or class after a colon to run a specific app in the Python file. Here's an example: ```bash textual run my_app.py:alternative_app From c1d21d29bd7d65a4f1b693e0da52a84d1383884a Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 08:18:04 +0100 Subject: [PATCH 49/89] in -> is --- docs/guide/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/input.md b/docs/guide/input.md index 7c0ac9237..457095ba4 100644 --- a/docs/guide/input.md +++ b/docs/guide/input.md @@ -10,7 +10,7 @@ This chapter will discuss how to make your app respond to input in the form of k ## Keyboard input -The most fundamental way to receive input in via [Key](./events/key) events. Let's write an app to show key events as you type. +The most fundamental way to receive input is via [Key](./events/key) events. Let's write an app to show key events as you type. === "key01.py" From 58ad9cd2082880023ec76dc4b2235063eb750c88 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 08:20:13 +0100 Subject: [PATCH 50/89] Capitalise start of sentence --- docs/guide/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/input.md b/docs/guide/input.md index 457095ba4..ffa5012a5 100644 --- a/docs/guide/input.md +++ b/docs/guide/input.md @@ -23,7 +23,7 @@ The most fundamental way to receive input is via [Key](./events/key) events. Let ```{.textual path="docs/examples/guide/input/key01.py", press="T,e,x,t,u,a,l,!,_"} ``` -Note the key event handler on the app which logs all key events. if you press any key it will show up on the screen. +Note the key event handler on the app which logs all key events. If you press any key it will show up on the screen. ### Attributes From 4ec8c0016aea025f6e341d870a40944c493f8e06 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 08:21:15 +0100 Subject: [PATCH 51/89] Add 'a' --- docs/guide/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/input.md b/docs/guide/input.md index ffa5012a5..a795600e5 100644 --- a/docs/guide/input.md +++ b/docs/guide/input.md @@ -29,7 +29,7 @@ Note the key event handler on the app which logs all key events. If you press an There are two main attributes on a key event. The `key` attribute is the _name_ of the key which may be a single character, or a longer identifier. Textual ensures that the `key` attribute could always be used in a method name. -Key events also contain a `char` attribute which contains single character if it is printable, or ``None`` if it is not printable (like a function key which has no corresponding character). +Key events also contain a `char` attribute which contains a single character if it is printable, or ``None`` if it is not printable (like a function key which has no corresponding character). To illustrate the difference between `key` and `char`, try `key01.py` with the space key. You should see something like the following: From e127ee6dc54025f82e499089caa7900bf303adba Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 08:31:05 +0100 Subject: [PATCH 52/89] Add code markup to a class name --- docs/guide/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/input.md b/docs/guide/input.md index a795600e5..70f5059fa 100644 --- a/docs/guide/input.md +++ b/docs/guide/input.md @@ -78,7 +78,7 @@ The following example shows how focus works in practice. ```{.textual path="docs/examples/guide/input/key03.py", press="tab,H,e,l,l,o,tab,W,o,r,l,d,!,_"} ``` -The app splits the screen in to quarters, with a TextLog widget in each quarter. If you click any of the text logs, you should see that it is highlighted to show that thw widget has focus. Key events will be sent to the focused widget only. +The app splits the screen in to quarters, with a `TextLog` widget in each quarter. If you click any of the text logs, you should see that it is highlighted to show that thw widget has focus. Key events will be sent to the focused widget only. !!! tip From cf5cc9832f9f236d1a1a8755b7ff92f7a7b3e850 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 08:34:30 +0100 Subject: [PATCH 53/89] Try and finish what looked like an unfinished line I'm not 100% sure if it makes sense to say "pressed" or "held down" here; I'm going with "held down" as pressed sort of suggests something a bit different. Mostly this change here is to highlight that this thought seems unfinished. --- docs/guide/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/input.md b/docs/guide/input.md index 70f5059fa..5d24d7445 100644 --- a/docs/guide/input.md +++ b/docs/guide/input.md @@ -156,7 +156,7 @@ Coordinates may be relative to the screen, so `(0, 0)` would be the top left of ### Mouse movements -When you move the mouse cursor over a widget it will receive [MouseMove](../events/mouse_move.md) events which contain the coordinate of the mouse and information about what modified keys (++ctrl++, ++shift++ etc). +When you move the mouse cursor over a widget it will receive [MouseMove](../events/mouse_move.md) events which contain the coordinate of the mouse and information about what modified keys (++ctrl++, ++shift++ etc) are held down. The following example shows mouse movements being used to _attach_ a widget to the mouse cursor. From 32f4f625876ba74c89b351b293a08362194ac558 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 08:37:59 +0100 Subject: [PATCH 54/89] Add 'the' before 'window' I guess 'a' could work here too. --- docs/guide/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/input.md b/docs/guide/input.md index 5d24d7445..6fc8fa911 100644 --- a/docs/guide/input.md +++ b/docs/guide/input.md @@ -200,7 +200,7 @@ If you want your app to respond to a mouse click you should prefer the Click eve ### Scroll events -Most mice have a scroll wheel which you can use to scroll window underneath the cursor. Scrollable containers in Textual will handle these automatically, but you can handle [MouseDown](../events/mouse_scroll_down.md) and [MouseUp](../events/mouse_scroll_up) if you want build your own scrolling functionality. +Most mice have a scroll wheel which you can use to scroll the window underneath the cursor. Scrollable containers in Textual will handle these automatically, but you can handle [MouseDown](../events/mouse_scroll_down.md) and [MouseUp](../events/mouse_scroll_up) if you want build your own scrolling functionality. !!! information From 079e2a304a1cbca5c8df790b4aa4307813eb9246 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 08:39:36 +0100 Subject: [PATCH 55/89] Correct the names for the mouse scroll events The links were correct, but the text for the link was wrong. --- docs/guide/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/input.md b/docs/guide/input.md index 6fc8fa911..28c134967 100644 --- a/docs/guide/input.md +++ b/docs/guide/input.md @@ -200,7 +200,7 @@ If you want your app to respond to a mouse click you should prefer the Click eve ### Scroll events -Most mice have a scroll wheel which you can use to scroll the window underneath the cursor. Scrollable containers in Textual will handle these automatically, but you can handle [MouseDown](../events/mouse_scroll_down.md) and [MouseUp](../events/mouse_scroll_up) if you want build your own scrolling functionality. +Most mice have a scroll wheel which you can use to scroll the window underneath the cursor. Scrollable containers in Textual will handle these automatically, but you can handle [MouseScrollDown](../events/mouse_scroll_down.md) and [MouseScrollUp](../events/mouse_scroll_up) if you want build your own scrolling functionality. !!! information From b6e27ac6f76d910bd98c6b38cb7d38bc538fbbc3 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 10:02:34 +0100 Subject: [PATCH 56/89] Clean trailing whitespace --- docs/guide/actions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/actions.md b/docs/guide/actions.md index 958f82a0d..b8069e326 100644 --- a/docs/guide/actions.md +++ b/docs/guide/actions.md @@ -42,7 +42,7 @@ Action strings have the following format: - The name of an action on is own will call the action method with no parameters. For example, an action string of `"bell"` will call `action_bell()`. - Actions may be followed by braces containing Python objects. For example, the action string `set_background("red")` will call `action_set_background("red")`. -- Actions may be prefixed with a _namespace_ (see below) follow by a dot. +- Actions may be prefixed with a _namespace_ (see below) follow by a dot.
--8<-- "docs/images/actions/format.excalidraw.svg" @@ -104,7 +104,7 @@ The following example defines a custom widget with its own `set_background` acti === "actions05.css" - ```sass title="actions05.css" + ```sass title="actions05.css" --8<-- "docs/examples/guide/actions/actions05.css" ``` From 9527248bc0d69b9b5bd121bad24e6b56a6ce0057 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 10:06:57 +0100 Subject: [PATCH 57/89] Remove 's' from 'strings' --- docs/guide/actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/actions.md b/docs/guide/actions.md index b8069e326..fd682cef9 100644 --- a/docs/guide/actions.md +++ b/docs/guide/actions.md @@ -50,7 +50,7 @@ Action strings have the following format: ### Parameters -If the action strings contains parameters, these must be valid Python literals. Which means you can include numbers, strings, dicts, lists etc. but you can't include variables or references to any other python symbols. +If the action string contains parameters, these must be valid Python literals. Which means you can include numbers, strings, dicts, lists etc. but you can't include variables or references to any other python symbols. Consequently `"set_background('blue')"` is a valid action string, but `"set_background(new_color)"` is not — because `new_color` is a variable and not a literal. From d7dc8d2203e86cd4c9f9378cc80cbdd196aca88e Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 10:08:24 +0100 Subject: [PATCH 58/89] Remove 's' from 'symbols' --- docs/guide/actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/actions.md b/docs/guide/actions.md index fd682cef9..3784f9140 100644 --- a/docs/guide/actions.md +++ b/docs/guide/actions.md @@ -50,7 +50,7 @@ Action strings have the following format: ### Parameters -If the action string contains parameters, these must be valid Python literals. Which means you can include numbers, strings, dicts, lists etc. but you can't include variables or references to any other python symbols. +If the action string contains parameters, these must be valid Python literals. Which means you can include numbers, strings, dicts, lists etc. but you can't include variables or references to any other python symbol. Consequently `"set_background('blue')"` is a valid action string, but `"set_background(new_color)"` is not — because `new_color` is a variable and not a literal. From 95a1b831600ffc1cc1a59d0b523e1d8f131a8929 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 10:09:37 +0100 Subject: [PATCH 59/89] Make the bell belong to the terminal --- docs/guide/actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/actions.md b/docs/guide/actions.md index 3784f9140..7a33a424e 100644 --- a/docs/guide/actions.md +++ b/docs/guide/actions.md @@ -71,7 +71,7 @@ The following example mounts simple static text with embedded action links. ```{.textual path="docs/examples/guide/actions/actions03.py"} ``` -When you click any of the links, Textual runs the `"set_background"` action to change the background to the given color and plays the terminals bell. +When you click any of the links, Textual runs the `"set_background"` action to change the background to the given color and plays the terminal's bell. ## Bindings From 614f30b301fc2e94ebad916f96fde123e9cde1dc Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 10:14:33 +0100 Subject: [PATCH 60/89] 'a' -> 'an' for SVG in docstrings An ess vee gee. --- src/textual/app.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/textual/app.py b/src/textual/app.py index 7cf010f3c..1e89de3c9 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -483,7 +483,7 @@ class App(Generic[ReturnType], DOMNode): self.dark = not self.dark def action_screenshot(self, filename: str | None, path: str = "~/") -> None: - """Save an SVG "screenshot". This action will save a SVG file containing the current contents of the screen. + """Save an SVG "screenshot". This action will save an SVG file containing the current contents of the screen. Args: filename (str | None, optional): Filename of screenshot, or None to auto-generate. Defaults to None. @@ -492,7 +492,7 @@ class App(Generic[ReturnType], DOMNode): self.save_screenshot(filename, path) def export_screenshot(self, *, title: str | None = None) -> str: - """Export a SVG screenshot of the current screen. + """Export an SVG screenshot of the current screen. Args: title (str | None, optional): The title of the exported screenshot or None @@ -519,7 +519,7 @@ class App(Generic[ReturnType], DOMNode): path: str = "./", time_format: str = "%Y-%m-%d %X %f", ) -> str: - """Save a SVG screenshot of the current screen. + """Save an SVG screenshot of the current screen. Args: filename (str | None, optional): Filename of SVG screenshot, or None to auto-generate From f8433e0ebbe93bf7b608157328352785818032a1 Mon Sep 17 00:00:00 2001 From: darrenburns Date: Sat, 15 Oct 2022 11:15:41 +0100 Subject: [PATCH 61/89] Get rid of string split key display, bug fix for not showing screen-level bindings (#910) --- sandbox/darren/just_a_box.py | 1 + src/textual/app.py | 6 +++--- src/textual/binding.py | 16 ++-------------- src/textual/widgets/_footer.py | 13 +++++-------- 4 files changed, 11 insertions(+), 25 deletions(-) diff --git a/sandbox/darren/just_a_box.py b/sandbox/darren/just_a_box.py index d4e53d178..fa2ee364d 100644 --- a/sandbox/darren/just_a_box.py +++ b/sandbox/darren/just_a_box.py @@ -14,6 +14,7 @@ class JustABox(App): key="o,f,w", action="widget_fade_out", description="opacity fade out", + key_display="o or f or w", ), ] diff --git a/src/textual/app.py b/src/textual/app.py index 7cf010f3c..b51420313 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -325,10 +325,10 @@ class App(Generic[ReturnType], DOMNode): @property def bindings(self) -> Bindings: """Get current bindings. If no widget is focused, then the app-level bindings - are returned. If a widget is focused, then any bindings present between that widget - and the App in the DOM are merged and returned.""" + are returned. If a widget is focused, then any bindings present in the active + screen and app are merged and returned.""" if self.focused is None: - return self._bindings + return Bindings.merge([self.screen._bindings, self._bindings]) else: return Bindings.merge( node._bindings for node in reversed(self.focused.ancestors) diff --git a/src/textual/binding.py b/src/textual/binding.py index 1f52a5a10..498201c76 100644 --- a/src/textual/binding.py +++ b/src/textual/binding.py @@ -47,26 +47,14 @@ class Bindings: for binding in bindings: if isinstance(binding, Binding): binding_keys = binding.key.split(",") - - # If there's a key display, split it and associate it with the keys - key_displays = ( - binding.key_display.split(",") if binding.key_display else [] - ) - if len(binding_keys) == len(key_displays): - keys_and_displays = zip(binding_keys, key_displays) - else: - keys_and_displays = [ - (key, binding.key_display) for key in binding_keys - ] - if len(binding_keys) > 1: - for key, display in keys_and_displays: + for key in binding_keys: new_binding = Binding( key=key, action=binding.action, description=binding.description, show=binding.show, - key_display=display, + key_display=binding.key_display, allow_forward=binding.allow_forward, ) yield new_binding diff --git a/src/textual/widgets/_footer.py b/src/textual/widgets/_footer.py index cd9808713..33e12375d 100644 --- a/src/textual/widgets/_footer.py +++ b/src/textual/widgets/_footer.py @@ -2,10 +2,9 @@ from __future__ import annotations from collections import defaultdict -from rich.console import RenderableType - -from rich.text import Text import rich.repr +from rich.console import RenderableType +from rich.text import Text from .. import events from ..reactive import Reactive, watch @@ -95,14 +94,12 @@ class Footer(Widget): action_to_bindings[binding.action].append(binding) for action, bindings in action_to_bindings.items(): - key_displays = [ + binding = bindings[0] + key_display = ( binding.key.upper() if binding.key_display is None else binding.key_display - for binding in bindings - ] - key_display = "ยท".join(key_displays) - binding = bindings[0] + ) hovered = self.highlight_key == binding.key key_text = Text.assemble( (f" {key_display} ", highlight_key_style if hovered else key_style), From 7f77e9a0a15cca37e0c55a9c44e407608dc09327 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 15 Oct 2022 13:10:13 +0100 Subject: [PATCH 62/89] Update docs/guide/input.md --- docs/guide/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/input.md b/docs/guide/input.md index 28c134967..f03f4e756 100644 --- a/docs/guide/input.md +++ b/docs/guide/input.md @@ -156,7 +156,7 @@ Coordinates may be relative to the screen, so `(0, 0)` would be the top left of ### Mouse movements -When you move the mouse cursor over a widget it will receive [MouseMove](../events/mouse_move.md) events which contain the coordinate of the mouse and information about what modified keys (++ctrl++, ++shift++ etc) are held down. +When you move the mouse cursor over a widget it will receive [MouseMove](../events/mouse_move.md) events which contain the coordinate of the mouse and information about what modifier keys (++ctrl++, ++shift++ etc) are held down. The following example shows mouse movements being used to _attach_ a widget to the mouse cursor. From 0a7b7dd1fdecfb7d86c66489a80ced1dc288a493 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 18:04:17 +0100 Subject: [PATCH 63/89] Remove trailing whitespace --- docs/guide/reactivity.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/guide/reactivity.md b/docs/guide/reactivity.md index 5b4cf2af7..1951eb237 100644 --- a/docs/guide/reactivity.md +++ b/docs/guide/reactivity.md @@ -33,7 +33,7 @@ The `reactive` constructor accepts a default value as the first positional argum !!! information - Textual uses Python's _descriptor protocol_ to create reactive attributes, which is the same protocol used by the builtin `property` decorator. + Textual uses Python's _descriptor protocol_ to create reactive attributes, which is the same protocol used by the builtin `property` decorator. You can get and set these attributes in the same way as if you had assigned them in a `__init__` method. For instance `self.name = "Jessica"`, `self.count += 1`, or `print(self.is_cool)`. @@ -81,7 +81,7 @@ Let's look at an example which illustrates this. In the following app, the value === "refresh01.css" - ```sass + ```sass --8<-- "docs/examples/guide/reactivity/refresh01.css" ``` @@ -121,7 +121,7 @@ The following example modifies "refresh01.py" so that the greeting has an automa --8<-- "docs/examples/guide/reactivity/refresh02.py" ``` - 1. This attribute will update the layout when changed. + 1. This attribute will update the layout when changed. === "refresh02.css" @@ -152,7 +152,7 @@ A common use for this is to restrict numbers to a given range. The following exa === "validate01.css" - ```sass + ```sass --8<-- "docs/examples/guide/reactivity/validate01.css" ``` @@ -181,7 +181,7 @@ The follow app will display any color you type in to the input. Try it with a va === "watch01.css" - ```sass + ```sass --8<-- "docs/examples/guide/reactivity/watch01.css" ``` @@ -196,7 +196,7 @@ The color is parsed in `on_input_submitted` and assigned to `self.color`. Becaus Compute methods are the final superpower offered by the `reactive` descriptor. Textual runs compute methods to calculate the value of a reactive attribute. Compute methods begin with `compute_` followed by the name of the reactive value. -You could be forgiven in thinking this sounds a lot like Python's property decorator. The difference is that Textual will cache the value of compute methods, and update them when any other reactive attribute changes. +You could be forgiven in thinking this sounds a lot like Python's property decorator. The difference is that Textual will cache the value of compute methods, and update them when any other reactive attribute changes. The following example uses a computed attribute. It displays three inputs for the each color component (red, green, and blue). If you enter numbers in to these inputs, the background color of another widget changes. @@ -211,7 +211,7 @@ The following example uses a computed attribute. It displays three inputs for th === "computed01.css" - ```sass + ```sass --8<-- "docs/examples/guide/reactivity/computed01.css" ``` From 306580ec93c34e0736ef6dab24f996f80bf61063 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 18:07:24 +0100 Subject: [PATCH 64/89] 'a' -> 'an' This one could go either way, I guess. If most folk read __init__ like I do, simply as the word "init" then this is needed; likewise if they say the underscore, on the other hand if folk tend to go with dunder-init...) I may recant this depending on the result of this: https://twitter.com/davepdotorg/status/1581331978049052672 --- docs/guide/reactivity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/reactivity.md b/docs/guide/reactivity.md index 1951eb237..075fcbf94 100644 --- a/docs/guide/reactivity.md +++ b/docs/guide/reactivity.md @@ -35,7 +35,7 @@ The `reactive` constructor accepts a default value as the first positional argum Textual uses Python's _descriptor protocol_ to create reactive attributes, which is the same protocol used by the builtin `property` decorator. -You can get and set these attributes in the same way as if you had assigned them in a `__init__` method. For instance `self.name = "Jessica"`, `self.count += 1`, or `print(self.is_cool)`. +You can get and set these attributes in the same way as if you had assigned them in an `__init__` method. For instance `self.name = "Jessica"`, `self.count += 1`, or `print(self.is_cool)`. ### Dynamic defaults From c159b434b55026e8c16ceee05e25ff517d39fcdb Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 18:18:29 +0100 Subject: [PATCH 65/89] Singular attribute to attributes If there's multiple... --- docs/guide/reactivity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/reactivity.md b/docs/guide/reactivity.md index 075fcbf94..a99998a96 100644 --- a/docs/guide/reactivity.md +++ b/docs/guide/reactivity.md @@ -69,7 +69,7 @@ The first superpower we will look at is "smart refresh". When you modify a react !!! information - If you modify multiple reactive attribute, Textual will only do a single refresh to minimize updates. + If you modify multiple reactive attributes, Textual will only do a single refresh to minimize updates. Let's look at an example which illustrates this. In the following app, the value of an input is used to update a "Hello, World!" type greeting. From 1805dd7abba27c1ba44c8bd57907a6c324f13921 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 18:23:27 +0100 Subject: [PATCH 66/89] 'follow' -> 'following' --- docs/guide/reactivity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/reactivity.md b/docs/guide/reactivity.md index a99998a96..f15039550 100644 --- a/docs/guide/reactivity.md +++ b/docs/guide/reactivity.md @@ -167,7 +167,7 @@ If you click the buttons in the above example it will show the current count. Wh Watch methods are another superpower. Textual will call watch methods when reactive attributes are modified. Watch methods begin with `watch_` followed by the name of the attribute. If the watch method accepts a positional argument, it will be called with the new assigned value. If the watch method accepts *two* positional arguments, it will be called with both the *old* value and the *new* value. -The follow app will display any color you type in to the input. Try it with a valid color in Textual CSS. For example `"darkorchid"` or `"#52de44". +The following app will display any color you type in to the input. Try it with a valid color in Textual CSS. For example `"darkorchid"` or `"#52de44". === "watch01.py" From 09fe0077edb4dbffba730884b6b296a0280810fe Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 18:23:52 +0100 Subject: [PATCH 67/89] Add missing code markup marker --- docs/guide/reactivity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/reactivity.md b/docs/guide/reactivity.md index f15039550..6001aa647 100644 --- a/docs/guide/reactivity.md +++ b/docs/guide/reactivity.md @@ -167,7 +167,7 @@ If you click the buttons in the above example it will show the current count. Wh Watch methods are another superpower. Textual will call watch methods when reactive attributes are modified. Watch methods begin with `watch_` followed by the name of the attribute. If the watch method accepts a positional argument, it will be called with the new assigned value. If the watch method accepts *two* positional arguments, it will be called with both the *old* value and the *new* value. -The following app will display any color you type in to the input. Try it with a valid color in Textual CSS. For example `"darkorchid"` or `"#52de44". +The following app will display any color you type in to the input. Try it with a valid color in Textual CSS. For example `"darkorchid"` or `"#52de44"`. === "watch01.py" From 67d722507b19d2f589590c8ba9e9bf4510a3b946 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 18:25:59 +0100 Subject: [PATCH 68/89] Remove unnecessary 'the' --- docs/guide/reactivity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/reactivity.md b/docs/guide/reactivity.md index 6001aa647..86a7d7d90 100644 --- a/docs/guide/reactivity.md +++ b/docs/guide/reactivity.md @@ -198,7 +198,7 @@ Compute methods are the final superpower offered by the `reactive` descriptor. T You could be forgiven in thinking this sounds a lot like Python's property decorator. The difference is that Textual will cache the value of compute methods, and update them when any other reactive attribute changes. -The following example uses a computed attribute. It displays three inputs for the each color component (red, green, and blue). If you enter numbers in to these inputs, the background color of another widget changes. +The following example uses a computed attribute. It displays three inputs for each color component (red, green, and blue). If you enter numbers in to these inputs, the background color of another widget changes. === "computed01.py" From da8f2d5fcb463c4d463d9919ebafb6e4ddcada6c Mon Sep 17 00:00:00 2001 From: Adam Huganir Date: Sat, 15 Oct 2022 16:34:27 -0400 Subject: [PATCH 69/89] README has 'development development' Was just reading the `About` section and caught this. Looking at the blame it looks like it used to be "web development" but was accidentally switched in the last merge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 16a5c89eb..d06a38eac 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Textual is a Python framework for creating interactive applications that run in ## About -Textual adds interactivity to [Rich](https://github.com/Textualize/rich) with a Python API inspired by modern development development. +Textual adds interactivity to [Rich](https://github.com/Textualize/rich) with a Python API inspired by modern web development. On modern terminal software (installed by default on most systems), Textual apps can use **16.7 million** colors with mouse support and smooth flicker-free animation. A powerful layout engine and re-usable components makes it possible to build apps that rival the desktop and web experience. From 237d17ff1668d46432edd13d05f937c0a0dbe9e7 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 21:51:53 +0100 Subject: [PATCH 70/89] Remove trailing whitespace --- docs/guide/widgets.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/guide/widgets.md b/docs/guide/widgets.md index 2a4c11fbc..3ec1224cd 100644 --- a/docs/guide/widgets.md +++ b/docs/guide/widgets.md @@ -26,7 +26,7 @@ Let's create a simple custom widget to display a greeting. The three highlighted lines define a custom widget class with just a [render()][textual.widget.Widget.render] method. Textual will display whatever is returned from render in the content area of your widget. We have returned a string in the code above, but there are other possible return types which we will cover later. -Note that the text contains tags in square brackets, i.e. `[b]`. This is [console markup](https://rich.readthedocs.io/en/latest/markup.html) which allows you to embed various styles within your content. If you run this you will find that `World` is in bold. +Note that the text contains tags in square brackets, i.e. `[b]`. This is [console markup](https://rich.readthedocs.io/en/latest/markup.html) which allows you to embed various styles within your content. If you run this you will find that `World` is in bold. ```{.textual path="docs/examples/guide/widgets/hello01.py"} ``` @@ -65,7 +65,7 @@ Let's use Static to create a widget which cycles through "hello" in various lang === "hello03.css" - ```sass title="hello03.css" + ```sass title="hello03.css" --8<-- "docs/examples/guide/widgets/hello03.css" ``` @@ -76,7 +76,7 @@ Let's use Static to create a widget which cycles through "hello" in various lang Note that there is no `render()` method on this widget. The Static class is handling the render for us. Instead we call `update()` when we want to update the content within the widget. -The `next_word` method updates the greeting. We call this method from the mount handler to get the first word, and from an click handler to cycle through the greetings when we click the widget. +The `next_word` method updates the greeting. We call this method from the mount handler to get the first word, and from an click handler to cycle through the greetings when we click the widget. ### Default CSS @@ -94,7 +94,7 @@ Here's the Hello example again, this time the widget has embedded default CSS: === "hello04.css" - ```sass title="hello04.css" + ```sass title="hello04.css" --8<-- "docs/examples/guide/widgets/hello04.css" ``` @@ -117,7 +117,7 @@ Text in a widget may be marked up with links which perform an action when clicke "Click [@click='app.bell']Me[/]" ``` -The `@click` tag introduces a click handler, which runs the `app.bell` action. +The `@click` tag introduces a click handler, which runs the `app.bell` action. Let's use markup links in the hello example so that the greeting becomes a link which updates the widget. @@ -167,7 +167,7 @@ This app will "play" fizz buzz by displaying a table of the first 15 numbers and ```{.textual path="docs/examples/guide/widgets/fizzbuzz01.py"} ``` -## Content size +## Content size Textual will auto-detect the dimensions of the content area from rich renderables if width or height is set to `auto`. You can override auto dimensions by implementing [get_content_width()][textual.widget.Widget.get_content_width] or [get_content_height()][textual.widget.Widget.get_content_height]. @@ -182,7 +182,7 @@ Let's modify the default width for the fizzbuzz example. By default, the table w === "fizzbuzz02.css" - ```sass title="fizzbuzz02.css" + ```sass title="fizzbuzz02.css" --8<-- "docs/examples/guide/widgets/fizzbuzz02.css" ``` From 338eca9e106bd3ffc8ef6eb8f32a41be1bd2ca45 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 21:54:29 +0100 Subject: [PATCH 71/89] it's -> its --- docs/guide/widgets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/widgets.md b/docs/guide/widgets.md index 3ec1224cd..7740d6ec6 100644 --- a/docs/guide/widgets.md +++ b/docs/guide/widgets.md @@ -15,7 +15,7 @@ A widget is a component of your UI responsible for managing a rectangular region There is a growing collection of [builtin widgets](../widgets/index.md) in Textual, but you can build entirely custom widgets that work in the same way. -The first step in building a widget is to import and extend a widget class. This can either be [Widget][textual.widget.Widget] which is the base class of all widgets, or one of it's subclasses. +The first step in building a widget is to import and extend a widget class. This can either be [Widget][textual.widget.Widget] which is the base class of all widgets, or one of its subclasses. Let's create a simple custom widget to display a greeting. From 4fb9dcd257c78cb90e90ccc70d8ad3ceb3714875 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 21:57:03 +0100 Subject: [PATCH 72/89] an -> a --- docs/guide/widgets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/widgets.md b/docs/guide/widgets.md index 7740d6ec6..bd2cdff2e 100644 --- a/docs/guide/widgets.md +++ b/docs/guide/widgets.md @@ -76,7 +76,7 @@ Let's use Static to create a widget which cycles through "hello" in various lang Note that there is no `render()` method on this widget. The Static class is handling the render for us. Instead we call `update()` when we want to update the content within the widget. -The `next_word` method updates the greeting. We call this method from the mount handler to get the first word, and from an click handler to cycle through the greetings when we click the widget. +The `next_word` method updates the greeting. We call this method from the mount handler to get the first word, and from a click handler to cycle through the greetings when we click the widget. ### Default CSS From 3992b1e7d35d5fa5d4c905d1d83dfb8d1a24867c Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 21:57:52 +0100 Subject: [PATCH 73/89] intent -> intend --- docs/guide/widgets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/widgets.md b/docs/guide/widgets.md index bd2cdff2e..6143ce874 100644 --- a/docs/guide/widgets.md +++ b/docs/guide/widgets.md @@ -80,7 +80,7 @@ The `next_word` method updates the greeting. We call this method from the mount ### Default CSS -When building an app it is best to keep your CSS in an external file. This allows you to see all your CSS in one place, and to enable live editing. However if you intent to distribute a widget (via PyPI for instance) it can be convenient to bundle the code and CSS together. You can do this by adding a `DEFAULT_CSS` class variable inside your widget class. +When building an app it is best to keep your CSS in an external file. This allows you to see all your CSS in one place, and to enable live editing. However if you intend to distribute a widget (via PyPI for instance) it can be convenient to bundle the code and CSS together. You can do this by adding a `DEFAULT_CSS` class variable inside your widget class. Textual's builtin widgets bundle CSS in this way, which is why you can see nicely styled widgets without having to copy any CSS code. From 799a769f3e5a44955e69d6e8bf341f9539057780 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:02:19 +0100 Subject: [PATCH 74/89] Add code markup to mention of the Table class --- docs/guide/widgets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/widgets.md b/docs/guide/widgets.md index 6143ce874..d30e30c96 100644 --- a/docs/guide/widgets.md +++ b/docs/guide/widgets.md @@ -191,7 +191,7 @@ Let's modify the default width for the fizzbuzz example. By default, the table w ```{.textual path="docs/examples/guide/widgets/fizzbuzz02.py"} ``` -Note that we've added `expand=True` to tell the Table to expand beyond the optimal width, so that it fills the 50 characters returned by `get_content_width`. +Note that we've added `expand=True` to tell the `Table` to expand beyond the optimal width, so that it fills the 50 characters returned by `get_content_width`. ## Compound widgets From f898fee1d1f906a0ba242c1f5c8367f324cbcd47 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:09:39 +0100 Subject: [PATCH 75/89] Remove trailing whitespace --- docs/guide/animation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/animation.md b/docs/guide/animation.md index 7768594d8..2a01d2632 100644 --- a/docs/guide/animation.md +++ b/docs/guide/animation.md @@ -77,7 +77,7 @@ You can specify which easing method to use via the `easing` parameter on the `an ## Completion callbacks -You can pass an callable to the animator via the `on_complete` parameter. Textual will run the callable when the animation has completed. +You can pass an callable to the animator via the `on_complete` parameter. Textual will run the callable when the animation has completed. ## Delaying animations From c670fc69605591e0f735026f8171445071f31cea Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:11:26 +0100 Subject: [PATCH 76/89] Add `as` --- docs/guide/animation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/animation.md b/docs/guide/animation.md index 2a01d2632..500d5e475 100644 --- a/docs/guide/animation.md +++ b/docs/guide/animation.md @@ -5,7 +5,7 @@ Ths chapter discusses how to use Textual's animation system to create visual eff ## Animating styles -Textual's animator can change an attribute from one value to another in fixed increments over a period of time. You can apply animations to [styles](styles.md) such `offset` to move widgets around the screen, and `opacity` to create fading effects. +Textual's animator can change an attribute from one value to another in fixed increments over a period of time. You can apply animations to [styles](styles.md) such as `offset` to move widgets around the screen, and `opacity` to create fading effects. Apps and widgets both have an [animate][textual.app.App.animate] method which will animate properties on those objects. Additionally, `styles` objects have an identical `animate` method which will animate styles. From 78af99e7803e1a1983f0bad758e4c363ee1fe027 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:14:07 +0100 Subject: [PATCH 77/89] an -> a --- docs/guide/animation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/animation.md b/docs/guide/animation.md index 500d5e475..99b9783a4 100644 --- a/docs/guide/animation.md +++ b/docs/guide/animation.md @@ -77,7 +77,7 @@ You can specify which easing method to use via the `easing` parameter on the `an ## Completion callbacks -You can pass an callable to the animator via the `on_complete` parameter. Textual will run the callable when the animation has completed. +You can pass a callable to the animator via the `on_complete` parameter. Textual will run the callable when the animation has completed. ## Delaying animations From c856ab3e3845582eb8d68bade15338ef2fcf0dc9 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:20:24 +0100 Subject: [PATCH 78/89] screen -> key --- docs/guide/screens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/screens.md b/docs/guide/screens.md index aeb0381ad..cfb28c711 100644 --- a/docs/guide/screens.md +++ b/docs/guide/screens.md @@ -39,7 +39,7 @@ Let's look at a simple example of writing a screen class to simulate Window's [b ```{.textual path="docs/examples/guide/screens/screen01.py" press="b,_"} ``` -If you run this you will see an empty screen. Hit the ++b++ screen to show a blue screen of death. Hit ++escape++ to return to the default screen. +If you run this you will see an empty screen. Hit the ++b++ key to show a blue screen of death. Hit ++escape++ to return to the default screen. The `BSOD` class above defines a screen with a key binding and compose method. These should be familiar as they work in the same way as apps. From 5f978847982645856d297254ed2dbbe916f67f28 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:21:18 +0100 Subject: [PATCH 79/89] associated -> associate --- docs/guide/screens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/screens.md b/docs/guide/screens.md index cfb28c711..cfbef1e3b 100644 --- a/docs/guide/screens.md +++ b/docs/guide/screens.md @@ -43,7 +43,7 @@ If you run this you will see an empty screen. Hit the ++b++ key to show a blue s The `BSOD` class above defines a screen with a key binding and compose method. These should be familiar as they work in the same way as apps. -The app class has a new `SCREENS` class variable. Textual uses this class variable to associated a name with screen object (the name is used to reference screens in the screen API). Also in the app is a key binding associated with the action `"push_screen('bsod')"`. The screen class has a similar action `"pop_screen"` bound to the ++escape++ key. We will cover these actions below. +The app class has a new `SCREENS` class variable. Textual uses this class variable to associate a name with screen object (the name is used to reference screens in the screen API). Also in the app is a key binding associated with the action `"push_screen('bsod')"`. The screen class has a similar action `"pop_screen"` bound to the ++escape++ key. We will cover these actions below. ## Named screens From f14f09d80a5914f00f72afcb1d1d80fc5ace2dc1 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:24:36 +0100 Subject: [PATCH 80/89] Add 'a' and code-markup `dict` --- docs/guide/screens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/screens.md b/docs/guide/screens.md index cfbef1e3b..8ddac8724 100644 --- a/docs/guide/screens.md +++ b/docs/guide/screens.md @@ -47,7 +47,7 @@ The app class has a new `SCREENS` class variable. Textual uses this class variab ## Named screens -You can associate a screen with a name by defining a `SCREENS` class variable in your app, which should be dict that maps names on to Screen objects. The name of the screen may be used interchangeably with screen objects in much of the screen API. +You can associate a screen with a name by defining a `SCREENS` class variable in your app, which should be a `dict` that maps names on to Screen objects. The name of the screen may be used interchangeably with screen objects in much of the screen API. You can also _install_ new named screens dynamically with the [install_screen][textual.app.App.install_screen] method. The following example installs the `BSOD` screen in a mount handler rather than from the `SCREENS` variable. From bdbdb62fd0973120bafac17cd5d4ae7cf3c24491 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:25:16 +0100 Subject: [PATCH 81/89] Code markup Screen --- docs/guide/screens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/screens.md b/docs/guide/screens.md index 8ddac8724..4103c8925 100644 --- a/docs/guide/screens.md +++ b/docs/guide/screens.md @@ -47,7 +47,7 @@ The app class has a new `SCREENS` class variable. Textual uses this class variab ## Named screens -You can associate a screen with a name by defining a `SCREENS` class variable in your app, which should be a `dict` that maps names on to Screen objects. The name of the screen may be used interchangeably with screen objects in much of the screen API. +You can associate a screen with a name by defining a `SCREENS` class variable in your app, which should be a `dict` that maps names on to `Screen` objects. The name of the screen may be used interchangeably with screen objects in much of the screen API. You can also _install_ new named screens dynamically with the [install_screen][textual.app.App.install_screen] method. The following example installs the `BSOD` screen in a mount handler rather than from the `SCREENS` variable. From a20dbbe32558420131f47b07dd35cfa501b707be Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sat, 15 Oct 2022 22:26:19 +0100 Subject: [PATCH 82/89] Drop `the` This could either be dropping `the`, as I've done here, or perhaps adding something like `approach` after `SCREENS`. I feel one or the other is needed to make this flow well. --- docs/guide/screens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/screens.md b/docs/guide/screens.md index 4103c8925..28a048e25 100644 --- a/docs/guide/screens.md +++ b/docs/guide/screens.md @@ -68,7 +68,7 @@ You can also _install_ new named screens dynamically with the [install_screen][t ```{.textual path="docs/examples/guide/screens/screen02.py" press="b,_"} ``` -Although both do the same thing, we recommend the `SCREENS` for screens that exist for the lifetime of your app. +Although both do the same thing, we recommend `SCREENS` for screens that exist for the lifetime of your app. ### Uninstalling screens From 0b2b00d93981ed9253ae8e6969e8291b9d6a1cfb Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sun, 16 Oct 2022 07:49:04 +0100 Subject: [PATCH 83/89] Correct the title for the Hide event --- docs/events/hide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/events/hide.md b/docs/events/hide.md index e4b4d9108..2f7655b4e 100644 --- a/docs/events/hide.md +++ b/docs/events/hide.md @@ -1,4 +1,4 @@ -# Show +# Hide The `Hide` event is sent to a widget when it is hidden from view. From 109f5ae814d2e06f35901f04ca003dec1ca0d0bb Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sun, 16 Oct 2022 07:51:59 +0100 Subject: [PATCH 84/89] captures -> captured --- src/textual/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textual/events.py b/src/textual/events.py index b8c56a24c..ee84b929f 100644 --- a/src/textual/events.py +++ b/src/textual/events.py @@ -148,7 +148,7 @@ class Hide(Event, bubble=False): class MouseCapture(Event, bubble=False): """Sent when the mouse has been captured. - When a mouse has been captures, all further mouse events will be sent to the capturing widget. + When a mouse has been captured, all further mouse events will be sent to the capturing widget. Args: From 682f9a8936a52a2ff7e6bf0095d8ef537b9d120d Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sun, 16 Oct 2022 08:12:42 +0100 Subject: [PATCH 85/89] Correct the class name that hides the widget in the eg Also add some code markup to the class name, as this seems common elsewhere in the docs. --- docs/styles/display.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/styles/display.md b/docs/styles/display.md index 962838939..5462367d4 100644 --- a/docs/styles/display.md +++ b/docs/styles/display.md @@ -17,7 +17,7 @@ display: [none|block]; ## Example -Note that the second widget is hidden by adding the "hidden" class which sets the display style to None. +Note that the second widget is hidden by adding the `"remove"` class which sets the display style to None. === "display.py" From 5df90e00c0cf3e3c14cf080d280d6aac137cb4d4 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sun, 16 Oct 2022 08:18:30 +0100 Subject: [PATCH 86/89] examples -> example --- docs/styles/outline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/styles/outline.md b/docs/styles/outline.md index 2267fedb7..c2e9b3eb8 100644 --- a/docs/styles/outline.md +++ b/docs/styles/outline.md @@ -43,7 +43,7 @@ For example, `heavy white` would display a heavy white line around a widget. ## Example -This examples shows a widget with an outline. Note how the outline occludes the text area. +This example shows a widget with an outline. Note how the outline occludes the text area. === "outline.py" From b235e4cff03488b4a4f5f9479276027779a12c54 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sun, 16 Oct 2022 08:19:20 +0100 Subject: [PATCH 87/89] Remove unnecessary indentation of example code --- docs/styles/outline.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/styles/outline.md b/docs/styles/outline.md index c2e9b3eb8..284c669a8 100644 --- a/docs/styles/outline.md +++ b/docs/styles/outline.md @@ -78,6 +78,6 @@ outline-left:outer red; # Set a heavy white outline widget.outline = ("heavy", "white) - # Set a red outline on the left - widget.outline_left = ("outer", "red) +# Set a red outline on the left +widget.outline_left = ("outer", "red) ``` From f867d5b0164c624b03ab14f93f33c9206f3950b1 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sun, 16 Oct 2022 08:22:30 +0100 Subject: [PATCH 88/89] Make the scrollbar belong to the widget --- docs/styles/scrollbar_size.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/styles/scrollbar_size.md b/docs/styles/scrollbar_size.md index a6bfbcce8..ccc9c5e80 100644 --- a/docs/styles/scrollbar_size.md +++ b/docs/styles/scrollbar_size.md @@ -12,7 +12,7 @@ scrollbar-size: ; ## Example -In this example we modify the size of the widgets scrollbar to be _much_ larger than usual. +In this example we modify the size of the widget's scrollbar to be _much_ larger than usual. === "scrollbar_size.py" From 2a8029be38f7f39383257f36a0f60395c2501fc7 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Sun, 16 Oct 2022 10:20:32 +0100 Subject: [PATCH 89/89] Correct the order of the widgets docs By the looks of things the list of docs got sorted, but didn't exclude the index, so the prev/next chain in the footer got broken around `header`. This corrects that. --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 2f3de4218..4c74f759a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -89,11 +89,11 @@ nav: - "styles/visibility.md" - "styles/width.md" - Widgets: + - "widgets/index.md" - "widgets/button.md" - "widgets/data_table.md" - "widgets/footer.md" - "widgets/header.md" - - "widgets/index.md" - "widgets/input.md" - "widgets/static.md" - "widgets/tree_control.md"