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