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