Possible to highlight matching quotes in vim? - vim

With the syntax highlighting in vim, I get the handy feature where the matching paren or bracket will be highlighted when I put the cursor over it. Is it possible to do the same thing for quotes?

While not eloquent, one workaround is to select everything inside of matching quotes. You can do this by using the command:
vi"
This will select everything in-between the quotes. However, you won't get proper results with nested quotes as it will match the first found ".

The problem with quotes is that they are symmetrical. It would be very hard to determine which quotes belong with each other.
For instance: "Which \"quotes\" go with each other in this statement?"
This has been discussed on the vim mailing lists a few times, as well as in the bug trackers of a few of the auto-delimiter type plugins. In every case that I've seen, it's been decided that this is better left as is.

The solution is here: Stackoverflow in matchquote except it has the unfortunate limitation that only the current line is considered.
matchit seems to comes close by allowing defining of multi-line matches of words such as if/endif but still no multi-line possibility that I can figure out to get matching for " and '.

VIM already highlights quoted text in a different color, so you can easily identify strings. Do you really need it to match quotes when the whole string is already highlighted?

From :h matchparen
The characters to be matched come from the 'matchpairs' option. You
can change the value to highlight different matches. Note that not
everything is possible. For example, you can't highlight single or
double quotes, because the start and end are equal.

Related

Substitute in vim, with special characters

I am trying to use substitute command in vim to enclose all occurences of a particular pattern
\cite{author1}
\cite{author2}
with
(\cite{author1})
(\cite{author2})
Based on other answers in stack exchangeI used the following vim command
%s/\\cite{(\w\+)}/(\\cite{\1})/g
But, no luck. It says "no matches found". I put two back slashes, one of which is supposed to be the escape character. Kindly help.
I know I could use some other editor and finish the job, but I want to know my mistake. Thank you.
please escape ()
%s/\\cite{\(\w\+\)}/(\\cite{\1})/g
You do not need a capture group to get the entire match. You can use \0 or & for the whole match in the replacement portion of your substitution.
:%s/\\cite{\w\+}/(&)/g
If you do want to use a capture group, then you need to escape the capture group/parenthesis.
:%s/\(foo\)/(\1)/g
For more help see:
:h :s%
:h /magic
As mentioned, normally you need escape the parentheses.
You can use very magic mode (\v) to make the regex simpler; removing the need to escape lots of the regex parts, including the parentheses for capturing:
%s/\v(\\cite\{\w+\})/(\1)/g
Knowing what every sign in a regular expression does in vim is sometimes very
difficult, especially for all the modes and configuration variables that this
depends on. For that reason, it is very important to have visual feedback about
what text are we really matching in any moment while crafting regular
expressions.
If you work with neovim, there is a special option called inccommand that you
can enable to live preview the matches and substitution. That way you can figure
out you errors more quickly. This feature is very likely to be included also in
vim in the future, but independently of that, you can also use simple vim to
give you visual feedback if you enable the option incsearch.
With incsearch set, you can watch the matches of / and ? while you write them
just to be sure that the pattern is correct. Later you can exploit a nice
feature from the substitution: if you leave the first section empty, the last
search will be used.
So you could first make the search:
/\\cite{\w\+}/(&)/g
In the meantime, vim will be showing you the matched text visually. Once you
are sure that the pattern is correct press enter, and finally type:
:%s//(\1)<Enter>
Also, in case you want something more powerful than this simple hack, you can go
for my plugin Extend.vim, that can
do that and much more with great visual feedback.

How to repeat a substitution the number of times the search word occurs in a row in a substitution command in Vim?

I would like to use tabs in a code that doesn’t use them. What I did until now to implement tabs was pretty handcrafty:
:%s/^ /\t/g
:%s/^\t /\t\t/g
. . .
Question: Is there a way to replace two spaces ( ) by tab (\t) the number of times it was found at the beginning of a line?
There are (at least) three substitution techniques relevant to this case.
1. The first one takes advantage of the preceding-atom matching
syntax to naturally define a step of indentation. According to the
question statement, an indent step is a pair of adjacent space
characters preceded with nothing but spaces from the beginning
of line. Following this definition, one can construct the actual
substitution pattern, right to left:
:%s/\%(^ *\)\#<= /\t/g
Indeed, the pattern designates an occurrence of two literal space
characters, but only when they are preceded by a zero-width match
of the atom just before \#<=, which is the pattern ^ * wrapped in
grouping parentheses \%(, \). These non-capturing parentheses are
used instead of the usual capturing ones, \(, \), since there is no
need in further referring to the matched string of leading spaces. Due
to the g flag, the above :substitute command runs through the
leading spaces pair by pair, and replaces each of them by single tab
character.
2. The second technique takes a different approach. Instead of
matching separate indent levels, one can break each of the lines
starting with space characters down into two lines: one containing
the indenting spaces of the original line, and another holding the
rest of it. After that, it is straightforward to replace all of the pairs
of spaces on the first line, and concatenate the lines back together:
:g/^ /s/^ \+/&\r/|-s/ /\t/g|j!
3. The third idea is to process leading spaces by means of Vim
scripting language. A convenient way of doing that is to use the
substitute with an expression feature of the :substitute command
(see :help sub-replace-\=). When started with \=, the substitute
string of the command enables to substitute the matches of a pattern
with results of evaluation of the expression specified after \=:
:%s#^ \+#\=repeat("\t",len(submatch(0))/2)
If you specifically want to convert spaces into tabs (or vice-versa) at the start of a line, there's the useful :retab command which takes care of that. For example:
:retab! 2 will convert spaces in groups of two to tabs
:set expandtab and then :retab! 2 will convert tabstops (of width 2) back to spaces
See :h :retab (and :h 'ts') for the details.
This is not a general solution for the original problem, but I think it covers the most common use case.
There is no general way of doing this using :s regex's. You can't make the /g modifier look backwards otherwise it'd be unusable, and you can't reliably check that you're at the beginning of the line without looking backwards.
The only way of doing it generally is to loop, like so:
:for i in range(100)
: %s/^\t*\zs /\t/e
:endfor
Which is ugly, slow and highly unrecommended. Use :retab

Delete anything other than pattern

Let's say this is my text:
this is my text this
is my text this is my text
my text is this
I would like to highlight all text except pattern and delete the highlighted text.
p.e. text: this must be the result.
text
texttext
text
I've found the code how to select all text except pattern:
\%(\%(.{-}\)\#!text\zs\)*
however I don't know how to delete all highlighted text.
This doesn't work:
:%s/\%(\%(.{-}\)\#!bell\zs\)*//
Can anyone help me?
Try this:
:%s/\(^\|\(text\)\#<=\).\{-}\($\|text\)\#=//g
Explanation:
\(^\|\(text\)\#<=\) # means start of line, or some point preceded by “text”
.\{-} # as few characters as possible
\($\|text\)\#= # without globbing characters, checking that we reached either end of line or occurrence of “text”.
Another way to do it:
Create a function that count matches of a pattern in a string (see :help match() to help you design that)
Use: :%s/.*/\=repeat('text', matchcount('text', submatch(0)))
Forgive me, because I'm not a vim expert, but wouldn't prepending the search with v find the inverse so that you could do something like this?
:v/pattern/d
I've implemented Benoit's clever regular expression as a custom :DeleteExcept command in my PatternsOnText plugin. It offers other related commands like :SubstituteExcept or :SubstituteInSearch, too.
OP's example would be
:%DeleteExcept /text/
Comparing that with #Benoit's explicit command (:%s/\(^\|\(text\)\#<=\).\{-}\($\|text\)\#=//g), it's a lot simpler.

In vim, is there a plugin to use % to match the corresponding double quote (")?

The % key is one of the best features of vim: it lets you jump from { to }, [ to ], and so on.
However, it does not work by default with quotes: Either " or ', probably because the opening and closing quote are the same character, making implementation more difficult.
Thinking a bit more about the problem, I'm convinced that it should be implemented, by counting if the number of preceding quotes is odd or even and jumping to the previous or next quote, accordingly.
Before I try to implement it myself, I'd just like to know if someone already has?
Depending on your reason for needing this, there may be a better way to accomplish what you're looking for. For example, if you have the following code:
foo(bar, "baz quux")
^
and your cursor happens to be at the ^, and you want to replace everything inside the quotes with something else, use ci". This uses the Vim "text objects" to change (c) everything inside (i) the quotes (") and puts you in insert mode like this:
foo(bar, "")
^
Then you can start typing the replacement text. There are many other text objects that are really useful for this kind of shortcut. Learn (and use) one new Vim command per week, and you'll be an expert in no time!
Greg's answer was very useful but i also like the 'f' and 'F' commands that move the cursor forward and backward to the character you press after the command.
So press f" to move to the next " character and F" to move to the previous one.
I have found this technique very useful for going to the start/end of a very long quoted string.
when cursor is inside the string, visually select the whole string using vi" or vi'
go to start/end of the string by pressing o
press escape to exit visual select mode
this actually takes the cursor next to the start/end quote character, but still feels pretty helpful.
Edit
Adding Stefan's excellent comment here which is a better option for anyone who may miss the comment.
If you use va" (and va') then it will actually visually select the quotes itself as well.
– Stefan van den Akker
I'd like to expand on Greg's answer, and introduce the surround.vim plugin.
Suppose that rather than editing the contents of your quotes, you want to modify the " characters themselves. Lets say you want to change from double-quotes to single-quotes.
foo(bar, "baz quux")
^
The surround plugin allows you to change this to
foo(bar, 'baz quux')
^
just by executing the following: cs"' (which reads: "change the surrounding double-quotes to single-quotes").
You could also delete the quote marks simply by running: ds" (which reads: "delete the surrounding double-quotes).
There is a good introduction to the surround plugin here.
I know this question is old but here is a plugin to use % to match the corresponding double quote:
https://github.com/airblade/vim-matchquote

Vim: need help with a tiny script code to highlight

I need a script code to highlight "[Capítulo" and "]" and everything between them. Thank you.
I want it to work everytime I open , for example, a .txt file. Just like code highlighting.
Here's an easy way to do it:
in vim, make sure syntax highlighting is on with :syn on
run the command :highlight to get a listing of all the highlight group names, and samples of what they look like. The Error group looks like it stands out well in my colorscheme, so I'll use that in my example (but you can use any of the other names, like Todo or Search)
:syntax match Error /\[Capítulo[^\]]*\]/
This pattern will keep you from greedily matching the largest chunk. Even though other people are suggesting you use the regular expression /\[Capítulo.*\]/ - it's probably not what you want, because it will match everything in between if there are two or more such patterns on a line.
For example /\[Capítulo.*\]/ will match this entire line:
[Capítulo foo] these words should not be highlighted [Capítulo bar]
The same example but with /\[Capítulo[^\]]*\]/ will only match stuff inside []:
[Capítulo foo] these words should not be highlighted [Capítulo bar]
With regular expressions, it's a common trick to make a group that matches everything but the character that you want to end your match, instead of using the .* which will match as many characters as it can. In this case, we make the group [^\]]* - which says "match everything except ]."
If this works the way you want it to, add the syntax match line without the ":" to your .vimrc
A regular expression is what you're looking for:
Type / to enter in "search mode" and type:
\[Capítulo.*\]/

Resources