Package: emacs;
Reported by: Philip Kaludercic <philipk <at> posteo.net>
Date: Sun, 30 Jan 2022 23:39:01 UTC
Severity: normal
Found in version 29.0.50
View this message in rfc822 format
From: Philip Kaludercic <philipk <at> posteo.net> To: Dmitry Gutov <dgutov <at> yandex.ru> Cc: Michael Albinus <michael.albinus <at> gmx.de>, 53644 <at> debbugs.gnu.org Subject: bug#53644: 29.0.50; xref-search-program breaks if programm not installed on a remote host Date: Tue, 08 Feb 2022 11:15:16 +0000
[Message part 1 (text/plain, inline)]
Dmitry Gutov <dgutov <at> yandex.ru> writes: > On 05.02.2022 16:38, Michael Albinus wrote: >> Dmitry Gutov <dgutov <at> yandex.ru> writes: >> >>> Hi Michael, >> Hi Dmitry, >> >>>>>> When invoking a command that respects xref-search-program via TRAMP, >>>>>> e.g. on a remote system that doesn't have (in my case ripgrep) >>>>>> installed, an error is signalled indicating that the search query >>>>>> couldn't be executed. >>>>> >>>>> One way to work around this will probably involve an addition to >>>>> find-file-hook and some code which checks (file-remote-p >>>>> buffer-file-name) and sets xref-search-program to a particular value >>>>> buffer-locally depending on the result. >>>>> >>>>> Or an around-advice for xref-matches-in-files. >>>> There are connection-local variables exactly for this use case. >>> >>> Is there a documented way on how to make the variable's value on >>> remote hosts customizable for the user too? >> Something like >> --8<---------------cut here---------------start------------->8--- >> (connection-local-set-profile-variables >> 'remote-xref-variables >> '((xref-search-program . "/bin/grep"))) >> (with-eval-after-load 'xref >> (connection-local-set-profiles >> '(:application tramp :machine "myhost") >> 'remote-xref-variables)) >> --8<---------------cut here---------------end--------------->8--- > > Nice. Some integration with the Customize UI probably wouldn't hurt, though. > > Philip, would you like to try writing a patch along the lines of > Michael's suggestion? > > It would need to use version checks, though, given that > connection-local vars were only added in Emacs 27. The following works, with one issue:
[Message part 2 (text/plain, inline)]
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 6677b4f004..b2f82f1889 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -1751,15 +1751,7 @@ xref-matches-in-files (remote-id (file-remote-p dir)) ;; The 'auto' default would be fine too, but ripgrep can't handle ;; the options we pass in that case. - (grep-highlight-matches nil) - (command (grep-expand-template (cdr - (or - (assoc - xref-search-program - xref-search-program-alist) - (user-error "Unknown search program `%s'" - xref-search-program))) - (xref--regexp-to-extended regexp)))) + (grep-highlight-matches nil)) (when remote-id (require 'tramp) (setq files (mapcar @@ -1770,25 +1762,56 @@ xref-matches-in-files (when (file-name-quoted-p (car files)) (setq files (mapcar #'file-name-unquote files))) (with-current-buffer output - (erase-buffer) (with-temp-buffer (insert (mapconcat #'identity files "\0")) - (setq default-directory dir) - (setq status - (xref--process-file-region (point-min) - (point-max) - shell-file-name - output - nil - shell-command-switch - command))) - (goto-char (point-min)) - (when (and (/= (point-min) (point-max)) - (not (looking-at grep-re)) - ;; TODO: Show these matches as well somehow? - (not (looking-at "Binary file .* matches"))) - (user-error "Search failed with status %d: %s" status - (buffer-substring (point-min) (line-end-position)))) + (let* ((default-directory dir) + (xref-search-program-alist xref-search-program-alist) + (program (if (version<= "27" emacs-version) + (with-connection-local-variables + xref-search-program) + xref-search-program))) + ;; In case `xref-search-program' is not installed on a + ;; remote system, we will speculatively try to start a + ;; different searcher to see if it is installed and works. + (catch 'ok + (while xref-search-program-alist + (with-current-buffer output + (erase-buffer)) + (setq status + (xref--process-file-region + (point-min) (point-max) + shell-file-name + output nil shell-command-switch + (grep-expand-template + (or (alist-get program xref-search-program-alist) + (user-error "Unknown search program `%s'" + program)) + (xref--regexp-to-extended regexp)))) + (with-current-buffer output + (goto-char (point-min)) + (unless (and (/= (point-min) (point-max)) + (not (looking-at grep-re)) + ;; TODO: Show these matches as well somehow? + (not (looking-at "Binary file .* matches"))) + (when (and (not (eq program xref-search-program)) + (version<= "27" emacs-version)) + ;; If possible and necessary, save whatever program + ;; was found as a connection local variable. + (let* ((host (file-remote-p default-directory 'host)) + (profile (intern (concat "xref-remote-" host)))) + (connection-local-set-profile-variables + profile `((xref-search-program . ,program))) + (connection-local-set-profiles + (list :machine host) profile))) + (throw 'ok t))) + (setq xref-search-program-alist + (remq (assq program xref-search-program-alist) + xref-search-program-alist) + program (caar xref-search-program-alist))) + (with-current-buffer output + (user-error "Search failed with status %d: %s" status + (buffer-string) + (buffer-substring (point-min) (line-end-position))))))) (while (re-search-forward grep-re nil t) (push (list (string-to-number (match-string line-group)) (match-string file-group)
[Message part 3 (text/plain, inline)]
xref--process-file-region takes shell-file-name, that should depend on the remote system. I could use something like (with-parsed-tramp-file-name default-directory d (tramp-get-method-parameter d 'tramp-remote-shell)) but it seems that `with-parsed-tramp-file-name' is not used outside of tramp, and byte-compiling triggers a warning. Is there some better way to do this? > To get you started, here's one example of this feature's usage: > https://github.com/company-mode/company-mode/blob/c25f1fbc3850e36e6521b77fa1641d5583365d8b/company-gtags.el#L71-L96 > > And you can search in Emacs's own repository, of course, for other examples. -- Philip Kaludercic
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.