]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/cc-mode.el
Speed up CC Mode fontification with less accurate functions extending region
[gnu-emacs] / lisp / progmodes / cc-mode.el
index 9ab04808af692d8164b797b947023d16cc696e1f..6711a02c93a987dc58db9feeb26bd2cd7b5902cd 100644 (file)
@@ -665,6 +665,14 @@ that requires a literal mode spec at compile time."
 (make-variable-buffer-local 'c-new-BEG)
 (defvar c-new-END 0)
 (make-variable-buffer-local 'c-new-END)
+;; The following two variables record the values of `c-new-BEG' and
+;; `c-new-END' just after `c-new-END' has been adjusted for the length of text
+;; inserted or removed.  They may be read by any after-change function (but
+;; should not be altered by one).
+(defvar c-old-BEG 0)
+(make-variable-buffer-local 'c-old-BEG)
+(defvar c-old-END 0)
+(make-variable-buffer-local 'c-old-END)
 
 (defun c-common-init (&optional mode)
   "Common initialization for all CC Mode modes.
@@ -877,9 +885,35 @@ Note that the style variables are always made local to the buffer."
   (memq (cadr (backtrace-frame 3))
        '(put-text-property remove-list-of-text-properties)))
 
+(defun c-depropertize-CPP (beg end)
+  ;; Remove the punctuation syntax-table text property from the CPP parts of
+  ;; (c-new-BEG c-new-END).
+  ;;
+  ;; This function is in the C/C++/ObjC values of
+  ;; `c-get-state-before-change-functions' and is called exclusively as a
+  ;; before change function.
+  (c-save-buffer-state ()
+    (goto-char c-new-BEG)
+    (while (and (< (point) beg)
+               (search-forward-regexp c-anchored-cpp-prefix beg t))
+      (goto-char (match-beginning 1))
+      (let ((m-beg (point)))
+       (c-end-of-macro)
+       (c-clear-char-property-with-value
+        m-beg (min (point) beg) 'syntax-table '(1))))
+
+    (goto-char end)
+    (while (and (< (point) c-new-END)
+               (search-forward-regexp c-anchored-cpp-prefix c-new-END t))
+      (goto-char (match-beginning 1))
+      (let ((m-beg (point)))
+       (c-end-of-macro)
+       (c-clear-char-property-with-value
+        m-beg (min (point) c-new-END) 'syntax-table '(1))))))
+
 (defun c-extend-region-for-CPP (beg end)
   ;; Adjust `c-new-BEG', `c-new-END' respectively to the beginning and end of
-  ;; any preprocessor construct they may be in. 
+  ;; any preprocessor construct they may be in.
   ;;
   ;; Point is undefined both before and after this function call; the buffer
   ;; has already been widened, and match-data saved.  The return value is
@@ -899,6 +933,25 @@ Note that the style variables are always made local to the buffer."
                                 ; with a c-cpp-delimiter category property
   (setq c-new-END (point)))
 
+(defun c-depropertize-new-text (beg end old-len)
+  ;; Remove from the new text in (BEG END) any and all text properties which
+  ;; might interfere with CC Mode's proper working.
+  ;;
+  ;; This function is called exclusively as an after-change function.  It
+  ;; appears in the value (for all languages) of
+  ;; `c-before-font-lock-functions'.  The value of point is undefined both on
+  ;; entry and exit, and the return value has no significance.  The parameters
+  ;; BEG, END, and OLD-LEN are the standard ones supplied to all after-change
+  ;; functions.
+  (c-save-buffer-state ()
+    (when (> end beg)
+      (c-clear-char-properties beg end 'syntax-table)
+      (c-clear-char-properties beg end 'category)
+      (c-clear-char-properties beg end 'c-is-sws)
+      (c-clear-char-properties beg end 'c-in-sws)
+      (c-clear-char-properties beg end 'c-type)
+      (c-clear-char-properties beg end 'c-awk-NL-prop))))
+
 (defun c-extend-font-lock-region-for-macros (begg endd old-len)
   ;; Extend the region (c-new-BEG c-new-END) to cover all (possibly changed)
   ;; preprocessor macros; The return value has no significance.
@@ -967,9 +1020,9 @@ Note that the style variables are always made local to the buffer."
   ;; Note: SPEED _MATTERS_ IN THIS FUNCTION!!!
   ;;
   ;; This function might make hidden buffer changes.
-  (c-save-buffer-state (limits )
+  (c-save-buffer-state (limits)
     ;; Clear 'syntax-table properties "punctuation":
-    (c-clear-char-property-with-value c-new-BEG c-new-END 'syntax-table '(1))
+    ;; (c-clear-char-property-with-value c-new-BEG c-new-END 'syntax-table '(1))
 
     ;; CPP "comment" markers:
     (if (eval-when-compile (memq 'category-properties c-emacs-features));Emacs.
@@ -1009,6 +1062,70 @@ Note that the style variables are always made local to the buffer."
            (forward-line))           ; no infinite loop with, e.g., "#//"
          )))))
 
+(defun c-before-after-change-digit-quote (beg end &optional old-len)
+  ;; This function either removes or applies the punctuation value ('(1)) of
+  ;; the `syntax-table' text property on single quote marks which are
+  ;; separator characters in long integer literals, e.g. "4'294'967'295".  It
+  ;; applies to both decimal/octal and hex literals.  (FIXME (2016-06-10): it
+  ;; should also apply to binary literals.)
+  ;;
+  ;; In both uses of the function, the `syntax-table' properties are
+  ;; removed/applied only on quote marks which appear to be digit separators.
+  ;;
+  ;; Point is undefined on both entry and exit to this function, and the
+  ;; return value has no significance.  The function is called solely as a
+  ;; before-change function (see `c-get-state-before-change-functions') and as
+  ;; an after change function (see `c-before-font-lock-functions', with the
+  ;; parameters BEG, END, and (optionally) OLD-LEN being given the standard
+  ;; values for before/after-change functions.
+  (c-save-buffer-state ((num-begin c-new-BEG) digit-re try-end)
+    (goto-char c-new-END)
+    (when (looking-at "\\(x\\)?[0-9a-fA-F']+")
+      (setq c-new-END (match-end 0)))
+    (goto-char c-new-BEG)
+    (when (looking-at "\\(x?\\)[0-9a-fA-F']")
+      (if (re-search-backward "\\(0x\\)?[0-9a-fA-F]*\\=" nil t)
+         (setq c-new-BEG (point))))
+
+    (while
+       (re-search-forward "[0-9a-fA-F]'[0-9a-fA-F]" c-new-END t)
+      (setq try-end (1- (point)))
+      (re-search-backward "[^0-9a-fA-F']" num-begin t)
+      (setq digit-re
+           (cond
+            ((and (not (bobp)) (eq (char-before) ?0) (memq (char-after) '(?x ?X)))
+             "[0-9a-fA-F]")
+            ((and (eq (char-after (1+ (point))) ?0)
+                  (memq (char-after (+ 2 (point))) '(?b ?B)))
+             "[01]")
+            ((memq (char-after (1+ (point))) '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
+             "[0-9]")
+            (t nil)))
+      (when digit-re
+       (cond ((eq (char-after) ?x) (forward-char))
+             ((looking-at ".?0[Bb]") (goto-char (match-end 0)))
+             ((looking-at digit-re))
+             (t (forward-char)))
+       (when (not (c-in-literal))
+         (let ((num-end             ; End of valid sequence of digits/quotes.
+                (save-excursion
+                  (re-search-forward
+                   (concat "\\=\\(" digit-re "+'\\)*" digit-re "+") nil t)
+                  (point))))
+           (setq try-end               ; End of sequence of digits/quotes
+                 (save-excursion
+                   (re-search-forward
+                    (concat "\\=\\(" digit-re "\\|'\\)+") nil t)
+                   (point)))
+           (while (re-search-forward
+                   (concat digit-re "\\('\\)" digit-re) num-end t)
+             (if old-len           ; i.e. are we in an after-change function?
+                 (c-put-char-property (match-beginning 1) 'syntax-table '(1))
+               (c-clear-char-property (match-beginning 1) 'syntax-table))
+             (backward-char)))))
+      (goto-char try-end)
+      (setq num-begin (point)))))
+
 (defun c-before-change (beg end)
   ;; Function to be put on `before-change-functions'.  Primarily, this calls
   ;; the language dependent `c-get-state-before-change-functions'.  It is
@@ -1125,8 +1242,8 @@ Note that the style variables are always made local to the buffer."
 
   ;; (c-new-BEG c-new-END) will be the region to fontify.  It may become
   ;; larger than (beg end).
-  ;; (setq c-new-BEG beg  c-new-END end)
   (setq c-new-END (- (+ c-new-END (- end beg)) old-len))
+  (setq c-old-BEG c-new-BEG  c-old-END c-new-END)
 
   (unless (c-called-from-text-property-change-p)
     (setq c-just-done-before-change nil)
@@ -1182,20 +1299,21 @@ Note that the style variables are always made local to the buffer."
   ;; This function is called indirectly from font locking stuff - either from
   ;; c-after-change (to prepare for after-change font-locking) or from font
   ;; lock context (etc.) fontification.
-  (let ((lit-limits (c-literal-limits))
+  (let ((lit-start (c-literal-start))
        (new-pos pos)
        bod-lim bo-decl)
     (goto-char (c-point 'bol new-pos))
-    (when lit-limits                   ; Comment or string.
-      (goto-char (car lit-limits)))
+    (when lit-start                    ; Comment or string.
+      (goto-char lit-start))
     (setq bod-lim (c-determine-limit 500))
 
     (while
        ;; Go to a less nested declaration each time round this loop.
        (and
-        (eq (car (c-beginning-of-decl-1 bod-lim)) 'same)
+        (c-syntactic-skip-backward "^;{}" bod-lim t)
         (> (point) bod-lim)
-        (progn (setq bo-decl (point))
+        (progn (c-forward-syntactic-ws)
+               (setq bo-decl (point))
                ;; Are we looking at a keyword such as "template" or
                ;; "typedef" which can decorate a type, or the type itself?
                (when (or (looking-at c-prefix-spec-kwds-re)
@@ -1444,7 +1562,8 @@ This function is called from `c-common-init', once per mode initialization."
 ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\'" . c++-mode))
 ;;;###autoload (add-to-list 'auto-mode-alist '("\\.\\(CC?\\|HH?\\)\\'" . c++-mode))
 
-;;;###autoload (add-to-list 'auto-mode-alist '("\\.[ch]\\'" . c-mode))
+;;;###autoload (add-to-list 'auto-mode-alist '("\\.c\\'" . c-mode))
+;;;###autoload (add-to-list 'auto-mode-alist '("\\.h\\'" . c-or-c++-mode))
 
 ;; NB: The following two associate yacc and lex files to C Mode, which
 ;; is not really suitable for those formats.  Anyway, afaik there's
@@ -1485,6 +1604,40 @@ Key bindings:
   (cc-imenu-init cc-imenu-c-generic-expression)
   (c-run-mode-hooks 'c-mode-common-hook))
 
+(defconst c-or-c++-mode--regexp
+  (eval-when-compile
+    (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\\)>"
+              "\\)")))
+  "A regexp applied to C header files to check if they are really C++.")
+
+;;;###autoload
+(defun c-or-c++-mode ()
+  "Analyse 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-mode' or `c++-mode'."
+  (if (save-excursion
+        (save-restriction
+          (save-match-data
+            (widen)
+            (goto-char (point-min))
+            (re-search-forward c-or-c++-mode--regexp
+                               (+ (point) c-guess-region-max) t))))
+      (c++-mode)
+    (c-mode)))
+
 \f
 ;; Support for C++