surround.vim vimpulse extension
Tim Harper
timcharper at gmail.com
Sun Jul 25 09:53:23 CEST 2010
On Sat, Jul 24, 2010 at 3:23 PM, Vegard Øye <vegard_oye at hotmail.com> wrote:
> On 2010-07-23 20:46, Tim Harper wrote:
>
>> I'm not extremely happy with my approach on how I'm looking into the
>> delete/change commands. Basically, I'm hijacking them in doing an
>> advise (as in defadvice) approach.
>
> There isn't a perfect way, not even in Vim itself. surround.vim does
> this:
>
> nmap ds <Plug>Dsurround
>
> Which corresponds to making a "careful" binding in Vimpulse -- that
> is, one of these lines:
>
> (vimpulse-map "ds" 'vimpulse-surround-delete)
> (vimpulse-make-careful-binding viper-vi-basic-map "ds" 'vimpulse-surround-delete)
>
> Which will execute `vimpulse-surround-delete' when the user hits "ds"
> and `vimpulse-delete' when the user hits "d" + any other key than "s".
> The fatal flaw with this approach, both in Emacs and Vim, is that the
> keystrokes are read /before/ Operator-Pending mode is entered, so the
> half-height "operator cursor" is permanently lost.
>
> Second approach: write a "null motion" (one that returns an empty
> range) and bind it to "s" in Operator-Pending mode:
>
> (defun vimpulse-surround-delete (&optional arg)
> (interactive)
> ;; Delete surrounding characters
> ...
> (viper-move-marker-locally 'viper-com-point (point)))
>
> (define-key vimpulse-operator-basic-map "s" 'vimpulse-surround-delete)
>
> This will preserve the half-height cursor. The call to
> `viper-move-marker-locally' ensures that the starting point is
> equivalent to the ending point -- e.g., (vimpulse-delete 45 45) --
> hence no actual deletion takes place.
>
> Third approach: we could make the function bodies of `vimpulse-delete'
> and `vimpulse-delete' contingent on a "cancellation variable". A
> pseudo-motion like above could set this to t during its execution to
> inhibit the deletion code of `vimpulse-delete', the change code of
> `vimpulse-change', and so on. (Conceivably, `vimpulse-range' itself
> could cancel further code execution with `keyboard-quit', but this
> would probably be noisy.)
>
> Fourth approach: stay with the delete-or-surround DWIM functions, but
> bind them in a separate, toggleable keymap rather than overwriting the
> basic bindings. Like this:
>
> (define-minor-mode surround-mode)
>
> (vimpulse-define-key 'surround-mode 'vi-state "d" 'vimpulse-delete-surround-or-delete)
> (vimpulse-define-key 'surround-mode 'vi-state "c" 'vimpulse-change-surround-or-change)
>
> Then you can enable surround-mode in certain buffers as appropriate,
> or turn it into a global minor mode.
Approach 4 does seem pretty good (better than the current behavior of
hijacking another keymap). What about option 5:
advise vimpulse-range to set the *vimpulse-surrounding* variable to
nil before calling it
advise vimpulse-delete with an around filter, if
*vimpulse-surrounding* is non-nil, then call vimpulse-surround-delete,
otherwise invoke as normal with ad-do-it
Benefits:
* If for some sick reason one decides to remap vimpulse-delete, they
can do so with less complexity of having to remap
vimpulse-delete-surround-or-delete (maybe dvorak users would want to?)
* Multiple plugins can chain in this way. Both the current solution
and approach 4 have the limitation that if another plugin wants to do
something similar, it will conflict with vimpulse-surround.
Drawbacks:
* We are depending on side-effect value from a previous function call.
This adds complexity and can make things difficult to follow.
More information about the implementations-list
mailing list