From 1033ae5b5fb5a79dbf5467f7bf2402cdb8871d6c Mon Sep 17 00:00:00 2001 From: Daniel Mendler Date: Sat, 18 Feb 2023 15:40:57 +0100 Subject: Drop text-property-search functions These functions are not used downstream as of now by packages which use Compat, such that no breakage is expected. Private usage is possible, but private users can copy text-property-search.el from the Emacs source directly to a directory on their load-path. text-property-search.el was added in 27.1 as a new library. The library had bugs which were fixed in Emacs 29. We must find a coherent solution to handle the addition of new libraries in Compat, which will work in the long term. Every Emacs version comes with new libraries. For example Emacs 29 alone added textsec, range, string-edit, vtable, pixel-fill and more. It is not feasible to replicate all these libraries in Compat. Larger libraries are ideally distributed separately via GNU ELPA as :core package or as a separate replica. For example seq.el is distributed in a form, which differs from upstream seq.el. Such compatibility packages could depend on Compat. Small libraries may be provided as part of Compat, but we should then provide the respective library file, such that requiring the feature will not lead to an error. In this case we could provide text-property-search.el. The difficulty will then be to ensure that we don't accidentally override a newer version of the library. --- NEWS.org | 2 + compat-27.el | 194 -------------------------------------------------------- compat-tests.el | 58 ----------------- compat.texi | 93 +-------------------------- 4 files changed, 4 insertions(+), 343 deletions(-) diff --git a/NEWS.org b/NEWS.org index 7532f7c..6ed9400 100644 --- a/NEWS.org +++ b/NEWS.org @@ -5,6 +5,8 @@ - compat-27: Drop obsolete ~compat-call dired-get-marked-files~. - compat-29: Add ~with-restriction~ and ~without-restriction~. - compat-29: Drop ~with-narrowing~. +- compat-27: Drop ~text-property-search-forward~ and ~-backward~. These functions + should be provided by a separate ~text-property-search~ ELPA package. * Release of "Compat" Version 29.1.3.4 diff --git a/compat-27.el b/compat-27.el index 30aa97c..c39ce52 100644 --- a/compat-27.el +++ b/compat-27.el @@ -607,200 +607,6 @@ January 1st being 1." month (1+ month))) (list nil nil nil ordinal month year nil nil nil))) -;;;; Defined in text-property-search.el - -(declare-function make-prop-match nil) -(compat-guard (not (fboundp 'make-prop-match)) ;; - (cl-defstruct (prop-match) beginning end value)) - -(compat-defun text-property-search-forward ;; - (property &optional value predicate not-current) - "Search for the next region of text where PREDICATE is true. -PREDICATE is used to decide whether a value of PROPERTY should be -considered as matching VALUE. - -If PREDICATE is a function, it will be called with two arguments: -VALUE and the value of PROPERTY. The function should return -non-nil if these two values are to be considered a match. - -Two special values of PREDICATE can also be used: -If PREDICATE is t, that means a value must `equal' VALUE to be -considered a match. -If PREDICATE is nil (which is the default value), a value will -match if is not `equal' to VALUE. Furthermore, a nil PREDICATE -means that the match region is ended if the value changes. For -instance, this means that if you loop with - - (while (setq prop (text-property-search-forward \\='face)) - ...) - -you will get all distinct regions with non-nil `face' values in -the buffer, and the `prop' object will have the details about the -match. See the manual for more details and examples about how -VALUE and PREDICATE interact. - -If NOT-CURRENT is non-nil, the function will search for the first -region that doesn't include point and has a value of PROPERTY -that matches VALUE. - -If no matches can be found, return nil and don't move point. -If found, move point to the end of the region and return a -`prop-match' object describing the match. To access the details -of the match, use `prop-match-beginning' and `prop-match-end' for -the buffer positions that limit the region, and -`prop-match-value' for the value of PROPERTY in the region." - (let* ((match-p - (lambda (prop-value) - (funcall - (cond - ((eq predicate t) - #'equal) - ((eq predicate nil) - (lambda (val p-val) - (not (equal val p-val)))) - (predicate)) - value prop-value))) - (find-end - (lambda (start) - (let (end) - (if (and value - (null predicate)) - ;; This is the normal case: We're looking for areas where the - ;; values aren't, so we aren't interested in sub-areas where the - ;; property has different values, all non-matching value. - (let ((ended nil)) - (while (not ended) - (setq end (next-single-property-change (point) property)) - (if (not end) - (progn - (goto-char (point-max)) - (setq end (point) - ended t)) - (goto-char end) - (unless (funcall match-p (get-text-property (point) property)) - (setq ended t))))) - ;; End this at the first place the property changes value. - (setq end (next-single-property-change (point) property nil (point-max))) - (goto-char end)) - (make-prop-match - :beginning start - :end end - :value (get-text-property start property)))))) - (cond - ;; No matches at the end of the buffer. - ((eobp) - nil) - ;; We're standing in the property we're looking for, so find the - ;; end. - ((and (funcall match-p (get-text-property (point) property)) - (not not-current)) - (funcall find-end (point))) - (t - (let ((origin (point)) - (ended nil) - pos) - ;; Find the next candidate. - (while (not ended) - (setq pos (next-single-property-change (point) property)) - (if (not pos) - (progn - (goto-char origin) - (setq ended t)) - (goto-char pos) - (if (funcall match-p (get-text-property (point) property)) - (setq ended (funcall find-end (point))) - ;; Skip past this section of non-matches. - (setq pos (next-single-property-change (point) property)) - (unless pos - (goto-char origin) - (setq ended t))))) - (and (not (eq ended t)) - ended)))))) - -(compat-defun text-property-search-backward ;; - (property &optional value predicate not-current) - "Search for the previous region of text whose PROPERTY matches VALUE. - -Like `text-property-search-forward', which see, but searches backward, -and if a matching region is found, place point at the start of the region." - (let* ((match-p - (lambda (prop-value) - (funcall - (cond - ((eq predicate t) - #'equal) - ((eq predicate nil) - (lambda (val p-val) - (not (equal val p-val)))) - (predicate)) - value prop-value))) - (find-end - (lambda (start) - (let (end) - (if (and value - (null predicate)) - ;; This is the normal case: We're looking for areas where the - ;; values aren't, so we aren't interested in sub-areas where the - ;; property has different values, all non-matching value. - (let ((ended nil)) - (while (not ended) - (setq end (previous-single-property-change (point) property)) - (if (not end) - (progn - (goto-char (point-min)) - (setq end (point) - ended t)) - (goto-char (1- end)) - (unless (funcall match-p (get-text-property (point) property)) - (goto-char end) - (setq ended t))))) - ;; End this at the first place the property changes value. - (setq end (previous-single-property-change - (point) property nil (point-min))) - (goto-char end)) - (make-prop-match - :beginning end - :end (1+ start) - :value (get-text-property end property)))))) - (cond - ;; We're at the start of the buffer; no previous matches. - ((bobp) - nil) - ;; We're standing in the property we're looking for, so find the - ;; end. - ((funcall match-p (get-text-property (1- (point)) property)) - (let ((origin (point)) - (match (funcall find-end (1- (point)) property value predicate))) - ;; When we want to ignore the current element, then repeat the - ;; search if we haven't moved out of it yet. - (if (and not-current - (equal (get-text-property (point) property) - (get-text-property origin property))) - (text-property-search-backward property value predicate) - match))) - (t - (let ((origin (point)) - (ended nil) - pos) - ;; Find the previous candidate. - (while (not ended) - (setq pos (previous-single-property-change (point) property)) - (if (not pos) - (progn - (goto-char origin) - (setq ended t)) - (goto-char (1- pos)) - (if (funcall match-p (get-text-property (point) property)) - (setq ended - (funcall find-end (point))) - ;; Skip past this section of non-matches. - (setq pos (previous-single-property-change (point) property)) - (unless pos - (goto-char origin) - (setq ended t))))) - (and (not (eq ended t)) - ended)))))) - ;;;; Defined in ring.el (compat-defun ring-resize (ring size) ;; diff --git a/compat-tests.el b/compat-tests.el index ba6cec4..d18e973 100644 --- a/compat-tests.el +++ b/compat-tests.el @@ -55,7 +55,6 @@ (require 'subr-x) (require 'time-date) (require 'image) -(require 'text-property-search nil t) ;; Setup tramp mock (require 'tramp) @@ -2380,63 +2379,6 @@ (should-equal (compat-call plist-get plist "one" #'string=) "eins") (should-equal plist '("one" "eins" "two" 2 "three" 3)))) -(ert-deftest prop-match () - (should (prop-match-p (make-prop-match))) - (should (prop-match-p (make-prop-match :end 1))) - (should (prop-match-p (make-prop-match :beginning 1 :end 2 :value 3))) - (should-equal 1 (prop-match-beginning (make-prop-match :beginning 1 :end 2 :value 3))) - (should-equal 2 (prop-match-end (make-prop-match :beginning 1 :end 2 :value 3))) - (should-equal 3 (prop-match-value (make-prop-match :beginning 1 :end 2 :value 3))) - (should-not (prop-match-p nil)) - (should-not (prop-match-p [])) - (should-not (prop-match-p 'symbol)) - (should-not (prop-match-p "string")) - (should-not (prop-match-p '(1 2 3)))) - -(ert-deftest text-property-search-forward () - (with-temp-buffer - (insert "one " - (propertize "two " 'prop 'val) - "three " - (propertize "four " 'prop 'wert) - "five ") - (goto-char (point-min)) - (let ((match (text-property-search-forward 'prop))) - (should (prop-match-p match)) - (should-equal (prop-match-beginning match) 5) - (should-equal (prop-match-end match) 9) - (should-equal (prop-match-value match) 'val)) - (let ((match (text-property-search-forward 'prop))) - (should (prop-match-p match)) - (should-equal (prop-match-beginning match) 15) - (should-equal (prop-match-end match) 20) - (should-equal (prop-match-value match) 'wert)) - (should-not (text-property-search-forward 'prop)) - (goto-char (point-min)) - (should-not (text-property-search-forward 'non-existant)))) - -(ert-deftest text-property-search-backward () - (with-temp-buffer - (insert "one " - (propertize "two " 'prop 'val) - "three " - (propertize "four " 'prop 'wert) - "five ") - (goto-char (point-max)) - (let ((match (text-property-search-backward 'prop))) - (should (prop-match-p match)) - (should-equal (prop-match-beginning match) 15) - (should-equal (prop-match-end match) 20) - (should-equal (prop-match-value match) 'wert)) - (let ((match (text-property-search-backward 'prop))) - (should (prop-match-p match)) - (should-equal (prop-match-beginning match) 5) - (should-equal (prop-match-end match) 9) - (should-equal (prop-match-value match) 'val)) - (should-not (text-property-search-backward 'prop)) - (goto-char (point-max)) - (should-not (text-property-search-backward 'non-existant)))) - (ert-deftest color-dark-p () (should (color-dark-p '(0 0 0))) (should (color-dark-p '(0.5 0.5 0.5))) diff --git a/compat.texi b/compat.texi index 521ca11..c64565e 100644 --- a/compat.texi +++ b/compat.texi @@ -1424,97 +1424,6 @@ This function creates an empty file named @var{filename}. As function signals an error. @end defun -@defun text-property-search-forward prop &optional value predicate not-current -Search for the next region that has text property @var{prop} set to -@var{value} according to @var{predicate}. - -This function is modeled after @code{search-forward} and friends in -that it moves point, but it returns a structure that describes the -match instead of returning it in @code{match-beginning} and friends. - -If the text property can't be found, the function returns @code{nil}. -If it's found, point is placed at the end of the region that has this -text property match, and a @code{prop-match} structure is returned. - -@var{predicate} can either be @code{t} (which is a synonym for -@code{equal}), @code{nil} (which means ``not equal''), or a predicate -that will be called with two parameters: The first is @var{value}, and -the second is the value of the text property we're inspecting. - -If @var{not-current}, if point is in a region where we have a match, -then skip past that and find the next instance instead. - -The @code{prop-match} structure has the following accessors: -@code{prop-match-beginning} (the start of the match), -@code{prop-match-end} (the end of the match), and -@code{prop-match-value} (the value of @var{property} at the start of -the match). - -In the examples below, imagine that you're in a buffer that looks like -this: - -@example -This is a bold and here's bolditalic and this is the end. -@end example - -That is, the ``bold'' words are the @code{bold} face, and the -``italic'' word is in the @code{italic} face. - -With point at the start: - -@lisp -(while (setq match (text-property-search-forward 'face 'bold t)) - (push (buffer-substring (prop-match-beginning match) - (prop-match-end match)) - words)) -@end lisp - -This will pick out all the words that use the @code{bold} face. - -@lisp -(while (setq match (text-property-search-forward 'face nil t)) - (push (buffer-substring (prop-match-beginning match) - (prop-match-end match)) - words)) -@end lisp - -This will pick out all the bits that have no face properties, which -will result in the list @samp{("This is a " "and here's " "and this is -the end")} (only reversed, since we used @code{push}). - -@lisp -(while (setq match (text-property-search-forward 'face nil nil)) - (push (buffer-substring (prop-match-beginning match) - (prop-match-end match)) - words)) -@end lisp - -This will pick out all the regions where @code{face} is set to -something, but this is split up into where the properties change, so -the result here will be @samp{("bold" "bold" "italic")}. - -For a more realistic example where you might use this, consider that -you have a buffer where certain sections represent URLs, and these are -tagged with @code{shr-url}. - -@lisp -(while (setq match (text-property-search-forward 'shr-url nil nil)) - (push (prop-match-value match) urls)) -@end lisp - -This will give you a list of all those URLs. - -@xref{elisp,,,Property Search}. -@end defun - -@defun text-property-search-backward prop &optional value predicate not-current -This is just like @code{text-property-search-forward}, but searches -backward instead. Point is placed at the beginning of the matched -region instead of the end, though. - -@xref{elisp,,,Property Search}. -@end defun - @subsection Extended Definitions These functions must be called explicitly via @code{compat-call}, since their calling convention or behavior was extended in Emacs 27.1: @@ -1673,6 +1582,8 @@ The @code{iso8601} library. @item The @code{exif} library. @item +The @code{text-property-search} library. +@item The @code{image-converter} library. @end itemize -- cgit v1.0