Skip to content

DevLog

Behind the Curtain of Inline Terminal Applications

Textual recently added the ability to run inline terminal apps. You can see this in action if you run the calculator example:

Inline Calculator

The application appears directly under the prompt, rather than occupying the full height of the screen—which is more typical of TUI applications. You can interact with this calculator using keys or the mouse. When you press Ctrl+C the calculator disappears and returns you to the prompt.

Here's another app that creates an inline code editor:

from textual.app import App, ComposeResult
from textual.widgets import TextArea


class InlineApp(App):
    CSS = """
    TextArea {
        height: auto;
        max-height: 50vh;
    }
    """

    def compose(self) -> ComposeResult:
        yield TextArea(language="python")


if __name__ == "__main__":
    InlineApp().run(inline=True)

This post will cover some of what goes on under the hood to make such inline apps work.

It's not going to go in to too much detail. I'm assuming most readers will be more interested in a birds-eye view rather than all the gory details.

Remote memory profiling with Memray

Memray is a memory profiler for Python, built by some very smart devs at Bloomberg. It is a fantastic tool to identify memory leaks in your code or other libraries (down to the C level)!

They recently added a Textual interface which looks amazing, and lets you monitor your process right from the terminal:

Memray

Things I learned building a text editor for the terminal

TextArea is the latest widget to be added to Textual's growing collection. It provides a multi-line space to edit text, and features optional syntax highlighting for a selection of languages.

text-area-welcome.gif

Adding a TextArea to your Textual app is as simple as adding this to your compose method:

yield TextArea()

Enabling syntax highlighting for a language is as simple as:

yield TextArea(language="python")

Working on the TextArea widget for Textual taught me a lot about Python and my general approach to software engineering. It gave me an appreciation for the subtle functionality behind the editors we use on a daily basis — features we may not even notice, despite some engineer spending hours perfecting it to provide a small boost to our development experience.

This post is a tour of some of these learnings.

To TUI or not to TUI

Tech moves pretty fast. If you don’t stop and look around once in a while, you could miss it. And yet some technology feels like it has been around forever.

Terminals are one of those forever-technologies.

No-async async with Python

A (reasonable) criticism of async is that it tends to proliferate in your code. In order to await something, your functions must be async all the way up the call-stack. This tends to result in you making things async just to support that one call that needs it or, worse, adding async just-in-case. Given that going from def to async def is a breaking change there is a strong incentive to go straight there.

Before you know it, you have adopted a policy of "async all the things".