aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2023-07-13 19:00:51 -0400
committerStefan Monnier2023-07-13 19:00:51 -0400
commit3ffb99f28f29cd98094f359ea316468572535aa0 (patch)
tree52c98ac7315345ab2a811107d82a90c8711e8195
parentee4cc106b88879c86d08c6fcda06657fb15df0f1 (diff)
downloademacs-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/NEWS4
-rw-r--r--etc/NEWS.262
-rw-r--r--lisp/button.el2
-rw-r--r--lisp/emacs-lisp/backtrace.el67
-rw-r--r--lisp/emacs-lisp/cl-print.el104
-rw-r--r--lisp/ielm.el7
-rw-r--r--test/lisp/emacs-lisp/cl-print-tests.el5
7 files changed, 108 insertions, 83 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 997f7e82c2b..3e56fbb973c 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -92,6 +92,10 @@ plus, minus, check-mark, start, etc.
92The 'tool-bar-position' frame parameter can be set to 'bottom' on all 92The 'tool-bar-position' frame parameter can be set to 'bottom' on all
93window systems other than Nextstep. 93window systems other than Nextstep.
94 94
95** You can expand the "..." truncation everywhere.
96The code that allowed "..." to be expanded in the *Backtrace* should
97now 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.
96Anything following the symbol 'mode-line-format-right-align' in 100Anything 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
1928Local variables: 1928Local variables:
1929coding: utf-8 1929coding: utf-8
1930mode: outline 1930mode: emacs-news
1931paragraph-separate: "[ ]*$" 1931paragraph-separate: "[ ]*$"
1932end: 1932end:
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
124In addition, the keyword argument :supertype may be used to specify a 124In 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
127changes to a supertype are not reflected in its subtypes)." 127changes 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.
141Fontify these in addition to the expressions Emacs Lisp mode 140Fontify these in addition to the expressions Emacs Lisp mode
142fontifies.") 141fontifies.")
@@ -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.
428Set it to VALUE unless the button is a `backtrace-ellipsis' button." 417Set 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)) 491For 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.
708Attempt to get the length of the returned string under LIMIT 672Attempt 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.
58Print the contents starting with the item at START, without 58This is used when replacing an ellipsis with the contents it
59delimiters." 59represents. OBJECT is the object that has been partially printed
60and START represents the place at which the contents where
61replaced with an ellipsis.
62Print 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.
420The function is called with 3 arguments, BEG, END, and FUNC.
421BEG and END delimit the ellipsis that will be replaced.
422FUNC is the function that will do the expansion.
423It should be called with a single argument specifying the desired
424limit of the expansion's length, as used in `cl-print-to-string-with-limit'.
425FUNC 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.
436BUTTON 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.
406Save state in the text property in order to print the elided part 458Save state in the text property in order to print the elided part
407of OBJECT later. START should be 0 if the whole OBJECT is being 459of OBJECT later. START should be nil if the whole OBJECT is being
408elided, otherwise it should be an index or other pointer into the 460elided, otherwise it should be an index or other pointer into the
409internals of OBJECT which can be passed to 461internals 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.
432VALUE should be the value of the `cl-print-ellipsis' text property 485VALUE should be the value of the `cl-print-ellipsis' text property
433which was attached to the ellipsis by `cl-prin1'." 486which 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
474the arguments VALUE and STREAM and which should respect 527the 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
476which case PRINT-FUNCTION will be called with `print-level' and 529which 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
531PRINT-FUNCTION will be called with the current values of `print-level'
532and `print-length'.
478 533
479Use this function with `cl-prin1' to print an object, 534Use this function with `cl-prin1' to print an object,
480abbreviating it with ellipses to fit within a size limit. Use 535abbreviating it with ellipses to fit within a size limit."
481this function with `cl-prin1-expand-ellipsis' to expand an 536 (setq limit (and (not (eq limit 0)) limit))
482ellipsis, abbreviating the expansion to stay within a size
483limit."
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))