From mboxrd@z Thu Jan  1 00:00:00 1970
Path: news.gmane.org!.POSTED!not-for-mail
From: npostavs@users.sourceforge.net
Newsgroups: gmane.emacs.bugs
Subject: bug#16828: 24.3.50;
	eval-expression, character representation of integer results
	time-consuming
Date: Thu, 18 May 2017 19:56:53 -0400
Message-ID: <878tltiure.fsf@users.sourceforge.net>
References: <CABr8ebbLKP8As7ud-u3wmJ4cuua1NhKX8_yGpfSd7-1p1ez+bA@mail.gmail.com>
	<83mwhk4v48.fsf@gnu.org>
	<CABr8ebYbBF7AgHHsKWtyAi-c6BHvNpBis48+PgcfcZBH1Y-7OA@mail.gmail.com>
	<83txbr2sye.fsf@gnu.org> <87zjljf086.fsf@rosalinde.fritz.box>
	<83a9di3lt1.fsf@gnu.org> <877g8mb3lh.fsf@Rainer.invalid>
	<b4my510yqdt.fsf@jpl.org> <530DBEEE.8060805@gmx.at>
	<87zig84s6l.fsf@users.sourceforge.net> <83wpbc9ldc.fsf@gnu.org>
	<CAM-tV-_t2bjpE2byh3NvJjw8dfxTwk4rM7EjwSdTM13EgC=-wA@mail.gmail.com>
	<83lgrs9k8p.fsf@gnu.org> <87inmw3x5b.fsf@users.sourceforge.net>
	<83fui09i5z.fsf@gnu.org> <87fui03pjr.fsf@users.sourceforge.net>
	<834lyg9b9t.fsf@gnu.org> <87a88752ej.fsf@users.sourceforge.net>
	<83y3vr9909.fsf@gnu.org>
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Trace: blaine.gmane.org 1495151780 29377 195.159.176.226 (18 May 2017 23:56:20 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Thu, 18 May 2017 23:56:20 +0000 (UTC)
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux)
Cc: 16828@debbugs.gnu.org
To: Eli Zaretskii <eliz@gnu.org>
Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Fri May 19 01:56:13 2017
Return-path: <bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org>
Envelope-to: geb-bug-gnu-emacs@m.gmane.org
Original-Received: from lists.gnu.org ([208.118.235.17])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org>)
	id 1dBVHB-0007Tc-46
	for geb-bug-gnu-emacs@m.gmane.org; Fri, 19 May 2017 01:56:13 +0200
Original-Received: from localhost ([::1]:55935 helo=lists.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.71)
	(envelope-from <bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org>)
	id 1dBVHG-00073U-Qy
	for geb-bug-gnu-emacs@m.gmane.org; Thu, 18 May 2017 19:56:18 -0400
Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:59802)
	by lists.gnu.org with esmtp (Exim 4.71)
	(envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1dBVH7-00073N-LM
	for bug-gnu-emacs@gnu.org; Thu, 18 May 2017 19:56:12 -0400
Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
	(envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1dBVH4-00022C-Ds
	for bug-gnu-emacs@gnu.org; Thu, 18 May 2017 19:56:09 -0400
Original-Received: from debbugs.gnu.org ([208.118.235.43]:51433)
	by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16)
	(Exim 4.71) (envelope-from <Debian-debbugs@debbugs.gnu.org>)
	id 1dBVH4-00021n-0O
	for bug-gnu-emacs@gnu.org; Thu, 18 May 2017 19:56:06 -0400
Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2)
	(envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1dBVH0-0004Lj-2W
	for bug-gnu-emacs@gnu.org; Thu, 18 May 2017 19:56:02 -0400
X-Loop: help-debbugs@gnu.org
Resent-From: npostavs@users.sourceforge.net
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces@debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@gnu.org
Resent-Date: Thu, 18 May 2017 23:56:02 +0000
Resent-Message-ID: <handler.16828.B16828.149515172816674@debbugs.gnu.org>
Resent-Sender: help-debbugs@gnu.org
X-GNU-PR-Message: followup 16828
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
Original-Received: via spool by 16828-submit@debbugs.gnu.org id=B16828.149515172816674
	(code B ref 16828); Thu, 18 May 2017 23:56:02 +0000
Original-Received: (at 16828) by debbugs.gnu.org; 18 May 2017 23:55:28 +0000
Original-Received: from localhost ([127.0.0.1]:54110 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces@debbugs.gnu.org>)
	id 1dBVGR-0004Kr-5v
	for submit@debbugs.gnu.org; Thu, 18 May 2017 19:55:28 -0400
Original-Received: from mail-it0-f42.google.com ([209.85.214.42]:35081)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <npostavs@gmail.com>) id 1dBVGO-0004Kc-0p
	for 16828@debbugs.gnu.org; Thu, 18 May 2017 19:55:25 -0400
Original-Received: by mail-it0-f42.google.com with SMTP id c15so109947274ith.0
	for <16828@debbugs.gnu.org>; Thu, 18 May 2017 16:55:23 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; 
	h=sender:from:to:cc:subject:references:date:in-reply-to:message-id
	:user-agent:mime-version;
	bh=4pHKDX5coPzAQmyfiKozUnveuGeji2/zhj/+b7jIS58=;
	b=p9NpYWLnGqppfpIH5rIJBbcrDr8j8KtAvbav6OYpQ4cFlf7HKLbY5ihD7UdLgGg4S0
	i04P6/GoW2HA225dDQdyzy0jHO8M06sPdidUVZdthie8Acj+41LReRFVQmpgTKMZQtcw
	qCrIl4tR1QcZ7RcSy4Qa86DibzucFJcF/DfHLywcX0yE5WHsl+2xyKtJaqUmXLc9/nZe
	soymNxvDw4Fkn5nS1+CSNL6d33s0b4fzWIDR83vq9re86QK1v2XDiFwY9m4RNTFJ96ro
	kKZYsYRZNT3mzi5w7Kws7mNH90KChvYOYCiXB5A6gOF+uZtkzR4hjMFxXHYSYIuw+nN7
	Pilw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
	d=1e100.net; s=20161025;
	h=x-gm-message-state:sender:from:to:cc:subject:references:date
	:in-reply-to:message-id:user-agent:mime-version;
	bh=4pHKDX5coPzAQmyfiKozUnveuGeji2/zhj/+b7jIS58=;
	b=P3k1nXpdY1nVQDJ60i7l1EFtDmPoxcnasclEIGbBuVfi3KDFxhnHBI57+jckvVtyd2
	SzzKj+JbsPFMx302d/Iz6mHKfT2IyM828j3DSaig08FHgWw2FZfNWGDVb9McnwPar0Qp
	xjuRrMVP25Ew7Wv6kfwK36OEhqcIWym4ybB4/lnjnL4Hz8BnI3HWwkGlpBZZIz3PNG8d
	DlSAKqMDP5ncBZ83XvoKp6x7ZPrkg3ycyLAgOlDgTUOHHgd2bDQR6C3HxE0VLufo01+/
	N7Xk4KnXlVLwKKLje7CCQBVt9eoTIbNj30sitr/iw6oV9Hsfgy9Dd0twsXntHID02jo9
	WrZw==
X-Gm-Message-State: AODbwcBBWkwgf78n4oZ7Kwvghr/+igcDAsZ5PUAfAhRvNtFBkeRGTVek
	1NwTVdHT6e/Z+A==
X-Received: by 10.36.172.105 with SMTP id m41mr4397234iti.110.1495151718296;
	Thu, 18 May 2017 16:55:18 -0700 (PDT)
Original-Received: from zony ([45.2.7.65]) by smtp.googlemail.com with ESMTPSA id
	f15sm3034103ioi.58.2017.05.18.16.55.16
	(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);
	Thu, 18 May 2017 16:55:17 -0700 (PDT)
In-Reply-To: <83y3vr9909.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 26 Mar
	2017 21:40:38 +0300")
X-BeenThere: debbugs-submit@debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic]
X-Received-From: 208.118.235.43
X-BeenThere: bug-gnu-emacs@gnu.org
List-Id: "Bug reports for GNU Emacs,
	the Swiss army knife of text editors" <bug-gnu-emacs.gnu.org>
List-Unsubscribe: <https://lists.gnu.org/mailman/options/bug-gnu-emacs>,
	<mailto:bug-gnu-emacs-request@gnu.org?subject=unsubscribe>
List-Archive: <http://lists.gnu.org/archive/html/bug-gnu-emacs/>
List-Post: <mailto:bug-gnu-emacs@gnu.org>
List-Help: <mailto:bug-gnu-emacs-request@gnu.org?subject=help>
List-Subscribe: <https://lists.gnu.org/mailman/listinfo/bug-gnu-emacs>,
	<mailto:bug-gnu-emacs-request@gnu.org?subject=subscribe>
Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org
Original-Sender: "bug-gnu-emacs"
	<bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org>
Xref: news.gmane.org gmane.emacs.bugs:132618
Archived-At: <http://permalink.gmane.org/gmane.emacs.bugs/132618>

--=-=-=
Content-Type: text/plain

Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> > Yes, I propose that the current behavior wrt the argument will be left
>> > unchanged, except when the argument is zero, i.e. "C-u 0".
>> 
>> Currently, zero also means no truncation, keeping that meaning seems
>> important too.  Perhaps a negative argument would be a better choice?
>
> Yes, that'd be fine with me.  Thanks.

I added `-' to echo in character format, and `-1' to print it to the
buffer.  I split the patch in 2 parts, the first just refactors the
printing code, the 2nd adds the new behaviour.


--=-=-=
Content-Type: text/plain
Content-Disposition: attachment;
 filename=v2-0001-Refactor-lisp-eval-result-printing.patch
Content-Description: patch

>From f5ebfc7e1d352e63794264cf971993c5c0d564b2 Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Sun, 23 Apr 2017 22:21:42 -0400
Subject: [PATCH v2 1/2] Refactor lisp eval result printing

* lisp/simple.el (eval-expression-print-format): Don't check
`standard-output' or `current-prefix-arg'.
(eval-expression-get-print-arguments): New function, centralizes
decision about how to print results of `eval-expression' and
`eval-last-sexp'.
(eval-expression):
* lisp/progmodes/elisp-mode.el (elisp--eval-last-sexp-print-value):
Use it.
---
 lisp/progmodes/elisp-mode.el            | 35 ++++++++++----------
 lisp/simple.el                          | 58 +++++++++++++++++----------------
 test/lisp/progmodes/elisp-mode-tests.el | 18 ++++++++++
 test/lisp/simple-tests.el               | 42 ++++++++++++++++++------
 4 files changed, 97 insertions(+), 56 deletions(-)

diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 53a0f66439..c2fdba47a0 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -1119,29 +1119,28 @@ elisp--eval-last-sexp
 output with no limit on the length and level of lists, and
 include additional formats for integers \(octal, hexadecimal, and
 character)."
-  (let ((standard-output (if eval-last-sexp-arg-internal (current-buffer) t)))
+  (pcase-let*
+      ((`(,insert-value ,no-truncate ,char-print)
+        (eval-expression-get-print-arguments eval-last-sexp-arg-internal)))
     ;; Setup the lexical environment if lexical-binding is enabled.
     (elisp--eval-last-sexp-print-value
      (eval (eval-sexp-add-defvars (elisp--preceding-sexp)) lexical-binding)
-     eval-last-sexp-arg-internal)))
-
-(defun elisp--eval-last-sexp-print-value (value &optional eval-last-sexp-arg-internal)
-  (let ((unabbreviated (let ((print-length nil) (print-level nil))
-			 (prin1-to-string value)))
-	(print-length (and (not (zerop (prefix-numeric-value
-					eval-last-sexp-arg-internal)))
-			   eval-expression-print-length))
-	(print-level (and (not (zerop (prefix-numeric-value
-				       eval-last-sexp-arg-internal)))
-			  eval-expression-print-level))
-	(beg (point))
-	end)
+     (if insert-value (current-buffer) t) no-truncate char-print)))
+
+(defun elisp--eval-last-sexp-print-value
+    (value output &optional no-truncate char-print)
+  (let* ((unabbreviated (let ((print-length nil) (print-level nil))
+                          (prin1-to-string value)))
+         (print-length (unless no-truncate eval-expression-print-length))
+         (print-level  (unless no-truncate eval-expression-print-level))
+         (beg (point))
+         end)
     (prog1
-	(prin1 value)
-      (let ((str (eval-expression-print-format value)))
-	(if str (princ str)))
+	(prin1 value output)
+      (let ((str (and char-print (eval-expression-print-format value))))
+	(if str (princ str output)))
       (setq end (point))
-      (when (and (bufferp standard-output)
+      (when (and (bufferp output)
 		 (or (not (null print-length))
 		     (not (null print-level)))
 		 (not (string= unabbreviated
diff --git a/lisp/simple.el b/lisp/simple.el
index 082406bdc4..68208118f1 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -1460,16 +1460,14 @@ eval-expression-print-format
 If VALUE is not an integer, nil is returned.
 This function is used by functions like `prin1' that display the
 result of expression evaluation."
-  (if (and (integerp value)
-	   (or (eq standard-output t)
-	       (zerop (prefix-numeric-value current-prefix-arg))))
-      (let ((char-string
-	     (if (and (characterp value)
-		      (char-displayable-p value))
-		 (prin1-char value))))
-        (if char-string
-            (format " (#o%o, #x%x, %s)" value value char-string)
-          (format " (#o%o, #x%x)" value value)))))
+  (when (integerp value)
+    (let ((char-string
+           (and (characterp value)
+                (char-displayable-p value)
+                (prin1-char value))))
+      (if char-string
+          (format " (#o%o, #x%x, %s)" value value char-string)
+        (format " (#o%o, #x%x)" value value)))))
 
 (defvar eval-expression-minibuffer-setup-hook nil
   "Hook run by `eval-expression' when entering the minibuffer.")
@@ -1488,9 +1486,21 @@ read--expression
                             read-expression-map t
                             'read-expression-history))))
 
+(defun eval-expression-get-print-arguments (prefix-argument)
+  "Get arguments for commands that print an expression result.
+Returns a list (INSERT-VALUE NO-TRUNCATE CHAR-PRINT)
+based on PREFIX-ARG.  This function determines the interpretation
+of the prefix argument for `eval-expression' and
+`eval-last-sexp'."
+  (let ((num (prefix-numeric-value prefix-argument)))
+    (list (not (memq prefix-argument '(nil)))
+          (= num 0)
+          (cond ((not (memq prefix-argument '(0 nil))) nil)
+                (t t)))))
+
 ;; We define this, rather than making `eval' interactive,
 ;; for the sake of completion of names like eval-region, eval-buffer.
-(defun eval-expression (exp &optional insert-value)
+(defun eval-expression (exp &optional insert-value no-truncate char-print)
   "Evaluate EXP and print value in the echo area.
 When called interactively, read an Emacs Lisp expression and evaluate it.
 Value is also consed on to front of the variable `values'.
@@ -1511,8 +1521,8 @@ eval-expression
 If `eval-expression-debug-on-error' is non-nil, which is the default,
 this command arranges for all errors to enter the debugger."
   (interactive
-   (list (read--expression "Eval: ")
-	 current-prefix-arg))
+   (cons (read--expression "Eval: ")
+         (eval-expression-get-print-arguments current-prefix-arg)))
 
   (if (null eval-expression-debug-on-error)
       (push (eval exp lexical-binding) values)
@@ -1527,23 +1537,15 @@ eval-expression
       (unless (eq old-value new-value)
 	(setq debug-on-error new-value))))
 
-  (let ((print-length (and (not (zerop (prefix-numeric-value insert-value)))
-			   eval-expression-print-length))
-	(print-level (and (not (zerop (prefix-numeric-value insert-value)))
-			  eval-expression-print-level))
+  (let ((print-length (unless no-truncate eval-expression-print-length))
+        (print-level  (unless no-truncate eval-expression-print-level))
         (deactivate-mark))
-    (if insert-value
-	(with-no-warnings
-	 (let ((standard-output (current-buffer)))
-	   (prog1
-	       (prin1 (car values))
-	     (when (zerop (prefix-numeric-value insert-value))
-	       (let ((str (eval-expression-print-format (car values))))
-		 (if str (princ str)))))))
+    (let ((out (if insert-value (current-buffer) t)))
       (prog1
-          (prin1 (car values) t)
-        (let ((str (eval-expression-print-format (car values))))
-          (if str (princ str t)))))))
+          (prin1 (car values) out)
+        (let ((str (and char-print
+                        (eval-expression-print-format (car values)))))
+          (when str (princ str out)))))))
 
 (defun edit-and-eval-command (prompt command)
   "Prompting with PROMPT, let user edit COMMAND and eval result.
diff --git a/test/lisp/progmodes/elisp-mode-tests.el b/test/lisp/progmodes/elisp-mode-tests.el
index 93c428b2d2..5edb590b1e 100644
--- a/test/lisp/progmodes/elisp-mode-tests.el
+++ b/test/lisp/progmodes/elisp-mode-tests.el
@@ -114,6 +114,24 @@ elisp--test-completions
       (should (member "backup-buffer" comps))
       (should-not (member "backup-inhibited" comps)))))
 
+;;; eval-last-sexp
+
+(ert-deftest eval-last-sexp-print-format-sym ()
+  (with-temp-buffer
+    (let ((current-prefix-arg '(4)))
+      (erase-buffer) (insert "t")
+      (call-interactively #'eval-last-sexp)
+      (should (equal (buffer-string) "tt")))))
+
+(ert-deftest eval-last-sexp-print-format-sym-echo ()
+  ;; We can only check the echo area when running interactive.
+  (skip-unless (not noninteractive))
+  (with-temp-buffer
+    (let ((current-prefix-arg nil))
+      (erase-buffer) (insert "t") (message nil)
+      (call-interactively #'eval-last-sexp)
+      (should (equal (current-message) "t")))))
+
 ;;; xref
 
 (defun xref-elisp-test-descr-to-target (xref)
diff --git a/test/lisp/simple-tests.el b/test/lisp/simple-tests.el
index f4849c4b21..b74e28ccaf 100644
--- a/test/lisp/simple-tests.el
+++ b/test/lisp/simple-tests.el
@@ -20,6 +20,7 @@
 ;;; Code:
 
 (require 'ert)
+(eval-when-compile (require 'cl-lib))
 
 (defmacro simple-test--dummy-buffer (&rest body)
   (declare (indent 0)
@@ -35,6 +36,8 @@ simple-test--dummy-buffer
              (buffer-substring (point) (point-max))))))
 
 
+
+;;; `transpose-sexps'
 (defmacro simple-test--transpositions (&rest body)
   (declare (indent 0)
            (debug t))
@@ -46,6 +49,13 @@ simple-test--transpositions
      (cons (buffer-substring (point-min) (point))
            (buffer-substring (point) (point-max)))))
 
+;;; Transposition with negative args (bug#20698, bug#21885)
+(ert-deftest simple-transpose-subr ()
+  (should (equal (simple-test--transpositions (transpose-sexps -1))
+                 '("(s1) (s2) (s4)" . " (s3) (s5)")))
+  (should (equal (simple-test--transpositions (transpose-sexps -2))
+                 '("(s1) (s4)" . " (s2) (s3) (s5)"))))
+
 
 ;;; `newline'
 (ert-deftest newline ()
@@ -239,8 +249,8 @@ simple-test--transpositions
       (should (equal ?\s (char-syntax ?\f)))
       (should (equal ?\s (char-syntax ?\n))))))
 
-
-;;; auto-boundary tests
+
+;;; undo auto-boundary tests
 (ert-deftest undo-auto-boundary-timer ()
   (should
    undo-auto-current-boundary-timer))
@@ -269,14 +279,6 @@ simple-test--transpositions
      (insert "hello")
      (undo-auto--boundaries 'test))))
 
-;;; Transposition with negative args (bug#20698, bug#21885)
-(ert-deftest simple-transpose-subr ()
-  (should (equal (simple-test--transpositions (transpose-sexps -1))
-                 '("(s1) (s2) (s4)" . " (s3) (s5)")))
-  (should (equal (simple-test--transpositions (transpose-sexps -2))
-                 '("(s1) (s4)" . " (s2) (s3) (s5)"))))
-
-
 ;; Test for a regression introduced by undo-auto--boundaries changes.
 ;; https://lists.gnu.org/archive/html/emacs-devel/2015-11/msg01652.html
 (defun undo-test-kill-c-a-then-undo ()
@@ -374,5 +376,25 @@ simple-test-undo-with-switched-buffer
        (undo)
        (point)))))
 
+
+;;; `eval-expression'
+
+(ert-deftest eval-expression-print-format-sym ()
+  (with-temp-buffer
+    (cl-letf (((symbol-function 'read--expression) (lambda (&rest _) t)))
+      (let ((current-prefix-arg '(4)))
+        (call-interactively #'eval-expression)
+        (should (equal (buffer-string) "t"))))))
+
+(ert-deftest eval-expression-print-format-sym-echo ()
+  ;; We can only check the echo area when running interactive.
+  (skip-unless (not noninteractive))
+  (with-temp-buffer
+    (cl-letf (((symbol-function 'read--expression) (lambda (&rest _) t)))
+      (let ((current-prefix-arg nil))
+        (message nil)
+        (call-interactively #'eval-expression)
+        (should (equal (current-message) "t"))))))
+
 (provide 'simple-test)
 ;;; simple-test.el ends here
-- 
2.11.1


--=-=-=
Content-Type: text/plain
Content-Disposition: attachment;
 filename=v2-0002-Limit-integers-printed-as-characters-Bug-16828.patch
Content-Description: patch

>From cb5c5e64b97aa8add81aa7537bb888ebe651d72d Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Sun, 23 Apr 2017 22:30:20 -0400
Subject: [PATCH v2 2/2] Limit integers printed as characters (Bug#16828)

* lisp/simple.el (eval-expression-print-maximum-character): New
variable.
(eval-expression-print-format): Only display value as character if
it's less than or equal to `eval-expression-print-maximum-character'.
(eval-expression-get-print-arguments): Check
eval-expression-print-maximum-character, allow negative arg to
override it.
(eval-expression):
* lisp/progmodes/elisp-mode.el (elisp--eval-last-sexp):
(elisp--eval-last-sexp-print-value): Handle new variable.
* doc/emacs/building.texi (Lisp Eval): Document new variable and
behavior.
* etc/NEWS: Announce it.
* test/lisp/progmodes/elisp-mode-tests.el
(eval-last-sexp-print-format-small-int):
(eval-last-sexp-print-format-small-int-echo):
(eval-last-sexp-print-format-large-int):
(eval-last-sexp-print-format-large-int-echo):
* test/lisp/simple-tests.el (eval-expression-print-format-small-int):
(eval-expression-print-format-small-int-echo):
(eval-expression-print-format-large-int):
(eval-expression-print-format-large-int-echo): New tests.
---
 doc/emacs/building.texi                 | 12 ++++++--
 etc/NEWS                                |  4 +++
 lisp/progmodes/elisp-mode.el            | 20 ++++++++-----
 lisp/simple.el                          | 53 ++++++++++++++++++++++-----------
 test/lisp/progmodes/elisp-mode-tests.el | 48 +++++++++++++++++++++++++++++
 test/lisp/simple-tests.el               | 52 ++++++++++++++++++++++++++++++++
 6 files changed, 160 insertions(+), 29 deletions(-)

diff --git a/doc/emacs/building.texi b/doc/emacs/building.texi
index ba8eae0759..56bdffbb31 100644
--- a/doc/emacs/building.texi
+++ b/doc/emacs/building.texi
@@ -1485,7 +1485,8 @@ Lisp Eval
 Emacs Lisp expression preceding point in the buffer, and displays the
 value in the echo area.  When the result of an evaluation is an
 integer, it is displayed together with the value in other formats
-(octal, hexadecimal, and character).
+(octal, hexadecimal, and character if
+@code{eval-expression-print-maximum-character} allows it).
 
   If @kbd{M-:} or @kbd{C-x C-e} is given a prefix argument, it inserts
 the value into the current buffer at point, rather than displaying it
@@ -1493,8 +1494,10 @@ Lisp Eval
 is inserted together with its value in other formats (octal,
 hexadecimal, and character).  Such a prefix argument also prevents
 abbreviation of the output according to the variables
-@code{eval-expression-print-level} and @code{eval-expression-print-length}
-(see below).
+@code{eval-expression-print-level} and
+@code{eval-expression-print-length} (see below).  Similarly, a prefix
+argument of @code{-1} overrides the effect of
+@code{eval-expression-print-length}.
 
 @kindex C-M-x @r{(Emacs Lisp mode)}
 @findex eval-defun
@@ -1524,6 +1527,7 @@ Lisp Eval
 
 @vindex eval-expression-print-level
 @vindex eval-expression-print-length
+@vindex eval-expression-print-maximum-character
 @vindex eval-expression-debug-on-error
   The options @code{eval-expression-print-level} and
 @code{eval-expression-print-length} control the maximum depth and
@@ -1533,6 +1537,8 @@ Lisp Eval
 printed in full.  @code{eval-expression-debug-on-error} controls
 whether evaluation errors invoke the debugger when these commands are
 used; its default is @code{t}.
+@code{eval-expression-print-maximum-character} prevents large integers
+from being displayed as characters.
 
 @node Lisp Interaction
 @section Lisp Interaction Buffers
diff --git a/etc/NEWS b/etc/NEWS
index e8f5b2e899..548d55d60d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -344,6 +344,10 @@ for DNS-querying functions 'nslookup-host', 'dns-lookup-host',
 and 'run-dig'.  Each function now accepts an optional name server
 argument interactively (with a prefix argument) and non-interactively.
 
++++
+** The new variable 'eval-expression-print-maximum-character' prevents
+large integers from being displayed as characters.
+
 
 * Editing Changes in Emacs 26.1
 
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index c2fdba47a0..6c6fb92504 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -1120,24 +1120,25 @@ elisp--eval-last-sexp
 include additional formats for integers \(octal, hexadecimal, and
 character)."
   (pcase-let*
-      ((`(,insert-value ,no-truncate ,char-print)
+      ((`(,insert-value ,no-truncate ,char-print-limit)
         (eval-expression-get-print-arguments eval-last-sexp-arg-internal)))
     ;; Setup the lexical environment if lexical-binding is enabled.
     (elisp--eval-last-sexp-print-value
      (eval (eval-sexp-add-defvars (elisp--preceding-sexp)) lexical-binding)
-     (if insert-value (current-buffer) t) no-truncate char-print)))
+     (if insert-value (current-buffer) t) no-truncate char-print-limit)))
 
 (defun elisp--eval-last-sexp-print-value
-    (value output &optional no-truncate char-print)
+    (value output &optional no-truncate char-print-limit)
   (let* ((unabbreviated (let ((print-length nil) (print-level nil))
                           (prin1-to-string value)))
+         (eval-expression-print-maximum-character char-print-limit)
          (print-length (unless no-truncate eval-expression-print-length))
          (print-level  (unless no-truncate eval-expression-print-level))
          (beg (point))
          end)
     (prog1
 	(prin1 value output)
-      (let ((str (and char-print (eval-expression-print-format value))))
+      (let ((str (and char-print-limit (eval-expression-print-format value))))
 	(if str (princ str output)))
       (setq end (point))
       (when (and (bufferp output)
@@ -1175,14 +1176,17 @@ eval-sexp-add-defvars
 
 (defun eval-last-sexp (eval-last-sexp-arg-internal)
   "Evaluate sexp before point; print value in the echo area.
-Interactively, with prefix argument, print output into current buffer.
+Interactively, with a non `-' prefix argument, print output into
+current buffer.
 
-Normally, this function truncates long output according to the value
-of the variables `eval-expression-print-length' and
+Normally, this function truncates long output according to the
+value of the variables `eval-expression-print-length' and
 `eval-expression-print-level'.  With a prefix argument of zero,
 however, there is no such truncation.  Such a prefix argument
 also causes integers to be printed in several additional formats
-\(octal, hexadecimal, and character).
+\(octal, hexadecimal, and character when the prefix argument is
+-1 or the integer is `eval-expression-print-maximum-character' or
+less).
 
 If `eval-expression-debug-on-error' is non-nil, which is the default,
 this command arranges for all errors to enter the debugger."
diff --git a/lisp/simple.el b/lisp/simple.el
index 68208118f1..4435da6463 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -1454,6 +1454,13 @@ eval-expression-debug-on-error
   :type 'boolean
   :version "21.1")
 
+(defcustom eval-expression-print-maximum-character 127
+  "The largest integer that will be displayed as a character.
+This affects printing by `eval-expression-print-format'."
+  :group 'lisp
+  :type 'integer
+  :version "26.1")
+
 (defun eval-expression-print-format (value)
   "If VALUE in an integer, return a specially formatted string.
 This string will typically look like \" (#o1, #x1, ?\\C-a)\".
@@ -1463,6 +1470,7 @@ eval-expression-print-format
   (when (integerp value)
     (let ((char-string
            (and (characterp value)
+                (<= value eval-expression-print-maximum-character)
                 (char-displayable-p value)
                 (prin1-char value))))
       (if char-string
@@ -1488,32 +1496,40 @@ read--expression
 
 (defun eval-expression-get-print-arguments (prefix-argument)
   "Get arguments for commands that print an expression result.
-Returns a list (INSERT-VALUE NO-TRUNCATE CHAR-PRINT)
+Returns a list (INSERT-VALUE NO-TRUNCATE CHAR-PRINT-LIMIT)
 based on PREFIX-ARG.  This function determines the interpretation
 of the prefix argument for `eval-expression' and
 `eval-last-sexp'."
   (let ((num (prefix-numeric-value prefix-argument)))
-    (list (not (memq prefix-argument '(nil)))
+    (list (not (memq prefix-argument '(- nil)))
           (= num 0)
-          (cond ((not (memq prefix-argument '(0 nil))) nil)
-                (t t)))))
+          (cond ((not (memq prefix-argument '(0 -1 - nil))) nil)
+                ((= num -1) most-positive-fixnum)
+                (t eval-expression-print-maximum-character)))))
 
 ;; We define this, rather than making `eval' interactive,
 ;; for the sake of completion of names like eval-region, eval-buffer.
-(defun eval-expression (exp &optional insert-value no-truncate char-print)
+(defun eval-expression (exp &optional insert-value no-truncate char-print-limit)
   "Evaluate EXP and print value in the echo area.
-When called interactively, read an Emacs Lisp expression and evaluate it.
-Value is also consed on to front of the variable `values'.
-If the resulting value is an integer, it will be printed in
-several additional formats (octal, hexadecimal, and character).
-Optional argument INSERT-VALUE non-nil (interactively, with
-prefix argument) means insert the result into the current buffer
-instead of printing it in the echo area.
-
-Normally, this function truncates long output according to the value
-of the variables `eval-expression-print-length' and
-`eval-expression-print-level'.  With a prefix argument of zero,
-however, there is no such truncation.
+When called interactively, read an Emacs Lisp expression and
+evaluate it.  Value is also consed on to front of the variable
+`values'.  Optional argument INSERT-VALUE non-nil (interactively,
+with a non `-' prefix argument) means insert the result into the
+current buffer instead of printing it in the echo area.
+
+Normally, this function truncates long output according to the
+value of the variables `eval-expression-print-length' and
+`eval-expression-print-level'.  When NO-TRUNCATE is
+non-nil (interactively, with a prefix argument of zero), however,
+there is no such truncation.
+
+If the resulting value is an integer, and CHAR-PRINT-LIMIT is
+non-nil (interactively, unless given a positive prefix argument)
+it will be printed in several additional formats (octal,
+hexadecimal, and character).  The character format is only used
+if the value is below CHAR-PRINT-LIMIT (interactively, if the
+prefix argument is -1 or the value is below
+`eval-expression-print-maximum-character').
 
 Runs the hook `eval-expression-minibuffer-setup-hook' on entering the
 minibuffer.
@@ -1539,11 +1555,12 @@ eval-expression
 
   (let ((print-length (unless no-truncate eval-expression-print-length))
         (print-level  (unless no-truncate eval-expression-print-level))
+        (eval-expression-print-maximum-character char-print-limit)
         (deactivate-mark))
     (let ((out (if insert-value (current-buffer) t)))
       (prog1
           (prin1 (car values) out)
-        (let ((str (and char-print
+        (let ((str (and char-print-limit
                         (eval-expression-print-format (car values)))))
           (when str (princ str out)))))))
 
diff --git a/test/lisp/progmodes/elisp-mode-tests.el b/test/lisp/progmodes/elisp-mode-tests.el
index 5edb590b1e..03ae8481ee 100644
--- a/test/lisp/progmodes/elisp-mode-tests.el
+++ b/test/lisp/progmodes/elisp-mode-tests.el
@@ -132,6 +132,54 @@ elisp--test-completions
       (call-interactively #'eval-last-sexp)
       (should (equal (current-message) "t")))))
 
+(ert-deftest eval-last-sexp-print-format-small-int ()
+  (with-temp-buffer
+    (let ((current-prefix-arg '(4)))
+      (erase-buffer) (insert "?A")
+      (call-interactively #'eval-last-sexp)
+      (should (equal (buffer-string) "?A65")))
+    (let ((current-prefix-arg 0))
+      (erase-buffer) (insert "?A")
+      (call-interactively #'eval-last-sexp)
+      (should (equal (buffer-string) "?A65 (#o101, #x41, ?A)")))))
+
+(ert-deftest eval-last-sexp-print-format-small-int-echo ()
+  (skip-unless (not noninteractive))
+  (with-temp-buffer
+    (let ((current-prefix-arg nil))
+      (erase-buffer) (insert "?A") (message nil)
+      (call-interactively #'eval-last-sexp)
+      (should (equal (current-message) "65 (#o101, #x41, ?A)")))))
+
+(ert-deftest eval-last-sexp-print-format-large-int ()
+  (with-temp-buffer
+    (let ((eval-expression-print-maximum-character ?A))
+      (let ((current-prefix-arg '(4)))
+        (erase-buffer) (insert "?B")
+        (call-interactively #'eval-last-sexp)
+        (should (equal (buffer-string) "?B66")))
+      (let ((current-prefix-arg 0))
+        (erase-buffer) (insert "?B")
+        (call-interactively #'eval-last-sexp)
+        (should (equal (buffer-string) "?B66 (#o102, #x42)")))
+      (let ((current-prefix-arg -1))
+        (erase-buffer) (insert "?B")
+        (call-interactively #'eval-last-sexp)
+        (should (equal (buffer-string) "?B66 (#o102, #x42, ?B)"))))))
+
+(ert-deftest eval-last-sexp-print-format-large-int-echo ()
+  (skip-unless (not noninteractive))
+  (with-temp-buffer
+    (let ((eval-expression-print-maximum-character ?A))
+      (let ((current-prefix-arg nil))
+        (erase-buffer) (insert "?B") (message nil)
+        (call-interactively #'eval-last-sexp)
+        (should (equal (current-message) "66 (#o102, #x42)")))
+      (let ((current-prefix-arg '-))
+        (erase-buffer) (insert "?B") (message nil)
+        (call-interactively #'eval-last-sexp)
+        (should (equal (current-message) "66 (#o102, #x42, ?B)"))))))
+
 ;;; xref
 
 (defun xref-elisp-test-descr-to-target (xref)
diff --git a/test/lisp/simple-tests.el b/test/lisp/simple-tests.el
index b74e28ccaf..180dcc0a20 100644
--- a/test/lisp/simple-tests.el
+++ b/test/lisp/simple-tests.el
@@ -396,5 +396,57 @@ simple-test-undo-with-switched-buffer
         (call-interactively #'eval-expression)
         (should (equal (current-message) "t"))))))
 
+(ert-deftest eval-expression-print-format-small-int ()
+  (with-temp-buffer
+    (cl-letf (((symbol-function 'read--expression) (lambda (&rest _) ?A)))
+      (let ((current-prefix-arg '(4)))
+        (erase-buffer)
+        (call-interactively #'eval-expression)
+        (should (equal (buffer-string) "65")))
+      (let ((current-prefix-arg 0))
+        (erase-buffer)
+        (call-interactively #'eval-expression)
+        (should (equal (buffer-string) "65 (#o101, #x41, ?A)"))))))
+
+(ert-deftest eval-expression-print-format-small-int-echo ()
+  (skip-unless (not noninteractive))
+  (with-temp-buffer
+    (cl-letf (((symbol-function 'read--expression) (lambda (&rest _) ?A)))
+      (let ((current-prefix-arg nil))
+        (message nil)
+        (call-interactively #'eval-expression)
+        (should (equal (current-message) "65 (#o101, #x41, ?A)"))))))
+
+(ert-deftest eval-expression-print-format-large-int ()
+  (with-temp-buffer
+    (cl-letf (((symbol-function 'read--expression) (lambda (&rest _) ?B))
+              (eval-expression-print-maximum-character ?A))
+      (let ((current-prefix-arg '(4)))
+        (erase-buffer)
+        (call-interactively #'eval-expression)
+        (should (equal (buffer-string) "66")))
+      (let ((current-prefix-arg 0))
+        (erase-buffer)
+        (call-interactively #'eval-expression)
+        (should (equal (buffer-string) "66 (#o102, #x42)")))
+      (let ((current-prefix-arg -1))
+        (erase-buffer)
+        (call-interactively #'eval-expression)
+        (should (equal (buffer-string) "66 (#o102, #x42, ?B)"))))))
+
+(ert-deftest eval-expression-print-format-large-int-echo ()
+  (skip-unless (not noninteractive))
+  (with-temp-buffer
+    (cl-letf (((symbol-function 'read--expression) (lambda (&rest _) ?B))
+              (eval-expression-print-maximum-character ?A))
+      (let ((current-prefix-arg nil))
+        (message nil)
+        (call-interactively #'eval-expression)
+        (should (equal (current-message) "66 (#o102, #x42)")))
+      (let ((current-prefix-arg '-))
+        (message nil)
+        (call-interactively #'eval-expression)
+        (should (equal (current-message) "66 (#o102, #x42, ?B)"))))))
+
 (provide 'simple-test)
 ;;; simple-test.el ends here
-- 
2.11.1


--=-=-=--