you can use, see the variable's documentation string.
@end defvar
-@defvar integer-output-format
-This variable specifies how to print integer numbers. The default is
-@code{nil}, meaning use the decimal format. When bound to @code{t},
-print integers as characters when an integer represents a character
-(@pxref{Basic Char Syntax}). When bound to the number @code{16},
-print non-negative integers in the hexadecimal format.
+@defvar print-integers-as-characters
+When this variable is non-@code{nil}, integers that represent
+graphic base characters will be printed using Lisp character syntax
+(@pxref{Basic Char Syntax}). Other numbers are printed the usual way.
+For example, the list @code{(4 65 -1 10)} would be printed as
+@samp{(4 ?A -1 ?\n)}.
+
+More precisely, values printed in character syntax are those
+representing characters belonging to the Unicode general categories
+Letter, Number, Punctuation, Symbol and Private-use
+(@pxref{Character Properties}), as well as the control characters
+having their own escape syntax such as newline.
@end defvar
\f
* Lisp Changes in Emacs 28.1
-** New variable 'integer-output-format' determines how to print integer values.
-When this variable is bound to the value 't', integers are printed by
-printing functions as characters when an integer represents a character.
-When bound to the number 16, non-negative integers are printed in the
-hexadecimal format.
-
+++
** 'define-globalized-minor-mode' now takes a ':predicate' parameter.
This can be used to control which major modes the minor mode should be
'replace-regexp-in-string', 'catch', 'throw', 'error', 'signal'
and 'play-sound-file'.
++++
+** New variable 'print-integers-as-characters' modifies integer printing.
+If this variable is non-nil, character syntax is used for printing
+numbers when this makes sense, such as '?A' for 65.
+
\f
* Changes in Emacs 28.1 on Non-Free Operating Systems
|| gen_cat == UNICODE_CATEGORY_Cn)); /* unassigned */
}
+/* Return true if C is graphic character that can be printed independently. */
+bool
+graphic_base_p (int c)
+{
+ Lisp_Object category = CHAR_TABLE_REF (Vunicode_category_table, c);
+ if (! FIXNUMP (category))
+ return false;
+ EMACS_INT gen_cat = XFIXNUM (category);
+
+ return (!(gen_cat == UNICODE_CATEGORY_Mn /* mark, nonspacing */
+ || gen_cat == UNICODE_CATEGORY_Mc /* mark, combining */
+ || gen_cat == UNICODE_CATEGORY_Me /* mark, enclosing */
+ || gen_cat == UNICODE_CATEGORY_Zs /* separator, space */
+ || gen_cat == UNICODE_CATEGORY_Zl /* separator, line */
+ || gen_cat == UNICODE_CATEGORY_Zp /* separator, paragraph */
+ || gen_cat == UNICODE_CATEGORY_Cc /* other, control */
+ || gen_cat == UNICODE_CATEGORY_Cs /* other, surrogate */
+ || gen_cat == UNICODE_CATEGORY_Cf /* other, format */
+ || gen_cat == UNICODE_CATEGORY_Cn)); /* other, unassigned */
+}
+
/* Return true if C is a horizontal whitespace character, as defined
by https://www.unicode.org/reports/tr18/tr18-19.html#blank. */
bool
extern bool graphicp (int);
extern bool printablep (int);
extern bool blankp (int);
+extern bool graphic_base_p (int);
/* Look up the element in char table OBJ at index CH, and return it as
an integer. If the element is not a character, return CH itself. */
return true;
}
+static char
+named_escape (int i)
+{
+ switch (i)
+ {
+ case '\b': return 'b';
+ case '\t': return 't';
+ case '\n': return 'n';
+ case '\f': return 'f';
+ case '\r': return 'r';
+ case ' ': return 's';
+ /* \a, \v, \e and \d are excluded from printing as escapes since
+ they are somewhat rare as characters and more likely to be
+ plain integers. */
+ }
+ return 0;
+}
+
static void
print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
{
{
case_Lisp_Int:
{
- int c;
- intmax_t i;
+ EMACS_INT i = XFIXNUM (obj);
+ char escaped_name;
- if (EQ (Vinteger_output_format, Qt) && CHARACTERP (obj)
- && (c = XFIXNUM (obj)))
+ if (print_integers_as_characters && i >= 0 && i <= MAX_UNICODE_CHAR
+ && ((escaped_name = named_escape (i))
+ || graphic_base_p (i)))
{
printchar ('?', printcharfun);
- if (escapeflag
- && (c == ';' || c == '(' || c == ')' || c == '{' || c == '}'
- || c == '[' || c == ']' || c == '\"' || c == '\'' || c == '\\'))
+ if (escaped_name)
+ {
+ printchar ('\\', printcharfun);
+ i = escaped_name;
+ }
+ else if (escapeflag
+ && (i == ';' || i == '\"' || i == '\'' || i == '\\'
+ || i == '(' || i == ')'
+ || i == '{' || i == '}'
+ || i == '[' || i == ']'))
printchar ('\\', printcharfun);
- printchar (c, printcharfun);
- }
- else if (INTEGERP (Vinteger_output_format)
- && integer_to_intmax (Vinteger_output_format, &i)
- && i == 16 && !NILP (Fnatnump (obj)))
- {
- int len = sprintf (buf, "#x%"pI"x", (EMACS_UINT) XFIXNUM (obj));
- strout (buf, len, len, printcharfun);
+ printchar (i, printcharfun);
}
else
{
- int len = sprintf (buf, "%"pI"d", XFIXNUM (obj));
+ int len = sprintf (buf, "%"pI"d", i);
strout (buf, len, len, printcharfun);
}
}
that represents the number without losing information. */);
Vfloat_output_format = Qnil;
- DEFVAR_LISP ("integer-output-format", Vinteger_output_format,
- doc: /* The format used to print integers.
-When t, print characters from integers that represent a character.
-When a number 16, print non-negative integers in the hexadecimal format.
-Otherwise, by default print integers in the decimal format. */);
- Vinteger_output_format = Qnil;
+ DEFVAR_BOOL ("print-integers-as-characters", print_integers_as_characters,
+ doc: /* Non-nil means integers are printed using characters syntax.
+Only independent graphic characters, and control characters with named
+escape sequences such as newline, are printed this way. Other
+integers, including those corresponding to raw bytes, are printed
+as numbers the usual way. */);
+ print_integers_as_characters = Qnil;
DEFVAR_LISP ("print-length", Vprint_length,
doc: /* Maximum length of list to print before abbreviating.
(let ((print-length 1))
(format "%S" h))))))
-(print-tests--deftest print-integer-output-format ()
+(print-tests--deftest print-integers-as-characters ()
;; Bug#44155.
- (let ((integer-output-format t)
- (syms (list ?? ?\; ?\( ?\) ?\{ ?\} ?\[ ?\] ?\" ?\' ?\\ ?Á)))
- (should (equal (read (print-tests--prin1-to-string syms)) syms))
- (should (equal (print-tests--prin1-to-string syms)
- (concat "(" (mapconcat #'prin1-char syms " ") ")"))))
- (let ((integer-output-format t)
- (syms (list -1 0 1 ?\120 4194175 4194176 (max-char) (1+ (max-char)))))
- (should (equal (read (print-tests--prin1-to-string syms)) syms)))
- (let ((integer-output-format 16)
- (syms (list -1 0 1 most-positive-fixnum (1+ most-positive-fixnum))))
- (should (equal (read (print-tests--prin1-to-string syms)) syms))
- (should (equal (print-tests--prin1-to-string syms)
- (concat "(" (mapconcat
- (lambda (i)
- (if (and (>= i 0) (<= i most-positive-fixnum))
- (format "#x%x" i) (format "%d" i)))
- syms " ") ")")))))
+ (let* ((print-integers-as-characters t)
+ (chars '(?? ?\; ?\( ?\) ?\{ ?\} ?\[ ?\] ?\" ?\' ?\\ ?f ?~ ?Á 32
+ ?\n ?\r ?\t ?\b ?\f ?\a ?\v ?\e ?\d))
+ (nums '(-1 -65 0 1 31 #x80 #x9f #x110000 #x3fff80 #x3fffff))
+ (nonprints '(#xd800 #xdfff #x030a #xffff #x2002 #x200c))
+ (printed-chars (print-tests--prin1-to-string chars))
+ (printed-nums (print-tests--prin1-to-string nums))
+ (printed-nonprints (print-tests--prin1-to-string nonprints)))
+ (should (equal (read printed-chars) chars))
+ (should (equal
+ printed-chars
+ (concat
+ "(?? ?\\; ?\\( ?\\) ?\\{ ?\\} ?\\[ ?\\] ?\\\" ?\\' ?\\\\"
+ " ?f ?~ ?Á ?\\s ?\\n ?\\r ?\\t ?\\b ?\\f 7 11 27 127)")))
+ (should (equal (read printed-nums) nums))
+ (should (equal printed-nums
+ "(-1 -65 0 1 31 128 159 1114112 4194176 4194303)"))
+ (should (equal (read printed-nonprints) nonprints))
+ (should (equal printed-nonprints
+ "(55296 57343 778 65535 8194 8204)"))))
(provide 'print-tests)
;;; print-tests.el ends here