Mercurial > hg > xemacs-beta
diff lisp/utils/facemenu.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | bcdc7deadc19 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/utils/facemenu.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,773 @@ +;;; facemenu.el --- create a face menu for interactively adding fonts to text +;; Copyright (c) 1994, 1995 Free Software Foundation, Inc. + +;; XEmacs version: Mike Sperber <sperber@informatik.uni-tuebingen.de> +;; Original author: Boris Goldowsky <boris@gnu.ai.mit.edu> +;; Keywords: faces + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Synched up with: FSF 19.30. + +;;; Commentary: +;; This file defines a menu of faces (bold, italic, etc) which allows you to +;; set the face used for a region of the buffer. Some faces also have +;; keybindings, which are shown in the menu. Faces with names beginning with +;; "fg:" or "bg:", as in "fg:red", are treated specially. +;; Such faces are assumed to consist only of a foreground (if "fg:") or +;; background (if "bg:") color. They are thus put into the color submenus +;; rather than the general Face submenu. These faces can also be +;; automatically created by selecting the "Other..." menu items in the +;; "Foreground" and "Background" submenus. +;; +;; The menu also contains submenus for indentation and justification-changing +;; commands. + +;;; Installation: +;; Just do a (require 'facemenu). +;; If you want the menu bound to a mouse button under XEmacs, do +;; (define-key global-map '(control button2) 'facemenu-menu) + +;;; Usage: +;; Selecting a face from the menu or typing the keyboard equivalent will +;; change the region to use that face. If you use transient-mark-mode and the +;; region is not active, the face will be remembered and used for the next +;; insertion. It will be forgotten if you move point or make other +;; modifications before inserting or typing anything. +;; +;; Faces can be selected from the keyboard as well. +;; The standard keybindings are M-g (or ESC g) + letter: +;; M-g i = "set italic", M-g b = "set bold", etc. + +;; +;; The order of the faces that appear in the menu and their keybindings can be +;; controlled by setting the variables `facemenu-keybindings' and +;; `facemenu-new-faces-at-end'. List faces that you don't use in documents +;; (eg, `region') in `facemenu-unlisted-faces'. + +;;; Known Problems: +;; Bold and Italic do not combine to create bold-italic if you select them +;; both, although most other combinations (eg bold + underline + some color) +;; do the intuitive thing. +;; +;; There is at present no way to display what the faces look like in +;; the menu itself. +;; +;; `list-faces-display' shows the faces in a different order than +;; this menu, which could be confusing. I do /not/ sort the list +;; alphabetically, because I like the default order: it puts the most +;; basic, common fonts first. +;; +;; Please send me any other problems, comments or ideas. + +;;; Code: + +(provide 'facemenu) + +(require 'easymenu) + +;;; Provide some binding for startup: +;;; XEmacs -- goto-line is a *much* better binding for M-g. +;;;dont ###autoload (define-key global-map "\M-g" 'facemenu-keymap) + +(defvar facemenu-key "\M-g" + "Prefix key to use for facemenu commands.") + +(defvar facemenu-keybindings + '((default . "d") + (bold . "b") + (italic . "i") + (bold-italic . "l") ; {bold} intersect {italic} = {l} + (underline . "u")) + "Alist of interesting faces and keybindings. +Each element is itself a list: the car is the name of the face, +the next element is the key to use as a keyboard equivalent of the menu item; +the binding is made in facemenu-keymap. + +The faces specifically mentioned in this list are put at the top of +the menu, in the order specified. All other faces which are defined, +except for those in `facemenu-unlisted-faces', are listed after them, +but get no keyboard equivalents. + +If you change this variable after loading facemenu.el, you will need to call +`facemenu-update' to make it take effect.") + +(defvar facemenu-new-faces-at-end t + "Where in the menu to insert newly-created faces. +This should be nil to put them at the top of the menu, or t to put them +just before \"Other\" at the end.") + +(defvar facemenu-unlisted-faces + '(modeline region secondary-selection highlight scratch-face + gui-button-face isearch hyperlink + modeline modeline-buffer-id modeline-mousable modeline-mousable-minor-mode + pointer primary-selection secondary-selection list-mode-item-selected + text-cursor zmacs-region + left-margin right-margin) + "List of faces not to include in the Face menu. +You can set this list before loading facemenu.el, or add a face to it before +creating that face if you do not want it to be listed. If you change the +variable so as to eliminate faces that have already been added to the menu, +call `facemenu-update' to recalculate the menu contents. + +If this variable is t, no faces will be added to the menu. This is useful for +temporarily turning off the feature that automatically adds faces to the menu +when they are created.") + +(defvar facemenu-relevant-face-attributes + '(foreground background font underline highlight dim blinking reverse) + "List of face attributes that facemenu fiddles with. +This is only relevant for XEmacs.") + +(easy-menu-define facemenu-face-menu () + "Menu for faces" + `("Face" + ["Other..." facemenu-set-face t])) + +(easy-menu-define facemenu-foreground-menu () + "Menu for foreground colors" + `("Foreground Color" + ["Other..." facemenu-set-foreground t])) + +(easy-menu-define facemenu-background-menu () + "Menu for background colors" + `("Background Color" + ["Other..." facemenu-set-background t])) + +(easy-menu-define facemenu-size-menu () + "Menu for font sizes." + '("Size" + ["Default" facemenu-set-size-default t] + ["Bigger" facemenu-make-larger t] + ["Smaller" facemenu-make-smaller t] + ["Much Bigger" facemenu-make-much-larger t] + ["Much Smaller" facemenu-make-much-smaller t])) + +(easy-menu-define facemenu-special-menu () + "Menu for non-face text-properties." + '("Special" + ["Read-Only" facemenu-set-read-only t] + ["Invisible" facemenu-set-invisible t] + ["Intangible" facemenu-set-intangible t] + ["Remove Special" facemenu-remove-special t])) + +(easy-menu-define facemenu-justification-menu () + "Menu for text justification commands." + '("Justification" + ["Center" set-justification-center t] + ["Full" set-justification-full t] + ["Right" set-justification-right t] + ["Unfilled" set-justification-none t])) + +(easy-menu-define facemenu-indentation-menu + () + "Submenu for indentation commands." + '("Indentation" + ["Indent More" increase-left-margin t] + ["Indent Less" decrease-left-margin t] + ["Indent Right More" increase-right-margin t] + ["Indent Right Less" decrease-right-margin t])) + +;;;###autoload +(defvar facemenu-menu nil + "Facemenu top-level menu keymap.") + +(defun facemenu-update-facemenu-menu () + (easy-menu-define facemenu-menu () + "Facemenu top-level menu" + (list "Text Properties" + facemenu-face-menu + facemenu-foreground-menu + facemenu-background-menu + facemenu-size-menu + facemenu-special-menu + "---" + facemenu-justification-menu + facemenu-indentation-menu + "---" + ["Remove Properties" facemenu-remove-props t] + ["List Properties" list-text-properties-at t] + ["Display Faces" list-faces-display t] + ["Display Colors" list-colors-display t]))) + +;;;###autoload +(defvar facemenu-keymap + (let ((map (make-sparse-keymap "Set face"))) + (define-key map ?o 'facemenu-set-face) + map) + "Keymap for face-changing commands. +`Facemenu-update' fills in the keymap according to the bindings +requested in `facemenu-keybindings'.") +(defalias 'facemenu-keymap facemenu-keymap) + +;;; Internal Variables + +(defvar facemenu-color-alist nil + ;; Don't initialize here; that doesn't work if preloaded. + "Alist of colors, used for completion. +If null, `facemenu-read-color' will set it.") + +(defun facemenu-update () + "Add or update the \"Face\" menu in the menu bar. +You can call this to update things if you change any of the menu configuration +variables." + (interactive) + + ;; Add each defined face to the menu. + (facemenu-iterate 'facemenu-add-new-face + (facemenu-complete-face-list facemenu-keybindings)) + (facemenu-update-facemenu-menu) + + ;; Global bindings: + (if (string-match "XEmacs" emacs-version) + (easy-menu-change '("Edit") (car facemenu-menu) (cdr facemenu-menu)) + (define-key global-map [C-down-mouse-2] 'facemenu-menu)) + (if facemenu-key (define-key global-map facemenu-key 'facemenu-keymap))) + +(fset 'facemenu-region-active-p + (if (string-match "XEmacs" emacs-version) + 'region-active-p + #'(lambda () + mark-active))) + +;;;###autoload +(defun facemenu-set-face (face &optional start end) + "Add FACE to the region or next character typed. +It will be added to the top of the face list; any faces lower on the list that +will not show through at all will be removed. + +Interactively, the face to be used is read with the minibuffer. + +If the region is active and there is no prefix argument, +this command sets the region to the requested face. + +Otherwise, this command specifies the face for the next character +inserted. Moving point or switching buffers before +typing a character to insert cancels the specification." + (interactive (list (read-face-name "Use face: "))) + (setq zmacs-region-stays t) + (barf-if-buffer-read-only) + (facemenu-add-new-face face) + (facemenu-update-facemenu-menu) + (if (and (facemenu-region-active-p) + (not current-prefix-arg)) + (let ((start (or start (region-beginning))) + (end (or end (region-end)))) + (facemenu-add-face face start end)) + (facemenu-self-insert-face face))) + +;;;###autoload +(defun facemenu-set-foreground (color &optional start end) + "Set the foreground color of the region or next character typed. +The color is prompted for. A face named `fg:color' is used \(or created). +If the region is active, it will be set to the requested face. If +it is inactive \(even if mark-even-if-inactive is set) the next +character that is typed \(via `self-insert-command') will be set to +the selected face. Moving point or switching buffers before +typing a character cancels the request." + (interactive (list (facemenu-read-color "Foreground color: "))) + (setq zmacs-region-stays t) + (let ((face (intern (concat "fg:" color)))) + (or (facemenu-get-face face) + (error "Unknown color: %s" color)) + (facemenu-set-face face start end))) + +;;;###autoload +(defun facemenu-set-background (color &optional start end) + "Set the background color of the region or next character typed. +The color is prompted for. A face named `bg:color' is used \(or created). +If the region is active, it will be set to the requested face. If +it is inactive \(even if mark-even-if-inactive is set) the next +character that is typed \(via `self-insert-command') will be set to +the selected face. Moving point or switching buffers before +typing a character cancels the request." + (interactive (list (facemenu-read-color "Background color: "))) + (setq zmacs-region-stays t) + (let ((face (intern (concat "bg:" color)))) + (or (facemenu-get-face face) + (error "Unknown color: %s" color)) + (facemenu-set-face face start end))) + +;;;###autoload +(defun facemenu-set-face-from-menu (face) + "Set the face of the region or next character typed. +This function is designed to be called from a menu; the face to use +is the menu item's name. + +If the region is active and there is no prefix argument, +this command sets the region to the requested face. + +Otherwise, this command specifies the face for the next character +inserted. Moving point or switching buffers before +typing a character to insert cancels the specification." + (let ((start (if (and (facemenu-region-active-p) + (not current-prefix-arg)) + (region-beginning))) + (end (if (and (facemenu-region-active-p) + (not current-prefix-arg)) + (region-end)))) + (barf-if-buffer-read-only) + (setq zmacs-region-stays t) + (facemenu-get-face face) + (if start + (facemenu-add-face face start end) + (facemenu-self-insert-face face)))) + +(defun facemenu-self-insert-face (face) + (setq self-insert-face (cond + ((null self-insert-face) face) + ((consp self-insert-face) + (facemenu-active-faces (cons face self-insert-face))) + (t + (facemenu-active-faces (list face self-insert-face)))) + self-insert-face-command this-command)) + +(defun facemenu-face-strip-size (face) + "Create a symbol from the name of FACE devoid of size information, +i.e. remove all larger- and smaller- prefixes." + (let* ((face-symbol (face-name face)) + (face-name (symbol-name face-symbol)) + (old-name face-name) + new-name) + (while + (not (string-equal + old-name + (setq new-name (replace-in-string old-name "^larger-" "")))) + (setq old-name new-name)) + + (while + (not (string-equal + old-name + (setq new-name (replace-in-string old-name "^smaller-" "")))) + (setq old-name new-name)) + + (if (string-equal new-name face-name) + face-symbol + (intern new-name)))) + +(defun facemenu-face-default-size (face) + (cond ((null face) nil) + ((consp face) (mapcar 'facemenu-face-strip-size face)) + (t (facemenu-face-strip-size face)))) + +;;;###autoload +(defun facemenu-set-size-default (start end) + (interactive "_r") + (put-text-property start end 'size nil) + (alter-text-property start end 'face 'facemenu-face-default-size)) + +(defun facemenu-ensure-size-property (start end) + "Ensure that the text between START and END has a 'size text property. +If it is not present, it is set to 0." + (let ((start start) + pos bound) + (while (setq pos (text-property-any start end 'size nil)) + (setq bound (or (text-property-not-all pos end 'size nil) end)) + (put-text-property pos bound 'size 0)))) + +(defun facemenu-sized-face (face size) + "Make a face FACE larger or smaller according to SIZE. +If SIZE is positive, it calls `make-face-larger' SIZE times, +else it calls `make-face-smaller' -SIZE times." + (if (zerop size) + face + (let ((name (symbol-name face)) + (measure size) + (change-face 'make-face-larger)) + + (if (> measure 0) + (setq prefix "larger-") + (setq prefix "smaller-") + (setq measure (- measure)) + (setq size (- size)) + (setq change-face 'make-face-smaller)) + + (while (not (zerop measure)) + (setq name (concat prefix name)) + (setq measure (1- measure))) + + (let ((symbol (intern name))) + (or (find-face symbol) + (let ((face (copy-face face symbol))) + (while (not (zerop size)) + (funcall change-face face) + (setq size (1- size))) + face)))))) + +(defun facemenu-adjust-face-sizes (face) + (cond + ((null face) (facemenu-sized-face 'default size)) + ((consp face) (mapcar + #'(lambda (face) + (facemenu-sized-face (facemenu-face-strip-size face) + size)) + face)) + (t (facemenu-sized-face face size)))) + +(defun facemenu-adjust-size (from to) + "Adjust the size of the text between FROM and TO according +to the values of the 'size property in that region." + (let ((pos from) + bound size) + (while (< pos to) + (setq size (get-text-property pos 'size)) + (setq bound (or (text-property-not-all pos to 'size size) to)) + (alter-text-property pos bound 'face 'facemenu-adjust-face-sizes) + (setq pos bound)))) + +(defun facemenu-change-size (from to f) + (facemenu-ensure-size-property from to) + (alter-text-property from to 'size f) + (facemenu-adjust-size from to)) + +;;;###autoload +(defun facemenu-make-larger (from to) + (interactive "_r") + (facemenu-change-size from to '1+)) + +;;;###autoload +(defun facemenu-make-smaller (from to) + (interactive "_r") + (facemenu-change-size from to '1-)) + +;;;###autoload +(defun facemenu-make-much-larger (from to) + (interactive "_r") + (facemenu-change-size from to #'(lambda (s) (+ 5 s)))) + +;;;###autoload +(defun facemenu-make-much-smaller (from to) + (interactive "_r") + (facemenu-change-size from to #'(lambda (s) (- s 5)))) + +;;;###autoload +(defun facemenu-set-invisible (start end) + "Make the region invisible. +This sets the `invisible' text property; it can be undone with +`facemenu-remove-special'." + (interactive "r") + (put-text-property start end 'invisible t)) + +;;;###autoload +(defun facemenu-set-intangible (start end) + "Make the region intangible: disallow moving into it. +This sets the `intangible' text property; it can be undone with +`facemenu-remove-special'." + (interactive "r") + (put-text-property start end 'intangible t)) + +;;;###autoload +(defun facemenu-set-read-only (start end) + "Make the region unmodifiable. +This sets the `read-only' text property; it can be undone with +`facemenu-remove-special'." + (interactive "r") + (put-text-property start end 'read-only t)) + +;;;###autoload +(defun facemenu-remove-props (start end) + "Remove all text properties that facemenu added to region." + (interactive "*_r") ; error if buffer is read-only despite the next line. + (let ((inhibit-read-only t)) + (remove-text-properties + start end '(face nil invisible nil intangible nil + read-only nil category nil size nil)))) + +;;;###autoload +(defun facemenu-remove-special (start end) + "Remove all the \"special\" text properties from the region. +These special properties include `invisible', `intangible' and `read-only'." + (interactive "*_r") ; error if buffer is read-only despite the next line. + (let ((inhibit-read-only t)) + (remove-text-properties + start end '(invisible nil intangible nil read-only nil)))) + +;;;###autoload +(defun list-text-properties-at (p) + "Pop up a buffer listing text-properties at LOCATION." + (interactive "d") + (let ((props (text-properties-at p))) + (if (null props) + (message "None") + (with-output-to-temp-buffer "*Text Properties*" + (princ (format "Text properties at %d:\n\n" p)) + (while props + (princ (format "%-20s %S\n" + (car props) (car (cdr props)))) + (setq props (cdr (cdr props)))))))) + +;;;###autoload +(defun facemenu-read-color (&optional prompt) + "Read a color using the minibuffer." + (if (string-match "XEmacs" emacs-version) + (read-color prompt) + (let ((col (completing-read + (or prompt "Color: ") + (or facemenu-color-alist + (if (or (eq window-system 'x) (eq window-system 'win32)) + (mapcar 'list (x-defined-colors)))) + nil t))) + (if (equal "" col) + nil + col)))) + +(defun facemenu-canonicalize-color (c) + (downcase (replace-in-string c " " ""))) + +(defun facemenu-unique (list) + "Uniquify LIST, deleting elements using `delete'. +Return the list with subsequent duplicate items removed by side effects." + (let ((list list)) + (while list + (setq list (setcdr list (delete (car list) (cdr list)))))) + list) + +;;;###autoload +(defun list-colors-display (&optional list) + "Display names of defined colors, and show what they look like. +If the optional argument LIST is non-nil, it should be a list of +colors to display. Otherwise, this command computes a list +of colors that the current display can handle." + (interactive) + (if (string-match "XEmacs" emacs-version) + (setq list + (facemenu-unique + (mapcar 'facemenu-canonicalize-color + (mapcar 'car (read-color-completion-table))))) + (if (and (null list) (or (eq window-system 'x) (eq window-system 'win32))) + (progn + (setq list (x-defined-colors)) + ;; Delete duplicate colors. + (let ((l list)) + (while (cdr l) + (if (facemenu-color-equal (car l) (car (cdr l))) + (setcdr l (cdr (cdr l))) + (setq l (cdr l)))))))) + (with-output-to-temp-buffer "*Colors*" + (save-excursion + (set-buffer standard-output) + (let ((facemenu-unlisted-faces t) + s) + (while list + (if (not (string-match "[0-9]" (car list))) + (progn + (setq s (point)) + (insert (car list)) + (indent-to 20) + (put-text-property s (point) 'face + (facemenu-get-face + (intern (concat "bg:" (car list))))) + (setq s (point)) + (insert " " (car list) "\n") + (put-text-property s (point) 'face + (facemenu-get-face + (intern (concat "fg:" (car list))))))) + (setq list (cdr list))))))) + +(fset 'facemenu-color-values + (if (fboundp 'x-color-values) + 'x-color-values + #'(lambda (color) + (color-instance-rgb-components + (make-color-instance color))))) + +(defun facemenu-color-equal (a b) + "Return t if colors A and B are the same color. +A and B should be strings naming colors. +This function queries the window-system server to find out what the +color names mean. It returns nil if the colors differ or if it can't +determine the correct answer." + (cond ((equal a b) t) + ((and (equal (facemenu-color-values a) + (facemenu-color-values b)))))) + +(defun facemenu-add-face (face start end) + "Add FACE to text between START and END. +For each section of that region that has a different face property, FACE will +be consed onto it, and other faces that are completely hidden by that will be +removed from the list. + +As a special case, if FACE is `default', then the region is left with NO face +text property. Otherwise, selecting the default face would not have any +effect." + (interactive "*_xFace:\nr") + (if (eq face 'default) + (remove-text-properties start end '(face default)) + (let ((part-start start) part-end) + (while (not (= part-start end)) + (setq part-end (next-single-property-change part-start 'face nil end)) + (let* ((prev (get-text-property part-start 'face)) + (size (get-text-property part-start 'size)) + (face (if size (facemenu-sized-face face size) face))) + (put-text-property part-start part-end 'face + (if (null prev) + face + (facemenu-active-faces + (cons face + (if (listp prev) prev (list prev))))))) + (setq part-start part-end))))) + +(defun facemenu-face-attributes (face) + "Create a vector of the relevant face attributes of face FACE." + (if (string-match "XEmacs" emacs-version) + (apply 'vector (mapcar #'(lambda (prop) + (face-property-instance face prop)) + facemenu-relevant-face-attributes)) + (internal-get-face (car face-list)))) + +(defun facemenu-active-faces (face-list) + "Return from FACE-LIST those faces that would be used for display. +This means each face attribute is not specified in a face earlier in FACE-LIST +and such a face is therefore active when used to display text." + (let* ((mask-atts (copy-sequence (facemenu-face-attributes (car face-list)))) + (default-atts (facemenu-face-attributes 'default)) + (active-list (list (car face-list))) + (face-list (cdr face-list)) + (mask-len (length mask-atts))) + (while face-list + (if (let ((face-atts (facemenu-face-attributes (car face-list))) + (i mask-len) + (useful nil)) + (while (>= (setq i (1- i)) 0) + (if (and (aref face-atts i) + (or (not (aref mask-atts i)) + (eq (aref mask-atts i) (aref default-atts i))) + (not (eq (aref face-atts i) (aref default-atts i)))) + (aset mask-atts i (setq useful t)))) + useful) + (setq active-list (cons (car face-list) active-list))) + (setq face-list (cdr face-list))) + (nreverse active-list))) + +(fset 'facemenu-find-face + (if (string-match "XEmacs" emacs-version) + 'find-face + 'internal-find-face)) + +(fset 'facemenu-color-defined-p + (if (string-match "XEmacs" emacs-version) + #'(lambda (c) + (color-instance-p (make-color-instance c nil t))) + #'(lambda (c) + (and (or (eq window-system 'x) (eq window-system 'win32)) + (x-color-defined-p color))))) + +(defun facemenu-get-face (symbol) + "Make sure FACE exists. +If not, it is created. If it is created and is of the form `fg:color', then +set the foreground to that color. If of the form `bg:color', set the +background. In any case, add it to the appropriate menu. Returns the face, +or nil if given a bad color." + (if (or (facemenu-find-face symbol) + (let* ((face (make-face symbol)) + (name (symbol-name symbol)) + (color-name (substring name 3)) + (color (if (string-match "XEmacs" emacs-version) + (make-color-specifier color-name) + color-name))) + (facemenu-add-new-face symbol) + (cond ((string-match "^fg:" name) + (set-face-foreground face color) + (facemenu-color-defined-p color-name)) + ((string-match "^bg:" name) + (set-face-background face color) + (facemenu-color-defined-p color-name)) + (t)))) + symbol)) + +(defun facemenu-menu-has-face (menu face-name) + "Check if menu MENU has an entry for face named by string FACE-NAME. +Returns entry if successful." + (facemenu-iterate + #'(lambda (m) + (and (vectorp m) + (string-equal face-name (aref m 0)) + m)) + (cdr menu))) + +(defun facemenu-insert-menu-entry (menu before-entry name function) + "Insert menu item with name NAME and associated function FUNCTION +into menu MENU before entry BEFORE-ENTRY." + (while (not (eq (cadr menu) before-entry)) + (setq menu (cdr menu))) + (setcdr menu (cons (vector name function t) (cdr menu)))) + +(defun facemenu-add-new-face (face) + "Add a FACE to the appropriate Face menu. +Automatically called when a new face is created." + (let* ((name (symbol-name face)) + (menu (cond ((string-match "^fg:" name) + (setq name (substring name 3)) + 'facemenu-foreground-menu) + ((string-match "^bg:" name) + (setq name (substring name 3)) + 'facemenu-background-menu) + (t 'facemenu-face-menu))) + (menu-value (symbol-value menu)) + (key (cdr (assoc face facemenu-keybindings)))) + (cond ((eq t facemenu-unlisted-faces)) + ((string-match "^larger-" name)) + ((string-match "^smaller-" name)) + ((memq face facemenu-unlisted-faces)) + (key ; has a keyboard equivalent. These go at the front. + (let ((function (intern (concat "facemenu-set-" name)))) + (fset function + (` (lambda () + (interactive "_") + (facemenu-set-face (quote (, face)))))) + (define-key 'facemenu-keymap key function) + (if (not (facemenu-menu-has-face menu-value name)) + (set menu + (cons (car menu-value) + (cons (vector name function t) + (cdr menu-value))))))) + ((facemenu-menu-has-face menu-value name)) + (t ; No keyboard equivalent. Figure out where to put it: + (let ((before-entry + (or (and facemenu-new-faces-at-end + (facemenu-menu-has-face menu-value "Other...")) + (cadr menu-value)))) + (facemenu-insert-menu-entry + menu-value before-entry name + (` (facemenu-set-face (quote (, face))))))))) + nil) ; Return nil for facemenu-iterate + +(defun facemenu-complete-face-list (&optional oldlist) + "Return list of all faces that look different. +Starts with given ALIST of faces, and adds elements only if they display +differently from any face already on the list. +The faces on ALIST will end up at the end of the returned list, in reverse +order." + (let ((list (nreverse (mapcar 'car oldlist)))) + (facemenu-iterate + (lambda (new-face) + (if (not (memq new-face list)) + (setq list (cons new-face list))) + nil) + (nreverse (face-list))) + list)) + +(defun facemenu-iterate (func iterate-list) + "Apply FUNC to each element of LIST until one returns non-nil. +Returns the non-nil value it found, or nil if all were nil." + (while (and iterate-list (not (funcall func (car iterate-list)))) + (setq iterate-list (cdr iterate-list))) + (car iterate-list)) + +(facemenu-update) + +;;; facemenu.el ends here