]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/cc-mode.el
Merge from origin/emacs-24
[gnu-emacs] / lisp / progmodes / cc-mode.el
index 1cba5027f288533dd96a33921b59b6f35c22f520..42ee14072d84048fb76815a6c32992cabdd4f126 100644 (file)
 ;; with your version of Emacs, you are incompatible!
 (cc-external-require 'easymenu)
 
-;; Autoload directive for emacsen that doesn't have an older CC Mode
-;; version in the dist.
-(autoload 'subword-mode "subword"
-  "Mode enabling subword movement and editing keys." t)
-
 ;; Load cc-fonts first after font-lock is loaded, since it isn't
 ;; necessary until font locking is requested.
 ; (eval-after-load "font-lock" ; 2006-07-09: font-lock is now preloaded.
@@ -185,8 +180,7 @@ control).  See \"cc-mode.el\" for more info."
            (run-hooks 'c-initialization-hook)
            ;; Fix obsolete variables.
            (if (boundp 'c-comment-continuation-stars)
-               (setq c-block-comment-prefix
-                     (symbol-value 'c-comment-continuation-stars)))
+               (setq c-block-comment-prefix c-comment-continuation-stars))
            (add-hook 'change-major-mode-hook 'c-leave-cc-mode-mode)
            (setq c-initialization-ok t)
            ;; Connect up with Emacs's electric-indent-mode, for >= Emacs 24.4
@@ -380,7 +374,7 @@ control).  See \"cc-mode.el\" for more info."
   ;; conflicts with OOBR
   ;;(define-key c-mode-base-map "\C-c\C-v"  'c-version)
   ;; (define-key c-mode-base-map "\C-c\C-y"  'c-toggle-hungry-state)  Commented out by ACM, 2005-11-22.
-  (define-key c-mode-base-map "\C-c\C-w" 'subword-mode)
+  (define-key c-mode-base-map "\C-c\C-w" 'c-subword-mode)
   )
 
 ;; We don't require the outline package, but we configure it a bit anyway.
@@ -472,6 +466,14 @@ preferably use the `c-mode-menu' language constant directly."
 (defvar c-maybe-stale-found-type nil)
 (make-variable-buffer-local 'c-maybe-stale-found-type)
 
+(defvar c-just-done-before-change nil)
+(make-variable-buffer-local 'c-just-done-before-change)
+;; This variable is set to t by `c-before-change' and to nil by
+;; `c-after-change'.  It is used to detect a spurious invocation of
+;; `before-change-functions' directly following on from a correct one.  This
+;; happens in some Emacsen, for example when `basic-save-buffer' does (insert
+;; ?\n) when `require-final-newline' is non-nil.
+
 (defun c-basic-common-init (mode default-style)
   "Do the necessary initialization for the syntax handling routines
 and the line breaking/filling code.  Intended to be used by other
@@ -542,10 +544,11 @@ that requires a literal mode spec at compile time."
   ;; Use this in Emacs 21+ to avoid meddling with the rear-nonsticky
   ;; property on each character.
   (when (boundp 'text-property-default-nonsticky)
+    (make-local-variable 'text-property-default-nonsticky)
     (mapc (lambda (tprop)
            (unless (assq tprop text-property-default-nonsticky)
-             (set (make-local-variable 'text-property-default-nonsticky)
-                   (cons `(,tprop . t) text-property-default-nonsticky))))
+             (setq text-property-default-nonsticky
+                    (cons `(,tprop . t) text-property-default-nonsticky))))
          '(syntax-table category c-type)))
 
   ;; In Emacs 21 and later it's possible to turn off the ad-hoc
@@ -605,10 +608,12 @@ that requires a literal mode spec at compile time."
     (make-local-hook 'before-change-functions)
     (make-local-hook 'after-change-functions))
   (add-hook 'before-change-functions 'c-before-change nil t)
+  (setq c-just-done-before-change nil)
   (add-hook 'after-change-functions 'c-after-change nil t)
-  (set (make-local-variable 'font-lock-extend-after-change-region-function)
-       'c-extend-after-change-region)) ; Currently (2009-05) used by all
-                       ; languages with #define (C, C++,; ObjC), and by AWK.
+  (when (boundp 'font-lock-extend-after-change-region-function)
+    (set (make-local-variable 'font-lock-extend-after-change-region-function)
+         'c-extend-after-change-region))) ; Currently (2009-05) used by all
+                          ; languages with #define (C, C++,; ObjC), and by AWK.
 
 (defun c-setup-doc-comment-style ()
   "Initialize the variables that depend on the value of `c-doc-comment-style'."
@@ -669,9 +674,11 @@ compatible with old code; callers should always specify it."
         (or (c-cpp-define-name) (c-defun-name))))
   (let ((rfn (assq mode c-require-final-newline)))
     (when rfn
-      (and (cdr rfn)
-          (set (make-local-variable 'require-final-newline)
-                mode-require-final-newline)))))
+      (if (boundp 'mode-require-final-newline)
+          (and (cdr rfn)
+               (set (make-local-variable 'require-final-newline)
+                    mode-require-final-newline))
+        (set (make-local-variable 'require-final-newline) (cdr rfn))))))
 
 (defun c-count-cfss (lv-alist)
   ;; LV-ALIST is an alist like `file-local-variables-alist'.  Count how many
@@ -948,7 +955,11 @@ Note that the style variables are always made local to the buffer."
          c-new-END (min (cdr new-bounds) (c-determine-+ve-limit 500 endd)))
     ;; Clear all old relevant properties.
     (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 'category 'c-cpp-delimiter)
+
+    ;; CPP "comment" markers:
+    (if (eval-when-compile (memq 'category-properties c-emacs-features));Emacs.
+       (c-clear-char-property-with-value
+        c-new-BEG c-new-END 'category 'c-cpp-delimiter))
     ;; FIXME!!!  What about the "<" and ">" category properties?  2009-11-16
 
     ;; Add needed properties to each CPP construct in the region.
@@ -972,8 +983,10 @@ Note that the style variables are always made local to the buffer."
          (setq mbeg (point))
          (if (> (c-syntactic-end-of-macro) mbeg)
              (progn
-               (c-neutralize-CPP-line mbeg (point))
-               (c-set-cpp-delimiters mbeg (point)))
+               (c-neutralize-CPP-line mbeg (point)) ; "punctuation" properties
+               (if (eval-when-compile
+                      (memq 'category-properties c-emacs-features)) ;Emacs.
+                   (c-set-cpp-delimiters mbeg (point)))) ; "comment" markers
            (forward-line))           ; no infinite loop with, e.g., "#//"
          )))))
 
@@ -993,64 +1006,71 @@ Note that the style variables are always made local to the buffer."
   ;; it/them from the cache.  Don't worry about being inside a string
   ;; or a comment - "wrongly" removing a symbol from `c-found-types'
   ;; isn't critical.
-  (setq c-maybe-stale-found-type nil)
-  (save-restriction
-    (save-match-data
-      (widen)
-      (save-excursion
-       ;; Are we inserting/deleting stuff in the middle of an identifier?
-       (c-unfind-enclosing-token beg)
-       (c-unfind-enclosing-token end)
-       ;; Are we coalescing two tokens together, e.g. "fo o" -> "foo"?
-       (when (< beg end)
-         (c-unfind-coalesced-tokens beg end))
-       ;; Are we (potentially) disrupting the syntactic context which
-       ;; makes a type a type?  E.g. by inserting stuff after "foo" in
-       ;; "foo bar;", or before "foo" in "typedef foo *bar;"?
-       ;;
-       ;; We search for appropriate c-type properties "near" the change.
-       ;; First, find an appropriate boundary for this property search.
-       (let (lim
-             type type-pos
-             marked-id term-pos
-             (end1
-              (or (and (eq (get-text-property end 'face) 'font-lock-comment-face)
-                       (previous-single-property-change end 'face))
-                  end)))
-         (when (>= end1 beg) ; Don't hassle about changes entirely in comments.
-           ;; Find a limit for the search for a `c-type' property
-           (while
-               (and (/= (skip-chars-backward "^;{}") 0)
-                    (> (point) (point-min))
-                    (memq (c-get-char-property (1- (point)) 'face)
-                          '(font-lock-comment-face font-lock-string-face))))
-           (setq lim (max (point-min) (1- (point))))
-
-           ;; Look for the latest `c-type' property before end1
-           (when (and (> end1 (point-min))
-                      (setq type-pos
-                            (if (get-text-property (1- end1) 'c-type)
-                                end1
-                              (previous-single-property-change end1 'c-type nil lim))))
-             (setq type (get-text-property (max (1- type-pos) lim) 'c-type))
-
-             (when (memq type '(c-decl-id-start c-decl-type-start))
-               ;; Get the identifier, if any, that the property is on.
-               (goto-char (1- type-pos))
-               (setq marked-id
-                     (when (looking-at "\\(\\sw\\|\\s_\\)")
-                       (c-beginning-of-current-token)
-                       (buffer-substring-no-properties (point) type-pos)))
-
-               (goto-char end1)
-               (skip-chars-forward "^;{}") ; FIXME!!!  loop for comment, maybe
-               (setq lim (point))
-               (setq term-pos
-                     (or (next-single-property-change end 'c-type nil lim) lim))
-               (setq c-maybe-stale-found-type
-                     (list type marked-id
-                           type-pos term-pos
-                           (buffer-substring-no-properties type-pos term-pos)
+  (unless c-just-done-before-change  ; Guard against a spurious second
+                             ; invocation of before-change-functions.
+    (setq c-just-done-before-change t)
+    (setq c-maybe-stale-found-type nil)
+    (save-restriction
+      (save-match-data
+       (widen)
+       (save-excursion
+         ;; Are we inserting/deleting stuff in the middle of an identifier?
+         (c-unfind-enclosing-token beg)
+         (c-unfind-enclosing-token end)
+         ;; Are we coalescing two tokens together, e.g. "fo o" -> "foo"?
+         (when (< beg end)
+           (c-unfind-coalesced-tokens beg end))
+         ;; Are we (potentially) disrupting the syntactic context which
+         ;; makes a type a type?  E.g. by inserting stuff after "foo" in
+         ;; "foo bar;", or before "foo" in "typedef foo *bar;"?
+         ;;
+         ;; We search for appropriate c-type properties "near" the change.
+         ;; First, find an appropriate boundary for this property search.
+         (let (lim
+               type type-pos
+               marked-id term-pos
+               (end1
+                (or (and (eq (get-text-property end 'face)
+                             'font-lock-comment-face)
+                         (previous-single-property-change end 'face))
+                    end)))
+           (when (>= end1 beg) ; Don't hassle about changes entirely in comments.
+             ;; Find a limit for the search for a `c-type' property
+             (while
+                 (and (/= (skip-chars-backward "^;{}") 0)
+                      (> (point) (point-min))
+                      (memq (c-get-char-property (1- (point)) 'face)
+                            '(font-lock-comment-face font-lock-string-face))))
+             (setq lim (max (point-min) (1- (point))))
+
+             ;; Look for the latest `c-type' property before end1
+             (when (and (> end1 (point-min))
+                        (setq type-pos
+                              (if (get-text-property (1- end1) 'c-type)
+                                  end1
+                                (previous-single-property-change end1 'c-type
+                                                                 nil lim))))
+               (setq type (get-text-property (max (1- type-pos) lim) 'c-type))
+
+               (when (memq type '(c-decl-id-start c-decl-type-start))
+                 ;; Get the identifier, if any, that the property is on.
+                 (goto-char (1- type-pos))
+                 (setq marked-id
+                       (when (looking-at "\\(\\sw\\|\\s_\\)")
+                         (c-beginning-of-current-token)
+                         (buffer-substring-no-properties (point) type-pos)))
+
+                 (goto-char end1)
+                 (skip-chars-forward "^;{}") ;FIXME!!! loop for comment, maybe
+                 (setq lim (point))
+                 (setq term-pos
+                       (or (c-next-single-property-change end 'c-type nil lim)
+                           lim))
+                 (setq c-maybe-stale-found-type
+                       (list type marked-id
+                             type-pos term-pos
+                             (buffer-substring-no-properties type-pos
+                                                             term-pos)
                              (buffer-substring-no-properties beg end)))))))
 
          (if c-get-state-before-change-functions
@@ -1061,7 +1081,7 @@ Note that the style variables are always made local to the buffer."
          )))
     ;; The following must be done here rather than in `c-after-change' because
     ;; newly inserted parens would foul up the invalidation algorithm.
-  (c-invalidate-state-cache beg))
+    (c-invalidate-state-cache beg)))
 
 (defvar c-in-after-change-fontification nil)
 (make-variable-buffer-local 'c-in-after-change-fontification)
@@ -1082,6 +1102,7 @@ Note that the style variables are always made local to the buffer."
   ;; This calls the language variable c-before-font-lock-functions, if non nil.
   ;; This typically sets `syntax-table' properties.
 
+  (setq c-just-done-before-change nil)
   (c-save-buffer-state (case-fold-search open-paren-in-column-0-is-defun-start)
     ;; When `combine-after-change-calls' is used we might get calls
     ;; with regions outside the current narrowing.  This has been
@@ -1102,11 +1123,12 @@ Note that the style variables are always made local to the buffer."
        ;; C-y is capable of spuriously converting category properties
        ;; c-</>-as-paren-syntax and c-cpp-delimiter into hard syntax-table
        ;; properties.  Remove these when it happens.
-       (c-clear-char-property-with-value beg end 'syntax-table
-                                         c-<-as-paren-syntax)
-       (c-clear-char-property-with-value beg end 'syntax-table
-                                         c->-as-paren-syntax)
-       (c-clear-char-property-with-value beg end 'syntax-table nil)
+       (when (eval-when-compile (memq 'category-properties c-emacs-features))
+         (c-clear-char-property-with-value beg end 'syntax-table
+                                           c-<-as-paren-syntax)
+         (c-clear-char-property-with-value beg end 'syntax-table
+                                           c->-as-paren-syntax)
+         (c-clear-char-property-with-value beg end 'syntax-table nil))
 
        (c-trim-found-types beg end old-len) ; maybe we don't need all of these.
        (c-invalidate-sws-region-after beg end)
@@ -1126,11 +1148,11 @@ Note that the style variables are always made local to the buffer."
                  (funcall fn beg end old-len))
                c-before-font-lock-functions))))))
 
-(defun c-set-fl-decl-start (pos)
+(defun c-fl-decl-start (pos)
   ;; If the beginning of the line containing POS is in the middle of a "local"
   ;; declaration (i.e. one which does not start outside of braces enclosing
   ;; POS, such as a struct), return the beginning of that declaration.
-  ;; Otherwise return POS.  Note that declarations, in this sense, can be
+  ;; Otherwise return nil.  Note that declarations, in this sense, can be
   ;; nested.
   ;;
   ;; This function is called indirectly from font locking stuff - either from
@@ -1167,29 +1189,50 @@ Note that the style variables are always made local to the buffer."
                              (1- (point)) 'syntax-table)
                             c-<-as-paren-syntax)))))
         (not (bobp)))
-      (backward-char))
-    new-pos))                          ; back over (, [, <.
-
-(defun c-change-set-fl-decl-start (_beg _end _old-len)
-  ;; Set c-new-BEG to the beginning of a "local" declaration if it('s BOL) is
-  ;; inside one.  This is called from an after-change-function, but the
-  ;; parameters BEG END and OLD-LEN are ignored.  See `c-set-fl-decl-start'
-  ;; for the detailed functionality.
-  (if font-lock-mode
-      (setq c-new-BEG (c-set-fl-decl-start c-new-BEG))))
-
-(defun c-context-set-fl-decl-start (beg end)
-  ;; Return a cons (NEW-BEG . END), where NEW-BEG is the beginning of a
-  ;; "local" declaration (BOL at) NEW is inside or BEG.  See
-  ;; `c-set-fl-decl-start' for the detailed functionality.
-  (cons (c-set-fl-decl-start beg) end))
+      (backward-char))                 ; back over (, [, <.
+    (and (/= new-pos pos) new-pos)))
+
+(defun c-change-expand-fl-region (beg end old-len)
+  ;; Expand the region (c-new-BEG c-new-END) to an after-change font-lock
+  ;; region.  This will usually be the smallest sequence of whole lines
+  ;; containing `c-new-BEG' and `c-new-END', but if `c-new-BEG' is in a
+  ;; "local" declaration (see `c-fl-decl-start') the beginning of this is used
+  ;; as the lower bound.
+  ;;
+  ;; This is called from an after-change-function, but the parameters BEG END
+  ;; and OLD-LEN are not used.
+   (if font-lock-mode
+       (setq c-new-BEG
+            (or (c-fl-decl-start c-new-BEG) (c-point 'bol c-new-BEG))
+            c-new-END (c-point 'bonl c-new-END))))
+
+(defun c-context-expand-fl-region (beg end)
+  ;; Return a cons (NEW-BEG . NEW-END), where NEW-BEG is the beginning of a
+  ;; "local" declaration containing BEG (see `c-fl-decl-start') or BOL BEG is
+  ;; in.  NEW-END is beginning of the line after the one END is in.
+  (cons (or (c-fl-decl-start beg) (c-point 'bol beg))
+       (c-point 'bonl end)))
+
+(defun c-before-context-fl-expand-region (beg end)
+  ;; Expand the region (BEG END) as specified by
+  ;; `c-before-context-fontification-functions'.  Return a cons of the bounds
+  ;; of the new region.
+  (save-restriction
+    (widen)
+    (save-excursion
+      (let ((new-beg beg) (new-end end) new-region)
+       (mapc (lambda (fn)
+               (setq new-region (funcall fn new-beg new-end))
+               (setq new-beg (car new-region) new-end (cdr new-region)))
+             c-before-context-fontification-functions)
+       new-region))))
 
 (defun c-font-lock-fontify-region (beg end &optional verbose)
   ;; Effectively advice around `font-lock-fontify-region' which extends the
   ;; region (BEG END), for example, to avoid context fontification chopping
-  ;; off the start of the context.  Do not do anything if it's already been
-  ;; done (i.e. from an after-change fontification.  An example (C++) where
-  ;; this used to happen is this:
+  ;; off the start of the context.  Do not extend the region if it's already
+  ;; been done (i.e. from an after-change fontification.  An example (C++)
+  ;; where the chopping off used to happen is this:
   ;;
   ;;     template <typename T>
   ;;
@@ -1198,17 +1241,39 @@ Note that the style variables are always made local to the buffer."
   ;; 
   ;; Type a space in the first blank line, and the fontification of the next
   ;; line was fouled up by context fontification.
-  (let ((new-beg beg) (new-end end) new-region case-fold-search
-       open-paren-in-column-0-is-defun-start)
-    (if c-in-after-change-fontification
-       (setq c-in-after-change-fontification nil)
-      (save-restriction
-       (widen)
-       (save-excursion
-         (mapc (lambda (fn)
-                 (setq new-region (funcall fn new-beg new-end))
-                 (setq new-beg (car new-region)  new-end (cdr new-region)))
-               c-before-context-fontification-functions))))
+  (let (new-beg new-end new-region case-fold-search
+               open-paren-in-column-0-is-defun-start)
+    (if (and c-in-after-change-fontification
+            (< beg c-new-END) (> end c-new-BEG))
+       ;; Region and the latest after-change fontification region overlap.
+       ;; Determine the upper and lower bounds of our adjusted region
+       ;; separately.
+       (progn
+         (if (<= beg c-new-BEG)
+             (setq c-in-after-change-fontification nil))
+         (setq new-beg
+               (if (and (>= beg (c-point 'bol c-new-BEG))
+                        (<= beg c-new-BEG))
+                   ;; Either jit-lock has accepted `c-new-BEG', or has
+                   ;; (probably) extended the change region spuriously to
+                   ;; BOL, which position likely has a syntactically
+                   ;; different position.  To ensure correct fontification,
+                   ;; we start at `c-new-BEG', assuming any characters to the
+                   ;; left of `c-new-BEG' on the line do not require
+                   ;; fontification.
+                   c-new-BEG
+                 (setq new-region (c-before-context-fl-expand-region beg end)
+                       new-end (cdr new-region))
+                 (car new-region)))
+         (setq new-end
+               (if (and (>= end (c-point 'bol c-new-END))
+                        (<= end c-new-END))
+                   c-new-END
+                 (or new-end
+                     (cdr (c-before-context-fl-expand-region beg end))))))
+      ;; Context (etc.) fontification.
+      (setq new-region (c-before-context-fl-expand-region beg end)
+           new-beg (car new-region)  new-end (cdr new-region)))
     (funcall (default-value 'font-lock-fontify-region-function)
             new-beg new-end verbose)))
 
@@ -1244,9 +1309,10 @@ This function is called from `c-common-init', once per mode initialization."
       (make-local-hook 'font-lock-mode-hook))
   (add-hook 'font-lock-mode-hook 'c-after-font-lock-init nil t))
 
+;; Emacs 22 and later.
 (defun c-extend-after-change-region (_beg _end _old-len)
   "Extend the region to be fontified, if necessary."
-  ;; Note: the parameters are ignored here.  This somewhat indirect
+  ;; Note: the parameter OLD-LEN is ignored here.  This somewhat indirect
   ;; implementation exists because it is minimally different from the
   ;; stand-alone CC Mode which, lacking
   ;; font-lock-extend-after-change-region-function, is forced to use advice
@@ -1255,8 +1321,30 @@ This function is called from `c-common-init', once per mode initialization."
   ;; Of the seven CC Mode languages, currently (2009-05) only C, C++, Objc
   ;; (the languages with #define) and AWK Mode make non-null use of this
   ;; function.
+  (when (eq font-lock-support-mode 'jit-lock-mode)
+    (save-restriction
+      (widen)
+      (if (< c-new-BEG beg)
+         (put-text-property c-new-BEG beg 'fontified nil))
+      (if (> c-new-END end)
+         (put-text-property end c-new-END 'fontified nil))))
   (cons c-new-BEG c-new-END))
 
+;; Emacs < 22 and XEmacs
+(defmacro c-advise-fl-for-region (function)
+  `(defadvice ,function (before get-awk-region activate)
+     ;; Make sure that any string/regexp is completely font-locked.
+     (when c-buffer-is-cc-mode
+       (save-excursion
+        (ad-set-arg 1 c-new-END)   ; end
+        (ad-set-arg 0 c-new-BEG)))))   ; beg
+
+(unless (boundp 'font-lock-extend-after-change-region-function)
+  (c-advise-fl-for-region font-lock-after-change-function)
+  (c-advise-fl-for-region jit-lock-after-change)
+  (c-advise-fl-for-region lazy-lock-defer-rest-after-change)
+  (c-advise-fl-for-region lazy-lock-defer-line-after-change))
+
 ;; Connect up to `electric-indent-mode' (Emacs 24.4 and later).
 (defun c-electric-indent-mode-hook ()
   ;; Emacs has en/disabled `electric-indent-mode'.  Propagate this through to
@@ -1327,6 +1415,7 @@ This function is called from `c-common-init', once per mode initialization."
 ;;;###autoload (add-to-list 'auto-mode-alist '("\\.i\\'" . c-mode))
 ;;;###autoload (add-to-list 'auto-mode-alist '("\\.ii\\'" . c++-mode))
 
+(unless (fboundp 'prog-mode) (defalias 'prog-mode 'fundamental-mode))
 
 ;;;###autoload
 (define-derived-mode c-mode prog-mode "C"
@@ -1784,4 +1873,8 @@ Key bindings:
 \f
 (cc-provide 'cc-mode)
 
+;;; Local Variables:
+;;; indent-tabs-mode: t
+;;; tab-width: 8
+;;; End:
 ;;; cc-mode.el ends here