init-cc.el 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. ;;; C/C++
  2. ;;; TODO: Should we split this into mode-c and mode-c++?
  3. (dolist (map (list c-mode-map c++-mode-map))
  4. (ambrevar/define-keys map "C-c m" 'cc-main
  5. "<f5>" 'ambrevar/cc-clean
  6. "M-." 'semantic-ia-fast-jump
  7. "C-c C-d" 'semantic-ia-show-summary
  8. "M-<tab>" 'semantic-complete-analyze-inline)
  9. (when (require 'company nil t)
  10. (define-key map (kbd "M-<tab>") (if (require 'helm-company nil t) 'helm-company 'company-complete))))
  11. ;; (define-key map (kbd "C-c o") 'ff-find-other-file)
  12. (defvaralias 'c-basic-offset 'tab-width)
  13. ;;; C additional faces.
  14. ;;; Useless in quasi-monochrome.
  15. ;; (dolist (mode '(c-mode c++-mode))
  16. ;; (font-lock-add-keywords
  17. ;; mode
  18. ;; '(("\\<\\(and\\|or\\|not\\)\\>" . font-lock-keyword-face)
  19. ;; ;; Functions.
  20. ;; ("\\<\\(\\sw+\\)(" 1 'font-lock-function-name-face)
  21. ;; ("\\<\\(\\sw+\\)<\\sw+>(" 1 'font-lock-function-name-face))))
  22. (defvar-local ambrevar/cc-ldlibs "-lm -pthread"
  23. "Custom linker flags for C/C++ linkage.")
  24. (defvar-local ambrevar/cc-ldflags ""
  25. "Custom linker libs for C/C++ linkage.")
  26. (defun ambrevar/cc-set-compiler (&optional nomakefile)
  27. "Set compile command to be nearest Makefile or a generic command.
  28. The Makefile is looked up in parent folders. If no Makefile is
  29. found (or if NOMAKEFILE is non-nil or if function was called with
  30. universal argument), then a configurable commandline is
  31. provided."
  32. (interactive "P")
  33. (hack-local-variables)
  34. ;; Alternatively, if a Makefile is found, we could change default directory
  35. ;; and leave the compile command to "make". Changing `default-directory'
  36. ;; could have side effects though.
  37. (let ((makefile-dir (locate-dominating-file "." "Makefile")))
  38. (if (and makefile-dir (not nomakefile))
  39. (setq compile-command (concat "make -k -C " (shell-quote-argument (file-name-directory makefile-dir))))
  40. (setq compile-command
  41. (let
  42. ((c++-p (eq major-mode 'c++-mode))
  43. (file (file-name-nondirectory buffer-file-name)))
  44. (format "%s %s -o '%s' %s %s %s"
  45. (if c++-p
  46. (or (getenv "CXX") "g++")
  47. (or (getenv "CC") "gcc"))
  48. (shell-quote-argument file)
  49. (shell-quote-argument (file-name-sans-extension file))
  50. (if c++-p
  51. (or (getenv "CXXFLAGS") "-Wall -Wextra -Wshadow -DDEBUG=9 -g3 -O0")
  52. (or (getenv "CFLAGS") "-ansi -pedantic -std=c11 -Wall -Wextra -Wshadow -DDEBUG=9 -g3 -O0"))
  53. (or (getenv "LDFLAGS") ambrevar/cc-ldflags)
  54. (or (getenv "LDLIBS") ambrevar/cc-ldlibs)))))))
  55. (defun ambrevar/cc-clean ()
  56. "Find Makefile and call the `clean' rule. If no Makefile is
  57. found, no action is taken. The previous `compile' command is
  58. restored."
  59. (interactive)
  60. (let (compile-command
  61. (makefile-dir (locate-dominating-file "." "Makefile")))
  62. (when makefile-dir
  63. (compile (format "make -k -C %s clean" (shell-quote-argument makefile-dir))))))
  64. ;;; It is tempting to add `ambrevar/cc-fmt' to the hook:
  65. ;; (add-hook 'before-save-hook 'ambrevar/cc-prettify nil t)
  66. ;;; Unlike Go however, there is no formatting standard and thus this would break
  67. ;;; the formatting rules of every third-party C file that does not follow the
  68. ;;; same style.
  69. (defun ambrevar/cc-prettify ()
  70. "Run uncrustify(1) on current buffer or region."
  71. (interactive)
  72. (let (status
  73. start end
  74. (formatbuf (get-buffer-create "*C format buffer*")))
  75. (if (use-region-p)
  76. (setq start (region-beginning) end (region-end))
  77. (setq start (point-min) end (point-max)))
  78. (setq status
  79. (call-process-region start end "uncrustify" nil formatbuf nil "-lc" "-q" "-c" (expand-file-name ".uncrustify.cfg" (getenv "HOME"))))
  80. (if (/= status 0)
  81. (error "error running uncrustify")
  82. (delete-region start end)
  83. (insert-buffer-substring formatbuf)
  84. (kill-buffer formatbuf))))
  85. ;;; GMP documentation
  86. (with-eval-after-load "info-look"
  87. (let ((mode-value (assoc 'c-mode (assoc 'symbol info-lookup-alist))))
  88. (setcar (nthcdr 3 mode-value)
  89. (cons '("(gmp)Function Index" nil "^ -.* " "\\>")
  90. (nth 3 mode-value)))))
  91. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  92. ;;; Options
  93. ;; We don't want semantic in Scheme and others.
  94. (setq semantic-new-buffer-setup-functions
  95. '((c-mode . semantic-default-c-setup)
  96. (c++-mode . semantic-default-c-setup)))
  97. ;;; Make sure Semanticdb folders is set before starting semantic.
  98. (semantic-mode 1)
  99. ;;; Extra semantic support
  100. ;;; Example:
  101. ;; (when (fboundp 'semantic-add-system-include)
  102. ;; (semantic-add-system-include "new/header/dir" 'c++-mode)
  103. ;; (add-to-list 'auto-mode-alist (cons qt4-base-dir 'c++-mode))
  104. ;; (add-hook
  105. ;; 'c++-mode-hook
  106. ;; (lambda ()
  107. ;; (when semantic-mode
  108. ;; (add-to-list 'semantic-lex-c-preprocessor-symbol-file "new/header/dir/config.h")))))
  109. (c-add-style
  110. "ambrevar"
  111. `((c-comment-only-line-offset . 0)
  112. (c-auto-align-backslashes . nil)
  113. (c-basic-offset . ,tab-width)
  114. (c-offsets-alist
  115. (arglist-cont-nonempty . +)
  116. (arglist-intro . +)
  117. (c . 0)
  118. (case-label . 0)
  119. (cpp-define-intro . 0)
  120. (cpp-macro . 0)
  121. (knr-argdecl-intro . 0)
  122. (label . 0)
  123. (statement-block-intro . +)
  124. (statement-cont . +)
  125. (substatement-label . 0)
  126. (substatement-open . 0))))
  127. (nconc c-default-style '((c-mode . "ambrevar") (c++-mode . "ambrevar")))
  128. ;;; Note that in Emacs 24, cc-mode calls its hooks manually in each mode init
  129. ;;; function. Since cc modes belong to prog-mode, each hook is called another
  130. ;;; time at the end of the initialization. No big deal since we only set some
  131. ;;; variables.
  132. (dolist (hook '(c-mode-hook c++-mode-hook))
  133. (when (require 'company nil t)
  134. (add-hook hook 'company-mode))
  135. (add-hook hook 'ambrevar/cc-set-compiler))
  136. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  137. ;;; Skeletons
  138. ;;; Note that it is possible to extend the skel syntax with
  139. ;;; `skeleton-further-elements'. For instance:
  140. ; (setq skeleton-further-elements '((q "\"")))
  141. (define-skeleton cc-debug
  142. "Insert debug macros."
  143. nil
  144. > "#ifdef DEBUG
  145. #define DEBUG_CMD(CMD) do {CMD;} while(0)
  146. #else
  147. #define DEBUG_CMD(CMD) do {} while(0)
  148. #endif
  149. "
  150. '(insert-and-indent
  151. "#define DEBUG_PRINT(...) DEBUG_CMD( \\
  152. fprintf(stderr, \"%s:%d:\\t(%s)\\t\", __FILE__, __LINE__, __func__); \\
  153. fprintf(stderr, __VA_ARGS__); \\
  154. fprintf(stderr, \"\\n\"); \\
  155. )"))
  156. (define-skeleton cc-getopt
  157. "Insert a getopt template."
  158. nil
  159. > "int opt;" \n
  160. "while ((opt = getopt(argc, argv, \":hV\")) != -1) {" \n
  161. "switch(opt) {" \n
  162. "case 'h':" > \n
  163. "usage(argv[0]);" \n
  164. "return 0;" \n
  165. "case 'V':" > \n
  166. "version();" \n
  167. "return 0;" \n
  168. "case ':':" > \n
  169. "fprintf(stderr, \"ERROR: -%c needs an argument.\\nTry '%s -h' for more information.\\n\", optopt, argv[0]);" \n
  170. "return EXIT_FAILURE;" \n
  171. "case '?':" > \n
  172. "fprintf(stderr, \"ERROR: Unknown argument %c.\\nTry '%s -h' for more information.\\n\", optopt, argv[0]);" \n
  173. "return EXIT_FAILURE;" \n
  174. "default:" > \n
  175. "usage(argv[0]);" \n
  176. "return EXIT_SUCCESS;" \n
  177. "}" > \n
  178. "}" > "\n" \n
  179. "if (optind >= argc) {" \n
  180. "fprintf(stderr, \"Expected argument after options\\n\");" \n
  181. "exit(EXIT_FAILURE);" \n
  182. "}" > \n)
  183. (define-skeleton cc-loadfile
  184. "Insert loadfile function."
  185. nil
  186. "unsigned long loadfile(const char *path, char **buffer_ptr) {" \n
  187. "#define MAX_FILESIZE 1073741824 /* One gigabyte */" > "\n" \n
  188. "/* Handle variable. */" \n
  189. "char *buffer;" "\n" \n
  190. "FILE *file = fopen(path, \"rb\");" \n
  191. "if (file == NULL) {" \n
  192. "perror(path);" \n
  193. "return 0;" \n
  194. "}" > "\n" \n
  195. "fseek(file, 0, SEEK_END);" \n
  196. "long length = ftell(file);" \n
  197. "/* fprintf(stdout, \"Note: file %s is %u bytes long.\\n\", path, length); */" "\n" \n
  198. "if (length > MAX_FILESIZE) {" \n
  199. "fprintf(stderr, \"%s size %ld is bigger than %d bytes.\\n\", path, length, MAX_FILESIZE);" \n
  200. "fclose(file);" \n
  201. "return 0;" \n
  202. "}" > "\n" \n
  203. "fseek(file, 0, SEEK_SET);" \n
  204. "buffer = (char *)malloc(length + 1);" \n
  205. "if (buffer == NULL) {" \n
  206. "perror(\"malloc\");" \n
  207. "fclose(file);" \n
  208. "return 0;" \n
  209. "}" > "\n" \n
  210. "if (fread(buffer, 1, length, file) == 0) {" \n
  211. "fclose(file);" \n
  212. "return 0;" \n
  213. "}" > "\n" \n
  214. "buffer[length] = '\\0';" \n
  215. "fclose(file);" "\n" \n
  216. "*buffer_ptr = buffer;" \n
  217. "return length;" \n
  218. "}" > \n)
  219. (define-skeleton cc-main
  220. "Insert main function with basic includes."
  221. nil
  222. > "#include <inttypes.h>
  223. #include <stdbool.h>
  224. #include <stdint.h>
  225. #include <stdio.h>
  226. #include <stdlib.h>
  227. #include <string.h>
  228. #include <unistd.h>
  229. int main(int argc, char **argv) {" \n
  230. > @ _ \n
  231. > "return 0;
  232. }" \n)
  233. (define-skeleton cc-usage-version
  234. "Insert usage() and version() functions."
  235. "Synopsis: "
  236. > "static void usage(const char *executable) {" \n
  237. "printf(\"Usage: %s [OPTIONS]\\n\\n\", executable);" \n
  238. "puts(\"" str "\\n\");" "\n" \n
  239. "puts(\"Options:\");" \n
  240. "puts(\" -h Print this help.\");" \n
  241. "puts(\" -V Print version information.\");" "\n" \n
  242. "puts(\"\");" \n
  243. "printf(\"See %s for more information.\\n\", MANPAGE);" \n
  244. "}" > "\n" \n
  245. "static void version() {" \n
  246. "printf(\"%s %s\\n\", APPNAME, VERSION);" \n
  247. "printf(\"Copyright © %s %s\\n\", YEAR, AUTHOR);" \n
  248. "}" > \n)
  249. (provide 'init-cc)