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 |
| :------------------- | :------------------------------- | :-------------------------------------------------- |
| <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 a</kbd> | `counsel-projectile-org-capture` | Open project agenda |
## 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>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 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 r</kbd> | Search project with rg: call `counsel-projectile-rg` (see below) |
| <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>.
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
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"))
:group 'counsel-projectile)
(defvar counsel-projectile-grep-base-command "grep -rnE %s -- %%s ."
"Format string to use in `cousel-projectile-grep-function' to
(defvar counsel-projectile-grep-base-command "grep -rnEI %s -- %%s %s"
"Format string to use in `cousel-projectile-grep' to
construct the command.")
(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)
"Grep for STRING in the current project."
(or (counsel-more-chars)
@ -636,11 +633,12 @@ construct the command.")
(insert (format "%d candidates:\n" (length cands)))
(ivy--occur-insert-lines cands)))
;;;###autoload
(defun counsel-projectile-grep (&optional options-or-cmd)
"Search the current project with grep.
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
additional options to be passed to grep, or an alternative git
@ -649,35 +647,30 @@ called with a prefix argument."
(interactive)
(if (and (eq (projectile-project-vcs) 'git)
projectile-use-git-grep)
(let ((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 options-or-cmd)
counsel-projectile-grep-initial-input))
(counsel-require-program (car (split-string counsel-projectile-grep-base-command)))
(let* ((ignored-files (mapconcat (lambda (i)
(concat "--exclude="
(shell-quote-argument i)
(counsel-projectile-git-grep options-or-cmd)
(let* ((path
(mapconcat 'shell-quote-argument
(projectile-normalise-paths
(car (projectile-parse-dirconfig-file)))
" "))
(projectile-ignored-files-rel)
""))
(ignored-dirs (mapconcat (lambda (i)
(concat "--exclude-dir="
(shell-quote-argument i)
(ignored-files
(mapconcat (lambda (i)
(concat "--exclude=" (shell-quote-argument i)))
(append
(projectile--globally-ignored-file-suffixes-glob)
(projectile-ignored-files-rel))
" "))
(ignored-dirs
(mapconcat (lambda (i)
(concat "--exclude-dir=" (shell-quote-argument i)))
(projectile-ignored-directories-rel)
" "))
(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)))
(ignored (concat ignored-files " " ignored-dirs))
(default-directory (projectile-project-root)))
(counsel-require-program
(car (split-string counsel-projectile-grep-base-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-read (projectile-prepend-project-name "grep")
#'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-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
(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"))
:group 'counsel-projectile)
(defvar counsel-projectile-ag-options-history nil
"History for `counsel-projectile-ag' options.")
;;;###autoload
(defun counsel-projectile-ag (&optional options)
"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
is called with a prefix argument."
(interactive)
(let* ((ignored (mapconcat (lambda (i)
(concat "--ignore "
(shell-quote-argument i)
(let* ((path (mapconcat 'shell-quote-argument
(projectile-normalise-paths
(car (projectile-parse-dirconfig-file)))
" "))
(append (projectile-ignored-files-rel)
(ignored
(mapconcat (lambda (i)
(concat "--ignore " (shell-quote-argument i)))
(append
(projectile--globally-ignored-file-suffixes-glob)
(projectile-ignored-files-rel)
(projectile-ignored-directories-rel))
" "))
(options
(if current-prefix-arg
(read-string (projectile-prepend-project-name "ag options: ")
ignored
'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)
(projectile-project-root)
options
(projectile-prepend-project-name "ag"))))
(projectile-prepend-project-name
(car (split-string counsel-ag-base-command))))))
;;* counsel-projectile-rg
@ -758,9 +775,6 @@ of `(ivy-thing-at-point)' by hitting \"M-n\" in the minibuffer."
(sexp :tag "Custom expression"))
:group 'counsel-projectile)
(defvar counsel-projectile-rg-options-history nil
"History for `counsel-projectile-rg' options.")
;;;###autoload
(defun counsel-projectile-rg (&optional options)
"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
is called with a prefix argument."
(interactive)
(let* ((ignored (mapconcat (lambda (i)
(concat "--glob "
(shell-quote-argument (concat "!" i))
(let* ((path
(mapconcat 'shell-quote-argument
(projectile-normalise-paths
(car (projectile-parse-dirconfig-file)))
" "))
(append (projectile-ignored-files-rel)
(ignored
(mapconcat (lambda (i)
(concat "--glob !" (shell-quote-argument i)))
(append
(projectile--globally-ignored-file-suffixes-glob)
(projectile-ignored-files-rel)
(projectile-ignored-directories-rel))
" "))
(options
(if current-prefix-arg
(read-string (projectile-prepend-project-name "rg options: ")
ignored
'counsel-projectile-rg-options-history)
(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)
(projectile-project-root)
options
(projectile-prepend-project-name "rg"))))
(projectile-prepend-project-name
(car (split-string counsel-rg-base-command))))))
;;* counsel-projectile-org-capture
@ -1044,6 +1062,8 @@ candidates list of `counsel-projectile-switch-project'."
"open project in vc-dir / magit / monky")
("sg" counsel-projectile-switch-project-action-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
"search project with ag")
("sr" counsel-projectile-switch-project-action-rg
@ -1179,17 +1199,22 @@ action."
(counsel-projectile-switch-project-by-name 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))
(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)
"Search PROJECT with `ag'."
"Search PROJECT with ag."
(let ((projectile-switch-project-action 'counsel-projectile-ag))
(counsel-projectile-switch-project-by-name 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))
(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-switch-project . counsel-projectile-switch-project)
(" " . counsel-projectile)
("si" . counsel-projectile-git-grep)
("Oc" . counsel-projectile-org-capture)
("Oa" . counsel-projectile-org-agenda))
"Alist of counsel-projectile key bindings.