@@ -63,6 +63,68 @@ def func(value):
63
63
return func
64
64
65
65
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
+
66
128
def is_pure_name (path ):
67
129
"""Return True if path is a name and not a file path."""
68
130
return (
@@ -265,58 +327,36 @@ def reattach(session):
265
327
click .style (config_file , fg = 'blue' , bold = True ))
266
328
builder .build ()
267
329
268
- if 'TMUX' in os .environ :
330
+ if 'TMUX' in os .environ : # tmuxp ran from inside tmux
269
331
if not detached and (answer_yes or click .confirm (
270
332
'Already inside TMUX, switch to session?'
271
333
)):
272
334
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
+
273
341
builder .session .switch_client ()
274
342
275
343
os .environ ['TMUX' ] = tmux_env
276
344
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' )
279
349
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.' )
311
351
312
- # join the hook's commands with semicolons
313
- hook_cmd = '{}' .format ('; ' .join (hook_cmd ))
352
+ # below: tmuxp ran outside of tmux
314
353
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' )
317
357
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' )
320
360
321
361
if not detached :
322
362
builder .session .attach_session ()
0 commit comments