find-where

Homepage: https://www.emacswiki.org/emacs/download/find-where.el

Author: Drew Adams

Updated:

Summary

Find where something is true

Commentary

Find where something is true.

 Get or go to the next place where some predicate is satisfied.

 But first, you don't really need this library! ;-)

 In Emacs and Emacs Lisp there are multiple ways to find things.
 And in many cases it will be simpler or more efficient to use
 another way than to take advantage of this library.

 What this library offers is some convenience sometimes, and a
 certain kind of generality: Specify what you want to find by a
 predicate.  The predicate is tested at successive places, forward
 or backward, until it is satisfied.

 By default, the forward and backward movement is among buffer
 positions, in the usual sense.  And by default, each movement
 before testing is just one character.  This is the minimum
 movement needed to get past the current position (which is often
 the last place found).

 Moving only one character and testing is obviously not very
 efficient, but it is all that can be done in the general case.

 When you know a way to move farther before testing and to be sure
 there is no need to test closer, you can take advantage of that by
 providing for the appropriate movement in the predicate you
 provide or in optional forward and backward movement functions.

 Clearly, this move-one-char-and-test approach is not the way to go
 for ordinary string searching.  Emacs uses an efficient,
 Boyer-Moore string-search algorithm (see
 https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm),
 which essentially moves forward in chunks that are as long as what
 your search string matches, rather than moving just a character at
 a time before each match attempt.

 So if you want to search for a sequence of characters, just use
 `(re-)search-forward' or similar.  And if you need an additional
 test at a match position (e.g., check a text or overlay property)
 you can easily add that.  So forget about this library for
 ordinary buffer search.

 Still, you might find this library convenient for some things,
 even in cases where there is an easy alternative.  The abstraction
 of defining a destination by a predicate that holds there can be
 helpful.

 So just what does it mean to "find where something is true"?  Find
 what?  Well, the what is defined by your predicate.  What is
 found, that is, returned, is both the position (where) and
 whatever the predicate returns as a non-nil value.  For example,
 you can find a text THING, such as the next vector with 13
 elements, and have it returned along with its bounds (start and
 end positions).
 
 The library defines some general functions to find and return the
 next or previous where-plus-what, which you provide with a
 defining predicate.  And it defines corresponding commands to go
 to the next or previous such location.

 The commands have names that start (after prefix `fw-') with
 `to-'.  The corresponding non-interactive functions generally have
 the same names without the `to-'.  For example, function
 `fw-next-where' returns the next position and data that satisfy a
 predicate, and command `fw-to-next-where' goes there.

 By default, movement is to the start position of something, but
 really the where, in relation to its what, is up to you.  The
 default behavior is thus different from the standard Emacs
 `forward-THING' and `backward-THING' behavior, which moves just
 past the THING rather than just to it.

 This default behavior applies to all functions provided here, not
 just to those (`fw-next-thing' etc.) that find buffer THINGs.  For
 THINGs, `find-where.el' requires library `thingatpt+.el', which
 uses and enhances standard library `thingatpt.el'.

 When repeated, the commands reuse the same predicate as the last
 time (it is the value of variable `fw-last-pred'), but a plain
 prefix argument (`C-u') makes them prompt you for the predicate to
 use.  The predicate you enter must accept a buffer position (the
 position to test) as its first argument.

 A typical use might check something about the character at (i.e.,
 after) that position.

 The THING-related function `fw-next-thing' just uses
 `fw-next-where' with a predicate that tests whether the position
 is at the start of a THING, where being at the start also means
 that the previous buffer position is not on the same thing (not
 just the same type of thing).

 For instance, if the THING type passed to `fw-next-thing' is
 `list' then it returns the start position of the next list (as
 well as the list text as a string and its end position).

 When repeated, the THING commands reuse the same THING type as the
 last time (it is the value of variable `fw-last-thing'), but a
 plain prefix argument (`C-u') makes them prompt you for the THING
 type to use.

 You can bind any of the commands defined here to keys, of course.
 But you can also easily define other commands that make use of
 them, and bind those commands to keys.

 For example, here's a simple command that moves to the start of
 the next use of face `font-lock-doc-face':

 (defun to-next-doc-face (n)
   "Move to next occurrence of `font-lock-doc-face'.
 With numeric prefix arg N, move to the Nth next occurrence."
   (interactive "p")
   (fw-to-next-where #'doc-face-start-p nil nil n))

 where the predicate is defined like so:

 (defun doc-face-start-p (position)
   "Return non-nil if char at POSITION starts `font-lock-doc-face'.
 That is, it has that face, and any char just before it does not."
   (and (eq (get-text-property position 'face) 'font-lock-doc-face)
        (or (= position (point-min))
            (not (eq (get-text-property (1- position) 'face)
                     'font-lock-doc-face)))))

 Note the use here of two complementary tests within the predicate.
 The character at the tested position must pass the test (having
 property `font-lock-doc-face'), and the preceding char, if there
 is one, must NOT pass the test.  This means that
 `to-next-doc-face' finds the _first_ character that passes the
 test.  This is typical of a predicate used with `find-where.el'
 functions.

 For this reason, you can use helper function `fw-test-start-p' to
 take care of that true-here-but-not-just-before-here logic.  It
 takes the position to test and a predicate as arguments.  The
 predicate must be true at the position and false just before the
 position, for `fw-test-start-p' to be true (return non-nil).

 Using `fw-test-start-p', `doc-face-start-p' becomes just this:

 (defun doc-face-start-p (position)
   "Return non-nil if char at POSITION starts `font-lock-doc-face'.
 That is, it has that face, and any char just before it does not."
   (fw-test-start-p position
                    (lambda ()
                      (eq (get-text-property (point) 'face)
                          'font-lock-doc-face))))

 The predicate arg to `fw-to-next-where' can accept additional
 arguments, besides the position.  So you can use a predicate that
 accepts, as argument, the face to look for, as well as the
 position to test.  For example:

 (defun face-start-p (position face)
   "Return non-nil if the character at POSITION starts FACE.
 That is, it has FACE, and any character just before it does not."
   (and (eq (get-text-property position 'face) face)
        (or (= position (point-min))
            (not (eq (get-text-property (1- position) 'face)
                     face)))))

 Or simplified using `fw-test-start-p':

 (defun face-start-p (position face)
   "Return non-nil if the character at POSITION starts FACE.
 That is, it has FACE, and any character just before it does not."
   (fw-test-start-p position
                    `(lambda ()
                       (eq (get-text-property (point) 'face)
                           ',face))))

 (defvar last-face nil "Last face used by `to-next-face'.")

 (defun to-next-face (arg)
   "Move to next text-property occurrence of face `last-face'.
 With plain `C-u', prompt for the face to assign to `last-face'.
 With numeric prefix arg N, move to the Nth next occurrence."
   (interactive "P")
   (if (or (consp arg)  (not last-face))
       (setq last-face  (read-face-name "Face: ")
             arg        1)
     (setq arg  (prefix-numeric-value arg)))
   (fw-to-next-where #'face-start-p nil (list last-face) arg))


 [Note: Text property `face' can actually have a list of faces as
  its value, so instead of using an `eq' text in those `*-start-p'
  functions a more realistic example would test for the particular
  face using both `eq' and `memq' (return true if either is true).]

 Now recall that the way `fw-to-next-where' works by default is to
 move forward only one char and then test with the predicate.  This
 is not very efficient, but it is all that can be done, unless
 there is some way to move farther forward before testing and be
 sure there is no need to test closer.

 In the case of testing for a given text property (or overlay
 property) at a buffer position there is such a better way: use
 function `next-single-property-change'.  Using that, we can define
 the forward-movement function `to-next-face-prop', which we can
 pass to `to-next-face' to override the default one-char movement
 (`forward-char').

 (defun to-next-face-prop ()
   "Go to next change in `face' text property."
   (let ((pos  (next-single-property-change (point) 'face)))
     (when pos (goto-char pos))))

 (defun to-next-face (arg)
   (interactive "P")
   (if (or (consp arg)  (not last-face))
       (setq last-face  (read-face-name "Face: ")
             arg        1)
     (setq arg  (prefix-numeric-value arg)))
   (fw-to-next-where #'face-start-p nil (list last-face) arg
                     nil nil nil #'to-next-face-prop))


 As an example of defining a next-THING command, this defines a
 command to move forward among sexps:

 (defun to-next-sexp (n)
   "Go to next start of a sexp."
   (interactive "p")
   (fw-to-next-thing 'sexp nil n))

 And this moves among strings:

 (defun to-next-string (n)
   "Go to next start of a string."
   (interactive "p")
   (fw-to-next-thing 'string nil n))

 Note that the various `fw-to-next-*' and `fw-to-previous-*'
 commands move to the _beginning_ of the next or previous place
 where something is true.  For example, if you use `fw-next-thing'
 with THING `word' then the cursor moves to the beginning of each
 word.  This is different from typical Emacs `forward-*' and
 `backward-*' commands, which move _past_ the end or the beginning
 of something.

 Typical Emacs `forward-*' commands essentially perform the
 following sequence of actions, expressed in terms of `fw-next-*':

   1. While some predicate PRED-X is NOT true, do `fw-to-next-X'.
   2. Do `fw-to-next-NOT-X'.

 Step 1 moves to the next place X is true (e.g., a word beginning).
 Step 2 moves just past where X continues to be true (e.g., just
 after the end of the word).

 Partly as a way of illustrating this, commands `fw-downward-word'
 and `fw-upward-word' act like Emacs `forward-word' and
 `backward-word', but they move through text vertically, not
 horizontally.  They are defined using steps 1 and 2.


 Commands defined here:

   `fw-downward-word', `fw-to-column-down', `fw-to-column-up',
   `fw-to-next-thing', `fw-to-next-where',
   `fw-to-next-where-vertical', `fw-to-previous-thing',
   `fw-to-previous-where', `fw-to-previous-where-vertical',
   `fw-upward-word'.

 Non-interactive functions defined here:

   `fw--next/prev-thing', `fw--next/prev-where',
   `fw--read-predicate', `fw--to-next/prev-thing',
   `fw--to-next/prev-where', `fw-next-thing', `fw-next-where',
   `fw-next-where-vertical', `fw-not-word-char-after-p',
   `fw-not-word-char-before-p', `fw-previous-thing',
   `fw-previous-where', `fw-previous-where-vertical',
   `fw-test-start-p', `fw-thing-start-p', `fw-word-char-after-p',
   `fw-word-char-before-p'.

 Internal variables defined here:

   `fw-last-pred', `fw-last-thing'.

Dependencies

Reverse dependencies