[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#69542: Feature request: making occur obey isearch-filter-predicate
From: |
Juri Linkov |
Subject: |
bug#69542: Feature request: making occur obey isearch-filter-predicate |
Date: |
Tue, 05 Mar 2024 18:30:20 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/30.0.50 (x86_64-pc-linux-gnu) |
> 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)
So you rewrote the loop from isearch-search:
(while retry
(setq isearch-success
(isearch-search-string isearch-string nil t))
(if (or (not isearch-success)
(funcall isearch-filter-predicate
(match-beginning 0) (match-end 0)))
(setq retry nil)
But this doesn't answer the question whether and how this could affect
re-search-forward in a non-hackish way. Adding an option? Not sure.
> (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)
I think duplicating the whole body of functions is not better
than using advice. An alternative would be to add a new variable
're-search-forward-function' and then to use it like
'(funcall re-search-forward-function)'.