Fixing duplicated tmux status bars and missing icons in Termius on iPhone

My tmux status bar looked fine on Linux, but connecting to the same session from Termius on my iPhone left repeated copies of the bar at the bottom of the screen. Moving it to the top was a useful workaround. I wanted to keep it at the bottom and keep the desktop’s colors and useful widgets.
The fix was a compact renderer for clients below 100 columns, followed by a targeted replacement for an icon the phone could not render. This extends my one-job status renderer: the phone still uses one status job, and a desktop attached to the same session keeps its full layout. The app is Termius, although I initially called it Terminus.
What I could establish
The server was running tmux 3.5a. The iPhone client had 71 columns, while
one desktop client attached to the same ai session had 148 columns. Both
reported xterm-256color.
That ruled out a simple $TERM check as a way to identify the phone. The
terminal type described capabilities, not which device was attached.
After loading the first working fix, I checked the client-specific branch:
|
|
Recorded output from that stage of the debugging session:
|
|

This is a terminal illustration rendered from the recorded command output, not a screenshot of the iPhone. Client sizes changed during the session.
The phone and desktop selected different renderers even when they shared the same tmux session.
First, edit the configuration tmux actually uses
My first change went into an old copy under Documents/myConfig/, rather than
the active ~/.tmux.conf. The phone continued to duplicate the bar. Editing a
backup file does not change the running server.
I checked the active options and then changed the live configuration:
|
|
The global status setting was on, and the position was bottom. tmux was
not configured to intentionally show multiple global status rows. My separate
pane-border-status bottom setting adds pane labels; those labels are distinct
from repeated copies of the global bar.
Treat duplicate rows and missing icons as separate failures
A terminal draws text into cells. If tmux counts a symbol as one cell but the client renders it with a different width, the cursor positions after that symbol can disagree. Repainting a full bottom row can then leave artifacts. The Oh my tmux troubleshooting guide describes duplicated status rows caused by disagreements about Unicode widths.
That explanation was consistent with my symptom: the bar contained Powerline separators, Nerd Font icons, and a long quote. Switching the phone’s status text to ASCII stopped the duplication, and I confirmed that on the phone. I did not capture terminal traces that isolate one exact offending glyph, so this is a successful workaround for the observed rendering problem, rather than proof of a specific Termius implementation bug.
A missing icon is a different question. The font may not contain the requested glyph, even when the terminal positions the rest of the row correctly. Fixing width-sensitive output does not automatically add missing glyphs to a font.
Select the compact layout per client
The important setting in ~/.tmux.conf is:
|
|
The condition is true when the client has fewer than 100 columns, or when
@mobile-status is explicitly on. The format is evaluated for each client
when the status is rendered. Setting a user option to a format string does not
itself evaluate that string; #{E:@mobile-status-condition} expands it later
in the relevant client context.
There was a small trap here. My first condition used
#{<:#{client_width},100}. In the isolated test on tmux 3.5a, it returned false
at 20 columns: this comparison follows string ordering. The e|< expression
makes the comparison numeric, and all four narrow test widths then selected
compact mode.
Width is a practical heuristic, not a device detector. A narrow desktop also gets the compact layout, and a phone widened to 100 columns or more gets the full layout. To force compact mode for the current session:
|
|
To remove that override and return to width detection:
|
|
The explicit override is session-scoped. It also affects other clients
attached to that session; the automatic width branch is what lets my phone
and desktop differ in the same session. Setting the override to off does
not disable automatic detection in this particular configuration.
Keep the colors and widgets, simplify the text
The first working phone bar was too plain: short labels and a clock, with most of the desktop information missing. I kept the ASCII protection but restored the desktop’s blue session block, cyan active window, muted inactive windows, and metric colors.
My existing renderer reads finished widget strings from
~/.cache/tmux-status/. I added an ascii mode to it, rather than adding
another tmux #() job for every metric. The relevant options are:
|
|
These wrap my existing setup: @quote_cond controls the desktop quote, and the
background daemon supplies the cached widget values. They are not a complete
replacement for an arbitrary .tmux.conf.
The mobile call passes 0 to omit the quote. The desktop keeps its existing
quote rule. #{q:session_name} quotes the session name for the shell command.
The renderer still prints both sides of the status line, using
#[default align=right range=right] before the metrics and clock.
In ASCII mode, I replace the decorative symbols and metric icons before stripping other non-ASCII text:
|
|
This is an excerpt from the full renderer. The ASCII
#[...] color and alignment tags survive the filter, so the phone can retain
the same theme without drawing the original decorative characters.
| Phone label | Value |
|---|---|
C |
CPU usage |
M |
Memory usage |
CX |
Codex remaining quota |
CL |
Claude remaining quota |
J |
Traffic value |
Below 100 columns, the script also removes reset countdowns in the form
(HH:MM) and drops the decimal part of percentages. The clock remains
HH:MM:SS, but the date is omitted. The blue session block becomes yellow
while the existing Pomodoro timer is running, just as it does on the desktop.
This changes what fits on the phone: the quote, non-ASCII session text, and some detail in the metrics are intentionally omitted. It does not translate Unicode text. The desktop rendering path bypasses the ASCII filter.
The clock is produced by date, because my long-running tmux server had
previously retained an old timezone. That is covered in the
timezone post.
I applied the same client condition to the active and inactive window formats
and the pane-border label. Cleaning only status-left would have left symbols
in the other parts of the status display.
Select the font inside Termius
Installing a Nerd Font on the Linux server does not select the font used by the iPhone SSH client. The client receives characters and renders them with its own font.
Termius already bundles patched fonts. Its iOS changelog records Nerd Font v3 support in version 5.8.7, released August 7, 2024, including Meslo, JetBrainsMono, and FiraCode.
For a current Termius installation:
- Open the SSH terminal and expand the panel above the keyboard.
- Open Themes and select the font.
- Try Meslo or JetBrainsMono.
The mobile terminal documentation explains that font and theme choices are saved for the host.
A small test avoids using the whole status bar as a font diagnostic:
|
|
Selecting a font does not disable the ASCII branch in my config. Nor does support for some Nerd Font characters guarantee support for every icon used by a desktop configuration.
Replace the specific unsupported tmux icon
The next reported problem was . My window-name configuration used it both
for the multiple-pane indicator and for the tmux and screen commands.
I replaced those three mappings with the older Font Awesome columns icon:
| Purpose | Original | Replacement |
|---|---|---|
| Multiple-pane indicator, tmux, screen | — U+EBC8 |
— U+F0DB |
The replacement exists in the Font Awesome 4.7 icon definitions. It is a compatibility candidate for older bundled Nerd Fonts; its age alone cannot guarantee that a particular phone font renders it correctly.
I keep overrides in ~/.config/tmux/tmux-nerd-font-window-name.yml. These
settings are merged into its existing config and icons mappings:
|
|
My setup compiles that YAML and the plugin’s defaults into a native tmux
automatic-rename-format. The generated file is ~/.tmux/window-icons.conf.
I changed the YAML source and regenerated it, so the next generation would
not undo the icon fix:
|
|
The generator is included with this post. It expects
yq and the defaults from the installed tmux-nerd-font-window-name plugin.
If your setup reads YAML directly through that plugin, use its reload
mechanism instead of assuming this generated file exists.
The compact window format had another problem: its first filter replaced
Unicode characters with _, and unknown commands such as Codex contributed
a ? placeholder. I changed the displayed-name expression to:
|
|
It keeps printable ASCII plus the chosen columns icon, removes the literal
? placeholder, and limits the result to eight characters. In a shell-only
window whose original name is just a different icon, this filter can leave an
empty label; the window index remains available.
The server-side phone format changed from _ ? code to codex. This was
the recorded expansion for the 71-column client:
|
|
I verified that the new generated format differed from the old one only in
those three icon replacements, and that the host’s wcwidth() reports one
cell for . Neither check substitutes for looking at the phone. The
duplicated-row fix was confirmed on the device; the final replacement glyph
still needed visual confirmation there when this post was written.
Shared automatic window names also use the replacement on the desktop. The desktop’s status colors, metric renderer, and Powerline layout stay as before. Existing manually named windows can retain an old symbol: updating an automatic-name format does not rewrite every saved window name.
Reload the changed options and redraw the phone
During debugging, I loaded only the changed options from a small config
fragment, rather than restarting tmux or re-running every plugin. The final
settings are saved in ~/.tmux.conf, so normal config reloads retain them.
In my config, that binding is Ctrl+k, then r. The usual command is:
|
|
Then find the phone client and redraw its complete display to clear the old artifacts:
|
|
Use the actual client name from the first command, such as /dev/pts/99.
refresh-client -S redraws only the status; I used a full redraw to clear the
copies left elsewhere on the screen.
What was verified
| Check | Result |
|---|---|
| iPhone after the compact renderer was loaded | Duplicate status rows stopped; confirmed on the device |
| Isolated clients at 20, 40, 80, and 99 columns | Compact branch selected |
| Isolated clients at 100 and 148 columns | Desktop branch selected |
| Session override, removal, and config reload | Branches behaved as configured |
| Desktop renderer before and after the phone-style change | Output matched after normalizing the changing clock |
| Final generated icon mapping and compact label | replaced in three mappings; retained in the phone label |
The useful distinction was between layout, character width, and font coverage. Keeping the desktop colors did not require keeping every desktop symbol. I kept a conservative text renderer for the narrow client and allowed one explicit replacement icon in its window labels.
相关内容
- 配置强大终端: zsh+tmux+powerline+autojump
- tmux lag, round 2: every status-bar fork froze the server for 30 ms
- Why my tmux was laggy: the status bar was forking a 1.2 GB server 24 times a second
- Linux 时区、系统时间与 tmux 状态栏时间不一致的排查
- tmux: error while loading shared libraries: libevent_core 2.1.so.6
支付宝
微信

william