(icon-mode): Adapt to new hideshow and improve regexps.
[bpt/emacs.git] / lisp / menu-bar.el
CommitLineData
235aa29b
ER
1;;; menu-bar.el --- define a default menu bar.
2
b578f267
EN
3;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
4
235aa29b 5;; Author: RMS
b7f66977 6;; Keywords: internal
235aa29b 7
1db87953
RS
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
b578f267
EN
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
1db87953 24
260130bb
KH
25;; Avishai Yacobi suggested some menu rearrangements.
26
b578f267
EN
27;;; Code:
28
d537086b
RS
29;;; User options:
30
30e19aee 31(defcustom buffers-menu-max-size 10
d537086b
RS
32 "*Maximum number of entries which may appear on the Buffers menu.
33If this is 10, then only the ten most-recently-selected buffers are shown.
34If this is nil, then all buffers are shown.
30e19aee
RS
35A large number or nil slows down menu responsiveness."
36 :type '(choice integer
37 (const :tag "All" nil))
38 :group 'mouse)
d537086b 39
b132f2b1
RM
40;; Don't clobber an existing menu-bar keymap, to preserve any menu-bar key
41;; definitions made in loaddefs.el.
42(or (lookup-key global-map [menu-bar])
43 (define-key global-map [menu-bar] (make-sparse-keymap "menu-bar")))
22390f50 44(defvar menu-bar-help-menu (make-sparse-keymap "Help"))
ffbdd83d
RS
45
46;; Force Help item to come last, after the major mode's own items.
0d31efcd
KH
47;; The symbol used to be called `help', but that gets confused with the
48;; help key.
49(setq menu-bar-final-items '(help-menu))
ffbdd83d 50
0d31efcd 51(define-key global-map [menu-bar help-menu] (cons "Help" menu-bar-help-menu))
ffbdd83d
RS
52(defvar menu-bar-search-menu (make-sparse-keymap "Search"))
53(define-key global-map [menu-bar search] (cons "Search" menu-bar-search-menu))
22390f50 54(defvar menu-bar-edit-menu (make-sparse-keymap "Edit"))
40954111 55(define-key global-map [menu-bar edit] (cons "Edit" menu-bar-edit-menu))
ffbdd83d
RS
56(defvar menu-bar-tools-menu (make-sparse-keymap "Tools"))
57(define-key global-map [menu-bar tools] (cons "Tools" menu-bar-tools-menu))
58(defvar menu-bar-files-menu (make-sparse-keymap "Files"))
59(define-key global-map [menu-bar files] (cons "Files" menu-bar-files-menu))
1b009b97
RS
60
61;; This alias is for compatibility with 19.28 and before.
62(defvar menu-bar-file-menu menu-bar-files-menu)
9bb8e471 63\f
9dcdc43d
RS
64(defvar vc-menu-map (make-sparse-keymap "Version Control"))
65
147f1d2a
RS
66(define-key menu-bar-tools-menu [gdb] '("Debugger..." . gdb))
67(define-key menu-bar-tools-menu [compile] '("Compile..." . compile))
68(define-key menu-bar-tools-menu [grep] '("Search Files..." . grep))
69
70(define-key menu-bar-tools-menu [separator-1]
71 '("--"))
72
e1726722 73(define-key menu-bar-tools-menu [calendar] '("Display Calendar" . calendar))
c0965058 74(define-key menu-bar-tools-menu [compose-mail] '("Send Mail" . compose-mail))
ffbdd83d 75(define-key menu-bar-tools-menu [rmail] '("Read Mail" . rmail))
96a699d0 76(define-key menu-bar-tools-menu [gnus] '("Read Net News" . gnus))
ffbdd83d
RS
77
78(define-key menu-bar-tools-menu [separator-vc]
79 '("--"))
80
fe74180c 81(define-key menu-bar-tools-menu [vc]
ffbdd83d 82 (cons "Version Control" vc-menu-map))
9bb8e471 83
ffbdd83d 84(define-key menu-bar-tools-menu [separator-compare]
9bb8e471
RS
85 '("--"))
86
ffbdd83d 87(define-key menu-bar-tools-menu [epatch]
080ac1ac 88 '("Apply Patch" . menu-bar-epatch-menu))
ffbdd83d 89(define-key menu-bar-tools-menu [ediff-merge]
5438ecd3 90 '("Merge" . menu-bar-ediff-merge-menu))
57eed34a 91(define-key menu-bar-tools-menu [compare]
40a8cde1 92 '("Compare" . menu-bar-ediff-menu))
9bb8e471 93
ffbdd83d 94(define-key menu-bar-tools-menu [separator-print]
9bb8e471
RS
95 '("--"))
96
ffbdd83d
RS
97(put 'print-region 'menu-enable 'mark-active)
98(put 'ps-print-region-with-faces 'menu-enable 'mark-active)
99
100(define-key menu-bar-tools-menu [ps-print-region]
101 '("Postscript Print Region" . ps-print-region-with-faces))
102(define-key menu-bar-tools-menu [ps-print-buffer]
103 '("Postscript Print Buffer" . ps-print-buffer-with-faces))
104(define-key menu-bar-tools-menu [print-region]
105 '("Print Region" . print-region))
106(define-key menu-bar-tools-menu [print-buffer]
107 '("Print Buffer" . print-buffer))
108\f
109(define-key menu-bar-files-menu [exit-emacs]
110 '("Exit Emacs" . save-buffers-kill-emacs))
111
112(define-key menu-bar-files-menu [separator-exit]
113 '("--"))
114
115(define-key menu-bar-files-menu [one-window]
116 '("One Window" . delete-other-windows))
117
118(define-key menu-bar-files-menu [split-window]
119 '("Split Window" . split-window-vertically))
9bb8e471 120
ca1a9692
RS
121(if (fboundp 'delete-frame)
122 (progn
a4e4b916
RS
123 ;; Don't use delete-frame as event name
124 ;; because that is a special event.
125 (define-key menu-bar-files-menu [delete-this-frame]
ca1a9692 126 '("Delete Frame" . delete-frame))
ffbdd83d
RS
127 (define-key menu-bar-files-menu [make-frame-on-display]
128 '("Open New Display..." . make-frame-on-display))
129 (define-key menu-bar-files-menu [make-frame]
ca1a9692 130 '("Make New Frame" . make-frame))))
9bb8e471 131
ffbdd83d 132(define-key menu-bar-files-menu [separator-buffers]
9bb8e471
RS
133 '("--"))
134
ffbdd83d
RS
135(define-key menu-bar-files-menu [kill-buffer]
136 '("Kill Current Buffer" . kill-this-buffer))
137(define-key menu-bar-files-menu [insert-file]
1f50590a 138 '("Insert File..." . insert-file))
ffbdd83d 139(define-key menu-bar-files-menu [revert-buffer]
2f1139a4 140 '("Revert Buffer" . revert-buffer))
ffbdd83d 141(define-key menu-bar-files-menu [write-file]
2f1139a4 142 '("Save Buffer As..." . write-file))
ffbdd83d
RS
143(define-key menu-bar-files-menu [save-buffer] '("Save Buffer" . save-buffer))
144(define-key menu-bar-files-menu [dired] '("Open Directory..." . dired))
145(define-key menu-bar-files-menu [open-file] '("Open File..." . find-file))
40a8cde1 146
9bb8e471 147\f
ffbdd83d
RS
148(defun nonincremental-search-forward (string)
149 "Read a string and search for it nonincrementally."
150 (interactive "sSearch for string: ")
151 (if (equal string "")
152 (search-forward (car search-ring))
153 (isearch-update-ring string nil)
154 (search-forward string)))
155
156(defun nonincremental-search-backward (string)
157 "Read a string and search backward for it nonincrementally."
158 (interactive "sSearch for string: ")
159 (if (equal string "")
160 (search-backward (car search-ring))
161 (isearch-update-ring string nil)
162 (search-backward string)))
163
164(defun nonincremental-re-search-forward (string)
165 "Read a regular expression and search for it nonincrementally."
166 (interactive "sSearch for regexp: ")
167 (if (equal string "")
168 (re-search-forward (car regexp-search-ring))
169 (isearch-update-ring string t)
170 (re-search-forward string)))
171
172(defun nonincremental-re-search-backward (string)
173 "Read a regular expression and search backward for it nonincrementally."
174 (interactive "sSearch for regexp: ")
175 (if (equal string "")
176 (re-search-backward (car regexp-search-ring))
177 (isearch-update-ring string t)
178 (re-search-backward string)))
179
1f50590a 180(defun nonincremental-repeat-search-forward ()
ffbdd83d
RS
181 "Search forward for the previous search string."
182 (interactive)
183 (search-forward (car search-ring)))
184
1f50590a 185(defun nonincremental-repeat-search-backward ()
ffbdd83d
RS
186 "Search backward for the previous search string."
187 (interactive)
188 (search-backward (car search-ring)))
189
1f50590a 190(defun nonincremental-repeat-re-search-forward ()
ffbdd83d
RS
191 "Search forward for the previous regular expression."
192 (interactive)
193 (re-search-forward (car regexp-search-ring)))
194
1f50590a 195(defun nonincremental-repeat-re-search-backward ()
ffbdd83d
RS
196 "Search backward for the previous regular expression."
197 (interactive)
198 (re-search-backward (car regexp-search-ring)))
199
1f50590a
RS
200(define-key menu-bar-search-menu [query-replace-regexp]
201 '("Query Replace Regexp..." . query-replace-regexp))
ffbdd83d 202(define-key menu-bar-search-menu [query-replace]
1f50590a 203 '("Query Replace..." . query-replace))
ffbdd83d 204(define-key menu-bar-search-menu [find-tag]
1f50590a 205 '("Find Tag..." . find-tag))
ffbdd83d
RS
206(define-key menu-bar-search-menu [bookmark]
207 '("Bookmarks" . menu-bar-bookmark-map))
208
209(define-key menu-bar-search-menu [separator-search]
210 '("--"))
211
fe74180c 212(define-key menu-bar-search-menu [repeat-regexp-back]
ffbdd83d 213 '("Repeat Regexp Backwards" . nonincremental-repeat-re-search-backward))
fe74180c 214(define-key menu-bar-search-menu [repeat-search-back]
ffbdd83d 215 '("Repeat Backwards" . nonincremental-repeat-search-backward))
fe74180c 216(define-key menu-bar-search-menu [repeat-regexp-fwd]
ffbdd83d 217 '("Repeat Regexp" . nonincremental-repeat-re-search-forward))
fe74180c 218(define-key menu-bar-search-menu [repeat-search-fwd]
ffbdd83d
RS
219 '("Repeat Search" . nonincremental-repeat-search-forward))
220
221(define-key menu-bar-search-menu [separator-repeat]
9bb8e471
RS
222 '("--"))
223
fe74180c 224(define-key menu-bar-search-menu [re-search-backward]
1f50590a 225 '("Regexp Search Backwards..." . nonincremental-re-search-backward))
fe74180c 226(define-key menu-bar-search-menu [search-backward]
1f50590a 227 '("Search Backwards..." . nonincremental-search-backward))
fe74180c 228(define-key menu-bar-search-menu [re-search-forward]
1f50590a 229 '("Regexp Search..." . nonincremental-re-search-forward))
fe74180c 230(define-key menu-bar-search-menu [search-forward]
1f50590a 231 '("Search..." . nonincremental-search-forward))
ffbdd83d 232\f
5b42ec2b
RS
233(if (fboundp 'start-process)
234 (define-key menu-bar-edit-menu [spell] '("Spell" . ispell-menu-map)))
9bb8e471 235(define-key menu-bar-edit-menu [fill] '("Fill" . fill-region))
6507ffb1 236(define-key menu-bar-edit-menu [props] '("Text Properties" . facemenu-menu))
9bb8e471
RS
237
238(define-key menu-bar-edit-menu [separator-edit]
239 '("--"))
240
241(define-key menu-bar-edit-menu [clear] '("Clear" . delete-region))
3dd92899 242
e1726722 243(define-key menu-bar-edit-menu [paste] '("Paste Most Recent" . yank))
3dd92899
KH
244
245(defvar yank-menu (cons "Select Yank" nil))
246(fset 'yank-menu (cons 'keymap yank-menu))
247(define-key menu-bar-edit-menu [select-paste] '("Select and Paste" . yank-menu))
4c0317b1 248(define-key menu-bar-edit-menu [copy] '("Copy" . menu-bar-kill-ring-save))
057d49d1
RS
249(define-key menu-bar-edit-menu [cut] '("Cut" . kill-region))
250(define-key menu-bar-edit-menu [undo] '("Undo" . undo))
251
4c0317b1
RS
252(defun menu-bar-kill-ring-save (beg end)
253 (interactive "r")
254 (if (mouse-region-match)
255 (message "Select a region with the mouse does `copy' automatically")
256 (kill-ring-save beg end)))
257
25b048ee
RS
258(put 'fill-region 'menu-enable '(and mark-active (not buffer-read-only)))
259(put 'kill-region 'menu-enable '(and mark-active (not buffer-read-only)))
4c0317b1 260(put 'menu-bar-kill-ring-save 'menu-enable 'mark-active)
25b048ee
RS
261(put 'yank 'menu-enable '(and (x-selection-exists-p) (not buffer-read-only)))
262(put 'yank-menu 'menu-enable '(and (cdr yank-menu) (not buffer-read-only)))
4c0317b1 263(put 'delete-region 'menu-enable '(and mark-active
25b048ee 264 (not buffer-read-only)
4c0317b1 265 (not (mouse-region-match))))
25b048ee
RS
266(put 'undo 'menu-enable '(and (not buffer-read-only)
267 (if (eq last-command 'undo)
268 pending-undo-list
269 (consp buffer-undo-list))))
3a841b0b 270(put 'query-replace 'menu-enable '(not buffer-read-only))
25b048ee 271(put 'query-replace-regexp 'menu-enable '(not buffer-read-only))
db774a16 272
9e18f0a0
RS
273(autoload 'ispell-menu-map "ispell" nil t 'keymap)
274
f9cf0be2 275;; These are alternative definitions for the cut, paste and copy
4c0317b1 276;; menu items. Use them if your system expects these to use the clipboard.
f9cf0be2 277
f9cf0be2
RS
278(put 'clipboard-kill-region 'menu-enable 'mark-active)
279(put 'clipboard-kill-ring-save 'menu-enable 'mark-active)
280(put 'clipboard-yank 'menu-enable
281 '(or (x-selection-exists-p) (x-selection-exists-p 'CLIPBOARD)))
282
283(defun clipboard-yank ()
284 "Reinsert the last stretch of killed text, or the clipboard contents."
285 (interactive)
286 (let ((x-select-enable-clipboard t))
287 (yank)))
288
289(defun clipboard-kill-ring-save (beg end)
290 "Copy region to kill ring, and save in the X clipboard."
291 (interactive "r")
292 (let ((x-select-enable-clipboard t))
293 (kill-ring-save beg end)))
294
295(defun clipboard-kill-region (beg end)
296 "Kill the region, and save it in the X clipboard."
297 (interactive "r")
298 (let ((x-select-enable-clipboard t))
299 (kill-region beg end)))
300
301(defun menu-bar-enable-clipboard ()
5cbdeb30
RS
302 "Make CUT, PASTE and COPY (keys and menu bar items) use the clipboard.
303Do the same for the keys of the same name."
f9cf0be2 304 (interactive)
5754d7f2
RS
305 ;; We can't use constant list structure here because it becomes pure,
306 ;; and because it gets modified with cache data.
307 (define-key menu-bar-edit-menu [paste]
308 (cons "Paste" 'clipboard-yank))
309 (define-key menu-bar-edit-menu [copy]
310 (cons "Copy" 'clipboard-kill-ring-save))
311 (define-key menu-bar-edit-menu [cut]
5cbdeb30
RS
312 (cons "Cut" 'clipboard-kill-region))
313
314 (define-key global-map [f20] 'clipboard-kill-region)
315 (define-key global-map [f16] 'clipboard-kill-ring-save)
316 (define-key global-map [f18] 'clipboard-yank)
317 ;; X11R6 versions
318 (define-key global-map [cut] 'clipboard-kill-region)
319 (define-key global-map [copy] 'clipboard-kill-ring-save)
320 (define-key global-map [paste] 'clipboard-yank))
f9cf0be2 321\f
a9f53ffb
RS
322
323;;; Menu support
324
325(defvar menu-bar-custom-menu (make-sparse-keymap "Customize"))
326
c9a86e71
RS
327(define-key menu-bar-custom-menu [custom-menu-update]
328 '("Update This Menu" . custom-menu-update))
a9f53ffb
RS
329(define-key menu-bar-custom-menu [customize-apropos]
330 '("Apropos..." . customize-apropos))
c9a86e71
RS
331(define-key menu-bar-custom-menu [customize-group]
332 '("Specific Group..." . customize-group))
a9f53ffb 333(define-key menu-bar-custom-menu [customize-face]
c9a86e71
RS
334 '("Specific Face..." . customize-face))
335(define-key menu-bar-custom-menu [customize-variable]
336 '("Specific Variable..." . customize-variable))
a9f53ffb 337(define-key menu-bar-custom-menu [customize]
c9a86e71 338 '("Browse Hierarchy of User Options" . customize))
a9f53ffb 339
efb166ff
RS
340(define-key menu-bar-help-menu [emacs-version]
341 '("Show Version" . emacs-version))
48433a65 342(define-key menu-bar-help-menu [report-emacs-bug]
1c6e18f6 343 '("Send Bug Report..." . report-emacs-bug))
260130bb
KH
344(define-key menu-bar-help-menu [finder-by-keyword]
345 '("Find Lisp Packages..." . finder-by-keyword))
ca9b40a1 346(define-key menu-bar-help-menu [emacs-tutorial]
db774a16 347 '("Emacs Tutorial" . help-with-tutorial))
260130bb
KH
348(define-key menu-bar-help-menu [man]
349 '("Man..." . manual-entry))
2f1139a4
RS
350(define-key menu-bar-help-menu [describe-variable]
351 '("Describe Variable..." . describe-variable))
352(define-key menu-bar-help-menu [describe-function]
353 '("Describe Function..." . describe-function))
354(define-key menu-bar-help-menu [describe-key]
355 '("Describe Key..." . describe-key))
356(define-key menu-bar-help-menu [list-keybindings]
357 '("List Keybindings" . describe-bindings))
358(define-key menu-bar-help-menu [command-apropos]
359 '("Command Apropos..." . command-apropos))
360(define-key menu-bar-help-menu [describe-mode]
361 '("Describe Mode" . describe-mode))
e1726722 362(define-key menu-bar-help-menu [info] '("Browse Manuals" . info))
889560ed 363(define-key menu-bar-help-menu [emacs-faq] '("Emacs FAQ" . view-emacs-FAQ))
2f1139a4 364(define-key menu-bar-help-menu [emacs-news] '("Emacs News" . view-emacs-news))
a0cd87a4
RS
365(define-key menu-bar-help-menu [customize-menu]
366 (cons "Customize" menu-bar-custom-menu))
889560ed 367
db774a16
RS
368(defun kill-this-buffer () ; for the menubar
369 "Kills the current buffer."
370 (interactive)
371 (kill-buffer (current-buffer)))
372
2f1139a4
RS
373(defun kill-this-buffer-enabled-p ()
374 (let ((count 0)
375 (buffers (buffer-list)))
376 (while buffers
377 (or (string-match "^ " (buffer-name (car buffers)))
378 (setq count (1+ count)))
379 (setq buffers (cdr buffers)))
a6f8cbf1 380 (and (not (window-minibuffer-p (frame-selected-window menu-updating-frame)))
1f50590a
RS
381 (> count 1))))
382
383(put 'kill-this-buffer 'menu-enable '(kill-this-buffer-enabled-p))
384
385(put 'save-buffer 'menu-enable
386 '(and (buffer-modified-p)
a6f8cbf1 387 (not (window-minibuffer-p (frame-selected-window menu-updating-frame)))))
1f50590a
RS
388
389(put 'write-file 'menu-enable
a6f8cbf1 390 '(not (window-minibuffer-p (frame-selected-window menu-updating-frame))))
1f50590a
RS
391
392(put 'find-file 'menu-enable
a6f8cbf1 393 '(not (window-minibuffer-p (frame-selected-window menu-updating-frame))))
1f50590a
RS
394
395(put 'dired 'menu-enable
a6f8cbf1 396 '(not (window-minibuffer-p (frame-selected-window menu-updating-frame))))
1f50590a
RS
397
398(put 'insert-file 'menu-enable
a6f8cbf1 399 '(not (window-minibuffer-p (frame-selected-window menu-updating-frame))))
2f1139a4 400
da183f87
RS
401(put 'revert-buffer 'menu-enable
402 '(or revert-buffer-function revert-buffer-insert-file-contents-function
403 (and (buffer-file-name)
660fa562
RM
404 (or (buffer-modified-p)
405 (not (verify-visited-file-modtime (current-buffer)))))))
82a74107 406
a0213a97
RS
407;; Permit deleting frame if it would leave a visible or iconified frame.
408(put 'delete-frame 'menu-enable
82a74107
KH
409 '(delete-frame-enabled-p))
410
411(defun delete-frame-enabled-p ()
412 "Return non-nil if `delete-frame' should be enabled in the menu bar."
413 (let ((frames (frame-list))
27aa8132
RS
414 (count 0))
415 (while frames
416 (if (frame-visible-p (car frames))
417 (setq count (1+ count)))
418 (setq frames (cdr frames)))
419 (> count 1)))
2f1139a4 420
db774a16
RS
421(put 'advertised-undo 'menu-enable
422 '(and (not (eq t buffer-undo-list))
423 (if (eq last-command 'undo)
2f1139a4
RS
424 (and (boundp 'pending-undo-list)
425 pending-undo-list)
426 buffer-undo-list)))
2877eac2 427
30e19aee
RS
428(defcustom yank-menu-length 20
429 "*Maximum length to display in the yank-menu."
430 :type 'integer
431 :group 'mouse)
3dd92899
KH
432
433(defun menu-bar-update-yank-menu (string old)
434 (let ((front (car (cdr yank-menu)))
435 (menu-string (if (<= (length string) yank-menu-length)
436 string
c3e1d435
RS
437 (concat
438 (substring string 0 (/ yank-menu-length 2))
439 "..."
440 (substring string (- (/ yank-menu-length 2)))))))
7c70a955
RS
441 ;; Don't let the menu string be all dashes
442 ;; because that has a special meaning in a menu.
443 (if (string-match "\\`-+\\'" menu-string)
444 (setq menu-string (concat menu-string " ")))
3dd92899
KH
445 ;; If we're supposed to be extending an existing string, and that
446 ;; string really is at the front of the menu, then update it in place.
447 (if (and old (or (eq old (car front))
448 (string= old (car front))))
dfabc98f 449 (progn
3dd92899
KH
450 (setcar front string)
451 (setcar (cdr front) menu-string))
452 (setcdr yank-menu
453 (cons
454 (cons string (cons menu-string 'menu-bar-select-yank))
455 (cdr yank-menu)))))
456 (if (> (length (cdr yank-menu)) kill-ring-max)
457 (setcdr (nthcdr kill-ring-max yank-menu) nil)))
458
459(defun menu-bar-select-yank ()
460 (interactive "*")
461 (push-mark (point))
462 (insert last-command-event))
40954111 463\f
3f557298
RS
464;; This definition is just to show what this looks like.
465;; It gets overridden below when menu-bar-update-buffers is called.
466(define-key global-map [menu-bar buffer]
467 (cons "Buffers" (make-sparse-keymap "Buffers")))
40954111 468
d0690d12
RS
469(defvar list-buffers-directory nil)
470
08e8171f
RS
471(defvar menu-bar-update-buffers-maxbuf)
472
09642d97
RS
473(defun menu-bar-select-buffer ()
474 (interactive)
475 (switch-to-buffer last-command-event))
476
477(defun menu-bar-select-frame ()
478 (interactive)
479 (make-frame-visible last-command-event)
480 (raise-frame last-command-event)
481 (select-frame last-command-event))
482
c171b42f
RS
483(defun menu-bar-update-buffers-1 (elt)
484 (cons (format
08e8171f 485 (format "%%%ds %%s%%s %%s" menu-bar-update-buffers-maxbuf)
c171b42f
RS
486 (cdr elt)
487 (if (buffer-modified-p (car elt))
488 "*" " ")
489 (save-excursion
490 (set-buffer (car elt))
491 (if buffer-read-only "%" " "))
492 (let ((file
493 (or (buffer-file-name (car elt))
494 (save-excursion
495 (set-buffer (car elt))
496 list-buffers-directory)
497 "")))
498 (setq file (or (file-name-directory file)
499 ""))
500 (if (> (length file) 20)
501 (setq file (concat "..." (substring file -17))))
502 file))
503 (car elt)))
504
06ff7539
RS
505(defvar menu-bar-buffers-menu-list-buffers-entry nil)
506
09642d97 507(defun menu-bar-update-buffers ()
29397c58 508 ;; If user discards the Buffers item, play along.
4d587a6c 509 (and (lookup-key (current-global-map) [menu-bar buffer])
29397c58
RS
510 (frame-or-buffer-changed-p)
511 (let ((buffers (buffer-list))
512 (frames (frame-list))
b3398af1 513 (maxlen 0)
29397c58
RS
514 buffers-menu frames-menu)
515 ;; If requested, list only the N most recently selected buffers.
516 (if (and (integerp buffers-menu-max-size)
517 (> buffers-menu-max-size 1))
518 (if (> (length buffers) buffers-menu-max-size)
519 (setcdr (nthcdr buffers-menu-max-size buffers) nil)))
520
521 ;; Make the menu of buffers proper.
522 (setq buffers-menu
523 (cons "Select Buffer"
c171b42f
RS
524 (let* ((buffer-list
525 (mapcar 'list buffers))
526 tail
08e8171f 527 (menu-bar-update-buffers-maxbuf 0)
c171b42f
RS
528 alist
529 head)
530 ;; Put into each element of buffer-list
531 ;; the name for actual display,
532 ;; perhaps truncated in the middle.
533 (setq tail buffer-list)
534 (while tail
535 (let ((name (buffer-name (car (car tail)))))
536 (setcdr (car tail)
537 (if (> (length name) 27)
538 (concat (substring name 0 12)
539 "..."
540 (substring name -12))
541 name)))
542 (setq tail (cdr tail)))
543 ;; Compute the maximum length of any name.
544 (setq tail buffer-list)
29397c58 545 (while tail
c171b42f 546 (or (eq ?\ (aref (cdr (car tail)) 0))
08e8171f
RS
547 (setq menu-bar-update-buffers-maxbuf
548 (max menu-bar-update-buffers-maxbuf
c171b42f 549 (length (cdr (car tail))))))
29397c58 550 (setq tail (cdr tail)))
c171b42f
RS
551 ;; Set ALIST to an alist of the form
552 ;; ITEM-STRING . BUFFER
553 (setq tail buffer-list)
29397c58
RS
554 (while tail
555 (let ((elt (car tail)))
c171b42f 556 (or (eq ?\ (aref (cdr elt) 0))
29397c58 557 (setq alist (cons
c171b42f 558 (menu-bar-update-buffers-1 elt)
29397c58
RS
559 alist)))
560 (and alist (> (length (car (car alist))) maxlen)
561 (setq maxlen (length (car (car alist))))))
562 (setq tail (cdr tail)))
563 (setq alist (nreverse alist))
06ff7539
RS
564 ;; Make the menu item for list-buffers
565 ;; or reuse the one we already have.
566 ;; The advantage in reusing one
567 ;; is that it already has the keyboard equivalent
568 ;; cached, so we save the time to look that up again.
569 (or menu-bar-buffers-menu-list-buffers-entry
570 (setq menu-bar-buffers-menu-list-buffers-entry
571 (cons
572 'list-buffers
573 (cons
574 ""
575 'list-buffers))))
576 ;; Update the item string for menu's new width.
577 (setcar (cdr menu-bar-buffers-menu-list-buffers-entry)
578 (concat (make-string (max (- (/ maxlen 2) 8) 0)
579 ?\ )
580 "List All Buffers"))
581 ;; Now make the actual list of items,
582 ;; ending with the list-buffers item.
29397c58
RS
583 (nconc (mapcar '(lambda (pair)
584 ;; This is somewhat risque, to use
585 ;; the buffer name itself as the event
586 ;; type to define, but it works.
587 ;; It would not work to use the buffer
588 ;; since a buffer as an event has its
589 ;; own meaning.
590 (nconc (list (buffer-name (cdr pair))
591 (car pair)
592 (cons nil nil))
593 'menu-bar-select-buffer))
594 alist)
06ff7539 595 (list menu-bar-buffers-menu-list-buffers-entry)))))
29397c58
RS
596
597
598 ;; Make a Frames menu if we have more than one frame.
599 (if (cdr frames)
b3398af1
RS
600 (let ((name (concat (make-string (max (- (/ maxlen 2) 3) 0)
601 ?\ )
602 "Frames"))
603 (frames-menu
604 (cons 'keymap
605 (cons "Select Frame"
606 (mapcar '(lambda (frame)
607 (nconc (list frame
608 (cdr (assq 'name
609 (frame-parameters frame)))
610 (cons nil nil))
611 'menu-bar-select-frame))
612 frames)))))
613 ;; Put it underneath the Buffers menu.
614 (setq buffers-menu (cons (cons 'frames (cons name frames-menu))
615 buffers-menu))))
29397c58
RS
616 (if buffers-menu
617 (setq buffers-menu (cons 'keymap buffers-menu)))
4d587a6c 618 (define-key (current-global-map) [menu-bar buffer]
b3398af1 619 (cons "Buffers" buffers-menu)))))
09642d97
RS
620
621(add-hook 'menu-bar-update-hook 'menu-bar-update-buffers)
2f1139a4 622
3f557298
RS
623(menu-bar-update-buffers)
624
40954111
RS
625;; this version is too slow
626;;;(defun format-buffers-menu-line (buffer)
627;;; "Returns a string to represent the given buffer in the Buffer menu.
628;;;nil means the buffer shouldn't be listed. You can redefine this."
629;;; (if (string-match "\\` " (buffer-name buffer))
630;;; nil
631;;; (save-excursion
632;;; (set-buffer buffer)
633;;; (let ((size (buffer-size)))
634;;; (format "%s%s %-19s %6s %-15s %s"
635;;; (if (buffer-modified-p) "*" " ")
636;;; (if buffer-read-only "%" " ")
637;;; (buffer-name)
638;;; size
639;;; mode-name
640;;; (or (buffer-file-name) ""))))))
641\f
25b048ee
RS
642;;; Set up a menu bar menu for the minibuffer.
643
644(mapcar
645 (function
646 (lambda (map)
647 (define-key map [menu-bar minibuf]
648 (cons "Minibuf" (make-sparse-keymap "Minibuf")))))
649 (list minibuffer-local-ns-map
650 minibuffer-local-must-match-map
651 minibuffer-local-isearch-map
652 minibuffer-local-map
653 minibuffer-local-completion-map))
654
655(mapcar
656 (function
657 (lambda (map)
658 (define-key map [menu-bar minibuf ?\?]
659 '("List Completions" . minibuffer-completion-help))
660 (define-key map [menu-bar minibuf space]
661 '("Complete Word" . minibuffer-complete-word))
662 (define-key map [menu-bar minibuf tab]
4e9d1906 663 '("Complete" . minibuffer-complete))
25b048ee
RS
664 ))
665 (list minibuffer-local-must-match-map
666 minibuffer-local-completion-map))
667
668(mapcar
669 (function
670 (lambda (map)
671 (define-key map [menu-bar minibuf quit]
672 '("Quit" . keyboard-escape-quit))
673 (define-key map [menu-bar minibuf return]
674 '("Enter" . exit-minibuffer))
675 ))
676 (list minibuffer-local-ns-map
677 minibuffer-local-must-match-map
678 minibuffer-local-isearch-map
679 minibuffer-local-map
680 minibuffer-local-completion-map))
681\f
7b7d6615
RS
682(defvar menu-bar-mode nil)
683
057d49d1 684(defun menu-bar-mode (flag)
dfd29450 685 "Toggle display of a menu bar on each frame.
057d49d1
RS
686This command applies to all frames that exist and frames to be
687created in the future.
688With a numeric argument, if the argument is negative,
dfd29450 689turn off menu bars; otherwise, turn on menu bars."
dad8e392 690 (interactive "P")
dad8e392 691
7b7d6615
RS
692 ;; Make menu-bar-mode and default-frame-alist consistent.
693 (let ((default (assq 'menu-bar-lines default-frame-alist)))
694 (if default
695 (setq menu-bar-mode (not (eq (cdr default) 0)))
696 (setq default-frame-alist
697 (cons (cons 'menu-bar-lines (if menu-bar-mode 1 0))
698 default-frame-alist))))
699
700 ;; Toggle or set the mode, according to FLAG.
701 (setq menu-bar-mode (if (null flag) (not menu-bar-mode)
702 (> (prefix-numeric-value flag) 0)))
703
704 ;; Apply it to default-frame-alist.
705 (let ((parameter (assq 'menu-bar-lines default-frame-alist)))
706 (if (consp parameter)
707 (setcdr parameter (if menu-bar-mode 1 0))
708 (setq default-frame-alist
709 (cons (cons 'menu-bar-lines (if menu-bar-mode 1 0))
710 default-frame-alist))))
711
712 ;; Apply it to existing frames.
713 (let ((frames (frame-list)))
714 (while frames
715 (let ((height (cdr (assq 'height (frame-parameters (car frames))))))
716 (modify-frame-parameters (car frames)
717 (list (cons 'menu-bar-lines
718 (if menu-bar-mode 1 0))))
719 (modify-frame-parameters (car frames)
720 (list (cons 'height height))))
721 (setq frames (cdr frames)))))
1db87953 722
bffa5d4d
RS
723(provide 'menu-bar)
724
235aa29b 725;;; menu-bar.el ends here