As a Real Programmer, you probably love how customizable Emacs is. You don't have to learn some new weird configuration file format, all the customizations are done in lisp, making it both powerful and simple to use. Lisp is an old and widely used language, so you probably already knew it or at least had it on the list of languages you wanted to learn.
However, for ordinary lusers, concepts like setq, "an alist
where the car of each element is a symbol", or `error in init
file' are not considered proper elements of an easy to use customization
interface. This is where the custom package enters the picture.
By supporting the custom package you allow the user to customize
your code without the need for any knowledge about lisp or lisp types,
and with automatic checks to ensure that the customizations are
syntactically correct. Perhaps you will even find that some Real
Programmers will prefer this interface for simple customizations.
Here is how to make your code customizable in ten easy steps. You don't have to complete all the steps at once, each step will make your package a little easier to customize.
(require 'custom) in the beginning of your code
Remark: this will not be necessary when custom becomes
bundled with Emacs.
defvar with defcustom for all user options,
see section Declarations.
defcustom declarations to specify
the type, see section Declarations.
custom-option-add, see section Declarations.custom-group-declare, see section Groups.
custom-group-add, see section Groups.
customize, see section Buffers and Menus.
customize-menu-create, see section Buffers and Menus.
widget-define, see section Defining New Widgets.
The custom library is implemented in two files:
All functions will be automatically loaded when needed.
Remark: this is not true for the unbundled version, your must insert an explicit `(require 'custom)' statement before declaring any variables for customization. The `custom-edit.el' file will still be loaded on demand.
Here should be an example of a major mode that makes full use of the
custom package.
Declaring user options make them much easier to edit in the customize buffer.
The custom package allows the user to edit the value of any
variable in a customize buffer, but works best if the variable has the
following two properties defined:
default-value
custom-reset-to-default command available in the
customize buffer, and also to avoid saving variables unnecessarily.
custom-type
The easiest way to set these properties is by declaring the variable
with defcustom instead of defvar.
default-value property of symbol to init.
Set the variable documentation for symbol to doc.
Set the custom-type property of symbol to type.
The following two pieces of lisp code are equivalent:
(defcustom symbol init doc type)
(defvar symbol init doc) (put 'symbol 'default-value 'init) (put 'symbol 'custom-type 'type)
Sometimes the user has to choose one or more options from a fixed set.
This can be implemented with variables declared with the Choice
or Multi custom types (see section Custom Types). If you want to
add an option such a set, you can do it with custom-option-add.
symbol should have a Choice or Multi
custom-type property, where type will be added a new
option. By default, the new option will be added first in the list of
option. If old is non-nil, the new option will be added after the
option with an old tag. If before is non-nil, the new
option will be added before the old option instead.
A typical use of custom-option-add is when your package define a
function intended to be added to hook variable defined in another
package.
How text with a given face should be displayed is a matter of personal
taste, and therefore an important item for customization. The users
preference is also likely to depend on the current visual. For example,
he might want text with the warning face to blink on a vt100
frame, but be displayed in large dark bold red letters on a color frame
with a light background.
In order to enable user customizations of a face used by your code, you have to make two declarations:
custom-face-declare.
defcustom) whose custom type is
Face and whose default value is the face you declared with
custom-face-declare.
Your code should only refer to the variable, never to the face directly. By convention, the face and the variable should have the same name.
A customize buffer for the variable will allow the user to:
clauses is a list with elements of the form (expr [attribute value]...). Each expr will be evaluated in turn, until one of them evaluates to non-nil. The face will then be initialized with the specified attributes. Known properties include:
:bold
:italic
:underline
:blink
:font
:stipple
:foreground
:background
Not all face properties are defined for all emacs versions nor for all visuals. Unknown properties will be silently ignored. When a new frame is created, the expr's will be reevaluated, and if a different expr is selected, the face will be created with a specific value for that frame.
In order to implement this, custom-face-declare will create an
entry in the global variable custom-face-declared-list of the
form (name expr clauses), where expr is from the
clause that was used for creating the global face.
This section should explain the syntax for a custom type, with some helpful examples. This this is essentially a duplication of the information in the chapter about Sexp Widgets (see section The Sexp Widgets), I will delay writting this section until the implementation is stable.
You can group related variables with custom-group-declare, which
allows you to create a menu or customize buffer containing all the
variables. A group can also contain other groups, allowing the creation
of both nested menus, and ridiculously huge customize buffers.
:tag
:doc
:format
:doc here.
:tag here.
You can add members to existing groups with custom-group-add.
Groups are actually implemented by setting the custom-type
property of the symbols to a special group widget. The two
following list expressions are equivalent:
(custom-group-declare name elements [ keyword value ]...)
(put 'name 'custom-type
(cons 'Group (append (list [ keyword value ]...)
elements)))
You can create a customize buffer from any symbol with a non-nil
custom-type property. This includes all variables declared with
defcustom and all groups declared with
custom-group-declare. You can also create customize buffers from
variables without the custom-type property; they will be assumed
to be able to hold any lisp Object. You can create a customize menus
from any symbol with a Group custom-type, in practice
meaning all groups declared with custom-group-declare.
emacs.
custom-group-declare.
The menu description is in the format expected by easy-menu-define.
Saving from a customization buffer will add two top level expressions to your `.emacs' file.
(customize-variables (var value)...)This will evaluate and assign value for each symbol var, and save the unevaluated value in the
saved-value property of
var.
(customize-faces (face clauses)...)where each clause has the form (expr [attribute value]...). This will create each face, and set the face attributes corresponding to the first expr that evaluates to non-nil. It will also create an entry in the global variable
custom-face-declared-list of the
form (name expr clauses), where expr is from the
clause that was used for creating the global face.
For some variables it is more common for the user to modify them than to set them. This practise has several advantages:
The primary examples are hooks that are set with add-hook and
remove-hook, large association lists like auto-mode-alist,
keymaps, and menus. The custom package should support these.
Most graphical user interface toolkits, such as Motif and XView, provide
a number of standard user interface controls (sometimes known as
`widgets' or `gadgets'). Emacs doesn't really support anything like
this, except for an incredible powerful text "widget". On the other
hand, Emacs does provide the necessary primitives to implement many
other widgets within a text buffer. The widget package
simplifies this task.
The basic widgets are:
This might not seem like much compared with other widget sets, but the Emacs widgets can be combined within each other, making it possible to build quite complex user interfaces.
Now of what possible use can support for widgets be in a text editor? I'm glad you asked. The answer is that widgets are useful for implementing forms. A form in emacs is a buffer where the user is supposed to fill out a number of fields, each of which has a specific meaning. The user is not supposed to change or delete any of the text between the fields. Examples of forms in Emacs are the `forms' package (of course), the customize buffers, the mail and news compose modes, and the HTML form support in the `w3' browser.
The advantages for a programmer of using the widget package to
implement forms are:
choice and
list widgets.
In order to minimize the code that is loaded by users who does not create any widgets, the code has been split in two files:
widget-define, and autoload the function widget-create.
A form consist of read only text for documentation and some fields, where each the fields contain two parts, as tag and a value. The tags are used to identify the fields, so the documentation can refer to the foo field, meaning the field tagged with `Foo'. Here is an example form:
Here is some documentation. Name: My Name Choose: This option Age: 14 See also other work for more information. Numbers: count to three below [INS] [DEL] One [INS] [DEL] Eh, two? [INS] [DEL] Five! [INS]
There are 4 fields in the example, tagged `Name', `Choose', `Age', and `Numbers' respectively. There are basically two thing the user can do within a form, namely editing the editable text fields and activating the buttons.
In the example, the values for the `Name' and `Age' fields are most likely displayed in editable text fields, and so are values for each of the members of the `Numbers' list. All the normal Emacs editing operations are available for editing these fields. The only restriction is that each change you make must be contained within a single editable text field. For example, capitalizing all text from the middle of one field to the middle of another field is prohibited. All changes to the text outside the editing fields is also prohibited.
There is one extra command available for editing editable text fields,
namely widget-kill-line, normally bound to C-k.
kill-line, except that it will not attempt to kill
past the end of the field.
Editing text fields are created by the string widget.
The editing text fields are highlighted with the following faces, making them easy to find:
The first face in the list above that applies to a field is used.
Some portions of the buffer have an associated action, which can be activated by a standard key or mouse command. These portions are called buttons. The default commands for activating a button are:
There is three different kind of buttons, all of which are present in the example:
choice widget. In
the example, `Choose' is an option field tag.
choice widget.
const widget.
To make them easier to locate, buttons are emphasized in the buffer.
The string is inserted into the buffer, with `%v' replaced by the button name.
The default value is `"%v"' if the current frame support faces, and `"*%v*"' otherwise.
You can use all the normal Emacs commands to move around in a form buffer, plus you will have these additional commands:
It is suggested that packages provides the following keybindings, unless they have a good reason not to:
Here should be the lisp code for implementing the example form (see section User Interface), but that will have to wait until I have some code to test it with. Here is instead the beginning of a fascist mail compose mode:
(require 'widget)
(defun fascist-mail ()
"An unfriendly mail compose mode."
(interactive)
(if (get-buffer "*Fascist Mail*")
(switch-to-buffer "*Fascist Mail*")
(switch-to-buffer "*Fascist Mail*")
(let ((aliases (nconc (mapcar (lambda (e) (list (car e)))
mail-aliases)
'(("Other" string)))))
(widget-create `(list (string :format " Subject: %v")
&rest
(choice :format "To: %v" ,@aliases))))
(widget-setup)))
Widgets are created with widget-create, which returns a
widget object. This object can be queried and manipulated by
other widget functions, until it is deleted with widget-delete.
After the widgets have been created, widget-setup must be called
to enable them.
The behavior of widget-create can be modified by the following
keyword arguments:
:position
:modified
Other keyword arguments can be used to overwrite the keyword arguments that are part of type.
The widget package depends on before-change-functions,
after-change-functions, and post-command-hook to be set in
order to work. This function will setup these three variables properly,
and should be called once for each buffer that contains widgets. If you
need to change the buffer outside the widgets, you should prevent
these hooks from being run by wrapping the code in an
widget-ignore form.
The behavior of widget-setup can be modified by the following
keyword arguments:
:buffer
:keymap
If the local keymap contains changes that makes it unsuited for editing,
you can use widget-keymap together with the :keymap
argument to widget-setup. Since widget-keymap has the
global map as its parent, the local bindings will be ignored.
widget-forward and
widget-backward, respectively. RET and mouse-2
are bound to widget-key-action and
widget-mouse-action.
Warning: The keymap specified with the :keymap argument
to widget-setup is only active when point is inside an editing
field. This is fine for keyboard events, but can be very surprising for
mouse events. If you redefine any mouse events, it is best to make sure
they have the same definition in the local keymap as in the editing
field keymap. If you want different actions depending on whether you
press the mouse button in or outside an editing field, make the mouse
function explicitly check the local-map text property.
widget-setup.
The syntax of a type specification is given below:
TYPE ::= (const [KEYWORD ARGUMENT]... VALUE)
| (string [KEYWORD ARGUMENT]...)
| string
| (choice [KEYWORD ARGUMENT]... [TYPE]...)
| (list [KEYWORD ARGUMENT]...
[[@] TYPE]... [&optional [[@] TYPE]...] [&rest [[@] TYPE]])
The following keywords are defined:
:compact
:value
:size
:button
choice widget, and to do nothing in the other widgets.
:doc
:tag
:format
:doc here.
:tag here.
:valid-p
const
equal to the widgets own value.
field
choice
list
:modified-p
:convert-value-to-internal
:value
keyword to widget-create or with widget-value-set it is
first converted using this function.@br
The default conversion function pass its argument unchanged.
:convert-value-to-external
widget-value, t
is first converted using this function.@br
The default conversion function just pass its argument unchanged.
Apart from the keywords, the widgets have very different syntax for the remaining arguments.
const
const widget.
string
choice
:tag field of the type is when the user is asked
to select one of the option. The type part used to for creating
the widget corresponding to the chosen option.
list
list type, the type elements up until the first
&optional or &rest keyword represent widgets which will
always be present. The type elements between the &optional
and &rest represents optional widgets. There can be no holes in
the list, so if an optional widget is missing, all widgets after it must
be missing to. The type element after the &rest keyword
represents a variable number widgets of the same type. All optional
widgets must be present before any widgets of this type can be present.
Inserting `@' tokens before a type means that, when
extraction the value of the list, the value of the component widget must
be a list which will be spliced into the result. See section Values.
A syntax for a widgets internal value depends on its type, as follows:
const
string
choice
list
list. Widgets whose type was prepended
with a `@' token in the lists type specification will have their
external value spliced into the list. Read the documentation string for
backquote to understand what this means.
You can examine or set this value by using the widget object that was
returned by widget-create. Uninitialized widgets does not have a
value.
It is possible to find both the part of the buffer that is associated
with a particular widget, and the widget that is associated with a
particular point in the buffer. The first can be done with
widget-area, while the later is accomplished by examining the
widget text property. This property will be set to the
associated widget object within the widgets, and be nil outside the
widgets.
If your application needs to associate some information with the widget
objects, for example a reference to the item being edited, it can be
done with widget-property-put and widget-property-get.
widget-property-put for property.
You can define specialized widgets with widget-define. It allows
you to create a shorthand for more complex widgets, including specifying
component widgets and default new default values for the keyword
arguments.
class.
name and class should both be symbols, class should be one
of the basic widget types (const, string, list, and
choice).
After the new widget has been defined, the following two calls will create identical widgets:
(widget-create name)
(widget-create (cons class (apply convert args)))
Using widget-define does just set the widget-type property
of name to a list with the three elements, class,
convert, and args, which is what widget-create uses.
If you just want to specify defaults for keywords with no complex
conversions, you can use identity as your conversion function.
It should be possible to add or remove items from a list with C-k and C-o.
A library of widgets for editing lisp expressions sexps is available by loading the `widget-sexp' package. All the sexp widgets have the following common syntax:
(name [ keyword value ]... arg...)
The `arg...' is where the syntax of the sexp widgets varies.
List
Vector
&optional keyword in the element list to specify that
the following elements are optional, and a &rest keyword before
the last element to specify that it can be repeated an arbitrary number
of times. You can insert a `@' token before any type whose value
will be a list, to indicate that the value should be splices directly
into the list rather than be a single element of the list. The precise
syntax is the the same as for the list widget, see section Types.
Cons
Choice
Multi
Choice widget only allows a single option to be
chosen, while the Multi widget allows the user to make multiple
choices.
The args is in both cases a list of types. For the Choice
widget, the value is the value of the widget representing the chosen
option, while the value of the Multi widget is a list values of
the widgets representing the chosen options.
String
Sexp
File
Number
Integer
Symbol
Boolean
Const
Face
All the standard keyword arguments described in section Types are available. For the sexp widgets, the following are likely to be useful:
:doc
:tag
:compact
:size
Some of the sexp widgets accept additional keywords:
:true
:false
:face