Skip to content

Commit 2a197c9

Browse files
authored
Merge pull request #656 from will-ockmore/append-window-same-session
Add the ability to append windows to a session
2 parents 2bec710 + 0660049 commit 2a197c9

File tree

8 files changed

+397
-50
lines changed

8 files changed

+397
-50
lines changed

docs/cli.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,23 @@ directory may be loaded with:
169169
170170
$ tmuxp load .
171171
172+
If you try to load a config file from within a tmux session, it will ask you
173+
if you want to load and attach to the new session, or just load detached.
174+
You can also load a config file and append the windows to the current active session.
175+
176+
::
177+
178+
Already inside TMUX, switch to session? yes/no
179+
Or (a)ppend windows in the current active session?
180+
[y/n/a]:
181+
182+
All of these options can be preselected to skip the prompt:
183+
184+
.. code-block:: bash
185+
$ tmuxp load -y config # load attached
186+
$ tmuxp load -d config # load detached
187+
$ tmuxp load -a config # append windows
188+
172189
Multiple sessions can be loaded at once. The first ones will be created
173190
without being attached. The last one will be attached if there is no
174191
``-d`` flag on the command line.

docs/quickstart.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ Load multiple tmux sessions at once:
5555
$ tmuxp load example.yaml anothersession.yaml
5656
5757
tmuxp will offer to ``switch-client`` for you if you're already in a
58-
session.
58+
session. You can also load a configuration, and append the windows to
59+
the current active session.
5960

6061
You can also have a custom tmuxp config directory by setting the
6162
``TMUX_CONFIGDIR`` in your environment variables.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
session_name: sample_three_windows
2+
windows:
3+
- window_name: first
4+
panes:
5+
- shell_command:
6+
- echo 'first window'
7+
- window_name: second
8+
panes:
9+
- shell_command:
10+
- echo 'second window'
11+
- window_name: third
12+
panes:
13+
- shell_command:
14+
- echo 'third window'
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
session_name: sample_two_windows
2+
windows:
3+
- window_name: first
4+
panes:
5+
- shell_command:
6+
- echo 'first window'
7+
- window_name: second
8+
panes:
9+
- shell_command:
10+
- echo 'second window'

tests/test_cli.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
import json
66
import os
77

8+
try:
9+
from unittest.mock import MagicMock
10+
except ImportError:
11+
from mock import MagicMock
12+
813
import pytest
914

1015
import click
@@ -18,6 +23,8 @@
1823
from tmuxp import cli, config, exc
1924
from tmuxp.cli import (
2025
_reattach,
26+
_load_attached,
27+
_load_append_windows_to_current_session,
2128
command_debug_info,
2229
command_ls,
2330
get_config_dir,
@@ -1088,6 +1095,107 @@ def test_reattach_plugins(server):
10881095
assert proc.stdout[0] == "'plugin_test_r'"
10891096

10901097

1098+
def test_load_attached(server, monkeypatch):
1099+
# Load a session and attach from outside tmux
1100+
monkeypatch.delenv('TMUX', raising=False)
1101+
1102+
attach_session_mock = MagicMock()
1103+
attach_session_mock.return_value.stderr = None
1104+
1105+
monkeypatch.setattr("libtmux.session.Session.attach_session", attach_session_mock)
1106+
1107+
yaml_config = loadfixture("workspacebuilder/two_pane.yaml")
1108+
sconfig = kaptan.Kaptan(handler='yaml')
1109+
sconfig = sconfig.import_config(yaml_config).get()
1110+
1111+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
1112+
1113+
_load_attached(builder, False)
1114+
1115+
assert builder.session.attach_session.call_count == 1
1116+
1117+
1118+
def test_load_attached_detached(server, monkeypatch):
1119+
# Load a session but don't attach
1120+
monkeypatch.delenv('TMUX', raising=False)
1121+
1122+
attach_session_mock = MagicMock()
1123+
attach_session_mock.return_value.stderr = None
1124+
1125+
monkeypatch.setattr("libtmux.session.Session.attach_session", attach_session_mock)
1126+
1127+
yaml_config = loadfixture("workspacebuilder/two_pane.yaml")
1128+
sconfig = kaptan.Kaptan(handler='yaml')
1129+
sconfig = sconfig.import_config(yaml_config).get()
1130+
1131+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
1132+
1133+
_load_attached(builder, True)
1134+
1135+
assert builder.session.attach_session.call_count == 0
1136+
1137+
1138+
def test_load_attached_within_tmux(server, monkeypatch):
1139+
# Load a session and attach from within tmux
1140+
monkeypatch.setenv('TMUX', "/tmp/tmux-1234/default,123,0")
1141+
1142+
switch_client_mock = MagicMock()
1143+
switch_client_mock.return_value.stderr = None
1144+
1145+
monkeypatch.setattr("libtmux.session.Session.switch_client", switch_client_mock)
1146+
1147+
yaml_config = loadfixture("workspacebuilder/two_pane.yaml")
1148+
sconfig = kaptan.Kaptan(handler='yaml')
1149+
sconfig = sconfig.import_config(yaml_config).get()
1150+
1151+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
1152+
1153+
_load_attached(builder, False)
1154+
1155+
assert builder.session.switch_client.call_count == 1
1156+
1157+
1158+
def test_load_attached_within_tmux_detached(server, monkeypatch):
1159+
# Load a session and attach from within tmux
1160+
monkeypatch.setenv('TMUX', "/tmp/tmux-1234/default,123,0")
1161+
1162+
switch_client_mock = MagicMock()
1163+
switch_client_mock.return_value.stderr = None
1164+
1165+
monkeypatch.setattr("libtmux.session.Session.switch_client", switch_client_mock)
1166+
1167+
yaml_config = loadfixture("workspacebuilder/two_pane.yaml")
1168+
sconfig = kaptan.Kaptan(handler='yaml')
1169+
sconfig = sconfig.import_config(yaml_config).get()
1170+
1171+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
1172+
1173+
_load_attached(builder, True)
1174+
1175+
assert builder.session.switch_client.call_count == 1
1176+
1177+
def test_load_append_windows_to_current_session(server, monkeypatch):
1178+
yaml_config = loadfixture("workspacebuilder/two_pane.yaml")
1179+
sconfig = kaptan.Kaptan(handler='yaml')
1180+
sconfig = sconfig.import_config(yaml_config).get()
1181+
1182+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
1183+
builder.build()
1184+
1185+
assert len(server.list_sessions()) == 1
1186+
assert len(server._list_windows()) == 3
1187+
1188+
# Assign an active pane to the session
1189+
monkeypatch.setenv("TMUX_PANE", server._list_panes()[0]["pane_id"])
1190+
1191+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
1192+
_load_append_windows_to_current_session(builder)
1193+
1194+
assert len(server.list_sessions()) == 1
1195+
assert len(server._list_windows()) == 6
1196+
1197+
1198+
10911199
def test_debug_info_cli(monkeypatch, tmpdir):
10921200
monkeypatch.setenv('SHELL', '/bin/bash')
10931201

tests/test_workspacebuilder.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,3 +779,90 @@ def test_plugin_system_multiple_plugins(session):
779779
# override methods are currently written
780780
proc = session.cmd('display-message', '-p', "'#W'")
781781
assert proc.stdout[0] == "'mp_test_awf'"
782+
783+
784+
def test_load_configs_same_session(server):
785+
yaml_config = loadfixture("workspacebuilder/three_windows.yaml")
786+
sconfig = kaptan.Kaptan(handler='yaml')
787+
sconfig = sconfig.import_config(yaml_config).get()
788+
789+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
790+
builder.build()
791+
792+
assert len(server.sessions) == 1
793+
assert len(server.sessions[0]._windows) == 3
794+
795+
yaml_config = loadfixture("workspacebuilder/two_windows.yaml")
796+
797+
sconfig = kaptan.Kaptan(handler='yaml')
798+
sconfig = sconfig.import_config(yaml_config).get()
799+
800+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
801+
builder.build()
802+
assert len(server.sessions) == 2
803+
assert len(server.sessions[1]._windows) == 2
804+
805+
yaml_config = loadfixture("workspacebuilder/two_windows.yaml")
806+
807+
sconfig = kaptan.Kaptan(handler='yaml')
808+
sconfig = sconfig.import_config(yaml_config).get()
809+
810+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
811+
builder.build(server.sessions[1], True)
812+
813+
assert len(server.sessions) == 2
814+
assert len(server.sessions[1]._windows) == 4
815+
816+
817+
def test_load_configs_separate_sessions(server):
818+
yaml_config = loadfixture("workspacebuilder/three_windows.yaml")
819+
sconfig = kaptan.Kaptan(handler='yaml')
820+
sconfig = sconfig.import_config(yaml_config).get()
821+
822+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
823+
builder.build()
824+
825+
assert len(server.sessions) == 1
826+
assert len(server.sessions[0]._windows) == 3
827+
828+
yaml_config = loadfixture("workspacebuilder/two_windows.yaml")
829+
830+
sconfig = kaptan.Kaptan(handler='yaml')
831+
sconfig = sconfig.import_config(yaml_config).get()
832+
833+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
834+
builder.build()
835+
836+
assert len(server.sessions) == 2
837+
assert len(server.sessions[0]._windows) == 3
838+
assert len(server.sessions[1]._windows) == 2
839+
840+
841+
def test_find_current_active_pane(server, monkeypatch):
842+
yaml_config = loadfixture("workspacebuilder/three_windows.yaml")
843+
sconfig = kaptan.Kaptan(handler='yaml')
844+
sconfig = sconfig.import_config(yaml_config).get()
845+
846+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
847+
builder.build()
848+
849+
yaml_config = loadfixture("workspacebuilder/two_windows.yaml")
850+
851+
sconfig = kaptan.Kaptan(handler='yaml')
852+
sconfig = sconfig.import_config(yaml_config).get()
853+
854+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
855+
builder.build()
856+
857+
assert len(server.list_sessions()) == 2
858+
859+
# Assign an active pane to the session
860+
second_session = server.list_sessions()[1]
861+
first_pane_on_second_session_id = (
862+
second_session.list_windows()[0].list_panes()[0]["pane_id"]
863+
)
864+
monkeypatch.setenv("TMUX_PANE", first_pane_on_second_session_id)
865+
866+
builder = WorkspaceBuilder(sconf=sconfig, server=server)
867+
868+
assert builder.find_current_attached_session() == second_session

0 commit comments

Comments
 (0)