mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 06:20:55 -08:00
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.
This commit is contained in:
parent
ee4cc106b8
commit
3ffb99f28f
7 changed files with 108 additions and 83 deletions
|
|
@ -54,9 +54,12 @@ call other entry points instead, such as `cl-prin1'."
|
|||
(prin1 object stream))
|
||||
|
||||
(cl-defgeneric cl-print-object-contents (_object _start _stream)
|
||||
"Dispatcher to print the contents of OBJECT on STREAM.
|
||||
Print the contents starting with the item at START, without
|
||||
delimiters."
|
||||
"Dispatcher to print partial contents of OBJECT on STREAM.
|
||||
This is used when replacing an ellipsis with the contents it
|
||||
represents. OBJECT is the object that has been partially printed
|
||||
and START represents the place at which the contents where
|
||||
replaced with an ellipsis.
|
||||
Print the contents hidden by the ellipsis to STREAM."
|
||||
;; Every cl-print-object method which can print an ellipsis should
|
||||
;; have a matching cl-print-object-contents method to expand an
|
||||
;; ellipsis.
|
||||
|
|
@ -65,7 +68,7 @@ delimiters."
|
|||
(cl-defmethod cl-print-object ((object cons) stream)
|
||||
(if (and cl-print--depth (natnump print-level)
|
||||
(> cl-print--depth print-level))
|
||||
(cl-print-insert-ellipsis object 0 stream)
|
||||
(cl-print-insert-ellipsis object nil stream)
|
||||
(let ((car (pop object)))
|
||||
(if (and print-quoted
|
||||
(memq car '(\, quote function \` \,@ \,.))
|
||||
|
|
@ -107,7 +110,7 @@ delimiters."
|
|||
(cl-defmethod cl-print-object ((object vector) stream)
|
||||
(if (and cl-print--depth (natnump print-level)
|
||||
(> cl-print--depth print-level))
|
||||
(cl-print-insert-ellipsis object 0 stream)
|
||||
(cl-print-insert-ellipsis object nil stream)
|
||||
(princ "[" stream)
|
||||
(cl-print--vector-contents object 0 stream)
|
||||
(princ "]" stream)))
|
||||
|
|
@ -129,6 +132,8 @@ delimiters."
|
|||
(cl-print--vector-contents object start stream)) ;FIXME: η-redex!
|
||||
|
||||
(cl-defmethod cl-print-object ((object hash-table) stream)
|
||||
;; FIXME: Make it possible to see the contents, like `prin1' does,
|
||||
;; e.g. using ellipsis. Make sure `cl-fill' can pretty print the result!
|
||||
(princ "#<hash-table " stream)
|
||||
(princ (hash-table-test object) stream)
|
||||
(princ " " stream)
|
||||
|
|
@ -158,6 +163,9 @@ into a button whose action shows the function's disassembly.")
|
|||
|
||||
(autoload 'disassemble-1 "disass")
|
||||
|
||||
;; FIXME: Don't degenerate to `prin1' for the contents of char-tables
|
||||
;; and records!
|
||||
|
||||
(cl-defmethod cl-print-object ((object compiled-function) stream)
|
||||
(unless stream (setq stream standard-output))
|
||||
;; 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.")
|
|||
(cl-defmethod cl-print-object ((object cl-structure-object) stream)
|
||||
(if (and cl-print--depth (natnump print-level)
|
||||
(> cl-print--depth print-level))
|
||||
(cl-print-insert-ellipsis object 0 stream)
|
||||
(cl-print-insert-ellipsis object nil stream)
|
||||
(princ "#s(" stream)
|
||||
(princ (cl--struct-class-name (cl-find-class (type-of object))) stream)
|
||||
(cl-print--struct-contents object 0 stream)
|
||||
|
|
@ -250,7 +258,7 @@ into a button whose action shows the function's disassembly.")
|
|||
cl-print--depth
|
||||
(natnump print-level)
|
||||
(> cl-print--depth print-level))
|
||||
(cl-print-insert-ellipsis object 0 stream)
|
||||
(cl-print-insert-ellipsis object nil stream)
|
||||
;; Print all or part of the string
|
||||
(when has-properties
|
||||
(princ "#(" stream))
|
||||
|
|
@ -325,6 +333,7 @@ into a button whose action shows the function's disassembly.")
|
|||
(cl-defmethod cl-print-object :around (object stream)
|
||||
;; FIXME: Only put such an :around method on types where it's relevant.
|
||||
(let ((cl-print--depth (if cl-print--depth (1+ cl-print--depth) 1)))
|
||||
;; FIXME: Handle print-level here once and forall?
|
||||
(cond
|
||||
(print-circle
|
||||
(let ((n (gethash object cl-print--number-table)))
|
||||
|
|
@ -401,10 +410,53 @@ into a button whose action shows the function's disassembly.")
|
|||
(cl-print--find-sharing object print-number-table)))
|
||||
print-number-table))
|
||||
|
||||
(define-button-type 'cl-print-ellipsis
|
||||
'skip t 'action #'cl-print-expand-ellipsis
|
||||
'help-echo "mouse-2, RET: expand this ellipsis")
|
||||
|
||||
(defvar cl-print-expand-ellipsis-function
|
||||
#'cl-print--default-expand-ellipsis
|
||||
"Function to tweak the way ellipses are expanded.
|
||||
The function is called with 3 arguments, BEG, END, and FUNC.
|
||||
BEG and END delimit the ellipsis that will be replaced.
|
||||
FUNC is the function that will do the expansion.
|
||||
It should be called with a single argument specifying the desired
|
||||
limit of the expansion's length, as used in `cl-print-to-string-with-limit'.
|
||||
FUNC will return the position of the end of the newly printed text.")
|
||||
|
||||
(defun cl-print--default-expand-ellipsis (begin end value line-length)
|
||||
(delete-region begin end)
|
||||
(insert (cl-print-to-string-with-limit
|
||||
#'cl-print--expand-ellipsis value line-length))
|
||||
(point))
|
||||
|
||||
|
||||
(defun cl-print-expand-ellipsis (&optional button)
|
||||
"Expand display of the elided form at BUTTON.
|
||||
BUTTON can also be a buffer position or nil (to mean point)."
|
||||
(interactive)
|
||||
(goto-char (cond
|
||||
((null button) (point))
|
||||
(t (button-start button))))
|
||||
(unless (get-text-property (point) 'cl-print-ellipsis)
|
||||
(if (and (> (point) (point-min))
|
||||
(get-text-property (1- (point)) 'cl-print-ellipsis))
|
||||
(backward-char)
|
||||
(user-error "No ellipsis to expand here")))
|
||||
(let* ((end (next-single-property-change (point) 'cl-print-ellipsis))
|
||||
(begin (previous-single-property-change end 'cl-print-ellipsis))
|
||||
(value (get-text-property begin 'cl-print-ellipsis)))
|
||||
;; FIXME: Rather than `t' (i.e. reuse the print-length/level unchanged),
|
||||
;; I think it would make sense to increase the level by 1 and to
|
||||
;; double the length at each expansion step.
|
||||
(funcall cl-print-expand-ellipsis-function
|
||||
begin end value t)
|
||||
(goto-char begin)))
|
||||
|
||||
(defun cl-print-insert-ellipsis (object start stream)
|
||||
"Print \"...\" to STREAM with the `cl-print-ellipsis' text property.
|
||||
Save state in the text property in order to print the elided part
|
||||
of OBJECT later. START should be 0 if the whole OBJECT is being
|
||||
of OBJECT later. START should be nil if the whole OBJECT is being
|
||||
elided, otherwise it should be an index or other pointer into the
|
||||
internals of OBJECT which can be passed to
|
||||
`cl-print-object-contents' at a future time."
|
||||
|
|
@ -423,11 +475,12 @@ STREAM should be a buffer. OBJECT and START are as described in
|
|||
`cl-print-insert-ellipsis'."
|
||||
(let ((value (list object start cl-print--number-table
|
||||
cl-print--currently-printing)))
|
||||
;; FIXME: Make it into a button!
|
||||
(with-current-buffer stream
|
||||
(put-text-property beg end 'cl-print-ellipsis value stream))))
|
||||
(put-text-property beg end 'cl-print-ellipsis value stream)
|
||||
(make-text-button beg end :type 'cl-print-ellipsis))))
|
||||
|
||||
;;;###autoload
|
||||
(defun cl-print-expand-ellipsis (value stream)
|
||||
(defun cl-print--expand-ellipsis (value stream)
|
||||
"Print the expansion of an ellipsis to STREAM.
|
||||
VALUE should be the value of the `cl-print-ellipsis' text property
|
||||
which was attached to the ellipsis by `cl-prin1'."
|
||||
|
|
@ -439,7 +492,7 @@ which was attached to the ellipsis by `cl-prin1'."
|
|||
(cl-print--currently-printing (nth 3 value)))
|
||||
(when (eq object (car cl-print--currently-printing))
|
||||
(pop cl-print--currently-printing))
|
||||
(if (equal start 0)
|
||||
(if (memq start '(0 nil))
|
||||
(cl-print-object object stream)
|
||||
(cl-print-object-contents object start stream))))
|
||||
|
||||
|
|
@ -474,22 +527,25 @@ characters with appropriate settings of `print-level' and
|
|||
the arguments VALUE and STREAM and which should respect
|
||||
`print-length' and `print-level'. LIMIT may be nil or zero in
|
||||
which case PRINT-FUNCTION will be called with `print-level' and
|
||||
`print-length' bound to nil.
|
||||
`print-length' bound to nil, and it can also be t in which case
|
||||
PRINT-FUNCTION will be called with the current values of `print-level'
|
||||
and `print-length'.
|
||||
|
||||
Use this function with `cl-prin1' to print an object,
|
||||
abbreviating it with ellipses to fit within a size limit. Use
|
||||
this function with `cl-prin1-expand-ellipsis' to expand an
|
||||
ellipsis, abbreviating the expansion to stay within a size
|
||||
limit."
|
||||
(setq limit (and (natnump limit)
|
||||
(not (zerop limit))
|
||||
limit))
|
||||
abbreviating it with ellipses to fit within a size limit."
|
||||
(setq limit (and (not (eq limit 0)) limit))
|
||||
;; Since this is used by the debugger when stack space may be
|
||||
;; limited, if you increase print-level here, add more depth in
|
||||
;; call_debugger (bug#31919).
|
||||
(let* ((print-length (when limit (min limit 50)))
|
||||
(print-level (when limit (min 8 (truncate (log limit)))))
|
||||
(delta-length (when limit
|
||||
(let* ((print-length (cond
|
||||
((null limit) nil)
|
||||
((eq limit t) print-length)
|
||||
(t (min limit 50))))
|
||||
(print-level (cond
|
||||
((null limit) nil)
|
||||
((eq limit t) print-level)
|
||||
(t (min 8 (truncate (log limit))))))
|
||||
(delta-length (when (natnump limit)
|
||||
(max 1 (truncate (/ print-length print-level))))))
|
||||
(with-temp-buffer
|
||||
(catch 'done
|
||||
|
|
@ -499,7 +555,7 @@ limit."
|
|||
(let ((result (- (point-max) (point-min))))
|
||||
;; Stop when either print-level is too low or the value is
|
||||
;; successfully printed in the space allowed.
|
||||
(when (or (not limit) (< result limit) (<= print-level 2))
|
||||
(when (or (not (natnump limit)) (< result limit) (<= print-level 2))
|
||||
(throw 'done (buffer-string)))
|
||||
(let* ((ratio (/ result limit))
|
||||
(delta-level (max 1 (min (- print-level 2) ratio))))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue