Please remove this {{Draft}}template, when you're sure the page is complete and correct.
|
Contents
- 1 Introduction
- 2 Files in support of Emacs in a Mageia system
- 3 Elisp code for customization
- 3.1 Common issues
- 3.2 Customizing non-functional properties
- 3.3 Customization of keyboard shortcuts
- 3.4 Customization of the menu bar
- 3.4.1 Naming menus and menu-items, finding the name of an item to be modified
- 3.4.2 Deleting an entire menu from the menu-bar, or deleting one of its menu-items
- 3.4.3 Adding a new item to a menu of the menu-bar
- 3.4.4 Adding a new menu to the menu-bar
- 3.4.5 A modified File menu
- 3.4.6 New Edit menu - selected issues
- 3.5 Debugging customization code
- 4 Documentation, references
- 5 Conclusions
- 6 Appendix: examples of Elisp code
Introduction
Emacs and Xemacs in Mageia
Up to and including Mageia-5, both Xemacs and Emacs packages had been part of the distribution. Future releases will probably not offer an Xemacs package any more - (1) upstream Xemacs is practically un-maintained: the latest stable release dates from 2009, and the version available in Mageia-5 suffers from a severe bug - https://bugs.mageia.org/show_bug.cgi?id=11254 , and (2) Emacs is a perfectly valid and properly maintained alternative. Therefore, it is advisable for users of Xemacs to consider rapidly migrating to Emacs.
Customization of Emacs
Just as with Xemacs, the control of the user interface of Emacs is implemented by "Elisp" code ("Emacs Lisp", a clone of the Lisp language, introduced in the late 1950's - a big compliment, not a negative comment). There exist practically no differences between Elisp in Xemacs and Emacs. Nevertheless, the libraries of Elisp modules that are required in support of such code differ between Xemacs and Emacs: the code written for personalizing the user interface of Xemacs needs to be adapted in order to implement a corresponding user interface for Emacs.
(X)emacs claims to be self-documenting. Much information in support of customization can be obtained by using the on-line help facilities offered in Emacs. However, on-line help is only available where the author of the corresponding code had included pertinent information into the source-code - and this is not everywhere the case. For instance, some of the most important library functions used for implementing the menu-bar are not well documented.
Scope of this wiki-page
The present wiki-page was originally aimed at supporting the migration from Xemacs to Emacs. But, drafting the page resulted increasingly in a kind of "quick guide to customizing Emacs" - and that is what the wiki-page now formally is. Nevertheless, the information relative to the migration from Xemacs to Emacs has been kept on board.
There exists ample documentation on Emacs and Elisp - this guide assumes that the reader will refer to that documentation whenever necessary, or has already some basic reading knowledge.
This wiki-page tries to be complementary to the already existing documentation: it selects and presents information that is relevant to customization. The structure of the text tries to compromise between a document that is agreeable to read, and the ease of finding particular pieces of information as need arises during the process of customization.
The page focuses on the creation of simple customization code and on customizing Emacs for a well defined usage profile. Customization can also produce sophisticated extensions of Emacs functionality and enhance portability, but that is beyond the scope of this page.
Files in support of Emacs in a Mageia system
Library modules
No user ever needs to look at the code that implements Emacs. However, if you want to customize the behavior of emacs, you need to put together - at least small - pieces of Elisp code. This can be substantially eased by consulting Elisp code that exists as part of emacs.
You find the library of Elips modules at "/usr/share/emacs/24.3/lisp/...". By default, the Emacs package of Mageia only installs compiled modules (xxx.elc files). If you want to consult the Elisp source-code, you also need to install the package emacs-el and than to de-compress the thus loaded xxx.el.gz files with gunzip.
A reminder: you can use the Mageia control center (its drakrpm component) to find the absolute paths of the files installed by the package (just open the "Files:" tab of the "Software management" window).
Initialization files
Events during the initialization of Emacs
The precise sequence of events that happen when emacs is launched is documented in the the emacs manual. In particular:
- first, emacs loads and executes all executable .el or .elc files in the directory /etc/emacs/site-start.d/ - the site initialization code,
- it then loads and executes a user initialization file at $HOME/.emacs or $HOME/.emacs.d/init.el - if such a file exists.
Keep this sequence of actions in mind when you write customization code, and remember that user initialization code may modify the results of site initialization.
Placing the initialization files
The Emacs documentation suggests $HOME/.emacs as the location for the user initialization file. However, this is not a good place: Xemacs considers .emacs as the potential name of its directory with user customization files, and Xemacs suggests to modify the contents of that file - a risk that can be avoided by placing the user initialization file of Emacs at $HOME/.emacs.d/init.el, an alternative location that is also supported.
In case you create site-initialization code (code that will be run for each user when emacs is launched), that code should be stored as files in directory /etc/emacs/site-start/.
The following lines describe an alternative approach that is well suited for Emacs on a single-user machine:
- store the bulk of the initialization code as shared setup files in some protected (belonging to root) directory,
- in $HOME/.emacs.d/init.el, do not much more than simply loading these files.
This approach offers several advantages:
- init.el remains small: it is easy to safely switch between vanilla Emacs and customized Emacs (the term "vanilla Emacs" is used throughout this wiki-page to refer to Emacs as it is installed from the Mageia repositories),
- the initialization modules can be shared between users (a common user and root, for instance - I have different background colors for "user Emacs" and "root Emacs" without needing to modify the distro-provided Emacs, just as I do for command-line terminal emulator windows),
- the directory with the initialization code can be put into a separate file-system, allowing to share a single copy between several OS partitions (useful when - for instance - you have several releases of Mageia in co-existance).
Potential conflicts between Xemacs and Emacs
Emacs and Xemacs are still very close to their common origin and the name-spaces still have some overlap. There exist some slight incompatibilities:
- The xemacs-extras package is in conflict with the emacs package: it is not possible to have a system that has, both, the emacs and the xemacs-extras packages installed. If, during migration, it is desirable to have Xemacs and Emacs in co-existance, the package xemacs-extra needs to be un-installed.
- As already mentioned, Xemacs considers the directory $HOME/.emacs as its initialization directory and risks to destroy a file at that location.
Elisp code for customization
Common issues
Name-space considerations
All functions and global (non-buffer-specific) variables in Emacs use a single name-space. If customization introduces function or variable names, be careful that their names do not coincide with existing names! A collision of a function name, for instance, would result in the re-definition of the existing Emacs function. The best method to avoid such collisions is to systematically use "my-..." or "nn-..." for all function and global variable names created for customization ("nn" being your initials).
Self documentation
Customization means writing code for personal use, and documentation becomes a secondary issue. Nevertheless, sticking to Emacs coding conventions on documentation is a good thing to do - it helps when code needs to be re-viewed some time in the far future, or when code is used by other users.
Documentation to provide in function headers
A function is documented in the header of the function definition:
- you compose documentation as a single string,
- you add that string as a third list-item in the header of the function definition (after the name of the function and after list of arguments, see the definition of the function my-setup-frame).
Newline characters in the documentation are non-transparent: Emacs treats them as part of the documentation string, just as white-spaces that follow the newline. The documentation string will be displayed as part of the information Emacs provides in response to a <Control-h> f key-sequence
Documentation to provide with the definition of variables
A variable is documented in the defvar command:
- again, you compose documentation as a single string,
- you add that string a a third list item in that command (after the variable name and the default value, as illustrated here).
The documentation string will be displayed as part of the information Emacs provides in response to a <Control-h> v key-sequence
Documentation of items in the menu-bar
This will be discussed in the Section on the customization of the menu-bar.
Customizing non-functional properties
Customizing the menu-bar and keyboard shortcuts controls how the functions of Emacs behave when they are executed. The initialization code discussed in this Section determines "the look" of the user-interface - the "Emacs eye candy".
An extensive and well-documented example of a user customization file can be found at http://www.mygooglest.com/fni/dot-emacs.html. Large parts of that code concern items discussed in the present Section. But, as opposed to this example, the code for customizing Emacs properties can be kept very short. The following paragraphs illustrate the customization of some aspects that frequently appears customization code.
Frame properties
Customization can define a set of properties that will be applied to all frames:
(modify-all-frames-parameters (list (cons 'height 25) (cons 'width 80) (cons 'font "DejaVu Sans Mono-10.5") (cons 'background-color my-default-background) (cons 'foreground-color "white") (cons 'cursor-color "red") ) )
This code is self-explaining (my-default-background is a global variable that must be previously defined: storing the background color in a variable facilitates having different backgrounds for root and for ordinary users). The manual of Emacs provides information on all properties that are supported in Emacs:
(defvar my-default-background (if (eq (user-uid) 0) "#5A0000" "#005538" ) "Default background colour of frames")
Calling "modify-all-frames-parameters" is not quite sufficient for a decent display of customized frames: frames will still have small black borders at their left and right sides - in Emacs terminology the "fringes", zones reserved for the display of curly arrows for marking wrapped lines; the fringe background can be made invisible by making it identical to the default frame-background, the foreground should be a contrasting color. The "modify-all-frames-parameters" function does not support parameters for defining these values: this problem can be dealt with by defining a "hook" - a function that is automatically called whenever a frame is created (the function-call to make the cursor blink acts on yet another feature that is not supported as a frame property):
(defun my-setup-frame () (set-face-foreground 'fringe "yellow") (set-face-background 'fringe my-default-background) (blink-cursor-mode 0) )
Calling the function just after the creation of the frame can be achieved by defining the after-make-frame-functions "hook" of Emacs:
(add-hook 'after-make-frame-functions (lambda ($new-frame) (progn (select-frame $new-frame) (my-setup-frame) ) ) )
Defining this hook when the user initialization code is executed comes too late for the frame which had been automatically created during the initialization of Emacs. This can easily be corrected by adding anywhere in the top-level of the user initialization code:
(my-setup-frame)
This example uses the lambda function: the definition of the hook requires an argument that is the name of a function: rather than explicitly defining a function and referring to it by its name, lambda is used to define the function "in-line" without cluttering the code with only locally needed functions.
Tabbing and indentation
The handling of tabs and of indentation is a quite complex issue. It depends
- on the mode of the current buffer (Emacs checks the suffix of file-names to determine the type of a file when it is opened; it defines the term "mode" as the syntax-specific behavior when text is edited in a buffer; this does not only concern tabbing and indentation, but also syntax-specific highlighting),
- and on preferences of the user with respect to tabbing and indentation.
The first issue is handled automatically by Emacs (it loads a particular module for each mode), the second one is controlled by variables which the user can set according to his preferences. The following list enumerates some frequently used variables (to find information on these variables, use the Emacs-help "<Control-h> v" key sequence - if necessary from a buffer that is in the mode for which the variable is defined):
Mode-independent variables | |
tab-width | |
indent-tabs-mode | |
tab-stop-list | |
Variables used for c-perl mode | |
cperl-close-paren-offset | |
cperl-continued-statement-offset | |
cperl-indent-level | |
cperl-indent-parens-as-block | |
cperl-tab-always-indent |
The value of these variables can be set by instructions like
(setq-default <name-of-variable> <default-value>)
or
(custom-set-variables '(<name-of-variable-1> <value-1>) '(<name-of-variable-2> <value-2>) etc. '(<name-of-variable-n> <value-n>))
To understand the handling of tabbing support by Emacs, some comments on the the function "defvaralias" may help: defvaralias allows to define an alias for a variable - a secondary name of the variable. The alias always has the same value as the original.
The constructs
(defvaralias 'c-basic-offset 'tab-width) (defvaralias 'cperl-indent-level 'tab-width)
permit to associate the value of the global variable tab-width to mode-specific aliases which are defined in the modules that handle that code.
General aspect and behavior of Emacs
(setq inhibit-startup-screen 1)
- This variable controls the window that will be displayed immediately after the launch of Emacs: a value of 1 suppresses the display of the Emacs welcome screen and immediately displays a data buffer.
(tool-bar-mode -1)
- This function controls whether Emacs frames will - in addition to the menu-bar - contain a toolbar: a negative value suppresses the display of the toolbar
### to be completed later - or drop the paragraph ?###
Customization of keyboard shortcuts
The function "global-set-key allows to bind a key - or a combination of keys - to a function. The function can be one of the functions provided by vanilla Emacs, or a function created by the user. Instead of a full explanation of how to define combinations of keys, have a look at a series of typical cases (and at) :
Bind the function "undo" to the "f4" function-key
(global-set-key (kbd "<f4>") 'undo)
For a list of names of key recognised by Emacs, such as f4, please refer to.
Bind the function "find-file" to the <Control><keypad-Enter> key-combination
(global-set-key (kbd "C-<kp-enter>") 'find-file)
"C-<kp-enter>" stands for a simultaneously pressing the "Control"-key and the "keypad-enter" key. Emacs refers to combinations with modifier keys as "C-..." ("Control"), S-..." ("Shift"), and "M-..." ("Meta", the "Alt"-key"); these three modifier keys can be used in any combination - for instance "C-S-<kp-enter>.
Bind the function "save-buffer" to the sequence "Control-x" - "Control-s"
(global-set-key (kbd "C-x C-s") 'save-buffer)
Emacs defines "Control-x" as a prefix-key, a key to be used as the first key in a 2-key sequence (lower-case characters represent the corresponding alphabetic key).
There exist other forms for representing key-combinations, but the one illustrated here is most commonly used.
Enhancing the menu-bar of Emacs is probably the most rewarding topic for customization; this is a slightly complex issue and will be discussed at a higher level of detail than the rest of this wiki-page. A series of screen-shots serves as illustration.
It would have been difficult to purge these illustrations from items that are too complex or too fancy with respect to the scope fixed for the present wiki-page. These items have therefore been kept as examples of what can easily be done, but they are not documented (this pertains, in particular to all functions and variables with names that start by jh-...).
### wording to be improved ( or find different approach? )###
Emacs uses different terms for referring to menus and menu items:
Menu- and menu-item labels
A label is an "external" tag - visible at the level of the user interface. It is perceived by the user as the "name of the menu", but the label is practically not used within Emacs when it addresses a menu or a menu-item. A label is normally specified as short text string, placed between two double-quotes ("). In the present discussion, "<menu-label>" or "<item-label>" will be used when talking about the label.
Menu- and menu-item names
When, for instance in a function call, Emacs refers to a menu or a menu-item, it normally requires a name to be specified as an internal tag for that entity. A name is normally specified by an unquoted symbol. The following discussion will use "<my-menu>" to refer to the name of a menu.
Keymap of a menu- or a menu-item
Menus and menu-items practically always are associated with a keymap see in the Emacs manual. Emacs sometimes refers to a menu or a menu-item by specifying the keymap rather than the name. The following discussion uses "<menu-keymap>" or "<item-keymap> when it refers to a keymap.
Finding the name of an existing menu or menu-item
When an existing menu or menu-item needs to be modified, the programmer must find out under which name that entity is already known. Only after the name has been found, the entity can be addressed and modified.
An efficient method for finding the name of the entity is to search for a corresponding text-string in the source-code of the module menubar.el - practically all menus in the menu-bar of vanilla Emacs and all their items are defined in that module.
Deleting an entire menu
A menu is deleted by setting its key-map to nil. For instance, if <my-menu> is a menu in the menu-bar, it will be destroyed by the command
(define-key global-map [menu-bar <my-menu>] nil)
This can, for instance, be used to delete the "Edit" menu that comes with vanilla Emacs - an action that is necessary before a totally new Edit menu can be defined.
Deleting a menu-item
The menu-item <my-item> of <my-menu> can be destroyed by the command
(define-key global-map [menu-bar <my-menu> <my-item>] nil)
- or by
(define-key menu-bar-<my-menu> [<my-item>] nil)
This is also valid if the menu-item is the header of a sub-menu: the command will destroy the header and the sub-menu it controls.
Adding a "button" menu-item to a new menu
While <my-menu> is being created, a new button-item can be added by the command
(bindings--define-key <my-menu> [<item-keymap>] '(menu-item "<item-label>" <item-function>))
That item will have the label <item-label> and invoke the target function <item-function> when a hit on the menu-item occurs; "define-key" requires that a unique key <item-keymap> is specified, even if that key is not used.
The function menu-item always specifies the label and the function of the item. It can have one or more additional arguments (their sequence is immaterial:
:enable | Elisp command that evaluates to true or false : controls whether the menu-item is active (enabled) or not; |
:help | help-text: will pop up when the mouse hovers over the menu item; |
:keys | text-string with shortcut keys right-adjusted comment, appended to the label of the menu-item used to display keyboard shortcuts that exist for the menu item. |
Adding a "check-button" menu-item to a new menu
While <my-menu> is being created, a new check-button-item can be added by the command
(bindings--define-key <my-menu> [<item-keymap>] (menu-bar-make-mm-toggle <control-variable> "<item-label>" "<help-text>" ))
Some documentation on the function menu-bar-make-mm-toggle can be found here: the variable <control-variable> must have been defined, it represents the state of the check-button and is automatically updated when the check-button is toggled.
Adding a sub-menu header item to a new menu
Use the same command as for creating a "button" menu-item - just replace the name of the target function by the name of the sub-menu.
Inserting a menu-item into an existing menu
A new menu-item can be inserted into an existing menu <my-menu> by the command
(define-key-after <my-menu> [<item-keymap>] (list 'menu-item "<item-label>" <item-function>) '<predecessor-item>)
The new item is inserted after the item <predecessor-item> of the target menu. The call to "define-key-after" uses the function "menu-item" which is described in the preceding paragraph.
The creation of a new menu requires two distinct steps to be coded:
- defining the new menu and its menu-items,
- inserting this menu into the menu-bar.
The menu <my-menu> is defined by defining its key-map - <my-menu-map> - and filling it with menu-item; each "<menu-item-..>" is created by a call to the function "menu-item" or to the function "menu-bar-make-mm-toggle", as discussed in the preceding paragraphs).
(defvar <my-menu-map> (let ((<my-menu> (make-sparse-keymap "<name-string>"))) <menu-item-1> <menu-item-2> ... ))
<name-string> is a name given to the menu being created; that name is not used if the menu is part of the menu-bar (hence in the context discussed here) - it is needed when the menu is used as a popup menu.
Once the menu is completely defined, it is inserted at the begin of the menu-bar, using the command
(bindings--define-key global-map [menu-bar <my-menu>] (cons "<menu-name>" <my-menu-map>))
The "File" menu of vanilla Emacs looks like a not very well-structured collection of miscellaneous items; moreover, some items one would expect in that menu are missing. In the example discussed here, the complete standard "File" menu has, therefore, been deleted and replaced by two menus - an entirely new menu with - again - the name "File" and a new menu with the name "Windows". Practically all menu-items that were present in the old "File" menu re-appear in one of these 2 menus, along with newly introduced menu-items. The following screen-shot shows an assembly of these two menus.
The underlying logic is evident: (1) sort the menu-items into functional groups"; (2) in each group, include additional items to make the group "functionally complete"; (3) fully profit from the ":keys" feature of the menu-item support to provide the user with a reminder on the available keyboard shortcuts.
The first Section of the Appendix presents the full code that implements the "Windows" menu.
The "Edit" menu, like the "File" menu has been substantially modified - the original menu has been deleted and replaced by a new one that has the same name. The following screenshot illustrates the new menu.
This menu presents some interesting aspects that will be shortly discussed.
Query Search/Replace instead of Emacs Incremental Search
The incremental search facility from vanilla Emacs has been abandoned - this is a question of taste, but of taste that is probably common to people who use Emacs for creating code. Instead, plain query searching is offered, very similar to what is available in Kwrite or Bluefish: when a user launches a Search or a Replace operation, he is asked to provide the target strings for searching and the replacement (where appropriate).
These strings are stored, and when the user starts a new operation, offered as default replies. They are also used as default when the user launches a Repeat operation - another feature of this menu, which - for the sake of brevity - is not discussed.
The user has the - check-button controlled - choice between remembering these target strings as specific to each buffer, or as global strings, common to each buffer.
Additional check-button controls determine
- the choice between by text-string matching or regular expression searches,
- case sensitivity,
- and the search direction (forward, backward).
The implementation of these features exploits standard functions of the Emacs library and does not require comments.
Option-control by check-button menu-items
The role of the check-buttons has been explained in the preceding paragraph. For the implementation of the check-buttons, please refer to the Section on check-button menu-items and remember that the key-element is the definition of a control-variable that toggles between true and false when the check-button is hit.
Sub-menu for case-toggling
Such a menu-item misses in vanilla Emacs. The discussion of this feature permits to illustrate how sub-menus can be implemented.
- in a first step, the sub-menu and its items must be defined - that is done precisely as already explained for the creation of menu-bar menus,
- the second step is to use the internal name of created menu and to add a sub-menu menu-item into the "Edit" menu.
The snippets in the second paragraph of the Appendix illustrate how this can be done. Again, the functions called by the menu-items to execute the corresponding actions is trivial and not commented here.
Debugging customization code
By experience, debugging of customization code is seldom a problem. A couple of hints may be helpful to be aware of the techniques available:
- Always keep a window with an instance of a correctly running Emacs on your desktop; using this window for correcting broken modules is faster than reverting to vanilla Emacs or using - for instance - kwrite.
- Always give your modules a file-name with the .el suffix; in consequence, Emacs will do the editing of your new module in elisp mode; use the Emacs-Lisp menu, i.e.the "byte-compile" feature, to check your modules against syntax errors.
- You can display intermediate values by using
(message <string-to-print>) (sit-for 2)
- The "sit-for" is necessary to avoid Emacs from just "flashing" the message and to give you a chance tor read it (2 is an arbitrary value - the number of seconds Emacs will wait); be aware that Emacs expects a string for the argument of "message", and that you have to convert numeric values - for instance - to strings when you call "message". The Emacs manual describes a series of functions for string conversion.
- The Emacs manual offers extensive instructions on the debugging of Elips code, but these instructions go beyond what is needed for the simple task of creating customization code.
- When you launch Emacs and some module with customization code is broken, Emacs reverts to vanilla and invites you to launch Emacs from a command string that specifies a debugging option; however, normally the debugging option does not provide very valuable information beyond the information already available in the current buffers of Emacs.
Documentation, references
The most important source for obtaining concise information on features of (X)Emacs is the on-line help facility:
- <Control-h> a provides an "apropos" list of Emacs commands and variables,
- <Control-h> f <function-name> will display information on a function,
- <Control-h> v <variable-name> will display information on a variable,
See http://www.emacswiki.org/emacs/SelfDocumentation for an extensive list of help commands. However, the information accessible through these help commands needs to be implemented by the author of the corresponding code as text that is glued into the corresponding code as "self-documentation" - it happens that this text is not provided.
Here are some more manuals and references with documentation on Emacs and Elisp (serveral documents are available both in an html and a pdf version):
General documentation on Emacs and Elisp | ||
[EM] | User manual : | http://www.gnu.org/software/emacs/manual |
[LM] | Elisp reference manual : | http://www.gnu.org/software/emacs/manual/html_node/elisp/index.html |
[EW] | Emacs wiki : | http://www.emacswiki.org/emacs |
[ET] | Tutorial : | http://www.linuxjournal.com/node/2821/print |
Description of selected customization commands | ||
[CE] | Emacs manual examples : | http://www.gnu.org/software/emacs/manual/html_node/emacs/Init-Examples.html |
[CC] | Some customization commands : | http://www.nongnu.org/emacsdoc-fr/manuel/init-file.html |
Additional info | ||
[CD] | Example: a complex init file: | http://www.mygooglest.com/fni/dot-emacs.html |
Web-searches for specific keywords on Elisp issues outside the official documentation provide amazingly scarce information.
Conclusions
Today, the quality of Xemacs and Emacs are at about the same level, the solidity of Emacs and the prospect of support at mid-term is certainly superior to that of Xemacs.
Migration is not a major effort; my experience - and I use a quite substantial amount of customization - has been that this effort can be completed in 1 or 2 days of work. There were two issues where features of Xemacs do not have a one-to-one equivalent in Emacs: (1) the concept of "Extents" (managing marked regions of text) is lacking in Emacs, and (2) after certain file-opening operations, an auxiliary window with directory list information tends to "hang around" in Emacs, and is difficult to get rid of automatically. Both issues are perfectly secondary.
Before deciding to invest into the migration from Xemacs to Emacs - and writing this wiki-page - I had tried to "do as everybody else" and had used the Kwrite editor for several months. The availability of features in Emacs and Kwrite is comparable, the decision for Emacs was nevertheless clear: it is easier and more versatile to use; moreover, there are ridiculous minor issues: for instance, Kwrite has the property of having selected text remain selected while you move around - and than to delete that selected text when you, accidentally and without being aware, hit some key. I never lost pieces of edited text so frequently as during my period of using Kwrite. Even without investing into customization, using Emacs is a very good choice - with a custom menu-bar you cannot do better!
Appendix: examples of Elisp code
The code examples in this Section only present the implementation of the menus - the implementation of the functions that implement the action code is more or less straightforward and not represented.
;; Window operations menu ;; ---------------------- (defvar jh-menu-bar-window-ops-menu (let ((menu (make-sparse-keymap "Windows"))) ; *** Delete frame (bindings--define-key menu [windows-a] '(menu-item "Delete frame" delete-frame :visible (fboundp 'delete-frame) :help "Delete currently selected frame" :keys "C-S-<delete>")) ; *** Remove other windows (bindings--define-key menu [windows-b] '(menu-item "Remove Other Windows" delete-other-windows :enable (not (one-window-p t nil)) :help "Make selected window fill whole frame" :keys "C-S-<backspace>")) ; *** Delete buffer and window (bindings--define-key menu [windows-c] '(menu-item "Delete current buffer and window" kill-buffer-and-window :visible (fboundp 'kill-buffer-and-window) :help "Delete current buffer and window" :keys "C-<backspace>")) ; *** Delete currently selected window (bindings--define-key menu [windows-d] '(menu-item "Delete current window (keep buffer)" quit-window :help "Delete currently selected window" :keys "S-<backspace>")) (bindings--define-key menu [windows-e] menu-bar-separator) ; *** Create a new frame (bindings--define-key menu [windows-f] '(menu-item "New Frame" make-frame-command :visible (fboundp 'make-frame-command) :help "Open a new frame")) ; *** Create new window at right (bindings--define-key menu [windows-g] '(menu-item "New Window on right of old" split-window-right :enable (and (menu-bar-menu-frame-live-and-visible-p) (menu-bar-non-minibuffer-window-p)) :help "Make new window on right of selected one")) ; *** Create new window below (bindings--define-key menu [windows-h] '(menu-item "New Window below old" split-window-below :enable (and (menu-bar-menu-frame-live-and-visible-p) (menu-bar-non-minibuffer-window-p)) :help "Make new window below selected one")) menu ))
Some of the menu-items are copy-pasted from the (deleted) "File" menu of the original vanilla menu, others have been newly implemented.
The command for inserting this menu into the menu-bar is
(bindings--define-key global-map [menu-bar jh-buffer] (cons "Windows" jh-menu-bar-window-ops-menu))
;; Define modify-case sub-menu ;; --------------------------- (defvar jh-modify-case-menu (let ((menu (make-sparse-keymap "Modify case"))) ; *** Capitalize region (bindings--define-key menu [case-a] '(menu-item "Capitalize region" capitalize-region :help "Convert 1st characters of all words to upper, rest to lower case")) ; *** Convert to lower case (bindings--define-key menu [case-b] '(menu-item "Convert region to Lower Case" downcase-region :help "Convert case in region (mark <-> cursor) to lower case")) ; *** Convert to upper case (bindings--define-key menu [case-c] '(menu-item "Convert region to Upper Case" upcase-region :help "Convert case in region (mark <-> cursor) to upper-case")) menu ))
- This menu can be inserted into the edit menu by the following command
; *** Modify-case sub-menu header (bindings--define-key menu [edit-b] `(menu-item "Modify case" , jh-modify-case-menu))