<br><br><div class="gmail_quote">On Sat, Feb 26, 2011 at 9:26 AM, Vegard Øye <span dir="ltr"><<a href="mailto:vegard_oye@hotmail.com">vegard_oye@hotmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
On 2011-02-25 22:20 +0100, Frank Fischer wrote:<br>
<br>
> Gitorious should be okay.<br>
<br>
Then Gitorious it is! :)<br>
<div class="im"><br>
> - repeating. Vim-mode uses keyboard-macro and those have to be<br>
> recorded. Recording them can be tricky if one keyboard macro calls<br>
> another one. Furthermore insert-mode is different because it<br>
> contains of several independent key-sequences. Using key-sequences<br>
> has some benefits but also some downsides, e.g., when lazy<br>
> completion packages are used<br>
<br>
</div>A big benefit of recording the keys is that it removes the need for<br>
repeat code in the commands themselves. For example, I have written<br>
some custom insertion commands for dealing with Lisp code (e.g.,<br>
"Insert after S-exp"); if I want them to repeat correctly under Viper,<br>
I have to edit the repeat history from within the commands, which is<br>
/extremely/ cumbersome. By contrast, a repeat system which monitors<br>
keystrokes and the current state would simply take note that I have<br>
entered Insert state, and update the repeat history accordingly.<br>
<br>
As you point out, some keystrokes are troublesome: "M-/", which calls<br>
`dabbrev-expand', may expand to different words in different places in<br>
the buffer. One solution may be to define the repeat history as a<br>
collection of keystrokes and buffer insertions, e.g.,<br>
<br>
([a b c] "inserted text" [d e])<br>
<br>
Most commands are remembered as keystrokes (vectors), but certain<br>
ones, like `dabbrev-expand', are remembered as insertions (strings)<br>
instead. The repeat system would use a "blacklist" of unsafe commands<br>
like `dabbrev-expand'; if the current command is listed, the system<br>
creates a marker at point (in `pre-command-hook'), lets the command<br>
execute, and then (in `post-command-hook') extracts the text between<br>
point and the marker, which goes into the repeat history like above.<br>
<div class="im"><br>
> - undo, vim usually undos everything done in insert-mode at once while<br>
> emacs undos insertion in steps.<br>
<br>
</div>This is not that difficult in itself, but becomes more complex when<br>
loading a custom undo package like undo-tree.el. (I would really like<br>
to use undo-tree.el in place of redo.el; it features a graphical<br>
interface which totally outclasses Vim's :undolist.)<br>
<br>
There is a case for making Vim-like "bulk undoing" toggleable:<br>
Emacs' fine-grained undoing can be valuable in some circumstances.<br>
The default should be Vim-like behavior, of course.<br>
<div class="im"><br>
> - catching of commands and motions. In each state the execution of<br>
> commands and motions has different effects and therefore some<br>
> special function has to be executed in each mode to deal with<br>
> commands and motions. In general I see two possibilities how this<br>
> special function can be executed. Either one hooks into pre- and/or<br>
> post-command hooks and checks whether the command/motion about to be<br>
> executed is a Vim operator and in this case do whatever is required<br>
> according to the current state. Or each command and motion is<br>
> defined in a special way in order to call the state specific handler<br>
> when it is executed. vim-mode uses the latter one because I try to<br>
> avoid pre- and post-command hooks if possible.<br>
<br>
</div>Ah, the relationship between operators and motions. This is an area<br>
where Vimpulse and vim-mode differ somewhat. In vim-mode, as I<br>
understand it, motions are passed to operators by parameter (or the<br>
operator reads a motion from the keyboard when called interactively).<br>
The operator executes the received motion to determine what text to<br>
act on. The resulting pair of buffer positions is used internally.<br>
<br>
In Vimpulse, the buffer positions /are/ the parameters (BEG and END).<br>
Operators work like region commands (i.e., (interactive "r")) in that<br>
they either receive the positions from the caller, or figure them out<br>
for themselves when called interactively. (Vimpulse also possesses<br>
some facilities for "passing a motion to an operator", which executes<br>
the specified motion and feeds its range to the operator. This is only<br>
used by the repeat system, though, and it would be totally superfluous<br>
if a keystroke-based system was in place.)<br>
<br>
For the sake of reusability, I recommend defining operator commands in<br>
the same way as region commands: with two parameters, BEG and END, and<br>
an `interactive' specification for determining their values by reading<br>
a motion from the keyboard.<br>
<div class="im"><br>
> - What to do with non-vim commands and motions? There should be a<br>
> simple rule so they work with vim in most cases as expected, but if<br>
> no meta-information is provided a non-vim command may always be<br>
> problematic (e.g., in operator-pending mode).<br>
<br>
</div>Well, we will likely have one macro for defining operators, and<br>
another for defining motions. Both can be set up to index all defined<br>
operators/motions for later lookup, which will give us some<br>
information to go on. By the way, I also think that all of Emacs'<br>
standard movement commands should be regarded as motions.<br>
<br>
We thus get a large list of commands which move the cursor, and can<br>
restrict Operator-Pending state to those commands. Alternatively, we<br>
can maintain a "blacklist" of Emacs commands which should /not/ be<br>
executed. In any case, I don't think it's overly problematic if a<br>
nonsensical command should get called; any damage will be undoable,<br>
after all. It's probably better to err on the side of allowing too<br>
many commands than too few.<br>
<div class="im"><br>
> - What to do with commands that change the current buffer? This is<br>
> problematic if some buffer-local variables are involved.<br>
<br>
</div>Right, which means that the repeat system cannot be buffer-local.<br>
I think it would just be confusing if it was, anyway.<br>
<div class="im"><br>
> - How to switch states and how to represent states (usually as<br>
> minor-modes, perhaps with some further meta-data like cursor,<br>
> info-message, ...)<br>
<br>
</div>We'll have a macro for defining those too, of course. :)<br>
<br>
I suggest that each state's toggle function be a command; e.g., in<br>
Vimpulse's development code, vi state defines the command<br>
`vimpulse-vi-state' for entering that state, emacs state defines<br>
`vimpulse-emacs-state', and so on. The command also has an optional<br>
argument which, if negative, disables the state; this is used<br>
internally when switching from one state to another.<br>
<div class="im"><br>
> - What is a motion? There are a few fundamental differences between<br>
> buffer-coordinates of Vim and Emacs. Vim known line/column, Emacs<br>
> knows just the offset. The choice how to represent coordinates can<br>
> be crucial. And of course there is that funny newline character,<br>
> which is usually invisible in Vim except for empty lines. Because a<br>
> motion is a important concept for many parts including operators and<br>
> visual-mode.<br>
<br>
</div>I think all of Emacs' regular movement commands should be valid<br>
motions. Furthermore, all of Emacs' selection commands should be valid<br>
text objects. In Vimpulse, "y C-x h" and "C-x h y" are equally valid<br>
ways of copying the whole buffer, and "d M-e" works just as well for<br>
deleting a sentence as does "d)".<br>
<br>
Given the above, the only thing which separates Emacs' movement<br>
commands from the other motions is their lack of a /type/. For<br>
example, the motion "j" has a type of `line', which means that "dj"<br>
deletes two whole lines. What a type is, then, is a way to transform<br>
two buffer positions to two other positions -- in this case, to two<br>
whole lines.<br>
<div class="im"><br>
> Probably a motion is represented by some abstract data<br>
> type and this data-type is an important part of the interface a user<br>
> must understand in order to write new motions and commands.<br>
> Therefore it should be well-defined from the beginning because it<br>
> cannot be changed easily afterwards.<br>
<br>
</div>I don't think it needs to be very abstract. I would rather try to keep<br>
things from getting too abstract, actually. One of the design rules I<br>
laid down in Vimpulse's new "TODO" list was that it should require as<br>
few packages as possible, and not invent new stuff unless it's<br>
absolutely necessary.<br>
<br>
The way I understand motions, they are just regular movement command<br>
plus a type. The type can be stored as a symbol property, e.g.,<br>
(put 'motion 'type 'line). The type itself, of course, must also be<br>
defined; for this, a minimal system may be warranted, since both<br>
Operator-Pending state and Visual state use types. I've pushed a<br>
currently unused "type system" to "development":<br>
<br>
<a href="http://gitorious.org/vimpulse/vimpulse/blobs/development/vimpulse-types.el" target="_blank">http://gitorious.org/vimpulse/vimpulse/blobs/development/vimpulse-types.el</a><br>
<br>
Now, it's a bit more involved than it has to be; the routines for<br>
reselecting (e.g., two lines anywhere in the buffer) are unnecessary<br>
given a keystroke-based repeat system. The advantages of a systematic<br>
approach is that it can be reused by Operator-Pending state and Visual<br>
state, making the overall code simpler. The only heavy lifting Visual<br>
state ends up doing (once initialized) is highlight the different<br>
types, which is rather trivial (with the exception of `block' ...).<br>
<div class="im"><br>
> In fact, there are only two (or three) difficult commands: yank,<br>
> delete and paste, but I hope the implementation in vim-mode is quite<br>
> good know (it uses yank-handlers for all three kinds of yanking and<br>
> also provides "yank-pop" stuff).<br>
<br>
</div>Yes, this is exactly the right way to do it. I think the actual yank<br>
handlers should be specified by the type system, so that `line' has<br>
one handler, `block' has another, and so on. That way, we avoid<br>
hard-coding these associations into the "yank" command.<br>
<div class="im"><br>
> What could be useful are frameworks or perhaps only some functions<br>
> which help defining more involved motions like text-objects. We should<br>
> provide helper-functions for typical text-objects like parentheses,<br>
> blocks, whatever. vim-mode (and vimpulse, too) contains a few of those<br>
> functions which are again independent.<br>
<br>
</div>Agreed; we should have a macro for defining text objects, too.<br>
<br>
To recap, we now have the following define macros:<br>
<br>
* `define-state'<br>
* `define-type'<br>
* `define-motion'<br>
* `define-text-object'<br>
* `define-operator'<br>
<br>
Do we need more than these?<br>
<div class="im"><br>
>> <a href="http://gitorious.org/vimpulse/vimpulse/blobs/development/vimpulse-states.el" target="_blank">http://gitorious.org/vimpulse/vimpulse/blobs/development/vimpulse-states.el</a><br>
><br>
</div><div class="im">> I read your comments and they sound reasonable. Adding auxiliary<br>
> keymaps should not be that difficult. As I remember correctly, local<br>
> keymaps were the biggest problem in vim-mode, but major and minor-mode<br>
> specific should be relatively easy. Of course this is very important<br>
> and should be done as one of the first things.<br>
<br>
</div>Actually, the current code already implements auxiliary keymaps,<br>
although I've not tested it thoroughly.<br>
<div class="im"><br>
> Note that vim-mode arranges keymaps in another hierarchy, too, which<br>
> allows to enable only few keybindings in certain major modes, e.g.,<br>
> only movement and window-commands in info-mode (somehow like<br>
> viper-on-more-modes I think). The difference is that many<br>
> standard-keybindings are not available in this case, e.g.,<br>
> insert-mode.<br>
<br>
</div>Yes, this is very sensible. Motions and text objects can be bound in<br>
their own keymap (or state), and that keymap is inherited by vi state,<br>
Visual state, and so on. Modes which do not work well in vi state, can<br>
come up in the motion state instead. Any shortcomings can be<br>
alleviated on a per-mode basis with mode-specific state bindings.<br>
<div class="im"><br>
>> Regarding test frameworks, I hear Christian Ohler's ert.el is now<br>
>> included with Emacs trunk, so we could go with that:<br>
><br>
</div><div class="im">> I never used any of those libraries but we should try. The main<br>
> problem is to cover all those funny special cases that arise (what<br>
> happens at the end of the buffer, on empty lines, ...) - most bugs<br>
> found in vim-mode are of this kind.<br>
<br>
</div>This can be tested by executing a keyboard macro in a temporary<br>
buffer. A lot of Vimpulse's early tests do this, e.g.,<br>
<br>
(deftest test-change-undo<br>
"Change a word and undo."<br>
(execute-kbd-macro "wcwfoo^[u")<br>
(assert-string=<br>
(buffer-substring 1 51)<br>
";; This buffer is for notes you don't want to save"))<br>
<div class="im"><br>
> This is another point which is currently very bad in vim-mode. How to<br>
> deal with errors, should there be a unique signalling scheme, where to<br>
> handle them, ...<br>
<br>
</div>In "indirect" cases, like when executing a motion to get a text range,<br>
I think any errors should be suppressed. When executing the motions by<br>
themselves, however, we should signal any problems with `error'.<br>
<div class="im"><br>
> Btw, Emacs 23 contains visual-line-mode which is quite useful. But<br>
> most commands work on buffer lines not on screen lines. Should we try<br>
> to support visual-lines, too (optionally)? If yes this has to be<br>
> considered for motions and commands, especially for operator-stuff,<br>
> too, and we should think of it from the beginning, because many<br>
> commands have to be implemented differently for visual-lines.<br>
<br>
</div>Yes, we should definitely support screen lines; I have "j" and "k"<br>
bound to `next-line' and `previous-line' because they work better in<br>
visual-line-mode. In Vim, one uses "gj" and "gk" to move by screen<br>
lines. I think this is very inefficient and would prefer an option for<br>
the regular commands. It may of course be disabled by default.<br>
<div class="im"><br>
> Another thing somehow related to tests is documentation. We should not<br>
> only write developer-documentation but also user-documentation right<br>
> from the start. This should contain instructions for all important<br>
> concepts and also examples for new motions and commands of all kind.<br>
> Where should we put this documentation? EmacsWiki? Hosting site?<br>
> Perhaps as tex-info?<br>
<br>
</div>Texinfo, definitely. I've had my share of arbitrary wiki syntax and<br>
never-ending comment blocks. A text file under version control is<br>
wiki-like enough for me.<br>
<div class="im"><br>
> Hm, I think a new cool name would be good. I prefer short names or at<br>
> least names that allow short prefixes for function names ;)<br>
<br>
</div>For the sake of brainstorming, I've grepped through /usr/share/dict<br>
for anything containing "vi". There isn't much, unfortunately, so I'll<br>
start with some acronyms comprising three letters:<br>
<br>
* avi, evi (augmented/extensible vi)<br>
* via, vie (vi augmented/extended)<br>
* vil (vi layer)<br>
* xvi (vi plus a cool letter)<br>
* yvi (yet a(nother) vi)</blockquote><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Things get slightly more descriptive when we allow four letters:<br>
<br>
* evil (extensible vi layer; this almost works too well)<br>
* nuvi (new (unlimited) vi)<br>
* vibe (vi is beautiful?)<br>
* vici (veni, vidi ...)<br>
* vimu (vi(m) emulation; vim unlimited; vi made usable)<br>
* vini (vi new and improved)<br>
* viva (viva la vi!)<br>
* yavi (yet another vi)<br></blockquote><div><br></div><div>evil is almost too perfect of a name for it. That gets my vote!</div><div><br></div><div>My next favorites:</div><div>* vimu</div><div>* viva</div><div><br>
</div><div>I think in terms of search-ability, vimu is likely to get a #1 hit in search engines. viva and evil are going to be hard terms to compete with. So, I might choose vimu over evil if practicality is the primary priority.</div>
<div><br></div><div>However... if people search for "emacs evil", they could probably find it in the first couple of hits... so it may not be so bad :)</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
With five letters or more, there are many proper names to choose from<br>
(elvis is the name of a vi clone): alvin, levi, david, vidal, vince.<br>
And we have:<br>
<br>
* anvil (a new vi layer; doesn't sound very light, though)<br>
* vibrant (the soothing, relaxing, vibrating editor)<br>
* vigil (vi greatly improved layer-something)<br>
* vital (vi is vital to, say, avoiding RSI ...)<br></blockquote><div><br></div><div>None of these resonate with me.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
More letters would be inconvenient; I want the name and code prefix to<br>
be one and the same. (I use an abbreviated prefix in<br>
viper-in-more-modes.el, and I hate the sight of it.)<br>
<br>
Of the above, I rather like "vimu". It's short, it's sweet, and it can<br>
be read as both "vi emulation" and "Vim emulation". Although I think<br>
Vim sets the baseline for what a modal editor should support, it's not<br>
the end of the road for me. A sufficiently extensible implementation<br>
will enable the user to explore uncharted territory.<br>
<br>
--<br>
<font color="#888888">Vegard<br>
</font><div><div></div><div class="h5"><br>
_______________________________________________<br>
implementations-list mailing list<br>
<a href="mailto:implementations-list@lists.ourproject.org">implementations-list@lists.ourproject.org</a><br>
<a href="https://lists.ourproject.org/cgi-bin/mailman/listinfo/implementations-list" target="_blank">https://lists.ourproject.org/cgi-bin/mailman/listinfo/implementations-list</a><br>
</div></div></blockquote></div><br>