;;; jao-skel-cpp.el -*- lexical-binding: t; -*- ;; Copyright (C) 2004, 2005, 2008, 2009, 2022 Jose Antonio Ortega Ruiz ;; Author: Jose A Ortega Ruiz ;; Keywords: tools ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; C/C++ skeletons. ;;; Code: (require 'jao-skel) (require 'thingatpt) ;;; Variables (defvar jao-skel-cpp-root-namespace nil "The root C++ namespace") (defvar jao-skel-cpp-brief-header-p nil "If non-nil, generate brief header comments") (defvar jao-skel-cpp-make-guard-function #'jao-skel-cpp-make-guard-name "Function generating #include guards") (defvar jao-skel-cpp-use-namespaces t "Whether to generate namespaces") (defvar jao-skel-cpp-single-line-namespaces t "Whether to put consecutive namespace decls in a single line") (defvar jao-skel-cpp-header-extension "hpp") ;;; Auxiliar functions (defun jao-skel-cpp--find-other (ext) (file-name-nondirectory (or (ff-other-file-name) (concat (file-name-sans-extension (buffer-name)) "." ext)))) (defun jao-skel-cpp-make-guard-name (ns) "Create a standard include guard name" (upcase (mapconcat #'identity `(,@ns ,(jao-skel-basename) ,(jao-skel-extension) ,(user-login-name) ,(format-time-string "%y%m%d%H%M")) "_"))) ;; namespaces (defsubst jao-skel-cpp--read-ns (curr) (read-string (format "Add namespace (current: %s): " (or curr "[none]")))) (defsubst jao-skel-cpp--ns2str (ns) (mapconcat 'identity ns "::")) (defun jao-skel-cpp--get-ns-list (&optional acc) (do* ((result acc (cons next result)) (next (jao-skel-cpp--read-ns (jao-skel-cpp--ns2str acc)) (jao-skel-cpp--read-ns (jao-skel-cpp--ns2str (reverse result))))) ((string= next "") (reverse result)))) (defun jao-skel-cpp--insert-open-ns-list (ns) (dolist (n ns) (insert (format "namespace %s {%s" n (if jao-skel-cpp-single-line-namespaces " " "\n"))) (indent-according-to-mode)) (when jao-skel-cpp-single-line-namespaces (newline) (indent-according-to-mode))) (defun jao-skel-cpp--insert-close-ns-list (ns) (if jao-skel-cpp-single-line-namespaces (insert (format "%s // namespace %s\n" (make-string (length ns) ?}) (jao-skel-cpp--ns2str ns))) (dolist (n (reverse ns)) (insert (format "} // namespace %s\n" n))))) (defun jao-skel-cpp--copy-ns-lines () (let ((lines)) (save-excursion (goto-char (point-min)) (while (re-search-forward "namespace\\s-\\w+\\s-{\\|}+\\s-//\\s-namespace" nil t) (push (thing-at-point 'line) lines) (next-line))) lines)) (defun jao-skel-cpp--copy-namespace () (let* ((name (ff-other-file-name)) (buff (and name (find-file-noselect name))) (nlines)) (when buff (let ((lines (save-current-buffer (set-buffer buff) (jao-skel-cpp--copy-ns-lines)))) (dolist (line lines) (push line nlines) (when (string-match "}" line) (push "\n\n\n\n" nlines))))) (mapconcat #'identity nlines "\n"))) (defsubst jao-skel-cpp--get-new-namespace () (when jao-skel-cpp-use-namespaces (jao-skel-cpp--get-ns-list (and jao-skel-cpp-root-namespace (list jao-skel-cpp-root-namespace))))) ;; skeletons (define-skeleton jao-skel-cpp-header-long "Initial file header blurb" "Brief file description: " "/**" > \n "* @file " (file-name-nondirectory (buffer-file-name)) > \n "* @brief " str > \n "* @author " (user-full-name) " <"user-mail-address">" > \n "* @date " (format-time-string "%a %b %d, %Y %H:%M") > \n "*" > \n (jao-skel-copyright-line "* " "") "*" > ?\n (jao-skel-insert-license) > \n \n _) (define-skeleton jao-skel-cpp-header-brief "Brief initial header blurb" nil (jao-skel-copyright-line "/* " " */") \n) (define-skeleton jao-skel-cpp-header-comment "Insert a standard comment block" nil '(if jao-skel-cpp-brief-header-p (jao-skel-cpp-header-brief) (jao-skel-cpp-header-long))) ;; source C/C++ file ------------------------------------------------------ (define-skeleton jao-skel-cpp-source-header "Insert a standard C++ source header" nil '(jao-skel-cpp-header-comment) ? \n "#include \"" (jao-skel-cpp--find-other jao-skel-cpp-header-extension) "\"" > \n \n _ (jao-skel-cpp--copy-namespace) \n) (define-skeleton jao-skel-c-source-header "Insert a standard C source header" nil '(jao-skel-cpp-header-comment) "#include \"" (jao-skel-cpp--find-other "h") "\"" > _ \n \n \n \n > \n) ;; header C/C++ files ------------------------------------------------------ ;; header guard ;; class definition (define-skeleton jao-skel-cpp-class-def "Insert a class definition" nil '(setq v1 (jao-skel-basename)) > \n "/**" > \n "*" > \n "*" > \n "*/" > \n "class " v1 > \n "{" > \n "public:" > \n "~" v1 "();" > \n v1 "();" > \n v1 "(const " v1 "& other);" > \n \n "private:" > \n "};" > \n) (define-skeleton jao-skel-cpp-header "Insert a standard C++ header (hpp files)" nil '(setq v1 (jao-skel-cpp--get-new-namespace)) '(setq v2 (funcall jao-skel-cpp-make-guard-function v1)) '(jao-skel-cpp-header-comment) > \n "#ifndef " v2 > \n "#define " v2 > \n \n '(when v1 (jao-skel-cpp--insert-open-ns-list v1)) _ '(jao-skel-cpp-class-def) > \n \n '(when v1 (jao-skel-cpp--insert-close-ns-list v1)) > \n \n "#endif // " v2 > \n) (define-skeleton jao-skel-c-header "Insert a standard C header (.h files)" nil '(jao-skel-cpp-header-comment) > \n '(setq v1 (funcall jao-skel-cpp-make-guard-function nil)) "#ifndef " v1 > \n "#define " v1 > _ \n \n \n \n "#endif /* " v1 " */" > \n > \n) (jao-skel-install* '(("\\.cpp$" jao-skel-cpp-source-header) ("\\.hpp$" jao-skel-cpp-header) ("\\.c$" jao-skel-c-source-header) ("\\.h$" jao-skel-c-header))) (provide 'jao-skel-cpp) ;;; jao-skel-cpp.el ends here