From 7a4fe8063f5ee38afdb9b94c948cb88284fb283b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 17 Mar 2024 08:28:44 -0500 Subject: [PATCH] refactor!(cmd): Explicit `target` keyword argument --- src/libtmux/pane.py | 27 +++++++++++++++--------- src/libtmux/server.py | 44 ++++++++++++++++++++++---------------- src/libtmux/session.py | 48 ++++++++++++++++++------------------------ src/libtmux/window.py | 30 +++++++++++++++----------- 4 files changed, 82 insertions(+), 67 deletions(-) diff --git a/src/libtmux/pane.py b/src/libtmux/pane.py index 5826bdbc7..34d2cee7f 100644 --- a/src/libtmux/pane.py +++ b/src/libtmux/pane.py @@ -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 -------- @@ -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) @@ -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(): @@ -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: diff --git a/src/libtmux/server.py b/src/libtmux/server.py index ab5dbeac9..d84d03f87 100644 --- a/src/libtmux/server.py +++ b/src/libtmux/server.py @@ -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 @@ -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` @@ -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]: @@ -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 @@ -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) @@ -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) @@ -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) @@ -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( diff --git a/src/libtmux/session.py b/src/libtmux/session.py index ed4a43d3a..045acb0bd 100644 --- a/src/libtmux/session.py +++ b/src/libtmux/session.py @@ -171,27 +171,17 @@ def 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): - # warnings.warn( - # "Use `target=...` instead of passing `-t` as an argument.", - # category=DeprecationWarning, - # stacklevel=2, - # ) - # 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) @@ -368,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) @@ -507,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) @@ -665,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.", @@ -679,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) @@ -708,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) @@ -809,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) @@ -830,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) diff --git a/src/libtmux/window.py b/src/libtmux/window.py index 9795f47d1..dd71fc0ad 100644 --- a/src/libtmux/window.py +++ b/src/libtmux/window.py @@ -141,11 +141,12 @@ def cmd( self, cmd: str, *args: t.Any, + target: t.Optional[t.Union[str, int]] = None, ) -> tmux_cmd: """Execute tmux subcommand within window context. - Automatically adds ``-t`` for object's indow ID to the command. Pass ``-t`` - in args to override. + Automatically binds target by adding ``-t`` for object's window ID to the + command. Pass ``target`` to keyword arguments to override. Examples -------- @@ -160,14 +161,19 @@ def cmd( ... 'split-window', '-P', '-F#{pane_id}').stdout[0], server=session.server) Pane(%... Window(@... ...:..., Session($1 libtmux_...))) + Parameters + ---------- + target : str, optional + Optional custom target override. By default, the target is the window ID. + Returns ------- :meth:`server.cmd` """ - if not any("-t" in str(x) for x in args): - args = ("-t", self.window_id, *args) + if target is None: + target = self.window_id - return self.server.cmd(cmd, *args) + return self.server.cmd(cmd, *args, target=target) """ Commands (tmux-like) @@ -188,9 +194,9 @@ def select_pane(self, target_pane: t.Union[str, int]) -> t.Optional["Pane"]: :class:`Pane` """ if target_pane in ["-l", "-U", "-D", "-L", "-R"]: - proc = self.cmd("select-pane", "-t%s" % self.window_id, target_pane) + proc = self.cmd("select-pane", target_pane, target=self.window_id) else: - proc = self.cmd("select-pane", "-t%s" % target_pane) + proc = self.cmd("select-pane", target=target_pane) if proc.stderr: raise exc.LibTmuxException(proc.stderr) @@ -367,12 +373,12 @@ def select_layout(self, layout: t.Optional[str] = None) -> "Window": 'custom' custom dimensions (see :term:`tmux(1)` manpages). """ - cmd = ["select-layout", f"-t{self.session_id}:{self.window_index}"] + cmd = ["select-layout"] if layout: # tmux allows select-layout without args cmd.append(layout) - proc = self.cmd(*cmd) + proc = self.cmd(*cmd, target=f"{self.session_id}:{self.window_index}") if proc.stderr: raise exc.LibTmuxException(proc.stderr) @@ -404,9 +410,9 @@ def set_window_option(self, option: str, value: t.Union[int, str]) -> "Window": cmd = self.cmd( "set-window-option", - f"-t{self.session_id}:{self.window_index}", option, value, + target=f"{self.session_id}:{self.window_index}", ) if isinstance(cmd.stderr, list) and len(cmd.stderr): @@ -608,7 +614,7 @@ def move_window( proc = self.cmd( "move-window", f"-s{self.session_id}:{self.window_index}", - f"-t{session}:{destination}", + target=f"{session}:{destination}", ) if proc.stderr: @@ -916,7 +922,7 @@ def kill_window(self) -> None: ) proc = self.cmd( "kill-window", - f"-t{self.session_id}:{self.window_index}", + target=f"{self.session_id}:{self.window_index}", ) if proc.stderr: