Skip to content

Commit c2c8e7c

Browse files
committed
split layout hook off into function, handle session scenarios
related: #312
1 parent d37f62b commit c2c8e7c

File tree

1 file changed

+80
-40
lines changed

1 file changed

+80
-40
lines changed

tmuxp/cli.py

+80-40
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,68 @@ def func(value):
6363
return func
6464

6565

66+
def set_layout_hook(session, hook_name):
67+
"""Set layout hooks to normalize layout.
68+
69+
References:
70+
71+
- tmuxp issue: https://github.com/tony/tmuxp/issues/309
72+
- tmux issue: https://github.com/tmux/tmux/issues/1106
73+
74+
tmux 2.6+ requires that the window be viewed with the client before
75+
select-layout adjustments can take effect.
76+
77+
To handle this, this function creates temporary hook for this session to
78+
iterate through all windows and select the layout.
79+
80+
In order for layout changes to take effect, a client must at the very
81+
least be attached to the window (not just the session).
82+
83+
hook_name is provided to allow this to set to multiple scenarios, such
84+
as 'client-attached' (which the user attaches the session). You may
85+
also want 'after-switch-client' for cases where the user loads tmuxp
86+
sessions inside tmux since tmuxp offers to switch for them.
87+
88+
Also, the hooks are set immediately unbind after they're invoked via -u.
89+
90+
:param session: session to bind hook to
91+
:type session: :class:`libtmux.session.Session`
92+
:param hook_name: hook name to bind to, e.g. 'client-attached'
93+
:type hook_name: str
94+
"""
95+
cmd = [
96+
'set-hook',
97+
'-t', session.id,
98+
hook_name
99+
]
100+
hook_cmd = []
101+
for window in session.windows:
102+
# unfortunately, select-layout won't work unless
103+
# we've literally selected the window at least once
104+
# with the client
105+
hook_cmd.append('selectw -t {}'.format(window.id))
106+
# edit: removed -t, or else it won't respect main-pane-w/h
107+
hook_cmd.append('selectl'.format(window.id))
108+
hook_cmd.append('selectw -p'.format(window.id))
109+
110+
# unset the hook immediately after executing
111+
hook_cmd.append(
112+
'set-hook -u -t {target_session} {hook_name}'.format(
113+
target_session=session.id,
114+
hook_name=hook_name
115+
)
116+
)
117+
118+
# join the hook's commands with semicolons
119+
hook_cmd = '{}'.format('; '.join(hook_cmd))
120+
121+
# append the hook command
122+
cmd.append(hook_cmd)
123+
124+
# create the hook
125+
session.cmd(*cmd)
126+
127+
66128
def is_pure_name(path):
67129
"""Return True if path is a name and not a file path."""
68130
return (
@@ -265,58 +327,36 @@ def reattach(session):
265327
click.style(config_file, fg='blue', bold=True))
266328
builder.build()
267329

268-
if 'TMUX' in os.environ:
330+
if 'TMUX' in os.environ: # tmuxp ran from inside tmux
269331
if not detached and (answer_yes or click.confirm(
270332
'Already inside TMUX, switch to session?'
271333
)):
272334
tmux_env = os.environ.pop('TMUX')
335+
336+
if has_gte_version('2.6'):
337+
# if using -d from inside tmux session + switching inside
338+
# https://github.com/tmux/tmux/blob/2.6/cmd-switch-client.c#L132
339+
set_layout_hook(builder.session, 'client-session-changed')
340+
273341
builder.session.switch_client()
274342

275343
os.environ['TMUX'] = tmux_env
276344
return builder.session
277-
else:
278-
sys.exit('Session created in detached state.')
345+
else: # session created in the background, from within tmux
346+
if has_gte_version('2.6'): # prepare for both cases
347+
set_layout_hook(builder.session, 'client-attached')
348+
set_layout_hook(builder.session, 'client-session-changed')
279349

280-
if has_gte_version('2.6'):
281-
# tmuxp issue: https://github.com/tony/tmuxp/issues/309
282-
# tmux issue: https://github.com/tmux/tmux/issues/1106
283-
#
284-
# tmux now requires that the window be viewed with the client
285-
# before select-layout adjustments can be meaningful
286-
#
287-
# To handle this, let's create a temporary hook for this
288-
# session to iterage and run select-layout on all windows
289-
# after client attaches.
290-
cmd = [
291-
'set-hook',
292-
'-t', builder.session.id,
293-
'client-attached'
294-
]
295-
hook_cmd = []
296-
for window in builder.session.windows:
297-
# unfortunately, select-layout won't work unless
298-
# we've literally selected the window at least once
299-
# with the client
300-
hook_cmd.append('selectw -t {}'.format(window.id))
301-
# edit: removed -t, or else it won't respect main-pane-w/h
302-
hook_cmd.append('selectl'.format(window.id))
303-
hook_cmd.append('selectw -p'.format(window.id))
304-
305-
# unset the hook immediately after executing
306-
hook_cmd.append(
307-
'set-hook -u -t {target_session} client-attached'.format(
308-
target_session=builder.session.id
309-
)
310-
)
350+
sys.exit('Session created in detached state.')
311351

312-
# join the hook's commands with semicolons
313-
hook_cmd = '{}'.format('; '.join(hook_cmd))
352+
# below: tmuxp ran outside of tmux
314353

315-
# append the hook command
316-
cmd.append(hook_cmd)
354+
if has_gte_version('2.6'):
355+
# if attaching for first time
356+
set_layout_hook(builder.session, 'client-attached')
317357

318-
# create the hook
319-
builder.session.cmd(*cmd)
358+
# for cases where user switches client for first time
359+
set_layout_hook(builder.session, 'client-session-changed')
320360

321361
if not detached:
322362
builder.session.attach_session()

0 commit comments

Comments
 (0)