Am Dienstag, 1. März 2011 schrieb Vegard Øye: > My point is that auto-completion /is/ a linear change.
But doesn't this depend on the concrete package? Completion could also insert text behind point (I think of some of those snippet packages). But that was not what I meant. When some of those completion-dialogs pops up, the user can keep on typing or use the cursor-keys or whatever to select possible completions. How do you realize that these commands should *not* be recorded although they may look like, e.g., a motion (I just don't know how these packages really work). If this packages inserts text behind point it will drop you in the second case, but then the sequence of keys just does not represent what has been inserted (the sequence may be something like [a b b <down> <down> <up> c d <enter>]. There are two cases: if you wait for some time after typing the second b you go into completion mode and the motions are mapped to completion dialog. But if you do not wait those motions are really motions. One would have to realize in which situation we are). But maybe I'm just too scary of those packages and such strange things never happen. Another point why I would prefer key-sequence as default in all cases is that sometimes insertion triggers other changes, too, like indentation. I this case repeation of key-sequences does what you want (indent according to where the repeation took place) while direct insertion of text may fail. This may depend, in this example, on whether the additional spaces are inserted just before point. In fact, is there a way to detect motion of point? Again another pre-/post-command-hook hack or something better? I ask because in some situations a certain motion or sequence of motions will actually change point while in other situations point will left unchanged (I think of motions like "tx" which does not move point if we are right before an x - okay we are in insert mode but again such situations may happen, e.g., end-of-line by leave point unchanged in one situation but when we repeat the keq-sequence elsewhere it would not). It seems to me that the key-sequence approach is almost always the right way. If there weren't those nasty completion things ... ;) Anyway, don't care about my arguments, I propably see problems where no problems are. > Yeah, and the `define-operator' macro should let one add code to that > specification (not replace it, just augment it). Actually, > `vimpulse-define-operator' allowed for this, just not in a very > obvious way. If the body contained an `interactive' form, the return > value of that form (which must be a list) would be concatenated with > the calculated values for BEG and END. E.g., > > (vimpulse-define-operator vimpulse-insert (beg end &optional arg) > "Insert before point." > (interactive (list current-prefix-arg)) > ...) > > This would roughly expand to the following function definition: > > (defun vimpulse-insert (beg end &optional arg) > "Insert before point." > (interactive (append (vimpulse-calculate-beg-and-end) > (list current-prefix-arg))) > ...) > > There might be a better syntax for this, but the functionality > is there. Perhaps we could extend the string-variant by further chars understood by define-operator? Would make the stuff more readable. > >> Btw, what about commands like , and ;. The do not have a specific > >> type. Their type may be either explicit or implicit depending on > >> the previous search command. > > Good point. "}" is another motion which, depending on the > circumstances, may use the `line' type instead of `exclusive'. I > ended up with a global variable for the current type, which is > initially set when the motion is executed, but may also be changed by > the motion itself. The final value is used for the type when the > buffer positions are normalized. Is a valid solution and should work. > >>> There is one case where I cannot see any other solution than a > >>> blacklist, though: normalizing Emacs' region to the Visual > >>> selection. We have to do this /before/ the next command is called > >>> (so we can't inspect its behavior), and we don't want to do it if > >>> the next command is a motion. > >> > >> I do not understand. You can inspect the command in a pre-command > >> hook and normalize the region accordingly or what do you mean? Of > >> course, this only works if the commands use the interactive > >> statement nicely. > > You can inspect the command, but you can't really know what it is > going to do. You could check out `interactive-form' to get a clue > (which I tried), but the problem is that the form turns into mush if > the function is compiled. Also, the command's behavior may be > contingent on the activation of the region (e.g., skeletons). > Consequently, there is no reliable way to identify region commands, > at least not before the command is executed. Exactly - I even doubt if this is possible after the command is executed in all cases. But never mind. Propably no one uses non-*evil* ;) motions anyway or only standard emacs stuff. Although I wish there were a better solution than a blacklist. > `when' and `unless' are provided by vanilla Elisp (in subr.el), cl.el > just redefines them. `defun*' is for keyword arguments, which we'll > probably not need. :) `lexical-let' provides lexical scope, which > I've never used in Vimpulse. (I've only had one use for it: in my > test framework, I needed to evaluate forms defined outside the > evaluating function; regular local bindings could overwrite the form. > What do you use `lexical-let' for? Closures?) Yes, I used closures for vim:defcmd and vim:defmotion magic and perhaps for a few other things. Don't care about dropping cl, I'm just too used to it and never cared about this dependency (at least at compile-time). For me cl with all its nice functions was a perfectly legal library to use and I really do not understand why it's not part of the core or I why its use is banished ... but this is has nothing to with our project, so never mind, just delete ;) > >> When you press "dw", "d" calls `delete', `delete' reads "w", "w" > >> is bound to `forward-word', `forward-word' is executed to get > >> buffer positions, and the positions are passed to the operator's > >> arguments. Then the operator's body is executed. > > > > It's just the difference to how vim-mode combines motions and > > operators. In vim-mode operator-pending is just a state as any > > other state, insert, normal or visual. When an operator is > > executed, the command's body is not executed immediately. Instead > > it is remembered for later use, then vim-mode switches to > > operator-pending mode and gives the control completely back to > > Emacs. When a motion is executed in operator-pending mode the > > stored operator is finally executed along with the motion. Similar > > things happen when a register is selected. In this case the > > register is stored and then vim-mode returns to normal mode and > > proceeds as usual. > > If I understand vim-mode correctly, the motion is read and executed > in another iteration of the command loop. In Vimpulse, everything > happens immediately: "w" is read from the keyboard, the corresponding > command is found with (key-binding "w"), and then it is executed. I > ended up building a little "keypress parser" for handling counts as > well. This is able to handle things that Emacs' command loop actually > can't, such as "da2w". See below (search for > `vimpulse-keypress-parser'): > > http://gitorious.org/vimpulse/vimpulse/blobs/master/vimpulse-operator >.el > > Vimpulse does have a brief Operator-Pending state, which is entered > before `key-binding' is called. When the motion is finished > executing, the state promptly switches back to Normal. Thus, > everything is done in a single iteration of the command loop. Using a custom key-parser was how vim-mode started. But then I realized that the default key-handling of Emacs is really enough and provides everything I need. Of course, I never handled the key-stuff in interactive. But I wonder if it is possible to switch to operator-pending, then call read-key-sequence (or something like this), then switch back and continue as before. Of course, before switching one has to read the numeric prefix but this should be possible, I think. Of course, you could not handle commands like "da2w" this way but "2d3w" should work. But I think "da2w" is not really important - vim does not know it, too, I think. Even more, it makes only sense after an "a" or "i", but "dg3j" looks odd. Or perhaps someone uses longer key-sequences. > However, we may reuse Emacs' /concept/ of sentences and words. The > `sentence-end-double-space' variable, for example, influences how > sentences are understood. Should we honor such things, or should we > invent our own system from scratch? Well, if written well those motions are rather stand-alone so it is not important to decide it now. Usually I prefer to reuse Emacs' own definition of things but often they do not really match Vim's - and this may lead to confusion of someone uses both, Emacs and Vim, and wants to have Emacs as close to Vim as possible. E.g. forward-sentence moves to the final period while Vim's version move to the beginning of the next sentence. In any case I would try to respect Emacs' own definitions if possible (sentence-end-double-space is such an example). But propably we just will have to have something own to make the motions behave as expected. Another question about types. You use :contract and :expand ... I wonder something like the following would better reflect what we need: evil:region "returns BEG and END of the real region covered by motion" evil:line-region "returns BEG end END of the lines covered" I mean, every motion is pair of coordinates and a type. We just need sometimes the Emacs region covered by this motion return by evil:region and sometimes vim:line-region to cover the corresponding lines. I think this should somehow correspond to :expand and :contract. I do not like those terms because I would expect from them that I can apply them several times (i.e., expand several times) - well, you can do it but it does not make sense. But I think you have a special use case where the suggestion above does not fit, right? So what do you expect from :expand and :contract, especially, why do you need the inverse transformation? It should be equally easy to store the original pair of BEG and END so the inversion should not be necessary. Well, whatever we decide for all those points above, I think it's time to start (if we want, I do ;)). To summarize, I think the follow things have to be done first: - create gitorious project - start basic documentation of texinfo sources (outline) - basic initialization of evil - state macros, simple state switching and keymaps, a state requires (roughly) * name * list of keymaps * cursor type (?) * a mode-line symbol (?) If this works, i.e., we can start the mode and switch happily between the states and all keymap-stuff works, would should start with the define-{operator,motions,...} macros. We do not need full functionality at this point only the basic stuff, so we can execute simple commands, perhaps simple operators (something like gu or g~ should be enough) and a few motions. Now we should implement the complete repeation and undo stuff, which is propably the most difficult part. But once this is ready we have a basis to implement all commands and motions and operators we need. >From now on we can propably reuse much from vimpulse and vim-mode, because each motion/command should be almost independent from the rest. This means we can easily test different possibilities and choose the best. Ex-mode as well as the interactive search can also be done now, it is just another independent subsystem. Once the core is ready I suppose the implementation of most commands and motions should be done relatively fast because they are already there. Bye, Frank -- Frank Fischer Chemnitz University of Technology, Department of Mathematics eMail: [email protected] Tel.: +49 (371) 531-36913 _______________________________________________ implementations-list mailing list [email protected] https://lists.ourproject.org/cgi-bin/mailman/listinfo/implementations-list
