Skip to content
gwmgwmgwmv1.10.0

v1.1.0

The first release driven by an outside report. Both features here come from #363, filed by @thachck: the sidebar layout not surviving a restart, and yanking being useless over SSH. Two small quality-of-life asks that each turned out to sit on top of a real defect.

The SSH one is worth spelling out, because it was not a plain failure. gwm only ever shelled out to the host clipboard binaries, which write to the clipboard of the machine gwm runs on. Over SSH to a macOS host, pbcopy is found, runs, and exits 0 - so gwm reported yanked branch name (pbcopy) while the text sat in a clipboard nobody could reach. A success message and an empty clipboard is worse than an error, and it is also why the obvious design (“fall back to OSC52 when no tool is found”) would never have fired: a tool was found, and it did succeed.

Chasing both reports surfaced three further defects that predated them - the sidebar layout being dropped on a workspace repo swap, the Settings selection walking off screen on a short terminal, and the sidebar docs naming keys that have been wrong since #290. All are fixed below.

  • [tui] clipboard - OSC52 so yanking works over SSH (#367, #368; part of #363, reported by @thachck).

    [tui]
    clipboard = "auto" # auto (default) | osc52 | tools

    auto emits an OSC52 escape sequence when $SSH_TTY / $SSH_CONNECTION is set - handing the text to the terminal emulator, which owns the clipboard you actually paste from - and uses the host tools otherwise. osc52 and tools force either path. Covers all four yanks (path, branch, worktree name, command logs). The status bar names the route that ran ((osc52) / (pbcopy)).

    Under tmux the sequence is wrapped in DCS passthrough; inside GNU screen gwm falls back to the host tools rather than emit a sequence screen would silently swallow. Payloads over 64 KiB are refused rather than truncated into a corrupt paste. Framing and base64 come from crossterm’s CopyToClipboard (feature osc52) rather than being hand-rolled.

  • [tui] sidebar_orientation - persist the sidebar layout (#365, #366; part of #363, reported by @thachck).

    [tui]
    sidebar_orientation = "stacked" # auto | side-by-side | stacked

    The orientation was runtime-only and reset on every launch; only sidebar_position survived a restart. It is now seeded at startup and on config reload, and editable from the Settings panel’s TUI tab. Default stays stacked (the #217 launch layout). Unknown values are a hard error at load time, consistent with sidebar_position and tui.open.mode.

  • The sidebar layout was ignored when switching repos in workspace mode (#366). sync_active_repo replaced the active config wholesale without re-deriving the sidebar from it, so a per-repo [tui] override did not apply until a reload or relaunch. This hole predated the new key: sidebar_position had it since workspace mode landed (#36). Both knobs now go through one shared apply, called from all three sites where the config becomes authoritative.

  • The Settings selection could walk off screen on a short terminal (#368). The modal is 60% of the terminal height, so 24 lines leave about six body rows - but the renderer only scrolled the selection into view on the Keys tab, on the stated reasoning that the field tabs were “short enough to never need this”. They were not: the sixth TUI field was already off screen at 24 lines, letting you cycle and edit a setting you could not see. The existing mechanism is now used by every tab with a selection; the Worktree tab benefited too.

  • The sidebar docs named the wrong keybindings (#366). The defaults are v (position), Space (cycle layout) and V (show/hide), but the docs said H toggles the position and V cycles the layout. H has not done that since #290 gave h/H to the user macros - a reader following the docs would fire a macro or hide the sidebar. Corrected across the example template, both locales, and the doc-comments.

  • The oversized-clipboard message contradicted itself (#368). Truncating division rendered 65 537 bytes as 64 KiB > 64 KiB, exactly when refusing the copy.

  • SidebarState::orientation doc-comment claimed the default was auto (#365). It has been stacked since #217 - live documentation of a default that did not exist, and the kind of stale comment that talks the next person into seeding the wrong value.

  • The Settings choice lists are derived from their enums (#366). The panel writes the selected choice verbatim into .gwm.toml, so a list that drifted from the enum’s serde spelling would make the panel produce a file that no longer loads. label() is now a const fn and the lists are built from it, making that drift impossible to express.
  • Bumped regex 1.12.4 → 1.13.0 (#364).
  • crossterm gains the osc52 feature, which pulls base64 0.22 transitively. cargo audit --deny warnings stays clean.

No breaking change. Both additions are new keys inside the existing [tui] section, which the stability policy treats as additive.

One behaviour change worth flagging: clipboard defaults to auto, so yanking while SSH’d now routes through OSC52 instead of the remote host’s clipboard. That is the reported bug being fixed, but if you want the remote clipboard, clipboard = "tools" restores the previous behaviour exactly.

OSC52 is never acknowledged by the terminal - gwm can report that it emitted the sequence, never that the terminal took it. Three consequences, all documented in the schema reference:

  • tmux needs set -g allow-passthrough on (off by default since tmux 3.3). The DCS wrapper is necessary but not sufficient, and gwm cannot enable it.
  • $SSH_CONNECTION can be stale inside a tmux pane, so auto can guess wrong. clipboard = "osc52" / "tools" override the detection.
  • Terminal support varies - kitty, WezTerm, Alacritty and iTerm2 (with the setting enabled) honour OSC52; Terminal.app does not.

The OSC52 decision logic, escape framing and tmux wrapping are pinned byte-for-byte by tests, with the base64 vectors verified against the system base64 rather than only against the library that produces them. A real SSH → tmux → terminal round-trip was not exercised before release: there is no SSH host in the build environment and no acknowledgement to assert against. If it misbehaves in your setup, please reopen #363.