aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorGemini Lasswell2018-07-14 08:05:51 -0700
committerGemini Lasswell2018-08-03 08:53:02 -0700
commita3ba34aeac1b41ca5d12bfe5644d3fdfa894ddda (patch)
tree3a04c22cc9f55cc2c8b629f9b4df9f316c8d2117 /lisp
parent2ede75c49b62439e15be3ab8be2c14594f846da6 (diff)
downloademacs-a3ba34aeac1b41ca5d12bfe5644d3fdfa894ddda.tar.gz
emacs-a3ba34aeac1b41ca5d12bfe5644d3fdfa894ddda.zip
Add new command to expand all "..."s in a backtrace frame
* doc/lispref/debugging.texi (Backtraces): Document new keybinding. * lisp/emacs-lisp/backtrace.el (backtrace-line-length): Add the option of unlimited line length. (backtrace--match-ellipsis-in-string): Add a comment to explain why this function is necessary. (backtrace-mode-map): Add keybinding for 'backtrace-expand-ellipses'. (backtrace-expand-ellipsis): Use 'cl-print-to-string-with-limit'. (backtrace-expand-ellipses): New command. (backtrace-print-to-string): Use 'cl-print-to-string-with-limit'. Tag the printed forms with a gensym instead of the values of print-length and print-level. (backtrace--print): Add 'stream' argument. * test/lisp/emacs-lisp/backtrace-tests.el (backtrace-tests--expand-ellipsis): Make the test less dependent on the implementation. (backtrace-tests--expand-ellipses): New test. Move the fitting of a printed representation into a limited number of characters using appropriate values of print-level and print-length from 'backtrace-print-to-string' to cl-print.el for future use by other parts of Emacs. * lisp/emacs-lisp/cl-print.el (cl-print-to-string-with-limit): New function. * test/lisp/emacs-lisp/cl-print-tests.el (cl-print-tests-print-to-string-with-limit): New test.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/emacs-lisp/backtrace.el124
-rw-r--r--lisp/emacs-lisp/cl-print.el40
2 files changed, 102 insertions, 62 deletions
diff --git a/lisp/emacs-lisp/backtrace.el b/lisp/emacs-lisp/backtrace.el
index 779feb43075..da5a777177d 100644
--- a/lisp/emacs-lisp/backtrace.el
+++ b/lisp/emacs-lisp/backtrace.el
@@ -55,7 +55,8 @@ order to debug the code that does fontification."
55 "Target length for lines in Backtrace buffers. 55 "Target length for lines in Backtrace buffers.
56Backtrace mode will attempt to abbreviate printing of backtrace 56Backtrace mode will attempt to abbreviate printing of backtrace
57frames to make them shorter than this, but success is not 57frames to make them shorter than this, but success is not
58guaranteed." 58guaranteed. If set to nil or zero, Backtrace mode will not
59abbreviate the forms it prints."
59 :type 'integer 60 :type 'integer
60 :group 'backtrace 61 :group 'backtrace
61 :version "27.1") 62 :version "27.1")
@@ -146,6 +147,9 @@ fontifies.")
146 147
147(defun backtrace--match-ellipsis-in-string (bound) 148(defun backtrace--match-ellipsis-in-string (bound)
148 ;; Fontify ellipses within strings as buttons. 149 ;; Fontify ellipses within strings as buttons.
150 ;; This is necessary because ellipses are text property buttons
151 ;; instead of overlay buttons, which is done because there could
152 ;; be a large number of them.
149 (when (re-search-forward "\\(\\.\\.\\.\\)\"" bound t) 153 (when (re-search-forward "\\(\\.\\.\\.\\)\"" bound t)
150 (and (get-text-property (- (point) 2) 'cl-print-ellipsis) 154 (and (get-text-property (- (point) 2) 'cl-print-ellipsis)
151 (get-text-property (- (point) 3) 'cl-print-ellipsis) 155 (get-text-property (- (point) 3) 'cl-print-ellipsis)
@@ -187,6 +191,7 @@ This is commonly used to recompute `backtrace-frames'.")
187 (define-key map "\C-m" 'backtrace-help-follow-symbol) 191 (define-key map "\C-m" 'backtrace-help-follow-symbol)
188 (define-key map "+" 'backtrace-pretty-print) 192 (define-key map "+" 'backtrace-pretty-print)
189 (define-key map "-" 'backtrace-collapse) 193 (define-key map "-" 'backtrace-collapse)
194 (define-key map "." 'backtrace-expand-ellipses)
190 (define-key map [follow-link] 'mouse-face) 195 (define-key map [follow-link] 'mouse-face)
191 (define-key map [mouse-2] 'mouse-select-window) 196 (define-key map [mouse-2] 'mouse-select-window)
192 map) 197 map)
@@ -207,9 +212,7 @@ This is commonly used to recompute `backtrace-frames'.")
207;; backtrace-form: A value applied to each printed representation of a 212;; backtrace-form: A value applied to each printed representation of a
208;; top-level s-expression, which needs to be different for sexps 213;; top-level s-expression, which needs to be different for sexps
209;; printed adjacent to each other, so the limits can be quickly 214;; printed adjacent to each other, so the limits can be quickly
210;; found for pretty-printing. The value chosen is a list contining 215;; found for pretty-printing.
211;; the values of print-level and print-length used to print the
212;; sexp, and those values are used when expanding ellipses.
213 216
214(defsubst backtrace-get-index (&optional pos) 217(defsubst backtrace-get-index (&optional pos)
215 "Return the index of the backtrace frame at POS. 218 "Return the index of the backtrace frame at POS.
@@ -423,9 +426,6 @@ Reprint the frame with the new view plist."
423 426
424(defun backtrace-expand-ellipsis (button) 427(defun backtrace-expand-ellipsis (button)
425 "Expand display of the elided form at BUTTON." 428 "Expand display of the elided form at BUTTON."
426 ;; TODO a command to expand all ... in form at point
427 ;; with argument, don't bind print-level, length??
428 ;; Enable undo so there's a way to go back?
429 (interactive) 429 (interactive)
430 (goto-char (button-start button)) 430 (goto-char (button-start button))
431 (unless (get-text-property (point) 'cl-print-ellipsis) 431 (unless (get-text-property (point) 'cl-print-ellipsis)
@@ -437,25 +437,44 @@ Reprint the frame with the new view plist."
437 (begin (previous-single-property-change end 'cl-print-ellipsis)) 437 (begin (previous-single-property-change end 'cl-print-ellipsis))
438 (value (get-text-property begin 'cl-print-ellipsis)) 438 (value (get-text-property begin 'cl-print-ellipsis))
439 (props (backtrace-get-text-properties begin)) 439 (props (backtrace-get-text-properties begin))
440 (tag (backtrace-get-form begin))
441 (length (nth 0 tag)) ; TODO should this work with a target char count
442 (level (nth 1 tag)) ; like backtrace-print-to-string?
443 (inhibit-read-only t)) 440 (inhibit-read-only t))
444 (backtrace--with-output-variables (backtrace-get-view) 441 (backtrace--with-output-variables (backtrace-get-view)
445 (let ((print-level level) 442 (delete-region begin end)
446 (print-length length)) 443 (insert (cl-print-to-string-with-limit #'cl-print-expand-ellipsis value
447 (delete-region begin end) 444 backtrace-line-length))
448 (cl-print-expand-ellipsis value (current-buffer)) 445 (setq end (point))
449 (setq end (point)) 446 (goto-char begin)
450 (goto-char begin) 447 (while (< (point) end)
451 (while (< (point) end) 448 (let ((next (next-single-property-change (point) 'cl-print-ellipsis
452 (let ((next (next-single-property-change (point) 'cl-print-ellipsis 449 nil end)))
453 nil end))) 450 (when (get-text-property (point) 'cl-print-ellipsis)
454 (when (get-text-property (point) 'cl-print-ellipsis) 451 (make-text-button (point) next :type 'backtrace-ellipsis))
455 (make-text-button (point) next :type 'backtrace-ellipsis)) 452 (goto-char next)))
456 (goto-char next))) 453 (goto-char begin)
457 (goto-char begin) 454 (add-text-properties begin end props))))
458 (add-text-properties begin end props))))) 455
456(defun backtrace-expand-ellipses (&optional no-limit)
457 "Expand display of all \"...\"s in the backtrace frame at point.
458\\<backtrace-mode-map>
459Each ellipsis will be limited to `backtrace-line-length'
460characters in its expansion. With optional prefix argument
461NO-LIMIT, do not limit the number of characters. Note that with
462or without the argument, using this command can result in very
463long lines and very poor display performance. If this happens
464and is a problem, use `\\[revert-buffer]' to return to the
465initial state of the Backtrace buffer."
466 (interactive "P")
467 (save-excursion
468 (let ((start (backtrace-get-frame-start))
469 (end (backtrace-get-frame-end))
470 (backtrace-line-length (unless no-limit backtrace-line-length)))
471 (goto-char end)
472 (while (> (point) start)
473 (let ((next (previous-single-property-change (point) 'cl-print-ellipsis
474 nil start)))
475 (when (get-text-property (point) 'cl-print-ellipsis)
476 (push-button (point)))
477 (goto-char next))))))
459 478
460(defun backtrace-pretty-print () 479(defun backtrace-pretty-print ()
461 "Pretty-print the top level s-expression at point." 480 "Pretty-print the top level s-expression at point."
@@ -605,8 +624,7 @@ line and recenter window line accordingly."
605 "Return a printed representation of OBJ formatted for backtraces. 624 "Return a printed representation of OBJ formatted for backtraces.
606Attempt to get the length of the returned string under LIMIT 625Attempt to get the length of the returned string under LIMIT
607charcters with appropriate settings of `print-level' and 626charcters with appropriate settings of `print-level' and
608`print-length.' Attach the settings used with the text property 627`print-length.' LIMIT defaults to `backtrace-line-length'."
609`backtrace-form'. LIMIT defaults to `backtrace-line-length'."
610 (backtrace--with-output-variables backtrace-view 628 (backtrace--with-output-variables backtrace-view
611 (backtrace--print-to-string obj limit))) 629 (backtrace--print-to-string obj limit)))
612 630
@@ -614,36 +632,20 @@ charcters with appropriate settings of `print-level' and
614 ;; This is for use by callers who wrap the call with 632 ;; This is for use by callers who wrap the call with
615 ;; backtrace--with-output-variables. 633 ;; backtrace--with-output-variables.
616 (setq limit (or limit backtrace-line-length)) 634 (setq limit (or limit backtrace-line-length))
617 (let* ((length 50) ; (/ backtrace-line-length 100) ?? 635 (with-temp-buffer
618 (level (truncate (log limit))) 636 (insert (cl-print-to-string-with-limit #'backtrace--print sexp limit))
619 (delta (truncate (/ length level)))) 637 ;; Add a unique backtrace-form property.
620 (with-temp-buffer 638 (put-text-property (point-min) (point) 'backtrace-form (gensym))
621 (catch 'done 639 ;; Make buttons from all the "..."s. Since there might be many of
622 (while t 640 ;; them, use text property buttons.
623 (erase-buffer) 641 (goto-char (point-min))
624 (let ((standard-output (current-buffer)) 642 (while (< (point) (point-max))
625 (print-length length) 643 (let ((end (next-single-property-change (point) 'cl-print-ellipsis
626 (print-level level)) 644 nil (point-max))))
627 (backtrace--print sexp)) 645 (when (get-text-property (point) 'cl-print-ellipsis)
628 ;; Stop when either the level is too low or the sexp is 646 (make-text-button (point) end :type 'backtrace-ellipsis))
629 ;; successfully printed in the space allowed. 647 (goto-char end)))
630 (when (or (< (- (point-max) (point-min)) limit) (= level 2)) 648 (buffer-string)))
631 (throw 'done nil))
632 (cl-decf level)
633 (cl-decf length delta)))
634 (put-text-property (point-min) (point)
635 'backtrace-form (list length level))
636 ;; Make buttons from all the "..."s.
637 ;; TODO should this be under control of :do-ellipses in the view
638 ;; plist?
639 (goto-char (point-min))
640 (while (< (point) (point-max))
641 (let ((end (next-single-property-change (point) 'cl-print-ellipsis
642 nil (point-max))))
643 (when (get-text-property (point) 'cl-print-ellipsis)
644 (make-text-button (point) end :type 'backtrace-ellipsis))
645 (goto-char end)))
646 (buffer-string))))
647 649
648(defun backtrace-print-frame (frame view) 650(defun backtrace-print-frame (frame view)
649 "Insert a backtrace FRAME at point formatted according to VIEW. 651 "Insert a backtrace FRAME at point formatted according to VIEW.
@@ -727,14 +729,14 @@ Print them only if :show-locals is non-nil in the VIEW plist."
727 (insert "\n"))) 729 (insert "\n")))
728 (put-text-property beg (point) 'backtrace-section 'locals)))) 730 (put-text-property beg (point) 'backtrace-section 'locals))))
729 731
730(defun backtrace--print (obj) 732(defun backtrace--print (obj &optional stream)
731 "Attempt to print OBJ using `backtrace-print-function'. 733 "Attempt to print OBJ to STREAM using `backtrace-print-function'.
732Fall back to `prin1' if there is an error." 734Fall back to `prin1' if there is an error."
733 (condition-case err 735 (condition-case err
734 (funcall backtrace-print-function obj) 736 (funcall backtrace-print-function obj stream)
735 (error 737 (error
736 (message "Error in backtrace printer: %S" err) 738 (message "Error in backtrace printer: %S" err)
737 (prin1 obj)))) 739 (prin1 obj stream))))
738 740
739(defun backtrace-update-flags () 741(defun backtrace-update-flags ()
740 "Update the display of the flags in the backtrace frame at point." 742 "Update the display of the flags in the backtrace frame at point."
@@ -805,8 +807,6 @@ followed by `backtrace-print-frame', once for each stack frame."
805 backtrace-font-lock-keywords-1 807 backtrace-font-lock-keywords-1
806 backtrace-font-lock-keywords-2) 808 backtrace-font-lock-keywords-2)
807 nil nil nil nil 809 nil nil nil nil
808 ;; TODO This one doesn't look necessary:
809 ;; (font-lock-mark-block-function . mark-defun)
810 (font-lock-syntactic-face-function 810 (font-lock-syntactic-face-function
811 . lisp-font-lock-syntactic-face-function)))) 811 . lisp-font-lock-syntactic-face-function))))
812 (setq truncate-lines t) 812 (setq truncate-lines t)
diff --git a/lisp/emacs-lisp/cl-print.el b/lisp/emacs-lisp/cl-print.el
index 337efa465a0..c63f5ac005c 100644
--- a/lisp/emacs-lisp/cl-print.el
+++ b/lisp/emacs-lisp/cl-print.el
@@ -524,5 +524,45 @@ node `(elisp)Output Variables'."
524 (cl-prin1 object (current-buffer)) 524 (cl-prin1 object (current-buffer))
525 (buffer-string))) 525 (buffer-string)))
526 526
527;;;###autoload
528(defun cl-print-to-string-with-limit (print-function value limit)
529 "Return a string containing a printed representation of VALUE.
530Attempt to get the length of the returned string under LIMIT
531characters with appropriate settings of `print-level' and
532`print-length.' Use PRINT-FUNCTION to print, which should take
533the arguments VALUE and STREAM and which should respect
534`print-length' and `print-level'. LIMIT may be nil or zero in
535which case PRINT-FUNCTION will be called with `print-level' and
536`print-length' bound to nil.
537
538Use this function with `cl-prin1' to print an object,
539abbreviating it with ellipses to fit within a size limit. Use
540this function with `cl-prin1-expand-ellipsis' to expand an
541ellipsis, abbreviating the expansion to stay within a size
542limit."
543 (setq limit (and (natnump limit)
544 (not (zerop limit))
545 limit))
546 ;; Since this is used by the debugger when stack space may be
547 ;; limited, if you increase print-level here, add more depth in
548 ;; call_debugger (bug#31919).
549 (let* ((print-length (when limit (min limit 50)))
550 (print-level (when limit (min 8 (truncate (log limit)))))
551 (delta (when limit
552 (max 1 (truncate (/ print-length print-level))))))
553 (with-temp-buffer
554 (catch 'done
555 (while t
556 (erase-buffer)
557 (funcall print-function value (current-buffer))
558 ;; Stop when either print-level is too low or the value is
559 ;; successfully printed in the space allowed.
560 (when (or (not limit)
561 (< (- (point-max) (point-min)) limit)
562 (= print-level 2))
563 (throw 'done (buffer-string)))
564 (cl-decf print-level)
565 (cl-decf print-length delta))))))
566
527(provide 'cl-print) 567(provide 'cl-print)
528;;; cl-print.el ends here 568;;; cl-print.el ends here