* bug#69542: Feature request: making occur obey isearch-filter-predicate
@ 2024-03-04 11:44 Gabriele Nicolardi
2024-03-05 16:30 ` Juri Linkov
0 siblings, 1 reply; 5+ messages in thread
From: Gabriele Nicolardi @ 2024-03-04 11:44 UTC (permalink / raw)
To: 69542
[-- Attachment #1: Type: text/plain, Size: 2912 bytes --]
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
[-- Attachment #2: Type: text/html, Size: 16713 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* bug#69542: Feature request: making occur obey isearch-filter-predicate
2024-03-04 11:44 bug#69542: Feature request: making occur obey isearch-filter-predicate Gabriele Nicolardi
@ 2024-03-05 16:30 ` Juri Linkov
2024-03-05 17:11 ` Gabriele Nicolardi
0 siblings, 1 reply; 5+ messages in thread
From: Juri Linkov @ 2024-03-05 16:30 UTC (permalink / raw)
To: Gabriele Nicolardi; +Cc: 69542
> 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)'.
^ permalink raw reply [flat|nested] 5+ messages in thread
* bug#69542: Feature request: making occur obey isearch-filter-predicate
2024-03-05 16:30 ` Juri Linkov
@ 2024-03-05 17:11 ` Gabriele Nicolardi
2024-03-06 17:47 ` Juri Linkov
2024-03-08 23:09 ` Gabriele Nicolardi
0 siblings, 2 replies; 5+ messages in thread
From: Gabriele Nicolardi @ 2024-03-05 17:11 UTC (permalink / raw)
To: Juri Linkov; +Cc: 69542
[-- Attachment #1: Type: text/plain, Size: 2809 bytes --]
> I think duplicating the whole body of functions is not better
> than using advice.
Until yesterday, I had no idea how to advise a function.
Now I'm experimenting with this code to obtain modified versions of
|occur| and |how-many| that are sensitive to |isearch-filter-predicate|.
I'm not a programmer, so my code may not be very rigorous:
;; 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)
(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)
The key is the `re-search-forward` function used in `how-many` and
`occur` definition. If you make it sensible to
`isearch-filter-predicate` also `how-many` and `occur` will be.
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).
Now I discovered how to build these functions I could be fine with my
modified ones, but making this feature avaible (maybe not default) in
the original functions could be a better idea.
> An alternative would be to add a new variable
> 're-search-forward-function' and then to use it like
> '(funcall re-search-forward-function)'.
The idea of a new function seems good to me.
[-- Attachment #2: Type: text/html, Size: 3955 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* bug#69542: Feature request: making occur obey isearch-filter-predicate
2024-03-05 17:11 ` Gabriele Nicolardi
@ 2024-03-06 17:47 ` Juri Linkov
2024-03-08 23:09 ` Gabriele Nicolardi
1 sibling, 0 replies; 5+ messages in thread
From: Juri Linkov @ 2024-03-06 17:47 UTC (permalink / raw)
To: Gabriele Nicolardi; +Cc: 69542
> An alternative would be to add a new variable
> 're-search-forward-function' and then to use it like
> '(funcall re-search-forward-function)'.
>
> The idea of a new function seems good to me.
Indeed, and this will require only a simple change in 'how-many'
and other functions to replace such calls
(re-search-forward regexp rend t)
with
(funcall re-search-forward-function regexp rend t)
^ permalink raw reply [flat|nested] 5+ messages in thread
* bug#69542: Feature request: making occur obey isearch-filter-predicate
2024-03-05 17:11 ` Gabriele Nicolardi
2024-03-06 17:47 ` Juri Linkov
@ 2024-03-08 23:09 ` Gabriele Nicolardi
1 sibling, 0 replies; 5+ messages in thread
From: Gabriele Nicolardi @ 2024-03-08 23:09 UTC (permalink / raw)
To: Juri Linkov; +Cc: 69542
[-- Attachment #1: Type: text/plain, Size: 1044 bytes --]
Il 05/03/24 18:11, Gabriele Nicolardi ha scritto:
>> I think duplicating the whole body of functions is not better
>> than using advice.
>
> Until yesterday, I had no idea how to advise a function.
>
> 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).
>
> Now I discovered how to build these functions I could be fine with my
> modified ones, but making this feature avaible (maybe not default) in
> the original functions could be a better idea
>
I found that advicing the |occur| and |how-many| function, overriding
the |re-search-forward| function with my modified version of it
(sensitive to |isearch-filter-predicate|) it’s not good at all.
That because some predicates, like e.g. |texmathp| provided by AUCTeX,
use |re-search-forward| too.
> .
>
>> An alternative would be to add a new variable
>> 're-search-forward-function' and then to use it like
>> '(funcall re-search-forward-function)'.
>
> The idea of a new function seems good to me.
>
>
[-- Attachment #2: Type: text/html, Size: 6979 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-03-08 23:09 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-04 11:44 bug#69542: Feature request: making occur obey isearch-filter-predicate Gabriele Nicolardi
2024-03-05 16:30 ` Juri Linkov
2024-03-05 17:11 ` Gabriele Nicolardi
2024-03-06 17:47 ` Juri Linkov
2024-03-08 23:09 ` Gabriele Nicolardi
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).