emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: propose adding Icicles to Emacs


From: Drew Adams
Subject: RE: propose adding Icicles to Emacs
Date: Thu, 14 Jun 2007 18:01:20 -0700

>     You seem bent on automatically converting all commands to
>     multi-commands. That might be useful, in a limited way. But
>     programmers will still need to be able to define multi-commands
>     that go beyond the simple case. I gave `icicle-search' as an
>     example.
>
> Would you please explain what is special about it?

Ouch! It's a mother. I'd really appreciate it if you'd take a look at the
doc for Icicles search and then take a look at the code for the functions.
It would be a lot easier then to talk about it.

I don't suggest that we need to start by taking all the stuff that
`icicle-search' does into account, but I think it would be a good idea if
you took a look, to see the kind of thing that might be done. IOW, let's
start, as you already have, with the low-hanging fruit (80/20 rule), but you
might want to take a look at the search stuff to get a picture of what's
possible.

I'd also suggest loading Icicles and giving `icicle-search' (`C-c`') a
whirl. It's easier to experience that to read about.

>     > The need to replace commands is a complexity, and the code will
>     > be much better if we avoid that complexity.
>
>     There is no need to replace any commands. Keep them all.
>
> As you have described it, Icicles replaces the command find-file.

No, it doesn't replace it. If I gave that impression then I misspoke. What
it does, if a user so chooses, is remap whatever keys `find-file' is bound
to to `icicle-find-file'. Upon exiting Icicle mode, it undoes this
remapping.

> It does this by defining a new command (Icicle-find-file?) and remapping
> remapping find-file to that.

Yes, it remaps the command's key bindings. The command `find-file' is not
redefined.

> I think this complexity is unnecessary, and I want to try to avoid
> installing it.

Don't install it. I said, "There is no need to replace any commands." I
said:

>   Speaking of replacement is off the mark. Multi-commands and the
>   ability to define them as appropriate for a given use are one
>   thing. Deciding to bind `C-x C-f' to a multi-command file-finding
>   function instead of vanilla `find-file' file is another thing - a
>   separate consideration. Forget the latter, if you will; it's not
>   necessary.

Today, Icicles gives users the option to rebind `C-x C-f' to an Icicles
command instead of `find-file'. We need not give users that option in the
future. And if you build in multi-commandness, then there is absolutely no
reason for such a rebinding - only the new, multi-command implementation of
`find-file' will be needed.

> The only purpose that I know of for defining Icicle-find-file is to
> implement multi-command behavior.  Is there any other reason?

No, that is correct - it is the only reason.

> I have proposed a modular and clean way to provide the multi-command
> behavior, without the need to replace commands in this way.  You said
> that my proposal doesn't do the whole job.  Maybe you are right, but I
> need you to explain.  What part of the job does it not do?

Insofar as I understand it, it would do the whole job for commands such as
`find-file'. Perhaps it could also do the whole job for any multi-commands
that one can define today using macros `icicle-define-command' and
`icicle-define-file-command'. I don't know.

I haven't seen anything concrete, so I'm not sure how you will implement it.
If it does everything that those macros do (or the equivalent), then it will
make every command that calls `completing-read' or `read-file-name' (in the
`interactive' spec at least) into a multi-command, and that will be a good
thing.

I'm not sure how you will proceed, but I'm sure it will be different from
what I do today. The macros define a command of zero args that calls
`completing-read' and applies the action function to the result. The
minibuffer binding of `C-RET' also applies the action funtion to the current
candidate.

IIUC, in your approach, a user defines a command of one or more args, one
arg of which is provided by a call to `completing-read' in the `interactive'
spec (in one way or another). Then, whatever that command does to that arg
in the command body is done to the current completion candidate when you use
C-RET - that is, the entire command body is executed with the current
candidate passed as the parameter. Is that it? And I assume that any other
args keep their same values during this process.

It might be that your approach will do everything that the macros currently
do, just differently. It sounds good to me.

>     No one is against modularity. I have not seen a "proposed
>     implementation", beyond some vague hand-waving.
>
> I gave you an outline of the scheme.  Of course I don't have all the
> details.  I am trying to work out the details but I need your help.

I'll do my best to help where I can.

>     However, that needs to be done
>     carefully and fully. For example, use of a standalone
>     minibuffer and non-nil pop-up-frames should also work.
>
> I expect we can write the code in Fcall_interactively to do TRT in
> those cases.  The only way to make sure is to try it.

Agreed. See below for my concerns about frame focus.

>     I agree about "independent of the specific command that was
>     run", but only in the case of run-of-the-mill multi-commands.
>
> Even if this only handles the run-of-the-mill multi-commands, and the
> exceptions are handled by your macros, that is still a big
> simplification.

No, there is a misunderstanding. My macros, like your proposal, only handle
the run-of-the-mill commands. To be more precise, they might be a bit less
run-of-the-mill than your approach (I'm not sure of your approach), because
they let you bind, in the definition of the action function itself, the
action function etc. for a recursive call to `completing-read' or
`read-file-name'. IOW, they recognize that particular function variable,
`icicle-candidate-action-fn', whereas I'm not sure if your code will (I hope
so).

More generally, to allow a programmer to define a non-run-of-the-mill
multi-command s?he needs to be able to bind:

1. `icicle-candidate-action-fn' - the action function
2. `icicle-candidate-alternative-action-fn' - an alternative action function
3. `icicle-delete-candidate-object' - a deletion action

#1 is necessary to enable `C-RET', that is, to make it a multi-command at
all. With your implementation of multi-commands, some such variable would
still be necessary in the general case, to override use of the command body
for the action function - that is, to provide a different action from what
the command itself performs when you finally choose a candidate once and for
all.

One use case is defining a command that is itself called when defining
another command. The first command might define a default action function if
`icicle-candidate-action-fn' is nil when it is called. The second command
can bind the action function to override the default in the command it
calls. (There was an example of this, but I no longer have one to point to.)

#2 is optional but required if you want to provide an alternative action
(invoked by `C-S-RET' etc.). Icicles search is an example of a command where
you can use the alternative action. The alternative action replaces all or
part of the current search hit. (The main action visits the current search
hit.) It is likely that there would be more Icicles commands in the future
that would provide alternative actions. And a programmer can define custom
commands that have alternative actions.

#3 is optional but required if you want to provide a deletion action
(invoked by `S-delete'). Today, there are several commands that provide a
deletion action. You can bind this variable to either a deletion function or
a variable whose value is a list of candidate objects (the object associated
with the target candidate is deleted from the list variable).

See this page for a description of #2 and #3:
http://www.emacswiki.org/cgi-bin/wiki/Icicles_-_More_About_Multi-Commands.

See this page for a description of Icicles search-and-replace using the
alternative action:
http://www.emacswiki.org/cgi-bin/wiki/Icicles_-_Search-And-Replace

In sum, I think your approach will handle most cases. It might handle all
cases handled by the macros. In the general case, a user would be able to
bind the variables to arbitrary functions and define an arbitrary command
that makes use of multi-commandness beyond the interactive spec.

> And we can continue trying to make this mechanism
> better; perhaps we can make it handle more of the commands.

I'm not against such an effort. In fact, I find it interesting. My current
assessment is that it is important for programmers to be able to specify an
arbitrary function for #1.  #2 and #3 could be considered nice-to-haves, but
#2 is needed for Icicles search, unless that is built in somehow. Whether
everything interesting can be cantoned to the `interactive' spec, I don't
know. I'd like to be able to bind #1, #2, and #3 in an arbitrary context and
call `completing-read' with those bindings current, to be able to use the
different actions during completion.

BTW, I should also mention that Icicles (optionally, but by default) uses a
multi-command version of `execute-extended-command'. This code is a bit
hairy. I think this feature is useful, but you might want to forego it if it
is too complicated to implement in your design. You might be interested to
take a look anyway. Perhaps you will see a way to do it in your approach, or
perhaps it will inspire other thoughts. At least, the example it will give a
flavor of using multi-command actions.

The code is in icicles-cmd.el. The description is here:
http://www.emacswiki.org/cgi-bin/wiki/Icicles_-_Multi_M-x.

[BTW - I understand that you don't often have Web access. The complete doc
(the same as is on the wiki) is also in files icicles-doc1.el and
icicles-doc2.el in plain-text form (not HTML). The section headings are
pretty much the same as the wiki page headings (URLs). So, for example,
http://www.emacswiki.org/cgi-bin/wiki/Icicles_-_Multi_M-x corresponds to
section "Icicles Multi `M-x'", in file icicles-doc1.el. So you can read up
on this stuff if you are interested.]

>     For some multi-commands you
>     want the frame focus to end up in a different place when you
>     are done, for example.
>
> Could you tell me about one example?  Maybe I can find a simple
> general mechanism to handle this too.

Let's not worry about this now. I'm not sure there will be a problem. What's
probably the most important about this is written further below.

>     You might typically work in the buffer of application after using a
>     multi-command, or you might instead typically want the
>     minibuffer frame to continue to have the focus so you can use it
>     again - different commands have different use cases.
>
> Can you tell me about one example of each type, so I can see
> why this is so?

I can't now. I spent a while looking, but I can't seem to find what I
thought I'd find.

I think the general situation is this. It's easiest to follow if you think
of pop-up-frames being non-nil, with a standalone minibuffer.

1. You invoke a multi-command.

2. You use `C-RET' on candidates. Each action might pop up a buffer in a
different frame, giving it the focus - which is what you want in this case
(often).

3. If you use C-g, then you typically want to return to the original
buffer/frame.

4. You hit RET to finally choose a buffer/frame. You typically want the
focus to end up there.

You might, for #3 or #4, want the focus to be different, but I don't have a
concrete example.

I think perhaps what I was thinking of was that in defining action functions
I sometimes need to put a `select-frame-set-input-focus' in the action
function, either to force the focus to a frame associated with the current
candidate or, on the contrary (and more typically), to force the focus to
the minibuffer in preparation for another `C-RET'.

If that is in fact the only use for this, then perhaps there is no problem.
Presumably, your code would (1) keep the focus on the minibuffer and its
frame during completion (i.e. for each `C-RET'), (2) leave the focus
wherever the final `RET' found it or put it, and (3) put the focus back on
the original buffer/frame in case of C-g or error.

In some places, such as the multi `M-x', I do a few weird things perhaps,
because I want the `C-RET' context to be just like a top-level context. But
that might be irrelevant, and in any case it is not something to worry about
now.

>     I had my multi-command definition macros available for my own use,
>     yet I did not use them to define some of the multi-commands. Why?
>     Because they are not flexible enough - they cannot be flexible
>     enough. There is no substitute for being able to code what is
>     needed in a particular case.
>
> Maybe that is true, but first let's make a reasonable effort to make a
> general mechanism handle as much of the job as possible.  Eventually
> we may decide to handle a few hard cases with your macros.

That sounds good to me. I think it would probably be advisable to at least
have your basic handling respect bindings for an action, alternative action,
and deletion functions. If that's available, then I think most of the
flexibility needed will be provided. IOW, if your mechanism provides what
the macros provide, then we're off to a good start.

>     Practically every place where I have used a non-nil value for
>     `icicle-use-candidates-only-once' is an example. It is not so
>     much that multiple invocation would be harmful (though perhaps
>     that can also be true for some commands). It is that, in many
>     cases, it is handy for the user to remove the candidate from
>     the list of available candidates, once it has been acted on.
>
> We could build that into the low-level mechanism too.

That sounds good.

> It would be
> quite clean.  Fcall_interactively just has to bind a certain variable
> to nil, which holds a list of completion alternatives to exclude.
> display-completion-list will ignore the alternatives in this list.
> Then, each time around Fcall_interactively adds the proper argument
> value to this list.

But would the value still really be one of the possible completions, so that
if you hit TAB or S-TAB again during the same invocation of
`completing-read' it would show up again? That is the current behavior, and
the behavior I prefer. Or else at least have some way to get that removed
candidate back without starting all over. I want users to be able to do as
much as possible on the fly, in the same invocation of `completing-read'.

> We could control the feature with a character in the interactive spec,
> as in (interactive "#bDelete Windows of buffer:")
> where # specifies using candidates only once.

That's fine, but for me that's getting ahead of ourselves at this point. If
it helps you think about it, good.

>     FYI - wrt clicking the `delete' key to remove a candidate -
>     I've recently defined a complementary feature, to save a
>     candidate for later consideration. I haven't yet uploaded
>     this feature to the wiki, but I'll do
>     so soon, after testing things a bit more.

FYI - I uploaded this new feature yesterday. I intend to change the binding
(to `insert' from `C-insert'), but I've spent too much time on these emails!

> These features seem interesting.  I think they can all be implemented
> cleanly in Fcall_interactively, but this suggests we might want to make
> it call some Lisp code which would handle some of these cases.

I'm in favor of Emacs doing stuff in Lisp, because I want to be able to hack
it, and I don't hack C code (no fun for me, need to compile and build,
etc.). I understand that doing stuff in C is good for performance. For me,
this is a bit of an area of experimentation (UI experimentation), so I'd
like to keep stuff in Lisp as much as possible, to let people explore and
extend the ideas. That's just me.

BTW, wrt using literal `interactive' specs (as opposed to a sexp that's
eval'd in list arg to `interactive') - I've been advising Icicles users who
write multi-commands (my implementation, not yours) not to use literal
specs, because then using `M-*' (progressive completion: multiple match
patterns) will require users to hit RET to exit each recursive minibuffer
level separately. That is, because I put a `catch' in my version of
`completing-read' and `read-file-name', when a user makes a final completion
choice after using `M-*' I can throw the chosen value to the top. If a
programmer instead uses a literal `interactive' spec then my
`completing-read' code doesn't get called.

This wouldn't be a problem for your code. You could make sure that
`interactive' DTRT for a recursive minibuffer within `completing-read' etc.
Just want to point out this use case.

An alternative would be to implement `M-*' differently, and not use a
recursive call to `completing-read' at all. In my implementation of `M-&',
for instance, which is another form of progressive completion that lets you
add predicates on the fly to narrow completion choices, I don't use a
recursive call to `completing-read'. Instead, I modify the current
`completing-read' predicate and then complete again (as in implicit TAB or
S-TAB). I'm just pointing out that there might be different approaches for
this kind of thing.

>     It's best to read about what Icicles search offers and how it
>     works, and then look at the code for `icicle-search' as an
>     example. I'll be glad to answer questions, but I don't want
>     to repeat here what is already written
>     elsewhere. Please see the links above.
>
> I will be glad to read the text you've already written, but finding
> that text would be a pain for me.  Could you please email it to me?

See above: the doc is all in files icicles-doc1.el and icicles-doc2.el. Do
you need me to email you the source files, or can you get them from Emacs
wiki? On the wiki, the files are here, as well as easy ways to download them
all: http://www.emacswiki.org/cgi-bin/wiki/Icicles_-_Libraries.

It would help if you would read up some. It would sure cut down the needed
back and forth by email. This is killing me. I can't imagine that anyone
else is reading any of this. Also, if you want, we can take some of this off
line if you think it bothers more than interests others.







reply via email to

[Prev in Thread] Current Thread [Next in Thread]