[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Emacsy: Context Sensitive Commands Design Question
From: |
Shane Celis |
Subject: |
Emacsy: Context Sensitive Commands Design Question |
Date: |
Thu, 29 Aug 2013 16:57:00 -0400 |
Hello guilers,
I'm developing Emacsy[1], and I'm trying to design a good way of grouping and
exposing interactive commands. My interest is specifically related to Emacsy,
but for guilers in general the question is, How should one provide exports of a
different flavor? We have only "public" exports. In my case I want a
"command" flavor of export. But I might want to export "customizable"
variables, or "minor-mode"s. I'm not trying to tackle the general task here.
In Emacs all commands are in the same namespace. Hit M-x TAB, and you'll
probably see thousands of them (I've got ~6k). A lot of the commands may only
be appropriate in certain modes, so I'm playing around with how best we can go
about grouping and exposing commands. My idea is that M-x only shows commands
that are in the current COMMAND_PATH, somewhat like a bash PATH. To show all
commands, one can type C-u M-x.
A command in Emacsy is a procedure that requires no arguments. It's written
for the user to invoke on command M-x or from a key binding. When called
interactively, it'll ask the user for information. When called with all
arguments provided, it will run non-interactively.
Suppose I have the following code which creates a command called 'echo':
(define-module (my-great-mode)
#:use-module (ice-9 optargs)
#:use-module (emacsy)
#:export (some-other-proc))
(define (some-other-proc)
"I am not a command."
#f)
(define* (echo #:optional (text (read-from-minibuffer "Echo what: ")))
(message text))
(export-command echo)
This module exports the procedure "some-other-proc" and I want it to _somehow_
export a command called "echo". The question is how to export this other
thing, this command? I have a couple of ideas, most based off grouping some
subset of procedures as commands inside a module, and using modules to group
the commands.
1. Create a command-interface module similar to the public-interface that
modules have. So instead of 'resolve-interface' and 'export', I'd have
'resolve-command-interface' and 'export-command'.
A (resolve-command-interface '(my-great-mode)) would return a module
(%module-command-interface) that contained bindings for all that module's
commands. This is the module that COMMAND_PATH would use for commands.
PRO: One could export commands and procedures entirely independently. Also,
one can use the module mechanisms of selecting a subset, algorithmic renaming,
etc. on these command modules.
CON: It seems like a lot of magic, but it's using the same mechanisms that
public interfaces use.
2. Have (export-command) just keep a list of commands, but just export a custom
public interface. So it might look like this internally:
(define (export-command-proc names)
(set! %command-set (append! %command-set names)))
(define (resolve-command-interface module-name)
(resolve-interface module-name #:select %command-set))
PRO: Less magic-y.
CON: One must export a command to both the public interface and the command;
maybe that's ok even preferable that they're not independent.
3. Have (export-command) create a new sub-module (my-great-mode %command).
PRO: Not too tricky.
CON: Pollutes the module namespace a little bit.
4. Still use modules, but make the user segregate their procedures and commands
into separate modules manually. So the user would have to define modules
(my-great-mode) and (my-great-mode commands).
PRO: No magic. Programmer does everything.
CON: Everything is managed by convention. Separating the commands and
procedures might be an awkward boundary. Consider an internal procedure in
(my-great-mode) that a command wants to use in (my-great-mode commands). Do
you expose it as public? Move it around? Use @@ to get to it?
5. Don't use modules at all. Make the user collect and manage <command-set>s
the same way they manage keymaps, for instance.
PRO: Nothing tricky, doesn't use modules at all. No magic.
CON: It has to work with the command being redefined; we can't just keep the
command procedure; we have to keep the variable which points to modules
possibly being a better solution.
6. Tag commands as special procedures perhaps by adding something to their
procedure properties. Implement a "command?" procedure. Export commands and
procedures to the same module. Then just pluck the commands out of all the
procedures by using command?.
PRO: No new modules. No new exports.
CON: Adding something to the procedure makes wrapping commands in other lambdas
awkward. Might necessitate a define-command, lambda-command, method-command,
which I'd prefer to avoid.
* * *
Thanks for indulging my scheme design question. What's the right thing to do?
What would you do?
-Shane
[1]: https://github.com/shanecelis/emacsy
- Emacsy: Context Sensitive Commands Design Question,
Shane Celis <=