+;;;###autoload
+(defun list-text-properties-at (p)
+ "Pop up a buffer listing text-properties at LOCATION."
+ (interactive "d")
+ (let ((props (text-properties-at p))
+ category
+ str)
+ (if (null props)
+ (message "None")
+ (if (and (not (cdr (cdr props)))
+ (not (eq (car props) 'category))
+ (< (length (setq str (format "Text property at %d: %s %S"
+ p (car props) (car (cdr props)))))
+ (frame-width)))
+ (message "%s" str)
+ (with-output-to-temp-buffer "*Text Properties*"
+ (princ (format "Text properties at %d:\n\n" p))
+ (while props
+ (if (eq (car props) 'category)
+ (setq category (car (cdr props))))
+ (princ (format "%-20s %S\n"
+ (car props) (car (cdr props))))
+ (setq props (cdr (cdr props))))
+ (if category
+ (progn
+ (setq props (symbol-plist category))
+ (princ (format "\nCategory %s:\n\n" category))
+ (while props
+ (princ (format "%-20s %S\n"
+ (car props) (car (cdr props))))
+ (if (eq (car props) 'category)
+ (setq category (car (cdr props))))
+ (setq props (cdr (cdr props)))))))))))
+
+;;;###autoload
+(defun facemenu-read-color (&optional prompt)
+ "Read a color using the minibuffer."
+ (let ((col (completing-read (or prompt "Color: ")
+ (or facemenu-color-alist
+ (if window-system
+ (mapcar 'list (x-defined-colors))))
+ nil t)))
+ (if (equal "" col)
+ nil
+ col)))
+
+;;;###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 (and (null list) window-system)
+ (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 (s)
+ (while list
+ (setq s (point))
+ (insert (car list))
+ (indent-to 20)
+ (put-text-property s (point) 'face
+ (cons 'background-color (car list)))
+ (setq s (point))
+ (insert " " (car list) "\n")
+ (put-text-property s (point) 'face
+ (cons 'foreground-color (car list)))
+ (setq list (cdr list)))))))
+
+(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 (memq window-system '(x w32))
+ (equal (x-color-values a) (x-color-values b))))
+ ((eq window-system 'pc)
+ (and (x-color-defined-p a) (x-color-defined-p b)
+ (eq (msdos-color-translate a) (msdos-color-translate b))))))
+
+(defun facemenu-add-face (face &optional start end)
+ "Add FACE to text between START and END.
+If START is `nil' or START to END is empty, add FACE to next typed character
+instead. 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.
+If `facemenu-add-face-function' and maybe `facemenu-end-add-face' are non-`nil'
+they are used to set the face information.
+
+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. See `facemenu-remove-face-function'."
+ (interactive "*xFace: \nr")
+ (if (and (eq face 'default)
+ (not (eq facemenu-remove-face-function t)))
+ (if facemenu-remove-face-function
+ (funcall facemenu-remove-face-function start end)
+ (if (and start (< start end))
+ (remove-text-properties start end '(face default))
+ (setq self-insert-face 'default
+ self-insert-face-command this-command)))
+ (if facemenu-add-face-function
+ (save-excursion
+ (if end (goto-char end))
+ (save-excursion
+ (if start (goto-char start))
+ (insert-before-markers
+ (funcall facemenu-add-face-function face end)))
+ (if facemenu-end-add-face
+ (insert (if (stringp facemenu-end-add-face)
+ facemenu-end-add-face
+ (funcall facemenu-end-add-face face)))))
+ (if (and start (< start end))
+ (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)))
+ (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)))
+ (setq self-insert-face (if (eq last-command self-insert-face-command)
+ (cons face (if (listp self-insert-face)
+ self-insert-face
+ (list self-insert-face)))
+ face)
+ self-insert-face-command this-command)))))
+
+(defun facemenu-active-faces (face-list &optional frame)
+ "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.
+If the optional argument FRAME is given, use the faces in that frame; otherwise
+use the selected frame. If t, then the global, non-frame faces are used."
+ (let* ((mask-atts (copy-sequence (internal-get-face (car face-list) frame)))
+ (active-list (list (car face-list)))
+ (face-list (cdr face-list))
+ (mask-len (length mask-atts)))
+ (while face-list
+ (if (let ((face-atts (internal-get-face (car face-list) frame))
+ (i mask-len) (useful nil))
+ (while (> (setq i (1- i)) 1)
+ (and (aref face-atts i) (not (aref mask-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)))
+
+(defun facemenu-get-face (symbol)
+ "Make sure FACE exists.
+If not, create it and add it to the appropriate menu. Return the symbol.
+
+If a window system is in use, and this function creates a face named
+`fg:color', then it sets the foreground to that color. Likewise, `bg:color'
+means to set the background. In either case, if the color is undefined,
+no color is set and a warning is issued."
+ (let ((name (symbol-name symbol))
+ foreground)
+ (cond ((internal-find-face symbol))
+ ((and window-system
+ (or (setq foreground (string-match "^fg:" name))
+ (string-match "^bg:" name)))
+ (let ((face (make-face symbol))
+ (color (substring name 3)))
+ (if (x-color-defined-p color)
+ (if foreground
+ (set-face-foreground face color)
+ (set-face-background face color))
+ (message "Color \"%s\" undefined" color))))
+ (t (make-face symbol))))
+ symbol)
+
+(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 docstring
+ (key (cdr (assoc face facemenu-keybindings)))
+ function menu-val)
+ (cond ((string-match "^fg:" name)
+ (setq name (substring name 3))
+ (setq docstring
+ (format "Select foreground color %s for subsequent insertion."
+ name))
+ (setq menu 'facemenu-foreground-menu))
+ ((string-match "^bg:" name)
+ (setq name (substring name 3))
+ (setq docstring
+ (format "Select background color %s for subsequent insertion."
+ name))
+ (setq menu 'facemenu-background-menu))
+ (t
+ (setq docstring
+ (format "Select face `%s' for subsequent insertion."
+ name))
+ (setq menu 'facemenu-face-menu)))
+ (cond ((eq t facemenu-unlisted-faces))
+ ((memq face facemenu-unlisted-faces))
+ ;; test against regexps in facemenu-unlisted-faces
+ ((let ((unlisted facemenu-unlisted-faces)
+ (matched nil))
+ (while (and unlisted (not matched))
+ (if (and (stringp (car unlisted))
+ (string-match (car unlisted) name))
+ (setq matched t)
+ (setq unlisted (cdr unlisted))))
+ matched))
+ (key ; has a keyboard equivalent. These go at the front.
+ (setq function (intern (concat "facemenu-set-" name)))
+ (fset function
+ `(lambda ()
+ ,docstring
+ (interactive)
+ (facemenu-set-face (quote ,face))))
+ (define-key 'facemenu-keymap key (cons name function))
+ (define-key menu key (cons name function)))
+ ((facemenu-iterate ; check if equivalent face is already in the menu
+ (lambda (m) (and (listp m)
+ (symbolp (car m))
+ (face-equal (car m) face)))
+ (cdr (symbol-function menu))))
+ (t ; No keyboard equivalent. Figure out where to put it:
+ (setq key (vector face)
+ function 'facemenu-set-face-from-menu
+ menu-val (symbol-function menu))
+ (if (and facemenu-new-faces-at-end
+ (> (length menu-val) 3))
+ (define-key-after menu-val key (cons name function)
+ (car (nth (- (length menu-val) 3) menu-val)))
+ (define-key menu key (cons name function))))))
+ nil) ; Return nil for facemenu-iterate