Skip to content

fix: load tmux config from symlink and honor set -q#68

Open
teng-lin wants to merge 2 commits into
Helvesec:mainfrom
teng-lin:fix/tmux-config-symlink-and-set-q
Open

fix: load tmux config from symlink and honor set -q#68
teng-lin wants to merge 2 commits into
Helvesec:mainfrom
teng-lin:fix/tmux-config-symlink-and-set-q

Conversation

@teng-lin

@teng-lin teng-lin commented Jun 27, 2026

Copy link
Copy Markdown

Fixes #67.

rmux silently ignores a standard oh-my-tmux install when used as the tmux-config fallback, and — once the config does load — startup hangs ~20s. Three independent issues, fixed in three commits.

1 — set -q is parsed but discarded

oh-my-tmux uses set -q -g status-utf8 on / setw -q -g utf8 on for options removed in newer tmux. tmux’s -q suppresses “unknown/ambiguous option” errors; rmux parsed -q and threw it away, so those lines raised invalid option: status-utf8. A single config error discards the entire file, so the whole config was dropped.

Now -q is captured into SetOptionFlags.quiet and suppresses unknown/ambiguous-option errors from resolve_set_option_scope (returning a no-op), matching tmux.

2 — the tmux-fallback reader rejects all symlinks

read_tmux_compat_source_entry used symlink_metadata + O_NOFOLLOW and rejected any symlink. Because the fallback path is best-effort, the error is swallowed — no message, no config. oh-my-tmux installs ~/.config/tmux/tmux.conf as a symlink, so it was silently skipped.

The symlink hardening (commit 2fd8872) was only meant to avoid blocking on a symlink→FIFO. Now the reader follows symlinks but stats the target (fs::metadata, which never blocks on a FIFO) to still skip FIFOs/dirs/devices, and keeps O_NONBLOCK as a second guard.

3 — a slow config run-shell freezes startup

Config run-shell commands run synchronously during startup config load, and the config-loading guard they hold gates client readiness. A command that blocks therefore makes rmux startup hang until the client’s 20s deadline. oh-my-tmux triggers this: its TMUX_PROGRAM detection / _apply_configuration shell out to the tmux binary against rmux’s socket and stall ~20s.

The daemon now releases the readiness guard after a short budget (2s) while the config keeps executing in the background — so a slow command no longer blocks startup. Normal configs finish far inside the budget and are never delayed; execution is not cancelled, so commands still complete and nothing is orphaned.

Verification

Real symlinked oh-my-tmux: startup drops from ~20s (hang) to ~2s, exit 0, options applied:

base-index 1   pane-base-index 1   history-limit 5000
escape-time 10   renumber-windows on   monitor-activity on

A plain rmux config still starts in ~0.02s (budget never triggers).

Tests

  • tmux_best_effort_source_follows_symlink_to_regular_file — symlink→regular-file is loaded.
  • startup_readiness_clears_before_a_blocking_run_shell_finishes — readiness clears before a blocking run-shell finishes (asserts the load task is still running, so it genuinely exercises the budget path).
  • Existing tmux_best_effort_source_skips_symlink_to_fifo_without_blocking still passes.
  • Full suites green: rmux-server (1648) and rmux-core (77); clippy clean.

Out of scope

Full oh-my-tmux theming still won’t work — it depends on the tmux binary via $TMUX_PROGRAM (re-detected via lsof, which rejects rmux’s internal daemon binary) and a deep _apply_configuration pipeline of bare tmux/rmux subcommands. This PR makes rmux load the config’s plain options and not hang; full oh-my-tmux compat is a separate effort tracked in #67.

Two bugs caused rmux to silently ignore a user's tmux config (e.g.
oh-my-tmux), both required to reproduce:

1. `set -q` was parsed but discarded, so options removed in newer tmux
   (`set -q -g status-utf8 on`, `setw -q -g utf8 on`) raised "invalid
   option" errors. A single config error discards the whole file, so the
   entire config was dropped. Capture `-q` and suppress unknown/ambiguous
   option errors (returning a no-op), matching tmux semantics.

2. The tmux-fallback reader rejected all symlinks via symlink_metadata +
   O_NOFOLLOW, silently skipping the symlinked ~/.config/tmux/tmux.conf
   that oh-my-tmux installs (the error is swallowed on the best-effort
   path). Follow symlinks but stat the target so FIFOs/dirs/devices are
   still skipped; keep O_NONBLOCK as a second guard against blocking.

Add a regression test that the best-effort tmux fallback follows a
symlink to a regular file.
@teng-lin teng-lin closed this Jun 27, 2026
Config `run-shell` commands run synchronously during startup config load,
and the config-loading guard they hold gates client readiness. A command
that blocks therefore makes `rmux` startup hang until the client's 20s
deadline expires. oh-my-tmux triggers this: it shells out to the tmux
binary against rmux's socket (TMUX_PROGRAM detection / _apply_configuration),
which stalls ~20s.

Release the readiness guard after a short budget (2s) while the config
keeps executing in the background, so a slow command no longer blocks
startup. Normal configs finish far inside the budget and are never delayed;
only a pathologically slow config releases readiness early. Execution is
not cancelled, so the commands still complete and nothing is orphaned.

Add a regression test that readiness clears before a blocking run-shell
finishes (with a short test-only budget).
@teng-lin teng-lin reopened this Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tmux config silently ignored: symlinked ~/.config/tmux/tmux.conf and set -q options

1 participant