Skip to content

New and improved commands #525

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 14 commits into from
Feb 16, 2024
Merged
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
26 changes: 26 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,32 @@ $ pip install --user --upgrade --pre libtmux

<!-- Maintainers and contributors: Insert change notes for the next release above -->

### New commands

- {meth}`Pane.kill()`

### Renamed commands

- `Window.select_window()` renamed to {meth}`Window.select()`
- Deprecated `Window.select_window()`
- `Pane.select_pane()` renamed to {meth}`Pane.select()`
- Deprecated `Pane.pane_select()`
- `Session.attach_session()` renamed to {meth}`Session.attach()`
- Deprecated `Session.attach_session()`
- `Server.kill_server()` renamed to {meth}`Server.kill()`
- Deprecated `Server.kill_server()`
- `Session.kill_session()` renamed to {meth}`Session.kill()`
- Deprecated `Session.kill_session()`
- `Window.kill_window()` renamed to {meth}`Window.kill()`
- Deprecated `Window.kill_window()`

### Improved commands

- {meth}`Server.new_session()`: Support environment variables
- {meth}`Window.split_window()`: Support `size` via `-l`

Supports columns/rows (`size=10`) and percentage (`size='10%'`)

## libtmux 0.29.0 (2024-02-16)

#### Bug fixes
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Close window:

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

Grab remaining tmux window:
Expand All @@ -140,7 +140,7 @@ Split window (create a new pane):
```python
>>> pane = window.split_window()
>>> pane = window.split_window(attach=False)
>>> pane.select_pane()
>>> pane.select()
Pane(%3 Window(@1 1:..., Session($1 ...)))
>>> window = session.new_window(attach=False, window_name="test")
>>> window
Expand Down
6 changes: 3 additions & 3 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ Window(@2 2:check this out, Session($1 ...))
And kill:

```python
>>> window.kill_window()
>>> window.kill()
```

Use {meth}`Session.windows` and {meth}`Session.windows.filter()` to list and sort
Expand Down Expand Up @@ -311,14 +311,14 @@ For one, arguments such as `attach=False` can be omittted.

This gives you the {class}`Pane` along with moving the cursor to a new window. You
can also use the `.select_*` available on the object, in this case the pane has
{meth}`Pane.select_pane()`.
{meth}`Pane.select()`.

```python
>>> pane = window.split_window(attach=False)
```

```python
>>> pane.select_pane()
>>> pane.select()
Pane(%1 Window(@1 ...:..., Session($1 ...)))
```

Expand Down
120 changes: 114 additions & 6 deletions src/libtmux/pane.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,20 +353,116 @@ def display_message(
self.cmd("display-message", cmd)
return None

def kill(
self,
all_except: t.Optional[bool] = None,
) -> None:
"""Kill :class:`Pane`.

``$ tmux kill-pane``.

Examples
--------
Kill a pane:
>>> pane_1 = pane.split_window()

>>> pane_1 in window.panes
True

>>> pane_1.kill()

>>> pane_1 not in window.panes
True

Kill all panes except the current one:
>>> pane.window.resize(height=100, width=100)
Window(@1 1...)

>>> one_pane_to_rule_them_all = pane.split_window()

>>> other_panes = pane.split_window(
... ), pane.split_window()

>>> all([p in window.panes for p in other_panes])
True

>>> one_pane_to_rule_them_all.kill(all_except=True)

>>> all([p not in window.panes for p in other_panes])
True

>>> one_pane_to_rule_them_all in window.panes
True
"""
flags: t.Tuple[str, ...] = ()

if all_except:
flags += ("-a",)

proc = self.cmd(
"kill-pane",
*flags,
)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)

return None

"""
Commands ("climber"-helpers)

These are commands that climb to the parent scope's methods with
additional scoped window info.
"""

def select(self) -> "Pane":
"""Select pane.

Examples
--------
>>> pane = window.attached_pane
>>> new_pane = window.split_window()
>>> pane.refresh()
>>> active_panes = [p for p in window.panes if p.pane_active == '1']

>>> pane in active_panes
True
>>> new_pane in active_panes
False

>>> new_pane.pane_active == '1'
False

>>> new_pane.select()
Pane(...)

>>> new_pane.pane_active == '1'
True
"""
proc = self.cmd("select-pane")

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)

self.refresh()

return self

def select_pane(self) -> "Pane":
"""Select pane.

To select a window object asynchrously. If a ``pane`` object exists
and is no longer longer the current window, ``w.select_pane()``
will make ``p`` the current pane.
Notes
-----
.. deprecated:: 0.30

Deprecated in favor of :meth:`.select()`.
"""
warnings.warn(
"Pane.select_pane() is deprecated in favor of Pane.select()",
category=DeprecationWarning,
stacklevel=2,
)
assert isinstance(self.pane_id, str)
pane = self.window.select_pane(self.pane_id)
if pane is None:
Expand All @@ -376,9 +472,12 @@ def select_pane(self) -> "Pane":
def split_window(
self,
attach: bool = False,
vertical: bool = True,
start_directory: t.Optional[str] = None,
percent: t.Optional[int] = None,
vertical: bool = True,
shell: t.Optional[str] = None,
size: t.Optional[t.Union[str, int]] = None,
percent: t.Optional[int] = None, # deprecated
environment: t.Optional[t.Dict[str, str]] = None,
) -> "Pane": # New Pane, not self
"""Split window at pane and return newly created :class:`Pane`.

Expand All @@ -392,13 +491,22 @@ def split_window(
specifies the working directory in which the new pane is created.
percent: int, optional
percentage to occupy with respect to current pane

Notes
-----
.. deprecated:: 0.28.0

``percent=25`` deprecated in favor of ``size="25%"``.
"""
return self.window.split_window(
target=self.pane_id,
start_directory=start_directory,
attach=attach,
start_directory=start_directory,
vertical=vertical,
shell=shell,
size=size,
percent=percent,
environment=environment,
)

"""
Expand Down
47 changes: 45 additions & 2 deletions src/libtmux/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,24 @@ def has_session(self, target_session: str, exact: bool = True) -> bool:

return False

def kill_server(self) -> None:
"""Kill tmux server."""
def kill(self) -> None:
"""Kill tmux server.

>>> svr = Server(socket_name="testing")
>>> svr
Server(socket_name=testing)

>>> svr.new_session()
Session(...)

>>> svr.is_alive()
True

>>> svr.kill()

>>> svr.is_alive()
False
"""
self.cmd("kill-server")

def kill_session(self, target_session: t.Union[str, int]) -> "Server":
Expand Down Expand Up @@ -350,6 +366,7 @@ def new_session(
window_command: t.Optional[str] = None,
x: t.Optional[t.Union[int, "DashLiteral"]] = None,
y: t.Optional[t.Union[int, "DashLiteral"]] = None,
environment: t.Optional[t.Dict[str, str]] = None,
*args: t.Any,
**kwargs: t.Any,
) -> Session:
Expand Down Expand Up @@ -468,6 +485,15 @@ def new_session(
if window_command:
tmux_args += (window_command,)

if environment:
if has_gte_version("3.2"):
for k, v in environment.items():
tmux_args += (f"-e{k}={v}",)
else:
logger.warning(
"Environment flag ignored, tmux 3.2 or newer required.",
)

proc = self.cmd("new-session", *tmux_args)

if proc.stderr:
Expand Down Expand Up @@ -575,6 +601,23 @@ def __repr__(self) -> str:
#
# Legacy: Redundant stuff we want to remove
#
def kill_server(self) -> None:
"""Kill tmux server.

Notes
-----
.. deprecated:: 0.30

Deprecated in favor of :meth:`.kill()`.

"""
warnings.warn(
"Server.kill_server() is deprecated in favor of Server.kill()",
category=DeprecationWarning,
stacklevel=2,
)
self.cmd("kill-server")

def _list_panes(self) -> t.List[PaneDict]:
"""Return list of panes in :py:obj:`dict` form.

Expand Down
Loading