From 05896d7773b24b3268416f023de318fb950625d2 Mon Sep 17 00:00:00 2001 From: Karl Heuer Date: Thu, 23 Oct 1997 07:31:26 +0000 Subject: [PATCH] (cc-imenu-c-prototype-macro-regexp): New var. (cc-imenu-c++-generic-expression): Patches to better match C++ code. Given by jan.dubois@ibm.net (Jan Dubois) (cc-imenu-java-generic-expression): Removed test for declaration statements. Patch given by Ake Stenhoff , as forwarded to me by RMS. Imenu support for Objective-C given by Masatake (jet) YAMATO. --- lisp/progmodes/cc-menus.el | 301 ++++++++++++++++++++++++++++++++----- 1 file changed, 261 insertions(+), 40 deletions(-) diff --git a/lisp/progmodes/cc-menus.el b/lisp/progmodes/cc-menus.el index 20c7640b606..d758d0707f8 100644 --- a/lisp/progmodes/cc-menus.el +++ b/lisp/progmodes/cc-menus.el @@ -7,7 +7,7 @@ ;; 1985 Richard M. Stallman ;; Maintainer: cc-mode-help@python.org ;; Created: 22-Apr-1997 (split from cc-mode.el) -;; Version: 5.17 +;; Version: 5.18 ;; Keywords: c languages oop ;; This file is part of GNU Emacs. @@ -29,56 +29,97 @@ ;; imenu integration +(defvar cc-imenu-c-prototype-macro-regexp nil + "RE matching macro names used to conditionally specify function prototypes. + +For example: + + #ifdef __STDC__ + #define _P(x) x + #else + #define _P(x) /*nothing*/ + #endif + + int main _P( (int argc, char *argv[]) ) + +A sample value might look like: `\\(_P\\|_PROTO\\)'.") + (defvar cc-imenu-c++-generic-expression (` - ((nil + ( + ;; Try to match ::operator definitions first. Otherwise `X::operator new ()' + ;; will be incorrectly recognised as function `new ()' because the regexps + ;; work by backtracking from the end of the definition. + (nil + (, + (concat + "^\\<.*" + "[^a-zA-Z0-9_:<>~]" ; match any non-identifier char + ; (note: this can be `\n') + "\\(" + "\\([a-zA-Z0-9_:<>~]*::\\)?" ; match an operator + "operator\\>[ \t]*" + "\\(()\\|[^(]*\\)" ; special case for `()' operator + "\\)" + + "[ \t]*([^)]*)[ \t]*[^ \t;]" ; followed by ws, arg list, + ; require something other than + ; a `;' after the (...) to + ; avoid prototypes. Can't + ; catch cases with () inside + ; the parentheses surrounding + ; the parameters. e.g.: + ; `int foo(int a=bar()) {...}' + )) 1) + ;; Special case to match a line like `main() {}' + ;; e.g. no return type, not even on the previous line. + (nil (, (concat - "^" ; beginning of line is required - "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>" - "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; type specs; there can be no - "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; more than 3 tokens, right? - - "\\(" ; last type spec including */& - "[a-zA-Z0-9_:]+" - "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)" ; either ptr/ref sign or ws - "\\)?" ; if there is a last type spec - "\\(" ; name, take into the imenu entry - "[a-zA-Z0-9_:~]+" ; member func, ctor or dtor... - ; (may not contain * because then - ; "a::operator char*" would - ; become "char*"!) - "\\|" - "\\([a-zA-Z0-9_:~]*::\\)?operator" - "[^a-zA-Z1-9_][^(]*" ; ...or operator - " \\)" - "[ \t]*([^)]*)[ \t\n]*[^ ;]" ; require something other than - ; a `;' after the (...) to - ; avoid prototypes. Can't - ; catch cases with () inside - ; the parentheses surrounding - ; the parameters. e.g.: - ; "int foo(int a=bar()) {...}" - - )) 6) + "^" + "\\([a-zA-Z_][a-zA-Z0-9_:<>~]*\\)" ; match function name + "[ \t]*([^)]*)[ \t]*[^ \t;]" ; see above + )) 1) + ;; Special case for definitions using phony prototype macros like: + ;; `int main _PROTO( (int argc,char *argv[]) )'. + ;; This case is only included if cc-imenu-c-prototype-macro-regexp is set. + ;; Only supported in c-code, so no `:<>~' chars in function name! + (,@ (if cc-imenu-c-prototype-macro-regexp + (` ((nil + (, + (concat + "^\\<.*" ; line MUST start with word char + "[^a-zA-Z0-9_]" ; match any non-identifier char + "\\([a-zA-Z_][a-zA-Z0-9_]*\\)" ; match function name + "[ \t]*" ; whitespace before macro name + cc-imenu-c-prototype-macro-regexp + "[ \t]*(" ; ws followed by first paren. + "[ \t]*([^)]*)[ \t]*[^ \t;]" ; see above + )) 1))))) + ;; General function name regexp + (nil + (, + (concat + "^\\<.*" ; line MUST start with word char + "[^a-zA-Z0-9_:<>~]" ; match any non-identifier char + "\\([a-zA-Z_][a-zA-Z0-9_:<>~]*\\)" ; match function name + "[ \t]*([^)]*)[ \t]*[^ \t;]" ; see above + )) 1) + ;; Class definitions ("Class" (, (concat - "^" ; beginning of line is required - "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>" - "class[ \t]+" - "\\([a-zA-Z0-9_]+\\)" ; the string we want to get - "[ \t]*[:{]" - )) 2))) + "^" ; beginning of line is required + "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a `template <...>' + "class[ \t]+" + "\\([a-zA-Z0-9_]+\\)" ; the string we want to get + "[ \t]*[:{]" + )) 2))) "Imenu generic expression for C++ mode. See `imenu-generic-expression'.") (defvar cc-imenu-c-generic-expression cc-imenu-c++-generic-expression "Imenu generic expression for C mode. See `imenu-generic-expression'.") -;(defvar cc-imenu-objc-generic-expression -; ()) -; Please contribute one! - (defvar cc-imenu-java-generic-expression (` ((nil @@ -93,11 +134,191 @@ "\\([ \t]*\\)+(" "\\([a-zA-Z,_1-9\n \t]*[[]?[]]?\\)*" ; arguments ")[ \t]*" - "[^;(]" +; "[^;(]" "[,a-zA-Z_1-9\n \t]*{" )) 6))) "Imenu generic expression for Java mode. See `imenu-generic-expression'.") +(defvar cc-imenu-objc-generic-expression + (concat + ;; For C + ;; Pick a token by (match-string 6) + (car (cdr (car cc-imenu-c++-generic-expression))) + ;; For Objective-C + ;; Pick a token by (match-string 8) + "\\|\\(" + "^[-+][:a-zA-Z0-9()*_<>\n\t ]*[;{]" ; Methods + "\\|" + "^@interface[\t ]+[a-zA-Z0-9_]+[\t ]*:" + "\\|" + "^@interface[\t ]+[a-zA-Z0-9_]+[\t ]*([a-zA-Z0-9_]+)" + "\\|" + ;; For NSObject, NSProxy and Object... They don't have super class. + "^@interface[\t ]+[a-zA-Z0-9_]+[\t ]*.*$" + "\\|" + "^@implementation[\t ]+[a-zA-Z0-9_]+[\t ]*([a-zA-Z0-9_]+)" + "\\|" + "^@implementation[\t ]+[a-zA-Z0-9_]+" + "\\|" + "^@protocol[\t ]+[a-zA-Z0-9_]+" "\\)") + "Imenu generic expression for ObjC mode. See `imenu-generic-expression'.") + + +;; Imenu support for objective-c uses functions. +(defsubst cc-imenu-objc-method-to-selector (method) + "Return the objc selector style string of METHOD. +Example: +- perform: (SEL)aSelector withObject: object1 withObject: object2; /* METHOD */ +=> +-perform:withObject:withObject:withObject: /* selector */" + (let ((return "") ; String to be returned + (p 0) ; Current scanning position in METHOD + (pmax (length method)) ; + char ; Current scanning target + (betweenparen 0) ; CHAR is in parentheses. + argreq ; An argument is required. + inargvar) ; position of CHAR is in an argument variable. + (while (< p pmax) + (setq char (aref method p) + p (1+ p)) + (cond + ;; Is CHAR part of a objc token? + ((and (not inargvar) ; Ignore if CHAR is part of an argument variable. + (eq 0 betweenparen) ; Ignore if CHAR is in parentheses. + (or (and (<= ?a char) (<= char ?z)) + (and (<= ?A char) (<= char ?Z)) + (and (<= ?0 char) (<= char ?9)) + (= ?_ char))) + (if argreq + (setq inargvar t + argreq nil) + (setq return (concat return (char-to-string char))))) + ;; Or a white space? + ((and inargvar (or (eq ?\ char) (eq ?\n char)) + (setq inargvar nil))) + ;; Or a method separator? + ;; If a method separator, the next token will be an argument variable. + ((eq ?: char) + (setq argreq t + return (concat return (char-to-string char)))) + ;; Or an open parentheses? + ((eq ?\( char) + (setq betweenparen (1+ betweenparen))) + ;; Or a close parentheses? + ((eq ?\) char) + (setq betweenparen (1- betweenparen))))) + return)) + +(defun cc-imenu-objc-remove-white-space (str) + "Remove all spaces and tabs from STR." + (let ((return "") + (p 0) + (max (length str)) + char) + (while (< p max) + (setq char (aref str p)) + (setq p (1+ p)) + (if (or (= char ?\ ) (= char ?\t)) + () + (setq return (concat return (char-to-string char))))) + return)) + +(defun cc-imenu-objc-function () + "imenu supports for objc-mode." + (let (methodlist + clist + (C 6) + (OBJC 8) + langnum + (classcount 0) + toplist + stupid + str + str2 + (intflen (length "@interface")) + (implen (length "@implementation")) + (prtlen (length "@protocol")) + bufsubst-fun) + ;; + ;; Does this emacs has buffer-substring-no-properties? + ;; + (fset 'bufsubst-fun (if (fboundp 'buffer-substring-no-properties) + (symbol-function 'buffer-substring-no-properties) + (symbol-function 'buffer-substring))) + (goto-char (point-max)) + (imenu-progress-message stupid 0) + ;; + (while (re-search-backward cc-imenu-objc-generic-expression nil t) + (imenu-progress-message stupid) + (setq langnum (if (match-beginning C) C OBJC)) + (setq str (bufsubst-fun (match-beginning langnum) (match-end langnum))) + ;; + (cond + ;; + ;; C + ;; + ((eq langnum C) + (setq clist (cons (cons str (match-beginning langnum)) clist))) + ;; + ;; ObjC + ;; + ;; An instance Method + ((eq (aref str 0) ?-) + (setq str (concat "-" (cc-imenu-objc-method-to-selector str))) + (setq methodlist (cons (cons str + (match-beginning langnum)) + methodlist))) + ;; A factory Method + ((eq (aref str 0) ?+) + (setq str (concat "+" (cc-imenu-objc-method-to-selector str))) + (setq methodlist (cons (cons str + (match-beginning langnum)) + methodlist))) + ;; Interface or implementation or protocol + ((eq (aref str 0) ?@) + (setq classcount (1+ classcount)) + (cond + ((and (> (length str) implen) + (string= (substring str 0 implen) "@implementation")) + (setq str (substring str implen) + str2 "@implementation")) + ((string= (substring str 0 intflen) "@interface") + (setq str (substring str intflen) + str2 "@interface")) + ((string= (substring str 0 prtlen) "@protocol") + (setq str (substring str prtlen) + str2 "@protocol"))) + (setq str (cc-imenu-objc-remove-white-space str)) + (setq methodlist (cons (cons str2 + (match-beginning langnum)) + methodlist)) + (setq toplist (cons nil (cons (cons str + methodlist) toplist)) + methodlist nil)))) + ;; + (imenu-progress-message stupid 100) + (if (eq (car toplist) nil) + (setq toplist (cdr toplist))) + + ;; In this buffer, there is only one or zero @{interface|implementation|protocol}. + (if (< classcount 2) + (let ((classname (car (car toplist))) + (p (cdr (car (cdr (car toplist))))) + last) + (setq toplist (cons (cons classname p) (cdr (cdr (car toplist))))) + ;; Add C lang token + (if clist + (progn + (setq last toplist) + (while (cdr last) + (setq last (cdr last))) + (setcdr last clist)))) + ;; Add C lang tokens as a sub menu + (setq toplist (cons (cons "C" clist) toplist))) + ;; + toplist + )) + (provide 'cc-menus) ;;; cc-menus.el ends here -- 2.39.2