Exact selected multiline string search in vim - vim

I have a buffer. In that buffer exists a string that spans multiple lines:
asdf
qrughatuxlnjtzu
... tens more lines...
I have one instance of this string readily available under my cursor. I want to search for other instances of this multiline string in the same buffer without having to manually copy/edit significant portions of said multiline string into the command buffer (n.b. manually replacing newlines with their regex equivalents is significant editing).
I've tried using How do I search for the selected text? (visual selection -> yank -> command buffer) + Exact string match in vim? (Like 'regex-off' mode in less.) (verbatim search), but the approaches do not appear to work for multiple lines.
How do I perform an exact multiline search of a selected string in Vim?

nnoremap <your keys> :<c-u>let #/=#"<cr>gvy:let [#/,#"]=[#",#/]<cr>/\V<c-r>=substitute(escape(#/,'/\'),'\n','\\n','g')<cr><cr>
Then visually select the lines with V (or v for part of lines), and then hit <ESC> and <your keys>.
Source is here (see answer by #Peter Rincker).

You could just search with \n as newline:
/asdf\nqrughatuxlnjtzu

Depending on the newline characters that are in your file you can include the end of line characters in your search too,
e.g. for Unix line endings you can search for
/asdf\nqrughatuxlnjtzu$
for windows line endings you'd use \r\n instead.
The $ character above will search to the end of the line so will exclude any line endings but this is necessary to avoid matching on lines such as
asdf
qrughatuxlnjtzuNotToBeMatched
Also see http://vim.wikia.com/wiki/Search_across_multiple_lines

I'd map * to search visual selected region with this:
vnoremap * "vy/\V<C-R>=substitute(escape(#v,'/\'),'\n','\\n','g')<CR><CR>

Related

How to convert visual selection from unicode to the corresponding character in vim command?

I'm trying to convert multiple instances of Unicode codes to their corresponding characters.
I have some text with this format:
U+00A9
And I want to generate the following next to it:
©
I have tried to select the code in visual mode and use the selection range '<,'> in command mode as input for i_CTRL_V but I don't know how to use special keys on a command.
I haven't found anything useful in the manual with :help command-mode . I could solve this problem using other tools but I want to improve my vim knowledge. Any hint is appreciated.
Edit:
As #m_mlvx has pointed out my goal is to visually select, then run some command that looks up the Unicode and does the substitution. Manually input a substitution like :s/U+00A9/U+00A9 ©/g is not what I'm interested in as it would require manually typing each of the special characters on every substitution.
Any hint is appreciated.
Here are a whole lot of them…
:help i_ctrl-v is about insert mode and ranges matter in command-line mode so :help command-mode is totally irrelevant.
When they work on text, Ex commands only work on lines, not arbitrary text. This makes ranges like '<,'> irrelevant in this case.
After carefully reading :help i_ctrl-v_digit, linked from :help i_ctrl-v, we can conclude that it is supposed to be used:
with a lowercase u,
without the +,
without worrying about the case of the value.
So both of these should be correct:
<C-v>u00a9
<C-v>u00A9
But your input is U+00A9 so, even if you somehow manage to "capture" that U+00A9, you won't be able to use it as-is: it must be sanitized first. I would go with a substitution but, depending on how you want to use that value in the end, there are probably dozens of methods:
substitute('U+00A9', '\(\a\)+\(.*\)', '\L\1\2', '')
Explanation:
\(\a\) captures an alphabetic character.
+ matches a literal +.
\(.*\) captures the rest.
\L lowercases everything that comes after it.
\1\2 reuses the two capture groups above.
From there, we can imagine a substitution-based method. Assuming "And I want to generate the following next to it" means that you want to obtain:
U+00A9©
you could do:
v<motion>
y
:call feedkeys("'>a\<C-v>" . substitute(#", '\(\a\)+\(.*\)', '\L\1\2', '') . "\<Esc>")<CR>
Explanation:
v<motion> visually selects the text covered by <motion>.
y yanks it to the "unnamed register" #".
:help feedkeys() is used as low-level way to send a complex series of characters to Vim's input queue. It allows us to build the macro programatically before executing it.
'> moves the cursor to the end of the visual selection.
a starts insert mode after the cursor.
<C-v> + the output of the substitution inserts the appropriate character.
That snippet begs for being turned into a mapping, though.
In case you would like to just convert unicodes to corresponding characters, you could use such nr2char function:
:%s/U+\(\x\{4\}\)/\=nr2char('0x'.submatch(1))/g
Brief explanation
U+\(\x\{4\}\) - search for a specific pattern (U+ and four hexadecimal characters which are stored in group 1)
\= - substitute with result of expression
'0x'.submatch(1) - append 0x to our group (U+00A9 -> 0x00A9)
In case you would like to have unicode character next to text you need to modify slightly right side (use submatch(0) to get full match and . to append)
In case someone wonders how to compose the substitution command:
'<,'>s/\<[uU]+\(\x\+\)\>/\=submatch(0)..' '..nr2char(str2nr(submatch(1), 16), 1)/g
The regex is:
word start
Letter "U" or "u"
Literal "plus"
One or more hex digits (put into "capture group")
word end
Then substituted by (:h sub-replace-expression) concatenation of:
the whole matched string
single space
character by UTF-8 hex code taken from "capture group"
This is to be executed in Visual/command mode and works over selected line range.

How does vim help files allow visual word selection to select text with periods?

I've noticed that when I use the commands viw in vim help files, it is able to select strings like: intro.txt
But when I create a basic file and add the text intro.txt and try to select the entire string using viw the visual selection stops at the ., so I am only able to select intro without the .txt portion.
Can someone explain why this is, and how I can force vim to select the entire string?
From the built-in help:
:help iw
iw "inner word", select [count] words (see |word|).
... word:
A word consists of a sequence of letters, digits and underscores, or a
sequence of other non-blank characters, separated with white space (spaces,
tabs, <EOL>). This can be changed with the 'iskeyword' option. An empty line
is also considered to be a word.
... 'iskeyword':
'iskeyword' 'isk' string (Vim default for MS-DOS and Win32:
"#,48-57,_,128-167,224-235"
otherwise: "#,48-57,_,192-255"
Vi default: "#,48-57,_")
local to buffer
{not in Vi}
Keywords are used in searching and recognizing with many commands:
"w", "*", "[i", etc. It is also used for "\k" in a |pattern|. See
'isfname' for a description of the format of this option. For C
programs you could use "a-z,A-Z,48-57,_,.,-,>".
For a help file it is set to all non-blank printable characters except
'*', '"' and '|' (so that CTRL-] on a command finds the help for that
command).

Select entire line in VIM, without the new line character

Which is the shortest way to select an entire line without the new line character in VIM?
I know that SHIFT + v selects the entire line, but with new line character.
To do this I go to the line and I press:
^ (puts the cursor at the start of the line)
v (starts the visual select)
$ (selects the entire line including new line character)
Left (unselects the new line character)
I also know that I can create a recording that does such a thing. But I am asking if is there any built-in shortcuts...
Yes, g_ is what you are looking for. g_ is like $, but without the newline character at the end.
Use 0vg_ or ^vg_, depending if you want to copy from the beginning of the line, or the first character on the line, respectively.
No, there is nothing built-in that does the job. That's why people have even created plugins to address the need.
Probably the most popular choice is textobj-line. With textobj-line you get two new text objects, al "a line" and il "inner line". Then,
vil selects the printable contents of the line (like ^vg_),
val selects the entire line contents (like 0v$h).
Both do not include the newline in the selection.
Pretty handy plugin if you ask me. And it works with operators, too.
By request, the installation:
With plain Vim:
Get the latest textobj-user and extract its directories into ~/.vim.
Get the latest textobj-line and extract its directories into ~/.vim.
Generate the help tags :helptags ~/.vim/doc.
With a plugin manager (recommended): just follow the usual installation procedure for your plugin manager, and don't forget to install the textobj-user dependency as well.
0v$
^v$
0vg_
^vg_
$v0
$v^
g_v0
g_v^
all do the job with different conceptions of what a line is (from first column or from first printable character, to last character or to last printable character). You can create a custom mapping if you like.
Note that selecting text is often unnecessary in vim.
Adding on to the answer by #glts, you can replicate the functionality of the textobj-line plugin using only vanilla vim mappings, no plugin installation required.
To do so, add the following to your .vimrc
vnoremap al :<C-U>normal 0v$h<CR>
omap al :normal val<CR>
vnoremap il :<C-U>normal ^vg_<CR>
omap il :normal vil<CR>
The al text object (short for 'a line') includes all characters in a line, but not the terminating newline. This includes all white space.
The il text object (short for 'inside line') goes from the first non-blank character to the last non-blank character.
Commands such as yil,val, and cil work as expected.
If you want to copy line into the buffer, you can use Du, which will delete from the cursor position to the end of line with D, and then revert changes with u. Text will be copied to the buffer without new line symbol.
Redefine $ for visual mode
The unwanted selection of the linefeed in visual mode can be permanently eliminated by adding the following visual mapping to .vimrc:
vnoremap $ g_
This replaces the standard behaviour of $ in visual mode for the move towards right before the linefeed g_.
You can still a mapping to what you want, e.g.:
nnoremap <leader>v 0v$
Another solution $ will be working as you want it to
:vnoremap $ $h
maps your original $ command to new one
Not exactly an answer to your question, but I wonder if you can skip selecting the line and do directly what you want next:
If you want to change the line, just cc
If you want to yank the line, 0y$ (note $ here does not capture the line break because it does not move over it in normal mode, unlike in visual mode)

Delete lines with highlighted text / delete highlighted text

Does anyone know how to delete:
lines with highlighted text
all highlighted text self
(highlighted text (p.e. after a search) not selected text)
Is there a command which search all highlighted text and delete the line?
(independent which search command or function I used to highlight text)
the g/pattern/d command does not always delete the highlighted text
p.e. /^\(.*\)\(\n\1\)\+$ --> highlight all double lines
but g/^\(.*\)\(\n\1\)\+$/d --> does NOT delete all double lines
Well, you can delete the searched pattern this way:
:%s/<pattern>//gc
And you can delete the whole line with the searched pattern this way:
:g/<pattern>/d
In addition to sixfeetsix' answer:
to delete all lines NOT containing <pattern>, type :g!/<pattern>/d or :v/<pattern>/g
to avoid having to type <pattern> after :g/, type :g/CTRL-r//d which inserts the content of the search register (CTRL-r/ means register /) into your command being typed.
how to delete: 2) all highlighted text self
You could use search-and-replace (substitute) to do this.
It is generally used like this:
:%s/your_search_here/your_replacement_here/gc
More specifically, replace your search results with nothing (to remove them):
:%s/your_search_here//gc
Omit the c at the end to replace all without confirmation.
Type :help :s for more info.
how to delete: 1) lines with highlighted text
To delete whole lines, you could either do a substitute, and just match the whole line with a regular expression (%s/^.*your_search_here.*\n//g), or you could use the multiple repeats (multi-repeat) feature.
It is generally used like this:
:g/your_search_here/[cmd]
More specifically, combine it with the normal command you use to delete a line (d):
:g/your_search_here/d
Type :help :g for more info.
Tips:
An easy way to get your query right before doing your substitute is to do your search in command mode rather than the default mode.
Instead of:
/your_search_here
Type:
:/your_search_here
Then you can go to command mode (:), hit the up key to bring up your last search, and edit the line to convert it to a substitute.
From this SuperUser answer:
You can use gn in version 7.4 onwards (and gN to go backwards). It replaces the v//e trick.
Search forward for the last used search pattern, like with `n`, and start Visual mode to select the match.
See :help gn or this Vimcast for more information.
I guess it's the essentially the same question as this:
Vim: when matching string across multiple lines using \_. in regex, yank command only works for the first line
It looks like a bug in Vim.

Vim: Split Words Into Lines?

I frequently use Shift+J in visual mode to join several selected lines into a single line with the original lines separated by spaces. But I am wondering if there is an opposite shortcut such that it will split selected words into separate lines (one word per line).
Of course I can do:
:'<,'>s/ /^M/g
But something more succinct in terms of keystrokes would be very useful. Has anyone else found a way to do this?
Thanks in advance,
-aj
Map it if you are using it often in your ~/.vimrc file or similar
vnoremap \ll :'<,'>s/ /^M/g<cr>
nnoremap \ll :s/ /^M/g<cr>
if you are only wanting to to it multiple times now you can use & command to repeat last search also
Theres also gqq but thats for textwidth eg 80 chars
Recently I stumbled across the same problem. My solution is the following vim function (put in my .vimrc):
function SplitToLines() range
for lnum in range(a:lastline, a:firstline, -1)
let words = split(getline(lnum))
execute lnum . "delete"
call append(lnum-1, words)
endfor
endfunction
This can be used with line ranges, e.g., as follows
:26call SplitToLines()
which would split line number 26. But the code also handles ranges of lines gracefully (that's why the range in the for loop is built in reverse order).
1,10call SplitToLines()
will split lines 1 to 10 into several lines. However, I mostly use this in visual mode, like
'<,'>call SplitToLines()
which splits all lines that are visually marked. Of course you may define some single letter abbreviation for this function call (with auto completion by Tab I do not find it necessary). Also note that by adding an additional argument which would also be used by 'split' you can have a function that does split lines at specific patterns (instead of just white space).
I use this in my config to Un-Join/split the last word on current line:
nnoremap <C-J> g_F<Space><Space>i<CR><Esc>k
It maps CTRL-j to do the opposite of Join, I think of it as Counter-Join :) I mostly use it to convert between K&R style vs ...the other kind of curly brace placement.
g_ : search for the last non-whitespace on current line
F<Space> : reverse-find first space
<Space> : go one character forward
i : enter insert mode
<CR> : insert a line break
<Esc> : return to normal mode
k : go up one line to where we begun

Resources