From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Dmitry Gutov Newsgroups: gmane.emacs.devel Subject: Re: find-file-project Date: Wed, 6 Jan 2016 03:29:09 +0200 Message-ID: <568C6DE5.8040201@yandex.ru> References: <86pp1j4ejm.fsf@stephe-leake.org> <55F899EA.7050700@yandex.ru> <86lhc73wog.fsf@stephe-leake.org> <55F8F2FA.6060902@yandex.ru> <867fnq1oe9.fsf@stephe-leake.org> <55F9A13A.3070101@yandex.ru> <55FB01BD.1070909@yandex.ru> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------090200050005020007040904" X-Trace: ger.gmane.org 1452043776 14084 80.91.229.3 (6 Jan 2016 01:29:36 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 6 Jan 2016 01:29:36 +0000 (UTC) Cc: Stephen Leake , emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Jan 06 02:29:33 2016 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1aGcup-00075k-PF for ged-emacs-devel@m.gmane.org; Wed, 06 Jan 2016 02:29:32 +0100 Original-Received: from localhost ([::1]:52157 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aGcup-0000yU-0j for ged-emacs-devel@m.gmane.org; Tue, 05 Jan 2016 20:29:31 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:49041) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aGcuZ-0000yD-QO for emacs-devel@gnu.org; Tue, 05 Jan 2016 20:29:16 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aGcuW-0001tE-GM for emacs-devel@gnu.org; Tue, 05 Jan 2016 20:29:15 -0500 Original-Received: from mail-lf0-x230.google.com ([2a00:1450:4010:c07::230]:33406) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aGcuW-0001t7-5g for emacs-devel@gnu.org; Tue, 05 Jan 2016 20:29:12 -0500 Original-Received: by mail-lf0-x230.google.com with SMTP id p203so306960267lfa.0 for ; Tue, 05 Jan 2016 17:29:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:subject:to:references:cc:from:message-id:date:user-agent :mime-version:in-reply-to:content-type; bh=3yhJqiJ5P2h0pVhqgKe/yLkkpXxt+8LV0jSkOh/b7iI=; b=VlHV4Io9WqjDsTwaRoh+gYzh8icA03C3zqutOOqQYaLEvN90ecCUGmCTuRcQSosQBh reFQk4G4u3dPVXYCCDmB1jRkLsLv58kb+8NBjuD1nU1u+KiuxnSSkPuKT/MJGthcDbsr QWoCXgeV7GEz1bwTgbpQXWHjyv+fLace3UMTqP0rfFp89ILYyEGJRDQb/rQe2CpGtW8g B0QUAkMRHT53ZMRgeCCy4ShD9OHRpgOqhhjcoKOuqr7TkpmTyVV7RaDPtRR6VaCkVXOf 1zNYWXfNOpUO1O54jOYFj7TVtilPADgCZcR413ke7uO7QB8MJfpcJqjZEU4DBYVUyNNE +4XA== X-Received: by 10.25.18.231 with SMTP id 100mr34436893lfs.25.1452043751164; Tue, 05 Jan 2016 17:29:11 -0800 (PST) Original-Received: from [192.168.1.190] ([178.252.127.222]) by smtp.googlemail.com with ESMTPSA id wu10sm16822404lbb.44.2016.01.05.17.29.10 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 05 Jan 2016 17:29:10 -0800 (PST) User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:43.0) Gecko/20100101 Thunderbird/43.0 In-Reply-To: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:4010:c07::230 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:197679 Archived-At: This is a multi-part message in MIME format. --------------090200050005020007040904 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Hi Stefan, On 09/18/2015 08:07 PM, Stefan Monnier wrote: > Of course, project-find-file could wrap the backend's completion table > so as to add its own `category' info to the meatadata, but > it's cumbersome. Getting back to the question of the new category, do you think `project-file' is a good enough name? Could we want to reuse it for non-project, or non-file completions, in the future? Here's the basic patch that I want to install, which should be enough to introduce the feature in 25.1 (to make project.el reasonably interesting at least for some fraction of users). Using partial-completion here requires starting input with a slash, but that's still better than no partial completion at all. --------------090200050005020007040904 Content-Type: text/x-patch; name="project-find-file.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="project-find-file.diff" diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 1251a4e..f6bcbd9 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -831,7 +831,8 @@ completion-styles (defvar completion-category-defaults '((buffer (styles . (basic substring))) - (unicode-name (styles . (basic substring)))) + (unicode-name (styles . (basic substring))) + (project-file (styles . (basic substring partial-completion)))) "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 d771587..2e3222f 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 @@ project--value-in-dir (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 @@ project--find-regexp-in (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 ae5ec61..5970011 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -876,7 +876,9 @@ xref-collect-matches 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 @@ xref--rgrep-command " " (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 --------------090200050005020007040904--