Vim Tips Wiki
Register
(→‎Comments: OptionSet autocmd useful for textwidth-based matching)
Tags: rollback sourceedit
(13 intermediate revisions by 8 users not shown)
Line 1: Line 1:
__NOTOC__
 
 
{{TipImported
 
{{TipImported
 
|id=810
 
|id=810
 
|previous=809
 
|previous=809
 
|next=812
 
|next=812
|created=October 25, 2004
+
|created=2004
 
|complexity=intermediate
 
|complexity=intermediate
 
|author=Nitin Raut
 
|author=Nitin Raut
Line 10: Line 9:
 
|rating=
 
|rating=
 
|category1=Syntax
 
|category1=Syntax
|category2=
+
|category2=Temporary
 
}}
 
}}
  +
{{deprecated|Vim 7.3 adds the 'colorcolumn' option which allows you to highlight a specific column. The methods herein may be useful for some users however.}}
There are a number of situations where it can be helpful to know when you are near or have exceeded a certain column width (say 80 columns). Vim's highlighting features can be used to easily identify when this occurs. Some editors show a line at this width; Vim cannot do this.
+
There are a number of situations where it can be helpful to know when you are near, or have exceeded a certain column width (say 80 columns). Vim's highlighting features can be used to easily identify when this occurs. Unlike some editors, Vim cannot show a line at this width.
  +
  +
You can also [[VimTip38|wrap long lines]], or show <code><</code> <code>></code> flags when [[VimTip396#HighlightLongLines|characters are not displayed]] on long lines.
   
 
==Searching==
 
==Searching==
A quick method to find long lines is a search like the following. If you use [[VimTip14|search highlighting]] (<tt>:set hlsearch</tt>), this will highlight all text in and after virtual column 80 (after tabs are expanded).
+
A quick method to find long lines is a search like the following. If you use [[VimTip14|search highlighting]] (<code>:set hlsearch</code>), this will highlight all text after virtual column 80 (after tabs are expanded).
 
<pre>
 
<pre>
/\%80v.*
+
/\%>80v.\+
 
</pre>
 
</pre>
   
 
==Matching==
 
==Matching==
A simple command will highlight any text past column 80:
+
A simple command will highlight any text after virtual column 80:
 
<pre>
 
<pre>
:match ErrorMsg '\%81v.*'
+
:match ErrorMsg '\%>80v.\+'
 
</pre>
 
</pre>
   
Of course, you can [[VimTip24|define your own highlight groups]] if ErrorMsg is not to your taste. Enter <tt>:match</tt> to clear matching.
+
Of course, you can [[VimTip24|define your own highlight groups]] if ErrorMsg is not to your taste. Enter <code>:match</code> to clear matching.
   
  +
Alternatively, you can just highlight any character in column 81. This is less visually aggressive if you have lines that extend past 80 characters, and thus is more suited to being placed in your .vimrc and left on all the time.
===Automatic===
 
If you want to be warned whenever text exceeds 80 columns you can use matching. In Vim 7.2 this is easy to achieve with the following commands (the <tt>-1</tt> means any search highlighting will override the match highlighting):
 
 
<pre>
 
<pre>
 
:2mat ErrorMsg '\%81v.'
:let w:m1=matchadd('Search','\%<81v.\%>71v',-1)
 
  +
</pre>
:let w:m2=matchadd('ErrorMsg','\%81v.*',-1)
 
  +
  +
==Replacing==
  +
Command to replace line text >80 chars from the previous word boundary to '...':
  +
<pre>
  +
:g/\%>79v/norm 77|gElC...
  +
</pre>
  +
  +
Credit to Accolade from #vim on Freenode.
  +
 
==Automatic matching==
 
If you want to be warned whenever text exceeds 80 columns you can use matching. In Vim 7.2 this is easy to achieve with the following commands (the <code>-1</code> means any search highlighting will override the match highlighting):
  +
<pre>
 
:let w:m1=matchadd('Search', '\%<81v.\%>77v', -1)
 
:let w:m2=matchadd('ErrorMsg', '\%>80v.\+', -1)
 
</pre>
 
</pre>
   
 
You can apply this highlighting automatically for all files with something like this in your [[vimrc]]:
 
You can apply this highlighting automatically for all files with something like this in your [[vimrc]]:
 
<pre>
 
<pre>
:au BufWinEnter * let w:m1=matchadd('Search','\%<81v.\%>71v',-1)
+
:au BufWinEnter * let w:m1=matchadd('Search', '\%<81v.\%>77v', -1)
:au BufWinEnter * let w:m2=matchadd('ErrorMsg','\%81v.*',-1)
+
:au BufWinEnter * let w:m2=matchadd('ErrorMsg', '\%>80v.\+', -1)
 
</pre>
 
</pre>
   
You can change the <tt>*</tt> to a different pattern, or a comma-separated list, to make it work only for certain file types like <tt>*.c,*.h</tt> for example.
+
You can change the <code>*</code> to a different pattern, or a comma-separated list, to make it work only for certain file types like <code>*.c,*.h</code> for example.
   
 
Since matches are local to a window and are not inherited when a new window is created, this method will not necessarily apply to all new windows you create. It will be pretty close, but if you really want to highlight in all windows, you will need to apply the highlighting [[Detect window creation with WinEnter|whenever you detect a window creation]].
 
Since matches are local to a window and are not inherited when a new window is created, this method will not necessarily apply to all new windows you create. It will be pretty close, but if you really want to highlight in all windows, you will need to apply the highlighting [[Detect window creation with WinEnter|whenever you detect a window creation]].
Line 51: Line 66:
 
</pre>
 
</pre>
   
Alternatively, use the following command if you are want to clear ''all'' matches that have been defined for this window:
+
Alternatively, the following command will clear ''all'' matches that have been defined for this window:
 
<pre>
 
<pre>
 
:call clearmatches()
 
:call clearmatches()
 
</pre>
 
</pre>
   
===Automatic (for Vim before version 7.1.40)===
+
==Automatic matching (for Vim before version 7.1.40)==
 
For earlier versions of Vim, the following is a close approximation:
 
For earlier versions of Vim, the following is a close approximation:
 
<pre>
 
<pre>
:syntax match Search /\%<81v.\%>71v/
+
:syntax match Search /\%<81v.\%>77v/
:syntax match ErrorMsg /\%81v.*/
+
:syntax match ErrorMsg /\%>80v.\+/
 
</pre>
 
</pre>
 
<pre>
 
<pre>
:au BufRead,BufNewFile * syntax match Search /\%<81v.\%>71v/
+
:au BufRead,BufNewFile * syntax match Search /\%<81v.\%>77v/
:au BufRead,BufNewFile * syntax match ErrorMsg /\%81v.*/
+
:au BufRead,BufNewFile * syntax match ErrorMsg /\%>80v.\+/
 
</pre>
 
</pre>
   
Line 74: Line 89:
 
</pre>
 
</pre>
   
This assumes you are editing a file using syntax rules contained in a syntax file (which usually do a <tt>syntax clear</tt> before applying their rules). If you are editing a file with no pre-existing syntax rules, you can get rid of ''all'' syntax highlighting with:
+
This assumes you are editing a file using syntax rules contained in a syntax file (which usually do a <code>syntax clear</code> before applying their rules). If you are editing a file with no pre-existing syntax rules, you can get rid of ''all'' syntax highlighting with:
 
<pre>
 
<pre>
 
:syntax clear
 
:syntax clear
 
</pre>
 
</pre>
   
  +
==Toggle matching based on textwidth==
===Manual===
 
If you don't like to ''always'' highlight long lines, but you want a fast way to check your line length, you can define a mapping to toggle highlighting on/off. This also allows you to easily define the highlight in terms of the <tt>'textwidth'</tt> option. The mapping could look like this:
+
If you don't like to ''always'' highlight long lines, but you want a fast way to check your line length, you can define a mapping to toggle highlighting on/off. This also allows you to easily define the highlight in terms of the <code>'textwidth'</code> option. The mapping could look like this:
   
 
<pre>
 
<pre>
nnoremap <Silent> <Leader>l
+
nnoremap <silent> <Leader>l
 
\ :if exists('w:long_line_match') <Bar>
 
\ :if exists('w:long_line_match') <Bar>
\ call matchdelete(w:long_line_match) <Bar>
+
\ silent! call matchdelete(w:long_line_match) <Bar>
 
\ unlet w:long_line_match <Bar>
 
\ unlet w:long_line_match <Bar>
 
\ elseif &textwidth > 0 <Bar>
 
\ elseif &textwidth > 0 <Bar>
\ let w:long_line_match = matchadd('ErrorMsg','\%'.&tw+1.'v.*',-1) <Bar>
+
\ let w:long_line_match = matchadd('ErrorMsg', '\%>'.&tw.'v.\+', -1) <Bar>
 
\ else <Bar>
 
\ else <Bar>
\ let w:long_line_match = matchadd('ErrorMsg','\%81v.*',-1) <Bar>
+
\ let w:long_line_match = matchadd('ErrorMsg', '\%>80v.\+', -1) <Bar>
 
\ endif<CR>
 
\ endif<CR>
 
</pre>
 
</pre>
  +
  +
==Explanation==
  +
The search pattern <code>\%>80v.\+</code> checks for a match at each position. If the position being tested is at a virtual column above 80, the text at that position is checked to see if it matches what follows (<code>.\+</code>). That matches one or more characters, up to but not including the end-of-line.
  +
  +
A simpler pattern such as <code>\%81v.*</code> fails to highlight text past the limit if there is no character in virtual column 81, for example if a tab starts just before that column. Furthermore, <code>\%81v.*</code> can give an erroneous highlight of column 81 on lines of exactly 80 characters.
  +
  +
The pattern <code>\%<81v.\%>77v</code> matches any character at virtual column 77 to 80 inclusive. The pattern checks for a match at each position: <code>\%<81v.</code> matches any character at a virtual column below 81; <code>\%>77v</code> causes the match to fail unless the virtual column of the next character is above 77.
   
 
==References==
 
==References==
Line 100: Line 122:
   
 
==Comments==
 
==Comments==
  +
Textwidth-based matching can be made automatic using the OptionSet autocmd event introduced in [https://github.com/vim/vim/releases/tag/v7.4.786 Vim 7.4.786]. I'm not spending time to figure out an exact script at the moment since I've personally switched over to the 'colorcolumn' option. --[[User:Fritzophrenic|Fritzophrenic]] ([[User talk:Fritzophrenic|talk]]) 16:10, September 2, 2015 (UTC)
 
I think the general matching pattern should be akin to:
 
:match ErrorMsg '\%81v.\+'
 
Note the use of ".\+" instead of ".*". The issue with the ".*" that I am observing is that it erroneously causes a one-character highlight if the text of the line extends to, but not past column 80. The problem is that "\%81v.*" is a zero-width match, and thus triggers in such cases, whereas the proposed pattern does not have this issue.
 

Revision as of 16:10, 2 September 2015

Tip 810 Printable Monobook Previous Next

created 2004 · complexity intermediate · author Nitin Raut · version 6.0


This tip is deprecated for the following reasons:

Vim 7.3 adds the 'colorcolumn' option which allows you to highlight a specific column. The methods herein may be useful for some users however.

There are a number of situations where it can be helpful to know when you are near, or have exceeded a certain column width (say 80 columns). Vim's highlighting features can be used to easily identify when this occurs. Unlike some editors, Vim cannot show a line at this width.

You can also wrap long lines, or show < > flags when characters are not displayed on long lines.

Searching

A quick method to find long lines is a search like the following. If you use search highlighting (:set hlsearch), this will highlight all text after virtual column 80 (after tabs are expanded).

/\%>80v.\+

Matching

A simple command will highlight any text after virtual column 80:

:match ErrorMsg '\%>80v.\+'

Of course, you can define your own highlight groups if ErrorMsg is not to your taste. Enter :match to clear matching.

Alternatively, you can just highlight any character in column 81. This is less visually aggressive if you have lines that extend past 80 characters, and thus is more suited to being placed in your .vimrc and left on all the time.

:2mat ErrorMsg '\%81v.'

Replacing

Command to replace line text >80 chars from the previous word boundary to '...':

:g/\%>79v/norm 77|gElC...

Credit to Accolade from #vim on Freenode.

Automatic matching

If you want to be warned whenever text exceeds 80 columns you can use matching. In Vim 7.2 this is easy to achieve with the following commands (the -1 means any search highlighting will override the match highlighting):

:let w:m1=matchadd('Search', '\%<81v.\%>77v', -1)
:let w:m2=matchadd('ErrorMsg', '\%>80v.\+', -1)

You can apply this highlighting automatically for all files with something like this in your vimrc:

:au BufWinEnter * let w:m1=matchadd('Search', '\%<81v.\%>77v', -1)
:au BufWinEnter * let w:m2=matchadd('ErrorMsg', '\%>80v.\+', -1)

You can change the * to a different pattern, or a comma-separated list, to make it work only for certain file types like *.c,*.h for example.

Since matches are local to a window and are not inherited when a new window is created, this method will not necessarily apply to all new windows you create. It will be pretty close, but if you really want to highlight in all windows, you will need to apply the highlighting whenever you detect a window creation.

Clear the highlighting with:

:call matchdelete(w:m1)
:call matchdelete(w:m2)

Alternatively, the following command will clear all matches that have been defined for this window:

:call clearmatches()

Automatic matching (for Vim before version 7.1.40)

For earlier versions of Vim, the following is a close approximation:

:syntax match Search /\%<81v.\%>77v/
:syntax match ErrorMsg /\%>80v.\+/
:au BufRead,BufNewFile * syntax match Search /\%<81v.\%>77v/
:au BufRead,BufNewFile * syntax match ErrorMsg /\%>80v.\+/

Note the use of BufRead and BufNewFile instead of BufWinEnter. Unlike matches, syntax is local to the buffer instead of the window.

Clear the highlighting (after saving any changes) with:

:e

This assumes you are editing a file using syntax rules contained in a syntax file (which usually do a syntax clear before applying their rules). If you are editing a file with no pre-existing syntax rules, you can get rid of all syntax highlighting with:

:syntax clear

Toggle matching based on textwidth

If you don't like to always highlight long lines, but you want a fast way to check your line length, you can define a mapping to toggle highlighting on/off. This also allows you to easily define the highlight in terms of the 'textwidth' option. The mapping could look like this:

nnoremap <silent> <Leader>l
      \ :if exists('w:long_line_match') <Bar>
      \   silent! call matchdelete(w:long_line_match) <Bar>
      \   unlet w:long_line_match <Bar>
      \ elseif &textwidth > 0 <Bar>
      \   let w:long_line_match = matchadd('ErrorMsg', '\%>'.&tw.'v.\+', -1) <Bar>
      \ else <Bar>
      \   let w:long_line_match = matchadd('ErrorMsg', '\%>80v.\+', -1) <Bar>
      \ endif<CR>

Explanation

The search pattern \%>80v.\+ checks for a match at each position. If the position being tested is at a virtual column above 80, the text at that position is checked to see if it matches what follows (.\+). That matches one or more characters, up to but not including the end-of-line.

A simpler pattern such as \%81v.* fails to highlight text past the limit if there is no character in virtual column 81, for example if a tab starts just before that column. Furthermore, \%81v.* can give an erroneous highlight of column 81 on lines of exactly 80 characters.

The pattern \%<81v.\%>77v matches any character at virtual column 77 to 80 inclusive. The pattern checks for a match at each position: \%<81v. matches any character at a virtual column below 81; \%>77v causes the match to fail unless the virtual column of the next character is above 77.

References

Comments

Textwidth-based matching can be made automatic using the OptionSet autocmd event introduced in Vim 7.4.786. I'm not spending time to figure out an exact script at the moment since I've personally switched over to the 'colorcolumn' option. --Fritzophrenic (talk) 16:10, September 2, 2015 (UTC)