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

0001 ;; kde-emacs-semantic.el
0002 ;;
0003 ;; Copyright (C)  2002  Zack Rusin <zack@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 ;;; Commentary:
0021 ;; Package provides four interactive functions:
0022 ;; - kde-function-doc-insert - creates a skeleton doxygen
0023 ;;                           documentation for function at point.
0024 ;;                           Customize it with kde-func-doc variables.
0025 ;;
0026 ;; - kde-function-expanded-at-point - returns t if function at point
0027 ;;                           has already been expanded.
0028 ;;
0029 ;; - kde-function-expand-at-point - expand (creates a stub) for function
0030 ;;                           at point (as long as function is a prototype
0031 ;;                           and haven't been expanded).
0032 ;;
0033 ;; - kde-create-skeletons - creates stubs for all methods in the current 
0034 ;;                       header file.
0035 ;; 
0036 ;; Package is very flexible, look at defcustom variables for things 
0037 ;; you can customize.
0038 
0039 ;;; Problems:
0040 ;; Most problems relate to C++ syntax which isn't handled correctly
0041 ;; by the Semantic package. For now templates aren't supported, I 
0042 ;; have a temporary solution for other problems (e.g. const functions,
0043 ;; QT/KDE specific access specifiers)
0044 
0045 ;;; Code:
0046 (require 'kde-emacs-vars)
0047 (require 'kde-emacs-general)
0048 
0049 ;*---------------------------------------------------------------------*/
0050 ;*    User configuration ...                                           */
0051 ;*---------------------------------------------------------------------*/
0052 ;;Not yet, not yet
0053 ;(defcustom kde-summary-function 'semantic-uml-prototype-nonterminal
0054 ;  "*Function to use when showing info about the token"
0055 ;  :group 'kde-devel
0056 ;  :type semantic-token->text-custom-list
0057 ;  )
0058 
0059 (defcustom kde-generate-docs-with-stubs nil
0060   "*Should function documentation be generated with the stubs."
0061   :group 'kde-devel
0062   :type 'boolean)
0063 
0064 (defcustom kde-expand-arg-start "( "
0065   "*A string which specifies how the function arguments format should start.
0066 e.g. \"( \" would start function arguments list like : \"func( int arg\".
0067 and \" (\" will format the begining of the function argument list as 
0068 follows : \"func (int arg\"."
0069   :group 'kde-devel
0070   :version "0.1"
0071   :type 'string)
0072 
0073 (defcustom kde-expand-arg-end " )"
0074   "*Just like kde-expand-arg-start but specifies how the list should end."
0075   :group 'kde-devel
0076   :version "0.1"
0077   :type 'string)
0078 
0079 (defcustom kde-expand-arg-break ", "
0080   "*Specifies how the arguments should be separated."
0081   :group 'kde-devel
0082   :version "0.1"
0083   :type 'string)
0084 
0085   
0086 ;*---------------------------------------------------------------------*/
0087 ;*    Functions  ...                                                   */
0088 ;*---------------------------------------------------------------------*/
0089 ;; FIXME : semantic doesn't handle QT access specifiers
0090 ;(setq-default global-semantic-show-unmatched-syntax-mode nil)
0091 ;(setq-default global-semantic-show-dirty-mode nil)
0092 
0093 (defun kde-format-func-arg (arg)
0094   "Formats one argument (from token to string)."
0095   (let ((ret ""))
0096     (if (semantic-token-variable-extra-spec arg 'const)
0097       (setq ret "const "))
0098     (setq ret (concat ret (car (semantic-token-type arg))))
0099     (if (semantic-token-variable-extra-spec arg 'pointer)
0100         (dotimes (idx (semantic-token-variable-extra-spec arg 'pointer))
0101           (setq ret (concat ret "*"))
0102           )
0103       )
0104     (if (semantic-token-variable-extra-spec arg 'reference)
0105         (setq ret (concat ret "&"))
0106       )
0107     (setq ret (concat ret " " (semantic-token-name arg)))
0108     ret
0109     ))
0110 
0111 (defun kde-format-args (token)
0112   "Formats all arguments from token to string.
0113 Token has to be the function variable list e.g.
0114 from semantic-token-function-args"
0115   (let ((res kde-expand-arg-start) (idx 1))
0116     (dolist (elt token res)
0117       (setq res (concat res (kde-format-func-arg elt)))
0118       (when (< idx (length token))
0119         (setq res (concat res kde-expand-arg-break)))
0120       (setq idx (1+ idx))
0121       )
0122     (setq res (concat res kde-expand-arg-end))
0123     ;; if it's something like "(   )" replace it with "()"
0124     (when (string= res (concat kde-expand-arg-start kde-expand-arg-end))
0125       (setq res (replace-regexp-in-string "([ \t]+)" "()" res)))
0126     res
0127     ))
0128 
0129 (defun kde-function-in-tokens (FUNC TOKENS)
0130   "Search for function in tokens. FUNC has to be a function
0131 token and TOKENS have to be a list of functions from buffer."
0132   (let ((ret)(elt))
0133     (while (and TOKENS (not ret))
0134       (setq elt (car TOKENS))
0135       (setq TOKENS (cdr TOKENS))
0136       (if (and (string= (semantic-token-name FUNC)
0137                         (semantic-token-name elt))
0138                (equal (semantic-token-type FUNC) 
0139                       (semantic-token-type elt))
0140                ;; FIXME (semantic) : Functions in some classes don't have the
0141                ;;                    'parent property set !!!
0142                ;;(string= (semantic-token-function-parent FUNC1)    
0143                ;;           (semantic-token-function-parent FUNC2)) 
0144                (string= (kde-format-args (semantic-token-function-args FUNC))
0145                         (kde-format-args (semantic-token-function-args elt))))
0146           (setq ret t))
0147       )
0148     ret
0149     ))
0150 
0151 ;; TODO support Q_SIGNALS too
0152 (defmacro kde-label-signals (pt)
0153   "Returns none-nil if the current access label == \"signals\""
0154   `(save-excursion
0155      (goto-char ,pt)
0156      (if (looking-at ":")
0157          (re-search-backward "signals" (point-at-bol) t)
0158        )
0159      ))
0160 
0161 (defun kde-label-namespace (pt)
0162   "Return the namespace to which the variable/function at point PT belongs to."
0163   (save-excursion
0164     (goto-char pt)
0165     (if (looking-at "::")
0166         (let ((start) (end))
0167           (re-search-backward "\\b\\w+" (point-at-bol) t)
0168           (setq start (match-beginning 0))
0169           (setq end   (match-end 0))
0170           (buffer-substring-no-properties start end)
0171           )
0172       )
0173     ))
0174 
0175 (defmacro kde-label-slots (pt)
0176   "Return none-nil if at PT there's slots access specifier."
0177   `(save-excursion
0178     (goto-char ,pt)
0179     (if (looking-at ":")
0180         ;; export this regex to a kde-emacs-vars defvar
0181         (re-search-backward "\\(public\\|protected\\|private\\)[ \t]+\\(slots\\|Q_SLOTS\\)" (point-at-bol) t))
0182     ))
0183 
0184 (defmacro kde-is-constructor (function)
0185   "Returns t if the FUNCTION is a constructor."
0186   `(semantic-token-function-extra-spec ,function 'constructor)
0187   )
0188 
0189 (defun kde-function-const (function)
0190   "Returns t if the FUNCTION has been declared as const, e.g.
0191 if given a token representing \"int getInt() const\" this functions
0192 would return t"
0193   (save-excursion
0194     (let ((start (semantic-token-start function)) 
0195           (end (semantic-token-end function)))
0196       (goto-char end)
0197       (if (re-search-backward "const\b*;" start t)
0198           t
0199         nil)
0200       )
0201     ))
0202 
0203 (defun kde-is-prototype (function)
0204   "Returns t if the FUNCTION is only a prototype."
0205   (cond
0206    ((semantic-token-function-extra-spec function 'prototype)
0207     t)
0208    (t 
0209     (kde-function-const function))
0210    ))
0211 
0212 
0213 
0214 (defun kde-function-at-point (pt)
0215   "Return function at pt as a token."
0216   (save-excursion
0217     (let ((token)
0218           (what (semantic-find-nonterminal-by-position pt (current-buffer)))
0219           (ctx))
0220       (goto-char pt)
0221       (if (eq (semantic-token-token what) 'function)
0222           what
0223         (semantic-find-nonterminal-by-position pt (semantic-token-type-parts what)))
0224       )
0225     ))
0226 
0227 (defun kde-function-construct (token pclass)
0228   "Constructs a function string from the TOKEN, with the parent class PCLASS."
0229   (let ((fname (semantic-token-name token)))
0230     (if (semantic-token-function-destructor token)
0231         (setq fname (concat "~" fname))
0232       )
0233     (if pclass
0234         (setq fname (concat pclass "::" fname))
0235       )
0236     (if (and
0237          (not (kde-is-constructor token))
0238          (not (semantic-token-function-destructor token)))
0239         (progn
0240           (cond 
0241            ((stringp (semantic-token-type token))
0242             (setq fname (concat (semantic-token-type token) "\n" fname))
0243             )
0244            (t
0245             (setq fname (concat (car (semantic-token-type token)) "\n" fname)))
0246            )
0247           (if (semantic-token-function-extra-spec token 'const)
0248               (setq fname (concat "const " fname))
0249             )
0250           )
0251       )
0252     (setq fname (concat fname (kde-format-args (semantic-token-function-args token))))
0253     (if (kde-function-const token)
0254         (setq fname (concat fname " const" ))
0255       )
0256     (setq fname (concat fname "\n{" "\n}"))
0257     fname
0258     )
0259   )
0260 
0261 (defun kde-class-expand (class-token)
0262   "Returns stubs for member functions as a string.
0263 class-token has to be a token representing either a class or a struct."
0264   (let ((ret "")
0265         (name    (semantic-token-name class-token))
0266         (parents (semantic-token-type-parent class-token))
0267         (parts   (semantic-token-type-parts class-token))
0268         (cur-token)
0269         (cur-token-name)
0270         (asignal)
0271         (aslot)
0272         (namespace)
0273         )
0274     (dolist (elt parts ret)
0275       (setq cur-token (semantic-token-token elt))
0276       (setq cur-token-name (semantic-token-name elt))
0277       (cond
0278        ((and
0279          (eq cur-token 'type)
0280          (stringp cur-token-name))
0281         (cond
0282          ((string= cur-token-name "class")
0283           (kde-class-expand elt)
0284           )
0285          ((string= cur-token-name "enum")
0286           ;;skip enums
0287           )
0288          ((string= cur-token-name "struct")
0289           (kde-class-expand elt)
0290           )
0291          )
0292         )
0293        ((and
0294          (eq cur-token 'function)
0295          (stringp cur-token-name))
0296         ;;FUNCTION - generate a skeleton for it
0297         (if (and (kde-is-prototype elt)
0298                  (not asignal))
0299             (setq ret (concat ret (kde-function-construct elt name) "\n\n"))
0300           )
0301         ;(insert (kde-function-documentation elt) "\n")
0302         )
0303        ((and
0304          (eq cur-token 'label)
0305          (stringp cur-token-name))
0306         (setq aslot   nil
0307               asignal nil)
0308         ;;LABEL - unsets both signals and slots
0309         )
0310        ((and
0311          (eq cur-token 'variable)
0312          cur-token-name)
0313         ;;VARIABLE - doesn't handle static variables correctly right now
0314         )
0315        ((not (stringp cur-token-name))
0316         (cond
0317          ((kde-label-signals (car (semantic-token-extent elt)))
0318           ;;SIGNALS - next prototypes belong to signals and we don't want to 
0319           ;;          expand those
0320           (setq asignal t
0321                 aslot   nil)
0322           )
0323          ((kde-label-namespace (car (semantic-token-extent elt)))
0324           ;;NAMESPACE - semantic doesn't handle things like Qt::ButtonState correctly
0325           ;;            so we do ;)
0326           (setq namespace (kde-label-namespace (car (semantic-token-extent elt))))
0327           )
0328          ((kde-label-slots (car (semantic-token-extent elt)))
0329           ;;SLOTS - for now just unset signals
0330           (setq aslot t
0331                 asignal   nil)
0332           )
0333          (t
0334           (insert "something else at " (number-to-string (car (semantic-token-extent elt))) "\n"))
0335          ))
0336        (t
0337         (insert "Unknown type :: " (prin1-to-string elt) " >>" (prin1-to-string cur-token) "\n"))
0338        )
0339       )
0340     ret
0341     )
0342   )
0343 
0344 (defun kde-expand-tokens (tokens)
0345   "Expands smenatic tokens to strings."
0346   (let ((ret ""))
0347     (dolist (elt tokens ret)
0348       (cond
0349        ((eq (semantic-token-token elt) 'type)
0350         (setq ret (concat ret (kde-class-expand elt)))
0351         )
0352        ((eq (semantic-token-token elt) 'function)
0353         (if (kde-is-prototype elt)
0354             (setq ret (concat ret (kde-function-construct elt nil) "\n\n"))
0355           )
0356         )
0357        ((eq (semantic-token-token elt) 'variable)
0358         ;; skip
0359         ;;(kde-extract-variable elt)
0360         )
0361        ((eq (semantic-token-token elt) 'include)
0362         ;;ignore includes for now
0363         )
0364        (t (insert "Unknown type : " (prin1-to-string (semantic-token-type elt)) "\n"))
0365        )
0366       )
0367     )
0368   )
0369 
0370 
0371 (defun kde-tokens-in-file (FILENAME)
0372   "Returns all tokens from a file with the FILENAME."
0373   (let ((exists (file-readable-p FILENAME))
0374         (buf (current-buffer))
0375         (tokens))
0376     (if exists
0377         (progn
0378           (find-file FILENAME)
0379           (setq tokens (semantic-bovinate-toplevel t))
0380           (switch-to-buffer buf)
0381           tokens)
0382       nil)
0383     ))
0384 
0385 (defun kde-function-in-file (FUNC FILENAME)
0386   "Returns non-nil if FUNC is in a file named FILENAME"
0387   (let ((tokens (kde-tokens-in-file FILENAME)))
0388     (if tokens
0389         (kde-function-in-tokens FUNC tokens)
0390       nil
0391       )
0392     ))
0393 
0394 (defun kde-function-is-expanded (FUNC)
0395   "Returns t if the function FUNC has been expanded."
0396   (let ((file (kde-file-get-cpp-h)))
0397     (if (cdr file)
0398         (if (kde-function-in-file FUNC (car file))
0399             t
0400           nil
0401           )
0402       nil)
0403     ))
0404 
0405 (defun kde-function-expanded-at-point (PT)
0406   "Returns non-nil if the function at point PT has already been expanded."
0407   (interactive "d")
0408   (let ((func (kde-function-at-point PT)))
0409     (kde-function-is-expanded func)
0410     )
0411   )
0412 
0413 (defun kde-create-skeletons ()
0414   "Creates functions stubs in the source file, for all functions
0415 in the current header file."
0416   (interactive)
0417   (let* ((all-tokens (semantic-bovinate-toplevel t))
0418         (filename (buffer-name))
0419         (cppfile (car (kde-file-get-cpp-h)))
0420         (funcs (kde-expand-tokens all-tokens)))
0421     (find-file cppfile)
0422     (save-excursion
0423       (insert "#include \"" filename "\"\n\n")
0424       (insert funcs)
0425       )
0426     )
0427   )
0428 
0429 (defun kde-function-expand-at-point (PT)
0430   "Expand function at point PT."
0431   (interactive "d")
0432   (let ((object (semantic-find-nonterminal-by-position PT (current-buffer)))
0433         (func (kde-function-at-point PT))
0434         (file)
0435         (buf)
0436         (parent))
0437     (if (and object (equal (semantic-token-type object) "class"))
0438         (setq parent (semantic-token-name object)))
0439     (if (and (not (kde-function-expanded-at-point PT))
0440              (kde-is-prototype func))
0441         (progn
0442           (setq func (kde-function-construct func parent))
0443           (setq file (car (kde-file-get-cpp-h)))
0444           (setq buf (current-buffer))
0445           (find-file file)
0446           (save-excursion
0447             (goto-char (point-max))
0448             (insert "\n" func "\n")
0449             )
0450           (switch-to-buffer buf)
0451           )
0452       (error "Function already expanded or defined!")
0453       )
0454     )
0455   )
0456 
0457 (provide 'kde-emacs-semantic)