comparison lisp/utils/facemenu.el @ 100:4be1180a9e89 r20-1b2

Import from CVS: tag r20-1b2
author cvs
date Mon, 13 Aug 2007 09:15:11 +0200
parents c7528f8e288d
children 1370575f1259
comparison
equal deleted inserted replaced
99:2d83cbd90d8d 100:4be1180a9e89
1 ;;; facemenu.el --- create a face menu for interactively adding fonts to text 1 ;;; facemenu.el --- create a face menu for interactively adding fonts to text
2 ;; Copyright (c) 1994, 1995 Free Software Foundation, Inc. 2 ;; Copyright (c) 1994, 1995, 1996 Free Software Foundation, Inc.
3 3
4 ;; XEmacs version: Mike Sperber <sperber@informatik.uni-tuebingen.de> 4 ;; XEmacs version: Mike Sperber <sperber@informatik.uni-tuebingen.de>
5 ;; Original author: Boris Goldowsky <boris@gnu.ai.mit.edu> 5 ;; Original author: Boris Goldowsky <boris@gnu.ai.mit.edu>
6 ;; Keywords: faces 6 ;; Keywords: faces
7 7
20 ;; You should have received a copy of the GNU General Public License 20 ;; You should have received a copy of the GNU General Public License
21 ;; along with XEmacs; see the file COPYING. If not, write to the Free 21 ;; along with XEmacs; see the file COPYING. If not, write to the Free
22 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 22 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 ;; 02111-1307, USA. 23 ;; 02111-1307, USA.
24 24
25 ;;; Synched up with: FSF 19.30. 25 ;;; Synched up with: FSF 19.34.
26 26
27 ;;; Commentary: 27 ;;; Commentary:
28
28 ;; This file defines a menu of faces (bold, italic, etc) which allows you to 29 ;; This file defines a menu of faces (bold, italic, etc) which allows you to
29 ;; set the face used for a region of the buffer. Some faces also have 30 ;; set the face used for a region of the buffer. Some faces also have
30 ;; keybindings, which are shown in the menu. Faces with names beginning with 31 ;; keybindings, which are shown in the menu. Faces with names beginning with
31 ;; "fg:" or "bg:", as in "fg:red", are treated specially. 32 ;; "fg:" or "bg:", as in "fg:red", are treated specially.
32 ;; Such faces are assumed to consist only of a foreground (if "fg:") or 33 ;; Such faces are assumed to consist only of a foreground (if "fg:") or
36 ;; "Foreground" and "Background" submenus. 37 ;; "Foreground" and "Background" submenus.
37 ;; 38 ;;
38 ;; The menu also contains submenus for indentation and justification-changing 39 ;; The menu also contains submenus for indentation and justification-changing
39 ;; commands. 40 ;; commands.
40 41
41 ;;; Installation:
42 ;; Just do a (require 'facemenu).
43 ;; If you want the menu bound to a mouse button under XEmacs, do
44 ;; (define-key global-map '(control button2) 'facemenu-menu)
45
46 ;;; Usage: 42 ;;; Usage:
47 ;; Selecting a face from the menu or typing the keyboard equivalent will 43 ;; Selecting a face from the menu or typing the keyboard equivalent will
48 ;; change the region to use that face. If you use transient-mark-mode and the 44 ;; change the region to use that face. If you use transient-mark-mode and the
49 ;; region is not active, the face will be remembered and used for the next 45 ;; region is not active, the face will be remembered and used for the next
50 ;; insertion. It will be forgotten if you move point or make other 46 ;; insertion. It will be forgotten if you move point or make other
52 ;; 48 ;;
53 ;; Faces can be selected from the keyboard as well. 49 ;; Faces can be selected from the keyboard as well.
54 ;; The standard keybindings are M-g (or ESC g) + letter: 50 ;; The standard keybindings are M-g (or ESC g) + letter:
55 ;; M-g i = "set italic", M-g b = "set bold", etc. 51 ;; M-g i = "set italic", M-g b = "set bold", etc.
56 52
53 ;;; Customization:
54 ;; An alternative set of keybindings that may be easier to type can be set up
55 ;; using "Alt" or "Hyper" keys. This requires that you either have or create
56 ;; an Alt or Hyper key on your keyboard. On my keyboard, there is a key
57 ;; labeled "Alt", but to make it act as an Alt key I have to put this command
58 ;; into my .xinitrc:
59 ;; xmodmap -e "add Mod3 = Alt_L"
60 ;; Or, I can make it into a Hyper key with this:
61 ;; xmodmap -e "keysym Alt_L = Hyper_L" -e "add Mod2 = Hyper_L"
62 ;; Check with local X-perts for how to do it on your system.
63 ;; Then you can define your keybindings with code like this in your .emacs:
64 ;; (setq facemenu-keybindings
65 ;; '((default . [?\H-d])
66 ;; (bold . [?\H-b])
67 ;; (italic . [?\H-i])
68 ;; (bold-italic . [?\H-l])
69 ;; (underline . [?\H-u])))
70 ;; (setq facemenu-keymap global-map)
71 ;; (setq facemenu-key nil)
72 ;; (define-key global-map [?\H-c] 'facemenu-set-foreground) ; set fg color
73 ;; (define-key global-map [?\H-C] 'facemenu-set-background) ; set bg color
74 ;; (require 'facemenu)
57 ;; 75 ;;
58 ;; The order of the faces that appear in the menu and their keybindings can be 76 ;; The order of the faces that appear in the menu and their keybindings can be
59 ;; controlled by setting the variables `facemenu-keybindings' and 77 ;; controlled by setting the variables `facemenu-keybindings' and
60 ;; `facemenu-new-faces-at-end'. List faces that you don't use in documents 78 ;; `facemenu-new-faces-at-end'. List faces that you don't use in documents
61 ;; (eg, `region') in `facemenu-unlisted-faces'. 79 ;; (eg, `region') in `facemenu-unlisted-faces'.
77 95
78 ;;; Code: 96 ;;; Code:
79 97
80 (provide 'facemenu) 98 (provide 'facemenu)
81 99
100 ;; XEmacs
82 (require 'easymenu) 101 (require 'easymenu)
83 102
84 ;;; Provide some binding for startup: 103 ;;; Provide some binding for startup:
85 ;;; XEmacs -- goto-line is a *much* better binding for M-g. 104 ;;; XEmacs -- goto-line is a *much* better binding for M-g.
86 ;;;dont ###autoload (define-key global-map "\M-g" 'facemenu-keymap) 105 ;;;dont ###autoload (define-key global-map "\M-g" 'facemenu-keymap)
110 (defvar facemenu-new-faces-at-end t 129 (defvar facemenu-new-faces-at-end t
111 "Where in the menu to insert newly-created faces. 130 "Where in the menu to insert newly-created faces.
112 This should be nil to put them at the top of the menu, or t to put them 131 This should be nil to put them at the top of the menu, or t to put them
113 just before \"Other\" at the end.") 132 just before \"Other\" at the end.")
114 133
134 ;; XEmacs -- additional faces
115 (defvar facemenu-unlisted-faces 135 (defvar facemenu-unlisted-faces
116 '(modeline region secondary-selection highlight scratch-face 136 '(modeline region secondary-selection highlight scratch-face
117 gui-button-face isearch hyperlink 137 gui-button-face isearch hyperlink
118 modeline modeline-buffer-id modeline-mousable modeline-mousable-minor-mode 138 modeline modeline-buffer-id modeline-mousable modeline-mousable-minor-mode
119 pointer primary-selection secondary-selection list-mode-item-selected 139 pointer primary-selection secondary-selection list-mode-item-selected
213 "Keymap for face-changing commands. 233 "Keymap for face-changing commands.
214 `Facemenu-update' fills in the keymap according to the bindings 234 `Facemenu-update' fills in the keymap according to the bindings
215 requested in `facemenu-keybindings'.") 235 requested in `facemenu-keybindings'.")
216 (defalias 'facemenu-keymap facemenu-keymap) 236 (defalias 'facemenu-keymap facemenu-keymap)
217 237
238
239 (defvar facemenu-add-face-function nil
240 "Function called at beginning of text to change or `nil'.
241 This function is passed the FACE to set and END of text to change, and must
242 return a string which is inserted. It may set `facemenu-end-add-face'.")
243
244 (defvar facemenu-end-add-face nil
245 "String to insert or function called at end of text to change or `nil'.
246 This function is passed the FACE to set, and must return a string which is
247 inserted.")
248
249 (defvar facemenu-remove-face-function nil
250 "When non-`nil' function called to remove faces.
251 This function is passed the START and END of text to change.
252 May also be `t' meaning to use `facemenu-add-face-function'.")
253
218 ;;; Internal Variables 254 ;;; Internal Variables
219 255
220 (defvar facemenu-color-alist nil 256 (defvar facemenu-color-alist nil
221 ;; Don't initialize here; that doesn't work if preloaded. 257 ;; Don't initialize here; that doesn't work if preloaded.
222 "Alist of colors, used for completion. 258 "Alist of colors, used for completion.
258 294
259 Otherwise, this command specifies the face for the next character 295 Otherwise, this command specifies the face for the next character
260 inserted. Moving point or switching buffers before 296 inserted. Moving point or switching buffers before
261 typing a character to insert cancels the specification." 297 typing a character to insert cancels the specification."
262 (interactive (list (read-face-name "Use face: "))) 298 (interactive (list (read-face-name "Use face: ")))
263 (setq zmacs-region-stays t) 299 (setq zmacs-region-stays t) ; XEmacs
264 (barf-if-buffer-read-only) 300 (barf-if-buffer-read-only)
265 (facemenu-add-new-face face) 301 (facemenu-add-new-face face)
266 (facemenu-update-facemenu-menu) 302 (facemenu-update-facemenu-menu) ; XEmacs
267 (if (and (facemenu-region-active-p) 303 (if (and (facemenu-region-active-p)
268 (not current-prefix-arg)) 304 (not current-prefix-arg))
269 (let ((start (or start (region-beginning))) 305 (let ((start (or start (region-beginning)))
270 (end (or end (region-end)))) 306 (end (or end (region-end))))
271 (facemenu-add-face face start end)) 307 (facemenu-add-face face start end))
302 (or (facemenu-get-face face) 338 (or (facemenu-get-face face)
303 (error "Unknown color: %s" color)) 339 (error "Unknown color: %s" color))
304 (facemenu-set-face face start end))) 340 (facemenu-set-face face start end)))
305 341
306 ;;;###autoload 342 ;;;###autoload
307 (defun facemenu-set-face-from-menu (face) 343 (defun facemenu-set-face-from-menu (face start end)
308 "Set the face of the region or next character typed. 344 "Set the face of the region or next character typed.
309 This function is designed to be called from a menu; the face to use 345 This function is designed to be called from a menu; the face to use
310 is the menu item's name. 346 is the menu item's name.
311 347
312 If the region is active and there is no prefix argument, 348 If the region is active and there is no prefix argument,
313 this command sets the region to the requested face. 349 this command sets the region to the requested face.
314 350
315 Otherwise, this command specifies the face for the next character 351 Otherwise, this command specifies the face for the next character
316 inserted. Moving point or switching buffers before 352 inserted. Moving point or switching buffers before
317 typing a character to insert cancels the specification." 353 typing a character to insert cancels the specification."
318 (let ((start (if (and (facemenu-region-active-p) 354 (interactive (list last-command-event
319 (not current-prefix-arg)) 355 (if (and (facemenu-region-active-p)
320 (region-beginning))) 356 (not current-prefix-arg))
321 (end (if (and (facemenu-region-active-p) 357 (region-beginning))
322 (not current-prefix-arg)) 358 (if (and (facemenu-region-active-p)
323 (region-end)))) 359 (not current-prefix-arg))
324 (barf-if-buffer-read-only) 360 (region-end))))
325 (setq zmacs-region-stays t) 361 (barf-if-buffer-read-only)
326 (facemenu-get-face face) 362 (setq zmacs-region-stays t) ; XEmacs
327 (if start 363 (facemenu-get-face face)
328 (facemenu-add-face face start end) 364 (if start
329 (facemenu-self-insert-face face)))) 365 (facemenu-add-face face start end)
330 366 (facemenu-self-insert-face face))) ; XEmacs
367
368 ;; XEmacs
331 (defun facemenu-self-insert-face (face) 369 (defun facemenu-self-insert-face (face)
332 (setq self-insert-face (cond 370 (setq self-insert-face (cond
333 ((null self-insert-face) face) 371 ((null self-insert-face) face)
334 ((consp self-insert-face) 372 ((consp self-insert-face)
335 (facemenu-active-faces (cons face self-insert-face))) 373 (facemenu-active-faces (cons face self-insert-face)))
415 ((consp face) (mapcar 453 ((consp face) (mapcar
416 #'(lambda (face) 454 #'(lambda (face)
417 (facemenu-sized-face (facemenu-face-strip-size face) 455 (facemenu-sized-face (facemenu-face-strip-size face)
418 size)) 456 size))
419 face)) 457 face))
420 (t (facemenu-sized-face face size)))) 458 ;;[BV 9-Feb-97] strip-face from this face too, please!
459 (t (facemenu-sized-face (facemenu-face-strip-size face) size))))
421 460
422 (defun facemenu-adjust-size (from to) 461 (defun facemenu-adjust-size (from to)
423 "Adjust the size of the text between FROM and TO according 462 "Adjust the size of the text between FROM and TO according
424 to the values of the 'size property in that region." 463 to the values of the 'size property in that region."
425 (let ((pos from) 464 (let ((pos from)
458 ;;;###autoload 497 ;;;###autoload
459 (defun facemenu-set-invisible (start end) 498 (defun facemenu-set-invisible (start end)
460 "Make the region invisible. 499 "Make the region invisible.
461 This sets the `invisible' text property; it can be undone with 500 This sets the `invisible' text property; it can be undone with
462 `facemenu-remove-special'." 501 `facemenu-remove-special'."
463 (interactive "r") 502 (interactive "_r")
464 (put-text-property start end 'invisible t)) 503 (put-text-property start end 'invisible t))
465 504
466 ;;;###autoload 505 ;;;###autoload
467 (defun facemenu-set-intangible (start end) 506 (defun facemenu-set-intangible (start end)
468 "Make the region intangible: disallow moving into it. 507 "Make the region intangible: disallow moving into it.
469 This sets the `intangible' text property; it can be undone with 508 This sets the `intangible' text property; it can be undone with
470 `facemenu-remove-special'." 509 `facemenu-remove-special'."
471 (interactive "r") 510 (interactive "_r")
472 (put-text-property start end 'intangible t)) 511 (put-text-property start end 'intangible t))
473 512
474 ;;;###autoload 513 ;;;###autoload
475 (defun facemenu-set-read-only (start end) 514 (defun facemenu-set-read-only (start end)
476 "Make the region unmodifiable. 515 "Make the region unmodifiable.
477 This sets the `read-only' text property; it can be undone with 516 This sets the `read-only' text property; it can be undone with
478 `facemenu-remove-special'." 517 `facemenu-remove-special'."
479 (interactive "r") 518 (interactive "_r")
480 (put-text-property start end 'read-only t)) 519 (put-text-property start end 'read-only t))
481 520
482 ;;;###autoload 521 ;;;###autoload
483 (defun facemenu-remove-props (start end) 522 (defun facemenu-remove-props (start end)
484 "Remove all text properties that facemenu added to region." 523 "Remove all text properties that facemenu added to region."
499 538
500 ;;;###autoload 539 ;;;###autoload
501 (defun list-text-properties-at (p) 540 (defun list-text-properties-at (p)
502 "Pop up a buffer listing text-properties at LOCATION." 541 "Pop up a buffer listing text-properties at LOCATION."
503 (interactive "d") 542 (interactive "d")
504 (let ((props (text-properties-at p))) 543 (let ((props (text-properties-at p))
544 category
545 str)
505 (if (null props) 546 (if (null props)
506 (message "None") 547 (message "None")
507 (with-output-to-temp-buffer "*Text Properties*" 548 (if (and (not (cdr (cdr props)))
508 (princ (format "Text properties at %d:\n\n" p)) 549 (not (eq (car props) 'category))
509 (while props 550 (< (length (setq str (format "Text property at %d: %s %S"
510 (princ (format "%-20s %S\n" 551 p (car props) (car (cdr props)))))
511 (car props) (car (cdr props)))) 552 (frame-width)))
512 (setq props (cdr (cdr props)))))))) 553 (message "%s" str)
554 (with-output-to-temp-buffer "*Text Properties*"
555 (princ (format "Text properties at %d:\n\n" p))
556 (while props
557 (if (eq (car props) 'category)
558 (setq category (car (cdr props))))
559 (princ (format "%-20s %S\n"
560 (car props) (car (cdr props))))
561 (setq props (cdr (cdr props))))
562 (if category
563 (progn
564 (setq props (symbol-plist category))
565 (princ (format "\nCategory %s:\n\n" category))
566 (while props
567 (princ (format "%-20s %S\n"
568 (car props) (car (cdr props))))
569 (if (eq (car props) 'category)
570 (setq category (car (cdr props))))
571 (setq props (cdr (cdr props)))))))))))
513 572
514 ;;;###autoload 573 ;;;###autoload
515 (defun facemenu-read-color (&optional prompt) 574 (defun facemenu-read-color (&optional prompt)
516 "Read a color using the minibuffer." 575 "Read a color using the minibuffer."
517 (if (string-match "XEmacs" emacs-version) 576 (if (string-match "XEmacs" emacs-version)
594 determine the correct answer." 653 determine the correct answer."
595 (cond ((equal a b) t) 654 (cond ((equal a b) t)
596 ((and (equal (facemenu-color-values a) 655 ((and (equal (facemenu-color-values a)
597 (facemenu-color-values b)))))) 656 (facemenu-color-values b))))))
598 657
599 (defun facemenu-add-face (face start end) 658 (defun facemenu-add-face (face &optional start end)
600 "Add FACE to text between START and END. 659 "Add FACE to text between START and END.
601 For each section of that region that has a different face property, FACE will 660 For each section of that region that has a different face property, FACE will
602 be consed onto it, and other faces that are completely hidden by that will be 661 be consed onto it, and other faces that are completely hidden by that will be
603 removed from the list. 662 removed from the list.
604 663
605 As a special case, if FACE is `default', then the region is left with NO face 664 As a special case, if FACE is `default', then the region is left with NO face
606 text property. Otherwise, selecting the default face would not have any 665 text property. Otherwise, selecting the default face would not have any
607 effect." 666 effect."
608 (interactive "*_xFace:\nr") 667 (interactive "*_xFace:\nr")
609 (if (eq face 'default) 668 (if (and (eq face 'default)
610 (remove-text-properties start end '(face default)) 669 (not (eq facemenu-remove-face-function t)))
611 (let ((part-start start) part-end) 670 (if facemenu-remove-face-function
612 (while (not (= part-start end)) 671 (funcall facemenu-remove-face-function start end)
613 (setq part-end (next-single-property-change part-start 'face nil end)) 672 (if (and start (< start end))
614 (let* ((prev (get-text-property part-start 'face)) 673 (remove-text-properties start end '(face default))
615 (size (get-text-property part-start 'size)) 674 (setq self-insert-face 'default
616 (face (if size (facemenu-sized-face face size) face))) 675 self-insert-face-command this-command)))
617 (put-text-property part-start part-end 'face 676 (if facemenu-add-face-function
618 (if (null prev) 677 (save-excursion
619 face 678 (if end (goto-char end))
620 (facemenu-active-faces 679 (save-excursion
621 (cons face 680 (if start (goto-char start))
622 (if (listp prev) prev (list prev))))))) 681 (insert-before-markers
623 (setq part-start part-end))))) 682 (funcall facemenu-add-face-function face end)))
624 683 (if facemenu-end-add-face
684 (insert (if (stringp facemenu-end-add-face)
685 facemenu-end-add-face
686 (funcall facemenu-end-add-face face)))))
687 (if (and start (< start end))
688 (let ((part-start start) part-end)
689 (while (not (= part-start end))
690 (setq part-end (next-single-property-change part-start 'face
691 nil end))
692 (let ((prev (get-text-property part-start 'face)))
693 (put-text-property part-start part-end 'face
694 (if (null prev)
695 face
696 (facemenu-active-faces
697 (cons face
698 (if (listp prev)
699 prev
700 (list prev)))))))
701 (setq part-start part-end)))
702 (setq self-insert-face (if (eq last-command self-insert-face-command)
703 (cons face (if (listp self-insert-face)
704 self-insert-face
705 (list self-insert-face)))
706 face)
707 self-insert-face-command this-command)))))
708
709 ;; XEmacs
625 (defun facemenu-face-attributes (face) 710 (defun facemenu-face-attributes (face)
626 "Create a vector of the relevant face attributes of face FACE." 711 "Create a vector of the relevant face attributes of face FACE."
627 (if (string-match "XEmacs" emacs-version) 712 (if (string-match "XEmacs" emacs-version)
628 (apply 'vector (mapcar #'(lambda (prop) 713 (apply 'vector (mapcar #'(lambda (prop)
629 (face-property-instance face prop)) 714 (face-property-instance face prop))