data-debug.el 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. ;;; data-debug.el --- Datastructure Debugger
  2. ;; Copyright (C) 2007-2012 Free Software Foundation, Inc.
  3. ;; Author: Eric M. Ludlam <zappo@gnu.org>
  4. ;; Version: 0.2
  5. ;; Keywords: OO, lisp
  6. ;; Package: cedet
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;;
  20. ;; Provide a simple way to investigate particularly large and complex
  21. ;; data structures.
  22. ;;
  23. ;; The best way to get started is to bind M-: to 'data-debug-eval-expression.
  24. ;;
  25. ;; (global-set-key "\M-:" 'data-debug-eval-expression)
  26. ;;
  27. ;; If you write functions with complex output that need debugging, you
  28. ;; can make them interactive with data-debug-show-stuff. For example:
  29. ;;
  30. ;; (defun my-complex-output-fcn ()
  31. ;; "Calculate something complicated at point, and return it."
  32. ;; (interactive) ;; function not normally interactive
  33. ;; (let ((stuff (do-stuff)))
  34. ;; (when (interactive-p)
  35. ;; (data-debug-show-stuff stuff "myStuff"))
  36. ;; stuff))
  37. (require 'font-lock)
  38. (require 'ring)
  39. ;;; Code:
  40. ;;; Compatibility
  41. ;;
  42. (if (featurep 'xemacs)
  43. (eval-and-compile
  44. (defalias 'data-debug-overlay-properties 'extent-properties)
  45. (defalias 'data-debug-overlay-p 'extentp)
  46. (if (not (fboundp 'propertize))
  47. (defun dd-propertize (string &rest properties)
  48. "Mimic 'propertize' in from Emacs 23."
  49. (add-text-properties 0 (length string) properties string)
  50. string
  51. )
  52. (defalias 'dd-propertize 'propertize))
  53. )
  54. ;; Regular Emacs
  55. (eval-and-compile
  56. (defalias 'data-debug-overlay-properties 'overlay-properties)
  57. (defalias 'data-debug-overlay-p 'overlayp)
  58. (defalias 'dd-propertize 'propertize)
  59. )
  60. )
  61. ;;; GENERIC STUFF
  62. ;;
  63. (defun data-debug-insert-property-list (proplist prefix &optional parent)
  64. "Insert the property list PROPLIST.
  65. Each line starts with PREFIX.
  66. The attributes belong to the tag PARENT."
  67. (while proplist
  68. (let ((pretext (concat (symbol-name (car proplist)) " : ")))
  69. (data-debug-insert-thing (car (cdr proplist))
  70. prefix
  71. pretext
  72. parent))
  73. (setq proplist (cdr (cdr proplist)))))
  74. ;;; overlays
  75. ;;
  76. (defun data-debug-insert-overlay-props (overlay prefix)
  77. "Insert all the parts of OVERLAY.
  78. PREFIX specifies what to insert at the start of each line."
  79. (let ((attrprefix (concat (make-string (length prefix) ? ) "# "))
  80. (proplist (data-debug-overlay-properties overlay)))
  81. (data-debug-insert-property-list
  82. proplist attrprefix)
  83. )
  84. )
  85. (defun data-debug-insert-overlay-from-point (point)
  86. "Insert the overlay found at the overlay button at POINT."
  87. (let ((overlay (get-text-property point 'ddebug))
  88. (indent (get-text-property point 'ddebug-indent))
  89. start
  90. )
  91. (end-of-line)
  92. (setq start (point))
  93. (forward-char 1)
  94. (data-debug-insert-overlay-props overlay
  95. (concat (make-string indent ? )
  96. "| "))
  97. (goto-char start)
  98. ))
  99. (defun data-debug-insert-overlay-button (overlay prefix prebuttontext)
  100. "Insert a button representing OVERLAY.
  101. PREFIX is the text that precedes the button.
  102. PREBUTTONTEXT is some text between prefix and the overlay button."
  103. (let ((start (point))
  104. (end nil)
  105. (str (format "%s" overlay))
  106. (tip nil))
  107. (insert prefix prebuttontext str)
  108. (setq end (point))
  109. (put-text-property (- end (length str)) end 'face 'font-lock-comment-face)
  110. (put-text-property start end 'ddebug overlay)
  111. (put-text-property start end 'ddebug-indent(length prefix))
  112. (put-text-property start end 'ddebug-prefix prefix)
  113. (put-text-property start end 'help-echo tip)
  114. (put-text-property start end 'ddebug-function
  115. 'data-debug-insert-overlay-from-point)
  116. (insert "\n")
  117. )
  118. )
  119. ;;; overlay list
  120. ;;
  121. (defun data-debug-insert-overlay-list (overlaylist prefix)
  122. "Insert all the parts of OVERLAYLIST.
  123. PREFIX specifies what to insert at the start of each line."
  124. (while overlaylist
  125. (data-debug-insert-overlay-button (car overlaylist)
  126. prefix
  127. "")
  128. (setq overlaylist (cdr overlaylist))))
  129. (defun data-debug-insert-overlay-list-from-point (point)
  130. "Insert the overlay found at the overlay list button at POINT."
  131. (let ((overlaylist (get-text-property point 'ddebug))
  132. (indent (get-text-property point 'ddebug-indent))
  133. start
  134. )
  135. (end-of-line)
  136. (setq start (point))
  137. (forward-char 1)
  138. (data-debug-insert-overlay-list overlaylist
  139. (concat (make-string indent ? )
  140. "* "))
  141. (goto-char start)
  142. ))
  143. (defun data-debug-insert-overlay-list-button (overlaylist
  144. prefix
  145. prebuttontext)
  146. "Insert a button representing OVERLAYLIST.
  147. PREFIX is the text that precedes the button.
  148. PREBUTTONTEXT is some text between prefix and the overlay list button."
  149. (let ((start (point))
  150. (end nil)
  151. (str (format "#<overlay list: %d entries>" (length overlaylist)))
  152. (tip nil))
  153. (insert prefix prebuttontext str)
  154. (setq end (point))
  155. (put-text-property (- end (length str)) end 'face 'font-lock-comment-face)
  156. (put-text-property start end 'ddebug overlaylist)
  157. (put-text-property start end 'ddebug-indent(length prefix))
  158. (put-text-property start end 'ddebug-prefix prefix)
  159. (put-text-property start end 'help-echo tip)
  160. (put-text-property start end 'ddebug-function
  161. 'data-debug-insert-overlay-list-from-point)
  162. (insert "\n")
  163. )
  164. )
  165. ;;; buffers
  166. ;;
  167. (defun data-debug-insert-buffer-props (buffer prefix)
  168. "Insert all the parts of BUFFER.
  169. PREFIX specifies what to insert at the start of each line."
  170. (let ((attrprefix (concat (make-string (length prefix) ? ) "# "))
  171. (proplist
  172. (list :filename (buffer-file-name buffer)
  173. :live (buffer-live-p buffer)
  174. :modified (buffer-modified-p buffer)
  175. :size (buffer-size buffer)
  176. :process (get-buffer-process buffer)
  177. :localvars (buffer-local-variables buffer)
  178. )))
  179. (data-debug-insert-property-list
  180. proplist attrprefix)
  181. )
  182. )
  183. (defun data-debug-insert-buffer-from-point (point)
  184. "Insert the buffer found at the buffer button at POINT."
  185. (let ((buffer (get-text-property point 'ddebug))
  186. (indent (get-text-property point 'ddebug-indent))
  187. start
  188. )
  189. (end-of-line)
  190. (setq start (point))
  191. (forward-char 1)
  192. (data-debug-insert-buffer-props buffer
  193. (concat (make-string indent ? )
  194. "| "))
  195. (goto-char start)
  196. ))
  197. (defun data-debug-insert-buffer-button (buffer prefix prebuttontext)
  198. "Insert a button representing BUFFER.
  199. PREFIX is the text that precedes the button.
  200. PREBUTTONTEXT is some text between prefix and the buffer button."
  201. (let ((start (point))
  202. (end nil)
  203. (str (format "%S" buffer))
  204. (tip nil))
  205. (insert prefix prebuttontext str)
  206. (setq end (point))
  207. (put-text-property (- end (length str)) end 'face 'font-lock-comment-face)
  208. (put-text-property start end 'ddebug buffer)
  209. (put-text-property start end 'ddebug-indent(length prefix))
  210. (put-text-property start end 'ddebug-prefix prefix)
  211. (put-text-property start end 'help-echo tip)
  212. (put-text-property start end 'ddebug-function
  213. 'data-debug-insert-buffer-from-point)
  214. (insert "\n")
  215. )
  216. )
  217. ;;; buffer list
  218. ;;
  219. (defun data-debug-insert-buffer-list (bufferlist prefix)
  220. "Insert all the parts of BUFFERLIST.
  221. PREFIX specifies what to insert at the start of each line."
  222. (while bufferlist
  223. (data-debug-insert-buffer-button (car bufferlist)
  224. prefix
  225. "")
  226. (setq bufferlist (cdr bufferlist))))
  227. (defun data-debug-insert-buffer-list-from-point (point)
  228. "Insert the buffer found at the buffer list button at POINT."
  229. (let ((bufferlist (get-text-property point 'ddebug))
  230. (indent (get-text-property point 'ddebug-indent))
  231. start
  232. )
  233. (end-of-line)
  234. (setq start (point))
  235. (forward-char 1)
  236. (data-debug-insert-buffer-list bufferlist
  237. (concat (make-string indent ? )
  238. "* "))
  239. (goto-char start)
  240. ))
  241. (defun data-debug-insert-buffer-list-button (bufferlist
  242. prefix
  243. prebuttontext)
  244. "Insert a button representing BUFFERLIST.
  245. PREFIX is the text that precedes the button.
  246. PREBUTTONTEXT is some text between prefix and the buffer list button."
  247. (let ((start (point))
  248. (end nil)
  249. (str (format "#<buffer list: %d entries>" (length bufferlist)))
  250. (tip nil))
  251. (insert prefix prebuttontext str)
  252. (setq end (point))
  253. (put-text-property (- end (length str)) end 'face 'font-lock-comment-face)
  254. (put-text-property start end 'ddebug bufferlist)
  255. (put-text-property start end 'ddebug-indent(length prefix))
  256. (put-text-property start end 'ddebug-prefix prefix)
  257. (put-text-property start end 'help-echo tip)
  258. (put-text-property start end 'ddebug-function
  259. 'data-debug-insert-buffer-list-from-point)
  260. (insert "\n")
  261. )
  262. )
  263. ;;; processes
  264. ;;
  265. (defun data-debug-insert-process-props (process prefix)
  266. "Insert all the parts of PROCESS.
  267. PREFIX specifies what to insert at the start of each line."
  268. (let ((attrprefix (concat (make-string (length prefix) ? ) "# "))
  269. (id (process-id process))
  270. (tty (process-tty-name process))
  271. (pcontact (process-contact process t))
  272. (proplist (process-plist process)))
  273. (data-debug-insert-property-list
  274. (append
  275. (if id (list 'id id))
  276. (if tty (list 'tty tty))
  277. (if pcontact pcontact)
  278. proplist)
  279. attrprefix)
  280. )
  281. )
  282. (defun data-debug-insert-process-from-point (point)
  283. "Insert the process found at the process button at POINT."
  284. (let ((process (get-text-property point 'ddebug))
  285. (indent (get-text-property point 'ddebug-indent))
  286. start
  287. )
  288. (end-of-line)
  289. (setq start (point))
  290. (forward-char 1)
  291. (data-debug-insert-process-props process
  292. (concat (make-string indent ? )
  293. "| "))
  294. (goto-char start)
  295. ))
  296. (defun data-debug-insert-process-button (process prefix prebuttontext)
  297. "Insert a button representing PROCESS.
  298. PREFIX is the text that precedes the button.
  299. PREBUTTONTEXT is some text between prefix and the process button."
  300. (let ((start (point))
  301. (end nil)
  302. (str (format "%S : %s" process (process-status process)))
  303. (tip nil))
  304. (insert prefix prebuttontext str)
  305. (setq end (point))
  306. (put-text-property (- end (length str)) end 'face 'font-lock-comment-face)
  307. (put-text-property start end 'ddebug process)
  308. (put-text-property start end 'ddebug-indent(length prefix))
  309. (put-text-property start end 'ddebug-prefix prefix)
  310. (put-text-property start end 'help-echo tip)
  311. (put-text-property start end 'ddebug-function
  312. 'data-debug-insert-process-from-point)
  313. (insert "\n")
  314. )
  315. )
  316. ;;; Rings
  317. ;;
  318. ;; A ring (like kill-ring, or whatever.)
  319. (defun data-debug-insert-ring-contents (ring prefix)
  320. "Insert all the parts of RING.
  321. PREFIX specifies what to insert at the start of each line."
  322. (let ((len (ring-length ring))
  323. (idx 0)
  324. )
  325. (while (< idx len)
  326. (data-debug-insert-thing (ring-ref ring idx) prefix "")
  327. (setq idx (1+ idx))
  328. )))
  329. (defun data-debug-insert-ring-items-from-point (point)
  330. "Insert the ring found at the ring button at POINT."
  331. (let ((ring (get-text-property point 'ddebug))
  332. (indent (get-text-property point 'ddebug-indent))
  333. start
  334. )
  335. (end-of-line)
  336. (setq start (point))
  337. (forward-char 1)
  338. (data-debug-insert-ring-contents ring
  339. (concat (make-string indent ? )
  340. "} "))
  341. (goto-char start)
  342. ))
  343. (defun data-debug-insert-ring-button (ring
  344. prefix
  345. prebuttontext)
  346. "Insert a button representing RING.
  347. PREFIX is the text that precedes the button.
  348. PREBUTTONTEXT is some text between prefix and the stuff list button."
  349. (let* ((start (point))
  350. (end nil)
  351. (str (format "#<RING: %d, %d max>"
  352. (ring-length ring)
  353. (ring-size ring)))
  354. (ringthing
  355. (if (= (ring-length ring) 0) nil (ring-ref ring 0)))
  356. (tip (format "Ring max-size %d, length %d."
  357. (ring-size ring)
  358. (ring-length ring)))
  359. )
  360. (insert prefix prebuttontext str)
  361. (setq end (point))
  362. (put-text-property (- end (length str)) end 'face 'font-lock-type-face)
  363. (put-text-property start end 'ddebug ring)
  364. (put-text-property start end 'ddebug-indent(length prefix))
  365. (put-text-property start end 'ddebug-prefix prefix)
  366. (put-text-property start end 'help-echo tip)
  367. (put-text-property start end 'ddebug-function
  368. 'data-debug-insert-ring-items-from-point)
  369. (insert "\n")
  370. )
  371. )
  372. ;;; Hash-table
  373. ;;
  374. (defun data-debug-insert-hash-table (hash-table prefix)
  375. "Insert the contents of HASH-TABLE inserting PREFIX before each element."
  376. (maphash
  377. (lambda (key value)
  378. (data-debug-insert-thing
  379. key prefix
  380. (dd-propertize "key " 'face font-lock-comment-face))
  381. (data-debug-insert-thing
  382. value prefix
  383. (dd-propertize "val " 'face font-lock-comment-face)))
  384. hash-table))
  385. (defun data-debug-insert-hash-table-from-point (point)
  386. "Insert the contents of the hash-table button at POINT."
  387. (let ((hash-table (get-text-property point 'ddebug))
  388. (indent (get-text-property point 'ddebug-indent))
  389. start)
  390. (end-of-line)
  391. (setq start (point))
  392. (forward-char 1)
  393. (data-debug-insert-hash-table
  394. hash-table
  395. (concat (make-string indent ? ) "> "))
  396. (goto-char start))
  397. )
  398. (defun data-debug-insert-hash-table-button (hash-table prefix prebuttontext)
  399. "Insert HASH-TABLE as expandable button with recursive prefix PREFIX and PREBUTTONTEXT in front of the button text."
  400. (let ((string (dd-propertize (format "%s" hash-table)
  401. 'face 'font-lock-keyword-face)))
  402. (insert (dd-propertize
  403. (concat prefix prebuttontext string)
  404. 'ddebug hash-table
  405. 'ddebug-indent (length prefix)
  406. 'ddebug-prefix prefix
  407. 'help-echo
  408. (format "Hash-table\nTest: %s\nWeakness: %s\nElements: %d (of %d)"
  409. (hash-table-test hash-table)
  410. (if (hash-table-weakness hash-table) "yes" "no")
  411. (hash-table-count hash-table)
  412. (hash-table-size hash-table))
  413. 'ddebug-function
  414. 'data-debug-insert-hash-table-from-point)
  415. "\n"))
  416. )
  417. ;;; Widget
  418. ;;
  419. ;; Widgets have a long list of properties
  420. (defun data-debug-insert-widget-properties (widget prefix)
  421. "Insert the contents of WIDGET inserting PREFIX before each element."
  422. (let ((type (car widget))
  423. (rest (cdr widget)))
  424. (while rest
  425. (data-debug-insert-thing (car (cdr rest))
  426. prefix
  427. (concat
  428. (dd-propertize (format "%s" (car rest))
  429. 'face font-lock-comment-face)
  430. " : "))
  431. (setq rest (cdr (cdr rest))))
  432. ))
  433. (defun data-debug-insert-widget-from-point (point)
  434. "Insert the contents of the widget button at POINT."
  435. (let ((widget (get-text-property point 'ddebug))
  436. (indent (get-text-property point 'ddebug-indent))
  437. start)
  438. (end-of-line)
  439. (setq start (point))
  440. (forward-char 1)
  441. (data-debug-insert-widget-properties
  442. widget (concat (make-string indent ? ) "# "))
  443. (goto-char start))
  444. )
  445. (defun data-debug-insert-widget (widget prefix prebuttontext)
  446. "Insert one WIDGET.
  447. A Symbol is a simple thing, but this provides some face and prefix rules.
  448. PREFIX is the text that precedes the button.
  449. PREBUTTONTEXT is some text between prefix and the thing."
  450. (let ((string (dd-propertize (format "#<WIDGET %s>" (car widget))
  451. 'face 'font-lock-keyword-face)))
  452. (insert (dd-propertize
  453. (concat prefix prebuttontext string)
  454. 'ddebug widget
  455. 'ddebug-indent (length prefix)
  456. 'ddebug-prefix prefix
  457. 'help-echo
  458. (format "Widget\nType: %s\n# Properties: %d"
  459. (car widget)
  460. (/ (1- (length widget)) 2))
  461. 'ddebug-function
  462. 'data-debug-insert-widget-from-point)
  463. "\n")))
  464. ;;; list of stuff
  465. ;;
  466. ;; just a list. random stuff inside.
  467. (defun data-debug-insert-stuff-list (stufflist prefix)
  468. "Insert all the parts of STUFFLIST.
  469. PREFIX specifies what to insert at the start of each line."
  470. (while stufflist
  471. (data-debug-insert-thing
  472. ;; Some lists may put a value in the CDR
  473. (if (listp stufflist) (car stufflist) stufflist)
  474. prefix
  475. "")
  476. (setq stufflist
  477. (if (listp stufflist)
  478. (cdr-safe stufflist)
  479. nil))))
  480. (defun data-debug-insert-stuff-list-from-point (point)
  481. "Insert the stuff found at the stuff list button at POINT."
  482. (let ((stufflist (get-text-property point 'ddebug))
  483. (indent (get-text-property point 'ddebug-indent))
  484. start
  485. )
  486. (end-of-line)
  487. (setq start (point))
  488. (forward-char 1)
  489. (data-debug-insert-stuff-list stufflist
  490. (concat (make-string indent ? )
  491. "> "))
  492. (goto-char start)
  493. ))
  494. (defun data-debug-insert-stuff-list-button (stufflist
  495. prefix
  496. prebuttontext)
  497. "Insert a button representing STUFFLIST.
  498. PREFIX is the text that precedes the button.
  499. PREBUTTONTEXT is some text between prefix and the stuff list button."
  500. (let ((start (point))
  501. (end nil)
  502. (str
  503. (condition-case nil
  504. (format "#<list o' stuff: %d entries>" (safe-length stufflist))
  505. (error "#<list o' stuff>")))
  506. (tip (if (or (listp (car stufflist))
  507. (vectorp (car stufflist)))
  508. ""
  509. (format "%s" stufflist))))
  510. (insert prefix prebuttontext str)
  511. (setq end (point))
  512. (put-text-property (- end (length str)) end 'face 'font-lock-variable-name-face)
  513. (put-text-property start end 'ddebug stufflist)
  514. (put-text-property start end 'ddebug-indent (length prefix))
  515. (put-text-property start end 'ddebug-prefix prefix)
  516. (put-text-property start end 'help-echo tip)
  517. (put-text-property start end 'ddebug-function
  518. 'data-debug-insert-stuff-list-from-point)
  519. (insert "\n")
  520. )
  521. )
  522. ;;; vector of stuff
  523. ;;
  524. ;; just a vector. random stuff inside.
  525. (defun data-debug-insert-stuff-vector (stuffvector prefix)
  526. "Insert all the parts of STUFFVECTOR.
  527. PREFIX specifies what to insert at the start of each line."
  528. (let ((idx 0))
  529. (while (< idx (length stuffvector))
  530. (data-debug-insert-thing
  531. ;; Some vectors may put a value in the CDR
  532. (aref stuffvector idx)
  533. prefix
  534. "")
  535. (setq idx (1+ idx)))))
  536. (defun data-debug-insert-stuff-vector-from-point (point)
  537. "Insert the stuff found at the stuff vector button at POINT."
  538. (let ((stuffvector (get-text-property point 'ddebug))
  539. (indent (get-text-property point 'ddebug-indent))
  540. start
  541. )
  542. (end-of-line)
  543. (setq start (point))
  544. (forward-char 1)
  545. (data-debug-insert-stuff-vector stuffvector
  546. (concat (make-string indent ? )
  547. "[ "))
  548. (goto-char start)
  549. ))
  550. (defun data-debug-insert-stuff-vector-button (stuffvector
  551. prefix
  552. prebuttontext)
  553. "Insert a button representing STUFFVECTOR.
  554. PREFIX is the text that precedes the button.
  555. PREBUTTONTEXT is some text between prefix and the stuff vector button."
  556. (let* ((start (point))
  557. (end nil)
  558. (str (format "#<vector o' stuff: %d entries>" (length stuffvector)))
  559. (tip str))
  560. (insert prefix prebuttontext str)
  561. (setq end (point))
  562. (put-text-property (- end (length str)) end 'face 'font-lock-variable-name-face)
  563. (put-text-property start end 'ddebug stuffvector)
  564. (put-text-property start end 'ddebug-indent (length prefix))
  565. (put-text-property start end 'ddebug-prefix prefix)
  566. (put-text-property start end 'help-echo tip)
  567. (put-text-property start end 'ddebug-function
  568. 'data-debug-insert-stuff-vector-from-point)
  569. (insert "\n")
  570. )
  571. )
  572. ;;; Symbol
  573. ;;
  574. (defun data-debug-insert-symbol-from-point (point)
  575. "Insert attached properties and possibly the value of symbol at POINT."
  576. (let ((symbol (get-text-property point 'ddebug))
  577. (indent (get-text-property point 'ddebug-indent))
  578. start)
  579. (end-of-line)
  580. (setq start (point))
  581. (forward-char 1)
  582. (when (and (not (fboundp symbol)) (boundp symbol))
  583. (data-debug-insert-thing
  584. (symbol-value symbol)
  585. (concat (make-string indent ? ) "> ")
  586. (concat
  587. (dd-propertize "value"
  588. 'face 'font-lock-comment-face)
  589. " ")))
  590. (data-debug-insert-property-list
  591. (symbol-plist symbol)
  592. (concat (make-string indent ? ) "> "))
  593. (goto-char start))
  594. )
  595. (defun data-debug-insert-symbol-button (symbol prefix prebuttontext)
  596. "Insert a button representing SYMBOL.
  597. PREFIX is the text that precedes the button.
  598. PREBUTTONTEXT is some text between prefix and the symbol button."
  599. (let ((string
  600. (cond ((fboundp symbol)
  601. (dd-propertize (concat "#'" (symbol-name symbol))
  602. 'face 'font-lock-function-name-face))
  603. ((boundp symbol)
  604. (dd-propertize (concat "'" (symbol-name symbol))
  605. 'face 'font-lock-variable-name-face))
  606. (t (format "'%s" symbol)))))
  607. (insert (dd-propertize
  608. (concat prefix prebuttontext string)
  609. 'ddebug symbol
  610. 'ddebug-indent (length prefix)
  611. 'ddebug-prefix prefix
  612. 'help-echo ""
  613. 'ddebug-function
  614. 'data-debug-insert-symbol-from-point)
  615. "\n"))
  616. )
  617. ;;; String
  618. (defun data-debug-insert-string (thing prefix prebuttontext)
  619. "Insert one symbol THING.
  620. A Symbol is a simple thing, but this provides some face and prefix rules.
  621. PREFIX is the text that precedes the button.
  622. PREBUTTONTEXT is some text between prefix and the thing."
  623. (let ((newstr thing))
  624. (while (string-match "\n" newstr)
  625. (setq newstr (replace-match "\\n" t t newstr)))
  626. (while (string-match "\t" newstr)
  627. (setq newstr (replace-match "\\t" t t newstr)))
  628. (insert prefix prebuttontext
  629. (dd-propertize (format "\"%s\"" newstr)
  630. 'face font-lock-string-face)
  631. "\n" )))
  632. ;;; Number
  633. (defun data-debug-insert-number (thing prefix prebuttontext)
  634. "Insert one symbol THING.
  635. A Symbol is a simple thing, but this provides some face and prefix rules.
  636. PREFIX is the text that precedes the button.
  637. PREBUTTONTEXT is some text between prefix and the thing."
  638. (insert prefix prebuttontext
  639. (dd-propertize (format "%S" thing)
  640. 'face font-lock-string-face)
  641. "\n"))
  642. ;;; Lambda Expression
  643. (defun data-debug-insert-lambda-expression (thing prefix prebuttontext)
  644. "Insert one lambda expression THING.
  645. A Symbol is a simple thing, but this provides some face and prefix rules.
  646. PREFIX is the text that precedes the button.
  647. PREBUTTONTEXT is some text between prefix and the thing."
  648. (let ((txt (prin1-to-string thing)))
  649. (data-debug-insert-simple-thing
  650. txt prefix prebuttontext 'font-lock-keyword-face))
  651. )
  652. ;;; nil thing
  653. (defun data-debug-insert-nil (thing prefix prebuttontext)
  654. "Insert one simple THING with a face.
  655. PREFIX is the text that precedes the button.
  656. PREBUTTONTEXT is some text between prefix and the thing.
  657. FACE is the face to use."
  658. (insert prefix prebuttontext)
  659. (insert ": ")
  660. (let ((start (point))
  661. (end nil))
  662. (insert "nil")
  663. (setq end (point))
  664. (insert "\n" )
  665. (put-text-property start end 'face 'font-lock-variable-name-face)
  666. ))
  667. ;;; simple thing
  668. (defun data-debug-insert-simple-thing (thing prefix prebuttontext face)
  669. "Insert one simple THING with a face.
  670. PREFIX is the text that precedes the button.
  671. PREBUTTONTEXT is some text between prefix and the thing.
  672. FACE is the face to use."
  673. (insert prefix prebuttontext)
  674. (let ((start (point))
  675. (end nil))
  676. (insert (format "%s" thing))
  677. (setq end (point))
  678. (insert "\n" )
  679. (put-text-property start end 'face face)
  680. ))
  681. ;;; custom thing
  682. (defun data-debug-insert-custom (thingstring prefix prebuttontext face)
  683. "Insert one simple THINGSTRING with a face.
  684. Use for simple items that need a custom insert.
  685. PREFIX is the text that precedes the button.
  686. PREBUTTONTEXT is some text between prefix and the thing.
  687. FACE is the face to use."
  688. (insert prefix prebuttontext)
  689. (let ((start (point))
  690. (end nil))
  691. (insert thingstring)
  692. (setq end (point))
  693. (insert "\n" )
  694. (put-text-property start end 'face face)
  695. ))
  696. (defvar data-debug-thing-alist
  697. '(
  698. ;; nil
  699. (null . data-debug-insert-nil)
  700. ;; Overlay
  701. (data-debug-overlay-p . data-debug-insert-overlay-button)
  702. ;; Overlay list
  703. ((lambda (thing) (and (consp thing) (data-debug-overlay-p (car thing)))) .
  704. data-debug-insert-overlay-list-button)
  705. ;; Buffer
  706. (bufferp . data-debug-insert-buffer-button)
  707. ;; Buffer list
  708. ((lambda (thing) (and (consp thing) (bufferp (car thing)))) .
  709. data-debug-insert-buffer-list-button)
  710. ;; Process
  711. (processp . data-debug-insert-process-button)
  712. ;; String
  713. (stringp . data-debug-insert-string)
  714. ;; Number
  715. (numberp . data-debug-insert-number)
  716. ;; Symbol
  717. (symbolp . data-debug-insert-symbol-button)
  718. ;; Ring
  719. (ring-p . data-debug-insert-ring-button)
  720. ;; Lambda Expression
  721. ((lambda (thing) (and (consp thing) (eq (car thing) 'lambda))) .
  722. data-debug-insert-lambda-expression)
  723. ;; Hash-table
  724. (hash-table-p . data-debug-insert-hash-table-button)
  725. ;; Widgets
  726. (widgetp . data-debug-insert-widget)
  727. ;; List of stuff
  728. (listp . data-debug-insert-stuff-list-button)
  729. ;; Vector of stuff
  730. (vectorp . data-debug-insert-stuff-vector-button)
  731. )
  732. "Alist of methods used to insert things into an Ddebug buffer.")
  733. ;; An augmentation function for the thing alist.
  734. (defun data-debug-add-specialized-thing (predicate fcn)
  735. "Add a new specialized thing to display with data-debug.
  736. PREDICATE is a function that returns t if a thing is this new type.
  737. FCN is a function that will display stuff in the data debug buffer."
  738. (let ((entry (cons predicate fcn))
  739. ;; Specialized entries show up AFTER nil,
  740. ;; but before listp, vectorp, symbolp, and
  741. ;; other general things. Splice it into
  742. ;; the beginning.
  743. (first (nthcdr 0 data-debug-thing-alist))
  744. (second (nthcdr 1 data-debug-thing-alist))
  745. )
  746. (when (not (member entry data-debug-thing-alist))
  747. (setcdr first (cons entry second)))))
  748. ;; uber insert method
  749. (defun data-debug-insert-thing (thing prefix prebuttontext &optional parent)
  750. "Insert THING with PREFIX.
  751. PREBUTTONTEXT is some text to insert between prefix and the thing
  752. that is not included in the indentation calculation of any children.
  753. If PARENT is non-nil, it is somehow related as a parent to thing."
  754. (when (catch 'done
  755. (dolist (test data-debug-thing-alist)
  756. (when (funcall (car test) thing)
  757. (condition-case nil
  758. (funcall (cdr test) thing prefix prebuttontext parent)
  759. (error
  760. (funcall (cdr test) thing prefix prebuttontext)))
  761. (throw 'done nil))
  762. )
  763. nil)
  764. (data-debug-insert-simple-thing (format "%S" thing)
  765. prefix
  766. prebuttontext
  767. 'bold)))
  768. ;;; MAJOR MODE
  769. ;;
  770. ;; The Ddebug major mode provides an interactive space to explore
  771. ;; complicated data structures.
  772. ;;
  773. (defgroup data-debug nil
  774. "data-debug group."
  775. :group 'extensions)
  776. (defvar data-debug-mode-syntax-table
  777. (let ((table (make-syntax-table (standard-syntax-table))))
  778. (modify-syntax-entry ?\; ". 12" table) ;; SEMI, Comment start ;;
  779. (modify-syntax-entry ?\n ">" table) ;; Comment end
  780. (modify-syntax-entry ?\" "\"" table) ;; String
  781. (modify-syntax-entry ?\- "_" table) ;; Symbol
  782. (modify-syntax-entry ?\\ "\\" table) ;; Quote
  783. (modify-syntax-entry ?\` "'" table) ;; Prefix ` (backquote)
  784. (modify-syntax-entry ?\' "'" table) ;; Prefix ' (quote)
  785. (modify-syntax-entry ?\, "'" table) ;; Prefix , (comma)
  786. table)
  787. "Syntax table used in data-debug macro buffers.")
  788. (defvar data-debug-map
  789. (let ((km (make-sparse-keymap)))
  790. (define-key km [mouse-2] 'data-debug-expand-or-contract-mouse)
  791. (define-key km " " 'data-debug-expand-or-contract)
  792. (define-key km "\C-m" 'data-debug-expand-or-contract)
  793. (define-key km "n" 'data-debug-next)
  794. (define-key km "p" 'data-debug-prev)
  795. (define-key km "N" 'data-debug-next-expando)
  796. (define-key km "P" 'data-debug-prev-expando)
  797. km)
  798. "Keymap used in data-debug.")
  799. (defcustom data-debug-mode-hook nil
  800. "*Hook run when data-debug starts."
  801. :group 'data-debug
  802. :type 'hook)
  803. (defun data-debug-mode ()
  804. "Major-mode for the Analyzer debugger.
  805. \\{data-debug-map}"
  806. (interactive)
  807. (kill-all-local-variables)
  808. (setq major-mode 'data-debug-mode
  809. mode-name "DATA-DEBUG"
  810. comment-start ";;"
  811. comment-end "")
  812. (set (make-local-variable 'comment-start-skip)
  813. "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+ *")
  814. (set-syntax-table data-debug-mode-syntax-table)
  815. (use-local-map data-debug-map)
  816. (run-hooks 'data-debug-hook)
  817. (buffer-disable-undo)
  818. (set (make-local-variable 'font-lock-global-modes) nil)
  819. (font-lock-mode -1)
  820. )
  821. ;;;###autoload
  822. (defun data-debug-new-buffer (name)
  823. "Create a new data-debug buffer with NAME."
  824. (let ((b (get-buffer-create name)))
  825. (pop-to-buffer b)
  826. (set-buffer b)
  827. (erase-buffer)
  828. (data-debug-mode)
  829. b))
  830. ;;; Ddebug mode commands
  831. ;;
  832. (defun data-debug-next ()
  833. "Go to the next line in the Ddebug buffer."
  834. (interactive)
  835. (forward-line 1)
  836. (beginning-of-line)
  837. (skip-chars-forward " *-><[]" (point-at-eol)))
  838. (defun data-debug-prev ()
  839. "Go to the previous line in the Ddebug buffer."
  840. (interactive)
  841. (forward-line -1)
  842. (beginning-of-line)
  843. (skip-chars-forward " *-><[]" (point-at-eol)))
  844. (defun data-debug-next-expando ()
  845. "Go to the next line in the Ddebug buffer.
  846. Contract the current line (if open) and expand the line
  847. we move to."
  848. (interactive)
  849. (data-debug-contract-current-line)
  850. (data-debug-next)
  851. (data-debug-expand-current-line)
  852. )
  853. (defun data-debug-prev-expando ()
  854. "Go to the previous line in the Ddebug buffer.
  855. Contract the current line (if open) and expand the line
  856. we move to."
  857. (interactive)
  858. (data-debug-contract-current-line)
  859. (data-debug-prev)
  860. (data-debug-expand-current-line)
  861. )
  862. (defun data-debug-current-line-expanded-p ()
  863. "Return non-nil if the current line is expanded."
  864. (let ((ti (current-indentation))
  865. (ni (condition-case nil
  866. (save-excursion
  867. (end-of-line)
  868. (forward-char 1)
  869. (current-indentation))
  870. (error 0))))
  871. (> ni ti)))
  872. (defun data-debug-line-expandable-p ()
  873. "Return non-nil if the current line is expandable.
  874. Lines that are not expandable are assumed to not be contractible."
  875. (not (get-text-property (point) 'ddebug-noexpand)))
  876. (defun data-debug-expand-current-line ()
  877. "Expand the current line (if possible).
  878. Do nothing if already expanded."
  879. (when (or (not (data-debug-line-expandable-p))
  880. (not (data-debug-current-line-expanded-p)))
  881. ;; If the next line is the same or less indentation, expand.
  882. (let ((fcn (get-text-property (point) 'ddebug-function)))
  883. (when fcn
  884. (funcall fcn (point))
  885. (beginning-of-line)
  886. ))))
  887. (defun data-debug-contract-current-line ()
  888. "Contract the current line (if possible).
  889. Do nothing if already contracted."
  890. (when (and (data-debug-current-line-expanded-p)
  891. ;; Don't contract if the current line is not expandable.
  892. (get-text-property (point) 'ddebug-function))
  893. (let ((ti (current-indentation))
  894. )
  895. ;; If next indentation is larger, collapse.
  896. (end-of-line)
  897. (forward-char 1)
  898. (let ((start (point))
  899. (end nil))
  900. (condition-case nil
  901. (progn
  902. ;; Keep checking indentation
  903. (while (or (> (current-indentation) ti)
  904. (looking-at "^\\s-*$"))
  905. (end-of-line)
  906. (forward-char 1))
  907. (setq end (point))
  908. )
  909. (error (setq end (point-max))))
  910. (delete-region start end)
  911. (forward-char -1)
  912. (beginning-of-line)))))
  913. (defun data-debug-expand-or-contract ()
  914. "Expand or contract anything at the current point."
  915. (interactive)
  916. (if (and (data-debug-line-expandable-p)
  917. (data-debug-current-line-expanded-p))
  918. (data-debug-contract-current-line)
  919. (data-debug-expand-current-line))
  920. (skip-chars-forward " *-><[]" (point-at-eol)))
  921. (defun data-debug-expand-or-contract-mouse (event)
  922. "Expand or contract anything at event EVENT."
  923. (interactive "e")
  924. (let* ((win (car (car (cdr event))))
  925. )
  926. (select-window win t)
  927. (save-excursion
  928. ;(goto-char (window-start win))
  929. (mouse-set-point event)
  930. (data-debug-expand-or-contract))
  931. ))
  932. ;;; GENERIC STRUCTURE DUMP
  933. ;;
  934. (defun data-debug-show-stuff (stuff name)
  935. "Data debug STUFF in a buffer named *NAME DDebug*."
  936. (data-debug-new-buffer (concat "*" name " DDebug*"))
  937. (data-debug-insert-thing stuff "?" "")
  938. (goto-char (point-min))
  939. (when (data-debug-line-expandable-p)
  940. (data-debug-expand-current-line)))
  941. ;;; DEBUG COMMANDS
  942. ;;
  943. ;; Various commands for displaying complex data structures.
  944. (defun data-debug-edebug-expr (expr)
  945. "Dump out the contents of some expression EXPR in edebug with ddebug."
  946. (interactive
  947. (list (let ((minibuffer-completing-symbol t))
  948. (read-from-minibuffer "Eval: "
  949. nil read-expression-map t
  950. 'read-expression-history))
  951. ))
  952. (let ((v (eval expr)))
  953. (if (not v)
  954. (message "Expression %s is nil." expr)
  955. (data-debug-show-stuff v "expression"))))
  956. (defun data-debug-eval-expression (expr)
  957. "Evaluate EXPR and display the value.
  958. If the result is something simple, show it in the echo area.
  959. If the result is a list or vector, then use the data debugger to display it."
  960. (interactive
  961. (list (let ((minibuffer-completing-symbol t))
  962. (read-from-minibuffer "Eval: "
  963. nil read-expression-map t
  964. 'read-expression-history))
  965. ))
  966. (if (null eval-expression-debug-on-error)
  967. (setq values (cons (eval expr) values))
  968. (let ((old-value (make-symbol "t")) new-value)
  969. ;; Bind debug-on-error to something unique so that we can
  970. ;; detect when evalled code changes it.
  971. (let ((debug-on-error old-value))
  972. (setq values (cons (eval expr) values))
  973. (setq new-value debug-on-error))
  974. ;; If evalled code has changed the value of debug-on-error,
  975. ;; propagate that change to the global binding.
  976. (unless (eq old-value new-value)
  977. (setq debug-on-error new-value))))
  978. (if (or (consp (car values)) (vectorp (car values)))
  979. (let ((v (car values)))
  980. (data-debug-show-stuff v "Expression"))
  981. ;; Old style
  982. (prog1
  983. (prin1 (car values) t)
  984. (let ((str (eval-expression-print-format (car values))))
  985. (if str (princ str t))))))
  986. (provide 'data-debug)
  987. (if (featurep 'eieio)
  988. (require 'eieio-datadebug))
  989. ;;; data-debug.el ends here