refactor of docs

This commit is contained in:
Will McGugan
2022-05-26 17:02:30 +01:00
parent 51f1957f1c
commit 3030557060
10 changed files with 165 additions and 110 deletions

5
custom_theme/main.html Normal file
View File

@@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block extrahead %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/fira_code.min.css" integrity="sha512-MbysAYimH1hH2xYzkkMHB6MqxBqfP0megxsCLknbYqHVwXTCg9IqHbk+ZP/vnhO8UEW6PaXAkKe2vQ+SWACxxA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
{% endblock %}

1
docs/actions.md Normal file
View File

@@ -0,0 +1 @@
# Actions

15
docs/events/mount.md Normal file
View File

@@ -0,0 +1,15 @@
# Mount
The `Mount` event is sent to a widget and Application when it is first mounted.
- [ ] Bubbles
## Parameters
`sender`
: The sender of the widget
## Code
::: textual.events.Mount

23
docs/events/resize.md Normal file
View File

@@ -0,0 +1,23 @@
# Resize
The `Resize` event is sent to a widget when its size changes and when it is first made visible.
- [x] Bubbles
## Parameters
`event.size`
: The new size of the Widget.
`event.virtual_size`
: The virtual size (scrollable area) of the Widget.
`event.container_size`
: The size of the widget's container.
## Code
::: textual.events.Resize

1
docs/guide/guide.md Normal file
View File

@@ -0,0 +1 @@
# Guide

View File

@@ -1,30 +1,11 @@
# Welcome # Welcome
Textual is framework for rapidly creating _text user interfaces_ (TUIs from here on) with Python. Welcome to the [Textual](https://github.com/Textualize/textual) framework documentation, built with ❤️ by [Textualize.io](https://www.textualize.io)
A TUI is an application that lives within a terminal, which can have mouse and keyboard support and user interface elements like windows and panels, but is rendered purely with text. They have a number of advantages over GUI applications: they can be launched from the command line, and return to the command line, and they work over ssh. ## Getting started
## Foo Textual is a Python framework which you can install via Pypi.
Creating a TUI can be challenging. It may be easier to create a GUI or web application than it is to build a TUI with traditional techniques. Often projects that could use one or the other never manage to ship either. ```bash
pip install textual
Textual seeks to lower the difficulty level of building a TUI by borrowing developments from the web world and to a lesser extent desktop applications. The goal is for it to be as easy to develop a TUI for your project as it would be to add a command line interface.XX ```
=== "simple.py"
```python
--8<-- "docs/examples/simple.py"
```
=== "simple.css"
```scss
--8<-- "docs/examples/simple.css"
```
=== "Result"
```{.textual path="docs/examples/simple.py" columns="80" lines="24"}
```
Textual also offers a number of enhancements over traditional TUI applications by taking advantage of improvements to terminal software and the hardware it runs on. Terminals are a far cry from their roots in ancient hardware and dial-up modems, yet much of the software that runs on them hasn't kept pace.

View File

@@ -2,7 +2,7 @@
Welcome to the Textual Introduction! Welcome to the Textual Introduction!
This is a very gentle introduction to creating Textual applications. This is a very gentle introduction to creating Textual applications. By the end of this document you should have an understanding of the basic concepts involved in using the Textual framework.
## Pre-requisites ## Pre-requisites
@@ -16,91 +16,87 @@ Lets looks at the simplest possible Textual app. It doesn't do much, but will de
If you would like to follow along and run the examples, navigate to the `docs/examples/introduction` directory from the command prompt. We will be looking at `intro01.py`, which you can see here: If you would like to follow along and run the examples, navigate to the `docs/examples/introduction` directory from the command prompt. We will be looking at `intro01.py`, which you can see here:
=== "intro01.py" ```python title="intro01.py"
--8<-- "docs/examples/introduction/intro01.py"
```python ```
--8<-- "docs/examples/introduction/intro01.py"
```
=== "Output"
```{.textual path="docs/examples/introduction/intro01.py"}
```
Enter the following command to run the application: Enter the following command to run the application:
```shell ```bash
python intro01.py python intro01.py
``` ```
The command prompt should disappear and you will see a blank screen. Hit ++ctrl+c++ to exit and return to the command prompt. The command prompt should disappear and you will see a blank screen. It will look something like the following:
Let's analyze this simple app. ```{.textual path="docs/examples/introduction/intro01.py"}
```
Hit ++ctrl+c++ to exit and return to the command prompt.
The first step in all Textual applications is to import the `App` class from `textual.app` and extend it: The first step in all Textual applications is to import the `App` class from `textual.app` and extend it:
```python ```python hl_lines="1 2 3 4 5" title="intro01.py"
from textual.app import App --8<-- "docs/examples/introduction/intro01.py"
class ExampleApp(App):
pass
``` ```
There will be a single App object in any Textual application. The App class is responsible for loading data, setting up the screen, managing events etc. There will be a single App class in any Textual application. The App class is responsible for loading data, setting up the screen, managing events etc. In a real app most of the core logic of your application will be contained within methods on the this class.
The following two lines create an instance of the application and calls `run()`: The last two lines create an instance of the application and calls `run()`:
```python ```python hl_lines="8 9" title="intro01.py"
app = ExampleApp() --8<-- "docs/examples/introduction/intro01.py"
app.run()
``` ```
The `run` method will put your terminal in to "application mode" which disables the prompt and allows Textual to take over input and output. The `run()` method will return when the application exits. The `run` method will put your terminal in to "application mode" which disables the prompt and allows Textual to take over input and output. When you press ++ctrl+c++ the application will exit application mode and re-enable the command prompt.
## Handling Events ## Handling Events
In the previously example our app did next to nothing. Most applications will contain event handler methods, which are called in response to user actions (such as key presses, mouse action) and other changes your app needs to know about such as terminal resize, scrolling, timers, etc. In the previously example our app did next to nothing. Most applications will contain event handler methods, which are called in response to user actions such as key presses and mouse movements in addition to other changes your app needs to know about such as terminal resize, scrolling, timers, etc.
!!! note !!! note
Although `intro01.py` did not explicitly define any event handlers, Textual still had to respond to the Key event to catch ++ctrl+c++, otherwise you wouldn't be able to exit the app. Although `intro01.py` did not explicitly define any event handlers, Textual still had to respond to events to catch ++ctrl+c++, otherwise you wouldn't be able to exit the app.
In our next example, we are going to handle two such events; `Mount` and `Key`. The `Mount` event is sent when the app is first run, and a `Key` event is sent when the user presses a key on the keyboard. Try running `intro02.py` in the `docs/examples/introduction`: In our next example, we are going to handle two events; `Mount` and `Key`. The `Mount` event is sent when the app is first run, and a `Key` event is sent when the user presses a key on the keyboard. Try running `intro02.py` in the `docs/examples/introduction`:
=== "intro02.py" ```python title="intro02.py"
--8<-- "docs/examples/introduction/intro02.py"
```python
--8<-- "docs/examples/introduction/intro02.py"
```
=== "Output"
```{.textual path="docs/examples/introduction/intro02.py"}
```
When you run this app you should see a blue screen. If you hit any of the number keys ++0++-++9++, the background will change to another color. You may also hear a beep or some other noise when a key is pressed, depending on how your terminal is configured. As before, pressing ++ctrl+c++ will exit the app and return you to your prompt.
There are two event handlers in this app class. Event handlers start with the text `on_` followed by the name of the event in lower case. Hence `on_mount` is called for the `Mount` event, and `on_key` is called for the `Key` event.
Here's the `on_mount` method again:
```python
def on_mount(self):
self.styles.background = "darkblue"
``` ```
This method sets the `background` attribute on `self.styles` to `"darkblue"` which makes the application background blue when the app loads. The `styles` object contains a variety of properties which define how your app looks. We will explore what you can do with this object later. When you run this app you should see a blue screen in your terminal, like the following:
```{.textual path="docs/examples/introduction/intro02.py"}
```
If you hit any of the number keys ++0++-++9++, the background will change color and you should hear a beep. As before, pressing ++ctrl+c++ will exit the app and return you to your prompt.
!!! note
The "beep" is your terminal's *bell*. Some terminals may be configured to play different noises or a visual indication of a bell rather than a noise.
There are two event handlers in this app. Event handlers start with the text `on_` followed by the name of the event in lower case. Hence `on_mount` is called for the `Mount` event, and `on_key` is called for the `Key` event.
The first event handler to run is `on_mount`:
```python hl_lines="19 20" title="intro02.py"
--8<-- "docs/examples/introduction/intro02.py"
```
This `on_mount` method sets the `background` attribute of `self.styles` to `"darkblue"` which updates the background color. There are a lot of other properties on the Styles object, which define how your app looks. We will explore what you can do with this object later.
!!! note
You may have noticed there was no function call to repaint the screen in this examples. Textual will detect when a refresh is required, and do it automatically.
The second event handler will receive `Key` events whenever you press a key on the keyboard: The second event handler will receive `Key` events whenever you press a key on the keyboard:
```python ```python hl_lines="22 23 24 25" title="intro02.py"
def on_key(self, event): --8<-- "docs/examples/introduction/intro02.py"
if event.key.isdigit():
self.styles.background = self.COLORS[int(event.key)]
self.bell()
``` ```
This method has an `event` positional argument which contains information regarding the key that was pressed. The body of the method sets the background to a corresponding color when you press one of the digit keys. It also calls `bell()` which is a method on App that plays your terminal's bell. This method has an `event` positional argument which contains information regarding the key that was pressed. The body of the method sets the background to a corresponding color int the `COLORS` list when you press one of the digit keys. It also calls `bell()` which is a method on App that plays your terminal's bell.
!!! note !!! note
@@ -108,38 +104,44 @@ This method has an `event` positional argument which contains information regard
## Widgets ## Widgets
Most Textual applications will also make use of one or more `Widget` classes. A Widget is a self contained component which is responsible for defining how a given part of the screen should look. Widgets respond to events in much the same way as the App does. More sophisticated user interfaces can be built by combining various widgets. Most Textual applications will also make use of one or more `Widget` classes. A Widget is a self contained component responsible for defining how a given part of the screen should look. Widgets respond to events in much the same way as the App does.
Let's look at an app which defines a very simple Widget to show the current time and date. Here is the code for `"clock01.py"` which is n the same directory as the previous examples: Let's look at an app with a simple Widget to show the current time and date. Here is the code for `"clock01.py"` which is in the same directory as the previous examples:
=== "clock01.py" ```python title="clock01.py"
--8<-- "docs/examples/introduction/clock01.py"
```python
--8<-- "docs/examples/introduction/clock01.py"
```
=== "Output"
```{.textual path="docs/examples/introduction/clock01.py"}
```
This script imports App as before, but also the `Widget` class from `textual.widget`, which is the base class for all Widgets. The `Clock` widget extends `Widget` and adds an `on_mount` handler which is called when the widget is first added to the application.
Lets have a look at the Clock's Mount event handler:
```python
def on_mount(self):
self.styles.content_align = ("center", "middle")
self.set_interval(1, self.refresh)
``` ```
The first line in that method sets the `content_align` attribute on the styles object, which defines how text is positioned within the Widget. We're setting it to a tuple of `("center", "middle")` which tells Textual to horizontally center the text, and place it in the middle vertically. If you resize the terminal you should notice that the text is automatically centered. Here's what you will see if you run this code:
The second line calls `self.set_interval` to request that Textual calls `self.refresh` to update the screen once a second. When the screen is refreshed, Textual will call the widget's `render()` method, which we can see here: ```{.textual path="docs/examples/introduction/clock01.py"}
```python
def render(self):
return datetime.now().strftime("%c")
``` ```
This method uses the datetime module to format the current date and time. It returns a string, but can also return a _Rich renderable_. Don't worry if you aren't familiar with [Rich](https://github.com/Textualize/rich), we will cover that later. This script imports App as before, but also the `Widget` class from `textual.widget`, which is the base class for all Widgets. To create a Clock widget we extend from the Widget base class:
```python title="clock01.py" hl_lines="7 8 9 10 11 12 13"
--8<-- "docs/examples/introduction/clock01.py"
```
Widgets support many of the same events as the Application itself, and can be thought of as mini-applications in their own right. The Clock widget also responds to a Mount event which is the first event received when a widget is _mounted_ (added to the App). The code in `Clock.on_mount` sets `styles.content_align` to tuple of `("center", "middle")` which tells Textual to display the Widget's content aligned to the horizontal center, and in the middle vertically. If you resize the terminal, you should find the time remains in the center.
The second line in `on_mount` calls `self.set_interval` which tells Textual to invoke the `self.refresh` function once a second to refresh the Clock widget.
When Textual refreshes a widget it calls it's `render` method:
```python title="clock01.py" hl_lines="12 13"
--8<-- "docs/examples/introduction/clock01.py"
```
The Clocks `render` method uses the datetime module to format the current date and time. It returns a string, but can also return a _Rich renderable_. Don't worry if you aren't familiar with [Rich](https://github.com/Textualize/rich), we will cover that later.
Before a Widget can be displayed, it must first be mounted on the app. This is typically done within the applications Mount handler, so that an application's widgets are added when the application first starts:
```python title="clock01.py" hl_lines="17 18"
--8<-- "docs/examples/introduction/clock01.py"
```
In the case of the clock application, we call `mount` with an instance of the `Clock` widget.
That's all there is to this Clock example. It will display the current time until you hit ++ctrl+c++

View File

@@ -1,12 +1,33 @@
site_name: Textual site_name: Textual
site_url: https://www.textualize.io/ site_url: https://www.textualize.io/
nav:
- "index.md"
- "introduction.md"
- Guide:
- "guide/guide.md"
- "actions.md"
- Events:
- "events/mount.md"
- "events/resize.md"
- Styles:
- "styles/width.md"
- Widgets: "/widgets/"
- Reference:
- "reference/app.md"
- "reference/events.md"
- "reference/widget.md"
markdown_extensions: markdown_extensions:
- admonition - admonition
- def_list
- meta - meta
- toc: - toc:
permalink: true permalink: true
baselevel: 1
- pymdownx.keys - pymdownx.keys
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.highlight: - pymdownx.highlight:
anchor_linenums: true anchor_linenums: true
- pymdownx.superfences: - pymdownx.superfences:
@@ -24,6 +45,9 @@ markdown_extensions:
theme: theme:
name: material name: material
custom_dir: custom_theme
# features:
# - navigation.tabs
palette: palette:
- media: "(prefers-color-scheme: light)" - media: "(prefers-color-scheme: light)"
scheme: default scheme: default
@@ -39,6 +63,7 @@ theme:
name: Switch to light mode name: Switch to light mode
plugins: plugins:
- search: - search:
- mkdocstrings: - mkdocstrings:
default_handler: python default_handler: python

View File

@@ -98,10 +98,12 @@ class Resize(Event, verbosity=2, bubble=False):
container_size: Size | None = None, container_size: Size | None = None,
) -> None: ) -> None:
""" """
Args: Args:
sender (MessageTarget): Event sender. sender (MessageTarget): The sender of the event (the Screen).
width (int): New width in terminal cells. size (Size): The new size of the Widget.
height (int): New height in terminal cells. virtual_size (Size): The virtual size (scrollable size) of the Widget.
container_size (Size | None, optional): The size of the Widget's container widget. Defaults to None.
""" """
self.size = size self.size = size
self.virtual_size = virtual_size self.virtual_size = virtual_size