Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix grep #1371

Merged
merged 10 commits into from
Jan 16, 2019
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## master (unreleased)

### Bugs fixed

* [#97](https://github.com/bbatsov/projectile/issues/97): Respect `.projectile`
ignores which are paths to files and patterns when using `projectile-grep`.

## 2.0.0 (2019-01-01)

### New features
Expand Down
157 changes: 144 additions & 13 deletions projectile.el
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
(require 'compile)
(require 'grep)
(eval-when-compile
(require 'find-dired)
(require 'subr-x))

(eval-when-compile
Expand Down Expand Up @@ -965,7 +966,7 @@ Invoked automatically when `projectile-mode' is enabled."
(mapcar #'projectile-discover-projects-in-directory projectile-project-search-path))


(defun delete-file-projectile-remove-from-cache (filename &optional trash)
(defun delete-file-projectile-remove-from-cache (filename &optional _trash)
(if (and projectile-enable-caching projectile-auto-update-cache (projectile-project-p))
(let* ((project-root (projectile-project-root))
(true-filename (file-truename filename))
Expand Down Expand Up @@ -1262,7 +1263,7 @@ they are excluded from the results of this function."
submodule))
submodules)))

(defun projectile-get-sub-projects-files (project-root vcs)
(defun projectile-get-sub-projects-files (project-root _vcs)
"Get files from sub-projects for PROJECT-ROOT recursively."
(projectile-flatten
(mapcar (lambda (sub-project)
Expand Down Expand Up @@ -2806,6 +2807,128 @@ This is a subset of `grep-read-files', where either a matching entry from
(format " (default %s)" default-value))))
(read-string (format "%s%s: " prefix-label default-label) nil nil default-value)))

(defvar projectile-grep-find-ignored-paths)
(defvar projectile-grep-find-unignored-paths)
(defvar projectile-grep-find-ignored-patterns)
(defvar projectile-grep-find-unignored-patterns)

(defun projectile-rgrep-default-command (regexp files dir)
"Compute the command for \\[rgrep] to use by default.

Extension of the Emacs 25.1 implementation of `rgrep-default-command', with
which it shares its arglist."
(require 'find-dired) ; for `find-name-arg'
(grep-expand-template
grep-find-template
regexp
(concat (shell-quote-argument "(")
" " find-name-arg " "
(mapconcat
#'shell-quote-argument
(split-string files)
(concat " -o " find-name-arg " "))
" "
(shell-quote-argument ")"))
dir
(concat
(and grep-find-ignored-directories
(concat "-type d "
(shell-quote-argument "(")
;; we should use shell-quote-argument here
" -path "
(mapconcat
'identity
(delq nil (mapcar
#'(lambda (ignore)
(cond ((stringp ignore)
(shell-quote-argument
(concat "*/" ignore)))
((consp ignore)
(and (funcall (car ignore) dir)
(shell-quote-argument
(concat "*/"
(cdr ignore)))))))
grep-find-ignored-directories))
" -o -path ")
" "
(shell-quote-argument ")")
" -prune -o "))
(and grep-find-ignored-files
(concat (shell-quote-argument "!") " -type d "
(shell-quote-argument "(")
;; we should use shell-quote-argument here
" -name "
(mapconcat
#'(lambda (ignore)
(cond ((stringp ignore)
(shell-quote-argument ignore))
((consp ignore)
(and (funcall (car ignore) dir)
(shell-quote-argument
(cdr ignore))))))
grep-find-ignored-files
" -o -name ")
" "
(shell-quote-argument ")")
" -prune -o "))
(and projectile-grep-find-ignored-paths
(concat (shell-quote-argument "(")
" -path "
(mapconcat
(lambda (ignore) (shell-quote-argument
(concat "./" ignore)))
projectile-grep-find-ignored-paths
" -o -path ")
" "
(shell-quote-argument ")")
" -prune -o "))
(and projectile-grep-find-ignored-patterns
(concat (shell-quote-argument "(")
(and (or projectile-grep-find-unignored-paths
projectile-grep-find-unignored-patterns)
(concat " "
(shell-quote-argument "(")))
" -path "
(mapconcat
(lambda (ignore)
(shell-quote-argument
(if (string-prefix-p "*" ignore) ignore
(concat "*/" ignore))))
projectile-grep-find-ignored-patterns
" -o -path ")
(and (or projectile-grep-find-unignored-paths
projectile-grep-find-unignored-patterns)
(concat " "
(shell-quote-argument ")")
" -a "
(shell-quote-argument "!")
" "
(shell-quote-argument "(")
(and projectile-grep-find-unignored-paths
(concat " -path "
(mapconcat
(lambda (ignore) (shell-quote-argument
(concat "./" ignore)))
projectile-grep-find-unignored-paths
" -o -path ")))
(and projectile-grep-find-unignored-paths
projectile-grep-find-unignored-patterns
" -o")
(and projectile-grep-find-unignored-patterns
(concat " -path "
(mapconcat
(lambda (ignore)
(shell-quote-argument
(if (string-prefix-p "*" ignore) ignore
(concat "*/" ignore))))
projectile-grep-find-unignored-patterns
" -o -path ")))
" "
(shell-quote-argument ")")))
" "
(shell-quote-argument ")")
" -prune -o ")))))

;;;###autoload
(defun projectile-grep (&optional regexp arg)
"Perform rgrep in the project.
Expand All @@ -2832,18 +2955,26 @@ With REGEXP given, don't query the user for a regexp."
(fboundp 'vc-git-grep))
(vc-git-grep search-regexp (or files "") root-dir)
;; paths for find-grep should relative and without trailing /
(let ((grep-find-ignored-directories
(cl-union (mapcar (lambda (f) (directory-file-name (file-relative-name f root-dir)))
(projectile-ignored-directories))
grep-find-ignored-directories))
(grep-find-ignored-files
(cl-union (append (mapcar (lambda (file)
(file-relative-name file root-dir))
(projectile-ignored-files))
(projectile--globally-ignored-file-suffixes-glob))
grep-find-ignored-files)))
(let ((grep-find-ignored-files
(cl-union (projectile--globally-ignored-file-suffixes-glob)
grep-find-ignored-files))
(projectile-grep-find-ignored-paths
(append (mapcar (lambda (f) (directory-file-name (file-relative-name f root-dir)))
(projectile-ignored-directories))
(mapcar (lambda (file)
(file-relative-name file root-dir))
(projectile-ignored-files))))
(projectile-grep-find-unignored-paths
(append (mapcar (lambda (f) (directory-file-name (file-relative-name f root-dir)))
(projectile-unignored-directories))
(mapcar (lambda (file)
(file-relative-name file root-dir))
(projectile-unignored-files))))
(projectile-grep-find-ignored-patterns (projectile-patterns-to-ignore))
(projectile-grep-find-unignored-patterns (projectile-patterns-to-ensure)))
(grep-compute-defaults)
(rgrep search-regexp (or files "* .*") root-dir))))
(cl-letf (((symbol-function 'rgrep-default-command) #'projectile-rgrep-default-command))
(rgrep search-regexp (or files "* .*") root-dir)))))
(run-hooks 'projectile-grep-finished-hook)))

;;;###autoload
Expand Down
54 changes: 54 additions & 0 deletions test/projectile-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,60 @@ test temp directory"
(expect (projectile-project-root) :to-equal correct-project-root))))))

(describe "projectile-grep"
(describe "rgrep"
(before-each
(spy-on 'compilation-start))
(it "excludes global ignores"
(projectile-test-with-sandbox
(projectile-test-with-files
("project/"
"project/.projectile")
(cd "project")
(with-current-buffer (find-file-noselect ".projectile" t)
(let ((grep-find-template "<X>")
(grep-find-ignored-directories '("IG_DIR"))
(grep-find-ignored-files '("IG_FILE"))
(projectile-globally-ignored-files '("GLOB_IG_FILE"))
(projectile-globally-ignored-file-suffixes '("IG_SUF"))
(projectile-globally-ignored-directories '("GLOB_IG_DIR")))
(projectile-grep "hi")))
(expect 'compilation-start :to-have-been-called-with
(concat "-type d \\( -path \\*/IG_DIR \\) -prune -o "
"\\! -type d \\( -name IG_FILE -o -name \\*IG_SUF \\) -prune -o "
"\\( -path ./GLOB_IG_DIR -o -path ./GLOB_IG_FILE \\) -prune -o ")
'grep-mode))))
(it "excludes project ignores"
(projectile-test-with-sandbox
(projectile-test-with-files
("project/bar/"
"project/baz/")
(cd "project")
(with-temp-file ".projectile" (insert (concat "-/*.txt\n"
"-/bar/*.txt\n"
"-/baz\n"
"-*.txt\n"
"-*.text\n"
"!/abc.txt\n"
"!/bar/abc.txt\n"
"!def.txt\n")))
(with-temp-file "foo.txt")
(with-temp-file "abc.txt")
(with-temp-file "bar/foo.txt")
(with-temp-file "bar/abc.txt")
(with-current-buffer (find-file-noselect ".projectile" t)
(let ((grep-find-template "<X>")
grep-find-ignored-directories grep-find-ignored-files
projectile-globally-ignored-files
projectile-globally-ignored-file-suffixes
projectile-globally-ignored-directories)
(projectile-grep "hi")))
(expect 'compilation-start :to-have-been-called-with
(concat "\\( -path ./baz -o -path ./foo.txt -o -path ./bar/foo.txt \\) -prune -o "
"\\( "
"\\( -path \\*.txt -o -path \\*.text \\) "
"-a \\! \\( -path ./abc.txt -o -path ./bar/abc.txt -o -path \\*/def.txt \\) "
"\\) -prune -o ")
'grep-mode)))))
(it "grep a git project using default files"
(require 'vc-git)
(projectile-test-with-sandbox
Expand Down