aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Goldowsky1994-10-20 18:15:25 +0000
committerBoris Goldowsky1994-10-20 18:15:25 +0000
commitbf7d4561c1a9a4885de5c61defb9bc844072bb67 (patch)
tree81e92c49ecf4540aa01ab29fcecb792a29beec7d
parent33af44e8448e9c6f0de668ed5251c483d3cf9ca0 (diff)
downloademacs-bf7d4561c1a9a4885de5c61defb9bc844072bb67.tar.gz
emacs-bf7d4561c1a9a4885de5c61defb9bc844072bb67.zip
(facemenu-get-face): Don't add to menu here.
(facemenu-face-menu, facemenu-foreground-menu, facemenu-background-menu): New or renamed variables for submenus.(facemenu-color-alist): Renamed from facemenu-colors. (facemenu-add-new-face): New function. (facemenu-update): Don't redo top-level menu; nothing should change. Move menu setup to defvars. Use facemenu-add-new-face. Changed global binding to C-down-mouse-3. (facemenu-menu): "Update" item removed; should no longer be needed interactively. (facemenu-complete-face-list): Just return faces, not keybindings.
-rw-r--r--lisp/facemenu.el343
1 files changed, 172 insertions, 171 deletions
diff --git a/lisp/facemenu.el b/lisp/facemenu.el
index f520ed43490..e5e2ba81001 100644
--- a/lisp/facemenu.el
+++ b/lisp/facemenu.el
@@ -21,9 +21,14 @@
21;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 21;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 22
23;;; Commentary: 23;;; Commentary:
24;; This file defines a menu of faces (bold, italic, etc) which 24;; This file defines a menu of faces (bold, italic, etc) which allows you to
25;; allows you to set the face used for a region of the buffer. 25;; set the face used for a region of the buffer. Some faces also have
26;; Some faces also have keybindings, which are shown in the menu. 26;; keybindings, which are shown in the menu. Faces with names beginning with
27;; "fg:" or "bg:", as in "fg:red", are treated specially. It is assumed that
28;; Such faces are assumed to consist only of a foreground (if "fg:") or
29;; background (if "bg:") color. They are thus put into the color submenus
30;; rather than the general Face submenu. Such faces can also be created on
31;; demand from the "Other..." menu items.
27 32
28;;; Installation: 33;;; Installation:
29;; Put this file somewhere on emacs's load-path, and put 34;; Put this file somewhere on emacs's load-path, and put
@@ -31,12 +36,11 @@
31;; in your .emacs file. 36;; in your .emacs file.
32 37
33;;; Usage: 38;;; Usage:
34;; Selecting a face from the menu or typing the keyboard equivalent 39;; Selecting a face from the menu or typing the keyboard equivalent will
35;; will change the region to use that face. 40;; change the region to use that face. If you use transient-mark-mode and the
36;; If you use transient-mark-mode and the region is not active, the 41;; region is not active, the face will be remembered and used for the next
37;; face will be remembered and used for the next insertion. It will 42;; insertion. It will be forgotten if you move point or make other
38;; be forgotten if you move point or make other modifications before 43;; modifications before inserting or typing anything.
39;; inserting or typing anything.
40;; 44;;
41;; Faces can be selected from the keyboard as well. 45;; Faces can be selected from the keyboard as well.
42;; The standard keybindings are M-s (or ESC s) + letter: 46;; The standard keybindings are M-s (or ESC s) + letter:
@@ -82,12 +86,6 @@
82(defvar facemenu-key "\M-s" 86(defvar facemenu-key "\M-s"
83 "Prefix to use for facemenu commands.") 87 "Prefix to use for facemenu commands.")
84 88
85(defvar facemenu-keymap nil
86 "Map for keybindings of face commands.
87If nil, `facemenu-update' will create one.
88`Facemenu-update' also fills in the keymap according to the bindings
89requested in facemenu-keybindings.")
90
91(defvar facemenu-keybindings 89(defvar facemenu-keybindings
92 '((default . "d") 90 '((default . "d")
93 (bold . "b") 91 (bold . "b")
@@ -113,94 +111,71 @@ If you change this variable after loading facemenu.el, you will need to call
113Set this before loading facemenu.el, or call `facemenu-update' after 111Set this before loading facemenu.el, or call `facemenu-update' after
114changing it.") 112changing it.")
115 113
116(defvar facemenu-colors 114(defvar facemenu-face-menu
117 (if (eq 'x window-system) 115 (let ((map (make-sparse-keymap "Face")))
118 (mapcar 'list (x-defined-colors))) 116 (define-key map [other] (cons "Other..." 'facemenu-set-face))
119 "Alist of colors, used for completion.") 117 map)
118 "Menu keymap for faces.")
119
120(defvar facemenu-foreground-menu
121 (let ((map (make-sparse-keymap "Foreground Color")))
122 (define-key map "o" (cons "Other" 'facemenu-set-foreground))
123 map)
124 "Menu keymap for foreground colors.")
125
126(defvar facemenu-background-menu
127 (let ((map (make-sparse-keymap "Background Color")))
128 (define-key map "o" (cons "Other" 'facemenu-set-background))
129 map)
130 "Menu keymap for background colors")
131
132(defvar facemenu-special-menu
133 (let ((map (make-sparse-keymap "Special")))
134 (define-key map [read-only] (cons "Read-Only" 'facemenu-set-read-only))
135 (define-key map [invisible] (cons "Invisible" 'facemenu-set-invisible))
136 map)
137 "Menu keymap for non-face text-properties.")
138
139(defvar facemenu-menu
140 (let ((map (make-sparse-keymap "Face")))
141 (define-key map [display] (cons "Display Faces" 'list-faces-display))
142 (define-key map [remove] (cons "Remove Props" 'facemenu-remove-all))
143 (define-key map [sep1] (list "-----------------"))
144 (define-key map [special] (cons "Special Props" facemenu-special-menu))
145 (define-key map [bg] (cons "Background Color" facemenu-background-menu))
146 (define-key map [fg] (cons "Foreground Color" facemenu-foreground-menu))
147 (define-key map [face] (cons "Face" facemenu-face-menu))
148 map)
149 "Facemenu top-level menu keymap")
150
151(defvar facemenu-keymap (make-sparse-keymap "Set face")
152 "Map for keyboard face-changing commands.
153`Facemenu-update' fills in the keymap according to the bindings
154requested in facemenu-keybindings.")
155
156;;; Internal Variables
157
158(defvar facemenu-color-alist nil
159 ;; Don't initialize here; that doesn't work if preloaded.
160 "Alist of colors, used for completion.
161If null, `facemenu-read-color' will set it.")
120 162
121(defvar facemenu-next nil) ; set when we are going to set a face on next char. 163(defvar facemenu-next nil) ; set when we are going to set a face on next char.
122(defvar facemenu-loc nil) 164(defvar facemenu-loc nil)
123 165
124(defalias 'facemenu-foreground (make-sparse-keymap "Foreground"))
125(defalias 'facemenu-background (make-sparse-keymap "Background"))
126
127(defun facemenu-update () 166(defun facemenu-update ()
128 "Add or update the \"Face\" menu in the menu bar." 167 "Add or update the \"Face\" menu in the menu bar.
168You can call this to update things if you change any of the menu configuration
169variables."
129 (interactive) 170 (interactive)
130 171
131 ;; Set up keymaps 172 ;; Global bindings:
132 (fset 'facemenu-menu (setq facemenu-menu (make-sparse-keymap "Face"))) 173 (define-key global-map [C-down-mouse-3] facemenu-menu)
133 (if (null facemenu-keymap) 174 (if facemenu-key (define-key global-map facemenu-key facemenu-keymap))
134 (fset 'facemenu-keymap
135 (setq facemenu-keymap (make-sparse-keymap "Set face"))))
136 (if facemenu-key
137 (define-key global-map facemenu-key facemenu-keymap))
138
139 ;; Define basic keys
140 ;; We construct this list structure explicitly because a quoted constant
141 ;; would be pure.
142 (define-key facemenu-menu [update] (cons "Update Menu" 'facemenu-update))
143 (define-key facemenu-menu [display] (cons "Display Faces"
144 'list-faces-display))
145 (define-key facemenu-menu [sep1] (list "-------------"))
146 (define-key facemenu-menu [remove] (cons "Remove Properties"
147 'facemenu-remove-all))
148 (define-key facemenu-menu [read-only] (cons "Read-Only"
149 'facemenu-set-read-only))
150 (define-key facemenu-menu [invisible] (cons "Invisible"
151 'facemenu-set-invisible))
152 (define-key facemenu-menu [sep2] (list "-------------"))
153 (define-key facemenu-menu [bg] (cons "Background Color"
154 'facemenu-background))
155 (define-key facemenu-menu [fg] (cons "Foreground Color"
156 'facemenu-foreground))
157 (define-key facemenu-menu [sep3] (list "-------------"))
158 (define-key facemenu-menu [other] (cons "Other..." 'facemenu-set-face))
159
160 (define-key 'facemenu-foreground "o" (cons "Other" 'facemenu-set-foreground))
161 (define-key 'facemenu-background "o" (cons "Other" 'facemenu-set-background))
162
163 ;; Define commands for face-changing
164 (facemenu-iterate
165 (lambda (f)
166 (let* ((face (car f))
167 (name (symbol-name face))
168 (key (cdr f))
169 (menu (cond ((string-match "^fg:" name) 'facemenu-foreground)
170 ((string-match "^bg:" name) 'facemenu-background)
171 (t facemenu-menu))))
172 (if (memq menu '(facemenu-foreground facemenu-background))
173 (setq name (substring name 3)))
174 (cond ((memq face facemenu-unlisted-faces)
175 nil)
176 ((null key) (define-key menu (vector face)
177 (cons name 'facemenu-set-face-from-menu)))
178 (t (let ((function (intern (concat "facemenu-set-" name))))
179 (fset function
180 (` (lambda () (interactive)
181 (facemenu-set-face (quote (, face))))))
182 (define-key facemenu-keymap key (cons name function))
183 (define-key menu key (cons name function))))))
184 nil)
185 (facemenu-complete-face-list facemenu-keybindings))
186
187 (define-key global-map (vector 'menu-bar 'Face)
188 (cons "Face" facemenu-menu)))
189
190; We'd really like to name the menu items as follows,
191; but we can't since menu entries don't display text properties (yet?)
192; (let ((s (copy-sequence (symbol-name face))))
193; (put-text-property 0 (1- (length s))
194; 'face face s)
195; s)
196 175
197;;;###autoload 176 ;; Add each defined face to the menu.
198(defun facemenu-read-color (prompt) 177 (facemenu-iterate 'facemenu-add-new-face
199 "Read a color using the minibuffer." 178 (facemenu-complete-face-list facemenu-keybindings)))
200 (let ((col (completing-read (or "Color: ") facemenu-colors nil t)))
201 (if (equal "" col)
202 nil
203 col)))
204 179
205;;;###autoload 180;;;###autoload
206(defun facemenu-set-face (face &optional start end) 181(defun facemenu-set-face (face &optional start end)
@@ -222,6 +197,7 @@ typing a character cancels the request."
222 (setq facemenu-next face 197 (setq facemenu-next face
223 facemenu-loc (point)))) 198 facemenu-loc (point))))
224 199
200;;;###autoload
225(defun facemenu-set-foreground (color &optional start end) 201(defun facemenu-set-foreground (color &optional start end)
226 "Set the foreground color of the region or next character typed. 202 "Set the foreground color of the region or next character typed.
227The color is prompted for. A face named `fg:color' is used \(or created). 203The color is prompted for. A face named `fg:color' is used \(or created).
@@ -236,6 +212,7 @@ typing a character cancels the request."
236 (error "Unknown color: %s" color)) 212 (error "Unknown color: %s" color))
237 (facemenu-set-face face start end))) 213 (facemenu-set-face face start end)))
238 214
215;;;###autoload
239(defun facemenu-set-background (color &optional start end) 216(defun facemenu-set-background (color &optional start end)
240 "Set the background color of the region or next character typed. 217 "Set the background color of the region or next character typed.
241The color is prompted for. A face named `bg:color' is used \(or created). 218The color is prompted for. A face named `bg:color' is used \(or created).
@@ -296,87 +273,41 @@ This sets the `read-only' text property; it can be undone with
296 start end '(face nil invisible nil intangible nil 273 start end '(face nil invisible nil intangible nil
297 read-only nil category nil)))) 274 read-only nil category nil))))
298 275
299(defun facemenu-get-face (face) 276;;;###autoload
300 "Make sure FACE exists. 277(defun facemenu-read-color (prompt)
301If not, it is created. If it is created and is of the form `fg:color', then 278 "Read a color using the minibuffer."
302set the foreground to that color. If of the form `bg:color', set the 279 (let ((col (completing-read (or "Color: ")
303background. In any case, add it to the appropriate menu. Returns nil if 280 (or facemenu-color-alist
304given a bad color." 281 (if (eq 'x window-system)
305 (if (internal-find-face face) 282 (mapcar 'list (x-defined-colors))))
306 t 283 nil t)))
307 (make-face face) 284 (if (equal "" col)
308 (let* ((name (symbol-name face)) 285 nil
309 (color (substring name 3))) 286 col)))
310 (cond ((string-match "^fg:" name)
311 (set-face-foreground face color)
312 (define-key 'facemenu-foreground (vector face)
313 (cons color 'facemenu-set-face-from-menu))
314 (x-color-defined-p color))
315 ((string-match "^bg:" name)
316 (set-face-background face color)
317 (define-key 'facemenu-background (vector face)
318 (cons color 'facemenu-set-face-from-menu))
319 (x-color-defined-p color))
320 (t
321 (define-key facemenu-menu (vector face)
322 (cons name 'facemenu-set-face-from-menu))
323 t)))))
324
325(defun facemenu-after-change (begin end old-length)
326 "May set the face of just-inserted text to user's request.
327This only happens if the change is an insertion, and
328`facemenu-set-face[-from-menu]' was called with point at the
329beginning of the insertion."
330 (if (null facemenu-next) ; exit immediately if no work
331 nil
332 (if (and (= 0 old-length) ; insertion
333 (= facemenu-loc begin)) ; point wasn't moved in between
334 (facemenu-add-face facemenu-next begin end))
335 (setq facemenu-next nil)))
336
337(defun facemenu-complete-face-list (&optional oldlist)
338 "Return alist of all faces that are look different.
339Starts with given LIST of faces, and adds elements only if they display
340differently from any face already on the list.
341The original LIST will end up at the end of the returned list, in reverse
342order. The elements added will have null cdrs."
343 (let ((list nil))
344 (facemenu-iterate
345 (function
346 (lambda (item)
347 (if (internal-find-face (car item))
348 (setq list (cons item list)))
349 nil))
350 oldlist)
351 (facemenu-iterate
352 (function
353 (lambda (new-face)
354 (if (not (facemenu-iterate
355 (function
356 (lambda (item) (face-equal (car item) new-face t)))
357 list))
358 (setq list (cons (cons new-face nil) list)))
359 nil))
360 (nreverse (face-list)))
361 list))
362 287
363(defun facemenu-add-face (face start end) 288(defun facemenu-add-face (face start end)
364 "Add FACE to text between START and END. 289 "Add FACE to text between START and END.
365For each section of that region that has a different face property, FACE will 290For each section of that region that has a different face property, FACE will
366be consed onto it, and other faces that are completely hidden by that will be 291be consed onto it, and other faces that are completely hidden by that will be
367removed from the list." 292removed from the list.
293
294As a special case, if FACE is `default', then the region is left with NO face
295text property. Otherwise, selecting the default face would not have any
296effect."
368 (interactive "*xFace:\nr") 297 (interactive "*xFace:\nr")
369 (let ((part-start start) part-end) 298 (if (eq face 'default)
370 (while (not (= part-start end)) 299 (remove-text-properties start end '(face default))
371 (setq part-end (next-single-property-change part-start 'face nil end)) 300 (let ((part-start start) part-end)
372 (let ((prev (get-text-property part-start 'face))) 301 (while (not (= part-start end))
373 (put-text-property part-start part-end 'face 302 (setq part-end (next-single-property-change part-start 'face nil end))
374 (if (null prev) 303 (let ((prev (get-text-property part-start 'face)))
375 face 304 (put-text-property part-start part-end 'face
376 (facemenu-discard-redundant-faces 305 (if (null prev)
377 (cons face 306 face
378 (if (listp prev) prev (list prev))))))) 307 (facemenu-discard-redundant-faces
379 (setq part-start part-end)))) 308 (cons face
309 (if (listp prev) prev (list prev)))))))
310 (setq part-start part-end)))))
380 311
381(defun facemenu-discard-redundant-faces (face-list &optional mask) 312(defun facemenu-discard-redundant-faces (face-list &optional mask)
382 "Remove from FACE-LIST any faces that won't show at all. 313 "Remove from FACE-LIST any faces that won't show at all.
@@ -401,6 +332,77 @@ earlier face."
401 (facemenu-discard-redundant-faces (cdr face-list) mask))) 332 (facemenu-discard-redundant-faces (cdr face-list) mask)))
402 (t (facemenu-discard-redundant-faces (cdr face-list) mask))))) 333 (t (facemenu-discard-redundant-faces (cdr face-list) mask)))))
403 334
335(defun facemenu-get-face (symbol)
336 "Make sure FACE exists.
337If not, it is created. If it is created and is of the form `fg:color', then
338set the foreground to that color. If of the form `bg:color', set the
339background. In any case, add it to the appropriate menu. Returns nil if
340given a bad color."
341 (or (internal-find-face symbol)
342 (let* ((face (make-face symbol))
343 (name (symbol-name symbol))
344 (color (substring name 3)))
345 (cond ((string-match "^fg:" name)
346 (set-face-foreground face color)
347 (and (eq 'x window-system) (x-color-defined-p color)))
348 ((string-match "^bg:" name)
349 (set-face-background face color)
350 (and (eq 'x window-system) (x-color-defined-p color)))
351 (t)))))
352
353(defun facemenu-add-new-face (face)
354 "Add a FACE to the appropriate Face menu.
355Automatically called when a new face is created."
356 (let* ((name (symbol-name face))
357 (menu (cond ((string-match "^fg:" name)
358 (setq name (substring name 3))
359 facemenu-foreground-menu)
360 ((string-match "^bg:" name)
361 (setq name (substring name 3))
362 facemenu-background-menu)
363 (t facemenu-face-menu)))
364 key)
365 (cond ((memq face facemenu-unlisted-faces)
366 nil)
367 ((setq key (cdr (assoc face facemenu-keybindings)))
368 (let ((function (intern (concat "facemenu-set-" name))))
369 (fset function
370 (` (lambda () (interactive)
371 (facemenu-set-face (quote (, face))))))
372 (define-key facemenu-keymap key (cons name function))
373 (define-key menu key (cons name function))))
374 (t (define-key menu (vector face)
375 (cons name 'facemenu-set-face-from-menu)))))
376 ;; Return nil for facemenu-iterate's benefit:
377 nil)
378
379(defun facemenu-after-change (begin end old-length)
380 "May set the face of just-inserted text to user's request.
381This only happens if the change is an insertion, and
382`facemenu-set-face[-from-menu]' was called with point at the
383beginning of the insertion."
384 (if (null facemenu-next) ; exit immediately if no work
385 nil
386 (if (and (= 0 old-length) ; insertion
387 (= facemenu-loc begin)) ; point wasn't moved in between
388 (facemenu-add-face facemenu-next begin end))
389 (setq facemenu-next nil)))
390
391(defun facemenu-complete-face-list (&optional oldlist)
392 "Return list of all faces that are look different.
393Starts with given ALIST of faces, and adds elements only if they display
394differently from any face already on the list.
395The faces on ALIST will end up at the end of the returned list, in reverse
396order."
397 (let ((list (nreverse (mapcar 'car oldlist))))
398 (facemenu-iterate
399 (lambda (new-face)
400 (if (not (memq new-face list))
401 (setq list (cons new-face list)))
402 nil)
403 (nreverse (face-list)))
404 list))
405
404(defun facemenu-iterate (func iterate-list) 406(defun facemenu-iterate (func iterate-list)
405 "Apply FUNC to each element of LIST until one returns non-nil. 407 "Apply FUNC to each element of LIST until one returns non-nil.
406Returns the non-nil value it found, or nil if all were nil." 408Returns the non-nil value it found, or nil if all were nil."
@@ -409,7 +411,6 @@ Returns the non-nil value it found, or nil if all were nil."
409 (car iterate-list)) 411 (car iterate-list))
410 412
411(facemenu-update) 413(facemenu-update)
412(add-hook 'menu-bar-final-items 'Face)
413(add-hook 'after-change-functions 'facemenu-after-change) 414(add-hook 'after-change-functions 'facemenu-after-change)
414 415
415;;; facemenu.el ends here 416;;; facemenu.el ends here