Fix init_buffer for USE_MMAP_FOR_BUFFERS case (backport from trunk)
[bpt/emacs.git] / lisp / face-remap.el
index 956c215..ae74b9d 100644 (file)
@@ -1,9 +1,9 @@
 ;;; face-remap.el --- Functions for managing `face-remapping-alist'
 ;;
-;; Copyright (C) 2008 Free Software Foundation, Inc.
+;; Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 ;;
 ;; Author: Miles Bader <miles@gnu.org>
-;; Keywords: faces face display user commands
+;; Keywords: faces face remapping display user commands
 ;;
 ;; This file is part of GNU Emacs.
 ;;
 ;; ----------------------------------------------------------------
 ;; Utility functions
 
-;;;### autoload
+;; Names of face attributes corresponding to lisp face-vector positions.
+;; This variable should probably be defined in C code where the actual
+;; definitions are available.
+;;
+(defvar internal-lisp-face-attributes
+  [nil
+   :family :foundry :swidth :height :weight :slant :underline :inverse
+   :foreground :background :stipple :overline :strike :box
+   :font :inherit :fontset :vector])
+
+(defun face-attrs-more-relative-p (attrs1 attrs2)
+"Return true if ATTRS1 contains a greater number of relative
+face-attributes than ATTRS2.  A face attribute is considered
+relative if `face-attribute-relative-p' returns non-nil.
+
+ATTRS1 and ATTRS2 may be any value suitable for a `face' text
+property, including face names, lists of face names,
+face-attribute plists, etc.
+
+This function can be used as a predicate with `sort', to sort
+face lists so that more specific faces are located near the end."
+  (unless (vectorp attrs1)
+    (setq attrs1 (face-attributes-as-vector attrs1)))
+  (unless (vectorp attrs2)
+    (setq attrs2 (face-attributes-as-vector attrs2)))
+  (let ((rel1-count 0) (rel2-count 0))
+    (dotimes (i (length attrs1))
+      (let ((attr (aref internal-lisp-face-attributes i)))
+       (when attr
+         (when (face-attribute-relative-p attr (aref attrs1 i))
+           (setq rel1-count (+ rel1-count 1)))
+         (when (face-attribute-relative-p attr (aref attrs2 i))
+           (setq rel2-count (+ rel2-count 1))))))
+    (< rel1-count rel2-count)))
+
+(defun face-remap-order (entry)
+  "Order ENTRY so that more relative face specs are near the beginning.
+The list structure of ENTRY may be destructively modified."
+  (setq entry (nreverse entry))
+  (setcdr entry (sort (cdr entry) 'face-attrs-more-relative-p))
+  (nreverse entry))
+
+;;;###autoload
 (defun face-remap-add-relative (face &rest specs)
   "Add a face remapping entry of FACE to SPECS in the current buffer.
 
@@ -72,18 +114,21 @@ SPECS can be any value suitable for the `face' text property,
 including a face name, a list of face names, or a face-attribute
 property list.  The attributes given by SPECS will be merged with
 any other currently active face remappings of FACE, and with the
-global definition of FACE, with the most recently added relative
-remapping taking precedence.
+global definition of FACE.  An attempt is made to sort multiple
+entries so that entries with relative face-attributes are applied
+after entries with absolute face-attributes.
 
 The base (lowest priority) remapping may be set to a specific
 value, instead of the default of the global face definition,
 using `face-remap-set-base'."
+  (while (and (consp specs) (null (cdr specs)))
+    (setq specs (car specs)))
   (make-local-variable 'face-remapping-alist)
   (let ((entry (assq face face-remapping-alist)))
     (when (null entry)
       (setq entry (list face face))    ; explicitly merge with global def
       (push entry face-remapping-alist))
-    (setcdr entry (cons specs (cdr entry)))
+    (setcdr entry (face-remap-order (cons specs (cdr entry))))
     (cons face specs)))
 
 (defun face-remap-remove-relative (cookie)
@@ -101,7 +146,7 @@ COOKIE should be the return value from that function."
                  (remq remapping face-remapping-alist)))
          (cdr cookie))))))
 
-;;;### autoload
+;;;###autoload
 (defun face-remap-reset-base (face)
   "Set the base remapping of FACE to inherit from FACE's global definition."
   (let ((entry (assq face face-remapping-alist)))
@@ -115,13 +160,15 @@ COOKIE should be the return value from that function."
                (remq entry face-remapping-alist))
        (setcar (last entry) face)))))  ; otherwise, just inherit global def
 
-;;;### autoload
+;;;###autoload
 (defun face-remap-set-base (face &rest specs)
   "Set the base remapping of FACE in the current buffer to SPECS.
 If SPECS is empty, the default base remapping is restored, which
 inherits from the global definition of FACE; note that this is
 different from SPECS containing a single value `nil', which does
 not inherit from the global definition of FACE."
+  (while (and (consp specs) (not (null (car specs))) (null (cdr specs)))
+    (setq specs (car specs)))
   (if (or (null specs)
          (and (eq (car specs) face) (null (cdr specs)))) ; default
       ;; Set entry back to default
@@ -141,7 +188,8 @@ not inherit from the global definition of FACE."
   "Scale factor used by `text-scale-mode'.
 Each positive or negative step scales the default face height by this amount."
   :group 'display
-  :type 'number)
+  :type 'number
+  :version "23.1")
 
 ;; current remapping cookie for text-scale-mode
 (defvar text-scale-mode-remapping nil)
@@ -163,10 +211,10 @@ The amount of scaling is determined by the variable
 face size by the value of the variable `text-scale-mode-step'
 \(a negative amount shrinks the text).
 
-The `text-scale-increase' and `text-scale-decrease' functions may
-be used to interactively modify the variable
-`text-scale-mode-amount' (they also enable or disable
-`text-scale-mode' as necessary)."
+The `text-scale-increase', `text-scale-decrease', and
+`text-scale-set' functions may be used to interactively modify
+the variable `text-scale-mode-amount' (they also enable or
+disable `text-scale-mode' as necessary)."
   :lighter (" " text-scale-mode-lighter)
   (when text-scale-mode-remapping
     (face-remap-remove-relative text-scale-mode-remapping))
@@ -182,7 +230,20 @@ be used to interactively modify the variable
   (force-window-update (current-buffer)))
 
 ;;;###autoload
-(defun text-scale-increase (&optional inc)
+(defun text-scale-set (level)
+  "Set the scale factor of the default face in the current buffer to LEVEL.
+If LEVEL is non-zero, `text-scale-mode' is enabled, otherwise it is disabled.
+
+LEVEL is a number of steps, with 0 representing the default size.
+Each step scales the height of the default face by the variable
+`text-scale-mode-step' (a negative number decreases the height by
+the same amount)."
+  (interactive "p")
+  (setq text-scale-mode-amount level)
+  (text-scale-mode (if (zerop text-scale-mode-amount) -1 1)))
+
+;;;###autoload
+(defun text-scale-increase (inc)
   "Increase the height of the default face in the current buffer by INC steps.
 If the new height is other than the default, `text-scale-mode' is enabled.
 
@@ -191,11 +252,12 @@ Each step scales the height of the default face by the variable
 height by the same amount).  As a special case, an argument of 0
 will remove any scaling currently active."
   (interactive "p")
-  (setq text-scale-mode-amount (if (= inc 0) 0 (+ text-scale-mode-amount inc)))
+  (setq text-scale-mode-amount
+       (if (= inc 0) 0 (+ (if text-scale-mode text-scale-mode-amount 0) inc)))
   (text-scale-mode (if (zerop text-scale-mode-amount) -1 1)))
 
 ;;;###autoload
-(defun text-scale-decrease (&optional dec)
+(defun text-scale-decrease (dec)
   "Decrease the height of the default face in the current buffer by DEC steps.
 See `text-scale-increase' for more details."
   (interactive "p")
@@ -206,7 +268,7 @@ See `text-scale-increase' for more details."
 ;;;###autoload (define-key ctl-x-map [(control ?=)] 'text-scale-adjust)
 ;;;###autoload (define-key ctl-x-map [(control ?0)] 'text-scale-adjust)
 ;;;###autoload
-(defun text-scale-adjust (&optional inc)
+(defun text-scale-adjust (inc)
   "Increase or decrease the height of the default face in the current buffer.
 
 The actual adjustment made depends on the final component of the
@@ -233,7 +295,8 @@ a top-level keymap, `text-scale-increase' or
   (interactive "p")
   (let ((first t)
        (step t)
-       (ev last-command-event))
+       (ev last-command-event)
+       (echo-keystrokes nil))
     (while step
       (let ((base (event-basic-type ev)))
        (cond ((or (eq base ?+) (eq base ?=))
@@ -249,32 +312,114 @@ a top-level keymap, `text-scale-increase' or
       (when step
        (text-scale-increase step)
        (setq inc 1 first nil)
-       (setq ev (read-event))))
+       (setq ev (read-event "+,-,0 for further adjustment: "))))
     (push ev unread-command-events)))
 
 \f
 ;; ----------------------------------------------------------------
-;; variable-pitch-mode
+;; buffer-face-mode
 
-;; suggested key binding: (global-set-key "\C-cv" 'variable-pitch-mode)
+(defcustom buffer-face-mode-face 'variable-pitch
+  "The face specification used by `buffer-face-mode'.
+It may contain any value suitable for a `face' text property,
+including a face name, a list of face names, a face-attribute
+plist, etc."
+  :group 'display
+  :version "23.1")
 
-;; current remapping cookie for  variable-pitch-mode
-(defvar variable-pitch-mode-remapping nil)
-(make-variable-buffer-local 'variable-pitch-mode-remapping)
+;; current remapping cookie for  buffer-face-mode
+(defvar buffer-face-mode-remapping nil)
+(make-variable-buffer-local 'buffer-face-mode-remapping)
 
 ;;;###autoload
-(define-minor-mode variable-pitch-mode
-  "Variable-pitch default-face mode.
-When active, causes the buffer text to be displayed using
-the `variable-pitch' face."
-  :lighter " VarPitch"
-  (when variable-pitch-mode-remapping
-    (face-remap-remove-relative variable-pitch-mode-remapping))
-  (setq variable-pitch-mode-remapping
-       (and variable-pitch-mode
-            (face-remap-add-relative 'default 'variable-pitch)))
+(define-minor-mode buffer-face-mode
+  "Minor mode for a buffer-specific default face.
+When enabled, the face specified by the variable
+`buffer-face-mode-face' is used to display the buffer text."
+  :lighter " BufFace"
+  (when buffer-face-mode-remapping
+    (face-remap-remove-relative buffer-face-mode-remapping))
+  (setq buffer-face-mode-remapping
+       (and buffer-face-mode
+            (face-remap-add-relative 'default buffer-face-mode-face)))
   (force-window-update (current-buffer)))
 
+;;;###autoload
+(defun buffer-face-set (&rest specs)
+  "Enable `buffer-face-mode', using face specs SPECS.
+SPECS can be any value suitable for the `face' text property,
+including a face name, a list of face names, or a face-attribute
+If SPECS is nil, then `buffer-face-mode' is disabled.
+
+This function will make the variable `buffer-face-mode-face'
+buffer local, and set it to FACE."
+  (interactive (list (read-face-name "Set buffer face")))
+  (while (and (consp specs) (null (cdr specs)))
+    (setq specs (car specs)))
+  (if (null specs)
+      (buffer-face-mode 0)
+    (set (make-local-variable 'buffer-face-mode-face) specs)
+    (buffer-face-mode t)))
+
+;;;###autoload
+(defun buffer-face-toggle (&rest specs)
+  "Toggle `buffer-face-mode', using face specs SPECS.
+SPECS can be any value suitable for the `face' text property,
+including a face name, a list of face names, or a face-attribute
+
+If `buffer-face-mode' is already enabled, and is currently using
+the face specs SPECS, then it is disabled; if buffer-face-mode is
+disabled, or is enabled and currently displaying some other face,
+then is left enabled, but the face changed to reflect SPECS.
+
+This function will make the variable `buffer-face-mode-face'
+buffer local, and set it to SPECS."
+  (interactive (list buffer-face-mode-face))
+  (while (and (consp specs) (null (cdr specs)))
+    (setq specs (car specs)))
+  (if (or (null specs)
+         (and buffer-face-mode (equal buffer-face-mode-face specs)))
+      (buffer-face-mode 0)
+    (set (make-local-variable 'buffer-face-mode-face) specs)
+    (buffer-face-mode t)))
+
+(defun buffer-face-mode-invoke (specs arg &optional interactive)
+  "Enable or disable `buffer-face-mode' using face specs SPECS, and argument ARG.
+ARG controls whether the mode is enabled or disabled, and is
+interpreted in the usual manner for minor-mode commands.
+
+SPECS can be any value suitable for the `face' text property,
+including a face name, a list of face names, or a face-attribute
+
+If INTERACTIVE is non-nil, a message will be displayed describing the result.
+
+This is a wrapper function which calls `buffer-face-set' or
+`buffer-face-toggle' (depending on ARG), and prints a status
+message in the echo area.  In many cases one of those functions
+may be more appropriate."
+  (let ((last-message (current-message)))
+    (if (or (eq arg 'toggle) (not arg))
+       (buffer-face-toggle specs)
+      (buffer-face-set (and (> (prefix-numeric-value arg) 0) specs)))
+    (when interactive
+      (unless (and (current-message)
+                  (not (equal last-message (current-message))))
+       (message "Buffer-Face mode %sabled"
+                (if buffer-face-mode "en" "dis"))))))
+
+\f
+;; ----------------------------------------------------------------
+;; variable-pitch-mode
+
+;;;###autoload
+(defun variable-pitch-mode (&optional arg)
+  "Variable-pitch default-face mode.
+An interface to `buffer-face-mode' which uses the `variable-pitch' face.
+Besides the choice of face, it is the same as `buffer-face-mode'."
+  (interactive (list (or current-prefix-arg 'toggle)))
+  (buffer-face-mode-invoke 'variable-pitch arg
+                          (called-interactively-p 'interactive)))
+
 
 (provide 'face-remap)