aboutsummaryrefslogtreecommitdiff
path: root/duet.el
diff options
context:
space:
mode:
Diffstat (limited to 'duet.el')
-rw-r--r--duet.el22
1 files changed, 19 insertions, 3 deletions
diff --git a/duet.el b/duet.el
index e8ae8c4..28d45f2 100644
--- a/duet.el
+++ b/duet.el
@@ -268,15 +268,30 @@ normalizer."
(unless (or (null score) (numberp score))
"handles must return a number or nil"))))
+(defun duet--command-spec-executable-p (spec)
+ "Return non-nil when process SPEC has a recognized, runnable execution shape.
+A SPEC is runnable when it is a non-empty plist carrying either a non-empty
+:argv whose elements are all strings (a CLI backend) or an explicit
+in-process mode such as :tramp (a backend that copies in process). A nil
+spec, a bare nil argv, or a shell string is not runnable."
+ (and (listp spec) spec
+ (not (plist-get spec :shell-command))
+ (or (plist-get spec :tramp)
+ (let ((argv (plist-get spec :argv)))
+ (and (consp argv) (cl-every #'stringp argv))))))
+
(defun duet--check-command (backend src dst opts)
"Return a minimum-tier command violation for BACKEND on SRC/DST/OPTS, or nil."
(if (not (functionp (duet-backend-command backend)))
"command must be a function"
(let ((spec (funcall (duet-backend-command backend) src dst opts)))
(cond
- ((not (listp spec)) "command must return a process-spec plist")
- ((plist-get spec :shell-command) "command must not build a shell string; use :argv")
- ((not (listp (plist-get spec :argv))) "command :argv must be an argument list")))))
+ ((not (and (listp spec) spec))
+ "command must return a non-empty process-spec plist")
+ ((plist-get spec :shell-command)
+ "command must not build a shell string; use :argv")
+ ((not (duet--command-spec-executable-p spec))
+ "command must return a runnable spec: a non-empty :argv of strings, or a declared in-process mode such as :tramp")))))
(defun duet--check-redaction (backend)
"Return a minimum-tier redaction violation for BACKEND, or nil.
@@ -494,6 +509,7 @@ backend's command builder. Return nil when no backend handles the pair."
:backend (duet-backend-name backend)
:route (duet--transfer-route src dst opts)
:argv (plist-get cmd :argv)
+ :tramp (plist-get cmd :tramp)
:default-directory (plist-get cmd :default-directory)
:process-environment (plist-get cmd :process-environment)
:async (if (plist-member opts :async) (plist-get opts :async) t))))))