|
Searching XEmacs
Quick Links
About XEmacs
Getting XEmacs
Customizing XEmacs
Troubleshooting XEmacs
Developing XEmacs
|
|
|
Lisp Interface Changes
Abstract
Owner: ???
Effort: ???
Dependencies: ???
Abstract: This document covers the major Lisp
interface changes that I am proposing for version 22. These
changes include full support for keyword parameters everywhere in
Elisp, a generalized object property interface, and changes to the
toolbar and menu API, in such a way that backward compatibility is
maintained for the most part. Most of these changes are being
done for the benefit of the improved user interface facilities
that I am proposing for version 22 in order to make their
associated interfaces cleaner and easier to use. As far as I
know, all of these changes can be made in such a way that the byte
code format does not need to be modified.
Keyword Parameters
I would like to make keyword parameters an integral part of Elisp.
The idea here is that you use the &key identifier
in the parameter list of a function and all of the following
parameters specified are keyword parameters. This means that when
these arguments are specified in a function call, they are
immediately preceded in the argument list by a keyword,
which is a symbol beginning with the `:' character. This allows
any argument to be specified independently of any other argument
with no need to place the arguments in any particular order. This
is particularly useful for functions that take many optional
parameters; using keyword parameters makes the code much cleaner
and easier to understand.
The cl package already provides keyword parameters of
a sort, but I would like to make this more integrated and useable
in a standard fashion. The interface that I am proposing is
essentially compatible with the keyword interface in Common Lisp,
but it may be a subset of the Common Lisp functionality,
especially in the first implementation. There is one departure
from the Common Lisp specification that I would like to make in
order to make it much easier to add keyword parameters to existing
functions with optional parameters, and in general, to make
optional and keyword parameters coexist more easily. The Common
Lisp specification indicates that if a function has both optional
and keyword parameters, the optional parameters are always
processed before the keyword parameters. This means, for example,
that if a function has three required parameters, two optional
parameters, and some number of keyword parameters following, and
the program attempts to call this function by passing in the three
required arguments, and then some keyword arguments, the first
keyword specified and the argument following it get assigned to
the first and second optional parameters as specified in the
function definition. This is certainly not what is intended, and
means that if a function defines both optional and keyword
parameters, any calls of this function must specify
nil for all of the optional arguments before using
any keywords. If the function definition is later changed to add
more optional parameters, all existing calls to this function that
use any keyword arguments will break. This problem goes away if
we simply process keyword parameters before the optional
parameters.
The primary changes needed to support the keyword syntax are:
-
The subr object type needs to be modified to contain
additional slots for the number and names of any keyword
parameters.
-
The implementation of the funcall function needs
to be modified so that it knows how to process keyword
parameters. This is the only place that will require very
much intricate coding, and much of the logic that would need
to be added can be lifted directly from the cl
code.
-
A new macro, similar to the DEFUN macro, and
probably called DEFUN_WITH_KEYWORDS , needs to be
defined so that built-in Lisp primitives containing keywords
can be created. Now, the DEFUN_WITH_KEYWORDS
macro should take an additional parameter which is a string,
which consists of the part of the lambda list declaration for
this primitive that begins with the &key
specifier. This string is parsed in the DEFSUBR
macro during XEmacs initialization, and is converted into the
appropriate structure that needs to be stored into the subr
object. In addition, the max_args parameter of the
DEFUN macro needs to be incremented by the number
of keyword parameters and these parameters are passed to the C
function simply as extra parameters at the end. The
DEFSUBR macro can sort out the actual number of
required, optional and keyword parameters that the function
takes, once it has parsed the keyword parameter string. (An
alternative that might make the declaration of a primitive a
little bit easier to understand would involve adding another
parameter to the DEFUN_WITH_KEYWORDS macro that
specifies the number of keyword parameters. However, this
would require some additional complexity in the preprocessor
definition of the DEFUN_WITH_KEYWORDS macro, and
probably isn't worth implementing).
-
The byte compiler would have to be modified slightly so that
it knows about keyword parameters when it parses the parameter
declaration of a function. For example, so that it issues the
correct warnings concerning calls to that function with
incorrect arguments.
-
The make-docfile program would have to be
modified so that it generates the correct parameter lists for
primitives defined using the DEFUN_WITH_KEYWORDS
macro.
-
Possibly other aspects of the help system that deal with
function descriptions might have to be modified.
-
A helper function might need to be defined to make it easier
for primitives that use both the &rest and
&key specifiers to parse their argument
lists.
Property Interface Changes
In my past work on XEmacs, I already expanded the standard
property functions of get , put , and
remprop to work on objects other than symbols and
defined an additional function object-plist for this
interface. I'd like to expand this interface further and
advertise it as the standard way to make property changes in
objects, especially the new objects that are going to be defined
in order to support the added user interface features of version
22. My proposed changes are as follows:
-
A new concept associated with each property called a
default value is introduced. (This concept already
exists, but not in a well-defined way.) The default value is
the value that the property assumes for certain value
retrieval functions such as get when it is
unbound, which is to say that its value has not been
explicitly specified. Note: the way to make a property unbound
is to call remprop . Note also that for some
built-in properties, setting the property to its default value
is equivalent to making it unbound.
-
The behavior of the get function is modified. If
the get function is called on a property that is
unbound and the third, optional default argument is
nil , then the default value of the property is
returned. If the default argument is not
nil , then whatever was specified as the value of
this argument is returned. For the most part, this is
upwardly compatible with the existing definition of
get because all user-defined properties have an
initial default value of nil . Code that calls
the get function and specifies nil
for the default argument, and expects to get
nil returned if the property is unbound, is
almost certainly wrong anyway.
-
A new function, get1 is defined. This function
does not take a default argument like the get
function. Instead, if the property is unbound, an error is
signaled. Note: get can be implemented in terms
of get1 .
-
New functions property-default-value and
property-bound-p are defined with the obvious
semantics.
-
An additional function property-built-in-p is
defined which takes two arguments, the first one being a
symbol naming an object type, and the second one specifying a
property, and indicates whether the property name has a
built-in meaning for objects of that type.
-
It is not necessary, or even desirable, for all object types
to allow user-defined properties. It is always possible to
simulate user-defined properties for an object by using a weak
hash table. Therefore, whether an object allows a user to
define properties or not should depend on the meaning of the
object. If an object does not allow user-defined properties,
the put function should signal an error, such as
undefined-property , when given any property other
than those that are predefined.
-
A function called
user-defined-properties-allowed-p should be
defined with the obvious semantics. (See the previous
item.)
-
Three more functions should be defined, called
built-in-property-name-list ,
property-name-list , and
user-defined-property-name-list .
Toolbar Interface Changes
I propose changing the way that toolbars are specified to make
them more flexible.
-
A new format for the vector that specifies a toolbar item is
allowed. In this format, the first three items of the vector
are required and are, respectively, a caption, a glyph list,
and a callback. The glyph list and callback arguments are the
same as in the current toolbar item specification, and the
caption is a string specifying the caption text placed below
the toolbar glyph. The caption text is required so that
toolbar items can be identified for the purpose of retrieving
and changing their property values. Putting the caption first
also makes it easy to distinguish between the new and the old
toolbar item vector formats. In the old format, the first
item, the glyph list, is either a list or a symbol. In the
new format, the first item is a string. In the new format,
following the three required items, are optional keyword items
specified using keywords in the same format as the menu item
vector format. The keywords that should be predefined are:
:help-echo , :context-menu ,
:drop-handlers , and :enabled-p . The
:enabled-p and :help-echo keyword
arguments are the same as the third and fourth items in the
old toolbar item vector format. The
:context-menu keyword is a list in standard menu
format that specifies additional items that will appear when
the context menu for the toolbar item is popped up.
(Typically, this happens when the right mouse button is
clicked on the toolbar item). The :drop-handlers
keyword is for use by the new drag-n-drop interface (see
Drag-n-Drop Interface Changes
), and is not normally specified or modified
directly.
-
Conceivably, there could also be keywords that are associated
with a toolbar itself, rather than with a particular toolbar
item. These keyword properties would be specified using
keywords and arguments that occur before any toolbar item
vectors, similarly to how things are done in menu
specifications. Possible properties could include
:captioned-p (whether the captions are visible
under the toolbar), :glyphs-visible-p (whether
the toolbar glyphs are visible), and
:context-menu (additional items that will appear
on the context menus for all toolbar items and additionally
will appear on the context menu that is popped up when the
right mouse button is clicked over a portion of the toolbar
that does not have any toolbar buttons in it). The current
standard practice with regards to such properties seems to be
to have separate specifiers, such as
left-toolbar-width ,
right-toolbar-width ,
left-toolbar-visible-p ,
right-toolbar-visible-p , etc. It could easily be
argued that there should be no such toolbar specifiers and
that all such properties should be part of the toolbar
instantiator itself. In this scheme, the only separate
specifiers that would exist for individual properties would be
default values. There are a lot of reasons why an interface
change like this makes sense. For example, currently when VM
sets its toolbar, it also sets the toolbar width and similar
properties. If you change which edge of the frame the VM
toolbar occurs in, VM will also have to go and modify all of
the position-specific toolbar specifiers for all of the other
properties associated with a toolbar. It doesn't really seem
to make sense to me for the user to be specifying the width
and visibility and such of specific toolbars that are attached
to specific edges because the user should be free to move the
toolbars around and expect that all of the toolbar properties
automatically move with the toolbar. (It is also easy to
imagine, for example, that a toolbar might not be attached to
the edge of the frame at all, but might be floating somewhere
on the user's screen). With an interface where these
properties are separate specifiers, this has to be done
manually. Currently, having the various toolbar properties be
inside of toolbar instantiators makes them difficult to
modify, but this will be different with the API that I propose
below.
-
I propose an API for modifying toolbar and toolbar item
properties, as well as making other changes to toolbar
instantiators, such as inserting or deleting toolbar items.
This API is based around the concept of a path. There are two
kinds of paths here -- toolbar paths and toolbar
item paths. Each kind of path is an object (of type
toolbar-path and toolbar-item-path ,
respectively) whose properties specify the location in a
toolbar instantiator where changes to the instantiator can be
made. A toolbar path, for example, would be created using the
make-toolbar-path function, which takes a toolbar
specifier (or optionally, a symbol, such as left ,
right , default , or nil ,
which refers to a particular toolbar), and optionally,
parameters such as the locale and the tag set, which specify
which actual instantiator inside of the toolbar specifier is
to be modified. A toolbar item path is created similarly
using a function called make-toolbar-item-path ,
which takes a toolbar specifier and a string naming the
caption of the toolbar item to be modified, as well as, of
course, optionally the locale and tag set parameters and
such.
The usefulness of these path objects is as arguments to
functions that will use them as pointers to the place in a
toolbar instantiator where the modification should be made.
Recall, for example, the generalized property interface
described above. If a function such as get or
put is called on a toolbar path or toolbar item
path, it will use the information contained in the path object
to retrieve or modify a property located at the end of the
path. The toolbar path objects can also be passed to new
functions that I propose defining, such as
add-toolbar-item ,
delete-toolbar-item , and
find-toolbar-item . These functions should be
parallel to the functions for inserting, deleting, finding,
etc. items in a menu. The toolbar item path objects can also
be passed to the drop-handler functions defined in
Drag-n-Drop Interface Changes
to retrieve or modify the drop handlers that are associated
with a toolbar item. (The idea here is that you can drag an
object and drop it onto a toolbar item, just as you could onto
a buffer, an extent, a menu item, or any other graphical
element).
-
We should at least think about allowing for separate default
and buffer-local toolbars. The user should either be able to
position these toolbars one above the other, or side by side,
occupying a single toolbar line. In the latter case, the
boundary between the toolbars should be draggable, and if a
toolbar takes up more room than is allocated for it, there
should be arrows that appear on one or both sides of the
toolbar so that the items in the toolbar can be scrolled left
or right. (For that matter, this sort of interface should
exist even when there is only one toolbar that is on a
particular toolbar line, because the toolbar may very well
have more items than can be displayed at once, and it's silly
in such a case if it's impossible to access the items that are
not currently visible).
-
The default context menu for toolbars (which should be
specified using a specifier called
default-toolbar-context-menu according to the
rules defined above) should contain entries allowing the user
to modify the appearance of a toolbar. Entries would include,
for example, whether the toolbar is captioned, whether the
glyphs for the toolbar are visible (if the toolbar is
captioned but its glyphs are not visible, the toolbar appears
as nothing but text; you can set things up this way, for
example, in Netscape), an option that brings up a package for
editing the contents of a toolbar, an option to allow the
caption face to be dchanged (perhaps thorough jan
edit-faces or custom interface),
etc.
Menu API Changes
-
I propose making a specifier for the menubar associated with
the frame. The specifier should be called
default-menubar and should replace the existing
current-menubar variable. This would increase
the power of the menubar interface and bring it in line with
the toolbar interface. (In order to provide proper backward
compatibility, we might have to
complete the symbol value handler
mechanism)
-
I propose an API for modifying menu instantiators similar to
the API composed above for toolbar instantiators. A new
object called a menu path (of type
menu-path ) can be created using the
make-menu-path function, and specifies a location
in a particular menu instantiator where changes can be made.
The first argument to make-menu-path specifies
which menu to modify and can be a specifier, a value such as
nil (which means to modify the default menubar
associated with the selected frame), or perhaps some other
kind of specification referring to some other menu, such as
the context menus invoked by the right mouse button. The
second argument to make-menu-path , also required,
is a list of zero or more strings that specifies the
particular menu or menu item in the instantiator that is being
referred to. The remaining arguments are optional and would
be a locale, a tag set, etc. The menu path object can be
passed to get , put or other standard
property functions to access or modify particular properties
of a menu or a menu item. It can also be passed to expanded
versions of the existing functions such as
find-menu-item , delete-menu-item ,
add-menu-button , etc. (It is really a shame that
add-menu-item is an obsolete function because it
is a much better name than add-menu-button ).
Finally, the menu path object can be passed to the
drop-handler functions described in
Drag-n-Drop Interface Changes
to access or modify the drop handlers that are associated with
a particular menu item.
-
New keyword properties should be added to the menu item
vector. These include :help-echo ,
:context-menu and :drop-handlers ,
with similar semantics to the corresponding keywords for
toolbar items. (It may seem a bit strange at first to have a
context menu associated with a particular menu item, but it is
a user interface concept that exists both in Open Look and in
Windows, and really makes a lot of sense if you give it a bit
of thought). These properties may not actually be implemented
at first, but at least the keywords for them should be
defined.
Ben Wing
|