0

I want to build a version of the how-many function that is sensitive to isearch-filter-predicate.

To achieve this, I had to first build a version of re-search-forward that obeys isearch-filter-predicate:

(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)

Now, since the definition of how-many in replace.el is as follows:

(defun how-many (regexp &optional rstart rend interactive)
  "..."
  (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 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)))

I want to define a function named how-many-ifp that calls re-search-forward-ifp instead of re-search-forward.

I mean something like:

(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"))
    ;; Pseudocode:
    ;; (let ((re-search-forward re-search-forward-ifp))

    (how-many regexp rstart rend interactive))

In practice, I need the symbol re-search-forward to call the function re-rearch-forward-ifp only within my definition. How can I do it?

I'm open to alternative solutions too.

EDIT. I just realized that the re-search-forward-ifp definition calls re-search-forward (Its alias search-forward-regexp). So I think that what I asked for is not possible to do.

1 Answer 1

0

To solve the issue of recursively redefining re-search-forward, I thought of creating a copy of the function to use for defining re-search-forward-ifp.

Edit. I rewrote my code like this:

;; 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)))

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

(advice-add 'how-many-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.

Edit 2. Unfortunately, this didn't turn out to be a good idea! By modifying re-search-forward within how-many using an advice/override, this function (re-search-forward) also gets altered within the definitions of certain predicates like, for instance, texmathp provided by AUCTeX.

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.