surround.vim vimpulse extension

Vegard Øye vegard_oye at
Sat Jul 24 23:23:48 CEST 2010

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

    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)
      ;; 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.


More information about the implementations-list mailing list