Warning, /sdk/kde-dev-scripts/kde-emacs/kde-emacs-utils.el is written in an unsupported language. File is not indexed.

0001 ;; kde-emacs-utils.el
0002 ;;
0003 ;; Copyright (C)  2002-2005  KDE Development Team <www.kde.org>
0004 ;;
0005 ;; This library is free software; you can redistribute it and/or
0006 ;; modify it under the terms of the GNU Lesser General Public
0007 ;; License as published by the Free Software Foundation; either
0008 ;; version 2.1 of the License, or (at your option) any later version.
0009 ;;
0010 ;; This library is distributed in the hope that it will be useful,
0011 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013 ;; Lesser General Public License for more details.
0014 ;;
0015 ;; You should have received a copy of the GNU Lesser General Public
0016 ;; License along with this library; if not, write to the Free Software
0017 ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0018 ;; 02110-1301  USA
0019 
0020 
0021 (require 'kde-emacs-vars)
0022 (require 'kde-emacs-general)
0023 (require 'kde-emacs-compat)
0024 
0025 (if (eq kde-emacs-type 'xemacs)
0026     (progn
0027       (require 'func-menu)
0028       (add-hook 'find-file-hooks 'fume-add-menubar-entry))
0029   (require 'imenu))
0030 
0031 (defmacro c-safe-scan-lists (from count depth)
0032   "Like `scan-lists' but returns nil instead of signalling errors.
0033 This function does not do any hidden buffer changes."
0034   (if (featurep 'xemacs)
0035       `(scan-lists ,from ,count ,depth nil t)
0036     `(c-safe (scan-lists ,from ,count ,depth))))
0037 
0038 (if (not (eq kde-include-directory nil))
0039     (setq sourcepair-header-path (list "." kde-include-directory "/*")))
0040 
0041 ;; returns non-nil if the given file has a using declaration
0042 ;; with the passed namespace
0043 (defun kde-file-has-using (namespace)
0044   (let (found)
0045     (save-excursion
0046       (beginning-of-buffer)
0047       (setq found (re-search-forward "^using" nil 1))
0048       (if found
0049           (setq found (search-forward namespace (line-end-position) 1))
0050         )
0051       )
0052     found)
0053   )
0054 ;; returns non-nill if the given file has a "namespace SomeNM" declaration
0055 ;; where SomeNM is passed via the namespace argument
0056 (defun kde-file-is-in-namespace (namespace)
0057   (let (found)
0058     (save-excursion
0059       (beginning-of-buffer)
0060       (setq found (re-search-forward "^namespace" nil 1))
0061       (if found
0062           (setq found (search-forward namespace (line-end-position) 1))
0063         )
0064       )
0065     found)
0066   )
0067 
0068 ; Helper function for getting the baseclass of the current class - in a C++ header file
0069 ; Only supports single inheritance
0070 (defun baseclass-under-point ()
0071   (let ((pos (c-safe-scan-lists (point) -1 1)))
0072     (save-excursion
0073       (goto-char (if pos pos (point-min)))
0074       (backward-word 2)                 ; move back over "public baseclass"
0075       (if (looking-at "public\\|protected\\|private[ \t]*")
0076           (progn
0077             (forward-word)
0078             (while (looking-at "[ \t]")
0079               (forward-char 1))
0080             (let ((start (point)))
0081               (forward-word)
0082               (buffer-substring start (point))))
0083         nil
0084         )))
0085     )
0086 
0087 ; Helper function for parsing our current position in a C++ header file
0088 ; returns (namespace (class function)) where (a b) is a cons.
0089 (defun method-under-point ()
0090   (let ((class nil)
0091         (namespace "") ; will contain A::B::
0092         (function nil))
0093     (save-excursion
0094       (backward-char)             ; in case we're after the ';'
0095       (search-forward ";" nil t)  ; look for the ';'
0096       (backward-char)
0097       (save-excursion
0098         ; Go up a level, skipping entire classes etc.
0099         ; This is a modified version of (backward-up-list) which doesn't
0100         ; throw an error when not found.
0101         (let ((pos (c-safe-scan-lists (point) -1 1)))
0102         ; +1 added here so that the regexp in the while matches the { too.
0103           (goto-char (if pos (+ pos 1) (point-min))))
0104         (while (re-search-backward "^[ ]*\\(class\\|namespace\\|struct\\)[ \t][^};]*{" nil t)
0105           (save-excursion
0106             (forward-word 1)
0107            (when (looking-at "[ \t]*[A-Z_]*_EXPORT[A-Z_]*[ \t]")
0108              (forward-word 1)
0109              (re-search-forward "[ \t]" nil t))
0110             (while (looking-at "[ \t]")
0111               (forward-char 1))
0112             (setq start (point))
0113             ; Parse class name ("Foo" or "Foo::Bar::Blah"). 
0114             ; Beware of "Foo:"
0115             (while (or (looking-at "[A-Za-z0-9_]") (looking-at "::"))
0116               (while (looking-at "[A-Za-z0-9_]")
0117                 (forward-char 1))
0118               (while (looking-at "::")
0119                 (forward-char 2))
0120               )
0121             (cond
0122              (class                     ; class found already, so the rest goes into the namespace
0123               (setq namespace (concat (buffer-substring start (point)) "::" namespace)))
0124              (t                         ; class==nil
0125               (setq class (buffer-substring start (point)))))
0126             )
0127         ; Go up one level again
0128         (let ((pos (c-safe-scan-lists (point) -1 1)))
0129           (goto-char (if pos (+ pos 1) (point-min))))
0130         ))
0131 
0132     ; Back to where we were, parse function name
0133     (let ((end (point)))          ; remember where the function decl ends
0134       (search-backward ")" nil t) ; look back for the end of the argument list
0135       (forward-char)
0136       (backward-sexp)             ; brings us back to the '('
0137       (backward-word 1)
0138       (when (looking-at "throw[ \t]") ; exception specification, look for () again
0139              (search-backward ")" nil t)
0140              (forward-char)
0141              (backward-sexp))
0142       ; now that we moved back enough, go to beginning of line.
0143       ; (we assume that the return type, function name, and '(' are on the same line)
0144       (re-search-backward "^[ \t]*")
0145       (while (looking-at "[ \t]")
0146         (forward-char 1))
0147       (when (looking-at "/\\*") ; C-style comment, like /*! \reimp */
0148         (re-search-forward "\\*/" nil t))
0149       (when (looking-at "Q_") ; Qt macro like Q_SCRIPTABLE
0150         (forward-sexp))
0151       (while (looking-at "[ \t]")
0152         (forward-char 1))
0153       (setq function (buffer-substring (point) end))
0154       )
0155     ) ; end of global save-excursion
0156     (cons namespace (cons class function)) ; the returned value
0157     )
0158   )
0159 
0160 ; get rid of virtual, static, multiple spaces, default values.
0161 (defun canonical-function-sig (function)
0162   (and (string-match "[ \t]*\\<virtual\\>[ \t]*" function)
0163        (setq function (replace-match " " t t function)))
0164   (and (string-match "^\\(virtual\\>\\)?[ \t]*" function)
0165        (setq function (replace-match "" t t function)))
0166   (and (string-match "^\\(explicit\\>\\)?[ \t]*" function)
0167        (setq function (replace-match "" t t function)))
0168   (and (string-match "^\\(static\\>\\)?[ \t]*" function)
0169        (setq function (replace-match "" t t function)))
0170   (while (string-match "  +" function) ; simplifyWhiteSpace
0171     (setq function (replace-match " " t t function)))
0172   (while (string-match "\t+" function)
0173     (setq function (replace-match " " t t function)))
0174   (while (string-match "^ " function)  ; remove leading whitespace
0175     (setq function (replace-match "" t t function)))
0176   ; remove default values. complex case: void foo(p=QString())
0177   (let ((startargs (string-match "(" function)))
0178     (while (string-match " ?=[^,()]+" function startargs) ; part 1 (stop at '(')
0179       (setq function (replace-match "" t t function)))
0180     (while (string-match "([^()]*)" function (+ startargs 1))       ; part 2, remove "(...)"
0181       (setq function (replace-match "" t t function))))
0182 
0183   (while (string-match " +," function) ; remove space before commas
0184     (setq function (replace-match "," t t function)))
0185   function ; the return value
0186 )
0187 
0188 ; Helper method which turns the function as seen in the header
0189 ; into the signature for its implementation
0190 ; Returns the fully-qualified signature of the function implementation
0191 (defun kde-function-impl-sig (namespace class _function)
0192   (let (
0193         (function (canonical-function-sig _function))
0194         (insertion-string nil))
0195     (and (stringp class)
0196          (cond
0197           ((string-match (concat "^ *" class "[ \\t]*(") function) ; constructor
0198            (setq insertion-string
0199                  (replace-match
0200                   (concat namespace class "::" class "(")
0201                   t t function)
0202                  ))
0203           ((string-match (concat "^ *~" class "[ \\t]*(") function) ; destructor
0204            (setq insertion-string
0205                  (replace-match
0206                   (concat namespace class "::~" class "(")
0207                   t t function)
0208                  ))
0209           ))                            ; end of "class required"
0210     (if (not (stringp insertion-string)) ; no ctor nor dtor
0211         (if (or (string-match " *\\([a-zA-Z0-9_]+\\)[ \\t]*(" function) ; normal method
0212                 (string-match " *\\(operator[^ \\t]+\\)[ \\t]*(" function)) ; operator
0213               (setq insertion-string
0214                     (replace-match
0215                      (if class
0216                          (concat " " namespace class "::" "\\1(") ; c++ method
0217                        (concat " " "\\1(")) ; c function
0218                      t nil function)
0219                     )
0220                                         ; else
0221           (error (concat "Can't parse declaration ``"
0222                          function "'' in class ``" class
0223                          "'', aborting"))))
0224     insertion-string ; the return value
0225     )
0226   )
0227 
0228 ;; Switch between the declaration of a class member in .cc/.cpp/.C, and its definition in the .h file
0229 ;; Written by David and Reggie after much hair tearing
0230 ;; Found since, might be worth looking at: http://www.hendawi.com/emacs/sourcepair.el
0231 (defun switch-to-function-def-xemacs ()
0232   (interactive)
0233   (let ((n (buffer-file-name))
0234         (namespace "")
0235         (class "")
0236         (function "")
0237         found
0238         )
0239     (if (member (concat "." (file-name-extension n)) sourcepair-source-extensions)
0240         ; TODO replace fume-function-before-point, needed for emacs,
0241         ; and for better namespace support.
0242         ;(progn
0243         ;  (let ((pos (kde-scan-lists (point) -1 1 nil t))) ; Go up a level
0244         ;    (goto-char (if pos (+ pos 1) (point-min))))
0245         (let ((a (fume-function-before-point))
0246               (functionregexp ""))
0247           
0248           (if (eq a nil)
0249               (progn
0250                 (kde-switch-cpp-h)
0251                 (message "point is not in a method"))
0252             (if (string-match "^\\(.*\\)::\\(.*\\)$" a)
0253                 (progn
0254                   (setq class (match-string 1 a))
0255                   (setq function (match-string 2 a))
0256                   (kde-switch-cpp-h)
0257                   (goto-char 0)
0258                                         ; Look for beginning of class ("\\s-+" means whitespace including newlines)
0259                   (re-search-forward
0260                    (concat "\\(class\\|struct\\|namespace\\)\\s-+"
0261                            "\\([A-Z_]+_EXPORT[A-Z_]*\\s-+\\)?"  ; allow for optional EXPORT macro
0262                            class "\\b"                          ; the classname - with word separator
0263                            "[^;]+{"                             ; the optional inheritance and the '{'
0264                            ) nil t)                             ; no error, just return nil if not found
0265 
0266                                         ; Look for function - with \\b prepended, unless this is about ~Foo.
0267                   (setq functionregexp (kde-function-regexp-quote function))
0268                   (and (not (string-match "^~" functionregexp))
0269                        (setq functionregexp (concat "\\b" functionregexp)))
0270                   ;; TODO keep looking, until we find a match that's not inside a comment
0271                   (re-search-forward (concat functionregexp "[ \t]*(") nil t))
0272                                         ; else: not a member method, maybe just a c function
0273               (progn
0274                 (setq function a)
0275                 (kde-switch-cpp-h)
0276                 (goto-char 0)
0277                 (re-search-forward (concat "\\b" (kde-function-regexp-quote function) "[ \t]*(") nil t))
0278               )
0279             )
0280           ))
0281     (if (member (concat "." (file-name-extension n)) sourcepair-header-extensions)
0282         (progn
0283           (let ((mup (method-under-point))
0284                 (sig "")
0285                 (pos 0))
0286         (setq namespace (car mup))
0287             (setq class (cadr mup))
0288             (setq function (cddr mup))
0289             (kde-switch-cpp-h)
0290 
0291         ;; First search with namespace prefixed
0292             (goto-char 0)
0293             (setq sig (kde-remove-newline (kde-function-impl-sig namespace class function)))
0294             (if (string-match "(.*" sig) ; remove args
0295                 (setq sig (replace-match "" nil t sig)))
0296             (setq found (re-search-forward (concat "^[^()]*" (kde-function-regexp-quote sig) "[ \t]*(") nil t) )
0297 
0298         (if (not found)
0299             (progn
0300               ; Now search without name space prefix
0301 
0302               (goto-char 0)
0303               (setq sig (kde-remove-newline (kde-function-impl-sig "" class function)))
0304               
0305               (if (string-match "(.*" sig) ; remove args
0306                   (setq sig (replace-match "" nil t sig)))
0307               (re-search-forward (concat "^[^()]*" (kde-function-regexp-quote sig) "[ \t]*(") nil t) ) )
0308         )))))
0309 
0310 (defun switch-to-def-semanticdb (arg)
0311   ;; This below was shared by Emacs Wiki
0312   ;; user nschum (Nikolaj Schumacher;
0313   ;; https://www.emacswiki.org/emacs/nschum) on the Emacs Wiki page
0314   ;; https://www.emacswiki.org/emacs/JumpToDefinition
0315   ;;
0316   ;; The work is licensed under version 2 of the GNU General Public License.
0317   ;;
0318   ;; Incorporated into this file by Akarsh Simha.
0319   ;;
0320   ;; Note that this is a more general method that finds the definition
0321   ;; of any symbol, not just a function.
0322 
0323   "Jump to the definition of the symbol, type or function at point.
0324   With prefix arg, find in other window."
0325     (interactive "P")
0326     (let* ((tag (or (semantic-idle-summary-current-symbol-info-context)
0327                     (semantic-idle-summary-current-symbol-info-brutish)
0328                     (error "No known tag at point")))
0329            (pos (or (semantic-tag-start tag)
0330                     (error "Tag definition not found")))
0331            (file (semantic-tag-file-name tag)))
0332       (if file
0333           (if arg (find-file-other-window file) (find-file file))
0334         (if arg (switch-to-buffer-other-window (current-buffer))))
0335       (push-mark)
0336       (goto-char pos)
0337       (end-of-line))
0338     )
0339 
0340 (defun switch-to-function-def-semanticdb (arg)
0341 
0342   ;; Modified switch-to-def-semanticdb to only find the current
0343   ;; function -- asimha
0344 
0345   "Jump to the definition of the function before point.
0346   With prefix arg, find in other window."
0347   (interactive "P")
0348 
0349   (if
0350       ;; Check if we are in a header file
0351       (member (concat "." (file-name-extension (buffer-file-name)))
0352       sourcepair-header-extensions)
0353 
0354       ;; If we are in a header file, simply use (which-function) to
0355       ;; find the function before point and (semantic-ia-fast-jump) to
0356       ;; jump
0357       (let* ((pos nil))
0358         (save-excursion
0359           (setq pos (search-backward (which-function))))
0360         (push-mark)
0361         (semantic-ia-fast-jump pos)
0362         )
0363 
0364     ;; We are in the source file.
0365 
0366     ;; (semantic-stickyfunc-tag-to-stick) returns the sticky tag,
0367     ;; which is the function before point in a source file, but it
0368     ;; returns the tag in the same file, not in the header file.So
0369     ;; we hack this by going to the function definition and then using
0370     ;; (semantic-idle-summary-current-symbol-info-context) etc.
0371     (let*  ((destpos nil)
0372            (desttag nil)
0373            (file nil))
0374       (push-mark)
0375       (save-excursion
0376         (end-of-line) ; This ensures that being at the beginning of the line does not take us to the previous function's declaration
0377         (beginning-of-defun)
0378         (re-search-forward "(")
0379         (forward-char -1)
0380         (re-search-backward "\\S-")
0381         (setq desttag (or (semantic-idle-summary-current-symbol-info-context)
0382                           (semantic-idle-summary-current-symbol-info-brutish)
0383                           (error "No known tag at point")))
0384         (setq destpos (or (semantic-tag-start desttag)
0385                           (error "Tag definition not found")))
0386         (setq file (semantic-tag-file-name desttag))
0387         )
0388       (if file
0389           (if arg (find-file-other-window file) (find-file file))
0390         (if arg (switch-to-buffer-other-window (current-buffer))))
0391       (goto-char destpos)
0392       (end-of-line)
0393       )
0394     )
0395   )
0396 
0397 
0398 (if (eq kde-emacs-type 'xemacs)
0399     (defun switch-to-function-def () (interactive) (switch-to-function-def-xemacs) )
0400   (defun switch-to-function-def (arg) (interactive "P") (switch-to-function-def-semanticdb arg))
0401   )
0402 
0403 
0404 (defun kde-remove-newline (str) 
0405     (replace-in-string str "\n" " "))
0406 ; quote for use as regexp, but replace spaces with "any whitespace"
0407 (defun kde-function-regexp-quote (str)
0408   (replace-in-string (regexp-quote str) "[ \n\t]" "[ \n\t]"))
0409 
0410 ; Initial implementation by Arnt Gulbransen
0411 ; Current maintainer: David Faure
0412 (defun agulbra-make-member ()
0413   "make a skeleton member function in the .cpp or .cc file"
0414   (interactive)
0415   (let* (
0416          (mup (method-under-point))
0417          (namespace (car mup))  ; will contain A::B::
0418          (class (cadr mup))
0419          (function (cddr mup))
0420          (file (buffer-file-name))
0421          (insertion-string (kde-function-impl-sig namespace class function))
0422          (function-sig (canonical-function-sig function))
0423          (msubstr nil)
0424          (start nil)
0425          (newcppfile nil)
0426          (baseclass nil)
0427          )
0428     ; First, assemble the skeleton text into insertion-string
0429     ; At this point it already contains the method signature
0430 
0431     ; If constructor: add call to base class 
0432     (and (stringp class)
0433          (string-match (concat "^ *" class "[ \\t]*(") function-sig) ; constructor
0434          (setq baseclass (baseclass-under-point))
0435          ; TODO: passing the parent parameter if baseclass starts with Q :)
0436          (setq insertion-string (concat insertion-string "\n    : " baseclass "()" )))
0437 
0438     ; Method body
0439     (setq insertion-string 
0440           (concat insertion-string "\n{\n"
0441                   (replace-in-string kde-make-member-default-impl "FUNCTION" 
0442                                      ; the function name and args, without newlines
0443                                      (replace-in-string insertion-string "\n" " " t)
0444                                      t)
0445                   "}\n"))
0446 
0447     ; Move to next method, to be ready for next call
0448     (backward-char)                ; in case we're after the ';'
0449     (re-search-forward ";" nil t)  ; end of this method decl
0450     (let ((moveToNext t))
0451       (while moveToNext
0452         (re-search-forward ";" nil t)  ; end of next method decl
0453         (save-excursion
0454           (forward-char -2) ; -1 goes to ';' itself, so go before that
0455           (while (looking-at "[ \t0=]")
0456             (forward-char -1))
0457           (forward-char 1)
0458           ; move to next method again if we're at a pure virtual method
0459           (setq moveToNext (looking-at "[ \t]*=[ \t]*0;"))
0460           )
0461         )
0462       )
0463 
0464     ; Switch to .cpp if the declaration was in a header file
0465     (if (member (concat "." (file-name-extension file)) sourcepair-header-extensions)
0466         (kde-switch-cpp-h)
0467       )
0468     ;(setq newcppfile (= (point-max) 1))
0469     (goto-char (point-max))
0470     (kde-comments-begin)
0471     (kde-skip-blank-lines)
0472     (setq msubstr (buffer-substring (point-at-bol) (point-at-eol)))
0473     ; TODO refine regexp
0474     (if (string-match "^#include.*moc.*" msubstr)
0475         (progn
0476           (while (string-match "^#include.*moc.*" msubstr)
0477             (forward-line -1)
0478             (setq msubstr (buffer-substring (point-at-bol) (point-at-eol)))
0479             )
0480           (end-of-line)
0481           (insert "\n"))
0482     ; else
0483       (progn
0484           (end-of-line)
0485           (insert "\n")
0486           (forward-line 1)
0487           ))
0488     (insert insertion-string)
0489     (forward-char -3)
0490     (c-indent-defun)
0491     ; Insert #include for the header if necessary
0492     (save-excursion
0493       (and (string-match ".*/" file)
0494            (setq file (replace-match "" t nil file)))
0495       (and (string-match "\\.h$" file)
0496            (functionp 'kdab-insert-header-non-interactive)
0497        (kdab-insert-header-non-interactive (file-name-sans-extension file))))
0498     (when (featurep 'fume-rescan-buffer)
0499       (fume-rescan-buffer))
0500     ))
0501 
0502 (defun add-file-to-buildsystem ()
0503   "Add the current (C++) file to either Makefile.am or a .pro file, whichever exists."
0504   ; Author: David
0505   (interactive)
0506   (if (file-readable-p "Makefile.am")
0507       (add-file-to-makefile-am)
0508     ; else: find a .pro file and add it there
0509     (let* ((files (directory-files "." nil ".pro$" nil t))
0510            (projfile (car files)))
0511       (if projfile
0512           (add-file-to-project projfile "^SOURCES[ \t]*") ; could be SOURCES= or SOURCES+=
0513         ; else: error
0514         (error "No build system file found")
0515         )))
0516   )
0517 
0518 ; internal helper for add-file-to-*
0519 (defun add-file-to-project (makefile searchString)
0520   (let ((file (buffer-name)))
0521     (if (not (file-readable-p makefile))
0522         (error (concat makefile " not found!"))
0523       )
0524     (find-file makefile)
0525     (goto-char (point-min))
0526     (if (re-search-forward searchString nil t)
0527         (progn
0528           (end-of-line)
0529           ; check if line ends with '\' [had to read make-mode.el to find this one!]
0530           (while (= (char-before) ?\\)
0531             (end-of-line 2)) ; moves to end of next line
0532           (insert " ")
0533           (insert file)
0534           )
0535       (error (concat searchString " not found"))
0536       ))
0537   )
0538 
0539 (defun add-file-to-makefile-am ()
0540   "Add the current file to the first _SOURCES line in the Makefile.am"
0541   ; Author: David
0542   (interactive)
0543   (add-file-to-project "Makefile.am" "_SOURCES")
0544   )
0545 
0546 
0547 ; Inserts a kDebug statement showing the name of the current method.
0548 ; You need to create the empty line first.
0549 (defun insert-kDebug ()
0550   (interactive)
0551   (if (and (boundp 'kdab-qt-version) (eq kdab-qt-version 4))
0552     (progn ; KDE4 version
0553       (insert "kDebug() << this << ;")
0554       (backward-char 1)
0555       )
0556     (progn ; KDE3 version
0557       (insert "kdDebug() << k_funcinfo "))
0558       (insert "<< endl;")
0559       (backward-char 8)
0560       )
0561   )
0562 
0563 ; finds a string to be used in the header-protection function ( see below )
0564 (defun kde-header-protection-definable-string ()
0565    (let* ((definablestring "")
0566           (f (buffer-file-name))
0567           (parts (nreverse (split-string f "/")))
0568           (i)
0569           (first-iter t)
0570           (iters (min (length parts) kde-header-protection-parts-to-show)))
0571      (dotimes (i iters)
0572        (let ((part (pop parts)))
0573          (setq definablestring
0574                (concat
0575                 (upcase (replace-in-string part "[\\.-]" "_"))
0576                 (if (not first-iter) "_" "")
0577                 definablestring
0578                 )
0579                )
0580          (setq first-iter nil)
0581          )
0582        )
0583      definablestring
0584      )
0585    )
0586 
0587 ; Creates the ifndef/define/endif statements necessary for a header file
0588 (defun header-protection ()
0589   (interactive)
0590   (let ((s (kde-header-protection-definable-string)))
0591     (save-excursion
0592       (goto-char (point-min))
0593       (insert "#ifndef " s "\n#define " s "\n\n")
0594       (goto-char (point-max))
0595       (insert "\n#endif\n")
0596       )
0597     )
0598   )
0599 
0600 ;; Add (setq magic-parens-mode nil) to your .emacs (before loading this file)
0601 ;; to disable the automatic spaces inside "( ... )" in C++ mode.
0602 ;; This can also be enabled/disabled per project using  magic-parens-mode: t  in .emacs-dirvars.
0603 
0604 ; Makes '(' insert '(' or ' ( ' where appropiate
0605 (defun insert-parens (arg) (interactive "*P")
0606   (if (and (not (c-in-literal))
0607            (boundp 'magic-parens-mode) magic-parens-mode)
0608       (let ((n nil) (except nil))
0609         (save-excursion
0610           (setq n (or (progn (forward-char -2) (looking-at "\\bif"))
0611                       (progn (forward-char -1) (looking-at "\\bfor"))
0612                       (progn (forward-char -1) (looking-at "\\bcase"))
0613                       (progn (forward-char -1) (looking-at "\\bwhile"))
0614                       )
0615                 )
0616           (setq except (or (progn (forward-char -2) (looking-at "kDebug"))
0617                            (looking-at "kError")
0618                            (progn (forward-char -2) (looking-at "kWarning"))
0619                            )
0620                 )
0621           )
0622         (cond
0623          (n (progn
0624               (insert " ")
0625               (self-insert-command (prefix-numeric-value arg))
0626               (insert kde-emacs-after-parent-string)
0627               ))
0628          (t ;else
0629           (self-insert-command (prefix-numeric-value arg))
0630           (cond ((not except) (insert kde-emacs-after-parent-string)))
0631           )))
0632     (self-insert-command (prefix-numeric-value arg)))
0633   )
0634 
0635 (defun insert-parens2 (arg) (interactive "*P")
0636   (if (and (not (c-in-literal))
0637            (boundp 'magic-parens-mode) magic-parens-mode)
0638       (let ((remv nil) (nospac nil))
0639         (forward-char -2)
0640         (setq remv (looking-at "( ")) ; () -> we'll have to remove that space
0641         (forward-char 1)
0642         (setq nospac ; no space to be added
0643               (or (looking-at " ")
0644                   (looking-at "(")
0645                   (save-excursion ; check for kDebug(123
0646                     (while (looking-at "[0-9]")
0647                       (forward-char -1))
0648                     (forward-char -7)
0649                     (or (looking-at "kDebug(")
0650                         (looking-at "kError(")
0651                            (progn (forward-char -2) (looking-at "kWarning("))
0652                            )
0653                     )
0654                   )
0655               )
0656         (forward-char 1)
0657         (cond
0658          (remv (progn
0659                  (delete-backward-char 1)
0660                  (self-insert-command (prefix-numeric-value arg)))) ; the () case
0661          (nospac (self-insert-command (prefix-numeric-value arg))) ; no space to be added
0662          (t ;else
0663           (if abbrev-mode ; XEmacs
0664               (expand-abbrev))
0665           (insert kde-emacs-after-parent-string)
0666           (self-insert-command (prefix-numeric-value arg))
0667           ))) ; normal case, prepend a space
0668     ;;(blink-matching-open) ; show the matching parens
0669     (self-insert-command (prefix-numeric-value arg)))
0670   )
0671 
0672 ; Makes ',' insert ', '
0673 (defun insert-comma (arg)
0674   (interactive "*P")
0675   (let* ((ch (char-after))
0676          (spacep (not (or (eq ch ? )
0677                           (c-in-literal)
0678                           arg))))
0679     (self-insert-command (prefix-numeric-value arg))
0680     (if spacep
0681         (insert " "))))
0682 
0683 (defun insert-semicolon (arg)
0684   (interactive "*P")
0685     (self-insert-command (prefix-numeric-value arg))
0686     (newline-and-indent))
0687 
0688 (defun insert-curly-brace (arg) (interactive "*P")
0689   (if (not (c-in-literal))
0690       (let ((n nil) (o nil)
0691             (spacep nil) (c nil)
0692             (oneliner nil) (cxxlambda nil)
0693             (clausekeyword nil) (dokeyword nil))
0694         (save-excursion
0695           (save-excursion
0696             (if (re-search-forward "[a-zA-Z]" (point-at-eol) t)
0697                 (setq oneliner t)))
0698           (forward-char -1)              ; These three lines are for the situation where
0699           (if (not (looking-at " "))     ; the user already have inserted a space after
0700               (forward-char 1)           ; the closing parenthesis
0701             (setq spacep t))
0702           (forward-char -2)
0703           (setq o (looking-at "()"))
0704           (forward-char 1)
0705           (setq n (looking-at ")"))
0706           (save-excursion (if (and
0707                (not oneliner)
0708                (not (eq
0709                     (count-lines (point-min) (point))
0710                     (count-lines (point-min) (point-max)))))
0711               (progn
0712                 (next-line 1)
0713                 (beginning-of-line)
0714                 (if (re-search-forward "[a-zA-Z]" (point-at-eol) t)
0715                     (setq c (eq (car (car (c-guess-basic-syntax))) 'substatement)))
0716                 )
0717               ))
0718 
0719           ; The following lines handle keywords 'else' and 'do' to insert a matching brace
0720           ; if the keyword is 'do', we also insert a while.
0721           (forward-char -1)
0722           (setq dokeyword (looking-at "do"))
0723           (setq clausekeyword (or dokeyword
0724                                   (progn (forward-char -2) (looking-at "else"))))
0725           )
0726           (setq cxxlambda (looking-back "\\[.*\\]\\s-*(.*)\\(\\s-*->.*\\)?\\s-*"))
0727         (cond
0728          ((or (or n clausekeyword) cxxlambda) (progn
0729               (if (not spacep) (insert " "))
0730               (self-insert-command (prefix-numeric-value arg))
0731               (if (not c) (newline-and-indent))
0732               (if oneliner (end-of-line))
0733              (save-excursion
0734               (if c
0735                   (progn
0736                     (next-line 1)
0737                     (end-of-line)
0738                     ))
0739               (newline-and-indent)
0740               (insert "}")
0741               (if cxxlambda (insert ";"))
0742               (if dokeyword (insert " while"))
0743               (c-indent-line))
0744               (c-indent-line)
0745              ))
0746          (o (progn
0747               (newline)
0748               (self-insert-command (prefix-numeric-value arg))
0749               (newline-and-indent)))
0750          (t (progn ;else
0751               (self-insert-command (prefix-numeric-value arg))
0752               (save-excursion
0753                 (beginning-of-line)
0754                 (c-indent-command))))
0755          ))
0756     (self-insert-command (prefix-numeric-value arg))
0757     )
0758 )
0759 
0760 ;; have PelDel mode work
0761 (put 'insert-parens 'pending-delete t)
0762 (put 'insert-parens2 'pending-delete t)
0763 (put 'insert-comma 'pending-delete t)
0764 (put 'insert-curly-brace 'pending-delete t)
0765 (put 'newline-and-indent 'pending-delete t)
0766 
0767 ; A wheel mouse that doesn't beep, unlike mwheel-install
0768 (defun scroll-me-up () (interactive) (scroll-up 4))
0769 (defun scroll-me-down () (interactive) (scroll-down 4))
0770 (defun scroll-me-up-a-bit () (interactive) (scroll-up 1))
0771 (defun scroll-me-down-a-bit () (interactive) (scroll-down 1))
0772 
0773 ; Compilation
0774 (defun makeclean ()
0775   "Executes a \"make clean\" in the current directory"
0776   (interactive)
0777   (compile (concat kde-emacs-make " clean"))
0778   )
0779 
0780 (defun make ()
0781   "Executes a \"make\" in the current directory"
0782   (interactive)
0783   (compile (concat kde-emacs-make " -k"))
0784   )
0785 
0786 (defun makeinstall ()
0787   "Executes a \"make install\" in the current directory"
0788   (interactive)
0789   (compile (concat kde-emacs-make " -k install"))
0790   )
0791 
0792 (defun makeinstallexec ()
0793   "Executes a \"make install-exec\" in the current directory"
0794   (interactive)
0795   (compile (concat kde-emacs-make " -k install-exec"))
0796   )
0797 
0798 (defun makethisfile ()
0799   "Try to compile the currently opened file"
0800   (interactive)
0801   (let ((f (file-name-nondirectory (buffer-file-name)))
0802         (objext nil))
0803 
0804     (if (and (file-readable-p "Makefile.am") (not (file-readable-p "CMakeLists.txt")))
0805         (setq objext "\.lo")
0806       (setq objext "\.o"))
0807     (if (string-match "\.cpp$" f) (setq f (replace-match objext t t f)))
0808     (if (string-match "\.cc$" f) (setq f (replace-match objext t t f)))
0809     (if (string-match "\.c$" f) (setq f (replace-match objext t t f)))
0810     (compile (concat kde-emacs-make " " f)))
0811   )
0812 
0813 ;; pc-like textmarking, deprecated in GNU Emacs 24+.
0814 (when (not (and (eq kde-emacs-type 'emacs)
0815                 (>= emacs-major-version 24)))
0816   (when kde-use-pc-select
0817     (progn
0818       (load "pc-select")
0819       (if (eq kde-emacs-type 'xemacs)
0820           (funcall 'pc-select-mode)
0821         (funcall 'pc-selection-mode)))))
0822 
0823 
0824 ; Move in other window
0825 (defun scroll-other-up () (interactive) (scroll-other-window-down 1)) ; hehe :)
0826 (defun scroll-other-down () (interactive) (scroll-other-window 1))
0827 
0828 (defun match-paren ()
0829   "Go to the matching parenthesis if on parenthesis otherwise do nothing."
0830   (interactive)
0831   (cond ((looking-at "[ \t]*[\({]") (forward-sexp) (backward-char))
0832         ((looking-at "[\)}]") (forward-char) (backward-sexp))))
0833 
0834 (defun kde-start-c++-header ()
0835   "Start a new C++ header by inserting include guards ( see \
0836    header-protection function ), inserting a license statement \
0837    and putting (point) at the correct position"
0838   (interactive)
0839   (header-protection)
0840   (insert "\n")
0841   (beginning-of-buffer)
0842   (kde-license-insert "GNU GPL")
0843   (next-line 1)
0844   (kill-line)
0845   (end-of-buffer)
0846   (next-line -3)
0847   (insert "\n")
0848 )
0849 
0850 (defun kde-year-range-parse-years-string (string)
0851   "parses something like \"2000, 2008-2010\" into a list of the form \
0852    ((2008 . 2010)(2000 . 2000))"
0853   (let ((pos -1)
0854         (oldpos)
0855         (l (length string))
0856         (currange "")
0857         (startyear)
0858         (endyear)
0859         (ret)
0860         )
0861     (while (< pos l)
0862       (setq oldpos (+ pos 1))
0863       (setq pos (string-match "[,]" string (+ pos 1)))
0864       (unless pos (setq pos l))
0865       (setq currange (substring string oldpos pos))
0866       (string-match "[0-9]+" currange)
0867       (setq startyear (string-to-int (match-string 0 currange)))
0868       (setq endyear
0869             (if (string-match "-" currange)
0870                 (string-to-int (substring currange (match-end 0)))
0871               startyear))
0872       (setq ret (cons (cons startyear endyear) ret))
0873       )
0874     ret
0875     )
0876   )
0877 
0878 (defun kde-year-range-contains-year (ranges year)
0879   "checks whether year is in ranges.. ( ranges is a list as \
0880    kde-year-range-parse-years-string returns.. "
0881   (let ((ret))
0882     (dolist (range ranges ret)
0883       (when (and (>= year (car range)) (<= year (cdr range)))
0884         (setq ret t))
0885       )))
0886 
0887 (defun kde-year-range-to-string (ranges)
0888   "converts ranges to a string.."
0889   (let ((ret ""))
0890     (dolist (range ranges)
0891       (setq ret 
0892             (concat
0893              (int-to-string (car range))
0894              (if (/= (cdr range) (car range))
0895                  (concat "-" (int-to-string (cdr range)))
0896                "")
0897              ", "
0898              ret) 
0899             )
0900       )
0901     ; remove extraneous ", "
0902     (setq ret (substring ret 0 (- (length ret) 2)))
0903     )
0904   )
0905 
0906 ; merges adjacent year ranges into one..
0907 (defun kde-year-range-cleanup (range)
0908   (let ((origrange range))
0909     (while (and range (cdr range))
0910       (let ((years (car range)) (nyears (cadr range)))
0911         (when (>= (+ (cdr nyears) 1) (car nyears))
0912           (setcar range (cons (car nyears) (cdr years)))
0913           (setcdr range (cddr range)))
0914         )
0915       (setq range (cdr range))
0916       )
0917     origrange
0918     )
0919   )
0920 
0921 ; adds year to range..
0922 (defun kde-year-range-add-year (range year)
0923   (while range
0924     (let ((years (car range)))
0925       (cond
0926        ((and (>= year (car years)) (<= year (cdr years))
0927              ; year is already in the range..
0928              (setq range nil)))
0929        ((= year (+ (cdr years) 1))
0930         (setcdr years year)
0931         (setq range nil))
0932        ((= year (- (car years) 1))
0933         (setcar years year)
0934         (setq range nil))
0935        )
0936       )
0937     (setq range (cdr range))
0938     )
0939   (kde-year-range-cleanup range)
0940   )
0941 
0942 (defun kde-add-copyright () (interactive)
0943   "Tries to add your kde-full-name and kde-email to the Copyright \
0944    statements at the top of a file...  It tries to figure out \
0945    if it's already there, and if so, updates the line to include the \
0946    current year.. ( well, replaces it by a new one, anyway :) )"
0947   (let ((wascomment ""))
0948     (save-excursion
0949       (beginning-of-buffer)
0950       (if (re-search-forward (concat "Copyright ([Cc]) \\([0-9 ,-]*\\) " (regexp-quote kde-full-name)) nil t)
0951           (progn
0952             (beginning-of-line)
0953             (let ((years (kde-year-range-cleanup (kde-year-range-parse-years-string (match-string 1))))
0954                   (new-copyright-string "Copyright (C) ")
0955                   (this-year (string-to-int (format-time-string "%Y"))))
0956               (when (not (kde-year-range-contains-year years this-year))
0957                 (kde-year-range-add-year years this-year))
0958               (setq new-copyright-string
0959                     (concat new-copyright-string (kde-year-range-to-string years)))
0960                                         ; finish new-copyright-string 
0961               (setq new-copyright-string
0962                     (concat new-copyright-string "  " kde-full-name " <" kde-email ">"))
0963               (beginning-of-line)
0964               (re-search-forward "Copyright ([Cc])")
0965               (beginning-of-line)
0966               (setq wascomment 
0967                     (buffer-substring (point)
0968                                       (match-beginning 0)
0969                                       ))
0970               (kill-line nil)
0971               (insert new-copyright-string)
0972               )
0973             )
0974         (beginning-of-buffer)
0975         (let ((first-copyright-str (re-search-forward "Copyright ([Cc])" nil t)))
0976           (if first-copyright-str
0977               (progn
0978                 (goto-char first-copyright-str)
0979                 (beginning-of-line)
0980                 (setq wascomment (buffer-substring (point) (match-beginning 0)))
0981                 (forward-line 1)
0982                 )
0983             (goto-line 2))
0984           )
0985         (beginning-of-line)
0986         (insert "Copyright (C) " (format-time-string "%Y") "  "
0987                 kde-full-name " <" kde-email ">\n")
0988         (forward-line -1)
0989         )
0990       (end-of-line)
0991       (let ((end (point)))
0992         (beginning-of-line)
0993         (insert wascomment)
0994         )
0995       )
0996     )
0997   )
0998 
0999 (defun kde-emacs-file-style-update ()
1000   "Updates the style header of this file"
1001   (interactive)
1002   (if (or (eq major-mode 'c++-mode)
1003           (eq major-mode 'c-mode))
1004       (let ((startpoint) (endpoint)
1005             (firstline) (strings)
1006             (str) (m) (m2) (var) (value)
1007             (final))
1008         (save-excursion
1009           (beginning-of-buffer)
1010           (setq startpoint (point))
1011           (setq endpoint (point-at-eol)))
1012         (setq firstline (buffer-substring startpoint endpoint))
1013         (if (string-match "-\*-\\([A-Za-z0-9\-\+\:\; ]+\\)-\*-" firstline)
1014             (delete-region startpoint endpoint))
1015         (setq final (concat "-*- "
1016                             "Mode: " mode-name "; "
1017                             "c-basic-offset: " (prin1-to-string c-basic-offset)  "; "
1018                             "indent-tabs-mode: " (prin1-to-string indent-tabs-mode)  "; "
1019                             "tab-width: " (prin1-to-string tab-width) "; "
1020                             "-*-"))
1021         (save-excursion
1022           (beginning-of-buffer)
1023           (insert final)
1024           (comment-region (point-at-bol) (point-at-eol))
1025           (newline)))))
1026 
1027 ; Helper for qt-open-header, for Qt 4. Opens a file if it says #include "../foo/bar.h",
1028 ; close it and open that file instead; recursively until finding a real file.
1029 (defun qt-follow-includes (file)
1030   (let ((line "")
1031         (begin nil)
1032         (buffer nil))
1033     (find-file file)
1034     (goto-char 0)
1035     (if (looking-at "#include \"")
1036         (progn
1037           (forward-char 10)
1038           (setq begin (point))
1039           (re-search-forward "\"" nil t)
1040           (backward-char 1)
1041           (setq file (buffer-substring begin (point)))
1042           (setq buffer (current-buffer))
1043           (qt-follow-includes file)
1044           (kill-buffer buffer)
1045           )
1046       ; else: this is the right file, skip the comments and go to the class
1047       (progn
1048         (re-search-forward "^class" nil t)
1049         (beginning-of-line))
1050     )))
1051 
1052 (defun qt-open-header ()
1053   "Open the Qt header file for the class under point"
1054   (interactive)
1055   (let* ((qtinc (concat (getenv "QTDIR") "/include/"))
1056         (class (thing-at-point 'word))
1057         (f nil)
1058         (file nil)
1059         (files nil)
1060         )
1061     (save-excursion
1062       ; The Qt3 case: the includes are directly in $QTDIR/include/, lowercased
1063       (setq f (concat qtinc (downcase class) ".h" ))
1064       (if (file-readable-p f)
1065           (setq file f)
1066         ; For some Qt3/e classes: add _qws
1067         (setq f (concat qtinc (downcase class) "_qws.h" ))
1068         (if (file-readable-p f)
1069             (setq file f)
1070         ; The Qt4 case: the includes are in $QTDIR/include/QSomething/, in original case
1071           (setq files (directory-files qtinc t nil "dirsonly"))
1072           (dolist (f files nil)
1073             (if (file-readable-p (concat f "/" class) )
1074                 (setq file (concat f "/" class))))
1075           ))
1076       (and file
1077            (qt-follow-includes file))
1078       )
1079   ))
1080 
1081 (provide 'kde-emacs-utils)