Skip to content

Commit 1d31a1f

Browse files
committed
Server,Session,Window,Pane: Add .acmd
1 parent 6755431 commit 1d31a1f

File tree

4 files changed

+249
-5
lines changed

4 files changed

+249
-5
lines changed

src/libtmux/pane.py

+48-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import warnings
1313
from typing import overload
1414

15-
from libtmux.common import has_gte_version, has_lt_version, tmux_cmd
15+
from libtmux.common import AsyncTmuxCmd, has_gte_version, has_lt_version, tmux_cmd
1616
from libtmux.constants import (
1717
PANE_DIRECTION_FLAG_MAP,
1818
RESIZE_ADJUSTMENT_DIRECTION_FLAG_MAP,
@@ -153,6 +153,53 @@ def cmd(
153153

154154
return self.server.cmd(cmd, *args, target=target)
155155

156+
async def acmd(
157+
self,
158+
cmd: str,
159+
*args: t.Any,
160+
target: t.Optional[t.Union[str, int]] = None,
161+
) -> AsyncTmuxCmd:
162+
"""Execute tmux subcommand within pane context.
163+
164+
Automatically binds target by adding ``-t`` for object's pane ID to the
165+
command. Pass ``target`` to keyword arguments to override.
166+
167+
Examples
168+
--------
169+
>>> import asyncio
170+
>>> async def test_acmd():
171+
... result = await pane.acmd('split-window', '-P')
172+
... print(result.stdout[0])
173+
>>> asyncio.run(test_acmd())
174+
libtmux...:...
175+
176+
From raw output to an enriched `Pane` object:
177+
178+
>>> async def test_from_pane():
179+
... pane_id_result = await pane.acmd(
180+
... 'split-window', '-P', '-F#{pane_id}'
181+
... )
182+
... return Pane.from_pane_id(
183+
... pane_id=pane_id_result.stdout[0],
184+
... server=session.server
185+
... )
186+
>>> asyncio.run(test_from_pane())
187+
Pane(%... Window(@... ...:..., Session($1 libtmux_...)))
188+
189+
Parameters
190+
----------
191+
target : str, optional
192+
Optional custom target override. By default, the target is the pane ID.
193+
194+
Returns
195+
-------
196+
:meth:`server.cmd`
197+
"""
198+
if target is None:
199+
target = self.pane_id
200+
201+
return await self.server.acmd(cmd, *args, target=target)
202+
156203
"""
157204
Commands (tmux-like)
158205
"""

src/libtmux/server.py

+94-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from . import exc, formats
2424
from .common import (
25+
AsyncTmuxCmd,
2526
EnvironmentMixin,
2627
PaneDict,
2728
SessionDict,
@@ -197,8 +198,12 @@ def cmd(
197198
198199
Output of `tmux -L ... new-window -P -F#{window_id}` to a `Window` object:
199200
200-
>>> Window.from_window_id(window_id=session.cmd(
201-
... 'new-window', '-P', '-F#{window_id}').stdout[0], server=session.server)
201+
>>> Window.from_window_id(
202+
... window_id=session.cmd(
203+
... 'new-window', '-P', '-F#{window_id}'
204+
... ).stdout[0],
205+
... server=session.server,
206+
... )
202207
Window(@4 3:..., Session($1 libtmux_...))
203208
204209
Create a pane from a window:
@@ -209,7 +214,9 @@ def cmd(
209214
Output of `tmux -L ... split-window -P -F#{pane_id}` to a `Pane` object:
210215
211216
>>> Pane.from_pane_id(pane_id=window.cmd(
212-
... 'split-window', '-P', '-F#{pane_id}').stdout[0], server=window.server)
217+
... 'split-window', '-P', '-F#{pane_id}').stdout[0],
218+
... server=window.server
219+
... )
213220
Pane(%... Window(@... ...:..., Session($1 libtmux_...)))
214221
215222
Parameters
@@ -247,6 +254,90 @@ def cmd(
247254

248255
return tmux_cmd(*svr_args, *cmd_args)
249256

257+
async def acmd(
258+
self,
259+
cmd: str,
260+
*args: t.Any,
261+
target: t.Optional[t.Union[str, int]] = None,
262+
) -> AsyncTmuxCmd:
263+
"""Execute tmux command respective of socket name and file, return output.
264+
265+
Examples
266+
--------
267+
>>> import asyncio
268+
>>> async def test_acmd():
269+
... result = await server.acmd('display-message', 'hi')
270+
... print(result.stdout)
271+
>>> asyncio.run(test_acmd())
272+
[]
273+
274+
New session:
275+
276+
>>> async def test_new_session():
277+
... result = await server.acmd(
278+
... 'new-session', '-d', '-P', '-F#{session_id}'
279+
... )
280+
... print(result.stdout[0])
281+
>>> asyncio.run(test_new_session())
282+
$...
283+
284+
Output of `tmux -L ... new-window -P -F#{window_id}` to a `Window` object:
285+
286+
>>> async def test_new_window():
287+
... result = await session.acmd('new-window', '-P', '-F#{window_id}')
288+
... window_id = result.stdout[0]
289+
... window = Window.from_window_id(window_id=window_id, server=server)
290+
... print(window)
291+
>>> asyncio.run(test_new_window())
292+
Window(@... ...:..., Session($... libtmux_...))
293+
294+
Create a pane from a window:
295+
296+
>>> async def test_split_window():
297+
... result = await server.acmd('split-window', '-P', '-F#{pane_id}')
298+
... print(result.stdout[0])
299+
>>> asyncio.run(test_split_window())
300+
%...
301+
302+
Output of `tmux -L ... split-window -P -F#{pane_id}` to a `Pane` object:
303+
304+
>>> async def test_pane():
305+
... result = await window.acmd('split-window', '-P', '-F#{pane_id}')
306+
... pane_id = result.stdout[0]
307+
... pane = Pane.from_pane_id(pane_id=pane_id, server=server)
308+
... print(pane)
309+
>>> asyncio.run(test_pane())
310+
Pane(%... Window(@... ...:..., Session($1 libtmux_...)))
311+
312+
Parameters
313+
----------
314+
target : str, optional
315+
Optional custom target.
316+
317+
Returns
318+
-------
319+
:class:`common.AsyncTmuxCmd`
320+
"""
321+
svr_args: list[t.Union[str, int]] = [cmd]
322+
cmd_args: list[t.Union[str, int]] = []
323+
if self.socket_name:
324+
svr_args.insert(0, f"-L{self.socket_name}")
325+
if self.socket_path:
326+
svr_args.insert(0, f"-S{self.socket_path}")
327+
if self.config_file:
328+
svr_args.insert(0, f"-f{self.config_file}")
329+
if self.colors:
330+
if self.colors == 256:
331+
svr_args.insert(0, "-2")
332+
elif self.colors == 88:
333+
svr_args.insert(0, "-8")
334+
else:
335+
raise exc.UnknownColorOption
336+
337+
cmd_args = ["-t", str(target), *args] if target is not None else [*args]
338+
339+
return await AsyncTmuxCmd.run(*svr_args, *cmd_args)
340+
250341
@property
251342
def attached_sessions(self) -> list[Session]:
252343
"""Return active :class:`Session`s.

src/libtmux/session.py

+57
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from . import exc
2323
from .common import (
24+
AsyncTmuxCmd,
2425
EnvironmentMixin,
2526
WindowDict,
2627
handle_option_error,
@@ -186,6 +187,62 @@ def cmd(
186187
target = self.session_id
187188
return self.server.cmd(cmd, *args, target=target)
188189

190+
async def acmd(
191+
self,
192+
cmd: str,
193+
*args: t.Any,
194+
target: t.Optional[t.Union[str, int]] = None,
195+
) -> AsyncTmuxCmd:
196+
"""Execute tmux subcommand within session context.
197+
198+
Automatically binds target by adding ``-t`` for object's session ID to the
199+
command. Pass ``target`` to keyword arguments to override.
200+
201+
Examples
202+
--------
203+
>>> import asyncio
204+
>>> async def test_acmd():
205+
... result = await session.acmd('new-window', '-P')
206+
... print(result.stdout[0])
207+
>>> asyncio.run(test_acmd())
208+
libtmux...:....0
209+
210+
From raw output to an enriched `Window` object:
211+
212+
>>> async def test_from_window():
213+
... window_id_result = await session.acmd(
214+
... 'new-window', '-P', '-F#{window_id}'
215+
... )
216+
... return Window.from_window_id(
217+
... window_id=window_id_result.stdout[0],
218+
... server=session.server
219+
... )
220+
>>> asyncio.run(test_from_window())
221+
Window(@... ...:..., Session($1 libtmux_...))
222+
223+
Parameters
224+
----------
225+
target : str, optional
226+
Optional custom target override. By default, the target is the session ID.
227+
228+
Returns
229+
-------
230+
:meth:`server.cmd`
231+
232+
Notes
233+
-----
234+
.. versionchanged:: 0.34
235+
236+
Passing target by ``-t`` is ignored. Use ``target`` keyword argument instead.
237+
238+
.. versionchanged:: 0.8
239+
240+
Renamed from ``.tmux`` to ``.cmd``.
241+
"""
242+
if target is None:
243+
target = self.session_id
244+
return await self.server.acmd(cmd, *args, target=target)
245+
189246
"""
190247
Commands (tmux-like)
191248
"""

src/libtmux/window.py

+50-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from libtmux.pane import Pane
2424

2525
from . import exc
26-
from .common import PaneDict, WindowOptionDict, handle_option_error
26+
from .common import AsyncTmuxCmd, PaneDict, WindowOptionDict, handle_option_error
2727

2828
if t.TYPE_CHECKING:
2929
from .server import Server
@@ -175,6 +175,55 @@ def cmd(
175175

176176
return self.server.cmd(cmd, *args, target=target)
177177

178+
async def acmd(
179+
self,
180+
cmd: str,
181+
*args: t.Any,
182+
target: t.Optional[t.Union[str, int]] = None,
183+
) -> AsyncTmuxCmd:
184+
"""Execute tmux subcommand within window context.
185+
186+
Automatically binds target by adding ``-t`` for object's window ID to the
187+
command. Pass ``target`` to keyword arguments to override.
188+
189+
Examples
190+
--------
191+
Create a pane from a window:
192+
193+
>>> import asyncio
194+
>>> async def test_acmd():
195+
... result = await window.acmd('split-window', '-P', '-F#{pane_id}')
196+
... print(result.stdout[0])
197+
>>> asyncio.run(test_acmd())
198+
%...
199+
200+
Magic, directly to a `Pane`:
201+
202+
>>> async def test_from_pane():
203+
... pane_id_result = await session.acmd(
204+
... 'split-window', '-P', '-F#{pane_id}'
205+
... )
206+
... return Pane.from_pane_id(
207+
... pane_id=pane_id_result.stdout[0],
208+
... server=session.server
209+
... )
210+
>>> asyncio.run(test_from_pane())
211+
Pane(%... Window(@... ...:..., Session($1 libtmux_...)))
212+
213+
Parameters
214+
----------
215+
target : str, optional
216+
Optional custom target override. By default, the target is the window ID.
217+
218+
Returns
219+
-------
220+
:meth:`server.cmd`
221+
"""
222+
if target is None:
223+
target = self.window_id
224+
225+
return await self.server.acmd(cmd, *args, target=target)
226+
178227
"""
179228
Commands (tmux-like)
180229
"""

0 commit comments

Comments
 (0)