;; -*- emacs-lisp -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; $Id: c.el,v 1.15 2005/08/02 23:47:21 ole Exp $
;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_* CamelCase
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(autoload 'camelCase-mode "camelCase-mode")
(setq camelCase-modeline-indicator " cC")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_* C++ Development Initialization
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Tell cc-mode not to check for old-style (K&R) function declarations.
;; This speeds up indenting a lot.
(setq c-recognize-knr-p nil)

(defun tags-generate-c-file ()
  "generate TAGS file from *.cc and *.hh"
  (interactive)
  (shell-command "etags *.cc *.hh *.c *.h 2>/dev/null"))

;; Special style for Linux source files
(defun linux-c-mode ()
  "C mode with adjusted defaults for use with the Linux kernel."
  (interactive)
  (c-mode)
  (c-set-style "K")
  (setq c-basic-offset 8))

(add-to-list 'auto-mode-alist
             '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode))

(defun c-semi&comma-no-newlines-at-all ()
  "never add a newline after a comma or a semicolon"
  'stop)

(defun ole-c-lineup-arglist-operators (langelem)
  "Line up lines starting with an infix operator under the open paren.
Return nil on lines that don't start with an operator, to leave those
cases to other lineup functions.  Example:

if (x < 10
    || at_limit (x,       <- c-lineup-arglist-operators
                 list)    <- c-lineup-arglist-operators returns nil
   )

Since this function doesn't do anything for lines without an infix
operator you typically want to use it together with some other lineup
settings, e.g. as follows:

\(c-set-offset 'arglist-cont '(c-lineup-arglist-operators 0))
\(c-set-offset 'arglist-cont-nonempty '(c-lineup-arglist-operators
                                        c-lineup-arglist))

Works with: arglist-cont, arglist-cont-nonempty."
  (save-excursion
    (back-to-indentation)
    (when (looking-at "[-+|&*%<>=]\\|\\(/[^/*]\\)")
      (c-lineup-arglist langelem))))

;; Suppresses newlines before non-blank lines
(defun ole-newline-after-opening-brace (syntax pos)
  "Controls newline insertion after opening braces."
  (save-excursion
    (if (and (= last-command-char ?{)
             (zerop (forward-line 1))
             (not (looking-at "^[ \t]*$")))
        '()
      '(after))))

(defun ole-newline-before-closing-brace (syntax pos)
  "Controls newline insertion after and before closing brace."
  (save-excursion
    (if (and (= last-command-char ?})
             (zerop (forward-line 0))
             (not (looking-at "^[ \t]*$")))
        '(before)
      '())))

(defun ole-newline-before-and-after-closing-brace (syntax pos)
  "Controls newline insertion after and before closing brace."
  (save-excursion
    (let ((list '()))
      (if (= last-command-char ?})
          (progn
            (if (and (zerop (forward-line 0))
                     (not (looking-at "^[ \t]*$")))
                (setq list '(before)))
            (if (and (zerop (forward-line 1))
                     (looking-at "^[ \t]*$"))
                (add-to-list 'list 'after t))))
      list)))

;; my personal style
(defconst personal-c-style
  '((c-basic-offset . 4)
    (c-tab-always-indent . nil)
    (c-comment-only-line-offset . 0)
    ;; for symbols also see doc of `c-offsets-alist'
    (c-hanging-braces-alist 
     . ((brace-list-intro)
        (brace-list-open)
        (brace-list-close)
        (brace-entry-open)
        (extern-lang-open after)
        (defun-open . ole-newline-after-opening-brace)
        (defun-close . ole-newline-before-closing-brace)
        (inline-open . ole-newline-after-opening-brace)
        (inline-close . ole-newline-before-closing-brace)
        (class-open . ole-newline-after-opening-brace)
        (class-close . ole-newline-before-and-after-closing-brace)
        (substatement-open . ole-newline-after-opening-brace)
        (substatement-close . ole-newline-before-and-after-closing-brace)
        (block-open . ole-newline-after-opening-brace)
        (block-close . ole-newline-before-and-after-closing-brace)
        (inexpr-class-open . ole-newline-after-opening-brace)
        (inexpr-class-close . ole-newline-before-closing-brace)))
    (c-hanging-colons-alist 
     . ((member-init-intro before)
        (inher-intro)
        (case-label after)
        (label after)
        (access-label after)))
    (c-cleanup-list 
     . (scope-operator
        brace-else-brace
        brace-elseif-brace
        brace-catch-brace
        list-close-comma
        defun-close-semi))
    (c-offsets-alist 
     . (
        ;;      (arglist-close . c-lineup-arglist)
        ;;      (func-decl-cont . c-lineup-java-throws)
        (arglist-intro . +)
        (arglist-cont-nonempty . (ole-c-lineup-arglist-operators ++))
        (arglist-close . c-lineup-arglist)
        (func-decl-cont . +)
        (inher-cont . c-lineup-java-inher)
        (inexpr-class . +)
        (topmost-intro-cont . +)
        (inline-open . 0)
        (substatement-open . 0)
        (case-label        . 0)
        (block-open        . 0)
        (knr-argdecl-intro . -)))
    (c-hanging-semi&comma-criteria 
     . (c-semi&comma-no-newlines-at-all))
    ) "My C Programming Style")

;; make style available
(c-add-style "personal" personal-c-style)

;; Customizations for all of c-mode, c++-mode, and objc-mode
(defun my-c-mode-common-hook ()
  ;; add my personal style and set it for the current buffer
  (c-set-style "personal")
  (camelCase-mode 1)
  (setq tab-width 4
        indent-tabs-mode nil)
  ;; eat whitespace with BS
  (c-toggle-hungry-state 1)
  (c-toggle-auto-state 1)
  (c-setup-paragraph-variables)
  ;; keybindings for C, C++, and Objective-C.  We can put these in
  ;; c-mode-map because c++-mode-map and objc-mode-map inherit it
  (define-key c-mode-map "\C-m" 'c-context-line-break)
  (define-key c-mode-map [(tab)]  'xref-indent-complete)
  (outline-minor-mode 1)
  )

(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)

(eval-after-load "cc-mode"
  '(progn
     (add-hook 'c-mode-common-hook 'my-c-mode-common-hook)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;