Emacs Evil "repeat" (dot) behavior - vim

I have the following line in my .emacs
(define-key evil-normal-state-map "\M-j" (lambda () (interactive) (evil-next-line 5)))
that makes navigation in a file easier. For instance, with M-j I go 5 lines below, so I don't have to press j 5 times. I do the same for all hjkl. The trouble is that this command pollutes the last repeat in Evil (the dot), so let's say I replace a word in a given line, then I do M-j to go change a word 5 lines below. If I press ., it will jump another 5 lines below, instead of replacing the word as it would happen in Vim. If I use any of hjkl though, it won't pollute the last repeat. How can I do so that my function doesn't pollute the last repeat?
EDIT: I just noticed that it doesn't actually happen with \M-j and \M-k, but only with \M-h and \M-l, so the problem is even stranger. Both are defined as:
(define-key evil-normal-state-map "\M-h" '(lambda () (interactive) (evil-backward-char 5)))
(define-key evil-normal-state-map "\M-l" '(lambda () (interactive) (evil-forward-char 5)))

Just replace the lambda with a defun say: (defun my-5-lines-down...)and then (evil-declare-motion 'my-5-lines-down)
In evil (and probably vim?) motions do not count as repeatables so this should do the trick. Alternatively you can use evil-define-motioninstead of defun if you want control over the jump list. See documentation for defining a motion.

Related

Search visual selction in emacs evil

I want to emulate a behavior I've had in vim, but in emacs evil-mode. I want * to search for the current visually selected text. The code below sort of works, but pressing n or N does not retain the search string
(define-key evil-visual-state-map (kbd "*")
(lambda () (interactive)
(let ((search-string (buffer-substring
(evil-range-beginning (evil-visual-range))
(evil-range-end (evil-visual-range)))))
(evil-normal-state)
(evil-search search-string t))))
I'm new to emacs/elisp. Any ideas on what the "right way" to do this is? In the evil-search.el source I see a function evil-ex-search-update-pattern that may be useful, but I'm not sure how to put it together.
Thanks!
Bailey Ling (a former Vim user) has made a plugin that accomplishes the same thing you're after: https://github.com/bling/evil-visualstar.
You can either install it, or peek through the source code (which may help solve your issue).

Better search in emacs with expand region

Suppose we have the following text:
(print "thIis-is-a-text")
and the cursor is in the word "this" which between char 'h' and 'i'.
In emacs, if I type C-s C-w, the text to search is 'is',
again C-w is 'is-is',
again C-w is 'is-is-a',
again C-w is 'is-is-a-text',
again C-w is 'is-is-a-text"'...
And there is a emacs plugin expand region: "Expand region increases the selected region by semantic units. Just keep pressing the key until it selects what you want."
So I want to make C-s C-w to be more intelligent: to combine with expand region.
Cursor between char 'h' and 'i' in the word 'this' again, my goal is:
when I type C-s C-w, the word 'this' will be the text to search,
again will be 'this-is-a-text',
again will be '"this-is-a-text"',
again will be 'print "this-is-a-text"',
again will be '(print "this-is-a-text")',
....(behaves like expand region, maybe this is not a good example...)
As I find sometimes expand region is quite useful in searching texts, I hope someone can write some codes to achieve this for me since I am new to emacs and elisp. Thanks and please forgive my broken English! :)
There's a very simple package called thingopt that uses thingatpt to do something similar to expand-region. I've been using a modified version for quite a while now, which adds isearch support. This question reminded me to fork and put up a pull request. I have the following in my init.el:
(define-key isearch-mode-map (kbd "C-S-s") 'upward-isearch-thing)
(define-key isearch-mode-map (kbd "M-3") 'upward-isearch-thing)
(global-set-key (kbd "C-S-s") 'upward-mark-thing)
(global-set-key (kbd "M-3") 'upward-mark-thing)
(setq upward-mark-thing-list
'(email
url
word
symbol
string
(up-list . *)
paragraph
))
I've tried expand-region, and I think I'd like it better, but it looks much more complicated, and I'd have to add isearch support before I'd start using it. Hopefully I'll (or someone else will) get around to it someday.
(defadvice isearch-yank-word-or-char (before move-to-beginning-of-word)
(unless (eq last-command this-command)
(goto-char (car (bounds-of-thing-at-point 'word)))))
(ad-activate 'isearch-yank-word-or-char)

Navigating top-level Lisp/Clojure forms in Vim

I use Vim for Clojure development. I'd like a movement key or mapping that will jump through the top-level forms in the buffer. { and } are close, but stop if there's a blank line in the middle of the form. slimv-paredit's ( and ) move within a top-level forms. Here's an example:
(def foo :bar)
(defn plus [x y]
(+ x y))
(def yum :cat)
Assuming the cursor starts at the top, I'd like to jump to the opening paren of foo, plus, and then yum.
I have added mappings [[ and ]] for moving to the previous/next defun in Slimv's paredit.vim. Please fetch it from the Slimv repository.
You can write a quick vim macro to do what you want. Put this in your .vimrc:
map \n /^(<CR>
When you press \n, you'll hop to the next form that starts on a line.

Is there an extension or mode in Emacs similar to surround.vim?

Surround.vim is a nifty vim extension that allows you to surround blocks of text with , brackets, braces, and pretty much any arbitrary "surround" character. It supports paragraph and word surround, but I frequently use it in visual mode.
I'm playing around with Emacs and wondering if there's something similar; something that will let me highlight a region and then have the marked region (or rectangle) enclosed with braces, brackets or tags.
Maybe wrap-region is what you need.
smartparens is another excellent option if need to wrap something with delimiters, tags, etc.
I use evil-surround. It emulates vim behaviour but unfortunately might not be what most emacs users want since it requires the evil vim mode.
However, it may or may not be right for you since you referenced surround.vim in the first place.
evil-surround seems to support most of the features in Surround.vim, including modifying surroundings.
I don't think there is anything built in for tags, but for parens you can do M-(. For brackets/braces/quotes you could do:
(global-set-key (kbd "M-[") 'insert-pair)
(global-set-key (kbd "M-{") 'insert-pair)
(global-set-key (kbd "M-\"") 'insert-pair)
Note that if you don't have a region highlighted, it will just insert the pair of whatevers and put the cursor in between them. Also handy for deleting matching whatevers is
(global-set-key (kbd "M-)") 'delete-pair)
If you want to insert tag pairs, it's some simple elisp:
(defun my-insert-tags (tag)
(interactive "sTag: ")
(if (region-active-p)
(let ((beg (region-beginning)))
(save-excursion
(goto-char (region-end))
(insert "</" tag ">")
(goto-char beg)
(insert "<" tag ">")))
(insert "<" tag ">")
(save-excursion
(insert "</" tag ">"))))
Don't know of any way of doing that in Emacs, not even with a module.
My Elisp is a little rusty, buy here's a simple function that will enclose the current region (marked text) or word with quotes ("):
(defun insert-quotes ()
"Inserts quotes (\") around the current region or work."
(interactive)
(let (start end bounds)
(if (and transient-mark-mode mark-active)
(setq start (region-beginning)
end (region-end))
(progn
(setq bounds (bounds-of-thing-at-point 'symbol))
(setq start (car bounds)
end (cdr bounds))))
(goto-char start)
(insert "\"")
(goto-char (+ end 1))
(insert "\"")))
Yes, there is a clone of surround.vim, as of 1 week ago: http://github.com/timcharper/vimpulse-surround.el
It requires vimpulse, which requires vim. It implements much of surround.vim's functionality.
maybe evil-surround is what you are looking for.
thanks.
So you want to select a region or similar and then make a box around it like a various modes do for comments? I believe emacs-wiki (http://www.emacswiki.org/) has some ascii-line art (and a figlet tool as well) that will do that. Searching for box, quite, line art ...
############################
# #
# I AM REGION, WE ARE MANY #
# #
############################

How do I emulate Vim's 'softtabstop' in Emacs?

I've been trying to get into emacs lately, and one of the things I need to get right is indentation.
Example 1:
sub foo {
my $bar = 'quux';
|
Example 2:
sub foo {
my $bar = 'quux'; |# foo
Imagine that the pipe character in the above examples indicates the cursor position. Now, I use (4) spaces for every indent level (no tabs), and I have emacs setup to indent my code automatically with that in mind. No problems there. But in the examples above, if I were to hit backspace at the indicated cursor positions, I want emacs to backspace all the way back to the next indent level (column / 4). That is, I want it to treat the preceding whitespace as if it were made up of tabs. Instead, it always just erases a single space character.
In vim, I turn on 'expandtab' to make it insert spaces instead of tabs, and 'softtabstop', which makes it (among other things) backspace to the next "soft tabstop" as described above.
In emacs, I suppose I could (if I knew emacs/elisp better) bind backspace to a function which does something like the following:
if indent-tabs-mode is nil
if the cursor position is preceded by whitespace
calculate the position of the previous "soft tabstop"
if there's enough whitespace
backspace all the way to that point
else
backspace by one character
What I want to know is, is there a simpler way to do this, and/or does anyone know of an existing solution?
This works for me, where the 'tab-width is used as the width of the columns. Set the key in the appropriate keymaps...
(local-set-key (kbd "DEL") 'backward-delete-whitespace-to-column)
(defun backward-delete-whitespace-to-column ()
"delete back to the previous column of whitespace, or as much whitespace as possible,
or just one char if that's not possible"
(interactive)
(if indent-tabs-mode
(call-interactively 'backward-delete-char-untabify)
(let ((movement (% (current-column) tab-width))
(p (point)))
(when (= movement 0) (setq movement tab-width))
(save-match-data
(if (string-match "\\w*\\(\\s-+\\)$" (buffer-substring-no-properties (- p movement) p))
(backward-delete-char-untabify (- (match-end 1) (match-beginning 1)))
(call-interactively 'backward-delete-char-untabify))))))

Resources