Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ environment-setup plumbing, so each example leads with the constructor call it
demonstrates instead of the socket-path and `$TMUX` boilerplate needed to run
it.

#### Task directories on Server, Session, Window and Pane

The class docstrings of {class}`~libtmux.Server`, {class}`~libtmux.Session`,
{class}`~libtmux.Window`, and {class}`~libtmux.Pane` now group their methods by
the job a reader arrives with, such as finding one thing, listing everything,
or sending input. Each group says what a call returns and which exception it
raises, then lists the members that do the job.

### Development

#### Ruff 0.17.3 for development (#825)
Expand Down
93 changes: 93 additions & 0 deletions src/libtmux/pane.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,99 @@ class Pane(
``Pane`` instances can send commands directly to a pane, or traverse
between linked tmux objects.

**Reading it.** Every field is a tmux format token read when the pane was
listed or last refreshed, and is ``None`` when tmux gave no value.
:meth:`~libtmux.Pane.refresh` rewrites the fields in place and raises
:exc:`~libtmux.exc.TmuxObjectDoesNotExist` when the pane has gone. The edge
properties convert tmux's flags to bools.

- Identity: :attr:`~libtmux.Pane.pane_id`, :attr:`~libtmux.Pane.id`
- Position: :attr:`~libtmux.Pane.pane_index`, :attr:`~libtmux.Pane.index`
- Size: :attr:`~libtmux.Pane.width`, :attr:`~libtmux.Pane.height`
- Edges: :attr:`~libtmux.Pane.at_top`, :attr:`~libtmux.Pane.at_bottom`,
:attr:`~libtmux.Pane.at_left`, :attr:`~libtmux.Pane.at_right`
- Title: :attr:`~libtmux.Pane.title`
- Re-read from tmux: :meth:`~libtmux.Pane.refresh`

**Finding it.** :meth:`~libtmux.Pane.from_pane_id` asks tmux for one pane and
raises :exc:`~libtmux.exc.TmuxObjectDoesNotExist` when it is not there.
:meth:`~libtmux.Pane.from_env` returns the pane this process runs inside, read
from ``$TMUX`` and ``$TMUX_PANE``, and raises :exc:`~libtmux.exc.NotInsideTmux`
outside one.

- By ID: :meth:`~libtmux.Pane.from_pane_id`
- The pane you run inside: :meth:`~libtmux.Pane.from_env`
- From a listing: :attr:`~libtmux.Server.panes`,
:attr:`~libtmux.Window.panes`

**Finding its parents.** Each access asks tmux.

- Parents: :attr:`~libtmux.Pane.window`, :attr:`~libtmux.Pane.session`

**Sending input.** :meth:`~libtmux.Pane.send_keys` presses Enter after the
keys unless ``enter=False``, and sends them literally with ``literal=True``.
Called without keys it needs ``reset``, ``repeat`` or ``copy_mode_cmd``, and
raises :exc:`ValueError` otherwise.

- Send keys: :meth:`~libtmux.Pane.send_keys`
- Press Enter: :meth:`~libtmux.Pane.enter`
- Paste a buffer: :meth:`~libtmux.Pane.paste_buffer`
- Send the prefix key: :meth:`~libtmux.Pane.send_prefix`

**Reading output.** :meth:`~libtmux.Pane.capture_pane` returns a list with one
string per row. ``start`` and ``end`` count from the first visible line, with
negative numbers reaching into the history, ``-`` for the start of the history
as ``start`` and for the end of the visible pane as ``end``. With ``to_buffer``
it stores the capture in a tmux buffer and returns ``None``. A flag newer than
the running tmux warns and is ignored.

- Capture rows: :meth:`~libtmux.Pane.capture_pane`
- Ask tmux for a format: :meth:`~libtmux.Pane.display_message`

**Splitting and arranging.** :meth:`~libtmux.Pane.split` divides this exact
pane, beneath it by default, and returns the new pane. Passing both ``size``
and ``percentage`` raises :exc:`ValueError`. A resize takes an adjustment, a
height and width, or zoom, and a height or width given as text must be digits
or a percentage.

- Split: :meth:`~libtmux.Pane.split`, :meth:`~libtmux.Pane.new_pane`
- Resize: :meth:`~libtmux.Pane.resize`, :meth:`~libtmux.Pane.set_width`,
:meth:`~libtmux.Pane.set_height`
- Exchange two panes: :meth:`~libtmux.Pane.swap`
- Move it into another window: :meth:`~libtmux.Pane.join`,
:meth:`~libtmux.Pane.move`
- Move it into a window of its own: :meth:`~libtmux.Pane.break_pane`
- Make it active: :meth:`~libtmux.Pane.select`

**Modes, pipes and history.** :meth:`~libtmux.Pane.pipe` copies the pane's
output to a shell command, and stops piping when given no command.
:meth:`~libtmux.Pane.clear_history` forgets the scrollback, and
:meth:`~libtmux.Pane.reset` also resets the terminal state.

- Copy mode: :meth:`~libtmux.Pane.copy_mode`
- Pipe output: :meth:`~libtmux.Pane.pipe`
- Scrollback and screen: :meth:`~libtmux.Pane.clear_history`,
:meth:`~libtmux.Pane.clear`, :meth:`~libtmux.Pane.reset`
- Title: :meth:`~libtmux.Pane.set_title`

**Changing it.** :meth:`~libtmux.Pane.respawn` documents ``kill=True`` as
required if the pane is still active. :meth:`~libtmux.Pane.kill` takes
``all_except`` to kill every other pane in the window instead.

- Restart what it runs: :meth:`~libtmux.Pane.respawn`
- Destroy it: :meth:`~libtmux.Pane.kill`

**Options and hooks.** An option or hook call acts on the pane scope by
default. The setters return the pane, so calls chain, and an unknown or
invalid name raises :exc:`~libtmux.exc.OptionError` or one of its subclasses.

- Options: :meth:`~libtmux.Pane.show_options`,
:meth:`~libtmux.Pane.show_option`, :meth:`~libtmux.Pane.set_option`,
:meth:`~libtmux.Pane.unset_option`
- Hooks: :meth:`~libtmux.Pane.show_hooks`, :meth:`~libtmux.Pane.show_hook`,
:meth:`~libtmux.Pane.set_hook`, :meth:`~libtmux.Pane.unset_hook`,
:meth:`~libtmux.Pane.run_hook`

Attributes
----------
default_option_scope : OptionScope | None
Expand Down
116 changes: 116 additions & 0 deletions src/libtmux/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,122 @@ class Server(

When instantiated stores information on live, running tmux server.

**Connecting.** Constructing a :class:`~libtmux.Server` runs no tmux command
of its own; it records the socket and settings every later call uses.
:meth:`~libtmux.Server.from_env` reads ``$TMUX`` without a subprocess, raises
:exc:`~libtmux.exc.NotInsideTmux` when it is unset, and does not check that the
server is alive. :meth:`~libtmux.Server.is_alive` answers a bool and never
raises, where :meth:`~libtmux.Server.raise_if_dead` raises
:exc:`~libtmux.exc.TmuxCommandNotFound` or
:class:`subprocess.CalledProcessError`.

- Name a server: :class:`~libtmux.Server`, :meth:`~libtmux.Server.from_env`
- Is anything listening: :meth:`~libtmux.Server.is_alive`,
:meth:`~libtmux.Server.raise_if_dead`
- Start the daemon: :meth:`~libtmux.Server.start_server`

**Finding one thing.** Each ``from_*_id`` constructor asks tmux for one object
and raises :exc:`~libtmux.exc.TmuxObjectDoesNotExist` when it is not there.
``get`` on a listing returns exactly one match, and raises
:exc:`~libtmux.exc.ObjectDoesNotExist` for none unless a default is passed,
and :exc:`~libtmux.exc.MultipleObjectsReturned` for several.
:meth:`~libtmux.Server.has_session` answers a bool, matches the name exactly
unless ``exact=False``, and raises :exc:`~libtmux.exc.BadSessionName` for an
empty name or one holding a period or colon.

- By ID: :meth:`~libtmux.Session.from_session_id`,
:meth:`~libtmux.Window.from_window_id`, :meth:`~libtmux.Pane.from_pane_id`
- One match from a listing:
:meth:`~libtmux._internal.query_list.QueryList.get`
- Exists, without returning it: :meth:`~libtmux.Server.has_session`

**Listing everything.** Each access reads tmux again and returns a
:class:`~libtmux._internal.query_list.QueryList`, so a list you keep is a
snapshot. :attr:`~libtmux.Server.sessions` and :attr:`~libtmux.Server.clients`
answer an empty list when the tmux command fails for any reason, so tell "no
sessions" from "tmux unreachable" with :meth:`~libtmux.Server.is_alive`.
:attr:`~libtmux.Server.windows` and :attr:`~libtmux.Server.panes` answer empty
only while the daemon is not up and raise on other tmux errors. Windows and
panes span every session.

- Listings: :attr:`~libtmux.Server.sessions`, :attr:`~libtmux.Server.windows`,
:attr:`~libtmux.Server.panes`, :attr:`~libtmux.Server.clients`
- With a client attached: :attr:`~libtmux.Server.attached_sessions`

**Filtering.** ``filter`` on a listing runs in Python against the full list.
The ``search_*`` methods hand tmux a ``-f`` format expression instead, and tmux
drops rows before any object is built. A malformed expression expands to empty
and hides every row without an error.

- In Python: :meth:`~libtmux._internal.query_list.QueryList.filter`
- In tmux: :meth:`~libtmux.Server.search_sessions`,
:meth:`~libtmux.Server.search_windows`, :meth:`~libtmux.Server.search_panes`

**Creating and destroying.** :meth:`~libtmux.Server.new_session` creates a
detached session and returns it. A name already in use raises
:exc:`~libtmux.exc.TmuxSessionExists` unless ``kill_session=True``.
:meth:`~libtmux.Server.kill_session` passes its target to tmux, which matches
it with ``fnmatch(3)``, so ``asdf`` also kills ``asdfasd``.
:meth:`~libtmux.Server.kill` stops the server and returns quietly when no
daemon is running.

- New session: :meth:`~libtmux.Server.new_session`
- Kill one session: :meth:`~libtmux.Server.kill_session`
- Stop the server: :meth:`~libtmux.Server.kill`

**Clients.** :attr:`~libtmux.Server.clients` returns typed
:class:`~libtmux.Client` objects and :meth:`~libtmux.Server.list_clients`
returns tmux's raw lines. Switching and attaching take a session name, which
raises :exc:`~libtmux.exc.BadSessionName` when it is empty or holds a period
or colon.

- Listing: :attr:`~libtmux.Server.clients`,
:meth:`~libtmux.Server.list_clients`
- Move one: :meth:`~libtmux.Server.switch_client`,
:meth:`~libtmux.Server.attach_session`
- Detach: :meth:`~libtmux.Server.detach_client`,
:meth:`~libtmux.Server.detach_all_clients`

**Options, hooks and environment.** These calls come from mixins and act on
the server scope by default. The option and hook setters return the object, so
calls chain, and an unknown or invalid option or hook name raises
:exc:`~libtmux.exc.OptionError` or one of its subclasses. The environment
calls act on the server's global environment, and the setters raise
:exc:`ValueError` when tmux reports an error.

- Options: :meth:`~libtmux.Server.show_options`,
:meth:`~libtmux.Server.show_option`, :meth:`~libtmux.Server.set_option`,
:meth:`~libtmux.Server.unset_option`
- Hooks: :meth:`~libtmux.Server.show_hooks`,
:meth:`~libtmux.Server.show_hook`, :meth:`~libtmux.Server.set_hook`,
:meth:`~libtmux.Server.set_hooks`, :meth:`~libtmux.Server.unset_hook`,
:meth:`~libtmux.Server.run_hook`
- Environment: :meth:`~libtmux.Server.show_environment`,
:meth:`~libtmux.Server.getenv`, :meth:`~libtmux.Server.set_environment`,
:meth:`~libtmux.Server.unset_environment`,
:meth:`~libtmux.Server.remove_environment`

**Buffers and key bindings.** Each wraps the tmux command of the same name and
raises :exc:`~libtmux.exc.LibTmuxException` when tmux writes to stderr.

- Buffers: :meth:`~libtmux.Server.list_buffers`,
:meth:`~libtmux.Server.show_buffer`, :meth:`~libtmux.Server.set_buffer`,
:meth:`~libtmux.Server.delete_buffer`, :meth:`~libtmux.Server.save_buffer`,
:meth:`~libtmux.Server.load_buffer`
- Key bindings: :meth:`~libtmux.Server.list_keys`,
:meth:`~libtmux.Server.bind_key`, :meth:`~libtmux.Server.unbind_key`

**Running a command.** Anything tmux can do that has no method here goes
through :meth:`~libtmux.Server.cmd`, which adds the socket, config file and
color flags and returns a :class:`~libtmux.common.tmux_cmd` holding the
return code, stdout and stderr. It does not check them. The shell and sourcing
helpers do, and raise :exc:`~libtmux.exc.LibTmuxException`.

- One command: :meth:`~libtmux.Server.cmd`
- Shell and conditionals: :meth:`~libtmux.Server.run_shell`,
:meth:`~libtmux.Server.if_shell`, :meth:`~libtmux.Server.wait_for`
- Configuration: :meth:`~libtmux.Server.source_file`

Parameters
----------
socket_name : str, optional
Expand Down
85 changes: 85 additions & 0 deletions src/libtmux/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,91 @@ class Session(

Holds :class:`Window` objects.

**Reading it.** Every field is a tmux format token read when the session was
listed or last refreshed, and is ``None`` when tmux gave no value.
:meth:`~libtmux.Session.refresh` rewrites the fields in place and returns
``None``.

- Identity: :attr:`~libtmux.Session.session_id`,
:attr:`~libtmux.Session.id`
- Name: :attr:`~libtmux.Session.session_name`, :attr:`~libtmux.Session.name`
- Re-read from tmux: :meth:`~libtmux.Session.refresh`

**Finding it.** :meth:`~libtmux.Session.from_session_id` asks tmux for one
session and raises :exc:`~libtmux.exc.TmuxObjectDoesNotExist` when it is gone.
:meth:`~libtmux.Session.from_env` resolves the session of the pane this
process runs inside, through ``$TMUX_PANE``, and raises
:exc:`~libtmux.exc.NotInsideTmux` outside one.

- By ID: :meth:`~libtmux.Session.from_session_id`
- The session you run inside: :meth:`~libtmux.Session.from_env`
- From a listing: :attr:`~libtmux.Server.sessions`
- By name, without returning it: :meth:`~libtmux.Server.has_session`

**Finding what is inside.** Each access reads tmux again and returns a
:class:`~libtmux._internal.query_list.QueryList`. Unlike
:attr:`~libtmux.Server.sessions`, these raise
:exc:`~libtmux.exc.LibTmuxException` when tmux writes to stderr.
:attr:`~libtmux.Session.active_window` raises
:exc:`~libtmux.exc.NoActiveWindow` or
:exc:`~libtmux.exc.MultipleActiveWindows` unless exactly one window is active.
:attr:`~libtmux.Session.active_pane` is the active window's active pane, or
``None``.

- Windows and panes: :attr:`~libtmux.Session.windows`,
:attr:`~libtmux.Session.panes`
- The active ones: :attr:`~libtmux.Session.active_window`,
:attr:`~libtmux.Session.active_pane`
- Filtered by tmux: :meth:`~libtmux.Session.search_windows`,
:meth:`~libtmux.Session.search_panes`

**Moving the selection.** Each returns the window that is now active and
raises :exc:`~libtmux.exc.LibTmuxException` when tmux refuses.

- Relative: :meth:`~libtmux.Session.next_window`,
:meth:`~libtmux.Session.previous_window`,
:meth:`~libtmux.Session.last_window`
- A named window: :meth:`~libtmux.Session.select_window`

**Adding windows.** :meth:`~libtmux.Session.new_window` returns the new
:class:`~libtmux.Window`. It is created detached unless ``attach=True``, and
it takes the next free index unless ``window_index`` names one.

- New window: :meth:`~libtmux.Session.new_window`
- Next to a window you hold: :meth:`~libtmux.Window.new_window`

**Changing it.** :meth:`~libtmux.Session.rename_session` raises
:exc:`~libtmux.exc.BadSessionName` for an empty name or one holding a period
or colon, refreshes the session and returns it.
:meth:`~libtmux.Session.kill` closes the linked windows and detaches every
client, and ``group=True`` needs tmux 3.7 or later, below which it warns and is
ignored.

- Rename: :meth:`~libtmux.Session.rename_session`
- Destroy it: :meth:`~libtmux.Session.kill`
- Close one window: :meth:`~libtmux.Session.kill_window`
- Detach its clients: :meth:`~libtmux.Session.detach_client`
- Attach a terminal or switch to it: :meth:`~libtmux.Session.attach`,
:meth:`~libtmux.Session.switch_client`

**Options, hooks and environment.** An option or hook call leaves the scope
flag off by default, which tmux resolves as session scope. The setters return
the session, so calls chain, and an unknown or invalid name raises
:exc:`~libtmux.exc.OptionError` or one of its subclasses. The environment
calls act on this session and raise :exc:`ValueError` when tmux reports an
error.

- Options: :meth:`~libtmux.Session.show_options`,
:meth:`~libtmux.Session.show_option`, :meth:`~libtmux.Session.set_option`,
:meth:`~libtmux.Session.unset_option`
- Hooks: :meth:`~libtmux.Session.show_hooks`,
:meth:`~libtmux.Session.show_hook`, :meth:`~libtmux.Session.set_hook`,
:meth:`~libtmux.Session.unset_hook`, :meth:`~libtmux.Session.run_hook`
- Environment: :meth:`~libtmux.Session.show_environment`,
:meth:`~libtmux.Session.getenv`, :meth:`~libtmux.Session.set_environment`,
:meth:`~libtmux.Session.unset_environment`,
:meth:`~libtmux.Session.remove_environment`

Parameters
----------
server : :class:`Server`
Expand Down
Loading
Loading