github jchultarsky/mirador v1.21.0
1.21.0 - 2026-10-08

4 hours ago

Release Notes

Changed

  • The Windows build carries the default config with the same line endings
    as every other build.
    It used to embed the file as the build machine's
    checkout wrote it, which on Windows is CRLF, so --print-config and the
    first-run config differed from macOS and Linux for no reason in the code.
    The repository now asks for LF everywhere. A config already on disk is
    untouched, and edits keep whatever endings it has.
  • Every dialog punches its title into the border. The w picker's
    PANELS and a prompt's label — ADD A CLOCK, WEATHER LOCATION,
    AGENDA FILE — were laid on the border bare, where the theme picker, the
    key map and every panel draw ┤TITLE├. All four dialogs now draw it the
    same way, and one too narrow for its title cuts it with … rather than
    letting the corner take the closing ├.

Fixed

  • An absurd pomodoro length is refused instead of overflowing. The three
    [pomodoro] lengths were checked only for being above zero, and the panel
    turns minutes into seconds unchecked, so a hand-edited length too large
    for that sum crashed a debug build and gave a release build a phase of
    some other length nobody wrote. Like the weather, markets and news refresh
    settings, each now stops at a year, and a config past it is refused with
    the key named.
  • --migrate-config no longer overwrites an earlier backup. It copied the
    original to config.toml.bak whether or not that name was taken, so the
    config a --reset-config had set aside there, or an earlier migration's
    backup, was replaced for good. It now takes the next free number, as the
    resets do.
  • The error for a key from an older version points at --migrate-config
    exactly when the migration would fix the file.
    The error kept its own list
    of those keys, and the list had three of the four the migration fixes, so a
    pre-0.1.0 [notes] side_by_side_min_width was told to read --print-config
    instead. It went by the key's name alone, where the migration also needs
    the right table, so forecast_days under [clocks] was sent to a migration
    that then refused it. And it promised an update in place wherever the key
    matched, though the migration writes nothing when the result would still
    not load: a forecast_hours added beside the stale forecast_days was
    refused as a duplicate. The error now asks the migration about the line the
    parser stopped on and whether it would finish. When it would, the error says
    what it will change; when it would not, it says what the line becomes and
    the first problem that stops the migration, by line.
  • The theme picker draws the theme it is previewing on a short terminal.
    Its list kept a twelve-row window in a dialog sixteen rows tall, so on a
    terminal under sixteen rows the foot of the window was cut, footer first,
    and End or ↓ previewed a theme whose name was nowhere on screen. The
    list now scrolls within the rows the terminal leaves it, as the w
    picker's does, the footer gives way to nothing but the row of the theme
    being previewed, and a page moves as far as the rows drawn.
  • A dialog's keys drop whole on a narrow terminal, and Esc goes last.
    The w and t pickers drew their key rows at full width and the terminal
    cut them wherever the edge fell — Esc put with no back, and narrower
    still the keep hint whole and Esc gone without a mark. The key map's row
    dropped from the end, so a narrow one said how to reload and not how to
    leave, and a prompt on a screen under twenty columns measured its help
    for the twenty it asked for. Every dialog's keys now drop whole, the way
    out last, and Esc on its own and still too wide ends in …, as a
    prompt's help already did.
  • The w picker says when it has cut a message. The line under its list
    gives way to what was just refused or why the config could not be
    written, and most of those are longer than the dialog's forty columns —
    the edited config does not describe the requested layout — so the
    terminal cut them at every size, with nothing to show the rest was
    missing. They now end in …, and so does the usual line on a narrow
    terminal.
  • One refresh of the watchlist asks for each symbol once. An r, or an
    added symbol, while the markets panel waited out the minute it leaves
    between rounds was answered by the next round and then again a minute
    later, so it cost two requests a symbol against a source that blocks by
    address. Removing a symbol also threw away an r pressed
    just before it, and the board waited out the whole interval instead.
  • The markets panel copies its board when a price lands, not every
    frame.
    It cloned every quote with its intraday series once a second, for
    numbers that change once a minute, and redrew each sparkline from the
    whole series. Both happen when a quote lands now. A quote also keeps at
    most a thousand intraday prices, averaged down rather than cut: the
    request asks for 78, and nothing stopped an answer carrying two million.
  • A long task or note list builds only the rows on screen. Every task
    and every note in the list was turned into a row on every frame, through
    an index of the whole store rebuilt each time, for a panel that drew the
    twenty that fit. Scrolling, the selection and clicks are as they were.
  • The task form's placeholders say when they are cut. In a form narrower
    than about 27 columns, what needs doing was cut by the terminal to a
    whole-looking what needs d. The placeholders now end in … where they
    do not fit.
  • The disk panel's read and write rates are in the units of its
    capacity.
    The readout under each device borrowed the network panel's
    figures, which count a kilobyte as 1,024 bytes, beside free space and size
    counted in thousands, the way a disk is sold — so one device showed two
    meanings of MB, and a disk moving a hundred million bytes a second read
    95.4 MB/s. The rates are decimal now, with a decimal place below ten of
    a unit and whole figures above: 100 MB/s, 1.4 MB/s, 327 kB/s, and
    0 kB/s for an idle disk.
  • A temperature panel with no sensors marks the cut in its headline.
    Narrower than No temperature sensors, it showed as much of the words as
    fitted — No temperatu — with nothing to say the rest had gone. It ends
    in … now, as the disk and battery panels' empty states already did.
  • The shipped config and the README name every widget there is. The
    README's guide to the panels opened on "Fourteen widgets", and the
    config's Available widgets comment stopped at thirteen and left out
    memory, disk, battery and temperature — three of them the panels
    the default layout does not place, which a reader adding one by hand has
    to find by name. The README says seventeen, and the comment
    lists all seventeen now, in a new config and in --print-config; a config
    already on disk keeps the comment it was written with.
  • Adding a clock on a short terminal adds the city on screen. The zone
    list kept a ten-row window in a dialog fifteen rows tall, so on a shorter
    terminal its foot was cut, Esc cancels first, while ↓ walked on into
    rows nobody could see and Enter added one of them. The list now scrolls
    within the rows the terminal leaves it, as both pickers' do, a page moves
    as far as the rows drawn, and the help with the way out gives way to
    nothing but the field and the city under the cursor. On a terminal too
    short to draw that city, Enter waits rather than adding it; Esc still
    cancels.
  • An empty panel's notice says when its lower lines are cut. The disk,
    battery and temperature panels explain an empty face in a line or two,
    and a panel too short for all of them drew the first with nothing to say
    the rest was missing. The last line drawn ends in … now when a line
    below it had something to say.
  • A line cut through emoji is no wider than its room. An emoji written
    with its presentation selector, ❤️ or ☀️, or joined to another, 👩‍💻,
    is drawn two cells wide, and the cut that ends a long title or headline in
    … measured it a character at a time, as one. Each such emoji left the
    line a cell wider than its room, and the terminal cut the excess without
    a mark. The cut now measures them as they are drawn.
  • A prompt's caret stays after the text once the field is full. Typing
    past the width of a prompt's field — a long path to the agenda file, say —
    scrolls the text, and the caret stopped a cell short of the end and sat
    on the last character typed, hiding the one just entered. It now sits in
    the cell after the text, which the field always kept free for it.
  • The key map's footer names the keys its reset question takes. While
    d asked whether to put every key back, the footer still offered
    r reload, d defaults and Esc close, and each of them answered no
    instead. It reads y reset Esc keep until the question is answered.
  • A paste takes the update notice down at once. A paste retires the
    notice and marks the watch log read, as a key does, but the screen is
    redrawn after a paste only when something asks, and a paste the focused
    panel did not take asked for nothing. The notice, and a watch log rule
    line the paste had just made untrue, stayed up until something else
    redrew. Both now go with the paste, as they do with a click.
  • The agenda marks a meeting the moment it starts. The ▸ beside an
    event under way, and the status bar's in 3m before one, are worked out
    as the panel is drawn, and the panel asked to be drawn only when it read
    its calendar again. With nothing else on the dashboard redrawing, a
    meeting started unmarked and the countdown ran behind the clock until the
    next read: about a minute at the default, an hour at
    refresh_secs = 3600. The default layout hid it, because the clock
    redraws every minute. The panel now redraws when an event starts or ends,
    and as each minute of the countdown goes by.
  • An absurd [news].refresh_minutes is refused instead of overflowing.
    The feed interval is turned from minutes into seconds unchecked, and it
    was left out when the weather and markets intervals were bounded, so a
    hand-edited value large enough crashed a debug build at startup and gave
    a release build an interval of nothing at all: every feed fetched again
    and again with no wait. It now stops at a year like the others, and a
    config past it is refused with the key named.
  • A note too long for its reader says so. The notes panel draws as much
    of a note's body as fits and scrolls for the rest, but nothing on screen
    said there was a rest: the default dashboard showed the example note as
    You are reading it in the and stopped, and a cut that fell between two
    sentences looked like the end of the note. The last row drawn now ends in
    … while there is more below it.

Install mirador 1.21.0

Install prebuilt binaries via shell script

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/jchultarsky/mirador/releases/download/v1.21.0/mirador-installer.sh | sh

Install prebuilt binaries via powershell script

powershell -ExecutionPolicy Bypass -c "irm https://github.com/jchultarsky/mirador/releases/download/v1.21.0/mirador-installer.ps1 | iex"

Download mirador 1.21.0

File Platform Checksum
mirador-aarch64-apple-darwin.tar.gz Apple Silicon macOS checksum
mirador-x86_64-apple-darwin.tar.gz Intel macOS checksum
mirador-x86_64-pc-windows-msvc.zip x64 Windows checksum
mirador-aarch64-unknown-linux-gnu.tar.gz ARM64 Linux checksum
mirador-x86_64-unknown-linux-gnu.tar.gz x64 Linux checksum

Verifying GitHub Artifact Attestations

The artifacts in this release have attestations generated with GitHub Artifact Attestations. These can be verified by using the GitHub CLI:

gh attestation verify <file-path of downloaded artifact> --repo jchultarsky/mirador

You can also download the attestation from GitHub and verify against that directly:

gh attestation verify <file-path of downloaded artifact> --bundle <file-path of downloaded attestation>

Don't miss a new mirador release

NewReleases is sending notifications on new releases.