Sample Code

Here are some examples of scripts using purdy as a library. Full source is available in the repository: https://github.com/cltrudeau/purdy/tree/master/extras/samples

Short Feature Demo

#!/usr/bin/env python
# mixed.py
from purdy.tui import AppFactory, Code

# =============================================================================

app = AppFactory.simple(auto_scroll=True)
box = app.box

text = """\
$ python
Python 3.13.5 (v3.13.5:6cb20a219a8, Jun 11 2025, 12:23:45)
Type "help", "copyright", "credits" or "license" for more information.
"""

con = Code.text(text)
repl = Code("../display_code/really_short.repl", theme="pyrepl")
code = Code("../display_code/code.py")

(box
    .append(con)
    .typewriter(repl)
    .wait()
    .transition(code[0:3])
    .wait()
    .highlight_chain(0, "1:4,10", 2, [0, "1:0,3"], "1:arg:1")
    .wait()
    .set_numbers(1)
    .wait()
    .append(code[3:])
)

app.run()

General Feature Demo

#!/usr/bin/env python
# features.py
#
# Shows off the main features of the purdy coding interface
from purdy.tui import AppFactory, Code, EscapeText

# =============================================================================

app = AppFactory.split(relative_height_bottom=2, auto_scroll_top=True,
    top_title="[on blue]Welcome to the purdy features demo[/]")
top = app.top
bottom = app.bottom
control = app.control

INTRO = "\nPress right arrow to show the next animation step →"

shell = """\
$ python
Python 3.13.5 (v3.13.5:6cb20a219a8, Jun 11 2025, 12:23:45)
Type "help", "copyright", "credits" or "license" for more information.
"""

con = Code.text(shell, "con")
repl = Code("../display_code/really_short.repl")
code = Code("../display_code/short.py")
long_code = Code("../display_code/code.py")

# Intro
(top
    .append(INTRO)
    .wait()
)

(top
    .append("The left arrow allows you to back up ←")
    .wait()
    .append("\nPurdy lets you present like you're coding")
    .append("   Both in the shell →")
    .wait()
)

# Bash + REPL
(bottom
    .append(con)
    .wait()
)

(top
    .append("   and the REPL →")
    .wait()
)

(bottom
    .append(repl)
    .wait()
)

# Transition to code
(top
    .append("\nThere are a variety of transition animations →")
    .wait()
)

(bottom
    .transition(code)
    .wait()
)

# Highlights
(top
    .append("\nYou can highlighting a line of code →")
    .wait()
)

(bottom
    .highlight(0)
    .wait()
)

(top
    .append("Or just parts of it →")
    .wait()
)

(bottom
    .highlight_off(0)
    .highlight("1:4,18")
    .wait()
    .highlight_all_off()
    .wait()
)

# Screen Transition
(top
    .append("\nYou can transition the whole screen →")
    .wait()
)

control.transition({
    top: "You can emulate typing → → →",
    bottom: None
})

# Typewriter
(bottom
    .wait()
    .append(con)
    .typewriter(repl)
    .wait()
)

(top
    .append("Typing with Textual markup →")
    .wait()
)

top.debug(80*"=")

(bottom
    .transition()
    .text_typewriter("one [green]two[/] three")
    .wait()
)

(top
    .append("Or you can escape text to keep it plain →")
    .wait()
)

(bottom
    .text_typewriter(EscapeText("four [five] six"))
    .wait()
)

(top
    .append("You can control the display →")
    .wait()
)

(bottom
    .transition(long_code)
    .wait()
)

(top
    .append("Turn line numbers on →")
    .wait()
)

(bottom
    .set_numbers(1)
    .wait()
)

(top
    .append("Animate scrolling →")
    .wait()
)

(bottom
    .move_by(10)
    .wait()
)

(top
    .append("\n[yellow]Checkout the coding API for details[/]")
)

app.run()

Using Different App Factories and Screen Layouts

#!/usr/bin/env python
# box.py
from purdy.tui import AppFactory, BoxSpec, Code, RowSpec

# =============================================================================

CONTENT = """This is some babbling text which will appear in a bunch of different colours. I'll just keep typing for a while. That should be enough I would think, yes?  """

def a1():
    row_specs = [
        RowSpec(1, [BoxSpec(1, border="br"), BoxSpec(2, border="b")]),
        RowSpec(2, [BoxSpec(2), BoxSpec(1)]),
    ]

    app = AppFactory.full(row_specs)
    app.rows[0][0].append("[blue]" + 3 * CONTENT + "[/]")
    app.rows[0][1].append("[green]" + 5 * CONTENT + "[/]")
    app.rows[1][0].append("[red]" + 7 * CONTENT + "[/]")
    app.rows[1][1].append("[orange]" + 7 * CONTENT + "[/]")
    return app

def a2():
    app = AppFactory.simple(title="[yellow]Static title[/]")
    app.box.append("[blue]" + 7 * CONTENT + "[/]")
    return app

def a3():
    app = AppFactory.split(20, relative_height_top=3,
        top_title="[yellow]Top static title[/]",
        bottom_title="[yellow]Top static title[/]")
    app.top.append("[blue]" + 7 * CONTENT + "[/]")
    app.bottom.append("[red]" + 7 * CONTENT + "[/]")
    return app

# Uncomment each function to see the different app factories in action

#a1().run()
#a2().run()
a3().run()

Typewriter Animations

#!/usr/bin/env python
# features.py
#
# Shows off the main features of the purdy coding interface
from purdy.tui import AppFactory, Code, EscapeText, TextSection

# =============================================================================

app = AppFactory.simple(auto_scroll=True)
box = app.box

INTRO = """\
[on blue]Typewriter demo[/]

Press right arrow to show the next animation step →

"""

repl = Code("../display_code/short.repl")

# Intro
(box
    .append(INTRO)
    .wait()
    .text_typewriter(EscapeText("plain text [no markup]"))
    .wait()
    .set_numbers(1)
    .append("Turned numbering on")
    .wait()
    .text_typewriter(
        TextSection(["multi-line mixed", EscapeText("with [escaped] text")])
    )
    .wait()
    .text_typewriter("some [green]markup[/] text")
    .wait()
    .text_typewriter(
        TextSection(["[yellow]multi-line[/]", "markup [green]text[/] section"])
    )
    .wait()
    .typewriter(repl)
    .append("Turning on pause after prompts")
    .wait()
    .typewriter(repl, prompt_wait=True)
)

app.run()