[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 5281946fbf 1/3: Make format-spec accept function substitutions
From: |
Stefan Kangas |
Subject: |
master 5281946fbf 1/3: Make format-spec accept function substitutions |
Date: |
Thu, 29 Sep 2022 10:10:39 -0400 (EDT) |
branch: master
commit 5281946fbf6b3cdbec5ce82e0057c71849faf4d2
Author: Stefan Kangas <stefankangas@gmail.com>
Commit: Stefan Kangas <stefankangas@gmail.com>
Make format-spec accept function substitutions
* lisp/format-spec.el (format-spec): Accept a function producing the
substitution for a character.
* doc/lispref/strings.texi (Custom Format Strings): Document the
above change.
* test/lisp/format-spec-tests.el (format-spec/function): New test.
Ref. https://lists.gnu.org/r/emacs-devel/2022-09/msg01875.html
---
doc/lispref/strings.texi | 5 +++++
etc/NEWS | 6 ++++++
lisp/format-spec.el | 17 +++++++++++++++--
test/lisp/format-spec-tests.el | 11 +++++++++++
4 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index 374381e595..ba247a3eda 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -1293,6 +1293,11 @@ The order of specifications in @var{template} need not
correspond to
the order of associations in @var{spec-alist}.
@end itemize
+REPLACEMENT can also be a function taking no arguments, and returning
+a string to be used for the replacement. It will only be called when
+the corresponding LETTER is used in the TEMPLATE. This is useful, for
+example, to avoid prompting for input unless it is needed.
+
The optional argument @var{ignore-missing} indicates how to handle
specification characters in @var{template} that are not found in
@var{spec-alist}. If it is @code{nil} or omitted, the function
diff --git a/etc/NEWS b/etc/NEWS
index 4bab95da51..2f96072bfb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3926,6 +3926,12 @@ the same but works by modifying LIST destructively.
---
** 'string-split' is now an alias for 'split-string'.
++++
+** 'format-spec' now accepts functions in the replacement.
+The function is called only when used in the format string. This is
+useful to avoid side-effects such as prompting, when the value is not
+actually being used for anything.
+
+++
** The variable 'max-specpdl-size' has been made obsolete.
Now 'max-lisp-eval-depth' alone is used for limiting Lisp recursion
diff --git a/lisp/format-spec.el b/lisp/format-spec.el
index 45c19aebc8..60ff9f9086 100644
--- a/lisp/format-spec.el
+++ b/lisp/format-spec.el
@@ -59,6 +59,18 @@ value associated with ?b in SPECIFICATION, either padding it
with
leading zeros or truncating leading characters until it's ten
characters wide\".
+the substitution for a specification character can also be a
+function, taking no arguments and returning a string to be used
+for the replacement. It will only be called if FORMAT uses that
+character. For example:
+
+ (format-spec \"%n\"
+ \\=`((?n . ,(lambda ()
+ (read-number \"Number: \")))))
+
+Note that it is best to make sure the function is not quoted,
+like above, so that it is compiled by the byte-compiler.
+
Any text properties of FORMAT are copied to the result, with any
text properties of a %-spec itself copied to its substitution.
@@ -94,14 +106,15 @@ is returned, where each format spec is its own element."
(width (match-string 2))
(trunc (match-string 3))
(char (string-to-char (match-string 4)))
- (text (assq char specification)))
+ (text (let ((res (cdr (assq char specification))))
+ (if (functionp res) (funcall res) res))))
(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 "%s" text)
(format-spec--parse-flags flags)
(and width (string-to-number width))
(and trunc (car (read-from-string trunc 1)))))
diff --git a/test/lisp/format-spec-tests.el b/test/lisp/format-spec-tests.el
index 4a3cc74c33..bd493ae1d7 100644
--- a/test/lisp/format-spec-tests.el
+++ b/test/lisp/format-spec-tests.el
@@ -148,6 +148,17 @@
(format-spec fmt '((?b . "asd") (?a . "fgh")))
#("fgh%asdasd" 0 3 (a b) 3 4 (c d) 7 10 (e f))))))
+(ert-deftest format-spec/function ()
+ (let* (called
+ (spec `((?a . "foo")
+ (?f . ,(lambda ()
+ (setq called t)
+ "bar")))))
+ (should (equal (format-spec "%a" spec) "foo"))
+ (should-not called)
+ (should (equal (format-spec "%f" spec) "bar"))
+ (should called)))
+
(ert-deftest format-spec-unknown ()
(should-error (format-spec "foo %b %z zot" '((?b . "bar"))))
(should-error (format-spec "foo %b %%%z zot" '((?b . "bar"))))