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)[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, useexcept exc.OptionError.- Parameters:
error (str) – Error response from subprocess call.
- Raises:
exc.OptionError –
- Return type:
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])
- Return type:
- Parameters:
error (str)
- libtmux.options.convert_value(value)[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'
- libtmux.options.convert_values(value)[source]¶
Recursively convert values to python types via
convert_value().- Return type:
Union[str,int,bool,None,list[str|int|bool|None],dict[str,str|int|bool|None],SparseArray[str|int|bool|None],TypeVar(_V)]- Parameters:
value (_V | None)
>>> 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}
- libtmux.options.parse_options_to_dict(stdout)[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
- libtmux.options.explode_arrays(_dict, force_array=False)[source]¶
Explode flat, naive options dict’s option arrays.
- Return type:
- Parameters:
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=Truefor 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]
- libtmux.options.explode_complex(_dict)[source]¶
Explode arrayed option’s complex values.
- Return type:
dict[str,str|int|list[str|int] |dict[str,list[str|int]] |SparseArray[str|int] |None]- Parameters:
_dict (dict[str, str | int | list[str] | dict[str, list[str]]])
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
- class libtmux.options.OptionsMixin[source]¶
Mixin for managing tmux options based on scope.
When not a user (custom) option, scope can be implied.
- __init__(default_option_scope=None)[source]¶
When not a user (custom) option, scope can be implied.
- Parameters:
default_option_scope (OptionScope | None)
- Return type:
None
- set_option(option, value, _format=None, prevent_overwrite=None, ignore_errors=None, suppress_warnings=None, append=None, g=None, global_=None, scope=<libtmux.constants._DefaultOptionScope object>)[source]¶
Set option for tmux target.
Wraps
$ tmux set-option <option> <value>.- Return type:
Self
- Parameters:
option (str) – option to set, e.g. ‘aggressive-resize’
value (str) – option value. True/False will turn in ‘on’ and ‘off’, also accepts string of ‘on’ or ‘off’ directly.
deprecated: (..) – 0.28: Deprecated by
gfor global, use global_` instead._format (bool | None)
prevent_overwrite (bool | None)
ignore_errors (bool | None)
suppress_warnings (bool | None)
append (bool | None)
g (bool | None)
global_ (bool | None)
scope (OptionScope | _DefaultOptionScope | None)
- Raises:
exc.OptionError –
Examples
>>> import typing as t >>> from libtmux.common import tmux_cmd >>> from libtmux.constants import OptionScope >>> from libtmux._internal.sparse_array import SparseArray
>>> class MyServer(OptionsMixin): ... socket_name = server.socket_name ... def cmd(self, cmd: str, *args: object): ... cmd_args: t.List[t.Union[str, int]] = [cmd] ... if self.socket_name: ... cmd_args.insert(0, f"-L{self.socket_name}") ... cmd_args.insert(0, "-f/dev/null") ... return tmux_cmd(*cmd_args, *args) ... ... default_option_scope = OptionScope.Server
>>> MyServer().set_option('escape-time', 1250) <libtmux.options.MyServer object at ...>
>>> MyServer()._show_option('escape-time') 1250
>>> MyServer().set_option('escape-time', 495) <libtmux.options.MyServer object at ...>
>>> MyServer()._show_option('escape-time') 495
- unset_option(option, unset_panes=None, global_=None, ignore_errors=None, scope=<libtmux.constants._DefaultOptionScope object>)[source]¶
Unset option for tmux target.
Wraps
$ tmux set-option -u <option>/$ tmux set-option -U <option>- Return type:
Self
- Parameters:
option (str) – option to unset, e.g. ‘aggressive-resize’
unset_panes (bool | None)
global_ (bool | None)
ignore_errors (bool | None)
scope (OptionScope | _DefaultOptionScope | None)
- Raises:
exc.OptionError –
Examples
>>> import typing as t >>> from libtmux.common import tmux_cmd >>> from libtmux.constants import OptionScope
>>> class MyServer(OptionsMixin): ... socket_name = server.socket_name ... def cmd(self, cmd: str, *args: object): ... cmd_args: t.List[t.Union[str, int]] = [cmd] ... if self.socket_name: ... cmd_args.insert(0, f"-L{self.socket_name}") ... cmd_args.insert(0, "-f/dev/null") ... return tmux_cmd(*cmd_args, *args) ... ... default_option_scope = OptionScope.Server
>>> MyServer().set_option('escape-time', 1250) <libtmux.options.MyServer object at ...>
>>> MyServer()._show_option('escape-time') 1250
>>> MyServer().unset_option('escape-time') <libtmux.options.MyServer object at ...>
>>> isinstance(MyServer()._show_option('escape-time'), int) True
- show_options(global_=False, scope=<libtmux.constants._DefaultOptionScope object>, include_hooks=None, include_inherited=None)[source]¶
Return all options for the target.
- Return type:
dict[str,str|int|list[str|int] |dict[str,list[str|int]] |SparseArray[str|int] |None]- Parameters:
global (bool, optional) – Pass
-gflag for global options, default False.scope (OptionScope | _DefaultOptionScope | None, optional) – Option scope (Server/Session/Window/Pane), defaults to object’s scope.
include_hooks (bool, optional) – Include hook options (
-Hflag).include_inherited (bool, optional) – Include inherited options (
-Aflag).global_ (bool)
- Returns:
Dictionary with all options, arrays exploded and values converted.
- Return type:
ExplodedComplexUntypedOptionsDict
- Raises:
exc.OptionError –
Examples
>>> options = server.show_options() >>> isinstance(options, dict) True
>>> 'buffer-limit' in options True
- show_option(option, global_=False, g=False, scope=<libtmux.constants._DefaultOptionScope object>, ignore_errors=None, include_hooks=None, include_inherited=None)[source]¶
Return option value for the target.
- Return type:
- Parameters:
- Raises:
exc.OptionError –
Examples
>>> import typing as t >>> from libtmux.common import tmux_cmd >>> from libtmux.constants import OptionScope
>>> class MyServer(OptionsMixin): ... socket_name = server.socket_name ... def cmd(self, cmd: str, *args: object): ... cmd_args: t.List[t.Union[str, int]] = [cmd] ... if self.socket_name: ... cmd_args.insert(0, f"-L{self.socket_name}") ... cmd_args.insert(0, "-f/dev/null") ... return tmux_cmd(*cmd_args, *args) ... ... default_option_scope = OptionScope.Server
>>> MyServer().cmd('new-session', '-d') <libtmux.common.tmux_cmd object at ...>
>>> MyServer().show_option('exit-unattached', global_=True) False