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