From: Dmitry Gutov Date: Thu, 7 Jan 2016 17:14:40 +0000 (+0300) Subject: Add project-find-file and project-or-external-find-file X-Git-Tag: emacs-25.0.90~246 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=ed41d117a434abd28df4585663c2311c87160d1c;p=emacs.git Add project-find-file and project-or-external-find-file * lisp/minibuffer.el (completion-category-defaults): Add `project-file' category. * lisp/progmodes/project.el (project-find-file) (project-or-external-find-file): New commands. (project--find-file-in): New private function. * lisp/progmodes/xref.el (xref-collect-matches): Use `expand-file-name' on DIR, to expand the tildes. (xref--find-ignores-arguments): Extract from `xref--rgrep-command'. --- diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 1251a4e1107..ecac0aeb135 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -831,7 +831,8 @@ styles for specific categories, such as files, buffers, etc." (defvar completion-category-defaults '((buffer (styles . (basic substring))) - (unicode-name (styles . (basic substring)))) + (unicode-name (styles . (basic substring))) + (project-file (styles . (basic substring)))) "Default settings for specific completion categories. Each entry has the shape (CATEGORY . ALIST) where ALIST is an association list that can specify properties such as: diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index d77158761eb..2e3222f55dc 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -45,10 +45,12 @@ ;;; TODO: -;; * Commands `project-find-file' and `project-or-external-find-file'. -;; Currently blocked on adding a new completion style that would let -;; the user enter just the base file name (or a part of it), and get -;; it expanded to the absolute file name. +;; * Reliably cache the list of files in the project, probably using +;; filenotify.el (if supported) to invalidate. And avoiding caching +;; if it's not available (manual cache invalidation is not nice). +;; +;; * Allow the backend to override the file-listing logic? Maybe also +;; to delegate file name completion to an external tool. ;; ;; * Build tool related functionality. Start with a `project-build' ;; command, which should provide completions on tasks to run, and @@ -258,6 +260,7 @@ DIRS must contain directory names." (declare-function xref-collect-matches "xref") (declare-function xref--show-xrefs "xref") (declare-function xref-backend-identifier-at-point "xref") +(declare-function xref--find-ignores-arguments "xref") ;;;###autoload (defun project-find-regexp (regexp) @@ -302,5 +305,42 @@ pattern to search for." (user-error "No matches for: %s" regexp)) (xref--show-xrefs xrefs nil))) +(defun project-find-file () + (interactive) + (let* ((pr (project-current t)) + (dirs (project-roots pr))) + (project--find-file-in dirs pr))) + +(defun project-or-external-find-file () + (interactive) + (let* ((pr (project-current t)) + (dirs (append + (project-roots pr) + (project-external-roots pr)))) + (project--find-file-in dirs pr))) + +;; FIXME: Uniquely abbreviate the roots? +(defun project--find-file-in (dirs project) + (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)))) + (provide 'project) ;;; project.el ends here diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index ae5ec61520d..59700115879 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -876,7 +876,9 @@ IGNORES is a list of glob patterns." grep-find-template t t)) (grep-highlight-matches nil) (command (xref--rgrep-command (xref--regexp-to-extended regexp) - files dir ignores)) + files + (expand-file-name dir) + ignores)) (orig-buffers (buffer-list)) (buf (get-buffer-create " *xref-grep*")) (grep-re (caar grep-regexp-alist)) @@ -912,23 +914,28 @@ IGNORES is a list of glob patterns." " " (shell-quote-argument ")")) dir - (concat - (shell-quote-argument "(") - " -path " - (mapconcat - (lambda (ignore) - (when (string-match-p "/\\'" ignore) - (setq ignore (concat ignore "*"))) - (if (string-match "\\`\\./" ignore) - (setq ignore (replace-match dir t t ignore)) - (unless (string-prefix-p "*" ignore) - (setq ignore (concat "*/" ignore)))) - (shell-quote-argument ignore)) - ignores - " -o -path ") - " " - (shell-quote-argument ")") - " -prune -o "))) + (xref--find-ignores-arguments ignores dir))) + +(defun xref--find-ignores-arguments (ignores dir) + ;; `shell-quote-argument' quotes the tilde as well. + (cl-assert (not (string-match-p "\\`~" dir))) + (concat + (shell-quote-argument "(") + " -path " + (mapconcat + (lambda (ignore) + (when (string-match-p "/\\'" ignore) + (setq ignore (concat ignore "*"))) + (if (string-match "\\`\\./" ignore) + (setq ignore (replace-match dir t t ignore)) + (unless (string-prefix-p "*" ignore) + (setq ignore (concat "*/" ignore)))) + (shell-quote-argument ignore)) + ignores + " -o -path ") + " " + (shell-quote-argument ")") + " -prune -o ")) (defun xref--regexp-to-extended (str) (replace-regexp-in-string