emacs-devel
[Top][All Lists]
Advanced

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

RE: Text property searching


From: Drew Adams
Subject: RE: Text property searching
Date: Mon, 16 Apr 2018 07:30:26 -0700 (PDT)

> >> The `t' there is the predicate: `t' means "equal", `nil' means "not
> >> equal", and then you can write your own predicates for other uses.
> >
> > "Equals or includes" should be another popular predicate (think faces).
> 
> Yes, that's true...  We could have a special symbol for that, or would
> it be confusing?

FWIW -

My library `isearch-prop.el' has long let you Isearch zones
that have arbitrary text-property or overlay-property values.

I agree that an eq/equal-or-memq/member predicate can be
useful.  But it's not really enough when it comes to dealing
with properties, including but not limited to `face' and
similar (whose values can combine for an accumulated effect).

Like what you propose, the code I use lets you use an
arbitrary predicate, but matching allows for matches that
involve overlap of property values, in this sense: If the
PROPERTY value is an atom then it must be a member of the
set of test VALUES, but if the PROPERTY value is a list,
then at least one of its elements must be a member of VALUES.

https://www.emacswiki.org/emacs/download/isearch-prop.el

---

This is the crux of the property-matching & predicate code:

(defun isearchp-property-matches-p (type property values
                                    match-fn position)
  "Return non-nil if POSITION has PROPERTY with a value matching VALUES.
TYPE is `overlay', `text', or nil, and specifies the type of property.
TYPE nil means look for both overlay and text properties.  Return
 non-nil if either matches.

Matching means finding text with a PROPERTY value that overlaps with
VALUES: If the value of PROPERTY is an atom, then it must be a member
of VALUES.  If it is a list, then at least one list element must be a
member of VALUES.

MATCH-FN is a binary predicate that is applied to each item of VALUES
and a zone of text with property PROP.  If it returns non-nil then the
zone is a search hit."
  (let* ((ov-matches-p   nil)
         (txt-matches-p  nil)
         (ovchk-p        (and (or (not type)  (eq type 'overlay))))
         (ovs            (and ovchk-p  (overlays-at position))))
    (when ovchk-p
      (setq ov-matches-p
            (catch 'i-p-m-p
              (dolist (ov  ovs)
                (when (isearchp-some
                       values (overlay-get ov property) match-fn)
                  (throw 'i-p-m-p t)))
              nil)))
    (when (and (or (not type)  (eq type 'text)))
      (setq txt-matches-p
            (isearchp-some
             values (get-text-property position property) match-fn)))
    (or ov-matches-p  txt-matches-p)))

(defun isearchp-property-filter-pred (type property values)
  "Return a predicate that uses `isearchp-property-matches-p'.
TYPE, PROPERTY, and VALUES are used by that function.
The predicate is suitable as a value of `isearch-filter-predicate'."
  (let ((tag  (make-symbol "isearchp-property-filter-pred")))
    `(lambda (beg end)
       (and (or (not (boundp 'isearchp-reg-beg))
                (not isearchp-reg-beg)
                (>= beg isearchp-reg-beg))
            (or (not (boundp 'isearchp-reg-end))
                (not isearchp-reg-end)
                (< end isearchp-reg-end))
            (or (isearch-filter-visible beg end)
                (not (or (eq search-invisible t)
                         (not (isearch-range-invisible beg end)))))
            (catch ',tag
              (while (< beg end)
                (let ((matches-p
                       (isearchp-property-matches-p
                        ',type ',property
                        ',values
                        (isearchp-property-default-match-fn ',property)
                        beg)))
                  (unless (if matches-p
                              (not isearchp-complement-domain-p)
                            isearchp-complement-domain-p)
                    (throw ',tag nil)))
                (setq beg  (1+ beg)))
              t)))))



reply via email to

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