Library Documentation

In addition to the easy to use command-line script, you can also write programs using the purdy library. The purdy command-line script uses this library to display a simple file to the screen.

Example Program

# reads 'my_code.py' and displays it to the screen with line numbers

from purdy.tui import AppFactory, Code

# An app is the entry to showing content. The AppFactory has convenience
# methods for creating an app.
app = AppFactory.simple(line_number=1)

# A `CodeBox` object is what displays your content to the screen. A simple
# app has one of these called `box`
box = app.box

# Read a file and parse it using the `Code` object
code = Code('my_code.py')

# You perform actions on the `CodeBox` by chaining calls. These calls
# effect how things are presented.
(box
    .append(code)
    .set_numbers(1)
)

# Purdy is a Textual app, so you run it like you would any Textual program
app.run()

Purdy is a Textual app, and the purdy.tui.apps.AppFactory is a convenient way to to create an app instance. Inside the app, you can have one or more purdy.tui.codebox.CodeBox objects that display contents. The purdy.tui.apps.AppFactory.simple() call creates a single CodeBox that fills the screen. purdy.tui.apps.AppFactory.split() creates a screen with two boxes one above the other.

You put content in a CodeBox using a purdy.content.Code object. The Code object constructor takes the name of a file to read. By default it attempts to detect what kind of content is in the file based on the file extension. There is a long list of extensions supported, each providing their own syntax highlighting. The three most common are .py for Python files, .repl for text captures of a Python REPL session, and .con for Bash shell sessions. A full list of supported file names can be found by running the purdy command without arguments.

The Code object also has a purdy.content.Code.text() method that can be used as a factory that parses a string. This method assumes the string contains Python code, but you can use the lexer argument to specify other kinds of content.

In addition to adding Code objects to the CodeBox, you can also add text in the form of Textual Markup. If you only want plain text, the purdy.tui.tui_content.EscapeText wrapper escapes the Textual Markup.

Once you have created an app, you access its CodeBox objects and perform actions on them. Actions change what you see on the screen. Two common actions are purdy.tui.codebox.CodeBox.append() which appends text to the box, and purdy.tui.codebox.CodeBox.typewriter() which animations typing of the content. If the content type being animated represents an interactive console, the typewriter animation will wait at each prompt, allowing you to control the pace of the animation. In Python, >>> and are considered prompts, and in Bash anything starting with $ is one.

Actions all return an instance of the CodeBox that called them, so can be chained together.

View more examples in the Sample Code section.


Library API

class purdy.tui.apps.AppFactory

Factory methods for creating a purdy app.

classmethod full(row_specs, max_height=None)

Creates a TUI screen based on a list of rows, where each row is a list of BoxSpec classes.

Parameters:
  • row_specs – list of RowSpec objects which describe the layout information for each row in the resulting display grid. Each RowSpec contains a list of BoxSpec objects, the sum of their widths in each row must be equal.

  • max_height – Max height of the app within your terminal. Defaults to None.

classmethod simple(max_height=None, line_number=None, auto_scroll=False, title=None)

Creates a purdy display with a single CodeBox inside of it.

Parameters:
  • max_height – limit the height of the content in the terminal, defaults to None

  • line_number – specify a starting line number for the code box, defaults to None

  • auto_scroll – when True, if content is added to the code box it scrolls to the bottom. Defaults to False.

  • title – a title to include at the top of the purdy.tui.codebox.CodeBox, defaults to None

classmethod split(max_height=None, line_number_top=None, auto_scroll_top=False, relative_height_top=1, line_number_bottom=None, auto_scroll_bottom=False, relative_height_bottom=1, top_title=None, bottom_title=None)

Creates a purdy display with two CodeBox objects one on top of the other.

Parameters:
  • max_height – limit the height of the content in the terminal, defaults to None

  • line_number_top – specify a starting line number for the top code box, defaults to None

  • auto_scroll_top – when True, if content is added to the top code box it scrolls to the bottom. Defaults to False.

  • relative_height_top – specify the height of the top code box against the bottom one. For example top=1, bottom=1 makes them the same size, top=3, bottom=1, makes them be 3/4 and 1/4 of the screen respectively

  • line_number_bottom – specify a starting line number for the bottom code box, defaults to None

  • auto_scroll_bottom – when True, if content is added to the bottom code box it scrolls to the bottom. Defaults to False.

  • relative_height_bottom – specify the height of the bottom code box against the top one.

  • top_title – a title to include over the top CodeBox, defaults to None

  • bottom_title – a title to include over the bottom CodeBox, defaults to None

class purdy.content.Code(filename, lexer='detect', theme=None)

Encapsulates CodeLine objects to track lines of code and any associated style information.

Constructor reads code from a file, build an associated parser, and add the resulting lines to this object.

Warning

Files must be in UTF-8 format

Parameters:
  • filename – Name of file to read of pathlib.Path object

  • lexer – Identifier that determines which LexerSpec to use when parsing the code. Defaults to “detect”

  • theme – Either a string containing the base name of a theme (without the category type like code, con, etc) or a Theme object. Defaults to None in which case it uses the class attribute default_theme_name as the theme name.

chunk(amount)

This method is for doing iterator-like access to the Code object. Each call returns a copy of the object containing a subset of lines, with each subsequent call returning the next subset. To reset to the beginning, set Code.current to 0.

Parameters:

amount – Number of CodeLine objects to include in the result

Returns:

A copy of this Code object but containing only a subset of its lines

fold(index, length)

Create a fold in the code

Parameters:
  • index – Index number to start the fold at

  • length – how many lines to include in the fold

highlight(*args)

Turn highlighting on for one or more code lines. Each argument can be an int (index value, supports negative indexing), a tuple (specifying starting line and number of lines to highlight, start line can be negative), a string specifying a range (“1-3” highlights lines 1 through 3 inclusive), or a partial highlight.

There are two kinds of highlighting for part of a line. The first is specified by a line number, a colon, a starting character position and a length. Example “3:15,5” highlights characters 15-20 on index line 3. The line number indicator supports negative indexing.

The second is for highlighting an argument in a function call or declaration. Example “3:arg:0” highlights the first argument on line three. The parsing of arguments is very naive, it simply looks for open parenthesis and commas to separate arguments. If your line has tuples or other things that would break that, use partial highlighting with start and length indexes.

# Example
code.highlight(
    3,          # highlight fourth line
    -1,         # last line
    "5-7"       # lines 5 through 7, inclusive
    "10:20,5"   # line 10, characters 20 through 25
    "12:arg:3"  # line 12, highlight the 4th argument
)

All start positions are zero indexed.

highlight_all_off()

Removes all highlighting

highlight_off(*args)

Turns highlighting for one or more code lines. See Code.highlight() for a list of available highlight specifiers

remaining_chunk()

Associated with the Code.chunk() call, but returns whatever is left in the block.

Returns:

A copy of this Code object but containing the lines remaining in the chunkification process

render_line(render_state, line, line_index)

Responsible for rendering the given line and appending the result into the RenderState object.

reset_metadata()

Sets all the style metadata back to defaults. Mostly used for testing.

spawn()

Returns a new Code object with the same parser and theme as this one, but empty of any code lines.

classmethod text(text, lexer='py', theme=None)

Factory method for reading code from a string instead of a file.

Parameters:
  • text – Text to parse

  • lexer – Identifier that determines which LexerSpec to use when parsing the code. Defaults to “detect”

unfold(index)

Removes a previously created fold that starts on the given index line.

class purdy.content.PyText(filename)

Container for text that is valid Python. Useful for doing pre-processing on source code before creating a Code object. Source text is stored in the .content attribute as a string.

Warning

Files must be in UTF-8 format

Parameters:

filename – name of file containing the Python you want to handle

get_part(name, header=None)

Returns a new PyText object containing just the named part of the original. Parts can be a function, class, or assigned variable.

Warning

If the named item is not found your source will be empty!

Parameters:
  • name – dot notated name of a function or class. Examples: Foo.bar would find the bar method of class Foo or an inner function named bar in a function named Foo

  • header – optionally include another part of the source file before the parsed content. Typically used to include the header portion of a file. If given an integer, it will include the first X number of lines. If given a tuple “(x, y)” does a slice on the code with those values

left_justify()

Returns a new PyText object, having removed a consistent amount of leading whitespace from the front of each line from the original so that at least one line is left-justified.

Warning

will not work with mixed tabs and spaces

remove_double_blanks(trim_whitespace=True)

Returns a new PyText object with any two blank lines in a row removed. If trim_whitespace is True (default) a line with only whitespace is considered blank, otherwise it only looks for n

Parameters:

trim_whitespace – when True, treat whitespace as a blank line

classmethod text(content)

Factory method based on text passed in instead of reading from a file.

Parameters:

content – the Python source code for this object

class purdy.themes.Theme(full_name, colour_map, inherit=None)

Encapsulates colourization theme information. Uses a dictionary mapping Pygments tokens to a colour code.

class purdy.tui.codebox.BoxSpec(width: int, line_number: int = None, auto_scroll: bool = False, border: str = '', title: str = '')

Used to describe each text area in the app that will be showing code.

Parameters:
  • width – relative width based on other boxes in the row. For example, row_specs=[Box_Spec(2), BoxSpec(1)] results in a single row where the first box takes up 2/3rds of the space.

  • line_number – Starting line number for code displayed in the box. Defaults to None

  • auto_scroll – True to scroll down when content gets added

  • border – A string specifying which borders are on for this box. Expects the letters “t”, “b”, “l”, “r” in any order for turning on the top, bottom, left, and right borders respectively. Defaults to no borders.

class purdy.tui.codebox.CodeBox(id, row_spec, box_spec)

Contains and controls content to be displayed to the screen. Wraps the display widget and includes the action methods for the purdy animations.

append(content)

Action: appends content to the CodeBox

Parameters:

content – Textual Markup, EscapeText, or a Code object

Returns:

this CodeBox so action calls can be chained

clear()

Action: wipes this CodeBox

Returns:

this CodeBox so action calls can be chained

highlight(*args, section_index=None)

Action: issue highlight commands to a Code block. See inside of this CodeBox. See highlight() for details on highlight specifiers.

Parameters:
  • args – series of highlight specifiers

  • section_indicator – Each thing added to the CodeBox is considered a section. This argument specifies the index of the section to apply the highlighting to. Defaults to None, meaning use the last section. It is up to you to make sure the section is the kind that supports highlighting.

highlight_all_off()

Action: remove highlighting from all Code sections within this CodeBox

Returns:

this CodeBox so action calls can be chained

highlight_chain(*args, section_index=None)

Action: Issue a series of highlight commands in sequence. Highlights the first, waits, turns it off, then highlights the next. Only works with Code blocks. See highlight() for details on highlight specifiers.

Parameters:
  • args – series of highlight specifiers. Each argument can also be a list to activate a set of highlight specifiers together

  • section_indicator – Each thing added to the CodeBox is considered a section. This argument specifies the index of the section to apply the highlighting to. Defaults to None, meaning use the last section. It is up to you to make sure the section is the kind that supports highlighting.

Returns:

this CodeBox so action calls can be chained

highlight_off(*args, section_index=None)

Issue highlight_off commands to a Code block. See highlight_off() for details on highlight specifiers.

Parameters:
  • args – series of highlight specifiers. Each argument can also be a list to deactivate a set of highlight specifiers together

  • section_indicator – The index number of the section to apply the highlighting to. Defaults to None, meaning use the last section. It is up to you to make sure the section is the kind that supports highlighting.

Returns:

this CodeBox so action calls can be chained

move_by(amount)

Action: scrolls this CodeBox by the given amount

Parameters:

amount – number of characters to scroll down, supports negative numbers for scrolling up

Returns:

this CodeBox so action calls can be chained

pause(pause, pause_variance=None)

Action: pause before next animation

Parameters:
  • pause – seconds to pause for

  • pause_variance – random amount to vary the pause by, defaults to None

Returns:

this CodeBox so action calls can be chained

prompt(prompt, answer, animate_answer=True, delay=0.13, delay_variance=0.03)

Appends two pieces of Textual markup into the CodeBox, first the prompt value, then waits, then animates the typing of the answer value. The answer appears on the same line as the prompt unless you explicitly include a newline.

Warning

This method only accepts Textual markup. It does not support EscapedText. Text with markup characters will need to be escaped manually

Parameters:
  • prompt – text to prompt with

  • answer – the answer to append

  • animate_answer – when True (default) use a typewriter animation for the answer

  • delay – Length of time to sleep between characters. Defaults to 0.13 seconds

  • delay_variance – amount of random variability in the typing delay. Defaults to 0.03 seconds

Returns:

this CodeBox so action calls can be chained

replace(content)

Action: replaces the content in this CodeBox with that provided

Parameters:

content – Textual Markup, EscapeText, or a Code object

Returns:

this CodeBox so action calls can be chained

set_numbers(starting_num)

Action: turn line numbering on for this CodeBox

Parameters:

starting_num – value to start the numbering with

Returns:

this CodeBox so action calls can be chained

text_typewriter(content, delay=0.13, delay_variance=0.03)

Action: performs a typing animation on Textual Markup or EscapeText.

Parameters:
  • content – Content to animate

  • delay – Length of time to sleep between characters. Defaults to 0.13 seconds

  • delay_variance – amount of random variability in the typing delay. Defaults to 0.03 seconds

Returns:

this CodeBox so action calls can be chained

transition(content=None, speed=1)

Action: performs a transition wipe animation then replaces the content in this CodeBox with that provided

Parameters:

content – Textual Markup, EscapeText, or a Code object

Returns:

this CodeBox so action calls can be chained

typewriter(code, skip_comments=True, skip_whitespace=True, delay=0.13, delay_variance=0.03, prompt_wait=False)

Action: performs a typing animation with the content in given Code object. Note that unlike most actions this one does not support Textual Markup, use CodeBox.text_typewriter() for that instead.

Parameters:
  • codeCode content to animate

  • skip_comments – When True (default) a comment is animated as a single item instead of typing it

  • skip_whitespace – When True (default) any block of whitespace is treated as a single item instead of each character within it

  • delay – Length of time to sleep between characters. Defaults to 0.13 seconds

  • delay_variance – amount of random variability in the typing delay. Defaults to 0.03 seconds

  • prompt_wait – When True, pause for interaction when at the end of a line beginning with prompt

Returns:

this CodeBox so action calls can be chained

update(content, ignore_auto_scroll=False)

Updates the content of the widget, typically shouldn’t be called directly.

wait()

Action: wait for a right arrow or skip command before proceeding to the next animation

Returns:

this CodeBox so action calls can be chained

class purdy.tui.codebox.RowSpec(height: int, boxes: list)

Container for a row of BoxSpec objects to describe a row in the display grid.

Parameters:
  • height – relative height of this row in comparison to others in the grid. For example [RowSpec(2, …), RowSpec(1,…)] produces two rows with the first taking up 2/3rds of the height of the screen.

  • boxes – a list of BoxSpec objects in this row