1
+ """Internal constants."""
2
+
3
+ import io
4
+ import logging
1
5
import typing as t
2
6
from dataclasses import dataclass , field
3
7
4
8
from libtmux ._internal .dataclasses import SkipDefaultFieldsReprMixin
9
+ from libtmux ._internal .sparse_array import SparseArray , is_sparse_array_list
5
10
6
- TerminalFeatures = t .Dict [str , t .List [str ]]
11
+ if t .TYPE_CHECKING :
12
+ from typing_extensions import TypeAlias
7
13
8
14
9
15
T = t .TypeVar ("T" )
10
16
17
+ TerminalFeatures = t .Dict [str , t .List [str ]]
18
+ HookArray : "TypeAlias" = "t.Dict[str, SparseArray[str]]"
11
19
12
- class TmuxArray (t .Dict [int , T ], t .Generic [T ]):
13
- """Support non-sequential indexes without raising IndexError."""
14
-
15
- def add (self , index : int , value : T ) -> None :
16
- self [index ] = value
17
-
18
- def append (self , value : T ) -> None :
19
- index = max (self .keys ()) + 1
20
- self [index ] = value
21
-
22
- def iter_values (self ) -> t .Iterator [T ]:
23
- for index in sorted (self .keys ()):
24
- yield self [index ]
25
-
26
- def as_list (self ) -> t .List [T ]:
27
- return [self [index ] for index in sorted (self .keys ())]
20
+ logger = logging .getLogger (__name__ )
28
21
29
22
30
23
@dataclass (repr = False )
@@ -33,7 +26,7 @@ class ServerOptions(
33
26
):
34
27
backspace : t .Optional [str ] = field (default = None )
35
28
buffer_limit : t .Optional [int ] = field (default = None )
36
- command_alias : TmuxArray [str ] = field (default_factory = TmuxArray )
29
+ command_alias : SparseArray [str ] = field (default_factory = SparseArray )
37
30
default_terminal : t .Optional [str ] = field (default = None )
38
31
copy_command : t .Optional [str ] = field (default = None )
39
32
escape_time : t .Optional [int ] = field (default = None )
@@ -47,8 +40,8 @@ class ServerOptions(
47
40
prompt_history_limit : t .Optional [int ] = field (default = None )
48
41
set_clipboard : t .Optional [t .Literal ["on" , "external" , "off" ]] = field (default = None )
49
42
terminal_features : TerminalFeatures = field (default_factory = dict )
50
- terminal_overrides : TmuxArray [str ] = field (default_factory = TmuxArray )
51
- user_keys : TmuxArray [str ] = field (default_factory = TmuxArray )
43
+ terminal_overrides : SparseArray [str ] = field (default_factory = SparseArray )
44
+ user_keys : SparseArray [str ] = field (default_factory = SparseArray )
52
45
53
46
def __init__ (self , ** kwargs : object ) -> None :
54
47
# Convert hyphenated keys to underscored attribute names and assign values
@@ -118,7 +111,7 @@ class SessionOptions(
118
111
status_right_length : t .Optional [int ] = field (default = None )
119
112
status_right_style : t .Optional [str ] = field (default = None )
120
113
status_style : t .Optional [str ] = field (default = None )
121
- update_environment : t . Optional [ t . List [ str ]] = field (default = None )
114
+ update_environment : SparseArray [ str ] = field (default_factory = SparseArray )
122
115
visual_activity : t .Optional [t .Literal ["on" , "off" , "both" ]] = field (default = None )
123
116
visual_bell : t .Optional [t .Literal ["on" , "off" , "both" ]] = field (default = None )
124
117
visual_silence : t .Optional [t .Literal ["on" , "off" , "both" ]] = field (default = None )
@@ -240,3 +233,224 @@ def __init__(self, **kwargs: object) -> None:
240
233
key_underscored = key .replace ("-" , "_" )
241
234
key_asterisk_removed = key_underscored .rstrip ("*" )
242
235
setattr (self , key_asterisk_removed , value )
236
+
237
+
238
+ @dataclass (repr = False )
239
+ class Hooks (
240
+ SkipDefaultFieldsReprMixin ,
241
+ ):
242
+ """tmux hooks data structure."""
243
+
244
+ # --- Tmux normal hooks ---
245
+ # Run when a window has activity. See monitor-activity.
246
+ alert_activity : SparseArray [str ] = field (default_factory = SparseArray )
247
+ # Run when a window has received a bell. See monitor-bell.
248
+ alert_bell : SparseArray [str ] = field (default_factory = SparseArray )
249
+ # Run when a window has been silent. See monitor-silence.
250
+ alert_silence : SparseArray [str ] = field (default_factory = SparseArray )
251
+ # Run when a client becomes the latest active client of its session.
252
+ client_active : SparseArray [str ] = field (default_factory = SparseArray )
253
+ # Run when a client is attached.
254
+ client_attached : SparseArray [str ] = field (default_factory = SparseArray )
255
+ # Run when a client is detached.
256
+ client_detached : SparseArray [str ] = field (default_factory = SparseArray )
257
+ # Run when focus enters a client.
258
+ client_focus_in : SparseArray [str ] = field (default_factory = SparseArray )
259
+ # Run when focus exits a client.
260
+ client_focus_out : SparseArray [str ] = field (default_factory = SparseArray )
261
+ # Run when a client is resized.
262
+ client_resized : SparseArray [str ] = field (default_factory = SparseArray )
263
+ # Run when a client's attached session is changed.
264
+ client_session_changed : SparseArray [str ] = field (default_factory = SparseArray )
265
+ # Run when the program running in a pane exits, but remain-on-exit is on so the pane
266
+ # has not closed.
267
+ pane_died : SparseArray [str ] = field (default_factory = SparseArray )
268
+ # Run when the program running in a pane exits.
269
+ pane_exited : SparseArray [str ] = field (default_factory = SparseArray )
270
+ # Run when the focus enters a pane, if the focus-events option is on.
271
+ pane_focus_in : SparseArray [str ] = field (default_factory = SparseArray )
272
+ # Run when the focus exits a pane, if the focus-events option is on.
273
+ pane_focus_out : SparseArray [str ] = field (default_factory = SparseArray )
274
+ # Run when the terminal clipboard is set using the xterm(1) escape sequence.
275
+ pane_set_clipboard : SparseArray [str ] = field (default_factory = SparseArray )
276
+ # Run when a new session created.
277
+ session_created : SparseArray [str ] = field (default_factory = SparseArray )
278
+ # Run when a session closed.
279
+ session_closed : SparseArray [str ] = field (default_factory = SparseArray )
280
+ # Run when a session is renamed.
281
+ session_renamed : SparseArray [str ] = field (default_factory = SparseArray )
282
+ # Run when a window is linked into a session.
283
+ window_linked : SparseArray [str ] = field (default_factory = SparseArray )
284
+ # Run when a window is renamed.
285
+ window_renamed : SparseArray [str ] = field (default_factory = SparseArray )
286
+ # Run when a window is resized. This may be after the client-resized hook is run.
287
+ window_resized : SparseArray [str ] = field (default_factory = SparseArray )
288
+ # Run when a window is unlinked from a session.
289
+ window_unlinked : SparseArray [str ] = field (default_factory = SparseArray )
290
+
291
+ # --- Tmux control mode hooks ---
292
+ # The client has detached.
293
+ client_detached_control : SparseArray [str ] = field (default_factory = SparseArray )
294
+ # The client is now attached to the session with ID session-id, which is named name.
295
+ client_session_changed_control : SparseArray [str ] = field (
296
+ default_factory = SparseArray ,
297
+ )
298
+ # An error has happened in a configuration file.
299
+ config_error : SparseArray [str ] = field (default_factory = SparseArray )
300
+ # The pane has been continued after being paused (if the pause-after flag is set,
301
+ # see refresh-client -A).
302
+ continue_control : SparseArray [str ] = field (default_factory = SparseArray )
303
+ # The tmux client is exiting immediately, either because it is not attached to any
304
+ # session or an error occurred.
305
+ exit_control : SparseArray [str ] = field (default_factory = SparseArray )
306
+ # New form of %output sent when the pause-after flag is set.
307
+ extended_output : SparseArray [str ] = field (default_factory = SparseArray )
308
+ # The layout of a window with ID window-id changed.
309
+ layout_change : SparseArray [str ] = field (default_factory = SparseArray )
310
+ # A message sent with the display-message command.
311
+ message_control : SparseArray [str ] = field (default_factory = SparseArray )
312
+ # A window pane produced output.
313
+ output : SparseArray [str ] = field (default_factory = SparseArray )
314
+ # The pane with ID pane-id has changed mode.
315
+ pane_mode_changed : SparseArray [str ] = field (default_factory = SparseArray )
316
+ # Paste buffer name has been changed.
317
+ paste_buffer_changed : SparseArray [str ] = field (default_factory = SparseArray )
318
+ # Paste buffer name has been deleted.
319
+ paste_buffer_deleted : SparseArray [str ] = field (default_factory = SparseArray )
320
+ # The pane has been paused (if the pause-after flag is set).
321
+ pause_control : SparseArray [str ] = field (default_factory = SparseArray )
322
+ # The client is now attached to the session with ID session-id, which is named name.
323
+ session_changed_control : SparseArray [str ] = field (default_factory = SparseArray )
324
+ # The current session was renamed to name.
325
+ session_renamed_control : SparseArray [str ] = field (default_factory = SparseArray )
326
+ # The session with ID session-id changed its active window to the window with ID
327
+ # window-id.
328
+ session_window_changed : SparseArray [str ] = field (default_factory = SparseArray )
329
+ # A session was created or destroyed.
330
+ sessions_changed : SparseArray [str ] = field (default_factory = SparseArray )
331
+ # The value of the format associated with subscription name has changed to value.
332
+ subscription_changed : SparseArray [str ] = field (default_factory = SparseArray )
333
+ # The window with ID window-id was created but is not linked to the current session.
334
+ unlinked_window_add : SparseArray [str ] = field (default_factory = SparseArray )
335
+ # The window with ID window-id, which is not linked to the current session, was
336
+ # closed.
337
+ unlinked_window_close : SparseArray [str ] = field (default_factory = SparseArray )
338
+ # The window with ID window-id, which is not linked to the current session, was
339
+ # renamed.
340
+ unlinked_window_renamed : SparseArray [str ] = field (default_factory = SparseArray )
341
+ # The window with ID window-id was linked to the current session.
342
+ window_add : SparseArray [str ] = field (default_factory = SparseArray )
343
+ # The window with ID window-id closed.
344
+ window_close : SparseArray [str ] = field (default_factory = SparseArray )
345
+ # The layout of a window with ID window-id changed. The new layout is window-layout.
346
+ # The window's visible layout is window-visible-layout and the window flags are
347
+ # window-flags.
348
+ window_layout_changed : SparseArray [str ] = field (default_factory = SparseArray )
349
+ # The active pane in the window with ID window-id changed to the pane with ID
350
+ # pane-id.
351
+ window_pane_changed : SparseArray [str ] = field (default_factory = SparseArray )
352
+ # The window with ID window-id was renamed to name.
353
+ window_renamed_control : SparseArray [str ] = field (default_factory = SparseArray )
354
+
355
+ # --- After hooks - Run after specific tmux commands complete ---
356
+ # Runs after 'bind-key' completes
357
+ after_bind_key : SparseArray [str ] = field (default_factory = SparseArray )
358
+ # Runs after 'capture-pane' completes
359
+ after_capture_pane : SparseArray [str ] = field (default_factory = SparseArray )
360
+ # Runs after 'copy-mode' completes
361
+ after_copy_mode : SparseArray [str ] = field (default_factory = SparseArray )
362
+ # Runs after 'display-message' completes
363
+ after_display_message : SparseArray [str ] = field (default_factory = SparseArray )
364
+ # Runs after 'display-panes' completes
365
+ after_display_panes : SparseArray [str ] = field (default_factory = SparseArray )
366
+ # Runs after 'kill-pane' completes
367
+ after_kill_pane : SparseArray [str ] = field (default_factory = SparseArray )
368
+ # Runs after 'list-buffers' completes
369
+ after_list_buffers : SparseArray [str ] = field (default_factory = SparseArray )
370
+ # Runs after 'list-clients' completes
371
+ after_list_clients : SparseArray [str ] = field (default_factory = SparseArray )
372
+ # Runs after 'list-keys' completes
373
+ after_list_keys : SparseArray [str ] = field (default_factory = SparseArray )
374
+ # Runs after 'list-panes' completes
375
+ after_list_panes : SparseArray [str ] = field (default_factory = SparseArray )
376
+ # Runs after 'list-sessions' completes
377
+ after_list_sessions : SparseArray [str ] = field (default_factory = SparseArray )
378
+ # Runs after 'list-windows' completes
379
+ after_list_windows : SparseArray [str ] = field (default_factory = SparseArray )
380
+ # Runs after 'load-buffer' completes
381
+ after_load_buffer : SparseArray [str ] = field (default_factory = SparseArray )
382
+ # Runs after 'lock-server' completes
383
+ after_lock_server : SparseArray [str ] = field (default_factory = SparseArray )
384
+ # Runs after 'new-session' completes
385
+ after_new_session : SparseArray [str ] = field (default_factory = SparseArray )
386
+ # Runs after 'new-window' completes
387
+ after_new_window : SparseArray [str ] = field (default_factory = SparseArray )
388
+ # Runs after 'paste-buffer' completes
389
+ after_paste_buffer : SparseArray [str ] = field (default_factory = SparseArray )
390
+ # Runs after 'pipe-pane' completes
391
+ after_pipe_pane : SparseArray [str ] = field (default_factory = SparseArray )
392
+ # Runs after 'queue' command is processed
393
+ after_queue : SparseArray [str ] = field (default_factory = SparseArray )
394
+ # Runs after 'refresh-client' completes
395
+ after_refresh_client : SparseArray [str ] = field (default_factory = SparseArray )
396
+ # Runs after 'rename-session' completes
397
+ after_rename_session : SparseArray [str ] = field (default_factory = SparseArray )
398
+ # Runs after 'rename-window' completes
399
+ after_rename_window : SparseArray [str ] = field (default_factory = SparseArray )
400
+ # Runs after 'resize-pane' completes
401
+ after_resize_pane : SparseArray [str ] = field (default_factory = SparseArray )
402
+ # Runs after 'resize-window' completes
403
+ after_resize_window : SparseArray [str ] = field (default_factory = SparseArray )
404
+ # Runs after 'save-buffer' completes
405
+ after_save_buffer : SparseArray [str ] = field (default_factory = SparseArray )
406
+ # Runs after 'select-layout' completes
407
+ after_select_layout : SparseArray [str ] = field (default_factory = SparseArray )
408
+ # Runs after 'select-pane' completes
409
+ after_select_pane : SparseArray [str ] = field (default_factory = SparseArray )
410
+ # Runs after 'select-window' completes
411
+ after_select_window : SparseArray [str ] = field (default_factory = SparseArray )
412
+ # Runs after 'send-keys' completes
413
+ after_send_keys : SparseArray [str ] = field (default_factory = SparseArray )
414
+ # Runs after 'set-buffer' completes
415
+ after_set_buffer : SparseArray [str ] = field (default_factory = SparseArray )
416
+ # Runs after 'set-environment' completes
417
+ after_set_environment : SparseArray [str ] = field (default_factory = SparseArray )
418
+ # Runs after 'set-hook' completes
419
+ after_set_hook : SparseArray [str ] = field (default_factory = SparseArray )
420
+ # Runs after 'set-option' completes
421
+ after_set_option : SparseArray [str ] = field (default_factory = SparseArray )
422
+ # Runs after 'show-environment' completes
423
+ after_show_environment : SparseArray [str ] = field (default_factory = SparseArray )
424
+ # Runs after 'show-messages' completes
425
+ after_show_messages : SparseArray [str ] = field (default_factory = SparseArray )
426
+ # Runs after 'show-options' completes
427
+ after_show_options : SparseArray [str ] = field (default_factory = SparseArray )
428
+ # Runs after 'split-window' completes
429
+ after_split_window : SparseArray [str ] = field (default_factory = SparseArray )
430
+ # Runs after 'unbind-key' completes
431
+ after_unbind_key : SparseArray [str ] = field (default_factory = SparseArray )
432
+
433
+ @classmethod
434
+ def from_stdout (cls , value : t .List [str ]) -> "Hooks" :
435
+ from libtmux .options import (
436
+ explode_arrays ,
437
+ explode_complex ,
438
+ parse_options_to_dict ,
439
+ )
440
+
441
+ output_exploded = explode_complex (
442
+ explode_arrays (
443
+ parse_options_to_dict (
444
+ io .StringIO ("\n " .join (value )),
445
+ ),
446
+ force_array = True ,
447
+ ),
448
+ )
449
+
450
+ assert is_sparse_array_list (output_exploded )
451
+
452
+ output_renamed : HookArray = {
453
+ k .lstrip ("%" ).replace ("-" , "_" ): v for k , v in output_exploded .items ()
454
+ }
455
+
456
+ return cls (** output_renamed )
0 commit comments