unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#53592: 26.3; Bind `M-:' to `pp-eval-expression' and enhance output
@ 2022-01-27 23:35 Drew Adams
  2022-01-28 11:04 ` ndame
  0 siblings, 1 reply; 2+ messages in thread
From: Drew Adams @ 2022-01-27 23:35 UTC (permalink / raw)
  To: 53592

[-- Attachment #1: Type: text/plain, Size: 3117 bytes --]

Enhancement request.  Feel free to split into separate requests, if you
think that's appropriate.  To me, all of what I suggest is related.

1. Bind `M-:' to `pp-eval-expression' by default, not to
   `eval-expression' - makes the input reading better and the output
   more useful.

2. Add keymap `pp-read-expression-map' (or similar).  It binds keys for
   `lisp-indent-line', `lisp-complete-symbol', `indent-sexp',
   `eval-defun', and `indent-pp-sexp'.

3. Define and use `pp-read--expression' instead of `read--expression'.
   (Only difference is that it uses `pp-read-expression-map'.)

2. Add option `pp-max-tooltip-size', so commands `pp-eval-last-sexp' and
  `pp-eval-expression' can optionally show output in a tooltip, and
  control its size.

3. Add options `pp-eval-expression-print-length' and
   `pp-eval-expression-print-level', which act like `print-length' and
   `print-level', but only for pretty-printing.  (No reason to suppose
   that the same values are appropriate for general printing and for
   pretty-printing.)  See definitions below.

4. Redefine `pp-display-expression', to do the following:
   a. Respect option `pp-max-tooltip-size'.
   b. Use no `emacs-lisp-mode-hook' or `change-major-mode-hook'.
   c. Call `font-lock-fontify-buffer'.
   d. Provide undo to buffer OUT-BUFFER-NAME.

5. Redefine `pp-eval-expression' to do the following:

   a. Add optional args, corresponding to prefix-arg behaviors.

      `INSERT-VALUE': non-nil (non-zero prefix arg) lets the command act
        the way `eval-expression' acts: inserts the result in the
        current buffer.

      `SWAP-TOOLTIP': non-nil (zero prefix arg) swaps the behavior
        defined by `pp-max-tooltip-size': if option says use tooltip
        then don't, and vice versa.

   b. With no prefix arg, respect `pp-max-tooltip-size'.  If tooltip not
      used then if value fits on one (frame-width) line then show value
      in the echo area.  Otherwise, show it in buffer `*Pp Eval
      Output*'.

   c. With negative prefix arg, print string values with "...".  With
      positive arg, omit the double-quotes.

   d.  Respect options `pp-eval-expression-print-length',
      `pp-eval-expression-print-level', `pp-max-tooltip-size', and
      `eval-expression-debug-on-error'.

6. Redefine `pp-eval-last-sexp': Same as `pp-eval-expression' wrt
   optional args `INSERT-VALUE' and `SWAP-TOOLTIP', and options
   `pp-eval-expression-print-length', `pp-eval-expression-print-level',
   `pp-max-tooltip-size', and `eval-expression-debug-on-error'.

The code (`pp+.el') is attached.  It's offered as is.  If it's generally
acceptable I can provide a patch.  If not, then please consider doing
what's requested in another way.


In GNU Emacs 26.3 (build 1, x86_64-w64-mingw32)
 of 2019-08-29
Repository revision: 96dd0196c28bc36779584e47fffcca433c9309cd
Windowing system distributor `Microsoft Corp.', version 10.0.19043
Configured using:
 `configure --without-dbus --host=x86_64-w64-mingw32
 --without-compress-install 'CFLAGS=-O2 -static -g3''


[-- Attachment #2: pp+.el --]
[-- Type: application/octet-stream, Size: 28594 bytes --]

;;; pp+.el --- Extensions to `pp.el'.
;;
;; Filename: pp+.el
;; Description: Extensions to `pp.el'.
;; Author: Drew Adams
;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com")
;; Copyright (C) 1999-2022, Drew Adams, all rights reserved.
;; Created: Fri Sep  3 13:45:40 1999
;; Version: 0
;; Package-Requires: ()
;; Last-Updated: Thu Jan 27 15:16:11 2022 (-0800)
;;           By: dradams
;;     Update #: 459
;; URL: https://www.emacswiki.org/emacs/download/pp%2b.el
;; Doc URL: https://emacswiki.org/emacs/EvaluatingExpressions
;; Keywords: lisp
;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26.x
;;
;; Features that might be required by this library:
;;
;;   `pp'.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;;    Extensions to `pp.el'.
;;
;;  Features:
;;
;;   * You can optionally show the result of pretty-printing in a
;;     tooltip at point, by customizing option `pp-max-tooltip-size'
;;     (Emacs 24+).
;;
;;   * You can use a zero prefix argument (e.g. `M-o') with
;;     `pp-eval-last-sexp' (`C-x C-e') or `pp-eval-expression', to
;;     swap the use of a tooltip defined by option
;;     `pp-max-tooltip-size'.  (Emacs 24+)
;;
;;   * There are additional commands that are versions of
;;     `pp-eval-last-sexp' and `pp-eval-expression' that always or
;;     never use a tooltip.  (Emacs 24+)
;;
;;   * Pretty-printing respects options
;;     `pp-eval-expression-print-length' and
;;     `pp-eval-expression-print-level', which act like `print-length'
;;     and `print-level', but only for pretty-printing.
;;
;;   * The buffer displaying the pretty-printed result is in
;;     `emacs-lisp-mode' (and is fontified accordingly), but without
;;     having run `emacs-lisp-mode-hook' or `change-major-mode-hook'.
;;     The buffer has undo: you can make changes there and undo them.
;;
;;   * Command `pp-eval-expression' is enhanced in these ways:
;;
;;      - Option `eval-expression-debug-on-error' is respected.
;;
;;      - With no prefix argument, option `pp-max-tooltip-size' is
;;        respected. If a tooltip is not used then if the value fits
;;        on one line (frame width) it is shown in the echo area.
;;        Otherwise, it is shown in buffer *Pp Eval Output*'.  (Emacs
;;        24+)
;;
;;      - With a zero prefix arg, the use of a tooltip according to
;;        `pp-max-tooltip-size' is swapped: if that option is `nil'
;;        then a tooltip is used, and if non-`nil' a tooltip is not
;;        used.  (Emacs 24+)
;;
;;      - With non-zero prefix argument, the value is inserted into
;;        the current buffer at point. With a negative prefix arg, if
;;        the value is a string, then it is inserted without being
;;        enclosed in double-quotes (").
;;
;;      - Completion is available, using keymap
;;        `pp-read-expression-map', which is like
;;        `read-expression-map' but with some Emacs-Lisp key bindings.
;;
;;   * Command `pp-eval-last-sexp' is enhanced in these ways (Emacs
;;     24+):
;;
;;      - With a zero prefix arg, the use of a tooltip according to
;;        `pp-max-tooltip-size' is swapped: if that option is `nil'
;;        then a tooltip is used, and if non-`nil' a tooltip is not
;;        used.
;;
;;      - With a non-zero prefix arg, the value is inserted into the
;;        current buffer at point.
;;
;;   * Alternative commands are defined that use a tooltip whenever
;;     possible, or that never use a tooltip (they ignore option
;;     `pp-max-tooltip-size'): `pp-eval-expression-with-tooltip',
;;     `pp-eval-expression-without-tooltip',
;;     `pp-eval-last-sexp-with-tooltip', and
;;     `pp-eval-last-sexp-without-tooltip' (Emacs 24+).
;;
;; 
;;
;;  Suggested binding: use `M-:' for `pp-eval-expression'.
;;
;;    (global-set-key [remap eval-expression] 'pp-eval-expression)
;;
;;
;;  User options defined here:
;;
;;    `pp-eval-expression-print-circle',
;;    `pp-eval-expression-print-length',
;;    `pp-eval-expression-print-level', `pp-max-tooltip-size' (Emacs
;;    24+).
;;
;;  Faces defined here:
;;
;;    `pp-tooltip' (Emacs 24+).
;;
;;  Commands defined here:
;;
;;    `pp-eval-expression-with-tooltip' (Emacs 24+),
;;    `pp-eval-expression-without-tooltip' (Emacs 24+),
;;    `pp-eval-last-sexp-with-tooltip' (Emacs 24+),
;;    `pp-eval-last-sexp-without-tooltip' (Emacs 24+).
;;
;;  Non-interactive functions defined here:
;;
;;    `pp-expression-size', `pp-read--expression' (Emacs 24.4+),
;;    `pp-show-tooltip' (Emacs 24+), `pp-tooltip-show' (Emacs 24+).
;;
;;  Variables defined here:
;;
;;    `pp-read-expression-map'.
;;
;;
;;  ***** NOTE: The following functions defined in `pp.el' have
;;              been REDEFINED HERE:
;;
;;    `pp-display-expression', `pp-eval-expression',
;;    `pp-eval-last-sexp' (Emacs 23+).
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Change Log:
;;
;; 2022/01/27 dadams
;;     pp-read--expression: Turn on eldoc-mode (that was added for Emacs 26+).
;; 2022/01/14 dadams
;;     pp-display-expression: Use ', for out-buffer-name in constructed lambda.  Enable undo in output.
;; 2018/06/29 dadams
;;     pp-eval-expression: Ensure not just (boundp 'lexical-binding) but also Emacs 24+.
;; 2017/10/23 dadams
;;     pp-show-tooltip, pp-expression-size, pp-display-expression:
;;       Wrap calls to posn-* with save-excursion.
;; 2017/10/08 dadams
;;     Added: pp-eval-expression-print-circle.
;;     pp-show-tooltip, pp-eval-last-sexp-with(out)-tooltip, pp-eval-last-sexp:
;;       Bind print-(circle|length|level) so pp-to-string prints all.
;; 2016/11/14 dadams
;;     pp-max-tooltip-size: Mention in doc that if point is off-screen then tooltip not used.
;;     pp-display-expression: If point is off-screen then do not try to use tooltip.
;; 2016/05/30 dadams
;;     pp-eval-last-sexp: Do not define for Emacs < 23.
;; 2016/05/21 dadams
;;     Added: pp-max-tooltip-size, face pp-tooltip, pp-show-tooltip,
;;            pp-tooltip-show, pp-expression-size, pp-eval-expression-with(out)-tooltip,
;;            pp-eval-last-sexp-with(out)-tooltip, (redefinition of) pp-eval-last-sexp.
;;     pp-display-expression: Use tooltip if pp-max-tooltip-size says to.  Added autoload cookie.
;;     pp-eval-expression: Added SWAP-TOOLTIP optional arg.
;;                         Use pp-read--expression (forgot to use it on 2015-04-18).
;;     pp-read--expression: Updated per Emacs 25 - use add-function.
;; 2016/05/01 dadams
;;     pp-eval-expression: Return result of evaluation.
;; 2015/04/18 dadms
;;     Added: pp-read--expression.
;;     pp-eval-expression: Updated for Emacs 24.4+: use pp-read--expression.
;; 2013/12/03 dadams
;;     pp-read-expression-map: Swap TAB and M-TAB, so 1st completes Lisp symbols.
;; 2013/02/15 dadams
;;     pp-eval-expression: Bind deactivate-mark to nil, like fix for Emacs bug #13724.
;; 2012/07/22 dadams
;;     pp-display-expression:
;;       Do not try to select old-window if it is no longer live.
;;       Use backquote + comma, to replace free var.
;; 2011/01/04 dadams
;;     Added autoload cookies for defcustom.
;; 2010/06/21 dadams
;;     pp-display-expression: Set the hooks locally instead of let-binding them, to
;;       avoid msg "Making change-major-mode-hook buffer-local while locally
;;       let-bound!" - suggestion from Stefan M.
;; 2010/01/12 dadams
;;     Added: pp-display-expression (redefinition).
;;     pp-eval-expression: Use pp-display-expression.
;; 2008/04/14 dadams
;;     pp-eval-expression: Treat negative prefix arg.
;; 2008/04/13 dadams
;;     pp-eval-expression:
;;       Treat prefix arg (added optional arg).
;;       Respect eval-expression-debug-on-error and pp-eval-expression-print-*.
;;     Added: pp-eval-expression-print-(length|level), pp-read-expression-map.
;; 2007/02/04 dadams
;;     pp-eval-expression: Undid 01/05 workaround, because RMS fixed vanilla Emacs.
;; 2007/01/05 dadams
;;     pp-eval-expression: Adjusted to fit Emacs 22 definition, which doesn't eval.
;; 2006/01/29 dadams
;;     pp-eval-expression: Use read-from-minibuffer.
;; 2005/01/04 dadams
;;     Set buffer-read-only to nil.
;; 2004/03/24 dadams
;;     pp-eval-expression: Added call to font-lock-fontify-buffer.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Code:

(require 'pp)

;;; Quiet the byte compiler.
(defvar eldoc-documentation-function)   ; In `eldoc.el' (Emacs 23+)
(defvar eval-expression-debug-on-error)
(defvar lexical-binding)                ; Emacs 24+
(defvar pp-max-tooltip-size)            ; Here, for Emacs 24+
(defvar tooltip-frame-parameters)       ; Emacs 22+
(defvar tooltip-hide-delay)             ; Emacs 22+
(defvar tooltip-x-offset)               ; Emacs 22+
(defvar tooltip-y-offset)               ; Emacs 22+
(defvar x-max-tooltip-size)             ; Emacs 22+

;;;;;;;;;;;;;;;;;;;;;;;;;;;


(defvar pp-read-expression-map nil
  "`read-expression-map' with some Emacs-Lisp key bindings.")
(unless pp-read-expression-map
  (let ((map  (make-sparse-keymap)))
    (define-key map "\M-\t" 'lisp-indent-line)
    (define-key map "\t" 'lisp-complete-symbol)
    (define-key map "\e\C-q" 'indent-sexp)
    (define-key map "\e\t" 'lisp-indent-line)
    (define-key map "\e\C-x" 'eval-defun)
    (define-key map "\e\C-q" 'indent-pp-sexp)
    ;;(define-key map "\177" 'backward-delete-char-untabify)
    (set-keymap-parent map minibuffer-local-map)
    (setq pp-read-expression-map  map)))

;;;###autoload
(defcustom pp-eval-expression-print-circle nil
  "*Value for `print-circle' while printing value in `pp-eval-expression'.
Non-nil means print recursive structures using #N= and #N# syntax."
  :group 'pp :group 'lisp :type 'boolean)

;;;###autoload
(defcustom pp-eval-expression-print-length nil
  "*Value for `print-length' while printing value in `pp-eval-expression'.
A value of nil means no limit."
  :group 'pp :group 'lisp :type '(choice (const :tag "No Limit" nil) integer))

;;;###autoload
(defcustom pp-eval-expression-print-level nil
  "*Value for `print-level' while printing value in `pp-eval-expression'.
A value of nil means no limit."
  :group 'pp :group 'lisp :type '(choice (const :tag "No Limit" nil) integer))

;; Only difference is `pp-read-expression-map' instead of `read-expression-map'.
(when (fboundp 'read--expression)       ; Emacs 24.4+

  (defun pp-read--expression (prompt &optional initial-contents)
    (let ((minibuffer-completing-symbol t))
      (minibuffer-with-setup-hook
       (lambda ()                       ; Vanilla Emacs FIXME: call `emacs-lisp-mode'?
         (add-function :before-until (local 'eldoc-documentation-function)
                       #'elisp-eldoc-documentation-function)
         (eldoc-mode 1)
         (add-hook 'completion-at-point-functions
                   #'elisp-completion-at-point nil t)
         (run-hooks 'eval-expression-minibuffer-setup-hook))
       (read-from-minibuffer prompt initial-contents
                             pp-read-expression-map t 'read-expression-history)))))

(when (fboundp 'window-inside-absolute-pixel-edges) ; Emacs 24+

  (defcustom pp-max-tooltip-size nil
    "Max size for showing pretty-printed values in a tooltip at point.
The value can be:

* A cons that has the same form as `x-max-tooltip-size':
  (WIDTH . HEIGHT), where WIDTH is the max width of the tooltip in
  chars and HEIGHT is the max height in chars.  If the value to be
  printed cannot fit in a tooltip this large then it is shown in
  buffer `*Pp Eval Output*'.

* nil, meaning never use a tooltip.

* t, meaning use a tooltip but clip the value to `x-max-tooltip-size'.

Note: Regardless of the option value, a tooltip is not used if point
is off-screen when pretty-printing is called for.  This can happen,
for instance, if pretty-printing the result of evaluating an
expression that moves point off-screen."
    :type `(choice
            (const :tag "Do not use a tooltip" nil)
            (const :tag "Always use a tooltip, and clip value if too big" t)
            (cons  :tag "Use a tooltip only if smaller than WIDTH x HEIGHT"
                   (integer :tag "Width (characters)"  :value ,(car x-max-tooltip-size))
                   (integer :tag "Height (characters)" :value ,(cdr x-max-tooltip-size))))
    :group 'pp :group 'lisp)

  (defface pp-tooltip
      '((((class color))
         :background "lightyellow"
         :foreground "black"
         :family     "Courier")
        (t
         :family     "Courier"))
    "Face for `pp-show-tooltip'."
    :group 'tooltip)

  (defun pp-tooltip-show (text &optional use-echo-area face)
    "Show TEXT according to option `pp-max-tooltip-size'.
Optional arg USE-ECHO-AREA non-nil means show TEXT in the echo area
 instead of in a tooltip.
Optional arg FACE defaults to `pp-tooltip'."
    (setq face  (or face  'pp-tooltip))
    (if use-echo-area                   ; Not used in code here.
        (tooltip-show-help-non-mode text)
      (condition-case error
          (let ((params  (copy-sequence tooltip-frame-parameters))
                (fg      (face-attribute face :foreground))
                (bg      (face-attribute face :background)))
            (when (stringp fg)
              (setq params  (tooltip-set-param params 'foreground-color fg)
                    params  (tooltip-set-param params 'border-color     fg)))
            (when (stringp bg)
              (setq params  (tooltip-set-param params 'background-color bg)))
            (x-show-tip (propertize text 'face face)
                        (selected-frame)
                        params
                        tooltip-hide-delay
                        tooltip-x-offset
                        tooltip-y-offset))
        (error (message "Error while displaying tooltip: %s" error)
               (sit-for 1)
               (message "%s" text)))))

  (defun pp-show-tooltip (value)
    "Show Lisp VALUE in a tooltip at point using face `pp-tooltip'."
    (save-excursion
      (let* ((posn-at-pt                (posn-at-point))
             (x-y                       (and posn-at-pt  (posn-x-y posn-at-pt)))
             (win-edges                 (and x-y  (window-inside-absolute-pixel-edges)))
             (left                      (and x-y  (+ (car x-y) (car win-edges))))
             (top                       (and x-y  (+ (cdr x-y) (cadr win-edges))))
             (tooltip-frame-parameters  `((name . "tooltip")
                                          (internal-border-width . 2)
                                          (border-width . 1)
                                          (left ,@ left)
                                          (top  ,@ top)))
             (print-length              pp-eval-expression-print-length)
             (print-level               pp-eval-expression-print-level)
             (print-circle              pp-eval-expression-print-circle))
        (pp-tooltip-show (pp-to-string value))
        value)))

  (defun pp-expression-size (value buffer)
    "Return the size in characters needed to pretty-print Lisp VALUE.
Pretty-print VALUE in BUFFER in a temporary invisible frame, then
return the value of `posn-col-row'.  If the value is non-`nil', it is
a cons (COLUMNS . ROWS) of the rectangle needed for the result of
pretty-printing."
    (save-excursion
      (let ((buf  (get-buffer-create buffer))
            posn)
        (with-current-buffer buf
          (erase-buffer)
          (let* ((special-display-buffer-names  ())
                 (special-display-regexps       ())
                 (invis-frame                   (make-frame '((visibility . nil))))
                 (win                           (display-buffer buf nil invis-frame)))
            (pp value buf)
            (with-selected-frame invis-frame
              (select-window win)
              (goto-char (point-max))
              (setq posn  (posn-at-point))
              (prog1 (and posn  (posn-col-row posn))
                (delete-frame))))))))

  (defun pp-eval-expression-with-tooltip (expression &optional insert-value)
    "This is `pp-eval-expression', but using a tooltip when possible.
This is `pp-eval-expression' with `pp-max-tooltip-size' bound to
`x-max-tooltip-size'.  A printed value larger than this is shown in
buffer `*Pp Eval Output*'."
    (interactive
     (list (if (fboundp 'pp-read--expression)
               (pp-read--expression "Eval: ")
             (read-from-minibuffer "Eval: " nil pp-read-expression-map t 'read-expression-history))
           current-prefix-arg))
    (let ((pp-max-tooltip-size  x-max-tooltip-size))
      (pp-eval-expression expression insert-value)))

  (defun pp-eval-expression-without-tooltip (expression &optional insert-value)
    "This is `pp-eval-expression', but never using a tooltip.
This is `pp-eval-expression' with `pp-max-tooltip-size' bound to `nil'."
    (interactive
     (list (if (fboundp 'pp-read--expression)
               (pp-read--expression "Eval: ")
             (read-from-minibuffer "Eval: " nil pp-read-expression-map t 'read-expression-history))
           current-prefix-arg))
    (let ((pp-max-tooltip-size  nil))
      (pp-eval-expression expression insert-value)))

  (defun pp-eval-last-sexp-with-tooltip (arg)
    "Run `pp-eval-expression-with-tooltip' on the sexp before point.
This is `pp-eval-last-sexp' with `pp-max-tooltip-size' bound to
`x-max-tooltip-size'.  A printed value larger than this is shown in
buffer `*Pp Eval Output*'."
    (interactive "P")
    (if arg
        (let ((print-length  pp-eval-expression-print-length)
              (print-level   pp-eval-expression-print-level)
              (print-circle  (and (boundp 'print-circle) ; Emacs 22+
                                  pp-eval-expression-print-circle)))
          (insert (pp-to-string (eval (pp-last-sexp) lexical-binding))))
      (let ((pp-max-tooltip-size  x-max-tooltip-size))
        (pp-eval-expression (pp-last-sexp)))))

  (defun pp-eval-last-sexp-without-tooltip (arg)
    "Run `pp-eval-expression-without-tooltip' on the sexp before point.
This is `pp-eval-expression' with `pp-max-tooltip-size' bound to `nil'."
    (interactive "P")
    (if arg
        (let ((print-length  pp-eval-expression-print-length)
              (print-level   pp-eval-expression-print-level)
              (print-circle  (and (boundp 'print-circle) ; Emacs 22+
                                  pp-eval-expression-print-circle)))
          (insert (pp-to-string (eval (pp-last-sexp) lexical-binding))))
      (let ((pp-max-tooltip-size  nil))
        (pp-eval-expression (pp-last-sexp)))))

  )


;; REPLACES ORIGINAL in `pp.el':
;; 1. Read with completion, using `pp-read-expression-map'.
;; 2. Progress message added.
;; 3. Added optional args: insertion behavior and swapping use of a tooltip.
;; 4. Respect `pp-eval-expression-print-length', `pp-eval-expression-print-level',
;;    `pp-max-tooltip-size', and `eval-expression-debug-on-error'.
;; 5. Adjusted to work in different Emacs releases.
;; 6. Return result of evaluation (it is also the car of variable `values').
;;
;;;###autoload
(defun pp-eval-expression (expression &optional insert-value swap-tooltip)
  "Read an Emacs-Lisp sexp, evaluate it, and pretty-print its value.
Add the value to the front of the variable `values'.
With no prefix arg, respect `pp-max-tooltip-size'.  If a tooltip is
 not used then if the value fits on one line (frame width) show it in
 the echo area.  Otherwise, show it in buffer `*Pp Eval Output*'.
With a zero prefix arg, this swaps the use of a tooltip according to
 `pp-max-tooltip-size': if that option is nil then a tooltip is used,
 and if non-nil a tooltip is not used.
With a non-zero prefix arg, insert the value into the current buffer
 at point.  If the prefix arg is negative and the value is a string
 then insert it into the buffer without double-quotes (`\"').

For Emacs prior to 24.4, the command has no support for a tooltip.
A zero prefix arg is then treated the same as a positive prefix arg.

Non-interactively:
 * Non-nil SWAP-TOOLTIP means swap the use of a tooltip.
 * Non-nil INSERT-VALUE is treated like a non-zero raw prefix arg:
   insert the value in the buffer (sans quotes if negative).

This command respects user options `pp-eval-expression-print-length',
`pp-eval-expression-print-level', `pp-max-tooltip-size', and
`eval-expression-debug-on-error'.

Emacs-Lisp mode completion and indentation bindings are in effect."
  (interactive
   (list (if (fboundp 'pp-read--expression)
             (pp-read--expression "Eval: ")
           (read-from-minibuffer "Eval: " nil pp-read-expression-map t 'read-expression-history))
         current-prefix-arg
         (zerop (prefix-numeric-value current-prefix-arg))))
  (if (and swap-tooltip  (fboundp 'pp-eval-expression-with-tooltip)) ; Emacs 24.4+
      (if (not pp-max-tooltip-size)
          (pp-eval-expression-with-tooltip expression)
        (pp-eval-expression-without-tooltip expression))
    (message "Evaluating...")
    (if (or (not (boundp 'eval-expression-debug-on-error))
            (null eval-expression-debug-on-error))
        (setq values  (cons (if (and (boundp 'lexical-binding)
                                     (> emacs-major-version 23)) ; Emacs 24+
                                (eval expression lexical-binding)
                              (eval expression))
                            values))
      (let ((old-value  (make-symbol "t"))
            new-value)
        ;; Bind `debug-on-error' to something unique so that we can
        ;; detect when evaled code changes it.
        (let ((debug-on-error  old-value))
          (setq values     (cons (eval expression) values)
                new-value  debug-on-error))
        ;; If evaled code has changed the value of `debug-on-error',
        ;; propagate that change to the global binding.
        (unless (eq old-value new-value)
          (setq debug-on-error  new-value))))
    (let ((print-length     pp-eval-expression-print-length)
          (print-level      pp-eval-expression-print-level)
          (deactivate-mark  nil))
      (cond (insert-value
             (message "Evaluating...done. Value inserted.")
             (setq insert-value  (prefix-numeric-value insert-value))
             (if (or (not (stringp (car values))) (wholenump insert-value))
                 (pp (car values) (current-buffer))
               (princ (car values) (current-buffer))))
            (t (pp-display-expression (car values) "*Pp Eval Output*")))
      (car values))))


;; REPLACES ORIGINAL in `pp.el':
;; 1. Added optional arg: swapping use of a tooltip.
;; 4. Respect `pp-eval-expression-print-length', `pp-eval-expression-print-level',
;;    `pp-max-tooltip-size', and `eval-expression-debug-on-error'.
;; 5. Adjusted to work in different Emacs releases.
;;
(when (fboundp 'pp-last-sexp)           ; Emacs 23+

  (defun pp-eval-last-sexp (insert-value &optional swap-tooltip)
    "Run `pp-eval-expression' on sexp before point.
With a zero prefix arg, this swaps the use of a tooltip according to
 `pp-max-tooltip-size': if that option is nil then a tooltip is used,
 and if non-nil a tooltip is not used.
With a non-zero prefix arg, pretty-print the value into the current
 buffer.
Ignores leading comment characters.

For Emacs prior to 24.4, the command has no support for a tooltip.
A zero prefix arg is then treated the same as a positive prefix arg.

Non-interactively:
 * Non-nil SWAP-TOOLTIP means swap the use of a tooltip.
 * Non-nil INSERT-VALUE is treated like a non-zero prefix arg:
   insert the value in the buffer.

This command respects user options `pp-eval-expression-print-length',
`pp-eval-expression-print-level', `pp-max-tooltip-size', and
`eval-expression-debug-on-error'."
    (interactive (list current-prefix-arg 
                       (zerop (prefix-numeric-value current-prefix-arg))))
    (if swap-tooltip
        (if (not pp-max-tooltip-size)
            (pp-eval-last-sexp-with-tooltip nil)
          (pp-eval-last-sexp-without-tooltip nil))
      (if insert-value
          (let ((print-length  pp-eval-expression-print-length)
                (print-level   pp-eval-expression-print-level)
                (print-circle  pp-eval-expression-print-circle))
            (insert (pp-to-string (eval (pp-last-sexp) lexical-binding))))
        (pp-eval-expression (pp-last-sexp)))))

  )


;; REPLACES ORIGINAL in `pp.el':
;;
;; 1. Respect `pp-max-tooltip-size'.
;; 2. Use no `emacs-lisp-mode-hook' or `change-major-mode-hook'.
;; 3. Call `font-lock-fontify-buffer'.
;; 4. Provide undo to buffer OUT-BUFFER-NAME.
;;
;;;###autoload
(defun pp-display-expression (expression out-buffer-name)
  "Prettify and show EXPRESSION, respecting option `pp-max-tooltip-size'.
If `pp-max-tooltip-size' is non-`nil' then show it with a tooltip.
Else, if there is room then show it in the echo-area.
Else show it in buffer OUT-BUFFER-NAME."
  (let* ((use-tooltip  (and (boundp 'pp-max-tooltip-size)  (eq pp-max-tooltip-size t))) ; Emacs 24+
         (sexp-size    (and (fboundp 'pp-show-tooltip) ; Emacs 24+
                            (not use-tooltip)
                            pp-max-tooltip-size
                            (pp-expression-size expression out-buffer-name)))
         (use-tooltip  (or use-tooltip  (and sexp-size
                                             (<= (car sexp-size) (car pp-max-tooltip-size))
                                             (<= (cdr sexp-size) (cdr pp-max-tooltip-size))))))
    (if (and use-tooltip  (save-excursion (posn-at-point))) ; Ensure that point is on-screen now.
        (progn (pp-show-tooltip expression)  (message nil))
      (let* ((old-show-function  temp-buffer-show-function)
             (temp-buffer-show-function
              `(lambda (buf)
                (with-current-buffer buf
                  (goto-char (point-min))
                  (end-of-line 1)
                  (if (or (< (1+ (point)) (point-max))
                          (>= (- (point) (point-min)) (frame-width)))
                      (let ((temp-buffer-show-function  ',old-show-function)
                            (old-selected               (selected-window))
                            (window                     (display-buffer buf)))
                        (goto-char (point-min)) ; Expected by some hooks ...
                        (make-frame-visible (window-frame window))
                        (unwind-protect
                             (progn (select-window window)  (run-hooks 'temp-buffer-show-hook))
                          (when (window-live-p old-selected) (select-window old-selected))
                          (message "Evaluating...done.  See buffer `%s'." ',out-buffer-name)))
                    (message "%s" (buffer-substring (point-min) (point))))))))
        (with-output-to-temp-buffer out-buffer-name
          (pp expression)
          (with-current-buffer standard-output
            (setq buffer-read-only  nil)
            (buffer-enable-undo)
            ;; Avoid `let'-binding because `change-major-mode-hook' is local.  IOW, avoid runtime
            ;; message: "Making change-major-mode-hook buffer-local while locally let-bound!"
            ;; Suggestion from Stefan M.: Set these hooks instead of binding, because they are not
            ;; permanent-local.  They are emptied and repopulated as needed by `emacs-lisp-mode'.
            (set (make-local-variable 'emacs-lisp-mode-hook) nil)
            (set (make-local-variable 'change-major-mode-hook) nil)
            (emacs-lisp-mode)
            (set (make-local-variable 'font-lock-verbose) nil)
            (font-lock-fontify-buffer)))))))

;;;;;;;;;;;;;;;;;;

(provide 'pp+)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; pp+.el ends here

^ permalink raw reply	[flat|nested] 2+ messages in thread

* bug#53592: 26.3; Bind `M-:' to `pp-eval-expression' and enhance output
  2022-01-27 23:35 bug#53592: 26.3; Bind `M-:' to `pp-eval-expression' and enhance output Drew Adams
@ 2022-01-28 11:04 ` ndame
  0 siblings, 0 replies; 2+ messages in thread
From: ndame @ 2022-01-28 11:04 UTC (permalink / raw)
  To: 53592@debbugs.gnu.org

[-- Attachment #1: Type: text/plain, Size: 644 bytes --]

You put too many things in the bug IMO. It's a lot. We talked about better eval output,
so this bug should be about that. The output.

Changing the output can be done in parallel to implementing syntax highlight which
the other bug is about. Mixing rebinding M-: here is just confusing things.

Like when you change a system you don't submit a single huge patch which changes
many things at once, because it's harder to see through. You submit multiple smaller
patches which are easier to digest. Similarly, bugs should have a narrower focus and
when that is done, then there can be a next bug about a some other change, etc.

Just my 2 cents..

[-- Attachment #2: Type: text/html, Size: 1420 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-01-28 11:04 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-27 23:35 bug#53592: 26.3; Bind `M-:' to `pp-eval-expression' and enhance output Drew Adams
2022-01-28 11:04 ` ndame

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).