C++ structure comparator generator
[emacsstuff.git] / cc-ide / cc-ide.el
1 ;;; cc-ide.el --- C++ IDE
2 ;;
3 ;; $Id$
4 ;;
5 ;; Copyright (C) 2000 Stefan Bund
6
7 ;; cc-ide.el is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published
9 ;; by the Free Software Foundation; either version 2, or (at your
10 ;; option) any later version.
11
12 ;; cc-ide.el is distributed in the hope that it will be useful, but
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 ;; General Public License for more details.
16
17 ;;; Commentary:
18
19 ;;; Change-Log:
20
21 ;; $Log$
22 ;;
23
24 ;;; Variables:
25
26 (defvar ccide-compile-opts "DEBUG=1"
27   "*Additional options to make command")
28
29 (defvar ccide-file-vars nil)
30
31 (defvar ccide-default-author "")
32 (defvar ccide-default-copyright "")
33
34 (defvar ccide-project-name nil)
35
36 (defvar ccide-all-includes nil
37   "*If non-nil, this is the name of a file to include to fetch all
38 includes of a project. This is used if single include files cannot be
39 correctly included.")
40
41 (defvar ccide-corba-skel-dir "")
42 (defvar ccide-corba-idl-dir "")
43 (defvar ccide-corba-idl-command "omniidl2 -w")
44
45 (defvar c-user-prefixes '("inline" "static" "prefix_")
46   "*List of possible prefixes for function definitions.")
47
48 (defvar ccide-default-prefix "prefix_"
49   "*Prefix added to every implementation header. Probably eiter empty or 'prefix_'")
50
51 (defvar ccide-gen-throw nil
52   "*If non-nil, generate throw_ specs")
53
54 (defvar ccide-project-root nil)
55
56 (defvar ccide-new-file-hook nil)
57
58 (defconst c-user-prefix-re (regexp-opt c-user-prefixes t))
59
60 (defconst ccide-doxy-tag-re
61   (concat "\\\\\\(group\\|defgroup\\|see\\|author\\|version\\|id\\|since"
62           "\\|returns?\\|throws?\\|exception\\|raises\\|param\\|li\\|brief"
63           "\\|internal\\|bug\\|fixme\\|todo\\|idea\\|implementation"
64           "\\|note\\|attention\\|warning\\|par\\|code\\|endcode"
65           "\\|post\\|pre\\|deprecated\\)\\b"))
66
67 (defconst ccide-special-extensions
68   '(".h" ".hh" ".mpp" ".ih" ".cc" ".cpp" ".ct" ".cti" ".cci" ".dox"))
69
70 (defconst ccide-implementation-extensions
71   '(".h" ".hh" ".ih" ".cc" ".cpp" ".ct" ".cti" ".cci"))
72
73 (defconst ccide-class-defaults-word
74   "// \\(default\\|no\\|protected\\|private\\|disabled\\|my\\)")
75
76 (defconst  ccide-bindings
77   '(
78     ;; file level
79     ("fc"  ccide-file-comment                 "File comment")
80     ("fs"  ccide-syncronize-includes          "Sync includes")
81     (nil   nil                                separator)
82
83     ;; class level
84     ("cc"  ccide-class-comment                "Class comment")
85     ("cg"  ccide-gen-class                    "Generate class")
86     ("cd"  ccide-gen-class-defaults           "Generate class defaults")
87     ("cD"  ccide-gen-class-defaults-impl      "Generate class defaults impl")
88
89     ("csd" ccide-set-class-defaults-default   "Set class defaults comment" "Default")
90     ("csn" ccide-set-class-defaults-no        "Set class defaults comment" "No")
91     ("csp" ccide-set-class-defaults-protected "Set class defaults comment" "Protected")
92     ("csr" ccide-set-class-defaults-private   "Set class defaults comment" "Private")
93     ("csx" ccide-set-class-defaults-disabled  "Set class defaults comment" "Disabled")
94     ("csm" ccide-set-class-defaults-my        "Set class defaults comment" "My")
95
96     ("cS"  ccide-gen-struct-constructors      "Generate structure constructors")
97     ("c<"  ccide-gen-struct-compare           "Generate structure compare operators")
98
99     ("ci"  ccide-class-impl-comment           "Generate class implemenation comment")
100
101     ("ce"  ccide-gen-exception                "Generate an exception class")
102
103     (nil   nil                                separator)
104
105     ;; method level
106     ("mc"  ccide-function-comment             "Method comment")
107     ("mp"  ccide-grab-prototype               "Grab prototype")
108     ("mr"  ccide-reformat-defun               "Reformat defun")
109     ("mx"  ccide-replace-defun                "Replace defun")
110     ("mt"  ccide-prefix-defun-type-with-class "Prefix defun type with class")
111     ("mn"  ccide-prefix-defun-type-with-namespace "Prefix defun type with namespace")
112     ("mi"  ccide-grab-inline-decl             "Grab inline decl")
113     ("mA"  ccide-grab-all-inlines             "Grab ALL inline decls")
114     ("mC"  ccide-grab-create-constructor      "Grab CREATE constructor")
115     ("mI"  ccide-grab-create-constructor-impl "Build CREATE cosntructor")
116     ("mf"  ccide-find-implementation          "Find method implementation")
117     ("mT"  ccide-insert-defun-prefix          "Insert current defun prefix at point")
118     (nil   nil                                separator)
119
120     ;; variable level
121     ("vc"  ccide-variable-comment             "Variable comment")
122     ("vf"  ccide-grab-access-fn               "Grab access methods")
123     (nil   nil                                separator)
124
125     ;; documentation
126     ("h"  ccide-hide-all-doxy-comments        "Hide all Doxygen comments")
127     ("s"  ccide-show-all-comments             "Show all Doxygen comments")
128
129 ;    ;; CORBA
130 ;    ("Cg"  ccide-gen-corba-impl                      "Generate CORBA impl")
131 ;    ("Cm"  ccide-gen-corba-impl-methods       "Generate CORBA impl methods")
132 ;    (nil   nil                               separator)
133
134     ;; templates
135 ;    ("ts"  ccide-scan-mantemps               "Scan mantemps")
136 ;    (nil   nil                                separator)
137
138 ;    ;; other
139 ;    ("of"  ccide-open-compilation-frame       "Open *compilation* frame")
140 ;    ("oc"  ccide-compile-compile              "Make -> Compile")
141 ;    ("ox"  ccide-compile-clean                "Make -> Clean")
142 ;    ("od"  ccide-compile-cleandepends         "Make -> Clean depends")
143 ;    ("ok"  ccide-compile-kill                 "Kill compilation")
144 ;    ("oh"  ccide-hide-compilation             "Hide *compilation* buffer")
145
146     ))
147
148 ;;; Code:
149
150 (require 'cc-engine-2)
151 (require 'cc-helper)
152 (require 'c++)
153 (require 'cl)
154 (require 'hideshow)
155 ;(require 'mantemp)
156 (require 'locate)
157 (require 'lucid)
158 (require 'varcmd)
159 (require 'misc-local)
160
161 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
162 ;; utils
163
164 (defsubst ccide-match-string (n)
165   (buffer-substring-no-properties (match-beginning n) (match-end n)))
166
167 (defun ccide-file-macro-name (&optional file-name)
168   (concat (upcase (file-name-extension (or file-name (buffer-file-name))))
169           "_"
170           (if ccide-project-name (concat ccide-project-name "_") "")
171           (if ccide-project-root
172               (string-replace "/" "_"
173                               (substring (file-name-directory
174                                           (expand-file-name (or file-name buffer-file-name)))
175                                          (length ccide-project-root))
176                               t)
177             "")
178           (string-replace "\\." "_" (file-name-sans-extension
179                                      (file-name-nondirectory
180                                       (or file-name (buffer-file-name))))
181                           t nil t t)
182           "_"))
183
184 (defun ccide-file-name (&optional extension file-name directory)
185   (concat (if directory (file-name-as-directory directory) "")
186           (file-name-sans-extension
187            (file-name-nondirectory
188             (or file-name (buffer-file-name))))
189           extension))
190
191 (defun ccide-in-doxy-comment ()
192   (save-excursion
193     (back-to-indentation)
194     (let ((lit (c-in-literal)))
195       (when (and (memq lit '(c c++))
196                  (progn (goto-char (car (c-literal-limits)))
197                         (looking-at "/\\(\\*\\*\\|///\\)<?[ \t\n\r@]")))
198         (goto-char (match-end 0))
199         (current-column)))))
200
201 (defun ccide-shell-command (command)
202   (let ((obuf (get-buffer-create "*ccide shell command*"))
203         exit-status)
204     (save-excursion
205       (set-buffer obuf)
206       (erase-buffer)
207       (insert command "\n"))
208     (setq exit-status (call-process shell-file-name nil "*ccide shell command*" nil
209                                     shell-command-switch command))
210     (and exit-status (equal exit-status 0))))
211
212 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
213 ;; file level
214
215 (defun ccide-file-comment ()
216   "Add a comment to this source file."
217   (interactive)
218   (let ((mode "c++")
219         point add-file-vars)
220     (push-mark)
221     (goto-char (point-min))
222     (insert "// $Id$\n"
223             "//\n"
224             "// Copyright (C) " (number-to-string (nth 5 (decode-time)))
225             " " ccide-default-author "\n"
226             ccide-default-copyright
227             "\n")
228
229     (cond ((string-match "\\.hh?$" (buffer-file-name))
230            (insert "/** \\file\n"
231                    "    \\brief " (ccide-file-name) " public header */\n\n"
232                    "#ifndef " (ccide-file-macro-name) "\n"
233                    "#define " (ccide-file-macro-name) " 1\n\n")
234            (if ccide-all-includes
235                (insert "#ifndef " (ccide-file-macro-name ccide-all-includes) "\n"
236                        "#error \"Don't include '" (file-name-nondirectory (buffer-file-name)) "'"
237                        " directly, include '" ccide-all-includes "'\"\n"
238                        "#endif\n\n"))
239            (insert "// Custom includes\n\n"
240                    "//#include \"" (ccide-file-name ".mpp") "\"\n"
241                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n\n")
242            (setq point (point))
243            (goto-char (point-max))
244            (insert "\n\n//-/////////////////////////////////////////////////////////////////////////////////////////////////\n")
245            (if ccide-all-includes
246                (insert "#endif\n"
247                        "#if !defined(" (ccide-file-macro-name ccide-all-includes) "_decls_) "
248                        "&& !defined(" (ccide-file-macro-name) "i_)\n"
249                        "#define " (ccide-file-macro-name) "i_\n"))
250            (insert "//#include \"" (ccide-file-name ".cci") "\"\n"
251                    "//#include \"" (ccide-file-name ".ct") "\"\n"
252                    "//#include \"" (ccide-file-name ".cti") "\"\n"
253                    "#endif"))
254
255           ((string-match "\\.mpp$" (buffer-file-name))
256            (insert "/** \\file\n"
257                    "    \\brief " (ccide-file-name) " Boost.Preprocesser external iteration include */\n\n"
258
259
260                    "#if !BOOST_PP_IS_ITERATING && !defined(" (ccide-file-macro-name) ")\n"
261                    "#define " (ccide-file-macro-name) " 1\n\n"
262                    "// Custom includes\n\n\n"
263                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
264                    "#elif BOOST_PP_IS_ITERATING //-/////////////////////////////////////////////////////////////////////\n"
265                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
266                    "// Local Macros\n\n\n"
267                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
268                    "#if BOOST_PP_ITERATION_FLAGS()==1 //-///////////////////////////////////////////////////////////////\n"
269                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n\n")
270            (setq point (point))
271            (goto-char (point-max))
272            (insert "\n\n//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
273                    "#endif //-//////////////////////////////////////////////////////////////////////////////////////////\n"
274                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
275                    "// Undefine local Macros\n\n\n"
276                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
277                    "#endif //-//////////////////////////////////////////////////////////////////////////////////////////\n"
278                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////"))
279
280           ((string-match "\\.ih$" (buffer-file-name))
281            (insert "/** \\file\n"
282                    "    \\brief " (ccide-file-name) " internal header */\n\n"
283                    "#ifndef " (ccide-file-macro-name) "\n"
284                    "#define " (ccide-file-macro-name) " 1\n\n"
285                    "// Custom includes\n\n"
286                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n\n")
287            (setq point (point))
288            (goto-char (point-max))
289            (insert "\n\n//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
290                    "#endif"))
291
292           ((or (string-match "\\.test\\.cc$" (buffer-file-name))
293                (string-match "\\.test\\.cpp$" (buffer-file-name)))
294            (insert "/** \\file\n"
295                    "    \\brief " (ccide-file-name) " unit tests */\n\n"
296                    "//#include \"" (ccide-file-name ".hh") "\"\n"
297                    "//#include \"" (ccide-file-name ".ih") "\"\n\n"
298                    "// Custom includes\n"
299                    "#include \"" (or ccide-all-includes
300                                      (ccide-file-name ".hh" (ccide-file-name))) "\"\n\n"
301                    "#include <boost/test/auto_unit_test.hpp>\n"
302                    "#include <boost/test/test_tools.hpp>\n\n"
303                    "#define prefix_\n"
304                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n\n")
305            (setq point (point))
306            (goto-char (point-max))
307            (insert "\n\n//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
308                    "#undef prefix_"))
309
310           ((or (string-match "\\.cc$" (buffer-file-name))
311                (string-match "\\.cpp$" (buffer-file-name)))
312            (insert "/** \\file\n"
313                    "    \\brief " (ccide-file-name) " non-inline non-template implementation */\n\n"
314                    (if ccide-all-includes "" "//")
315                    "#include \"" (or ccide-all-includes (ccide-file-name ".hh")) "\"\n"
316                    "//#include \"" (ccide-file-name ".ih") "\"\n\n"
317                    "// Custom includes\n\n"
318                    "//#include \"" (ccide-file-name ".mpp") "\"\n"
319                    "#define prefix_\n"
320                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n\n")
321            (setq point (point))
322            (goto-char (point-max))
323            (insert "\n\n//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
324                    "#undef prefix_\n"
325                    "//#include \"" (ccide-file-name ".mpp") "\""))
326
327           ((string-match "\\.cci$" (buffer-file-name))
328            (insert "/** \\file\n"
329                    "    \\brief " (ccide-file-name) " inline non-template implementation */\n\n"
330                    "//#include \"" (ccide-file-name ".ih") "\"\n\n"
331                    "// Custom includes\n\n"
332                    "#define prefix_ inline\n"
333                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n\n")
334            (setq point (point))
335            (goto-char (point-max))
336            (insert "\n\n//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
337                    "#undef prefix_"))
338
339           ((string-match "\\.ct$" (buffer-file-name))
340            (insert "/** \\file\n"
341                    "    \\brief " (ccide-file-name) " non-inline template implementation  */\n\n"
342                    "//#include \"" (ccide-file-name ".ih") "\"\n\n"
343                    "// Custom includes\n\n"
344                    "#define prefix_\n"
345                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n\n")
346            (setq point (point))
347            (goto-char (point-max))
348            (insert "\n\n//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
349                    "#undef prefix_"))
350
351           ((string-match "\\.cti$" (buffer-file-name))
352            (insert "/** \\file\n"
353                    "    \\brief " (ccide-file-name) " inline template implementation */\n\n"
354                    "//#include \"" (ccide-file-name ".ih") "\"\n\n"
355                    "// Custom includes\n\n"
356                    "#define prefix_ inline\n"
357                    "//-/////////////////////////////////////////////////////////////////////////////////////////////////\n\n")
358            (setq point (point))
359            (goto-char (point-max))
360            (insert "\n\n//-/////////////////////////////////////////////////////////////////////////////////////////////////\n"
361                    "#undef prefix_"))
362
363           ((string-match "\\.dox$" (buffer-file-name))
364            (insert "/** \\mainpage\n\n    ")
365            (setq point (point))
366            (insert "\n */")
367            (setq add-file-vars '(( mode . flyspell)
368                                  ( mode . auto-fill))))
369
370           ((string-match "\\.java$" (buffer-file-name))
371            (setq mode "jde")
372            (setq point (point))
373            (goto-char (point-max)))
374
375           (t
376            (setq point (point))
377            (goto-char (point-max))))
378
379     (insert "\n\n\f\n"
380             "// Local Variables:\n"
381             "// mode: " mode "\n")
382     (loop for (var . value) in ccide-file-vars
383           do (insert "// " (symbol-name var) ": " (prin1-to-string value) "\n"))
384     (loop for (var . value) in add-file-vars
385           do (insert "// " (symbol-name var) ": " (prin1-to-string value) "\n"))
386     (insert "// End:\n")
387     (if point
388         (goto-char point))
389     (if (equal mode "jde")
390         (let ((package (file-name-directory (buffer-file-name))))
391           (jdeap-initialize-setup)
392           (if (not (equal jdeap-current-source-directory "."))
393               (if (string-match
394                    (concat "^" (regexp-quote jdeap-current-source-directory))
395                    package)
396                   (progn
397                     (setq package (substring package
398                                              (match-end 0)
399                                              (1- (length package))))
400                     (insert "package "
401                             (string-replace "/" "." package t)
402                             ";\n\n"))))
403           (insert "class " (file-name-sans-extension
404                             (file-name-nondirectory
405                              (buffer-file-name))) "\n{}")
406           (beginning-of-line))))
407   (run-hooks 'ccide-new-file-hooks))
408
409 (defun ccide-sync-file-variables ()
410   "Syncronize file variables to the current value of ccide-file-vars"
411   (interactive)
412   (save-excursion
413     (goto-char (point-max))
414     (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
415     (let ((case-fold-search t))
416       (if (search-forward "Local Variables:" nil t)
417           (let (prefix suffix vars)
418             (skip-chars-forward " \t")
419             (or (eolp)
420                 (setq suffix (buffer-substring (point) (progn (end-of-line) (point)))))
421             (goto-char (match-beginning 0))
422             (or (bolp)
423                 (setq prefix (buffer-substring (point) (progn (beginning-of-line) (point)))))
424             (loop do (progn
425                        (forward-line 1)
426                        (if (and prefix (looking-at prefix))
427                            (goto-char (match-end 0)))
428                        (skip-chars-forward " \t"))
429                   while (not (looking-at "end:"))
430                   do (progn
431                        (setq vars (cons (intern (buffer-substring
432                                                  (point)
433                                                  (progn (skip-chars-forward "^:\n") (point))))
434                                         vars))))
435             (beginning-of-line)
436             (loop for (var . value) in ccide-file-vars
437                   do (if (not (memq var vars))
438                          (insert (or prefix "")
439                                  (symbol-name var) ": " (prin1-to-string value)
440                                  (or suffix "") "\n"))))))))
441
442 (defun ccide-syncronize-includes ()
443   "Syncronize include's in all other files"
444   (interactive)
445   (let (buffer-map)
446     (loop for extension in ccide-special-extensions
447           for file-name = (ccide-file-name extension)
448           do (setq buffer-map
449                    (cons (cons file-name
450                                (or (find-buffer-visiting file-name)
451                                    (and (file-readable-p file-name)
452                                         (find-file-noselect file-name))))
453                          buffer-map)))
454     (save-excursion
455       (loop for buffer in buffer-map
456             if (cdr buffer)
457               do (progn
458                    (set-buffer (cdr buffer))
459                    (save-excursion
460                      (loop for include in buffer-map
461                            do (progn
462                                 (goto-char (point-min))
463                                 (while (re-search-forward
464                                         (concat "^\\(//\\)?#\\s-*include \""
465                                                 (regexp-quote (car include))
466                                                 "\"\\s-*$")
467                                         nil t)
468                                   (goto-char (match-beginning 0))
469                                   (if (looking-at "//")
470                                       (if (cdr include)
471                                           (delete-char 2))
472                                     (if (not (cdr include))
473                                         (insert "//")))
474                                   (forward-line 1))))))))))
475
476 (defun ccide-auto-decorate-new-files ()
477   (if (and (buffer-file-name) (= (point-min) (point-max)))
478       (let ((status (buffer-modified-p)))
479         (ccide-file-comment)
480         (set-buffer-modified-p status))))
481
482 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
483 ;; class level
484
485 (defun ccide-class-comment ()
486   "Add comment to start of current class definition"
487   (interactive)
488   (let ((class (c-get-class-at-point)))
489     (if (not class)
490         (error "No class found")
491       (goto-char (or (aref (car class) 3)
492                      (aref (car class) 1)))
493       (if (save-excursion
494             (forward-line -1)
495             (ccide-in-doxy-comment))
496           (progn
497             (search-backward "/**" nil t)
498             (forward-char 4))
499         (let ((indent (make-string (current-indentation) ? )))
500           (insert "/** \\brief  ")
501           (save-excursion
502             (insert "\n"
503                     indent " */\n"
504                     indent)))))))
505
506 (defun ccide-gen-class (name &optional defns)
507   "Generate class declaration template"
508   (interactive (list (read-string (concat "Class name (default "
509                                           (ccide-file-name)
510                                           "): ")
511                                   nil nil (ccide-file-name))))
512   (insert "class " name)
513   (indent-according-to-mode)
514   (let ((in (make-string c-basic-offset ? ))
515         (ofs (make-string (current-indentation) ? ))
516         (sl (make-string (- 100 3 c-basic-offset (current-indentation)) ?/)))
517     (save-excursion
518       (beginning-of-line)
519       (open-line 1)
520       (insert ofs "/** \\brief\n"
521               ofs "  */"))
522     (insert "\n" ofs)
523     (save-excursion
524       (insert "{\n"
525               ofs "public:\n"
526               ofs in "//-" sl "\n"
527               ofs in "// Types\n\n"
528               ofs in "//-" sl "\n"
529               ofs in "///\\name Structors and default members\n"
530               ofs in "//\\{\n\n"
531               ofs in "// default default constructor\n"
532               ofs in "// default copy constructor\n"
533               ofs in "// default copy assignment\n"
534               ofs in "// default destructor\n\n"
535               ofs in "// no conversion constructors\n\n"
536               ofs in "//\\}\n"
537               ofs in "//-" sl "\n"
538               ofs in "///\\name Accessors\n"
539               ofs in "//\\{\n\n"
540               ofs in "//\\}\n"
541               ofs in "//-" sl "\n"
542               ofs in "///\\name Mutators\n"
543               ofs in "//\\{\n\n"
544               ofs in "//\\}\n\n")
545       (loop for defn in defns
546             do (insert ofs in defn ";\n"))
547       (if defns
548           (insert "\n"))
549       (insert ofs "protected:\n\n"
550               ofs "private:\n\n"
551               ofs "};\n"))))
552
553 (defun ccide-gen-class-defaults ()
554   "Generate signatures of the default functions: default constructor,
555 copy constructor, assignment operator and destructor."
556   (indent-according-to-mode)
557   (let* ((name (c-scope-name (aref (car (c-get-class-at-point)) 1)))
558          (in (make-string c-basic-offset ? ))
559          (ofs (make-string (current-indentation) ? ))
560          (tspec (if ccide-gen-throw (concat "\n" ofs in "throw_(());\n") ";\n"))
561          (colon 0))
562     (while (string-match "::" name colon)
563       (setq colon (match-end 0)))
564     (setq name (substring name colon))
565     (beginning-of-line)
566     (delete-horizontal-space)
567     (loop with exit = nil
568           do (message (concat "1-dflt constr, 2-destr, "
569                               "3-copy constr, 4-copy assmnt, "
570                               "c-all copy, d-all dflt, RET-all/done: "))
571           for ch = (read-event)
572           for first = t then nil
573           do (cond ((eq ch 'return)
574                     (if first
575                         (insert ofs name "()"
576                                 tspec
577                                 ofs name "(const " name "& other)"
578                                 tspec
579                                 ofs "~" name "();\n"
580                                 ofs name "& operator=(const " name "& other)"
581                                 tspec))
582                     (setq exit t))
583                    ((eq ch ?1)
584                     (insert ofs name "()"
585                             tspec))
586                    ((eq ch ?2)
587                     (insert ofs "~" name "();\n"))
588                    ((eq ch ?3)
589                     (insert ofs name "(const " name "& other)"
590                             tspec))
591                    ((eq ch ?4)
592                     (insert ofs name "& operator=(const " name "& other)"
593                             tspec))
594                    ((eq ch ?c)
595                     (insert ofs name "(const " name "& other)"
596                             tspec
597                             ofs name "& operator=(const " name "& other)"
598                             tspec))
599                    ((eq ch ?d)
600                     (insert ofs name "()"
601                             tspec
602                             ofs "~" name "();\n"))
603                    (t (setq unread-command-events (cons ch unread-command-events))
604                       (setq exit t)))
605           while (not exit))))
606
607 (defun ccide-gen-class-defaults-impl ()
608   "Generate default implementations for class default functions"
609   (interactive)
610   (let ((defn (c-build-default-funcions-impl)))
611     (kill-new (cadr defn))
612     (message (concat (car defn) " default members"))))
613
614 (defun ccide-set-class-defaults-comment (word)
615   (save-excursion
616     (back-to-indentation)
617     (if (not (looking-at ccide-class-defaults-word))
618         (message "Not at class defaults commnet")
619       (replace-match word t t nil 1))))
620
621 (defmacro ccide-build-class-defaults-f (sym)
622   (let ((fn (intern (concat "ccide-set-class-defaults-"
623                             (symbol-name sym)))))
624     `(defun ,fn ()
625        (interactive)
626        (ccide-set-class-defaults-comment ,(symbol-name sym)))))
627
628 (ccide-build-class-defaults-f no)
629 (ccide-build-class-defaults-f default)
630 (ccide-build-class-defaults-f my)
631 (ccide-build-class-defaults-f protected)
632 (ccide-build-class-defaults-f private)
633 (ccide-build-class-defaults-f disabled)
634
635 (defun ccide-gen-struct-constructors ()
636   (interactive)
637   (save-excursion
638     (beginning-of-line)
639     (open-line 1)
640     (indent-according-to-mode)
641     (let* ((scope (c-get-block-scope))
642            (class (c-parse-class scope))
643            (variables (c-get-variable-members-with-type class))
644            (name (c-scope-name (aref (car (last scope)) 1)))
645            (in (make-string (current-indentation) ? ))
646            (inin (make-string (+ (current-indentation) c-basic-offset) ? )))
647       (insert name "()\n" inin ": ")
648       (loop for var in variables
649             for first = t then nil
650             if (not first) do (insert ", ")
651             do (insert (car var) " ()"))
652       (insert " {}\n\n"
653               in name "(")
654       (loop for var in variables
655             for first = t then nil
656             if (not first) do (insert ", ")
657             do (insert (cdr var) " " (car var) "_"))
658       (insert ")\n" inin ": ")
659       (loop for var in variables
660             for first = t then nil
661             if (not first) do (insert ", ")
662             do (insert (car var) " (" (car var) "_)"))
663       (insert " {}"))))
664
665
666 (defun ccide-gen-struct-compare ()
667   (interactive)
668   (save-excursion
669     (beginning-of-line)
670     (open-line 1)
671     (indent-according-to-mode)
672     (let* ((scope (c-get-block-scope))
673            (class (c-parse-class scope))
674            (variables (c-get-variable-members-with-type class))
675            (name (c-scope-name (aref (car (last scope)) 1)))
676            (in (make-string (current-indentation) ? ))
677            (inin (make-string (+ (current-indentation) c-basic-offset) ? )))
678
679       (insert "bool operator<(" name " const & other) const\n"
680               in "{ return\n")
681       (loop for ((varName . varType) . tail) on variables
682             do (insert inin varName " < other." varName " ? true :")
683             do (if tail
684                    (insert "\n" inin "other." varName " < " varName " ? false :\n")
685                  (insert " false; }\n\n")))
686       (insert in "bool operator==(" name " const & other) const\n"
687               in "{ return\n")
688       (loop for ((varName . varType) . tail) on variables
689             do (insert inin varName " == other." varName)
690             do (if tail (insert " &&\n") (insert "; }\n\n")))
691       (insert in "std::size_type hash_value() const\n"
692               in "{ std::size_t current (0);\n")
693       (loop for ((varName . varType) . tail) on variables
694             do (insert inin "boost::hash_combine(current, " varName ");\n"))
695       (insert inin "return current; }\n\n")
696       (insert in "void write(std::ostream & os) const\n"
697               in "{ os << \"{ \"")
698       (loop for ((varName . varType) . tail) on variables
699             do (insert "\n" inin "<< " varName)
700             do (if tail (insert " << ' '")))
701       (insert " << \" }\"; }\n"))))
702
703 (defun ccide-class-impl-comment ()
704   "Get implementation comment for current class"
705   (interactive)
706   (let* ((scope (c-get-block-scope))
707          (name (c-get-full-prefix scope)))
708     (kill-new (concat (make-string 75 ?/) "\n"
709                       "// " name "\n\n"
710                       "// protected\n\n"
711                       "// private\n\n"))
712     (message name)))
713
714 (defun ccide-gen-exception (class &optional description)
715   (interactive "sException name: \nsDescription (defaults to full class name): ")
716   (beginning-of-line)
717   (open-line 1)
718   (indent-according-to-mode)
719   (save-excursion
720     (let ((in (make-string c-basic-offset ? ))
721           (ofs (make-string (current-indentation) ? ))
722           (prefix (c-get-full-prefix (c-get-block-scope)))
723           p)
724       (insert "struct " class " : public std::exception\n"
725               ofs "{ virtual char const * what() const throw() ")
726       (setq p (point))
727       (insert "{ return \""
728               (if (and description (> (length description) 0))
729                   description
730                 (concat prefix "::" class))
731               "\"; } };")
732       (if (> (current-column) fill-column)
733           (save-excursion
734             (goto-char p)
735             (insert "\n" ofs in in))))))
736
737 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
738 ;; function/method level
739
740 (defun ccide-function-comment ()
741   "Add comment for current function"
742   (interactive)
743   (if (memq (c-in-literal) '(c c++))
744       ; Assume, we are in the functions comment ...
745       (progn
746         (c-forward-out-of-comment)
747         (c-backward-syntactic-ws)
748         (c-backward-sexp))
749     (beginning-of-line))
750   (c-beginning-of-defun-or-decl)
751   (let ((defun (c-get-defun-state))
752         (indent (make-string comment-column ? ))
753         place)
754     (goto-char (or (aref defun 7) (car (aref defun 6))))
755     (c-backward-syntactic-ws)
756     (if (looking-at "[ \t\n\r]*///<")
757         (progn
758           (delete-region (point) (progn (skip-chars-forward " \t\n\r") (point)))
759           (if (> (current-column) comment-column)
760               (insert "\n"))
761           (indent-to-column comment-column)
762           (search-forward "*/")
763           (forward-char -2))
764       (if (> (current-column) comment-column)
765           (insert "\n"))
766       (indent-to-column comment-column)
767       (insert "///< ")
768       (setq place (point))
769       (insert "\n"
770               indent "/**< ")
771       (insert             "\\pre \n"
772                           indent "     \\post */")
773       (save-excursion
774         (goto-char (car (aref defun 2)))
775         (setq defun (c-get-defun-state)))
776       (forward-char -2))
777     (ccide-function-comment-adjust defun (concat indent "     "))
778     (if place (goto-char place))))
779
780 (defun ccide-function-comment-grab-args ()
781   (let ((limit (save-excursion
782                  (search-backward "/**" nil t)
783                  (point)))
784         (end  (point))
785         begin start args argend)
786     (setq argend end)
787     (while (or (search-backward "\\param" limit t)
788                (search-backward "\\return" limit t)))
789     (beginning-of-line)
790     (setq start (point))
791     (setq begin start)
792     (while (search-forward "\\param" argend t)
793       (or (search-forward "\\param" argend t)
794           (search-forward "\\return" argend t)
795           (goto-char argend))
796       (beginning-of-line)
797       (setq args (cons (ccide-function-comment-parse-arg start (point))
798                        args))
799       (setq start (point)))
800     (prog1
801         (if (not (search-forward "\return" argend t))
802             (cons nil args)
803           (beginning-of-line)
804           (cons (buffer-substring (point) argend) args))
805       (delete-region begin end))))
806
807 (defun ccide-function-comment-parse-arg (start end)
808   (save-excursion
809     (goto-char start)
810     (re-search-forward "\\\\param\\(\\[[^]]*\\]\\)?\\s-*\\(\\S-*\\)" end t)
811     (cons (match-string 2)
812           (cons (buffer-substring start (match-beginning 2))
813                 (buffer-substring (match-end 2) end)))))
814
815 (defun ccide-function-comment-get-throws (defun)
816   (if (aref defun 4)
817       (save-excursion
818         (goto-char (car (aref defun 4)))
819         (if (re-search-forward "\\(throw_\\|throw\\)((?\\s-*\\([^()]*\\))?)"
820                                (cdr (aref defun 4)) t)
821             (let ((spec (match-string 2)))
822               (if (> (length spec) 0)
823                   spec))))))
824
825 (defun ccide-function-comment-adjust (defun indent)
826   (insert "\n")
827   (let* ((defargs (mapcar (function (lambda (x)
828                                       (c-get-template-argument-name (car x) (cdr x))))
829                           (aref defun 3)))
830          (defret (and (aref defun 1)
831                       (not (string-match (concat "^\\("
832                                                  c-special-key
833                                                  "\\s-*\\)*\\s-*void$")
834                                          (buffer-substring (car (aref defun 1))
835                                                            (cdr (aref defun 1)))))))
836          (throws (ccide-function-comment-get-throws defun))
837          (xargs (ccide-function-comment-grab-args))
838          (docargs (cdr xargs))
839          (docret (car xargs))
840          (def-in-doc (loop for defarg in defargs always (assoc defarg docargs)))
841          (doc-in-def (loop for docarg in docargs always (member (car docarg) defargs)))
842          (size-eq (= (length defargs) (length docargs))))
843     ;; We differentiate four types changes
844     ;;  - new arguments
845     ;;  - removed arguments
846     ;;  - reordered arguments
847     ;;  - renamed arguments
848     ;;
849     ;; If the change cannot be described by one of the above, it has
850     ;; to be resolved manually
851     (if throws
852         (insert indent "\\throws " throws "\n"))
853     (cond (doc-in-def
854            ;; reordered arguments or new arguments (or no change)
855            (loop for defarg in defargs
856                  for docarg = (assoc defarg docargs)
857                  do (if docarg
858                         (insert (cadr docarg) (car docarg) (cddr docarg))
859                       (insert indent "\\param " defarg " \n"))))
860           (size-eq ; and (not doc-in-def)
861            ;; renamed arguments
862            (loop for defarg in defargs
863                  for docarg in docargs
864                  do (insert (cadr docarg) defarg (cddr docarg))))
865           (def-in-doc
866             ;; removed arguments
867             (loop for defarg in defargs
868                   for docarg = (assoc defarg docargs)
869                   do (insert (cadr docarg) (car docarg) (cddr docarg))))
870           (t (error "Arg change too complex. Resolve manualy.")))
871     ;; return value is simple
872     (if defret
873         (if docret
874             (insert docret)
875           (insert indent "\\return \n"))))
876   (delete-char -1)
877   (delete-horizontal-space)
878   (insert " "))
879
880 (defun ccide-grab-prototype (&optional prefix)
881   "Grab prototype of function defined or declared at point. Prefix
882 arg, if given, specifies the kind of prefix (inline, static, ...) to use."
883   (interactive "P")
884   (save-excursion
885     (c-beginning-of-defun-or-decl)
886     (let* ((prfx (or (and prefix (nth (prefix-numeric-value prefix) c-user-prefixes))
887                      ccide-default-prefix))
888            (defn (c-build-defun prfx)))
889       (kill-new (concat (cadr defn) "\n{}\n"))
890       (message (concat (or prfx "")
891                        (if prfx " " "")
892                        (car defn))))))
893
894 (defun ccide-reformat-defun ()
895   "Reformat the defn of the current defun."
896   (interactive)
897   (save-excursion
898     (c-beginning-of-defun-or-decl)
899     (let ((defn (c-build-defun nil t)))
900       (delete-region (or (caar (aref (caddr defn) 0))
901                          (car (aref (caddr defn) 1))
902                          (car (aref (caddr defn) 2)))
903                      (or (car (aref (caddr defn) 6))
904                          (aref (caddr defn) 7)))
905       (insert (cadr defn) "\n"))))
906
907 (defun ccide-replace-defun ()
908   "Replace the function header with the one on the top of the kill
909 ring (presumably placed there using c++-grab-prototype)."
910   (interactive)
911   (save-excursion
912     (c-beginning-of-defun-or-decl)
913     (let ((parse (c-parse-defun)))
914       (delete-region (or (aref parse 0)
915                          (aref parse 1)
916                          (aref parse 2))
917                      (or (aref parse 5)
918                          (aref parse 6)
919                          (aref parse 7)))
920       (yank)
921       (delete-char -3))))
922
923 (defun ccide-prefix-defun-type-with-class (&optional strip)
924   "If a non-keyword type symbol is found prefixing the current defun,
925 it will be prefixed with the current class prefix."
926   (interactive "p")
927   (save-excursion
928     (c-beginning-of-defun-or-decl)
929     (let* ((parse (c-parse-defun))
930            (prefix (c-scope-name (aref parse 2) (+ (or strip 0) 0))))
931       (goto-char (aref parse 1))
932       (while (and (or (looking-at c-any-key)
933                       (looking-at c-user-prefix-re)
934                       (not (c-at-symbol-p)))
935                   (< (point) (aref parse 2))
936                   (not (eobp)))
937         (c-forward-token-1)
938         (c-forward-syntactic-ws))
939       (if (and (c-at-symbol-p)
940                (< (point) (aref parse 2))
941                (not (looking-at (regexp-quote prefix))))
942           (let ((pos (string-match "<" prefix)))
943             (if pos
944                 (insert "typename "))
945             (if (and pos (looking-at (concat (substring prefix 0 pos)
946                                              "\\b[^_]")))
947                 (progn
948                   (goto-char (match-end 0))
949                   (c-backward-syntactic-ws)
950                   (insert (substring prefix pos)))
951               (insert prefix "::"))
952             (ccide-reformat-defun))))))
953
954 (defun ccide-prefix-defun-type-with-namespace (&optional strip)
955   (interactive "p")
956   (ccide-prefix-defun-type-with-class (+ (or strip 0) 1)))
957
958 (defun ccide-insert-defun-prefix (&optional strip)
959   "Insert the current defun prefix at point."
960   (interactive "p")
961   (let* ((parse (c-parse-defun))
962          (prefix (c-scope-name (aref parse 2) (+ (or strip 0) 0))))
963     (insert prefix "::")))
964
965 (defun ccide-kill-inline-decl (defn)
966   (save-excursion
967     (if (aref (caddr defn) 6)
968         (progn
969           (goto-char (cdr (aref (caddr defn) 6)))
970           (let ((end-mark (point-marker)))
971             (goto-char (car (aref (caddr defn) 6)))
972             (indent-rigidly (point) end-mark
973                             (- (current-column)))
974             (prog1
975                 (concat (cadr defn)
976                         "\n"
977                         (buffer-substring-no-properties (point) end-mark)
978                         "\n")
979               (when (aref (caddr defn) 5)
980                 (goto-char (caar (aref (caddr defn) 5)))
981                 (c-backward-syntactic-ws)
982                 (skip-chars-backward ":"))
983               (c-backward-syntactic-ws)
984               (delete-region (point) end-mark)
985               (insert ";"))))
986       (concat (cadr defn) "\n{}\n"))))
987
988 (defun ccide-grab-inline-decl ()
989   "Grab the inline decl at point at turn it into an out-of-line inline
990 declaration at the top of the kill ring."
991   (interactive)
992   (let ((defn (c-build-defun (or ccide-default-prefix "inline"))))
993     (kill-new (ccide-kill-inline-decl defn))
994     (message (concat (or ccide-default-prefix "indline")
995                      " "
996                      (car defn)))))
997
998 (defun ccide-grab-all-inlines ()
999   "Grab all inline decls in the current class"
1000   (interactive)
1001   (let ((class (c-parse-class (c-get-block-scope)))
1002         defns)
1003     (when class
1004       (loop for method in (nreverse (aref class 4))
1005             do (when (eq (car method) 'method)
1006                  (let ((defn (save-excursion
1007                                (goto-char (cdr method))
1008                                (c-build-defun (or ccide-default-prefix "inline")))))
1009                    (if (aref (caddr defn) 6)
1010                        (setq defns (nconc defns (list (ccide-kill-inline-decl defn))))))))
1011       (setq defns (nreverse defns))
1012       (kill-new (loop for defn in defns
1013                       for next = nil then t
1014                       if next concat "\n";
1015                       concat defn))
1016       (message (format "%d inlines grabed to kill ring" (length defns))))))
1017
1018 (defun ccide-grab-create-constructor ()
1019   (interactive)
1020   (let ((defn (c-build-create-constructor)))
1021     (kill-new (cadr defn))
1022     (message (car defn))))
1023
1024 (defun ccide-grab-create-constructor-impl (&optional prefix)
1025   (interactive "P")
1026   (let* ((prfx (or (and prefix (nth (prefix-numeric-value prefix) c-user-prefixes))
1027                    ccide-default-prefix))
1028          (defn (c-build-create-constructor-impl prfx)))
1029     (kill-new (cadr defn))
1030     (message (concat (or prfx "")
1031                      (if prfx " " "")
1032                      (car defn)))))
1033
1034 (defun ccide-find-implementation (&optional other-window)
1035   "Find implementation of method declared at point."
1036   (interactive "P")
1037   (let* ((state (c-get-defun-state))
1038          (name (c-defun-short-name state))
1039          (scoped-name (c-defun-full-name state))
1040          (args (ccide-implementation-args state))
1041          (targs (ccide-implementation-template-args state))
1042          rv fallback)
1043
1044     (loop for ext in ccide-implementation-extensions
1045           for filename = (ccide-file-name ext)
1046           while (not rv)
1047           do (progn
1048                (let ((buf (or (find-buffer-visiting filename)
1049                                   (and (file-readable-p filename)
1050                                        (find-file-noselect filename)))))
1051                  (when buf
1052                    (let ((found (save-excursion
1053                                   (set-buffer buf)
1054                                   (ccide-find-implementation-1 name scoped-name args targs
1055                                                                (not (aref state 6))
1056                                                                (car (aref state 2))))))
1057                      (if found
1058                          (if (cdr found)
1059                              (setq rv (cons buf found))
1060                            (if (not fallback) (setq fallback (cons buf found))))))))))
1061     (if (not rv) (setq rv fallback))
1062     (if rv
1063         (let* ((buf (car rv))
1064                (pos (cadr rv))
1065                (win (get-buffer-window buf)))
1066           (if win
1067               (select-window win)
1068             (if other-window
1069                 (switch-to-buffer-other-window buf)
1070               (switch-to-buffer buf)))
1071           (goto-char pos)
1072           (forward-char -1)
1073           (c-beginning-of-defun-or-decl))
1074       (message (concat "Implementation of " scoped-name " not found.")))))
1075
1076 (defun ccide-implementation-args (state)
1077   (string-replace "[ \t\n\r]+" ""
1078                   (loop for (start . end) in (aref state 3)
1079                         for sep = "" then ","
1080                         concat sep
1081                         concat (buffer-substring-no-properties
1082                                 start (save-excursion
1083                                         (goto-char start)
1084                                         (if (search-forward "=" end 'move) (forward-char -1))
1085                                         (point))))
1086
1087                   t))
1088
1089 (defun ccide-implementation-template-args (state)
1090   (and (aref state 0)
1091        (string-replace "[ \t\n\r]+" ""
1092                        (loop for (start . end) in   (save-excursion
1093                                                       (goto-char (caar (last (aref state 0))))
1094                                                       (c-parse-template-declaration))
1095                              for sep = "" then ","
1096                              concat sep
1097                              concat (buffer-substring-no-properties
1098                                      start (save-excursion
1099                                              (goto-char start)
1100                                              (if (search-forward "=" end 'move) (forward-char -1))
1101                                              (point))))
1102                        t)))
1103
1104 (defun ccide-find-implementation-1 (name scoped-name args targs with-body skip-def)
1105   ;; Within the current buffer, search for all implementations of the
1106   ;; given function. The rv is a list of conses. The car holds the
1107   ;; buffer position of the implementation, the cdr is t if the name,
1108   ;; scoped-name and args are matched, otherwise the args did not match.
1109   (save-excursion
1110     (goto-char (point-min))
1111     (let ((re (concat (if (eq (char-syntax (aref name 0)) ?w) "\\<" "")
1112                       (regexp-quote name)
1113                       (if (eq (char-syntax (aref name (1- (length name)))) ?w) "\\>" "")))
1114           fallback rv check-state)
1115       (while (and (not rv) (re-search-forward re nil t))
1116         (if (c-save-buffer-state ()
1117               (and (c-at-toplevel-p)
1118                    (not (c-in-literal))
1119                    (setq check-state (condition-case nil (c-get-defun-state) (error nil)))
1120                    (not (= (car (aref check-state 2)) skip-def))))
1121             (if (string= scoped-name (c-defun-full-name check-state))
1122                 (if (and (if with-body (aref check-state 6) (not (aref check-state 6)))
1123                          (string= args (ccide-implementation-args check-state))
1124                          (string= targs (ccide-implementation-template-args check-state)))
1125                     (setq rv (cons (point) t))
1126                   (if (not fallback)
1127                       (setq fallback (cons (point) nil)))))))
1128       (or rv fallback))))
1129
1130 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1131 ;; variable/type level
1132
1133 (defun ccide-variable-comment ()
1134   "Add a comment to current variable declaration."
1135   (interactive)
1136   (c-forward-out-of-comment)
1137   (c-forward-syntactic-ws)
1138   (while (not (looking-at ";"))
1139     (c-forward-sexp)
1140     (c-forward-syntactic-ws))
1141   (forward-char 1)
1142   (if (> (current-column) comment-column)
1143       (insert "\n" (make-string comment-column ? ) "///< ")
1144     (indent-to-column comment-column)
1145     (insert "///< ")))
1146
1147 (defun ccide-grab-access-fn ()
1148   (interactive)
1149   (save-excursion
1150     (beginning-of-line)
1151     (if (looking-at (concat c++-simple-type-regexp "[ \t\n\r][a-zA-Z0-9_]+[ \t\n\r]*;"))
1152         (let ((vardef (match-string 0))
1153               (in (make-string c-basic-offset ? ))
1154               type reftype varname fnname argname ws)
1155           (forward-line -1)
1156           (back-to-indentation)
1157           (string-match "^[ \t\n\r]*\\(.*\\)[ \t\n\r]\\([a-zA-Z0-9_]+\\)[ \t\n\r]*;$"
1158                         vardef)
1159           (setq varname (match-string 2 vardef)
1160                 type (match-string 1 vardef)
1161                 ws (substring vardef 0 (match-beginning 1)))
1162           (if (string-match "_$" varname)
1163               (setq fnname (string-replace "_$" "" varname)
1164                     argname (concat "a_" fnname))
1165             (setq fnname (concat "q_" varname)
1166                   argname (concat "a_" varname)))
1167           (if (string-match "^[ \t\n\r]*" type)
1168               (setq type (substring type (match-end 0))))
1169           (if (string-match "^[A-Z]" type)
1170               (setq reftype (concat type " const &"))
1171             (setq reftype type))
1172           (kill-new (concat ws type " " fnname "(" reftype " " argname ")\n"
1173                             ws in "{\n"
1174                             ws in in type " old" varname " = " varname ";\n"
1175                             ws in in varname " = " argname ";\n"
1176                             ws in in "return old" varname ";\n"
1177                             ws in "}\n\n"
1178                             ws reftype " " fnname "() const\n"
1179                             ws in "{ return " varname "; }\n"))
1180
1181           (message varname))
1182       (message "No variable found"))))
1183
1184 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1185 ;; doxy comment support functions
1186
1187 (defun ccide-special-indent-function ()
1188   "Function to indent doxy comments correctly"
1189   (let ((indent (ccide-in-doxy-comment)))
1190     (if indent
1191         (let ((lim (save-excursion
1192                      (back-to-indentation)
1193                      (c-literal-limits)))
1194               (pos (- (point-max) (point))))
1195           (save-excursion
1196             (back-to-indentation)
1197             (if (looking-at "*/")
1198                 (incf indent -3)
1199               (let ((para (or (save-excursion (re-search-backward "^\\s-*$" (car lim) t))
1200                               (car lim))))
1201                 (if (and (not (looking-at ccide-doxy-tag-re))
1202                          (re-search-backward (concat "^\\s-*"
1203                                                      ccide-doxy-tag-re)
1204                                              para t))
1205                     (incf indent 4)))))
1206           (delete-region (progn (beginning-of-line) (point))
1207                          (progn (back-to-indentation) (point)))
1208           (indent-to indent)
1209           (if (> (- (point-max) pos) (point))
1210               (goto-char (- (point-max) pos)))))))
1211
1212 (defun ccide-fill-function ()
1213   "auto-fill function for doxy comments"
1214   (if (do-auto-fill)
1215       (if (not fill-prefix)
1216           (indent-according-to-mode))))
1217
1218 (defun ccide-hide-all-doxy-comments ()
1219   "Hide all doxy comments"
1220   (interactive)
1221   (save-excursion
1222     (goto-char (point-min))
1223     (while (re-search-forward "^\\s-*/\\*\\*" nil t)
1224       (beginning-of-line)
1225       (forward-line -1)
1226       (if (not (looking-at "\\s-*$"))
1227           (forward-line 1))
1228       (forward-char -1)
1229       (let ((start (point)))
1230         (if (re-search-forward "\\*/" nil t)
1231             (progn
1232               (if (looking-at "\\s-*\n")
1233                   (forward-line 1))
1234               (forward-char -1)
1235               (let ((overlay (make-overlay start (point))))
1236                 (overlay-put overlay 'intangible 'hs)
1237                 (overlay-put overlay 'invisible 'hs)))))))
1238   (message "Done."))
1239
1240 (defun ccide-show-all-comments ()
1241   "Show all comments"
1242   (interactive)
1243   (save-excursion
1244     (goto-char (point-min))
1245     (while (not (eobp))
1246       (goto-char (next-overlay-change (point)))
1247       (loop for overlay in (overlays-at (point))
1248             if (eq (overlay-get overlay 'invisible) 'hs)
1249             do (delete-overlay overlay))))
1250   (message "Done."))
1251
1252 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1253 ;; CORBA support (omniORB2)
1254
1255 (defun ccide-get-corba-headers ()
1256   (let (files)
1257     (save-excursion
1258       (goto-char (point-min))
1259       (while (re-search-forward "#include\\s-*[\"<]\\([^\">]*\\)\\.hh[\">]" nil t)
1260         (setq files (cons (ccide-match-string 1) files)))
1261       (nreverse files))))
1262
1263 (defun ccide-corba-maybe-build-hh (file)
1264   (let ((skel (ccide-file-name ".hh" file ccide-corba-skel-dir))
1265         (idl (ccide-file-name ".idl" file ccide-corba-idl-dir)))
1266     (if (and (file-readable-p idl)
1267              (or (not (file-readable-p skel))
1268                  (file-newer-than-file-p idl skel)))
1269         (let ((buffer (find-buffer-visiting (ccide-file-name ".hh" file))))
1270           (if buffer
1271               (kill-buffer buffer))
1272           (message "Please wait ... building %s" (ccide-file-name ".hh" file))
1273           (if (ccide-shell-command (concat "cd "
1274                                            (real-path-name ccide-corba-skel-dir)
1275                                            " && "
1276                                            ccide-corba-idl-command
1277                                            (if (> (length ccide-corba-idl-dir) 0)
1278                                                (concat " -I" ccide-corba-idl-dir))
1279                                            " "
1280                                            idl))
1281               ()
1282             (display-buffer (get-buffer-create "*ccide shell command*"))
1283             (error "Generation of %s failed" (ccide-file-name ".hh")))))
1284     (if (not (file-readable-p skel))
1285         (error "No file %s or %s"
1286                (ccide-file-name ".hh" file) (ccide-file-name ".idl" file)))))
1287
1288 (defun ccide-corba-list-skeletons-1 (hh-file)
1289   (ccide-corba-maybe-build-hh hh-file)
1290   (let ((hh-buf (find-file-noselect (ccide-file-name ".hh" hh-file)))
1291         skels)
1292     (save-excursion
1293       (set-buffer hh-buf)
1294       (save-excursion
1295         (goto-char (point-min))
1296         (while (re-search-forward "^\\s-*class\\s-+_sk_\\([a-zA-Z0-9_]+\\)\\s-+:"
1297                                   nil t)
1298           (setq skels (cons (ccide-match-string 1) skels)))))
1299     (mapcar (function (lambda (x) (cons x hh-file)))
1300             (sort skels 'string-lessp))))
1301
1302 (defun ccide-corba-list-skeletons ()
1303   (let ((files (ccide-get-corba-headers)))
1304     (loop for file in files
1305           append (ccide-corba-list-skeletons-1 file))))
1306
1307 (defun ccide-gen-corba-impl (class)
1308   (interactive (list (completing-read "Class name of skeleton: "
1309                                       (ccide-corba-list-skeletons)
1310                                       nil t)))
1311   (let* ((skels (ccide-corba-list-skeletons))
1312          (hh-file (ccide-file-name ".hh" (cdr (assoc class skels))
1313                                    ccide-corba-skel-dir))
1314          (hh-buf (find-file-noselect (ccide-file-name ".hh" hh-file
1315                                                       ccide-corba-skel-dir))))
1316     (ccide-gen-class (concat class "_i"))
1317     (insert (make-string c-basic-offset ? ) ": public virtual _sk_" class "\n")
1318     (save-excursion
1319       (search-forward "protected:" nil t)
1320       (forward-line -1)
1321       (ccide-gen-corba-impl-methods)
1322       (insert "\n"))))
1323
1324 (defun ccide-get-corba-defns (hh-file class)
1325   (let ((hh-buf (find-file-noselect hh-file))
1326         defns)
1327     (save-excursion
1328       (set-buffer hh-buf)
1329       (save-excursion
1330         (goto-char (point-min))
1331         (if (not (re-search-forward (concat "^\\s-*class\\s-+_sk_" class "\\s-+:")
1332                                     nil t))
1333             (error "CORBA skeleton class not found.")
1334           (search-forward "{")
1335           (forward-char -1)
1336           (let ((end (save-excursion (forward-sexp) (point))))
1337             (while (and (< (point) end)
1338                         (< (forward-line 1) 1))
1339               (if (looking-at "\\s-+virtual\\s-+\\(.*)\\)\\s-*=\\s-*0;\\s-*$")
1340                   (setq defns (cons (match-string 1) defns))))))))
1341     (nreverse defns)))
1342
1343 (defun ccide-gen-corba-impl-methods ()
1344   (interactive)
1345   (let* ((class (c-get-class-at-point))
1346          (point (point)))
1347     (if (not class)
1348         (error "No class at point."))
1349     (save-excursion
1350       (goto-char (aref (car class) 1))
1351       (if (not (re-search-forward ":\\s-*public\\s-*virtual\\s-*_sk_\\([^ \t\n\r{},:]*\\)"
1352                                   nil t))
1353           (error "No CORBA impl at point."))
1354       (let* ((name (ccide-match-string 1))
1355              (skels (ccide-corba-list-skeletons))
1356              (hh-file (ccide-file-name ".hh" (cdr (assoc name skels))
1357                                        ccide-corba-skel-dir))
1358              (defns (ccide-get-corba-defns hh-file name))
1359              end)
1360         (goto-char (aref (car class) 2))
1361         (save-excursion
1362           (c-forward-sexp)
1363           (setq end (point)))
1364         (if (re-search-forward "^\\s-*// CORBA$" end t)
1365             (let ((start (match-beginning 0)))
1366               (if (re-search-forward "^\\s-*// END-CORBA$" end t)
1367                   (let ((eend (match-end 0)))
1368                     (goto-char start)
1369                     (forward-line 1)
1370                     (if (re-search-forward "/\\*\\|//" (match-beginning 0) t)
1371                         (if (y-or-n-p "Remove CORBA Funktion comments? (y/n)")
1372                             (delete-region start (1+ eend))
1373                           (goto-char eend)
1374                           (beginning-of-line)
1375                           (delete-region (point) (progn
1376                                                    (end-of-line)
1377                                                    (1+ (point))))
1378                           (save-excursion
1379                             (goto-char start)
1380                             (delete-region (point) (progn
1381                                                      (end-of-line)
1382                                                      (1+ (point)))))
1383                           (insert "\n"))
1384                       (delete-region start (1+ eend))))))
1385           (goto-char point))
1386         (indent-according-to-mode)
1387         (insert "// CORBA\n")
1388         (loop for defn in defns
1389               do (progn
1390                    (save-excursion (insert defn ";"))
1391                    (indent-according-to-mode)
1392                    (let ((start (point)) end)
1393                      (end-of-line)
1394                      (setq end (point))
1395                      (goto-char start)
1396                      (while (re-search-forward "\\s-+" end t)
1397                        (replace-match " ")
1398                        (setq end (- end (- (match-end 0) (match-beginning 0) 1))))
1399                      (end-of-line)
1400                      (loop with done = nil
1401                            while (> (current-column) c-max-def-column)
1402                            do (while (and (> (current-column) c-max-def-column)
1403                                           (search-backward "," start t)))
1404                            do (if (looking-at ",")
1405                                   (progn
1406                                     (forward-char 1)
1407                                     (insert "\n")
1408                                     (open-line 1)
1409                                     (indent-according-to-mode)
1410                                     (delete-char 2)
1411                                     (setq start (point))
1412                                     (end-of-line))
1413                                 (setq done t))
1414                            while (not done)))
1415                    (insert "\n")))
1416         (indent-according-to-mode)
1417         (insert "// END-CORBA\n")))))
1418
1419 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1420 ;; template support
1421
1422 (defun ccide-scan-mantemps ()
1423   "Scan *compilation* buffer for errors and generate manual template
1424 instatiations at point."
1425   (interactive)
1426   (save-excursion
1427     (set-buffer "*compilation*")
1428     (goto-char (point-min)))
1429   (save-excursion
1430     (set-buffer (get-buffer-create "*mantemps*"))
1431     (erase-buffer)
1432     (loop for temp = (ccide-get-mantemp)
1433           while temp
1434           do (insert temp "\n"))
1435     (mantemp-make-mantemps-buffer)
1436     (goto-char (point-min))
1437     (while (progn
1438              (ccide-fix-mantemp)
1439              (< (forward-line 1) 1))))
1440   (insert-buffer-substring "*mantemps*"))
1441
1442 (defun ccide-get-mantemp ()
1443   (save-excursion
1444     (set-buffer "*compilation*")
1445     (if (search-forward "undefined reference to `" nil t)
1446         (let ((start (point)))
1447           (end-of-line)
1448           (search-backward "'" nil t)
1449           (buffer-substring start (point))))))
1450
1451 (defun ccide-fix-mantemp ()
1452   (let ((end (save-excursion
1453                (end-of-line) (point))))
1454     (if (and (save-excursion (search-forward "(" end t))
1455              (search-forward " class" end t))
1456         (progn
1457           (forward-char -6)
1458           (delete-char 6)))))
1459
1460 (provide 'cc-ide)
1461
1462 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1463 ;; other stuff
1464
1465 (defun ccide-open-compilation-frame ()
1466   (interactive)
1467   (let ((c-frame (selected-frame))
1468         (compilation-frame (make-frame '((minibuffer . nil)
1469                                          (unsplittable . t)
1470                                          (menu-bar-lines . 0)
1471                                          (top . -87)
1472                                          (left . 36)
1473                                          (width . 169)
1474                                          (height . 9)))))
1475     (select-frame compilation-frame)
1476     (switch-to-buffer "*compilation*")
1477     (set-window-dedicated-p (selected-window) t)))
1478
1479 (defun ccide-compile (command)
1480   (delete-other-windows)
1481   (split-window-horizontally)
1482   (compile command)
1483   (save-excursion
1484     (set-buffer "*compilation*")
1485     (let ((point (point-max)))
1486       (goto-char point)
1487       (loop for window in (get-buffer-window-list "*compilation*" nil t)
1488             do (set-window-point window point)))))
1489
1490 (defun ccide-compile-compile ()
1491   (interactive)
1492   (ccide-compile (concat "make -k " ccide-compile-opts)))
1493
1494 (defun ccide-compile-clean ()
1495   (interactive)
1496   (ccide-compile (concat "make -k " ccide-compile-opts " clean")))
1497
1498 (defun ccide-compile-cleandepends ()
1499   (interactive)
1500   (ccide-compile (concat "make -k " ccide-compile-opts " cleandepends")))
1501
1502 (defun ccide-compile-kill ()
1503   (interactive)
1504   (set-buffer "*compilation*")
1505   (kill-compilation))
1506
1507 (defun ccide-hide-compilation ()
1508   (interactive)
1509   (let ((active (selected-window)))
1510     (unwind-protect
1511         (loop for window in (get-buffer-window-list "*compilation*")
1512               do (progn (select-window window)
1513                         (switch-to-buffer (other-buffer "*compilation*"))))
1514       (select-window active))))
1515
1516 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1517 ;; keymap and installation
1518
1519 (defun ccide-bind-keys (prefix map)
1520   (loop for binding in ccide-bindings
1521         do (apply 'vcmd-define-key
1522                   map
1523                   (concat prefix (car binding))
1524                   (cadr binding)
1525                   "IDE"
1526                   (cddr binding))))
1527
1528 (defun ccide-install-it ()
1529   (save-excursion
1530     (hs-minor-mode 1)
1531     (hs-show-all))
1532   (local-unset-key "\C-c;")
1533   (local-unset-key [menu-bar IDE])
1534   (ccide-bind-keys "\C-c;" (current-local-map))
1535   (local-set-key "\C-cC" 'ccide-hide-all-doxy-comments)
1536   (local-set-key "\C-cS" 'ccide-show-all-comments)
1537   (set (make-local-variable 'auto-fill-function) 'ccide-fill-function)
1538   (set (make-local-variable 'paragraph-start) (concat "[ \t\f]*$\\|[ \t\f]*" ccide-doxy-tag-re))
1539   (set (make-local-variable 'paragraph-separate) "[ \t\f]*$")
1540   (auto-fill-mode -1)
1541   (ccide-project-load-config)
1542   (ccide-directory-load-config)
1543   (ccide-auto-decorate-new-files))
1544
1545 (defun ccide-project-load-config ()
1546   (if (buffer-file-name)
1547       (let ((conf (ccide-project-search-upwards '(".project.el" "project.el")
1548                                                 (file-name-directory (buffer-file-name)))))
1549         (when conf
1550           (set (make-local-variable 'ccide-project-root) (file-name-directory conf))
1551           (load-file conf)))))
1552
1553 (defun ccide-project-search-upwards (names &optional base)
1554   "Search for FILE in all directories starting at DIR and going up the directory hierarchy.
1555 DIR defaults to ccide-project-root. If FILE is a list, search for any file in list."
1556   (if (not (consp names))
1557       (setq names (list names)))
1558   (loop for dir = (or base ccide-project-root) then (directory-file-name (file-name-directory dir))
1559         while (not (string= dir "/"))
1560         thereis (loop for name in names
1561                       for path = (expand-file-name name dir)
1562                       thereis (and (file-readable-p path) path))))
1563
1564 (defun ccide-directory-load-config ()
1565   (if (file-readable-p ".dir.el")
1566       (load-file ".dir.el")))
1567
1568 (add-hook 'c-mode-hook 'ccide-install-it)
1569 (add-hook 'c++-mode-hook 'ccide-install-it)
1570 (add-hook 'c-special-indent-hook 'ccide-special-indent-function)
1571
1572 (loop for extension in ccide-special-extensions
1573       for re = (concat (regexp-quote extension) "$")
1574       if (not (assoc re auto-mode-alist))
1575         do (setq auto-mode-alist (append auto-mode-alist
1576                                          (list (cons re 'c++-mode)))))
1577
1578 (defadvice c-indent-line (after c-indent-less compile disable) ;activate
1579   ;; new indent function for c-mode: do standard indentation first. If line
1580   ;; is to long using standard indentation, just indent by c-basic-indentation.
1581   (let ((cc (save-excursion (end-of-line) (current-column)))
1582         indent)
1583     (if (> cc  85)
1584         (let ((pos (- (point-max) (point))))
1585           (beginning-of-line)
1586           (let ((point (point))
1587                 (line (1+ (count-lines 1 (point))))
1588                 indent)
1589             (c-beginning-of-statement-2)
1590             (if (and (not (c-crosses-statement-barrier-p (point) point))
1591                      (not (eq (+ (count-lines 1 (point))
1592                                  (if (bolp) 1 0))
1593                               line)))
1594                 (progn
1595                   (setq indent (+ (current-indentation) c-basic-offset))
1596                   (goto-char point)
1597                   (if (< indent (current-indentation))
1598                       (progn
1599                         (setq ad-return-value
1600                               (+ ad-return-value
1601                                  (- (current-indentation) indent)))
1602                         (delete-region (c-point 'bol) (c-point 'boi))
1603                         (indent-to indent))))))
1604           (if (< (point) (c-point 'boi))
1605               (back-to-indentation)
1606             (if (> (- (point-max) pos) (point))
1607                 (goto-char (- (point-max) pos))))))))
1608
1609
1610 \f
1611 ;;; Local Variables:
1612 ;;; elisp-project-autoload-file-name: "cc-autoload.el"
1613 ;;; End: