File: sepia-tree.el

package info (click to toggle)
sepia 0.992-7
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 648 kB
  • sloc: perl: 2,811; lisp: 2,655; sh: 46; makefile: 14
file content (145 lines) | stat: -rw-r--r-- 4,851 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
;;; sepia-tree.el -- tree-widget-based calle[re] navigation

;; Copyright (C) 2004-2008 Sean O'Rourke.  All rights reserved, some
;; wrongs reversed.  This code is distributed under the same terms as
;; Perl itself.

;;; Commentary:

;; See the README file that comes with the distribution.

;;; Code:

(require 'tree-widget)
(require 'cl)

(defvar sepia-tree-use-image nil
  "*If non-nil, show tree-widget with icons.")

(defun sepia-tree-button-cb (widget &rest blah)
  (let* ((pw (widget-get widget :parent))
         (wid-name (widget-get pw :sepia-name))
         (location (and wid-name (car (xref-location wid-name)))))
    (cond
      ((not location) (error "Can't find %s." wid-name))
      (current-prefix-arg
       (find-file-other-window (car location))
       (sepia-set-found (list location) 'function)
       (sepia-next))
      ((widget-get widget :sepia-shown-p)
       (save-excursion
	 (end-of-line)
	 (let ((inhibit-read-only t))
	   (delete-region (point)
			  (+ 1 (point) (widget-get widget :sepia-shown-p))))
	 (widget-put widget :sepia-shown-p nil)))
      (t
       (let ((str (apply #'sepia-extract-def location)))
	 (if str
	     (save-excursion
	       (end-of-line)
	       (widget-put widget :sepia-shown-p (length str))
	       (widget-insert "\n" str))
	     (message "(not found)")))))))

(defun sepia-tree-node-cb (widget &rest blah)
  (let ((func (widget-get widget :sepia-func)))
    (or (widget-get widget :args)
	(let ((children (funcall func widget)))
	  (if children
	      (mapcar
	       (lambda (x) (sepia-tree-node func x))
	       children)
	      (widget-put widget :has-children nil))))))

(defun sepia-tree-node (func name)
  "Make a tree node for the object specified by FILE, LINE, OBJ,
and MOD.  The new node will have a property :sepia-X
corresponding to each of these values.  FUNC is a function that
will, given a widget, generate its children."
  `(tree-widget
    :node (push-button
	   :tag ,name
	   :format "%[%t%]\n"
	   :notify sepia-tree-button-cb)
    :dynargs sepia-tree-node-cb
    :has-children t
    :sepia-name ,name
    :sepia-func ,func))

(defun sepia-tree-tidy-buffer (name)
  "Get/create a new, tidy buffer for the tree widget."
  (switch-to-buffer name)
  (kill-all-local-variables)
  ;; because the widget images are ugly.
  (set (make-local-variable 'widget-image-enable) sepia-tree-use-image)
  (let ((inhibit-read-only t))
    (erase-buffer))
  (let ((all (overlay-lists)))
    (mapcar #'delete-overlay (car all))
    (mapcar #'delete-overlay (cdr all)))
  (toggle-read-only 1)
  (view-mode -1))

(defun sepia-build-tree-buffer (func defs bufname)
  (if defs
      (lexical-let ((func func))
        (sepia-tree-tidy-buffer bufname)
        (with-current-buffer bufname
          (dolist (x defs)
            (widget-create
                   (sepia-tree-node
                    (lambda (widget)
                      (funcall func (widget-get widget :sepia-name)))
                    x)))
          (use-local-map (copy-keymap widget-keymap))
;;        (local-set-key "\M-." sepia-keymap)
;;        (sepia-install-keys)
          (let ((view-read-only nil))
            (toggle-read-only 1))
          (goto-char (point-min))
	  (message "Type C-h m for usage information")))
      (message "No items for %s" bufname)))

;;;###autoload
(defun sepia-callee-tree (name)
  "Create a tree view of a function's callees.

Pressing RET on a function's name displays its definition.  With
prefix argument, RET instead visits in another window."
  (interactive (let ((func (sepia-interactive-arg 'function))
                     (mod (sepia-interactive-module)))
                 (list (if mod (format "%s::%s" mod func)
                           func))))
  (let* ((defs (xref-apropos name)))
    (sepia-build-tree-buffer
     #'xref-callees
     defs
     (format "*%s callees*" name))))

(defun sepia-caller-tree (name)
  "Create a tree view of a function's callers.

Pressing RET on a function's name displays its definition.  With
prefix argument, RET instead visits in another window."
  (interactive (let ((func (sepia-interactive-arg 'function))
                     (mod (sepia-interactive-module)))
                 (list (if mod (format "%s::%s" mod func)
                           func))))
  (let* ((defs (xref-apropos name)))
    (sepia-build-tree-buffer
     #'xref-callers
     defs (format "*%s callers*" name))))

;;;###autoload
(defun sepia-module-callee-tree (mod)
  "Display a callee tree for each of MOD's subroutines.

Pressing RET on a function's name displays its definition.  With
prefix argument, RET instead visits in another window."
  (interactive (list (sepia-interactive-arg 'module)))
  (let ((defs (xref-mod-subs mod)))
    (sepia-build-tree-buffer #'xref-callees defs (format "*%s subs*" mod))))

(provide 'sepia-tree)
;;; sepia.el ends here