diff options
| author | Gemini Lasswell | 2018-05-27 11:38:00 -0700 |
|---|---|---|
| committer | Gemini Lasswell | 2018-06-04 08:57:10 -0700 |
| commit | 5d448ca98cd59287b2c20175e2e6638f1922db57 (patch) | |
| tree | c7db77439fede92045ab369392acd046d6824b96 | |
| parent | 03697e648c080f6b007b6ef8443fd4448bc52364 (diff) | |
| download | emacs-5d448ca98cd59287b2c20175e2e6638f1922db57.tar.gz emacs-5d448ca98cd59287b2c20175e2e6638f1922db57.zip | |
Make cl-print respect print-level and print-length (bug#31559)
* lisp/emacs-lisp/cl-print.el (cl-print--depth): New variable.
(cl-print-object) <cons>: Print ellipsis if printing depth greater
than 'print-level' or length of list greater than 'print-length'.
(cl-print-object) <vector>: Truncate printing with ellipsis if
vector is longer than 'print-length'.
(cl-print-object) <cl-structure-object>: Truncate printing with
ellipsis if structure has more slots than 'print-length'.
(cl-print-object) <:around>: Bind 'cl-print--depth'.
* test/lisp/emacs-lisp/cl-print-tests.el
(cl-print-tests-3, cl-print-tests-4): New tests.
(cherry picked from commit 0f48d18fd2a30f29cc3592a835d2a2254c9b0afb)
| -rw-r--r-- | lisp/emacs-lisp/cl-print.el | 115 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/cl-print-tests.el | 25 |
2 files changed, 93 insertions, 47 deletions
diff --git a/lisp/emacs-lisp/cl-print.el b/lisp/emacs-lisp/cl-print.el index 7c0e81c9349..780b9fb3fe9 100644 --- a/lisp/emacs-lisp/cl-print.el +++ b/lisp/emacs-lisp/cl-print.el | |||
| @@ -40,6 +40,10 @@ | |||
| 40 | 40 | ||
| 41 | (defvar cl-print--number-table nil) | 41 | (defvar cl-print--number-table nil) |
| 42 | (defvar cl-print--currently-printing nil) | 42 | (defvar cl-print--currently-printing nil) |
| 43 | (defvar cl-print--depth nil | ||
| 44 | "Depth of recursion within cl-print functions. | ||
| 45 | Compared to `print-level' to determine when to stop recursing.") | ||
| 46 | |||
| 43 | 47 | ||
| 44 | ;;;###autoload | 48 | ;;;###autoload |
| 45 | (cl-defgeneric cl-print-object (object stream) | 49 | (cl-defgeneric cl-print-object (object stream) |
| @@ -52,33 +56,45 @@ call other entry points instead, such as `cl-prin1'." | |||
| 52 | (prin1 object stream)) | 56 | (prin1 object stream)) |
| 53 | 57 | ||
| 54 | (cl-defmethod cl-print-object ((object cons) stream) | 58 | (cl-defmethod cl-print-object ((object cons) stream) |
| 55 | (let ((car (pop object))) | 59 | (if (and cl-print--depth (natnump print-level) |
| 56 | (if (and (memq car '(\, quote \` \,@ \,.)) | 60 | (> cl-print--depth print-level)) |
| 57 | (consp object) | 61 | (princ "..." stream) |
| 58 | (null (cdr object))) | 62 | (let ((car (pop object)) |
| 59 | (progn | 63 | (count 1)) |
| 60 | (princ (if (eq car 'quote) '\' car) stream) | 64 | (if (and (memq car '(\, quote \` \,@ \,.)) |
| 61 | (cl-print-object (car object) stream)) | 65 | (consp object) |
| 62 | (princ "(" stream) | 66 | (null (cdr object))) |
| 63 | (cl-print-object car stream) | 67 | (progn |
| 64 | (while (and (consp object) | 68 | (princ (if (eq car 'quote) '\' car) stream) |
| 65 | (not (cond | 69 | (cl-print-object (car object) stream)) |
| 66 | (cl-print--number-table | 70 | (princ "(" stream) |
| 67 | (numberp (gethash object cl-print--number-table))) | 71 | (cl-print-object car stream) |
| 68 | ((memq object cl-print--currently-printing)) | 72 | (while (and (consp object) |
| 69 | (t (push object cl-print--currently-printing) | 73 | (not (cond |
| 70 | nil)))) | 74 | (cl-print--number-table |
| 71 | (princ " " stream) | 75 | (numberp (gethash object cl-print--number-table))) |
| 72 | (cl-print-object (pop object) stream)) | 76 | ((memq object cl-print--currently-printing)) |
| 73 | (when object | 77 | (t (push object cl-print--currently-printing) |
| 74 | (princ " . " stream) (cl-print-object object stream)) | 78 | nil)))) |
| 75 | (princ ")" stream)))) | 79 | (princ " " stream) |
| 80 | (if (or (not (natnump print-length)) (> print-length count)) | ||
| 81 | (cl-print-object (pop object) stream) | ||
| 82 | (princ "..." stream) | ||
| 83 | (setq object nil)) | ||
| 84 | (cl-incf count)) | ||
| 85 | (when object | ||
| 86 | (princ " . " stream) (cl-print-object object stream)) | ||
| 87 | (princ ")" stream))))) | ||
| 76 | 88 | ||
| 77 | (cl-defmethod cl-print-object ((object vector) stream) | 89 | (cl-defmethod cl-print-object ((object vector) stream) |
| 78 | (princ "[" stream) | 90 | (princ "[" stream) |
| 79 | (dotimes (i (length object)) | 91 | (let ((count (length object))) |
| 80 | (unless (zerop i) (princ " " stream)) | 92 | (dotimes (i (if (natnump print-length) |
| 81 | (cl-print-object (aref object i) stream)) | 93 | (min print-length count) count)) |
| 94 | (unless (zerop i) (princ " " stream)) | ||
| 95 | (cl-print-object (aref object i) stream)) | ||
| 96 | (when (and (natnump print-length) (< print-length count)) | ||
| 97 | (princ " ..." stream))) | ||
| 82 | (princ "]" stream)) | 98 | (princ "]" stream)) |
| 83 | 99 | ||
| 84 | (cl-defmethod cl-print-object ((object hash-table) stream) | 100 | (cl-defmethod cl-print-object ((object hash-table) stream) |
| @@ -180,14 +196,18 @@ into a button whose action shows the function's disassembly.") | |||
| 180 | (cl-defmethod cl-print-object ((object cl-structure-object) stream) | 196 | (cl-defmethod cl-print-object ((object cl-structure-object) stream) |
| 181 | (princ "#s(" stream) | 197 | (princ "#s(" stream) |
| 182 | (let* ((class (cl-find-class (type-of object))) | 198 | (let* ((class (cl-find-class (type-of object))) |
| 183 | (slots (cl--struct-class-slots class))) | 199 | (slots (cl--struct-class-slots class)) |
| 200 | (count (length slots))) | ||
| 184 | (princ (cl--struct-class-name class) stream) | 201 | (princ (cl--struct-class-name class) stream) |
| 185 | (dotimes (i (length slots)) | 202 | (dotimes (i (if (natnump print-length) |
| 203 | (min print-length count) count)) | ||
| 186 | (let ((slot (aref slots i))) | 204 | (let ((slot (aref slots i))) |
| 187 | (princ " :" stream) | 205 | (princ " :" stream) |
| 188 | (princ (cl--slot-descriptor-name slot) stream) | 206 | (princ (cl--slot-descriptor-name slot) stream) |
| 189 | (princ " " stream) | 207 | (princ " " stream) |
| 190 | (cl-print-object (aref object (1+ i)) stream)))) | 208 | (cl-print-object (aref object (1+ i)) stream))) |
| 209 | (when (and (natnump print-length) (< print-length count)) | ||
| 210 | (princ " ..." stream))) | ||
| 191 | (princ ")" stream)) | 211 | (princ ")" stream)) |
| 192 | 212 | ||
| 193 | ;;; Circularity and sharing. | 213 | ;;; Circularity and sharing. |
| @@ -198,26 +218,27 @@ into a button whose action shows the function's disassembly.") | |||
| 198 | 218 | ||
| 199 | (cl-defmethod cl-print-object :around (object stream) | 219 | (cl-defmethod cl-print-object :around (object stream) |
| 200 | ;; FIXME: Only put such an :around method on types where it's relevant. | 220 | ;; FIXME: Only put such an :around method on types where it's relevant. |
| 201 | (cond | 221 | (let ((cl-print--depth (if cl-print--depth (1+ cl-print--depth) 1))) |
| 202 | (print-circle | 222 | (cond |
| 203 | (let ((n (gethash object cl-print--number-table))) | 223 | (print-circle |
| 204 | (if (not (numberp n)) | 224 | (let ((n (gethash object cl-print--number-table))) |
| 205 | (cl-call-next-method) | 225 | (if (not (numberp n)) |
| 206 | (if (> n 0) | 226 | (cl-call-next-method) |
| 207 | ;; Already printed. Just print a reference. | 227 | (if (> n 0) |
| 208 | (progn (princ "#" stream) (princ n stream) (princ "#" stream)) | 228 | ;; Already printed. Just print a reference. |
| 209 | (puthash object (- n) cl-print--number-table) | 229 | (progn (princ "#" stream) (princ n stream) (princ "#" stream)) |
| 210 | (princ "#" stream) (princ (- n) stream) (princ "=" stream) | 230 | (puthash object (- n) cl-print--number-table) |
| 211 | (cl-call-next-method))))) | 231 | (princ "#" stream) (princ (- n) stream) (princ "=" stream) |
| 212 | ((let ((already-printing (memq object cl-print--currently-printing))) | 232 | (cl-call-next-method))))) |
| 213 | (when already-printing | 233 | ((let ((already-printing (memq object cl-print--currently-printing))) |
| 214 | ;; Currently printing, just print reference to avoid endless | 234 | (when already-printing |
| 215 | ;; recursion. | 235 | ;; Currently printing, just print reference to avoid endless |
| 216 | (princ "#" stream) | 236 | ;; recursion. |
| 217 | (princ (length (cdr already-printing)) stream)))) | 237 | (princ "#" stream) |
| 218 | (t (let ((cl-print--currently-printing | 238 | (princ (length (cdr already-printing)) stream)))) |
| 219 | (cons object cl-print--currently-printing))) | 239 | (t (let ((cl-print--currently-printing |
| 220 | (cl-call-next-method))))) | 240 | (cons object cl-print--currently-printing))) |
| 241 | (cl-call-next-method)))))) | ||
| 221 | 242 | ||
| 222 | (defvar cl-print--number-index nil) | 243 | (defvar cl-print--number-index nil) |
| 223 | 244 | ||
diff --git a/test/lisp/emacs-lisp/cl-print-tests.el b/test/lisp/emacs-lisp/cl-print-tests.el index d986c4015d7..bfce4a16cec 100644 --- a/test/lisp/emacs-lisp/cl-print-tests.el +++ b/test/lisp/emacs-lisp/cl-print-tests.el | |||
| @@ -47,6 +47,31 @@ | |||
| 47 | "\\`(#1=#s(foo 1 2 3) #1#)\\'" | 47 | "\\`(#1=#s(foo 1 2 3) #1#)\\'" |
| 48 | (cl-prin1-to-string (list x x))))))) | 48 | (cl-prin1-to-string (list x x))))))) |
| 49 | 49 | ||
| 50 | (cl-defstruct (cl-print-tests-struct | ||
| 51 | (:constructor cl-print-tests-con)) | ||
| 52 | a b c d e) | ||
| 53 | |||
| 54 | (ert-deftest cl-print-tests-3 () | ||
| 55 | "CL printing observes `print-length'." | ||
| 56 | (let ((long-list (make-list 5 'a)) | ||
| 57 | (long-vec (make-vector 5 'b)) | ||
| 58 | (long-struct (cl-print-tests-con)) | ||
| 59 | (print-length 4)) | ||
| 60 | (should (equal "(a a a a ...)" (cl-prin1-to-string long-list))) | ||
| 61 | (should (equal "[b b b b ...]" (cl-prin1-to-string long-vec))) | ||
| 62 | (should (equal "#s(cl-print-tests-struct :a nil :b nil :c nil :d nil ...)" | ||
| 63 | (cl-prin1-to-string long-struct))))) | ||
| 64 | |||
| 65 | (ert-deftest cl-print-tests-4 () | ||
| 66 | "CL printing observes `print-level'." | ||
| 67 | (let ((deep-list '(a (b (c (d (e)))))) | ||
| 68 | (deep-struct (cl-print-tests-con)) | ||
| 69 | (print-level 4)) | ||
| 70 | (setf (cl-print-tests-struct-a deep-struct) deep-list) | ||
| 71 | (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string deep-list))) | ||
| 72 | (should (equal "#s(cl-print-tests-struct :a (a (b (c ...))) :b nil :c nil :d nil :e nil)" | ||
| 73 | (cl-prin1-to-string deep-struct))))) | ||
| 74 | |||
| 50 | (ert-deftest cl-print-circle () | 75 | (ert-deftest cl-print-circle () |
| 51 | (let ((x '(#1=(a . #1#) #1#))) | 76 | (let ((x '(#1=(a . #1#) #1#))) |
| 52 | (let ((print-circle nil)) | 77 | (let ((print-circle nil)) |