Having my :vim and M-x emacs-ing it too

In 2008 or so, I switched from Textmate to vim. Then from vim to emacs. Then emacs to vim. Back to emacs. Vim. Emacs. Vim.

Then I discovered Vimpulse for emacs, and that was that.

Vimpulse is now Evil and it’s better than ever.

Here are some great tweaks.

(evil-define-motion evil-little-word (count)
  :type exclusive
  (let* ((case-fold-search nil)
		 (count (if count count 1)))
	(while (> count 0)
	  (forward-char)
	  (search-forward-regexp "[_A-Z]\\|\\W" nil t)
	  (backward-char)
	  (decf count))))

This is essentially clw from a previous post, but here we’re defining a new unit of editing. This lets you:

(define-key evil-operator-state-map (kbd "lw") 'evil-little-word)

And then you’ve got clw and dlw which delete the “one” in “oneTwoThree” or in “one_two_three”. I use this all the time.

Here’s something even more useful: Ever boil over because in emacs (and vim for that matter) every text deletion pulls that text into your kill-ring (register)? I sure do. Sometimes, I just want something gone, and I never want to see it again!

More often, I want to paste something from my clipboard over something else, which requires that my clipboard not be messed with by the pasting process.

(Emacs translation: More often, I want to yank something from my kill-ring…)
(Vim translation: More often, I want to put something from my default register…)

(evil-define-operator evil-destroy (beg end type register yank-handler)
  (evil-delete beg end type ?_ yank-handler))

There is some unfortunate copy and paste code going on here, and I’d be happy to hear about how to eliminate it, but in essence this is just the d operator (delete), but without any clipboard operations going on. (Note the updated, cleaner implementation, inspired by Russell’s comment.)

You can then bind this to something, I use X, and utterly and irrevocably DESTROY some text. But that’s not end game. Next step is this:

(evil-define-operator evil-destroy-replace (beg end type register yank-handler)
  (evil-destroy beg end type register yank-handler)
  (evil-paste-before 1 register))

This will replace a bit of text with whatever’s in the clipboard without altering the clipboard, and I use this all the time.

I bind it to q, which, yeah, is supposed to be for evil macros, but I’ve got emacs macro bindings, so that’s fine.

This works with motion and text objects, so you can do things like yi" to copy between double-quotes and then qi"┬áto paste inside different double-quotes (assuming you’ve bound to q). qi(, qi' and qi{ all also work as you’d expect.

This is incredibly useful, and once you have it, you won’t know how you lived without it. It is also possible in vim. Read all about it here (the second response) http://stackoverflow.com/questions/2471175/vim-replace-word-with-contents-of-paste-buffer.

One last thing, and this one is great!

(defun whitespace-only-p (string)
  (equal "" (replace-regexp-in-string "[ \t\n]" "" string)))

(defadvice evil-delete (around evil-delete-yank activate)
  (if (whitespace-only-p (buffer-substring beg end))
	  (evil-destroy beg end type register yank-handler)
	ad-do-it))

What does this do? Only the best thing ever! With regular, pull-into-the-clipboard deletion, things work as usual. However, should you delete a blank line (or any whitespace-only region), the clipboard is left alone.

Ooooooh lordy, that’s nice. No more pushing blank line deletions into your clipboard! Who wanted that anyway?

(If anyone knows how to build a similar solution for vim, post to the comments.)

About selah

Programmer at Prominence Advisors. Also dabbling musician. Also cycling commuter.
This entry was posted in Emacs, Programming, Vim and tagged , , . Bookmark the permalink.

2 Responses to Having my :vim and M-x emacs-ing it too

  1. Russell Stewart says:

    Nice idea. You inspired me to implement this in a slightly different way. Basically, IMO, the standard delete function is fine except the copy into register part. Normally, you can void this by typing: “_d, as the “_ is a void register. So I just looked up the delete-char function in the evil source and modified the function to automatically assume the “_ register had been typed before. Here is my final code:

    (define-key evil-normal-state-map “X” ‘evil-destroy)
    (define-key evil-visual-state-map “X” ‘evil-destroy)

    (evil-define-operator evil-destroy (beg end type register yank-handler)
    “Delete text from BEG to END with TYPE.
    Save in REGISTER or in the kill-ring with YANK-HANDLER.”
    (interactive “”)
    (unless register
    (let ((text (filter-buffer-substring beg end)))
    (unless (string-match-p “\n” text)
    ;; set the small delete register
    (evil-set-register ?- text))))
    (setq register 95) ;;; THIS IS WHERE THE MAGIC HAPPENS
    ;; (print register)
    (evil-yank beg end type register yank-handler)
    (cond
    ((eq type ‘block)
    (evil-apply-on-block #’delete-region beg end nil))
    ((and (eq type ‘line)
    (= end (point-max))
    (or (= beg end)
    (/= (char-before end) ?\n))
    (/= beg (point-min))
    (= (char-before beg) ?\n))
    (delete-region (1- beg) end))
    (t
    (delete-region beg end)))
    ;; place cursor on beginning of line
    (when (and (evil-called-interactively-p)
    (eq type ‘line))
    (evil-first-non-blank)))

    • selah says:

      Good point! But how about

      (evil-define-operator evil-destroy (beg end type register yank-handler)
        (evil-delete beg end type ?_ yank-handler))
      

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">