]> git.eshelyaron.com Git - emacs.git/commitdiff
Revert "Revert "Add c-or-c++-ts-mode (bug#59613)""
authorYuan Fu <casouri@gmail.com>
Wed, 18 Jan 2023 06:30:09 +0000 (22:30 -0800)
committerYuan Fu <casouri@gmail.com>
Wed, 18 Jan 2023 06:32:40 +0000 (22:32 -0800)
This reverts commit d46f7f4edcce14e6cbd8e2d7091dbabbe08defc1.

Aaaactually, we need this, otherwise we can't use tree-sitter based C
mode for header files.

etc/NEWS
lisp/progmodes/c-ts-mode.el

index d1ddd0194c1199e0209fe5ab73d0c77f5a96a509..95dd4a24ec3a69e5df92b1c1f13a3884f94cd29e 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3235,6 +3235,11 @@ programs in the C language.
 An optional major mode based on the tree-sitter library for editing
 programs in the C++ language.
 
++++
+*** New command 'c-or-c++-ts-mode'.
+A command that automatically guesses the language of a header file,
+and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly.
+
 +++
 *** New major mode 'java-ts-mode'.
 An optional major mode based on the tree-sitter library for editing
index 89a08a6fa9c30fab44d15170fda381263c011719..f9f75a0e4520a1d0e1af33aba65a2e0ffb8906ec 100644 (file)
@@ -972,6 +972,50 @@ This mode is independent from the classic cc-mode.el based
     (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp))
     (treesit-major-mode-setup)))
 
+;; We could alternatively use parsers, but if this works well, I don't
+;; see the need to change.  This is copied verbatim from cc-guess.el.
+(defconst c-ts-mode--c-or-c++-regexp
+  (eval-when-compile
+    (let ((id "[a-zA-Z_][a-zA-Z0-9_]*") (ws "[ \t]+") (ws-maybe "[ \t]*")
+          (headers '("string" "string_view" "iostream" "map" "unordered_map"
+                     "set" "unordered_set" "vector" "tuple")))
+      (concat "^" ws-maybe "\\(?:"
+              "using"     ws "\\(?:namespace" ws
+              "\\|" id "::"
+              "\\|" id ws-maybe "=\\)"
+              "\\|" "\\(?:inline" ws "\\)?namespace"
+              "\\(:?" ws "\\(?:" id "::\\)*" id "\\)?" ws-maybe "{"
+              "\\|" "class"     ws id
+              "\\(?:" ws "final" "\\)?" ws-maybe "[:{;\n]"
+              "\\|" "struct"     ws id "\\(?:" ws "final" ws-maybe "[:{\n]"
+              "\\|" ws-maybe ":\\)"
+              "\\|" "template"  ws-maybe "<.*?>"
+              "\\|" "#include"  ws-maybe "<" (regexp-opt headers) ">"
+              "\\)")))
+  "A regexp applied to C header files to check if they are really C++.")
+
+;;;###autoload
+(defun c-or-c++-ts-mode ()
+  "Analyze buffer and enable either C or C++ mode.
+
+Some people and projects use .h extension for C++ header files
+which is also the one used for C header files.  This makes
+matching on file name insufficient for detecting major mode that
+should be used.
+
+This function attempts to use file contents to determine whether
+the code is C or C++ and based on that chooses whether to enable
+`c-ts-mode' or `c++-ts-mode'."
+  (interactive)
+  (if (save-excursion
+        (save-restriction
+          (save-match-data ; Why `save-match-data'?
+            (widen)
+            (goto-char (point-min))
+            (re-search-forward c-ts-mode--c-or-c++-regexp nil t))))
+      (c++-ts-mode)
+    (c-ts-mode)))
+
 (provide 'c-ts-mode)
 
 ;;; c-ts-mode.el ends here