On 2010-08-19 19:06, Štěpán Němec wrote:
I went for the minor mode approach (and thus the second recommended solution above) to be able to enable and disable the plugin cleanly.
Good!
There are still glitches, though, e.g. with the mode enabled, `cw' eats the space after the word being changed, unlike in plain Vim(pulse) ... I guess I'll try to investigate when I get the time'n'energy, but the relevant parts of Vimpulse make my head explode, so I welcome any advice or contribution. ;-)
In a simple world, motions and operators would be completely orthogonal. In the real world, special cases turn out to have their uses. The "w" and "W" motions normally include the trailing space, unless the operator is "c", in which case they exclude it. (This strange-yet-intuitive behavior is not a Vim hack, but is part of classical vi, as can be seen by running Viper only or enabling :set compatible in Vim.) Which raises an implementation question: are operators functions of text ranges, or functions of motions? If motions and operators are orthogonal, then it doesn't matter where the text range came from, and operators may take a range as their input. If the motion does matter, on the other hand, then that should be the operator's argument. Vimpulse's solution is to accept both in different contexts. If the operator is called interactively, then not only is a motion read from the keyboard, but the current motion and operator can be accessed via the variables `vimpulse-this-motion' and `vimpulse-this-operator'. If the operator is called programmatically, on the other hand, then only a text range is specified, and no motion enters the picture. Finally, there's `vimpulse-operator-apply', which lets us pass a motion to an operator in a programmatic context. It is used by the repeat system, which remembers the last repeatable operator/motion combination in `vimpulse-last-operator' and `vimpulse-last-motion'. Based on this, a cleaner way to define the dispatchers would be (defun vimpulse-change-surround-or-change (beg end &optional dont-save) (interactive (vimpulse-range)) (if (memq vimpulse-this-motion '(vimpulse-surround-paren vimpulse-surround-bracket vimpulse-surround-brace vimpulse-surround-angle vimpulse-surround-single-quote vimpulse-surround-double-quote)) (vimpulse-surround-change beg end (eq *vimpulse-surrounding* 'strip)) (vimpulse-operator-apply 'vimpulse-change vimpulse-this-motion vimpulse-this-count))) where the `memq' expression would of course be replaced by a call to a `vimpulse-surround-object-p' function which looked up the motion in a list autogenerated by the `vimpulse-surround-define-text-object' macro. This definition also obviates the need to list the dispatcher in `vimpulse-newline-cmds', since it is an operator proper. Speaking of macros, I think an even cleaner solution would be to build a condition into all operators for bypassing the operator's body when called interactively. If the motion sets some variable to t, then the operator will do nothing -- only the motion is executed. Defining the surround commands as "standalone motions", there is no need for dispatcher functions at all, which lets vimpulse-surround play nicely with other extensions which might do similar things. Furthermore, such a variable would allow for a reversal of roles where the motion is calling the operator (which is actually how vip and Viper were implemented), letting one add instructions /after/ the operator. For example, a custom "dap" object may clean up whitespace between paragraphs as a separate step, so that the deleted paragraph may be pasted without the extra whitespace. There's a lot of possibilites once you have a general `vimpulse-define-operator' macro in place. -- Vegard