Subject: bug#79173: 30.1; TRAMP simplified syntax produces empty completing-read candidates

From: Michael Albinus <[email-masked]>
Date: Wed, 06 Aug 2025 09:30:46 +0200

Reuben Thomas <[email-masked]> writes:

Hi Reuben,

> I installed this patch by first installing tramp 2.8.0.1 in Emacs 30.1
> from ELPA, then applying the patch, then starting Emacs and
> recompiling tramp.sh and tramp-sh.el, then restarting Emacs.
>
> This did not quite have the expected effect.
>
> The error from vertico was gone, but when I type a single slash at the
> find-file prompt, I now get prompted to log in to an SSH host. This
> sounds as though two lists have gotten out of sync: one with the empty
> entry, and one without. Do let me know if I can do further
> investigation.

Same here with vertico. This now seems a vertico error. The backtrace is
as follows:

--8<---------------cut here---------------start------------->8---
  backtrace()
  tramp-error((tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) file-error #("Tramp failed to connect.  If this happens repeatedly, try\n    ‘M-x tramp-cleanup-this-connection’" 63 96 (font-lock-face help-key-binding face help-key-binding)))
  apply(tramp-error (tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) file-error #("Tramp failed to connect.  If this happens repeatedly, try\n    ‘M-x tramp-cleanup-this-connection’" 63 96 (font-lock-face help-key-binding face help-key-binding)) nil)
  tramp-process-actions(#<process *tramp/scp infempbln01.int.infinit-services.com*> (tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) 1 ((tramp-login-prompt-regexp tramp-action-login) (tramp-password-prompt-regexp tramp-action-password) (tramp-otp-password-prompt-regexp tramp-action-otp-password) (tramp-fingerprint-prompt-regexp tramp-action-fingerprint) (tramp-wrong-passwd-regexp tramp-action-permission-denied) (shell-prompt-pattern tramp-action-succeed) (tramp-shell-prompt-pattern tramp-action-succeed) (tramp-yesno-prompt-regexp tramp-action-yesno) (tramp-yn-prompt-regexp tramp-action-yn) (tramp-terminal-prompt-regexp tramp-action-terminal) (tramp-antispoof-regexp tramp-action-confirm-message) (tramp-security-key-confirm-regexp tramp-action-show-and-confirm-message) (tramp-security-key-pin-regexp tramp-action-otp-password) (tramp-process-alive-regexp tramp-action-process-alive)) 60)
  tramp-maybe-open-connection((tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil))
  tramp-send-command((tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) "echo ~ 2>/dev/null; echo tramp_exit_status $?")
  tramp-send-command-and-check((tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) "echo ~")
  tramp-sh-handle-get-home-directory((tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) "")
  tramp-sh-file-name-handler(tramp-get-home-directory (tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) "")
  apply(tramp-sh-file-name-handler tramp-get-home-directory ((tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) ""))
  tramp-file-name-handler(tramp-get-home-directory (tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) "")
  tramp-get-home-directory((tramp-file-name #("scp" 0 3 (tramp-default t)) nil nil "infempbln01.int.infinit-services.com" nil "" nil) "")
  tramp-sh-handle-expand-file-name("/infempbln01.int.infinit-services.com:" nil)
  tramp-sh-file-name-handler(expand-file-name "/infempbln01.int.infinit-services.com:" nil)
  apply(tramp-sh-file-name-handler expand-file-name ("/infempbln01.int.infinit-services.com:" nil))
  tramp-file-name-handler(expand-file-name "/infempbln01.int.infinit-services.com:" nil)
  file-name-all-completions("" "/infempbln01.int.infinit-services.com:")
  completion-file-name-table("/infempbln01.int.infinit-services.com:" file-exists-p t)
  completion-pcm--all-completions("/infempbln01.int.infinit-services.com:" nil completion-file-name-table file-exists-p)
  completion-pcm--find-all-completions("/i-:" completion-file-name-table file-exists-p 4)
  completion-pcm-all-completions("/i-:" completion-file-name-table file-exists-p 4)
  #f(compiled-function (style) #<bytecode -0x851335bf00f499a>)(partial-completion)
  #f(compiled-function (elt) #<bytecode 0x114e79b73560d32b>)(partial-completion)
  mapc(#f(compiled-function (elt) #<bytecode 0x114e79b73560d32b>) (basic partial-completion emacs22))
  seq-do(#f(compiled-function (elt) #<bytecode 0x114e79b73560d32b>) (basic partial-completion emacs22))
  seq-some(#f(compiled-function (style) #<bytecode -0x851335bf00f499a>) (basic partial-completion emacs22))
  completion--nth-completion(2 "~/src/emacs-30//i-:" read-file-name-internal file-exists-p 19 (metadata (category . file) (completion--unquote-requote . t)))
  completion-all-completions("~/src/emacs-30//i-:" read-file-name-internal file-exists-p 19 (metadata (category . file) (completion--unquote-requote . t)))
  vertico--filter-completions("~/src/emacs-30//i-:" read-file-name-internal file-exists-p 19 (metadata (category . file) (completion--unquote-requote . t)))
  vertico--recompute(19 "~/src/emacs-30//i-:")
  vertico--update(interruptible)
  #<subr F616e6f6e796d6f75732d6c616d626461_anonymous_lambda_13>()
  #f(compiled-function () #<bytecode 0x18c0b2df11f5>)()
  handler-bind-1(#f(compiled-function () #<bytecode 0x18c0b2df11f5>) (error) vertico--debug)
  vertico--protect(#<subr F616e6f6e796d6f75732d6c616d626461_anonymous_lambda_13>)
  vertico--exhibit()
  #<subr completing-read-default>("Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/src/emacs-30/" file-name-history "~/src/emacs-30/" nil)
  apply((#<subr completing-read-default> "Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/src/emacs-30/" file-name-history "~/src/emacs-30/" nil))
  vertico--advice(#<subr completing-read-default> "Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/src/emacs-30/" file-name-history "~/src/emacs-30/" nil)
  apply(vertico--advice #<subr completing-read-default> ("Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/src/emacs-30/" file-name-history "~/src/emacs-30/" nil))
  completing-read-default("Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/src/emacs-30/" file-name-history "~/src/emacs-30/" nil)
  read-file-name-default("Find file: " nil "~/src/emacs-30/" confirm-after-completion nil nil)
  read-file-name("Find file: " nil "~/src/emacs-30/" confirm-after-completion)
  find-file-read-args("Find file: " confirm-after-completion)
  byte-code("\300\301\302 \"\207" [find-file-read-args "Find file: " confirm-nonexistent-file-or-buffer] 3)
  command-execute(find-file)
--8<---------------cut here---------------end--------------->8---

As we see, there is

--8<---------------cut here---------------start------------->8---
  completion-pcm--all-completions("/infempbln01.int.infinit-services.com:" nil completion-file-name-table file-exists-p)
  completion-pcm--find-all-completions("/i-:" completion-file-name-table file-exists-p 4)
  completion-pcm-all-completions("/i-:" completion-file-name-table file-exists-p 4)
...
  vertico--filter-completions("~/src/emacs-30//i-:" read-file-name-internal file-exists-p 19 (metadata (category . file) (completion--unquote-requote . t)))
--8<---------------cut here---------------end--------------->8---

This is OK, "infempbln01.int.infinit-services.com" is a valid completion
for "/i-:". However, vertico must not trigger to open that host. This
can be achieved by let-binding minibuffer-completing-file-name, for
example by the following patch in vertico.el:

*** /home/albinus/.emacs.d/elpa/vertico-2.4/vertico.el.~1~	2025-08-05 09:44:34.923858379 +0200
--- /home/albinus/.emacs.d/elpa/vertico-2.4/vertico.el	2025-08-06 09:21:14.376181020 +0200
***************
*** 211,217 ****
  
  (defun vertico--filter-completions (&rest args)
    "Compute all completions for ARGS with lazy highlighting."
!   (dlet ((completion-lazy-hilit t) (completion-lazy-hilit-fn nil))
      (static-if (>= emacs-major-version 30)
          (cons (apply #'completion-all-completions args) completion-lazy-hilit-fn)
        (cl-letf* ((orig-pcm (symbol-function #'completion-pcm--hilit-commonality))
--- 211,217 ----
  
  (defun vertico--filter-completions (&rest args)
    "Compute all completions for ARGS with lazy highlighting."
!   (dlet ((completion-lazy-hilit t) (completion-lazy-hilit-fn nil) (minibuffer-completing-file-name t))
      (static-if (>= emacs-major-version 30)
          (cons (apply #'completion-all-completions args) completion-lazy-hilit-fn)
        (cl-letf* ((orig-pcm (symbol-function #'completion-pcm--hilit-commonality))

Best regards, Michael.