Skip to content

cmd(): Explicit custom targets #535

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 2 commits into from
Mar 17, 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
13 changes: 13 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ $ pip install --user --upgrade --pre libtmux

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

### Breaking changes

#### Command target change (#919)

Commands: All `cmd()` methods using custom or overridden targets must use the keyword argument
`target`. This avoids entanglement with inner shell values that include `-t` for
other purposes. These methods include:

- {meth}`Server.cmd()`
- {meth}`Session.cmd()`
- {meth}`Window.cmd()`
- {meth}`Pane.cmd()`

## libtmux 0.33.0 (2024-03-17)

### Breaking changes
Expand Down
27 changes: 17 additions & 10 deletions src/libtmux/pane.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,16 @@ def session(self) -> "Session":
Commands (pane-scoped)
"""

def cmd(self, cmd: str, *args: t.Any) -> tmux_cmd:
def cmd(
self,
cmd: str,
*args: t.Any,
target: t.Optional[t.Union[str, int]] = None,
) -> tmux_cmd:
"""Execute tmux subcommand within pane context.

Automatically adds ``-t`` for object's pane ID to the command. Pass ``-t``
in args to override.
Automatically binds target by adding ``-t`` for object's pane ID to the
command. Pass ``target`` to keyword arguments to override.

Examples
--------
Expand All @@ -134,14 +139,19 @@ def cmd(self, cmd: str, *args: t.Any) -> tmux_cmd:
... 'split-window', '-P', '-F#{pane_id}').stdout[0], server=pane.server)
Pane(%... Window(@... ...:..., Session($1 libtmux_...)))

Parameters
----------
target : str, optional
Optional custom target override. By default, the target is the pane ID.

Returns
-------
:meth:`server.cmd`
"""
if not any("-t" in str(x) for x in args):
args = ("-t", self.pane_id, *args)
if target is None:
target = self.pane_id

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

"""
Commands (tmux-like)
Expand Down Expand Up @@ -620,9 +630,6 @@ def split(
if not attach:
tmux_args += ("-d",)

if target is not None:
tmux_args += (f"-t{target}",)

if environment:
if has_gte_version("3.0"):
for k, v in environment.items():
Expand All @@ -635,7 +642,7 @@ def split(
if shell:
tmux_args += (shell,)

pane_cmd = self.cmd("split-window", *tmux_args)
pane_cmd = self.cmd("split-window", *tmux_args, target=target)

# tmux < 1.7. This is added in 1.7.
if pane_cmd.stderr:
Expand Down
44 changes: 26 additions & 18 deletions src/libtmux/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,12 @@ def raise_if_dead(self) -> None:
#
# Command
#
def cmd(self, cmd: str, *args: t.Any) -> tmux_cmd:
def cmd(
self,
cmd: str,
*args: t.Any,
target: t.Optional[t.Union[str, int]] = None,
) -> tmux_cmd:
"""Execute tmux command respective of socket name and file, return output.

Examples
Expand Down Expand Up @@ -207,6 +212,11 @@ def cmd(self, cmd: str, *args: t.Any) -> tmux_cmd:
... 'split-window', '-P', '-F#{pane_id}').stdout[0], server=window.server)
Pane(%... Window(@... ...:..., Session($1 libtmux_...)))

Parameters
----------
target : str, optional
Optional custom target.

Returns
-------
:class:`common.tmux_cmd`
Expand All @@ -217,22 +227,25 @@ def cmd(self, cmd: str, *args: t.Any) -> tmux_cmd:

Renamed from ``.tmux`` to ``.cmd``.
"""
cmd_args: t.List[t.Union[str, int]] = [cmd, *args]
svr_args: t.List[t.Union[str, int]] = [cmd]
cmd_args: t.List[t.Union[str, int]] = []
if self.socket_name:
cmd_args.insert(0, f"-L{self.socket_name}")
svr_args.insert(0, f"-L{self.socket_name}")
if self.socket_path:
cmd_args.insert(0, f"-S{self.socket_path}")
svr_args.insert(0, f"-S{self.socket_path}")
if self.config_file:
cmd_args.insert(0, f"-f{self.config_file}")
svr_args.insert(0, f"-f{self.config_file}")
if self.colors:
if self.colors == 256:
cmd_args.insert(0, "-2")
svr_args.insert(0, "-2")
elif self.colors == 88:
cmd_args.insert(0, "-8")
svr_args.insert(0, "-8")
else:
raise exc.UnknownColorOption()

return tmux_cmd(*cmd_args)
cmd_args = ["-t", str(target), *args] if target is not None else [*args]

return tmux_cmd(*svr_args, *cmd_args)

@property
def attached_sessions(self) -> t.List[Session]:
Expand Down Expand Up @@ -274,7 +287,7 @@ def has_session(self, target_session: str, exact: bool = True) -> bool:
if exact and has_gte_version("2.1"):
target_session = f"={target_session}"

proc = self.cmd("has-session", "-t%s" % target_session)
proc = self.cmd("has-session", target=target_session)

if not proc.returncode:
return True
Expand Down Expand Up @@ -318,7 +331,7 @@ def kill_session(self, target_session: t.Union[str, int]) -> "Server":
------
:exc:`exc.BadSessionName`
"""
proc = self.cmd("kill-session", "-t%s" % target_session)
proc = self.cmd("kill-session", target=target_session)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)
Expand All @@ -339,7 +352,7 @@ def switch_client(self, target_session: str) -> None:
"""
session_check_name(target_session)

proc = self.cmd("switch-client", "-t%s" % target_session)
proc = self.cmd("switch-client", target=target_session)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)
Expand All @@ -357,12 +370,7 @@ def attach_session(self, target_session: t.Optional[str] = None) -> None:
:exc:`exc.BadSessionName`
"""
session_check_name(target_session)

tmux_args: t.Tuple[str, ...] = ()
if target_session:
tmux_args += ("-t%s" % target_session,)

proc = self.cmd("attach-session", *tmux_args)
proc = self.cmd("attach-session", target=target_session)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)
Expand Down Expand Up @@ -456,7 +464,7 @@ def new_session(

if self.has_session(session_name):
if kill_session:
self.cmd("kill-session", "-t%s" % session_name)
self.cmd("kill-session", target=session_name)
logger.info("session %s exists. killed it." % session_name)
else:
raise exc.TmuxSessionExists(
Expand Down
56 changes: 31 additions & 25 deletions src/libtmux/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,13 @@ def panes(self) -> QueryList["Pane"]:
#
# Command
#
def cmd(self, cmd: str, *args: t.Any) -> tmux_cmd:
def cmd(
self, cmd: str, *args: t.Any, target: t.Optional[t.Union[str, int]] = None
) -> tmux_cmd:
"""Execute tmux subcommand within session context.

Automatically adds ``-t`` for object's session ID to the command. Pass ``-t``
in args to override.
Automatically binds target by adding ``-t`` for object's session ID to the
command. Pass ``target`` to keyword arguments to override.

Examples
--------
Expand All @@ -158,28 +160,28 @@ def cmd(self, cmd: str, *args: t.Any) -> tmux_cmd:
... 'new-window', '-P', '-F#{window_id}').stdout[0], server=session.server)
Window(@... ...:..., Session($1 libtmux_...))

Parameters
----------
target : str, optional
Optional custom target override. By default, the target is the session ID.

Returns
-------
:meth:`server.cmd`

Notes
-----
.. versionchanged:: 0.34

Passing target by ``-t`` is ignored. Use ``target`` keyword argument instead.

.. versionchanged:: 0.8

Renamed from ``.tmux`` to ``.cmd``.
"""
# if -t is not set in any arg yet
if not any("-t" in str(x) for x in args):
# insert -t immediately after 1st arg, as per tmux format
new_args: t.Tuple[str, ...] = ()
assert isinstance(self.session_id, str)
new_args += (
"-t",
self.session_id,
)
new_args += args
args = new_args
return self.server.cmd(cmd, *args)
if target is None:
target = self.session_id
return self.server.cmd(cmd, *args, target=target)

"""
Commands (tmux-like)
Expand Down Expand Up @@ -356,9 +358,9 @@ def select_window(self, target_window: t.Union[str, int]) -> "Window":
# Note that we also provide the session ID here, since cmd()
# will not automatically add it as there is already a '-t'
# argument provided.
target = f"-t{self.session_id}:{target_window}"
target = f"{self.session_id}:{target_window}"

proc = self.cmd("select-window", target)
proc = self.cmd("select-window", target=target)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)
Expand Down Expand Up @@ -495,7 +497,7 @@ def switch_client(self) -> "Session":
------
:exc:`exc.LibTmuxException`
"""
proc = self.cmd("switch-client", "-t%s" % self.session_id)
proc = self.cmd("switch-client", target=self.session_id)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)
Expand Down Expand Up @@ -653,9 +655,13 @@ def new_window(
"Direction flag ignored, requires tmux 3.1 or newer.",
)

target: t.Optional[str] = None
if window_index is not None:
# empty string for window_index will use the first one available
target = f"{self.session_id}:{window_index}"
if target_window:
if has_gte_version("3.2"):
window_args += (f"-t{target_window}",)
target = target_window
else:
logger.warning(
"Window target ignored, requires tmux 3.1 or newer.",
Expand All @@ -667,7 +673,7 @@ def new_window(
if window_shell:
window_args += (window_shell,)

cmd = self.cmd("new-window", *window_args)
cmd = self.cmd("new-window", *window_args, target=target)

if cmd.stderr:
raise exc.LibTmuxException(cmd.stderr)
Expand Down Expand Up @@ -696,11 +702,11 @@ def kill_window(self, target_window: t.Optional[str] = None) -> None:
"""
if target_window:
if isinstance(target_window, int):
target = "-t%s:%d" % (self.window_name, target_window)
target = "%s:%d" % (self.window_name, target_window)
else:
target = "-t%s" % target_window
target = "%s" % target_window

proc = self.cmd("kill-window", target)
proc = self.cmd("kill-window", target=target)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)
Expand Down Expand Up @@ -797,7 +803,7 @@ def attach_session(self) -> "Session":
category=DeprecationWarning,
stacklevel=2,
)
proc = self.cmd("attach-session", "-t%s" % self.session_id)
proc = self.cmd("attach-session", target=self.session_id)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)
Expand All @@ -818,7 +824,7 @@ def kill_session(self) -> None:
category=DeprecationWarning,
stacklevel=2,
)
proc = self.cmd("kill-session", "-t%s" % self.session_id)
proc = self.cmd("kill-session", target=self.session_id)

if proc.stderr:
raise exc.LibTmuxException(proc.stderr)
Expand Down
Loading