Better search in emacs with expand region - search

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)

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

Emacs Evil "repeat" (dot) behavior

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.

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

Searching for marked (selected) text in Emacs

I use emacs for viewing and editing code and other text files. I wanted to know if there is a way to search forward or backward for text which is marked in the current buffer. Similar to what I can do in notepad or wordpad. As in can I mark some text in the buffer and do a C-s or C-r and be able to search with the marked text without actually typing in the whole search text?
Thank you,
Rohit
#Alex nails it.
Another option I use quite often is C-s C-w to search for the word after the current mark. Hitting C-w repeatedly increases the search with additional words (e.g., C-s C-w C-w C-w searches for the 3 words after the current mark).
Similarly, C-s M-s C-e searches for the rest of the line after the current mark and C-s C-M-y searches for the character after the mark. These are both repeatable in the same way (the former by somewhat-awkwardly repeating M-s C-e after C-s).
Yes. M-W (to get a copy of the selected text) C-s <RET> C-y <RET>. Then repeat C-s as needed. Similarly for C-r.
I am using the following which does not have the problem of having to type more then one successive C-s to find later occurences:
(defun search-selection (beg end)
"search for selected text"
(interactive "r")
(kill-ring-save beg end)
(isearch-mode t nil nil nil)
(isearch-yank-pop)
)
(define-key global-map (kbd "<C-f3>") 'search-selection)
The disadvantage of the previous code is that the selected text is copied to the stretch. The following code does not have this problem:
(defun search-selection (beg end)
"search for selected text"
(interactive "r")
(let (
(selection (buffer-substring-no-properties beg end))
)
(deactivate-mark)
(isearch-mode t nil nil nil)
(isearch-yank-string selection)
)
)
(define-key global-map (kbd "<C-f3>") 'search-selection)
Other answers describe how to search for copied text, or how to search for the word at point. But none of them actually describe how to "search with the marked text."
Adding the following hook will make it so that the currently-selected text is the text used for an isearch:
(defun jrh-isearch-with-region ()
"Use region as the isearch text."
(when mark-active
(let ((region (funcall region-extract-function nil)))
(deactivate-mark)
(isearch-push-state)
(isearch-yank-string region))))
(add-hook 'isearch-mode-hook #'jrh-isearch-with-region)
Tip: This pairs nicely with expand-region.
The shortest key sequence to do this is M-w C-s M-y.
There is a great function for this: isearch-forward-symbol-at-point. It highlights all occurrences of the word where your point is located - no need to place the point at the beginning of the word. Then you can move to next or previous with C-s or C-r.
Note that it is an exact match: if you use it on hi it won't match chill for instance.
I mapped if to command-f (mac OSX): (global-set-key (kbd "s-f") 'isearch-forward-symbol-at-point) in the init file.
The answers above (including the accepted one) are too cumbersome IMHO. I found the following info and like it well better:
“Ctrl+s Ctrl+w”. This will search the current word, but you must move
your cursor to the beginning of the word first.
http://xah-forum.blogspot.com/2009/08/search-word-under-cursor-in-emacs.html
You can find C-s help by doing C-h k C-s, and it says:
Type DEL to cancel last input item from end of search string. Type RET
to exit, leaving point at location found. Type LFD (C-j) to match end
of line. Type C-s to search again forward, C-r to search again
backward. Type C-w to yank next word or character in buffer onto the
end of the search string, and search for it. Type C-M-w to delete
character from end of search string. Type C-M-y to yank char from
buffer onto end of search string and search for it. Type M-s C-e to
yank rest of line onto end of search string and search for it. Type
C-y to yank the last string of killed text. Type M-y to replace string
just yanked into search prompt with string killed before it. Type C-q
to quote control character to search for it. Type C-x 8 RET to add a
character to search by Unicode name, with completion. C-g while
searching or when search has failed cancels input back to what has
been found successfully. C-g when search is successful aborts and
moves point to starting point.
If you try to exit with the search string still empty, it invokes
nonincremental search.
Type M-c to toggle search case-sensitivity. Type M-s i to toggle
search in invisible text. Type M-r to toggle regular-expression mode.
Type M-s w to toggle word mode. Type M-s _ to toggle symbol mode. Type
M-s ' to toggle character folding.
Type M-s SPC to toggle whitespace matching. In incremental searches, a
space or spaces normally matches any whitespace defined by the
variable ‘search-whitespace-regexp’; see also the variables
‘isearch-lax-whitespace’ and ‘isearch-regexp-lax-whitespace’.
Type M-s e to edit the search string in the minibuffer.
Also supported is a search ring of the previous 16 search strings.
Type M-n to search for the next item in the search ring. Type M-p to
search for the previous item in the search ring. Type C-M-i to
complete the search string using the search ring.
Type M-% to run ‘query-replace’ with string to replace from last
search string. Type C-M-% to run ‘query-replace-regexp’ with the last
search string. Type M-s o to run ‘occur’ that shows the last search
string. Type M-s h r to run ‘highlight-regexp’ that highlights the
last search string.
Type C-h b to display all Isearch key bindings. Type C-h k to display
documentation of Isearch key. Type C-h m to display documentation of
Isearch mode.
Adopted Jackson's Answer for Swiper:
(defun swiper-isearch-selected ()
"Use region as the isearch text."
(interactive)
(if mark-active
(swiper-isearch (funcall region-extract-function nil))
(swiper-isearch)))
Additionally, if there is no selected region, it just falls back to the regular swiper-isearch.

Resources