aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2019-07-11 18:44:30 +0200
committerLars Ingebrigtsen2019-07-11 18:44:30 +0200
commitb44f0c457997af53808218536ebfdf507ddb5995 (patch)
treec4fc4df143a0e913b8c6d9ea91ac159b4afd102f
parentb41ddb7a8b11c8234e2f010d0db1b13e395468ae (diff)
downloademacs-b44f0c457997af53808218536ebfdf507ddb5995.tar.gz
emacs-b44f0c457997af53808218536ebfdf507ddb5995.zip
Allow passing unknown specs to format-spec
* lisp/format-spec.el (format-spec): Allow passing through format strings that have no specs (to be able to act as a filter). Also add an example. * test/lisp/format-spec-tests.el (test-format-spec): Add tests for the new functionality.
-rw-r--r--lisp/format-spec.el69
-rw-r--r--test/lisp/format-spec-tests.el12
2 files changed, 53 insertions, 28 deletions
diff --git a/lisp/format-spec.el b/lisp/format-spec.el
index 4455c594286..cf2d364bb28 100644
--- a/lisp/format-spec.el
+++ b/lisp/format-spec.el
@@ -24,40 +24,55 @@
24 24
25;;; Code: 25;;; Code:
26 26
27(defun format-spec (format specification) 27(defun format-spec (format specification &optional only-present)
28 "Return a string based on FORMAT and SPECIFICATION. 28 "Return a string based on FORMAT and SPECIFICATION.
29FORMAT is a string containing `format'-like specs like \"bash %u %k\", 29FORMAT is a string containing `format'-like specs like \"su - %u %k\",
30while SPECIFICATION is an alist mapping from format spec characters 30while SPECIFICATION is an alist mapping from format spec characters
31to values. Any text properties on a %-spec itself are propagated to 31to values.
32the text that it generates." 32
33For instance:
34
35 (format-spec \"su - %u %k\"
36 `((?u . ,(user-login-name))
37 (?k . \"ls\")))
38
39Any text properties on a %-spec itself are propagated to the text
40that it generates.
41
42If ONLY-PRESENT, format spec characters not present in
43SPECIFICATION are ignored, and the \"%\" characters are left
44where they are, including \"%%\" strings."
33 (with-temp-buffer 45 (with-temp-buffer
34 (insert format) 46 (insert format)
35 (goto-char (point-min)) 47 (goto-char (point-min))
36 (while (search-forward "%" nil t) 48 (while (search-forward "%" nil t)
37 (cond 49 (cond
38 ;; Quoted percent sign. 50 ;; Quoted percent sign.
39 ((eq (char-after) ?%) 51 ((eq (char-after) ?%)
40 (delete-char 1)) 52 (unless only-present
41 ;; Valid format spec. 53 (delete-char 1)))
42 ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]\\)") 54 ;; Valid format spec.
43 (let* ((num (match-string 1)) 55 ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]\\)")
44 (spec (string-to-char (match-string 2))) 56 (let* ((num (match-string 1))
45 (val (assq spec specification))) 57 (spec (string-to-char (match-string 2)))
46 (unless val 58 (val (assq spec specification)))
47 (error "Invalid format character: `%%%c'" spec)) 59 (if (not val)
48 (setq val (cdr val)) 60 (unless only-present
49 ;; Pad result to desired length. 61 (error "Invalid format character: `%%%c'" spec))
50 (let ((text (format (concat "%" num "s") val))) 62 (setq val (cdr val))
51 ;; Insert first, to preserve text properties. 63 ;; Pad result to desired length.
52 (insert-and-inherit text) 64 (let ((text (format (concat "%" num "s") val)))
53 ;; Delete the specifier body. 65 ;; Insert first, to preserve text properties.
54 (delete-region (+ (match-beginning 0) (length text)) 66 (insert-and-inherit text)
55 (+ (match-end 0) (length text))) 67 ;; Delete the specifier body.
56 ;; Delete the percent sign. 68 (delete-region (+ (match-beginning 0) (length text))
57 (delete-region (1- (match-beginning 0)) (match-beginning 0))))) 69 (+ (match-end 0) (length text)))
58 ;; Signal an error on bogus format strings. 70 ;; Delete the percent sign.
59 (t 71 (delete-region (1- (match-beginning 0)) (match-beginning 0))))))
60 (error "Invalid format string")))) 72 ;; Signal an error on bogus format strings.
73 (t
74 (unless only-present
75 (error "Invalid format string")))))
61 (buffer-string))) 76 (buffer-string)))
62 77
63(defun format-spec-make (&rest pairs) 78(defun format-spec-make (&rest pairs)
diff --git a/test/lisp/format-spec-tests.el b/test/lisp/format-spec-tests.el
index a5c62ac9ce3..e831657a3e6 100644
--- a/test/lisp/format-spec-tests.el
+++ b/test/lisp/format-spec-tests.el
@@ -23,11 +23,21 @@
23(require 'format-spec) 23(require 'format-spec)
24 24
25(ert-deftest test-format-spec () 25(ert-deftest test-format-spec ()
26 (should (equal (format-spec "foo %b zot" '((?b . "bar"))) 26 (should (equal (format-spec "foo %b zot" `((?b . "bar")))
27 "foo bar zot")) 27 "foo bar zot"))
28 (should (equal (format-spec "foo %-10b zot" '((?b . "bar"))) 28 (should (equal (format-spec "foo %-10b zot" '((?b . "bar")))
29 "foo bar zot")) 29 "foo bar zot"))
30 (should (equal (format-spec "foo %10b zot" '((?b . "bar"))) 30 (should (equal (format-spec "foo %10b zot" '((?b . "bar")))
31 "foo bar zot"))) 31 "foo bar zot")))
32 32
33(ert-deftest test-format-unknown ()
34 (should (eq (condition-case _
35 (format-spec "foo %b %z zot" '((?b . "bar")))
36 (error :error))
37 :error))
38 (should (equal (format-spec "foo %b %z zot" '((?b . "bar")) t)
39 "foo bar %z zot"))
40 (should (equal (format-spec "foo %b %z %% zot" '((?b . "bar")) t)
41 "foo bar %z %% zot")))
42
33;;; format-spec-tests.el ends here 43;;; format-spec-tests.el ends here