; Problem with this RE: a) If the line before the function declaration ; is a preprocessor directive (like a #define) ending in one or more ; c++ type keywords they will get included into the type spec. b) if ; you define a symbol like #define _const const the expression won't ; work at all ; Another possible regexp for c++-simple-type-regexp is "^.+". This ; will make any text before the name of the function but in the same ; line be the type of the function. Problem: Type cannot span multiple ; lines. (defvar c++-prefixes '("__inline__" "static")) (defconst c++-simple-type-regexp "\\(\\([ \t\n\r]+\\(inline\\|explicit\\|unsigned\\|signed\\|short\\|long\\|const\\|static\\|friend\\)\\)*[ \t\n\r]+[a-zA-Z0-9_]+\\(<[a-zA-Z0-9_, \t\n\t]*>\\)?\\([ \t\n\r]+\\(const[ \t\n\r]+\\)\\)?\\([*&]\\|\\[[ \t\n\r]*[0-9]+[ \t\n\r]*\\]\\)*\\([ \t\n\r]+const\\)?\\)[ \t\n\r]*" "*The RE for a simple type in C++ that is types that neither involve blocks nor functions") (defconst c++-function-regexp "[^a-zA-Z0-9_:]\\(\\([a-zA-Z0-9_]+\\(<[a-zA-Z0-9_, \t\n\r]*>\\)?::\\)*\\(\\(operator[ \t\n\r]*\\([-+*/.&^|=]\\|++\\|--\\|&&\\|||\\|new\\|delete\\|()\\|\\[\\]\\|->\\|[^();{}]+\\)=?\\)\\|~?[a-zA-Z0-e9_]+\\)\\)[ \t\n\r]*" "The RE for a function definition or declaration") (defconst c++-class-regexp "\\(class\\|namespace\\)[ \t\n\r]+\\([a-zA-Z0-9_:]+\\)\\([ \t\n\r]*:\\([ \t\n\r]*\\(public\\|protected\\|private\\)?[ \t\n\r]*\\([a-zA-Z0-9_]+\\(<[^>]*>\\)?\\(::\\)?\\)*[ \t\n\r]*,?\\)*\\)?[ \t\n\r]*" "The RE for a class declaration") (defconst c++-template-regexp "template[ \t\n\r]*<\\([^>]*\\)>[ \t\n\r]*" "The RE for matching template clauses.") (defconst c++-function-keywords '( "if" "while" "for" "repeat" "class" "struct" "union" "switch" ) "C++ Keywords which may introduce a block") (defconst c++-keywords '( "if" "while" "for" "repeat" "class" "struct" "union" "typedef" "char" "int" "float" "double" "signed" "unsigned" "long" "const" "switch" "case" "repeat" "until" "do" "class" "public" "protected" "private" "friend" "operator" "void" "static" "explicit" ) "C++ keywords") (defvar c++-smart-wrap-column 80) (require 'cc-cmds) (require 'cc-engine) (defun c++-scan-type-backward () "Scans backward to find the longest valid simple type ending at POINT. Assumes POINT is at the end of a C++ simple type expression. Leaves POINT at the beginning of the type expression and returns ( TYPE-START . TYPE-END )" (save-excursion (let ((end (point)) start) (re-search-backward c++-simple-type-regexp 'nil 't) (catch 'exit (while (and (re-search-forward c++-simple-type-regexp end 't) (< (abs (- end (match-end 0))) 2)) (goto-char (match-beginning 0)) (setq start (point)) (if (not (re-search-backward c++-simple-type-regexp 'nil 't)) (throw 'exit)))) (if start (progn (goto-char start) (skip-chars-forward " \t\n\r") (setq start (point)) (goto-char end) (skip-chars-backward " \t\n\r" start) (cons start (point))) 'nil )))) (defun c++-get-function () "Get the last function declared or called at or after POINT. Returns a list ( ( DECL-START . DECL-END ) ( TYPE-START . TYPE-END ) ( NAME-START . NAME_END ) ( ARGLIST-START . ARGLIST-END ) ( FLAGS-START . FLAGS-END ) )" (save-excursion (if (re-search-backward (concat c++-function-regexp "(") 'nil 'true) (goto-char (match-end 0))) (if (re-search-forward (concat c++-function-regexp "(") 'nil 't) (let (type name arglist flags) (setq name (cons (match-beginning 1) (match-end 1))) (goto-char (1- (match-end 0))) (setq arglist (cons (point) 'nil)) (if (condition-case nil (progn (forward-list 1) t) (scan-error nil)) (progn (setcdr arglist (point)) (if (looking-at "\\([ \t\n\r]*\\(const\\|throw[ \t\n\r]*([^();{}]*)\\|__throw__[ \t\n\t]*(([^();{}]*))\\)\\)*") (progn (setq flags (cons (match-beginning 0) (match-end 0))) (goto-char (match-end 0))) (setq flags (cons (cdr arglist) (cdr arglist)))) (if (looking-at "[ \t\n\r]*:[^;{]*") (goto-char (match-end 0))) (if (looking-at "[ \t\n\r]*[{;]") (progn (goto-char (car name)) (setq type (c++-scan-type-backward)) (if (not type) (setq type (cons (car name) (car name)))) (list (cons (car type) (cdr flags)) type name arglist flags))))))))) (defun c++-get-function-defn () "Get the function defined at POINT. Returns a list ( ( DECL-START . DECL-END ) ( TYPE-START . TYPE-END ) ( NAME-START . NAME_END ) ( ARGLIST-START . ARGLIST-END ) ( FLAGS-START . FLAGS-END ) ( BODY-START . BODY-END) )" (save-excursion (let (body fn end) (while (not fn) (if (condition-case nil (progn (up-list -1) t) (error (setq fn t) nil)) (save-excursion (setq body (cons (point) (save-excursion (forward-list 1) (point)))) (save-excursion (while (condition-case nil (progn (up-list -1) (setq end (point)) t) (scan-error nil)))) (while (re-search-backward (concat c++-function-regexp "(") end t) (let ((tryfn (c++-get-function))) (if tryfn (save-excursion (goto-char (cdar tryfn)) (if (and (looking-at "[ \t\n\r]*\\(:[^;{]*\\)?{") (eq (1- (match-end 0)) (car body))) (progn (if (match-beginning 1) (setcar body (match-beginning 1))) (setq fn tryfn)))))))))) (if (eq fn t) nil (nconc fn (list body)))))) (defun c++-get-classname () "Get classname which is active at POINT" (let (class (re 't)) (save-excursion (while re (if (and (condition-case nil (progn (up-list -1) 't) (error (setq re 'nil))) (re-search-backward (concat c++-class-regexp "\\=") 'nil 't)) (setq class (concat (match-string 2) (if class "::" "") class ))))) class)) (defun c++-get-current-class-prefix () "Get the class prefix currently active at POINT. If within a class decl, returns that class name (nested classes are supported). If within a function definition at global level, returns the class prefix of this function. Returns 'nil if no class prefix can be found" (let ((x (c++-get-classname))) (if x x (let ((x (or (c++-get-function-defn) (c++-get-function)))) (if x (save-excursion (goto-char (car (nth 2 x))) (if (re-search-forward "\\=\\([a-zA-Z_0-9]+::\\)+") (buffer-substring (match-beginning 0) (- (match-end 0) 2)) 'nil)) 'nil))))) (defun c++-split-template-arg (arg) "Split ARG, a template argument list, and return list of arg names." (let ((raw-args (split-string arg "[ \t\n\r]*,[ \t\n\r]"))) (loop for raw-arg in raw-args if (string-match "[a-zA-Z0-9_-]+$" raw-arg) collect (match-string 0 raw-arg) else collect raw-arg))) (defun c++-get-classname-with-templates () (let (classname template-args (re 't)) (save-excursion (while re (if (and (condition-case nil (progn (up-list -1) 't) (error (setq re 'nil))) (re-search-backward (concat c++-class-regexp "\\=") nil t)) (let ((template-suffix "") (class (match-string 2))) (if (re-search-backward (concat c++-template-regexp "\\=") nil t) (let* ((s (match-string 1)) (args (c++-split-template-arg s)) (raw-args (split-string s "[ \t\n\r]*,[ \t\n\r]"))) (setq template-suffix (concat "<" (mapconcat 'identity args ",") ">")) (loop for arg in raw-args if (not (member arg template-args)) do (setq template-args (nconc template-args (list arg)))))) (setq classname (concat class template-suffix (if classname "::" "") classname)))))) (and classname (cons classname (and template-args (mapconcat 'identity template-args ", ")))))) (defun c++-get-current-class-prefix-with-templates () "Get the class prefix currently active at POINT. If within a class decl, returns that class name (nested classes are supported). If within a function definition at global level, returns the class prefix of this function. Returns 'nil if no class prefix can be found" (let ((x (c++-get-classname-with-templates))) (if x (car x) (let ((x (or (c++-get-function-defn) (c++-get-function)))) (if x (save-excursion (goto-char (car (nth 2 x))) (if (re-search-forward "\\=\\([a-zA-Z_0-9]+\\(<[a-zA-Z0-9_, \t\n\r]*>\\)?::\\)+") (buffer-substring (match-beginning 0) (- (match-end 0) 2)) 'nil)) 'nil))))) (defun c++-grab-inline-decl () "Grab the inline declaration at POINT and change it into a standard declaration. This function deletes the declaration found at POINT and places the new declaration into the top of the kill ring" (interactive) (let ((fn (c++-get-function-defn)) (class (c++-get-classname-with-templates))) (if (and fn class) (progn (kill-new (concat (if (cdr class) (concat "template <" (cdr class) ">\n") "") "inline " (buffer-substring (car (nth 0 fn)) (car (nth 2 fn))) (car class) "::" (buffer-substring (car (nth 2 fn)) (cdr (nth 5 fn))) "\n")) (delete-region (cdr (nth 4 fn)) (cdr (nth 5 fn))) (goto-char (cdr (nth 4 fn))) (insert ";") (delete-blank-lines)) (if (interactive-p) (message "Not inside inline function definition body"))))) (defun c++-insert-class-prefix () "Insert the current class prefix at POINT. See also c++-get-current-class-prefix" (interactive) (let ((x (c++-get-current-class-prefix-with-templates))) (if x (insert x "::") (message "Not in scope of any class")))) (defun c++-next-user-symbol () "Move POINT to next non-keyword symbol." (interactive) (let (pos) (if (looking-at "[a-zA-Z_:]+") (setq pos (re-search-forward "[a-zA-Z_:]+" 'nil 't))) (while (and (setq pos (re-search-forward "[a-zA-Z_:]*[a-zA-Z_]" 'nil 't)) (or (member (match-string 0) c++-keywords) (c-in-literal)))) (goto-char pos))) (defun c++-previous-user-symbol () "Move POINT to previous non-keyword symbol." (interactive) (while (and (re-search-backward "[a-zA-Z_]" 'nil 't) (progn (skip-chars-backward "a-zA-Z_:") (or (member (buffer-substring (point) (match-end 0)) c++-keywords) (c-in-literal)))))) (defun c++-next-function-call () "Move POINT to next function call" (interactive) (let ((start (point)) fn) (while (and (setq fn (c++-get-function)) (or (>= start (car (nth 0 fn))) (member (buffer-substring (car (nth 2 fn)) (cdr (nth 2 fn))) c++-function-keywords) (/= (car (nth 1 fn)) (car (nth 2 fn))))) (goto-char (cdr (nth 0 fn))) (re-search-forward "{;" 'nil 't)) (goto-char (if fn (car (nth 0 fn)) start)))) (defun c++-next-function-definition () "Move POINT to the next function definition or declaration" (interactive) (let ((start (point)) fn) (while (and (setq fn (c++-get-function)) (or (>= start (car (nth 0 fn))) (member (buffer-substring (car (nth 2 fn)) (cdr (nth 2 fn))) c++-function-keywords) (= (car (nth 1 fn)) (car (nth 2 fn))))) (goto-char (cdr (nth 0 fn))) (re-search-forward "[{;]" 'nil 't)) (goto-char (if fn (car (nth 0 fn)) start)))) (defun c++-smart-yank () "Yank-pop top of kill ring and reformat the yanked object." (interactive) (push-mark) (let ((text (current-kill 0)) end-mark line-start) (save-excursion (insert text) (setq end-mark (point-marker))) (while (< (point) (marker-position end-mark)) (beginning-of-line) (c-indent-command) (setq line-start (point)) (end-of-line) (if (> (current-column) c++-smart-wrap-column) (progn (move-to-column c++-smart-wrap-column) (if (search-backward ",") (progn (forward-char 1) (open-line 1))))) (forward-line 1)))) (provide 'c++)