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, |
5df4f04c | 4 | ;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 |
d7a0267c | 5 | ;; Free Software Foundation, Inc. |
785eecbb | 6 | |
d9e94c22 MS |
7 | ;; Authors: 1998- Martin Stjernholm |
8 | ;; 1992-1999 Barry A. Warsaw | |
5858f68c GM |
9 | ;; 1987 Dave Detlefs |
10 | ;; 1987 Stewart Clamen | |
785eecbb | 11 | ;; 1985 Richard M. Stallman |
0ec8351b | 12 | ;; Maintainer: bug-cc-mode@gnu.org |
785eecbb | 13 | ;; Created: 22-Apr-1997 (split from cc-mode.el) |
8729df59 | 14 | ;; Version: See cc-mode.el |
785eecbb RS |
15 | ;; Keywords: c languages oop |
16 | ||
17 | ;; This file is part of GNU Emacs. | |
18 | ||
b1fc2b50 | 19 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
785eecbb | 20 | ;; it under the terms of the GNU General Public License as published by |
b1fc2b50 GM |
21 | ;; the Free Software Foundation, either version 3 of the License, or |
22 | ;; (at your option) any later version. | |
785eecbb RS |
23 | |
24 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
25 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 | ;; GNU General Public License for more details. | |
28 | ||
29 | ;; You should have received a copy of the GNU General Public License | |
b1fc2b50 | 30 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
785eecbb | 31 | |
3afbc435 PJ |
32 | ;;; Commentary: |
33 | ||
34 | ;;; Code: | |
35 | ||
0ec8351b | 36 | (eval-when-compile |
51f606de | 37 | (let ((load-path |
130c507e GM |
38 | (if (and (boundp 'byte-compile-dest-file) |
39 | (stringp byte-compile-dest-file)) | |
40 | (cons (file-name-directory byte-compile-dest-file) load-path) | |
51f606de | 41 | load-path))) |
d9e94c22 MS |
42 | (load "cc-bytecomp" nil t))) |
43 | ||
44 | (cc-require 'cc-defs) | |
51f606de | 45 | |
130c507e GM |
46 | ;; The things referenced in imenu, which we don't require. |
47 | (cc-bytecomp-defvar imenu-case-fold-search) | |
48 | (cc-bytecomp-defvar imenu-generic-expression) | |
d9e94c22 | 49 | (cc-bytecomp-defvar imenu-create-index-function) |
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 | |
41a962dd GM |
107 | ;; \n added to prevent overflow in regexp matcher. |
108 | ;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2007-02/msg00021.html | |
109 | "[^()\n]*" ; no parentheses before | |
d9e94c22 MS |
110 | "[^" c-alnum "_:<>~]" ; match any non-identifier char |
111 | "\\([" c-alpha "_][" c-alnum "_:<>~]*\\)" ; match function name | |
a66cd3ee MS |
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 | |
51f606de | 115 | ) 1) |
05896d77 KH |
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! | |
51f606de GM |
120 | ,@(if cc-imenu-c-prototype-macro-regexp |
121 | `((nil | |
122 | ,(concat | |
05896d77 | 123 | "^\\<.*" ; line MUST start with word char |
d9e94c22 MS |
124 | "[^" c-alnum "_]" ; match any non-identifier char |
125 | "\\([" c-alpha "_][" c-alnum "_]*\\)" ; match function name | |
05896d77 KH |
126 | "[ \t]*" ; whitespace before macro name |
127 | cc-imenu-c-prototype-macro-regexp | |
128 | "[ \t]*(" ; ws followed by first paren. | |
8729df59 | 129 | "[ \t]*([^)]*)[ \t]*)[ \t]*[^ \t;]" ; see above |
51f606de | 130 | ) 1))) |
05896d77 | 131 | ;; Class definitions |
304515db | 132 | ("Class" |
51f606de | 133 | ,(concat |
05896d77 KH |
134 | "^" ; beginning of line is required |
135 | "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a `template <...>' | |
130c507e | 136 | "\\(class\\|struct\\)[ \t]+" |
0ec8351b | 137 | "\\(" ; the string we want to get |
d9e94c22 | 138 | "[" c-alnum "_]+" ; class name |
130c507e | 139 | "\\(<[^>]+>\\)?" ; possibly explicitly specialized |
0ec8351b | 140 | "\\)" |
a66cd3ee | 141 | "\\([ \t\n]\\|\\\\\n\\)*[:{]" |
130c507e | 142 | ) 3)) |
785eecbb | 143 | "Imenu generic expression for C++ mode. See `imenu-generic-expression'.") |
304515db | 144 | |
785eecbb RS |
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 | ||
785eecbb | 149 | (defvar cc-imenu-java-generic-expression |
51f606de GM |
150 | `((nil |
151 | ,(concat | |
9f0ad260 | 152 | "[" c-alpha "_][\]\[." c-alnum "_<> ]+[ \t\n\r]+" ; type spec |
c3b616a9 | 153 | "\\([" c-alpha "_][" c-alnum "_]*\\)" ; method name |
d9e94c22 | 154 | "[ \t\n\r]*" |
9f0ad260 AM |
155 | ;; An argument list htat is either empty or contains any number |
156 | ;; of arguments. An argument is any number of annotations | |
157 | ;; followed by a type spec followed by a word. A word is an | |
158 | ;; identifier. A type spec is an identifier, possibly followed | |
159 | ;; by < typespec > possibly followed by []. | |
160 | (concat "(" | |
161 | "\\(" | |
c3b616a9 AM |
162 | "[ \t\n\r]*" |
163 | "\\(" | |
164 | "@" | |
165 | "[" c-alpha "_]" | |
166 | "[" c-alnum "._]""*" | |
167 | "[ \t\n\r]+" | |
168 | "\\)*" | |
169 | "\\(" | |
170 | "[" c-alpha "_]" | |
171 | "[\]\[" c-alnum "_.]*" | |
172 | "\\(" | |
173 | ||
174 | "<" | |
175 | "[ \t\n\r]*" | |
176 | "[\]\[.," c-alnum "_<> \t\n\r]*" | |
177 | ">" | |
178 | "\\)?" | |
179 | "\\(\\[\\]\\)?" | |
180 | "[ \t\n\r]+" | |
181 | "\\)" | |
182 | "[" c-alpha "_]" | |
183 | "[" c-alnum "_]*" | |
184 | "[ \t\n\r,]*" | |
9f0ad260 | 185 | "\\)*" |
c3b616a9 AM |
186 | ")" |
187 | "[.," c-alnum " \t\n\r]*" | |
188 | "{" | |
189 | )) 1)) | |
9f0ad260 AM |
190 | "Imenu generic expression for Java mode. See |
191 | `imenu-generic-expression'.") | |
785eecbb | 192 | |
304515db | 193 | ;; *Warning for cc-mode developers* |
f1063b2f RS |
194 | ;; |
195 | ;; `cc-imenu-objc-generic-expression' elements depend on | |
196 | ;; `cc-imenu-c++-generic-expression'. So if you change this | |
197 | ;; expression, you need to change following variables, | |
198 | ;; `cc-imenu-objc-generic-expression-*-index', | |
199 | ;; too. `cc-imenu-objc-function' uses these *-index variables, in | |
200 | ;; order to know where the each regexp *group \\(foobar\\)* elements | |
201 | ;; are started. | |
202 | ;; | |
304515db GM |
203 | ;; *-index variables are initialized during `cc-imenu-objc-generic-expression' |
204 | ;; being initialized. | |
f1063b2f RS |
205 | ;; |
206 | ||
207 | ;; Internal variables | |
208 | (defvar cc-imenu-objc-generic-expression-noreturn-index nil) | |
209 | (defvar cc-imenu-objc-generic-expression-general-func-index nil) | |
210 | (defvar cc-imenu-objc-generic-expression-proto-index nil) | |
211 | (defvar cc-imenu-objc-generic-expression-objc-base-index nil) | |
212 | ||
304515db GM |
213 | (defvar cc-imenu-objc-generic-expression |
214 | (concat | |
8729df59 | 215 | ;; |
304515db | 216 | ;; For C |
8729df59 KH |
217 | ;; |
218 | ;; > Special case to match a line like `main() {}' | |
219 | ;; > e.g. no return type, not even on the previous line. | |
220 | ;; Pick a token by (match-string 1) | |
f1063b2f RS |
221 | (car (cdr (nth 1 cc-imenu-c++-generic-expression))) ; -> index += 2 |
222 | (prog2 (setq cc-imenu-objc-generic-expression-noreturn-index 1) "") | |
8729df59 KH |
223 | "\\|" |
224 | ;; > General function name regexp | |
f1063b2f | 225 | ;; Pick a token by (match-string 3) |
d9e94c22 | 226 | (car (cdr (nth 2 cc-imenu-c++-generic-expression))) ; -> index += 5 |
f1063b2f | 227 | (prog2 (setq cc-imenu-objc-generic-expression-general-func-index 3) "") |
8729df59 KH |
228 | ;; > Special case for definitions using phony prototype macros like: |
229 | ;; > `int main _PROTO( (int argc,char *argv[]) )'. | |
d9e94c22 | 230 | ;; Pick a token by (match-string 8) |
8729df59 | 231 | (if cc-imenu-c-prototype-macro-regexp |
304515db | 232 | (concat |
8729df59 | 233 | "\\|" |
f1063b2f | 234 | (car (cdr (nth 3 cc-imenu-c++-generic-expression))) ; -> index += 1 |
d9e94c22 | 235 | (prog2 (setq cc-imenu-objc-generic-expression-objc-base-index 9) "") |
f1063b2f | 236 | ) |
d9e94c22 | 237 | (prog2 (setq cc-imenu-objc-generic-expression-objc-base-index 8) "") |
f1063b2f | 238 | "") ; -> index += 0 |
d9e94c22 | 239 | (prog2 (setq cc-imenu-objc-generic-expression-proto-index 8) "") |
8729df59 | 240 | ;; |
05896d77 | 241 | ;; For Objective-C |
d9e94c22 | 242 | ;; Pick a token by (match-string 8 or 9) |
8729df59 | 243 | ;; |
304515db | 244 | "\\|\\(" |
d9e94c22 | 245 | "^[-+][:" c-alnum "()*_<>\n\t ]*[;{]" ; Methods |
304515db | 246 | "\\|" |
d9e94c22 | 247 | "^@interface[\t ]+[" c-alnum "_]+[\t ]*:" |
304515db | 248 | "\\|" |
d9e94c22 | 249 | "^@interface[\t ]+[" c-alnum "_]+[\t ]*([" c-alnum "_]+)" |
304515db | 250 | "\\|" |
05896d77 | 251 | ;; For NSObject, NSProxy and Object... They don't have super class. |
d9e94c22 | 252 | "^@interface[\t ]+[" c-alnum "_]+[\t ]*.*$" |
304515db | 253 | "\\|" |
d9e94c22 | 254 | "^@implementation[\t ]+[" c-alnum "_]+[\t ]*([" c-alnum "_]+)" |
304515db | 255 | "\\|" |
d9e94c22 | 256 | "^@implementation[\t ]+[" c-alnum "_]+" |
304515db | 257 | "\\|" |
d9e94c22 | 258 | "^@protocol[\t ]+[" c-alnum "_]+" "\\)") |
05896d77 KH |
259 | "Imenu generic expression for ObjC mode. See `imenu-generic-expression'.") |
260 | ||
261 | ||
262 | ;; Imenu support for objective-c uses functions. | |
263 | (defsubst cc-imenu-objc-method-to-selector (method) | |
264 | "Return the objc selector style string of METHOD. | |
304515db | 265 | Example: |
05896d77 KH |
266 | - perform: (SEL)aSelector withObject: object1 withObject: object2; /* METHOD */ |
267 | => | |
268 | -perform:withObject:withObject:withObject: /* selector */" | |
269 | (let ((return "") ; String to be returned | |
304515db GM |
270 | (p 0) ; Current scanning position in METHOD |
271 | (pmax (length method)) ; | |
05896d77 KH |
272 | char ; Current scanning target |
273 | (betweenparen 0) ; CHAR is in parentheses. | |
274 | argreq ; An argument is required. | |
275 | inargvar) ; position of CHAR is in an argument variable. | |
276 | (while (< p pmax) | |
277 | (setq char (aref method p) | |
278 | p (1+ p)) | |
279 | (cond | |
280 | ;; Is CHAR part of a objc token? | |
281 | ((and (not inargvar) ; Ignore if CHAR is part of an argument variable. | |
282 | (eq 0 betweenparen) ; Ignore if CHAR is in parentheses. | |
283 | (or (and (<= ?a char) (<= char ?z)) | |
284 | (and (<= ?A char) (<= char ?Z)) | |
285 | (and (<= ?0 char) (<= char ?9)) | |
286 | (= ?_ char))) | |
33ee2fc8 | 287 | (if argreq |
05896d77 KH |
288 | (setq inargvar t |
289 | argreq nil) | |
290 | (setq return (concat return (char-to-string char))))) | |
291 | ;; Or a white space? | |
304515db | 292 | ((and inargvar (or (eq ?\ char) (eq ?\n char)) |
05896d77 KH |
293 | (setq inargvar nil))) |
294 | ;; Or a method separator? | |
295 | ;; If a method separator, the next token will be an argument variable. | |
304515db GM |
296 | ((eq ?: char) |
297 | (setq argreq t | |
05896d77 KH |
298 | return (concat return (char-to-string char)))) |
299 | ;; Or an open parentheses? | |
300 | ((eq ?\( char) | |
301 | (setq betweenparen (1+ betweenparen))) | |
302 | ;; Or a close parentheses? | |
303 | ((eq ?\) char) | |
304 | (setq betweenparen (1- betweenparen))))) | |
305 | return)) | |
306 | ||
307 | (defun cc-imenu-objc-remove-white-space (str) | |
308 | "Remove all spaces and tabs from STR." | |
309 | (let ((return "") | |
310 | (p 0) | |
304515db | 311 | (max (length str)) |
05896d77 KH |
312 | char) |
313 | (while (< p max) | |
314 | (setq char (aref str p)) | |
315 | (setq p (1+ p)) | |
316 | (if (or (= char ?\ ) (= char ?\t)) | |
317 | () | |
318 | (setq return (concat return (char-to-string char))))) | |
319 | return)) | |
320 | ||
321 | (defun cc-imenu-objc-function () | |
33ee2fc8 | 322 | "Imenu support for Objective C mode." |
05896d77 KH |
323 | (let (methodlist |
324 | clist | |
8729df59 | 325 | ;; |
f1063b2f | 326 | ;; OBJC, Cnoreturn, Cgeneralfunc, Cproto are constants. |
8729df59 | 327 | ;; |
304515db | 328 | ;; *Warning for developers* |
8729df59 KH |
329 | ;; These constants depend on `cc-imenu-c++-generic-expression'. |
330 | ;; | |
f1063b2f RS |
331 | (OBJC cc-imenu-objc-generic-expression-objc-base-index) |
332 | ;; Special case to match a line like `main() {}' | |
333 | (Cnoreturn cc-imenu-objc-generic-expression-noreturn-index) | |
334 | ;; General function name regexp | |
335 | (Cgeneralfunc cc-imenu-objc-generic-expression-general-func-index) | |
336 | ;; Special case for definitions using phony prototype macros like: | |
337 | (Cproto cc-imenu-objc-generic-expression-proto-index) | |
05896d77 | 338 | langnum |
8729df59 | 339 | ;; |
05896d77 KH |
340 | (classcount 0) |
341 | toplist | |
05896d77 | 342 | str |
304515db | 343 | str2 |
05896d77 KH |
344 | (intflen (length "@interface")) |
345 | (implen (length "@implementation")) | |
346 | (prtlen (length "@protocol")) | |
f1063b2f RS |
347 | (func |
348 | ;; | |
304515db | 349 | ;; Does this emacs have buffer-substring-no-properties? |
f1063b2f RS |
350 | ;; |
351 | (if (fboundp 'buffer-substring-no-properties) | |
352 | 'buffer-substring-no-properties | |
353 | 'buffer-substring))) | |
0ec8351b | 354 | (goto-char (point-max)) |
05896d77 KH |
355 | ;; |
356 | (while (re-search-backward cc-imenu-objc-generic-expression nil t) | |
304515db | 357 | (setq langnum (if (match-beginning OBJC) |
8729df59 KH |
358 | OBJC |
359 | (cond | |
f1063b2f RS |
360 | ((match-beginning Cproto) Cproto) |
361 | ((match-beginning Cgeneralfunc) Cgeneralfunc) | |
362 | ((match-beginning Cnoreturn) Cnoreturn)))) | |
363 | (setq str (funcall func (match-beginning langnum) (match-end langnum))) | |
05896d77 | 364 | ;; |
304515db | 365 | (cond |
05896d77 KH |
366 | ;; |
367 | ;; C | |
368 | ;; | |
8729df59 | 369 | ((not (eq langnum OBJC)) |
05896d77 KH |
370 | (setq clist (cons (cons str (match-beginning langnum)) clist))) |
371 | ;; | |
372 | ;; ObjC | |
304515db | 373 | ;; |
05896d77 KH |
374 | ;; An instance Method |
375 | ((eq (aref str 0) ?-) | |
376 | (setq str (concat "-" (cc-imenu-objc-method-to-selector str))) | |
377 | (setq methodlist (cons (cons str | |
378 | (match-beginning langnum)) | |
379 | methodlist))) | |
380 | ;; A factory Method | |
381 | ((eq (aref str 0) ?+) | |
382 | (setq str (concat "+" (cc-imenu-objc-method-to-selector str))) | |
383 | (setq methodlist (cons (cons str | |
384 | (match-beginning langnum)) | |
385 | methodlist))) | |
304515db | 386 | ;; Interface or implementation or protocol |
05896d77 KH |
387 | ((eq (aref str 0) ?@) |
388 | (setq classcount (1+ classcount)) | |
304515db | 389 | (cond |
05896d77 KH |
390 | ((and (> (length str) implen) |
391 | (string= (substring str 0 implen) "@implementation")) | |
392 | (setq str (substring str implen) | |
393 | str2 "@implementation")) | |
394 | ((string= (substring str 0 intflen) "@interface") | |
395 | (setq str (substring str intflen) | |
396 | str2 "@interface")) | |
397 | ((string= (substring str 0 prtlen) "@protocol") | |
398 | (setq str (substring str prtlen) | |
399 | str2 "@protocol"))) | |
400 | (setq str (cc-imenu-objc-remove-white-space str)) | |
401 | (setq methodlist (cons (cons str2 | |
402 | (match-beginning langnum)) | |
403 | methodlist)) | |
404 | (setq toplist (cons nil (cons (cons str | |
405 | methodlist) toplist)) | |
406 | methodlist nil)))) | |
304515db | 407 | ;; |
05896d77 KH |
408 | (if (eq (car toplist) nil) |
409 | (setq toplist (cdr toplist))) | |
410 | ||
411 | ;; In this buffer, there is only one or zero @{interface|implementation|protocol}. | |
412 | (if (< classcount 2) | |
413 | (let ((classname (car (car toplist))) | |
414 | (p (cdr (car (cdr (car toplist))))) | |
415 | last) | |
416 | (setq toplist (cons (cons classname p) (cdr (cdr (car toplist))))) | |
417 | ;; Add C lang token | |
418 | (if clist | |
419 | (progn | |
420 | (setq last toplist) | |
421 | (while (cdr last) | |
422 | (setq last (cdr last))) | |
423 | (setcdr last clist)))) | |
424 | ;; Add C lang tokens as a sub menu | |
d9e94c22 MS |
425 | (if clist |
426 | (setq toplist (cons (cons "C" clist) toplist)))) | |
05896d77 KH |
427 | ;; |
428 | toplist | |
429 | )) | |
430 | ||
0ec8351b BW |
431 | ;(defvar cc-imenu-pike-generic-expression |
432 | ; ()) | |
433 | ; FIXME: Please contribute one! | |
434 | ||
d9e94c22 MS |
435 | (defun cc-imenu-init (mode-generic-expression |
436 | &optional mode-create-index-function) | |
51f606de | 437 | (setq imenu-generic-expression mode-generic-expression |
d9e94c22 MS |
438 | imenu-case-fold-search nil) |
439 | (when mode-create-index-function | |
440 | (setq imenu-create-index-function mode-create-index-function))) | |
51f606de | 441 | |
785eecbb | 442 | \f |
130c507e | 443 | (cc-provide 'cc-menus) |
3afbc435 | 444 | |
cbee283d | 445 | ;; arch-tag: f6b60933-91f0-4145-ab44-70ca6d1b919b |
785eecbb | 446 | ;;; cc-menus.el ends here |