SMIE: Reliably distinguish openers/closers in smie-prec2-levels
[bpt/emacs.git] / lisp / progmodes / cc-mode.el
index 49d9ebe..505a566 100644 (file)
@@ -1,8 +1,8 @@
 ;;; cc-mode.el --- major mode for editing C and similar languages
 
 ;; Copyright (C) 1985, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;;   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-;;   Free Software Foundation, Inc.
+;;   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+;;   2010  Free Software Foundation, Inc.
 
 ;; Authors:    2003- Alan Mackenzie
 ;;             1998- Martin Stjernholm
@@ -12,7 +12,7 @@
 ;;             1985 Richard M. Stallman
 ;; Maintainer: bug-cc-mode@gnu.org
 ;; Created:    a long, long, time ago. adapted from the original c-mode.el
-;; Keywords:   c languages oop
+;; Keywords:   c languages
 
 ;; This file is part of GNU Emacs.
 
 (cc-bytecomp-defvar adaptive-fill-first-line-regexp) ; Emacs
 (cc-bytecomp-defun set-keymap-parents) ; XEmacs
 (cc-bytecomp-defun run-mode-hooks)     ; Emacs 21.1
-(cc-bytecomp-obsolete-fun make-local-hook) ; Marked obsolete in Emacs 21.1.
 
 ;; We set these variables during mode init, yet we don't require
 ;; font-lock.
@@ -522,7 +521,7 @@ that requires a literal mode spec at compile time."
 
   (when (or c-recognize-<>-arglists
            (c-major-mode-is 'awk-mode)
-           (c-major-mode-is '(c-mode c++-mode objc-mode)))
+           (c-major-mode-is '(java-mode c-mode c++-mode objc-mode)))
     ;; We'll use the syntax-table text property to change the syntax
     ;; of some chars for this language, so do the necessary setup for
     ;; that.
@@ -541,19 +540,15 @@ that requires a literal mode spec at compile time."
       (make-local-variable 'lookup-syntax-properties)
       (setq lookup-syntax-properties t)))
 
-  ;; Use this in Emacs 21 to avoid meddling with the rear-nonsticky
+  ;; 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)
-    (let ((elem (assq 'syntax-table text-property-default-nonsticky)))
-      (if elem
-         (setcdr elem t)
-       (setq text-property-default-nonsticky
-             (cons '(syntax-table . t)
-                   text-property-default-nonsticky))))
-    (setq text-property-default-nonsticky
-         (cons '(c-type . t)
-               text-property-default-nonsticky)))
+    (mapc (lambda (tprop)
+           (unless (assq tprop 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
   ;; heuristic that open parens in column 0 are defun starters.  Since
@@ -604,9 +599,10 @@ that requires a literal mode spec at compile time."
 
   ;; Install the functions that ensure that various internal caches
   ;; don't become invalid due to buffer changes.
-  (make-local-hook 'before-change-functions)
+  (when (featurep 'xemacs)
+    (make-local-hook 'before-change-functions)
+    (make-local-hook 'after-change-functions))
   (add-hook 'before-change-functions 'c-before-change nil t)
-  (make-local-hook 'after-change-functions)
   (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
@@ -620,6 +616,15 @@ that requires a literal mode spec at compile time."
     (font-lock-mode 0)
     (font-lock-mode 1)))
 
+;; Buffer local variables defining the region to be fontified by a font lock
+;; after-change function.  They are set in c-after-change to
+;; after-change-function's BEG and END, and may be modified by a
+;; `c-before-font-lock-function'.
+(defvar c-new-BEG 0)
+(make-variable-buffer-local 'c-new-BEG)
+(defvar c-new-END 0)
+(make-variable-buffer-local 'c-new-END)
+
 (defun c-common-init (&optional mode)
   "Common initialization for all CC Mode modes.
 In addition to the work done by `c-basic-common-init' and
@@ -644,9 +649,13 @@ compatible with old code; callers should always specify it."
   ;; Starting a mode is a sort of "change".  So call the change functions...
   (save-restriction
     (widen)
+    (setq c-new-BEG (point-min))
+    (setq c-new-END (point-max))
     (save-excursion
-      (if c-get-state-before-change-function
-         (funcall c-get-state-before-change-function (point-min) (point-max)))
+      (if c-get-state-before-change-functions
+         (mapc (lambda (fn)
+                 (funcall fn (point-min) (point-max)))
+               c-get-state-before-change-functions))
       (if c-before-font-lock-function
          (funcall c-before-font-lock-function (point-min) (point-max)
                   (- (point-max) (point-min))))))
@@ -662,6 +671,17 @@ compatible with old code; callers should always specify it."
       (and (cdr rfn)
           (setq require-final-newline mode-require-final-newline)))))
 
+(defun c-count-cfss (lv-alist)
+  ;; LV-ALIST is an alist like `file-local-variables-alist'.  Count how many
+  ;; elements with the key `c-file-style' there are in it.
+  (let ((elt-ptr lv-alist) elt (cownt 0))
+    (while elt-ptr
+      (setq elt (car elt-ptr)
+           elt-ptr (cdr elt-ptr))
+      (when (eq (car elt) 'c-file-style)
+       (setq cownt (1+ cownt))))
+    cownt))
+                                                         
 (defun c-before-hack-hook ()
   "Set the CC Mode style and \"offsets\" when in the buffer's local variables.
 They are set only when, respectively, the pseudo variables
@@ -669,11 +689,24 @@ They are set only when, respectively, the pseudo variables
 
 This function is called from the hook `before-hack-local-variables-hook'."
   (when c-buffer-is-cc-mode
-    (let ((stile (cdr (assq 'c-file-style file-local-variables-alist)))
+    (let ((mode-cons (assq 'mode file-local-variables-alist))
+         (stile (cdr (assq 'c-file-style file-local-variables-alist)))
          (offsets (cdr (assq 'c-file-offsets file-local-variables-alist))))
+      (when mode-cons
+       (hack-one-local-variable (car mode-cons) (cdr mode-cons))
+       (setq file-local-variables-alist
+             (delq mode-cons file-local-variables-alist)))
       (when stile
        (or (stringp stile) (error "c-file-style is not a string"))
-       (c-set-style stile))
+       (if (boundp 'dir-local-variables-alist)
+           ;; Determine whether `c-file-style' was set in the file's local
+           ;; variables or in a .dir-locals.el (a directory setting).
+           (let ((cfs-in-file-and-dir-count
+                  (c-count-cfss file-local-variables-alist))
+                 (cfs-in-dir-count (c-count-cfss dir-local-variables-alist)))
+             (c-set-style stile
+                          (= cfs-in-file-and-dir-count cfs-in-dir-count)))
+         (c-set-style stile)))
       (when offsets
        (mapc
         (lambda (langentry)
@@ -779,7 +812,7 @@ Note that the style variables are always made local to the buffer."
 
 (defmacro c-run-mode-hooks (&rest hooks)
   ;; Emacs 21.1 has introduced a system with delayed mode hooks that
-  ;; require the use of the new function `run-mode-hooks'.
+  ;; requires the use of the new function `run-mode-hooks'.
   (if (cc-bytecomp-fboundp 'run-mode-hooks)
       `(run-mode-hooks ,@hooks)
     `(progn ,@(mapcar (lambda (hook) `(run-hooks ,hook)) hooks))))
@@ -787,15 +820,6 @@ Note that the style variables are always made local to the buffer."
 \f
 ;;; Change hooks, linking with Font Lock.
 
-;; Buffer local variables defining the region to be fontified by a font lock
-;; after-change function.  They are set in c-after-change to
-;; after-change-function's BEG and END, and may be modified by a
-;; `c-before-font-lock-function'.
-(defvar c-new-BEG 0)
-(make-variable-buffer-local 'c-new-BEG)
-(defvar c-new-END 0)
-(make-variable-buffer-local 'c-new-END)
-
 ;; Buffer local variables recording Beginning/End-of-Macro position before a
 ;; change, when a macro straddles, respectively, the BEG or END (or both) of
 ;; the change region.  Otherwise these have the values BEG/END.
@@ -812,16 +836,18 @@ Note that the style variables are always made local to the buffer."
   ;; has already been widened, and match-data saved.  The return value is
   ;; meaningless.
   ;;
-  ;; This function is the C/C++/ObjC value of
-  ;; `c-get-state-before-change-function' and is called exclusively as a
+  ;; 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.
   (goto-char beg)
   (c-beginning-of-macro)
   (setq c-old-BOM (point))
 
   (goto-char end)
-  (if (c-beginning-of-macro)
-    (c-end-of-macro))
+  (when (c-beginning-of-macro)
+    (c-end-of-macro)
+    (or (eobp) (forward-char)))         ; Over the terminating NL which may be marked
+                                ; with a c-cpp-delimiter category property
   (setq c-old-EOM (point)))
 
 (defun c-neutralize-CPP-line (beg end)
@@ -886,17 +912,19 @@ Note that the style variables are always made local to the buffer."
     ;; inside a string, comment, or macro.
     (goto-char c-old-BOM)        ; already set to old start of macro or begg.
     (setq c-new-BEG
-         (if (setq limits (c-state-literal-at (point)))
-             (cdr limits)          ; go forward out of any string or comment.
-           (point)))
+         (min c-new-BEG
+              (if (setq limits (c-state-literal-at (point)))
+                  (cdr limits)     ; go forward out of any string or comment.
+                (point))))
 
     (goto-char endd)
     (if (setq limits (c-state-literal-at (point)))
        (goto-char (car limits)))  ; go backward out of any string or comment.
     (if (c-beginning-of-macro)
        (c-end-of-macro))
-    (setq c-new-END (max (+ (- c-old-EOM old-len) (- endd begg))
-                  (point)))
+    (setq c-new-END (max c-new-END
+                        (+ (- c-old-EOM old-len) (- endd begg))
+                        (point)))
 
     ;; Clear all old relevant properties.
     (c-clear-char-property-with-value c-new-BEG c-new-END 'syntax-table '(1))
@@ -926,8 +954,8 @@ Note that the style variables are always made local to the buffer."
          )))))
 
 (defun c-before-change (beg end)
-  ;; Function to be put on `before-change-function'.  Primarily, this calls
-  ;; the language dependent `c-get-state-before-change-function'.  It is
+  ;; Function to be put on `before-change-functions'.  Primarily, this calls
+  ;; the language dependent `c-get-state-before-change-functions'.  It is
   ;; otherwise used only to remove stale entries from the `c-found-types'
   ;; cache, and to record entries which a `c-after-change' function might
   ;; confirm as stale.
@@ -1005,8 +1033,10 @@ Note that the style variables are always made local to the buffer."
        ;; larger than (beg end).
        (setq c-new-BEG beg
              c-new-END end)
-       (if c-get-state-before-change-function
-           (funcall c-get-state-before-change-function beg end))
+       (if c-get-state-before-change-functions
+           (mapc (lambda (fn)
+                   (funcall fn beg end))
+                 c-get-state-before-change-functions))
        ))))
 
 (defun c-after-change (beg end old-len)
@@ -1040,6 +1070,14 @@ Note that the style variables are always made local to the buffer."
          (when (> beg end)
            (setq beg end)))
 
+       ;; C-y is capable of spuriously converting category properties
+       ;; c-</>-as-paren-syntax 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-trim-found-types beg end old-len) ; maybe we don't need all of these.
        (c-invalidate-sws-region-after beg end)
        (c-invalidate-state-cache beg)
@@ -1075,8 +1113,8 @@ This does not load the font-lock package.  Use after
          c-beginning-of-syntax
          (font-lock-mark-block-function
           . c-mark-function)))
-
-  (make-local-hook 'font-lock-mode-hook)
+  (if (featurep 'xemacs)
+      (make-local-hook 'font-lock-mode-hook))
   (add-hook 'font-lock-mode-hook 'c-after-font-lock-init nil t))
 
 (defun c-extend-after-change-region (beg end old-len)