| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document is based on Jamie Zawinski's xemacs wishlist. Throughout this page, "I" refers to Jamie. The list has been substantially reformatted and edited to fit the needs of this site. If you have any soul at all, you'll go check out the original. OK? You should also check out some other wishlists.
I've ranked these (roughly) from easiest to hardest; though of all of them, I think the debugger improvements would be the most useful. I think the combination of emacs+gdb is the best Unix development environment currently available, but it's still lamentably primitive and extremely frustrating (much like Unix itself), especially if you know what kinds of features more modern integrated debuggers have.
Keyboard macros are one of the most useful concepts that emacs has to offer, but there's room for improvement.
Often, I'll define a keyboard macro, and then realize that I've left something out, or that there's more that I need to do; for example, I may define a macro that does something to the current line, and then realize that I want to apply it to a lot of lines. So, I'd like this to work:
C-x ( ; start macro #1 ... ; (do stuff) C-x ) ; done with macro #1 ... ; (do stuff) C-x ( ; start macro #2 C-x e ; execute macro #1 (splice it into macro #2) C-s foo ; move forward to the next spot C-x ) ; done with macro #2 C-u 1000 C-x e ; apply the new macro |
That is, simply, one should be able to wrap new text around an existing macro. I can't tell you how many times I've defined a complex macro but left out the "C-n C-a" at the end...
Yes, you can accomplish this with M-x name-last-kbd-macro, but that's a pain. And it's also more permanent than I'd often like.
Right now, the act of defining a macro stops if you get an error while defining it, and all of the characters you've already typed into the macro are gone. It needn't be that way. I think that, when that first error occurs, the user should be given the option of taking the last command off of the macro and trying again.
The macro-reader knows where the bounds of multi-character command sequences are, and it could even keep track of the corresponding undo records; rubbing out the previous entry on the macro could also undo any changes that command had made. (This should also work if the macro spans multiple buffers, and should restore window configurations as well.)
You'd want multi-level undo for this as well, so maybe the way to go would be to add some new key sequence which was used only as the back-up-inside-a-keyboard-macro-definition command.
I'm not totally sure that this would end up being very usable; maybe it would be too hard to deal with. Which brings us to:
I only just discovered edit-kbd-macro (C-x C-k).
It is very, very cool.
The trick it does of showing the command which will be executed is somewhat error-prone, as it can only look up things in the current map or the global map; if the macro changed buffers, it wouldn't be displaying the right commands. (One of the things I often use macros for is operating on many files at once, by bringing up a dired buffer of those files, editing them, and then moving on to the next.)
However, if the act of recording a macro also kept track of the actual commands that had gotten executed, it could make use of that info as well.
Another way of editing a macro, other than as text in a buffer, would be to have a command which single-steps a macro: you would lean on the space bar to watch the macro execute one character (command?) at a time, and then when you reached the point you wanted to change, you could do some gesture to either: insert some keystrokes into the middle of the macro and then continue; or to replace the rest of the macro from here to the end; or something.
Another similar hack might be to convert a macro to the equivalent
lisp code, so that one could tweak it later in ways that would be too
hard to do from the keyboard (wrapping parts of it in while loops or
something.) (M-x insert-kbd-macro isn't really what I'm
talking about here: I mean insert the list of commands, not the list
of keystrokes.)
In the spirit of the `teach-extended-commands-p' variable,
it would be interesting if emacs would keep track of what are the
commands I use most often, perhaps grouped by proximity or mode -- it
would then be more obvious which commands were most likely candidates
for placement on a toolbar, or popup menu, or just a more convenient key
binding.
Bonus points if it figures out that I type "bt\n" and "ret\ny\n" into my `*gdb*' buffer about a hundred thousand times a day.
The thing that "File/Open..." pops up has excellent hack value, but as a user interface, it's an abomination. Isn't it time someone added a real file selection dialog already? (For the Motifly-challenged, the Athena-based file selector that GhostView uses seems adequate.)
It's great that XEmacs has a toolbar, but it's damn near impossible to customize it.
Currently, to define a toolbar button that has a text equivalent, one must edit a pixmap, and put the text there! That's prohibitive. One should be able to add some kind of generic toolbar button, with a plain icon or none at all, but which has a text label, without having to use a paint program.
In my c-mode-hook, for example, I can add a couple of new
keybindings, and delete a few others, and to do that, I don't have to
duplicate the entire definition of the c-mode-map. Making
mode-local additions and subtractions to the toolbars should be as
easy.
The same situation holds for the right-mouse-button popup menu; one should be able to add new commands to those menus without difficulty. One problem is that each mode which does have a popup menu implements it in a different way...
About half of the work is done to make a replacement for the
XmText widget which offloads editing responsibility to an
external Emacs process. Someone should finish that. The benefit here
would be that then, any Motif program could be linked such that all
editing happened with a real Emacs behind it. (If you're Athena-minded,
flavor with Text instead of XmText -- it's probably
easy to make it work with both.)
The part of this that is done already is the ability to run an Emacs screen on a Window object that has been created by another process (this is what the `ExternalClient.c' and `ExternalShell.c' stuff is.) What is left to be done is, adding the text-widget-editor aspects of this.
First, the emacs screen being displayed on that window would have to be one without a modeline, and one which behaved sensibly in the context of "I am a small multi-line text area embedded in a dialog box" as opposed to "I am a full-on text editor and lord of all that I survey."
Second, the API that the (non-emacs-aware) user of the
XmText widget expects would need to be implemented: give the
caller the ability to pull the edited text string back out, and so on.
The idea here being, hooking up emacs as the widget editor should be as
transparent as possible.
Some of you may have seen my `gdb-highlight.el' package, that I posted to gnu.emacs.sources last month. I think it's really cool, but there should be a lot more work in that direction. For those of you who haven't seen it, what it does is watch text that gets inserted into the `*gdb*' buffer and make very nearly everything be clickable and have a context-sensitive menu. Generally, the types that are noticed are:
Any time one of those objects is presented in the `*gdb*' buffer, it is mousable. Clicking middle button on it takes some default action (edits the function, selects the stack frame, disables the breakpoint, ...) Clicking the right button pops up a menu of commands, including commands specific to the object under the mouse, and/or other objects on the same line.
So that's all well and good, and I get far more joy out of what this code does for me than I expected, but there are still a bunch of limitations. The debugger interface needs to do much, much more.
The idea behind gdbsrc-mode is on the side of the angels:
one should be able to focus on the source code and not on the debugger
buffer, absolutely. But the implementation is just awful.
First and foremost, it should not change "modes" (in the more
general sense). Any commands that it defines should be on keys which
are exclusively used for that purpose, not keys which are normally
self-inserting. I can't be the only person who usually has occasion to
actually edit the sources which the debugger has chosen to
display! Switching into and out of gdbsrc-mode is
prohibitive.
I want to be looking at my sources at all times, yet I don't want to have to give up my source-editing gestures. I think the right way to accomplish this is to put the gdbsrc commands on the toolbar and on popup menus; or to let the user define their own keys (I could see devoting my kp_enter key to "step", or something common like that.)
Also it's extremely frustrating that one can't turn off gdbsrc mode once it has been loaded, without exiting and restarting emacs; that alone means that I'd probably never take the time to learn how to use it, without first having taken the time to repair it...
I want to be able to double-click on a variable name to highlight it, and then drag it to the debugger window to have its value printed.
I want gestures that let me write as well as read: for example, to store value A into slot B.
Any time there is a running gdb which has breakpoints, the buffers holding the lines on which those breakpoints are set should have icons in them. These icons should be context-sensitive: I should be able to pop up a menu to enable or disable them, to delete them, to change their commands or conditions.
I should also be able to move them. It's annoying when you have a breakpoint with a complex condition or command on it, and then you realize that you really want it to be at a different location. I want to be able to drag-and-drop the icon to its new home.
I want a window off to the side that shows persistent information -- it should have a pane which is a drag-editable, drag-reorderable representation of the elements on gdb's "display" list; they should be displayed here instead of being just dumped in with the rest of the output in the `*gdb*' buffer.
I want a pane that displays the current call-stack and nothing else. I want a pane that displays the arguments and locals of the currently-selected frame and nothing else. I want these both to update as I move around on the stack.
Since the unfortunate reality is that excavating this information from gdb can be slow, it would be a good idea for these panes to have a toggle button on them which meant "stop updating", so that when I want to move fast, I can, but I can easily get the display back when I need it again.
The reason for all of this is that I spend entirely too much time scrolling around in the `*gdb*' buffer; with gdb-highlight, I can just click on a line in the backtrace output to go to that frame, but I find that I spend a lot of time looking for that backtrace: since it's mixed in with all the other random output, I waste time looking around for things (and usually just give up and type "bt" again, then thrash around as the buffer scrolls, and I try to find the lower frames that I'm interested in, as they have invariably scrolled off the window already...
This would be especially handy given that gdb leaks like a sieve, and with a big program, I only get a few dozen relink-and-rerun attempts before gdb has blown my swap space.
When a program is recompiled and then reloaded into gdb, the breakpoints often end up in less-than-useful places. For example, when I edit text which occurs in a file anywhere before a breakpoint, emacs is aware that the line of the bp hasn't changed, but just that it is in a different place relative to the top of the file. Gdb doesn't know this, so your breakpoints end up getting set in the wrong places (usually the maximally inconvenient places, like after a loop instead of inside it). But emacs knows, so emacs should inform the debugger, and move the breakpoints back to the places they were intended to be.
(Possibly the OOBR stuff does some of this, but can't tell, because I've never been able to get it to do anything but beep at me and mumble about environments. I find it pretty funny that the manual keeps explaining to me how intuitive it is, without actually giving me a clue how to launch it...)
It'd be nice to be able to create more complex dialog boxes from emacs-lisp: ones with checkboxes, radio button groups, text fields, and popup menus.
One of the things that the now-defunct Energize code (the C side of it, that is) could do was embed a dialog box between the toolbar and the main text area -- buffers could have control panels associated with them, that had all kinds of complex behavior.
You know, I've encountered people who have been using emacs for years, and never use the mark stack for navigation. I can't live without it; "C-u C-SPC" is among my most common gestures.
It would be a lot easier to realize what's going to happen if the marks on the mark stack were visible. They could be displayed as small "caret" glyphs, for example; something large enough to be visible, but not easily mistaken for a character or for the cursor.
The marks and the selected region should be visible in the scrollbar as well -- I don't remember where I first saw this idea, but it's very cool: there's a second, less-strongly-rendered "thumb" in the scrollbar which indicates the position and size of the selection; and there are tiny tick-marks which indicate the positions of the saved points.
Markers which are in registers (point-to-register, C-x
/) should be displayed differently (more prominent.)
It'd be cool if you could pick up markers and move them around, to adjust the points you'll be coming back to later.
The emacs GC is very primitive; it is also, fortunately, a rather well isolated module, and it would not be a very big task to swap it with a new one (once that new one was written, that is.) Someone should go bone up on modern GC techniques, and then just dive right in...
Yadda yadda, this list goes to eleven.
Subject:
Re: XEmacs wishlist
Date: Wed, 14 May 1997 16:18:23 -0700
From: Jamie Zawinski <jwz@netscape.com>
Newsgroups: comp.emacs.xemacs, comp.emacs
Andreas Schwab wrote:
Use `C-u C-x (':start-kbd-macro:
Non-nil arg (prefix arg) means append to last macro defined; This begins by re-executing that macro as if you typed it again.
Cool, I didn't know it did that...
But it only lets you append. I often want to prepend, or embed the macro multiple times (motion 1, C-x e, motion 2, C-x e, motion 3.)
Author: Ben Wing
DISTRIBUTION ISSUES
A. Unified Source Tarball.
Packages go under root/lib/xemacs/xemacs-packages and no one ever has to mess with --package-path and the result can be moved from one directory to another pre- or post-install.
Unified Binary Tarballs with Packages.
Same principles as above.
If people complain, we can also provide split binary tarballs (architecture dependent and independent) and place these files in a subdirectory so as not to confuse the majority just looking for one tarball.
Under Windows, we need to provide a WISE-style GUI setup program. It's already there but needs some work so you can select "all" packages easily (should be the default).
Parallel Root and Package Trees.
If the user downloads separately, the main source and the packages, he will naturally untar them into the same directory. This results in the parallel root and package structure. We should support this as a "last resort," i.e., if we find no packages anywhere and are about to resign ourselves to not having packages, then look for a parallel package tree. The user who sets things up like this should be able to either run in place or "make install" and get a proper installed XEmacs. Never should the user have to touch --package-path.
II. WINDOWS PRINTING
Looks like the internals are done but not the GUI. This must be working in 21.2.
III. WINDOWS MULE
Basic support should be there. There's already a patch to get things started and I'll be doing more work to make this real.
IV. GUTTER ETC.
This stuff needs to be "stable" and generally free from bugs. Any APIs we create need to be well-reviewed or marked clearly as experimental.
V. PORTABLE DUMPER
Last bits need to be cleaned up. This should be made the "default" for a while to flush-out problems. Under Microsoft Windows, Portable Dumper must be the default in 21.2 because of the problems with the existing dump process.
COMMENT: I'd like to feature freeze this pretty soon and create a 21.3 tree where all of my major overhauls of Mule-related stuff will go in. At the same time or around, we need to do the move-around in the repository (or create a new one) and "upgrade" to the latest CVS server.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
A while ago I created a package called Sysdep, which aimed to be a forward compatibility package for Elisp. The idea was that instead of having to write your package using the oldest version of Emacs that you wanted to support, you could use the newest XEmacs API, and then simply load the Sysdep package, which would automatically define the new API in terms of older APIs as necessary. The idea of this package was good, but its design wasn't perfect, and it wasn't widely adopted. I propose a new package called Compat that corrects the design flaws in Sysdep, and hopefully will be adopted by most of the major packages.
In addition, this package will provide macros that can be used to bracket code as necessary to disable byte compiler warnings generated as a result of supporting the APIs of different versions of Emacs; or rather the Compat package strives to provide useful constructs to make doing this support easier, and these constructs have the side effect of not causing spurious byte compiler warnings. The idea here is that it should be possible to create well-written, clean, and understandable Elisp that supports both older and newer APIs, and has no byte compiler warnings. Currently many warnings are unavoidable, and as a result, they are simply ignored, which also causes a lot of legitimate warnings to be ignored.
The approach taken by the Sysdep package to make sure that the newest API was always supported was fairly simple: when the Sysdep package was loaded, it checked for the existence of new API functions, and if they weren't defined, it defined them in terms of older API functions that were defined. This had the advantage that the checks for which API functions were defined were done only once at load time rather than each time the function was called. However, the fact that the new APIs were globally defined caused a lot of problems with unwanted interactions, both with other versions of the Sysdep package provided as part of other packages, and simply with compatibility code of other sorts in packages that would determine whether an API existed by checking for the existence of certain functions within that API. In addition, the Sysdep package did not scale well because it defined all of the functions that it supported, regardless of whether or not they were used.
The Compat package remedies the first problem by ensuring that the new APIs are defined only within the lexical scope of the packages that actually make use of the Compat package. It remedies the second problem by ensuring that only definitions of functions that are actually used are loaded. This all works roughly according to the following scheme:
Part of the Compat package is a module called the Compat generator.
This module is actually run as an additional step during byte
compilation of a package that uses Compat. This can happen either
through the makefile or through the use of an eval-when-compile
call within the package code itself. What the generator does is scan
all of the Lisp code in the package, determine which function calls are
made that the Compat package knows about, and generates custom
compat code that conditionally defines just these functions when
the package is loaded. The custom compat code can either be
written to a separate Lisp file (for use with multi-file packages), or
inserted into the beginning of the Lisp file of a single file package.
(In the latter case, the package indicates where this generated code
should go through the use of magic comments that mark the beginning and
end of the section. Some will say that doing this trick is bad juju,
but I have done this sort of thing before, and it works very well in
practice).
The functions in the custom compat code have their names prefixed
with both the name of the package and the word compat, ensuring
that there will be no name space conflicts with other functions in the
same package, or with other packages that make use of the Compat
package.
The actual definitions of the functions in the custom compat code
are determined at run time. When the equivalent API already exists, the
wrapper functions are simply defined directly in terms of the actual
functions, so that the only run time overhead from using the Compat
package is one additional function call. (Alternatively, even this
small overhead could be avoided by retrieving the definitions of the
actual functions and supplying them as the definitions of the wrapper
functions. However, this appears to me to not be completely safe. For
example, it might have bad interactions with the advice package).
The code that wants to make use of the custom compat code is
bracketed by a call to the construct compat-execute. What this
actually does is lexically bind all of the function names that are being
redefined with macro functions by using the Common Lisp macro macrolet.
(The definition of this macro is in the CL package, but in order for
things to work on all platforms, the definition of this macro will
presumably have to be copied and inserted into the custom compat
code).
In addition, the Compat package should define the macro
compat-if-fboundp. Similar macros such as
compile-when-fboundp and compile-case-fboundp could be
defined using similar principles). The compat-if-fboundp macro
behaves just like an (if (fboundp ...) ...) clause when executed,
but in addition, when it's compiled, it ensures that the code inside the
if-true sub-block will not cause any byte compiler warnings about
the function in question being unbound. I think that the way to
implement this would be to make compat-if-fboundp be a macro that
does what it's supposed to do, but which defines its own byte code
handler, which ensures that the particular warning in question will be
suppressed. (Actually ensuring that just the warning in question is
suppressed, and not any others, might be rather tricky. It certainly
requires further thought).
Note: An alternative way of avoiding both warnings about unbound
functions and warnings about obsolete functions is to just call the
function in question by using funcall, instead of calling the
function directly. This seems rather inelegant to me, though, and
doesn't make it obvious why the function is being called in such a
roundabout manner. Perhaps the Compat package should also provide a
macro compat-funcall, which works exactly like funcall,
but which indicates to anyone reading the code why the code is expressed
in such a fashion.
If you're wondering how to implement the part of the Compat generator
where it scans Lisp code to find function calls for functions that it
wants to do something about, I think the best way is to simply process
the code using the Lisp function read and recursively descend any
lists looking for function names as the first element of any list
encountered. This might extract out a few more functions than are
actually called, but it is almost certainly safer than doing anything
trickier like byte compiling the code, and attempting to look for
function calls in the result. (It could also be argued that the names
of the functions should be extracted, not only from the first element of
lists, but anywhere symbol occurs. For example, to catch places
where a function is called using funcall or apply.
However, such uses of functions would not be affected by the surrounding
macrolet call, and so there doesn't appear to be any point in extracting
them).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
Abstract: I propose completely redoing the drag-n-drop interface to make it powerful and extensible enough to support such concepts as drag over and drag under visuals and context menus invoked when a drag is done with the right mouse button, to allow drop handlers to be defined for all sorts of graphical elements including buffers, extents, mode lines, toolbar items, menubar items, glyphs, etc., and to allow different packages to add and remove drop handlers for the same drop sites without interfering with each other. The changes are extensive enough that I think they can only be implemented in version 22, and the drag-n-drop interface should remain experimental until then.
The new drag-n-drop interface centers around the twin concepts of drop site and drop handler. A drop site specifies a particular graphical element where an object can be dropped onto, and a drop handler encapsulates all of the behavior that happens when such an object is dragged over and dropped onto a drop site.
Each drop site has an object associated with it which is passed to
functions that are part of the drop handlers associated with that site.
The type of this object depends on the graphical element that comprises
the drop site. The drop site object can be a buffer, an extent, a
glyph, a menu path, a toolbar item path, etc. (These last two object
types are defined in Lisp Interface Changes
in the sections on menu and toolbar API changes. If we wanted to allow
drops onto other kinds of drop sites, for example mode lines, we would
have to create corresponding path objects). Each such object type
should be able to be accessed using the generalized property interface
defined above, and should have a property called drop-handlers
associated with it that specifies all of the drop handlers associated
with the drop site. Normally, this property is not accessed directly,
but instead by using the drop handler API defined below, and Lisp
packages should not make any assumptions about the format of the data
contained in the drop-handlers property.
Each drop handler has an object of type drop-handler associated
with it, whose primary purpose is to be a container for the various
properties associated with a particular drop handler. These could
include, for example, a function invoked when the drop occurs, a context
menu invoked when a drop occurs as a result of a drag with the right
mouse button, functions invoked when a dragged object enters, leaves, or
moves within a drop site, the shape that the mouse pointer changes to
when an object is dragged over a drop site that allows this particular
object to be dropped onto it, the MIME types (actually a regular
expression matching the MIME types) of the allowable objects that can be
dropped onto the drop site, a package tag (a symbol specifying the
package that created the drop handler, used for identification
purposes), etc. The drop handler object is passed to the functions that
are invoked as a result of a drag or a drop, most likely indirectly as
one of the properties of the drag or drop event passed to the function.
Properties of a drop handler object are accessed and modified in the
standard fashion using the generalized property interface.
A drop handler is added to a drop site using the add-drop-handler
function. The drop handler itself can either be created separately
using the make-drop-handler function and then passed in as one of
the parameters to add-drop-handler, or it will be created
automatically by the add-drop-handler function, if the drop
handler argument is omitted, but keyword arguments corresponding to the
valid keyword properties for a drop handler are specified in the
add-drop-handler call. Other functions, such as
find-drop-handler, add-drop-handler (when specifying a
drop handler before which the drop handler in question is to be added),
remove-drop-handler etc. should be defined with obvious
semantics. All of these functions take or return a drop site object
which, as mentioned above, can be one of several object types
corresponding to graphical elements. Defined drop handler functions
locate a particular drop handler using either the MIME-type or
package-tag property of the drop handler, as defined above.
Logically, the drop handlers associated with a particular drop site are an ordered list. The first drop handler whose specified MIME type matches the MIME type of the object being dragged or dropped controls what happens to this object. This is important particularly because the specified MIME type of the drop handler can be a regular expression that, for example, matches all audio objects with any sub-type.
In the current drag-n-drop API, there is a distinction made between objects with an associated MIME type and objects with an associated URL. I think that this distinction is arbitrary, and should not exist. All objects should have a MIME type associated with them, and a new XEmacs-specific MIME type should be defined for URLs, file names, etc. as necessary. I am not even sure that this is necessary, however, as the MIME specification may specify a general concept of a pointer or link to an object, which is exactly what we want. Also in some cases (for example, the name of a file that is locally available), the pointer or link will have another MIME type associated with it, which is the type of the object that is being pointed to. I am not quite sure how we should handle URL and file name objects being dragged, but I am positive that it needs to be integrated with the mechanism used when an object itself is being dragged or dropped.
As is described in a separate page, the
misc-user-event event type should be removed and split up into a
number of separate event types. Two such event types would be
drag-event and drop-event. A drop event is used when an
object is actually dropped, and a drag event is used if a function is
invoked as part of the dragging process. (Such a function would
typically be used to control what are called drag under visuals,
which are changes to the appearance of the drop site reflecting the fact
that a compatible object is being dragged over it). The drag events and
drop events encapsulate all of the information that is pertinent to the
drag or drop action occurring, including such information as the actual
MIME type of the object in question, the drop handler that caused a
function to be invoked, the mouse event (or possibly even a keyboard
event) corresponding to the user's action that is causing the drag or
drop, etc. This event is always passed to any function that is invoked
as a result of the drag or drop. There should never be any need to
refer to the current-mouse-event variable, and in fact, this
variable should not be changed at all during a drag or a drop.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
Abstract: Apparently, if you know the name of a package (for
example, fusion), you can load it using the require
function, but there's no standard way to turn it on or turn it off. The
only way to figure out how to do that is to go read the source file,
where hopefully the comments at the start tell you the appropriate magic
incantations that you need to run in order to turn the extension on or
off. There really needs to be standard functions, such as
enable-extension and disable-extension, to do this sort of
thing. It seems like a glaring omission that this isn't currently
present, and it's really surprising to me that nobody has remarked on
this.
The easy part of this is defining the interface, and I think it should
be done as soon as possible. When the package is loaded, it simply
calls some standard function in the package system, and passes it the
names of enable and disable functions, or perhaps just one function that
takes an argument specifying whether to enable or disable. In any case,
this data is kept in a table which is used by the
enable-extension and disable-extension function. There
should also be functions such as extension-enabled-p and
enabled-extension-list, and so on with obvious semantics. The
hard part is actually getting packages to obey this standard interface,
but this is mitigated by the fact that the changes needed to support
this interface are so simple.
I have been conceiving of these enabling and disabling functions as turning the feature on or off globally. It's probably also useful to have a standard interface returning a extension on or off in just the particular buffer. Perhaps then the appropriate interface would involve registering a single function that takes an argument that specifies various things, such as turn off globally, turn on globally, turn on or off in the current buffer, etc.
Part of this interface should specify the correct way to define global
key bindings. The correct rule for this, of course, is that the key
bindings should not happen when the package is loaded, which is often
how things are currently done, but only when the extension is actually
enabled. The key bindings should go away when the extension is
disabled. I think that in order to support this properly, we should
expand the keymap interface slightly, so that in addition to other
properties associated with each key binding is a list of shadow
bindings. Then there should be a function called
define-key-shadowing, which is just like define-key but
which also remembers the previous key binding in a shadow list. Then
there can be another function, something like undefine-key, which
restores the binding to the most recently added item on the shadow list.
There are already hash tables associated with each key binding, and it
should be easy to stuff additional values, such as a shadow list, into
the hash table. Probably there should also be functions called
global-set-key-shadowing and global-unset-key-shadowing
with obvious semantics.
Once this interface is defined, it should be easy to expand the custom package so it knows about this interface. Then it will be possible to put all sorts of extensions on the options menu so that they could be turned off and turned on very easily, and then when you save the options out to a file, the design settings for whether these extensions are enabled or not are saved out with it. A whole lot of custom junk that's been added to a lot of different packages could be removed. After doing this, we might want to think of a way to classify extensions according to how likely we think the user will want to use them. This way we can avoid the problem of having a list of 100 extensions and the user not being able to figure out which ones might be useful. Perhaps the most useful extensions would appear immediately on the extensions menu, and the less useful ones would appear in a submenu of that, and another submenu might contain even less useful extensions. Of course the package authors might not be too happy with this, but the users probably will be. I think this at least deserves a thought, although it's possible you might simply want to maintain a list on the web site of extensions and a judgment on first of all, how commonly a user might want this extension, and second of all, how well written and bug-free the package is. Both of these sorts of judgments could be obtained by doing user surveys if need be.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
Abstract: A proposal is outlined for converting XEmacs to use
the .xemacs subdirectory for its initialization files instead of
putting them in the user's home directory. In the process, a general
pre-initialization scheme is created whereby all of the initialization
parameters, such as the location of the initialization files, whether
these files are loaded or not, where the initial frame is created,
etc. that are currently specified by command line arguments, by
environment variables, and other means, can be specified in a uniform
way using Lisp code. Reasonable default behavior for everything will
still be provided, and the older, simpler means can be used if desired.
Compatibility with the current location and name of the initialization
file, and the current ill-chosen use for the .xemacs directory is
maintained, and the problem of how to gracefully migrate a user from the
old scheme into the new scheme while still allowing the user to use GNU
Emacs or older versions of XEmacs is solved. A proposal for changing
the way that the initial frame is mapped is also outlined; this would
allow the user's initialization file to control the way that the initial
frame appears without resorting to hacks, while still making echo area
messages visible as they appear, and allowing the user to debug errors
in the initialization file.
XEmacs has a defined pre-initialization process. This process,
whose purpose is to compute the values of the parameters that control
how the initializiaton process proceeds, occurs as early as possible
after the Lisp engine has been initialized, and in particular, it occurs
before any devices have been opened, or before any initialization
parameters are set that could reasonably be expected to be changed. In
fact, the pre-initialization process should take care of setting these
parameters. The code that implements the pre-initialization process
should be written in Lisp and should be called from the Lisp function
normal-top-level, and the general way that the user customizes
this process should also be done using Lisp code.
The pre-initialization process involves a number of properties, for
example the directory containing the user initialization files (normally
the .xemacs subdirectory), the name of the user init file, the
name of the custom init file, where and what type the initial device is,
whether and when the initial frame is mapped, etc. A standard interface
is provided for getting and setting the values of these properties using
functions such as set-pre-init-property,
pre-init-property, etc. At various points during the
pre-initialization process, the value of many of these properties can be
undecided, which means that at the end of the process, the value of
these properties will be derived from other properties in some fashion
that is specific to each property.
The default values of these properties are set first from the registry
under Windows, then from environment variables, then from command line
switches, such as -q and -nw.
One of the command line switches is -pre-init, whose value is a
Lisp expression to be evaluated at pre-initialization time, similar to
the -eval command line switch. This allows any
pre-initialization property to be set from the command line.
Let's define the term to determine a pre-initialization property to mean if the value of a property is undetermined, it is computed and set according to a rule that is specific to the property. Then after the pre-init properties are initialized from the registry, from the environment variables, from command line arguments, two of the pre-init properties (specifically the init file directory and the location of the pre-init file) are determined. The purpose of the pre-init file is to contain Lisp code that is run at pre-initialization time, and to control how the initialization proceeds. It is a bit similar to the standard init file, but the code in the pre-init file shouldn't do anything other than set pre-init properties. Executing any code that does I/O might not produce expected results because the only device that will exist at the time is probably a stream device connected to the standard I/O of the XEmacs process.
After the pre-init file has been run, all of the rest of the pre-init properties are determined, and these values are then used to control the initialization process. Some of the rules used in determining specific properties are:
If the .xemacs sub-directory exists, and it's not obviously a
package root (which probably means that it contains a file like
init.el or pre-init.el, or if neither of those files is
present, then it doesn't contain any sub-directories or files that look
like what would be in a package root), then it becomes the value of the
init file directory. Otherwise the user's home directory is used.
If the init file directory is the user's home directory, then the init
file is called .emacs. Otherwise, it's called init.el.
If the init file directory is the user's home directory, then the
pre-init file is called .xemacs-pre-init.el. Otherwise it's
called pre-init.el. (One of the reasons for this rule has to do
with the dialog box that might be displayed at startup. This will be
described below.)
If the init file directory is the user's home directory, then the custom
init file is called .xemacs-custom-init.el. Otherwise, it's
called custom-init.el.
After the first normal device is created, but before any frames are
created on it, the XEmacs initialization code checks to see if the old
init file scheme is being used, which is to say that the init file
directory is the same as the user's home directory. If that's the case,
then normally a dialog box comes up (or a question is asked on the
terminal if XEmacs is being run in a non-windowing mode) which asks if
the user wants to migrate his initialization files to the new scheme.
The possible responses are Yes, No, and No,
and don't ask this again. If this last response is chosen, then the
file .xemacs-pre-init.el in the user's home directory is created
or appended to with a line of Lisp code that sets up a pre-init property
indicating that this dialog box shouldn't come up again. If the
Yes option is chosen, then any package root files in
.xemacs are moved into .xemacs/packages, the file
.emacs is moved into .xemacs/init.el and .emacs in
the home directory becomes a symlink to this file. This way some
compatibility is still maintained with GNU Emacs and older versions of
XEmacs. The code that implements this has to be written very carefully
to make sure that it doesn't accidentally delete or mess up any of the
files that get moved around.
The custom init file is where the custom package writes its options. This obviously needs to be a separate file from the standard init file. It should also be loaded before the init file rather than after, as is usually done currently, so that the init file can override these options if it wants to.
In addition to the above scheme, the way that XEmacs handles mapping the initial frame should be changed. However, this change perhaps should be delayed to a later version of XEmacs because of the user visible changes that it entails and the possible breakage in people's init files that might occur. (For example, if the rest of the scheme is implemented in 21.2, then this part of the scheme might want to be delayed until version 22.) The basic idea is that the initial frame is not created before the initialization file is run, but instead a banner frame is created containing the XEmacs logo, a button that allows the user to cancel the execution of the init file and an area where messages that are output in the process of running this file are displayed. This area should contain a number of lines, which makes it better than the current scheme where only the last message is visible. After the init file is done, the initial frame is mapped. This way the init file can make face changes and other such modifications that affect initial frame and then have the initial frame correctly come up with these changes and not see any frame dancing or other problems that exist currently.
There should be a function that allows the initialization file to
explicitly create and map the first frame if it wants to. There should
also be a pre-init property that controls whether the banner frame
appears (of course it defaults to true) a property controlling when the
initial frame is created (before or after the init file, defaulting to
after), and a property controlling whether the initial frame is mapped
(normally true, but will be false if the -unmapped command line
argument is given).
If an error occurs in the init file, then the initial frame should always be created and mapped at that time so that the error is displayed and the debugger has a place to be invoked.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
NOTE: These changes are partly motivated by the various user-interface changes elsewhere in this document, and partly for Mule support. In general the various APIs in this document would benefit greatly from built-in keywords.
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.
DEFUN_WITH_KEYWORDS (Ffoo, "foo", 2, 5, 6, ALLOW_OTHER_KEYWORDS,
(ichi, ARG_NIL), (ni, ARG_NIL), (san, ARG_UNBOUND), 0,
(arg1, arg2, arg3, arg4, arg5)
)
{
...
}
-> C fun of 12 args:
(arg1, ... arg5, ichi, ..., roku, other keywords)
Circled in blue is actual example declaration
DEFUN_WITH_KEYWORDS (Ffoo, "foo", 1,2,0 (bar, baz) <- arg list
[ MIN ARGS, MAX ARGS, something that could be REST, SPECIFY_DEFAULT or
REST_SPEC]
[#KEYWORDS [ ALLOW_OTHER, SPECIFY_DEFAULT, ALLOW_OTHER_SPECIFY_DEFAULT
6, ALLOW_OTHER_SPECIFY_DEFAULT,
(ichi, 0) (ni, 0), (san, DEFAULT_UNBOUND), (shi, "t"), (go, "5"),
(roku, "(current-buffer)")
<- specifies arguments, default values (string to be read into Lisp
data during init; then forms evalled at fn ref time.
,0 <- [INTERACTIVE SPEC] )
LO = Lisp_Object
-> LO Ffoo (LO bar, LO baz, LO ichi, LO ni, LO san, LO shi, LO go,
LO roku, int numkeywords, LO *other_keywords)
#define DEFUN_WITH_KEYWORDS (fun, funstr, minargs, maxargs, argspec, \
#args, num_keywords, keywordspec, keywords, intspec) \
LO fun (DWK_ARGS (maxargs, args) \
DWK_KEYWORDS (num_keywords, keywordspec, keywords))
#define DWK_KEYWORDS (num_keywords, keywordspec, keywords) \
DWK_KEYWORDS ## keywordspec (keywords)
DWK_OTHER_KEYWORDS ## keywordspec)
#define DWK_KEYWORDS_ALLOW_OTHER (x,y)
DWK_KEYWORDS (x,y)
#define DWK_KEYWORDS_ALLOW_OTHER_SPECIFICATIONS (x,y)
DWK_KEYWORDS_SPECIFY_DEFAULT (x,y)
#define DWK_KEYWORDS_SPECIFY_DEFAULT (numkey, key)
ARGLIST_CAR ## numkey key
#define ARGLT_GRZ (x,y) LO CAR x, LO CAR y
|
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
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.
Another idea:
(define-property-method
predicate object-type
predicate cons :(KEYWORD) (all lists beginning with KEYWORD)
:put putfun
:get
:remprop
:object-props
:clear-properties
:map-properties
e.g. (define-property-method 'hash-table
:put #'(lambda (obj key value) (puthash key obj value)))
|
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| 40.8.1 Future Work -- Easier Toolbar Customization | ||
| 40.8.2 Future Work -- Toolbar Interface Changes |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
Abstract: One of XEmacs' greatest strengths is its ability to be customized endlessly. Unfortunately, it is often too difficult to figure out how to do this. There has been some recent work like the Custom package, which helps in this regard, but I think there's a lot more work that needs to be done. Here are some ideas (which certainly could use some more thought).
Although there is currently an edit-toolbar package, it is not
well integrated with XEmacs, and in general it is much too hard to
customize the way toolbars look. I would like to see an interface that
works a bit like the way things work under Windows, where you can
right-click on a toolbar to get a menu of options that allows you to
change aspects of the toolbar. The general idea is that if you
right-click on an item itself, you can do things to that item, whereas
if you right-click on a blank part of a toolbar, you can change the
properties of the toolbar. Some of the items on the right-click menu
for a particular toolbar button should be specified by the button
itself. Others should be standard. For example, there should be an
Execute item which simply does what would happen if you
left-click on a toolbar button. There should probably be a
Delete item to get rid of the toolbar button and a
Properties item, which brings up a property sheet that allows
you to do things like change the icon and the command string that's
associated with the toolbar button.
The options to change the appearance of the toolbar itself should
probably appear both on the context menu for specific buttons, and on
the menu that appears when you click on a blank part of the toolbar.
That way, if there isn't a blank part of the toolbar, you can still
change the toolbar appearance. As for what appears in these items, in
Outlook Express, for example, there are three different menu items, one
of which is called Buttons, which brings up, or pops up a
window which allows you to edit the toolbar, which for us could pop up a
new frame, which is running edit-toolbar.el. The second item is
called Align, which contains a submenu that says Top,
Bottom, Left, and Right, which will be just
like setting the default toolbar position. The third one says
Text Labels, which would just let you select whether there are
captions or not. I think all three of these are useful and are easy to
implement in XEmacs. These things also need to be integrated with
custom so that a user can control whether these options apply to all
sessions, and in such a case can save the settings out to an options
file. edit-toolbar.el in particular needs to integrate with
custom. Currently it has some sort of hokey stuff of its own, which it
saves out to a .toolbar file. Another useful option to have,
once we draw the captions dynamically rather than using pre-generated
ones, would be the ability to change the font size of the captions. I'm
sure that Kyle, for one, would appreciate this.
(This is incomplete.....)
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
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.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
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.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
Abstract: This page describes why the misc-user event type should be split up into a number of different event types, and how to do this.
The misc-user event should not exist as a single event type. It should
be split up into a number of different event types: one for scrollbar
events, one for menu events, and one or two for drag-n-drop events.
Possibly there will be other event types created in the future. The
reason for this is that the misc-user event was a bad design choice when
I made it, and it has only gotten worse with Oliver's attempts to add
features to it to make it be used for drag-n-drop. I know that there
was originally a separate drag-n-drop event type, and it was folded into
the misc-user event type on my recommendation, but I have now realized
the error of my ways. I had originally created a single event type in
an attempt to prevent some Lisp programs from breaking because they
might have a case statement over various event types, and would not be
able to handle new event types appearing. I think now that these
programs simply need to be written in a way to handle new event types
appearing. It's not very hard to do this. You just use predicates
instead of doing a case statement over the event type. If we preserve
the existing predicate called misc-user-event-p, and just make
sure that it evaluates to true when given any user event type other than
the standard simple ones, then most existing code will not break either
when we split the event types up like this, or if we add any new event
types in the future.
More specifically, the only clean way to design the misc-user event type would be to add a sub-type field to it, and then have the nature of all the other fields in the event type be dependent on this sub-type. But then in essence, we'd just be reimplementing the whole event-type scheme inside of misc-user events, which would be rather pointless.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| 40.11.1 Future Work -- Abstracted Mouse Pointer Interface | ||
| 40.11.2 Future Work -- Busy Pointer |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
Abstract: We need to create a new image format that allows
standard pointer shapes to be specified in a way that works on all
Windows systems. I suggest that this be called pointer, which
has one tag associated with it, named :data, and whose value is a
string. The possible strings that can be specified here are predefined
by XEmacs, and are guaranteed to work across all Windows systems. This
means that we may need to provide our own definition for pointer shapes
that are not standard on some systems. In particular, there are a lot
more standard pointer shapes under X than under Windows, and most of
these pointer shapes are fairly useful. There are also a few pointer
shapes (I think the hand, for example) on Windows, but not on X.
Converting the X pointer shapes to Windows should be easy because the
definitions of the pointer shapes are simply XBM files, which we can
read under Windows. Going the other way might be a little bit more
difficult, but it should still not be that hard.
While we're at it, we should change the image format currently called
cursor-font to x-cursor-font, because it only works under
X Windows. We also need to change the format called resource to
be mswindows-resource. At least in the case of
cursor-font, the old value should be maintained for compatibility
as an obsolete alias. The resource format was added so recently
that it's possible that we can just change it.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
Automatically make the mouse pointer switch to a busy shape (watch signal) when XEmacs has been "busy" for more than, e.g. 2 seconds. Define the busy time as the time since the last time that XEmacs was ready to receive input from the user. An implementation might be:
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| 40.12.1 Future Work -- Everything should obey duplicable extents |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
A lot of functions don't properly track duplicable extents. For
example, the concat function does, but the format function
does not, and extents in keymap prompts are not displayed either. All
of the functions that generate strings or string-like entities should
track the extents that are associated with the strings. Currently this
is difficult because there is no general mechanism implemented for doing
this. I propose such a general mechanism, which would not be hard to
implement, and would be easy to use in other functions that build up
strings.
The basic idea is that we create a C structure that is analogous to a
Lisp string in that it contains string data and lists of extents for
that data. Unlike standard Lisp strings, however, this structure (let's
call it lisp_string_struct) can be incrementally updated and its
allocation is handled explicitly so that no garbage is generated. (This
is important for example, in the event-handling code which would want to
use this structure, but needs to not generate any garbage for efficiency
reasons). Both the string data and the list of extents in this string
are handled using dynarrs so that it is easy to incrementally update
this structure. Functions should exist to create and destroy instances
of lisp_string_struct to generate a Lisp string from a
lisp_string_struct and vice-versa to append a sub-string of a
Lisp string to a lisp_string_struct, to just append characters to
a lisp_string_struct, etc. The only thing possibly tricky about
implementing these functions is implementing the copying of extents from
a Lisp string into a lisp_string_struct. However, there is
already a function copy_string_extents() that does basically this
exact thing, and it should be easy to create a modified version of this
function.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Author: Ben Wing
Abstract: The purpose of this proposal is to present a coherent plan for how development branches in XEmacs are managed. This will cover such issues as stable versus experimental branches, creating new branches, synchronizing patches between branches, and how version numbers are assigned to branches.
A development branch is defined to be a linear series of releases of the XEmacs code base, each of which is derived from the previous one. When the XEmacs development tree is forked and two branches are created where there used to be one, the branch that is intended to be more stable and have fewer changes made to it is considered the one that inherits the parent branch, and the other branch is considered to have begun at the branching point. The less stable of the two branches will eventually be forked again, while this will not happen usually to the more stable of the two branches, and its development will eventually come to an end. This means that every branch has a definite ending point. For example, the 20.x branch began at the point when the released 19.13 code tree was split into a 19.x and a 20.x branch, and a 20.x branch will end when the last 20.x release (probably numbered 20.5 or 20.6) is released.
I think that there should always be three active development branches at any time. These branches can be designated the stable, the semi-stable, and the experimental branches. This situation has existed in the current code tree as soon as the 21.0 development branch was split. In this situation, the stable branch is the 20.x series. The semi-stable branch is the 21.0 release and the stability releases that follow. The experimental branch is the branch that was created as the result of the 21.0 development branch split. Typically, the stable branch has been released for a long period of time. The semi-stable branch has been released for a short period of time, or is about to be released, and the experimental branch has not yet been released, and will probably not be released for awhile. The conditions that should hold in all circumstances are:
There should be three active branches.
The experimental branch should never be in feature freeze.
The reason for the second condition is to ensure that active development can always proceed and is never throttled, as is happening currently at the end of the 21.0 release cycle. What this means is that as soon as the experimental branch is deemed to be stable enough to go into feature freeze:
The current stable branch is made inactive and all further development on it ceases.
The semi-stable branch, which by now should have been released for a fair amount of time, and should be fairly stable, gets renamed to the stable branch.
The experimental branch is forked into two branches, one of which becomes the semi-stable branch, and the other, the experimental branch.
The stable branch is always in high resistance, which is to say that the only changes that can be made to the code are important bug fixes involving a small amount of code where it should be clear just by reading the code that no destabilizing code has been introduced. The semi-stable branch is in low resistance, which means that no major features can be added, but except right before a release fairly major code changes are allowed. Features can be added if they are sufficiently small, if they are deemed sufficiently critical due to severe problems that would exist if the features were not added (for example, replacement of the unexec mechanism with a portable solution would be a feature that could be added to the semi-stable branch provided that it did not involve an overly radical code re-architecture, because otherwise it might be impossible to build XEmacs on some architectures or with some compilers), or if the primary purpose of the new feature is to remedy an incompleteness in a recent architectural change that was not finished in a prior release due to lack of time (for example, abstracting the mouse pointer and list-of-colors interfaces, which were left out of 21.0). There is no feature resistance in place in the experimental branch, which allows full development to proceed at all times.
In general, both the stable and semi-stable branches will contain previous net releases. In addition, there will be beta releases in all three branches, and possibly development snapshots between the beta releases. It's obviously necessary to have a good version numbering scheme in order to keep everything straight.
First of all, it needs to be immediately clear from the version number whether the release is a beta release or a net release. Steve has proposed getting rid of the beta version numbering system, which I think would be a big mistake. Furthermore, the net release version number and beta release version number should be kept separate, just as they are now, to make it completely clear where any particular release stands. There may be alternate ways of phrasing a beta release other than something like 21.0 beta 34, but in all such systems, the beta number needs to be zero for any release version. Three possible alternative systems, none of which I like very much, are:
The beta number is simply an extra number in the regular version number. Then, for example, 21.0 beta 34 becomes 21.0.34. The problem is that the release version, which would simply be called 21.0, appears to be earlier than 21.0 beta 34.
The beta releases appear as later revisions of earlier releases. Then, for example, 21.1 beta 34 becomes 21.0.34, and 21.0 beta 34 would have to become 21.-1.34. This has both the obvious ugliness of negative version numbers and the problem that it makes beta releases appear to be associated with their previous releases, when in fact they are more closely associated with the following release.
Simply make the beta version number be negative. In this scheme, you'd start with something like -1000 as the first beta, and then 21.0 beta 34 would get renumbered to 21.0.-968. Obviously, this is a crazy and convoluted scheme as well, and we would be best to avoid it.
Currently, the between-beta snapshots are not numbered, but I think that they probably should be. If appropriate scripts are handled to automate beta release, it should be very easy to have a version number automatically updated whenever a snapshot is made. The number could be added either as a separate snapshot number, and you'd have 21.0 beta 34 pre 1, which becomes before 21.0 beta 34; or we could make the beta number be floating point, and then the same snapshot would have to be called 21.0 beta 33.1. The latter solution seems quite kludgey to me.
There also needs to be a clear way to distinguish, when a net release is made, which branch the release is a part of. Again, three solutions come to mind:
The major version number reflects which development branch the release is in and the minor version number indicates how many releases have been made along this branch. In this scheme, 21.0 is always the first release of the 21 series development branch, and when this branch is split, the child branch that becomes the experimental branch gets version numbers starting with 22. This scheme is the simplest, and it's the one I like best.
We move to a three-part version number. In this scheme, the first two numbers indicate the branch, and the third number indicates the release along the branch. In this scheme, we have numbers like 21.0.1, which would be the second release in the 21.0 series branch, and 21.1.2, which would be the third release in the 21.1 series branch. The major version number then gets increased only very occasionally, and only when a sufficiently major architectural change has been made, particularly one that causes compatibility problems with code written for previous branches. I think schemes like this are unnecessary in most circumstances, because usually either the major version number ends up changing so often that the second number is always either zero or one, or the major version number never changes, and as such becomes useless. By the time the major version number would change, the product itself has changed so much that it often gets renamed. Furthermore, it is clear that the two version number scheme has been used throughout most of the history of Emacs, and recently we have been following the two number scheme also. If we introduced a third revision number, at this point it would both confuse existing code that assumed there were two numbers, and would look rather silly given that the major version number is so high and would probably remain at the same place for quite a long time.
A third scheme that would attempt to cross the two schemes would keep the same concept of major version number as for the three number scheme, and would compress the second and third numbers of the three number scheme into one number by using increments of ten. For example, the current 21.x branch would have releases No. 21.0, 21.1, etc. The next branch would be No. 21.10, 21.11, etc. I don't like this scheme very much because it seems rather kludgey, and also because it is not used in any other product as far as I know.
Another scheme that would combine the second and third numbers in the three number scheme would be to have the releases in the current 21.x series be numbered 21.0, then 21.01, then 22.02, etc. The next series is 21.1, then 21.11, then 21.12, etc. This is similar to the way that version numbers are done for DOS in Windows. I also think that this scheme is fairly silly because, like the previous scheme, its only purpose is to avoid increasing the major version number very much. But given that we have already have a fairly large major version number, there doesn't seem to be any particular problem with increasing this number by one every year or two. Some people will object that by doing this, it becomes impossible to tell when a change is so major that it causes a lot of code breakage, but past releases have not been accurate indicators of this. For example, 19.12 caused a lot of code breakage, but 20.0 caused less, and 21.0 caused less still. In the GNU Emacs world, there were byte code changes made between 19.28 and 19.29, but as far as I know, not between 19.29 and 20.0.
With three active development branches, synchronizing code changes between the branches is obviously somewhat of a problem. To make things easier, I propose a few general guidelines:
Merging between different branches need not happen that often. It should not happen more often than necessary to avoid undue burden on the maintainer, but needs to be done at all defined checkpoints. These checkpoints need to be noted in all of the places that track changes along the branch, for example, in all of the change logs and in all of the CVS tags.
Every code change that can be considered a self-contained unit, no matter how large or small, needs to have a change log entry, preferably a single change log entry associated with it. This is an absolute requirement. There should be no code changes without an associated change log entry. Otherwise, it is highly likely that patches will not be correctly synchronized across all versions, and will get lost. There is no need for change log entries to contain unnecessary detail though, and it is important that there be no more change log entries than necessary, which means that two or more change log entries associated with a single patch need to be grouped together if possible. This might imply that there should be one global change log instead of change logs in each directory, or at the very least, the number of separate change logs should be kept to a minimum.
The patch that is associated with each change log entry needs to be kept around somewhere. The reason for this is that when synchronizing code from some branch to some earlier branch, it is necessary to go through each change log entry and decide whether a change is worthy to make it into a more stable branch. If so, the patch associated with this change needs to be individually applied to the earlier branch.
All changes made in more stable branches get merged into less stable branches unless the change really is completely unnecessary in the less stable branch because it is superseded by some other change. This will probably mean more developers making changes to the semi-stable branch than to the experimental branch. This means that developers should strive to do their development in the most stable branch that they expect their code to go into. An alternative to this which is perhaps more workable is simply to insist that all developers make all patches based off of the experimental branch, and then later merge these patches down to the more stable branches as necessary. This means, however, that submitted patches should never be combinations of two or more unrelated changes. Whenever such patches are submitted, they should either be rejected (which should apply to anybody who should know better, which probably means everybody on the beta list and anybody else who is a regular contributor), or the maintainer or some other designated party needs to filter the combined patch into separate patches, one per logical change.
The maintainer should keep all the patches around in some data base, and the patches should be given an identifier consisting of the author of the patch, the date the patch was submitted, and some other identifying characteristic, such as a number, in case there is more than one patch on the same date by the same author. The database should hopefully be correctly marked at all times with something indicating which branches the patch has been applied to, and this database should hopefully be publicly visible so that patch authors can determine whether their patches have been applied, and whether their patches have been received, so that patches do not get needlessly resubmitted.
Global automatable changes such as textual renaming, reordering, and additions or deletions of parameters in function calls should still be allowed, even with multiple development branches. (Sometimes these are necessary for code cleanliness, and in the long run, they save a lot of time, even through they may cause some headaches in the short-term.) In general, when such changes are made, they should occur in a separate beta version that contains only such changes and no other patches, and the changes should be made in both the semi-stable and experimental branches at the same time. The description of the beta version should make it very clear that the beta is comprised of such changes. The reason for doing these things is to make it easier for people to diff between beta versions in order to figure out the changes that were made without the diff getting cluttered up by these code cleanliness changes that don't change any actual behavior.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |   |