diff options
| author | Dmitry Gutov | 2016-01-30 07:21:31 +0300 |
|---|---|---|
| committer | Dmitry Gutov | 2016-01-30 07:21:31 +0300 |
| commit | 2b87dea0b8ccbfe4faf13a8f2d6c955c2756e161 (patch) | |
| tree | 1dc4b3cdf66b764a53bf8e0c3408d7229fb98178 | |
| parent | 06083cf41c473404d246de9b91a0116f38c5485f (diff) | |
| download | emacs-2b87dea0b8ccbfe4faf13a8f2d6c955c2756e161.tar.gz emacs-2b87dea0b8ccbfe4faf13a8f2d6c955c2756e161.zip | |
Improve project-find-file yet again!
* lisp/progmodes/project.el (project--completing-read-strict):
New function.
(project-find-file-in): Use it.
(project-file-completion-table): Move the default
implementation inside the cl-defgeneric form.
(http://lists.gnu.org/archive/html/emacs-devel/2016-01/msg01720.html)
| -rw-r--r-- | lisp/progmodes/project.el | 87 |
1 files changed, 51 insertions, 36 deletions
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 2cc76aa6af7..0b05de29089 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el | |||
| @@ -154,12 +154,33 @@ end it with `/'. DIR must be one of `project-roots' or | |||
| 154 | vc-directory-exclusion-list) | 154 | vc-directory-exclusion-list) |
| 155 | grep-find-ignored-files)) | 155 | grep-find-ignored-files)) |
| 156 | 156 | ||
| 157 | (cl-defgeneric project-file-completion-table (_project _dirs) | 157 | (cl-defgeneric project-file-completion-table (project dirs) |
| 158 | "Return a completion table for files in directories DIRS in PROJECT. | 158 | "Return a completion table for files in directories DIRS in PROJECT. |
| 159 | DIRS is a list of absolute directories; it should be some | 159 | DIRS is a list of absolute directories; it should be some |
| 160 | subset of the project roots and external roots. | 160 | subset of the project roots and external roots. |
| 161 | PROJECT is used to find the project ignores and other project meta-data." | 161 | |
| 162 | ) | 162 | The default implementation uses `find-program'. PROJECT is used |
| 163 | to find the list of ignores for each directory." | ||
| 164 | ;; FIXME: Uniquely abbreviate the roots? | ||
| 165 | (require 'xref) | ||
| 166 | (let ((all-files | ||
| 167 | (cl-mapcan | ||
| 168 | (lambda (dir) | ||
| 169 | (let ((command | ||
| 170 | (format "%s %s %s -type f -print0" | ||
| 171 | find-program | ||
| 172 | dir | ||
| 173 | (xref--find-ignores-arguments | ||
| 174 | (project-ignores project dir) | ||
| 175 | (expand-file-name dir))))) | ||
| 176 | (split-string (shell-command-to-string command) "\0" t))) | ||
| 177 | dirs))) | ||
| 178 | (lambda (string pred action) | ||
| 179 | (cond | ||
| 180 | ((eq action 'metadata) | ||
| 181 | '(metadata . ((category . project-file)))) | ||
| 182 | (t | ||
| 183 | (complete-with-action action all-files string pred)))))) | ||
| 163 | 184 | ||
| 164 | (defgroup project-vc nil | 185 | (defgroup project-vc nil |
| 165 | "Project implementation using the VC package." | 186 | "Project implementation using the VC package." |
| @@ -340,40 +361,34 @@ recognized." | |||
| 340 | (project-external-roots pr)))) | 361 | (project-external-roots pr)))) |
| 341 | (project-find-file-in (thing-at-point 'filename) dirs pr))) | 362 | (project-find-file-in (thing-at-point 'filename) dirs pr))) |
| 342 | 363 | ||
| 343 | ;; FIXME: Uniquely abbreviate the roots? | ||
| 344 | (cl-defmethod project-file-completion-table (project dirs) | ||
| 345 | "Default implementation using `find-program'." | ||
| 346 | (require 'xref) | ||
| 347 | (let ((all-files | ||
| 348 | (cl-mapcan | ||
| 349 | (lambda (dir) | ||
| 350 | (let ((command | ||
| 351 | (format "%s %s %s -type f -print0" | ||
| 352 | find-program | ||
| 353 | dir | ||
| 354 | (xref--find-ignores-arguments | ||
| 355 | (project-ignores project dir) | ||
| 356 | (expand-file-name dir))))) | ||
| 357 | (split-string (shell-command-to-string command) "\0" t))) | ||
| 358 | dirs))) | ||
| 359 | (lambda (string pred action) | ||
| 360 | (cond | ||
| 361 | ((eq action 'metadata) | ||
| 362 | '(metadata . ((category . project-file)))) | ||
| 363 | (t | ||
| 364 | (complete-with-action action all-files string pred)))) | ||
| 365 | )) | ||
| 366 | |||
| 367 | (defun project-find-file-in (filename dirs project) | 364 | (defun project-find-file-in (filename dirs project) |
| 368 | "Complete FILENAME in DIRS in PROJECT, visit the file." | 365 | "Complete FILENAME in DIRS in PROJECT and visit the result." |
| 369 | ;; FIXME: verify that filename is accepted by the completion table | 366 | (let* ((table (project-file-completion-table project dirs)) |
| 370 | (find-file | 367 | (file (project--completing-read-strict |
| 371 | (completing-read | 368 | "Find file" table nil nil |
| 372 | (if filename | 369 | filename))) |
| 373 | (format "Find file (%s): " filename) | 370 | (if (string= file "") |
| 374 | "Find file: ") | 371 | (user-error "You didn't specify the file") |
| 375 | (project-file-completion-table project dirs) | 372 | (find-file file)))) |
| 376 | nil t nil nil filename))) | 373 | |
| 374 | (defun project--completing-read-strict (prompt | ||
| 375 | collection &optional predicate | ||
| 376 | hist default inherit-input-method) | ||
| 377 | (when (and default (not (test-completion default collection predicate))) | ||
| 378 | (setq default (car (completion-try-completion | ||
| 379 | default collection predicate (length default))))) | ||
| 380 | (let* ((new-prompt (if default | ||
| 381 | (format "%s (default %s): " prompt default) | ||
| 382 | (format "%s: " prompt))) | ||
| 383 | (res (completing-read new-prompt | ||
| 384 | collection predicate t | ||
| 385 | nil hist default inherit-input-method))) | ||
| 386 | (if (and (equal res default) | ||
| 387 | (not (test-completion res collection predicate))) | ||
| 388 | (completing-read (format "%s: " prompt) | ||
| 389 | collection predicate t res hist nil | ||
| 390 | inherit-input-method) | ||
| 391 | res))) | ||
| 377 | 392 | ||
| 378 | (provide 'project) | 393 | (provide 'project) |
| 379 | ;;; project.el ends here | 394 | ;;; project.el ends here |