1

I want to build a modified version of the occur command that obeys to isearch-filter-predicate. I made some tests and I found that I can do it using a modified version of re-search-forward that I built:

(defalias 're-search-forward-copy
  (symbol-function 're-search-forward)
  "Copy of `re-search-forward'")

(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 (re-search-forward-copy 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)

This is my modified version of occur that obeys isearch-filter-predicate:

(defun occur-ifp (regexp &optional nlines region)
  "Modified version of `occur' that filters (skips) matches according to
`isearch-filter-predicate'."
  (interactive
   (nconc (occur-read-primary-args)
          (and (use-region-p) (list (region-bounds)))))
  (unwind-protect
      (progn
        (advice-add 're-search-forward :override #'re-search-forward-ifp)
        (occur regexp nlines region))
    (advice-remove 're-search-forward #'re-search-forward-ifp)))

I copied the interactive stuff from the original occur command in replace.el but I'd prefer to have a cleaner definition. I mean something like:

;; PSEUDOCODE (closure?):
(let ((re-search-forward re-search-forward-ifp))
  (defalias 'occur-ifp
    (symbol-function 'occur)))

Is it possible?

1 Answer 1

1

This code seems to work, even though it's not a "closure":

;; I need a copy of `re-search-forward' because it will be temporary adviced in
;; `how-many-ifp' and `occur-ifp' functions:
(defalias 're-search-forward-copy
  (symbol-function 're-search-forward)
  "Copy of `re-search-forward'")

(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 (re-search-forward-copy 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 override-re-search-forward (orig-fun &rest args)
  "Temporary advice the `re-search-forward' function, overriding it with
`re-search-forward-ifp' to make it sensitive to `isearch-filter-predicate'"
  (unwind-protect
      (progn
        (advice-add 're-search-forward :override #'re-search-forward-ifp)
        (apply orig-fun args))
    (advice-remove 're-search-forward #'re-search-forward-ifp)))

Definition and advicing of occur-ifp:

(defalias 'occur-ifp
  (symbol-function 'occur)
  "Copy of the `occur' function (to be) adviced to obey to
`isearch-filter-predicate'")

(advice-add 'occur-ifp :around #'override-re-search-forward)

I don't know if advicing a function to advice a function inside it is a good idea but it seem to work (I need more tests).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.