project autoload extension
[emacsstuff.git] / cc-ide / cc-ide.el
index 2594614..1adbd3f 100644 (file)
@@ -55,6 +55,14 @@ correctly included.")
 
 (defvar ccide-new-file-hook nil)
 
+(defvar ccide-new-file-command nil)
+
+(defvar ccide-clang-format-command nil)
+
+(defvar ccide-uncrustify-command "uncrustify")
+(defvar ccide-uncrustify-config nil)
+(defvar ccide-auto-format-tag nil)
+
 (defconst c-user-prefix-re (regexp-opt c-user-prefixes t))
 
 (defconst ccide-doxy-tag-re
@@ -78,6 +86,7 @@ correctly included.")
     ;; file level
     ("fc"  ccide-file-comment                 "File comment")
     ("fs"  ccide-syncronize-includes          "Sync includes")
+    ("ff"  ccide-clang-format-buffer          "Reformat buffer")
     (nil   nil                                separator)
 
     ;; class level
@@ -123,8 +132,11 @@ correctly included.")
     (nil   nil                                separator)
 
     ;; documentation
-    ("h"  ccide-hide-all-doxy-comments        "Hide all Doxygen comments")
-    ("s"  ccide-show-all-comments             "Show all Doxygen comments")
+    ("h"   ccide-hide-all-doxy-comments        "Hide all Doxygen comments")
+    ("s"   ccide-show-all-comments             "Show all Doxygen comments")
+
+    ;; cython
+    ("yp"  ccide-grab-pxd-fn                   "Generate pxd function/method decl")
 
 ;    ;; CORBA
 ;    ("Cg"  ccide-gen-corba-impl                      "Generate CORBA impl")
@@ -463,7 +475,7 @@ correctly included.")
                                 (while (re-search-forward
                                         (concat "^\\(//\\)?#\\s-*include \""
                                                 (regexp-quote (car include))
-                                                "\"\\s-*$")
+                                                "\"\\s-*")
                                         nil t)
                                   (goto-char (match-beginning 0))
                                   (if (looking-at "//")
@@ -475,9 +487,18 @@ correctly included.")
 
 (defun ccide-auto-decorate-new-files ()
   (if (and (buffer-file-name) (= (point-min) (point-max)))
-      (let ((status (buffer-modified-p)))
-        (ccide-file-comment)
-        (set-buffer-modified-p status))))
+      (if (or (not ccide-new-file-command)
+              (not (progn
+                     (save-buffer)
+                     (condition-case nil
+                         (progn
+                           (shell-command (format "%s %s" ccide-new-file-command (buffer-file-name)))
+                           (revert-buffer t t t)
+                           t)
+                       (error nil nil)))))
+          (let ((status (buffer-modified-p)))
+            (ccide-file-comment)
+            (set-buffer-modified-p status)))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; class level
@@ -1460,6 +1481,17 @@ instatiations at point."
 (provide 'cc-ide)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; cython support
+
+(defun ccide-grab-pxd-fn ()
+  (interactive)
+  (save-excursion
+    (c-beginning-of-defun-or-decl)
+    (let ((defn (c-build-pxd)))
+      (kill-new (cadr defn))
+      (message (concat (car defn))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; other stuff
 
 (defun ccide-open-compilation-frame ()
@@ -1540,12 +1572,143 @@ instatiations at point."
   (auto-fill-mode -1)
   (ccide-project-load-config)
   (ccide-directory-load-config)
-  (ccide-auto-decorate-new-files))
+  (ccide-auto-decorate-new-files)
+  (if ccide-clang-format-command
+      (add-hook 'write-contents-functions 'ccide-clang-format-buffer nil t))
+  (if ccide-uncrustify-config
+      (add-hook 'write-contents-functions 'ccide-uncrustify-format-buffer nil t)))
+
+(defun ccide-match-auto-format-tag ()
+  (or (not ccide-auto-format-tag)
+      (and (save-excursion
+             (goto-char (point-min))
+             (search-forward ccide-auto-format-tag
+                             (save-excursion (forward-line 4) (point))
+                             t)) t)))
+
+(require 'xmltok)
+
+(defun clang-format-xmltok-attribute (name)
+  (loop for attribute in xmltok-attributes
+        if (string= (buffer-substring-no-properties (xmltok-attribute-name-start attribute)
+                                                    (xmltok-attribute-name-end attribute))
+                    name)
+        return (buffer-substring-no-properties (xmltok-attribute-value-start attribute)
+                                               (xmltok-attribute-value-end attribute))))
+
+(defun clang-format-parse-replacement-text ()
+  (cond ((eq tok 'char-ref)
+         (let ((number-start (+ xmltok-start 2))
+               (number-end (1- (point))))
+           (if (not (string= (buffer-substring-no-properties xmltok-start number-start)
+                             "&#"))
+               (error "invalid character reference"))
+           (char-to-string (string-to-number (buffer-substring-no-properties number-start
+                                                                             number-end)))))
+
+        (t
+         (buffer-substring-no-properties xmltok-start (point)))))
+
+(defun clang-format-parse-replacement ()
+  (let ((offset (string-to-number (clang-format-xmltok-attribute "offset")))
+        (length (string-to-number (clang-format-xmltok-attribute "length"))))
+    (list offset
+          length
+          (loop for tok = (xmltok-forward)
+                while (not (eq tok 'end-tag))
+                concat (clang-format-parse-replacement-text)))))
+
+(defun clang-format-parse-header ()
+  (let ((incflag (clang-format-xmltok-attribute "incomplete_format")))
+    (if (string= incflag "true")
+        (warn "clang-format: C++ syntax error in file"))))
+
+(defun clang-format-parse-replacements (buffer)
+  (save-excursion
+    (set-buffer buffer)
+    (goto-char (point-min))
+    (xmltok-forward-prolog)
+    (loop for tok = (xmltok-forward)
+          while tok
+          for n = (buffer-substring-no-properties (1+ xmltok-start) xmltok-name-end)
+          if (and (eq tok 'start-tag)
+                  (string= n "replacement")) collect (clang-format-parse-replacement)
+          else if (and (eq tok ' start-tag)
+                       (string= n "replacements")) do (clang-format-parse-header))))
+
+(defun clang-format-apply-replacements (replacements)
+  (loop for (offset length replacement) in (nreverse replacements)
+        do (progn
+             (goto-char (1+ offset))
+             (delete-char length)
+             (insert replacement))))
+
+(defun ccide-clang-format-buffer ()
+  (interactive)
+  (if (and ccide-clang-format-command (ccide-match-auto-format-tag))
+      (let ((replacementsBuffer (get-buffer-create " *clang-format-replacements*")))
+        (save-excursion (set-buffer replacementsBuffer) (erase-buffer))
+        (shell-command-on-region (point-min) (point-max) ccide-clang-format-command
+                                 replacementsBuffer nil)
+        (let ((replacements (clang-format-parse-replacements replacementsBuffer)))
+          (save-excursion
+            (clang-format-apply-replacements replacements)))))
+  nil)
+
+(defun ccide-parse-ed-diff (buffer)
+  ;; an ed-diff already has the replacements in reverse order
+  (save-excursion
+    (set-buffer buffer)
+    (goto-char (point-min))
+    (loop while (= (forward-line 1) 0)
+          if (looking-at "Unmatched")
+            do (error (buffer-substring-no-properties (point) (progn (end-of-line) (point))))
+          for b = (point)
+          for e = (save-excursion (end-of-line) (point))
+          for k = (search-forward "," e t)
+          for m = (buffer-substring-no-properties (1- e) e)
+          for rb = (when (not (equal m "d"))
+                     (forward-line 1) (point))
+          for re = (when (not (equal m "d"))
+                     (while (and (not (looking-at "\\.$")) (= (forward-line 1) 0))) (point))
+          for bl = (string-to-number (buffer-substring-no-properties b (1- (or k e))))
+          for el = (string-to-number (buffer-substring-no-properties (or k b) (1- e)))
+          collect (list (if (equal m "a") (1+ bl) bl)
+                        (1+ el)
+                        (if (not (equal m "d"))
+                            (buffer-substring-no-properties rb re)
+                          "")))))
+
+(defun ccide-apply-ed-diff (replacements)
+  (loop for (first last replacement) in replacements
+        do (progn
+             (goto-line first)
+             (delete-region (point) (progn (goto-line last) (point)))
+             (insert replacement))))
+
+(defun ccide-uncrustify-format-buffer ()
+  (interactive)
+  (if (and ccide-uncrustify-config (ccide-match-auto-format-tag))
+      (let ((tempFile (make-temp-file "ccideuncrustify"))
+            (diffBuffer (get-buffer-create " *uncrustify-format-diff*")))
+        (unwind-protect
+            (progn
+              (write-region (point-min) (point-max) tempFile)
+              (shell-command (concat (shell-quote-argument ccide-uncrustify-command)
+                                     " -c " (shell-quote-argument
+                                             (expand-file-name ccide-uncrustify-config))
+                                     " -l CPP -f " (shell-quote-argument tempFile)
+                                     " | diff -e " (shell-quote-argument tempFile) " -")
+                             diffBuffer nil))
+          (delete-file tempFile))
+        (let ((replacements (ccide-parse-ed-diff diffBuffer)))
+          (save-excursion
+            (ccide-apply-ed-diff replacements))))
+    nil))
 
-(defun ccide-project-load-config ()
-  (if (buffer-file-name)
-      (let ((conf (ccide-project-search-upwards '(".project.el" "project.el")
-                                                (file-name-directory (buffer-file-name)))))
+(defun ccide-project-load-config (&optional force)
+  (if (or force (buffer-file-name))
+      (let ((conf (ccide-project-search-upwards '(".project.el" "project.el") default-directory)))
         (when conf
           (set (make-local-variable 'ccide-project-root) (file-name-directory conf))
           (load-file conf)))))
@@ -1606,7 +1769,6 @@ DIR defaults to ccide-project-root. If FILE is a list, search for any file in li
             (if (> (- (point-max) pos) (point))
                 (goto-char (- (point-max) pos))))))))
 
-
 \f
 ;;; Local Variables:
 ;;; elisp-project-autoload-file-name: "cc-autoload.el"