diff options
| author | Stefan Monnier | 2023-07-13 19:00:51 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2023-07-13 19:00:51 -0400 |
| commit | 3ffb99f28f29cd98094f359ea316468572535aa0 (patch) | |
| tree | 52c98ac7315345ab2a811107d82a90c8711e8195 | |
| parent | ee4cc106b88879c86d08c6fcda06657fb15df0f1 (diff) | |
| download | emacs-3ffb99f28f29cd98094f359ea316468572535aa0.tar.gz emacs-3ffb99f28f29cd98094f359ea316468572535aa0.zip | |
cl-print: Put buttons on ellipses
Currently, in *Backtrace* we have a nice behavior for cl-printed objects
where they're truncated by default to a manageable size but we can click
on the "..." to expand them when needed.
The patch below moves that functionality to `cl-print.el` such
that it can be enjoyed "everywhere" (bug#64536). It also has the
benefit of simplifying the code since `backtrace.el` had to look for
ellipses in order to add buttons to them, whereas now we can put
the ellipses right when we write them.
* lisp/emacs-lisp/cl-print.el (cl-print-object-contents): Improve docstring.
(cl-print-expand-ellipsis-function): New var.
(cl-print--default-expand-ellipsis): New function.
(cl-print-expand-ellipsis): New command.
(cl-print-insert-ellipsis): Allow nil instead of 0 to mean "this elides
the whole object".
(cl-print-ellipsis): Move button type from `backtrace.el`.
(cl-print-propertize-ellipsis): Put a button.
(cl-print--expand-ellipsis): Rename from `cl-print-expand-ellipsis`.
(cl-print-to-string-with-limit): Allow new value t for `limit`.
* lisp/emacs-lisp/backtrace.el (backtrace--font-lock-keywords): Simplify.
(backtrace--match-ellipsis-in-string): Delete function.
(backtrace--change-button-skip): Adjust to new button type name.
(backtrace--expand-ellipsis): New function, extracted from
`backtrace-expand-ellipsis`.
(backtrace-expand-ellipsis): Delete function.
(backtrace-ellipsis): Move button type to `cl-print.el`.
(backtrace--print-to-string): Don't look for cl-print ellipses any more.
(backtrace-mode): Use `backtrace--expand-ellipsis`.
* lisp/ielm.el (ielm--expand-ellipsis): New function.
(inferior-emacs-lisp-mode): Use it to fill the data when expanded.
* test/lisp/emacs-lisp/cl-print-tests.el
(cl-print-tests-check-ellipsis-expansion)
(cl-print-tests-check-ellipsis-expansion-rx): Adjust to new internal
function name.
| -rw-r--r-- | etc/NEWS | 4 | ||||
| -rw-r--r-- | etc/NEWS.26 | 2 | ||||
| -rw-r--r-- | lisp/button.el | 2 | ||||
| -rw-r--r-- | lisp/emacs-lisp/backtrace.el | 67 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-print.el | 104 | ||||
| -rw-r--r-- | lisp/ielm.el | 7 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/cl-print-tests.el | 5 |
7 files changed, 108 insertions, 83 deletions
| @@ -92,6 +92,10 @@ plus, minus, check-mark, start, etc. | |||
| 92 | The 'tool-bar-position' frame parameter can be set to 'bottom' on all | 92 | The 'tool-bar-position' frame parameter can be set to 'bottom' on all |
| 93 | window systems other than Nextstep. | 93 | window systems other than Nextstep. |
| 94 | 94 | ||
| 95 | ** You can expand the "..." truncation everywhere. | ||
| 96 | The code that allowed "..." to be expanded in the *Backtrace* should | ||
| 97 | now work anywhere the data is generated by `cl-print`. | ||
| 98 | |||
| 95 | ** Modeline elements can now be right-aligned. | 99 | ** Modeline elements can now be right-aligned. |
| 96 | Anything following the symbol 'mode-line-format-right-align' in | 100 | Anything following the symbol 'mode-line-format-right-align' in |
| 97 | 'mode-line-format' will be right-aligned. Exactly where it is | 101 | 'mode-line-format' will be right-aligned. Exactly where it is |
diff --git a/etc/NEWS.26 b/etc/NEWS.26 index 1692e23483c..29eee5eb4a2 100644 --- a/etc/NEWS.26 +++ b/etc/NEWS.26 | |||
| @@ -1927,6 +1927,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | |||
| 1927 | 1927 | ||
| 1928 | Local variables: | 1928 | Local variables: |
| 1929 | coding: utf-8 | 1929 | coding: utf-8 |
| 1930 | mode: outline | 1930 | mode: emacs-news |
| 1931 | paragraph-separate: "[ ]*$" | 1931 | paragraph-separate: "[ ]*$" |
| 1932 | end: | 1932 | end: |
diff --git a/lisp/button.el b/lisp/button.el index f043073ea86..002064fbea0 100644 --- a/lisp/button.el +++ b/lisp/button.el | |||
| @@ -123,7 +123,7 @@ argument). | |||
| 123 | 123 | ||
| 124 | In addition, the keyword argument :supertype may be used to specify a | 124 | In addition, the keyword argument :supertype may be used to specify a |
| 125 | `button-type' from which NAME inherits its default property values | 125 | `button-type' from which NAME inherits its default property values |
| 126 | (however, the inheritance happens only when NAME is defined; subsequent | 126 | \(however, the inheritance happens only when NAME is defined; subsequent |
| 127 | changes to a supertype are not reflected in its subtypes)." | 127 | changes to a supertype are not reflected in its subtypes)." |
| 128 | (declare (indent defun)) | 128 | (declare (indent defun)) |
| 129 | (let ((catsym (make-symbol (concat (symbol-name name) "-button"))) | 129 | (let ((catsym (make-symbol (concat (symbol-name name) "-button"))) |
diff --git a/lisp/emacs-lisp/backtrace.el b/lisp/emacs-lisp/backtrace.el index 57912c854b0..af06577fe56 100644 --- a/lisp/emacs-lisp/backtrace.el +++ b/lisp/emacs-lisp/backtrace.el | |||
| @@ -135,8 +135,7 @@ frames before its nearest activation frame are discarded." | |||
| 135 | ;; Font Locking support | 135 | ;; Font Locking support |
| 136 | 136 | ||
| 137 | (defconst backtrace--font-lock-keywords | 137 | (defconst backtrace--font-lock-keywords |
| 138 | '((backtrace--match-ellipsis-in-string | 138 | '() |
| 139 | (1 'button prepend))) | ||
| 140 | "Expressions to fontify in Backtrace mode. | 139 | "Expressions to fontify in Backtrace mode. |
| 141 | Fontify these in addition to the expressions Emacs Lisp mode | 140 | Fontify these in addition to the expressions Emacs Lisp mode |
| 142 | fontifies.") | 141 | fontifies.") |
| @@ -154,16 +153,6 @@ fontifies.") | |||
| 154 | backtrace--font-lock-keywords) | 153 | backtrace--font-lock-keywords) |
| 155 | "Gaudy level highlighting for Backtrace mode.") | 154 | "Gaudy level highlighting for Backtrace mode.") |
| 156 | 155 | ||
| 157 | (defun backtrace--match-ellipsis-in-string (bound) | ||
| 158 | ;; Fontify ellipses within strings as buttons. | ||
| 159 | ;; This is necessary because ellipses are text property buttons | ||
| 160 | ;; instead of overlay buttons, which is done because there could | ||
| 161 | ;; be a large number of them. | ||
| 162 | (when (re-search-forward "\\(\\.\\.\\.\\)\"" bound t) | ||
| 163 | (and (get-text-property (- (point) 2) 'cl-print-ellipsis) | ||
| 164 | (get-text-property (- (point) 3) 'cl-print-ellipsis) | ||
| 165 | (get-text-property (- (point) 4) 'cl-print-ellipsis)))) | ||
| 166 | |||
| 167 | ;;; Xref support | 156 | ;;; Xref support |
| 168 | 157 | ||
| 169 | (defun backtrace--xref-backend () 'elisp) | 158 | (defun backtrace--xref-backend () 'elisp) |
| @@ -425,11 +414,11 @@ the buffer." | |||
| 425 | 414 | ||
| 426 | (defun backtrace--change-button-skip (beg end value) | 415 | (defun backtrace--change-button-skip (beg end value) |
| 427 | "Change the skip property on all buttons between BEG and END. | 416 | "Change the skip property on all buttons between BEG and END. |
| 428 | Set it to VALUE unless the button is a `backtrace-ellipsis' button." | 417 | Set it to VALUE unless the button is a `cl-print-ellipsis' button." |
| 429 | (let ((inhibit-read-only t)) | 418 | (let ((inhibit-read-only t)) |
| 430 | (setq beg (next-button beg)) | 419 | (setq beg (next-button beg)) |
| 431 | (while (and beg (< beg end)) | 420 | (while (and beg (< beg end)) |
| 432 | (unless (eq (button-type beg) 'backtrace-ellipsis) | 421 | (unless (eq (button-type beg) cl-print-ellipsis) |
| 433 | (button-put beg 'skip value)) | 422 | (button-put beg 'skip value)) |
| 434 | (setq beg (next-button beg))))) | 423 | (setq beg (next-button beg))))) |
| 435 | 424 | ||
| @@ -497,33 +486,15 @@ Reprint the frame with the new view plist." | |||
| 497 | `(backtrace-index ,index backtrace-view ,view)) | 486 | `(backtrace-index ,index backtrace-view ,view)) |
| 498 | (goto-char min))) | 487 | (goto-char min))) |
| 499 | 488 | ||
| 500 | (defun backtrace-expand-ellipsis (button) | 489 | (defun backtrace--expand-ellipsis (orig-fun begin end val _length &rest args) |
| 501 | "Expand display of the elided form at BUTTON." | 490 | "Wrapper to expand an ellipsis. |
| 502 | (goto-char (button-start button)) | 491 | For use on `cl-print-expand-ellipsis-function'." |
| 503 | (unless (get-text-property (point) 'cl-print-ellipsis) | 492 | (let* ((props (backtrace-get-text-properties begin)) |
| 504 | (if (and (> (point) (point-min)) | ||
| 505 | (get-text-property (1- (point)) 'cl-print-ellipsis)) | ||
| 506 | (backward-char) | ||
| 507 | (user-error "No ellipsis to expand here"))) | ||
| 508 | (let* ((end (next-single-property-change (point) 'cl-print-ellipsis)) | ||
| 509 | (begin (previous-single-property-change end 'cl-print-ellipsis)) | ||
| 510 | (value (get-text-property begin 'cl-print-ellipsis)) | ||
| 511 | (props (backtrace-get-text-properties begin)) | ||
| 512 | (inhibit-read-only t)) | 493 | (inhibit-read-only t)) |
| 513 | (backtrace--with-output-variables (backtrace-get-view) | 494 | (backtrace--with-output-variables (backtrace-get-view) |
| 514 | (delete-region begin end) | 495 | (let ((end (apply orig-fun begin end val backtrace-line-length args))) |
| 515 | (insert (cl-print-to-string-with-limit #'cl-print-expand-ellipsis value | 496 | (add-text-properties begin end props) |
| 516 | backtrace-line-length)) | 497 | end)))) |
| 517 | (setq end (point)) | ||
| 518 | (goto-char begin) | ||
| 519 | (while (< (point) end) | ||
| 520 | (let ((next (next-single-property-change (point) 'cl-print-ellipsis | ||
| 521 | nil end))) | ||
| 522 | (when (get-text-property (point) 'cl-print-ellipsis) | ||
| 523 | (make-text-button (point) next :type 'backtrace-ellipsis)) | ||
| 524 | (goto-char next))) | ||
| 525 | (goto-char begin) | ||
| 526 | (add-text-properties begin end props)))) | ||
| 527 | 498 | ||
| 528 | (defun backtrace-expand-ellipses (&optional no-limit) | 499 | (defun backtrace-expand-ellipses (&optional no-limit) |
| 529 | "Expand display of all \"...\"s in the backtrace frame at point. | 500 | "Expand display of all \"...\"s in the backtrace frame at point. |
| @@ -696,13 +667,6 @@ line and recenter window line accordingly." | |||
| 696 | (recenter window-line))) | 667 | (recenter window-line))) |
| 697 | (goto-char (point-min))))) | 668 | (goto-char (point-min))))) |
| 698 | 669 | ||
| 699 | ;; Define button type used for ...'s. | ||
| 700 | ;; Set skip property so you don't have to TAB through 100 of them to | ||
| 701 | ;; get to the next function name. | ||
| 702 | (define-button-type 'backtrace-ellipsis | ||
| 703 | 'skip t 'action #'backtrace-expand-ellipsis | ||
| 704 | 'help-echo "mouse-2, RET: expand this ellipsis") | ||
| 705 | |||
| 706 | (defun backtrace-print-to-string (obj &optional limit) | 670 | (defun backtrace-print-to-string (obj &optional limit) |
| 707 | "Return a printed representation of OBJ formatted for backtraces. | 671 | "Return a printed representation of OBJ formatted for backtraces. |
| 708 | Attempt to get the length of the returned string under LIMIT | 672 | Attempt to get the length of the returned string under LIMIT |
| @@ -719,15 +683,6 @@ characters with appropriate settings of `print-level' and | |||
| 719 | (insert (cl-print-to-string-with-limit #'backtrace--print sexp limit)) | 683 | (insert (cl-print-to-string-with-limit #'backtrace--print sexp limit)) |
| 720 | ;; Add a unique backtrace-form property. | 684 | ;; Add a unique backtrace-form property. |
| 721 | (put-text-property (point-min) (point) 'backtrace-form (gensym)) | 685 | (put-text-property (point-min) (point) 'backtrace-form (gensym)) |
| 722 | ;; Make buttons from all the "..."s. Since there might be many of | ||
| 723 | ;; them, use text property buttons. | ||
| 724 | (goto-char (point-min)) | ||
| 725 | (while (< (point) (point-max)) | ||
| 726 | (let ((end (next-single-property-change (point) 'cl-print-ellipsis | ||
| 727 | nil (point-max)))) | ||
| 728 | (when (get-text-property (point) 'cl-print-ellipsis) | ||
| 729 | (make-text-button (point) end :type 'backtrace-ellipsis)) | ||
| 730 | (goto-char end))) | ||
| 731 | (buffer-string))) | 686 | (buffer-string))) |
| 732 | 687 | ||
| 733 | (defun backtrace-print-frame (frame view) | 688 | (defun backtrace-print-frame (frame view) |
| @@ -918,6 +873,8 @@ followed by `backtrace-print-frame', once for each stack frame." | |||
| 918 | (setq-local filter-buffer-substring-function #'backtrace--filter-visible) | 873 | (setq-local filter-buffer-substring-function #'backtrace--filter-visible) |
| 919 | (setq-local indent-line-function 'lisp-indent-line) | 874 | (setq-local indent-line-function 'lisp-indent-line) |
| 920 | (setq-local indent-region-function 'lisp-indent-region) | 875 | (setq-local indent-region-function 'lisp-indent-region) |
| 876 | (add-function :around (local 'cl-print-expand-ellipsis-function) | ||
| 877 | #'backtrace--expand-ellipsis) | ||
| 921 | (add-hook 'xref-backend-functions #'backtrace--xref-backend nil t)) | 878 | (add-hook 'xref-backend-functions #'backtrace--xref-backend nil t)) |
| 922 | 879 | ||
| 923 | (put 'backtrace-mode 'mode-class 'special) | 880 | (put 'backtrace-mode 'mode-class 'special) |
diff --git a/lisp/emacs-lisp/cl-print.el b/lisp/emacs-lisp/cl-print.el index 9578d556421..905c2bc9f09 100644 --- a/lisp/emacs-lisp/cl-print.el +++ b/lisp/emacs-lisp/cl-print.el | |||
| @@ -54,9 +54,12 @@ call other entry points instead, such as `cl-prin1'." | |||
| 54 | (prin1 object stream)) | 54 | (prin1 object stream)) |
| 55 | 55 | ||
| 56 | (cl-defgeneric cl-print-object-contents (_object _start _stream) | 56 | (cl-defgeneric cl-print-object-contents (_object _start _stream) |
| 57 | "Dispatcher to print the contents of OBJECT on STREAM. | 57 | "Dispatcher to print partial contents of OBJECT on STREAM. |
| 58 | Print the contents starting with the item at START, without | 58 | This is used when replacing an ellipsis with the contents it |
| 59 | delimiters." | 59 | represents. OBJECT is the object that has been partially printed |
| 60 | and START represents the place at which the contents where | ||
| 61 | replaced with an ellipsis. | ||
| 62 | Print the contents hidden by the ellipsis to STREAM." | ||
| 60 | ;; Every cl-print-object method which can print an ellipsis should | 63 | ;; Every cl-print-object method which can print an ellipsis should |
| 61 | ;; have a matching cl-print-object-contents method to expand an | 64 | ;; have a matching cl-print-object-contents method to expand an |
| 62 | ;; ellipsis. | 65 | ;; ellipsis. |
| @@ -65,7 +68,7 @@ delimiters." | |||
| 65 | (cl-defmethod cl-print-object ((object cons) stream) | 68 | (cl-defmethod cl-print-object ((object cons) stream) |
| 66 | (if (and cl-print--depth (natnump print-level) | 69 | (if (and cl-print--depth (natnump print-level) |
| 67 | (> cl-print--depth print-level)) | 70 | (> cl-print--depth print-level)) |
| 68 | (cl-print-insert-ellipsis object 0 stream) | 71 | (cl-print-insert-ellipsis object nil stream) |
| 69 | (let ((car (pop object))) | 72 | (let ((car (pop object))) |
| 70 | (if (and print-quoted | 73 | (if (and print-quoted |
| 71 | (memq car '(\, quote function \` \,@ \,.)) | 74 | (memq car '(\, quote function \` \,@ \,.)) |
| @@ -107,7 +110,7 @@ delimiters." | |||
| 107 | (cl-defmethod cl-print-object ((object vector) stream) | 110 | (cl-defmethod cl-print-object ((object vector) stream) |
| 108 | (if (and cl-print--depth (natnump print-level) | 111 | (if (and cl-print--depth (natnump print-level) |
| 109 | (> cl-print--depth print-level)) | 112 | (> cl-print--depth print-level)) |
| 110 | (cl-print-insert-ellipsis object 0 stream) | 113 | (cl-print-insert-ellipsis object nil stream) |
| 111 | (princ "[" stream) | 114 | (princ "[" stream) |
| 112 | (cl-print--vector-contents object 0 stream) | 115 | (cl-print--vector-contents object 0 stream) |
| 113 | (princ "]" stream))) | 116 | (princ "]" stream))) |
| @@ -129,6 +132,8 @@ delimiters." | |||
| 129 | (cl-print--vector-contents object start stream)) ;FIXME: η-redex! | 132 | (cl-print--vector-contents object start stream)) ;FIXME: η-redex! |
| 130 | 133 | ||
| 131 | (cl-defmethod cl-print-object ((object hash-table) stream) | 134 | (cl-defmethod cl-print-object ((object hash-table) stream) |
| 135 | ;; FIXME: Make it possible to see the contents, like `prin1' does, | ||
| 136 | ;; e.g. using ellipsis. Make sure `cl-fill' can pretty print the result! | ||
| 132 | (princ "#<hash-table " stream) | 137 | (princ "#<hash-table " stream) |
| 133 | (princ (hash-table-test object) stream) | 138 | (princ (hash-table-test object) stream) |
| 134 | (princ " " stream) | 139 | (princ " " stream) |
| @@ -158,6 +163,9 @@ into a button whose action shows the function's disassembly.") | |||
| 158 | 163 | ||
| 159 | (autoload 'disassemble-1 "disass") | 164 | (autoload 'disassemble-1 "disass") |
| 160 | 165 | ||
| 166 | ;; FIXME: Don't degenerate to `prin1' for the contents of char-tables | ||
| 167 | ;; and records! | ||
| 168 | |||
| 161 | (cl-defmethod cl-print-object ((object compiled-function) stream) | 169 | (cl-defmethod cl-print-object ((object compiled-function) stream) |
| 162 | (unless stream (setq stream standard-output)) | 170 | (unless stream (setq stream standard-output)) |
| 163 | ;; We use "#f(...)" rather than "#<...>" so that pp.el gives better results. | 171 | ;; We use "#f(...)" rather than "#<...>" so that pp.el gives better results. |
| @@ -212,7 +220,7 @@ into a button whose action shows the function's disassembly.") | |||
| 212 | (cl-defmethod cl-print-object ((object cl-structure-object) stream) | 220 | (cl-defmethod cl-print-object ((object cl-structure-object) stream) |
| 213 | (if (and cl-print--depth (natnump print-level) | 221 | (if (and cl-print--depth (natnump print-level) |
| 214 | (> cl-print--depth print-level)) | 222 | (> cl-print--depth print-level)) |
| 215 | (cl-print-insert-ellipsis object 0 stream) | 223 | (cl-print-insert-ellipsis object nil stream) |
| 216 | (princ "#s(" stream) | 224 | (princ "#s(" stream) |
| 217 | (princ (cl--struct-class-name (cl-find-class (type-of object))) stream) | 225 | (princ (cl--struct-class-name (cl-find-class (type-of object))) stream) |
| 218 | (cl-print--struct-contents object 0 stream) | 226 | (cl-print--struct-contents object 0 stream) |
| @@ -250,7 +258,7 @@ into a button whose action shows the function's disassembly.") | |||
| 250 | cl-print--depth | 258 | cl-print--depth |
| 251 | (natnump print-level) | 259 | (natnump print-level) |
| 252 | (> cl-print--depth print-level)) | 260 | (> cl-print--depth print-level)) |
| 253 | (cl-print-insert-ellipsis object 0 stream) | 261 | (cl-print-insert-ellipsis object nil stream) |
| 254 | ;; Print all or part of the string | 262 | ;; Print all or part of the string |
| 255 | (when has-properties | 263 | (when has-properties |
| 256 | (princ "#(" stream)) | 264 | (princ "#(" stream)) |
| @@ -325,6 +333,7 @@ into a button whose action shows the function's disassembly.") | |||
| 325 | (cl-defmethod cl-print-object :around (object stream) | 333 | (cl-defmethod cl-print-object :around (object stream) |
| 326 | ;; FIXME: Only put such an :around method on types where it's relevant. | 334 | ;; FIXME: Only put such an :around method on types where it's relevant. |
| 327 | (let ((cl-print--depth (if cl-print--depth (1+ cl-print--depth) 1))) | 335 | (let ((cl-print--depth (if cl-print--depth (1+ cl-print--depth) 1))) |
| 336 | ;; FIXME: Handle print-level here once and forall? | ||
| 328 | (cond | 337 | (cond |
| 329 | (print-circle | 338 | (print-circle |
| 330 | (let ((n (gethash object cl-print--number-table))) | 339 | (let ((n (gethash object cl-print--number-table))) |
| @@ -401,10 +410,53 @@ into a button whose action shows the function's disassembly.") | |||
| 401 | (cl-print--find-sharing object print-number-table))) | 410 | (cl-print--find-sharing object print-number-table))) |
| 402 | print-number-table)) | 411 | print-number-table)) |
| 403 | 412 | ||
| 413 | (define-button-type 'cl-print-ellipsis | ||
| 414 | 'skip t 'action #'cl-print-expand-ellipsis | ||
| 415 | 'help-echo "mouse-2, RET: expand this ellipsis") | ||
| 416 | |||
| 417 | (defvar cl-print-expand-ellipsis-function | ||
| 418 | #'cl-print--default-expand-ellipsis | ||
| 419 | "Function to tweak the way ellipses are expanded. | ||
| 420 | The function is called with 3 arguments, BEG, END, and FUNC. | ||
| 421 | BEG and END delimit the ellipsis that will be replaced. | ||
| 422 | FUNC is the function that will do the expansion. | ||
| 423 | It should be called with a single argument specifying the desired | ||
| 424 | limit of the expansion's length, as used in `cl-print-to-string-with-limit'. | ||
| 425 | FUNC will return the position of the end of the newly printed text.") | ||
| 426 | |||
| 427 | (defun cl-print--default-expand-ellipsis (begin end value line-length) | ||
| 428 | (delete-region begin end) | ||
| 429 | (insert (cl-print-to-string-with-limit | ||
| 430 | #'cl-print--expand-ellipsis value line-length)) | ||
| 431 | (point)) | ||
| 432 | |||
| 433 | |||
| 434 | (defun cl-print-expand-ellipsis (&optional button) | ||
| 435 | "Expand display of the elided form at BUTTON. | ||
| 436 | BUTTON can also be a buffer position or nil (to mean point)." | ||
| 437 | (interactive) | ||
| 438 | (goto-char (cond | ||
| 439 | ((null button) (point)) | ||
| 440 | (t (button-start button)))) | ||
| 441 | (unless (get-text-property (point) 'cl-print-ellipsis) | ||
| 442 | (if (and (> (point) (point-min)) | ||
| 443 | (get-text-property (1- (point)) 'cl-print-ellipsis)) | ||
| 444 | (backward-char) | ||
| 445 | (user-error "No ellipsis to expand here"))) | ||
| 446 | (let* ((end (next-single-property-change (point) 'cl-print-ellipsis)) | ||
| 447 | (begin (previous-single-property-change end 'cl-print-ellipsis)) | ||
| 448 | (value (get-text-property begin 'cl-print-ellipsis))) | ||
| 449 | ;; FIXME: Rather than `t' (i.e. reuse the print-length/level unchanged), | ||
| 450 | ;; I think it would make sense to increase the level by 1 and to | ||
| 451 | ;; double the length at each expansion step. | ||
| 452 | (funcall cl-print-expand-ellipsis-function | ||
| 453 | begin end value t) | ||
| 454 | (goto-char begin))) | ||
| 455 | |||
| 404 | (defun cl-print-insert-ellipsis (object start stream) | 456 | (defun cl-print-insert-ellipsis (object start stream) |
| 405 | "Print \"...\" to STREAM with the `cl-print-ellipsis' text property. | 457 | "Print \"...\" to STREAM with the `cl-print-ellipsis' text property. |
| 406 | Save state in the text property in order to print the elided part | 458 | Save state in the text property in order to print the elided part |
| 407 | of OBJECT later. START should be 0 if the whole OBJECT is being | 459 | of OBJECT later. START should be nil if the whole OBJECT is being |
| 408 | elided, otherwise it should be an index or other pointer into the | 460 | elided, otherwise it should be an index or other pointer into the |
| 409 | internals of OBJECT which can be passed to | 461 | internals of OBJECT which can be passed to |
| 410 | `cl-print-object-contents' at a future time." | 462 | `cl-print-object-contents' at a future time." |
| @@ -423,11 +475,12 @@ STREAM should be a buffer. OBJECT and START are as described in | |||
| 423 | `cl-print-insert-ellipsis'." | 475 | `cl-print-insert-ellipsis'." |
| 424 | (let ((value (list object start cl-print--number-table | 476 | (let ((value (list object start cl-print--number-table |
| 425 | cl-print--currently-printing))) | 477 | cl-print--currently-printing))) |
| 478 | ;; FIXME: Make it into a button! | ||
| 426 | (with-current-buffer stream | 479 | (with-current-buffer stream |
| 427 | (put-text-property beg end 'cl-print-ellipsis value stream)))) | 480 | (put-text-property beg end 'cl-print-ellipsis value stream) |
| 481 | (make-text-button beg end :type 'cl-print-ellipsis)))) | ||
| 428 | 482 | ||
| 429 | ;;;###autoload | 483 | (defun cl-print--expand-ellipsis (value stream) |
| 430 | (defun cl-print-expand-ellipsis (value stream) | ||
| 431 | "Print the expansion of an ellipsis to STREAM. | 484 | "Print the expansion of an ellipsis to STREAM. |
| 432 | VALUE should be the value of the `cl-print-ellipsis' text property | 485 | VALUE should be the value of the `cl-print-ellipsis' text property |
| 433 | which was attached to the ellipsis by `cl-prin1'." | 486 | which was attached to the ellipsis by `cl-prin1'." |
| @@ -439,7 +492,7 @@ which was attached to the ellipsis by `cl-prin1'." | |||
| 439 | (cl-print--currently-printing (nth 3 value))) | 492 | (cl-print--currently-printing (nth 3 value))) |
| 440 | (when (eq object (car cl-print--currently-printing)) | 493 | (when (eq object (car cl-print--currently-printing)) |
| 441 | (pop cl-print--currently-printing)) | 494 | (pop cl-print--currently-printing)) |
| 442 | (if (equal start 0) | 495 | (if (memq start '(0 nil)) |
| 443 | (cl-print-object object stream) | 496 | (cl-print-object object stream) |
| 444 | (cl-print-object-contents object start stream)))) | 497 | (cl-print-object-contents object start stream)))) |
| 445 | 498 | ||
| @@ -474,22 +527,25 @@ characters with appropriate settings of `print-level' and | |||
| 474 | the arguments VALUE and STREAM and which should respect | 527 | the arguments VALUE and STREAM and which should respect |
| 475 | `print-length' and `print-level'. LIMIT may be nil or zero in | 528 | `print-length' and `print-level'. LIMIT may be nil or zero in |
| 476 | which case PRINT-FUNCTION will be called with `print-level' and | 529 | which case PRINT-FUNCTION will be called with `print-level' and |
| 477 | `print-length' bound to nil. | 530 | `print-length' bound to nil, and it can also be t in which case |
| 531 | PRINT-FUNCTION will be called with the current values of `print-level' | ||
| 532 | and `print-length'. | ||
| 478 | 533 | ||
| 479 | Use this function with `cl-prin1' to print an object, | 534 | Use this function with `cl-prin1' to print an object, |
| 480 | abbreviating it with ellipses to fit within a size limit. Use | 535 | abbreviating it with ellipses to fit within a size limit." |
| 481 | this function with `cl-prin1-expand-ellipsis' to expand an | 536 | (setq limit (and (not (eq limit 0)) limit)) |
| 482 | ellipsis, abbreviating the expansion to stay within a size | ||
| 483 | limit." | ||
| 484 | (setq limit (and (natnump limit) | ||
| 485 | (not (zerop limit)) | ||
| 486 | limit)) | ||
| 487 | ;; Since this is used by the debugger when stack space may be | 537 | ;; Since this is used by the debugger when stack space may be |
| 488 | ;; limited, if you increase print-level here, add more depth in | 538 | ;; limited, if you increase print-level here, add more depth in |
| 489 | ;; call_debugger (bug#31919). | 539 | ;; call_debugger (bug#31919). |
| 490 | (let* ((print-length (when limit (min limit 50))) | 540 | (let* ((print-length (cond |
| 491 | (print-level (when limit (min 8 (truncate (log limit))))) | 541 | ((null limit) nil) |
| 492 | (delta-length (when limit | 542 | ((eq limit t) print-length) |
| 543 | (t (min limit 50)))) | ||
| 544 | (print-level (cond | ||
| 545 | ((null limit) nil) | ||
| 546 | ((eq limit t) print-level) | ||
| 547 | (t (min 8 (truncate (log limit)))))) | ||
| 548 | (delta-length (when (natnump limit) | ||
| 493 | (max 1 (truncate (/ print-length print-level)))))) | 549 | (max 1 (truncate (/ print-length print-level)))))) |
| 494 | (with-temp-buffer | 550 | (with-temp-buffer |
| 495 | (catch 'done | 551 | (catch 'done |
| @@ -499,7 +555,7 @@ limit." | |||
| 499 | (let ((result (- (point-max) (point-min)))) | 555 | (let ((result (- (point-max) (point-min)))) |
| 500 | ;; Stop when either print-level is too low or the value is | 556 | ;; Stop when either print-level is too low or the value is |
| 501 | ;; successfully printed in the space allowed. | 557 | ;; successfully printed in the space allowed. |
| 502 | (when (or (not limit) (< result limit) (<= print-level 2)) | 558 | (when (or (not (natnump limit)) (< result limit) (<= print-level 2)) |
| 503 | (throw 'done (buffer-string))) | 559 | (throw 'done (buffer-string))) |
| 504 | (let* ((ratio (/ result limit)) | 560 | (let* ((ratio (/ result limit)) |
| 505 | (delta-level (max 1 (min (- print-level 2) ratio)))) | 561 | (delta-level (max 1 (min (- print-level 2) ratio)))) |
diff --git a/lisp/ielm.el b/lisp/ielm.el index 5c370733c05..01550de71b5 100644 --- a/lisp/ielm.el +++ b/lisp/ielm.el | |||
| @@ -500,6 +500,11 @@ behavior of the indirect buffer." | |||
| 500 | "Run `ielm-indirect-setup-hook'." | 500 | "Run `ielm-indirect-setup-hook'." |
| 501 | (run-hooks 'ielm-indirect-setup-hook)) | 501 | (run-hooks 'ielm-indirect-setup-hook)) |
| 502 | 502 | ||
| 503 | (defun ielm--expand-ellipsis (orig-fun beg &rest args) | ||
| 504 | (let ((end (copy-marker (apply orig-fun beg args) t))) | ||
| 505 | (funcall pp-default-function beg end) | ||
| 506 | end)) | ||
| 507 | |||
| 503 | ;;; Major mode | 508 | ;;; Major mode |
| 504 | 509 | ||
| 505 | (define-derived-mode inferior-emacs-lisp-mode comint-mode "IELM" | 510 | (define-derived-mode inferior-emacs-lisp-mode comint-mode "IELM" |
| @@ -582,6 +587,8 @@ Customized bindings may be defined in `ielm-map', which currently contains: | |||
| 582 | (setq-local comment-use-syntax t) | 587 | (setq-local comment-use-syntax t) |
| 583 | (setq-local lexical-binding t) | 588 | (setq-local lexical-binding t) |
| 584 | 589 | ||
| 590 | (add-function :around (local 'cl-print-expand-ellipsis-function) | ||
| 591 | #'ielm--expand-ellipsis) | ||
| 585 | (setq-local indent-line-function #'ielm-indent-line) | 592 | (setq-local indent-line-function #'ielm-indent-line) |
| 586 | (setq-local ielm-working-buffer (current-buffer)) | 593 | (setq-local ielm-working-buffer (current-buffer)) |
| 587 | (setq-local fill-paragraph-function #'lisp-fill-paragraph) | 594 | (setq-local fill-paragraph-function #'lisp-fill-paragraph) |
diff --git a/test/lisp/emacs-lisp/cl-print-tests.el b/test/lisp/emacs-lisp/cl-print-tests.el index af94dae310c..3073a42e39d 100644 --- a/test/lisp/emacs-lisp/cl-print-tests.el +++ b/test/lisp/emacs-lisp/cl-print-tests.el | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | ;;; Code: | 25 | ;;; Code: |
| 26 | 26 | ||
| 27 | (require 'ert) | 27 | (require 'ert) |
| 28 | (require 'cl-print) | ||
| 28 | 29 | ||
| 29 | (cl-defstruct (cl-print-tests-struct | 30 | (cl-defstruct (cl-print-tests-struct |
| 30 | (:constructor cl-print-tests-con)) | 31 | (:constructor cl-print-tests-con)) |
| @@ -113,7 +114,7 @@ | |||
| 113 | (should pos) | 114 | (should pos) |
| 114 | (setq value (get-text-property pos 'cl-print-ellipsis result)) | 115 | (setq value (get-text-property pos 'cl-print-ellipsis result)) |
| 115 | (should (equal expected result)) | 116 | (should (equal expected result)) |
| 116 | (should (equal expanded (with-output-to-string (cl-print-expand-ellipsis | 117 | (should (equal expanded (with-output-to-string (cl-print--expand-ellipsis |
| 117 | value nil)))))) | 118 | value nil)))))) |
| 118 | 119 | ||
| 119 | (defun cl-print-tests-check-ellipsis-expansion-rx (obj expected expanded) | 120 | (defun cl-print-tests-check-ellipsis-expansion-rx (obj expected expanded) |
| @@ -122,7 +123,7 @@ | |||
| 122 | (value (get-text-property pos 'cl-print-ellipsis result))) | 123 | (value (get-text-property pos 'cl-print-ellipsis result))) |
| 123 | (should (string-match expected result)) | 124 | (should (string-match expected result)) |
| 124 | (should (string-match expanded (with-output-to-string | 125 | (should (string-match expanded (with-output-to-string |
| 125 | (cl-print-expand-ellipsis value nil)))))) | 126 | (cl-print--expand-ellipsis value nil)))))) |
| 126 | 127 | ||
| 127 | (ert-deftest cl-print-tests-print-to-string-with-limit () | 128 | (ert-deftest cl-print-tests-print-to-string-with-limit () |
| 128 | (let* ((thing10 (make-list 10 'a)) | 129 | (let* ((thing10 (make-list 10 'a)) |