@@ -32,6 +32,167 @@ $ uvx --from 'libtmux' --prerelease allow python
3232
3333<!-- To maintainers and contributors: Please add notes for the forthcoming version below -->
3434
35+ ### Overview
36+
37+ libtmux 0.49 brings a major enhancement to option and hook management. The new
38+ {class}` ~options.OptionsMixin ` and {class}` ~hooks.HooksMixin ` classes provide a
39+ unified, typed API for managing tmux options and hooks across all object types.
40+
41+ ** Highlights:**
42+
43+ - ** Unified Options API** : New ` show_option() ` , ` show_options() ` , ` set_option() ` ,
44+ and ` unset_option() ` methods available on Server, Session, Window, and Pane.
45+ - ** Hook Management** : Full programmatic control over tmux hooks with support for
46+ indexed hook arrays and bulk operations.
47+ - ** SparseArray** : New internal data structure for handling tmux's sparse indexed
48+ arrays (e.g., ` command-alias[0] ` , ` command-alias[99] ` ).
49+ - ** tmux 3.2+ baseline** : Removed support for tmux versions below 3.2a, enabling
50+ cleaner code and full hook/option feature support.
51+
52+ ### What's New
53+
54+ #### Unified Options API (#516 )
55+
56+ All tmux objects now share a consistent options interface through
57+ {class}` ~options.OptionsMixin ` :
58+
59+ ``` python
60+ import libtmux
61+
62+ server = libtmux.Server()
63+ session = server.sessions[0 ]
64+ window = session.windows[0 ]
65+ pane = window.panes[0 ]
66+
67+ # Get all options as a structured dict
68+ session.show_options()
69+ # {'activity-action': 'other', 'base-index': 0, ...}
70+
71+ # Get a single option value
72+ session.show_option(' base-index' )
73+ # 0
74+
75+ # Set an option
76+ window.set_option(' automatic-rename' , True )
77+
78+ # Unset an option (revert to default)
79+ window.unset_option(' automatic-rename' )
80+ ```
81+
82+ ** New methods on Server, Session, Window, and Pane:**
83+
84+ | Method | Description |
85+ | --------| -------------|
86+ | ` show_options() ` | Get all options as a structured dict |
87+ | ` show_option(name) ` | Get a single option value |
88+ | ` set_option(name, value) ` | Set an option |
89+ | ` unset_option(name) ` | Unset/remove an option |
90+
91+ ** New parameters for ` set_option() ` :**
92+
93+ | Parameter | tmux flag | Description |
94+ | -----------| -----------| -------------|
95+ | ` _format ` | ` -F ` | Expand format strings in value |
96+ | ` unset ` | ` -u ` | Unset the option |
97+ | ` global_ ` | ` -g ` | Set as global option |
98+ | ` unset_panes ` | ` -U ` | Also unset in child panes |
99+ | ` prevent_overwrite ` | ` -o ` | Don't overwrite if exists |
100+ | ` suppress_warnings ` | ` -q ` | Suppress warnings |
101+ | ` append ` | ` -a ` | Append to existing value |
102+
103+ #### Hook Management (#516 )
104+
105+ New {class}` ~hooks.HooksMixin ` provides programmatic control over tmux hooks:
106+
107+ ``` python
108+ session = server.sessions[0 ]
109+
110+ # Set a hook
111+ session.set_hook(' session-renamed' , ' display-message "Renamed!"' )
112+
113+ # Get hook value
114+ session.show_hook(' session-renamed' )
115+ # 'display-message "Renamed!"'
116+
117+ # Get all hooks
118+ session.show_hooks()
119+ # {'session-renamed': 'display-message "Renamed!"'}
120+
121+ # Remove a hook
122+ session.unset_hook(' session-renamed' )
123+ ```
124+
125+ ** Indexed hooks and bulk operations:**
126+
127+ tmux hooks support multiple values via indices (e.g., ` session-renamed[0] ` ,
128+ ` session-renamed[1] ` ). The bulk operations API makes this easy:
129+
130+ ``` python
131+ # Set multiple hooks at once
132+ session.set_hooks(' session-renamed' , {
133+ 0 : ' display-message "Hook 0"' ,
134+ 1 : ' display-message "Hook 1"' ,
135+ 5 : ' run-shell "echo hook 5"' ,
136+ })
137+
138+ # Get all indexed values for a hook
139+ session.get_hook_values(' session-renamed' )
140+ # SparseArray({0: 'display-message "Hook 0"', 1: '...', 5: '...'})
141+
142+ # Get just the indices
143+ session.get_hook_indices(' session-renamed' )
144+ # [0, 1, 5]
145+
146+ # Append at next available index
147+ session.append_hook(' session-renamed' , ' display-message "Hook 6"' )
148+
149+ # Clear all indexed values for a hook
150+ session.clear_hook(' session-renamed' )
151+ ```
152+
153+ ** Hook methods available on Server, Session, Window, and Pane:**
154+
155+ | Method | Description |
156+ | --------| -------------|
157+ | ` set_hook(hook, value) ` | Set a hook |
158+ | ` show_hook(hook) ` | Get hook value |
159+ | ` show_hooks() ` | Get all hooks |
160+ | ` unset_hook(hook) ` | Remove a hook |
161+ | ` run_hook(hook) ` | Run a hook immediately |
162+ | ` set_hooks(hook, values) ` | Set multiple indexed hooks |
163+ | ` get_hook_indices(hook) ` | Get list of indices |
164+ | ` get_hook_values(hook) ` | Get all values as SparseArray |
165+ | ` append_hook(hook, value) ` | Append at next index |
166+ | ` clear_hook(hook) ` | Remove all indexed values |
167+
168+ #### SparseArray for Indexed Options (#516 )
169+
170+ tmux uses sparse indexed arrays for options like ` command-alias[0] ` ,
171+ ` command-alias[99] ` , ` terminal-features[0] ` . Python lists can't represent
172+ gaps in indices, so libtmux introduces {class}` ~_internal.sparse_array.SparseArray ` :
173+
174+ ``` python
175+ >> > from libtmux._internal.sparse_array import SparseArray
176+
177+ >> > arr: SparseArray[str ] = SparseArray()
178+ >> > arr.add(0 , " first" )
179+ >> > arr.add(99 , " ninety-ninth" ) # Gap in indices preserved!
180+ >> > arr[0 ]
181+ ' first'
182+ >> > arr[99 ]
183+ ' ninety-ninth'
184+ >> > list (arr.keys())
185+ [0 , 99 ]
186+ >> > list (arr.iter_values()) # Values in index order
187+ [' first' , ' ninety-ninth' ]
188+ ```
189+
190+ #### New Constants (#516 )
191+
192+ - {class}` ~constants.OptionScope ` enum: ` Server ` , ` Session ` , ` Window ` , ` Pane `
193+ - ` OPTION_SCOPE_FLAG_MAP ` : Maps scope to tmux flags (` -s ` , ` -w ` , ` -p ` )
194+ - ` HOOK_SCOPE_FLAG_MAP ` : Maps scope to hook flags
195+
35196### Breaking Changes
36197
37198#### tmux 1.8 to 3.1c support removed (#608 )
@@ -44,6 +205,35 @@ deprecation announced in v0.48.0.
44205- Removed version guards throughout the codebase
45206- For users on older tmux, use libtmux v0.48.x
46207
208+ #### Deprecated Window methods (#516 )
209+
210+ The following methods are deprecated and will be removed in a future release:
211+
212+ | Deprecated | Replacement |
213+ | ------------| -------------|
214+ | ` Window.set_window_option() ` | ` Window.set_option() ` |
215+ | ` Window.show_window_option() ` | ` Window.show_option() ` |
216+ | ` Window.show_window_options() ` | ` Window.show_options() ` |
217+
218+ The old methods will emit a {class}` DeprecationWarning ` when called:
219+
220+ ``` python
221+ window.set_window_option(' automatic-rename' , ' on' )
222+ # DeprecationWarning: Window.set_window_option() is deprecated
223+
224+ # Use the new method instead:
225+ window.set_option(' automatic-rename' , True )
226+ ```
227+
228+ ### tmux Version Compatibility
229+
230+ | Feature | Minimum tmux |
231+ | ---------| -------------|
232+ | All options/hooks features | 3.2+ |
233+ | Window/Pane hook scopes (` -w ` , ` -p ` ) | 3.2+ |
234+ | ` client-active ` , ` window-resized ` hooks | 3.3+ |
235+ | ` pane-title-changed ` hook | 3.5+ |
236+
47237## libtmux 0.48.0 (2025-11-28)
48238
49239### Breaking Changes
0 commit comments