bug#41758: 28.0.50; Fix and extend format-spec

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

bug#41758: 28.0.50; Fix and extend format-spec

Basil L. Contovounesios
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


0001-Fix-and-extend-format-spec.patch (50K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

bug#41758: 28.0.50; Fix and extend format-spec

Basil L. Contovounesios
"Basil L. Contovounesios" <[hidden email]> writes:

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

Any objections to installing this on master?

--
Basil



Reply | Threaded
Open this post in threaded view
|

bug#41758: 28.0.50; Fix and extend format-spec

Basil L. Contovounesios
tags 41758 fixed
close 41758 28.1
quit

Pushed to master and closing.

Fix and extend format-spec (bug#41758)
0185d76e74 2020-06-18 12:46:21 +0100
https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=0185d76e7426eb1b58a9b60b0d18e763ddf57dea

--
Basil