;;;; -*- mode:emacs-lisp; coding:utf-8; lexical-binding:t -*- (require 'cl) ;; (let ((types (make-hash-table :test (function equal))) ;; (objects (make-hash-table)) ;; (queue '())) ;; (do-symbols (symbol) ;; (push symbol queue)) ;; (loop ;; while queue ;; for object = (pop queue) ;; do (unless (gethash object objects) ;; (setf (gethash object objects) t) ;; (incf (gethash (type-of object) types 0)) ;; (typecase object ;; (symbol ;; (when (boundp object) (push (symbol-value object) queue)) ;; (when (fboundp object) (push (symbol-function object) queue)) ;; (setf queue (nconc (copy-list (symbol-plist object)) queue))) ;; (cons ;; (push (car object) queue) ;; (push (cdr object) queue)) ;; (vector ;; (loop for i below (length object) ;; do (push (aref object i) queue)))))) ;; (values ;; types ;; (hash-table-count objects))) ;; (#s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8 data ;; ( ;; cons 674435 ;; string 95654 ;; integer 94087 ;; symbol 73342 ;; compiled-function 16826 ;; vector 12107 ;; subr 1125 ;; float 461 ;; marker 174 ;; char-table 158 ;; overlay 18 ;; buffer 72 ;; hash-table 25 ;; process 5 ;; frame 2 ;; window-configuration 2 ;; window 2 ;; obarray 1 ;; )) ;; 968495) ;; --> ((window window-configuration hash-table frame marker buffer overlay process char-table float vector subr compiled-function string cons integer symbol) ;; 964895) (defvar inspect:*inspectors* (make-hash-table)) (defmacro inspect:define-inspector (type (object) &body body) `(setf (gethash ',type *inspectors*) (lambda (,object) (block ,type ,@body)))) (defun inspect:function-parameter-list (function) "Return the parameter list of the emacs FUNCTION." (let* ((def (if (symbolp function) (symbol-function function) function)) (help (help-function-arglist def)) (doc (documentation function)) (split (help-split-fundoc doc function))) (or help (when (first split) (cdar (read-from-string (first split)))) split :unknown))) (defun inspect:function-argument-counts (function) "Return a cons continaing the minimum and maximum number of arguments the FUNCTION can take." (let* ((args (split-lambda-list-on-keywords (maptree (lambda (item) (if (memq item '(&optional &rest)) (intern (string-upcase item)) item)) (function-parameter-list (function enlarge-window))) :ordinary)) (min (length (cdr (assoc '&MANDATORY args))))) (if (assoc '&REST args) (cons min '&rest) (cons min (+ min (length (cdr (assoc '&OPTIONAL args)))))))) (defun inspect:hash-table-slots (hash-table) (let ((slots '())) (maphash (lambda (k v) (push (cons k v) slots)) hash-table) (nreverse slots))) (defun inspect:vector-slots (vector) (let ((slots '())) (loop for i below (length vector) do (push (cons i (aref vector i)) slots)) (nreverse slots))) (defun inspect:obarray-symbols (obarray) (let ((symbols '())) (do-symbols (symbol obarray) (push symbol symbols)) (mapcar (let ((i -1)) (lambda (symbol) (cons (incf i) symbol))) (sort symbols (function string<))))) (defun inspect:buffer-slots (buffer) ;; properties are in string ;; markers? processes? what else? (list (list :string (with-current-buffer buffer (buffer-string))))) (defparameter inspect:*type-attribute-alist* '((cons car cdr) (string ;; text-properties-at length string-bytes) (integer identity) (float identity) (symbol symbol-name (boundp symbol-value) (fboundp symbol-function) symbol-plist function-overload-p) (compiled-function function-argument-counts function-parameter-list) (vector length (:contents inspect:vector-slots)) (subr subr-name subr-arity) (marker marker-buffer marker-position marker-insertion-type) (char-table ;; char-table-extra-slot ;; char-table-range char-table-parent char-table-subtype) (overlay overlay-buffer overlay-start overlay-end overlay-properties) (buffer buffer-name buffer-file-name buffer-size buffer-base-buffer buffer-chars-modified-tick buffer-live-p buffer-local-variables buffer-modified-p buffer-modified-tick (:contents inspect:buffer-slots)) (hash-table hash-table-test hash-table-weakness hash-table-count hash-table-size hash-table-rehash-size hash-table-rehash-threshold (:contents inspect:hash-table-slots)) (process process-id process-name process-type process-plist process-buffer process-coding-system process-command process-contact process-datagram-address process-filter process-filter-multibyte-p ;; process-get process-inherit-coding-system-flag process-live-p process-mark process-query-on-exit-flag process-running-child-p process-sentinel process-status process-exit-status process-tty-name) (frame frame-name frame-title frame-left frame-top frame-width frame-height frame-pixel-left frame-pixel-top frame-pixel-width frame-pixel-height frame-left-fringe frame-right-fringe frame-auto-lower frame-auto-raise frame-foreground-color frame-background-color frame-background-mode frame-border-color frame-border-width frame-buffer-list frame-buffer-predicate frame-cursor-color frame-cursor-type frame-display frame-display-type frame-font frame-icon-name frame-icon-type frame-internal-border-width frame-line-spacing frame-menu-bar-lines frame-minibuffer frame-modeline frame-mouse-color frame-parent-id frame-window-id frame-outer-window-id frame-screen-gamma frame-horizontal-scroll-bars frame-vertical-scroll-bars frame-scroll-bar-background frame-scroll-bar-foreground frame-scroll-bar-width frame-current-scroll-bars frame-tool-bar-lines frame-unsplittable frame-visibility frame-wait-for-wm frame-char-height frame-char-width frame-face-alist frame-first-window frame-focus frame-live-p frame-parameters frame-pointer-visible-p frame-root-window frame-selected-window frame-terminal frame-terminal-default-bg-mode frame-visible-p window-system window-list window-tree buffer-list) (window-configuration window-configuration-frame) (window window-atom-root window-body-size window-body-height window-body-width window-buffer window-buffer-height window-next-buffers window-prev-buffers window-child window-child-count window-top-child window-left-child window-last-child window-combination-limit window-combinations window-combined-p window-current-scroll-bars window-dedicated-p window-deletable-p window-display-table window-dot window-edges window-end window-fixed-size-p window-frame window-fringes window-full-height-p window-full-width-p window-height window-hscroll window-inside-absolute-pixel-edges window-inside-edges window-inside-pixel-edges window-left window-right window-left-column window-top-line window-line-height window-live-p window-margins window-max-delta window-min-delta window-min-size window-minibuffer-p window-next-sibling window-prev-sibling window-normal-size window-parameters window-parent window-pixel-edges window-point window-safely-shrinkable-p window-scroll-bars window-size-fixed-p window-split-min-size window-splittable-p window-start window-state-get window-text-height window-total-height window-total-size window-total-width window-use-time window-valid-p window-vscroll window-width frame-root-window-p) (obarray (:contents inspect:obarray-symbols))) " An a-list mapping types to a list of attributes. Each attribute is either: - a symbol naming a predicate or reader function. - a list of symbols naming predicate or reader functions; the rest of the list is applied only when the preceding elements return true. - a list containing the keyword :contents and a symbol naming a function that takes an object of the given type, returning an a-list of (key . value) for each slot in the object. ") (defun inspect:max-slot-name-width (slots) (loop for slot in slots maximize (cond ((symbolp slot) (length (symbol-name slot))) ((stringp slot) (length slot)) ((atom slot) 0) ((eq :contents (first slot)) 0) (t (reduce (function max) slot :key (lambda (fun) (length (symbol-name fun)))))))) (defun inspect:insert-description (object) (let* ((type (type-of object)) (slots (cdr (assoc type inspect:*type-attribute-alist*))) (width (inspect:max-slot-name-width slots)) (fmtstr (format "%%-%ds : %%S\n" width)) (print-length 10) (print-level 4)) (insert (format "\nObject of type %s\n\n" type)) (loop for slot in slots do (cond ((symbolp slot) (insert (format fmtstr slot (funcall slot object)))) ((atom slot) 0) ((eq :contents (first slot)) (insert "Contents:\n") (let* ((slots (funcall (second slot) object)) (width (inspect:max-slot-name-width (mapcar (lambda (slot) (format "%S" (car slot))) slots))) (fmtstr (format "[%%%dS] : %%S\n" width))) (loop for (key . value) in slots do (insert (format fmtstr key value))))) (t (loop for predicate in slot for value = (funcall slot object) do (insert (format fmtstr slot value)) while value)))))) ;; (inspect:insert-description '(a . 2)) ;; (inspect:insert-description '[(a . 2) 3 4.5 "Hello"]) ;; (inspect:insert-description (selected-frame))