diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 85f3907..41dc810 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -154,6 +154,14 @@ project--find-in-directory vc-directory-exclusion-list) grep-find-ignored-files)) +(cl-defgeneric project--file-completion-table (_project _dirs) + "Return a completion table for files in directories DIRS in PROJECT. +If non-nil, DIRS is a list of absolute directories; it should be some +subset of the project roots and external roots. If nil, the backend +uses all the directories it knows about. +PROJECT is used to find the project ignores and other project meta-data." + ) + (defgroup project-vc nil "Project implementation using the VC package." :version "25.1" @@ -313,51 +321,57 @@ project--find-regexp-in ;;;###autoload (defun project-find-file () - "Visit a file in the current project's roots. - -This is like `find-file', but it limits the file-name completion -candidates to the files within the current project roots." + "Visit a file (with completion) in the current project's roots. +The completion default is the filename at point, if one is +recognized." (interactive) (let* ((pr (project-current t)) (dirs (project-roots pr))) - (project--find-file-in dirs pr))) + (project--find-file-in (thing-at-point 'filename) dirs pr))) ;;;###autoload (defun project-or-external-find-file () "Visit a file in the current project's roots or external roots. - -This is like `find-file', but it limits the file-name completion -candidates to the files within the current project roots and external roots." +The completion default is the filename at point, if one is +recognized." (interactive) (let* ((pr (project-current t)) (dirs (append (project-roots pr) (project-external-roots pr)))) - (project--find-file-in dirs pr))) + (project--find-file-in (thing-at-point 'filename) dirs pr))) ;; FIXME: Uniquely abbreviate the roots? -(defun project--find-file-in (dirs project) +(cl-defmethod project--file-completion-table (project dirs) + "Default implementation using `find-program'." (require 'xref) - (let* ((all-files - (cl-mapcan - (lambda (dir) - (let ((command - (format "%s %s %s -type f -print0" - find-program - dir - (xref--find-ignores-arguments - (project-ignores project dir) - (expand-file-name dir))))) - (split-string (shell-command-to-string command) "\0" t))) - dirs)) - (table (lambda (string pred action) - (cond - ((eq action 'metadata) - '(metadata . ((category . project-file)))) - (t - (complete-with-action action all-files string pred)))))) - (find-file - (completing-read "Find file: " table nil t)))) + (let ((all-files + (cl-mapcan + (lambda (dir) + (let ((command + (format "%s %s %s -type f -print0" + find-program + dir + (xref--find-ignores-arguments + (project-ignores project dir) + (expand-file-name dir))))) + (split-string (shell-command-to-string command) "\0" t))) + dirs))) + (lambda (string pred action) + (cond + ((eq action 'metadata) + '(metadata . ((category . project-file)))) + (t + (complete-with-action action all-files string pred)))) + )) + +(defun project--find-file-in (filename dirs project) + "Complete FILENAME in DIRS in PROJECT, visit the file." + (find-file + (completing-read + (format "Find file (%s): " filename) + (project--file-completion-table project dirs) + nil t nil nil filename))) (provide 'project) ;;; project.el ends here diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 267853d..2fd7297 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -854,6 +854,7 @@ xref-etags-mode (declare-function semantic-symref-find-references-by-name "semantic/symref") (declare-function semantic-find-file-noselect "semantic/fw") (declare-function grep-expand-template "grep") +(defvar ede-minor-mode) ;; ede.el (defun xref-collect-references (symbol dir) "Collect references to SYMBOL inside DIR. @@ -948,6 +949,9 @@ xref--rgrep-command (xref--find-ignores-arguments ignores dir))) (defun xref--find-ignores-arguments (ignores dir) + "Convert IGNORES and DIR to a list of arguments for 'find'. +IGNORES is a list of glob patterns. DIR is an absolute +directory, used as the root of the ignore globs." ;; `shell-quote-argument' quotes the tilde as well. (cl-assert (not (string-match-p "\\`~" dir))) (when ignores