Skip to content

Copying text from an attached pane includes trailing spaces on every line (xshell; tmux does not) #217

Open

Description

@huangya90

Summary

When selecting and copying text from an rmux-attached pane in xshell, every
copied line is padded with trailing spaces up to the terminal column width. The
same selection under tmux in the same terminal does not include those
trailing spaces. Reproduced on rmux 0.10.0.

Steps to reproduce

  1. In xshell, run rmux (or rmux attach -t ). Terminal is wide
    (e.g. ~200 columns).
  2. Run any command that prints short lines, e.g. ifconfig enp0s8 .
  3. Select the output with the mouse and copy.
  4. Paste into any editor.

Expected behavior

Each pasted line ends right after its content, with no trailing whitespace
(what tmux produces in the identical terminal).

Actual behavior

Every line is padded with spaces to the full terminal width. Example (trailing
spaces shown as · ):

tony@tony-2204-dt:~$ ifconfig enp0s8···············································
enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500·······················
        inet 192.168.1.20  netmask 255.255.255.0  broadcast 192.168.1.255··········

Environment

• rmux: 0.10.0 (also reproduced on latest main , pulled today)
• Outer terminal: xshell
• OS: Ubuntu 22.04 ( tony-2204-dt )
• Control: tmux in the same xshell session → no trailing spaces

Root cause from AI, just FYI

rmux renders each internal grid row to the outer terminal using
GridRenderOptions { include_empty_cells: true, trim_spaces: false } . This
materializes trailing blank cells as literal space ( 0x20 ) bytes out to the
pane's full column width. The EL sequence ( \x1b[K , erase-to-end-of-line) that
would clear those spaces is only emitted under a narrow optimization gate, so in
the common case the literal spaces survive in the outer terminal's grid and a
selection copy includes them.

tmux, by contrast, clears to end-of-line on every rendered row, so the outer
terminal's trailing cells stay empty and copies are clean.

Full-redraw path — crates/rmux-server/src/renderer/pane_screen.rs

• The clean path is gated by sparse_full_width_clear (line 146), which requires
pane.x == 0 && pane.cols == terminal.cols && pane_default_style(...).is_none()
&& copy_mode_overlays.is_none() .
• include_empty_cells: !sparse_full_width_clear and trim_spaces: false
(lines 162–163) — when the gate is false, trailing blank cells become literal
spaces.
• \x1b[K is emitted only inside if sparse_full_width_clear { ... }
(lines 213–218).

Incremental render path — crates/rmux-server/src/renderer/pane_delta.rs

• Also uses include_empty_cells: true, trim_spaces: false (lines 204–205).
• \x1b[K is emitted only when compact_plain_ascii_line_delta(...) returns
clear_to_eol == true (lines 301–307). Per the tests, that is limited to the
full-width-line-shrinking case ( pane_delta_clears_full_width_line_when_plain_ascii_shrinks ,
line 1213) — ordinary output lines do not clear to EOL.

Supporting evidence

• The cell-level renderer writes spaces for blank trailing cells when
include_empty_cells: true + trim_spaces: false
( crates/rmux-core/src/grid/cell.rs , around lines 944–946 and 1349).
• The team already exercises the EL mechanism in
crates/rmux-server/src/renderer/erase_wrap_tests.rs:36
( \x1b[2;1H\x1b[0m\x1b[K ) — but only on the sparse path.

Suggested fix

Decouple "clear trailing cells to end-of-line" from the "pane is full-width /
has no style" optimization. In both pane_screen.rs and pane_delta.rs , emit
\x1b[K at the end of every rendered row — applying the pane's default
background style beforehand and resetting after, exactly as tmux does. This keeps
the outer terminal's trailing cells empty (clean copies) while still allowing
background-color fills to render correctly. When include_empty_cells must stay
true for background fill, the literal fill spaces should be followed by an EL
so they do not survive in the outer terminal's grid.

Activity

  1. self-assigned this
    on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions