Subject: bug#64198: Feature request: compile.el's "Find this in" prompt should be hookable.

From: Daniel Martín <[email-masked]>
Date: Thu, 22 Jun 2023 19:58:43 +0200

Dave Abrahams <[email-masked]> writes:
>
> Swift is a programming language.  When its assertions (like C's
> assert() macro) fail, a diagnostic is output with a file ID and
> line. The file ID looks like a path, but it's really not. If it's a
> path in the filesystem, that's coincidental but it's likely to point
> to the right file.  I don't want to manually hunt down the file every
> time an assertion fails; I'd rather emacs made an educated guess based
> on the current project.  It's obviously not the right answer for
> everyone, but I'd like to have the hooks needed to implement that
> without too much hackery.

This is the Elisp code you posted on GitHub, based on customizing
compilation-parse-errors-filename-function:

(defun dwa/path-tails-matching (path paths)
  "Returns the elements of PATHS with PATH as their suffix, matching by path component."
  (let ((tail (file-name-concat "/" path)))
    (seq-filter (lambda (full-path) (string-suffix-p tail full-path)) paths)))

(defun dwa/compilation-parse-errors-filename-in-project (path-in-error)
  "If PATH-IN-ERROR is found in the filesystem, returns it
unchanged; otherwise tries to return a unique file in the current
project likely to be identified by PATH-IN-ERROR.  Returns
PATH-IN-ERROR unchanged if no such file can be found."
  (if (file-exists-p path-in-error) path-in-error
    ;; First look for relative path suffixes.
    (let* ((candidates (project-files (project-current t)))
	   (full-matches (dwa/path-tails-matching path-in-error candidates)))

      ;; If not found, try just the filename component of
      ;; path-in-error; Swift assertions are weird and include a
      ;; module name that doesn't necessarily correspond to anything in the
      ;; filesystem.
      (cond ((null full-matches)
	     (let ((filename-matches
		   (dwa/path-tails-matching (file-name-nondirectory path-in-error) candidates)))
	       (cond ((null filename-matches) path-in-error)
		     ;; unique match; return it
		     ((null (cadr filename-matches)) (car filename-matches))
		     ;; multiple matches; consider prompting for the user to select one.
		     (t path-in-error))))
	    ;; unique match; return it
	    ((null (cadr matches)) (car matches))
	     ; multiple matches; consider prompting for the user to select one.
	    (t path-in-error)))))

(setq compilation-parse-errors-filename-function 'dwa/compilation-parse-errors-filename-in-project)

I've tried it and it seems to work well, although I agree that the code
is a bit hacky and prone to error.  How would the new hooks you propose
simplify this customization code?

Similar use cases have been discussed in the mailing list in the past.
Someone proposed to make compilation-find-file customizable, which may
not be a bad idea.  See
https://lists.gnu.org/archive/html/emacs-devel/2021-04/msg00910.html