开发者

How to use vimpulse together with autopair.el

开发者 https://www.devze.com 2023-03-06 12:59 出处:网络
It seems that when vimpulse is running, autopair only works partially in the sense that pressing backspace in empty bracket pairs will no longer remove the closing bracket but only the opening one (wh

It seems that when vimpulse is running, autopair only works partially in the sense that pressing backspace in empty bracket pairs will no longer remove the closing bracket but only the opening one (which means backspace functions as normal backspace now). An example:

(When Vimpulse and autopair are both active, and current mode is INSERT mode, "|" denotes the 开发者_如何学Pythoncursor)

begin: (|)

Now press "backspace"

expected result: | (both opening and closing brackets are removed)

actual result: |) (only the opening bracket is removed)

I know this has to do with the fact that vimpulse (or rather viper-mode) remapped [backspace] from delete-backward-char to something else (viper-delete-backward-char I think). But I could not find a fix to it.

Could anybody find a solution to this? (so that backspace key will remove both opening and closing bracket when the bracket is empty and cursor is in between).

Thanks!


i think something like this in your init file would work:

(add-hook 'autopair-mode-hook 
  '(lambda ()
    (define-key autopair-emulation-alist [remap viper-delete-backward-char] 'autopair-backspace)))


I will answer this question myself.

I could not figure out an "orthodoxy" way to solve the problem and I came up with a hack.

The function that is bound to in viper insert mode (viper-del-backward-char-in-insert) is adviced to check whether cursor is currently in a matched pair, if so, the character after the cursor is deleted before the actual function is called. This also takes into account possible problem caused by prefix character (backslash).

Just copy the code below into your .emacs file after viper-mode or vimpulse is loaded.

(defun not-escaped (escape-char)

  "Character immediately before cursor is not prefixed by escape-char"
  (let ((count 0))
    (save-excursion
      (if (char-before)
          (backward-char))
      (while (and (char-before)
                  (= (char-before) escape-char))
        (setq count (+ count 1))
        (backward-char))
      (if (= 0
             (% count 2))
          t
        nil))))

(defun in-matched-empty-pair (pair-list)
  "tell if cursor is in an empty pair in pair-list"
  (let ((next-char (char-after))
        (prev-char (char-before))
        (matched nil)
        (pair)
        (pair-left)
        (pair-right))
    (if (and next-char
             prev-char)
          (while (and (setq pair
                       (pop pair-list))
                      (not matched))
            (setq pair-left (pop pair)
                  pair-right (pop pair))
            (if (= next-char pair-right)
                (if (and
                     (= prev-char pair-left)
                     (not-escaped ?\\))
                    (setq matched t)))))
    (if matched
        t
      nil)))

(defvar viper-workaround-pairs
      '(
        (?\" ?\")
        (?\' ?\')
        (?\` ?\`)
        (?\( ?\))
        (?\[ ?\])
        (?\{ ?\})
        ))

;; Workaround for integration problem with autopair
(defadvice viper-del-backward-char-in-insert (before viper-auto-delete-pair-backward())
  (if (in-matched-empty-pair viper-workaround-pairs)
      (delete-char 1)))

;; Activate advice
(ad-activate 'viper-del-backward-char-in-insert)

This is a hack but it is probably the best I could do now.


Here is my updated solution. Put the following in your .emacs file after the code that loads autopair and vimpulse:

(add-to-ordered-list 'emulation-mode-map-alists (car (last emulation-mode-map-alists)) 400)

It moves autopair's keymap in front of viper's one, giving it higher priority. Maybe you have to adept the order number (here 400), depending on whether you are using additional emulation-modes. The result can be checked with C-x v emulation-mode-map-alists. In my case:

(viper--intercept-key-maps cua--keymap-alist autopair-emulation-alist viper--key-maps)

Now, autopair-emulation-alist should be listed before viper--key-maps.


baumichel found the trick. I just add a quick snippet to help :

First, as autopair-mode simply appends autopair-emulation-alist, evaluate:

(defadvice viper-change-state-to-insert (after autopair nil activate)
  (add-to-ordered-list 'emulation-mode-map-alists 'autopair-emulation-alist 300))

Then, remember that vimpulse-normalize-minor-mode-map-alist removes all viper keymaps in front of the alist, so execute:

(defadvice vimpulse-normalize-minor-mode-map-alist (after order-viper--key-maps nil activate)
   (add-to-ordered-list 'emulation-mode-map-alists 'viper--key-maps 500))

That works for me! I evaluate these snippets in an embedded eval-after-load for both vimpulse and autopair.

My idea is that Emacs dev should rethink the emulation-mode-map-alists and use a property list indexing priority order like this: ((:name viper--key-maps :after (cua--keymap-alist autopair-emulation-alist)) (:name viper--intercept-key-maps :before (cua--keymap-alist autopair-emulation-alist))). Old packages like viper, CUA and so on should be better maintained because our setup becomes ugly after years with Emacs.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号