Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
13f0ccd
feat!(Window): Set option flags
tony Feb 5, 2024
fba6d91
refactor!(Window): Deprecate set_window_option -> set_option
tony Feb 5, 2024
5a905eb
tests(Window): Rename test for show_window_options()
tony Feb 6, 2024
3c86458
tests(Window): set_option
tony Feb 6, 2024
d47023b
Window: Add show_option(), deprecate show_window_option()
tony Feb 6, 2024
cfd4763
chore(Window): {set,show}-window-option -> {set,show}-option -w
tony Feb 6, 2024
9b69ac7
libtmux.constants: Add OptionScope and OPTION_SCOPE_FLAG_MAP
tony Feb 6, 2024
ebbacec
feat(Window): scope param for Window.{set,show}_option
tony Feb 6, 2024
3431630
tests(Window): show_options w/ scope
tony Feb 6, 2024
4d2fd59
tests: show_window_option() -> show_option()
tony Feb 6, 2024
c7ddb03
feat(common): Add CmdMixin, CmdProtocol
tony Feb 8, 2024
273c31f
refactor!(options): Move handle_options_error -> options
tony Feb 8, 2024
75de0b6
feat(internal[sparse_array]): Add SparseArray
tony Jun 20, 2024
beac94b
feat(options): Add OptionsMixin
tony Feb 8, 2024
bf19ca6
feat(Window): Use OptionsMixin for Window.set_option, Window.show_opt…
tony Feb 7, 2024
5b3a745
feat(Pane): Use OptionsMixin for Pane.set_option, Pane.show_option(s)
tony Feb 5, 2024
c44709f
feat(Session): Use OptionsMixin for Session.set_option, Session.show_…
tony Feb 7, 2024
bbb5767
feat(Server): Use OptionsMixin for Server.set_option, Server.show_opt…
tony Feb 8, 2024
0f583b2
tests: Handle Window.show_options scope mismatch
tony Feb 7, 2024
d3c4d47
tests(window): Version guard to scope
tony Feb 6, 2024
55563e9
tests(Window): For Window.default_option_scope
tony Feb 8, 2024
e5882ad
docs(options): Add page for option helpers
tony Feb 8, 2024
94b4931
internal(constants[options]): GPT generated dataclasses
tony Feb 9, 2024
8b8d160
tests(test_options): Test OptionsMixin
tony Feb 8, 2024
eb72519
constants: Add HOOK_SCOPE_FLAG_MAP
tony Feb 16, 2024
bb5b398
docs(API): Document internal constants
tony Feb 15, 2024
2245b54
feat(internal[constants]): Add Hooks data structure
tony Feb 15, 2024
b2fb5a7
feat!(hooks): HooksMixin
tony Feb 15, 2024
e6d742c
feat(Pane): Add HooksMixin
tony Feb 15, 2024
4d0a3e0
feat(Window): Add HooksMixin
tony Feb 15, 2024
ef35102
feat(Session): Add HooksMixin
tony Feb 15, 2024
a6a5779
feat(Server): Add HooksMixin
tony Feb 15, 2024
e160705
docs(API): Add Hooks
tony Feb 16, 2024
93d4330
tests(test_hooks): Test HooksMixin
tony Feb 15, 2024
f61c9e3
fix(options): improve type safety for SparseArray handling
tony Feb 23, 2025
4db4672
test(options): update terminal-features test for tmux 3.4
tony Feb 23, 2025
7a31af6
test(options): improve test coverage and type safety
tony Feb 23, 2025
9d60be1
fix(tests): improve type safety in style option tests
tony Feb 23, 2025
7d94e99
fix(tests): handle status-format version compatibility
tony Feb 23, 2025
3fd7458
fix(tests): handle update-environment version compatibility
tony Feb 23, 2025
4dfe898
fix(compat): add tmux version compatibility for 3.2a-3.5
tony Oct 25, 2025
bd68cc8
fix(tests): handle tmux version differences in options tests
tony Oct 25, 2025
917af2a
fix(tests): handle style option format changes in tmux 3.2
tony Oct 25, 2025
dcae8e3
fix(tests): handle bold→bright conversion in complex style test
tony Oct 25, 2025
9c1dc7c
fix(tests): skip format expansion test on tmux <3.2
tony Oct 25, 2025
b6e93f6
feat(constants): add missing tmux 3.5+ options and hooks
tony Nov 26, 2025
a61e279
tests(options): add comprehensive option test grid
tony Nov 26, 2025
9cfafe5
tests(hooks): add comprehensive hook test grid
tony Nov 26, 2025
e8e9190
SparseArray(docs): add comprehensive doctests
tony Nov 26, 2025
4b2feb2
Hooks(docs): add doctests for from_stdout parsing pipeline
tony Nov 26, 2025
423d3b5
options(docs): add force_array=True doctest for hooks parsing
tony Nov 26, 2025
b9cd2f1
hooks(feat): add bulk operations API for managing indexed hooks
tony Nov 26, 2025
69eca19
tests(hooks): add comprehensive bulk operations test grid
tony Nov 26, 2025
62d39a3
fix(tests): set correct min_version for hooks and options
tony Nov 26, 2025
7b136b0
fix(tests): correct min_version for additional hooks and options
tony Nov 26, 2025
210014a
docs(hooks): convert commented examples to runnable doctests
tony Nov 26, 2025
c49c295
refactor(tests): remove dead code and unused xfail
tony Nov 26, 2025
49fea06
docs(internals): add SparseArray doc page
tony Nov 26, 2025
c0b3021
fix(tests): remove undefined TmuxArray reference
tony Nov 27, 2025
f0fac89
hooks(refactor): rename set_hooks_bulk -> set_hooks
tony Nov 28, 2025
34796e1
tests(hooks): update for set_hooks_bulk -> set_hooks rename
tony Nov 28, 2025
6456301
hooks(fix): correct show_hook return type to include SparseArray
tony Nov 28, 2025
d97a3e2
hooks(refactor): remove redundant bulk operations methods
tony Nov 28, 2025
7045630
tests(hooks): update for simplified bulk operations API
tony Nov 28, 2025
afab007
hooks(fix): add doctest cleanup for tmux < 3.0 compatibility
tony Nov 28, 2025
70efe1d
hooks(docs): skip set_hooks doctests for cross-version compat
tony Nov 28, 2025
b0a89a0
hooks(feat): add warning for set_hooks on tmux < 3.0
tony Nov 28, 2025
d9d38b9
tests(hooks): add version compatibility tests
tony Nov 28, 2025
ef284a5
hooks(fix): remove < 3.0 warning and doctest skips
tony Nov 28, 2025
a59b181
tests(hooks): remove < 3.0 module skip
tony Nov 28, 2025
881fa39
tests(hooks): delete version compat test file
tony Nov 28, 2025
0086e86
tests: remove obsolete < 3.2 skipif markers
tony Nov 28, 2025
79bdf0a
hooks(docs): update module docstring for 3.2+ baseline
tony Nov 28, 2025
a9f21f4
SparseArray(fix[append]): Handle empty array case
tony Nov 29, 2025
421e736
hooks(fix[show_hooks]): Store string hook values in returned dict
tony Nov 29, 2025
a2c0b30
options(feat[show_options]): Add public show_options() method
tony Nov 29, 2025
3ba8017
Window(refactor[show_window_options]): Update deprecation to use show…
tony Nov 29, 2025
6b8995c
options(fix[scope_flag]): Skip empty Session scope flag in tmux commands
tony Nov 29, 2025
6681e75
tests(test_options[show_options]): Add parametrized tests for show_op…
tony Nov 29, 2025
1f34b31
tests(test_hooks[run_hook]): Add test for run_hook() method
tony Nov 29, 2025
7d344e7
tests(test_sparse_array): Add tests for SparseArray utility class
tony Nov 29, 2025
6965fa3
tests(test_hooks): Add set_hook flag combination tests
tony Nov 29, 2025
04ecdd6
tests(test_hooks): Add hook scope tests for session/window/pane
tony Nov 29, 2025
f5fe594
tests(test_hooks): Add show_hooks parsing edge case tests
tony Nov 29, 2025
6295916
tests(test_options): Add convert_values SparseArray tests
tony Nov 29, 2025
277bda0
tests(legacy_api/test_window): Remove duplicate test_set_and_show_opt…
tony Nov 29, 2025
0ccd7cd
tests(test_window): Add deprecation warning tests for Window option m…
tony Nov 29, 2025
cd2d14a
tests/legacy_api/test_window.py(refactor): Remove unused has_gte_vers…
tony Nov 29, 2025
f2b0d40
tests/test_window.py(refactor): Simplify version conditionals
tony Nov 29, 2025
74c9681
docs(CHANGES): Add release notes for options and hooks features
tony Nov 29, 2025
327e85e
Window(fix[show_window_option]): Use public show_option() API
tony Nov 30, 2025
f827521
OptionsMixin(fix[show_option]): Forward legacy g parameter
tony Nov 30, 2025
17c4ccd
OptionsMixin(fix[show_option]): Add deprecation warning for g parameter
tony Nov 30, 2025
90757c9
OptionsMixin(fix): Use DeprecationWarning for deprecated g parameter
tony Nov 30, 2025
5afa214
tests(test_options): Add test for g parameter deprecation warning
tony Nov 30, 2025
e5a5b9d
HooksMixin(fix[show_hook]): Forward global_ parameter to _show_hook
tony Nov 30, 2025
3d37594
docs(CHANGES): Remove references to unimplemented hook methods
tony Nov 30, 2025
e4722dc
constants(fix[HOOK_SCOPE_FLAG_MAP]): Map Server scope to -g flag
tony Nov 30, 2025
a93d0fe
HooksMixin(fix[show_hook]): Strip % prefix for control-mode hooks
tony Nov 30, 2025
4c400a2
HooksMixin(fix[set_hook]): Add deprecation warning for g parameter
tony Nov 30, 2025
ebb507f
HooksMixin(feat[run_hook]): Add global_ parameter
tony Nov 30, 2025
3fcc34d
options(refactor[convert_values]): Remove dead SparseArray branch
tony Nov 30, 2025
da38b70
hooks.py(fix[set_hook]): Remove invalid _format parameter
tony Nov 30, 2025
2ca8063
hooks.py(fix[set_hook]): Remove invalid prevent_overwrite parameter
tony Nov 30, 2025
ff368f4
hooks.py(fix[set_hook]): Remove invalid ignore_errors parameter
tony Nov 30, 2025
0c3decc
hooks.py(fix[unset_hook]): Remove invalid ignore_errors parameter
tony Nov 30, 2025
a9a5bb2
hooks.py(fix[show_hooks]): Remove invalid ignore_errors parameter
tony Nov 30, 2025
7c316bf
hooks.py(fix[_show_hook, show_hook]): Remove invalid ignore_errors pa…
tony Nov 30, 2025
ec97859
tests/test_options.py(test): Add test for indexed array option lookup
tony Nov 30, 2025
c2d52ca
options.py(fix[_show_option]): Handle bracketed array indices correctly
tony Nov 30, 2025
f33f5f2
tests/test_window.py(fix): Suppress secondary deprecation warning in …
tony Nov 30, 2025
fa6117e
options.py(fix[explode_complex]): Parse multi-feature terminal-overrides
tony Nov 30, 2025
6b81b0c
hooks.py(fix[show_hook]): Handle indexed hook queries correctly
tony Nov 30, 2025
18d9f80
options.py(fix[_show_option]): Handle inherited option marker in lookups
tony Nov 30, 2025
39d20cc
options.py(fix[explode_arrays]): Preserve inherited marker in array keys
tony Nov 30, 2025
b92cc73
tests/test_options.py(feat): Add inherited array marker preservation …
tony Nov 30, 2025
ded89cd
docs(MIGRATION): Add migration notes for options/hooks API (#516)
tony Nov 30, 2025
9440065
docs(topics): Add options and hooks topic guide (#516)
tony Nov 30, 2025
d24226e
docs(quickstart): Add options section with examples (#516)
tony Nov 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,149 @@ $ uvx --from 'libtmux' --prerelease allow python

_Future release notes will be placed here_

### Overview

libtmux 0.50 brings a major enhancement to option and hook management. The new
{class}`~options.OptionsMixin` and {class}`~hooks.HooksMixin` classes provide a
unified, typed API for managing tmux options and hooks across all object types.

**Highlights:**

- **Unified Options API**: New `show_option()`, `show_options()`, `set_option()`,
and `unset_option()` methods available on Server, Session, Window, and Pane.
- **Hook Management**: Full programmatic control over tmux hooks with support for
indexed hook arrays and bulk operations.
- **SparseArray**: New internal data structure for handling tmux's sparse indexed
arrays (e.g., `command-alias[0]`, `command-alias[99]`).
- **tmux 3.2+ baseline**: Removed support for tmux versions below 3.2a, enabling
cleaner code and full hook/option feature support.

### What's New

#### Unified Options API (#516)

All tmux objects now share a consistent options interface through
{class}`~options.OptionsMixin`:

```python
import libtmux

server = libtmux.Server()
session = server.sessions[0]
window = session.windows[0]
pane = window.panes[0]

# Get all options as a structured dict
session.show_options()
# {'activity-action': 'other', 'base-index': 0, ...}

# Get a single option value
session.show_option('base-index')
# 0

# Set an option
window.set_option('automatic-rename', True)

# Unset an option (revert to default)
window.unset_option('automatic-rename')
```

**New methods on Server, Session, Window, and Pane:**

| Method | Description |
|--------|-------------|
| `show_options()` | Get all options as a structured dict |
| `show_option(name)` | Get a single option value |
| `set_option(name, value)` | Set an option |
| `unset_option(name)` | Unset/remove an option |

**New parameters for `set_option()`:**

| Parameter | tmux flag | Description |
|-----------|-----------|-------------|
| `_format` | `-F` | Expand format strings in value |
| `unset` | `-u` | Unset the option |
| `global_` | `-g` | Set as global option |
| `unset_panes` | `-U` | Also unset in child panes |
| `prevent_overwrite` | `-o` | Don't overwrite if exists |
| `suppress_warnings` | `-q` | Suppress warnings |
| `append` | `-a` | Append to existing value |

#### Hook Management (#516)

New {class}`~hooks.HooksMixin` provides programmatic control over tmux hooks:

```python
session = server.sessions[0]

# Set a hook
session.set_hook('session-renamed', 'display-message "Renamed!"')

# Get hook value
session.show_hook('session-renamed')
# 'display-message "Renamed!"'

# Get all hooks
session.show_hooks()
# {'session-renamed': 'display-message "Renamed!"'}

# Remove a hook
session.unset_hook('session-renamed')
```

**Indexed hooks and bulk operations:**

tmux hooks support multiple values via indices (e.g., `session-renamed[0]`,
`session-renamed[1]`). The bulk operations API makes this easy:

```python
# Set multiple hooks at once
session.set_hooks('session-renamed', {
0: 'display-message "Hook 0"',
1: 'display-message "Hook 1"',
5: 'run-shell "echo hook 5"',
})
```

**Hook methods available on Server, Session, Window, and Pane:**

| Method | Description |
|--------|-------------|
| `set_hook(hook, value)` | Set a hook |
| `show_hook(hook)` | Get hook value (returns SparseArray for indexed hooks) |
| `show_hooks()` | Get all hooks |
| `unset_hook(hook)` | Remove a hook |
| `run_hook(hook)` | Run a hook immediately |
| `set_hooks(hook, values)` | Set multiple indexed hooks at once |

#### SparseArray for Indexed Options (#516)

tmux uses sparse indexed arrays for options like `command-alias[0]`,
`command-alias[99]`, `terminal-features[0]`. Python lists can't represent
gaps in indices, so libtmux introduces {class}`~_internal.sparse_array.SparseArray`:

```python
>>> from libtmux._internal.sparse_array import SparseArray

>>> arr: SparseArray[str] = SparseArray()
>>> arr.add(0, "first")
>>> arr.add(99, "ninety-ninth") # Gap in indices preserved!
>>> arr[0]
'first'
>>> arr[99]
'ninety-ninth'
>>> list(arr.keys())
[0, 99]
>>> list(arr.iter_values()) # Values in index order
['first', 'ninety-ninth']
```

#### New Constants (#516)

- {class}`~constants.OptionScope` enum: `Server`, `Session`, `Window`, `Pane`
- `OPTION_SCOPE_FLAG_MAP`: Maps scope to tmux flags (`-s`, `-w`, `-p`)
- `HOOK_SCOPE_FLAG_MAP`: Maps scope to hook flags

## libtmux 0.49.0 (2025-11-29)

### Breaking Changes
Expand All @@ -48,6 +191,35 @@ deprecation announced in v0.48.0.
- Removed version guards throughout the codebase
- For users on older tmux, use libtmux v0.48.x

#### Deprecated Window methods (#516)

The following methods are deprecated and will be removed in a future release:

| Deprecated | Replacement |
|------------|-------------|
| `Window.set_window_option()` | `Window.set_option()` |
| `Window.show_window_option()` | `Window.show_option()` |
| `Window.show_window_options()` | `Window.show_options()` |

The old methods will emit a {class}`DeprecationWarning` when called:

```python
window.set_window_option('automatic-rename', 'on')
# DeprecationWarning: Window.set_window_option() is deprecated

# Use the new method instead:
window.set_option('automatic-rename', True)
```

### tmux Version Compatibility

| Feature | Minimum tmux |
|---------|-------------|
| All options/hooks features | 3.2+ |
| Window/Pane hook scopes (`-w`, `-p`) | 3.2+ |
| `client-active`, `window-resized` hooks | 3.3+ |
| `pane-title-changed` hook | 3.5+ |

## libtmux 0.48.0 (2025-11-28)

### Breaking Changes
Expand Down
87 changes: 87 additions & 0 deletions MIGRATION
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,93 @@ _Detailed migration steps for the next version will be posted here._

<!-- To the maintainers and contributors: please add migration details for the upcoming release here -->

## libtmux 0.50.0: Unified Options and Hooks API (#516)

### New unified options API

All tmux objects (Server, Session, Window, Pane) now share a consistent options
interface through {class}`~libtmux.options.OptionsMixin`:

```python
# Get all options
session.show_options()

# Get a single option
session.show_option('base-index')

# Set an option
window.set_option('automatic-rename', True)

# Unset an option
window.unset_option('automatic-rename')
```

### New hooks API

All tmux objects now support hook management through
{class}`~libtmux.hooks.HooksMixin`:

```python
# Set a hook
session.set_hook('session-renamed', 'display-message "Renamed!"')

# Get hook value
session.show_hook('session-renamed')

# Get all hooks
session.show_hooks()

# Remove a hook
session.unset_hook('session-renamed')
```

### Deprecated Window methods

The following `Window` methods are deprecated and will be removed in a future
release:

| Deprecated | Replacement |
|------------|-------------|
| `Window.set_window_option()` | {meth}`Window.set_option() <libtmux.Window.set_option>` |
| `Window.show_window_option()` | {meth}`Window.show_option() <libtmux.Window.show_option>` |
| `Window.show_window_options()` | {meth}`Window.show_options() <libtmux.Window.show_options>` |

**Before (deprecated):**

```python
window.set_window_option('automatic-rename', 'on')
window.show_window_option('automatic-rename')
window.show_window_options()
```

**After (0.50.0+):**

```python
window.set_option('automatic-rename', True)
window.show_option('automatic-rename')
window.show_options()
```

### Deprecated `g` parameter

The `g` parameter for global options is deprecated in favor of `global_`:

**Before (deprecated):**

```python
session.show_option('status', g=True)
session.set_option('status', 'off', g=True)
```

**After (0.50.0+):**

```python
session.show_option('status', global_=True)
session.set_option('status', 'off', global_=True)
```

Using the old `g` parameter will emit a {class}`DeprecationWarning`.

## libtmux 0.46.0 (2025-02-25)

#### Imports removed from libtmux.test (#580)
Expand Down
6 changes: 6 additions & 0 deletions docs/api/hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Hooks

```{eval-rst}
.. automodule:: libtmux.hooks
:members:
```
2 changes: 2 additions & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ servers
sessions
windows
panes
options
hooks
constants
common
exceptions
Expand Down
6 changes: 6 additions & 0 deletions docs/api/options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Options

```{eval-rst}
.. automodule:: libtmux.options
:members:
```
15 changes: 15 additions & 0 deletions docs/internals/constants.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Internal Constants - `libtmux._internal.constants`

:::{warning}
Be careful with these! These constants are private, internal as they're **not** covered by version policies. They can break or be removed between minor versions!

If you need a data structure here made public or stabilized please [file an issue](https://github.com/tmux-python/libtmux/issues).
:::

```{eval-rst}
.. automodule:: libtmux._internal.constants
:members:
:undoc-members:
:inherited-members:
:show-inheritance:
```
2 changes: 2 additions & 0 deletions docs/internals/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ If you need an internal API stabilized please [file an issue](https://github.com
```{toctree}
dataclasses
query_list
constants
sparse_array
```

## Environmental variables
Expand Down
14 changes: 14 additions & 0 deletions docs/internals/sparse_array.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Internal Sparse Array - `libtmux._internal.sparse_array`

:::{warning}
Be careful with these! Internal APIs are **not** covered by version policies. They can break or be removed between minor versions!

If you need an internal API stabilized please [file an issue](https://github.com/tmux-python/libtmux/issues).
:::

```{eval-rst}
.. automodule:: libtmux._internal.sparse_array
:members:
:undoc-members:
:show-inheritance:
```
32 changes: 32 additions & 0 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,38 @@ automatically sent, the leading space character prevents adding it to the user's
shell history. Omitting `enter=false` means the default behavior (sending the
command) is done, without needing to use `pane.enter()` after.

## Working with options

libtmux provides a unified API for managing tmux options across Server, Session,
Window, and Pane objects.

### Getting options

```python
>>> server.show_option('buffer-limit')
50

>>> window.show_options() # doctest: +ELLIPSIS
{...}
```

### Setting options

```python
>>> window.set_option('automatic-rename', False) # doctest: +ELLIPSIS
Window(@... ...)

>>> window.show_option('automatic-rename')
False

>>> window.unset_option('automatic-rename') # doctest: +ELLIPSIS
Window(@... ...)
```

:::{seealso}
See {ref}`options-and-hooks` for more details on options and hooks.
:::

## Final notes

These objects created use tmux's internal usage of ID's to make servers,
Expand Down
1 change: 1 addition & 0 deletions docs/topics/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ Explore libtmux’s core functionalities and underlying principles at a high lev

context_managers
traversal
options_and_hooks
```
Loading