tmux-python / tmux-python/tmuxp

here mode level 2: eliminate send_keys entirely — split-window/swap-pane/kill-pane

Open
#1,032 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
4.6k
Forks
248
Avg merge
2h 13m
Merged PRs (30d)
1

Description

Parent: #1030

Approach

Eliminate all send_keys usage in --here mode by replacing the "mutate existing pane" pattern with "create fresh pane, swap into position." This is the cleanest possible approach — zero shell assumptions.

Core idea

Instead of sending cd, export, and shell commands to the existing pane (which assumes a POSIX shell is running), create a brand-new pane with the correct directory, environment, and shell, then swap it into the position of the original pane and kill the original.

Implementation

Replace builder.py:690-727:

# Before: send_keys cd, export, shell into existing pane
active_pane.send_keys(f"cd {shlex.quote(start_directory)}", enter=True)
for _ekey, _eval in environment.items():
    _here_pane.send_keys(f"export {_ekey}={shlex.quote(str(_eval))}", enter=True)
_here_pane.send_keys(window_shell, enter=True)

With:

# After: create fresh pane with correct state, swap into position
_active_pane = window.active_pane
assert _active_pane is not None

# Build split-window args
split_kwargs: dict[str, t.Any] = {}
if start_directory:
    split_kwargs["start_directory"] = start_directory
if environment:
    split_kwargs["environment"] = environment
if window_shell:
    split_kwargs["shell"] = window_shell

# Create new pane with correct dir/env/shell via tmux primitives
new_pane = window.split(**split_kwargs)

# Swap new pane into the position of the original
new_pane.cmd("swap-pane", "-t", _active_pane.pane_id)

# Kill the original pane (now in the split position)
_active_pane.kill()
How this maps to tmux commands
tmux split-window -c /path/to/dir -e KEY=VALUE [shell_command]
tmux swap-pane -t %original_pane_id
tmux kill-pane -t %original_pane_id
tmux version requirements
  • split-window -c: Available since tmux 1.9
  • split-window -e: Available since tmux 3.2 (tmuxp's minimum)
  • swap-pane: Available since tmux 0.8
  • All within tmuxp's tmux 3.2+ minimum requirement
Comparison with teamocil

teamocil uses send_keys cd for directory and split-window -c for new panes. This approach goes further than teamocil by eliminating even the cd send_keys call.

Trade-offs

Pros:

  • Zero send_keys for infrastructure — no shell assumption at all
  • Works regardless of what's running in the active pane (vim, python, fish)
  • Environment set at pane creation time via -e (tmux 3.2+)
  • Directory set via -c (tmux primitive)
  • Clean pane with fresh shell — no history pollution

Cons:

  • Destroys the user's existing shell state (history, local variables, aliases loaded via .bashrc)
  • Brief visual flash as the swap occurs
  • More complex than Level 1 — uses swap-pane + kill-pane which is unusual in libtmux
  • The existing pane is killed — if the user had unsaved work in a background process, it's gone
  • May need libtmux API additions if split() doesn't support -e kwargs yet
Behavioral change

This changes --here semantics from "modify the existing pane in-place" to "replace the existing pane with a fresh one." Users who rely on existing shell state in the first pane would lose it. This may be acceptable since --here is conceptually "rebuild this window" — but it should be documented.

Tests to add/update
  • Rewrite test_here_mode_provisions_environment to verify env via pane capture (new pane inherits env)
  • Rewrite test_here_mode_start_directory_special_chars to verify cwd without send_keys
  • Add test verifying --here works when active pane runs a non-shell program
  • Add test verifying original pane is replaced (pane count stays at 1)
libtmux prerequisites

Check whether window.split() supports:

  • environment kwarg (maps to -e KEY=VALUE)
  • shell kwarg (maps to the shell/command argument)
  • start_directory kwarg (maps to -c)

If not, these would need to be added to libtmux first.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read src/tmuxp/workspace/builder.py lines 690-727 and inspect whether libtmux window.split() supports environment, shell, and start_directory. Run the existing here-mode tests, including test_here_mode_provisions_environment and test_here_mode_start_directory_special_chars, then add coverage for non-shell panes and pane replacement. Done means --here avoids send_keys while preserving one pane with the requested directory, environment, and shell.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli, tooling
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.