Tags: patch I attach a patch which fixes and extends some of the changes made to format-spec's behaviour in Emacs 27. Some of the proposed changes were already alluded to in the discussion of bug#41571. --- Before Emacs 27, format-spec was implemented in terms of 'format', allowing e.g.: (format-spec "%.2s" '((?s . "שָׁלוֹם"))) ; => "שָׁל" In Emacs 27, a precision modifier ".N" is still supported (doesn't signal an error), but is a no-op: (format-spec "%.2s" '((?s . "שָׁלוֹם"))) ; => "שָׁלוֹם" This is arguably a regression (since format-spec's docstring historically said it supported "'format'-like specs" without explicitly listing the precision modifier as one of them). I wouldn't be surprised if someone misses this feature. Instead, Emacs 27 added the notion of "padding or truncating" (as a single operation) to a desired length: (format-spec "%>2s" '((?s . "שָׁלוֹם"))) ; => "שָ" There are two problems with this: 0. Unlike 'format', it truncates to length rather than width. 1. It is impossible to specify separate padding and truncation, e.g.: (format "%3.2s" "שָׁלוֹם") ; => " שָׁל" The attached patch brings back 'format'-like truncation based on string width, and separate from padding: (format-spec "%>2s" '((?s . "שָׁלוֹם"))) ; => "שָׁל" (format-spec "%3.2s" '((?s . "שָׁלוֹם"))) ; => " שָׁל" (let ((f "%3.2s") (s "שָׁלוֹם")) (equal (format-spec f `((?s . ,s))) (format f s))) ; => t --- Emacs 27 also added an optional third argument for ignoring the case when the caller does not provide a particular replacement, e.g.: (format-spec "%s" ()) ; => (error "Invalid format character: ‘%s’") (format-spec "%s" () t) ; => "%s" The problem with a non-nil third argument is that it also unconditionally leaves '%%' verbatim in the output: (format-spec "%%%s" () t) ; => "%%%s" I'm sure this has its uses, but I find it a surprising default since the replacement of '%%' is always known. The function battery-format in lisp/battery.el is an example of where the usual replacement of '%%' is desirable, even when some replacements are not provided. The attached patch therefore adds two new special values to the optional third argument: (format-spec "%%%s" () 'ignore) ; => "%%s" (format-spec "%%%s" () 'delete) ; => "%" Together with the Emacs 27 behaviour, I think these should cover most bases. WDYT? Thanks, -- Basil