[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

1) (elisp) `Advising Named Functions', 2) search filtering example

From: Drew Adams
Subject: 1) (elisp) `Advising Named Functions', 2) search filtering example
Date: Sun, 16 Oct 2016 22:25:09 -0700 (PDT)

1. Node `Advising Named Functions' of the Elisp manual says this:

 For these reasons, advice should be reserved for the cases
 where you cannot modify a function’s behavior in any other way.
 If it is possible to do the same thing via a hook, that is
 preferable. ...

 In particular, Emacs’s own source files should not put advice
 on functions in Emacs.  (There are currently a few exceptions
 to this convention, but we aim to correct them.)

Is that still true?  Is this the policy, even with the new
advice system?

If so, then it seems that it is being ignored, as new advice
has been added to `isearch-filter-predicate' in `dired-aux.el'
and `wdired.el'.

And the `isearch.el' code has been modified to accommodate such
advising, instead of, for example, just using a hook variable.


2. As a related aside, I recently added, to my library
`isearch+.el', an ability to add search-filter predicates on
the fly.

a. At first, I took the hook approach:

`isearch-filter-predicate' is essentially a hook, so I made
it one explicitly.  I modified (my version of) the code that
uses it, so that the value could be either a function or a
list of functions.  I used `run-hook-with-args-until-failure'
for the (now true) hook variable `isearch-filter-predicate'.

This approach was simple to implement.  However, it would
also mean modifying any and all code that uses or will use
`isearch-filter-predicate' differently.  In particular,
code in `replace.el', as well as the code in `dired-aux.el'
and `wdired.el' mentioned above.

b. Figuring that the current wave of advising instead of
hooking is here to stay, I then took the different approach
of using `add-function', `remove-function', etc. instead of
a hook.

The implementation is not as simple or straightforward as
for a hook, but it is clean enough.  I'm sticking with it,
as I expect that this is the way the wind is blowing now.

(Note that one difference from a hook is that a hook does
not privilege the first hook function in any way (or the
last, depending on how you look at it).  Removing advice
is not equivalent to `remove-hook'.  It never "empties the
hook" completely - the function that was advised is still
there after removal of all advice.)

Anyway, using either approach you can do any of these
things while searching, to modify the zones you search:

* `M-? &' (`isearchp-add-filter-predicate') adds a filter
  predicate, AND-ing it as an additional `:after-while' filter.

* `M-? |' (`isearchp-or-filter-predicate') adds a filter
  predicate, OR-ing it as an additional `:before-until' filter.

* `M-? ~' (`isearchp-complement-filter') complements the current
  filter.  It either adds an `:around' filter that complements
  or it removes an existing top-level complementing filter.

* `M-? -' (`isearchp-remove-filter-predicate') removes the last
  added filter predicate (aka advice).

* `M-? !' (`isearchp-set-filter-predicate') sets the overall
  filter predicate (advised `isearch-filter-predicate') to a
  single predicate.

* `M-? 0' (`isearchp-reset-filter-predicate') resets
  `isearch-filter-predicate' to its original (unadvised) value.

* `M-? s' (`isearchp-save-filter-predicate') saves the current
  filter-predicate suite (advised `isearch-filter-predicate')
  for subsequent searches.  Unless you save it, the next
  Isearch starts out from scratch, using the last (unadvised)
  value of `isearch-filter-predicate'.

* `M-? n' (`isearchp-defun-filter-predicate') names the current
  suite of filter predicates, creating a named predicate that
  does the same thing.  (You can use that name with `M-? -' to
  remove that predicate.)  With a prefix arg it can also set or
  save (i.e., do what `M-? !' or `M-? s' does).

* `M-? M-h' (`isearchp-show-filters') echoes the current suite
  of filter predicates (advice and original, unadvised

* `M-? @', `M-? <', and `M-? >' (`isearchp-near',
  `isearchp-near-before', and `isearchp-near-after') constrain
  searching to be within a given distance of (near) another
  search pattern.

When you use one of the commands that adds a filter predicate as
advice to `isearch-filter-predicate' you can be prompted for two
things: (1) a name for the predicate and (2) text to add to the
Isearch prompt as a reminder of filtering.  Two user options
control this prompting:

* `isearchp-prompt-for-filter-name' says whether to prompt you
  always, never, or only when the predicate that you provide is
  not a symbol (it is a lambda form).  The last of these is the
  default behavior.  If you are prompted and provide a name, you
  can use that name with `M-? -' to remove that predicate.

* `isearchp-prompt-for-isearch-prompt-prefix' says whether to
  prompt you for a prefix to add to the Isearch prompt.  You are
  prompted by default, but if you don't care to see such a
  prompt prefix and you don't want to be bothered by it, you can
  customize this to skip prompting.

In addition, whatever the value of these options, when you add a
filter predicate you can override the option values by using a
prefix argument.  A non-positive prefix arg overrides the option
for name prompting, and a non-negative prefix arg overrides the
option for prompt-prefix prompting.  (So zero, e.g., `M-0',
overrides both.)

(The code is here, if anyone wants to play with it:

reply via email to

[Prev in Thread] Current Thread [Next in Thread]