aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Nazarewicz2016-06-07 14:05:36 +0200
committerMichal Nazarewicz2016-06-15 18:26:12 +0200
commit40e0ef481160d0a0b2290d47c012cc50021a8a82 (patch)
tree4e728d3bdec813b592efa7834f8863d37d4f68b2
parent3be326e8e50e296ebd6ed116b5e5b7b54267b087 (diff)
downloademacs-40e0ef481160d0a0b2290d47c012cc50021a8a82.tar.gz
emacs-40e0ef481160d0a0b2290d47c012cc50021a8a82.zip
Automatically detect whether .h file is C or C++
* lisp/progmodes/cc-mode.el (c-or-c++-mode): A new function which analyses contents of the buffer to determine whether it looks like C++ source code and based on that enables c-mode or c++-mode. (c-or-c++-mode--regexp): Regular expression which, when matches a buffer, signals file is C++.
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/progmodes/cc-mode.el39
-rw-r--r--test/lisp/progmodes/cc-mode.el65
3 files changed, 109 insertions, 2 deletions
diff --git a/etc/NEWS b/etc/NEWS
index e2c99a10275..d8583cf5ab8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -357,6 +357,13 @@ string is computed dynamically based on 'url-privacy-level'.
357colorful faces to make it more obvious to the user what the state is. 357colorful faces to make it more obvious to the user what the state is.
358See the 'vc-faces' customization group. 358See the 'vc-faces' customization group.
359 359
360** CC mode
361
362*** Opening a .h file will turn C or C++ mode depending on language used.
363This is done with the help of 'c-or-c++-mode' function which analyses
364contents of the buffer to determine whether it's a C or C++ source
365file.
366
360 367
361* New Modes and Packages in Emacs 25.2 368* New Modes and Packages in Emacs 25.2
362 369
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 6f326133671..dd8d771a66f 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -912,7 +912,7 @@ Note that the style variables are always made local to the buffer."
912 912
913(defun c-extend-region-for-CPP (beg end) 913(defun c-extend-region-for-CPP (beg end)
914 ;; Adjust `c-new-BEG', `c-new-END' respectively to the beginning and end of 914 ;; Adjust `c-new-BEG', `c-new-END' respectively to the beginning and end of
915 ;; any preprocessor construct they may be in. 915 ;; any preprocessor construct they may be in.
916 ;; 916 ;;
917 ;; Point is undefined both before and after this function call; the buffer 917 ;; Point is undefined both before and after this function call; the buffer
918 ;; has already been widened, and match-data saved. The return value is 918 ;; has already been widened, and match-data saved. The return value is
@@ -1477,7 +1477,8 @@ This function is called from `c-common-init', once per mode initialization."
1477;;;###autoload (add-to-list 'auto-mode-alist '("\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\'" . c++-mode)) 1477;;;###autoload (add-to-list 'auto-mode-alist '("\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\'" . c++-mode))
1478;;;###autoload (add-to-list 'auto-mode-alist '("\\.\\(CC?\\|HH?\\)\\'" . c++-mode)) 1478;;;###autoload (add-to-list 'auto-mode-alist '("\\.\\(CC?\\|HH?\\)\\'" . c++-mode))
1479 1479
1480;;;###autoload (add-to-list 'auto-mode-alist '("\\.[ch]\\'" . c-mode)) 1480;;;###autoload (add-to-list 'auto-mode-alist '("\\.c\\'" . c-mode))
1481;;;###autoload (add-to-list 'auto-mode-alist '("\\.h\\'" . c-or-c++-mode))
1481 1482
1482;; NB: The following two associate yacc and lex files to C Mode, which 1483;; NB: The following two associate yacc and lex files to C Mode, which
1483;; is not really suitable for those formats. Anyway, afaik there's 1484;; is not really suitable for those formats. Anyway, afaik there's
@@ -1518,6 +1519,40 @@ Key bindings:
1518 (cc-imenu-init cc-imenu-c-generic-expression) 1519 (cc-imenu-init cc-imenu-c-generic-expression)
1519 (c-run-mode-hooks 'c-mode-common-hook)) 1520 (c-run-mode-hooks 'c-mode-common-hook))
1520 1521
1522(defconst c-or-c++-mode--regexp
1523 (eval-when-compile
1524 (let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*"))
1525 (concat "^" ws-maybe "\\(?:"
1526 "using" ws "\\(?:namespace" ws "std;\\|std::\\)"
1527 "\\|" "namespace" "\\(:?" ws id "\\)?" ws-maybe "{"
1528 "\\|" "class" ws id ws-maybe "[:{\n]"
1529 "\\|" "template" ws-maybe "<.*>"
1530 "\\|" "#include" ws-maybe "<\\(?:string\\|iostream\\|map\\)>"
1531 "\\)")))
1532 "A regexp applied to C header files to check if they are really C++.")
1533
1534;;;###autoload
1535(defun c-or-c++-mode ()
1536 "Analyse buffer and enable either C or C++ mode.
1537
1538Some people and projects use .h extension for C++ header files
1539which is also the one used for C header files. This makes
1540matching on file name insufficient for detecting major mode that
1541should be used.
1542
1543This function attempts to use file contents to determine whether
1544the code is C or C++ and based on that chooses whether to enable
1545`c-mode' or `c++-mode'."
1546 (if (save-excursion
1547 (save-restriction
1548 (save-match-data
1549 (widen)
1550 (goto-char (point-min))
1551 (re-search-forward c-or-c++-mode--regexp
1552 (+ (point) c-guess-region-max) t))))
1553 (c++-mode)
1554 (c-mode)))
1555
1521 1556
1522;; Support for C++ 1557;; Support for C++
1523 1558
diff --git a/test/lisp/progmodes/cc-mode.el b/test/lisp/progmodes/cc-mode.el
new file mode 100644
index 00000000000..6cd9fa4bad5
--- /dev/null
+++ b/test/lisp/progmodes/cc-mode.el
@@ -0,0 +1,65 @@
1;;; cc-mode-tests.el --- Test suite for cc-mode. -*- lexical-binning: t -*-
2
3;; Copyright (C) 2016 Free Software Foundation, Inc.
4
5;; Author: Michal Nazarewicz <mina86@mina86.com>
6;; Keywords: internal
7;; Human-Keywords: internal
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software: you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23
24;;; Code:
25
26(require 'ert)
27(require 'ert-x)
28(require 'cc-mode)
29
30(ert-deftest c-or-c++-mode ()
31 "Test c-or-c++-mode language detection."
32 (cl-letf* ((mode nil)
33 (do-test (lambda (content expected)
34 (delete-region (point-min) (point-max))
35 (insert content)
36 (setq mode nil)
37 (c-or-c++-mode)
38 (unless(eq expected mode)
39 (ert-fail
40 (format "expected %s but got %s when testing '%s'"
41 expected mode content)))))
42 ((symbol-function 'c-mode) (lambda () (setq mode 'c-mode)))
43 ((symbol-function 'c++-mode) (lambda () (setq mode 'c++-mode))))
44 (with-temp-buffer
45 (mapc (lambda (content)
46 (funcall do-test content 'c++-mode)
47 (funcall do-test (concat "// " content) 'c-mode)
48 (funcall do-test (concat " * " content) 'c-mode))
49 '("using \t namespace \t std;"
50 "using \t std::string;"
51 "namespace \t {"
52 "namespace \t foo \t {"
53 "class \t Blah_42 \t {"
54 "class \t Blah_42 \t \n"
55 "class \t _42_Blah:public Foo {"
56 "template \t < class T >"
57 "template< class T >"
58 "#include <string>"
59 "#include<iostream>"
60 "#include \t <map>"))
61
62 (mapc (lambda (content) (funcall do-test content 'c-mode))
63 '("struct \t Blah_42 \t {"
64 "struct template {"
65 "#include <string.h>")))))