From e0ba1ba1d3bf68f44e0aa8e315edc64c5bf423a9 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Mon, 25 Dec 2017 00:44:35 -0500 Subject: [PATCH 01/10] add rg-dwim-regexp --- rg.el | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/rg.el b/rg.el index c14be78..92942f8 100644 --- a/rg.el +++ b/rg.el @@ -1007,6 +1007,13 @@ prefix is not supplied `rg-keymap-prefix' is used." (message "Global key bindings for `rg' enabled with prefix: %s" (edmacro-format-keys prefix)))) +;;;###autoload +(defun rg-run-in-project (regexp files) + (let ((root (rg-project-root buffer-file-name))) + (if root + (rg-run regexp files root) + (signal 'user-error '("No project root found"))))) + ;;;###autoload (defun rg-project (regexp files) "Run ripgrep in current project searching for REGEXP in FILES. @@ -1018,10 +1025,18 @@ version control system." (let* ((regexp (rg-read-pattern)) (files (rg-read-files regexp))) (list regexp files)))) - (let ((root (rg-project-root buffer-file-name))) - (if root - (rg-run regexp files root) - (signal 'user-error '("No project root found"))))) + (rg-run-in-project regexp files)) + +;;;###autoload +(defun rg-dwim-regexp (regexp) + "Run ripgrep in current project searching for REGEXP in files +like the current file" + (interactive + (progn + (let* ((regexp (rg-read-pattern))) + (list regexp)))) + (let ((files (car (rg-default-alias)))) + (rg-run-in-project regexp files))) ;;;###autoload (defun rg-dwim (&optional curdir) From df18cec5660485a451839e447453289c79bf6449 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Mon, 25 Dec 2017 15:51:39 -0500 Subject: [PATCH 02/10] add docstrings --- rg.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rg.el b/rg.el index 92942f8..65399d5 100644 --- a/rg.el +++ b/rg.el @@ -1007,8 +1007,8 @@ prefix is not supplied `rg-keymap-prefix' is used." (message "Global key bindings for `rg' enabled with prefix: %s" (edmacro-format-keys prefix)))) -;;;###autoload (defun rg-run-in-project (regexp files) + "Search for `REGEXP' in files of type `FILES' starting at the rg-project-root." (let ((root (rg-project-root buffer-file-name))) (if root (rg-run regexp files root) @@ -1029,8 +1029,7 @@ version control system." ;;;###autoload (defun rg-dwim-regexp (regexp) - "Run ripgrep in current project searching for REGEXP in files -like the current file" + "Run ripgrep in current project searching for REGEXP in files like the current file." (interactive (progn (let* ((regexp (rg-read-pattern))) From 9ca4eda6dac82f327a48e190b172f1d768c106a0 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Mon, 25 Dec 2017 16:23:00 -0500 Subject: [PATCH 03/10] add test for rg-dwim-regexp --- test/rg.el-test.el | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/rg.el-test.el b/test/rg.el-test.el index 7bb22ec..d04acab 100644 --- a/test/rg.el-test.el +++ b/test/rg.el-test.el @@ -651,6 +651,26 @@ and ungrouped otherwise." (rg-dwim 'curdir) (should (equal (expand-file-name called-dir) (expand-file-name default-directory))))) +(ert-deftest rg-integration/dwim-regexp-search () + "Test `rg-dwim-regexp'." + (cl-letf ((called-pattern nil) + (called-files nil) + (called-dir nil) + (called-literal nil) + (project-dir (expand-file-name default-directory)) + ((symbol-function #'rg-run) + (lambda (pattern files dir &optional literal _) + (setq called-pattern pattern) + (setq called-files files) + (setq called-dir dir) + (setq called-literal literal)))) + (find-file "test/data/foo.el") + (rg-dwim-regexp "hello") + (should (equal called-pattern "hello")) + (should (equal called-files "elisp")) + (should (equal (expand-file-name called-dir) project-dir)) + (should (eq called-literal nil)))) + (ert-deftest rg-integration/project-search () "Test `rg-project'." (cl-letf ((called-pattern nil) From 64d7bf0042f0cec92b55a75d741197964663aa66 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Sat, 6 Jan 2018 22:22:24 -0500 Subject: [PATCH 04/10] add a macro to define search configurations --- rg.el | 171 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 107 insertions(+), 64 deletions(-) diff --git a/rg.el b/rg.el index 65399d5..0f87cf5 100644 --- a/rg.el +++ b/rg.el @@ -409,12 +409,13 @@ If LITERAL is non nil prompt for literal pattern." nil default-directory t))) (list pattern files dir))) -(defun rg-read-files (pattern) +(defun rg-read-files (&optional pattern) "Read files argument for interactive rg. PATTERN is the search string." - (let ((default-alias (rg-default-alias))) + (let ((default-alias (rg-default-alias)) + (pattern-string (if pattern (concat "for \"" pattern "\" ") + ""))) (completing-read - (concat "Search for \"" pattern - "\" in files" + (concat "Search " pattern-string "in files" (if default-alias (concat " (default: [" (car default-alias) "] = " @@ -1007,81 +1008,123 @@ prefix is not supplied `rg-keymap-prefix' is used." (message "Global key bindings for `rg' enabled with prefix: %s" (edmacro-format-keys prefix)))) -(defun rg-run-in-project (regexp files) - "Search for `REGEXP' in files of type `FILES' starting at the rg-project-root." - (let ((root (rg-project-root buffer-file-name))) - (if root - (rg-run regexp files root) - (signal 'user-error '("No project root found"))))) +(defun rg-set-search-defaults (args) + (if (not (plist-get args :pattern)) (plist-put args :pattern 'regexp) + args)) + +(defun rg-search-parse-local-bindings (search-cfg) + (let* ((binding-list `((confirm ,(plist-get search-cfg :confirm)))) + (pattern-opt (plist-get search-cfg :pattern)) + (literal (or (eq pattern-opt 'literal) + (eq pattern-opt 'point))) + (alias-opt (plist-get search-cfg :files)) + (dir-opt (plist-get search-cfg :dir))) + + ;; literal binding + (setq binding-list (append binding-list `((literal ,literal)))) + + ;; pattern binding + (when (not (or (eq pattern-opt 'literal) + (eq pattern-opt 'regexp))) + (let ((pattern (cond ((eq pattern-opt 'point) '(grep-tag-default)) + (t pattern-opt)))) + (setq binding-list (append binding-list `((pattern ,pattern)))))) + + ;; dir binding + (when dir-opt + (let ((dirs (cond ((eq dir-opt 'project) '(rg-project-root + buffer-file-name)) + ((eq dir-opt 'current) 'default-directory) + (t dir-opt)))) + (setq binding-list (append binding-list `((dir ,dirs)))))) + + ;; file alias binding + (when alias-opt + (let ((files (if (eq alias-opt 'current) '(car (rg-default-alias)) + alias-opt))) + (setq binding-list (append binding-list `((files ,files)))))) + + binding-list)) + +(defun rg-search-parse-interactive-pattern-arg (search-cfg) + (let* ((opt (plist-get search-cfg :pattern)) + (literal (eq opt 'literal))) + (when (not (eq opt 'point)) + (cond ((not opt) `((pattern . (rg-read-pattern nil ,literal)))) + (t `((pattern . ,opt))))))) + +(defun rg-search-parse-interactive-file-alias-arg (search-cfg) + (when (not (plist-get search-cfg :files)) + '((files . (rg-read-files))))) + +(defun rg-search-parse-interactive-dir-arg (search-cfg) + (when (not (plist-get search-cfg :dir)) + '((dir . (read-directory-name + "In directory: " nil default-directory t))))) + +(defun rg-search-parse-interactive-args (search-cfg) + (let* ((iargs '())) + (setq iargs + (append iargs (rg-search-parse-interactive-pattern-arg search-cfg))) + (setq iargs + (append iargs (rg-search-parse-interactive-file-alias-arg + search-cfg))) + (setq iargs + (append iargs (rg-search-parse-interactive-dir-arg search-cfg))) + + iargs)) ;;;###autoload -(defun rg-project (regexp files) - "Run ripgrep in current project searching for REGEXP in FILES. -The project root will will be determined by either common project -packages like projectile and `find-file-in-project' or the source -version control system." - (interactive - (progn - (let* ((regexp (rg-read-pattern)) - (files (rg-read-files regexp))) - (list regexp files)))) - (rg-run-in-project regexp files)) +(defmacro rg-define-search (name &rest args) + (let* ((search-cfg (rg-set-search-defaults args)) + (local-bindings (rg-search-parse-local-bindings search-cfg)) + (iargs (rg-search-parse-interactive-args search-cfg))) + `(defun ,name ,(mapcar 'car iargs) + (interactive + (list ,(mapcar 'cdr iargs))) + (let* ,local-bindings + (rg-run pattern files dir literal confirm))))) ;;;###autoload -(defun rg-dwim-regexp (regexp) - "Run ripgrep in current project searching for REGEXP in files like the current file." - (interactive - (progn - (let* ((regexp (rg-read-pattern))) - (list regexp)))) - (let ((files (car (rg-default-alias)))) - (rg-run-in-project regexp files))) +(rg-define-search rg-project + :dir project) + +;;;###autoload +(rg-define-search rg-dwim-project-dir + :pattern point + :files current + :dir project) + +;;;###autoload +(rg-define-search rg-dwim-current-dir + :pattern point + :files current + :dir current) ;;;###autoload (defun rg-dwim (&optional curdir) "Run ripgrep without user interaction figuring out the intention by magic(!). The default magic searches for thing at point in files matching current file under project root directory. - With \\[universal-argument] prefix (CURDIR), search is done in current dir instead of project root." (interactive "P") - (let* ((literal (grep-tag-default)) - (files (car (rg-default-alias))) - (dir (or (when curdir default-directory) - (rg-project-root buffer-file-name)))) - (rg-run literal files dir 'literal))) - -(defun rg-literal (pattern files dir &optional confirm) - "Run ripgrep, searching for literal PATTERN in FILES in directory DIR. -With \\[universal-argument] prefix (CONFIRM), you can edit the -constructed shell command line before it is executed." - (interactive - (progn - (append (rg-read-input 'literal) - (list (equal current-prefix-arg '(4)))))) - (rg-run pattern files dir 'literal confirm)) + (if curdir + (rg-dwim-current-dir) + (rg-dwim-project-dir))) + + +;;;###autoload +(rg-define-search rg-dwim-regexp + :files current + :dir project) + +;;;###autoload +(rg-define-search rg-literal + :pattern literal) ;;;###autoload -(defun rg (regexp files dir &optional confirm) - "Run ripgrep, searching for REGEXP in FILES in directory DIR. -The search is limited to file names matching shell pattern FILES. -FILES may use abbreviations defined in `rg-custom-type-aliases' or -ripgrep builtin type aliases, e.g. entering `elisp' is equivalent to `*.el'. - -REGEXP is a regexp as defined by the ripgrep executable. - -With \\[universal-argument] prefix (CONFIRM), you can edit the -constructed shell command line before it is executed. - -Collect output in a buffer. While ripgrep runs asynchronously, you -can use \\[next-error] (M-x `next-error'), or \\\\[compile-goto-error] \ -in the rg output buffer, to go to the lines where rg found matches." - (interactive - (progn - (append (rg-read-input) - (list (equal current-prefix-arg '(4)))))) - (rg-run regexp files dir nil confirm)) +(rg-define-search rg) (provide 'rg) From 9a24e3a333ee1318d4f0165e154d8dae41d32a9c Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Sun, 7 Jan 2018 20:51:02 -0500 Subject: [PATCH 05/10] allow rg-define-search to take an optional docstring --- rg.el | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/rg.el b/rg.el index 0f87cf5..a24b617 100644 --- a/rg.el +++ b/rg.el @@ -1053,33 +1053,36 @@ prefix is not supplied `rg-keymap-prefix' is used." (cond ((not opt) `((pattern . (rg-read-pattern nil ,literal)))) (t `((pattern . ,opt))))))) -(defun rg-search-parse-interactive-file-alias-arg (search-cfg) - (when (not (plist-get search-cfg :files)) - '((files . (rg-read-files))))) - -(defun rg-search-parse-interactive-dir-arg (search-cfg) - (when (not (plist-get search-cfg :dir)) - '((dir . (read-directory-name - "In directory: " nil default-directory t))))) - (defun rg-search-parse-interactive-args (search-cfg) - (let* ((iargs '())) + (let* ((dir-opt (plist-get search-cfg :dir)) + (files-opt (plist-get search-cfg :files)) + (iargs '())) + (setq iargs (append iargs (rg-search-parse-interactive-pattern-arg search-cfg))) - (setq iargs - (append iargs (rg-search-parse-interactive-file-alias-arg - search-cfg))) - (setq iargs - (append iargs (rg-search-parse-interactive-dir-arg search-cfg))) + + (when (not files-opt) + (setq iargs + (append iargs '((files . (rg-read-files)))))) + + (when (not dir-opt) + (setq iargs + (append iargs + '((dir . (read-directory-name + "In directory: " nil default-directory t)))))) + iargs)) ;;;###autoload (defmacro rg-define-search (name &rest args) - (let* ((search-cfg (rg-set-search-defaults args)) + (let* ((body (macroexp-parse-body args)) + (docstring (car body)) + (search-cfg (rg-set-search-defaults (cdr body))) (local-bindings (rg-search-parse-local-bindings search-cfg)) (iargs (rg-search-parse-interactive-args search-cfg))) `(defun ,name ,(mapcar 'car iargs) + ,@docstring (interactive (list ,(mapcar 'cdr iargs))) (let* ,local-bindings @@ -1109,11 +1112,9 @@ current file under project root directory. With \\[universal-argument] prefix (CURDIR), search is done in current dir instead of project root." (interactive "P") - (if curdir - (rg-dwim-current-dir) + (if curdir (rg-dwim-current-dir) (rg-dwim-project-dir))) - ;;;###autoload (rg-define-search rg-dwim-regexp :files current From 7a1a87554633d262db0436afd24bc68969d6b3c6 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Mon, 8 Jan 2018 22:43:57 -0500 Subject: [PATCH 06/10] add some docstrings. --- rg.el | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/rg.el b/rg.el index a24b617..204e607 100644 --- a/rg.el +++ b/rg.el @@ -1090,27 +1090,35 @@ prefix is not supplied `rg-keymap-prefix' is used." ;;;###autoload (rg-define-search rg-project - :dir project) + "Run ripgrep in current project searching for REGEXP in FILES. +The project root will will be determined by either common project +packages like projectile and `find-file-in-project' or the source +version control system." + :dir project) ;;;###autoload (rg-define-search rg-dwim-project-dir - :pattern point - :files current - :dir project) + "Search for thing at point in files matching the current file +under the project root directory." + :pattern point + :files current + :dir project) ;;;###autoload (rg-define-search rg-dwim-current-dir - :pattern point - :files current - :dir current) + "Search for thing at point in files matching the current file +under the current directory." + :pattern point + :files current + :dir current) ;;;###autoload (defun rg-dwim (&optional curdir) - "Run ripgrep without user interaction figuring out the intention by magic(!). -The default magic searches for thing at point in files matching -current file under project root directory. -With \\[universal-argument] prefix (CURDIR), search is done in current dir -instead of project root." + "Run ripgrep without user interaction figuring out the +intention by magic(!). The default magic searches for thing at +point in files matching current file under project root +directory. With \\[universal-argument] prefix (CURDIR), search is +done in current dir instead of project root." (interactive "P") (if curdir (rg-dwim-current-dir) (rg-dwim-project-dir))) @@ -1125,7 +1133,18 @@ instead of project root." :pattern literal) ;;;###autoload -(rg-define-search rg) +(rg-define-search rg + "Run ripgrep, searching for REGEXP in FILES in directory DIR. +The search is limited to file names matching shell pattern FILES. +FILES may use abbreviations defined in `rg-custom-type-aliases' +or ripgrep builtin type aliases, e.g. entering `elisp' is +equivalent to `*.el'. REGEXP is a regexp as defined by the +ripgrep executable. With \\[universal-argument] prefix (CONFIRM), +you can edit the constructed shell command line before it is +executed. Collect output in a buffer. While ripgrep runs +asynchronously, you can use \\[next-error] (M-x `next-error'), or +\\\\[compile-goto-error] \ in the rg output +buffer, to go to the lines where rg found matches.") (provide 'rg) From a3b91dfd26798df3d42c5f413f3ee044c90775c2 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Sat, 13 Jan 2018 08:00:36 -0500 Subject: [PATCH 07/10] split pattern arg; docstrings; cleanup --- rg.el | 138 +++++++++++++++++++++++++++------------------ test/rg.el-test.el | 20 ------- 2 files changed, 82 insertions(+), 76 deletions(-) diff --git a/rg.el b/rg.el index 204e607..f519490 100644 --- a/rg.el +++ b/rg.el @@ -400,15 +400,6 @@ included." (rg-get-type-aliases t))) '("all" . "*")))) -(defun rg-read-input (&optional literal) - "Prompt user for input and return a list of the results. -If LITERAL is non nil prompt for literal pattern." - (let* ((pattern (rg-read-pattern nil literal)) - (files (rg-read-files pattern)) - (dir (read-directory-name "In directory: " - nil default-directory t))) - (list pattern files dir))) - (defun rg-read-files (&optional pattern) "Read files argument for interactive rg. PATTERN is the search string." (let ((default-alias (rg-default-alias)) @@ -1008,27 +999,49 @@ prefix is not supplied `rg-keymap-prefix' is used." (message "Global key bindings for `rg' enabled with prefix: %s" (edmacro-format-keys prefix)))) +(defun rg-search-parse-body (args) + "Parse a function ARGS into (DECLARATIONS . EXPS)." + (let ((decls ())) + (while (and (cdr args) + (let ((e (car args))) + (or (stringp e) + (memq (car-safe e) + '(:documentation declare interactive cl-declare))))) + (push (pop args) decls)) + (cons (nreverse decls) args))) + (defun rg-set-search-defaults (args) - (if (not (plist-get args :pattern)) (plist-put args :pattern 'regexp) - args)) + "Set defaults for required search options missing from ARGS. +If the :format option is missing, set it to 'regexp, and if +the :query option is missing, set it to 'ask" + (unless (plist-get args :format) + (setq args (plist-put args :format 'regexp))) + + (unless (plist-get args :query) + (setq args (plist-put args :query 'ask))) + + args) (defun rg-search-parse-local-bindings (search-cfg) - (let* ((binding-list `((confirm ,(plist-get search-cfg :confirm)))) - (pattern-opt (plist-get search-cfg :pattern)) - (literal (or (eq pattern-opt 'literal) - (eq pattern-opt 'point))) + "Parse local bindings for search functions from SEARCH-CFG." + (let* ((format-opt (plist-get search-cfg :format)) + (query-opt (plist-get search-cfg :query)) (alias-opt (plist-get search-cfg :files)) - (dir-opt (plist-get search-cfg :dir))) + (dir-opt (plist-get search-cfg :dir)) + (binding-list `((literal ,(eq format-opt 'literal))))) + + ;; confirm binding + (cond ((eq confirm-opt 'never) + (setq binding-list (append binding-list `((confirm nil)))) - ;; literal binding - (setq binding-list (append binding-list `((literal ,literal)))) + (eq confirm-opt 'always) + (setq binding-list (append binding-list `((confirm t)))))) - ;; pattern binding - (when (not (or (eq pattern-opt 'literal) - (eq pattern-opt 'regexp))) - (let ((pattern (cond ((eq pattern-opt 'point) '(grep-tag-default)) - (t pattern-opt)))) - (setq binding-list (append binding-list `((pattern ,pattern)))))) + ;; query binding + (unless (eq query-opt 'ask) + (let ((query (cond ((eq query-opt 'point) '(grep-tag-default)) + (t query-opt)))) + (setq binding-list (append binding-list `((query ,query)))))) ;; dir binding (when dir-opt @@ -1040,32 +1053,36 @@ prefix is not supplied `rg-keymap-prefix' is used." ;; file alias binding (when alias-opt - (let ((files (if (eq alias-opt 'current) '(car (rg-default-alias)) + (let ((files (if (eq alias-opt 'current) + '(car (rg-default-alias)) alias-opt))) (setq binding-list (append binding-list `((files ,files)))))) binding-list)) -(defun rg-search-parse-interactive-pattern-arg (search-cfg) - (let* ((opt (plist-get search-cfg :pattern)) - (literal (eq opt 'literal))) - (when (not (eq opt 'point)) - (cond ((not opt) `((pattern . (rg-read-pattern nil ,literal)))) - (t `((pattern . ,opt))))))) - (defun rg-search-parse-interactive-args (search-cfg) - (let* ((dir-opt (plist-get search-cfg :dir)) + "Parse interactive args from SEARCH-CFG for search functions." + (let* ((confirm-opt (plist-get search-cfg :confirm)) + (query-opt (plist-get search-cfg :query)) + (format-opt (plist-get search-cfg :format)) + (literal (eq format-opt 'literal)) + (dir-opt (plist-get search-cfg :dir)) (files-opt (plist-get search-cfg :files)) (iargs '())) - (setq iargs - (append iargs (rg-search-parse-interactive-pattern-arg search-cfg))) + (when (eq confirm-opt 'prefix) + (setq iargs (append iargs '((confirm . (equal current-prefix-arg + '(4))))))) + + (when (eq query-opt 'ask) + (setq iargs + (append iargs `((query . (rg-read-pattern nil ,literal)))))) - (when (not files-opt) + (unless files-opt (setq iargs (append iargs '((files . (rg-read-files)))))) - (when (not dir-opt) + (unless dir-opt (setq iargs (append iargs '((dir . (read-directory-name @@ -1076,17 +1093,23 @@ prefix is not supplied `rg-keymap-prefix' is used." ;;;###autoload (defmacro rg-define-search (name &rest args) - (let* ((body (macroexp-parse-body args)) - (docstring (car body)) + "Define an rg search functions named NAME. +ARGS is a search specification with `:query' (point or ask), +`:format' (literal or regexp), `files' (rg or custom file alias), +`dir' (root search directory), and `confirm' as allowable options +specifying the behavior of the search function." + (declare (indent defun)) + (let* ((body (rg-search-parse-body args)) + (decls (car body)) (search-cfg (rg-set-search-defaults (cdr body))) (local-bindings (rg-search-parse-local-bindings search-cfg)) (iargs (rg-search-parse-interactive-args search-cfg))) `(defun ,name ,(mapcar 'car iargs) - ,@docstring + ,@decls (interactive - (list ,(mapcar 'cdr iargs))) - (let* ,local-bindings - (rg-run pattern files dir literal confirm))))) + (list ,@(mapcar 'cdr iargs))) + (let ,local-bindings + (rg-run query files dir literal confirm))))) ;;;###autoload (rg-define-search rg-project @@ -1100,7 +1123,8 @@ version control system." (rg-define-search rg-dwim-project-dir "Search for thing at point in files matching the current file under the project root directory." - :pattern point + :query point + :format literal :files current :dir project) @@ -1108,29 +1132,30 @@ under the project root directory." (rg-define-search rg-dwim-current-dir "Search for thing at point in files matching the current file under the current directory." - :pattern point + :query point + :format literal :files current :dir current) ;;;###autoload (defun rg-dwim (&optional curdir) - "Run ripgrep without user interaction figuring out the -intention by magic(!). The default magic searches for thing at + "Run ripgrep without user interaction figuring out the intention by magic(!). +The default magic searches for thing at point in files matching current file under project root -directory. With \\[universal-argument] prefix (CURDIR), search is +directory. With \\[universal-argument] prefix (CURDIR), search is done in current dir instead of project root." (interactive "P") - (if curdir (rg-dwim-current-dir) + (if curdir + (rg-dwim-current-dir) (rg-dwim-project-dir))) -;;;###autoload -(rg-define-search rg-dwim-regexp - :files current - :dir project) - ;;;###autoload (rg-define-search rg-literal - :pattern literal) + "Run ripgrep, searching for literal PATTERN in FILES in directory DIR. +With \\[universal-argument] prefix (CONFIRM), you can edit the +constructed shell command line before it is executed." + :format literal + :confirm prefix) ;;;###autoload (rg-define-search rg @@ -1144,7 +1169,8 @@ you can edit the constructed shell command line before it is executed. Collect output in a buffer. While ripgrep runs asynchronously, you can use \\[next-error] (M-x `next-error'), or \\\\[compile-goto-error] \ in the rg output -buffer, to go to the lines where rg found matches.") +buffer, to go to the lines where rg found matches." + :confirm prefix) (provide 'rg) diff --git a/test/rg.el-test.el b/test/rg.el-test.el index d04acab..7bb22ec 100644 --- a/test/rg.el-test.el +++ b/test/rg.el-test.el @@ -651,26 +651,6 @@ and ungrouped otherwise." (rg-dwim 'curdir) (should (equal (expand-file-name called-dir) (expand-file-name default-directory))))) -(ert-deftest rg-integration/dwim-regexp-search () - "Test `rg-dwim-regexp'." - (cl-letf ((called-pattern nil) - (called-files nil) - (called-dir nil) - (called-literal nil) - (project-dir (expand-file-name default-directory)) - ((symbol-function #'rg-run) - (lambda (pattern files dir &optional literal _) - (setq called-pattern pattern) - (setq called-files files) - (setq called-dir dir) - (setq called-literal literal)))) - (find-file "test/data/foo.el") - (rg-dwim-regexp "hello") - (should (equal called-pattern "hello")) - (should (equal called-files "elisp")) - (should (equal (expand-file-name called-dir) project-dir)) - (should (eq called-literal nil)))) - (ert-deftest rg-integration/project-search () "Test `rg-project'." (cl-letf ((called-pattern nil) From a515fcf44959d8590d0d2038377877968794dc84 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Sun, 14 Jan 2018 10:43:57 -0500 Subject: [PATCH 08/10] set confirm option in local bindings --- rg.el | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/rg.el b/rg.el index f519490..fb2f966 100644 --- a/rg.el +++ b/rg.el @@ -1012,8 +1012,12 @@ prefix is not supplied `rg-keymap-prefix' is used." (defun rg-set-search-defaults (args) "Set defaults for required search options missing from ARGS. -If the :format option is missing, set it to 'regexp, and if +If the :confirm option is missing, set it to 'never, if +the :format option is missing, set it to 'regexp, and if the :query option is missing, set it to 'ask" + (unless (plist-get args :confirm) + (setq args (plist-put args :confirm 'never))) + (unless (plist-get args :format) (setq args (plist-put args :format 'regexp))) @@ -1024,7 +1028,8 @@ the :query option is missing, set it to 'ask" (defun rg-search-parse-local-bindings (search-cfg) "Parse local bindings for search functions from SEARCH-CFG." - (let* ((format-opt (plist-get search-cfg :format)) + (let* ((confirm-opt (plist-get search-cfg :confirm)) + (format-opt (plist-get search-cfg :format)) (query-opt (plist-get search-cfg :query)) (alias-opt (plist-get search-cfg :files)) (dir-opt (plist-get search-cfg :dir)) @@ -1032,10 +1037,15 @@ the :query option is missing, set it to 'ask" ;; confirm binding (cond ((eq confirm-opt 'never) - (setq binding-list (append binding-list `((confirm nil)))) + (setq binding-list (append binding-list `((confirm nil))))) + + ((eq confirm-opt 'always) + (setq binding-list (append binding-list `((confirm t))))) - (eq confirm-opt 'always) - (setq binding-list (append binding-list `((confirm t)))))) + ((eq confirm-opt 'prefix) + (setq binding-list (append binding-list + '((confirm (equal current-prefix-arg + '(4)))))))) ;; query binding (unless (eq query-opt 'ask) @@ -1062,18 +1072,13 @@ the :query option is missing, set it to 'ask" (defun rg-search-parse-interactive-args (search-cfg) "Parse interactive args from SEARCH-CFG for search functions." - (let* ((confirm-opt (plist-get search-cfg :confirm)) - (query-opt (plist-get search-cfg :query)) + (let* ((query-opt (plist-get search-cfg :query)) (format-opt (plist-get search-cfg :format)) (literal (eq format-opt 'literal)) (dir-opt (plist-get search-cfg :dir)) (files-opt (plist-get search-cfg :files)) (iargs '())) - (when (eq confirm-opt 'prefix) - (setq iargs (append iargs '((confirm . (equal current-prefix-arg - '(4))))))) - (when (eq query-opt 'ask) (setq iargs (append iargs `((query . (rg-read-pattern nil ,literal)))))) @@ -1088,7 +1093,6 @@ the :query option is missing, set it to 'ask" '((dir . (read-directory-name "In directory: " nil default-directory t)))))) - iargs)) ;;;###autoload From ba37fe76530d8134ab657829b1f314e1c7105a22 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Sun, 14 Jan 2018 20:26:23 -0500 Subject: [PATCH 09/10] evaluate function definitions during compilation --- rg.el | 188 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 96 insertions(+), 92 deletions(-) diff --git a/rg.el b/rg.el index fb2f966..9e6e4c0 100644 --- a/rg.el +++ b/rg.el @@ -999,101 +999,105 @@ prefix is not supplied `rg-keymap-prefix' is used." (message "Global key bindings for `rg' enabled with prefix: %s" (edmacro-format-keys prefix)))) -(defun rg-search-parse-body (args) - "Parse a function ARGS into (DECLARATIONS . EXPS)." - (let ((decls ())) - (while (and (cdr args) - (let ((e (car args))) - (or (stringp e) - (memq (car-safe e) - '(:documentation declare interactive cl-declare))))) - (push (pop args) decls)) - (cons (nreverse decls) args))) - -(defun rg-set-search-defaults (args) - "Set defaults for required search options missing from ARGS. +(eval-when-compile + (defun rg-search-parse-body (args) + "Parse a function ARGS into (DECLARATIONS . EXPS)." + (let ((decls ())) + (while (and (cdr args) + (let ((e (car args))) + (or (stringp e) + (memq (car-safe e) + '(:documentation declare interactive cl-declare))))) + (push (pop args) decls)) + (cons (nreverse decls) args)))) + +(eval-when-compile + (defun rg-set-search-defaults (args) + "Set defaults for required search options missing from ARGS. If the :confirm option is missing, set it to 'never, if the :format option is missing, set it to 'regexp, and if the :query option is missing, set it to 'ask" - (unless (plist-get args :confirm) - (setq args (plist-put args :confirm 'never))) - - (unless (plist-get args :format) - (setq args (plist-put args :format 'regexp))) - - (unless (plist-get args :query) - (setq args (plist-put args :query 'ask))) - - args) - -(defun rg-search-parse-local-bindings (search-cfg) - "Parse local bindings for search functions from SEARCH-CFG." - (let* ((confirm-opt (plist-get search-cfg :confirm)) - (format-opt (plist-get search-cfg :format)) - (query-opt (plist-get search-cfg :query)) - (alias-opt (plist-get search-cfg :files)) - (dir-opt (plist-get search-cfg :dir)) - (binding-list `((literal ,(eq format-opt 'literal))))) - - ;; confirm binding - (cond ((eq confirm-opt 'never) - (setq binding-list (append binding-list `((confirm nil))))) - - ((eq confirm-opt 'always) - (setq binding-list (append binding-list `((confirm t))))) - - ((eq confirm-opt 'prefix) - (setq binding-list (append binding-list - '((confirm (equal current-prefix-arg - '(4)))))))) - - ;; query binding - (unless (eq query-opt 'ask) - (let ((query (cond ((eq query-opt 'point) '(grep-tag-default)) - (t query-opt)))) - (setq binding-list (append binding-list `((query ,query)))))) - - ;; dir binding - (when dir-opt - (let ((dirs (cond ((eq dir-opt 'project) '(rg-project-root - buffer-file-name)) - ((eq dir-opt 'current) 'default-directory) - (t dir-opt)))) - (setq binding-list (append binding-list `((dir ,dirs)))))) - - ;; file alias binding - (when alias-opt - (let ((files (if (eq alias-opt 'current) - '(car (rg-default-alias)) - alias-opt))) - (setq binding-list (append binding-list `((files ,files)))))) - - binding-list)) - -(defun rg-search-parse-interactive-args (search-cfg) - "Parse interactive args from SEARCH-CFG for search functions." - (let* ((query-opt (plist-get search-cfg :query)) - (format-opt (plist-get search-cfg :format)) - (literal (eq format-opt 'literal)) - (dir-opt (plist-get search-cfg :dir)) - (files-opt (plist-get search-cfg :files)) - (iargs '())) - - (when (eq query-opt 'ask) - (setq iargs - (append iargs `((query . (rg-read-pattern nil ,literal)))))) - - (unless files-opt - (setq iargs - (append iargs '((files . (rg-read-files)))))) - - (unless dir-opt - (setq iargs - (append iargs - '((dir . (read-directory-name - "In directory: " nil default-directory t)))))) - - iargs)) + (unless (plist-get args :confirm) + (setq args (plist-put args :confirm 'never))) + + (unless (plist-get args :format) + (setq args (plist-put args :format 'regexp))) + + (unless (plist-get args :query) + (setq args (plist-put args :query 'ask))) + + args)) + +(eval-when-compile + (defun rg-search-parse-local-bindings (search-cfg) + "Parse local bindings for search functions from SEARCH-CFG." + (let* ((confirm-opt (plist-get search-cfg :confirm)) + (format-opt (plist-get search-cfg :format)) + (query-opt (plist-get search-cfg :query)) + (alias-opt (plist-get search-cfg :files)) + (dir-opt (plist-get search-cfg :dir)) + (binding-list `((literal ,(eq format-opt 'literal))))) + + ;; confirm binding + (cond ((eq confirm-opt 'never) + (setq binding-list (append binding-list `((confirm nil))))) + + ((eq confirm-opt 'always) + (setq binding-list (append binding-list `((confirm t))))) + + ((eq confirm-opt 'prefix) + (setq binding-list (append binding-list + '((confirm (equal current-prefix-arg + '(4)))))))) + + ;; query binding + (unless (eq query-opt 'ask) + (let ((query (cond ((eq query-opt 'point) '(grep-tag-default)) + (t query-opt)))) + (setq binding-list (append binding-list `((query ,query)))))) + + ;; dir binding + (when dir-opt + (let ((dirs (cond ((eq dir-opt 'project) '(rg-project-root + buffer-file-name)) + ((eq dir-opt 'current) 'default-directory) + (t dir-opt)))) + (setq binding-list (append binding-list `((dir ,dirs)))))) + + ;; file alias binding + (when alias-opt + (let ((files (if (eq alias-opt 'current) + '(car (rg-default-alias)) + alias-opt))) + (setq binding-list (append binding-list `((files ,files)))))) + + binding-list))) + +(eval-when-compile + (defun rg-search-parse-interactive-args (search-cfg) + "Parse interactive args from SEARCH-CFG for search functions." + (let* ((query-opt (plist-get search-cfg :query)) + (format-opt (plist-get search-cfg :format)) + (literal (eq format-opt 'literal)) + (dir-opt (plist-get search-cfg :dir)) + (files-opt (plist-get search-cfg :files)) + (iargs '())) + + (when (eq query-opt 'ask) + (setq iargs + (append iargs `((query . (rg-read-pattern nil ,literal)))))) + + (unless files-opt + (setq iargs + (append iargs '((files . (rg-read-files)))))) + + (unless dir-opt + (setq iargs + (append iargs + '((dir . (read-directory-name + "In directory: " nil default-directory t)))))) + + iargs))) ;;;###autoload (defmacro rg-define-search (name &rest args) From c558a147d2169d288dbcf313b81dd054cb2b33ce Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Sun, 14 Jan 2018 20:42:56 -0500 Subject: [PATCH 10/10] make the documentation consistent. --- rg.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/rg.el b/rg.el index 9e6e4c0..f449aa9 100644 --- a/rg.el +++ b/rg.el @@ -1014,9 +1014,9 @@ prefix is not supplied `rg-keymap-prefix' is used." (eval-when-compile (defun rg-set-search-defaults (args) "Set defaults for required search options missing from ARGS. -If the :confirm option is missing, set it to 'never, if -the :format option is missing, set it to 'regexp, and if -the :query option is missing, set it to 'ask" +If the :confirm option is missing, set it to NEVER, if +the :format option is missing, set it to REGEXP, and if +the :query option is missing, set it to ASK" (unless (plist-get args :confirm) (setq args (plist-put args :confirm 'never))) @@ -1102,10 +1102,11 @@ the :query option is missing, set it to 'ask" ;;;###autoload (defmacro rg-define-search (name &rest args) "Define an rg search functions named NAME. -ARGS is a search specification with `:query' (point or ask), -`:format' (literal or regexp), `files' (rg or custom file alias), -`dir' (root search directory), and `confirm' as allowable options -specifying the behavior of the search function." +ARGS is a search specification with :query (POINT or ASK), +:format (LITERAL or REGEXP), :files (rg or custom file alias), +:dir (root search directory), and :confirm (NEVER, ALWAYS, or +PREFIX) as allowable options specifying the behavior of the +search function." (declare (indent defun)) (let* ((body (rg-search-parse-body args)) (decls (car body))