Blog
Making Markdown tables line up in any terminal
A Markdown table is supposed to line up. In a terminal it often
doesn't: put a column of ✅, ⚠️ and ★ next
to each other and the box drifts a character at a time until the borders go
ragged. editxr 1.6 fixes that — and the honest fix turned out to be
to stop guessing.
│ Panic attack │ ★ │ ⛔ │ Generate │ │ Fear │ ✓ │ ⚠️ │ Partial │ ← this row used to slip left │ Loss of a pet │ — │ ⛔ │ Generate │
Why terminal tables drift
A terminal is a grid of fixed cells, and every glyph occupies a whole number of them — one column or two. To draw a border in the right place, the editor has to know that width for each character. ASCII is one, most CJK is two; those are easy. Emoji and symbols are where it falls apart.
★ (U+2605) and ✓ (U+2713) look like emoji but most
terminals draw them narrow, one column. ✅ and
⛔ take two. And ⚠️ depends on the terminal:
Terminal.app draws it narrow, iTerm2 with "Unicode 9 widths" draws it wide — and
that's a per-user setting. There is no static table of widths that is correct
everywhere. Guess two columns for a glyph the terminal draws in one, repeat it
down a status column, and every border below slides over by one.
Measure, don't guess
So editxr stopped guessing and started asking. On startup it prints each
unusual glyph off-screen and sends the one question every terminal answers —
ESC [ 6 n, "where is the cursor now?" — then reads back the column
and takes the difference as the glyph's true width. Whatever your terminal and
your settings actually do, editxr measures it and lays the table out to match.
It re-measures when you open a file that brings in symbols it hasn't seen, and
when there's no terminal to ask — a pipe, a test, a silent terminal — it falls
back to a sensible heuristic instead of hanging. Curious what your terminal does?
editxr --probe-widths prints the measured width of each symbol next
to the built-in guess.
And a smaller nicety: tables that agree with each other
Once each table lines up on its own, the next thing you notice is that two
tables in the same document don't line up with each other. So editxr now
pads every table out to the width of the widest one, so their borders run
straight down the page. It's on by default; toggle "Align tables to widest" from
the command palette (Ctrl+/) if you'd rather each table keep its
natural width.
A sidebar came along too
The same release adds a docked left sidebar with two modes. Outline
lists the document's headings and follows your cursor as you scroll — press
Enter on one to jump there. Files is an explorer for
the current directory. Tab moves focus into the panel, arrows (or
j/k) move, Enter opens a file or jumps to a
heading, and Esc hands focus back to the editor. Both modes live
behind the palette.