-
Notifications
You must be signed in to change notification settings - Fork 236
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.9split-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_keysfor 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-panewhich 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-ekwargs 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_environmentto verify env via pane capture (new pane inherits env) - Rewrite
test_here_mode_start_directory_special_charsto verify cwd withoutsend_keys - Add test verifying
--hereworks 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:
environmentkwarg (maps to-e KEY=VALUE)shellkwarg (maps to the shell/command argument)start_directorykwarg (maps to-c)
If not, these would need to be added to libtmux first.