]> code.delx.au - gnu-emacs/blobdiff - lisp/faces.el
New primitives sxhash-eq, sxhash-eql
[gnu-emacs] / lisp / faces.el
index 511b35412655bc485d37e02f78c76ed0a4372b15..c9cc611a97a1537f38fd8652a91b608897e1e980 100644 (file)
@@ -1,6 +1,6 @@
 ;;; faces.el --- Lisp faces
 
-;; Copyright (C) 1992-1996, 1998-2015 Free Software Foundation, Inc.
+;; Copyright (C) 1992-1996, 1998-2016 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: internal
@@ -276,7 +276,7 @@ If FRAME is omitted or nil, use the selected frame."
 (defun face-list-p (face-or-list)
   "True if FACE-OR-LIST is a list of faces.
 Return nil if FACE-OR-LIST is a non-nil atom, or a cons cell whose car
-is either 'foreground-color, 'background-color, or a keyword."
+is either `foreground-color', `background-color', or a keyword."
   ;; The logic of merge_face_ref (xfaces.c) is recreated here.
   (and (listp face-or-list)
        (not (memq (car face-or-list)
@@ -433,7 +433,7 @@ completely specified)."
 (defun face-attribute-merged-with (attribute value faces &optional frame)
   "Merges ATTRIBUTE, initially VALUE, with faces from FACES until absolute.
 FACES may be either a single face or a list of faces.
-\[This is an internal function.]"
+[This is an internal function.]"
   (cond ((not (face-attribute-relative-p attribute value))
         value)
        ((null faces)
@@ -1005,7 +1005,7 @@ a single face name."
     (setq default (car (split-string default crm-separator t))))
 
   (let ((prompt (if default
-                    (format "%s (default `%s'): " prompt default)
+                    (format-message "%s (default `%s'): " prompt default)
                   (format "%s: " prompt)))
         aliasfaces nonaliasfaces faces)
     ;; Build up the completion tables.
@@ -1136,10 +1136,10 @@ Value is the new attribute value."
   (setq name (concat (upcase (substring name 0 1)) (substring name 1)))
   (let* ((completion-ignore-case t)
         (value (completing-read
-                (if default
-                    (format "%s for face `%s' (default %s): "
-                            name face default)
-                  (format "%s for face `%s': " name face))
+                 (format-message (if default
+                                     "%s for face `%s' (default %s): "
+                                   "%s for face `%s': ")
+                                 name face default)
                 completion-alist nil nil nil nil default)))
     (if (equal value "") default value)))
 
@@ -1224,7 +1224,8 @@ of a global face.  Value is the new attribute value."
   "Read the name of a font for FACE on FRAME.
 If optional argument FRAME is nil or omitted, use the selected frame."
   (let ((completion-ignore-case t))
-    (completing-read (format "Set font attributes of face `%s' from font: " face)
+    (completing-read (format-message
+                      "Set font attributes of face `%s' from font: " face)
                     (append (fontset-list) (x-list-fonts "*" nil frame)))))
 
 
@@ -1435,17 +1436,17 @@ If FRAME is omitted or nil, use the selected frame."
                  (when alias
                    (setq face alias)
                    (insert
-                    (format (substitute-command-keys
-                              "\n  %s is an alias for the face ‘%s’.\n%s")
-                            f alias
-                            (if (setq obsolete (get f 'obsolete-face))
-                                (format (substitute-command-keys
-                                          "  This face is obsolete%s; use ‘%s’ instead.\n")
-                                        (if (stringp obsolete)
-                                            (format " since %s" obsolete)
-                                          "")
-                                        alias)
-                              ""))))
+                    (format-message
+                      "\n  %s is an alias for the face `%s'.\n%s"
+                      f alias
+                      (if (setq obsolete (get f 'obsolete-face))
+                          (format-message
+                           "  This face is obsolete%s; use `%s' instead.\n"
+                           (if (stringp obsolete)
+                               (format " since %s" obsolete)
+                             "")
+                           alias)
+                        ""))))
                  (insert "\nDocumentation:\n"
                           (substitute-command-keys
                            (or (face-documentation face)
@@ -1458,13 +1459,13 @@ If FRAME is omitted or nil, use the selected frame."
                    (help-xref-button 1 'help-customize-face f)))
                (setq file-name (find-lisp-object-file-name f 'defface))
                (when file-name
-                 (princ (substitute-command-keys "Defined in "))
+                 (princ (substitute-command-keys "Defined in `"))
                  (princ (file-name-nondirectory file-name))
-                 (princ (substitute-command-keys ""))
+                 (princ (substitute-command-keys "'"))
                  ;; Make a hyperlink to the library.
                  (save-excursion
                    (re-search-backward
-                     (substitute-command-keys "‘\\([^‘’]+\\)’") nil t)
+                     (substitute-command-keys "`\\([^`']+\\)'") nil t)
                    (help-xref-button 1 'help-face-def f file-name))
                  (princ ".")
                  (terpri)
@@ -1597,6 +1598,13 @@ is given, in which case return its value instead."
          result
        no-match-retval))))
 
+;; When over 80 faces get processed at frame creation time, all but
+;; one specifying all attributes as "unspecified", generating this
+;; list every time means a lot of consing.
+(defconst face--attributes-unspecified
+  (apply 'append
+         (mapcar (lambda (x) (list (car x) 'unspecified))
+                 face-attribute-name-alist)))
 
 (defun face-spec-reset-face (face &optional frame)
   "Reset all attributes of FACE on FRAME to unspecified."
@@ -1621,9 +1629,7 @@ is given, in which case return its value instead."
                                     "unspecified-fg"
                                   "unspecified-bg")))))
           ;; For all other faces, unspecify all attributes.
-          (apply 'append
-                 (mapcar (lambda (x) (list (car x) 'unspecified))
-                         face-attribute-name-alist)))))
+           face--attributes-unspecified)))
 
 (defun face-spec-set (face spec &optional spec-type)
   "Set the face spec SPEC for FACE.
@@ -1786,6 +1792,32 @@ If FRAME is nil, that stands for the selected frame."
     (mapcar 'car (tty-color-alist frame))))
 (defalias 'x-defined-colors 'defined-colors)
 
+(defun defined-colors-with-face-attributes (&optional frame)
+  "Return a list of colors supported for a particular frame.
+See `defined-colors' for arguments and return value. In contrast
+to `define-colors' the elements of the returned list are color
+strings with text properties, that make the color names render
+with the color they represent as background color."
+  (mapcar
+   (lambda (color-name)
+     (let ((foreground (readable-foreground-color color-name))
+          (color      (copy-sequence color-name)))
+       (propertize color 'face (list :foreground foreground
+                                    :background color))))
+   (defined-colors frame)))
+
+(defun readable-foreground-color (color)
+  "Return a readable foreground color for background COLOR."
+  (let* ((rgb   (color-values color))
+        (max   (apply #'max rgb))
+        (black (car (color-values "black")))
+        (white (car (color-values "white"))))
+    ;; Select black or white depending on which one is less similar to
+    ;; the brightest component.
+    (if (> (abs (- max black)) (abs (- max white)))
+       "black"
+      "white")))
+
 (declare-function xw-color-defined-p "xfns.c" (color &optional frame))
 
 (defun color-defined-p (color &optional frame)
@@ -1890,22 +1922,24 @@ resulting color name in the echo area."
         (colors (or facemenu-color-alist
                     (append '("foreground at point" "background at point")
                             (if allow-empty-name '(""))
-                            (defined-colors))))
+                             (if (display-color-p)
+                                 (defined-colors-with-face-attributes)
+                               (defined-colors)))))
         (color (completing-read
                 (or prompt "Color (name or #RGB triplet): ")
                 ;; Completing function for reading colors, accepting
                 ;; both color names and RGB triplets.
                 (lambda (string pred flag)
                   (cond
-                   ((null flag) ; Try completion.
+                   ((null flag)        ; Try completion.
                     (or (try-completion string colors pred)
                         (if (color-defined-p string)
                             string)))
-                   ((eq flag t) ; List all completions.
+                   ((eq flag t)        ; List all completions.
                     (or (all-completions string colors pred)
                         (if (color-defined-p string)
                             (list string))))
-                   ((eq flag 'lambda) ; Test completion.
+                   ((eq flag 'lambda)  ; Test completion.
                     (or (member string colors)
                         (color-defined-p string)))))
                 nil t)))
@@ -1952,39 +1986,44 @@ Return nil if there is no face."
         (delete-dups (nreverse faces))
       (car (last faces)))))
 
-(defun foreground-color-at-point ()
-  "Return the foreground color of the character after point."
+(defun faces--attribute-at-point (attribute &optional attribute-unnamed)
+  "Return the face ATTRIBUTE at point.
+ATTRIBUTE is a keyword.
+If ATTRIBUTE-UNNAMED is non-nil, it is a symbol to look for in
+unnamed faces (e.g, `foreground-color')."
   ;; `face-at-point' alone is not sufficient.  It only gets named faces.
   ;; Need also pick up any face properties that are not associated with named faces.
-  (let ((face (or (face-at-point)
-                 (get-char-property (point) 'read-face-name)
-                 (get-char-property (point) 'face))))
-    (cond ((and face (symbolp face))
-          (let ((value (face-foreground face nil 'default)))
-            (if (member value '("unspecified-fg" "unspecified-bg"))
-                nil
-              value)))
-         ((consp face)
-          (cond ((memq 'foreground-color face) (cdr (memq 'foreground-color face)))
-                ((memq ':foreground face) (cadr (memq ':foreground face)))))
-         (t nil))))                    ; Invalid face value.
+  (let ((faces (or (get-char-property (point) 'read-face-name)
+                   ;; If `font-lock-mode' is on, `font-lock-face' takes precedence.
+                   (and font-lock-mode
+                        (get-char-property (point) 'font-lock-face))
+                   (get-char-property (point) 'face)))
+        (found nil))
+    (dolist (face (if (face-list-p faces)
+                      faces
+                    (list faces)))
+      (cond (found)
+            ((and face (symbolp face))
+             (let ((value (face-attribute-specified-or
+                           (face-attribute face attribute nil t)
+                           nil)))
+               (unless (member value '(nil "unspecified-fg" "unspecified-bg"))
+                 (setq found value))))
+            ((consp face)
+             (setq found (cond ((and attribute-unnamed
+                                     (memq attribute-unnamed face))
+                                (cdr (memq attribute-unnamed face)))
+                               ((memq attribute face) (cadr (memq attribute face))))))))
+    (or found
+        (face-attribute 'default attribute))))
+
+(defun foreground-color-at-point ()
+  "Return the foreground color of the character after point."
+  (faces--attribute-at-point :foreground 'foreground-color))
 
 (defun background-color-at-point ()
   "Return the background color of the character after point."
-  ;; `face-at-point' alone is not sufficient.  It only gets named faces.
-  ;; Need also pick up any face properties that are not associated with named faces.
-  (let ((face (or (face-at-point)
-                 (get-char-property (point) 'read-face-name)
-                 (get-char-property (point) 'face))))
-    (cond ((and face (symbolp face))
-          (let ((value (face-background face nil 'default)))
-            (if (member value '("unspecified-fg" "unspecified-bg"))
-                nil
-              value)))
-         ((consp face)
-          (cond ((memq 'background-color face) (cdr (memq 'background-color face)))
-                ((memq ':background face) (cadr (memq ':background face)))))
-         (t nil))))                    ; Invalid face value.
+  (faces--attribute-at-point :background 'background-color))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2659,6 +2698,13 @@ It is used for characters of no fonts too."
   :version "24.1"
   :group 'basic-faces)
 
+(defface read-multiple-choice-face
+  '((t (:inherit underline
+        :weight bold)))
+  "Face for the symbol name in Apropos output."
+  :group 'basic-faces
+  :version "25.2")
+
 ;; Faces for TTY menus.
 (defface tty-menu-enabled-face
   '((t
@@ -2690,10 +2736,12 @@ It is used for characters of no fonts too."
      :background "turquoise")          ; looks OK on tty (becomes cyan)
     (((class color) (background dark))
      :background "steelblue3")         ; looks OK on tty (becomes blue)
-    (((background dark))
+    (((background dark) (min-colors 4))
      :background "grey50")
+    (((background light) (min-colors 4))
+     :background "gray")
     (t
-     :background "gray"))
+     :inherit underline))
   "Face used for a matching paren."
   :group 'paren-showing-faces)