new command: counsel-projectile-grep

This commit is contained in:
Eric Danan 2017-11-07 23:52:29 +01:00
parent 293a8f2f6a
commit 332e4c9817

View file

@ -62,6 +62,21 @@ candidates list of `counsel-projectile-switch-project'."
:type 'boolean :type 'boolean
:group 'counsel-projectile) :group 'counsel-projectile)
(defcustom counsel-projectile-grep-initial-input nil
"Initial minibuffer input for `counsel-projectile-grep'. If
non-nil, it should be a Lisp expression whose evaluation yields
the initial input string.
Note that you can always insert the value
of `(ivy-thing-at-point)' by hitting \"M-n\" in the minibuffer."
:type '(choice
(const :tag "None" nil)
(const :tag "Symbol at point (generic)" '(thing-at-point 'symbol t))
(const :tag "Symbol or selection at point (projectile)" '(projectile-symbol-or-selection-at-point))
(const :tag "Thing at point (ivy)" '(ivy-thing-at-point))
(sexp :tag "Custom expression"))
:group 'counsel-projectile)
(defcustom counsel-projectile-ag-initial-input nil (defcustom counsel-projectile-ag-initial-input nil
"Initial minibuffer input for `counsel-projectile-ag'. If "Initial minibuffer input for `counsel-projectile-ag'. If
non-nil, it should be a Lisp expression whose evaluation yields non-nil, it should be a Lisp expression whose evaluation yields
@ -203,6 +218,8 @@ afterwards to apply your changes."
"open in vc-dir / magit / monky") "open in vc-dir / magit / monky")
("e" counsel-projectile-switch-project-action-run-eshell ("e" counsel-projectile-switch-project-action-run-eshell
"start eshell") "start eshell")
("G" counsel-projectile-switch-project-action-grep
"search with grep")
("a" counsel-projectile-switch-project-action-ag ("a" counsel-projectile-switch-project-action-ag
"search with ag") "search with ag")
("R" counsel-projectile-switch-project-action-rg ("R" counsel-projectile-switch-project-action-rg
@ -391,6 +408,114 @@ names as in `ivy--buffer-list'."
'counsel-projectile-switch-to-buffer 'counsel-projectile-switch-to-buffer
'ivy-switch-buffer-transformer) 'ivy-switch-buffer-transformer)
;;; counsel-projectile-grep
(defvar counsel-projectile-grep-base-command "grep -rnE %s -- %%s ."
"Format string to use in `cousel-projectile-grep-function' to
construct the command.")
(defvar counsel-projectile-grep-base-command nil)
(defun counsel-projectile-grep-function (string)
"Grep in the current project for STRING."
(if (< (length string) 3)
(counsel-more-chars 3)
(let ((default-directory counsel--git-dir)
(regex (counsel-unquote-regex-parens
(setq ivy--old-re
(ivy--regex string)))))
(counsel--async-command (format counsel-projectile-grep-command
(shell-quote-argument regex)))
nil)))
(defun counsel-projectile-grep-transformer (str)
"Higlight file and line number in STR, first removing the
\"./\" prefix from the filename."
;; This makes the display consistent with `counsel-git-grep' and
;; `counsel-ag'-like commands.
(counsel-git-grep-transformer (string-remove-prefix "./" str)))
(defun counsel-projectile-grep-occur ()
"Generate a custom occur buffer for `counsel-projectile-grep'."
;; Copied from `counsel-grep-like-occur', except that we don't
;; prepend "./" to the candidates since grep already does so.
(unless (eq major-mode 'ivy-occur-grep-mode)
(ivy-occur-grep-mode)
(setq default-directory counsel--git-dir))
(setq ivy-text
(and (string-match "\"\\(.*\\)\"" (buffer-name))
(match-string 1 (buffer-name))))
(let* ((cmd (format counsel-projectile-grep-command
(shell-quote-argument
(counsel-unquote-regex-parens
(ivy--regex ivy-text)))))
(cands (split-string (shell-command-to-string cmd) "\n" t)))
;; Need precise number of header lines for `wgrep' to work.
(insert (format "-*- mode:grep; default-directory: %S -*-\n\n\n"
default-directory))
(insert (format "%d candidates:\n" (length cands)))
(ivy--occur-insert-lines cands)))
(defun counsel-projectile-grep (&optional options-or-cmd)
"Run a grep search in the project.
In a git project, use `counsel-git-grep'. In a non-git project,
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
grep command. It is read from the minibuffer if the function is
called with a prefix argument."
(interactive)
(if (projectile-project-p)
(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* ((options (if current-prefix-arg
(read-string "options: ")
options-or-cmd))
(ignored-files
(cl-union (projectile-ignored-files-rel) grep-find-ignored-files))
(ignored-dirs
(cl-union (projectile-ignored-directories-rel) grep-find-ignored-directories))
(options
(concat options " "
(mapconcat (lambda (i)
(concat "--exclude=" (shell-quote-argument i)))
ignored-files
" ")
" "
(mapconcat (lambda (i)
(concat "--exclude-dir=" (shell-quote-argument i)))
ignored-dirs
" "))))
(setq counsel-projectile-grep-command
(format counsel-projectile-grep-base-command options))
(ivy-set-prompt 'counsel-projectile-grep counsel-prompt-function)
(setq counsel--git-dir (projectile-project-root))
(ivy-read (projectile-prepend-project-name "grep")
#'counsel-projectile-grep-function
:initial-input counsel-projectile-grep-initial-input
:dynamic-collection t
:keymap counsel-ag-map
:history 'counsel-git-grep-history
:action #'counsel-git-grep-action
:unwind (lambda ()
(counsel-delete-process)
(swiper--cleanup))
:caller 'counsel-projectile-grep)))
(user-error "You're not in a project")))
(counsel-set-async-exit-code 'counsel-projectile-grep 1 "No matches found")
(ivy-set-occur 'counsel-projectile-grep 'counsel-projectile-grep-occur)
(ivy-set-display-transformer 'counsel-projectile-grep 'counsel-projectile-grep-transformer)
;;; counsel-projectile-ag ;;; counsel-projectile-ag
;;;###autoload ;;;###autoload
@ -545,6 +670,12 @@ in vc-dir / magit / monky."
(let ((projectile-switch-project-action 'projectile-run-eshell)) (let ((projectile-switch-project-action 'projectile-run-eshell))
(counsel-projectile-switch-project-action project))) (counsel-projectile-switch-project-action project)))
(defun counsel-projectile-switch-project-action-grep (project)
"Action for `counsel-projectile-switch-project' to search
PROJECT with `grep'."
(let ((projectile-switch-project-action 'counsel-projectile-ag))
(counsel-projectile-switch-project-action project)))
(defun counsel-projectile-switch-project-action-ag (project) (defun counsel-projectile-switch-project-action-ag (project)
"Action for `counsel-projectile-switch-project' to search "Action for `counsel-projectile-switch-project' to search
PROJECT with `ag'." PROJECT with `ag'."
@ -659,6 +790,9 @@ With a prefix ARG invalidates the cache first."
(def-projectile-commander-method ?b (def-projectile-commander-method ?b
"Switch to project buffer." "Switch to project buffer."
(counsel-projectile-switch-to-buffer)) (counsel-projectile-switch-to-buffer))
(def-projectile-commander-method ?g
"Run grep on project."
(counsel-projectile-grep))
(def-projectile-commander-method ?A (def-projectile-commander-method ?A
"Search project files with ag." "Search project files with ag."
(counsel-projectile-ag)) (counsel-projectile-ag))
@ -675,6 +809,7 @@ With a prefix ARG invalidates the cache first."
(define-key projectile-mode-map [remap projectile-find-file] #'counsel-projectile-find-file) (define-key projectile-mode-map [remap projectile-find-file] #'counsel-projectile-find-file)
(define-key projectile-mode-map [remap projectile-find-dir] #'counsel-projectile-find-dir) (define-key projectile-mode-map [remap projectile-find-dir] #'counsel-projectile-find-dir)
(define-key projectile-mode-map [remap projectile-switch-project] #'counsel-projectile-switch-project) (define-key projectile-mode-map [remap projectile-switch-project] #'counsel-projectile-switch-project)
(define-key projectile-mode-map [remap projectile-grep] #'counsel-projectile-grep)
(define-key projectile-mode-map [remap projectile-ag] #'counsel-projectile-ag) (define-key projectile-mode-map [remap projectile-ag] #'counsel-projectile-ag)
(define-key projectile-mode-map [remap projectile-switch-to-buffer] #'counsel-projectile-switch-to-buffer) (define-key projectile-mode-map [remap projectile-switch-to-buffer] #'counsel-projectile-switch-to-buffer)
(counsel-projectile-commander-bindings)) (counsel-projectile-commander-bindings))
@ -684,6 +819,7 @@ With a prefix ARG invalidates the cache first."
(define-key projectile-mode-map [remap projectile-find-file] nil) (define-key projectile-mode-map [remap projectile-find-file] nil)
(define-key projectile-mode-map [remap projectile-find-dir] nil) (define-key projectile-mode-map [remap projectile-find-dir] nil)
(define-key projectile-mode-map [remap projectile-switch-project] nil) (define-key projectile-mode-map [remap projectile-switch-project] nil)
(define-key projectile-mode-map [remap projectile-grep] nil)
(define-key projectile-mode-map [remap projectile-ag] nil) (define-key projectile-mode-map [remap projectile-ag] nil)
(define-key projectile-mode-map [remap projectile-switch-to-buffer] nil) (define-key projectile-mode-map [remap projectile-switch-to-buffer] nil)
(projectile-commander-bindings)))) (projectile-commander-bindings))))