From unknown Mon Jun 16 23:55:33 2025 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.509 (Entity 5.509) Content-Type: text/plain; charset=utf-8 From: bug#41571 <41571@debbugs.gnu.org> To: bug#41571 <41571@debbugs.gnu.org> Subject: Status: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" Reply-To: bug#41571 <41571@debbugs.gnu.org> Date: Tue, 17 Jun 2025 06:55:33 +0000 retitle 41571 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Tex= t" reassign 41571 emacs submitter 41571 "Basil L. Contovounesios" severity 41571 minor tag 41571 fixed patch thanks From debbugs-submit-bounces@debbugs.gnu.org Wed May 27 19:57:44 2020 Received: (at submit) by debbugs.gnu.org; 27 May 2020 23:57:45 +0000 Received: from localhost ([127.0.0.1]:50331 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1je5vc-0007ZS-8c for submit@debbugs.gnu.org; Wed, 27 May 2020 19:57:44 -0400 Received: from lists.gnu.org ([209.51.188.17]:57774) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1je5va-0007ZL-ML for submit@debbugs.gnu.org; Wed, 27 May 2020 19:57:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59964) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1je5va-0001YZ-Do for bug-gnu-emacs@gnu.org; Wed, 27 May 2020 19:57:42 -0400 Received: from mail-wm1-x343.google.com ([2a00:1450:4864:20::343]:39677) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1je5vY-0006PK-HE for bug-gnu-emacs@gnu.org; Wed, 27 May 2020 19:57:42 -0400 Received: by mail-wm1-x343.google.com with SMTP id k26so1357638wmi.4 for ; Wed, 27 May 2020 16:57:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tcd-ie.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:mime-version; bh=unbdSy0OAg9x6Fvo3R1XO6497auQkOJejjFwRssFYB8=; b=SUF2jeIQnH0csI3SkBwpBonujb04lmUbVP1AY+kNtrK/FiJzP9p/i/hFvM9wPzGlvU wEGVwQ0R8vbc1qDJhzOxFWW/pxLqwkbFJYOv5RCQsyoburBF8OwghOf+mgQBC8Sd9ch0 uxV1+bDRn1w0ZTB9nd4G53DyJH3ahTxc4sTdkq1xnuOpOuokC2Ld0jWH7kGA2wK/b3gj SB7YeyF9H2l8ihKBDv50eSDQRNeEsqTKTwb/8IslWl9Xy8UzDuPcQXa/zT/5iOClbZn3 bWdq//JhP0IuNazx3kVacaH/JVWmcmBf6YcNvqbN+Pb4bZZ4KPtwL+8tAxEH6+yeMaks Udcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version; bh=unbdSy0OAg9x6Fvo3R1XO6497auQkOJejjFwRssFYB8=; b=bwdy27POVDh9tiNRRsVk6vz4ovFzowgKjL5UysxGnc/rlqU4xarRyKQ0Ac9ALh5uhq RL3WKCrRwYY+rIyxdxU/wsIjsfL1Rb7H1y4bOmTHb74ExOd0mopTuvRTdNF/pKAumeOU hmpN09SxwdbbJnftGpqTPRHfgnhlxLCzA62XPfBTN9eIVRMCdMdw6dryd/pixtJupks4 6YcPpPQUr3F5gswVmcPH/20Zbv/dspWe/NN/Ywnh5VeRtCAWi0Qtt7SftyDS4RXyIcAP UUOMemXor7oQQBDHpA2twR6Tt+LmhhC21RQyJ3IEwwidBKPe4YrusGza+3Y1k2iLzQa3 bJRA== X-Gm-Message-State: AOAM532+e0ZhNbywQIQ54ZyeE8e//aeYETgJReGA1hwWzJllvJ7GME+Y SldRaQodNvbNjY0dvpqUiJR8ArI78S8= X-Google-Smtp-Source: ABdhPJxWnx6k8IPtZ4lwaT5hsQnc2ki8njYAuQyXvN4meDEo7GgBZR/GIdjLbUlS75Ldpc86Z8PJYA== X-Received: by 2002:a1c:64c1:: with SMTP id y184mr523759wmb.175.1590623856592; Wed, 27 May 2020 16:57:36 -0700 (PDT) Received: from localhost ([2a02:8084:20e2:c380:92bd:1bfd:38fc:fae2]) by smtp.gmail.com with ESMTPSA id d4sm4079948wre.22.2020.05.27.16.57.35 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 May 2020 16:57:35 -0700 (PDT) From: "Basil L. Contovounesios" To: bug-gnu-emacs@gnu.org Subject: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" Date: Thu, 28 May 2020 00:57:34 +0100 Message-ID: <877dwxexsh.fsf@tcd.ie> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: none client-ip=2a00:1450:4864:20::343; envelope-from=contovob@tcd.ie; helo=mail-wm1-x343.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) --=-=-= Content-Type: text/plain Severity: minor Tags: patch --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Document-format-spec-under-Strings-and-Characters.patch >From 9f63db1262683c1b7c58909d04bb2efa4ac2491a Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Thu, 28 May 2020 00:53:42 +0100 Subject: [PATCH] Document format-spec under Strings and Characters * doc/lispref/text.texi (Interpolated Strings): Move from here... * doc/lispref/strings.texi (Interpolating Strings): ...to here. --- doc/lispref/strings.texi | 62 ++++++++++++++++++++++++++++++++++++++ doc/lispref/text.texi | 64 ---------------------------------------- 2 files changed, 62 insertions(+), 64 deletions(-) diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 70c3b3cf4b..e1e40243fb 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -28,6 +28,7 @@ Strings and Characters * Text Comparison:: Comparing characters or strings. * String Conversion:: Converting to and from characters and strings. * Formatting Strings:: @code{format}: Emacs's analogue of @code{printf}. +* Interpolating Strings:: Formatting customizable strings. * Case Conversion:: Case conversion functions. * Case Tables:: Customizing case conversion. @end menu @@ -1122,6 +1123,67 @@ Formatting Strings NaNs and can lose precision and type, and @samp{#x%x} and @samp{#o%o} can mishandle negative integers. @xref{Input Functions}. +@node Interpolating Strings +@section Formatting Customizable Strings + +It is, in some circumstances, useful to present users with a string to +be customized that can then be expanded programmatically. For +instance, @code{erc-header-line-format} is @code{"%n on %t (%m,%l) +%o"}, and each of those characters after the percent signs are +expanded when the header line is computed. To do this, the +@code{format-spec} function is used: + +@defun format-spec format specification &optional only-present +@var{format} is the format specification string as in the example +above. @var{specification} is an alist that has elements where the +@code{car} is a character and the @code{cdr} is the substitution. + +If @var{only-present} is @code{nil}, errors will be signaled if a +format character has been used that's not present in +@var{specification}. If it's non-@code{nil}, that format +specification is left verbatim in the result. +@end defun + +Here's a trivial example: + +@example +(format-spec "su - %u %l" + `((?u . ,(user-login-name)) + (?l . "ls"))) + @result{} "su - foo ls" +@end example + +In addition to allowing padding/limiting to a certain length, the +following modifiers can be used: + +@table @asis +@item @samp{0} +Pad with zeros instead of the default spaces. + +@item @samp{-} +Pad to the right. + +@item @samp{^} +Use upper case. + +@item @samp{_} +Use lower case. + +@item @samp{<} +If the length needs to be limited, remove characters from the left. + +@item @samp{>} +Same as previous, but remove characters from the right. +@end table + +If contradictory modifiers are used (for instance, both upper and +lower case), then what happens is undefined. + +As an example, @samp{"%<010b"} means ``insert the @samp{b} expansion, +but pad with leading zeros if it's less than ten characters, and if +it's more than ten characters, shorten by removing characters from the +left.'' + @node Case Conversion @section Case Conversion in Lisp @cindex upper case diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index de436fa9e6..a14867e1d1 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -58,7 +58,6 @@ Text of another buffer. * Decompression:: Dealing with compressed data. * Base 64:: Conversion to or from base 64 encoding. -* Interpolated Strings:: Formatting Customizable Strings. * Checksum/Hash:: Computing cryptographic hashes. * GnuTLS Cryptography:: Cryptographic algorithms imported from GnuTLS. * Parsing HTML/XML:: Parsing HTML and XML. @@ -4662,69 +4661,6 @@ Base 64 is optional, and the URL variant of base 64 encoding is used. @end defun - -@node Interpolated Strings -@section Formatting Customizable Strings - -It is, in some circumstances, useful to present users with a string to -be customized that can then be expanded programmatically. For -instance, @code{erc-header-line-format} is @code{"%n on %t (%m,%l) -%o"}, and each of those characters after the percent signs are -expanded when the header line is computed. To do this, the -@code{format-spec} function is used: - -@defun format-spec format specification &optional only-present -@var{format} is the format specification string as in the example -above. @var{specification} is an alist that has elements where the -@code{car} is a character and the @code{cdr} is the substitution. - -If @var{only-present} is @code{nil}, errors will be signaled if a -format character has been used that's not present in -@var{specification}. If it's non-@code{nil}, that format -specification is left verbatim in the result. -@end defun - -Here's a trivial example: - -@example -(format-spec "su - %u %l" - `((?u . ,(user-login-name)) - (?l . "ls"))) - @result{} "su - foo ls" -@end example - -In addition to allowing padding/limiting to a certain length, the -following modifiers can be used: - -@table @asis -@item @samp{0} -Pad with zeros instead of the default spaces. - -@item @samp{-} -Pad to the right. - -@item @samp{^} -Use upper case. - -@item @samp{_} -Use lower case. - -@item @samp{<} -If the length needs to be limited, remove characters from the left. - -@item @samp{>} -Same as previous, but remove characters from the right. -@end table - -If contradictory modifiers are used (for instance, both upper and -lower case), then what happens is undefined. - -As an example, @samp{"%<010b"} means ``insert the @samp{b} expansion, -but pad with leading zeros if it's less than ten characters, and if -it's more than ten characters, shorten by removing characters from the -left.'' - - @node Checksum/Hash @section Checksum/Hash @cindex MD5 checksum -- 2.26.2 --=-=-= Content-Type: text/plain The Elisp manual node "(elisp) Interpolated Strings", which documents the function format-spec and is new in Emacs 27, is currently included under "(elisp) Text", which opens with: This chapter describes the functions that deal with the text in a buffer. Most examine, insert, or delete text in the current buffer, often operating at point or on text adjacent to point. Many are interactive. All the functions that change the text provide for undoing the changes (*note Undo). I think a more appropriate location would be following "(elisp) Formatting Strings", or at least under "(elisp) Strings and Characters". Patch for emacs-27 attached. WDYT? Thanks, -- Basil In GNU Emacs 27.0.91 (build 7, x86_64-pc-linux-gnu, X toolkit, Xaw3d scroll bars) of 2020-05-27 built on thunk Repository revision: 9d7fd78421a339f00892b3241845b1024e2eff7d Repository branch: emacs-27 Windowing system distributor 'The X.Org Foundation', version 11.0.12008000 System Description: Debian GNU/Linux bullseye/sid --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Thu May 28 02:59:05 2020 Received: (at 41571) by debbugs.gnu.org; 28 May 2020 06:59:05 +0000 Received: from localhost ([127.0.0.1]:50818 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jeCVN-0003IZ-4D for submit@debbugs.gnu.org; Thu, 28 May 2020 02:59:05 -0400 Received: from eggs.gnu.org ([209.51.188.92]:39152) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jeCVL-0003I3-Fo for 41571@debbugs.gnu.org; Thu, 28 May 2020 02:59:03 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:56106) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jeCVF-0005fj-KA; Thu, 28 May 2020 02:58:57 -0400 Received: from [176.228.60.248] (port=1153 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1jeCVE-0005SP-K2; Thu, 28 May 2020 02:58:57 -0400 Date: Thu, 28 May 2020 09:58:47 +0300 Message-Id: <83d06osfyw.fsf@gnu.org> From: Eli Zaretskii To: "Basil L. Contovounesios" In-Reply-To: <877dwxexsh.fsf@tcd.ie> (contovob@tcd.ie) Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: "Basil L. Contovounesios" > Date: Thu, 28 May 2020 00:57:34 +0100 > > The Elisp manual node "(elisp) Interpolated Strings", which documents > the function format-spec and is new in Emacs 27, is currently included > under "(elisp) Text", which opens with: > > This chapter describes the functions that deal with the text in a > buffer. Most examine, insert, or delete text in the current buffer, > often operating at point or on text adjacent to point. Many are > interactive. All the functions that change the text provide for undoing > the changes (*note Undo). > > I think a more appropriate location would be following "(elisp) > Formatting Strings", or at least under "(elisp) Strings and Characters". I agree, but can we please take this opportunity to improve that section? First, it uses passive tense too much for no real reason AFAICT. More importantly, the description of the feature is not clear enough. I had trouble understanding even the "trivial example" it shows, let alone all the rest. The very purpose of the feature is not really obvious after reading the text. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Thu May 28 06:42:04 2020 Received: (at 41571) by debbugs.gnu.org; 28 May 2020 10:42:04 +0000 Received: from localhost ([127.0.0.1]:51081 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jeFzA-0000kX-Aw for submit@debbugs.gnu.org; Thu, 28 May 2020 06:42:04 -0400 Received: from mail-wr1-f51.google.com ([209.85.221.51]:46542) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jeFz8-0000k2-VX for 41571@debbugs.gnu.org; Thu, 28 May 2020 06:42:03 -0400 Received: by mail-wr1-f51.google.com with SMTP id x6so13715086wrm.13 for <41571@debbugs.gnu.org>; Thu, 28 May 2020 03:42:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tcd-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=ZafJMcmciYt8qZc40fJyo1wub5EPral+PIMI1ot+aPo=; b=fCh7GLRMbacffT3myB6rXlj0AAOQd18Fu7tjylrGix6De/ay9Qd8VmlwuhQKvHYjxO 58apjTHI37T0hQup34ksSJUBuAGk3YBYIG7w0BbXANlmoFBxrsANddgy3sFaXVKe9SmI EbNsjxb7mD/UHOMswtobBrw4R9vpNSLyZjW7O5AFLsKxuqvOwasazEvxPHFCKAxAK+yC 4Rut58lDrwbmUN/Ku2H8JSWfWfcVmcuVHIXtFU8Q2hLCpgTkdEBsRVmtW5gpTz5RYfDj IBQ/v1Mpr6NiE3XY0YI/W4WkcnF4xJ8fWnw2Nj2+wqEsRlaEdDMsMRbHrAZzZBkm9lOs +nNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=ZafJMcmciYt8qZc40fJyo1wub5EPral+PIMI1ot+aPo=; b=SYYE+EPSIXhXE/mCqpMiGSeUg/deBTngLWAzJf8uLjUpwtJ9AtDRWp5Aw8ew7IHa6z HvJh1Bxnpxqn6wd50FW9gUeLWNYx6sRSRpBhwjh8zU+1I6YaK4Dy4p1LQzTrJ3bJZjb9 zbyi4Nie7w3GtOCMoA8AynDgSsWRwR9xNDVCybWhhfObF3Hje+2Js4jbWu/4tK9ZgtW4 KuXPc4SJOTpKUQoPVXoDr/vbopcdMeKvSr/jfoj2ZxiVPrUVkgZCG7kOBAmS4EfKsrmN Zvy5DeAeVF6iUBrYR76GcOdpNhFg9rHoAqBe9EpjS/E8qoH3T0RTWHhvckujTfhToiGi EVqw== X-Gm-Message-State: AOAM532XBuK6t5XIzCw3A7sqYbjnZurHRiBrMyF72tiRzH8q2J5tgTys +xbA2QcyKFPfTSHzt/kOkVx08i/pzHs= X-Google-Smtp-Source: ABdhPJygKYmL6mkxBj3dlqZaWs8Jjk3KyrQim1g9uU8N9z8wJIZbJRp8YTZpMrY6pXPPfRe6qTtCUw== X-Received: by 2002:adf:e30e:: with SMTP id b14mr830882wrj.334.1590662516740; Thu, 28 May 2020 03:41:56 -0700 (PDT) Received: from localhost ([2a02:8084:20e2:c380:1f68:7ff5:120d:64e]) by smtp.gmail.com with ESMTPSA id k21sm1068756wrd.24.2020.05.28.03.41.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2020 03:41:56 -0700 (PDT) From: "Basil L. Contovounesios" To: Eli Zaretskii Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> Date: Thu, 28 May 2020 11:41:54 +0100 In-Reply-To: <83d06osfyw.fsf@gnu.org> (Eli Zaretskii's message of "Thu, 28 May 2020 09:58:47 +0300") Message-ID: <87zh9sfij1.fsf@tcd.ie> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Eli Zaretskii writes: >> From: "Basil L. Contovounesios" >> Date: Thu, 28 May 2020 00:57:34 +0100 >> >> The Elisp manual node "(elisp) Interpolated Strings", which documents >> the function format-spec and is new in Emacs 27, is currently included >> under "(elisp) Text", which opens with: >> >> This chapter describes the functions that deal with the text in a >> buffer. Most examine, insert, or delete text in the current buffer, >> often operating at point or on text adjacent to point. Many are >> interactive. All the functions that change the text provide for undoing >> the changes (*note Undo). >> >> I think a more appropriate location would be following "(elisp) >> Formatting Strings", or at least under "(elisp) Strings and Characters". > > I agree, but can we please take this opportunity to improve that > section? First, it uses passive tense too much for no real reason > AFAICT. More importantly, the description of the feature is not clear > enough. I had trouble understanding even the "trivial example" it > shows, let alone all the rest. The very purpose of the feature is not > really obvious after reading the text. Sure, I'll give it a try, as I was already working on improving the format-spec implementation and documentation on master. While I'm at it, may I change the node name? Interpolating is the same as formatting in this context, so the difference between the two nodes is not clear to me. Perhaps something like: * Formatting Custom Strings:: Formatting custom @code{format} specifications. In fact, couldn't format-spec be documented alongside format and format-message under "(elisp) Formatting Strings"? Or does format-spec need its own node? Just to recap: format-spec is like format, except it allows custom %-sequence characters, such as %z, which are substituted in a similar way to format's %s. A common use case is to allow users to customise different output presented to them via custom format control strings. Thanks, -- Basil From debbugs-submit-bounces@debbugs.gnu.org Thu May 28 07:34:13 2020 Received: (at 41571) by debbugs.gnu.org; 28 May 2020 11:34:13 +0000 Received: from localhost ([127.0.0.1]:51182 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jeGnd-0004HV-D1 for submit@debbugs.gnu.org; Thu, 28 May 2020 07:34:13 -0400 Received: from eggs.gnu.org ([209.51.188.92]:46018) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jeGnc-0004HH-7y for 41571@debbugs.gnu.org; Thu, 28 May 2020 07:34:12 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:58919) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jeGnW-00040J-9J; Thu, 28 May 2020 07:34:06 -0400 Received: from [176.228.60.248] (port=2080 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1jeGnV-0001Mi-GO; Thu, 28 May 2020 07:34:06 -0400 Date: Thu, 28 May 2020 14:33:57 +0300 Message-Id: <837dwws38a.fsf@gnu.org> From: Eli Zaretskii To: "Basil L. Contovounesios" In-Reply-To: <87zh9sfij1.fsf@tcd.ie> (contovob@tcd.ie) Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> <87zh9sfij1.fsf@tcd.ie> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: "Basil L. Contovounesios" > Cc: 41571@debbugs.gnu.org > Date: Thu, 28 May 2020 11:41:54 +0100 > > While I'm at it, may I change the node name? Sure, the names aren't cast in stone, and the current one doesn't strike me as especially successful/accurate. > In fact, couldn't format-spec be documented alongside format and > format-message under "(elisp) Formatting Strings"? I thought about that as well when I read your original message, but concluded that "Formatting Strings" is already too long. We could end that node with a sentence referring to the next one, so that interested readers could continue there right away. WDYT? > Just to recap: format-spec is like format, except it allows custom > %-sequence characters, such as %z, which are substituted in a similar > way to format's %s. A common use case is to allow users to customise > different output presented to them via custom format control strings. This text is sorely missed at the beginning of the node about format-spec. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Fri May 29 14:35:42 2020 Received: (at 41571) by debbugs.gnu.org; 29 May 2020 18:35:42 +0000 Received: from localhost ([127.0.0.1]:56224 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jejr3-0003HQ-Ro for submit@debbugs.gnu.org; Fri, 29 May 2020 14:35:42 -0400 Received: from mail-wm1-f54.google.com ([209.85.128.54]:37177) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jejr1-0003HC-Dp for 41571@debbugs.gnu.org; Fri, 29 May 2020 14:35:40 -0400 Received: by mail-wm1-f54.google.com with SMTP id f5so4886291wmh.2 for <41571@debbugs.gnu.org>; Fri, 29 May 2020 11:35:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tcd-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=8I+H//YGfW9ir6jmEcN763PFz54Rv8nHC7NlZ3L7iPY=; b=IppET66+yOCsscP8C/FhmmV7u6I8+JABs2y2iVG8rrHtycy5jE0FDBdn3aTZ9pQ5kc KNpMp1UT5mZmOd4/3A6uoqIVyTsrf7151yDdEjIsnJtcXvFuMKj4BiZAk6I/3+muFG7V m5xfztkLC79+SP56dEnivuWvGxjA0uH1wV4X9UBT2FzFA+XVVVLo1iTUeEsMa4HKcFCH RNpBYM4klnOs25p8wbKxauqO4QC2vN+agJ9GbC1I5DjtgCWiLeEe24KbM1/KYZSJMbh9 LHF9347agR2cAYX8Xr3ZioyL4a78wEcm7EFjWmtHY76yTPiSWNApY5dnnnbzwQ+Tkpfa cGgw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=8I+H//YGfW9ir6jmEcN763PFz54Rv8nHC7NlZ3L7iPY=; b=F9Yu0+Y3wjxvqzXLQvGb2MMdhHpEPkNoQSnDkTQCOYvkKlsCcZMx6jsVHzUoQ0nk6I Nqji1sRVOBEmGJbaWrWbudxN+frgiVy/dKrkpaY4j+2EBgk3qGb3hJm8maZXywEq3HC2 Ai3HSFbO50184HsBWHmiAo4LlgooYK1q3ZpNjajUHxQyCXaOZXugDUBIECZI4CfPOP0p eZk9MvvKCYVNlqSCkUDzJ244oblfFQqYV+SP1eRwCEO/vNmQNCLeapRqZI/ura7LaWhj DPaU8qfafLFa0nLO9OeIJRCNoqVukZRDuJkmHpE+SBvxelu9D57rRVdI6uttIGSnJL3e y/Aw== X-Gm-Message-State: AOAM53317Vqzpn/ZHd737QhNAN/CGp29ZlqHSRCRsSOXATqREcIDDlma MYLOSBk9YOYEA1C3+X2LuqhrXQ== X-Google-Smtp-Source: ABdhPJz5iVlgXlr6nmjSkhskoy9Ars7j2yAQd3rlQXTMGEq8IdyJYrDAQlHf2kuQfK3FJJgU+Drbpg== X-Received: by 2002:a1c:2644:: with SMTP id m65mr9592707wmm.178.1590777333310; Fri, 29 May 2020 11:35:33 -0700 (PDT) Received: from localhost ([2a02:8084:20e2:c380:1f68:7ff5:120d:64e]) by smtp.gmail.com with ESMTPSA id r4sm10882103wro.32.2020.05.29.11.35.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 May 2020 11:35:32 -0700 (PDT) From: "Basil L. Contovounesios" To: Eli Zaretskii Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> <87zh9sfij1.fsf@tcd.ie> <837dwws38a.fsf@gnu.org> Date: Fri, 29 May 2020 19:35:31 +0100 In-Reply-To: <837dwws38a.fsf@gnu.org> (Eli Zaretskii's message of "Thu, 28 May 2020 14:33:57 +0300") Message-ID: <877dwu4mj0.fsf@tcd.ie> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Improve-format-spec-documentation-bug-41571.patch >From b6a7bfbbb08d5c09e85f50b9100b39c1e1645bc2 Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Thu, 28 May 2020 00:53:42 +0100 Subject: [PATCH] Improve format-spec documentation (bug#41571) * doc/lispref/text.texi (Interpolated Strings): Move from here... * doc/lispref/strings.texi (Custom Format Strings): ...to here, renaming the node and clarifying the documentation. (Formatting Strings): End node with sentence referring to the next one. * lisp/format-spec.el (format-spec): Clarify docstring. --- doc/lispref/strings.texi | 138 +++++++++++++++++++++++++++++++++++++++ doc/lispref/text.texi | 64 ------------------ lisp/format-spec.el | 49 ++++++++------ 3 files changed, 168 insertions(+), 83 deletions(-) diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 70c3b3cf4b..0c750a8143 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -28,6 +28,7 @@ Strings and Characters * Text Comparison:: Comparing characters or strings. * String Conversion:: Converting to and from characters and strings. * Formatting Strings:: @code{format}: Emacs's analogue of @code{printf}. +* Custom Format Strings:: Formatting custom @code{format} specifications. * Case Conversion:: Case conversion functions. * Case Tables:: Customizing case conversion. @end menu @@ -1122,6 +1123,143 @@ Formatting Strings NaNs and can lose precision and type, and @samp{#x%x} and @samp{#o%o} can mishandle negative integers. @xref{Input Functions}. +The functions described in this section accept a fixed set of +specification characters. The next section describes a function +@code{format-spec} which accepts custom specification characters. + +@node Custom Format Strings +@section Custom Format Strings +@cindex custom format string +@cindex custom @samp{%}-sequence in format + +It is, in some circumstances, useful to allow users to control how +certain text is generated via custom format control strings. For +example, a format string could control how to display someone's +forename, surname, and email address. Using the function +@code{format} described in the previous section, the format string +could be something like @code{"%s %s <%s>"}. This approach quickly +becomes impractical, however, as it can be unclear which specification +character corresponds to which piece of information. + +A more convenient format string for such cases would be something like +@code{"%f %l <%e>"}, where each specification character carries more +semantic information and can easily be rearranged relative to other +specification characters. The function @code{format-spec} described +in this section performs a similar function to @code{format}, except +it operates on format control strings that comprise arbitrary +specification characters. + +@defun format-spec format specification &optional only-present +This function returns a string equal to the format control string +@var{format}, replacing any format specifications it contains with +values found in the alist @var{specification} (@pxref{Association +Lists}). + +Each key in @var{specification} is a format specification character, +and its associated value is the string to replace it with. For +example, an alist entry @code{(?a . "alpha")} means to replace any +@samp{%a} specifications in @var{format} with @samp{alpha}. + +The characters in @var{format}, other than the format specifications, +are copied directly into the output, including their text properties, +if any. Any text properties of the format specifications are copied +to their substitutions. + +Some useful properties are gained as a result of @var{specification} +being an alist. The alist may contain more unique keys than there are +unique specification characters in @var{format}; unused keys are +simply ignored. If the same key is contained more than once, the +first one found is used. If @var{format} contains the same format +specification character more than once, then the same value found in +@var{specification} is used as a basis for all of that character's +substitutions. + +The optional argument @var{only-present} indicates how to handle +format specification characters in @var{format} that are not found in +@var{specification}. If it is @code{nil} or omitted, an error is +emitted. Otherwise, those format specifications and any occurrences +of @samp{%%} in @var{format} are left verbatim in the output, +including their text properties, if any. +@end defun + +The syntax of format specifications accepted by @code{format-spec} is +similar, but not identical, to that accepted by @code{format}. In +both cases, a format specification is a sequence of characters +beginning with @samp{%} and ending with an alphabetic letter such as +@samp{s}. The only exception to this is the specification @samp{%%}, +which is replaced with a single @samp{%}. + +Unlike @code{format}, which assigns specific meanings to a fixed set +of specification characters, @code{format-spec} accepts arbitrary +specification characters and treats them all equally. For example: + +@example +(format-spec "su - %u %l" + `((?u . ,(user-login-name)) + (?l . "ls"))) + @result{} "su - foo ls" +@end example + +A format specification can include any number of the following flag +characters immediately after the @samp{%} to modify aspects of the +substitution. + +@table @samp +@item 0 +This flag causes any padding inserted by the width, if specified, to +consist of @samp{0} characters instead of spaces. + +@item - +This flag causes any padding inserted by the width, if specified, to +be inserted on the right rather than the left. + +@item < +This flag causes the substitution to be truncated to the given width, +if specified, by removing characters from the left. + +@item > +This flag causes the substitution to be truncated to the given width, +if specified, by removing characters from the right. + +@item ^ +This flag converts the substituted text to upper case (@pxref{Case +Conversion}). + +@item _ +This flag converts the substituted text to lower case (@pxref{Case +Conversion}). +@end table + +The result of using contradictory flags (for instance, both upper and +lower case) is undefined. + +As is the case with @code{format}, a format specification can include +a width, which is a decimal number that appears after any flags. If a +substitution contains fewer characters than its specified width, it is +extended with padding, normally comprising spaces inserted on the +left: + +@example +(format-spec "%8a is padded on the left with spaces" + '((?a . "alpha"))) + @result{} " alpha is padded on the left with spaces" +@end example + +Here is a more complicated example that combines several +aforementioned features: + +@example +(format-spec "%<06e %<06b" + '((?b . "beta") + (?e . "epsilon"))) + @result{} "psilon 00beta" +@end example + +This format string means ``substitute into the output the values +associated with @code{?e} and @code{?b} in the given alist, either +padding them with leading zeros or truncating leading characters until +they're each six characters wide.'' + @node Case Conversion @section Case Conversion in Lisp @cindex upper case diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index de436fa9e6..a14867e1d1 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -58,7 +58,6 @@ Text of another buffer. * Decompression:: Dealing with compressed data. * Base 64:: Conversion to or from base 64 encoding. -* Interpolated Strings:: Formatting Customizable Strings. * Checksum/Hash:: Computing cryptographic hashes. * GnuTLS Cryptography:: Cryptographic algorithms imported from GnuTLS. * Parsing HTML/XML:: Parsing HTML and XML. @@ -4662,69 +4661,6 @@ Base 64 is optional, and the URL variant of base 64 encoding is used. @end defun - -@node Interpolated Strings -@section Formatting Customizable Strings - -It is, in some circumstances, useful to present users with a string to -be customized that can then be expanded programmatically. For -instance, @code{erc-header-line-format} is @code{"%n on %t (%m,%l) -%o"}, and each of those characters after the percent signs are -expanded when the header line is computed. To do this, the -@code{format-spec} function is used: - -@defun format-spec format specification &optional only-present -@var{format} is the format specification string as in the example -above. @var{specification} is an alist that has elements where the -@code{car} is a character and the @code{cdr} is the substitution. - -If @var{only-present} is @code{nil}, errors will be signaled if a -format character has been used that's not present in -@var{specification}. If it's non-@code{nil}, that format -specification is left verbatim in the result. -@end defun - -Here's a trivial example: - -@example -(format-spec "su - %u %l" - `((?u . ,(user-login-name)) - (?l . "ls"))) - @result{} "su - foo ls" -@end example - -In addition to allowing padding/limiting to a certain length, the -following modifiers can be used: - -@table @asis -@item @samp{0} -Pad with zeros instead of the default spaces. - -@item @samp{-} -Pad to the right. - -@item @samp{^} -Use upper case. - -@item @samp{_} -Use lower case. - -@item @samp{<} -If the length needs to be limited, remove characters from the left. - -@item @samp{>} -Same as previous, but remove characters from the right. -@end table - -If contradictory modifiers are used (for instance, both upper and -lower case), then what happens is undefined. - -As an example, @samp{"%<010b"} means ``insert the @samp{b} expansion, -but pad with leading zeros if it's less than ten characters, and if -it's more than ten characters, shorten by removing characters from the -left.'' - - @node Checksum/Hash @section Checksum/Hash @cindex MD5 checksum diff --git a/lisp/format-spec.el b/lisp/format-spec.el index f418cea425..4bf636e685 100644 --- a/lisp/format-spec.el +++ b/lisp/format-spec.el @@ -29,35 +29,46 @@ (defun format-spec (format specification &optional only-present) "Return a string based on FORMAT and SPECIFICATION. -FORMAT is a string containing `format'-like specs like \"su - %u %k\", -while SPECIFICATION is an alist mapping from format spec characters -to values. +FORMAT is a string containing `format'-like specs like \"su - %u %k\". +SPECIFICATION is an alist mapping format specification characters +to their substitutions. For instance: (format-spec \"su - %u %l\" - `((?u . ,(user-login-name)) + \\=`((?u . ,(user-login-name)) (?l . \"ls\"))) -Each format spec can have modifiers, where \"%<010b\" means \"if -the expansion is shorter than ten characters, zero-pad it, and if -it's longer, chop off characters from the left side\". +Each %-spec may contain optional flag and width modifiers, as +follows: -The following modifiers are allowed: + %character -* 0: Use zero-padding. -* -: Pad to the right. -* ^: Upper-case the expansion. -* _: Lower-case the expansion. -* <: Limit the length by removing chars from the left. -* >: Limit the length by removing chars from the right. +The following flags are allowed: -Any text properties on a %-spec itself are propagated to the text -that it generates. +* 0: Pad to the width, if given, with zeros instead of spaces. +* -: Pad to the width, if given, on the right instead of the left. +* <: Truncate to the width, if given, by removing leading characters. +* >: Truncate to the width, if given, by removing trailing characters. +* ^: Convert to upper case. +* _: Convert to lower case. -If ONLY-PRESENT, format spec characters not present in -SPECIFICATION are ignored, and the \"%\" characters are left -where they are, including \"%%\" strings." +The width modifier behaves like the corresponding one in `format' +when applied to %s. + +For example, \"%<010b\" means \"substitute into the output the +value associated with ?b in SPECIFICATION, either padding it with +leading zeros or truncating leading characters until it's ten +characters wide\". + +Any text properties of FORMAT are copied to the result, with any +text properties of a %-spec itself copied to its substitution. + +ONLY-PRESENT indicates how to handle %-spec characters not +present in SPECIFICATION. If it is nil or omitted, emit an +error; otherwise leave those %-specs and any occurrences of +\"%%\" in FORMAT verbatim in the result, including their text +properties, if any." (with-temp-buffer (insert format) (goto-char (point-min)) -- 2.26.2 --=-=-= Content-Type: text/plain Eli Zaretskii writes: >> From: "Basil L. Contovounesios" >> Cc: 41571@debbugs.gnu.org >> Date: Thu, 28 May 2020 11:41:54 +0100 >> >> While I'm at it, may I change the node name? > > Sure, the names aren't cast in stone, and the current one doesn't > strike me as especially successful/accurate. > >> In fact, couldn't format-spec be documented alongside format and >> format-message under "(elisp) Formatting Strings"? > > I thought about that as well when I read your original message, but > concluded that "Formatting Strings" is already too long. We could > end that node with a sentence referring to the next one, so that > interested readers could continue there right away. WDYT? SGTM. >> Just to recap: format-spec is like format, except it allows custom >> %-sequence characters, such as %z, which are substituted in a similar >> way to format's %s. A common use case is to allow users to customise >> different output presented to them via custom format control strings. > > This text is sorely missed at the beginning of the node about > format-spec. How's the attached for emacs-27? Thanks, -- Basil --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Fri May 29 15:41:40 2020 Received: (at 41571) by debbugs.gnu.org; 29 May 2020 19:41:41 +0000 Received: from localhost ([127.0.0.1]:56271 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jeksu-00059q-Fc for submit@debbugs.gnu.org; Fri, 29 May 2020 15:41:40 -0400 Received: from eggs.gnu.org ([209.51.188.92]:56616) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jekss-00059c-Kz for 41571@debbugs.gnu.org; Fri, 29 May 2020 15:41:39 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:46508) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jeksm-0000BT-TQ; Fri, 29 May 2020 15:41:32 -0400 Received: from [176.228.60.248] (port=1396 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1jeksk-0001Ei-Ag; Fri, 29 May 2020 15:41:32 -0400 Date: Fri, 29 May 2020 22:41:24 +0300 Message-Id: <83mu5qmsuz.fsf@gnu.org> From: Eli Zaretskii To: "Basil L. Contovounesios" In-Reply-To: <877dwu4mj0.fsf@tcd.ie> (contovob@tcd.ie) Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> <87zh9sfij1.fsf@tcd.ie> <837dwws38a.fsf@gnu.org> <877dwu4mj0.fsf@tcd.ie> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: "Basil L. Contovounesios" > Cc: 41571@debbugs.gnu.org > Date: Fri, 29 May 2020 19:35:31 +0100 > > How's the attached for emacs-27? Thanks, it's much better, but it still "needs work". (Btw, why are you attachments appear before the text? It makes responding harder, because I need to bring the citations to the front.) > +The functions described in this section accept a fixed set of > +specification characters. The next section describes a function > +@code{format-spec} which accepts custom specification characters. This would benefit from making it clear what you mean by "specification characters". An example would clarify that. (It is actually a general comment to your text: you frequently use terms that are left unexplained, which makes the reader stumble and try to understand what you mean. Specific examples below.) > +It is, in some circumstances, useful to allow users to control how The beginning of this sentence is unnecessarily complex. A much simpler variant would be Sometimes it is useful to allow Lisp programs to control... Note that I replaced "users" with "Lisp programs", since we are not talking about Emacs users here. > +A more convenient format string for such cases would be something like > +@code{"%f %l <%e>"}, where each specification character carries more > +semantic information and can easily be rearranged relative to other > +specification characters. The function @code{format-spec} described > +in this section performs a similar function to @code{format}, except > +it operates on format control strings that comprise arbitrary > +specification characters. "comprise" => "include", or even just "use" > +@defun format-spec format specification &optional only-present > +This function returns a string equal to the format control string The "equal" here is confusing, because equality is not really important here, especially since the job of this function is to produce strings that are NOT equal to the original. > +@var{format}, replacing any format specifications it contains with > +values found in the alist @var{specification} (@pxref{Association > +Lists}). > + > +Each key in @var{specification} is a format specification character, > +and its associated value is the string to replace it with. For > +example, an alist entry @code{(?a . "alpha")} means to replace any > +@samp{%a} specifications in @var{format} with @samp{alpha}. You say "key in SPECIFICATION", but SPECIFICATION is an alist, and a key in an alist has well-known meaning. The "key" above should be "association". And in general I'd rearrange the text to make the format of SPECIFICATION more explicit, something like: @defun format-spec template spec-alist &optional only-present This function returns a format string suitable for using in @code{format} and similar functions. The format string is produced from @var{template} according to conversions specified in @var{spec-alist}, which is an alist (@pxref{Association Lists}) of the form @w{@code{(@var{letter} . @var{replacement})}}. Each specification @code{%@var{letter}} in @var{template} will be replaced by @var{replacement} when producing the resulting format string. > +Some useful properties are gained as a result of @var{specification} > +being an alist. The alist may contain more unique keys than there are > +unique specification characters in @var{format}; unused keys are > +simply ignored. If the same key is contained more than once, the > +first one found is used. If @var{format} contains the same format > +specification character more than once, then the same value found in > +@var{specification} is used as a basis for all of that character's > +substitutions. Here you use "key" without first explaining what it is. Also, this paragraph describes several distinct features, so it is better to use an itemized list instead of just one sentence after another: it makes the description easier to grasp by dividing it into distinct smaller chunks. > +The optional argument @var{only-present} indicates how to handle > +format specification characters in @var{format} that are not found in > +@var{specification}. If it is @code{nil} or omitted, an error is > +emitted. Passive tense alert! Suggest to rephrase If it is @code{nil} or omitted, the function signals an error. > +The syntax of format specifications accepted by @code{format-spec} is > +similar, but not identical, to that accepted by @code{format}. In > +both cases, a format specification is a sequence of characters > +beginning with @samp{%} and ending with an alphabetic letter such as > +@samp{s}. The only exception to this is the specification @samp{%%}, > +which is replaced with a single @samp{%}. How is what's described in the last sentence "an exception"? Format strings used by 'format' also behave like that, right? > +Unlike @code{format}, which assigns specific meanings to a fixed set > +of specification characters, @code{format-spec} accepts arbitrary > +specification characters and treats them all equally. For example: > + > +@example > +(format-spec "su - %u %l" > + `((?u . ,(user-login-name)) > + (?l . "ls"))) > + @result{} "su - foo ls" > +@end example This example stops short of explaining why this function is useful: making the replacements fixed strings, as in "ls", is not the reason. OTOH, the use of user-login-name is obfuscated by the backtick notation, which seems to say that some magic is needed here. I think the reason for having this function should be explained better, with more meaningful examples. > +@item 0 > +This flag causes any padding inserted by the width, if specified, to ^^^^^^^^^^^^^^^^^^^^^ Width cannot insert anything, so this should be reworded. Same in a few other items. > +@item < > +This flag causes the substitution to be truncated to the given width, > +if specified, by removing characters from the left. "truncated ... by removing characters" is unnecessarily complicated. Why not say simply "truncated on the left"? > +@item > > +This flag causes the substitution to be truncated to the given width, > +if specified, by removing characters from the right. Same here. > +As is the case with @code{format}, a format specification can include > +a width, which is a decimal number that appears after any flags. If a > +substitution contains fewer characters than its specified width, it is > +extended with padding, normally comprising spaces inserted on the^^^^^ > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > +left: > ^^^^ "it is padded on the left" is simpler and more clear. > +Here is a more complicated example that combines several > +aforementioned features: > + > +@example > +(format-spec "%<06e %<06b" > + '((?b . "beta") > + (?e . "epsilon"))) > + @result{} "psilon 00beta" > +@end example Can we make this example be less trivial? This use case doesn't justify using format-spec at all. Even the subtle point of having the format specs in the order different from the alist is not evident unless you make a point of mentioning it (something that IMO should have been done earlier in the description). Thanks. From debbugs-submit-bounces@debbugs.gnu.org Sun May 31 05:24:59 2020 Received: (at 41571) by debbugs.gnu.org; 31 May 2020 09:24:59 +0000 Received: from localhost ([127.0.0.1]:59726 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jfKDC-0003FC-Au for submit@debbugs.gnu.org; Sun, 31 May 2020 05:24:59 -0400 Received: from mail-wm1-f54.google.com ([209.85.128.54]:33832) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jfKD9-0003Ew-G0 for 41571@debbugs.gnu.org; Sun, 31 May 2020 05:24:56 -0400 Received: by mail-wm1-f54.google.com with SMTP id u26so9913045wmn.1 for <41571@debbugs.gnu.org>; Sun, 31 May 2020 02:24:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tcd-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=Gu/Qr5pcJxhcOJGKArJiSrMzFJDtyvUGsZDSltSBIpA=; b=NQOQMarUYdukD00Mn50CAq53V20DkUdHkGHfkXgmRCfCfGSkSCbrYcHnWfn3HZeE2l iOaa8FoVLDPIBxvGnLHJqxsadoWtDCM6MsL+7yoU9EY9+NI/8ClG2dkvPjZfo1wzehHW E1sR7NUuV9WLmLSgjh7lUqoarY0lpPlWiuJc81rT2oWr0eDZq0cinP9gOBFYFKealv23 HC+6Iqzuvi3FT39Up12nBxfNQfCen8VUPgXBbdyVzauRlCsKkPqON03rwYijXcgLppzi 6RKpKpLBE9KJLmhT68T4Id8ye7inVErcPpxj39/h6K7yDZlmuTk4Vrz2jNnhu4Cl7fgf R+pw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=Gu/Qr5pcJxhcOJGKArJiSrMzFJDtyvUGsZDSltSBIpA=; b=BcIb0aEvsxVPTt6LcsDtoLgM7HVStaOKGgvqkz5gGIHgS2AJh5G9cNQ5ertomv1lZp sL82OuoT4+JQ2go9mvGkHuKrMHCNlaRmxv+reZTc6CT7sOuhE7vgdN8wDzG0ETyfHi1t ZEqAbqVPqzve9zOP1wFx/fsZVf96twcaSlJeHvIP/KJSayo3K3iS6XjgmrzdlmxEgbpe zNFRfG850gxUrpmcrY/AGhGYiH1B8GymRbfnfCK0SGEU5dH0mYJI+M00G4Xj0ocCfhSV SxdSebN7gguz0Ak4dteJcAdrGmJ7Uy/1wBLmHr9adiNkFCrJdjpbC31d/Qk2q1CVLCLA 2Hig== X-Gm-Message-State: AOAM530nZe/1czoasHcGuGiFEUMSvMvG6f2wWZnLsefe0m0OMh+ragKX N9chQIjrub8v87z/ZS4HXbrqqA== X-Google-Smtp-Source: ABdhPJy+UlwD+J70Zm+BUd013W7cca3EyY15e80gjnwz/9Z3PPazZM9P2Ey03203S7NuA9tmw0NKMw== X-Received: by 2002:a05:600c:2c4b:: with SMTP id r11mr15620364wmg.144.1590917089441; Sun, 31 May 2020 02:24:49 -0700 (PDT) Received: from localhost ([2a02:8084:20e2:c380:1f68:7ff5:120d:64e]) by smtp.gmail.com with ESMTPSA id z9sm5789556wmi.41.2020.05.31.02.24.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 31 May 2020 02:24:48 -0700 (PDT) From: "Basil L. Contovounesios" To: Eli Zaretskii Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> <87zh9sfij1.fsf@tcd.ie> <837dwws38a.fsf@gnu.org> <877dwu4mj0.fsf@tcd.ie> <83mu5qmsuz.fsf@gnu.org> Date: Sun, 31 May 2020 10:24:46 +0100 In-Reply-To: <83mu5qmsuz.fsf@gnu.org> (Eli Zaretskii's message of "Fri, 29 May 2020 22:41:24 +0300") Message-ID: <87wo4s8nj5.fsf@tcd.ie> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Eli Zaretskii writes: >> From: "Basil L. Contovounesios" >> Cc: 41571@debbugs.gnu.org >> Date: Fri, 29 May 2020 19:35:31 +0100 >> >> How's the attached for emacs-27? > > Thanks, it's much better, but it still "needs work". Thanks for the very helpful feedback. > (Btw, why are you attachments appear before the text? It makes > responding harder, because I need to bring the citations to the > front.) Sorry, I got into the habit of doing that because I wasn't sure whether attachments should go before or after the email signature. I'm guessing after? >> +The functions described in this section accept a fixed set of >> +specification characters. The next section describes a function >> +@code{format-spec} which accepts custom specification characters. > > This would benefit from making it clear what you mean by > "specification characters". An example would clarify that. > > (It is actually a general comment to your text: you frequently use > terms that are left unexplained, which makes the reader stumble and > try to understand what you mean. Specific examples below.) I agree that this sentence can be further clarified, but in general I tried to reuse existing terminology and phrasing to the greatest extent possible (maybe even too much). E.g. the preceding paragraphs in "(elisp) Formatting Strings" define and make extensive use of the terms "format string", "format specification", "format specification character", as well as the shorter forms "specification character" and "specification". >> +It is, in some circumstances, useful to allow users to control how > > The beginning of this sentence is unnecessarily complex. A much > simpler variant would be > > Sometimes it is useful to allow Lisp programs to control... > > Note that I replaced "users" with "Lisp programs", since we are not > talking about Emacs users here. Done. >> +A more convenient format string for such cases would be something like >> +@code{"%f %l <%e>"}, where each specification character carries more >> +semantic information and can easily be rearranged relative to other >> +specification characters. The function @code{format-spec} described >> +in this section performs a similar function to @code{format}, except >> +it operates on format control strings that comprise arbitrary >> +specification characters. > > "comprise" => "include", or even just "use" Done. >> +@defun format-spec format specification &optional only-present >> +This function returns a string equal to the format control string > > The "equal" here is confusing, because equality is not really > important here, especially since the job of this function is to > produce strings that are NOT equal to the original. I agree; this is just a copy of the corresponding text from "(elisp) Formatting Strings". >> +@var{format}, replacing any format specifications it contains with >> +values found in the alist @var{specification} (@pxref{Association >> +Lists}). >> + >> +Each key in @var{specification} is a format specification character, >> +and its associated value is the string to replace it with. For >> +example, an alist entry @code{(?a . "alpha")} means to replace any >> +@samp{%a} specifications in @var{format} with @samp{alpha}. > > You say "key in SPECIFICATION", but SPECIFICATION is an alist, and a > key in an alist has well-known meaning. The "key" above should be > "association". "Each key in [the alist] is a [...] character" means each key in each association in the alist is a character, so the wording is not wrong, just unclear. > And in general I'd rearrange the text to make the > format of SPECIFICATION more explicit, something like: > > @defun format-spec template spec-alist &optional only-present > This function returns a format string suitable for using in > @code{format} and similar functions. The format string is produced > from @var{template} according to conversions specified in > @var{spec-alist}, which is an alist (@pxref{Association Lists}) of > the form @w{@code{(@var{letter} . @var{replacement})}}. Each > specification @code{%@var{letter}} in @var{template} will be > replaced by @var{replacement} when producing the resulting format > string. This wording is much clearer, but the description of the output is wrong: 'format-spec' and 'format' both produce the same result - a formatted string, not a format string. 'format-spec' is an alternative to 'format', not a precursor. >> +Some useful properties are gained as a result of @var{specification} >> +being an alist. The alist may contain more unique keys than there are >> +unique specification characters in @var{format}; unused keys are >> +simply ignored. If the same key is contained more than once, the >> +first one found is used. If @var{format} contains the same format >> +specification character more than once, then the same value found in >> +@var{specification} is used as a basis for all of that character's >> +substitutions. > > Here you use "key" without first explaining what it is. I was relying on the preceding xref to the node on alists, which defines the terms "alist", "key", and "associated value". > Also, this paragraph describes several distinct features, so it is > better to use an itemized list instead of just one sentence after > another: it makes the description easier to grasp by dividing it into > distinct smaller chunks. Done, including mentioning that associations can appear in a different order to their corresponding format specifications in the format string. >> +The optional argument @var{only-present} indicates how to handle >> +format specification characters in @var{format} that are not found in >> +@var{specification}. If it is @code{nil} or omitted, an error is >> +emitted. > > Passive tense alert! Suggest to rephrase > > If it is @code{nil} or omitted, the function signals an error. Fire extinguished. >> +The syntax of format specifications accepted by @code{format-spec} is >> +similar, but not identical, to that accepted by @code{format}. In >> +both cases, a format specification is a sequence of characters >> +beginning with @samp{%} and ending with an alphabetic letter such as >> +@samp{s}. The only exception to this is the specification @samp{%%}, >> +which is replaced with a single @samp{%}. > > How is what's described in the last sentence "an exception"? Format > strings used by 'format' also behave like that, right? It's an exception to "beginning with % and ending with a letter". Would it be clearer if I said "the only specification that does not end in a letter is %%, which is replaced with a single % in the output"? >> +Unlike @code{format}, which assigns specific meanings to a fixed set >> +of specification characters, @code{format-spec} accepts arbitrary >> +specification characters and treats them all equally. For example: >> + >> +@example >> +(format-spec "su - %u %l" >> + `((?u . ,(user-login-name)) >> + (?l . "ls"))) >> + @result{} "su - foo ls" >> +@end example > > This example stops short of explaining why this function is useful: > making the replacements fixed strings, as in "ls", is not the reason. > OTOH, the use of user-login-name is obfuscated by the backtick > notation, which seems to say that some magic is needed here. > > I think the reason for having this function should be explained > better, with more meaningful examples. Hm, I'm not sure how to give a better existential justification; this example just serves as a usage example. The main use case for format-spec I've seen is where one part of the program produces an alist with all the information that could ever be needed, and another part of the program formats an often user-customisable format string using this data. An example of such a use case is in battery.el, where the alist produced by battery-status-function is used to format battery-echo-area-format and battery-mode-line-format (battery.el doesn't currently use format-spec, but it could and my WIP patch for master changes that). Would replicating such a use case make a better example? E.g.: (setq my-site-info (list (cons ?s system-name) (cons ?t (symbol-name system-type)) (cons ?c system-configuration) (cons ?v emacs-version) (cons ?e invocation-name) (cons ?p (number-to-string (emacs-pid))) (cons ?a user-mail-address) (cons ?n user-full-name))) (format-spec "%e %v (%c)" my-site-info) => "emacs 28.0.50 (x86_64-pc-linux-gnu)" (format-spec "%n <%a>" my-site-info) => "Emacs Developers " >> +@item 0 >> +This flag causes any padding inserted by the width, if specified, to > ^^^^^^^^^^^^^^^^^^^^^ > Width cannot insert anything, so this should be reworded. Same in a > few other items. Most of this phrasing is taken from "(elisp) Formatting Strings". Is it clear enough to say "...causes any padding specified by the width to..."? >> +@item < >> +This flag causes the substitution to be truncated to the given width, >> +if specified, by removing characters from the left. > > "truncated ... by removing characters" is unnecessarily complicated. > Why not say simply "truncated on the left"? Done. >> +@item > >> +This flag causes the substitution to be truncated to the given width, >> +if specified, by removing characters from the right. > > Same here. Done. >> +As is the case with @code{format}, a format specification can include >> +a width, which is a decimal number that appears after any flags. If a >> +substitution contains fewer characters than its specified width, it is >> +extended with padding, normally comprising spaces inserted on the^^^^^ >> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >> +left: >> ^^^^ > > "it is padded on the left" is simpler and more clear. Done. >> +Here is a more complicated example that combines several >> +aforementioned features: >> + >> +@example >> +(format-spec "%<06e %<06b" >> + '((?b . "beta") >> + (?e . "epsilon"))) >> + @result{} "psilon 00beta" >> +@end example > > Can we make this example be less trivial? This use case doesn't > justify using format-spec at all. It's hard coming up with a simple enough example that both justifies format-spec and showcases modifier combinations. Would replicating a subset of the output of battery-status-function be any good? E.g.: (setq my-battery-info (list (cons ?p "73") ; Percentage (cons ?L "Battery") ; Status (cons ?t "2:23") ; Remaining time (cons ?c "24330") ; Capacity (cons ?r "10.6"))) ; Rate of discharge (format-spec "%>^-3L : %3p%% (%05t left)" my-battery-info) => "BAT : 73% (02:23 left)" (format-spec "%>^-3L : %3p%% (%05t left)" (cons (cons ?L "AC") my-battery-info)) => "AC : 73% (02:23 left)" > Even the subtle point of having the format specs in the order > different from the alist is not evident unless you make a point of > mentioning it (something that IMO should have been done earlier in the > description). Done. How's the new attached version? -- Basil --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Improve-format-spec-documentation-bug-41571.patch >From 096755e58259a0520e44787a00d891e3bf6d4048 Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Thu, 28 May 2020 00:53:42 +0100 Subject: [PATCH] Improve format-spec documentation (bug#41571) * doc/lispref/text.texi (Interpolated Strings): Move from here... * doc/lispref/strings.texi (Custom Format Strings): ...to here, renaming the node and clarifying the documentation. (Formatting Strings): End node with sentence referring to the next one. * lisp/format-spec.el (format-spec): Clarify docstring. --- doc/lispref/strings.texi | 168 +++++++++++++++++++++++++++++++++++++++ doc/lispref/text.texi | 64 --------------- lisp/format-spec.el | 49 +++++++----- 3 files changed, 198 insertions(+), 83 deletions(-) diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 70c3b3cf4b..9098774fe9 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -28,6 +28,7 @@ Strings and Characters * Text Comparison:: Comparing characters or strings. * String Conversion:: Converting to and from characters and strings. * Formatting Strings:: @code{format}: Emacs's analogue of @code{printf}. +* Custom Format Strings:: Formatting custom @code{format} specifications. * Case Conversion:: Case conversion functions. * Case Tables:: Customizing case conversion. @end menu @@ -1122,6 +1123,173 @@ Formatting Strings NaNs and can lose precision and type, and @samp{#x%x} and @samp{#o%o} can mishandle negative integers. @xref{Input Functions}. +The functions described in this section accept a fixed set of +specification characters. The next section describes a function +@code{format-spec} which can accept custom specification characters, +such as @samp{%a} or @samp{%z}. + +@node Custom Format Strings +@section Custom Format Strings +@cindex custom format string +@cindex custom @samp{%}-sequence in format + +Sometimes it is useful to allow Lisp programs to control how certain +text is generated via custom format control strings. For example, a +format string could control how to display someone's forename, +surname, and email address. Using the function @code{format} +described in the previous section, the format string could be +something like @w{@code{"%s %s <%s>"}}. This approach quickly becomes +impractical, however, as it can be unclear which specification +character corresponds to which piece of information. + +A more convenient format string for such cases would be something like +@w{@code{"%f %l <%e>"}}, where each specification character carries +more semantic information and can easily be rearranged relative to +other specification characters. The function @code{format-spec} +described in this section performs a similar function to +@code{format}, except it operates on format control strings that use +arbitrary specification characters. + +@defun format-spec template spec-alist &optional only-present +This function returns a string produced from the format string +@var{template} according to conversions specified in @var{spec-alist}, +which is an alist (@pxref{Association Lists}) of the form +@w{@code{(@var{letter} . @var{replacement})}}. Each specification +@code{%@var{letter}} in @var{template} will be replaced by +@var{replacement} when formatting the resulting string. + +The characters in @var{template}, other than the format +specifications, are copied directly into the output, including their +text properties, if any. Any text properties of the format +specifications are copied to their replacements. + +Using an alist to specify conversions gives rise to some useful +properties: + +@itemize @bullet +@item +If @var{spec-alist} contains more unique @var{letter} keys than there +are unique specification characters in @var{template}, the unused keys +are simply ignored. +@item +If @var{spec-alist} contains more than one association with the same +@var{letter}, the closest one to the start of the list is used. +@item +If @var{template} contains the same specification character more than +once, then the same @var{replacement} found in @var{spec-alist} is +used as a basis for all of that character's substitutions. +@item +The order of specifications in @var{template} need not correspond to +the order of associations in @var{spec-alist}. +@end itemize + +The optional argument @var{only-present} 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 +signals an error. Otherwise, those format specifications and any +occurrences of @samp{%%} in @var{template} are left verbatim in the +output, including their text properties, if any. +@end defun + +The syntax of format specifications accepted by @code{format-spec} is +similar, but not identical, to that accepted by @code{format}. In +both cases, a format specification is a sequence of characters +beginning with @samp{%} and ending with an alphabetic letter such as +@samp{s}. The only specification that does not end in a letter is +@samp{%%}, which is replaced with a single @samp{%} in the output. + +Unlike @code{format}, which assigns specific meanings to a fixed set +of specification characters, @code{format-spec} accepts arbitrary +specification characters and treats them all equally. For example: + +@example +@group +(setq my-site-info + (list (cons ?s system-name) + (cons ?t (symbol-name system-type)) + (cons ?c system-configuration) + (cons ?v emacs-version) + (cons ?e invocation-name) + (cons ?p (number-to-string (emacs-pid))) + (cons ?a user-mail-address) + (cons ?n user-full-name))) + +(format-spec "%e %v (%c)" my-site-info) + @result{} "emacs 27.1 (x86_64-pc-linux-gnu)" + +(format-spec "%n <%a>" my-site-info) + @result{} "Emacs Developers " +@end group +@end example + +A format specification can include any number of the following flag +characters immediately after the @samp{%} to modify aspects of the +substitution. + +@table @samp +@item 0 +This flag causes any padding specified by the width to consist of +@samp{0} characters instead of spaces. + +@item - +This flag causes any padding specified by the width to be inserted on +the right rather than the left. + +@item < +This flag causes the substitution to be truncated on the left to the +given width, if specified. + +@item > +This flag causes the substitution to be truncated on the right to the +given width, if specified. + +@item ^ +This flag converts the substituted text to upper case (@pxref{Case +Conversion}). + +@item _ +This flag converts the substituted text to lower case (@pxref{Case +Conversion}). +@end table + +The result of using contradictory flags (for instance, both upper and +lower case) is undefined. + +As is the case with @code{format}, a format specification can include +a width, which is a decimal number that appears after any flags. If a +substitution contains fewer characters than its specified width, it is +padded on the left: + +@example +@group +(format-spec "%8a is padded on the left with spaces" + '((?a . "alpha"))) + @result{} " alpha is padded on the left with spaces" +@end group +@end example + +Here is a more complicated example that combines several +aforementioned features: + +@example +@group +(setq my-battery-info + (list (cons ?p "73") ; Percentage + (cons ?L "Battery") ; Status + (cons ?t "2:23") ; Remaining time + (cons ?c "24330") ; Capacity + (cons ?r "10.6"))) ; Rate of discharge + +(format-spec "%>^-3L : %3p%% (%05t left)" my-battery-info) + @result{} "BAT : 73% (02:23 left)" + +(format-spec "%>^-3L : %3p%% (%05t left)" + (cons (cons ?L "AC") + my-battery-info)) + @result{} "AC : 73% (02:23 left)" +@end group +@end example + @node Case Conversion @section Case Conversion in Lisp @cindex upper case diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index de436fa9e6..a14867e1d1 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -58,7 +58,6 @@ Text of another buffer. * Decompression:: Dealing with compressed data. * Base 64:: Conversion to or from base 64 encoding. -* Interpolated Strings:: Formatting Customizable Strings. * Checksum/Hash:: Computing cryptographic hashes. * GnuTLS Cryptography:: Cryptographic algorithms imported from GnuTLS. * Parsing HTML/XML:: Parsing HTML and XML. @@ -4662,69 +4661,6 @@ Base 64 is optional, and the URL variant of base 64 encoding is used. @end defun - -@node Interpolated Strings -@section Formatting Customizable Strings - -It is, in some circumstances, useful to present users with a string to -be customized that can then be expanded programmatically. For -instance, @code{erc-header-line-format} is @code{"%n on %t (%m,%l) -%o"}, and each of those characters after the percent signs are -expanded when the header line is computed. To do this, the -@code{format-spec} function is used: - -@defun format-spec format specification &optional only-present -@var{format} is the format specification string as in the example -above. @var{specification} is an alist that has elements where the -@code{car} is a character and the @code{cdr} is the substitution. - -If @var{only-present} is @code{nil}, errors will be signaled if a -format character has been used that's not present in -@var{specification}. If it's non-@code{nil}, that format -specification is left verbatim in the result. -@end defun - -Here's a trivial example: - -@example -(format-spec "su - %u %l" - `((?u . ,(user-login-name)) - (?l . "ls"))) - @result{} "su - foo ls" -@end example - -In addition to allowing padding/limiting to a certain length, the -following modifiers can be used: - -@table @asis -@item @samp{0} -Pad with zeros instead of the default spaces. - -@item @samp{-} -Pad to the right. - -@item @samp{^} -Use upper case. - -@item @samp{_} -Use lower case. - -@item @samp{<} -If the length needs to be limited, remove characters from the left. - -@item @samp{>} -Same as previous, but remove characters from the right. -@end table - -If contradictory modifiers are used (for instance, both upper and -lower case), then what happens is undefined. - -As an example, @samp{"%<010b"} means ``insert the @samp{b} expansion, -but pad with leading zeros if it's less than ten characters, and if -it's more than ten characters, shorten by removing characters from the -left.'' - - @node Checksum/Hash @section Checksum/Hash @cindex MD5 checksum diff --git a/lisp/format-spec.el b/lisp/format-spec.el index f418cea425..9278bd74c4 100644 --- a/lisp/format-spec.el +++ b/lisp/format-spec.el @@ -29,35 +29,46 @@ (defun format-spec (format specification &optional only-present) "Return a string based on FORMAT and SPECIFICATION. -FORMAT is a string containing `format'-like specs like \"su - %u %k\", -while SPECIFICATION is an alist mapping from format spec characters -to values. +FORMAT is a string containing `format'-like specs like \"su - %u %k\". +SPECIFICATION is an alist mapping format specification characters +to their substitutions. For instance: (format-spec \"su - %u %l\" - `((?u . ,(user-login-name)) + \\=`((?u . ,(user-login-name)) (?l . \"ls\"))) -Each format spec can have modifiers, where \"%<010b\" means \"if -the expansion is shorter than ten characters, zero-pad it, and if -it's longer, chop off characters from the left side\". +Each %-spec may contain optional flag and width modifiers, as +follows: -The following modifiers are allowed: + %character -* 0: Use zero-padding. -* -: Pad to the right. -* ^: Upper-case the expansion. -* _: Lower-case the expansion. -* <: Limit the length by removing chars from the left. -* >: Limit the length by removing chars from the right. +The following flags are allowed: -Any text properties on a %-spec itself are propagated to the text -that it generates. +* 0: Pad to the width, if given, with zeros instead of spaces. +* -: Pad to the width, if given, on the right instead of the left. +* <: Truncate to the width, if given, on the left. +* >: Truncate to the width, if given, on the right. +* ^: Convert to upper case. +* _: Convert to lower case. -If ONLY-PRESENT, format spec characters not present in -SPECIFICATION are ignored, and the \"%\" characters are left -where they are, including \"%%\" strings." +The width modifier behaves like the corresponding one in `format' +when applied to %s. + +For example, \"%<010b\" means \"substitute into the output the +value associated with ?b in SPECIFICATION, either padding it with +leading zeros or truncating leading characters until it's ten +characters wide\". + +Any text properties of FORMAT are copied to the result, with any +text properties of a %-spec itself copied to its substitution. + +ONLY-PRESENT indicates how to handle %-spec characters not +present in SPECIFICATION. If it is nil or omitted, emit an +error; otherwise leave those %-specs and any occurrences of +\"%%\" in FORMAT verbatim in the result, including their text +properties, if any." (with-temp-buffer (insert format) (goto-char (point-min)) -- 2.26.2 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Sun May 31 12:04:06 2020 Received: (at 41571) by debbugs.gnu.org; 31 May 2020 16:04:06 +0000 Received: from localhost ([127.0.0.1]:33663 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jfQRS-00072e-2Z for submit@debbugs.gnu.org; Sun, 31 May 2020 12:04:06 -0400 Received: from eggs.gnu.org ([209.51.188.92]:44598) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jfQRP-00071M-Tj for 41571@debbugs.gnu.org; Sun, 31 May 2020 12:04:04 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:56230) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jfQRJ-0000Ka-Su; Sun, 31 May 2020 12:03:57 -0400 Received: from [176.228.60.248] (port=2003 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1jfQRI-0005eO-Bk; Sun, 31 May 2020 12:03:57 -0400 Date: Sun, 31 May 2020 19:03:55 +0300 Message-Id: <831rn0ks5w.fsf@gnu.org> From: Eli Zaretskii To: "Basil L. Contovounesios" In-Reply-To: <87wo4s8nj5.fsf@tcd.ie> (contovob@tcd.ie) Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> <87zh9sfij1.fsf@tcd.ie> <837dwws38a.fsf@gnu.org> <877dwu4mj0.fsf@tcd.ie> <83mu5qmsuz.fsf@gnu.org> <87wo4s8nj5.fsf@tcd.ie> X-Spam-Score: -1.4 (-) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.4 (--) > From: "Basil L. Contovounesios" > Cc: 41571@debbugs.gnu.org > Date: Sun, 31 May 2020 10:24:46 +0100 > > > (Btw, why are you attachments appear before the text? It makes > > responding harder, because I need to bring the citations to the > > front.) > > Sorry, I got into the habit of doing that because I wasn't sure whether > attachments should go before or after the email signature. I'm guessing > after? Yes, after is better if you include text that is worded as a preamble to the patch (which is usually the case). > > @defun format-spec template spec-alist &optional only-present > > This function returns a format string suitable for using in > > @code{format} and similar functions. The format string is produced > > from @var{template} according to conversions specified in > > @var{spec-alist}, which is an alist (@pxref{Association Lists}) of > > the form @w{@code{(@var{letter} . @var{replacement})}}. Each > > specification @code{%@var{letter}} in @var{template} will be > > replaced by @var{replacement} when producing the resulting format > > string. > > This wording is much clearer, but the description of the output is > wrong: 'format-spec' and 'format' both produce the same result - a > formatted string, not a format string. Well, that just reflects on how the original text could lead to a grave misunderstanding, doesn't it? ;-) > > Here you use "key" without first explaining what it is. > > I was relying on the preceding xref to the node on alists, which defines > the terms "alist", "key", and "associated value". I don't recommend to rely on that, not in general. Cross-references are there for readers who want to see additional details, but the text should be self-explanatory even if the cross-references are not followed. IOW, the cross-references are optional reading. > > How is what's described in the last sentence "an exception"? Format > > strings used by 'format' also behave like that, right? > > It's an exception to "beginning with % and ending with a letter". Ah! But the text was worded in a way that led me to believe the exception was from the similarity between 'format' and 'format-spec'. > Would it be clearer if I said "the only specification that does not end > in a letter is %%, which is replaced with a single % in the output"? Not sure. Perhaps that sentence should simply be removed, because it looks like the differences between these two APIs are described in the following paragraph. And %% is supported the same by both of them, so mentioning it here is just a distraction. > The main use case for format-spec I've seen is where one part of the > program produces an alist with all the information that could ever be > needed, and another part of the program formats an often > user-customisable format string using this data. > > An example of such a use case is in battery.el, where the alist produced > by battery-status-function is used to format battery-echo-area-format > and battery-mode-line-format (battery.el doesn't currently use > format-spec, but it could and my WIP patch for master changes that). How about saying this in the text? In fact, "user-customizable format string" is never mentioned in the text, it is only hinted upon in the menu entry leading to this node. If the main use case is to let users customize string-valued variables conveniently, that use case should be described and explained in more detail, including why it makes customization more convenient. > How's the new attached version? It is much better, thanks. From debbugs-submit-bounces@debbugs.gnu.org Tue Jun 02 10:03:49 2020 Received: (at 41571) by debbugs.gnu.org; 2 Jun 2020 14:03:49 +0000 Received: from localhost ([127.0.0.1]:40493 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jg7W8-00064k-OL for submit@debbugs.gnu.org; Tue, 02 Jun 2020 10:03:49 -0400 Received: from mail-wm1-f52.google.com ([209.85.128.52]:54147) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jg7W6-00064V-Kk for 41571@debbugs.gnu.org; Tue, 02 Jun 2020 10:03:47 -0400 Received: by mail-wm1-f52.google.com with SMTP id l26so3049849wme.3 for <41571@debbugs.gnu.org>; Tue, 02 Jun 2020 07:03:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tcd-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=5hncf2Ovc0t1CqBOFXtYC8Sjkv9KU14QOc/PkoB/Hyo=; b=EKqM5tTPqX+HUTb5IP1ykjb3kQKHvCSIOntZRxtbMLyQlMAJ7ePjSkHZ6TiC4CTY5r 5hAbD165L/nh7we740Qm6GMBSnDLlvgTAu0JfEGjkVlz0gx+e+vjeJP+vd57t7GJy9fu 8TbrZCwkF/0H2xHMO9l4JngSdQ0+ID2c91cQ2OR3/sFkVFwEO5tu8DGc50DN/yd/TakK dE+mxoXswumkWOfEeJ6WcQYkvEG8/p+/XGHtQqKs8ha3oF/oVKBVP0mxX+dw/RaR9gCV qGQ3hhHT8lT1iyg6m6qBu7jyXhuf0JfXAzhmZIpD5zosUxKnVeWntBaUQFsNCsIHqwxa 9L+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=5hncf2Ovc0t1CqBOFXtYC8Sjkv9KU14QOc/PkoB/Hyo=; b=ZbLJNJzDJIPdbSXFW4qxt5f0T/aWBw4ZkfMJThbkF3nzwSGTgDhNnRXY0VLFGrUGC4 ZvPB8ng6mifslT3h4fd1jsRwLlW1tIsxUqjaAsdnTl2K15nMkXsntqVNjC0/999T+/dM LQmjUb9qudhcnw8gZwKVuy915zINoH9DE1DJB27MeIVI6sZjBr8QCgw1SAm37vVg5ahW 7P9d0C5VJ4WcA6e7MVyLJ7m4IHX+7dUNzNjzdj7BBSokcoZs1rfZIXvcIRCldNpujdwO beiI09NJjLqwsql2uUzaYRi9zd9FAy836r52wClbxJagspq+CKe5J0Hd/pMxoV44J60S 8S0w== X-Gm-Message-State: AOAM533latlHRJatQvSNIUwUIa0j+Mquwn2lXtIih462QwNdHmimmaWK Kj5jijcW24slDc+1I0D2cg63tg== X-Google-Smtp-Source: ABdhPJyUS45eus1deOalngpubwBHbM27KUcRRMCK7uGIsjgkKvlVnq4e0ygHKVbTknlGf595bkuJEg== X-Received: by 2002:a1c:2183:: with SMTP id h125mr4228349wmh.88.1591106620624; Tue, 02 Jun 2020 07:03:40 -0700 (PDT) Received: from localhost ([2a02:8084:20e2:c380:1f68:7ff5:120d:64e]) by smtp.gmail.com with ESMTPSA id o9sm3738000wmh.37.2020.06.02.07.03.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Jun 2020 07:03:39 -0700 (PDT) From: "Basil L. Contovounesios" To: Eli Zaretskii Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> <87zh9sfij1.fsf@tcd.ie> <837dwws38a.fsf@gnu.org> <877dwu4mj0.fsf@tcd.ie> <83mu5qmsuz.fsf@gnu.org> <87wo4s8nj5.fsf@tcd.ie> <831rn0ks5w.fsf@gnu.org> Date: Tue, 02 Jun 2020 15:03:36 +0100 In-Reply-To: <831rn0ks5w.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 31 May 2020 19:03:55 +0300") Message-ID: <875zc9muo7.fsf@tcd.ie> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Eli Zaretskii writes: >> From: "Basil L. Contovounesios" >> Cc: 41571@debbugs.gnu.org >> Date: Sun, 31 May 2020 10:24:46 +0100 >> >> > (Btw, why are you attachments appear before the text? It makes >> > responding harder, because I need to bring the citations to the >> > front.) >> >> Sorry, I got into the habit of doing that because I wasn't sure whether >> attachments should go before or after the email signature. I'm guessing >> after? > > Yes, after is better if you include text that is worded as a preamble > to the patch (which is usually the case). OK. >> This wording is much clearer, but the description of the output is >> wrong: 'format-spec' and 'format' both produce the same result - a >> formatted string, not a format string. > > Well, that just reflects on how the original text could lead to a > grave misunderstanding, doesn't it? ;-) I thought truth is in the eye of the beholder. ;) >> > Here you use "key" without first explaining what it is. >> >> I was relying on the preceding xref to the node on alists, which defines >> the terms "alist", "key", and "associated value". > > I don't recommend to rely on that, not in general. Cross-references > are there for readers who want to see additional details, but the text > should be self-explanatory even if the cross-references are not > followed. IOW, the cross-references are optional reading. OK. >> > How is what's described in the last sentence "an exception"? Format >> > strings used by 'format' also behave like that, right? >> >> It's an exception to "beginning with % and ending with a letter". > > Ah! But the text was worded in a way that led me to believe the > exception was from the similarity between 'format' and 'format-spec'. > >> Would it be clearer if I said "the only specification that does not end >> in a letter is %%, which is replaced with a single % in the output"? > > Not sure. Perhaps that sentence should simply be removed, because it > looks like the differences between these two APIs are described in the > following paragraph. And %% is supported the same by both of them, so > mentioning it here is just a distraction. Done. >> The main use case for format-spec I've seen is where one part of the >> program produces an alist with all the information that could ever be >> needed, and another part of the program formats an often >> user-customisable format string using this data. >> >> An example of such a use case is in battery.el, where the alist produced >> by battery-status-function is used to format battery-echo-area-format >> and battery-mode-line-format (battery.el doesn't currently use >> format-spec, but it could and my WIP patch for master changes that). > > How about saying this in the text? In fact, "user-customizable format > string" is never mentioned in the text, it is only hinted upon in the > menu entry leading to this node. Done. > If the main use case is to let users customize string-valued variables > conveniently, that use case should be described and explained in more > detail, including why it makes customization more convenient. I already tried doing that in the two opening paragraphs, which is why the original text said something like "allow the user to control..." rather than "allow Lisp programs to control...". I've now mentioned both in the opening and added a new paragraph at the end of the section. How's the attached? Thanks, -- Basil --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Improve-format-spec-documentation-bug-41571.patch >From b07e3b1d97e73c5cf0cd60edf4838b555530bbf0 Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Thu, 28 May 2020 00:53:42 +0100 Subject: [PATCH] Improve format-spec documentation (bug#41571) * doc/lispref/text.texi (Interpolated Strings): Move from here... * doc/lispref/strings.texi (Custom Format Strings): ...to here, renaming the node and clarifying the documentation. (Formatting Strings): End node with sentence referring to the next one. * lisp/format-spec.el (format-spec): Clarify docstring. --- doc/lispref/strings.texi | 176 +++++++++++++++++++++++++++++++++++++++ doc/lispref/text.texi | 64 -------------- lisp/format-spec.el | 49 ++++++----- 3 files changed, 206 insertions(+), 83 deletions(-) diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 70c3b3cf4b..4a7bda57c4 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -28,6 +28,7 @@ Strings and Characters * Text Comparison:: Comparing characters or strings. * String Conversion:: Converting to and from characters and strings. * Formatting Strings:: @code{format}: Emacs's analogue of @code{printf}. +* Custom Format Strings:: Formatting custom @code{format} specifications. * Case Conversion:: Case conversion functions. * Case Tables:: Customizing case conversion. @end menu @@ -1122,6 +1123,181 @@ Formatting Strings NaNs and can lose precision and type, and @samp{#x%x} and @samp{#o%o} can mishandle negative integers. @xref{Input Functions}. +The functions described in this section accept a fixed set of +specification characters. The next section describes a function +@code{format-spec} which can accept custom specification characters, +such as @samp{%a} or @samp{%z}. + +@node Custom Format Strings +@section Custom Format Strings +@cindex custom format string +@cindex custom @samp{%}-sequence in format + +Sometimes it is useful to allow users and Lisp programs alike to +control how certain text is generated via custom format control +strings. For example, a format string could control how to display +someone's forename, surname, and email address. Using the function +@code{format} described in the previous section, the format string +could be something like @w{@code{"%s %s <%s>"}}. This approach +quickly becomes impractical, however, as it can be unclear which +specification character corresponds to which piece of information. + +A more convenient format string for such cases would be something like +@w{@code{"%f %l <%e>"}}, where each specification character carries +more semantic information and can easily be rearranged relative to +other specification characters, making such format strings more easily +customizable by the user. + +The function @code{format-spec} described in this section performs a +similar function to @code{format}, except it operates on format +control strings that use arbitrary specification characters. + +@defun format-spec template spec-alist &optional only-present +This function returns a string produced from the format string +@var{template} according to conversions specified in @var{spec-alist}, +which is an alist (@pxref{Association Lists}) of the form +@w{@code{(@var{letter} . @var{replacement})}}. Each specification +@code{%@var{letter}} in @var{template} will be replaced by +@var{replacement} when formatting the resulting string. + +The characters in @var{template}, other than the format +specifications, are copied directly into the output, including their +text properties, if any. Any text properties of the format +specifications are copied to their replacements. + +Using an alist to specify conversions gives rise to some useful +properties: + +@itemize @bullet +@item +If @var{spec-alist} contains more unique @var{letter} keys than there +are unique specification characters in @var{template}, the unused keys +are simply ignored. +@item +If @var{spec-alist} contains more than one association with the same +@var{letter}, the closest one to the start of the list is used. +@item +If @var{template} contains the same specification character more than +once, then the same @var{replacement} found in @var{spec-alist} is +used as a basis for all of that character's substitutions. +@item +The order of specifications in @var{template} need not correspond to +the order of associations in @var{spec-alist}. +@end itemize + +The optional argument @var{only-present} 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 +signals an error. Otherwise, those format specifications and any +occurrences of @samp{%%} in @var{template} are left verbatim in the +output, including their text properties, if any. +@end defun + +The syntax of format specifications accepted by @code{format-spec} is +similar, but not identical, to that accepted by @code{format}. In +both cases, a format specification is a sequence of characters +beginning with @samp{%} and ending with an alphabetic letter such as +@samp{s}. + +Unlike @code{format}, which assigns specific meanings to a fixed set +of specification characters, @code{format-spec} accepts arbitrary +specification characters and treats them all equally. For example: + +@example +@group +(setq my-site-info + (list (cons ?s system-name) + (cons ?t (symbol-name system-type)) + (cons ?c system-configuration) + (cons ?v emacs-version) + (cons ?e invocation-name) + (cons ?p (number-to-string (emacs-pid))) + (cons ?a user-mail-address) + (cons ?n user-full-name))) + +(format-spec "%e %v (%c)" my-site-info) + @result{} "emacs 27.1 (x86_64-pc-linux-gnu)" + +(format-spec "%n <%a>" my-site-info) + @result{} "Emacs Developers " +@end group +@end example + +A format specification can include any number of the following flag +characters immediately after the @samp{%} to modify aspects of the +substitution. + +@table @samp +@item 0 +This flag causes any padding specified by the width to consist of +@samp{0} characters instead of spaces. + +@item - +This flag causes any padding specified by the width to be inserted on +the right rather than the left. + +@item < +This flag causes the substitution to be truncated on the left to the +given width, if specified. + +@item > +This flag causes the substitution to be truncated on the right to the +given width, if specified. + +@item ^ +This flag converts the substituted text to upper case (@pxref{Case +Conversion}). + +@item _ +This flag converts the substituted text to lower case (@pxref{Case +Conversion}). +@end table + +The result of using contradictory flags (for instance, both upper and +lower case) is undefined. + +As is the case with @code{format}, a format specification can include +a width, which is a decimal number that appears after any flags. If a +substitution contains fewer characters than its specified width, it is +padded on the left: + +@example +@group +(format-spec "%8a is padded on the left with spaces" + '((?a . "alpha"))) + @result{} " alpha is padded on the left with spaces" +@end group +@end example + +Here is a more complicated example that combines several +aforementioned features: + +@example +@group +(setq my-battery-info + (list (cons ?p "73") ; Percentage + (cons ?L "Battery") ; Status + (cons ?t "2:23") ; Remaining time + (cons ?c "24330") ; Capacity + (cons ?r "10.6"))) ; Rate of discharge + +(format-spec "%>^-3L : %3p%% (%05t left)" my-battery-info) + @result{} "BAT : 73% (02:23 left)" + +(format-spec "%>^-3L : %3p%% (%05t left)" + (cons (cons ?L "AC") + my-battery-info)) + @result{} "AC : 73% (02:23 left)" +@end group +@end example + +As the examples in this section illustrate, @code{format-spec} is +often used for selectively formatting an assortment of different +pieces of information. This is useful in programs that provide +user-customizable format strings, as the user can choose to format +with a regular syntax and in any desired order only a subset of the +information that the program makes available. + @node Case Conversion @section Case Conversion in Lisp @cindex upper case diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index de436fa9e6..a14867e1d1 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -58,7 +58,6 @@ Text of another buffer. * Decompression:: Dealing with compressed data. * Base 64:: Conversion to or from base 64 encoding. -* Interpolated Strings:: Formatting Customizable Strings. * Checksum/Hash:: Computing cryptographic hashes. * GnuTLS Cryptography:: Cryptographic algorithms imported from GnuTLS. * Parsing HTML/XML:: Parsing HTML and XML. @@ -4662,69 +4661,6 @@ Base 64 is optional, and the URL variant of base 64 encoding is used. @end defun - -@node Interpolated Strings -@section Formatting Customizable Strings - -It is, in some circumstances, useful to present users with a string to -be customized that can then be expanded programmatically. For -instance, @code{erc-header-line-format} is @code{"%n on %t (%m,%l) -%o"}, and each of those characters after the percent signs are -expanded when the header line is computed. To do this, the -@code{format-spec} function is used: - -@defun format-spec format specification &optional only-present -@var{format} is the format specification string as in the example -above. @var{specification} is an alist that has elements where the -@code{car} is a character and the @code{cdr} is the substitution. - -If @var{only-present} is @code{nil}, errors will be signaled if a -format character has been used that's not present in -@var{specification}. If it's non-@code{nil}, that format -specification is left verbatim in the result. -@end defun - -Here's a trivial example: - -@example -(format-spec "su - %u %l" - `((?u . ,(user-login-name)) - (?l . "ls"))) - @result{} "su - foo ls" -@end example - -In addition to allowing padding/limiting to a certain length, the -following modifiers can be used: - -@table @asis -@item @samp{0} -Pad with zeros instead of the default spaces. - -@item @samp{-} -Pad to the right. - -@item @samp{^} -Use upper case. - -@item @samp{_} -Use lower case. - -@item @samp{<} -If the length needs to be limited, remove characters from the left. - -@item @samp{>} -Same as previous, but remove characters from the right. -@end table - -If contradictory modifiers are used (for instance, both upper and -lower case), then what happens is undefined. - -As an example, @samp{"%<010b"} means ``insert the @samp{b} expansion, -but pad with leading zeros if it's less than ten characters, and if -it's more than ten characters, shorten by removing characters from the -left.'' - - @node Checksum/Hash @section Checksum/Hash @cindex MD5 checksum diff --git a/lisp/format-spec.el b/lisp/format-spec.el index f418cea425..9278bd74c4 100644 --- a/lisp/format-spec.el +++ b/lisp/format-spec.el @@ -29,35 +29,46 @@ (defun format-spec (format specification &optional only-present) "Return a string based on FORMAT and SPECIFICATION. -FORMAT is a string containing `format'-like specs like \"su - %u %k\", -while SPECIFICATION is an alist mapping from format spec characters -to values. +FORMAT is a string containing `format'-like specs like \"su - %u %k\". +SPECIFICATION is an alist mapping format specification characters +to their substitutions. For instance: (format-spec \"su - %u %l\" - `((?u . ,(user-login-name)) + \\=`((?u . ,(user-login-name)) (?l . \"ls\"))) -Each format spec can have modifiers, where \"%<010b\" means \"if -the expansion is shorter than ten characters, zero-pad it, and if -it's longer, chop off characters from the left side\". +Each %-spec may contain optional flag and width modifiers, as +follows: -The following modifiers are allowed: + %character -* 0: Use zero-padding. -* -: Pad to the right. -* ^: Upper-case the expansion. -* _: Lower-case the expansion. -* <: Limit the length by removing chars from the left. -* >: Limit the length by removing chars from the right. +The following flags are allowed: -Any text properties on a %-spec itself are propagated to the text -that it generates. +* 0: Pad to the width, if given, with zeros instead of spaces. +* -: Pad to the width, if given, on the right instead of the left. +* <: Truncate to the width, if given, on the left. +* >: Truncate to the width, if given, on the right. +* ^: Convert to upper case. +* _: Convert to lower case. -If ONLY-PRESENT, format spec characters not present in -SPECIFICATION are ignored, and the \"%\" characters are left -where they are, including \"%%\" strings." +The width modifier behaves like the corresponding one in `format' +when applied to %s. + +For example, \"%<010b\" means \"substitute into the output the +value associated with ?b in SPECIFICATION, either padding it with +leading zeros or truncating leading characters until it's ten +characters wide\". + +Any text properties of FORMAT are copied to the result, with any +text properties of a %-spec itself copied to its substitution. + +ONLY-PRESENT indicates how to handle %-spec characters not +present in SPECIFICATION. If it is nil or omitted, emit an +error; otherwise leave those %-specs and any occurrences of +\"%%\" in FORMAT verbatim in the result, including their text +properties, if any." (with-temp-buffer (insert format) (goto-char (point-min)) -- 2.26.2 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Tue Jun 02 12:57:23 2020 Received: (at 41571) by debbugs.gnu.org; 2 Jun 2020 16:57:23 +0000 Received: from localhost ([127.0.0.1]:40793 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jgAE7-0002GW-GD for submit@debbugs.gnu.org; Tue, 02 Jun 2020 12:57:23 -0400 Received: from eggs.gnu.org ([209.51.188.92]:59836) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jgAE6-0002GK-6Y for 41571@debbugs.gnu.org; Tue, 02 Jun 2020 12:57:22 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:48259) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jgAE0-0006UY-Hw; Tue, 02 Jun 2020 12:57:16 -0400 Received: from [176.228.60.248] (port=3229 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1jgADz-0003qw-AL; Tue, 02 Jun 2020 12:57:16 -0400 Date: Tue, 02 Jun 2020 19:56:57 +0300 Message-Id: <83o8q1cso6.fsf@gnu.org> From: Eli Zaretskii To: "Basil L. Contovounesios" In-Reply-To: <875zc9muo7.fsf@tcd.ie> (contovob@tcd.ie) Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> <87zh9sfij1.fsf@tcd.ie> <837dwws38a.fsf@gnu.org> <877dwu4mj0.fsf@tcd.ie> <83mu5qmsuz.fsf@gnu.org> <87wo4s8nj5.fsf@tcd.ie> <831rn0ks5w.fsf@gnu.org> <875zc9muo7.fsf@tcd.ie> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 41571 Cc: 41571@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: "Basil L. Contovounesios" > Cc: 41571@debbugs.gnu.org > Date: Tue, 02 Jun 2020 15:03:36 +0100 > > > If the main use case is to let users customize string-valued variables > > conveniently, that use case should be described and explained in more > > detail, including why it makes customization more convenient. > > I already tried doing that in the two opening paragraphs, which is why > the original text said something like "allow the user to control..." > rather than "allow Lisp programs to control...". I've now mentioned > both in the opening and added a new paragraph at the end of the section. > > How's the attached? LGTM, thanks. From debbugs-submit-bounces@debbugs.gnu.org Tue Jun 02 15:58:16 2020 Received: (at control) by debbugs.gnu.org; 2 Jun 2020 19:58:16 +0000 Received: from localhost ([127.0.0.1]:41031 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jgD3A-0000LT-G3 for submit@debbugs.gnu.org; Tue, 02 Jun 2020 15:58:16 -0400 Received: from mail-wr1-f44.google.com ([209.85.221.44]:42013) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jgD2x-0000Kj-7g for control@debbugs.gnu.org; Tue, 02 Jun 2020 15:58:15 -0400 Received: by mail-wr1-f44.google.com with SMTP id p5so4621662wrw.9 for ; Tue, 02 Jun 2020 12:58:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tcd-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=76HUy6Au2wOjj4yqyaRDaZDYsdlfW/g01jGXcKNv+Vw=; b=LhatS1pqYyaBam9wI7hWiPC6SAU8L82g0aaPRF+lUJFOeIe0fthHIDviTphzX7lz3p XRNNy0xmEr119bkaHLOYSxl13TQ363HY7/ug7MJ27e2xrbp4QqSPYdG6OhTJx3EeUKLw qX8sZA04bkEJWng4OJrVIlsyIoIJa+40u5eMlh9Bcv5tC6Wj56fChj7Hx4kl6G+FPeQp oxti/vEN0purQLbcSm2NrqeIK2bcNv59EDcB1q1FrRGAvH9cDhtphywAX8ob2WYoMmQv bSsrgu2p1ibqSfR+oi8Uy8PkBTJvqasM/ywVyari8cUs8YJIl52umF1I1l2xpa9K06IR j9nw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=76HUy6Au2wOjj4yqyaRDaZDYsdlfW/g01jGXcKNv+Vw=; b=N4nPJUwg+YcDFzpgaWQ7qZt0PAtXxh9T3xzzlfI585gXcIiOnWrbXRUxgBZW4rsQXI 8ySSljaZkY1Mf1Vwl2ztcr+k1k+4D0i8Wufb9lczpjVEJsKAQy7UErEn4+YsdlniAv8C 6bGjVolSj5O2jgemggkh0F2+9oYhuYKlf0H0FCgR/PiuNaciTv4GhWya6VzkVFBrQXuq D780cTFeGqMDQ5d+5fXIWIJqqh+EjanVBzkpx4zvgtB6LxibjkBd7i3q3QijReqFj4oy rwJd9pU8QsP5gwR8YIiZ/yGG07bDHTSN7HhhV3UA+MBFbBTban8xaGqxtsSo/Ws/AzPk G60w== X-Gm-Message-State: AOAM532JNyS8PPLGo6byKxRtIturevC9Eb43K54NjQBX8xolT2FrWVtL ouyhY+jnbSB+3lBS7xdK5nPHXQ== X-Google-Smtp-Source: ABdhPJw6YGf5kr3hZfOi2IVXKXVRIMmytZA45dxp+yGIFigC2FyF57+IS8SqYoWudXmr64A4gYvugA== X-Received: by 2002:adf:fd4f:: with SMTP id h15mr27323961wrs.397.1591127877266; Tue, 02 Jun 2020 12:57:57 -0700 (PDT) Received: from localhost ([2a02:8084:20e2:c380:1f68:7ff5:120d:64e]) by smtp.gmail.com with ESMTPSA id y5sm36258wrs.63.2020.06.02.12.57.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Jun 2020 12:57:56 -0700 (PDT) From: "Basil L. Contovounesios" To: Eli Zaretskii Subject: Re: bug#41571: 27.0.91; "(elisp) Interpolated Strings" is under "(elisp) Text" References: <877dwxexsh.fsf@tcd.ie> <83d06osfyw.fsf@gnu.org> <87zh9sfij1.fsf@tcd.ie> <837dwws38a.fsf@gnu.org> <877dwu4mj0.fsf@tcd.ie> <83mu5qmsuz.fsf@gnu.org> <87wo4s8nj5.fsf@tcd.ie> <831rn0ks5w.fsf@gnu.org> <875zc9muo7.fsf@tcd.ie> <83o8q1cso6.fsf@gnu.org> Date: Tue, 02 Jun 2020 20:57:55 +0100 In-Reply-To: <83o8q1cso6.fsf@gnu.org> (Eli Zaretskii's message of "Tue, 02 Jun 2020 19:56:57 +0300") Message-ID: <87mu5li6kc.fsf@tcd.ie> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: control Cc: 41571-done@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) tags 41571 fixed close 41571 27.1 quit Eli Zaretskii writes: >> From: "Basil L. Contovounesios" >> Cc: 41571@debbugs.gnu.org >> Date: Tue, 02 Jun 2020 15:03:36 +0100 >> >> How's the attached? > > LGTM, thanks. Thanks, pushed to emacs-27. Improve format-spec documentation (bug#41571) b07e3b1d97 2020-06-02 14:58:25 +0100 https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=b07e3b1d97e73c5cf0cd60edf4838b555530bbf0 -- Basil From unknown Mon Jun 16 23:55:33 2025 Received: (at fakecontrol) by fakecontrolmessage; To: internal_control@debbugs.gnu.org From: Debbugs Internal Request Subject: Internal Control Message-Id: bug archived. Date: Wed, 01 Jul 2020 11:24:06 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator