Ограничить длину строк в отладочном выводе - PullRequest
3 голосов
/ 27 апреля 2020

Я использую emacs, slime и sbcl. Когда меня бросают в отладчик, когда возникает условие, как мне ограничить размер вывода? Я вычислил *print-length* и *print-level*, но что делать с длинными строками или строками с множеством строк? Скажи,

(defun monkeys (length)
  "Generate a random string"
  (with-output-to-string (out)
    (dotimes (i length)
      (write-char
       (code-char
        (let ((c (random 27)))
          (if (zerop c)
              (if (zerop (random 5)) 10 32)
              (+ 95 c)))) out))))

(1+ (monkeys 10000)) ; drop into debugger

Ответы [ 2 ]

4 голосов
/ 28 апреля 2020

Короче говоря, на sbcl *print-vector-length* можно использовать. Из исходного кода SBCL:

(defparameter *print-vector-length* nil
  "Like *PRINT-LENGTH* but works on strings and bit-vectors.
Does not affect the cases that are already controlled by *PRINT-LENGTH*")

Длинная история, я почему-то никогда не думал смотреть на исходный код. Однако, благодаря ответу @tfb, у меня, по крайней мере, была отправная точка. Итак, я продолжил читать о таблице отправки симпатичного принтера, и, просто чтобы посмотреть, как выглядят функции отправки, я проверил, какая функция отправки по умолчанию для 'string:

(pprint-dispatch 'string)

Это дает #<FUNCTION SB-KERNEL:OUTPUT-UGLY-OBJECT> , Я искал его в исходном коде SBCL и по пути нашел необходимый параметр.

3 голосов
/ 27 апреля 2020

Принтер CL - сложная и замечательная вещь, и я забыл большинство того, что я знал о нем, так что этот ответ вполне может быть неправильным.

Нет тривиального способа управления печать больших строк: вы можете управлять печатью больших общих массивов с помощью *print-array*, но в этом случае есть специальное исключение для строк.

Тогда существует плохой подход и менее плохой подход.

плохой подход : определите метод на print-object. Я думаю, что вам разрешено делать это для строк, но если вы сделаете это, то ваш метод будет вызываться всякий раз, когда вы хотите, чтобы строка была напечатана, поэтому вам лучше быть уверенным, что это правильно. Вероятно, способ обеспечить это - убедиться, что он слушает какую-то переменную и, если переменная не просит ее сделать что-то, он просто использует call-next-method, чтобы выполнить реализацию, которая, вероятно, является правильной.

Менее плохой подход : используйте таблицу отправки симпатичного принтера, чтобы сделать то, что вам нужно. Это менее плохо (и, возможно, даже хорошо), потому что это не изменит того, что происходит, когда *print-pretty* ложно, и вы также можете просто вернуть исходную таблицу, когда захотите.

Вот игрушка попытаться сделать это. Предупреждение : я не потратил достаточно времени, чтобы достаточно серьезно подумать о том, как это взаимодействует со всеми настройками управления принтером, и, как я уже сказал, я забыл много деталей, поэтому это почти наверняка просто неверно в много случаев. Так что не используйте это в рабочем коде, но что-то вроде этого может быть достаточно для целей отладки, где то, что напечатано, просто должно сказать вам достаточно для отладки программы и не должно быть правильным во всех деталях.

(defvar *toy-print-pprint-dispatch*
  ;; a copy of the default pprint dispatch table
  (copy-pprint-dispatch nil))

(defvar *longest-string*
  ;; the longest string we try to print properly
  40)

(defun write-string-maybe (stream string)
  ;; Maybe write a string.
  (check-type string string "not a string")
  (cond (*print-readably*
         (write string :stream stream :pretty nil :readably t))
        ((<= (length string) *longest-string*)
         (write string :stream stream :pretty nil))
        (t
         ;; pretty sure this is wrong as it should defang the string
         ;; at least
         (print-unreadable-object (string stream :type t)
           (write-string string stream :start 0 :end *longest-string*)
           (write-string "..." stream )))))

(set-pprint-dispatch 'string 'write-string-maybe 0 *toy-print-pprint-dispatch*)

(defun monkeys (length)
  "Generate a random string"
  (with-output-to-string (out)
    (dotimes (i length)
      (write-char
       (code-char
        (let ((c (random 27)))
          (if (zerop c)
              (if (zerop (random 5)) 10 32)
              (+ 95 c)))) out))))

(defun test-it ()
  (let ((*print-pretty* t)
        (*print-pprint-dispatch* *toy-print-pprint-dispatch*))
    (print (monkeys *longest-string*))
    (print (monkeys (* *longest-string* 2)))
    (let ((*print-pretty* nil))
      (print (monkeys (* *longest-string* 2))))
    (values)))

А теперь:

> (test-it)

"pcbkhetnbanuvsvsvqobbqlcodnafmpgdnlku pf" 
#<simple-base-string vehgsgnjxixyp`hq`wcwwskmcg`r`jdplcsbdxvo...> 
"tp ixreii ixpeb`pgrvcobcbysgikylabidrierclrijo`edugnerlslj srryypbpravomcuxupynf" 

...