(invisible_p, invisible_ellipsis_p): Handle list
[bpt/emacs.git] / lisp / menu-bar.el
CommitLineData
235aa29b
ER
1;;; menu-bar.el --- define a default menu bar.
2
3;; Author: RMS
b7f66977 4;; Keywords: internal
235aa29b 5
03dcd202 6;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
1db87953
RS
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING. If not, write to
22;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
235aa29b 24;;; Code:
1db87953 25
b132f2b1
RM
26;; Don't clobber an existing menu-bar keymap, to preserve any menu-bar key
27;; definitions made in loaddefs.el.
28(or (lookup-key global-map [menu-bar])
29 (define-key global-map [menu-bar] (make-sparse-keymap "menu-bar")))
22390f50 30(defvar menu-bar-help-menu (make-sparse-keymap "Help"))
da183f87
RS
31;; Put Help item last.
32(setq menu-bar-final-items '(help))
33(define-key global-map [menu-bar help] (cons "Help" menu-bar-help-menu))
22390f50 34(defvar menu-bar-edit-menu (make-sparse-keymap "Edit"))
40954111 35(define-key global-map [menu-bar edit] (cons "Edit" menu-bar-edit-menu))
22390f50 36(defvar menu-bar-file-menu (make-sparse-keymap "File"))
40954111 37(define-key global-map [menu-bar file] (cons "File" menu-bar-file-menu))
9bb8e471 38\f
9dcdc43d
RS
39(defvar vc-menu-map (make-sparse-keymap "Version Control"))
40
ca9b40a1 41(define-key menu-bar-file-menu [exit-emacs]
db774a16 42 '("Exit Emacs" . save-buffers-kill-emacs))
9bb8e471
RS
43
44(define-key menu-bar-file-menu [separator-compare]
45 '("--"))
46
080ac1ac
RS
47(define-key menu-bar-file-menu [epatch]
48 '("Apply Patch" . menu-bar-epatch-menu))
5438ecd3
KH
49(define-key menu-bar-file-menu [ediff-merge]
50 '("Merge" . menu-bar-ediff-merge-menu))
080ac1ac 51(define-key menu-bar-file-menu [ediff]
40a8cde1 52 '("Compare" . menu-bar-ediff-menu))
9bb8e471
RS
53
54(define-key menu-bar-file-menu [separator-misc]
55 '("--"))
56
661b05a7
RS
57(define-key menu-bar-file-menu [calendar] '("Calendar" . calendar))
58(define-key menu-bar-file-menu [rmail] '("Read Mail" . rmail))
59(define-key menu-bar-file-menu [gnus] '("Read Net News" . gnus))
9bb8e471 60
ca1a9692
RS
61(if (fboundp 'delete-frame)
62 (progn
63 (define-key menu-bar-file-menu [separator-frames]
64 '("--"))
65
66 (define-key menu-bar-file-menu [delete-frame]
67 '("Delete Frame" . delete-frame))
08e8171f
RS
68 (define-key menu-bar-file-menu [make-frame-on-display]
69 '("Make Frame on Display" . make-frame-on-display))
ca1a9692
RS
70 (define-key menu-bar-file-menu [make-frame]
71 '("Make New Frame" . make-frame))))
9bb8e471
RS
72
73(define-key menu-bar-file-menu [separator-buffers]
74 '("--"))
75
9d441895 76(define-key menu-bar-file-menu [bookmark]
966bcddd 77 '("Bookmarks" . menu-bar-bookmark-map))
9bb8e471
RS
78(define-key menu-bar-file-menu [print-buffer]
79 '("Print Buffer" . print-buffer))
80(define-key menu-bar-file-menu [kill-buffer]
b85fdafb 81 '("Kill (Current) Buffer" . kill-this-buffer))
df4d8e01
RS
82(define-key menu-bar-file-menu [insert-file]
83 '("Insert File" . insert-file))
9dcdc43d
RS
84(define-key menu-bar-file-menu [vc-menu]
85 (cons "Version Control" vc-menu-map))
2f1139a4
RS
86(define-key menu-bar-file-menu [revert-buffer]
87 '("Revert Buffer" . revert-buffer))
88(define-key menu-bar-file-menu [write-file]
89 '("Save Buffer As..." . write-file))
90(define-key menu-bar-file-menu [save-buffer] '("Save Buffer" . save-buffer))
76202b57 91(define-key menu-bar-file-menu [dired] '("Open Directory..." . dired))
2f1139a4 92(define-key menu-bar-file-menu [open-file] '("Open File..." . find-file))
40a8cde1
RS
93
94;; This is just one element of the ediff menu--the first.
95(define-key menu-bar-ediff-menu [window]
96 '("This Window And Next Window" . compare-windows))
9bb8e471 97\f
33aa8946
RS
98(define-key menu-bar-edit-menu [query-replace]
99 '("Query Replace" . query-replace))
50d195ee
RS
100(define-key menu-bar-edit-menu [re-search-back]
101 '("Regexp Search Backwards" . re-search-backward))
102(define-key menu-bar-edit-menu [search-back]
103 '("Search Backwards" . search-backward))
104(define-key menu-bar-edit-menu [re-search-fwd]
105 '("Regexp Search" . re-search-forward))
106(define-key menu-bar-edit-menu [search-fwd]
107 '("Search" . search-forward))
9bb8e471
RS
108
109(define-key menu-bar-edit-menu [separator-misc]
110 '("--"))
111
112(define-key menu-bar-edit-menu [spell] '("Spell" . ispell-menu-map))
113(define-key menu-bar-edit-menu [fill] '("Fill" . fill-region))
114
115(define-key menu-bar-edit-menu [separator-edit]
116 '("--"))
117
118(define-key menu-bar-edit-menu [clear] '("Clear" . delete-region))
3dd92899
KH
119
120(define-key menu-bar-edit-menu [paste] '("Paste most recent" . yank))
121
122(defvar yank-menu (cons "Select Yank" nil))
123(fset 'yank-menu (cons 'keymap yank-menu))
124(define-key menu-bar-edit-menu [select-paste] '("Select and Paste" . yank-menu))
4c0317b1 125(define-key menu-bar-edit-menu [copy] '("Copy" . menu-bar-kill-ring-save))
057d49d1
RS
126(define-key menu-bar-edit-menu [cut] '("Cut" . kill-region))
127(define-key menu-bar-edit-menu [undo] '("Undo" . undo))
128
4c0317b1
RS
129(defun menu-bar-kill-ring-save (beg end)
130 (interactive "r")
131 (if (mouse-region-match)
132 (message "Select a region with the mouse does `copy' automatically")
133 (kill-ring-save beg end)))
134
057d49d1
RS
135(put 'fill-region 'menu-enable 'mark-active)
136(put 'kill-region 'menu-enable 'mark-active)
4c0317b1 137(put 'menu-bar-kill-ring-save 'menu-enable 'mark-active)
057d49d1 138(put 'yank 'menu-enable '(x-selection-exists-p))
3dd92899 139(put 'yank-menu 'menu-enable '(cdr yank-menu))
4c0317b1
RS
140(put 'delete-region 'menu-enable '(and mark-active
141 (not (mouse-region-match))))
057d49d1
RS
142(put 'undo 'menu-enable '(if (eq last-command 'undo)
143 pending-undo-list
144 (consp buffer-undo-list)))
3a841b0b 145(put 'query-replace 'menu-enable '(not buffer-read-only))
db774a16 146
9e18f0a0
RS
147(autoload 'ispell-menu-map "ispell" nil t 'keymap)
148
f9cf0be2 149;; These are alternative definitions for the cut, paste and copy
4c0317b1 150;; menu items. Use them if your system expects these to use the clipboard.
f9cf0be2 151
f9cf0be2
RS
152(put 'clipboard-kill-region 'menu-enable 'mark-active)
153(put 'clipboard-kill-ring-save 'menu-enable 'mark-active)
154(put 'clipboard-yank 'menu-enable
155 '(or (x-selection-exists-p) (x-selection-exists-p 'CLIPBOARD)))
156
157(defun clipboard-yank ()
158 "Reinsert the last stretch of killed text, or the clipboard contents."
159 (interactive)
160 (let ((x-select-enable-clipboard t))
161 (yank)))
162
163(defun clipboard-kill-ring-save (beg end)
164 "Copy region to kill ring, and save in the X clipboard."
165 (interactive "r")
166 (let ((x-select-enable-clipboard t))
167 (kill-ring-save beg end)))
168
169(defun clipboard-kill-region (beg end)
170 "Kill the region, and save it in the X clipboard."
171 (interactive "r")
172 (let ((x-select-enable-clipboard t))
173 (kill-region beg end)))
174
175(defun menu-bar-enable-clipboard ()
5cbdeb30
RS
176 "Make CUT, PASTE and COPY (keys and menu bar items) use the clipboard.
177Do the same for the keys of the same name."
f9cf0be2 178 (interactive)
5754d7f2
RS
179 ;; We can't use constant list structure here because it becomes pure,
180 ;; and because it gets modified with cache data.
181 (define-key menu-bar-edit-menu [paste]
182 (cons "Paste" 'clipboard-yank))
183 (define-key menu-bar-edit-menu [copy]
184 (cons "Copy" 'clipboard-kill-ring-save))
185 (define-key menu-bar-edit-menu [cut]
5cbdeb30
RS
186 (cons "Cut" 'clipboard-kill-region))
187
188 (define-key global-map [f20] 'clipboard-kill-region)
189 (define-key global-map [f16] 'clipboard-kill-ring-save)
190 (define-key global-map [f18] 'clipboard-yank)
191 ;; X11R6 versions
192 (define-key global-map [cut] 'clipboard-kill-region)
193 (define-key global-map [copy] 'clipboard-kill-ring-save)
194 (define-key global-map [paste] 'clipboard-yank))
f9cf0be2 195\f
efb166ff
RS
196(define-key menu-bar-help-menu [emacs-version]
197 '("Show Version" . emacs-version))
48433a65
RS
198(define-key menu-bar-help-menu [report-emacs-bug]
199 '("Send Bug Report" . report-emacs-bug))
ca9b40a1 200(define-key menu-bar-help-menu [emacs-tutorial]
db774a16 201 '("Emacs Tutorial" . help-with-tutorial))
2f1139a4
RS
202(define-key menu-bar-help-menu [man] '("Man..." . manual-entry))
203(define-key menu-bar-help-menu [describe-variable]
204 '("Describe Variable..." . describe-variable))
205(define-key menu-bar-help-menu [describe-function]
206 '("Describe Function..." . describe-function))
207(define-key menu-bar-help-menu [describe-key]
208 '("Describe Key..." . describe-key))
209(define-key menu-bar-help-menu [list-keybindings]
210 '("List Keybindings" . describe-bindings))
211(define-key menu-bar-help-menu [command-apropos]
212 '("Command Apropos..." . command-apropos))
213(define-key menu-bar-help-menu [describe-mode]
214 '("Describe Mode" . describe-mode))
215(define-key menu-bar-help-menu [info] '("Info" . info))
889560ed 216(define-key menu-bar-help-menu [emacs-faq] '("Emacs FAQ" . view-emacs-FAQ))
2f1139a4 217(define-key menu-bar-help-menu [emacs-news] '("Emacs News" . view-emacs-news))
889560ed 218
db774a16
RS
219(defun kill-this-buffer () ; for the menubar
220 "Kills the current buffer."
221 (interactive)
222 (kill-buffer (current-buffer)))
223
2f1139a4
RS
224(defun kill-this-buffer-enabled-p ()
225 (let ((count 0)
226 (buffers (buffer-list)))
227 (while buffers
228 (or (string-match "^ " (buffer-name (car buffers)))
229 (setq count (1+ count)))
230 (setq buffers (cdr buffers)))
231 (> count 1)))
232
db774a16 233(put 'save-buffer 'menu-enable '(buffer-modified-p))
da183f87
RS
234(put 'revert-buffer 'menu-enable
235 '(or revert-buffer-function revert-buffer-insert-file-contents-function
236 (and (buffer-file-name)
660fa562
RM
237 (or (buffer-modified-p)
238 (not (verify-visited-file-modtime (current-buffer)))))))
a0213a97
RS
239;; Permit deleting frame if it would leave a visible or iconified frame.
240(put 'delete-frame 'menu-enable
241 '(let ((frames (frame-list))
242 (count 0))
243 (while frames
244 (if (cdr (assq 'visibility (frame-parameters (car frames))))
245 (setq count (1+ count)))
246 (setq frames (cdr frames)))
247 (> count 1)))
2f1139a4
RS
248(put 'kill-this-buffer 'menu-enable '(kill-this-buffer-enabled-p))
249
db774a16
RS
250(put 'advertised-undo 'menu-enable
251 '(and (not (eq t buffer-undo-list))
252 (if (eq last-command 'undo)
2f1139a4
RS
253 (and (boundp 'pending-undo-list)
254 pending-undo-list)
255 buffer-undo-list)))
2877eac2 256
c3e1d435 257(defvar yank-menu-length 20
3dd92899
KH
258 "*Maximum length to display in the yank-menu.")
259
260(defun menu-bar-update-yank-menu (string old)
261 (let ((front (car (cdr yank-menu)))
262 (menu-string (if (<= (length string) yank-menu-length)
263 string
c3e1d435
RS
264 (concat
265 (substring string 0 (/ yank-menu-length 2))
266 "..."
267 (substring string (- (/ yank-menu-length 2)))))))
3dd92899
KH
268 ;; If we're supposed to be extending an existing string, and that
269 ;; string really is at the front of the menu, then update it in place.
270 (if (and old (or (eq old (car front))
271 (string= old (car front))))
dfabc98f 272 (progn
3dd92899
KH
273 (setcar front string)
274 (setcar (cdr front) menu-string))
275 (setcdr yank-menu
276 (cons
277 (cons string (cons menu-string 'menu-bar-select-yank))
278 (cdr yank-menu)))))
279 (if (> (length (cdr yank-menu)) kill-ring-max)
280 (setcdr (nthcdr kill-ring-max yank-menu) nil)))
281
282(defun menu-bar-select-yank ()
283 (interactive "*")
284 (push-mark (point))
285 (insert last-command-event))
40954111 286\f
09642d97
RS
287(define-key global-map [menu-bar buffer] '("Buffers" . menu-bar-buffers))
288
289(defalias 'menu-bar-buffers (make-sparse-keymap "Buffers"))
40954111 290
40954111
RS
291(defvar buffers-menu-max-size 10
292 "*Maximum number of entries which may appear on the Buffers menu.
293If this is 10, then only the ten most-recently-selected buffers are shown.
294If this is nil, then all buffers are shown.
295A large number or nil slows down menu responsiveness.")
296
d0690d12
RS
297(defvar list-buffers-directory nil)
298
08e8171f
RS
299(defvar menu-bar-update-buffers-maxbuf)
300
09642d97
RS
301(defun menu-bar-select-buffer ()
302 (interactive)
303 (switch-to-buffer last-command-event))
304
305(defun menu-bar-select-frame ()
306 (interactive)
307 (make-frame-visible last-command-event)
308 (raise-frame last-command-event)
309 (select-frame last-command-event))
310
c171b42f
RS
311(defun menu-bar-update-buffers-1 (elt)
312 (cons (format
08e8171f 313 (format "%%%ds %%s%%s %%s" menu-bar-update-buffers-maxbuf)
c171b42f
RS
314 (cdr elt)
315 (if (buffer-modified-p (car elt))
316 "*" " ")
317 (save-excursion
318 (set-buffer (car elt))
319 (if buffer-read-only "%" " "))
320 (let ((file
321 (or (buffer-file-name (car elt))
322 (save-excursion
323 (set-buffer (car elt))
324 list-buffers-directory)
325 "")))
326 (setq file (or (file-name-directory file)
327 ""))
328 (if (> (length file) 20)
329 (setq file (concat "..." (substring file -17))))
330 file))
331 (car elt)))
332
09642d97 333(defun menu-bar-update-buffers ()
29397c58 334 ;; If user discards the Buffers item, play along.
4d587a6c 335 (and (lookup-key (current-global-map) [menu-bar buffer])
29397c58
RS
336 (frame-or-buffer-changed-p)
337 (let ((buffers (buffer-list))
338 (frames (frame-list))
339 buffers-menu frames-menu)
340 ;; If requested, list only the N most recently selected buffers.
341 (if (and (integerp buffers-menu-max-size)
342 (> buffers-menu-max-size 1))
343 (if (> (length buffers) buffers-menu-max-size)
344 (setcdr (nthcdr buffers-menu-max-size buffers) nil)))
345
346 ;; Make the menu of buffers proper.
347 (setq buffers-menu
348 (cons "Select Buffer"
c171b42f
RS
349 (let* ((buffer-list
350 (mapcar 'list buffers))
351 tail
08e8171f 352 (menu-bar-update-buffers-maxbuf 0)
c171b42f
RS
353 (maxlen 0)
354 alist
355 head)
356 ;; Put into each element of buffer-list
357 ;; the name for actual display,
358 ;; perhaps truncated in the middle.
359 (setq tail buffer-list)
360 (while tail
361 (let ((name (buffer-name (car (car tail)))))
362 (setcdr (car tail)
363 (if (> (length name) 27)
364 (concat (substring name 0 12)
365 "..."
366 (substring name -12))
367 name)))
368 (setq tail (cdr tail)))
369 ;; Compute the maximum length of any name.
370 (setq tail buffer-list)
29397c58 371 (while tail
c171b42f 372 (or (eq ?\ (aref (cdr (car tail)) 0))
08e8171f
RS
373 (setq menu-bar-update-buffers-maxbuf
374 (max menu-bar-update-buffers-maxbuf
c171b42f 375 (length (cdr (car tail))))))
29397c58 376 (setq tail (cdr tail)))
c171b42f
RS
377 ;; Set ALIST to an alist of the form
378 ;; ITEM-STRING . BUFFER
379 (setq tail buffer-list)
29397c58
RS
380 (while tail
381 (let ((elt (car tail)))
c171b42f 382 (or (eq ?\ (aref (cdr elt) 0))
29397c58 383 (setq alist (cons
c171b42f 384 (menu-bar-update-buffers-1 elt)
29397c58
RS
385 alist)))
386 (and alist (> (length (car (car alist))) maxlen)
387 (setq maxlen (length (car (car alist))))))
388 (setq tail (cdr tail)))
389 (setq alist (nreverse alist))
390 (nconc (mapcar '(lambda (pair)
391 ;; This is somewhat risque, to use
392 ;; the buffer name itself as the event
393 ;; type to define, but it works.
394 ;; It would not work to use the buffer
395 ;; since a buffer as an event has its
396 ;; own meaning.
397 (nconc (list (buffer-name (cdr pair))
398 (car pair)
399 (cons nil nil))
400 'menu-bar-select-buffer))
401 alist)
402 (list
096ec7e7 403 (cons
29397c58
RS
404 'list-buffers
405 (cons
406 (concat (make-string (max (- (/ maxlen 2) 8) 0)
407 ?\ )
408 "List All Buffers")
409 'list-buffers)))))))
410
411
412 ;; Make a Frames menu if we have more than one frame.
413 (if (cdr frames)
414 (setq frames-menu
415 (cons "Select Frame"
416 (mapcar '(lambda (frame)
417 (nconc (list frame
418 (cdr (assq 'name
419 (frame-parameters frame)))
420 (cons nil nil))
421 'menu-bar-select-frame))
422 frames))))
423 (if buffers-menu
424 (setq buffers-menu (cons 'keymap buffers-menu)))
425 (if frames-menu
426 (setq frames-menu (cons 'keymap frames-menu)))
4d587a6c 427 (define-key (current-global-map) [menu-bar buffer]
29397c58
RS
428 (cons "Buffers"
429 (if (and buffers-menu frames-menu)
430 (list 'keymap "Buffers and Frames"
431 (cons 'buffers (cons "Buffers" buffers-menu))
432 (cons 'frames (cons "Frames" frames-menu)))
433 (or buffers-menu frames-menu 'undefined)))))))
09642d97
RS
434
435(add-hook 'menu-bar-update-hook 'menu-bar-update-buffers)
2f1139a4 436
40954111
RS
437;; this version is too slow
438;;;(defun format-buffers-menu-line (buffer)
439;;; "Returns a string to represent the given buffer in the Buffer menu.
440;;;nil means the buffer shouldn't be listed. You can redefine this."
441;;; (if (string-match "\\` " (buffer-name buffer))
442;;; nil
443;;; (save-excursion
444;;; (set-buffer buffer)
445;;; (let ((size (buffer-size)))
446;;; (format "%s%s %-19s %6s %-15s %s"
447;;; (if (buffer-modified-p) "*" " ")
448;;; (if buffer-read-only "%" " ")
449;;; (buffer-name)
450;;; size
451;;; mode-name
452;;; (or (buffer-file-name) ""))))))
453\f
7b7d6615
RS
454(defvar menu-bar-mode nil)
455
057d49d1 456(defun menu-bar-mode (flag)
dfd29450 457 "Toggle display of a menu bar on each frame.
057d49d1
RS
458This command applies to all frames that exist and frames to be
459created in the future.
460With a numeric argument, if the argument is negative,
dfd29450 461turn off menu bars; otherwise, turn on menu bars."
dad8e392 462 (interactive "P")
dad8e392 463
7b7d6615
RS
464 ;; Make menu-bar-mode and default-frame-alist consistent.
465 (let ((default (assq 'menu-bar-lines default-frame-alist)))
466 (if default
467 (setq menu-bar-mode (not (eq (cdr default) 0)))
468 (setq default-frame-alist
469 (cons (cons 'menu-bar-lines (if menu-bar-mode 1 0))
470 default-frame-alist))))
471
472 ;; Toggle or set the mode, according to FLAG.
473 (setq menu-bar-mode (if (null flag) (not menu-bar-mode)
474 (> (prefix-numeric-value flag) 0)))
475
476 ;; Apply it to default-frame-alist.
477 (let ((parameter (assq 'menu-bar-lines default-frame-alist)))
478 (if (consp parameter)
479 (setcdr parameter (if menu-bar-mode 1 0))
480 (setq default-frame-alist
481 (cons (cons 'menu-bar-lines (if menu-bar-mode 1 0))
482 default-frame-alist))))
483
484 ;; Apply it to existing frames.
485 (let ((frames (frame-list)))
486 (while frames
487 (let ((height (cdr (assq 'height (frame-parameters (car frames))))))
488 (modify-frame-parameters (car frames)
489 (list (cons 'menu-bar-lines
490 (if menu-bar-mode 1 0))))
491 (modify-frame-parameters (car frames)
492 (list (cons 'height height))))
493 (setq frames (cdr frames)))))
1db87953 494
bffa5d4d
RS
495(provide 'menu-bar)
496
235aa29b 497;;; menu-bar.el ends here