Commit | Line | Data |
---|---|---|
785eecbb RS |
1 | ;;; cc-menus.el --- imenu support for CC Mode |
2 | ||
d9e94c22 | 3 | ;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. |
785eecbb | 4 | |
d9e94c22 MS |
5 | ;; Authors: 1998- Martin Stjernholm |
6 | ;; 1992-1999 Barry A. Warsaw | |
785eecbb RS |
7 | ;; 1987 Dave Detlefs and Stewart Clamen |
8 | ;; 1985 Richard M. Stallman | |
0ec8351b | 9 | ;; Maintainer: bug-cc-mode@gnu.org |
785eecbb | 10 | ;; Created: 22-Apr-1997 (split from cc-mode.el) |
8729df59 | 11 | ;; Version: See cc-mode.el |
785eecbb RS |
12 | ;; Keywords: c languages oop |
13 | ||
14 | ;; This file is part of GNU Emacs. | |
15 | ||
16 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
17 | ;; it under the terms of the GNU General Public License as published by | |
18 | ;; the Free Software Foundation; either version 2, or (at your option) | |
19 | ;; any later version. | |
20 | ||
21 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
22 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | ;; GNU General Public License for more details. | |
25 | ||
26 | ;; You should have received a copy of the GNU General Public License | |
a66cd3ee | 27 | ;; along with GNU Emacs; see the file COPYING. If not, write to |
130c507e | 28 | ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
785eecbb RS |
29 | ;; Boston, MA 02111-1307, USA. |
30 | ||
3afbc435 PJ |
31 | ;;; Commentary: |
32 | ||
33 | ;;; Code: | |
34 | ||
0ec8351b | 35 | (eval-when-compile |
51f606de | 36 | (let ((load-path |
130c507e GM |
37 | (if (and (boundp 'byte-compile-dest-file) |
38 | (stringp byte-compile-dest-file)) | |
39 | (cons (file-name-directory byte-compile-dest-file) load-path) | |
51f606de | 40 | load-path))) |
d9e94c22 MS |
41 | (load "cc-bytecomp" nil t))) |
42 | ||
43 | (cc-require 'cc-defs) | |
51f606de | 44 | |
130c507e GM |
45 | ;; The things referenced in imenu, which we don't require. |
46 | (cc-bytecomp-defvar imenu-case-fold-search) | |
47 | (cc-bytecomp-defvar imenu-generic-expression) | |
d9e94c22 | 48 | (cc-bytecomp-defvar imenu-create-index-function) |
130c507e | 49 | (cc-bytecomp-defun imenu-progress-message) |
0ec8351b | 50 | |
785eecbb RS |
51 | \f |
52 | ;; imenu integration | |
05896d77 KH |
53 | (defvar cc-imenu-c-prototype-macro-regexp nil |
54 | "RE matching macro names used to conditionally specify function prototypes. | |
55 | ||
56 | For example: | |
57 | ||
58 | #ifdef __STDC__ | |
59 | #define _P(x) x | |
60 | #else | |
61 | #define _P(x) /*nothing*/ | |
62 | #endif | |
63 | ||
64 | int main _P( (int argc, char *argv[]) ) | |
65 | ||
66 | A sample value might look like: `\\(_P\\|_PROTO\\)'.") | |
67 | ||
785eecbb | 68 | (defvar cc-imenu-c++-generic-expression |
51f606de | 69 | `( |
05896d77 KH |
70 | ;; Try to match ::operator definitions first. Otherwise `X::operator new ()' |
71 | ;; will be incorrectly recognised as function `new ()' because the regexps | |
72 | ;; work by backtracking from the end of the definition. | |
73 | (nil | |
51f606de | 74 | ,(concat |
05896d77 | 75 | "^\\<.*" |
d9e94c22 | 76 | "[^" c-alnum "_:<>~]" ; match any non-identifier char |
05896d77 KH |
77 | ; (note: this can be `\n') |
78 | "\\(" | |
d9e94c22 | 79 | "\\([" c-alnum "_:<>~]*::\\)?" ; match an operator |
05896d77 KH |
80 | "operator\\>[ \t]*" |
81 | "\\(()\\|[^(]*\\)" ; special case for `()' operator | |
82 | "\\)" | |
83 | ||
84 | "[ \t]*([^)]*)[ \t]*[^ \t;]" ; followed by ws, arg list, | |
85 | ; require something other than | |
86 | ; a `;' after the (...) to | |
87 | ; avoid prototypes. Can't | |
88 | ; catch cases with () inside | |
89 | ; the parentheses surrounding | |
90 | ; the parameters. e.g.: | |
91 | ; `int foo(int a=bar()) {...}' | |
51f606de | 92 | ) 1) |
05896d77 KH |
93 | ;; Special case to match a line like `main() {}' |
94 | ;; e.g. no return type, not even on the previous line. | |
95 | (nil | |
51f606de | 96 | ,(concat |
05896d77 | 97 | "^" |
d9e94c22 | 98 | "\\([" c-alpha "_][" c-alnum "_:<>~]*\\)" ; match function name |
f1063b2f RS |
99 | "[ \t]*(" ; see above, BUT |
100 | "[ \t]*\\([^ \t(*][^)]*\\)?)" ; the arg list must not start | |
101 | "[ \t]*[^ \t;(]" ; with an asterisk or parentheses | |
51f606de | 102 | ) 1) |
8729df59 KH |
103 | ;; General function name regexp |
104 | (nil | |
51f606de GM |
105 | ,(concat |
106 | "^\\<" ; line MUST start with word char | |
107 | "[^()]*" ; no parentheses before | |
d9e94c22 MS |
108 | "[^" c-alnum "_:<>~]" ; match any non-identifier char |
109 | "\\([" c-alpha "_][" c-alnum "_:<>~]*\\)" ; match function name | |
a66cd3ee MS |
110 | "\\([ \t\n]\\|\\\\\n\\)*(" ; see above, BUT the arg list |
111 | "\\([ \t\n]\\|\\\\\n\\)*\\([^ \t\n(*][^)]*\\)?)" ; must not start | |
112 | "\\([ \t\n]\\|\\\\\n\\)*[^ \t\n;(]" ; with an asterisk or parentheses | |
51f606de | 113 | ) 1) |
05896d77 KH |
114 | ;; Special case for definitions using phony prototype macros like: |
115 | ;; `int main _PROTO( (int argc,char *argv[]) )'. | |
116 | ;; This case is only included if cc-imenu-c-prototype-macro-regexp is set. | |
117 | ;; Only supported in c-code, so no `:<>~' chars in function name! | |
51f606de GM |
118 | ,@(if cc-imenu-c-prototype-macro-regexp |
119 | `((nil | |
120 | ,(concat | |
05896d77 | 121 | "^\\<.*" ; line MUST start with word char |
d9e94c22 MS |
122 | "[^" c-alnum "_]" ; match any non-identifier char |
123 | "\\([" c-alpha "_][" c-alnum "_]*\\)" ; match function name | |
05896d77 KH |
124 | "[ \t]*" ; whitespace before macro name |
125 | cc-imenu-c-prototype-macro-regexp | |
126 | "[ \t]*(" ; ws followed by first paren. | |
8729df59 | 127 | "[ \t]*([^)]*)[ \t]*)[ \t]*[^ \t;]" ; see above |
51f606de | 128 | ) 1))) |
05896d77 | 129 | ;; Class definitions |
d9e94c22 | 130 | ("Class" |
51f606de | 131 | ,(concat |
05896d77 KH |
132 | "^" ; beginning of line is required |
133 | "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a `template <...>' | |
130c507e | 134 | "\\(class\\|struct\\)[ \t]+" |
0ec8351b | 135 | "\\(" ; the string we want to get |
d9e94c22 | 136 | "[" c-alnum "_]+" ; class name |
130c507e | 137 | "\\(<[^>]+>\\)?" ; possibly explicitly specialized |
0ec8351b | 138 | "\\)" |
a66cd3ee | 139 | "\\([ \t\n]\\|\\\\\n\\)*[:{]" |
130c507e | 140 | ) 3)) |
785eecbb | 141 | "Imenu generic expression for C++ mode. See `imenu-generic-expression'.") |
d9e94c22 | 142 | |
785eecbb RS |
143 | (defvar cc-imenu-c-generic-expression |
144 | cc-imenu-c++-generic-expression | |
145 | "Imenu generic expression for C mode. See `imenu-generic-expression'.") | |
146 | ||
785eecbb | 147 | (defvar cc-imenu-java-generic-expression |
51f606de GM |
148 | `((nil |
149 | ,(concat | |
d9e94c22 MS |
150 | "[" c-alpha "_][\]\[." c-alnum "_]+[ \t\n\r]+" ; type spec |
151 | "\\([" c-alpha "_][" c-alnum "_]+\\)" ; method name | |
152 | "[ \t\n\r]*" | |
153 | ;; An argument list that is either empty or contains at least | |
154 | ;; two identifiers with only space between them. This avoids | |
155 | ;; matching e.g. "else if (foo)". | |
156 | (concat "([ \t\n\r]*" | |
157 | "\\([\]\[.," c-alnum "_]+" | |
158 | "[ \t\n\r]+" | |
159 | "[\]\[.," c-alnum "_]" | |
160 | "[\]\[.," c-alnum "_ \t\n\r]*" | |
161 | "\\)?)") | |
162 | "[.," c-alnum "_ \t\n\r]*" | |
163 | "{" | |
164 | ) 1)) | |
785eecbb RS |
165 | "Imenu generic expression for Java mode. See `imenu-generic-expression'.") |
166 | ||
d9e94c22 | 167 | ;; *Warning for cc-mode developers* |
f1063b2f RS |
168 | ;; |
169 | ;; `cc-imenu-objc-generic-expression' elements depend on | |
170 | ;; `cc-imenu-c++-generic-expression'. So if you change this | |
171 | ;; expression, you need to change following variables, | |
172 | ;; `cc-imenu-objc-generic-expression-*-index', | |
173 | ;; too. `cc-imenu-objc-function' uses these *-index variables, in | |
174 | ;; order to know where the each regexp *group \\(foobar\\)* elements | |
175 | ;; are started. | |
176 | ;; | |
d9e94c22 MS |
177 | ;; *-index variables are initialized during `cc-imenu-objc-generic-expression' |
178 | ;; being initialized. | |
f1063b2f RS |
179 | ;; |
180 | ||
181 | ;; Internal variables | |
182 | (defvar cc-imenu-objc-generic-expression-noreturn-index nil) | |
183 | (defvar cc-imenu-objc-generic-expression-general-func-index nil) | |
184 | (defvar cc-imenu-objc-generic-expression-proto-index nil) | |
185 | (defvar cc-imenu-objc-generic-expression-objc-base-index nil) | |
186 | ||
d9e94c22 MS |
187 | (defvar cc-imenu-objc-generic-expression |
188 | (concat | |
8729df59 | 189 | ;; |
d9e94c22 | 190 | ;; For C |
8729df59 KH |
191 | ;; |
192 | ;; > Special case to match a line like `main() {}' | |
193 | ;; > e.g. no return type, not even on the previous line. | |
194 | ;; Pick a token by (match-string 1) | |
f1063b2f RS |
195 | (car (cdr (nth 1 cc-imenu-c++-generic-expression))) ; -> index += 2 |
196 | (prog2 (setq cc-imenu-objc-generic-expression-noreturn-index 1) "") | |
8729df59 KH |
197 | "\\|" |
198 | ;; > General function name regexp | |
f1063b2f | 199 | ;; Pick a token by (match-string 3) |
d9e94c22 | 200 | (car (cdr (nth 2 cc-imenu-c++-generic-expression))) ; -> index += 5 |
f1063b2f | 201 | (prog2 (setq cc-imenu-objc-generic-expression-general-func-index 3) "") |
8729df59 KH |
202 | ;; > Special case for definitions using phony prototype macros like: |
203 | ;; > `int main _PROTO( (int argc,char *argv[]) )'. | |
d9e94c22 | 204 | ;; Pick a token by (match-string 8) |
8729df59 | 205 | (if cc-imenu-c-prototype-macro-regexp |
d9e94c22 | 206 | (concat |
8729df59 | 207 | "\\|" |
f1063b2f | 208 | (car (cdr (nth 3 cc-imenu-c++-generic-expression))) ; -> index += 1 |
d9e94c22 | 209 | (prog2 (setq cc-imenu-objc-generic-expression-objc-base-index 9) "") |
f1063b2f | 210 | ) |
d9e94c22 | 211 | (prog2 (setq cc-imenu-objc-generic-expression-objc-base-index 8) "") |
f1063b2f | 212 | "") ; -> index += 0 |
d9e94c22 | 213 | (prog2 (setq cc-imenu-objc-generic-expression-proto-index 8) "") |
8729df59 | 214 | ;; |
05896d77 | 215 | ;; For Objective-C |
d9e94c22 | 216 | ;; Pick a token by (match-string 8 or 9) |
8729df59 | 217 | ;; |
d9e94c22 MS |
218 | "\\|\\(" |
219 | "^[-+][:" c-alnum "()*_<>\n\t ]*[;{]" ; Methods | |
220 | "\\|" | |
221 | "^@interface[\t ]+[" c-alnum "_]+[\t ]*:" | |
222 | "\\|" | |
223 | "^@interface[\t ]+[" c-alnum "_]+[\t ]*([" c-alnum "_]+)" | |
224 | "\\|" | |
05896d77 | 225 | ;; For NSObject, NSProxy and Object... They don't have super class. |
d9e94c22 MS |
226 | "^@interface[\t ]+[" c-alnum "_]+[\t ]*.*$" |
227 | "\\|" | |
228 | "^@implementation[\t ]+[" c-alnum "_]+[\t ]*([" c-alnum "_]+)" | |
229 | "\\|" | |
230 | "^@implementation[\t ]+[" c-alnum "_]+" | |
231 | "\\|" | |
232 | "^@protocol[\t ]+[" c-alnum "_]+" "\\)") | |
05896d77 KH |
233 | "Imenu generic expression for ObjC mode. See `imenu-generic-expression'.") |
234 | ||
235 | ||
236 | ;; Imenu support for objective-c uses functions. | |
237 | (defsubst cc-imenu-objc-method-to-selector (method) | |
238 | "Return the objc selector style string of METHOD. | |
d9e94c22 | 239 | Example: |
05896d77 KH |
240 | - perform: (SEL)aSelector withObject: object1 withObject: object2; /* METHOD */ |
241 | => | |
242 | -perform:withObject:withObject:withObject: /* selector */" | |
d9e94c22 | 243 | ;; This function does not do any hidden buffer changes. |
05896d77 | 244 | (let ((return "") ; String to be returned |
d9e94c22 MS |
245 | (p 0) ; Current scanning position in METHOD |
246 | (pmax (length method)) ; | |
05896d77 KH |
247 | char ; Current scanning target |
248 | (betweenparen 0) ; CHAR is in parentheses. | |
249 | argreq ; An argument is required. | |
250 | inargvar) ; position of CHAR is in an argument variable. | |
251 | (while (< p pmax) | |
252 | (setq char (aref method p) | |
253 | p (1+ p)) | |
254 | (cond | |
255 | ;; Is CHAR part of a objc token? | |
256 | ((and (not inargvar) ; Ignore if CHAR is part of an argument variable. | |
257 | (eq 0 betweenparen) ; Ignore if CHAR is in parentheses. | |
258 | (or (and (<= ?a char) (<= char ?z)) | |
259 | (and (<= ?A char) (<= char ?Z)) | |
260 | (and (<= ?0 char) (<= char ?9)) | |
261 | (= ?_ char))) | |
d9e94c22 | 262 | (if argreq |
05896d77 KH |
263 | (setq inargvar t |
264 | argreq nil) | |
265 | (setq return (concat return (char-to-string char))))) | |
266 | ;; Or a white space? | |
d9e94c22 | 267 | ((and inargvar (or (eq ?\ char) (eq ?\n char)) |
05896d77 KH |
268 | (setq inargvar nil))) |
269 | ;; Or a method separator? | |
270 | ;; If a method separator, the next token will be an argument variable. | |
d9e94c22 MS |
271 | ((eq ?: char) |
272 | (setq argreq t | |
05896d77 KH |
273 | return (concat return (char-to-string char)))) |
274 | ;; Or an open parentheses? | |
275 | ((eq ?\( char) | |
276 | (setq betweenparen (1+ betweenparen))) | |
277 | ;; Or a close parentheses? | |
278 | ((eq ?\) char) | |
279 | (setq betweenparen (1- betweenparen))))) | |
280 | return)) | |
281 | ||
282 | (defun cc-imenu-objc-remove-white-space (str) | |
283 | "Remove all spaces and tabs from STR." | |
d9e94c22 | 284 | ;; This function does not do any hidden buffer changes. |
05896d77 KH |
285 | (let ((return "") |
286 | (p 0) | |
d9e94c22 | 287 | (max (length str)) |
05896d77 KH |
288 | char) |
289 | (while (< p max) | |
290 | (setq char (aref str p)) | |
291 | (setq p (1+ p)) | |
292 | (if (or (= char ?\ ) (= char ?\t)) | |
293 | () | |
294 | (setq return (concat return (char-to-string char))))) | |
295 | return)) | |
296 | ||
297 | (defun cc-imenu-objc-function () | |
298 | "imenu supports for objc-mode." | |
d9e94c22 | 299 | ;; This function does not do any hidden buffer changes. |
05896d77 KH |
300 | (let (methodlist |
301 | clist | |
8729df59 | 302 | ;; |
f1063b2f | 303 | ;; OBJC, Cnoreturn, Cgeneralfunc, Cproto are constants. |
8729df59 | 304 | ;; |
d9e94c22 | 305 | ;; *Warning for developers* |
8729df59 KH |
306 | ;; These constants depend on `cc-imenu-c++-generic-expression'. |
307 | ;; | |
f1063b2f RS |
308 | (OBJC cc-imenu-objc-generic-expression-objc-base-index) |
309 | ;; Special case to match a line like `main() {}' | |
310 | (Cnoreturn cc-imenu-objc-generic-expression-noreturn-index) | |
311 | ;; General function name regexp | |
312 | (Cgeneralfunc cc-imenu-objc-generic-expression-general-func-index) | |
313 | ;; Special case for definitions using phony prototype macros like: | |
314 | (Cproto cc-imenu-objc-generic-expression-proto-index) | |
05896d77 | 315 | langnum |
8729df59 | 316 | ;; |
05896d77 KH |
317 | (classcount 0) |
318 | toplist | |
319 | stupid | |
320 | str | |
d9e94c22 | 321 | str2 |
05896d77 KH |
322 | (intflen (length "@interface")) |
323 | (implen (length "@implementation")) | |
324 | (prtlen (length "@protocol")) | |
f1063b2f RS |
325 | (func |
326 | ;; | |
d9e94c22 | 327 | ;; Does this emacs has buffer-substring-no-properties? |
f1063b2f RS |
328 | ;; |
329 | (if (fboundp 'buffer-substring-no-properties) | |
330 | 'buffer-substring-no-properties | |
331 | 'buffer-substring))) | |
0ec8351b | 332 | (goto-char (point-max)) |
05896d77 KH |
333 | (imenu-progress-message stupid 0) |
334 | ;; | |
335 | (while (re-search-backward cc-imenu-objc-generic-expression nil t) | |
336 | (imenu-progress-message stupid) | |
d9e94c22 | 337 | (setq langnum (if (match-beginning OBJC) |
8729df59 KH |
338 | OBJC |
339 | (cond | |
f1063b2f RS |
340 | ((match-beginning Cproto) Cproto) |
341 | ((match-beginning Cgeneralfunc) Cgeneralfunc) | |
342 | ((match-beginning Cnoreturn) Cnoreturn)))) | |
343 | (setq str (funcall func (match-beginning langnum) (match-end langnum))) | |
05896d77 | 344 | ;; |
d9e94c22 | 345 | (cond |
05896d77 KH |
346 | ;; |
347 | ;; C | |
348 | ;; | |
8729df59 | 349 | ((not (eq langnum OBJC)) |
05896d77 KH |
350 | (setq clist (cons (cons str (match-beginning langnum)) clist))) |
351 | ;; | |
352 | ;; ObjC | |
d9e94c22 | 353 | ;; |
05896d77 KH |
354 | ;; An instance Method |
355 | ((eq (aref str 0) ?-) | |
356 | (setq str (concat "-" (cc-imenu-objc-method-to-selector str))) | |
357 | (setq methodlist (cons (cons str | |
358 | (match-beginning langnum)) | |
359 | methodlist))) | |
360 | ;; A factory Method | |
361 | ((eq (aref str 0) ?+) | |
362 | (setq str (concat "+" (cc-imenu-objc-method-to-selector str))) | |
363 | (setq methodlist (cons (cons str | |
364 | (match-beginning langnum)) | |
365 | methodlist))) | |
d9e94c22 | 366 | ;; Interface or implementation or protocol |
05896d77 KH |
367 | ((eq (aref str 0) ?@) |
368 | (setq classcount (1+ classcount)) | |
d9e94c22 | 369 | (cond |
05896d77 KH |
370 | ((and (> (length str) implen) |
371 | (string= (substring str 0 implen) "@implementation")) | |
372 | (setq str (substring str implen) | |
373 | str2 "@implementation")) | |
374 | ((string= (substring str 0 intflen) "@interface") | |
375 | (setq str (substring str intflen) | |
376 | str2 "@interface")) | |
377 | ((string= (substring str 0 prtlen) "@protocol") | |
378 | (setq str (substring str prtlen) | |
379 | str2 "@protocol"))) | |
380 | (setq str (cc-imenu-objc-remove-white-space str)) | |
381 | (setq methodlist (cons (cons str2 | |
382 | (match-beginning langnum)) | |
383 | methodlist)) | |
384 | (setq toplist (cons nil (cons (cons str | |
385 | methodlist) toplist)) | |
386 | methodlist nil)))) | |
d9e94c22 | 387 | ;; |
05896d77 KH |
388 | (imenu-progress-message stupid 100) |
389 | (if (eq (car toplist) nil) | |
390 | (setq toplist (cdr toplist))) | |
391 | ||
392 | ;; In this buffer, there is only one or zero @{interface|implementation|protocol}. | |
393 | (if (< classcount 2) | |
394 | (let ((classname (car (car toplist))) | |
395 | (p (cdr (car (cdr (car toplist))))) | |
396 | last) | |
397 | (setq toplist (cons (cons classname p) (cdr (cdr (car toplist))))) | |
398 | ;; Add C lang token | |
399 | (if clist | |
400 | (progn | |
401 | (setq last toplist) | |
402 | (while (cdr last) | |
403 | (setq last (cdr last))) | |
404 | (setcdr last clist)))) | |
405 | ;; Add C lang tokens as a sub menu | |
d9e94c22 MS |
406 | (if clist |
407 | (setq toplist (cons (cons "C" clist) toplist)))) | |
05896d77 KH |
408 | ;; |
409 | toplist | |
410 | )) | |
411 | ||
0ec8351b BW |
412 | ;(defvar cc-imenu-pike-generic-expression |
413 | ; ()) | |
414 | ; FIXME: Please contribute one! | |
415 | ||
d9e94c22 MS |
416 | (defun cc-imenu-init (mode-generic-expression |
417 | &optional mode-create-index-function) | |
418 | ;; This function does not do any hidden buffer changes. | |
51f606de | 419 | (setq imenu-generic-expression mode-generic-expression |
d9e94c22 MS |
420 | imenu-case-fold-search nil) |
421 | (when mode-create-index-function | |
422 | (setq imenu-create-index-function mode-create-index-function))) | |
51f606de | 423 | |
785eecbb | 424 | \f |
130c507e | 425 | (cc-provide 'cc-menus) |
3afbc435 | 426 | |
6b61353c | 427 | ;;; arch-tag: f6b60933-91f0-4145-ab44-70ca6d1b919b |
785eecbb | 428 | ;;; cc-menus.el ends here |