FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Add a vertical (side) status line by dewyze · Pull Request #5468 · tmux/tmux · GitHub

/ tmux Public

Add a vertical (side) status line - #5468

Open
dewyze wants to merge 15 commits into
tmux:masterfrom
dewyze:vertical_status_line
Open

Add a vertical (side) status line#5468
dewyze wants to merge 15 commits into
tmux:masterfrom
dewyze:vertical_status_line

Conversation

dewyze commented Aug 4, 2026
edited
Loading

Copy link
Copy Markdown

Hello, I saw the vertical status line issue and decided to take a shot at it with an LLM. I would call this "Human directed, LLM Written." I am not a C dev, I'm a ruby dev, but did my best to direct it based on previous art, some QA, and asking it to do its best to act like @nicm in PR review.

I know that LLM generated PRs created a bigger burden for maintainers when the PR author doesn't have full context, and I acknowledge if this missed the mark, or is too much work in that area, let me know.

That being said, happy to address any and all feedback you have to help this land. I include a screenshot of a separate plugin I am working on and will publish after this to get the "herder" type feel, that is ultimately my goal here, I don't want to leave tmux.

Let me know how I can help! -- John

--- BELOW THIS LINE IS LLM GENERATED ---

Implements the vertical status line described by @nicm in #4910.

What this does

A vertical status line ("side status line") at the left or right of the terminal, drawn from formats like the existing status line:

0:editor                $ ...window content...
1:server*
2:logs-

Three new session options:

  • side-status (off/left/right, default off) — enable and position.
  • side-status-width (default 24) — fixed width in columns.
  • side-status-format[] — format array; each member may produce multiple rows. The default shows one row per window using the window status styles (not the window status formats, which lay text out for a horizontal line); with more than one session it shows a clickable row per session with the current session's windows indented below it, so clicking a collapsed session switches to and expands it.

It reuses status-style and status-interval rather than adding parallel options, and works instead of or in addition to the horizontal status line (status off + side-status left gives vertical only).

Against the requirements from #4910

  • "a way to express new line here" — a new nl style (#[nl]), plus literal newlines in the expanded string. Because #[...] passes through format expansion untouched, #[nl] can be emitted conditionally inside #{W:...}/#{P:...} loops, so a loop produces one row per item. Colours, attributes and any open range carry over the break (an open range is closed at the end of the row and reopened on the next, giving one range per row).
  • "ranges would need a y position as well as an x range" — struct style_range gains a y field, stamped with the row a range was drawn on. The side status keeps one flat y-aware range list; the horizontal status line's per-line lists are unchanged.
  • "trimming and keeping the current window visible" — rows drawn under list=on form a vertical list section trimmed to the available height and scrolled to keep the list=focus row centred; rows drawn under list=left-marker/list=right-marker replace the first/last visible list row when rows are hidden above/below. Same syntax as the horizontal list, transposed.
  • Mouse — clicks on the bar resolve ranges by column and row and fire the existing MouseDown1Status/...StatusDefault/etc. bindings (no new key names); mouse_status_range, mouse_status_line, mouse_x, mouse_y work with bar-relative positions. Window-area clicks subtract the bar's columns everywhere the status lines are already subtracted from rows.

Commit structure

The first three commits (y on ranges, the nl keyword, the default-aligned list fix) stand alone and can go in as a separate change first if you prefer — happy to split the PR. The first three commits are behaviour-preserving and independently useful (y on ranges, the nl keyword, format_draw_lines); one small fix (default-aligned lists were silently dropped by format_draw); then options, geometry, rendering, mouse, docs. Each commit builds cleanly.

Known tradeoff

With any side bar no pane is ever full-width, so the linefeed/scroll fast paths fall back to region redraws on terminals without DECSLRM left/right margin support. Terminals with margins (xterm, iTerm2, wezterm, recent VTE) are unaffected. This is the same cost vertically-split panes already pay, but the bar imposes it on full-screen panes too.

Naming (side-status-* vs something else) and the default format are easy to change if you'd prefer different colours on this bikeshed.

QA / testing

Regress: regress/side-status.sh (golden scenes for left/right/coexistence/width/off, regenerate with GENERATE=1). The full regress suite passes except screen-redraw-menus.sh, which fails identically on unpatched master on macOS.

Quick start:

./tmux -Ltest -f/dev/null new -A -s test
set -g side-status left            # bar appears, window shrinks
set -g side-status right           # moves to the right
set -g side-status-width 30        # resizes
set -g status off                  # vertical only
set -g mouse on                    # click a window row to select it

Worth exercising interactively:

  • Create/kill/rename windows: the bar updates immediately; more windows than rows scrolls the list around the current window with ^/v marker rows.
  • Both status lines on (status 2 + side-status left), messages and the command prompt (they overdraw the bar and restore on the next redraw), display-popup and menus over the bar.
  • Mouse: click window rows (select), pane clicks/drags land on the right cells with a left bar, border drag-resize, split-window/join-pane mouse targets.
  • Resize the terminal below side-status-width + 1: the bar disables itself; above: it returns.
  • window-size latest with two clients of different widths attached to the same session; zoomed panes; a window bigger than the client (panning).
  • Scroll a full-screen pane (e.g. yes) on a terminal without margin support to feel the redraw cost described above.

🤖 Generated with Claude Code

dewyze and others added 9 commits August 4, 2026 13:22
Ranges so far only carry a start and end column; areas spanning multiple
rows (such as a vertical status line) need to know which row a range is
on. Add a y field, zeroed by the existing producer in format_draw, and a
style_ranges_get_range_at helper to look up a range by both column and
row. No behaviour change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ
Parsed like push-default and friends into a transient flag on the style
that a consumer drawing a multi-row area can act on and reset; nothing
reads it yet, so it is accepted but ignored everywhere. The field is
called nl rather than newline because term.h defines newline as a
macro.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ
format_draw silently discarded the list and after screens when the list
was entered without an explicit alignment; the shipped formats always
set align so this was never visible. Treat a default-aligned list as
part of the left, the same as ordinary default-aligned content. Needed
so that a single row of a multi-row format, which renders without the
caller's alignment context, keeps its list content.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ
Split an expanded format into rows at nl styles and literal newlines,
carrying colours, attributes and any open range over the break; a range
open at a break is closed at the end of the row and reopened on the
next, so a multi-row region becomes one range per row, each stamped
with the screen row it was drawn on.

Rows whose text is drawn under list=on or list=focus form a list
section that is trimmed to the available height and scrolled to keep
the focus row visible, with rows drawn under list=left-marker and
list=right-marker replacing the first and last visible list row when
rows are hidden above or below. Each row is then drawn by format_draw,
so per-row alignment, trimming and ranges work as on the status line.

Nothing calls this yet; it is for areas spanning multiple rows such as
a vertical status line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ
side-status enables a vertical status line at the left or right of the
terminal, side-status-width sets its width and side-status-format is an
array of formats where each member may produce multiple rows with the
nl style. The position and width are cached in the session like the
existing status line, with side_status_size, side_status_at_column and
side_status_rows accessors. Nothing draws the side status line yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ
When side-status is on, the window area loses side-status-width columns
and, for a bar on the left, shifts right by the same amount: window
size calculation, the panning offsets, the scene draw coordinates, the
immediate pane output offsets and cursor placement all learn the shift,
mirroring what status_line_size already does for rows. Nothing draws
into the reserved columns yet.

The full-width tty fast paths need no change: with a left bar the x
offset is nonzero and with a right bar the pane is narrower than the
terminal, so they disable themselves.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ
Add a side status screen to the client, drawn by side_status_redraw:
the side-status-format array members are expanded, joined with newlines
(a newline starts a new row, so each member's rows follow the previous
member's) and drawn with format_draw_lines using the status-style
colours. The joined expansion is cached so an unchanged bar is skipped
without any terminal output, like the existing status line.

The bar is composited in redraw_draw as per-row partial lines before
the status line, so a full-width message or prompt overdraws it, and
redraws whenever the status line would: no new client flag is needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ
Save the side status position and width in the mouse event and check
clicks against the side status ranges by column and row, reusing the
same range-to-location resolution as the status line (factored into a
helper), so the existing MouseDown1Status and friends fire for the side
status line too and no new key names are needed.

Clicks in the window area subtract the side status columns wherever the
status lines are already subtracted from the row: pane resolution,
cmd_mouse_at, the border drag handlers, menu placement and the window
menu. The mouse_status_line, mouse_status_range, mouse_x and mouse_y
formats resolve side status clicks with positions relative to the bar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017EBimQYoNdaRG5SvwSSmPJ

mgrant0 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

What happens when there's more than one status line? e.g. set -g status 3

nicm commented Aug 5, 2026

Copy link
Copy Markdown
Member

This looks like the right idea on a quick look.

I don't think we should support more than one side status line.

I'm not that wild about the name "side" but it will do for now.

What is the point in side-status-format being an array when you can only have one side status line?

I think the default green background is too bold for the right status line and instead it should probably be green-on-black with a line on the right (ACS x).

The default width of 24 is far too wide, make it 10.

Do not use ^ and v for up and down markers, they look horrible, use ACS arrow characters (- and .).

I like the default tree view but it'd look nicer if the child items also had arrows, like tree mode (I just changed it to use an ACS arrow also).

Functions in status.c should have a status_ prefix so side_status_size should be status_side_size etc.

nicm moved this from Not Started to Waiting in Open Issues & PRs Aug 5, 2026
dewyze and others added 5 commits August 5, 2026 08:06
Requested by nicm: functions in status.c should be named status_side_*.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Requested by nicm: 24 is far too wide.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Requested by nicm: ACS up and down arrows instead of ^ and v for the
list markers, and tree mode style ACS branch markers and arrows for the
current session's windows in the sessions view, matching the tree mode
default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Requested by nicm: the status-style green background is too bold for the
side status line, so give it its own side-status-style option defaulting
to green on black and draw an ACS vertical line on the edge next to the
window area. The line takes the edge column out of the side status
width; format_draw_lines gains a starting column so content on a right
side status line begins after the line, and the range lookup skips the
line column.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The default style, width, format glyphs and the edge line changed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

dewyze commented Aug 5, 2026

Copy link
Copy Markdown
Author

@nicm Thanks, all pushed:

  • status.c functions renamed to status_side_*.
  • Default width 10.
  • ACS up/down arrows for the list markers; the sessions view uses the
    tree mode branch markers and arrow (tq/mq + +).
  • Default style is green on black with an ACS x line on the edge next
    to the window area, taken out of side-status-width. I read "line on
    the right" as the separator against the window area; easy to flip if
    you meant otherwise.

Width: 10 as asked, but the line and branch markers leave five columns
for a window name, so most truncate. 14 leaves nine. Not attached,
screenshots below. Thoughts on 14?

Style: status-style couldn't give green on black here, so I added
side-status-style. The alternative is colors in the default format
string, but blank rows below the content would still fill from
status-style. Happy to switch if you prefer.

Array: each member adds its rows below the previous one, so a plugin
can append rows without clobbering the user's format. If you don't see
value there for multiple plugins to be able to contribute I'll fold it to a single string.

Width: 10

Width 14:

dewyze commented Aug 5, 2026

Copy link
Copy Markdown
Author

@mgrant0

The horizontal status rows keep the full terminal width; the bar fills
the remaining rows above (or below with status-position top). So
status 3 plus side-status left gives three full-width rows at the
bottom and the bar in the rest. Screenshot: status 3, a popup, and
more windows than rows (the arrow is the scroll marker).

nicm commented Aug 5, 2026

Copy link
Copy Markdown
Member

I think a single option is fine.

Width 14 or even 16 is OK.

Requested by nicm: a single option instead of an array, and 14 for the
default width so the default format's window names fit beside the edge
line and tree markers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

dewyze commented Aug 5, 2026

Copy link
Copy Markdown
Author

Done: side-status-format is a single option and the default width is 14.

dewyze commented Aug 5, 2026
edited
Loading

Copy link
Copy Markdown
Author

One question I have, is does it make more sense for a side bar (is "vertical status bar or side bar" a better name?) to actually extend to the bottom and the bottom status line stops at the side bar? I think in most other apps, the side bar wins, but I also don't want to break years of tradition on this one.

I don't have a strong opinion, I imagine most people can customize their setup and if they want both on at the same time they can adjust their lines to be what they want.

nicm commented Aug 5, 2026
edited
Loading

Copy link
Copy Markdown
Member

We don't call it the "status bar", it is the "status line". So really this should be "status column" but that is a bit weird...

I personally would keep it so it does not shorten the status line, I think it would look odd since for most people the bottom row will be empty.

dewyze commented Aug 6, 2026

Copy link
Copy Markdown
Author

Maybe "status panel" Is the most accurate? It's not a line or a sidebar (despite it being on the side), it's the idea of more space than a line?

Either way, are the next steps just time to review? Otherwise let me know anything else I can help with.

nicm commented Aug 6, 2026

Copy link
Copy Markdown
Member

I think "side status" is probably OK for now, but I'll think about it.

I will need to take another look at it but I am away all next week so it will not be until after that.

This will be a 3.9 feature in any case, so it will wait until 3.8 is tagged before it goes in.

nicm moved this from Waiting to For Review in Open Issues & PRs Aug 6, 2026
nicm mentioned this pull request Aug 6, 2026
18 tasks
dewyze added a commit to dewyze/tmux-agent-bar that referenced this pull request Aug 12, 2026
- Screenshot from tmux/tmux#5468 up top, with a caption explaining the
  vertical bar's glyphs.
- Setup is one section (bar + hooks), with vertical mode as a delta:
  same install, one option, build tmux from PR #5468 until 3.9.
- Match-your-theme section for scripts/adopt-theme.sh.
- Fix the config table (@agent_bar_trace row was orphaned mid-table).
- Architecture moved to the bottom; Claude-only status made explicit
  with a PRs-welcome pointer to the two-file harness recipe.
- Rename-hotkey recipe (@agent_name is just a pane option).
- Roadmap item 9 now points at the open PR instead of issue #4910.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: For Review

Development

Successfully merging this pull request may close these issues.

3 participants


Back | FazBrowse Home | New Git URL