blob: ed1b4aa44b123c94c5a1dd0b06c8f56adf12fac6 [file] [log] [blame]
;;; qpid-c++-mode.el --- Qpid specific c++-mode customizations.
;;
;; Licensed to the Apache Software Foundation (ASF) under one or more
;; contributor license agreements. See the NOTICE file distributed
;; with this work for additional information regarding copyright
;; ownership. The ASF licenses this file to you under the Apache
;; License, Version 2.0 (the * "License") ; you may not use this file
;; except in compliance with the License. You may obtain a copy of
;; the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
;; implied. See the License for the specific language governing
;; permissions and limitations under the License.
;;
;;;=====================================================================
;;; Commentary:
;;
;; C++ customizations to make c++ mode follow the Qpid style guidelines,
;; along with some other handy functions to generate initial starting point
;; .h and .cpp files etc.
;;
;; I have this in my .emacs:
;; (add-to-list 'auto-mode-alist '("\\.h$" . c++-mode))
;; (require 'qpid-c++-mode)
;;
;; Written by Alan Conway: aconway@redhat.com
;;
;; For latest version, check
;; http://svn.apache.org/repos/asf/qpid/trunk/qpid/cpp/etc/emacs/qpid-c++-mode.el
;;
(require 'cc-mode)
;; Increment the version number if you change this file.
(defconst qpid-c++-version "1.00" "Qpid C++ style support version number.")
(defun qpid-c++-version ()
"Echo the current version of qpid-c++-mode in the minibuffer."
(interactive)
(message "Using qpid-c++-mode version %s" qpid-c++-version))
(defun qpid-c++-mode ()
"Qpid C++ mode customizations"
(c-add-style "qpid-c++"
'("gnu"
(indent-tabs-mode . nil)
(c-basic-offset . 4)
(c-offsets-alist .
((statement-case-intro . *)
(statement-case-open . *)
(substatement-open . 0)
(case-label . *)
(access-label . /)
(friend . /)
(arglist-intro . +)
(arglist-cont . 0)
(arglist-close . 0)
(inline-open . 0)
(brace-list-open . 0)
(innamespace . 0)
))) )
(c-set-style "qpid-c++")
(setq c-hungry-delete-key t)
(setq c-tab-always-indent t)
(setq c-hanging-braces-alist '((substatement-open . (after))
(extern-lang-open . (after))
(defun-open . (after))
(class-open . (after))
(block-open . (after))
(inline-open . (after))
(defun-block-intro . (after))
(inclass . (after))
(topmost-intro . (after))
(brace-list-open)
(brace-list-close)
(namespace-open)
))
(setq c-hanging-colons-alist '((member-init-intro)
(inher-intro)
(case-label)
(label)
(access-label)))
(setq mode-name "Qpid C++"))
(defun copyright ()
(interactive)
(insert "/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* \"License\"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/"))
(defun indent-buffer ()
(interactive)
(indent-region (point-min) (point-max) nil))
(defun path-to-namespace (path)
(replace-regexp-in-string "/" "::" (replace-regexp-in-string "/$" "" path)))
(defun src-subpath (path)
(if (string-match "/src/\\(.*\\)$" path) (match-string 1 path) ""))
(defun namespace-for-file (file)
(path-to-namespace (src-subpath (file-name-directory file))))
(defun cpp-guard-for-file (file)
(upcase (replace-regexp-in-string "[/.-]" "_" (src-subpath file))))
(defun ask-for-namespace ()
(read-from-minibuffer "Namespace: " (namespace-for-file (buffer-file-name))))
;;; Generate starting point code for new files
(defun insert-ns-open (namespaces)
(mapcar (lambda (ns) (insert "namespace " ns " {\n")) namespaces))
(defun insert-ns-close (namespaces)
(mapcar (lambda (ns) (insert "}")) namespaces)
(insert " // namespace " (mapconcat 'identity namespaces "::") "\n"))
(defun ns-around-region (namespace)
(interactive (list (ask-for-namespace)))
(save-excursion
(let ((namespaces (split-string namespace "::")))
(if (< (mark) (point)) (exchange-point-and-mark))
(insert "\n")
(insert-ns-open namespaces)
(goto-char (mark))
(insert "\n")
(insert-ns-close namespaces))))
(defun insert-class.h (class namespaces)
"Insert class skeleton in .h file"
(insert-ns-open namespaces)
(insert "\n"
"/**\n *\n */\n"
" class " class "\n"
" {\n public:\nprivate:\n};\n"
)
(insert-ns-close namespaces))
(defun insert-platform.h (class namespaces)
"Insert platform #include for platform class."
(insert "#include <qpid/sys/platform.h>\n"
"#include QPID_PLATFORM_H(" class ".h)\n"))
(defun .h (namespace &optional content)
"Initialize a .h file with Qpid copyright etc."
(interactive (list (ask-for-namespace)))
(copyright)
(let ((content (or content 'insert-class.h))
(class (file-name-nondirectory
(file-name-sans-extension(buffer-file-name))))
(namespaces (split-string namespace "::")))
(insert "\n")
(apply content class namespaces nil)
(insert "\n"))
(previous-line 1)
(beginning-of-line)
(indent-buffer)
(save-excursion (cpp-guard)))
(defun .cpp (namespace)
"Initialize an empty .cpp file with Qpid copyright etc."
(interactive (list (ask-for-namespace)))
(copyright)
(insert "\n#include \"" (file-name-sans-extension
(file-name-nondirectory buffer-file-name))
".h\"\n\n")
(let ((namespaces (split-string namespace "::")))
(insert-ns-open namespaces)
(insert-ns-close namespaces))
(indent-buffer))
(defun cpp-guard ()
"Insert C preprocessor macro guard to prevent file rescanning.
The guard macro is defined from the name of the immediate containing
directory and the name of the file."
(interactive)
(let ((name (cpp-guard-for-file (buffer-file-name))))
(goto-char (point-min))
(save-excursion
(if (looking-at "#ifndef .*\n#define .*\n\n")
(let ((ifndef (match-data 0)))
(goto-char (point-max))
(previous-line 1)
(beginning-of-line)
(if (looking-at "#endif")
(progn
(kill-line 1)
(kill-region (car ifndef) (cadr ifndef)))))))
(insert "#ifndef " name "\n#define " name "\n\n")
(goto-char (point-max))
(beginning-of-line)
(insert (format "#endif /*!%s*/\n" name))))
(add-hook 'c++-mode-hook 'qpid-c++-mode)
(provide 'qpid-c++-mode)