From 3be522f8e448d884d3c722864191d774d84ef484 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Mon, 1 Jul 2019 23:31:01 -0300 Subject: [PATCH 01/14] load config and append windows in same session --- tmuxp/cli.py | 11 +++++++++-- tmuxp/workspacebuilder.py | 27 ++++++++++++++++++--------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/tmuxp/cli.py b/tmuxp/cli.py index f74b187c383..b59e4c907d9 100644 --- a/tmuxp/cli.py +++ b/tmuxp/cli.py @@ -531,12 +531,13 @@ def load_workspace( + click.style(config_file, fg='blue', bold=True) ) - builder.build() # load tmux session via workspace builder if 'TMUX' in os.environ: # tmuxp ran from inside tmux if not detached and ( answer_yes or click.confirm('Already inside TMUX, switch to session?') ): + builder.build() # load tmux session via workspace builder + # unset TMUX, save it, e.g. '/tmp/tmux-1000/default,30668,0' tmux_env = os.environ.pop('TMUX') @@ -547,13 +548,19 @@ def load_workspace( os.environ['TMUX'] = tmux_env # set TMUX back again return builder.session - else: # session created in the background, from within tmux + else: # windows created in the same session + current_attached_sesssion = builder.find_current_attached_session() + builder.build(current_attached_sesssion) + if has_gte_version('2.6'): # prepare for both cases set_layout_hook(builder.session, 'client-attached') set_layout_hook(builder.session, 'client-session-changed') sys.exit('Session created in detached state.') else: # tmuxp ran from inside tmux + + builder.build() # load tmux session via workspace builder + if has_gte_version('2.6'): # if attaching for first time set_layout_hook(builder.session, 'client-attached') diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index 2cb36492609..5f1c69f7d67 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -202,7 +202,7 @@ def build(self, session=None): if focus: focus.select_window() - def iter_create_windows(self, s): + def iter_create_windows(self, session): """ Return :class:`libtmux.Window` iterating through session config dict. @@ -222,17 +222,17 @@ def iter_create_windows(self, s): Newly created window, and the section from the tmuxp configuration that was used to create the window. """ - for i, wconf in enumerate(self.sconf['windows'], start=1): + for wconf in self.sconf['windows']: if 'window_name' not in wconf: window_name = None else: window_name = wconf['window_name'] w1 = None - if i == int(1): # if first window, use window 1 - w1 = s.attached_window + is_first_window = self.first_window(session) + if is_first_window: # if first window, use window 1 + w1 = session.attached_window w1.move_window(99) - pass if 'start_directory' in wconf: sd = wconf['start_directory'] @@ -244,7 +244,7 @@ def iter_create_windows(self, s): else: ws = None - w = s.new_window( + w = session.new_window( window_name=window_name, start_directory=sd, attach=False, # do not move to the new window @@ -252,10 +252,13 @@ def iter_create_windows(self, s): window_shell=ws, ) - if i == int(1) and w1: # if first window, use window 1 + if is_first_window and w1: # if first window, use window 1 w1.kill_window() + assert isinstance(w, Window) - s.server._update_windows() + + session.server._update_windows() + if 'options' in wconf and isinstance(wconf['options'], dict): for key, val in wconf['options'].items(): w.set_window_option(key, val) @@ -263,7 +266,7 @@ def iter_create_windows(self, s): if 'focus' in wconf and wconf['focus']: w.select_window() - s.server._update_windows() + session.server._update_windows() yield w, wconf @@ -349,6 +352,12 @@ def config_after_window(self, w, wconf): for key, val in wconf['options_after'].items(): w.set_window_option(key, val) + def find_current_attached_session(self): + return self.server.list_sessions()[0] + + def first_window(self, session): + return len(session.windows) == 0 + def freeze(session): """ From e1bc91a194300091d7042d265e24e8f9aefecad4 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Tue, 2 Jul 2019 23:58:21 -0300 Subject: [PATCH 02/14] fix first window pass --- tmuxp/workspacebuilder.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index 5f1c69f7d67..9c1d4e61129 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -122,6 +122,7 @@ def build(self, session=None): session to build workspace in """ + self.previous_session = False if not session: if not self.server: raise exc.TmuxpException( @@ -143,6 +144,8 @@ def build(self, session=None): assert self.sconf['session_name'] == session.name assert len(self.sconf['session_name']) > 0 + else: + self.previous_session = True self.session = session self.server = session.server @@ -222,15 +225,17 @@ def iter_create_windows(self, session): Newly created window, and the section from the tmuxp configuration that was used to create the window. """ - for wconf in self.sconf['windows']: + for i, wconf in enumerate(self.sconf['windows'], start=1): if 'window_name' not in wconf: window_name = None else: window_name = wconf['window_name'] + is_first_window_pass = self.first_window_pass(i) + w1 = None - is_first_window = self.first_window(session) - if is_first_window: # if first window, use window 1 + #if i == int(1): + if is_first_window_pass: # if first window, use window 1 w1 = session.attached_window w1.move_window(99) @@ -252,8 +257,8 @@ def iter_create_windows(self, session): window_shell=ws, ) - if is_first_window and w1: # if first window, use window 1 - w1.kill_window() + if is_first_window_pass: + session.attached_window.kill_window() assert isinstance(w, Window) @@ -355,8 +360,8 @@ def config_after_window(self, w, wconf): def find_current_attached_session(self): return self.server.list_sessions()[0] - def first_window(self, session): - return len(session.windows) == 0 + def first_window_pass(self, i): + return len(self.session.windows) == 1 and i == 1 and not self.previous_session def freeze(session): From 2ebd3ebe4d7430668f0553f3add90fcdff3eb3b0 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Wed, 3 Jul 2019 22:42:45 -0300 Subject: [PATCH 03/14] add menu to maintain compatibility --- tmuxp/cli.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tmuxp/cli.py b/tmuxp/cli.py index b59e4c907d9..b0e27735610 100644 --- a/tmuxp/cli.py +++ b/tmuxp/cli.py @@ -531,11 +531,12 @@ def load_workspace( + click.style(config_file, fg='blue', bold=True) ) - if 'TMUX' in os.environ: # tmuxp ran from inside tmux - if not detached and ( - answer_yes or click.confirm('Already inside TMUX, switch to session?') - ): + msg = 'Already inside TMUX, \n(a)ttach, (d)etach in a new session or append windows in (c)urrent session?\n[a/d/c]' + options = ['a', 'd', 'c'] + choice = click.prompt(msg, value_proc=_validate_choices(options)) + + if not detached and choice == 'a': builder.build() # load tmux session via workspace builder # unset TMUX, save it, e.g. '/tmp/tmux-1000/default,30668,0' @@ -548,17 +549,20 @@ def load_workspace( os.environ['TMUX'] = tmux_env # set TMUX back again return builder.session - else: # windows created in the same session + elif not detached and choice == 'c': # windows created in the same session current_attached_sesssion = builder.find_current_attached_session() builder.build(current_attached_sesssion) if has_gte_version('2.6'): # prepare for both cases set_layout_hook(builder.session, 'client-attached') set_layout_hook(builder.session, 'client-session-changed') - + else: + builder.build() + if has_gte_version('2.6'): # prepare for both cases + set_layout_hook(builder.session, 'client-attached') + set_layout_hook(builder.session, 'client-session-changed') sys.exit('Session created in detached state.') - else: # tmuxp ran from inside tmux - + else: builder.build() # load tmux session via workspace builder if has_gte_version('2.6'): From 6b5b702be161a0680e26498e05b261f97ee5ea22 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Wed, 3 Jul 2019 23:34:52 -0300 Subject: [PATCH 04/14] fix tests --- tmuxp/workspacebuilder.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index 9c1d4e61129..0dcee50a0ca 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -122,7 +122,7 @@ def build(self, session=None): session to build workspace in """ - self.previous_session = False + previous_session = False if not session: if not self.server: raise exc.TmuxpException( @@ -145,7 +145,7 @@ def build(self, session=None): assert self.sconf['session_name'] == session.name assert len(self.sconf['session_name']) > 0 else: - self.previous_session = True + previous_session = True self.session = session self.server = session.server @@ -205,7 +205,7 @@ def build(self, session=None): if focus: focus.select_window() - def iter_create_windows(self, session): + def iter_create_windows(self, session, previous_session=False): """ Return :class:`libtmux.Window` iterating through session config dict. @@ -231,10 +231,9 @@ def iter_create_windows(self, session): else: window_name = wconf['window_name'] - is_first_window_pass = self.first_window_pass(i) + is_first_window_pass = self.first_window_pass(i, session, previous_session) w1 = None - #if i == int(1): if is_first_window_pass: # if first window, use window 1 w1 = session.attached_window w1.move_window(99) @@ -360,8 +359,8 @@ def config_after_window(self, w, wconf): def find_current_attached_session(self): return self.server.list_sessions()[0] - def first_window_pass(self, i): - return len(self.session.windows) == 1 and i == 1 and not self.previous_session + def first_window_pass(self, i, session, previous_session): + return len(session.windows) == 1 and i == 1 and not previous_session def freeze(session): From a065296ee9d322a722c8bbad8fd8187cad275c65 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Sat, 6 Jul 2019 00:12:07 -0300 Subject: [PATCH 05/14] add tests to load configs in same session --- .../workspacebuilder/three_windows.yaml | 15 ++++++ .../workspacebuilder/two_windows.yaml | 10 ++++ tests/test_workspacebuilder.py | 48 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 tests/fixtures/workspacebuilder/three_windows.yaml create mode 100644 tests/fixtures/workspacebuilder/two_windows.yaml diff --git a/tests/fixtures/workspacebuilder/three_windows.yaml b/tests/fixtures/workspacebuilder/three_windows.yaml new file mode 100644 index 00000000000..6d571088aa5 --- /dev/null +++ b/tests/fixtures/workspacebuilder/three_windows.yaml @@ -0,0 +1,15 @@ +session_name: sample_three_windows +windows: +- window_name: first + panes: + - shell_command: + - echo 'first window' +- window_name: second + panes: + - shell_command: + - echo 'second window' +- window_name: third + panes: + - shell_command: + - echo 'third window' + diff --git a/tests/fixtures/workspacebuilder/two_windows.yaml b/tests/fixtures/workspacebuilder/two_windows.yaml new file mode 100644 index 00000000000..0f1d40f34a9 --- /dev/null +++ b/tests/fixtures/workspacebuilder/two_windows.yaml @@ -0,0 +1,10 @@ +session_name: sample_two_windows +windows: +- window_name: first + panes: + - shell_command: + - echo 'first window' +- window_name: second + panes: + - shell_command: + - echo 'second window' diff --git a/tests/test_workspacebuilder.py b/tests/test_workspacebuilder.py index 6085ea46d47..22d12fc3ad6 100644 --- a/tests/test_workspacebuilder.py +++ b/tests/test_workspacebuilder.py @@ -673,3 +673,51 @@ def test_before_load_true_if_test_passes_with_args(server): with temp_session(server) as session: builder.build(session=session) + + +def test_load_configs_same_session(server): + yaml_config = loadfixture("workspacebuilder/three_windows.yaml") + sconfig = kaptan.Kaptan(handler='yaml') + sconfig = sconfig.import_config(yaml_config).get() + + builder = WorkspaceBuilder(sconf=sconfig, server=server) + builder.build() + + assert len(server.sessions) == 1 + assert len(server.sessions[0]._windows) == 3 + + yaml_config = loadfixture("workspacebuilder/two_windows.yaml") + + sconfig = kaptan.Kaptan(handler='yaml') + sconfig = sconfig.import_config(yaml_config).get() + + builder = WorkspaceBuilder(sconf=sconfig, server=server) + builder.build(server.sessions[0]) + + assert len(server.sessions) == 1 + assert len(server.sessions[0]._windows) == 5 + + +def test_load_configs_separate_sessions(server): + yaml_config = loadfixture("workspacebuilder/three_windows.yaml") + sconfig = kaptan.Kaptan(handler='yaml') + sconfig = sconfig.import_config(yaml_config).get() + + builder = WorkspaceBuilder(sconf=sconfig, server=server) + builder.build() + + assert len(server.sessions) == 1 + assert len(server.sessions[0]._windows) == 3 + + yaml_config = loadfixture("workspacebuilder/two_windows.yaml") + + sconfig = kaptan.Kaptan(handler='yaml') + sconfig = sconfig.import_config(yaml_config).get() + + builder = WorkspaceBuilder(sconf=sconfig, server=server) + builder.build() + + assert len(server.sessions) == 2 + assert len(server.sessions[0]._windows) == 3 + assert len(server.sessions[1]._windows) == 2 + From b85dfca3c6af387e7c1e7763bd35042a52c57153 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Sat, 6 Jul 2019 00:27:41 -0300 Subject: [PATCH 06/14] remove unused code Since now we can attach, detach and append using the same menu, we do not need the _reattach anymore --- doc/api.rst | 1 - tmuxp/cli.py | 37 ------------------------------------- tmuxp/workspacebuilder.py | 8 -------- 3 files changed, 46 deletions(-) diff --git a/doc/api.rst b/doc/api.rst index 031e3d9f1bf..8cf77d104f0 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -18,7 +18,6 @@ Internals CLI --- -.. automethod:: tmuxp.cli._reattach .. automethod:: tmuxp.cli.get_config_dir .. automethod:: tmuxp.cli.get_teamocil_dir .. automethod:: tmuxp.cli.get_tmuxinator_dir diff --git a/tmuxp/cli.py b/tmuxp/cli.py index b0e27735610..3cf9a71d685 100644 --- a/tmuxp/cli.py +++ b/tmuxp/cli.py @@ -368,29 +368,6 @@ def scan_config(config, config_dir=None): return config -def _reattach(session): - """ - Reattach session (depending on env being inside tmux already or not) - - Parameters - ---------- - session : :class:`libtmux.Session` - - Notes - ----- - If ``TMUX`` environmental variable exists in the environment this script is - running, that means we're in a tmux client. So ``tmux switch-client`` will - load the session. - - If not, ``tmux attach-session`` loads the client to the target session. - """ - if 'TMUX' in os.environ: - session.switch_client() - - else: - session.attach_session() - - def load_workspace( config_file, socket_name=None, @@ -511,20 +488,6 @@ def load_workspace( session_name = sconfig['session_name'] - # if the session already exists, prompt the user to attach. tmuxp doesn't - # support incremental session building or appending (yet, PR's welcome!) - if builder.session_exists(session_name): - if not detached and ( - answer_yes - or click.confirm( - '%s is already running. Attach?' - % click.style(session_name, fg='green'), - default=True, - ) - ): - _reattach(builder.session) - return - try: click.echo( click.style('[Loading] ', fg='green') diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index 0dcee50a0ca..0c8e82f793f 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -98,14 +98,6 @@ def __init__(self, sconf, server=None): self.sconf = sconf - def session_exists(self, session_name=None): - exists = self.server.has_session(session_name) - if not exists: - return exists - - self.session = self.server.find_where({'session_name': session_name}) - return True - def build(self, session=None): """ Build tmux workspace in session. From 590f44091b1ff320e93fbe79e6dc05ca7a0c386a Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Sat, 6 Jul 2019 00:37:57 -0300 Subject: [PATCH 07/14] add better comments --- tmuxp/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmuxp/cli.py b/tmuxp/cli.py index 3cf9a71d685..256abb085b6 100644 --- a/tmuxp/cli.py +++ b/tmuxp/cli.py @@ -500,7 +500,7 @@ def load_workspace( choice = click.prompt(msg, value_proc=_validate_choices(options)) if not detached and choice == 'a': - builder.build() # load tmux session via workspace builder + builder.build() # load config in a new session and attach # unset TMUX, save it, e.g. '/tmp/tmux-1000/default,30668,0' tmux_env = os.environ.pop('TMUX') @@ -519,14 +519,14 @@ def load_workspace( if has_gte_version('2.6'): # prepare for both cases set_layout_hook(builder.session, 'client-attached') set_layout_hook(builder.session, 'client-session-changed') - else: + else: # load config in a new detached session builder.build() if has_gte_version('2.6'): # prepare for both cases set_layout_hook(builder.session, 'client-attached') set_layout_hook(builder.session, 'client-session-changed') sys.exit('Session created in detached state.') else: - builder.build() # load tmux session via workspace builder + builder.build() # load config in a new session if has_gte_version('2.6'): # if attaching for first time From 353c7d7621c48a87f6a6aa8e20e9db5fcbc60528 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Sat, 6 Jul 2019 00:54:23 -0300 Subject: [PATCH 08/14] give a better parameter name --- tmuxp/workspacebuilder.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index 0c8e82f793f..90a1514b7ec 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -114,7 +114,7 @@ def build(self, session=None): session to build workspace in """ - previous_session = False + self.previous_session = False if not session: if not self.server: raise exc.TmuxpException( @@ -137,7 +137,7 @@ def build(self, session=None): assert self.sconf['session_name'] == session.name assert len(self.sconf['session_name']) > 0 else: - previous_session = True + self.previous_session = True self.session = session self.server = session.server @@ -172,7 +172,7 @@ def build(self, session=None): for option, value in self.sconf['environment'].items(): self.session.set_environment(option, value) - for w, wconf in self.iter_create_windows(session): + for w, wconf in self.iter_create_windows(session, self.append_windows_same_session()): assert isinstance(w, Window) focus_pane = None @@ -197,7 +197,7 @@ def build(self, session=None): if focus: focus.select_window() - def iter_create_windows(self, session, previous_session=False): + def iter_create_windows(self, session, append_same_sassion=False): """ Return :class:`libtmux.Window` iterating through session config dict. @@ -223,7 +223,7 @@ def iter_create_windows(self, session, previous_session=False): else: window_name = wconf['window_name'] - is_first_window_pass = self.first_window_pass(i, session, previous_session) + is_first_window_pass = self.first_window_pass(i, session, append_same_sassion) w1 = None if is_first_window_pass: # if first window, use window 1 @@ -351,8 +351,11 @@ def config_after_window(self, w, wconf): def find_current_attached_session(self): return self.server.list_sessions()[0] - def first_window_pass(self, i, session, previous_session): - return len(session.windows) == 1 and i == 1 and not previous_session + def first_window_pass(self, i, session, append_same_sassion): + return len(session.windows) == 1 and i == 1 and not append_same_sassion + + def append_windows_same_session(self): + return self.previous_session def freeze(session): From 670d715d780a20c37b54c405ffb849a4afa86be2 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Mon, 8 Jul 2019 23:19:35 -0300 Subject: [PATCH 09/14] fix flake8 recommendations --- tmuxp/cli.py | 5 ++--- tmuxp/workspacebuilder.py | 7 +++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tmuxp/cli.py b/tmuxp/cli.py index 256abb085b6..0c924e7792f 100644 --- a/tmuxp/cli.py +++ b/tmuxp/cli.py @@ -486,8 +486,6 @@ def load_workspace( click.echo('%s is empty or parsed no config data' % config_file, err=True) return - session_name = sconfig['session_name'] - try: click.echo( click.style('[Loading] ', fg='green') @@ -495,7 +493,8 @@ def load_workspace( ) if 'TMUX' in os.environ: # tmuxp ran from inside tmux - msg = 'Already inside TMUX, \n(a)ttach, (d)etach in a new session or append windows in (c)urrent session?\n[a/d/c]' + msg = "Already inside TMUX, \n(a)ttach, (d)etach in a new session "\ + "or append windows in (c)urrent session?\n[a/d/c]" options = ['a', 'd', 'c'] choice = click.prompt(msg, value_proc=_validate_choices(options)) diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index 90a1514b7ec..61111617bf2 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -172,7 +172,8 @@ def build(self, session=None): for option, value in self.sconf['environment'].items(): self.session.set_environment(option, value) - for w, wconf in self.iter_create_windows(session, self.append_windows_same_session()): + append_windows = self.append_windows_same_session() + for w, wconf in self.iter_create_windows(session, append_windows): assert isinstance(w, Window) focus_pane = None @@ -223,7 +224,9 @@ def iter_create_windows(self, session, append_same_sassion=False): else: window_name = wconf['window_name'] - is_first_window_pass = self.first_window_pass(i, session, append_same_sassion) + is_first_window_pass = self.first_window_pass( + i, session, append_same_sassion + ) w1 = None if is_first_window_pass: # if first window, use window 1 From 71ad54e486b987eead737c69d96e2dbd92ffee68 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Tue, 9 Jul 2019 23:12:30 -0300 Subject: [PATCH 10/14] [refactor] simplify load maintaining params compatibility --- tmuxp/cli.py | 92 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 37 deletions(-) diff --git a/tmuxp/cli.py b/tmuxp/cli.py index 0c924e7792f..187ef7bd372 100644 --- a/tmuxp/cli.py +++ b/tmuxp/cli.py @@ -492,50 +492,27 @@ def load_workspace( + click.style(config_file, fg='blue', bold=True) ) + if detached: + return load_detached(builder) + + if answer_yes: + load_attached(builder, detached) + return builder.session + if 'TMUX' in os.environ: # tmuxp ran from inside tmux msg = "Already inside TMUX, \n(a)ttach, (d)etach in a new session "\ "or append windows in (c)urrent session?\n[a/d/c]" options = ['a', 'd', 'c'] choice = click.prompt(msg, value_proc=_validate_choices(options)) - if not detached and choice == 'a': - builder.build() # load config in a new session and attach - - # unset TMUX, save it, e.g. '/tmp/tmux-1000/default,30668,0' - tmux_env = os.environ.pop('TMUX') - - if has_gte_version('2.6'): - set_layout_hook(builder.session, 'client-session-changed') - - builder.session.switch_client() # switch client to new session - - os.environ['TMUX'] = tmux_env # set TMUX back again - return builder.session - elif not detached and choice == 'c': # windows created in the same session - current_attached_sesssion = builder.find_current_attached_session() - builder.build(current_attached_sesssion) - - if has_gte_version('2.6'): # prepare for both cases - set_layout_hook(builder.session, 'client-attached') - set_layout_hook(builder.session, 'client-session-changed') - else: # load config in a new detached session - builder.build() - if has_gte_version('2.6'): # prepare for both cases - set_layout_hook(builder.session, 'client-attached') - set_layout_hook(builder.session, 'client-session-changed') - sys.exit('Session created in detached state.') + if choice == 'a': + load_attached(builder, detached) + elif choice == 'c': + load_append_windows_same_session(builder) + else: + return load_detached(builder) else: - builder.build() # load config in a new session - - if has_gte_version('2.6'): - # if attaching for first time - set_layout_hook(builder.session, 'client-attached') - - # for cases where user switches client for first time - set_layout_hook(builder.session, 'client-session-changed') - - if not detached: - builder.session.attach_session() + load_attached(builder, detached) except exc.TmuxpException as e: import traceback @@ -563,6 +540,47 @@ def load_workspace( return builder.session +def load_attached(builder, detached): + """ + Load config in a new session and attach. + """ + builder.build() # load config in a new session + if 'TMUX' in os.environ: + # unset TMUX, save it, e.g. '/tmp/tmux-1000/default,30668,0' + tmux_env = os.environ.pop('TMUX') + if has_gte_version('2.6'): + set_layout_hook(builder.session, 'client-session-changed') + builder.session.switch_client() # switch client to new session + os.environ['TMUX'] = tmux_env # set TMUX back again + else: + if has_gte_version('2.6'): + # if attaching for first time + set_layout_hook(builder.session, 'client-attached') + # for cases where user switches client for first time + set_layout_hook(builder.session, 'client-session-changed') + if not detached: + builder.session.attach_session() + + +def load_detached(builder): + builder.build() + if has_gte_version('2.6'): # prepare for both cases + set_layout_hook(builder.session, 'client-attached') + set_layout_hook(builder.session, 'client-session-changed') + return sys.exit('Session created in detached state.') + + +def load_append_windows_same_session(builder): + """ + Load configs in the active session appending windows + """ + current_attached_sesssion = builder.find_current_attached_session() + builder.build(current_attached_sesssion) + if has_gte_version('2.6'): # prepare for both cases + set_layout_hook(builder.session, 'client-attached') + set_layout_hook(builder.session, 'client-session-changed') + + @click.group(context_settings={'obj': {}}) @click.version_option(__version__, '-V', '--version', message='%(prog)s %(version)s') @click.option( From de947107affb3184b495e9cce65175be2f6c5a7b Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Wed, 10 Jul 2019 22:32:37 -0300 Subject: [PATCH 11/14] add CLI append option and maintain params compatibility --- tmuxp/cli.py | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/tmuxp/cli.py b/tmuxp/cli.py index 187ef7bd372..8c2b6838ce8 100644 --- a/tmuxp/cli.py +++ b/tmuxp/cli.py @@ -375,6 +375,7 @@ def load_workspace( colors=None, detached=False, answer_yes=False, + append=False, ): """ Load a tmux "workspace" session via tmuxp file. @@ -393,7 +394,10 @@ def load_workspace( detached : bool Force detached state. default False. answer_yes : bool - Assume yes when given prompt. default False. + Assume yes when given prompt to attach in a new sesion. default False. + append: bool + Assume current when given prompt to append windows in in same Session. + Default False. Notes ----- @@ -493,21 +497,29 @@ def load_workspace( ) if detached: - return load_detached(builder) + load_detached(builder) + return builder.session + + if append: + if 'TMUX' in os.environ: + load_append_windows_same_session(builder) + else: + load_attached(builder, detached) + return builder.session if answer_yes: load_attached(builder, detached) return builder.session if 'TMUX' in os.environ: # tmuxp ran from inside tmux - msg = "Already inside TMUX, \n(a)ttach, (d)etach in a new session "\ - "or append windows in (c)urrent session?\n[a/d/c]" - options = ['a', 'd', 'c'] + msg = "Already inside TMUX, switch to session? yes/no\n"\ + "Or (a)ppend windows in the current active session?\n[y/n/a]" + options = ['y', 'n', 'a'] choice = click.prompt(msg, value_proc=_validate_choices(options)) - if choice == 'a': + if choice == 'y': load_attached(builder, detached) - elif choice == 'c': + elif choice == 'a': load_append_windows_same_session(builder) else: return load_detached(builder) @@ -567,7 +579,7 @@ def load_detached(builder): if has_gte_version('2.6'): # prepare for both cases set_layout_hook(builder.session, 'client-attached') set_layout_hook(builder.session, 'client-session-changed') - return sys.exit('Session created in detached state.') + print('Session created in detached state.') def load_append_windows_same_session(builder): @@ -737,6 +749,9 @@ def command_freeze(session_name, socket_name, socket_path): @click.option( '-d', 'detached', help='Load the session without attaching it', is_flag=True ) +@click.option( + '-a', 'append', help='Load appending windows in active session', is_flag=True +) @click.option( 'colors', '-2', @@ -750,7 +765,16 @@ def command_freeze(session_name, socket_name, socket_path): flag_value=88, help='Like -2, but indicates that the terminal supports 88 colours.', ) -def command_load(ctx, config, socket_name, socket_path, answer_yes, detached, colors): +def command_load( + ctx, + config, + socket_name, + socket_path, + answer_yes, + detached, + colors, + append +): """Load a tmux workspace from each CONFIG. CONFIG is a specifier for a configuration file. @@ -781,6 +805,7 @@ def command_load(ctx, config, socket_name, socket_path, answer_yes, detached, co 'answer_yes': answer_yes, 'colors': colors, 'detached': detached, + 'append': append } if not config: From bb3da3751caf8f30c7ca910f2d30c93f2a9d8054 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Wed, 10 Jul 2019 23:14:04 -0300 Subject: [PATCH 12/14] update docs with new method params --- doc/cli.rst | 18 ++++++++++++++++++ doc/quickstart.rst | 3 ++- tmuxp/workspacebuilder.py | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/doc/cli.rst b/doc/cli.rst index 9fc5ba7b07c..40b10438ef2 100644 --- a/doc/cli.rst +++ b/doc/cli.rst @@ -84,6 +84,24 @@ without being attached. The last one will be attached if there is no $ tmuxp load ... +If you try to load a config file within a tmux session, it will ask you +if you want to load and attach in the new session or just load detached. +You can also load config appending windows in the current active session. + +:: + + Already inside TMUX, switch to session? yes/no + Or (a)ppend windows in the current active session? + [y/n/a]: + +All this modes you can force doing: + +.. code-block:: bash + + $ tmuxp load -y config # load attached + $ tmuxp load -d config # load detached + $ tmuxp load -a config # load appending + .. _cli_import: Import diff --git a/doc/quickstart.rst b/doc/quickstart.rst index 380c8edae1c..c89b13871f1 100644 --- a/doc/quickstart.rst +++ b/doc/quickstart.rst @@ -55,7 +55,8 @@ Load multiple tmux sessions at once: $ tmuxp load example.yaml anothersession.yaml tmuxp will offer to ``switch-client`` for you if you're already in a -session. +session. You can also load config appending windows in the current +active session. You can also have a custom tmuxp config directory by setting the ``TMUX_CONFIGDIR`` in your environment variables. diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index 61111617bf2..db0b88fc8ab 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -211,6 +211,9 @@ def iter_create_windows(self, session, append_same_sassion=False): ---------- session : :class:`libtmux.Session` session to create windows in + append_same_sassion : bool + trick to identify previous open session and create + windows appending in the current session. default False. Returns ------- From 604e3b37640c2afe571e26459d7b75f6ab28859e Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Wed, 10 Jul 2019 23:20:26 -0300 Subject: [PATCH 13/14] update version --- tmuxp/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmuxp/__about__.py b/tmuxp/__about__.py index 37322d441f1..859816bd088 100644 --- a/tmuxp/__about__.py +++ b/tmuxp/__about__.py @@ -1,6 +1,6 @@ __title__ = 'tmuxp' __package_name__ = 'tmuxp' -__version__ = '1.5.3' +__version__ = '1.6.0' __description__ = 'tmux session manager' __email__ = 'tony@git-pull.com' __author__ = 'Tony Narlock' From 8cf07a03faf474e6693a60707f63fda30a465188 Mon Sep 17 00:00:00 2001 From: "Emanuel H. Farias" Date: Sat, 13 Jul 2019 01:11:07 -0300 Subject: [PATCH 14/14] fix tests forcing append on build as param --- tests/test_workspacebuilder.py | 2 +- tmuxp/cli.py | 2 +- tmuxp/workspacebuilder.py | 13 ++++--------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/tests/test_workspacebuilder.py b/tests/test_workspacebuilder.py index 22d12fc3ad6..93729eedd17 100644 --- a/tests/test_workspacebuilder.py +++ b/tests/test_workspacebuilder.py @@ -692,7 +692,7 @@ def test_load_configs_same_session(server): sconfig = sconfig.import_config(yaml_config).get() builder = WorkspaceBuilder(sconf=sconfig, server=server) - builder.build(server.sessions[0]) + builder.build(server.sessions[0], True) assert len(server.sessions) == 1 assert len(server.sessions[0]._windows) == 5 diff --git a/tmuxp/cli.py b/tmuxp/cli.py index 8c2b6838ce8..fe4bb3bf178 100644 --- a/tmuxp/cli.py +++ b/tmuxp/cli.py @@ -587,7 +587,7 @@ def load_append_windows_same_session(builder): Load configs in the active session appending windows """ current_attached_sesssion = builder.find_current_attached_session() - builder.build(current_attached_sesssion) + builder.build(current_attached_sesssion, True) if has_gte_version('2.6'): # prepare for both cases set_layout_hook(builder.session, 'client-attached') set_layout_hook(builder.session, 'client-session-changed') diff --git a/tmuxp/workspacebuilder.py b/tmuxp/workspacebuilder.py index db0b88fc8ab..4e3cd3888c5 100644 --- a/tmuxp/workspacebuilder.py +++ b/tmuxp/workspacebuilder.py @@ -98,7 +98,7 @@ def __init__(self, sconf, server=None): self.sconf = sconf - def build(self, session=None): + def build(self, session=None, append=False): """ Build tmux workspace in session. @@ -112,9 +112,10 @@ def build(self, session=None): ---------- session : :class:`libtmux.Session` session to build workspace in + append : bool + append windows in current active session """ - self.previous_session = False if not session: if not self.server: raise exc.TmuxpException( @@ -136,8 +137,6 @@ def build(self, session=None): assert self.sconf['session_name'] == session.name assert len(self.sconf['session_name']) > 0 - else: - self.previous_session = True self.session = session self.server = session.server @@ -172,8 +171,7 @@ def build(self, session=None): for option, value in self.sconf['environment'].items(): self.session.set_environment(option, value) - append_windows = self.append_windows_same_session() - for w, wconf in self.iter_create_windows(session, append_windows): + for w, wconf in self.iter_create_windows(session, append): assert isinstance(w, Window) focus_pane = None @@ -360,9 +358,6 @@ def find_current_attached_session(self): def first_window_pass(self, i, session, append_same_sassion): return len(session.windows) == 1 and i == 1 and not append_same_sassion - def append_windows_same_session(self): - return self.previous_session - def freeze(session): """