-
-
Notifications
You must be signed in to change notification settings - Fork 338
grep for TODOs
Mohsin Kaleem edited this page May 25, 2020
·
2 revisions
users of hl-todo
may be wanting a convenient way to jump to TODO entries in your current project.
Here's a nice way to get that working using ripgrep or ag.
(require 'hl-todo)
(require 'counsel)
(defvar hl-todo-keyword-faces)
(defgroup counsel-todo nil
"use ivy to jump to TODOs.")
(defcustom counsel-todo-backend 'rg
"backend to use for `counsel-todo-command'"
:group 'counsel-todo
:type 'symbol
:options '(rg ag))
(defcustom counsel-todo-command
(cl-case counsel-todo-backend
('rg counsel-rg-base-command)
('ag counsel-ag-base-command))
"command string used for searching with `counsel-todo'.")
(defun counsel-todo-function (string &rest _)
(let ((regexp (counsel--elisp-to-pcre
(cl-loop for (keyword . _) in hl-todo-keyword-faces
for i from 1 upto (length hl-todo-keyword-faces)
unless (= i 1)
do (setq keyword (concat "\\|" keyword))
end
concat keyword))))
(counsel--async-command
(format counsel-todo-command
(shell-quote-argument regexp)))
'()))
(cl-defun counsel-todo (arg &optional initial-input initial-directory &key caller)
(interactive "P")
(when (and arg (not initial-directory))
(setq initial-directory
(counsel-read-directory-name "TODOs in directory: ")))
(counsel-require-program counsel-todo-command)
(let ((default-directory (or initial-directory
(counsel--git-root)
(ivy-state-directory ivy-last)
default-directory)))
(ivy-read "TODO: "
#'counsel-todo-function
:initial-input initial-input
;; :dynamic-collection t
:keymap counsel-ag-map
:history 'counsel-git-grep-history
:action #'counsel-git-grep-action
:unwind #'counsel-delete-process
:require-match t
:caller (or caller 'counsel-todo))))
;; inherit config from counsel-ag
(ivy-configure 'counsel-todo
:occur #'counsel-ag-occur
:unwind-fn #'counsel--grep-unwind
:display-transformer-fn #'counsel-git-grep-transformer
:grep-p t
:exit-codes '(1 "No matches found"))
(provide '+counsel-todo)
the previous solution just displays matched lines in the default face, this makes it hard to see where the TODOs appear so here's a display-transformer that highlights TODO keywords as well.
(defun counsel-todo--get-face (keyword)
(hl-todo--combine-face
(cdr
(cl-assoc keyword hl-todo-keyword-faces :test #'string-match-p))))
(defun counsel-todo-transformer (str)
(save-match-data
(let ((regex (hl-todo--regexp))
(search-start 0) start end)
(while (string-match regex str search-start)
(setq start (match-beginning 1)
end (match-end 1)
search-start end)
(add-face-text-property start end
(counsel-todo--get-face (substring str start end))
nil str))))
(counsel-git-grep-transformer str))
(ivy-configure 'counsel-todo
:display-transformer-fn #'counsel-todo-transformer)