diff options
| author | Gemini Lasswell | 2018-06-15 10:26:13 -0700 |
|---|---|---|
| committer | Gemini Lasswell | 2018-08-03 08:53:02 -0700 |
| commit | 8a7620955b4d859caecd9a5dc9f2a986baf994fd (patch) | |
| tree | b0749d1815b471e881579d6483cf0684089ff4a5 | |
| parent | eba16e5e5829c244d313101a769d4988946387d9 (diff) | |
| download | emacs-8a7620955b4d859caecd9a5dc9f2a986baf994fd.tar.gz emacs-8a7620955b4d859caecd9a5dc9f2a986baf994fd.zip | |
Add methods for strings to cl-print
* lisp/emacs-lisp/cl-print.el (cl-print-object) <string>: New method.
(cl-print-object-contents) <string>: New method.
(cl-print--find-sharing): Look in string property lists.
* test/lisp/emacs-lisp/cl-print-tests.el (cl-print-tests-3): Test
printing of long strings.
(cl-print-tests-4): Test printing of strings nested in other objects.
(cl-print-tests-strings, cl-print-tests-ellipsis-string): New
tests.
| -rw-r--r-- | lisp/emacs-lisp/cl-print.el | 102 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/cl-print-tests.el | 53 |
2 files changed, 152 insertions, 3 deletions
diff --git a/lisp/emacs-lisp/cl-print.el b/lisp/emacs-lisp/cl-print.el index e638e58275a..337efa465a0 100644 --- a/lisp/emacs-lisp/cl-print.el +++ b/lisp/emacs-lisp/cl-print.el | |||
| @@ -285,6 +285,95 @@ into a button whose action shows the function's disassembly.") | |||
| 285 | (princ " " stream) | 285 | (princ " " stream) |
| 286 | (cl-print-insert-ellipsis object limit stream)))) | 286 | (cl-print-insert-ellipsis object limit stream)))) |
| 287 | 287 | ||
| 288 | (cl-defmethod cl-print-object ((object string) stream) | ||
| 289 | (unless stream (setq stream standard-output)) | ||
| 290 | (let* ((has-properties (or (text-properties-at 0 object) | ||
| 291 | (next-property-change 0 object))) | ||
| 292 | (len (length object)) | ||
| 293 | (limit (if (natnump print-length) (min print-length len) len))) | ||
| 294 | (if (and has-properties | ||
| 295 | cl-print--depth | ||
| 296 | (natnump print-level) | ||
| 297 | (> cl-print--depth print-level)) | ||
| 298 | (cl-print-insert-ellipsis object 0 stream) | ||
| 299 | ;; Print all or part of the string | ||
| 300 | (when has-properties | ||
| 301 | (princ "#(" stream)) | ||
| 302 | (if (= limit len) | ||
| 303 | (prin1 (if has-properties (substring-no-properties object) object) | ||
| 304 | stream) | ||
| 305 | (let ((part (concat (substring-no-properties object 0 limit) "..."))) | ||
| 306 | (prin1 part stream) | ||
| 307 | (when (bufferp stream) | ||
| 308 | (with-current-buffer stream | ||
| 309 | (cl-print-propertize-ellipsis object limit | ||
| 310 | (- (point) 4) | ||
| 311 | (- (point) 1) stream))))) | ||
| 312 | ;; Print the property list. | ||
| 313 | (when has-properties | ||
| 314 | (let* ((interval-limit (and (natnump print-length) | ||
| 315 | (max 1 (/ print-length 3)))) | ||
| 316 | (interval-count 0) | ||
| 317 | (start-pos (if (text-properties-at 0 object) | ||
| 318 | 0 (next-property-change 0 object))) | ||
| 319 | (end-pos (next-property-change start-pos object len))) | ||
| 320 | (while (and (or (null interval-limit) | ||
| 321 | (< interval-count interval-limit)) | ||
| 322 | (< start-pos len)) | ||
| 323 | (let ((props (text-properties-at start-pos object))) | ||
| 324 | (when props | ||
| 325 | (princ " " stream) (princ start-pos stream) | ||
| 326 | (princ " " stream) (princ end-pos stream) | ||
| 327 | (princ " " stream) (cl-print-object props stream) | ||
| 328 | (cl-incf interval-count)) | ||
| 329 | (setq start-pos end-pos | ||
| 330 | end-pos (next-property-change start-pos object len)))) | ||
| 331 | (when (< start-pos len) | ||
| 332 | (princ " " stream) | ||
| 333 | (cl-print-insert-ellipsis object (list start-pos) stream))) | ||
| 334 | (princ ")" stream))))) | ||
| 335 | |||
| 336 | (cl-defmethod cl-print-object-contents ((object string) start stream) | ||
| 337 | ;; If START is an integer, it is an index into the string, and the | ||
| 338 | ;; ellipsis that needs to be expanded is part of the string. If | ||
| 339 | ;; START is a cons, its car is an index into the string, and the | ||
| 340 | ;; ellipsis that needs to be expanded is in the property list. | ||
| 341 | (let* ((len (length object))) | ||
| 342 | (if (atom start) | ||
| 343 | ;; Print part of the string. | ||
| 344 | (let* ((limit (if (natnump print-length) | ||
| 345 | (min (+ start print-length) len) len)) | ||
| 346 | (substr (substring-no-properties object start limit)) | ||
| 347 | (printed (prin1-to-string substr)) | ||
| 348 | (trimmed (substring printed 1 (1- (length printed))))) | ||
| 349 | (princ trimmed) | ||
| 350 | (when (< limit len) | ||
| 351 | (cl-print-insert-ellipsis object limit stream))) | ||
| 352 | |||
| 353 | ;; Print part of the property list. | ||
| 354 | (let* ((first t) | ||
| 355 | (interval-limit (and (natnump print-length) | ||
| 356 | (max 1 (/ print-length 3)))) | ||
| 357 | (interval-count 0) | ||
| 358 | (start-pos (car start)) | ||
| 359 | (end-pos (next-property-change start-pos object len))) | ||
| 360 | (while (and (or (null interval-limit) | ||
| 361 | (< interval-count interval-limit)) | ||
| 362 | (< start-pos len)) | ||
| 363 | (let ((props (text-properties-at start-pos object))) | ||
| 364 | (when props | ||
| 365 | (if first | ||
| 366 | (setq first nil) | ||
| 367 | (princ " " stream)) | ||
| 368 | (princ start-pos stream) | ||
| 369 | (princ " " stream) (princ end-pos stream) | ||
| 370 | (princ " " stream) (cl-print-object props stream) | ||
| 371 | (cl-incf interval-count)) | ||
| 372 | (setq start-pos end-pos | ||
| 373 | end-pos (next-property-change start-pos object len)))) | ||
| 374 | (when (< start-pos len) | ||
| 375 | (princ " " stream) | ||
| 376 | (cl-print-insert-ellipsis object (list start-pos) stream)))))) | ||
| 288 | 377 | ||
| 289 | ;;; Circularity and sharing. | 378 | ;;; Circularity and sharing. |
| 290 | 379 | ||
| @@ -346,8 +435,17 @@ into a button whose action shows the function's disassembly.") | |||
| 346 | (push cdr stack) | 435 | (push cdr stack) |
| 347 | (push car stack)) | 436 | (push car stack)) |
| 348 | ((pred stringp) | 437 | ((pred stringp) |
| 349 | ;; We presumably won't print its text-properties. | 438 | (let* ((len (length object)) |
| 350 | nil) | 439 | (start (if (text-properties-at 0 object) |
| 440 | 0 (next-property-change 0 object))) | ||
| 441 | (end (and start | ||
| 442 | (next-property-change start object len)))) | ||
| 443 | (while (and start (< start len)) | ||
| 444 | (let ((props (text-properties-at start object))) | ||
| 445 | (when props | ||
| 446 | (push props stack)) | ||
| 447 | (setq start end | ||
| 448 | end (next-property-change start object len)))))) | ||
| 351 | ((or (pred arrayp) (pred byte-code-function-p)) | 449 | ((or (pred arrayp) (pred byte-code-function-p)) |
| 352 | ;; FIXME: Inefficient for char-tables! | 450 | ;; FIXME: Inefficient for char-tables! |
| 353 | (dotimes (i (length object)) | 451 | (dotimes (i (length object)) |
diff --git a/test/lisp/emacs-lisp/cl-print-tests.el b/test/lisp/emacs-lisp/cl-print-tests.el index 2b5eb3402bf..7594d2466b5 100644 --- a/test/lisp/emacs-lisp/cl-print-tests.el +++ b/test/lisp/emacs-lisp/cl-print-tests.el | |||
| @@ -56,11 +56,13 @@ | |||
| 56 | (let ((long-list (make-list 5 'a)) | 56 | (let ((long-list (make-list 5 'a)) |
| 57 | (long-vec (make-vector 5 'b)) | 57 | (long-vec (make-vector 5 'b)) |
| 58 | (long-struct (cl-print-tests-con)) | 58 | (long-struct (cl-print-tests-con)) |
| 59 | (long-string (make-string 5 ?a)) | ||
| 59 | (print-length 4)) | 60 | (print-length 4)) |
| 60 | (should (equal "(a a a a ...)" (cl-prin1-to-string long-list))) | 61 | (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 "[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 | (should (equal "#s(cl-print-tests-struct :a nil :b nil :c nil :d nil ...)" |
| 63 | (cl-prin1-to-string long-struct))))) | 64 | (cl-prin1-to-string long-struct))) |
| 65 | (should (equal "\"aaaa...\"" (cl-prin1-to-string long-string))))) | ||
| 64 | 66 | ||
| 65 | (ert-deftest cl-print-tests-4 () | 67 | (ert-deftest cl-print-tests-4 () |
| 66 | "CL printing observes `print-level'." | 68 | "CL printing observes `print-level'." |
| @@ -68,11 +70,16 @@ | |||
| 68 | (buried-vector '(a (b (c (d [e]))))) | 70 | (buried-vector '(a (b (c (d [e]))))) |
| 69 | (deep-struct (cl-print-tests-con)) | 71 | (deep-struct (cl-print-tests-con)) |
| 70 | (buried-struct `(a (b (c (d ,deep-struct))))) | 72 | (buried-struct `(a (b (c (d ,deep-struct))))) |
| 73 | (buried-string '(a (b (c (d #("hello" 0 5 (cl-print-test t))))))) | ||
| 74 | (buried-simple-string '(a (b (c (d "hello"))))) | ||
| 71 | (print-level 4)) | 75 | (print-level 4)) |
| 72 | (setf (cl-print-tests-struct-a deep-struct) deep-list) | 76 | (setf (cl-print-tests-struct-a deep-struct) deep-list) |
| 73 | (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string deep-list))) | 77 | (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string deep-list))) |
| 74 | (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string buried-vector))) | 78 | (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string buried-vector))) |
| 75 | (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string buried-struct))) | 79 | (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string buried-struct))) |
| 80 | (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string buried-string))) | ||
| 81 | (should (equal "(a (b (c (d \"hello\"))))" | ||
| 82 | (cl-prin1-to-string buried-simple-string))) | ||
| 76 | (should (equal "#s(cl-print-tests-struct :a (a (b (c ...))) :b nil :c nil :d nil :e nil)" | 83 | (should (equal "#s(cl-print-tests-struct :a (a (b (c ...))) :b nil :c nil :d nil :e nil)" |
| 77 | (cl-prin1-to-string deep-struct))))) | 84 | (cl-prin1-to-string deep-struct))))) |
| 78 | 85 | ||
| @@ -86,6 +93,35 @@ | |||
| 86 | (should (equal "((quote a) (function b) (\\` ((\\, c) (\\,@ d))))" | 93 | (should (equal "((quote a) (function b) (\\` ((\\, c) (\\,@ d))))" |
| 87 | (cl-prin1-to-string quoted-stuff)))))) | 94 | (cl-prin1-to-string quoted-stuff)))))) |
| 88 | 95 | ||
| 96 | (ert-deftest cl-print-tests-strings () | ||
| 97 | "CL printing prints strings and propertized strings." | ||
| 98 | (let* ((str1 "abcdefghij") | ||
| 99 | (str2 #("abcdefghij" 3 6 (bold t) 7 9 (italic t))) | ||
| 100 | (str3 #("abcdefghij" 0 10 (test t))) | ||
| 101 | (obj '(a b)) | ||
| 102 | ;; Since the byte compiler reuses string literals, | ||
| 103 | ;; and the put-text-property call is destructive, use | ||
| 104 | ;; copy-sequence to make a new string. | ||
| 105 | (str4 (copy-sequence "abcdefghij"))) | ||
| 106 | (put-text-property 0 5 'test obj str4) | ||
| 107 | (put-text-property 7 10 'test obj str4) | ||
| 108 | |||
| 109 | (should (equal "\"abcdefghij\"" (cl-prin1-to-string str1))) | ||
| 110 | (should (equal "#(\"abcdefghij\" 3 6 (bold t) 7 9 (italic t))" | ||
| 111 | (cl-prin1-to-string str2))) | ||
| 112 | (should (equal "#(\"abcdefghij\" 0 10 (test t))" | ||
| 113 | (cl-prin1-to-string str3))) | ||
| 114 | (let ((print-circle nil)) | ||
| 115 | (should | ||
| 116 | (equal | ||
| 117 | "#(\"abcdefghij\" 0 5 (test (a b)) 7 10 (test (a b)))" | ||
| 118 | (cl-prin1-to-string str4)))) | ||
| 119 | (let ((print-circle t)) | ||
| 120 | (should | ||
| 121 | (equal | ||
| 122 | "#(\"abcdefghij\" 0 5 (test #1=(a b)) 7 10 (test #1#))" | ||
| 123 | (cl-prin1-to-string str4)))))) | ||
| 124 | |||
| 89 | (ert-deftest cl-print-tests-ellipsis-cons () | 125 | (ert-deftest cl-print-tests-ellipsis-cons () |
| 90 | "Ellipsis expansion works in conses." | 126 | "Ellipsis expansion works in conses." |
| 91 | (let ((print-length 4) | 127 | (let ((print-length 4) |
| @@ -113,6 +149,21 @@ | |||
| 113 | (cl-print-tests-check-ellipsis-expansion | 149 | (cl-print-tests-check-ellipsis-expansion |
| 114 | [a [b [c [d [e]]]]] "[a [b [c ...]]]" "[d [e]]"))) | 150 | [a [b [c [d [e]]]]] "[a [b [c ...]]]" "[d [e]]"))) |
| 115 | 151 | ||
| 152 | (ert-deftest cl-print-tests-ellipsis-string () | ||
| 153 | "Ellipsis expansion works in strings." | ||
| 154 | (let ((print-length 4) | ||
| 155 | (print-level 3)) | ||
| 156 | (cl-print-tests-check-ellipsis-expansion | ||
| 157 | "abcdefg" "\"abcd...\"" "efg") | ||
| 158 | (cl-print-tests-check-ellipsis-expansion | ||
| 159 | "abcdefghijk" "\"abcd...\"" "efgh...") | ||
| 160 | (cl-print-tests-check-ellipsis-expansion | ||
| 161 | '(1 (2 (3 #("abcde" 0 5 (test t))))) | ||
| 162 | "(1 (2 (3 ...)))" "#(\"abcd...\" 0 5 (test t))") | ||
| 163 | (cl-print-tests-check-ellipsis-expansion | ||
| 164 | #("abcd" 0 1 (bold t) 1 2 (invisible t) 3 4 (italic t)) | ||
| 165 | "#(\"abcd\" 0 1 (bold t) ...)" "1 2 (invisible t) ..."))) | ||
| 166 | |||
| 116 | (ert-deftest cl-print-tests-ellipsis-struct () | 167 | (ert-deftest cl-print-tests-ellipsis-struct () |
| 117 | "Ellipsis expansion works in structures." | 168 | "Ellipsis expansion works in structures." |
| 118 | (let ((print-length 4) | 169 | (let ((print-length 4) |