Skip to content

ADR 0073: The command line moves to the status bar

Status

Accepted

Context

The : command line was a centred floating panel, one per buffer, in the same family as Find/Replace and Open/Save-As (ADR 0022, ADR 0025).

Every other part of vim's bottom line had already arrived in the status bar and stayed there: the mode label (ADR 0046), messages (ADR 0062), the language-server segment (ADR 0063), and the position readout (ADR 0023). Command entry was the one piece that floated somewhere else.

That mattered more with / search coming. A floating / is not what anyone who types / is expecting, and putting it in a panel would have meant two search surfaces with no clear division between them.

There is precedent for moving chrome off centre rather than defending the design system: ADR 0026 moved find/replace to the top-right on direct feedback that a centred panel sat on top of the text being searched. A : prompt over the code is the same complaint one step further.

Decision

The : line lives in the status bar

CommandLine stops being a FloatingPanel and becomes a plain widget in the status bar: a prompt label and a SmoothLineEdit, no badge, no frame, no scale+fade. The prompt character is the affordance, which is what vim has always relied on.

One instance for the window rather than one per buffer, re-pointed at whichever viewport is active — the shape OutputPanel already uses, and for the same reason: there is one status bar.

While the prompt is up, it takes the mode and message area

The bar has four tenants. The prompt displaces the two on the left and leaves the two on the right alone:

closed prompt open
left mode label prompt + field
middle message prompt + field
right LSP segment unchanged
far right Ln, Col unchanged

Displacing the position readout was never considered — :42 is a command about a line number, and hiding the line number while it is typed would be perverse. Vim keeps the ruler for the same reason.

It fades; it does not scale

Floating panels open with scale+fade (ADR 0022). This does not. The status bar is a fixed strip, and scaling a line of it reads as the chrome itself moving rather than as something appearing in it. A fade at the existing kChrome tier (ADR 0053), no new duration.

Find/Replace stays a floating panel

Ctrl+F is unchanged. It has two fields, which do not fit on one line, and vim's own answer to replace is :s/a/b/ — through the command line anyway (ADR 0102 added it). So the division is by shape, not by audience:

  • status bar line — : commands, and / ? search: one field
  • floating FindBar — find and replace: two fields

Ctrl+; still opens the command line, now the status-bar one. Same two-bindings-two-audiences split as gd/F12 (ADR 0067).

Consequences

CommandLine is no longer a FloatingPanel, so it loses that base's animation, dragging, snapshot machinery and theming hooks — all of which it either did not want or now does differently. isModalPanelOpen() asks it isPromptOpen() rather than isVisible(), since a status-bar widget's visibility is managed by the bar.

One trap, worth writing down because it cost real time: QStatusBar sizes itself from every item it holds, including hidden ones. A QLineEdit's size hint is two pixels taller than a QLabel's, so merely adding this widget grew the bar by 2px and moved every other label in it — with the prompt closed, and on every screen. The line edit's height is now pinned to the prompt label's. QStatusBar::addWidget() also shows what it is given, undoing a hide() in the constructor.

A ~2px gap remains between the prompt character and the text, from QLineEdit's own fixed internal margin, which setTextMargins(0,…) does not remove. Left alone rather than subclassing the paint path for two pixels.

/ and ? are now a prefix on an existing surface rather than new UI, which is the point of doing this first.