Hi,

I’d like occur to obey to isearch-filter-predicate like query-replace* and isearch* commands.

This is an example of what I do:

(defmacro with-ifp-predicates (PREDICATES &rest body)
   "Allows assigning a list of predicates to the
 variable `isearch-filter-predicate'.

Below is an example of usage:

(with-ifp-predicates '(skip-maths skip-comments)
  (query-replace \"foo\" \"bar\" nil (point-min) (point-max)))"
  (declare (indent 1))
  `(let ((isearch-filter-predicate isearch-filter-predicate))
     (mapc (lambda (predicate)
               (add-function :before-while isearch-filter-predicate predicate))
             ,PREDICATES)
     ,@body))

(I always use let-binding for operations that involve isearch-filter-predicate.)

In some cases, I would like to have something like this:

(with-ifp-predicates '(predicate1 predicate2)
   (save-window-excursion
     (occur "foo")
     (query-replace \"foo\" \"bar\" nil (point-min) (point-max)))) 

with occur showing me only the strings that match the active predicates.

I wrote a mail to emacs-devel@gnu.org and I have verified that others also believe that this solution would be helpful and consistent with the functioning of some other functions defined in replace.el.

I’d also like to add this feature to the how-many function.

I already wrote this modified version (Emacs 29.2):


(defun re-search-forward-ifp (REGEXP &optional BOUND NOERROR COUNT)
  "Modified version of `search-forward-regexp' that
    filters (skips) matches according to `isearch-filter-predicate'."

  (let ((POINT (point)))
    (catch 'filtered
      (while (search-forward-regexp REGEXP BOUND NOERROR COUNT)
        (let ((B (match-beginning 0))
              (E (match-end 0)))
          (when (funcall isearch-filter-predicate B E)
            (throw 'filtered (point)))))
      (goto-char POINT)
      nil)))
(defalias 'search-forward-regexp-ifp 're-search-forward-ifp)

(defun how-many-ifp (regexp &optional rstart rend interactive)
  "Modified version of `how-many' that filters (skips) matches
    according to `isearch-filter-predicate'."

  (interactive
   (keep-lines-read-args "How many matches for regexp"))
  (save-excursion
    (if rstart
        (if rend
            (progn
              (goto-char (min rstart rend))
              (setq rend (max rstart rend)))
          (goto-char rstart)
          (setq rend (point-max)))
      (if (and interactive (use-region-p))
          (setq rstart (region-beginning)
                rend (region-end))
        (setq rstart (point)
              rend (point-max)))
      (goto-char rstart))
    (let ((count 0)
          (case-fold-search
           (if (and case-fold-search search-upper-case)
               (isearch-no-upper-case-p regexp t)
             case-fold-search)))
      (while (and (< (point) rend)
                  (re-search-forward-ifp regexp rend t))
        ;; Ensure forward progress on zero-length matches like "^$".
        (when (and (= (match-beginning 0) (match-end 0))
                   (not (eobp)))
          (forward-char 1))
        (setq count (1+ count)))
      (when interactive (message (ngettext "%d occurrence"
                                           "%d occurrences"
                                           count)
                                 count))
      count)))
(defalias 'count-matches-ifp 'how-many-ifp)

Best regards,

Gabriele Nicolardi