1
(require 'speedbar)
2
3
(defvar rails-speedbar:roots
4
  '(("Controllers"      rails-core:controllers       rails-core:controller-file)
5
    ("Helpers"          rails-core:helpers           rails-core:helper-file)
6
    ("Models"           rails-core:models            rails-core:model-file)
7
    ("Observers"        rails-core:observers         rails-core:observer-file)
8
    ("Mailers"          rails-core:mailers           rails-core:mailer-file)
9
    ("Migrations"       rails-core:migrations        rails-core:migration-file)
10
    ("Functional Tests" rails-core:functional-tests  rails-core:functional-test-file)
11
    ("Unit Tests"       rails-core:unit-tests        rails-core:unit-test-file)
12
    ("Fixtures"         rails-core:fixtures          rails-core:fixture-file)
13
    ("RSpec Controllers" rails-core:rspec-controllers  rails-core:rspec-controller-file)
14
    ("RSpec Fixtures"    rails-core:rspec-fixtures     rails-core:rspec-fixture-file)
15
    ("RSpec Lib"         rails-core:rspec-lib          rails-core:rspec-lib-file)
16
    ("RSpec Models"      rails-core:rspec-models       rails-core:rspec-model-file)
17
    ("RSpec Views"       rails-core:rspec-views        rails-core:rspec-view-file)
18
    ("Fixtures"          rails-core:fixtures           rails-core:fixture-file)
19
    ("Configuration"    rails-core:configuration-files rails-core:configuration-file)))
20
21
(defvar rails-speedbar:menu-items nil)
22
(defvar rails-speedbar:key-map
23
  (let ((map (speedbar-make-specialized-keymap)))
24
    (define-key map " " 'speedbar-toggle-line-expansion)
25
    (define-key map "+" 'speedbar-expand-line)
26
    (define-key map "=" 'speedbar-expand-line)
27
    (define-key map "-" 'speedbar-contract-line)
28
    (define-key map "e" 'speedbar-edit-line)
29
    (define-key map "\C-m" 'speedbar-edit-line)
30
    map))
31
32
(defun rails-speedbar:display (directory depth)
33
  (setq speedbar-update-flag nil)
34
  (speedbar-with-writable
35
    (insert (rails-project:root) "\n"))
36
  (dolist (i rails-speedbar:roots)
37
    (speedbar-make-tag-line 'angle
38
                            ?+
39
                            'rails-speedbar:expand-group
40
                            (car i)
41
                            (car i)
42
                            nil
43
                            nil
44
                            nil
45
                            depth))
46
  (speedbar-make-tag-line 'angle
47
                          ?+
48
                          'rails-speedbar:expand-directory
49
                          (concat (rails-speedbar:root) "app/views")
50
                          "Views"
51
                          nil
52
                          nil
53
                          nil
54
                          depth))
55
56
(defun rails-speedbar:expand-directory (text token indent)
57
  (cond
58
   ((string-match "+" text)
59
    (speedbar-change-expand-button-char ?-)
60
    (let ((files (directory-files token nil "^[^.]")))
61
      (save-excursion
62
        (end-of-line) (forward-char 1)
63
        (speedbar-with-writable
64
        (dolist (i files)
65
          (if (file-directory-p (format "%s/%s" token i))
66
              (speedbar-make-tag-line 'curly
67
                                      ?+
68
                                      'rails-speedbar:expand-directory
69
                                      (format "%s/%s" token i)
70
                                      i
71
                                      nil nil nil
72
                                      (+ 1 indent))
73
            (speedbar-make-tag-line 'statictag
74
                                    ??
75
                                    nil
76
                                    nil
77
                                    i
78
                                    'rails-speedbar:find-file
79
                                    (format "%s/%s" token i)
80
                                    nil
81
                                    (+ 1 indent))))))))
82
   ((string-match "-" text)
83
    (speedbar-change-expand-button-char ?+)
84
    (speedbar-delete-subblock indent))))
85
86
(defun rails-speedbar:expand-group (text token indent)
87
  (cond
88
   ((string-match "+" text)
89
    (speedbar-change-expand-button-char ?-)
90
    (let* ((fn (find-if #'(lambda(i) (string= token (car i)))
91
                        rails-speedbar:roots))
92
           (lst (apply (nth 1 fn) (list)))
93
           (find (nth 2 fn)))
94
      (speedbar-with-writable
95
        (save-excursion
96
          (end-of-line) (forward-char 1)
97
          (dolist (i lst)
98
            (speedbar-make-tag-line 'bracket
99
                                    ?+
100
                                    'rails-speedbar:expand-tags
101
                                    (rails-speedbar:in-root (rails-core:file (apply find (list i))))
102
                                    i
103
                                    'rails-speedbar:find-file
104
                                    (rails-speedbar:in-root (rails-core:file (apply find (list i))))
105
                                    nil
106
                                    (+ indent 1)))))))
107
   ((string-match "-" text)
108
    (speedbar-change-expand-button-char ?+)
109
    (speedbar-delete-subblock indent))))
110
111
(defun rails-speedbar:expand-tags (text token indent)
112
  (cond
113
   ((string-match "+" text)
114
    (let ((lst (speedbar-fetch-dynamic-tags token)))
115
      (if (not lst)
116
          (speedbar-change-expand-button-char ??)
117
        (progn
118
          (speedbar-change-expand-button-char ?-)
119
          (speedbar-with-writable
120
            (save-excursion
121
              (end-of-line) (forward-char 1)
122
              (speedbar-insert-generic-list indent
123
                                            (cdr lst)
124
                                            'speedbar-tag-expand
125
                                            'speedbar-tag-find)))))))
126
   ((string-match "-" text)
127
    (speedbar-change-expand-button-char ?+)
128
    (speedbar-delete-subblock indent))))
129
130
(defun rails-speedbar:line-directory (&optional depth)
131
  (save-excursion
132
    (end-of-line)
133
    (let ((start (point)))
134
      (when (search-backward "[-]" nil t)
135
        (end-of-line)
136
        (skip-syntax-backward "w")
137
        (get-text-property (point) 'speedbar-token)))))
138
139
(defun rails-speedbar:find-file (text token indent)
140
  (typecase token
141
    (string (speedbar-find-file-in-frame token))))
142
143
(defun rails-speedbar:root ()
144
  (save-excursion
145
    (goto-char (point-min))
146
    (let* ((root (current-line-string))
147
           (root (if (file-directory-p root)
148
                     root
149
                   (rails-project:root))))
150
      root)))
151
152
(defmacro rails-speedbar:in-root (&rest body)
153
  `(flet ((rails-project:root () ,(rails-speedbar:root)))
154
     ,@body))
155
156
(defun rails-speedbar:get-focus ()
157
  (interactive)
158
  (speedbar-change-initial-expansion-list "Ruby On Rails")
159
  (let ((default-directory (rails-project:root)))
160
    (speedbar-get-focus)))
161
162
(defun rails-speedbar-feature:install ()
163
  (speedbar-add-expansion-list
164
   '("Ruby On Rails"
165
     rails-speedbar:menu-items
166
     rails-speedbar:key-map
167
     rails-speedbar:display))
168
  (speedbar-add-mode-functions-list
169
   '("Ruby On Rails"
170
     (speedbar-line-directory . rails-speedbar:line-directory)))
171
172
  (define-key rails-minor-mode-map (kbd "<f11>") 'rails-speedbar:get-focus)
173
  (define-key-after
174
    (lookup-key rails-minor-mode-map [menu-bar rails])
175
    [speedbar] '("Toggle Speedbar" . rails-speedbar:get-focus)
176
    'svn-status))
177
178
(provide 'rails-speedbar-feature)