emacs-diffs
[Top][All Lists]
Advanced

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

master 40d1633 1/2: Add a SPLIT parameter to `format-spec'


From: Lars Ingebrigtsen
Subject: master 40d1633 1/2: Add a SPLIT parameter to `format-spec'
Date: Mon, 28 Dec 2020 21:10:11 -0500 (EST)

branch: master
commit 40d16332597d3aa564c9950ae1831faf6867c71a
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Add a SPLIT parameter to `format-spec'
    
    * doc/lispref/strings.texi (Custom Format Strings): Document it.
    
    * lisp/format-spec.el (format-spec): Add an optional parameter to
    return a list of strings (bug#33740).
---
 doc/lispref/strings.texi       |  12 ++++-
 etc/NEWS                       |   5 ++
 lisp/format-spec.el            | 103 +++++++++++++++++++++++------------------
 test/lisp/format-spec-tests.el |  10 ++++
 4 files changed, 85 insertions(+), 45 deletions(-)

diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index a31e71d..4ac5057 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -1216,7 +1216,7 @@ The function @code{format-spec} described in this section 
performs a
 similar function to @code{format}, except it operates on format
 control strings that use arbitrary specification characters.
 
-@defun format-spec template spec-alist &optional ignore-missing
+@defun format-spec template spec-alist &optional ignore-missing split
 This function returns a string produced from the format string
 @var{template} according to conversions specified in @var{spec-alist},
 which is an alist (@pxref{Association Lists}) of the form
@@ -1258,6 +1258,16 @@ any; if it is @code{delete}, those format specifications 
are removed
 from the output; any other non-@code{nil} value is handled like
 @code{ignore}, but any occurrences of @samp{%%} are also left verbatim
 in the output.
+
+If the optional argument @var{split} is non-@code{nil}, instead of
+returning a single string, @code{format-spec} will split the result
+into a list of strings, based on where the substitutions were
+performed.  For instance:
+
+@example
+(format-spec "foo %b bar" '((?b . "zot")) nil t)
+     @result{} ("foo " "zot" " bar")
+@end example
 @end defun
 
 The syntax of format specifications accepted by @code{format-spec} is
diff --git a/etc/NEWS b/etc/NEWS
index f828269..cd40061 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2179,6 +2179,11 @@ In order for the two functions to behave more 
consistently,
 length, and also supports format specifications that include a
 truncating precision field, such as "%.2a".
 
++++
+** 'format-spec' now takes an optional SPLIT parameter.
+If non-nil, 'format-spec' will split the resulting string into a list
+of strings, based on where the format specs (and expansions) were.
+
 ---
 ** New function 'color-values-from-color-spec'.
 This can be used to parse RGB color specs in several formats and
diff --git a/lisp/format-spec.el b/lisp/format-spec.el
index 6af79a4..3abcd51 100644
--- a/lisp/format-spec.el
+++ b/lisp/format-spec.el
@@ -25,7 +25,7 @@
 ;;; Code:
 
 ;;;###autoload
-(defun format-spec (format specification &optional ignore-missing)
+(defun format-spec (format specification &optional ignore-missing split)
   "Return a string based on FORMAT and SPECIFICATION.
 FORMAT is a string containing `format'-like specs like \"su - %u %k\".
 SPECIFICATION is an alist mapping format specification characters
@@ -68,50 +68,65 @@ error; if it is the symbol `ignore', leave those %-specs 
verbatim
 in the result, including their text properties, if any; if it is
 the symbol `delete', remove those %-specs from the result;
 otherwise do the same as for the symbol `ignore', but also leave
-any occurrences of \"%%\" in FORMAT verbatim in the result."
+any occurrences of \"%%\" in FORMAT verbatim in the result.
+
+If SPLIT, instead of returning a single string, a list of strings
+is returned, where each format spec is its own element."
   (with-temp-buffer
-    (insert format)
-    (goto-char (point-min))
-    (while (search-forward "%" nil t)
-      (cond
-       ;; Quoted percent sign.
-       ((= (following-char) ?%)
-        (when (memq ignore-missing '(nil ignore delete))
-          (delete-char 1)))
-       ;; Valid format spec.
-       ((looking-at (rx (? (group (+ (in " 0<>^_-"))))
-                        (? (group (+ digit)))
-                        (? (group ?. (+ digit)))
-                        (group alpha)))
-        (let* ((beg (point))
-               (end (match-end 0))
-               (flags (match-string 1))
-               (width (match-string 2))
-               (trunc (match-string 3))
-               (char (string-to-char (match-string 4)))
-               (text (assq char specification)))
-          (cond (text
-                 ;; Handle flags.
-                 (setq text (format-spec--do-flags
-                             (format "%s" (cdr text))
-                             (format-spec--parse-flags flags)
-                             (and width (string-to-number width))
-                             (and trunc (car (read-from-string trunc 1)))))
-                 ;; Insert first, to preserve text properties.
-                 (insert-and-inherit text)
-                 ;; Delete the specifier body.
-                 (delete-region (point) (+ end (length text)))
-                 ;; Delete the percent sign.
-                 (delete-region (1- beg) beg))
-                ((eq ignore-missing 'delete)
-                 ;; Delete the whole format spec.
-                 (delete-region (1- beg) end))
-                ((not ignore-missing)
-                 (error "Invalid format character: `%%%c'" char)))))
-       ;; Signal an error on bogus format strings.
-       ((not ignore-missing)
-        (error "Invalid format string"))))
-    (buffer-string)))
+    (let ((split-start (point-min))
+          (split-result nil))
+      (insert format)
+      (goto-char (point-min))
+      (while (search-forward "%" nil t)
+        (cond
+         ;; Quoted percent sign.
+         ((= (following-char) ?%)
+          (when (memq ignore-missing '(nil ignore delete))
+            (delete-char 1)))
+         ;; Valid format spec.
+         ((looking-at (rx (? (group (+ (in " 0<>^_-"))))
+                          (? (group (+ digit)))
+                          (? (group ?. (+ digit)))
+                          (group alpha)))
+          (let* ((beg (point))
+                 (end (match-end 0))
+                 (flags (match-string 1))
+                 (width (match-string 2))
+                 (trunc (match-string 3))
+                 (char (string-to-char (match-string 4)))
+                 (text (assq char specification)))
+            (when (and split
+                       (not (= (1- beg) split-start)))
+              (push (buffer-substring split-start (1- beg)) split-result))
+            (cond (text
+                   ;; Handle flags.
+                   (setq text (format-spec--do-flags
+                               (format "%s" (cdr text))
+                               (format-spec--parse-flags flags)
+                               (and width (string-to-number width))
+                               (and trunc (car (read-from-string trunc 1)))))
+                   ;; Insert first, to preserve text properties.
+                   (insert-and-inherit text)
+                   ;; Delete the specifier body.
+                   (delete-region (point) (+ end (length text)))
+                   ;; Delete the percent sign.
+                   (delete-region (1- beg) beg))
+                  ((eq ignore-missing 'delete)
+                   ;; Delete the whole format spec.
+                   (delete-region (1- beg) end))
+                  ((not ignore-missing)
+                   (error "Invalid format character: `%%%c'" char)))
+            (when split
+              (push (buffer-substring (1- beg) (point)) split-result)
+              (setq split-start (point)))))
+         ;; Signal an error on bogus format strings.
+         ((not ignore-missing)
+          (error "Invalid format string"))))
+      (if (not split)
+          (buffer-string)
+        (unless (= split-start (point-max))
+          (push (buffer-substring split-start (point-max)) split-result))
+        (nreverse split-result)))))
 
 (defun format-spec--do-flags (str flags width trunc)
   "Return STR formatted according to FLAGS, WIDTH, and TRUNC.
diff --git a/test/lisp/format-spec-tests.el b/test/lisp/format-spec-tests.el
index 1188221..cced862 100644
--- a/test/lisp/format-spec-tests.el
+++ b/test/lisp/format-spec-tests.el
@@ -178,4 +178,14 @@
   (should (equal (format-spec "foo %>4b zot" '((?b . "longbar")))
                  "foo long zot")))
 
+(ert-deftest format-spec-split ()
+  (should (equal (format-spec "foo %b bar" '((?b . "zot")) nil t)
+                 '("foo " "zot" " bar")))
+  (should (equal (format-spec "%b bar" '((?b . "zot")) nil t)
+                 '("zot" " bar")))
+  (should (equal (format-spec "%b" '((?b . "zot")) nil t)
+                 '("zot")))
+  (should (equal (format-spec "foo %b" '((?b . "zot")) nil t)
+                 '("foo " "zot"))))
+
 ;;; format-spec-tests.el ends here



reply via email to

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