Skip to content

Commit f5f490a

Browse files
committed
fix(builder[here]): Use respawn-pane and set_environment instead of send_keys
Replace send_keys("export ...") and send_keys(window_shell) with tmux primitives in --here mode: - Environment: session.set_environment() + respawn-pane -e (inherited by new panes, no POSIX shell assumption) - Shell replacement: respawn-pane -k (kills current process, starts fresh shell — no typing into foreground programs) - Directory: respawn-pane -c (tmux primitive, no send_keys cd) This eliminates all send_keys usage for infrastructure setup in --here mode, matching teamocil's approach of using tmux primitives over send_keys. Fixes the fish/nu shell incompatibility and the "types into vim" failure mode. Closes #1031
1 parent 886e63d commit f5f490a

2 files changed

Lines changed: 31 additions & 21 deletions

File tree

src/tmuxp/workspace/builder.py

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -692,39 +692,44 @@ def iter_create_windows(
692692
if panes and "start_directory" in panes[0]:
693693
start_directory = panes[0]["start_directory"]
694694

695-
if start_directory:
696-
active_pane = window.active_pane
697-
if active_pane is not None:
698-
active_pane.send_keys(
699-
f"cd {shlex.quote(start_directory)}",
700-
enter=True,
701-
)
702-
703-
# Provision environment — no window.set_environment in tmux,
704-
# so export into the active pane's shell
695+
# Provision environment via tmux session env (inherited
696+
# by new panes). Matches teamocil, which does not inject
697+
# env vars via send_keys at all.
705698
environment = window_config.get("environment")
706699
if panes and "environment" in panes[0]:
707700
environment = panes[0]["environment"]
708701
if environment:
709-
_here_pane = window.active_pane
710-
if _here_pane is not None:
711-
for _ekey, _eval in environment.items():
712-
_here_pane.send_keys(
713-
f"export {_ekey}={shlex.quote(str(_eval))}",
714-
enter=True,
715-
)
702+
for _ekey, _eval in environment.items():
703+
session.set_environment(_ekey, str(_eval))
716704

717-
# Provision window_shell — send to active pane
705+
# Resolve window_shell
718706
window_shell = window_config.get("window_shell")
719707
try:
720708
if panes[0]["shell"] != "":
721709
window_shell = panes[0]["shell"]
722710
except (KeyError, IndexError):
723711
pass
724-
if window_shell:
712+
713+
# Use respawn-pane to provision the reused pane with the
714+
# correct directory, environment, and shell. This avoids
715+
# send_keys entirely — no POSIX shell assumption, no
716+
# typing into foreground programs, no history pollution.
717+
# Matches teamocil's approach of using tmux primitives
718+
# over send_keys for infrastructure setup.
719+
if start_directory or environment or window_shell:
725720
_here_pane = window.active_pane
726721
if _here_pane is not None:
727-
_here_pane.send_keys(window_shell, enter=True)
722+
_respawn_args: list[str] = ["respawn-pane", "-k"]
723+
if start_directory:
724+
_respawn_args.extend(["-c", start_directory])
725+
if environment:
726+
for _ekey, _eval in environment.items():
727+
_respawn_args.extend(
728+
["-e", f"{_ekey}={_eval}"],
729+
)
730+
if window_shell:
731+
_respawn_args.append(window_shell)
732+
_here_pane.cmd(*_respawn_args)
728733
else:
729734
is_first_window_pass = self.first_window_pass(
730735
window_iterator,

tests/workspace/test_builder.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ def test_here_mode_duplicate_session_name(
605605
def test_here_mode_provisions_environment(
606606
session: Session,
607607
) -> None:
608-
"""--here mode exports environment variables into the active pane."""
608+
"""--here mode sets environment via session and respawn-pane, not send_keys."""
609609
from libtmux.test.retry import retry_until
610610

611611
workspace: dict[str, t.Any] = {
@@ -625,6 +625,11 @@ def test_here_mode_provisions_environment(
625625
builder = WorkspaceBuilder(session_config=workspace, server=session.server)
626626
builder.build(session=session, here=True)
627627

628+
# Verify env var is set at session level (tmux primitive)
629+
env = session.show_environment()
630+
assert env.get("TMUXP_HERE_TEST") == "hello_here"
631+
632+
# Verify the respawned pane also sees the var
628633
pane = session.active_window.active_pane
629634
assert pane is not None
630635

0 commit comments

Comments
 (0)