1
;;; swank-fancy-inspector.lisp --- Fancy inspector for CLOS objects
3
;; Author: Marco Baringer <mb@bese.it> and others
4
;; License: Public Domain
9
;; Subclass `backend-inspector' so that backend specific methods are
11
(defclass fancy-inspector (backend-inspector) ())
13
(defmethod inspect-for-emacs ((symbol symbol) (inspector fancy-inspector))
14
(declare (ignore inspector))
15
(let ((package (symbol-package symbol)))
16
(multiple-value-bind (_symbol status)
17
(and package (find-symbol (string symbol) package))
18
(declare (ignore _symbol))
22
(label-value-line "Its name is" (symbol-name symbol))
25
(cond ((boundp symbol)
26
(label-value-line (if (constantp symbol)
27
"It is a constant of value"
28
"It is a global variable bound to")
29
(symbol-value symbol)))
30
(t '("It is unbound." (:newline))))
31
(docstring-ispec "Documentation" symbol 'variable)
32
(multiple-value-bind (expansion definedp) (macroexpand symbol)
34
(label-value-line "It is a symbol macro with expansion"
39
(append (if (macro-function symbol)
40
`("It a macro with macro-function: "
41
(:value ,(macro-function symbol)))
42
`("It is a function: "
43
(:value ,(symbol-function symbol))))
44
`(" " (:action "[make funbound]"
45
,(lambda () (fmakunbound symbol))))
47
`("It has no function value." (:newline)))
48
(docstring-ispec "Function Documentation" symbol 'function)
49
(if (compiler-macro-function symbol)
50
(label-value-line "It also names the compiler macro"
51
(compiler-macro-function symbol)))
52
(docstring-ispec "Compiler Macro Documentation"
53
symbol 'compiler-macro)
57
`("It is " ,(string-downcase (string status))
59
(:value ,package ,(package-name package))
60
,@(if (eq :internal status)
62
(:action "[export it]"
63
,(lambda () (export symbol package)))))
65
(:action "[unintern it]"
66
,(lambda () (unintern symbol package)))
68
'("It is a non-interned symbol." (:newline)))
71
(label-value-line "Property list" (symbol-plist symbol))
74
(if (find-class symbol nil)
75
`("It names the class "
76
(:value ,(find-class symbol) ,(string symbol))
79
,(lambda () (setf (find-class symbol) nil)))
83
(if (find-package symbol)
84
(label-value-line "It names the package" (find-package symbol)))
87
(defun docstring-ispec (label object kind)
88
"Return a inspector spec if OBJECT has a docstring of of kind KIND."
89
(let ((docstring (documentation object kind)))
90
(cond ((not docstring) nil)
91
((< (+ (length label) (length docstring))
93
(list label ": " docstring '(:newline)))
95
(list label ": " '(:newline) " " docstring '(:newline))))))
97
(defmethod inspect-for-emacs ((f function) (inspector fancy-inspector))
98
(declare (ignore inspector))
101
(label-value-line "Name" (function-name f))
102
`("Its argument list is: "
103
,(inspector-princ (arglist f)) (:newline))
104
(docstring-ispec "Documentation" f t)
105
(if (function-lambda-expression f)
106
(label-value-line "Lambda Expression"
107
(function-lambda-expression f))))))
109
(defun method-specializers-for-inspect (method)
110
"Return a \"pretty\" list of the method's specializers. Normal
111
specializers are replaced by the name of the class, eql
112
specializers are replaced by `(eql ,object)."
113
(mapcar (lambda (spec)
115
(swank-mop:eql-specializer
116
`(eql ,(swank-mop:eql-specializer-object spec)))
117
(t (swank-mop:class-name spec))))
118
(swank-mop:method-specializers method)))
120
(defun method-for-inspect-value (method)
121
"Returns a \"pretty\" list describing METHOD. The first element
122
of the list is the name of generic-function method is
123
specialiazed on, the second element is the method qualifiers,
124
the rest of the list is the method's specialiazers (as per
125
method-specializers-for-inspect)."
126
(append (list (swank-mop:generic-function-name
127
(swank-mop:method-generic-function method)))
128
(swank-mop:method-qualifiers method)
129
(method-specializers-for-inspect method)))
131
(defmethod inspect-for-emacs ((object standard-object)
132
(inspector fancy-inspector))
133
(let ((class (class-of object)))
135
`("Class: " (:value ,class) (:newline)
136
,@(all-slots-for-inspector object inspector)))))
138
(defvar *gf-method-getter* 'methods-by-applicability
139
"This function is called to get the methods of a generic function.
140
The default returns the method sorted by applicability.
141
See `methods-by-applicability'.")
143
(defun specializer< (specializer1 specializer2)
144
"Return true if SPECIALIZER1 is more specific than SPECIALIZER2."
145
(let ((s1 specializer1) (s2 specializer2) )
146
(cond ((typep s1 'swank-mop:eql-specializer)
147
(not (typep s2 'swank-mop:eql-specializer)))
150
(and (swank-mop:class-finalized-p class)
151
(swank-mop:class-precedence-list class))))
152
(member s2 (cpl s1)))))))
154
(defun methods-by-applicability (gf)
155
"Return methods ordered by most specific argument types.
157
`method-specializer<' is used for sorting."
158
;; FIXME: argument-precedence-order and qualifiers are ignored.
159
(labels ((method< (meth1 meth2)
160
(loop for s1 in (swank-mop:method-specializers meth1)
161
for s2 in (swank-mop:method-specializers meth2)
162
do (cond ((specializer< s2 s1) (return nil))
163
((specializer< s1 s2) (return t))))))
164
(stable-sort (copy-seq (swank-mop:generic-function-methods gf)) #'method<)))
166
(defun abbrev-doc (doc &optional (maxlen 80))
167
"Return the first sentence of DOC, but not more than MAXLAN characters."
168
(subseq doc 0 (min (1+ (or (position #\. doc) (1- maxlen)))
172
(defgeneric inspect-slot-for-emacs (class object slot)
173
(:method (class object slot)
174
(let ((slot-name (swank-mop:slot-definition-name slot))
175
(boundp (swank-mop:slot-boundp-using-class class object slot)))
177
`((:value ,(swank-mop:slot-value-using-class class object slot)))
180
(:action "[set value]"
181
,(lambda () (with-simple-restart
182
(abort "Abort setting slot ~S" slot-name)
183
(let ((value-string (eval-in-emacs
186
,(format nil "Set slot ~S to (evaluated) : " slot-name))
188
(when (and value-string
189
(not (string= value-string "")))
190
(setf (swank-mop:slot-value-using-class class object slot)
191
(eval (read-from-string value-string))))))))
193
`(" " (:action "[make unbound]"
194
,(lambda () (swank-mop:slot-makunbound-using-class class object slot)))))))))
196
(defgeneric all-slots-for-inspector (object inspector)
197
(:method ((object standard-object) inspector)
198
(declare (ignore inspector))
199
(append '("--------------------" (:newline)
200
"All Slots:" (:newline))
201
(let* ((class (class-of object))
202
(direct-slots (swank-mop:class-direct-slots class))
203
(effective-slots (sort (copy-seq (swank-mop:class-slots class))
204
#'string< :key #'swank-mop:slot-definition-name))
205
(slot-presentations (loop for effective-slot :in effective-slots
206
collect (inspect-slot-for-emacs
207
class object effective-slot)))
208
(longest-slot-name-length
209
(loop for slot :in effective-slots
210
maximize (length (symbol-name
211
(swank-mop:slot-definition-name slot))))))
213
for effective-slot :in effective-slots
214
for slot-presentation :in slot-presentations
215
for direct-slot = (find (swank-mop:slot-definition-name effective-slot)
216
direct-slots :key #'swank-mop:slot-definition-name)
217
for slot-name = (inspector-princ
218
(swank-mop:slot-definition-name effective-slot))
219
for padding-length = (- longest-slot-name-length
221
(swank-mop:slot-definition-name
223
collect `(:value ,(if direct-slot
224
(list direct-slot effective-slot)
227
collect (make-array padding-length
228
:element-type 'character
229
:initial-element #\Space)
231
append slot-presentation
232
collect '(:newline))))))
234
(defmethod inspect-for-emacs ((gf standard-generic-function)
235
(inspector fancy-inspector))
236
(flet ((lv (label value) (label-value-line label value)))
238
"A generic function."
240
(lv "Name" (swank-mop:generic-function-name gf))
241
(lv "Arguments" (swank-mop:generic-function-lambda-list gf))
242
(docstring-ispec "Documentation" gf t)
243
(lv "Method class" (swank-mop:generic-function-method-class gf))
244
(lv "Method combination"
245
(swank-mop:generic-function-method-combination gf))
246
`("Methods: " (:newline))
247
(loop for method in (funcall *gf-method-getter* gf) append
248
`((:value ,method ,(inspector-princ
249
;; drop the name of the GF
250
(cdr (method-for-inspect-value method))))
252
(:action "[remove method]"
253
,(let ((m method)) ; LOOP reassigns method
255
(remove-method gf m))))
258
(all-slots-for-inspector gf inspector)))))
260
(defmethod inspect-for-emacs ((method standard-method)
261
(inspector fancy-inspector))
263
`("Method defined on the generic function "
264
(:value ,(swank-mop:method-generic-function method)
266
(swank-mop:generic-function-name
267
(swank-mop:method-generic-function method))))
269
,@(docstring-ispec "Documentation" method t)
270
"Lambda List: " (:value ,(swank-mop:method-lambda-list method))
272
"Specializers: " (:value ,(swank-mop:method-specializers method)
273
,(inspector-princ (method-specializers-for-inspect method)))
275
"Qualifiers: " (:value ,(swank-mop:method-qualifiers method))
277
"Method function: " (:value ,(swank-mop:method-function method))
279
,@(all-slots-for-inspector method inspector))))
281
(defmethod inspect-for-emacs ((class standard-class)
282
(inspector fancy-inspector))
284
`("Name: " (:value ,(class-name class))
287
,@(common-seperated-spec (swank-mop:class-direct-superclasses class))
290
,@(common-seperated-spec
291
(swank-mop:class-direct-slots class)
293
`(:value ,slot ,(inspector-princ (swank-mop:slot-definition-name slot)))))
296
,@(if (swank-mop:class-finalized-p class)
297
(common-seperated-spec
298
(swank-mop:class-slots class)
300
`(:value ,slot ,(inspector-princ
301
(swank-mop:slot-definition-name slot)))))
302
'("#<N/A (class not finalized)>"))
304
,@(let ((doc (documentation class t)))
306
`("Documentation:" (:newline) ,(inspector-princ doc) (:newline))))
308
,@(common-seperated-spec (swank-mop:class-direct-subclasses class)
310
`(:value ,sub ,(inspector-princ (class-name sub)))))
313
,@(if (swank-mop:class-finalized-p class)
314
(common-seperated-spec (swank-mop:class-precedence-list class)
316
`(:value ,class ,(inspector-princ (class-name class)))))
317
'("#<N/A (class not finalized)>"))
319
,@(when (swank-mop:specializer-direct-methods class)
320
`("It is used as a direct specializer in the following methods:" (:newline)
322
for method in (sort (copy-seq (swank-mop:specializer-direct-methods class))
323
#'string< :key (lambda (x)
325
(let ((name (swank-mop::generic-function-name
326
(swank-mop::method-generic-function x))))
327
(if (symbolp name) name (second name))))))
329
collect `(:value ,method ,(inspector-princ (method-for-inspect-value method)))
331
if (documentation method t)
332
collect " Documentation: " and
333
collect (abbrev-doc (documentation method t)) and
334
collect '(:newline))))
335
"Prototype: " ,(if (swank-mop:class-finalized-p class)
336
`(:value ,(swank-mop:class-prototype class))
337
'"#<N/A (class not finalized)>")
339
,@(all-slots-for-inspector class inspector))))
341
(defmethod inspect-for-emacs ((slot swank-mop:standard-slot-definition)
342
(inspector fancy-inspector))
344
`("Name: " (:value ,(swank-mop:slot-definition-name slot))
346
,@(when (swank-mop:slot-definition-documentation slot)
347
`("Documentation:" (:newline)
348
(:value ,(swank-mop:slot-definition-documentation slot))
350
"Init args: " (:value ,(swank-mop:slot-definition-initargs slot)) (:newline)
351
"Init form: " ,(if (swank-mop:slot-definition-initfunction slot)
352
`(:value ,(swank-mop:slot-definition-initform slot))
353
"#<unspecified>") (:newline)
354
"Init function: " (:value ,(swank-mop:slot-definition-initfunction slot))
356
,@(all-slots-for-inspector slot inspector))))
359
;; Wrapper structure over the list of symbols of a package that should
360
;; be displayed with their respective classification flags. This is
361
;; because we need a unique type to dispatch on in INSPECT-FOR-EMACS.
362
;; Used by the Inspector for packages.
363
(defstruct (%package-symbols-container (:conc-name %container.)
364
(:constructor %%make-package-symbols-container))
365
title ;; A string; the title of the inspector page in Emacs.
366
description ;; A list of renderable objects; used as description.
367
symbols ;; A list of symbols. Supposed to be sorted alphabetically.
368
grouping-kind ;; Either :SYMBOL or :CLASSIFICATION. Cf. MAKE-SYMBOLS-LISTING.
371
(defun %make-package-symbols-container (&key title description symbols)
372
(%%make-package-symbols-container :title title :description description
373
:symbols symbols :grouping-kind :symbol))
375
(defgeneric make-symbols-listing (grouping-kind symbols))
377
(defmethod make-symbols-listing ((grouping-kind (eql :symbol)) symbols)
378
"Returns an object renderable by Emacs' inspector side that
379
alphabetically lists all the symbols in SYMBOLS together with a
380
concise string representation of what each symbol
381
represents (cf. CLASSIFY-SYMBOL & Fuzzy Completion.)"
382
(let ((max-length (loop for s in symbols maximizing (length (symbol-name s))))
383
(distance 10)) ; empty distance between name and classification
384
(flet ((string-representations (symbol)
385
(let* ((name (symbol-name symbol))
386
(length (length name))
387
(padding (- max-length length))
388
(classification (classify-symbol symbol)))
392
(make-string (+ padding distance) :initial-element #\Space))
393
(symbol-classification->string classification)))))
394
`("" ; 8 is (length "Symbols:")
395
"Symbols:" ,(make-string (+ -8 max-length distance) :initial-element #\Space) "Flags:"
397
,(concatenate 'string ; underlining dashes
398
(make-string (+ max-length distance -1) :initial-element #\-)
400
(let* ((dummy (classify-symbol (gensym)))
401
(dummy (symbol-classification->string dummy))
402
(classification-length (length dummy)))
403
(make-string classification-length :initial-element #\-)))
405
,@(loop for symbol in symbols appending
406
(multiple-value-bind (symbol-string classification-string)
407
(string-representations symbol)
408
`((:value ,symbol ,symbol-string) ,classification-string
412
(defmethod make-symbols-listing ((grouping-kind (eql :classification)) symbols)
413
"For each possible classification (cf. CLASSIFY-SYMBOL), group
414
all the symbols in SYMBOLS to all of their respective
415
classifications. (If a symbol is, for instance, boundp and a
416
generic-function, it'll appear both below the BOUNDP group and
417
the GENERIC-FUNCTION group.) As macros and special-operators are
418
specified to be FBOUNDP, there is no general FBOUNDP group,
419
instead there are the three explicit FUNCTION, MACRO and
420
SPECIAL-OPERATOR groups."
421
(let ((table (make-hash-table :test #'eq)))
422
(flet ((maybe-convert-fboundps (classifications)
423
;; Convert an :FBOUNDP in CLASSIFICATIONS to :FUNCTION if possible.
424
(if (and (member :fboundp classifications)
425
(not (member :macro classifications))
426
(not (member :special-operator classifications)))
427
(substitute :function :fboundp classifications)
428
(remove :fboundp classifications))))
429
(loop for symbol in symbols do
430
(loop for classification in (maybe-convert-fboundps (classify-symbol symbol))
431
;; SYMBOLS are supposed to be sorted alphabetically;
432
;; this property is preserved here except for reversing.
433
do (push symbol (gethash classification table)))))
434
(let* ((classifications (loop for k being each hash-key in table collect k))
435
(classifications (sort classifications #'string<)))
436
(loop for classification in classifications
437
for symbols = (gethash classification table)
438
appending`(,(symbol-name classification)
440
,(make-string 64 :initial-element #\-)
442
,@(mapcan #'(lambda (symbol)
443
(list `(:value ,symbol ,(symbol-name symbol)) '(:newline)))
444
(nreverse symbols)) ; restore alphabetic orderness.
448
(defmethod inspect-for-emacs ((%container %package-symbols-container)
449
(inspector fancy-inspector))
450
(declare (ignore inspector))
451
(with-struct (%container. title description symbols grouping-kind) %container
455
" " ,(ecase grouping-kind
457
`(:action "[Group by classification]"
458
,(lambda () (setf grouping-kind :classification))
461
`(:action "[Group by symbol]"
462
,(lambda () (setf grouping-kind :symbol))
464
(:newline) (:newline)
465
,@(make-symbols-listing grouping-kind symbols)))))
468
(defmethod inspect-for-emacs ((package package)
469
(inspector fancy-inspector))
470
(declare (ignore inspector))
471
(let ((package-name (package-name package))
472
(package-nicknames (package-nicknames package))
473
(package-use-list (package-use-list package))
474
(package-used-by-list (package-used-by-list package))
475
(shadowed-symbols (package-shadowing-symbols package))
476
(present-symbols '()) (present-symbols-length 0)
477
(internal-symbols '()) (internal-symbols-length 0)
478
(external-symbols '()) (external-symbols-length 0))
480
(do-symbols* (sym package)
481
(let ((status (symbol-status sym package)))
482
(when (not (eq status :inherited))
483
(push sym present-symbols) (incf present-symbols-length)
484
(if (eq status :internal)
485
(progn (push sym internal-symbols) (incf internal-symbols-length))
486
(progn (push sym external-symbols) (incf external-symbols-length))))))
488
(setf package-nicknames (sort (copy-list package-nicknames) #'string<)
489
package-use-list (sort (copy-list package-use-list) #'string< :key #'package-name)
490
package-used-by-list (sort (copy-list package-used-by-list) #'string< :key #'package-name)
491
shadowed-symbols (sort (copy-list shadowed-symbols) #'string<))
493
(setf present-symbols (sort present-symbols #'string<) ; SORT + STRING-LESSP
494
internal-symbols (sort internal-symbols #'string<) ; conses on at least
495
external-symbols (sort external-symbols #'string<)) ; SBCL 0.9.18.
500
`("" ; dummy to preserve indentation.
501
"Name: " (:value ,package-name) (:newline)
503
"Nick names: " ,@(common-seperated-spec package-nicknames) (:newline)
505
,@(when (documentation package t)
506
`("Documentation:" (:newline) ,(documentation package t) (:newline)))
508
"Use list: " ,@(common-seperated-spec
511
`(:value ,package ,(package-name package))))
514
"Used by list: " ,@(common-seperated-spec
517
`(:value ,package ,(package-name package))))
520
,@ ; ,@(flet ((...)) ...) would break indentation in Emacs.
521
(flet ((display-link (type symbols length &key title description)
523
(format nil "0 ~A symbols." type)
524
`(:value ,(%make-package-symbols-container :title title
525
:description description
527
,(format nil "~D ~A symbol~P." length type length)))))
529
`(,(display-link "present" present-symbols present-symbols-length
530
:title (format nil "All present symbols of package \"~A\"" package-name)
532
'("A symbol is considered present in a package if it's" (:newline)
533
"\"accessible in that package directly, rather than" (:newline)
534
"being inherited from another package.\"" (:newline)
535
"(CLHS glossary entry for `present')" (:newline)))
538
,(display-link "external" external-symbols external-symbols-length
539
:title (format nil "All external symbols of package \"~A\"" package-name)
541
'("A symbol is considered external of a package if it's" (:newline)
542
"\"part of the `external interface' to the package and" (:newline)
543
"[is] inherited by any other package that uses the" (:newline)
544
"package.\" (CLHS glossary entry of `external')" (:newline)))
546
,(display-link "internal" internal-symbols internal-symbols-length
547
:title (format nil "All internal symbols of package \"~A\"" package-name)
549
'("A symbol is considered internal of a package if it's" (:newline)
550
"present and not external---that is if the package is" (:newline)
551
"the home package of the symbol, or if the symbol has" (:newline)
552
"been explicitly imported into the package." (:newline)
554
"Notice that inherited symbols will thus not be listed," (:newline)
555
"which deliberately deviates from the CLHS glossary" (:newline)
556
"entry of `internal' because it's assumed to be more" (:newline)
557
"useful this way." (:newline)))
559
,(display-link "shadowed" shadowed-symbols (length shadowed-symbols)
560
:title (format nil "All shadowed symbols of package \"~A\"" package-name)
561
:description nil)))))))
564
(defmethod inspect-for-emacs ((pathname pathname)
565
(inspector fancy-inspector))
566
(declare (ignore inspector))
567
(values (if (wild-pathname-p pathname)
570
(append (label-value-line*
571
("Namestring" (namestring pathname))
572
("Host" (pathname-host pathname))
573
("Device" (pathname-device pathname))
574
("Directory" (pathname-directory pathname))
575
("Name" (pathname-name pathname))
576
("Type" (pathname-type pathname))
577
("Version" (pathname-version pathname)))
578
(unless (or (wild-pathname-p pathname)
579
(not (probe-file pathname)))
580
(label-value-line "Truename" (truename pathname))))))
582
(defmethod inspect-for-emacs ((pathname logical-pathname)
583
(inspector fancy-inspector))
584
(declare (ignore inspector))
585
(values "A logical pathname."
588
("Namestring" (namestring pathname))
589
("Physical pathname: " (translate-logical-pathname pathname)))
591
,(pathname-host pathname)
592
" (" (:value ,(logical-pathname-translations
593
(pathname-host pathname)))
594
"other translations)"
597
("Directory" (pathname-directory pathname))
598
("Name" (pathname-name pathname))
599
("Type" (pathname-type pathname))
600
("Version" (pathname-version pathname))
601
("Truename" (if (not (wild-pathname-p pathname))
602
(probe-file pathname)))))))
604
(defmethod inspect-for-emacs ((n number)
605
(inspector fancy-inspector))
606
(declare (ignore inspector))
607
(values "A number." `("Value: " ,(princ-to-string n))))
609
(defun format-iso8601-time (time-value &optional include-timezone-p)
610
"Formats a universal time TIME-VALUE in ISO 8601 format, with
611
the time zone included if INCLUDE-TIMEZONE-P is non-NIL"
612
;; Taken from http://www.pvv.ntnu.no/~nsaa/ISO8601.html
613
;; Thanks, Nikolai Sandved and Thomas Russ!
614
(flet ((format-iso8601-timezone (zone)
617
(multiple-value-bind (h m) (truncate (abs zone) 1.0)
618
;; Tricky. Sign of time zone is reversed in ISO 8601
619
;; relative to Common Lisp convention!
620
(format nil "~:[+~;-~]~2,'0D:~2,'0D"
621
(> zone 0) h (round (* 60 m)))))))
622
(multiple-value-bind (second minute hour day month year dow dst zone)
623
(decode-universal-time time-value)
624
(declare (ignore dow dst))
625
(format nil "~4,'0D-~2,'0D-~2,'0DT~2,'0D:~2,'0D:~2,'0D~:[~*~;~A~]"
626
year month day hour minute second
627
include-timezone-p (format-iso8601-timezone zone)))))
629
(defmethod inspect-for-emacs ((i integer)
630
(inspector fancy-inspector))
631
(declare (ignore inspector))
634
`(,(format nil "Value: ~D = #x~8,'0X = #o~O = #b~,,' ,8:B~@[ = ~E~]"
635
i i i i (ignore-errors (coerce i 'float)))
637
(when (< -1 i char-code-limit)
638
(label-value-line "Code-char" (code-char i)))
639
(label-value-line "Integer-length" (integer-length i))
641
(label-value-line "Universal-time" (format-iso8601-time i t))))))
643
(defmethod inspect-for-emacs ((c complex)
644
(inspector fancy-inspector))
645
(declare (ignore inspector))
646
(values "A complex number."
648
("Real part" (realpart c))
649
("Imaginary part" (imagpart c)))))
651
(defmethod inspect-for-emacs ((r ratio)
652
(inspector fancy-inspector))
653
(declare (ignore inspector))
654
(values "A non-integer ratio."
656
("Numerator" (numerator r))
657
("Denominator" (denominator r))
658
("As float" (float r)))))
660
(defmethod inspect-for-emacs ((f float)
661
(inspector fancy-inspector))
662
(declare (ignore inspector))
663
(values "A floating point number."
665
((> f most-positive-long-float)
666
(list "Positive infinity."))
667
((< f most-negative-long-float)
668
(list "Negative infinity."))
670
(list "Not a Number."))
672
(multiple-value-bind (significand exponent sign) (decode-float f)
674
`("Scientific: " ,(format nil "~E" f) (:newline)
677
(:value ,significand) " * "
678
(:value ,(float-radix f)) "^" (:value ,exponent) (:newline))
679
(label-value-line "Digits" (float-digits f))
680
(label-value-line "Precision" (float-precision f))))))))
682
(defmethod inspect-for-emacs ((stream file-stream)
683
(inspector fancy-inspector))
684
(declare (ignore inspector))
685
(multiple-value-bind (title content)
687
(declare (ignore title))
688
(values "A file stream."
691
(:value ,(pathname stream))
693
(:action "[visit file and show current position]"
694
,(let ((pathname (pathname stream))
695
(position (file-position stream)))
697
(ed-in-emacs `(,pathname :charpos ,position))))
702
(defmethod inspect-for-emacs ((condition stream-error)
703
(inspector fancy-inspector))
704
(declare (ignore inspector))
705
(multiple-value-bind (title content)
707
(let ((stream (stream-error-stream condition)))
708
(if (typep stream 'file-stream)
709
(values "A stream error."
712
(:value ,(pathname stream))
714
(:action "[visit file and show current position]"
715
,(let ((pathname (pathname stream))
716
(position (file-position stream)))
718
(ed-in-emacs `(,pathname :charpos ,position))))
722
(values title content)))))
724
(defvar *fancy-inpector-undo-list* nil)
726
(defslimefun fancy-inspector-init ()
727
(let ((i *default-inspector*))
728
(push (lambda () (setq *default-inspector* i))
729
*fancy-inpector-undo-list*))
730
(setq *default-inspector* (make-instance 'fancy-inspector))
733
(defslimefun fancy-inspector-unload ()
734
(loop while *fancy-inpector-undo-list* do
735
(funcall (pop *fancy-inpector-undo-list*))))
737
(provide :swank-fancy-inspector)
b'\\ No newline at end of file'