-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathheaders.el
295 lines (263 loc) · 10.3 KB
/
headers.el
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
;; headers.el -- show first line of all definitions in a buffer
;; Michael Ernst <[email protected]>
;; 5/20/93
;; Thanks to David Glasser <[email protected]> for improvements.
;;; Commentary:
;; Function `headers' (bound to C-x C-p C-h) shows the first line of all
;; definitions in a buffer; from the definitions buffer, the user may jump
;; to one of them via "g" or "j" or "C-c C-c".
;;
;; It is easy to add support for new languages.
;;
;; This borrows ideas from page-ext.el. I would have preferred to use
;; page-ext.el, but it doesn't display the page separator, only what
;; follows it on that line.
;;
;; However, this should probably be rewritten to use page-ext.el; they are
;; quite duplicative.
;;; Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; User-visible variables
;;;
(defvar headers-regexp nil
"Regexp to use when searching for definition headers.
Overrides all other defaults. If nil, a default is used.")
(make-variable-buffer-local 'headers-regexp)
(defvar headers-omit-regexp nil
"Regexp to ignore when searching for definition headers.
Overrides all other defaults. If nil, a default is used.")
(make-variable-buffer-local 'headers-omit-regexp)
(defvar headers-scheme-regexp nil
"If non-nil, use this regexp instead of the default in Scheme mode.")
(defvar headers-internal-definitions-p nil
"If non-nil, internal definitions are included in the headers buffer.
If you set this, then you may want to set `headers-scheme-regexp' or
adjust `scheme-defform-regexp' to include named-lambda.")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Other variables
;;;
(defvar headers-code-buffer nil
"The buffer containing the code for this headers buffer.")
(make-variable-buffer-local 'headers-code-buffer)
;; This requires ANSI C, or nearly; for instance, all functions must have
;; a return type.
;; This could use a bit more work, but it catches a lot as it is.
;; It doesn't cope with user-defined types at all.
;; (defvar c-type-regexp "\\(char\\|inline\\|int\\|void\\)\\s *\\**")
(defvar c-type-regexp "\\(\\w\\|:\\)+\\s *\\**")
;; what is the colon doing here?
(defvar c-symbol-regexp "\\(\\w\\|:\\)+")
(defvar c-type-and-symbol-regexp
(concat c-type-regexp
"\\("
"\\s *"
c-symbol-regexp
"\\)?")
"Actually the type is optional.")
(defvar c-args-regexp
(concat "("
"\\("
c-type-and-symbol-regexp
",\\s *"
"\\)"
c-type-and-symbol-regexp
")"))
(defvar c-definition-regexp
(concat "^"
c-type-and-symbol-regexp
"\\("
"\\s *"
c-args-regexp
"\\)?"))
;; not \\w+, as that omits "_.".
(defvar java-word-regexp "\\b[A-Za-z0-9_]\\([A-Za-z0-9_.$<]*[A-Za-z0-9_]\\)?\\b>?")
;; Empty square brackets with leading space.
(defvar square-brackets-regexp "\\(\\s *\\[\\s *\\]\\)")
;; Like type-and-symbol; maybe just 1 symbol
(defvar java-symbols-regexp
(concat java-word-regexp square-brackets-regexp "*"
"\\(\\s +" java-word-regexp square-brackets-regexp "*" "\\)*"
))
(defvar java-args-regexp
(concat "(\\s *"
"\\("
java-symbols-regexp
"\\("
"\\s *,\\s *"
java-symbols-regexp
"\\)*"
"\\s *"
"\\)?"
")"
"[ \t]*\\($\\|[^ \t.]\\)" ; aviod "foo()" in "foo().bar();"
))
;; Unfortunately, this doesn't get member variables, only methods.
;; I don't see how to get the member variables without catching too
;; many local variables.
(defvar java-definition-regexp
(concat "\\("
"^[ \t]*"
java-symbols-regexp
"\\("
"\\s *"
java-args-regexp
"\\)"
"\\|"
"^[ \t]*\\(\\(public\\|private\\|protected\\|final\\|abstract\\)\\b.*\\)?\\bclass\\b"
"\\)"))
(defvar java-nondefinition-regexp
(concat
"^[ \t]*\\(catch\\|if\\|return\\|switch\\|while\\)\\b" ; these aren't (typeless) methods
"\\|"
"^[ \t]*[^a].*\;$" ; ends w/semicolon, but isn't abstract
))
(defvar headers-map (make-sparse-keymap)
"Keymap for the headers buffer.")
(define-key headers-map "\C-c\C-c" 'headers-goto)
(define-key headers-map "g" 'headers-goto)
(define-key headers-map "j" 'headers-goto)
(define-key headers-map "\C-m" 'headers-goto)
(define-key headers-map [mouse-2] 'headers-mouse-goto)
(define-key headers-map " " 'next-line)
(define-key headers-map "n" 'next-line)
(define-key headers-map "p" 'previous-line)
(if (not (boundp 'ctl-x-ctl-p-map))
(progn
(defvar ctl-x-ctl-p-map (make-sparse-keymap)
"Keymap for subcommands of C-x C-p, which are for page handling.")
(fset 'ctl-x-ctl-p-prefix ctl-x-ctl-p-map)
(global-unset-key "\C-x\C-p")
(define-key ctl-x-map "\C-p" 'ctl-x-ctl-p-prefix)
(define-key ctl-x-ctl-p-map "\C-m" 'mark-page)
(fset 'ctl-x-ctl-p-prefix ctl-x-ctl-p-map)))
(define-key ctl-x-ctl-p-map "\C-h" 'headers)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Computing headers
;;;
;; This ought to go to a nearby definition, not stay at the beginning of
;; the buffer.
(defun headers ()
"Display a buffer of definition \(function\) headers for this code buffer."
(interactive)
(let ((code-buffer (current-buffer))
(code-tab-width tab-width)
(header-buffer (get-buffer-create
(concat "*Definitions in: " (buffer-name))))
(current-header (save-excursion
(end-of-defun 1) ; associate comments w/following def
(beginning-of-defun 1)
(concat "\n" (buffer-line) "\n")))
(regexp (headers-regexp))
(omit-regexp (headers-omit-regexp))
(page-regexp (or (headers-page-delimiter) page-delimiter)))
(pop-to-buffer header-buffer)
(buffer-disable-undo header-buffer)
(setq buffer-read-only nil)
(erase-buffer)
(setq tab-width code-tab-width)
(use-local-map headers-map)
(setq headers-code-buffer code-buffer)
(insert-buffer-substring headers-code-buffer)
(goto-char (point-min))
(delete-non-matching-lines (concat "\\(" regexp "\\|" page-regexp "\\)"))
(if omit-regexp
(delete-matching-lines omit-regexp))
(replace-regexp-noninteractive "\n\n\n+" "\n\n")
(goto-char (point-min))
(if (search-forward current-header nil t)
(forward-line -1))
(shrink-window-if-larger-than-buffer)
(set-buffer-modified-p nil)
(setq buffer-read-only t)))
(defun headers-goto ()
"Go to the definition whose header is under point."
(interactive)
(let* ((string (concat "\n" (buffer-line) "\n")))
(pop-to-buffer headers-code-buffer)
(push-mark)
(goto-char (point-min))
(search-forward string)
(forward-line -1)))
(defun headers-mouse-goto (event)
"Go to the definition whose header is clicked upon."
(interactive "e")
(save-excursion
(set-buffer (window-buffer (posn-window (event-end event))))
(goto-char (posn-point (event-end event)))
(headers-goto)))
(defun buffer-line ()
"Return the text of the current line of the buffer."
(buffer-substring (line-beginning-position) (line-end-position)))
(defun headers-regexp ()
"Return a regular expression for finding headers in the current major mode."
(or headers-regexp
(cond ((or (eq major-mode 'scheme-mode)
(eq major-mode 'chez-scheme-mode))
(or headers-scheme-regexp
(concat (if headers-internal-definitions-p "^[\t ]*(" "^\(")
(substring (or scheme-defform-regexp "^def") 1))))
((or (eq major-mode 'lisp-mode)
(eq major-mode 'emacs-lisp-mode)
(eq major-mode 'fi:common-lisp-mode))
"^\(def")
((or (eq major-mode 'c-mode)
(eq major-mode 'c++-mode))
c-definition-regexp)
((or (eq major-mode 'java-mode)
(eq major-mode 'jde-mode))
java-definition-regexp)
((eq major-mode 'perl-mode)
"^\\(sub\\|my\\)\\b")
((eq major-mode 'python-mode)
"^[ \t]*\\(def\\|class\\)\\b")
((eq major-mode 'texinfo-mode)
"^@\\(chapter\\|\\(sub\\)*section\\)[ \t]")
((eq major-mode 'cecil-mode)
;; This is giving me trouble: doesn't always include everything.
(let ((top-alternatives
(list
(concat ;; (regexp-opt
;; '("abstract" "template" "concrete" "dynamic")
;; 'paren)
"\\(abstract\\|concrete\\|dynamic\\|template\\)"
"?"
"[ \t]*"
;; (regexp-opt
;; '("representation" "object") 'paren)
"\\(object\\|representation\\)")
;; (regexp-opt
;; '("type" "predicate" "signature" "method" "module") 'paren)
"\\(m\\(ethod\\|odule\\)\\|predicate\\|signature\\|type\\)"
(concat "extend[ \t]+"
;; (regexp-opt
;; '("type" "representation" "object") 'paren)
;; "?"
)
;; "\\(method[ \t]+\\)?implementation"
(concat
"\\(shared[ \t]+\\)?"
"\\(var[ \t]+\\)?"
"field[ \t]+"
;; (regexp-opt
;; '("signature" "field implementation") 'paren)
;; "?"
))))
(concat
"^[ \t]*\\(public\\|private\\|protected\\)?[ \t]*"
(regexp-opt top-alternatives 'paren)
"\\b")))
(t
(error "headers.el doesn't understand %s; please teach it"
major-mode)))))
(defun headers-omit-regexp ()
"Return regexp for omitted headers in current major mode."
(or headers-omit-regexp
(cond
((or (eq major-mode 'java-mode)
(eq major-mode 'jde-mode))
java-nondefinition-regexp))))
(defun headers-page-delimiter ()
"Return page delimiter for current major mode."
nil)
(provide 'headers)
;;; headers.el ends here