diff --git a/modules/lang/cc/autoload.el b/modules/lang/cc/autoload.el index 9b8a18ef1..000f7eb70 100644 --- a/modules/lang/cc/autoload.el +++ b/modules/lang/cc/autoload.el @@ -66,6 +66,45 @@ preceded by the opening brace or a comma (disregarding whitespace in between)." (memq (char-before) (list ?, ?\( ?\;)))) (c-lineup-arglist langlem))) +(defun +cc--re-search-for (regexp) + (save-excursion + (save-restriction + (save-match-data + (widen) + (goto-char (point-min)) + (re-search-forward regexp magic-mode-regexp-match-limit t))))) + +;;;###autoload +(defun +cc-c-c++-objc-mode (&optional file) + "Sets either `c-mode', `objc-mode' or `c++-mode', whichever is appropriate." + (let ((base (file-name-sans-extension buffer-file-name)) + file) + (cond ((file-exists-p! (or (concat base ".cpp") + (concat base ".cc"))) + (c++-mode)) + ((or (file-exists-p! (or (concat base ".m") + (concat base ".mm"))) + (+cc--re-search-for + (concat "^[ \t\r]*\\(?:" + "@\\(?:class\\|interface\\|property\\|end\\)\\_>" + "\\|#import +" + "\\|[-+] ([a-zA-Z0-9_]+)" + "\\)"))) + (objc-mode)) + ((fboundp 'c-or-c++-mode) ; introduced in Emacs 26.1 + (c-or-c++-mode)) + ((+cc--re-search-for ; TODO Remove this along with Emacs 25 support + (let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*")) + (concat "^" ws-maybe "\\(?:" + "using" ws "\\(?:namespace" ws "std;\\|std::\\)" + "\\|" "namespace" "\\(:?" ws id "\\)?" ws-maybe "{" + "\\|" "class" ws id ws-maybe "[:{\n]" + "\\|" "template" ws-maybe "<.*>" + "\\|" "#include" ws-maybe "<\\(?:string\\|iostream\\|map\\)>" + "\\)"))) + (c++-mode)) + ((c-mode))))) + ;; ;; Hooks diff --git a/modules/lang/cc/config.el b/modules/lang/cc/config.el index 24a1871a5..9ebedc341 100644 --- a/modules/lang/cc/config.el +++ b/modules/lang/cc/config.el @@ -26,37 +26,19 @@ compilation database is present in the project.") (def-package! cc-mode :commands (c-mode c++-mode objc-mode java-mode) :mode ("\\.mm\\'" . objc-mode) - :preface - ;; The plusses in c++-mode can be annoying to search for ivy/helm (which reads - ;; queries as regexps), so wee add these for convenience. - (defalias 'cpp-mode 'c++-mode) - (defvaralias 'cpp-mode-map 'c++-mode-map) - - (defun +cc-c++-header-file-p () - (and buffer-file-name - (equal (file-name-extension buffer-file-name) "h") - (or (file-exists-p (expand-file-name - (concat (file-name-sans-extension buffer-file-name) - ".cpp"))) - (when-let* ((file (car-safe (projectile-get-other-files - buffer-file-name - (projectile-current-project-files))))) - (equal (file-name-extension file) "cpp"))))) - - (defun +cc-objc-header-file-p () - (and buffer-file-name - (equal (file-name-extension buffer-file-name) "h") - (re-search-forward "@\\" magic-mode-regexp-match-limit t))) - - (unless (assq '+cc-c++-header-file-p magic-mode-alist) - (push '(+cc-c++-header-file-p . c++-mode) magic-mode-alist) - (push '(+cc-objc-header-file-p . objc-mode) magic-mode-alist)) - :init (setq-default c-basic-offset tab-width c-backspace-function #'delete-backward-char c-default-style "doom") + ;; The plusses in c++-mode can be annoying to search for ivy/helm (which reads + ;; queries as regexps), so we add these for convenience. + (defalias 'cpp-mode 'c++-mode) + (defvaralias 'cpp-mode-map 'c++-mode-map) + + ;; Activate `c-mode', `c++-mode' or `objc-mode' depending on heuristics + (add-to-list 'auto-mode-alist '("\\.h\\'" . +cc-c-c++-objc-mode)) + :config (set-electric! '(c-mode c++-mode objc-mode java-mode) :chars '(?\n ?\}))