Fix and extend format-spec (bug#41758)
* lisp/format-spec.el: Use lexical-binding. Remove dependence on subr-x.el. (format-spec-make): Clarify docstring. (format-spec--parse-modifiers): Rename to... (format-spec--parse-flags): ...this and simplify. In particular, don't bother parsing :space-pad which is redundant and unused. (format-spec--pad): Remove, replacing with... (format-spec--do-flags): ...this new helper function which performs more of format-spec's supported text manipulation. (format-spec): Autoload. Allow optional argument to take on special values 'ignore' and 'delete' for more control over what happens when a replacement for a format specification isn't provided. Bring back proper support for a precision modifier similar to that of 'format'. * lisp/battery.el (battery-format): Rewrite in terms of format-spec. (battery-echo-area-format, battery-mode-line-format): Mention support of format-spec syntax in docstrings. * doc/lispref/strings.texi (Custom Format Strings): * etc/NEWS: Document and announce these changes. * lisp/dired-aux.el (dired-do-compress-to): * lisp/erc/erc-match.el (erc-log-matches): * lisp/erc/erc.el (erc-update-mode-line-buffer): * lisp/gnus/gnus-sieve.el (gnus-sieve-update): * lisp/gnus/gssapi.el (open-gssapi-stream): * lisp/gnus/mail-source.el (mail-source-fetch-file) (mail-source-fetch-directory, mail-source-fetch-pop) (mail-source-fetch-imap): * lisp/gnus/message.el (message-insert-formatted-citation-line): * lisp/image-dired.el: * lisp/net/eww.el: * lisp/net/imap.el (imap-kerberos4-open, imap-gssapi-open) (imap-shell-open): * lisp/net/network-stream.el (network-stream-open-shell): * lisp/obsolete/tls.el (open-tls-stream): * lisp/textmodes/tex-mode.el: Remove extraneous loads and autoloads of format-spec now that it is autoloaded and simplify its uses where possible. * test/lisp/battery-tests.el (battery-format): Test new format-spec support. * test/lisp/format-spec-tests.el (test-format-spec): Rename to... (format-spec) ...this, extending test cases. (test-format-unknown): Rename to... (format-spec-unknown): ...this, extending test cases. (test-format-modifiers): Rename to... (format-spec-flags): ...this. (format-spec-make, format-spec-parse-flags, format-spec-do-flags) (format-spec-do-flags-truncate, format-spec-do-flags-pad) (format-spec-do-flags-chop, format-spec-do-flags-case): New tests.
This commit is contained in:
parent
97d1f672ac
commit
0185d76e74
19 changed files with 407 additions and 290 deletions
|
@ -1152,7 +1152,7 @@ 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
|
||||
@defun format-spec template spec-alist &optional ignore-missing
|
||||
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
|
||||
|
@ -1185,12 +1185,15 @@ 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
|
||||
The optional argument @var{ignore-missing} 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.
|
||||
signals an error; if it is @code{ignore}, those format specifications
|
||||
are left verbatim in the output, including their text properties, if
|
||||
any; if it is @code{delete}, those format specifications are removed
|
||||
from the output; any other non-@code{nil} value is handled like
|
||||
@code{ignore}, but any occurrences of @samp{%%} are also left verbatim
|
||||
in the output.
|
||||
@end defun
|
||||
|
||||
The syntax of format specifications accepted by @code{format-spec} is
|
||||
|
@ -1238,7 +1241,7 @@ the right rather than the left.
|
|||
|
||||
@item <
|
||||
This flag causes the substitution to be truncated on the left to the
|
||||
given width, if specified.
|
||||
given width and precision, if specified.
|
||||
|
||||
@item >
|
||||
This flag causes the substitution to be truncated on the right to the
|
||||
|
@ -1257,9 +1260,12 @@ 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:
|
||||
a width, which is a decimal number that appears after any flags, and a
|
||||
precision, which is a decimal-point @samp{.} followed by a decimal
|
||||
number that appears after any flags and width.
|
||||
|
||||
If a substitution contains fewer characters than its specified width,
|
||||
it is padded on the left:
|
||||
|
||||
@example
|
||||
@group
|
||||
|
@ -1269,6 +1275,17 @@ padded on the left:
|
|||
@end group
|
||||
@end example
|
||||
|
||||
If a substitution contains more characters than its specified
|
||||
precision, it is truncated on the right:
|
||||
|
||||
@example
|
||||
@group
|
||||
(format-spec "%.2a is truncated on the right"
|
||||
'((?a . "alpha")))
|
||||
@result{} "al is truncated on the right"
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Here is a more complicated example that combines several
|
||||
aforementioned features:
|
||||
|
||||
|
|
17
etc/NEWS
17
etc/NEWS
|
@ -461,6 +461,16 @@ In Emacs 24.3, the variable 'dbus-event-error-hooks' was renamed to
|
|||
The old names, which were kept as obsolete aliases of the new names,
|
||||
have now been removed.
|
||||
|
||||
** Battery
|
||||
|
||||
---
|
||||
*** A richer syntax can be used to format battery status information.
|
||||
The user options 'battery-mode-line-format' and
|
||||
'battery-echo-area-format' now support the full formatting syntax of
|
||||
the function 'format-spec' documented under '(elisp) Custom Format
|
||||
Strings'. The new syntax includes specifiers for padding and
|
||||
truncation, amongst other things.
|
||||
|
||||
|
||||
* New Modes and Packages in Emacs 28.1
|
||||
|
||||
|
@ -578,6 +588,13 @@ for encoding and decoding without having to bind
|
|||
It controls, whether 'process-file' returns a string when a remote
|
||||
process is interrupted by a signal.
|
||||
|
||||
+++
|
||||
** The behavior of 'format-spec' is now closer to that of 'format'.
|
||||
In order for the two functions to behave more consistently,
|
||||
'format-spec' now pads and truncates based on string width rather than
|
||||
length, and also supports format specifications that include a
|
||||
truncating precision field, such as '%.2a'.
|
||||
|
||||
|
||||
* Changes in Emacs 28.1 on Non-Free Operating Systems
|
||||
|
||||
|
|
|
@ -121,7 +121,10 @@ string are substituted as defined by the current value of the variable
|
|||
%p Battery load percentage
|
||||
%m Remaining time (to charge or discharge) in minutes
|
||||
%h Remaining time (to charge or discharge) in hours
|
||||
%t Remaining time (to charge or discharge) in the form `h:min'"
|
||||
%t Remaining time (to charge or discharge) in the form `h:min'
|
||||
|
||||
The full `format-spec' formatting syntax is supported."
|
||||
:link '(info-link "(elisp) Custom Format Strings")
|
||||
:type '(choice string (const nil)))
|
||||
|
||||
(defvar battery-mode-line-string nil
|
||||
|
@ -153,7 +156,10 @@ string are substituted as defined by the current value of the variable
|
|||
%p Battery load percentage
|
||||
%m Remaining time (to charge or discharge) in minutes
|
||||
%h Remaining time (to charge or discharge) in hours
|
||||
%t Remaining time (to charge or discharge) in the form `h:min'"
|
||||
%t Remaining time (to charge or discharge) in the form `h:min'
|
||||
|
||||
The full `format-spec' formatting syntax is supported."
|
||||
:link '(info-link "(elisp) Custom Format Strings")
|
||||
:type '(choice string (const nil)))
|
||||
|
||||
(defcustom battery-update-interval 60
|
||||
|
@ -823,13 +829,7 @@ The following %-sequences are provided:
|
|||
|
||||
(defun battery-format (format alist)
|
||||
"Substitute %-sequences in FORMAT."
|
||||
(replace-regexp-in-string
|
||||
"%."
|
||||
(lambda (str)
|
||||
(let ((char (aref str 1)))
|
||||
(if (eq char ?%) "%"
|
||||
(or (cdr (assoc char alist)) ""))))
|
||||
format t t))
|
||||
(format-spec format alist 'delete))
|
||||
|
||||
(defun battery-search-for-one-match-in-files (files regexp match-num)
|
||||
"Search REGEXP in the content of the files listed in FILES.
|
||||
|
|
|
@ -1064,8 +1064,6 @@ corresponding command.
|
|||
Within CMD, %i denotes the input file(s), and %o denotes the
|
||||
output file. %i path(s) are relative, while %o is absolute.")
|
||||
|
||||
(declare-function format-spec "format-spec.el" (format specification))
|
||||
|
||||
;;;###autoload
|
||||
(defun dired-do-compress-to ()
|
||||
"Compress selected files and directories to an archive.
|
||||
|
@ -1073,7 +1071,6 @@ Prompt for the archive file name.
|
|||
Choose the archiving command based on the archive file-name extension
|
||||
and `dired-compress-files-alist'."
|
||||
(interactive)
|
||||
(require 'format-spec)
|
||||
(let* ((in-files (dired-get-marked-files nil nil nil nil t))
|
||||
(out-file (expand-file-name (read-file-name "Compress to: ")))
|
||||
(rule (cl-find-if
|
||||
|
@ -1093,12 +1090,12 @@ and `dired-compress-files-alist'."
|
|||
(when (zerop
|
||||
(dired-shell-command
|
||||
(format-spec (cdr rule)
|
||||
`((?\o . ,(shell-quote-argument out-file))
|
||||
(?\i . ,(mapconcat
|
||||
(lambda (file-desc)
|
||||
(shell-quote-argument (file-name-nondirectory
|
||||
file-desc)))
|
||||
in-files " "))))))
|
||||
`((?o . ,(shell-quote-argument out-file))
|
||||
(?i . ,(mapconcat
|
||||
(lambda (in-file)
|
||||
(shell-quote-argument
|
||||
(file-name-nondirectory in-file)))
|
||||
in-files " "))))))
|
||||
(message (ngettext "Compressed %d file to %s"
|
||||
"Compressed %d files to %s"
|
||||
(length in-files))
|
||||
|
|
|
@ -555,16 +555,15 @@ See `erc-log-match-format'."
|
|||
(and (eq erc-log-matches-flag 'away)
|
||||
(erc-away-time)))
|
||||
match-buffer-name)
|
||||
(let ((line (format-spec erc-log-match-format
|
||||
(format-spec-make
|
||||
?n nick
|
||||
?t (format-time-string
|
||||
(or (and (boundp 'erc-timestamp-format)
|
||||
erc-timestamp-format)
|
||||
"[%Y-%m-%d %H:%M] "))
|
||||
?c (or (erc-default-target) "")
|
||||
?m message
|
||||
?u nickuserhost))))
|
||||
(let ((line (format-spec
|
||||
erc-log-match-format
|
||||
`((?n . ,nick)
|
||||
(?t . ,(format-time-string
|
||||
(or (bound-and-true-p erc-timestamp-format)
|
||||
"[%Y-%m-%d %H:%M] ")))
|
||||
(?c . ,(or (erc-default-target) ""))
|
||||
(?m . ,message)
|
||||
(?u . ,nickuserhost)))))
|
||||
(with-current-buffer (erc-log-matches-make-buffer match-buffer-name)
|
||||
(let ((inhibit-read-only t))
|
||||
(goto-char (point-max))
|
||||
|
|
|
@ -6391,17 +6391,16 @@ if `erc-away' is non-nil."
|
|||
(defun erc-update-mode-line-buffer (buffer)
|
||||
"Update the mode line in a single ERC buffer BUFFER."
|
||||
(with-current-buffer buffer
|
||||
(let ((spec (format-spec-make
|
||||
?a (erc-format-away-status)
|
||||
?l (erc-format-lag-time)
|
||||
?m (erc-format-channel-modes)
|
||||
?n (or (erc-current-nick) "")
|
||||
?N (erc-format-network)
|
||||
?o (or (erc-controls-strip erc-channel-topic) "")
|
||||
?p (erc-port-to-string erc-session-port)
|
||||
?s (erc-format-target-and/or-server)
|
||||
?S (erc-format-target-and/or-network)
|
||||
?t (erc-format-target)))
|
||||
(let ((spec `((?a . ,(erc-format-away-status))
|
||||
(?l . ,(erc-format-lag-time))
|
||||
(?m . ,(erc-format-channel-modes))
|
||||
(?n . ,(or (erc-current-nick) ""))
|
||||
(?N . ,(erc-format-network))
|
||||
(?o . ,(or (erc-controls-strip erc-channel-topic) ""))
|
||||
(?p . ,(erc-port-to-string erc-session-port))
|
||||
(?s . ,(erc-format-target-and/or-server))
|
||||
(?S . ,(erc-format-target-and/or-network))
|
||||
(?t . ,(erc-format-target))))
|
||||
(process-status (cond ((and (erc-server-process-alive)
|
||||
(not erc-server-connected))
|
||||
":connecting")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
;;; format-spec.el --- functions for formatting arbitrary formatting strings
|
||||
;;; format-spec.el --- format arbitrary formatting strings -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 1999-2020 Free Software Foundation, Inc.
|
||||
|
||||
|
@ -24,10 +24,8 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(eval-when-compile
|
||||
(require 'subr-x))
|
||||
|
||||
(defun format-spec (format specification &optional only-present)
|
||||
;;;###autoload
|
||||
(defun format-spec (format specification &optional ignore-missing)
|
||||
"Return a string based on FORMAT and SPECIFICATION.
|
||||
FORMAT is a string containing `format'-like specs like \"su - %u %k\".
|
||||
SPECIFICATION is an alist mapping format specification characters
|
||||
|
@ -39,22 +37,22 @@ For instance:
|
|||
\\=`((?u . ,(user-login-name))
|
||||
(?l . \"ls\")))
|
||||
|
||||
Each %-spec may contain optional flag and width modifiers, as
|
||||
follows:
|
||||
Each %-spec may contain optional flag, width, and precision
|
||||
modifiers, as follows:
|
||||
|
||||
%<flags><width>character
|
||||
%<flags><width><precision>character
|
||||
|
||||
The following flags are allowed:
|
||||
|
||||
* 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.
|
||||
* <: Truncate to the width and precision, if given, on the left.
|
||||
* >: Truncate to the width and precision, if given, on the right.
|
||||
* ^: Convert to upper case.
|
||||
* _: Convert to lower case.
|
||||
|
||||
The width modifier behaves like the corresponding one in `format'
|
||||
when applied to %s.
|
||||
The width and truncation modifiers behave like the corresponding
|
||||
ones 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
|
||||
|
@ -64,89 +62,108 @@ 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
|
||||
IGNORE-MISSING 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."
|
||||
error; if it is the symbol `ignore', leave those %-specs verbatim
|
||||
in the result, including their text properties, if any; if it is
|
||||
the symbol `delete', remove those %-specs from the result;
|
||||
otherwise do the same as for the symbol `ignore', but also leave
|
||||
any occurrences of \"%%\" in FORMAT verbatim in the result."
|
||||
(with-temp-buffer
|
||||
(insert format)
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "%" nil t)
|
||||
(cond
|
||||
;; Quoted percent sign.
|
||||
((eq (char-after) ?%)
|
||||
(unless only-present
|
||||
(delete-char 1)))
|
||||
;; Valid format spec.
|
||||
((looking-at "\\([-0 _^<>]*\\)\\([0-9.]*\\)\\([a-zA-Z]\\)")
|
||||
(let* ((modifiers (match-string 1))
|
||||
(num (match-string 2))
|
||||
(spec (string-to-char (match-string 3)))
|
||||
(val (assq spec specification)))
|
||||
(if (not val)
|
||||
(unless only-present
|
||||
(error "Invalid format character: `%%%c'" spec))
|
||||
(setq val (cdr val)
|
||||
modifiers (format-spec--parse-modifiers modifiers))
|
||||
;; Pad result to desired length.
|
||||
(let ((text (format "%s" val)))
|
||||
(when num
|
||||
(setq num (string-to-number num))
|
||||
(setq text (format-spec--pad text num modifiers))
|
||||
(when (> (length text) num)
|
||||
(cond
|
||||
((memq :chop-left modifiers)
|
||||
(setq text (substring text (- (length text) num))))
|
||||
((memq :chop-right modifiers)
|
||||
(setq text (substring text 0 num))))))
|
||||
(when (memq :uppercase modifiers)
|
||||
(setq text (upcase text)))
|
||||
(when (memq :lowercase modifiers)
|
||||
(setq text (downcase text)))
|
||||
;; Insert first, to preserve text properties.
|
||||
(insert-and-inherit text)
|
||||
;; Delete the specifier body.
|
||||
(delete-region (+ (match-beginning 0) (length text))
|
||||
(+ (match-end 0) (length text)))
|
||||
;; Delete the percent sign.
|
||||
(delete-region (1- (match-beginning 0)) (match-beginning 0))))))
|
||||
;; Signal an error on bogus format strings.
|
||||
(t
|
||||
(unless only-present
|
||||
(error "Invalid format string")))))
|
||||
;; Quoted percent sign.
|
||||
((= (following-char) ?%)
|
||||
(when (memq ignore-missing '(nil ignore delete))
|
||||
(delete-char 1)))
|
||||
;; Valid format spec.
|
||||
((looking-at (rx (? (group (+ (in " 0<>^_-"))))
|
||||
(? (group (+ digit)))
|
||||
(? (group ?. (+ digit)))
|
||||
(group alpha)))
|
||||
(let* ((beg (point))
|
||||
(end (match-end 0))
|
||||
(flags (match-string 1))
|
||||
(width (match-string 2))
|
||||
(trunc (match-string 3))
|
||||
(char (string-to-char (match-string 4)))
|
||||
(text (assq char specification)))
|
||||
(cond (text
|
||||
;; Handle flags.
|
||||
(setq text (format-spec--do-flags
|
||||
(format "%s" (cdr text))
|
||||
(format-spec--parse-flags flags)
|
||||
(and width (string-to-number width))
|
||||
(and trunc (car (read-from-string trunc 1)))))
|
||||
;; Insert first, to preserve text properties.
|
||||
(insert-and-inherit text)
|
||||
;; Delete the specifier body.
|
||||
(delete-region (point) (+ end (length text)))
|
||||
;; Delete the percent sign.
|
||||
(delete-region (1- beg) beg))
|
||||
((eq ignore-missing 'delete)
|
||||
;; Delete the whole format spec.
|
||||
(delete-region (1- beg) end))
|
||||
((not ignore-missing)
|
||||
(error "Invalid format character: `%%%c'" char)))))
|
||||
;; Signal an error on bogus format strings.
|
||||
((not ignore-missing)
|
||||
(error "Invalid format string"))))
|
||||
(buffer-string)))
|
||||
|
||||
(defun format-spec--pad (text total-length modifiers)
|
||||
(if (> (length text) total-length)
|
||||
;; The text is longer than the specified length; do nothing.
|
||||
text
|
||||
(let ((padding (make-string (- total-length (length text))
|
||||
(if (memq :zero-pad modifiers)
|
||||
?0
|
||||
?\s))))
|
||||
(if (memq :right-pad modifiers)
|
||||
(concat text padding)
|
||||
(concat padding text)))))
|
||||
(defun format-spec--do-flags (str flags width trunc)
|
||||
"Return STR formatted according to FLAGS, WIDTH, and TRUNC.
|
||||
FLAGS is a list of keywords as returned by
|
||||
`format-spec--parse-flags'. WIDTH and TRUNC are either nil or
|
||||
string widths corresponding to `format-spec' modifiers."
|
||||
(let (diff str-width)
|
||||
;; Truncate original string first, like `format' does.
|
||||
(when trunc
|
||||
(setq str-width (string-width str))
|
||||
(when (> (setq diff (- str-width trunc)) 0)
|
||||
(setq str (if (memq :chop-left flags)
|
||||
(truncate-string-to-width str str-width diff)
|
||||
(format (format "%%.%ds" trunc) str))
|
||||
;; We know the new width so save it for later.
|
||||
str-width trunc)))
|
||||
;; Pad or chop to width.
|
||||
(when width
|
||||
(setq str-width (or str-width (string-width str))
|
||||
diff (- width str-width))
|
||||
(cond ((zerop diff))
|
||||
((> diff 0)
|
||||
(let ((pad (make-string diff (if (memq :pad-zero flags) ?0 ?\s))))
|
||||
(setq str (if (memq :pad-right flags)
|
||||
(concat str pad)
|
||||
(concat pad str)))))
|
||||
((memq :chop-left flags)
|
||||
(setq str (truncate-string-to-width str str-width (- diff))))
|
||||
((memq :chop-right flags)
|
||||
(setq str (format (format "%%.%ds" width) str))))))
|
||||
;; Fiddle case.
|
||||
(cond ((memq :upcase flags)
|
||||
(upcase str))
|
||||
((memq :downcase flags)
|
||||
(downcase str))
|
||||
(str)))
|
||||
|
||||
(defun format-spec--parse-modifiers (modifiers)
|
||||
(defun format-spec--parse-flags (flags)
|
||||
"Convert sequence of FLAGS to list of human-readable keywords."
|
||||
(mapcan (lambda (char)
|
||||
(when-let ((modifier
|
||||
(pcase char
|
||||
(?0 :zero-pad)
|
||||
(?\s :space-pad)
|
||||
(?^ :uppercase)
|
||||
(?_ :lowercase)
|
||||
(?- :right-pad)
|
||||
(?< :chop-left)
|
||||
(?> :chop-right))))
|
||||
(list modifier)))
|
||||
modifiers))
|
||||
(pcase char
|
||||
(?0 (list :pad-zero))
|
||||
(?- (list :pad-right))
|
||||
(?< (list :chop-left))
|
||||
(?> (list :chop-right))
|
||||
(?^ (list :upcase))
|
||||
(?_ (list :downcase))))
|
||||
flags))
|
||||
|
||||
(defun format-spec-make (&rest pairs)
|
||||
"Return an alist suitable for use in `format-spec' based on PAIRS.
|
||||
PAIRS is a list where every other element is a character and a value,
|
||||
starting with a character."
|
||||
PAIRS is a property list with characters as keys."
|
||||
(let (alist)
|
||||
(while pairs
|
||||
(unless (cdr pairs)
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
|
||||
(require 'gnus)
|
||||
(require 'gnus-sum)
|
||||
(require 'format-spec)
|
||||
(autoload 'sieve-mode "sieve-mode")
|
||||
(eval-when-compile
|
||||
(require 'sieve))
|
||||
|
||||
|
@ -88,10 +86,10 @@ See the documentation for these variables and functions for details."
|
|||
(save-buffer)
|
||||
(shell-command
|
||||
(format-spec gnus-sieve-update-shell-command
|
||||
(format-spec-make ?f gnus-sieve-file
|
||||
?s (or (cadr (gnus-server-get-method
|
||||
nil gnus-sieve-select-method))
|
||||
"")))))
|
||||
`((?f . ,gnus-sieve-file)
|
||||
(?s . ,(or (cadr (gnus-server-get-method
|
||||
nil gnus-sieve-select-method))
|
||||
""))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun gnus-sieve-generate ()
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(require 'format-spec)
|
||||
|
||||
(defcustom gssapi-program (list
|
||||
(concat "gsasl %s %p "
|
||||
"--mechanism GSSAPI "
|
||||
|
@ -53,12 +51,9 @@ tried until a successful connection is made."
|
|||
(coding-system-for-write 'binary)
|
||||
(process (start-process
|
||||
name buffer shell-file-name shell-command-switch
|
||||
(format-spec
|
||||
cmd
|
||||
(format-spec-make
|
||||
?s server
|
||||
?p (number-to-string port)
|
||||
?l user))))
|
||||
(format-spec cmd `((?s . ,server)
|
||||
(?p . ,(number-to-string port))
|
||||
(?l . ,user)))))
|
||||
response)
|
||||
(when process
|
||||
(while (and (memq (process-status process) '(open run))
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(require 'format-spec)
|
||||
(eval-when-compile
|
||||
(require 'cl-lib)
|
||||
(require 'imap))
|
||||
|
@ -769,14 +768,14 @@ Deleting old (> %s day(s)) incoming mail file `%s'." diff bfile)
|
|||
"Fetcher for single-file sources."
|
||||
(mail-source-bind (file source)
|
||||
(mail-source-run-script
|
||||
prescript (format-spec-make ?t mail-source-crash-box)
|
||||
prescript `((?t . ,mail-source-crash-box))
|
||||
prescript-delay)
|
||||
(let ((mail-source-string (format "file:%s" path)))
|
||||
(if (mail-source-movemail path mail-source-crash-box)
|
||||
(prog1
|
||||
(mail-source-callback callback path)
|
||||
(mail-source-run-script
|
||||
postscript (format-spec-make ?t mail-source-crash-box))
|
||||
postscript `((?t . ,mail-source-crash-box)))
|
||||
(mail-source-delete-crash-box))
|
||||
0))))
|
||||
|
||||
|
@ -784,7 +783,7 @@ Deleting old (> %s day(s)) incoming mail file `%s'." diff bfile)
|
|||
"Fetcher for directory sources."
|
||||
(mail-source-bind (directory source)
|
||||
(mail-source-run-script
|
||||
prescript (format-spec-make ?t path) prescript-delay)
|
||||
prescript `((?t . ,path)) prescript-delay)
|
||||
(let ((found 0)
|
||||
(mail-source-string (format "directory:%s" path)))
|
||||
(dolist (file (directory-files
|
||||
|
@ -793,7 +792,7 @@ Deleting old (> %s day(s)) incoming mail file `%s'." diff bfile)
|
|||
(funcall predicate file)
|
||||
(mail-source-movemail file mail-source-crash-box))
|
||||
(cl-incf found (mail-source-callback callback file))
|
||||
(mail-source-run-script postscript (format-spec-make ?t path))
|
||||
(mail-source-run-script postscript `((?t . ,path)))
|
||||
(mail-source-delete-crash-box)))
|
||||
found)))
|
||||
|
||||
|
@ -803,8 +802,8 @@ Deleting old (> %s day(s)) incoming mail file `%s'." diff bfile)
|
|||
;; fixme: deal with stream type in format specs
|
||||
(mail-source-run-script
|
||||
prescript
|
||||
(format-spec-make ?p password ?t mail-source-crash-box
|
||||
?s server ?P port ?u user)
|
||||
`((?p . ,password) (?t . ,mail-source-crash-box)
|
||||
(?s . ,server) (?P . ,port) (?u . ,user))
|
||||
prescript-delay)
|
||||
(let ((from (format "%s:%s:%s" server user port))
|
||||
(mail-source-string (format "pop:%s@%s" user server))
|
||||
|
@ -825,8 +824,8 @@ Deleting old (> %s day(s)) incoming mail file `%s'." diff bfile)
|
|||
(mail-source-fetch-with-program
|
||||
(format-spec
|
||||
program
|
||||
(format-spec-make ?p password ?t mail-source-crash-box
|
||||
?s server ?P port ?u user))))
|
||||
`((?p . ,password) (?t . ,mail-source-crash-box)
|
||||
(?s . ,server) (?P . ,port) (?u . ,user)))))
|
||||
(function
|
||||
(funcall function mail-source-crash-box))
|
||||
;; The default is to use pop3.el.
|
||||
|
@ -863,8 +862,8 @@ Deleting old (> %s day(s)) incoming mail file `%s'." diff bfile)
|
|||
(setq mail-source-new-mail-available nil))
|
||||
(mail-source-run-script
|
||||
postscript
|
||||
(format-spec-make ?p password ?t mail-source-crash-box
|
||||
?s server ?P port ?u user))
|
||||
`((?p . ,password) (?t . ,mail-source-crash-box)
|
||||
(?s . ,server) (?P . ,port) (?u . ,user)))
|
||||
(mail-source-delete-crash-box)))
|
||||
;; We nix out the password in case the error
|
||||
;; was because of a wrong password being given.
|
||||
|
@ -1077,8 +1076,9 @@ This only works when `display-time' is enabled."
|
|||
"Fetcher for imap sources."
|
||||
(mail-source-bind (imap source)
|
||||
(mail-source-run-script
|
||||
prescript (format-spec-make ?p password ?t mail-source-crash-box
|
||||
?s server ?P port ?u user)
|
||||
prescript
|
||||
`((?p . ,password) (?t . ,mail-source-crash-box)
|
||||
(?s . ,server) (?P . ,port) (?u . ,user))
|
||||
prescript-delay)
|
||||
(let ((from (format "%s:%s:%s" server user port))
|
||||
(found 0)
|
||||
|
@ -1143,8 +1143,8 @@ This only works when `display-time' is enabled."
|
|||
(kill-buffer buf)
|
||||
(mail-source-run-script
|
||||
postscript
|
||||
(format-spec-make ?p password ?t mail-source-crash-box
|
||||
?s server ?P port ?u user))
|
||||
`((?p . ,password) (?t . ,mail-source-crash-box)
|
||||
(?s . ,server) (?P . ,port) (?u . ,user)))
|
||||
found)))
|
||||
|
||||
(provide 'mail-source)
|
||||
|
|
|
@ -42,13 +42,12 @@
|
|||
(require 'mail-parse)
|
||||
(require 'mml)
|
||||
(require 'rfc822)
|
||||
(require 'format-spec)
|
||||
(require 'dired)
|
||||
(require 'mm-util)
|
||||
(require 'rfc2047)
|
||||
(require 'puny)
|
||||
(require 'rmc) ; read-multiple-choice
|
||||
(eval-when-compile (require 'subr-x)) ; when-let*
|
||||
(require 'rmc) ; read-multiple-choice
|
||||
(eval-when-compile (require 'subr-x))
|
||||
|
||||
(autoload 'mailclient-send-it "mailclient")
|
||||
|
||||
|
@ -440,8 +439,8 @@ whitespace)."
|
|||
|
||||
(defcustom message-elide-ellipsis "\n[...]\n\n"
|
||||
"The string which is inserted for elided text.
|
||||
This is a format-spec string, and you can use %l to say how many
|
||||
lines were removed, and %c to say how many characters were
|
||||
This is a `format-spec' string, and you can use %l to say how
|
||||
many lines were removed, and %c to say how many characters were
|
||||
removed."
|
||||
:type 'string
|
||||
:link '(custom-manual "(message)Various Commands")
|
||||
|
@ -3977,7 +3976,6 @@ This function uses `mail-citation-hook' if that is non-nil."
|
|||
"Cite function in the standard Message manner."
|
||||
(message-cite-original-1 nil))
|
||||
|
||||
(autoload 'format-spec "format-spec")
|
||||
(autoload 'gnus-date-get-time "gnus-util")
|
||||
|
||||
(defun message-insert-formatted-citation-line (&optional from date tz)
|
||||
|
@ -4002,20 +4000,18 @@ See `message-citation-line-format'."
|
|||
(when (or message-reply-headers (and from date))
|
||||
(unless from
|
||||
(setq from (mail-header-from message-reply-headers)))
|
||||
(let* ((data (condition-case ()
|
||||
(funcall (if (boundp 'gnus-extract-address-components)
|
||||
gnus-extract-address-components
|
||||
'mail-extract-address-components)
|
||||
from)
|
||||
(error nil)))
|
||||
(let* ((data (ignore-errors
|
||||
(funcall (or (bound-and-true-p
|
||||
gnus-extract-address-components)
|
||||
#'mail-extract-address-components)
|
||||
from)))
|
||||
(name (car data))
|
||||
(fname name)
|
||||
(lname name)
|
||||
(net (car (cdr data)))
|
||||
(name-or-net (or (car data)
|
||||
(car (cdr data)) from))
|
||||
(net (cadr data))
|
||||
(name-or-net (or name net from))
|
||||
(time
|
||||
(when (string-match "%[^fnNFL]" message-citation-line-format)
|
||||
(when (string-match-p "%[^FLNfn]" message-citation-line-format)
|
||||
(cond ((numberp (car-safe date)) date) ;; backward compatibility
|
||||
(date (gnus-date-get-time date))
|
||||
(t
|
||||
|
@ -4024,68 +4020,53 @@ See `message-citation-line-format'."
|
|||
(tz (or tz
|
||||
(when (stringp date)
|
||||
(nth 8 (parse-time-string date)))))
|
||||
(flist
|
||||
(let ((i ?A) lst)
|
||||
(when (stringp name)
|
||||
;; Guess first name and last name:
|
||||
(let* ((names (delq
|
||||
nil
|
||||
(mapcar
|
||||
(lambda (x)
|
||||
(if (string-match "\\`\\(\\w\\|[-.]\\)+\\'"
|
||||
x)
|
||||
x
|
||||
nil))
|
||||
(split-string name "[ \t]+"))))
|
||||
(count (length names)))
|
||||
(cond ((= count 1)
|
||||
(setq fname (car names)
|
||||
lname ""))
|
||||
((or (= count 2) (= count 3))
|
||||
(setq fname (car names)
|
||||
lname (mapconcat 'identity (cdr names) " ")))
|
||||
((> count 3)
|
||||
(setq fname (mapconcat 'identity
|
||||
(butlast names (- count 2))
|
||||
" ")
|
||||
lname (mapconcat 'identity
|
||||
(nthcdr 2 names)
|
||||
" "))))
|
||||
(when (string-match "\\(.*\\),\\'" fname)
|
||||
(let ((newlname (match-string 1 fname)))
|
||||
(setq fname lname lname newlname)))))
|
||||
;; The following letters are not used in `format-time-string':
|
||||
(push ?E lst) (push "<E>" lst)
|
||||
(push ?F lst) (push (or fname name-or-net) lst)
|
||||
;; We might want to use "" instead of "<X>" later.
|
||||
(push ?J lst) (push "<J>" lst)
|
||||
(push ?K lst) (push "<K>" lst)
|
||||
(push ?L lst) (push lname lst)
|
||||
(push ?N lst) (push name-or-net lst)
|
||||
(push ?O lst) (push "<O>" lst)
|
||||
(push ?P lst) (push "<P>" lst)
|
||||
(push ?Q lst) (push "<Q>" lst)
|
||||
(push ?f lst) (push from lst)
|
||||
(push ?i lst) (push "<i>" lst)
|
||||
(push ?n lst) (push net lst)
|
||||
(push ?o lst) (push "<o>" lst)
|
||||
(push ?q lst) (push "<q>" lst)
|
||||
(push ?t lst) (push "<t>" lst)
|
||||
(push ?v lst) (push "<v>" lst)
|
||||
;; Delegate the rest to `format-time-string':
|
||||
(while (<= i ?z)
|
||||
(when (and (not (memq i lst))
|
||||
;; Skip (Z,a)
|
||||
(or (<= i ?Z)
|
||||
(>= i ?a)))
|
||||
(push i lst)
|
||||
(push (condition-case nil
|
||||
(format-time-string (format "%%%c" i) time tz)
|
||||
(error (format ">%c<" i)))
|
||||
lst))
|
||||
(setq i (1+ i)))
|
||||
(reverse lst)))
|
||||
(spec (apply 'format-spec-make flist)))
|
||||
spec)
|
||||
(when (stringp name)
|
||||
;; Guess first name and last name:
|
||||
(let* ((names (seq-filter
|
||||
(lambda (s)
|
||||
(string-match-p (rx bos (+ (in word ?. ?-)) eos) s))
|
||||
(split-string name "[ \t]+")))
|
||||
(count (length names)))
|
||||
(cond ((= count 1)
|
||||
(setq fname (car names)
|
||||
lname ""))
|
||||
((or (= count 2) (= count 3))
|
||||
(setq fname (car names)
|
||||
lname (string-join (cdr names) " ")))
|
||||
((> count 3)
|
||||
(setq fname (string-join (butlast names (- count 2))
|
||||
" ")
|
||||
lname (string-join (nthcdr 2 names) " "))))
|
||||
(when (string-match "\\(.*\\),\\'" fname)
|
||||
(let ((newlname (match-string 1 fname)))
|
||||
(setq fname lname lname newlname)))))
|
||||
;; The following letters are not used in `format-time-string':
|
||||
(push (cons ?E "<E>") spec)
|
||||
(push (cons ?F (or fname name-or-net)) spec)
|
||||
;; We might want to use "" instead of "<X>" later.
|
||||
(push (cons ?J "<J>") spec)
|
||||
(push (cons ?K "<K>") spec)
|
||||
(push (cons ?L lname) spec)
|
||||
(push (cons ?N name-or-net) spec)
|
||||
(push (cons ?O "<O>") spec)
|
||||
(push (cons ?P "<P>") spec)
|
||||
(push (cons ?Q "<Q>") spec)
|
||||
(push (cons ?f from) spec)
|
||||
(push (cons ?i "<i>") spec)
|
||||
(push (cons ?n net) spec)
|
||||
(push (cons ?o "<o>") spec)
|
||||
(push (cons ?q "<q>") spec)
|
||||
(push (cons ?t "<t>") spec)
|
||||
(push (cons ?v "<v>") spec)
|
||||
;; Delegate the rest to `format-time-string':
|
||||
(dolist (c (nconc (number-sequence ?A ?Z)
|
||||
(number-sequence ?a ?z)))
|
||||
(unless (assq c spec)
|
||||
(push (cons c (condition-case nil
|
||||
(format-time-string (format "%%%c" c) time tz)
|
||||
(error (format ">%c<" c))))
|
||||
spec)))
|
||||
(insert (format-spec message-citation-line-format spec)))
|
||||
(newline)))
|
||||
|
||||
|
|
|
@ -149,7 +149,6 @@
|
|||
;;; Code:
|
||||
|
||||
(require 'dired)
|
||||
(require 'format-spec)
|
||||
(require 'image-mode)
|
||||
(require 'widget)
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'format-spec)
|
||||
(require 'shr)
|
||||
(require 'url)
|
||||
(require 'url-queue)
|
||||
|
|
|
@ -136,7 +136,6 @@
|
|||
;;; Code:
|
||||
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
(require 'format-spec)
|
||||
(require 'utf7)
|
||||
(require 'rfc2104)
|
||||
;; Hmm... digest-md5 is not part of Emacs.
|
||||
|
@ -517,12 +516,9 @@ sure of changing the value of `foo'."
|
|||
(process-connection-type imap-process-connection-type)
|
||||
(process (start-process
|
||||
name buffer shell-file-name shell-command-switch
|
||||
(format-spec
|
||||
cmd
|
||||
(format-spec-make
|
||||
?s server
|
||||
?p (number-to-string port)
|
||||
?l imap-default-user))))
|
||||
(format-spec cmd `((?s . ,server)
|
||||
(?p . ,(number-to-string port))
|
||||
(?l . ,imap-default-user)))))
|
||||
response)
|
||||
(when process
|
||||
(with-current-buffer buffer
|
||||
|
@ -583,12 +579,9 @@ sure of changing the value of `foo'."
|
|||
(process-connection-type imap-process-connection-type)
|
||||
(process (start-process
|
||||
name buffer shell-file-name shell-command-switch
|
||||
(format-spec
|
||||
cmd
|
||||
(format-spec-make
|
||||
?s server
|
||||
?p (number-to-string port)
|
||||
?l imap-default-user))))
|
||||
(format-spec cmd `((?s . ,server)
|
||||
(?p . ,(number-to-string port))
|
||||
(?l . ,imap-default-user)))))
|
||||
response)
|
||||
(when process
|
||||
(with-current-buffer buffer
|
||||
|
@ -701,13 +694,10 @@ sure of changing the value of `foo'."
|
|||
(process-connection-type imap-process-connection-type)
|
||||
(process (start-process
|
||||
name buffer shell-file-name shell-command-switch
|
||||
(format-spec
|
||||
cmd
|
||||
(format-spec-make
|
||||
?s server
|
||||
?g imap-shell-host
|
||||
?p (number-to-string port)
|
||||
?l imap-default-user)))))
|
||||
(format-spec cmd `((?s . ,server)
|
||||
(?g . ,imap-shell-host)
|
||||
(?p . ,(number-to-string port))
|
||||
(?l . ,imap-default-user))))))
|
||||
(when process
|
||||
(while (and (memq (process-status process) '(open run))
|
||||
(set-buffer buffer) ;; XXX "blue moon" nntp.el bug
|
||||
|
|
|
@ -170,8 +170,8 @@ a greeting from the server.
|
|||
:nowait, if non-nil, says the connection should be made
|
||||
asynchronously, if possible.
|
||||
|
||||
:shell-command is a format-spec string that can be used if :type
|
||||
is `shell'. It has two specs, %s for host and %p for port
|
||||
:shell-command is a `format-spec' string that can be used if
|
||||
:type is `shell'. It has two specs, %s for host and %p for port
|
||||
number. Example: \"ssh gateway nc %s %p\".
|
||||
|
||||
:tls-parameters is a list that should be supplied if you're
|
||||
|
@ -453,11 +453,7 @@ gnutls-boot (as returned by `gnutls-boot-parameters')."
|
|||
(network-stream-command stream capability-command eo-capa)
|
||||
'tls)))))))
|
||||
|
||||
(declare-function format-spec "format-spec" (format spec))
|
||||
(declare-function format-spec-make "format-spec" (&rest pairs))
|
||||
|
||||
(defun network-stream-open-shell (name buffer host service parameters)
|
||||
(require 'format-spec)
|
||||
(let* ((capability-command (plist-get parameters :capability-command))
|
||||
(eoc (plist-get parameters :end-of-command))
|
||||
(start (with-current-buffer buffer (point)))
|
||||
|
@ -467,9 +463,8 @@ gnutls-boot (as returned by `gnutls-boot-parameters')."
|
|||
shell-command-switch
|
||||
(format-spec
|
||||
(plist-get parameters :shell-command)
|
||||
(format-spec-make
|
||||
?s host
|
||||
?p service))))))
|
||||
`((?s . ,host)
|
||||
(?p . ,service)))))))
|
||||
(when coding (if (consp coding)
|
||||
(set-process-coding-system stream
|
||||
(car coding)
|
||||
|
|
|
@ -47,9 +47,6 @@
|
|||
|
||||
(require 'gnutls)
|
||||
|
||||
(autoload 'format-spec "format-spec")
|
||||
(autoload 'format-spec-make "format-spec")
|
||||
|
||||
(defgroup tls nil
|
||||
"Transport Layer Security (TLS) parameters."
|
||||
:group 'comm)
|
||||
|
@ -224,14 +221,11 @@ Fourth arg PORT is an integer specifying a port to connect to."
|
|||
(while (and (not done) (setq cmd (pop cmds)))
|
||||
(let ((process-connection-type tls-process-connection-type)
|
||||
(formatted-cmd
|
||||
(format-spec
|
||||
cmd
|
||||
(format-spec-make
|
||||
?t (car (gnutls-trustfiles))
|
||||
?h host
|
||||
?p (if (integerp port)
|
||||
(int-to-string port)
|
||||
port)))))
|
||||
(format-spec cmd `((?t . ,(car (gnutls-trustfiles)))
|
||||
(?h . ,host)
|
||||
(?p . ,(if (integerp port)
|
||||
(number-to-string port)
|
||||
port))))))
|
||||
(message "Opening TLS connection with `%s'..." formatted-cmd)
|
||||
(setq process (start-process
|
||||
name buffer shell-file-name shell-command-switch
|
||||
|
|
|
@ -2295,9 +2295,6 @@ FILE is typically the output DVI or PDF file."
|
|||
(setq uptodate nil)))))
|
||||
uptodate)))
|
||||
|
||||
|
||||
(autoload 'format-spec "format-spec")
|
||||
|
||||
(defvar tex-executable-cache nil)
|
||||
(defun tex-executable-exists-p (name)
|
||||
"Like `executable-find' but with a cache."
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
"Test `battery-format'."
|
||||
(should (equal (battery-format "" ()) ""))
|
||||
(should (equal (battery-format "" '((?b . "-"))) ""))
|
||||
(should (equal (battery-format "%a%b%p%%" '((?b . "-") (?p . "99")))
|
||||
"-99%")))
|
||||
(should (equal (battery-format "%2a%-3b%.1p%%" '((?b . "-") (?p . "99")))
|
||||
"- 9%")))
|
||||
|
||||
;;; battery-tests.el ends here
|
||||
|
|
|
@ -22,22 +22,145 @@
|
|||
(require 'ert)
|
||||
(require 'format-spec)
|
||||
|
||||
(ert-deftest test-format-spec ()
|
||||
(ert-deftest format-spec-make ()
|
||||
"Test `format-spec-make'."
|
||||
(should-not (format-spec-make))
|
||||
(should-error (format-spec-make ?b))
|
||||
(should (equal (format-spec-make ?b "b") '((?b . "b"))))
|
||||
(should-error (format-spec-make ?b "b" ?a))
|
||||
(should (equal (format-spec-make ?b "b" ?a 'a)
|
||||
'((?b . "b")
|
||||
(?a . a)))))
|
||||
|
||||
(ert-deftest format-spec-parse-flags ()
|
||||
"Test `format-spec--parse-flags'."
|
||||
(should-not (format-spec--parse-flags nil))
|
||||
(should-not (format-spec--parse-flags ""))
|
||||
(should (equal (format-spec--parse-flags "-") '(:pad-right)))
|
||||
(should (equal (format-spec--parse-flags " 0") '(:pad-zero)))
|
||||
(should (equal (format-spec--parse-flags " -x0y< >^_z ")
|
||||
'(:pad-right :pad-zero :chop-left :chop-right
|
||||
:upcase :downcase))))
|
||||
|
||||
(ert-deftest format-spec-do-flags ()
|
||||
"Test `format-spec--do-flags'."
|
||||
(should (equal (format-spec--do-flags "" () nil nil) ""))
|
||||
(dolist (flag '(:pad-zero :pad-right :upcase :downcase
|
||||
:chop-left :chop-right))
|
||||
(should (equal (format-spec--do-flags "" (list flag) nil nil) "")))
|
||||
(should (equal (format-spec--do-flags "FOOBAR" '(:downcase :chop-right) 5 2)
|
||||
" fo"))
|
||||
(should (equal (format-spec--do-flags
|
||||
"foobar" '(:pad-zero :pad-right :upcase :chop-left) 5 2)
|
||||
"AR000")))
|
||||
|
||||
(ert-deftest format-spec-do-flags-truncate ()
|
||||
"Test `format-spec--do-flags' truncation."
|
||||
(let (flags)
|
||||
(should (equal (format-spec--do-flags "" flags nil 0) ""))
|
||||
(should (equal (format-spec--do-flags "" flags nil 1) ""))
|
||||
(should (equal (format-spec--do-flags "a" flags nil 0) ""))
|
||||
(should (equal (format-spec--do-flags "a" flags nil 1) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags nil 2) "a"))
|
||||
(should (equal (format-spec--do-flags "asd" flags nil 0) ""))
|
||||
(should (equal (format-spec--do-flags "asd" flags nil 1) "a")))
|
||||
(let ((flags '(:chop-left)))
|
||||
(should (equal (format-spec--do-flags "" flags nil 0) ""))
|
||||
(should (equal (format-spec--do-flags "" flags nil 1) ""))
|
||||
(should (equal (format-spec--do-flags "a" flags nil 0) ""))
|
||||
(should (equal (format-spec--do-flags "a" flags nil 1) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags nil 2) "a"))
|
||||
(should (equal (format-spec--do-flags "asd" flags nil 0) ""))
|
||||
(should (equal (format-spec--do-flags "asd" flags nil 1) "d"))))
|
||||
|
||||
(ert-deftest format-spec-do-flags-pad ()
|
||||
"Test `format-spec--do-flags' padding."
|
||||
(let (flags)
|
||||
(should (equal (format-spec--do-flags "" flags 0 nil) ""))
|
||||
(should (equal (format-spec--do-flags "" flags 1 nil) " "))
|
||||
(should (equal (format-spec--do-flags "a" flags 0 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags 2 nil) " a")))
|
||||
(let ((flags '(:pad-zero)))
|
||||
(should (equal (format-spec--do-flags "" flags 0 nil) ""))
|
||||
(should (equal (format-spec--do-flags "" flags 1 nil) "0"))
|
||||
(should (equal (format-spec--do-flags "a" flags 0 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags 2 nil) "0a")))
|
||||
(let ((flags '(:pad-right)))
|
||||
(should (equal (format-spec--do-flags "" flags 0 nil) ""))
|
||||
(should (equal (format-spec--do-flags "" flags 1 nil) " "))
|
||||
(should (equal (format-spec--do-flags "a" flags 0 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags 2 nil) "a ")))
|
||||
(let ((flags '(:pad-right :pad-zero)))
|
||||
(should (equal (format-spec--do-flags "" flags 0 nil) ""))
|
||||
(should (equal (format-spec--do-flags "" flags 1 nil) "0"))
|
||||
(should (equal (format-spec--do-flags "a" flags 0 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "a" flags 2 nil) "a0"))))
|
||||
|
||||
(ert-deftest format-spec-do-flags-chop ()
|
||||
"Test `format-spec--do-flags' chopping."
|
||||
(let ((flags '(:chop-left)))
|
||||
(should (equal (format-spec--do-flags "a" flags 0 nil) ""))
|
||||
(should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "asd" flags 0 nil) ""))
|
||||
(should (equal (format-spec--do-flags "asd" flags 1 nil) "d")))
|
||||
(let ((flags '(:chop-right)))
|
||||
(should (equal (format-spec--do-flags "a" flags 0 nil) ""))
|
||||
(should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
|
||||
(should (equal (format-spec--do-flags "asd" flags 0 nil) ""))
|
||||
(should (equal (format-spec--do-flags "asd" flags 1 nil) "a"))))
|
||||
|
||||
(ert-deftest format-spec-do-flags-case ()
|
||||
"Test `format-spec--do-flags' case fiddling."
|
||||
(dolist (flag '(:pad-zero :pad-right :chop-left :chop-right))
|
||||
(let ((flags (list flag)))
|
||||
(should (equal (format-spec--do-flags "a" flags nil nil) "a"))
|
||||
(should (equal (format-spec--do-flags "A" flags nil nil) "A")))
|
||||
(let ((flags (list flag :downcase)))
|
||||
(should (equal (format-spec--do-flags "a" flags nil nil) "a"))
|
||||
(should (equal (format-spec--do-flags "A" flags nil nil) "a")))
|
||||
(let ((flags (list flag :upcase)))
|
||||
(should (equal (format-spec--do-flags "a" flags nil nil) "A"))
|
||||
(should (equal (format-spec--do-flags "A" flags nil nil) "A")))))
|
||||
|
||||
(ert-deftest format-spec ()
|
||||
(should (equal (format-spec "" ()) ""))
|
||||
(should (equal (format-spec "a" ()) "a"))
|
||||
(should (equal (format-spec "b" '((?b . "bar"))) "b"))
|
||||
(should (equal (format-spec "%%%b%%b%b%%" '((?b . "bar"))) "%bar%bbar%"))
|
||||
(should (equal (format-spec "foo %b zot" `((?b . "bar")))
|
||||
"foo bar zot"))
|
||||
(should (equal (format-spec "foo %-10b zot" '((?b . "bar")))
|
||||
"foo bar zot"))
|
||||
(should (equal (format-spec "foo %10b zot" '((?b . "bar")))
|
||||
"foo bar zot")))
|
||||
"foo bar zot"))
|
||||
(should (equal-including-properties
|
||||
(format-spec (propertize "a" 'a 'b) '((?a . "foo")))
|
||||
#("a" 0 1 (a b))))
|
||||
(let ((fmt (concat (propertize "%a" 'a 'b)
|
||||
(propertize "%%" 'c 'd)
|
||||
"%b"
|
||||
(propertize "%b" 'e 'f))))
|
||||
(should (equal-including-properties
|
||||
(format-spec fmt '((?b . "asd") (?a . "fgh")))
|
||||
#("fgh%asdasd" 0 3 (a b) 3 4 (c d) 7 10 (e f))))))
|
||||
|
||||
(ert-deftest test-format-unknown ()
|
||||
(ert-deftest format-spec-unknown ()
|
||||
(should-error (format-spec "foo %b %z zot" '((?b . "bar"))))
|
||||
(should-error (format-spec "foo %b %%%z zot" '((?b . "bar"))))
|
||||
(should (equal (format-spec "foo %b %z zot" '((?b . "bar")) t)
|
||||
"foo bar %z zot"))
|
||||
(should (equal (format-spec "foo %b %z %% zot" '((?b . "bar")) t)
|
||||
"foo bar %z %% zot")))
|
||||
(should (equal (format-spec "foo %4b %%%4z %%4 zot" '((?b . "bar")) t)
|
||||
"foo bar %%%4z %%4 zot"))
|
||||
(should (equal (format-spec "foo %4b %%%4z %%4 zot" '((?b . "bar")) 'ignore)
|
||||
"foo bar %%4z %4 zot"))
|
||||
(should (equal (format-spec "foo %4b %%%4z %%4 zot" '((?b . "bar")) 'delete)
|
||||
"foo bar % %4 zot")))
|
||||
|
||||
(ert-deftest test-format-modifiers ()
|
||||
(ert-deftest format-spec-flags ()
|
||||
(should (equal (format-spec "foo %10b zot" '((?b . "bar")))
|
||||
"foo bar zot"))
|
||||
(should (equal (format-spec "foo % 10b zot" '((?b . "bar")))
|
||||
|
|
Loading…
Add table
Reference in a new issue