From 7f98d9c6d59472abf189ccd5a5c76415f9d1cbb3 Mon Sep 17 00:00:00 2001 From: Philipp Stephani
Date: Wed, 31 May 2017 22:09:39 -0700 Subject: [PATCH 1/2] Implement field numbers in format strings A field number explicitly specifies the argument to be formatted. This is especially important for potential localization work, since grammars of various languages dictate different word orders. * src/editfns.c (Fformat): Update documentation. (styled_format): Implement field numbers. * doc/lispref/strings.texi (Formatting Strings): Document field numbers. * lisp/emacs-lisp/bytecomp.el (byte-compile-format-warn): Adapt. * test/src/editfns-tests.el (format-with-field): New unit test. --- doc/lispref/strings.texi | 31 ++++++++++++++++++++++--- etc/NEWS | 3 +++ lisp/emacs-lisp/bytecomp.el | 11 ++++++--- src/editfns.c | 55 ++++++++++++++++++++++++++++++++++++++------- test/src/editfns-tests.el | 18 +++++++++++++++ 5 files changed, 104 insertions(+), 14 deletions(-) diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 9436a96..9bf52f2 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -864,7 +864,8 @@ Formatting Strings (format "%s" @var{arbitrary-string}) @end example - If @var{string} contains more than one format specification, the + If @var{string} contains more than one format specification and none +of the format specifications contain an explicit field number, the format specifications correspond to successive values from @var{objects}. Thus, the first format specification in @var{string} uses the first such value, the second format specification uses the @@ -961,6 +962,25 @@ Formatting Strings @end group @end example address@hidden field number + A specification can have a @dfn{field number}, which is a decimal +number after the initial @samp{%}, followed by a literal dollar sign address@hidden If you provide a field numer, then the argument to be +printed corresponds to the given field number instead of the next +argument. Field numbers start at 1. + +You can mix specifications with and without field numbers. A +specification without a field number that follows a specification with +a field number will convert the argument after the one specified by +the field number: + address@hidden +(format "First argument %2$s, then %s, then %1$s" 1 2 3) + @result{} "First argument 2, then 3, then 1" address@hidden example + +You can't use field numbers in a @samp{%%} specification. + @cindex field width @cindex padding A specification can have a @dfn{width}, which is a decimal number @@ -996,9 +1016,14 @@ Formatting Strings @end group @end example +If you want to use both a field number and a width, place the field +number before the width. For example, in @samp{%2$7s}, @samp{2} is +the field number and @samp{7} is the width. + @cindex flags in format specifications - Immediately after the @samp{%} and before the optional width -specifier, you can also put certain @dfn{flag characters}. + After the @samp{%} and before the optional width specifier, you can +also put certain @dfn{flag characters}. The flag characters need to +come directly after a potential field number. The flag @samp{+} inserts a plus sign before a positive number, so that it always has a sign. A space character as flag inserts a space diff --git a/etc/NEWS b/etc/NEWS index 43e7897..e31c0c7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -364,6 +364,9 @@ large integers from being displayed as characters. ** Two new commands for finding the source code of Emacs Lisp libraries: 'find-library-other-window' and 'find-library-other-frame'. +** You can now provide explicit field numbers in format specifiers. +For example, '(format "%2$s %1$s" 1 2)' produces "2 1". + * Editing Changes in Emacs 26.1 diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 12a7d4a..e5b9b47 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -1375,10 +1375,15 @@ byte-compile-format-warn (let ((nfields (with-temp-buffer (insert (nth 1 form)) (goto-char (point-min)) - (let ((n 0)) + (let ((i 0) (n 0)) (while (re-search-forward "%." nil t) - (unless (eq ?% (char-after (1+ (match-beginning 0)))) - (setq n (1+ n)))) + (backward-char) + (unless (eq ?% (char-after)) + (setq i (if (looking-at "\\([0-9]+\\)\\$") + (string-to-number (match-string 1) 10) + (1+ i)) + n (max n i))) + (forward-char)) n))) (nargs (- (length form) 2))) (unless (= nargs nfields) diff --git a/src/editfns.c b/src/editfns.c index 89a6724..44341ce 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -48,6 +48,7 @@ along with GNU Emacs. If not, see