cp-grep, cp-ag, cp-rg: support kept directories

Also support globally ignored file suffixes.

Separate out `counsel-projectile-git-grep` from
`counsel-projectile-grep` and give it a key binding.
This commit is contained in:
Eric Danan 2018-08-22 02:04:23 +02:00
parent 6b69bbf621
commit 96f69f8217
2 changed files with 105 additions and 71 deletions

View file

@ -83,6 +83,7 @@ New commands:
| Key binding | Command | Description | | Key binding | Command | Description |
| :------------------- | :------------------------------- | :-------------------------------------------------- | | :------------------- | :------------------------------- | :-------------------------------------------------- |
| <kbd>C-c p SPC</kbd> | `counsel-projectile` | Jump to a project buffer or file, or switch project | | <kbd>C-c p SPC</kbd> | `counsel-projectile` | Jump to a project buffer or file, or switch project |
| <kbd>C-c p s i</kbd> | `counsel-projectile-git-grep` | Search project with git grep |
| <kbd>C-c p O c</kbd> | `counsel-projectile-org-capture` | Capture into project | | <kbd>C-c p O c</kbd> | `counsel-projectile-org-capture` | Capture into project |
| <kbd>C-c p O a</kbd> | `counsel-projectile-org-capture` | Open project agenda | | <kbd>C-c p O a</kbd> | `counsel-projectile-org-capture` | Open project agenda |
## The `counsel-projectile` command ## The `counsel-projectile` command
@ -123,6 +124,7 @@ This command is a replacement for `projectile-switch-project`. It adds the possi
| <kbd>E</kbd> | Edit project directory-local variables | | <kbd>E</kbd> | Edit project directory-local variables |
| <kbd>v</kbd> | Open project in vc-dir / magit / monky | | <kbd>v</kbd> | Open project in vc-dir / magit / monky |
| <kbd>s g</kbd> | Search project with grep: call `counsel-projectile-grep` (see below) | | <kbd>s g</kbd> | Search project with grep: call `counsel-projectile-grep` (see below) |
| <kbd>s i</kbd> | Search project with git grep: call `counsel-projectile-git-grep` (see below) |
| <kbd>s s</kbd> | Search project with ag: call `counsel-projectile-ag` (see below) | | <kbd>s s</kbd> | Search project with ag: call `counsel-projectile-ag` (see below) |
| <kbd>s r</kbd> | Search project with rg: call `counsel-projectile-rg` (see below) | | <kbd>s r</kbd> | Search project with rg: call `counsel-projectile-rg` (see below) |
| <kbd>x s</kbd> | Invoke shell from the project root | | <kbd>x s</kbd> | Invoke shell from the project root |
@ -178,6 +180,12 @@ The key binding <kbd>C-c C-k</kbd> can also be used from the minibuffer to kill
Default key binding: <kbd>C-c p s g</kbd>. Default key binding: <kbd>C-c p s g</kbd>.
This command is a replacement for `projectile-grep`. It searches all project files with `grep`, taking advantage of ivy's support for updating the list of candidates after each input (dynamic collections). Each canidate corresponds to a matching line in some project file, and there is only one action that opens that file at that line. This command is a replacement for `projectile-grep`. It searches all project files with `grep`, taking advantage of ivy's support for updating the list of candidates after each input (dynamic collections). Each canidate corresponds to a matching line in some project file, and there is only one action that opens that file at that line.
If inside a git project and the variable `projectile-use-git-grep` is non-nil, then `counsel-projectile-grep` uses `git grep` instead of `grep`, by calling the function `counsel-projectile-git-grep` (see below).
## The `counsel-projectile-git-grep` command
Default key binding: <kbd>C-c p s i</kbd>.
This command is similar to `counsel-projectile-grep` (see above) but uses `git grep` instead of `grep` (hence it only works in git projects).
## The `counsel-projectile-ag` command ## The `counsel-projectile-ag` command
Default key binding: <kbd>C-c p s s</kbd>. Default key binding: <kbd>C-c p s s</kbd>.

View file

@ -588,15 +588,12 @@ of `(ivy-thing-at-point)' by hitting \"M-n\" in the minibuffer."
(sexp :tag "Custom expression")) (sexp :tag "Custom expression"))
:group 'counsel-projectile) :group 'counsel-projectile)
(defvar counsel-projectile-grep-base-command "grep -rnE %s -- %%s ." (defvar counsel-projectile-grep-base-command "grep -rnEI %s -- %%s %s"
"Format string to use in `cousel-projectile-grep-function' to "Format string to use in `cousel-projectile-grep' to
construct the command.") construct the command.")
(defvar counsel-projectile-grep-command nil) (defvar counsel-projectile-grep-command nil)
(defvar counsel-projectile-grep-options-history nil
"History for `counsel-projectile-grep' options.")
(defun counsel-projectile-grep-function (string) (defun counsel-projectile-grep-function (string)
"Grep for STRING in the current project." "Grep for STRING in the current project."
(or (counsel-more-chars) (or (counsel-more-chars)
@ -636,11 +633,12 @@ construct the command.")
(insert (format "%d candidates:\n" (length cands))) (insert (format "%d candidates:\n" (length cands)))
(ivy--occur-insert-lines cands))) (ivy--occur-insert-lines cands)))
;;;###autoload
(defun counsel-projectile-grep (&optional options-or-cmd) (defun counsel-projectile-grep (&optional options-or-cmd)
"Search the current project with grep. "Search the current project with grep.
If inside a git project and `projectile-use-git-grep' is non-nil, If inside a git project and `projectile-use-git-grep' is non-nil,
use `counsel-git-grep'. Otherwise use grep recursively. use git grep. Otherwise use grep recursively.
OPTIONS-OR-CMD, if non-nil, is a string containing either OPTIONS-OR-CMD, if non-nil, is a string containing either
additional options to be passed to grep, or an alternative git additional options to be passed to grep, or an alternative git
@ -648,36 +646,31 @@ grep command. It is read from the minibuffer if the function is
called with a prefix argument." called with a prefix argument."
(interactive) (interactive)
(if (and (eq (projectile-project-vcs) 'git) (if (and (eq (projectile-project-vcs) 'git)
projectile-use-git-grep) projectile-use-git-grep)
(let ((counsel-prompt-function (counsel-projectile-git-grep options-or-cmd)
(lambda () (let* ((path
(ivy-add-prompt-count (mapconcat 'shell-quote-argument
(format "%s: " (projectile-prepend-project-name (ivy-state-prompt ivy-last))))))) (projectile-normalise-paths
(counsel-git-grep (or current-prefix-arg options-or-cmd) (car (projectile-parse-dirconfig-file)))
counsel-projectile-grep-initial-input)) " "))
(counsel-require-program (car (split-string counsel-projectile-grep-base-command))) (ignored-files
(let* ((ignored-files (mapconcat (lambda (i) (mapconcat (lambda (i)
(concat "--exclude=" (concat "--exclude=" (shell-quote-argument i)))
(shell-quote-argument i) (append
" ")) (projectile--globally-ignored-file-suffixes-glob)
(projectile-ignored-files-rel) (projectile-ignored-files-rel))
"")) " "))
(ignored-dirs (mapconcat (lambda (i) (ignored-dirs
(concat "--exclude-dir=" (mapconcat (lambda (i)
(shell-quote-argument i) (concat "--exclude-dir=" (shell-quote-argument i)))
" ")) (projectile-ignored-directories-rel)
(projectile-ignored-directories-rel) " "))
"")) (ignored (concat ignored-files " " ignored-dirs))
(ignored (concat ignored-files ignored-dirs))
(options
(if current-prefix-arg
(read-string (projectile-prepend-project-name "grep options: ")
ignored
'counsel-projectile-grep-options-history)
(concat ignored options-or-cmd)))
(default-directory (projectile-project-root))) (default-directory (projectile-project-root)))
(counsel-require-program
(car (split-string counsel-projectile-grep-base-command)))
(setq counsel-projectile-grep-command (setq counsel-projectile-grep-command
(format counsel-projectile-grep-base-command options)) (format counsel-projectile-grep-base-command ignored path))
(ivy-set-prompt 'counsel-projectile-grep counsel-prompt-function) (ivy-set-prompt 'counsel-projectile-grep counsel-prompt-function)
(ivy-read (projectile-prepend-project-name "grep") (ivy-read (projectile-prepend-project-name "grep")
#'counsel-projectile-grep-function #'counsel-projectile-grep-function
@ -695,6 +688,30 @@ called with a prefix argument."
(ivy-set-occur 'counsel-projectile-grep 'counsel-projectile-grep-occur) (ivy-set-occur 'counsel-projectile-grep 'counsel-projectile-grep-occur)
(ivy-set-display-transformer 'counsel-projectile-grep 'counsel-projectile-grep-transformer) (ivy-set-display-transformer 'counsel-projectile-grep 'counsel-projectile-grep-transformer)
;;;###autoload
(defun counsel-projectile-git-grep (&optional cmd)
"Search the current project with git grep.
CMD, if non-nil, is a string containing an alternative git grep
command. It is read from the minibuffer if the function is called
with a prefix argument."
(interactive)
(let* ((path
(mapconcat 'shell-quote-argument
(projectile-normalise-paths
(car (projectile-parse-dirconfig-file)))
" "))
(counsel-git-grep-cmd-default
(concat (concat (string-trim-right counsel-git-grep-cmd-default " \\.")
" " path)))
(counsel-prompt-function
(lambda ()
(ivy-add-prompt-count
(format "%s: " (projectile-prepend-project-name
(ivy-state-prompt ivy-last)))))))
(counsel-git-grep (or current-prefix-arg cmd)
counsel-projectile-grep-initial-input)))
;;* counsel-projectile-ag ;;* counsel-projectile-ag
(defcustom counsel-projectile-ag-initial-input nil (defcustom counsel-projectile-ag-initial-input nil
@ -712,9 +729,6 @@ of `(ivy-thing-at-point)' by hitting \"M-n\" in the minibuffer."
(sexp :tag "Custom expression")) (sexp :tag "Custom expression"))
:group 'counsel-projectile) :group 'counsel-projectile)
(defvar counsel-projectile-ag-options-history nil
"History for `counsel-projectile-ag' options.")
;;;###autoload ;;;###autoload
(defun counsel-projectile-ag (&optional options) (defun counsel-projectile-ag (&optional options)
"Search the current project with ag. "Search the current project with ag.
@ -723,23 +737,26 @@ OPTIONS, if non-nil, is a string containing additional options to
be passed to ag. It is read from the minibuffer if the function be passed to ag. It is read from the minibuffer if the function
is called with a prefix argument." is called with a prefix argument."
(interactive) (interactive)
(let* ((ignored (mapconcat (lambda (i) (let* ((path (mapconcat 'shell-quote-argument
(concat "--ignore " (projectile-normalise-paths
(shell-quote-argument i) (car (projectile-parse-dirconfig-file)))
" ")) " "))
(append (projectile-ignored-files-rel) (ignored
(projectile-ignored-directories-rel)) (mapconcat (lambda (i)
"")) (concat "--ignore " (shell-quote-argument i)))
(options (append
(if current-prefix-arg (projectile--globally-ignored-file-suffixes-glob)
(read-string (projectile-prepend-project-name "ag options: ") (projectile-ignored-files-rel)
ignored (projectile-ignored-directories-rel))
'counsel-projectile-ag-options-history) " "))
(concat ignored options)))) (counsel-ag-base-command
(format (string-trim-right counsel-ag-base-command " \\.")
(concat ignored " %s " path))))
(counsel-ag (eval counsel-projectile-ag-initial-input) (counsel-ag (eval counsel-projectile-ag-initial-input)
(projectile-project-root) (projectile-project-root)
options options
(projectile-prepend-project-name "ag")))) (projectile-prepend-project-name
(car (split-string counsel-ag-base-command))))))
;;* counsel-projectile-rg ;;* counsel-projectile-rg
@ -758,9 +775,6 @@ of `(ivy-thing-at-point)' by hitting \"M-n\" in the minibuffer."
(sexp :tag "Custom expression")) (sexp :tag "Custom expression"))
:group 'counsel-projectile) :group 'counsel-projectile)
(defvar counsel-projectile-rg-options-history nil
"History for `counsel-projectile-rg' options.")
;;;###autoload ;;;###autoload
(defun counsel-projectile-rg (&optional options) (defun counsel-projectile-rg (&optional options)
"Search the current project with rg. "Search the current project with rg.
@ -769,23 +783,27 @@ OPTIONS, if non-nil, is a string containing additional options to
be passed to rg. It is read from the minibuffer if the function be passed to rg. It is read from the minibuffer if the function
is called with a prefix argument." is called with a prefix argument."
(interactive) (interactive)
(let* ((ignored (mapconcat (lambda (i) (let* ((path
(concat "--glob " (mapconcat 'shell-quote-argument
(shell-quote-argument (concat "!" i)) (projectile-normalise-paths
" ")) (car (projectile-parse-dirconfig-file)))
(append (projectile-ignored-files-rel) " "))
(projectile-ignored-directories-rel)) (ignored
"")) (mapconcat (lambda (i)
(options (concat "--glob !" (shell-quote-argument i)))
(if current-prefix-arg (append
(read-string (projectile-prepend-project-name "rg options: ") (projectile--globally-ignored-file-suffixes-glob)
ignored (projectile-ignored-files-rel)
'counsel-projectile-rg-options-history) (projectile-ignored-directories-rel))
(concat ignored options)))) " "))
(counsel-rg-base-command
(format (string-trim-right counsel-rg-base-command " \\.")
(concat ignored " %s " path))))
(counsel-rg (eval counsel-projectile-rg-initial-input) (counsel-rg (eval counsel-projectile-rg-initial-input)
(projectile-project-root) (projectile-project-root)
options options
(projectile-prepend-project-name "rg")))) (projectile-prepend-project-name
(car (split-string counsel-rg-base-command))))))
;;* counsel-projectile-org-capture ;;* counsel-projectile-org-capture
@ -1044,6 +1062,8 @@ candidates list of `counsel-projectile-switch-project'."
"open project in vc-dir / magit / monky") "open project in vc-dir / magit / monky")
("sg" counsel-projectile-switch-project-action-grep ("sg" counsel-projectile-switch-project-action-grep
"search project with grep") "search project with grep")
("si" counsel-projectile-switch-project-action-git-grep
"search project with git grep")
("ss" counsel-projectile-switch-project-action-ag ("ss" counsel-projectile-switch-project-action-ag
"search project with ag") "search project with ag")
("sr" counsel-projectile-switch-project-action-rg ("sr" counsel-projectile-switch-project-action-rg
@ -1179,17 +1199,22 @@ action."
(counsel-projectile-switch-project-by-name project))) (counsel-projectile-switch-project-by-name project)))
(defun counsel-projectile-switch-project-action-grep (project) (defun counsel-projectile-switch-project-action-grep (project)
"Search PROJECT with `grep'." "Search PROJECT with grep."
(let ((projectile-switch-project-action 'counsel-projectile-grep)) (let ((projectile-switch-project-action 'counsel-projectile-grep))
(counsel-projectile-switch-project-by-name project))) (counsel-projectile-switch-project-by-name project)))
(defun counsel-projectile-switch-project-action-git-grep (project)
"Search PROJECT with git grep."
(let ((projectile-switch-project-action 'counsel-projectile-git-grep))
(counsel-projectile-switch-project-by-name project)))
(defun counsel-projectile-switch-project-action-ag (project) (defun counsel-projectile-switch-project-action-ag (project)
"Search PROJECT with `ag'." "Search PROJECT with ag."
(let ((projectile-switch-project-action 'counsel-projectile-ag)) (let ((projectile-switch-project-action 'counsel-projectile-ag))
(counsel-projectile-switch-project-by-name project))) (counsel-projectile-switch-project-by-name project)))
(defun counsel-projectile-switch-project-action-rg (project) (defun counsel-projectile-switch-project-action-rg (project)
"Search PROJECT with `rg'." "Search PROJECT with rg."
(let ((projectile-switch-project-action 'counsel-projectile-rg)) (let ((projectile-switch-project-action 'counsel-projectile-rg))
(counsel-projectile-switch-project-by-name project))) (counsel-projectile-switch-project-by-name project)))
@ -1383,6 +1408,7 @@ If not inside a project, call `counsel-projectile-switch-project'."
(projectile-ripgrep . counsel-projectile-rg) (projectile-ripgrep . counsel-projectile-rg)
(projectile-switch-project . counsel-projectile-switch-project) (projectile-switch-project . counsel-projectile-switch-project)
(" " . counsel-projectile) (" " . counsel-projectile)
("si" . counsel-projectile-git-grep)
("Oc" . counsel-projectile-org-capture) ("Oc" . counsel-projectile-org-capture)
("Oa" . counsel-projectile-org-agenda)) ("Oa" . counsel-projectile-org-agenda))
"Alist of counsel-projectile key bindings. "Alist of counsel-projectile key bindings.