Skip to content

readaloud 2.0.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 08:45
· 32 commits to main since this release

The computational half of readaloud is now Rust, and a source file is read through its
syntax tree and coloured like an editor would.

A Rust core

  • Everything that is computation moved out of Python into a compiled extension,
    readaloud._core, built with PyO3 and maturin: terminal cell widths (wide CJK and
    emoji), the pronunciation engine, word and sentence splitting and chunking, the
    escape-sequence parser with its Markdown cleanup, and the alignment of Kokoro's
    timestamps onto the spoken words. The Python that remains is the interface: the
    config file, the document model, the TUI, playback.
  • Each port is checked against the Python it replaced, on random input as well as the
    known cases, so a file reads exactly as it did. The Unicode tables are generated from
    Python's own database, so the two sides never disagree about a character.
  • The Homebrew bundle ships the extension built on the macOS 14 runner with the pinned
    Rust; nothing is compiled on your machine.

Source code, read and coloured through its grammar

  • A .py file is parsed with tree-sitter and said node by node the way you describe
    it in a [syntax.py] section: def foo(bar: int, baz: str='') -> str: can be
    "function foo takes bar type int and baz type string with a default of empty string
    and returns type string", a | in a type annotation "or" and one between sets
    "pipe", foo().bar "foo dot bar", __init__ "dunder init". A rule names a node's
    fields ($name, $parameters), the node in full ($0) or its parts ($*), and may
    be confined to a context (type/binary_operator) or a field
    (function_definition.return_type). Comments, strings and docstrings are untouched
    unless a rule names them. See Syntax.
  • The file is coloured by the grammar's own highlights query, in the terminal's
    colours: keywords, strings, comments, function and type names. highlight = no or
    --no-color leaves it plain.
  • Grammars are plug-ins. readaloud ships the tree-sitter runtime and no grammar; a
    language's grammar is loaded at run time from its tree-sitter-<language> package
    (prebuilt wheels, no compiler) or from a Neovim parser/ directory. The Homebrew
    install has Python's; uv tool install readaloud --with tree-sitter-rust adds Rust.
  • Each spoken word lights the word it came from: "takes" lights the first
    parameter, "or" the type after the |, and a body of code keeps its lines.
  • A section can apply to one file type: [config.py], [parts.py], [shapes.py],
    [pronunciations.py] and [syntax.py] lay over the general ones for a file with
    that suffix, and markdown = no reads it as written, so code keeps its #, *args
    and underscores. See File types.

Shapes

  • Shapes and parts live in the config file, with none built in: a [shapes] line is
    a regular expression and how to say what it matched, [parts] the named pieces the
    patterns are built from. The shipped file reads settings.py:281-283 as "settings dot
    pie lines 281 to 283", localhost:8080 as "local host port 8080", a URL with its
    scheme, host, port and each slash of its path, and leaves a time as written.
  • Named shapes (param: /pattern/ = wording) let a wording say a list of any
    length: ${params|param|,=and} says every match of param in the group, with "and"
    for each comma. A shape may span 48 words and several lines.
  • What a shape or a rule says goes through the pronunciation entries and the patterns
    once more, so .py = dot pie and /__(\w+)__/ = dunder $1 apply inside them.

Config file: one change to make

  • The settings section is [config], not [readaloud]. A file that still says
    [readaloud] is warned about and its settings fall back to their defaults until the
    header is renamed. Everything else in an existing file reads as before.
  • The file a first run writes, and --write-config, is readaloud.conf shipped as it
    is, with one-line comments and the pronunciations in groups.

Other changes

  • follow_margin defaults to 5 rows: the spoken word stays about six rows from the top
    in follow mode, with the text below it in view.
  • The README no longer suggests mdcat --ansi notes.md | readaloud: a piped table reads
    line by line; -md reads it cell by cell.
  • tests/fixtures/edge-cases.md gathers the text that is hardest to read well, for
    listening to by hand.