From Mageia wiki
Jump to: navigation, search
this page is a draft.
It requires improvements. If you want to improve it, simply log in and click on the Edit tab.

Please remove this {{Draft}}template, when you're sure the page is complete and correct.


View the other draft pages, or other pages to improve and maintain.


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 this Section of the emacs manual. In particular:

  • first, emacs loads and executes all executable .el or .elc files that exist 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 the directory /etc/emacs/site-start/.

Shared user setup files

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-existence).

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:

  1. 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.
  2. As already mentioned, Xemacs considers the directory $HOME/.emacs as its initialization directory and risks to destroy a file at that location.
  3. Like Emacs, Xemacs places its site initialization files into the directory /etc/emacs/site-startd.d/. Although Emacs probably will not load these Xemacs files, errors might be thrown when that directory is submitted to a global re-compilation.

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 as part of the defvar command:

  • again, you compose documentation as a single string,
  • you add that string as 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 appear in 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 already have been 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 frame properties that are supported in Emacs:

(defvar my-default-background (if (eq (user-uid) 0) "#5A0000" "#005538" )
                                      "Default background colour of frames")

This call to "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 fringes can be made invisible by making their background identical to the default frame-background (the foreground should be a contrasting color). But the background color of the fringes does not figure in the list of parameters recognized by "modify-all-frames-parameters". 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 (please refer to),
  • 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 - using perl as an example for mode-specific issues
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.

Emacs considers the variable "tab-width " as a global variable - a varible which is not mode-specific. The function calls

 
(defvaralias 'c-basic-offset 'tab-width)
(defvaralias 'cperl-indent-level 'tab-width)

permit to associate the value of 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 display of the "Emacs welcome screen" window that is, by default, displayed immediately after the launch of Emacs: a value of 1 suppresses the display of that window 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.

(put 'upcase-region 'disabled nil)

This is specific to the case-modification functions: it inhibits a (quite disruptive) query from Emacs (dito for downcase-region); you can drop this line if the case modification functions are not called.

Reference [CF ] contains a long list of setup commands that can be used as a repertory with additional candidates for your customization file.

Customization of file-type specific behaviour

Whenever Emacs opens a file, it determines the type of the file and associates a corresponding mode to the buffer in which the file is edited (the type is derived from the name of the file, for instance by checking for a suffix).

The mode of a buffer controls a series of important features - such as tabbing, indentation, syntax-checking and highlighting. Emacs contains a large set of modules which define and handle these features - not only for IT-specific properties, but also for may varieties of text-files.

These modules need to make assumptions on what the user expects as "type-specific behaviour' - which is quite often arbitrary and may conflict with personal preferences or the user.

Mode hooks

The user can deal with this type of problem by defining mode-hooks: function-like blocks of statements that are automatically executed when a buffer is initialized for a given mode.

The following code illustrates such a mode hook:

(add-hook 'change-log-mode-hook
        (lambda ()
            (progn 
                (setq tab-width 4)
                (auto-fill-mode -1)
            ))

This particular hook is needed when a file with the name of - for instance - CHANGELOG is edited. Emacs decides that for editing such a file the "change-log" mode is required, which forces the tab-width to 8 and forces automatically breaking lines that are longer than 72 characters - even if the initialisation file had established global conditions that are different (this line-breaking feature is set by calling the function "auto-fill-mode" with a positive argument, cancelled by a negative argument).

There is one particular case which is worth-while mentioning: the line-breaking features is automatically established for text-mode and all its sub-modes; defining a hook that calls auto-fill-mode with a negative argument does not help in this case - very probably because the implementation of the text-mode module uses itself a hook to establish line breaking, and that this hook happens to be executed after any user-defined hook. The solution is to include the following line into the user's emacs intialization code:

(remove-hook 'text-mode-hook #'turn-on-auto-fill)

This line very simply cancels the un-desired hook of the text-mode module.

It is, evidently, not possible to create a list of recommended mode-hooks. The recommendation is to start by implementing the logically evident customisation code for Emacs, and then to create mode-hooks whenever the need for such hooks appears (the mode selected by emacs for a given buffer figures at the end of the mode-line of the buffer).

Customization of keyboard shortcuts

The function "global-set-key" allows to bind a key - or a combination of keys - to a function. The function is called when such a keyboard event happens; it 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 recognized 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.

Customization of the menu bar

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. The following paragraphs document the basic operations necessary for modifying the menu-bar and its menus. Some complementary information can be found here. Emacs supports various alternatives of coding menu-bar customization; the approach documented here corresponds to the approach used in the module menu-bar.el.

One item, however, is missing: there are no simple instructions for modifying the order of already existing menus, nor for inserting a new menu at some place different from the left side of the menu-bar (but there is always the crude solution: delete all menus and re-create them in the desired order - this is possible without excessive loss of performance).

One issue to be aware of: Emacs assembles menu-items in an inverted sequence: the first menu-item you have defined will appear at the bottom of the menu, the last one at the top.

Naming menus and menu-items, finding the name of an item to be modified

Emacs uses several 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 will use an "internal name", a symbol defined to represent that entity. The following discussion will use "<my-menu>" to refer to that internal name.

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 customization intends to modify an existing menu or menu-item, a function call needs to be made with the name of the menu or the menu-item as an argument, a name that had been defined as part of the implementation of Emacs. That means that somehow that name must be detected.

An efficient method for finding the name 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.

The function "menu-item" - advanced issues

New menu-items are created by calling the function "define-key. For most types of menu-items, this function - in turn - will call the function "menu-item".

The following paragraphs discuss some detailed aspects of the function "menu-item". Note that these details only need to be considered in particular cases, normally you can simply copy the sample code proposed in the following sections.

Item properties

The function "menu-item" permits to specify particular properties of the item by appending additional pairs of arguments after the leading two mandatory arguments. The first item of the pair is a key, the second one a double-quoted string or a function call:

: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 that can enumerate shortcut keys:

right-adjusted comment, appended to the label of the menu-item used to display keyboard shortcuts that exist for the menu item;

:button   description of a button in a button-item to be added:

add a check-button or a radio-button - please refer to or see the implementation of "Line Wrapping" in the "Options" menu (module menu-bar.el).

Note: the two mandatory arguments are

  1. the first argument must be the label of the item, a short string placed between double-quotes,
  2. the second argument determines what Emacs has to do when there is a hit on the item; this can be the name of a function to call, the name of a sub-menu to open, or the name of the control-variable of a toggle-item; this name must always be quoted (see the Section on quoting),

Quoting and backquoting

The call off the function "menu-item" must be "quoted": that means that the function is not called at the time the Elisp interpreter reads the code (i.e. when the menu-item is defined), but that calling and the evaluation of arguments is deferred to some later time - the time when there is a hit on the menu-item.

Back-quoting is a special case of quoting: in a back-quoted list, the handling of each item can be individually determined and depends on whether the item is preceded by a comma ( , ) or not:

  • items that are not preceded by a comma are quoted (their evaluation is deferred),
  • items that follow a comma are not quoted - evaluated immediately.

Plain quoting uses the ' quote character, back-quoting uses `. For more information on back-quoting refer to and also to. In the normal case,

  • button menu-items are defined with plain quoting,
  • sub-menu header items always with back-quoting; the argument (the name of the sub-menu) is preceded by a comma.

But in particular situations, also button menu-items can be back-quoted. This is rather a mess - probably the best approach when back-quoting might be required is to look at existing examples (for instance the menu-bar.el library module) and to resort to trial and error. For instance, have a look at the "Copy" item of the Edit menu in the module menu-bar.el, and try to understand why that item needs back-quoting with a comma!

In-line coding of the target function

Instead of providing the (quoted) name of a target function, it is possible to specify the code of the target function in-line, using the "lambda" function. This is illustrated in the following code snippet:

(bindings--define-key <my-menu> [<item-keymap>]
                      `(menu-item "<item-label>" ,(lambda ()
                           (interactive)
                           ( ... ))

Note that "menu-item" is called with back-quoting, and that the argument with the lambda function is preceded by a comma. This way of coding the target function offers additional flexibility - for instance, it permits to implement target functions that are called with arguments. The creation of a sub-menu for manually setting the mode of a buffer is an example where this can be very useful.

Deleting an entire menu from the menu-bar, deleting one of its menu-items

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 new item to a menu of the menu-bar

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>))

This will create a menu-item with the label <item-label> that invokes 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.

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. For this to work, you must also define a function that has the same name as the variable; the function must (1) read the old value from the variable, (2) compute the new value and (3) update the variable. On a hit on the check-button menu-item, Emacs will automatically execute this function.

Adding a "sub-menu header" item to a new menu

This is very similar to the creation of a "button" menu-item:

(bindings--define-key <my-menu> [<item-keymap>]
                              `(menu-item "<item-label>" ,<sub-menu-name> ))

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.

Adding a new menu to the menu-bar

The creation of a new menu requires two distinct steps to be coded:

  1. defining the new menu and its menu-items,
  2. 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-items; 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 left side of the menu-bar, using the command

(bindings--define-key global-map [menu-bar <my-menu>]
                            (cons "<menu-name>" <my-menu-map>))

Example: putting things together

The preceding paragraphs have a certain aspect of a dry repertory of functions and commands. This wiki-page therefore proposes a small example with Elisp code that can be added to customize vanilla Emacs. That should help to apply this documentation to writing Elisp for a fully functional user initialization and setup file.

To keep this wiki-page at a manageable size, the example cannot contain any effectively usable examples - it does not go beyond demo customization :

  • the user initialization file just loads a setup module that, in turn, contains the bulk of the initialization code (this illustrates how such a module is loaded); for practical reasons, that setup module is placed into the home directory of the user,
  • the setup module
  • executes some basic setup functions (tabs, initialization of frames),
  • defines the variables needed,
  • defines some keyboard shortcuts,
  • adds a short menu ("Demo") at the left side of the menu-bar,
  • the menu-items are "one of each" for the different types discussed in the present wiki-page,
  • when an item is hit, it simply triggers the display of short message.

The insertion of a new menu-item at a place within an existing menu is illustrated differently: a "simple compare" function is coded, a button menu-item that calls that function is then inserted into the "Tools" menu - right after the existing "Compare (Ediff)" sub-menu header menu-item.

The code of the user initialization file ($HOME,.emacs.d/init.el) and of the library setup file ($HOME/emacs_setup.el) is presented in the Appendix. The following screen-shot illustrates the "look" of the thus customized editor.

DemoMenu.png
New "Demo" menu

In case you are interested in fully operational customization files in order to find "inspiration" or pieces of code to be copy/pasted into your new menu-bar, it is worth while to do some searching in the internet, several such examples exist.

Debugging customization code

By experience, debugging of Emacs 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.
  • When you launch Emacs while some module with customization code is broken, execution of the customization code is abandoned. Emacs will invite you to re-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.
$ emacs --debug-init

Documentation, references

The most important source for obtaining concise information on features of (X)Emacs is the on-line help facility:

  • <Control-h> a <search-key>   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 (several 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] Selection of commands in User manual : 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
 [CF] More customization commands : https://ryuslash.org/dotfiles/emacs/init.html
 [EI] Introduction to the .emacs file http://www.math.utah.edu/docs/info/emacs-lisp-intro_17.html
Examples of user initialization files
 [CD] Very extensive customization 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

Discussion

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.

Customization of the user-interface is very simple. The menu-bar of Emacs is quit malleable, the functions needed for modifying menus are explained in this page: it is easy to adapt the "look-and-feel" of the user interface to your individual habits, and the functionality of Emacs can easily be extended beyond what "vanilla Emacs" makes available.

Migration from Xemacs 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.

Practical experience

abc

Appendix: examples of Elisp code

Emacs user initialisation file

This file must be placed at $HOME/.emacs.d/init.el

;; Load demo customization file
;; ----------------------------

( load-file (substitute-in-file-name "$HOME/emacs-setup.el") )

;; For expert users:
;;  - suppress startup screen if emacs is called with an argmuent (a file name)
;;    (e.g. launched by a hit on the file-manager icon of the target-file).

(if (> (length command-line-args) 1) (setq inhibit-startup-screen 1) ())

;;  - inhibit the toolbar

(tool-bar-mode -1)

;; Enable case conversion functions

(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)

Setup module

This file must be placed at $HOME/emacs-setup.el

;; Emacs wiki-guide customisation file
;; ===================================


;; General setup, key bindings
;; ===========================

;; Initial setup, keyboard shortcuts

(setq-default tab-width 4)
(setq tab-width 4)
(defvaralias 'c-basic-offset 'tab-width)
(defvaralias 'cperl-indent-level 'tab-width)


(defalias 'perl-mode 'cperl-mode)


;; Initialization of frames
;; Set the standard properties of a newly created buffer
;; -----------------------------------------------------

(defvar my-default-background (if (eq (user-uid) 0) "#5A0000" "#005538" )
                                     "Default frame background colour")
(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 "#ffffff")
  (cons 'cursor-color "red") ))


(defun my-setup-frame ()
"Initialise a just created buffer:
  - set the background of the fringe to the background colour of frames
  - set the foreground of the fringe to yellow
  - make the cursor non-blinking."

  (set-face-foreground 'fringe "yellow")
  (set-face-background 'fringe my-default-background)
  (blink-cursor-mode 0)
)
(my-setup-frame)

(add-hook 'after-make-frame-functions
              (lambda ($new-frame)
                (progn
                  (select-frame $new-frame)
                  (my-setup-frame)
              )) )


;; Key-bindings
;; ------------

(global-set-key (kbd "<f4>")    'undo)    ; undo
(global-set-key (kbd "C-u")     'undo)    ; undo



;; Create and attach the "Demo" menu
;; =================================


            ;; Action functions and control variables
            ;; --------------------------------------

( defun my-plain-button ()
  (interactive)
  (message "Hit on plain-button demo-button")
  (sit-for 1 )
)

(defvar my-toggle-button nil
                "*State of toggle demo  menu-item")
(defun my-toggle-button ()
  (interactive)
  (setq my-toggle-button (not my-toggle-button) )
  (let (temp)
    ( if my-toggle-button (setq temp "t") (setq temp "nil") )
    (message (concat "Value of toggle demo button is now " temp ) )
  )
  (sit-for 1)
)

            ;; Action function for "simple compare"

(defun my-launch-compare ()
  (interactive)
  (let ( ($window1 (get-buffer-window)) $window2)
    (if (one-window-p t)
      (progn
        (goto-char (point-min))
        (find-file-other-window  (read-file-name "Compare with : "))
        (setq $window2 (get-buffer-window))
        (goto-char (point-min))
      )
      (progn
        (setq $window2 (next-window))
      )
    )
    (compare-windows nil)
    (add-text-properties (point-min) (+ (point-max) 1) '(face "isearch-fail"))
  )
)

              ;; Tools menu: add "Simple compare" button after compare button

(define-key-after
      menu-bar-tools-menu [tools-compare]
                 '(menu-item "Simple Compare" my-launch-compare ) 'compare )

              ;; Sub-menu for case-modifications

(defvar my-modify-case-menu
  (let ((menu (make-sparse-keymap "Modify 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  ))

            ;; Main demo menu
            ;; --------------

(defvar my-demo-menu
  (let ((menu (make-sparse-keymap "Demo")))

                                                ; *** Modify-case sub-menu header

        (bindings--define-key menu [edit-a]
            `(menu-item "Modify case", my-modify-case-menu))

                                                ; *** Plain button 

        (bindings--define-key menu [edit-b]
            '(menu-item "Plain button" my-plain-button
                :help "Demonstrate plain button-item"))

                                                ; *** Undo button with keyboard shortcuts 

        (bindings--define-key menu [edit-c]
            '(menu-item "Undo button" undo
                :help "Demonstrate keyboard shortcuts"
                :keys "C-u <f4>"))

                                                ; *** Separator below checkbutton

        (bindings--define-key menu [edit-d]
                menu-bar-separator)

                                                ; *** Toggle button

        (bindings--define-key menu [edit-e]
                (menu-bar-make-mm-toggle
                  my-toggle-button
                    "Toggle  button"
                    "Demonstrate check-button menu-item"
                )
        )

        menu ))

            ;; Attach the demo menu at left side of the menu-bar

(bindings--define-key global-map [menu-bar my-demo]
            (cons "Demo" my-demo-menu))