]> git.eshelyaron.com Git - emacs.git/commitdiff
Add a SPLIT parameter to `format-spec'
authorLars Ingebrigtsen <larsi@gnus.org>
Tue, 29 Dec 2020 02:04:51 +0000 (03:04 +0100)
committerLars Ingebrigtsen <larsi@gnus.org>
Tue, 29 Dec 2020 02:04:51 +0000 (03:04 +0100)
* 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
etc/NEWS
lisp/format-spec.el
test/lisp/format-spec-tests.el

index a31e71d5260c466c00a09c5354aa23bef2dbd380..4ac5057454fa00cf8f5caaed3fc14c00970472c8 100644 (file)
@@ -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
index f8282696e4602705e04b2c34ac36a191f6568d58..cd4006170d284a20a3e3fdc6fa25160610444172 100644 (file)
--- 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
index 6af79a44167aa3d43f977d9c7a4be22319ef2b8d..3abcd5183a3ac1ecbc96e8e3aed7208412f4a933 100644 (file)
@@ -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.
index 11882217afb54a80627fab67fc7a4dd2270855aa..cced8623330466e4c8cd5e58daededcbdf53387e 100644 (file)
   (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