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
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
;;; 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
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.