;;; ravi-init-cpp.el --- C/C++ handling ;; Copyright (C) 2013 ;; Author: ;; Keywords: ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; C/C++ initialization ;;; Code: ; Generate a random string (of letters and numbers) of a given length (defun ravi-random-ucn-string (len) (coerce (loop for i below len for x = (random 36) collect (+ x (cond ((< x 10) 48) ((< x 36) (- 65 10)) ))) 'string)) (use-package cmake-mode :mode (("CMakeLists\\.txt\\'" . cmake-mode) ("\\.cmake\\'" . cmake-mode)) ;:ensure t ) (defvar get-buffer-compile-command (lambda (file) (cons file 1))) (make-variable-buffer-local 'get-buffer-compile-command) (setq-default compile-command "") (defun compile-dwim (&optional arg) "Compile Do What I Mean. Compile using `compile-command'. When `compile-command' is empty prompt for its default value. With prefix C-u always prompt for the default value of `compile-command'. With prefix C-u C-u prompt for buffer local compile command with suggestion from `get-buffer-compile-command'. An empty input removes the local compile command for the current buffer." (interactive "P") (cond ((and arg (> (car arg) 4)) (let ((cmd (read-from-minibuffer "Buffer local compile command: " (funcall get-buffer-compile-command (or (file-relative-name (buffer-file-name)) "")) nil nil 'compile-history))) (cond ((equal cmd "") (kill-local-variable 'compile-command) (kill-local-variable 'compilation-directory)) (t (set (make-local-variable 'compile-command) cmd) (set (make-local-variable 'compilation-directory) default-directory)))) (when (not (equal compile-command "")) ;; `compile' changes the default value of ;; compilation-directory but this is a buffer local ;; compilation (let ((dirbak (default-value 'compilation-directory))) (compile compile-command) (setq-default compilation-directory dirbak)))) ((or (and arg (<= (car arg) 4)) (equal compile-command "")) (setq-default compile-command (read-shell-command "Compile command: " (if (equal compile-command "") "make " compile-command) 'compile-history)) (setq-default compilation-directory default-directory) (when (not (equal (default-value 'compile-command) "")) (compile (default-value 'compile-command)))) (t (recompile)))) (use-package dummy-h-mode :mode (("\\.h\\'" . dummy-h-mode)) :config (progn (setq dummy-h-mode-default-major-mode 'c++-mode)) :ensure t) (use-package cc-mode :mode (("\\.h\\(h\\|xx\\|pp\\)\\'" . c++-mode) ("\\.ccfg\\'" . c++-mode) ("\\.m\\'" . c-mode) ("\\.mm\\'" . c++-mode)) :init (progn (use-package doxymacs :load-path (lambda () (ravi/emacs-file "site-lisp/doxymacs/lisp")) :config (progn (doxymacs-mode) (setq doxymacs-file-comment-template '("/**" > n " * " (doxymacs-doxygen-command-char) "file" > n " * " > n " * " (doxymacs-doxygen-command-char) "brief " (p "Brief description of this file: ") > n " */" > n) ) (setq doxymacs-external-xml-parser-executable (ravi/emacs-file "site-lisp/doxymacs/c/doxymacs_parser")) (setq doxymacs-use-external-xml-parser t) (setq doxymacs-command-character "\\") ) :diminish doxymacs-mode ) (defvar printf-index 0) (defun insert-counting-printf (arg) (interactive "P") (if arg (setq printf-index 0)) (if t (insert (format "std::cerr << \"step %d..\" << std::endl;\n" (setq printf-index (1+ printf-index)))) (insert (format "printf(\"step %d..\\n\");\n" (setq printf-index (1+ printf-index))))) (forward-line -1) (indent-according-to-mode) (forward-line)) ) :config (progn (defun my-c-mode-common-hook () (hs-minor-mode 1) (hs-hide-initial-comment-block) (hide-ifdef-mode 1) (which-function-mode 1) (diminish 'hs-minor-mode) (diminish 'hide-ifdef-mode) (bind-key "C-c p" 'insert-counting-printf c-mode-base-map) (doxymacs-mode 1) (doxymacs-font-lock) ;(define-key c-mode-base-map [return] 'c-context-line-break) (bind-key "" 'c-context-line-break c-mode-base-map) (unbind-key "M-j" c-mode-base-map) (bind-key "C-c C-i" 'c-includes-current-file c-mode-base-map) (when (and (featurep 'ravi-ergodox-mode) ravi-ergodox-mode) (bind-key "H-h" 'compile-dwim c-mode-base-map)) (set (make-local-variable 'parens-require-spaces) t) (setq fill-column 88) (bind-key "M-q" 'c-fill-paragraph c-mode-base-map) (c-toggle-electric-state 1) (c-toggle-auto-newline 1) (c-toggle-hungry-state 1) (c-set-style "stroustrup") (setq c-basic-offset 2) (setq c-recognize-knr-p nil) (modify-syntax-entry ?_ "w" c-mode-syntax-table) (add-to-list 'c-cleanup-list 'empty-defun-braces) (add-to-list 'c-cleanup-list 'defun-close-semi) (add-to-list 'c-cleanup-list 'list-close-comma) (add-to-list 'c-cleanup-list 'scope-operator) ;; one-liner-defun and comment-close-slash found to be annoying (font-lock-add-keywords 'c++-mode '(("\\<\\(assert\\|DEBUG\\)(" 1 font-lock-warning-face t)))) (add-hook 'c-mode-common-hook 'my-c-mode-common-hook) (defun my-c++-mode-hook () (setq c-offsets-alist (append '((statement-cont . c-lineup-math) (inline-open . 0)) c-offsets-alist)) (let ((innamespaceindent (if (and (buffer-file-name) (string-equal "ccfg" (file-name-extension (buffer-file-name)))) 2 0)) ) (setq c-offsets-alist (append `((innamespace . ,innamespaceindent) ) c-offsets-alist)) ) (modify-syntax-entry ?_ "w" c++-mode-syntax-table) (setq c-macro-cppflags "-x c++") (setq c-macro-prompt-flag t) ) (add-hook 'c++-mode-hook 'my-c++-mode-hook) ;; Stuff from kde-emacs (defvar kde-header-protection-parts-to-show 1 "Set this variable to the number of parts from the file name you want to be used for the defined word in the header-protection function.. E.g. setting this to 3 makes header-protection define KIG_MISC_NEWTYPE_H for a file named /home/domi/src/kdenonbeta/kig/misc/newtype.h") (defun kde-header-protection-definable-string () (let* ((definablestring (concat "_" (ravi-random-ucn-string 6)) ) (f (buffer-file-name)) (parts (nreverse (split-string f "/"))) (i) (first-iter t) (iters (min (length parts) kde-header-protection-parts-to-show))) (dotimes (i iters) (let ((part (pop parts))) (setq definablestring (concat (upcase (replace-regexp-in-string "[\\.-]" "_" part)) (if (not first-iter) "_" "") definablestring ) ) (setq first-iter nil) ) ) definablestring ) ) ;; Creates the ifndef/define/endif statements necessary for a header file (defun header-protection () (interactive) (let ((s (kde-header-protection-definable-string))) (save-excursion (goto-char (point-min)) (insert "#ifndef " s "\n#define " s "\n\n") (goto-char (point-max)) (insert "\n#endif\n") ) ) ) (defun ravi-start-c++-header () "Start a new C++ header by inserting include guards ( see \ header-protection function ), inserting a license statement \ and putting (point) at the correct position" (interactive) (header-protection) (insert "\n") (beginning-of-buffer) (save-excursion (let ((start (point-min)) (comment-style 'box) (end) ) (goto-char start) (insert (ravi-license-header)) (setq end (point)) (comment-region start end) ) ) (end-of-buffer) (next-line -3) (insert "\n") (doxymacs-insert-file-comment) ) (setq auto-insert-query nil) (define-auto-insert "\\.\\([Cc]\\|cc\\|cpp\\|cxx\\|tcc\\)\\'" 'ravi-auto-insert-cpp) (define-auto-insert "\\.\\([Hh]\\|hh\\|hpp\\)\\'" 'ravi-start-c++-header) (defun ravi-license-insert () (progn (let ((start (point-min)) (comment-style 'box) (end) ) (goto-char start) (insert (ravi-license-header)) (insert "\n") (setq end (point)) (comment-region start end)))) (defun ravi-auto-insert-cpp () (progn (ravi-license-insert) (doxymacs-insert-file-comment))) (defun ravi/add-space-before-paren-c (&rest ignored) (message "Handler invoked") (when (looking-back "\\b\\(for\\|while\\|if\\|switch\\)(") (save-excursion (backward-char) (insert-char ?\s) ) )) (defadvice c-electric-paren (after ravi/add-space-around-parens activate) (unless (c-in-literal) (cond ((looking-back "([[:space:]]*") (progn ;; Open parenthesis was the last command; add a space before it if ;; necessary, and ensure that the point is placed after a space (save-excursion (re-search-backward "([[:space:]]*") (unless (looking-at "(") (message "Logic error; opening paren not found")) (when (looking-back "\\b\\(for\\|while\\|if\\|switch\\|catch\\)") (insert-char ?\s))) (if (and (looking-at " ") (not (looking-at " )"))) (forward-char) (insert-char ?\s)) ) ) ((looking-back ")[[:space:]]*") ;; Closing parenthesis was the last command; add spaces if necessary (progn ;; Compact empty function calls (when (looking-back "([[:space:]]+)[[:space:]]*") (save-excursion (re-search-backward ")[[:space:]]*") (delete-horizontal-space) ) ) ;; Add space before closing parenthesis (unless (looking-back "()[[:space:]]*") (save-excursion (re-search-backward ")[[:space:]]*") (unless (looking-at ")") (message "Logic error; closing paren not found")) (unless (looking-back " ") (insert-char ?\s))) ) (let (need-to-add-newline) (save-excursion (c-backward-sexp) (c-backward-syntactic-ws) ;; FIXME: do-while loops are not handled correctly (setq need-to-add-newline (looking-back "\\b\\(for\\|while\\|if\\|switch\\|catch\\)")) ) (when need-to-add-newline (c-newline-and-indent))) ) ) )) ) (defadvice c-electric-semi&comma (after ravi/add-space-after-comma activate) (cond ((looking-back ",") (if (looking-at " [^)]") (forward-char) (insert-char ?\s))) ((looking-back ") ;[[:space:]\n]*") (save-excursion (re-search-backward " ;[[:space:]\n]*") (delete-char 1))))) ;; Do not activate region as it interferes with region-bindings-mode (defadvice c-electric-brace (after ravi/do-not-activate-region activate) (deactivate-mark)) (defmacro ravi/fake-send-key (key-to-bind char-to-bind) (let ((command (key-binding key-to-bind))) (setq last-command-event char-to-bind) (setq this-command command) (call-interactively command)) ) (defun ravi/insert-closing-delimiter() (interactive) (if (c-in-literal) (self-insert-command) (progn ;; Find nearest unmatched opening delimiter (let (brace-type) (save-excursion (backward-up-list) (cond ((looking-at "{") (setq brace-type 'brace-type-brace)) ((looking-at "(") (setq brace-type 'brace-type-paren)) ((looking-at "\\[") (setq brace-type 'brace-type-square)) (t (setq brace-type 'brace-type-none)) )) (cond ((eq brace-type 'brace-type-brace) (ravi/fake-send-key "}" ?\})) ((eq brace-type 'brace-type-paren) (ravi/fake-send-key ")" ?\))) ; Uncommenting the line below would lead to infinite recursion ;((eq 'brace-type 'brace-type-square) (ravi/fake-send-key "]" ?\])) (t (self-insert-command 1)) ) )))) (bind-key "]" 'ravi/insert-closing-delimiter c-mode-base-map) (bind-key "" 'compile-dwim c-mode-base-map) (bind-key "" 'hs-hide-block c-mode-base-map) (bind-key "" 'hs-show-block c-mode-base-map) (setq hide-ifdef-initially nil) (bind-key "" 'hide-ifdef-block c-mode-base-map) (bind-key "" 'show-ifdef-block c-mode-base-map) ;; (setq c-syntactic-indentation nil) ) ) (provide 'ravi-init-cpp) ;;; ravi-init-cpp.el ends here