Skip to content

Streamline and document direct commands #527

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fee8d4c
conftest(doctest): Add libtmux objects
tony Feb 17, 2024
88ee7cd
chore(tmux_cmd): Improve docstring, add doctest
tony Feb 16, 2024
f9245be
docs(Server.cmd): Fix typo
tony Feb 17, 2024
53ce1c5
docs(README): Direct usage examples
tony Feb 17, 2024
7552e3b
docs(README): Overhaul doctests
tony Feb 17, 2024
5a86a95
docs(quickstart): Add raw commands
tony Feb 17, 2024
7547e9c
docs(Server.cmd): Add examples
tony Feb 17, 2024
e4a47c2
chore(Server.cmd): Accept cmd as first positional argument
tony Feb 17, 2024
8c297fc
chore(Session.cmd): Accept cmd as first positional argument
tony Feb 17, 2024
2dd6331
Session(cmd): Remove **kwargs
tony Feb 17, 2024
a801351
Server(cmd): Remove **kwargs
tony Feb 17, 2024
c44225a
Window(cmd): Remove **kwargs
tony Feb 17, 2024
20c4cd0
Pane(cmd): Remove **kwargs
tony Feb 17, 2024
d512f90
Server.attached_sessions: Simplify by using filter
tony Feb 17, 2024
eb3bc27
Session.attached_window: Use .filter
tony Feb 17, 2024
9d95438
feat: Rename Session.attached_window -> Session.active_window
tony Feb 17, 2024
9c67ae6
refactor(Session.active_window): Use renamed method
tony Feb 17, 2024
3b7aa9f
Window.attached_pane: Use .filter
tony Feb 17, 2024
e35e3d9
feat: Rename Window.attached_pane -> Window.active_pane
tony Feb 17, 2024
bc4a971
Session: Consolidate duplicate computed property (attached_pane)
tony Feb 17, 2024
5cede5a
feat: Rename Session.attached_pane -> Session.active_pane
tony Feb 17, 2024
d75d5ff
refactor({Window,Session}.active_pane): Use renamed method
tony Feb 17, 2024
01ab013
refactor!(tmux_cmd): Remove kwargs
tony Feb 17, 2024
25e45fd
docs(Session.cmd): Add examples
tony Feb 17, 2024
702d530
docs(Window.cmd): Add examples
tony Feb 17, 2024
bcae86a
docs(Pane.cmd): Add examples
tony Feb 17, 2024
0ade87a
docs(CHANGES): Typo
tony Feb 17, 2024
e7eb5a5
docs(CHANGES): Note command updates
tony Feb 17, 2024
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
32 changes: 30 additions & 2 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@ $ pip install --user --upgrade --pre libtmux

<!-- To maintainers and contributors: Please add notes for the forthcoming version above -->

### Cleanups (#527)

- Streamline `{Server,Session,Window,Pane}.cmd()`, across all usages to:
- Use `cmd: str` as first positional
- Removed unused keyword arguments `**kwargs`

### Renamings (#527)

- `Session.attached_window` renamed to {meth}`Session.active_window`
- `Session.attached_window` deprecated
- `Session.attached_pane` renamed to {meth}`Session.active_pane`
- `Session.attached_pane` deprecated
- `Window.attached_pane` renamed to {meth}`Window.active_pane`
- `Window.attached_pane` deprecated

### Improvements (#527)

- `Server.attached_windows` now users `QueryList`'s `.filter()`

### Documentation (#527)

- Document `.cmd` in README and quickstart
- Add doctests and improve docstrings to `cmd()` methods across:
- {meth}`Server.cmd()`
- {meth}`Session.cmd()`
- {meth}`Window.cmd()`
- {meth}`Pane.cmd()`

## libtmux 0.30.2 (2024-02-16)

### Development
Expand Down Expand Up @@ -80,7 +108,7 @@ _Maintenance only, no bug fixes or new features_

## libtmux 0.28.0 (2024-02-14)

### Breaking change
### Breaking changes

#### Detached / unselected by default (#523)

Expand Down Expand Up @@ -164,7 +192,7 @@ Tip: If {meth}`Pane.resize()` was not taking affect <= 0.27.1, try to resize wit

## libtmux 0.26.0 (2024-02-06)

### Breaking change
### Breaking changes

- `get_by_id()` (already deprecated) keyword argument renamed from `id` to
`Server.get_by_id(session_id)`, `Session.get_by_id(window_id)`, and `Window.get_by_id(pane_id)` (#514)
Expand Down
83 changes: 70 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ Connect to a live tmux session:

```python
>>> import libtmux
>>> s = libtmux.Server()
>>> s
>>> svr = libtmux.Server()
>>> svr
Server(socket_path=/tmp/tmux-.../default)
```

Expand All @@ -66,6 +66,49 @@ current tmux server / session / window pane.
[ptpython]: https://github.com/prompt-toolkit/ptpython
[ipython]: https://ipython.org/

Run any tmux command, respective of context:

Honors tmux socket name and path:

```python
>>> server = Server(socket_name='libtmux_doctest')
>>> server.cmd('display-message', 'hello world')
<libtmux...>
```

New session:

```python
>>> server.cmd('new-session', '-d', '-P', '-F#{session_id}').stdout[0]
'$2'
```

```python
>>> session.cmd('new-window', '-P').stdout[0]
'libtmux...:2.0'
```

Time for some tech, direct to a rich, `Window` object:

```python
>>> Window.from_window_id(window_id=session.cmd('new-window', '-P', '-F#{window_id}').stdout[0], server=session.server)
Window(@2 2:..., Session($1 libtmux_...))
```

Create a pane from a window:

```python
>>> window.cmd('split-window', '-P', '-F#{pane_id}').stdout[0]
'%2'
```

Magic, directly to a `Pane`:

```python
>>> Pane.from_pane_id(pane_id=session.cmd('split-window', '-P', '-F#{pane_id}').stdout[0], server=session.server)
Pane(%... Window(@1 1:..., Session($1 libtmux_...)))
```

List sessions:

```python
Expand All @@ -87,43 +130,57 @@ Direct lookup:
Session($1 ...)
```

Find session by dict lookup:
Filter sesions:

```python
>>> server.sessions[0].rename_session('foo')
Session($1 foo)
>>> server.sessions.filter(session_name="foo")[0]
>>> server.sessions.filter(session_name="foo")
[Session($1 foo)]
>>> server.sessions.get(session_name="foo")
Session($1 foo)
```

Control your session:

```python
>>> session.rename_session('foo')
Session($1 foo)
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@2 2:ha in the bg, Session($1 foo))
>>> session.kill_window("ha in")
>>> session
Session($1 ...)

>>> session.rename_session('my-session')
Session($1 my-session)
```

Create new window in the background (don't switch to it):

```python
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@2 2:ha in the bg, Session($1 ...))
>>> bg_window = session.new_window(attach=False, window_name="ha in the bg")
>>> bg_window
Window(@... 2:ha in the bg, Session($1 ...))

# Session can search the window
>>> session.windows.filter(window_name__startswith="ha")
[Window(@... 2:ha in the bg, Session($1 ...))]

# Directly
>>> session.windows.get(window_name__startswith="ha")
Window(@... 2:ha in the bg, Session($1 ...))

# Clean up
>>> bg_window.kill()
```

Close window:

```python
>>> w = session.attached_window
>>> w = session.active_window
>>> w.kill()
```

Grab remaining tmux window:

```python
>>> window = session.attached_window
>>> window = session.active_window
>>> window.split_window(attach=False)
Pane(%2 Window(@1 1:... Session($1 ...)))
```
Expand Down
12 changes: 10 additions & 2 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
import pytest
from _pytest.doctest import DoctestItem

from libtmux.pane import Pane
from libtmux.pytest_plugin import USING_ZSH
from libtmux.server import Server
from libtmux.session import Session
from libtmux.window import Window

if t.TYPE_CHECKING:
from libtmux.session import Session
Expand All @@ -30,11 +34,15 @@ def add_doctest_fixtures(
"""Configure doctest fixtures for pytest-doctest."""
if isinstance(request._pyfuncitem, DoctestItem) and shutil.which("tmux"):
request.getfixturevalue("set_home")
doctest_namespace["Server"] = Server
doctest_namespace["Session"] = Session
doctest_namespace["Window"] = Window
doctest_namespace["Pane"] = Pane
doctest_namespace["server"] = request.getfixturevalue("server")
session: "Session" = request.getfixturevalue("session")
doctest_namespace["session"] = session
doctest_namespace["window"] = session.attached_window
doctest_namespace["pane"] = session.attached_pane
doctest_namespace["window"] = session.active_window
doctest_namespace["pane"] = session.active_pane
doctest_namespace["request"] = request


Expand Down
44 changes: 39 additions & 5 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,44 @@ equivalent to `$ tmux -L mysocket`.
`server` is now a living object bound to the tmux server's Sessions,
Windows and Panes.

## Raw, contextual commands

New session:

```python
>>> server.cmd('new-session', '-d', '-P', '-F#{session_id}').stdout[0]
'$2'
```

```python
>>> session.cmd('new-window', '-P').stdout[0]
'libtmux...:2.0'
```

Time for some tech, direct to a rich, `Window` object:

```python
>>> Window.from_window_id(window_id=session.cmd('new-window', '-P', '-F#{window_id}').stdout[0], server=session.server)
Window(@2 2:..., Session($1 libtmux_...))
```

Create a pane from a window:

```python
>>> window.cmd('split-window', '-P', '-F#{pane_id}').stdout[0]
'%2'
```

Magic, directly to a `Pane`:

```python
>>> Pane.from_pane_id(pane_id=session.cmd('split-window', '-P', '-F#{pane_id}').stdout[0], server=session.server)
Pane(%... Window(@1 1:..., Session($1 libtmux_...)))
```

## Find your {class}`Session`

If you have multiple tmux sessions open, you can see that all of the
methods in {class}`Server` are available.
If you have multiple tmux sessions open, all methods in {class}`Server` are available.

We can list sessions with {meth}`Server.sessions`:

Expand Down Expand Up @@ -268,11 +302,11 @@ through active {class}`Window`'s.

## Manipulating windows

Now that we know how to create windows, let's use one. Let's use {meth}`Session.attached_window()`
Now that we know how to create windows, let's use one. Let's use {meth}`Session.active_window()`
to grab our current window.

```python
>>> window = session.attached_window
>>> window = session.active_window
```

`window` now has access to all of the objects inside of {class}`Window`.
Expand All @@ -286,7 +320,7 @@ Pane(%2 Window(@1 ...:..., Session($1 ...)))

Powered up. Let's have a break down:

1. `window = session.attached_window()` gave us the {class}`Window` of the current attached to window.
1. `window = session.active_window()` gave us the {class}`Window` of the current attached to window.
2. `attach=False` assures the cursor didn't switch to the newly created pane.
3. Returned the created {class}`Pane`.

Expand Down
4 changes: 2 additions & 2 deletions docs/reference/properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ from libtmux.neo import Obj
The same concepts apply for {class}`~libtmux.Window`:

```python
>>> window = session.attached_window
>>> window = session.active_window

>>> window
Window(@1 ...:..., Session($1 ...))
Expand Down Expand Up @@ -109,7 +109,7 @@ Use attribute access for details not accessible via properties:
Get the {class}`~libtmux.Pane`:

```python
>>> pane = window.attached_pane
>>> pane = window.active_pane

>>> pane
Pane(%1 Window(@1 ...:..., Session($1 libtmux_...)))
Expand Down
8 changes: 4 additions & 4 deletions docs/topics/traversal.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,27 +71,27 @@ Window(@1 ...:..., Session($1 ...))
Grab the currently focused window from session:

```python
>>> session.attached_window
>>> session.active_window
Window(@1 ...:..., Session($1 ...))
```

Grab the currently focused {class}`Pane` from session:

```python
>>> session.attached_pane
>>> session.active_pane
Pane(%1 Window(@1 ...:..., Session($1 ...)))
```

Assign the attached {class}`~libtmux.Pane` to `p`:

```python
>>> p = session.attached_pane
>>> p = session.active_pane
```

Access the window/server of a pane:

```python
>>> p = session.attached_pane
>>> p = session.active_pane
>>> p.window
Window(@1 ...:..., Session($1 ...))

Expand Down
21 changes: 11 additions & 10 deletions src/libtmux/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,20 +187,21 @@ def getenv(self, name: str) -> Optional[t.Union[str, bool]]:


class tmux_cmd:
""":term:`tmux(1)` command via :py:mod:`subprocess`.
"""Run any :term:`tmux(1)` command through :py:mod:`subprocess`.

Examples
--------
.. code-block:: python
Create a new session, check for error:

proc = tmux_cmd('new-session', '-s%' % 'my session')
>>> proc = tmux_cmd(f'-L{server.socket_name}', 'new-session', '-d', '-P', '-F#S')
>>> if proc.stderr:
... raise exc.LibTmuxException(
... 'Command: %s returned error: %s' % (proc.cmd, proc.stderr)
... )
...

if proc.stderr:
raise exc.LibTmuxException(
'Command: %s returned error: %s' % (proc.cmd, proc.stderr)
)

print('tmux command returned %s' % proc.stdout)
>>> print(f'tmux command returned {" ".join(proc.stdout)}')
tmux command returned 2

Equivalent to:

Expand All @@ -214,7 +215,7 @@ class tmux_cmd:
Renamed from ``tmux`` to ``tmux_cmd``.
"""

def __init__(self, *args: t.Any, **kwargs: t.Any) -> None:
def __init__(self, *args: t.Any) -> None:
tmux_bin = shutil.which("tmux")
if not tmux_bin:
raise exc.TmuxCommandNotFound()
Expand Down
Loading