Options¶

Helpers for tmux options.

Option parsing function trade testability and clarity for performance.

Tmux options¶

Options in tmux consist of empty values, strings, integers, arrays, and complex shapes.

Marshalling types from text:

Integers: buffer-limit 50 to {'buffer-limit': 50} Booleans: exit-unattached on to {'exit-unattached': True}

Exploding arrays:

command-alias[1] split-pane=split-window to {'command-alias[1]': {'split-pane=split-window'}}

However, there is no equivalent to the above type of object in Python (a sparse array), so a SparseArray is used.

Exploding complex shapes:

"choose-session=choose-tree -s" to {'choose-session': 'choose-tree -s'}

Finally, we need to convert hyphenated keys to underscored attribute names and assign values, as python does not allow hyphens in attribute names.

command-alias is command_alias in python.

Options object¶

Dataclasses are used to provide typed access to tmux’ option shape.

Extra data gleaned from the options, such as user options (custom data) and an option being inherited,

User options¶

There are also custom user options, preceded with @, which exist are stored to Options.context.user_options as a dictionary.

> tmux set-option -w my-custom-variable my-value invalid option: my-custom-option

> tmux set-option -w @my-custom-option my-value > tmux show-option -w @my-custom-optione my-value

Inherited options¶

tmux show-options -A can include inherited options. The raw output of an inherited option is detected by the key having a *:

visual-activity* on
visual-bell* off

A list of options that are inherited is kept at Options.context._inherited_options and Options.context.inherited_options.

They are mixed with the normal options, to differentiate them, run show_options() without include_inherited=True.

libtmux.options.handle_option_error(error)
¶
function[source]

Raise exception if error in option command found.

In tmux 3.0, show-option and show-window-option return invalid option instead of unknown option. See https://github.com/tmux/tmux/blob/3.0/cmd-show-options.c.

In tmux >2.4, there are 3 different types of option errors:

  • unknown option

  • invalid option

  • ambiguous option

In tmux <2.4, unknown option was the only option.

All errors raised will have the base error of exc.OptionError. So to catch any option error, use except exc.OptionError.

Parameters:

error (str) – Error response from subprocess call.

Return type:

type[OptionError]

:raises exc.OptionError, exc.UnknownOption, exc.InvalidOption,: :raises exc.AmbiguousOption:

Examples

>>> result = server.cmd(
...     'set-option',
...     'unknown-option-name',
... )
>>> bool(isinstance(result.stderr, list) and len(result.stderr))
True
>>> import pytest
>>> from libtmux import exc
>>> with pytest.raises(exc.OptionError):
...     handle_option_error(result.stderr[0])
libtmux.options.convert_value(value)
¶
function[source]

Convert raw option strings to python types.

Examples

>>> convert_value("on")
True
>>> convert_value("off")
False
>>> convert_value("1")
1
>>> convert_value("50")
50
>>> convert_value("%50")
'%50'
Parameters:

value (_V | None)

Return type:

ConvertedValue | _V | None

libtmux.options.convert_values(value)
¶
function[source]

Recursively convert values to python types via convert_value().

>>> convert_values(None)
>>> convert_values("on")
True
>>> convert_values("off")
False
>>> convert_values(["on"])
[True]
>>> convert_values(["off"])
[False]
>>> convert_values({"window_index": "1"})
{'window_index': 1}
>>> convert_values({"visual-bell": "on"})
{'visual-bell': True}
Parameters:

value (_V | None)

Return type:

ConvertedValues | _V | None

libtmux.options.parse_options_to_dict(stdout)
¶
function[source]

Process subprocess.stdout options or hook output to flat, naive, untyped dict.

Does not explode arrays or deep values.

Examples

>>> import io
>>> raw_options = io.StringIO("status-keys vi")
>>> parse_options_to_dict(raw_options) == {"status-keys": "vi"}
True
>>> int_options = io.StringIO("message-limit 50")
>>> parse_options_to_dict(int_options) == {"message-limit": "50"}
True
>>> empty_option = io.StringIO("user-keys")
>>> parse_options_to_dict(empty_option) == {"user-keys": None}
True
>>> array_option = io.StringIO("command-alias[0] split-pane=split-window")
>>> parse_options_to_dict(array_option) == {
... "command-alias[0]": "split-pane=split-window"}
True
>>> array_option = io.StringIO("command-alias[40] split-pane=split-window")
>>> parse_options_to_dict(array_option) == {
... "command-alias[40]": "split-pane=split-window"}
True
>>> many_options = io.StringIO(r'''status-keys
... command-alias[0] split-pane=split-window
... ''')
>>> parse_options_to_dict(many_options) == {
... "command-alias[0]": "split-pane=split-window",
... "status-keys": None,}
True
>>> many_more_options = io.StringIO(r'''
... terminal-features[0] xterm*:clipboard:ccolour:cstyle:focus
... terminal-features[1] screen*:title
... ''')
>>> parse_options_to_dict(many_more_options) == {
... "terminal-features[0]": "xterm*:clipboard:ccolour:cstyle:focus",
... "terminal-features[1]": "screen*:title",}
True
>>> quoted_option = io.StringIO(r'''
... command-alias[0] "choose-session=choose-tree -s"
... ''')
>>> parse_options_to_dict(quoted_option) == {
... "command-alias[0]": "choose-session=choose-tree -s",
... }
True
Parameters:

stdout (IO[str])

Return type:

UntypedOptionsDict

libtmux.options.explode_arrays(_dict, force_array=False)
¶
function[source]

Explode flat, naive options dict’s option arrays.

Examples

>>> import io
>>> many_more_options = io.StringIO(r'''
... terminal-features[0] xterm*:clipboard:ccolour:cstyle:focus
... terminal-features[1] screen*:title
... ''')
>>> many_more_flat_dict = parse_options_to_dict(many_more_options)
>>> many_more_flat_dict == {
... "terminal-features[0]": "xterm*:clipboard:ccolour:cstyle:focus",
... "terminal-features[1]": "screen*:title",}
True
>>> explode_arrays(many_more_flat_dict) == {
... "terminal-features": {0: "xterm*:clipboard:ccolour:cstyle:focus",
... 1: "screen*:title"}}
True

tmux arrays allow non-sequential indexes, so we need to support that:

>>> explode_arrays(parse_options_to_dict(io.StringIO(r'''
... terminal-features[0] xterm*:clipboard:ccolour:cstyle:focus
... terminal-features[5] screen*:title
... '''))) == {
... "terminal-features": {0: "xterm*:clipboard:ccolour:cstyle:focus",
... 5: "screen*:title"}}
True

Use force_array=True for hooks, which always use array format:

>>> from libtmux._internal.sparse_array import SparseArray
>>> hooks_output = io.StringIO(r'''
... session-renamed[0] display-message 'renamed'
... session-renamed[5] refresh-client
... pane-focus-in[0] run-shell 'echo focus'
... ''')
>>> hooks_exploded = explode_arrays(
...     parse_options_to_dict(hooks_output),
...     force_array=True,
... )

Each hook becomes a SparseArray preserving indices:

>>> isinstance(hooks_exploded["session-renamed"], SparseArray)
True
>>> hooks_exploded["session-renamed"][0]
"display-message 'renamed'"
>>> hooks_exploded["session-renamed"][5]
'refresh-client'
>>> sorted(hooks_exploded["session-renamed"].keys())
[0, 5]
Parameters:
  • _dict (UntypedOptionsDict)

  • force_array (bool)

Return type:

ExplodedUntypedOptionsDict

libtmux.options.explode_complex(_dict)
¶
function[source]

Explode arrayed option’s complex values.

Examples

>>> import io
>>> explode_complex(explode_arrays(parse_options_to_dict(io.StringIO(r'''
... terminal-features[0] xterm*:clipboard:ccolour:cstyle:focus
... terminal-features[5] screen*:title
... '''))))
{'terminal-features': {'xterm*': ['clipboard', 'ccolour', 'cstyle', 'focus'], 'screen*': ['title']}}
>>> explode_complex(explode_arrays(parse_options_to_dict(io.StringIO(r'''
... terminal-features[0] xterm*:clipboard:ccolour:cstyle:focus
... terminal-features[5] screen*:title
... ''')))) == {
... "terminal-features": {"xterm*": ["clipboard", "ccolour", "cstyle", "focus"],
... "screen*": ["title"]}}
True
>>> explode_complex(explode_arrays(parse_options_to_dict(io.StringIO(r'''
... command-alias[0] split-pane=split-window
... command-alias[1] splitp=split-window
... command-alias[2] "server-info=show-messages -JT"
... ''')))) == {
... "command-alias": {"split-pane": "split-window",
... "splitp": "split-window",
... "server-info": "show-messages -JT"}}
True
>>> explode_complex(explode_arrays({"terminal-features": {0: "xterm*:clipboard:ccolour:cstyle:focus",
... 1: "screen*:title"}}))
{'terminal-features': {0: 'xterm*:clipboard:ccolour:cstyle:focus', 1: 'screen*:title'}}
>>> explode_complex(explode_arrays({"terminal-features": {0: "xterm*:clipboard:ccolour:cstyle:focus",
... 8: "screen*:title"}})) == SparseArray({'terminal-features': {0:
... 'xterm*:clipboard:ccolour:cstyle:focus', 8: 'screen*:title'}})
True
>>> explode_complex(explode_arrays(parse_options_to_dict(io.StringIO(r'''
... terminal-overrides[0] xterm-256color:Tc
... terminal-overrides[1] *:U8=0
... ''')))) == {
... "terminal-overrides": {"xterm-256color": {"Tc": None},
... "*": {"U8": 0}}}
True
>>> explode_complex(explode_arrays(parse_options_to_dict(io.StringIO(r'''
... user-keys[100] "\e[test"
... user-keys[6] "\e\n"
... user-keys[0] "\e[5;30012~"
... ''')))) == {
... "user-keys": {0: "\\e[5;30012~",
... 6: "\\e\\n",
... 100: "\\e[test"}}
True
>>> explode_complex(explode_arrays(parse_options_to_dict(io.StringIO(r'''
... status-format[0] "#[align=left range=left #{E:status-left-style}]#[push-default]#{T;=/#{status-left-length}:status-left}#[pop-default]#[norange default]#[list=on align=#{status-justify}]#[list=left-marker]<#[list=right-marker]>#[list=on]#{W:#[range=window|#{window_index} #{E:window-status-style}#{?#{&&:#{window_last_flag},#{!=:#{E:window-status-last-style},default}}, #{E:window-status-last-style},}#{?#{&&:#{window_bell_flag},#{!=:#{E:window-status-bell-style},default}}, #{E:window-status-bell-style},#{?#{&&:#{||:#{window_activity_flag},#{window_silence_flag}},#{!=:#{E:window-status-activity-style},default}}, #{E:window-status-activity-style},}}]#[push-default]#{T:window-status-format}#[pop-default]#[norange default]#{?window_end_flag,,#{window-status-separator}},#[range=window|#{window_index} list=focus #{?#{!=:#{E:window-status-current-style},default},#{E:window-status-current-style},#{E:window-status-style}}#{?#{&&:#{window_last_flag},#{!=:#{E:window-status-last-style},default}}, #{E:window-status-last-style},}#{?#{&&:#{window_bell_flag},#{!=:#{E:window-status-bell-style},default}}, #{E:window-status-bell-style},#{?#{&&:#{||:#{window_activity_flag},#{window_silence_flag}},#{!=:#{E:window-status-activity-style},default}}, #{E:window-status-activity-style},}}]#[push-default]#{T:window-status-current-format}#[pop-default]#[norange list=on default]#{?window_end_flag,,#{window-status-separator}}}#[nolist align=right range=right #{E:status-right-style}]#[push-default]#{T;=/#{status-right-length}:status-right}#[pop-default]#[norange default]"
... status-format[1] "#[align=centre]#{P:#{?pane_active,#[reverse],}#{pane_index}[#{pane_width}x#{pane_height}]#[default] }"
... ''')))) == {
... "status-format": {0: "#[align=left range=left #{E:status-left-style}]#[push-default]#{T;=/#{status-left-length}:status-left}#[pop-default]#[norange default]#[list=on align=#{status-justify}]#[list=left-marker]<#[list=right-marker]>#[list=on]#{W:#[range=window|#{window_index} #{E:window-status-style}#{?#{&&:#{window_last_flag},#{!=:#{E:window-status-last-style},default}}, #{E:window-status-last-style},}#{?#{&&:#{window_bell_flag},#{!=:#{E:window-status-bell-style},default}}, #{E:window-status-bell-style},#{?#{&&:#{||:#{window_activity_flag},#{window_silence_flag}},#{!=:#{E:window-status-activity-style},default}}, #{E:window-status-activity-style},}}]#[push-default]#{T:window-status-format}#[pop-default]#[norange default]#{?window_end_flag,,#{window-status-separator}},#[range=window|#{window_index} list=focus #{?#{!=:#{E:window-status-current-style},default},#{E:window-status-current-style},#{E:window-status-style}}#{?#{&&:#{window_last_flag},#{!=:#{E:window-status-last-style},default}}, #{E:window-status-last-style},}#{?#{&&:#{window_bell_flag},#{!=:#{E:window-status-bell-style},default}}, #{E:window-status-bell-style},#{?#{&&:#{||:#{window_activity_flag},#{window_silence_flag}},#{!=:#{E:window-status-activity-style},default}}, #{E:window-status-activity-style},}}]#[push-default]#{T:window-status-current-format}#[pop-default]#[norange list=on default]#{?window_end_flag,,#{window-status-separator}}}#[nolist align=right range=right #{E:status-right-style}]#[push-default]#{T;=/#{status-right-length}:status-right}#[pop-default]#[norange default]",
... 1: "#[align=centre]#{P:#{?pane_active,#[reverse],}#{pane_index}[#{pane_width}x#{pane_height}]#[default] }",
... }}
True
Parameters:

_dict (ExplodedUntypedOptionsDict)

Return type:

ExplodedComplexUntypedOptionsDict

class libtmux.options.OptionsMixin
¶

Bases: CmdMixin

Mixin for managing tmux options based on scope.