On Sat, Jul 24, 2010 at 3:23 PM, Vegard Øye <[email protected]> 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.