Skip to content

Commit 03fccd5

Browse files
authored
New and improved commands (#525)
- Renamings for `{Server,Session,Window.kill()`, `{Window,Session}.attach_{window,session}`, `{Pane,Window}.attach_{pane,window}` - Add `Pane.kill()`
2 parents 2ea184a + 5fa852c commit 03fccd5

File tree

13 files changed

+533
-39
lines changed

13 files changed

+533
-39
lines changed

CHANGES

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,32 @@ $ pip install --user --upgrade --pre libtmux
1414

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

17+
### New commands
18+
19+
- {meth}`Pane.kill()`
20+
21+
### Renamed commands
22+
23+
- `Window.select_window()` renamed to {meth}`Window.select()`
24+
- Deprecated `Window.select_window()`
25+
- `Pane.select_pane()` renamed to {meth}`Pane.select()`
26+
- Deprecated `Pane.pane_select()`
27+
- `Session.attach_session()` renamed to {meth}`Session.attach()`
28+
- Deprecated `Session.attach_session()`
29+
- `Server.kill_server()` renamed to {meth}`Server.kill()`
30+
- Deprecated `Server.kill_server()`
31+
- `Session.kill_session()` renamed to {meth}`Session.kill()`
32+
- Deprecated `Session.kill_session()`
33+
- `Window.kill_window()` renamed to {meth}`Window.kill()`
34+
- Deprecated `Window.kill_window()`
35+
36+
### Improved commands
37+
38+
- {meth}`Server.new_session()`: Support environment variables
39+
- {meth}`Window.split_window()`: Support `size` via `-l`
40+
41+
Supports columns/rows (`size=10`) and percentage (`size='10%'`)
42+
1743
## libtmux 0.29.0 (2024-02-16)
1844

1945
#### Bug fixes

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ Close window:
117117

118118
```python
119119
>>> w = session.attached_window
120-
>>> w.kill_window()
120+
>>> w.kill()
121121
```
122122

123123
Grab remaining tmux window:
@@ -140,7 +140,7 @@ Split window (create a new pane):
140140
```python
141141
>>> pane = window.split_window()
142142
>>> pane = window.split_window(attach=False)
143-
>>> pane.select_pane()
143+
>>> pane.select()
144144
Pane(%3 Window(@1 1:..., Session($1 ...)))
145145
>>> window = session.new_window(attach=False, window_name="test")
146146
>>> window

docs/quickstart.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ Window(@2 2:check this out, Session($1 ...))
260260
And kill:
261261

262262
```python
263-
>>> window.kill_window()
263+
>>> window.kill()
264264
```
265265

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

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

316316
```python
317317
>>> pane = window.split_window(attach=False)
318318
```
319319

320320
```python
321-
>>> pane.select_pane()
321+
>>> pane.select()
322322
Pane(%1 Window(@1 ...:..., Session($1 ...)))
323323
```
324324

src/libtmux/pane.py

Lines changed: 114 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -353,20 +353,116 @@ def display_message(
353353
self.cmd("display-message", cmd)
354354
return None
355355

356+
def kill(
357+
self,
358+
all_except: t.Optional[bool] = None,
359+
) -> None:
360+
"""Kill :class:`Pane`.
361+
362+
``$ tmux kill-pane``.
363+
364+
Examples
365+
--------
366+
Kill a pane:
367+
>>> pane_1 = pane.split_window()
368+
369+
>>> pane_1 in window.panes
370+
True
371+
372+
>>> pane_1.kill()
373+
374+
>>> pane_1 not in window.panes
375+
True
376+
377+
Kill all panes except the current one:
378+
>>> pane.window.resize(height=100, width=100)
379+
Window(@1 1...)
380+
381+
>>> one_pane_to_rule_them_all = pane.split_window()
382+
383+
>>> other_panes = pane.split_window(
384+
... ), pane.split_window()
385+
386+
>>> all([p in window.panes for p in other_panes])
387+
True
388+
389+
>>> one_pane_to_rule_them_all.kill(all_except=True)
390+
391+
>>> all([p not in window.panes for p in other_panes])
392+
True
393+
394+
>>> one_pane_to_rule_them_all in window.panes
395+
True
396+
"""
397+
flags: t.Tuple[str, ...] = ()
398+
399+
if all_except:
400+
flags += ("-a",)
401+
402+
proc = self.cmd(
403+
"kill-pane",
404+
*flags,
405+
)
406+
407+
if proc.stderr:
408+
raise exc.LibTmuxException(proc.stderr)
409+
410+
return None
411+
356412
"""
357413
Commands ("climber"-helpers)
358414
359415
These are commands that climb to the parent scope's methods with
360416
additional scoped window info.
361417
"""
362418

419+
def select(self) -> "Pane":
420+
"""Select pane.
421+
422+
Examples
423+
--------
424+
>>> pane = window.attached_pane
425+
>>> new_pane = window.split_window()
426+
>>> pane.refresh()
427+
>>> active_panes = [p for p in window.panes if p.pane_active == '1']
428+
429+
>>> pane in active_panes
430+
True
431+
>>> new_pane in active_panes
432+
False
433+
434+
>>> new_pane.pane_active == '1'
435+
False
436+
437+
>>> new_pane.select()
438+
Pane(...)
439+
440+
>>> new_pane.pane_active == '1'
441+
True
442+
"""
443+
proc = self.cmd("select-pane")
444+
445+
if proc.stderr:
446+
raise exc.LibTmuxException(proc.stderr)
447+
448+
self.refresh()
449+
450+
return self
451+
363452
def select_pane(self) -> "Pane":
364453
"""Select pane.
365454
366-
To select a window object asynchrously. If a ``pane`` object exists
367-
and is no longer longer the current window, ``w.select_pane()``
368-
will make ``p`` the current pane.
455+
Notes
456+
-----
457+
.. deprecated:: 0.30
458+
459+
Deprecated in favor of :meth:`.select()`.
369460
"""
461+
warnings.warn(
462+
"Pane.select_pane() is deprecated in favor of Pane.select()",
463+
category=DeprecationWarning,
464+
stacklevel=2,
465+
)
370466
assert isinstance(self.pane_id, str)
371467
pane = self.window.select_pane(self.pane_id)
372468
if pane is None:
@@ -376,9 +472,12 @@ def select_pane(self) -> "Pane":
376472
def split_window(
377473
self,
378474
attach: bool = False,
379-
vertical: bool = True,
380475
start_directory: t.Optional[str] = None,
381-
percent: t.Optional[int] = None,
476+
vertical: bool = True,
477+
shell: t.Optional[str] = None,
478+
size: t.Optional[t.Union[str, int]] = None,
479+
percent: t.Optional[int] = None, # deprecated
480+
environment: t.Optional[t.Dict[str, str]] = None,
382481
) -> "Pane": # New Pane, not self
383482
"""Split window at pane and return newly created :class:`Pane`.
384483
@@ -392,13 +491,22 @@ def split_window(
392491
specifies the working directory in which the new pane is created.
393492
percent: int, optional
394493
percentage to occupy with respect to current pane
494+
495+
Notes
496+
-----
497+
.. deprecated:: 0.28.0
498+
499+
``percent=25`` deprecated in favor of ``size="25%"``.
395500
"""
396501
return self.window.split_window(
397502
target=self.pane_id,
398-
start_directory=start_directory,
399503
attach=attach,
504+
start_directory=start_directory,
400505
vertical=vertical,
506+
shell=shell,
507+
size=size,
401508
percent=percent,
509+
environment=environment,
402510
)
403511

404512
"""

src/libtmux/server.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,24 @@ def has_session(self, target_session: str, exact: bool = True) -> bool:
270270

271271
return False
272272

273-
def kill_server(self) -> None:
274-
"""Kill tmux server."""
273+
def kill(self) -> None:
274+
"""Kill tmux server.
275+
276+
>>> svr = Server(socket_name="testing")
277+
>>> svr
278+
Server(socket_name=testing)
279+
280+
>>> svr.new_session()
281+
Session(...)
282+
283+
>>> svr.is_alive()
284+
True
285+
286+
>>> svr.kill()
287+
288+
>>> svr.is_alive()
289+
False
290+
"""
275291
self.cmd("kill-server")
276292

277293
def kill_session(self, target_session: t.Union[str, int]) -> "Server":
@@ -350,6 +366,7 @@ def new_session(
350366
window_command: t.Optional[str] = None,
351367
x: t.Optional[t.Union[int, "DashLiteral"]] = None,
352368
y: t.Optional[t.Union[int, "DashLiteral"]] = None,
369+
environment: t.Optional[t.Dict[str, str]] = None,
353370
*args: t.Any,
354371
**kwargs: t.Any,
355372
) -> Session:
@@ -468,6 +485,15 @@ def new_session(
468485
if window_command:
469486
tmux_args += (window_command,)
470487

488+
if environment:
489+
if has_gte_version("3.2"):
490+
for k, v in environment.items():
491+
tmux_args += (f"-e{k}={v}",)
492+
else:
493+
logger.warning(
494+
"Environment flag ignored, tmux 3.2 or newer required.",
495+
)
496+
471497
proc = self.cmd("new-session", *tmux_args)
472498

473499
if proc.stderr:
@@ -575,6 +601,23 @@ def __repr__(self) -> str:
575601
#
576602
# Legacy: Redundant stuff we want to remove
577603
#
604+
def kill_server(self) -> None:
605+
"""Kill tmux server.
606+
607+
Notes
608+
-----
609+
.. deprecated:: 0.30
610+
611+
Deprecated in favor of :meth:`.kill()`.
612+
613+
"""
614+
warnings.warn(
615+
"Server.kill_server() is deprecated in favor of Server.kill()",
616+
category=DeprecationWarning,
617+
stacklevel=2,
618+
)
619+
self.cmd("kill-server")
620+
578621
def _list_panes(self) -> t.List[PaneDict]:
579622
"""Return list of panes in :py:obj:`dict` form.
580623

0 commit comments

Comments
 (0)