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'.
This commit is contained in:
Dmitry Gutov 2016-01-07 20:14:40 +03:00
parent 056da45d2c
commit ed41d117a4
3 changed files with 71 additions and 23 deletions

View file

@ -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:

View file

@ -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

View file

@ -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