aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vterm.el62
1 files changed, 60 insertions, 2 deletions
diff --git a/vterm.el b/vterm.el
index 8f71e77..3d0e8c4 100644
--- a/vterm.el
+++ b/vterm.el
@@ -176,7 +176,18 @@ the executable."
"The shell that gets run in the vterm for tramp.
`vterm-tramp-shells' has to be a list of pairs of the format:
-\(TRAMP-METHOD SHELL)"
+\(TRAMP-METHOD SHELL)
+
+Set SHELL to \\='login-shell to use the user's login shell on the host.
+The login-shell detection currently works for POSIX-compliant remote
+hosts that have the getent command (regular GNU/Linux distros, *BSDs,
+but not MacOS X unfortunately).
+
+You can specify an additional second SHELL command as a fallback
+that is used when the login-shell detection fails, e.g.,
+\\='((\"ssh\" login-shell \"/bin/bash\") ...)
+If no second SHELL command is specified with \\='login-shell, vterm will
+fall back to tramp's shell."
:type '(alist :key-type string :value-type string)
:group 'vterm)
@@ -826,11 +837,58 @@ Exceptions are defined by `vterm-keymap-exceptions'."
(setq next-error-function 'vterm-next-error-function)
(setq-local bookmark-make-record-function 'vterm--bookmark-make-record))
+(defun vterm--tramp-get-shell (method)
+ "Get the shell for a remote location as specified in `vterm-tramp-shells'.
+The argument METHOD is the method string (as used by tramp) to get the shell
+for, or t to get the default shell for all methods."
+ (let* ((specs (cdr (assoc method vterm-tramp-shells)))
+ (first (car specs))
+ (second (cadr specs)))
+ ;; Allow '(... login-shell) or '(... 'login-shell).
+ (if (or (eq first 'login-shell)
+ (and (consp first) (eq (cadr first) 'login-shell)))
+ ;; If the first element is 'login-shell, try to determine the user's
+ ;; login shell on the remote host. This should work for all
+ ;; POSIX-compliant systems with the getent command in PATH. This
+ ;; includes regular GNU/Linux distros, *BSDs, but not MacOS X. If
+ ;; the login-shell determination fails at any point, the second
+ ;; element in the shell spec is used (if present, otherwise nil is
+ ;; returned).
+ (let* ((entry (ignore-errors
+ (with-output-to-string
+ (with-current-buffer standard-output
+ ;; The getent command returns the passwd entry
+ ;; for the specified user independently of the
+ ;; used name service (i.e., not only for static
+ ;; passwd files, but also for LDAP, etc).
+ ;;
+ ;; Use a shell command here to get $LOGNAME.
+ ;; Using the tramp user does not always work as
+ ;; it can be nil, e.g., with ssh host configs.
+ ;; $LOGNAME is defined in all POSIX-compliant
+ ;; systems.
+ (unless (= 0 (process-file-shell-command
+ "getent passwd $LOGNAME"
+ nil (current-buffer) nil))
+ (error "Unexpected return value"))
+ ;; If we have more than one line, the output is
+ ;; not the expected single passwd entry.
+ ;; Most likely, $LOGNAME is not set.
+ (when (> (count-lines (point-min) (point-max)) 1)
+ (error "Unexpected output"))))))
+ (shell (when entry
+ ;; The returned Unix passwd entry is a colon-
+ ;; separated line. The 6th (last) element specifies
+ ;; the user's shell.
+ (nth 6 (split-string entry ":" nil "[ \t\n\r]+")))))
+ (or shell second))
+ first)))
+
(defun vterm--get-shell ()
"Get the shell that gets run in the vterm."
(if (ignore-errors (file-remote-p default-directory))
(with-parsed-tramp-file-name default-directory nil
- (or (cadr (assoc method vterm-tramp-shells))
+ (or (vterm--tramp-get-shell method)
(with-connection-local-variables shell-file-name)
vterm-shell))
vterm-shell))