Vim Tips Wiki
No edit summary
Tag: sourceedit
(→‎Related scripts: Add alternative that only goes over modified lines)
Tag: Visual edit
(8 intermediate revisions by 7 users not shown)
Line 1: Line 1:
  +
{{TipImported
<meta content="HTML Tidy for Linux (vers 25 March 2009), see www.w3.org" name="generator" />
 
  +
|id=878
<title></title>
 
  +
|previous=876
<title></title>
 
  +
|next=879
<title></title>
 
  +
|created=2005
<style type="text/css">
 
  +
|complexity=intermediate
/*<![CDATA[*/
 
  +
|author=Bertram Scharpf
b.cleanuphtml-5 {
 
  +
|version=6.0
font-style: italic
 
  +
|rating=0/4
}
 
  +
|category1=Syntax
h1.cleanuphtml-4 {
 
  +
|category2=
font-style: italic;
 
  +
}}
font-weight: bold
 
  +
}
 
  +
==Simple commands to remove unwanted whitespace==
img.cleanuphtml-3 {
 
  +
In a search, <code>\s</code> finds whitespace (a space or a tab), and <code>\+</code> finds one or more occurrences.
padding: 0px;
 
  +
margin: 0px;
 
  +
The following command deletes any trailing whitespace at the end of each line. If no trailing whitespace is found no change occurs, and the <code>e</code> flag means no error is displayed.
width: 350px;
 
  +
<pre>
height: 234px;
 
  +
:%s/\s\+$//e
border: 1px solid #000000;
 
  +
</pre>
}
 
  +
img.cleanuphtml-2 {
 
  +
The following deletes any leading whitespace at the beginning of each line.
padding: 0px;
 
  +
<pre>
margin: 0px;
 
  +
:%s/^\s\+//e
border: 1px solid #000000;
 
  +
" Same thing (:le = :left = left-align given range; % = all lines):
}
 
  +
:%le
span.cleanuphtml-1 {
 
  +
</pre>
color: #bc0b44;
 
  +
}
 
  +
With the following mapping a user can press F5 to delete all trailing whitespace. The variable <code>_s</code> is used to save and restore the last search pattern register (so next time the user presses <code>n</code> they will continue their last search), and <code>:nohl</code> is used to switch off search highlighting (so trailing spaces will not be highlighted while the user types). The <code>e</code> flag is used in the substitute command so no error is shown if trailing whitespace is not found. Unlike before, the substitution text must be specified in order to use the required flag.
/*]]>*/</style>
 
  +
<pre>
<!-- Clean HTML generated by http://www.cleanuphtml.com/ -->
 
  +
:nnoremap <silent> <F5> :let _s=@/ <Bar> :%s/\s\+$//e <Bar> :let @/=_s <Bar> :nohl <Bar> :unlet _s <CR>
<meta content="Cleanup HTML" name="Generator" />
 
<p>
+
</pre>
  +
&nbsp;
 
  +
See [[VimTip396|Highlighting whitespaces at end of line]] to display, rather than delete, unwanted whitespace.
</p>
 
  +
<p>
 
  +
==Display or remove unwanted whitespace with a script==
&nbsp;
 
  +
The following is a more elaborate procedure that can display or remove unwanted whitespace. Here, "unwanted" means any spaces before a tab character, or any space or tab at the end of a line.
</p>
 
  +
<p>
 
  +
<pre>
&nbsp;
 
  +
function ShowSpaces(...)
</p>
 
  +
let @/='\v(\s+$)|( +\ze\t)'
<div>
 
  +
let oldhlsearch=&hlsearch
&nbsp;
 
  +
if !a:0
</div>
 
  +
let &hlsearch=!&hlsearch
<div class="&lt;title&gt;&lt;/title&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;div&gt; &amp;nbsp; &lt;/div&gt; &lt;div&gt; &lt;p&gt; &lt;b&gt;&lt;i&gt;&lt;a href=&quot;/prices.html&quot;&gt;Prices&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; &lt;/p&gt; &lt;div&gt; &lt;h1&gt;&lt;span style=&quot;color: #9c744a;&quot;&gt;Apartment for enormous porch (2 outputs)a extensive lounge room kitchen air satellite television on appeal.&lt;/span&gt;&lt;/h1&gt; &lt;/div&gt; &lt;div class=&quot;&amp;lt;svg width=&amp;quot;640&amp;quot; height=&amp;quot;480&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; OVERFLOW=&amp;quot;hidden&amp;quot;&amp;gt; &amp;lt;!-- Created with Liveweave.com --&amp;gt; &amp;lt;g&amp;gt; &amp;lt;title&amp;gt;Layer 1&amp;lt;/title&amp;gt; &amp;lt;/g&amp;gt; &amp;lt;/svg&amp;gt;&quot;&gt; &lt;p&gt; &lt;b&gt;&lt;i&gt;&lt;img align=&quot;&quot; alt=&quot;living room TV kitchen&quot; class=&quot;cleanuphtml-2&quot; height=&quot;233&quot; src=&quot;http://File1.npage.de/010130/69/bilder/2vb_4918-2.jpg&quot; style=&quot;margin: 0px; padding: 0px; border: 1px solid rgb(0, 0, 0); border-image: none;&quot; title=&quot;living 1&quot; width=&quot;450&quot; /&gt;&lt;/i&gt;&lt;/b&gt; &lt;/p&gt; &lt;p&gt; &lt;b&gt;&lt;i&gt;&lt;img align=&quot;&quot; alt=&quot;big&quot; class=&quot;cleanuphtml-2&quot; height=&quot;299&quot; src=&quot;http://File1.npage.de/010130/69/bilder/2vb_4922-2.jpg&quot; style=&quot;margin: 0px; padding: 0px; border: 1px solid rgb(0, 0, 0); border-image: none;&quot; title=&quot;living 2&quot; width=&quot;450&quot; /&gt;&lt;/i&gt;&lt;/b&gt; &lt;/p&gt; &lt;p&gt; &lt;b&gt;&lt;i&gt;&lt;img align=&quot;&quot; alt=&quot;looking&quot; class=&quot;cleanuphtml-2&quot; height=&quot;301&quot; src=&quot;http://File1.npage.de/010130/69/bilder/2vb_4927-2.jpg&quot; style=&quot;margin: 0px; padding: 0px; border: 1px solid rgb(0, 0, 0); border-image: none;&quot; title=&quot;bedroom outputs&quot; width=&quot;450&quot; /&gt;&lt;/i&gt;&lt;/b&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;/div&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;/div&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;script src='http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js'&gt;&lt;/script&gt;&lt;script&gt;&lt;/script&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt; &lt;div class=&quot;clearfix&quot;&gt; &amp;nbsp; &lt;/div&gt; &lt;div class=&quot;footer&quot;&gt; &amp;nbsp; &lt;/div&gt; &lt;script type=&quot;text/javascript&quot;&gt; &lt;/script&gt; &lt;p&gt; &amp;nbsp; &lt;/p&gt;" lang="en" xml:lang="en">
 
  +
else
<p>
 
  +
let &hlsearch=a:1
&nbsp;
 
  +
end
</p>
 
  +
return oldhlsearch
<h1 class="cleanuphtml-4"><em><em><strong><a><span class="cleanuphtml-1 cleanuphtml-1">From the corridor you can achieve the flat,it has an open to lounge with kitchen and atmosphere.Offers you a north side of greenery enclosure view with structure and out of sight Biokovo mountain scene.The kitchen sufficiently bright and prepared.</span></a><img alt="from the kitchen" class="cleanuphtml-2 cleanuphtml-2 img-responsive" height="404" src="../files/images/2vb_4887-2.jpg" title="living space" width="550" /><img alt="from the entrance" class="cleanuphtml-2 cleanuphtml-2 img-responsive" height="408" src="../files/images/2vb_4888-2.jpg" title="living space" width="551" /><img alt="dining table" class="cleanuphtml-2 cleanuphtml-2 img-responsive" height="408" src="http://www.makar80.eu/files/images/2vb_4884-2.jpg" title="View toward kitchen" width="550" /><img alt="shower cabin" class="cleanuphtml-3 cleanuphtml-3 img-responsive" src="http://www.makar80.eu/files/images/2vb_4895-2.jpg" title="bathroom" /><img alt="trundle" class="cleanuphtml-4 cleanuphtml-2 img-responsive" height="233" src="http://www.makar80.eu/files/images/2vb_4868-2.jpg" title="bedroom" width="350" /></strong></em></em></h1>
 
  +
endfunction
<div class="modal">
 
  +
<ul>
 
  +
function TrimSpaces() range
<li>
 
  +
let oldhlsearch=ShowSpaces(1)
<h1 class="cleanuphtml-4"><em><em><strong><a href="kontakt.html">Contact form</a></strong></em></em></h1>
 
  +
execute a:firstline.",".a:lastline."substitute ///gec"
<b class="cleanuphtml-5"><em><em><strong><a href="../sitemap.html">Sitemap</a></strong></em></em></b>
 
  +
let &hlsearch=oldhlsearch
</li>
 
  +
endfunction
</ul>
 
  +
<div class="modal-dialog">
 
  +
command -bar -nargs=? ShowSpaces call ShowSpaces(<args>)
<div class="modal-content">
 
  +
command -bar -nargs=0 -range=% TrimSpaces <line1>,<line2>call TrimSpaces()
&nbsp;
 
  +
nnoremap <F12> :ShowSpaces 1<CR>
</div>
 
  +
nnoremap <S-F12> m`:TrimSpaces<CR>``
</div>
 
  +
vnoremap <S-F12> :TrimSpaces<CR>
</div>
 
<p>
+
</pre>
  +
&nbsp;
 
  +
This is a similar function which similates the manual steps for removing the whitespace.
</p>
 
<p>
+
<pre>
  +
function StripTrailingWhitespace()
&nbsp;
 
  +
if !&binary && &filetype != 'diff'
</p>
 
  +
normal mz
</div>
 
  +
normal Hmy
<p>
 
  +
%s/\s\+$//e
&nbsp;
 
  +
normal 'yz<CR>
</p>
 
  +
normal `z
<p>
 
  +
endif
&nbsp;
 
  +
endfunction
</p>
 
  +
</pre>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js" type=
 
  +
However, this has minor side-effects, such as influencing undo history and sometimes changing scroll position.
"text/javascript">
 
  +
</script><script type="text/javascript">
 
  +
==Automatically removing all trailing whitespace==
</script>
 
  +
One way to make sure to remove all trailing whitespace in a file is to set an <code>autocmd</code> in your .vimrc file. Every time the user issues a <code>:w</code> command, Vim will automatically remove all trailing whitespace before saving.
<p>
 
  +
<pre>
&nbsp;
 
  +
autocmd BufWritePre * %s/\s\+$//e
</p>
 
  +
</pre>
<div class="clearfix">
 
  +
&nbsp;
 
  +
However, this is a potentially dangerous autocmd to have as it will always strip trailing whitespace from every file a user saves. Sometimes, trailing whitespace is desired, or even essential in a file so be careful when implementing this <code>autocmd</code>.
</div>
 
  +
<div class="footer">
 
  +
One method to mitigate this issue in a .vimrc file, where trailing whitespace matters, is to change how .vimrc prepends wrapped lines. For example, add the following into the .vimrc:
&nbsp;
 
</div>
+
<pre>
  +
set wrap
<script type="text/javascript">
 
  +
set linebreak
</script>
 
  +
" note trailing space at end of next line
<h1>&nbsp;</h1>
 
  +
set showbreak=>\ \ \
<p>
 
  +
</pre>
&nbsp;
 
  +
</p>
 
  +
Now when saving the .vimrc it will use <code>"> \"</code> instead of <code>"> "</code> to prepend wrapped lines.
<p>
 
  +
&nbsp;
 
  +
A user can also specify a particular filetype in an <code>autocmd</code> so that only that filetype will be changed when saving. The following only changes files with the extension .pl:
</p>
 
  +
<pre>
  +
autocmd BufWritePre *.pl %s/\s\+$//e
  +
</pre>
  +
  +
Additionally, a FileType autocommand can be used to restrict the <code>autocmd</code> to certain file types only.
  +
<pre>
  +
autocmd FileType c,cpp,java,php autocmd BufWritePre <buffer> %s/\s\+$//e
  +
</pre>
  +
  +
==See also==
  +
*{{help|:autocmd}} - Additional information on <code>autocmd</code>
  +
  +
==Related scripts==
  +
* The {{script|id=3967|text=DeleteTrailingWhitespace}} plugin offers a eponymous command, and can remove trailing whitespace automatically when the buffer is written.
  +
* The {{script|id=3201|text=trailing-whitespace}} plugin defines :FixWhitespace.
  +
* The {{script|id=3735|text=bad-whitespace}} plugin defines :EraseBadWhitespace.
  +
* The {{script|id=3938|text=Trailer Trash}} plugin defines :Trim.
  +
* The [https://github.com/axelf4/vim-strip-trailing-whitespace vim-strip-trailing-whitespace] plugin touches only modified lines on save.
  +
  +
==Comments==
  +
Here's what I use in my .vimrc:
  +
<pre>
  +
" Removes trailing spaces
  +
function TrimWhiteSpace()
  +
%s/\s*$//
  +
''
  +
endfunction
  +
  +
set list listchars=trail:.,extends:>
  +
autocmd FileWritePre * call TrimWhiteSpace()
  +
autocmd FileAppendPre * call TrimWhiteSpace()
  +
autocmd FilterWritePre * call TrimWhiteSpace()
  +
autocmd BufWritePre * call TrimWhiteSpace()
  +
  +
map <F2> :call TrimWhiteSpace()<CR>
  +
map! <F2> :call TrimWhiteSpace()<CR>
  +
</pre>
  +
  +
----
  +
My preferred setting of list and listchars so that I can see my whitespace instead of removing it:
  +
<pre>
  +
set list listchars=tab:»·,trail:·
  +
</pre>
  +
  +
This gives:<br>
  +
»·······text after tab with four spaces after it····
  +
  +
Or try
  +
<pre>
  +
set list lcs=tab:·⁖,trail:¶
  +
</pre>
  +
  +
This gives:<br>
  +
·⁖⁖⁖⁖⁖⁖⁖text after tab with four spaces after it¶¶¶¶
  +
----
  +
There is one occasion where I want to keep my trailing space. But even in those documents, I want to keep it in only in one place, and not every occurrence.
  +
  +
Here is my substitution pattern:
  +
<pre>
  +
s/\(^--\)\@<!\s*$//
  +
</pre>
  +
  +
This will eliminate all trailing whitespaces except for the one in an email signature marker (-- ). See [[wikipedia:Signature block]].
  +
  +
In the function in the tip, this expands to:
  +
<pre>
  +
execute a:firstline.",".a:lastline."substitute /\\(^--\\)\\@<!\\s*$//ge"
  +
</pre>
  +
  +
Also, I've found the autocmds to work better like this:
  +
<pre>
  +
autocmd FileWritePre * TrimSpaces
  +
autocmd FileAppendPre * TrimSpaces
  +
autocmd FilterWritePre * TrimSpaces
  +
autocmd BufWritePre * TrimSpaces
  +
</pre>
  +
  +
(taking advantage of the default range defined in Betram's command definition)
  +
  +
----
  +
I modified one of the above scripts to let the user know if whitespace was found
  +
<pre>
  +
" automatically remove trailing whitespace before write
  +
function! StripTrailingWhitespace()
  +
normal mZ
  +
%s/\s\+$//e
  +
if line("'Z") != line(".")
  +
echo "Stripped whitespace\n"
  +
endif
  +
normal `Z
  +
endfunction
  +
autocmd BufWritePre *.cpp,*.hpp,*.i :call StripTrailingWhitespace()
  +
</pre>
  +
  +
----
  +
I didn't get the <code>*</code> match to work so I used <code>*.*</code> instead:
  +
<pre>
  +
autocmd BufWritePre *.* %s/\s\+$//e
  +
</pre>
  +
  +
----
  +
Marks are unnecessary, at least in Vim 7. (Yes, that <code>*.{cpp,h,c,etc}</code> syntax is valid. Much better than <code>*.cpp,*.h,*.c,*.etc</code> IMHO.)
  +
  +
<pre>
  +
autocmd BufWritePre *.{cpp,h,c,etc} call StripTrailingWhite()
  +
  +
function! StripTrailingWhite()
  +
let l:winview = winsaveview()
  +
silent! %s/\s\+$//
  +
call winrestview(l:winview)
  +
endfunction
  +
</pre>
  +
----
  +
Actually because <code>%s</code> seems like is forcing a redraw line by line (is a guess) (see also option <code>lazyredraw</code>), I get faster result by entering EX mode first:
  +
<pre>
  +
autocmd BufWritePre <Esc>Q :call StripTailingWhite()<CR>:visual<CR>
  +
</pre>
  +
This was a guess that worked but my limited knowledge can't answer why.
  +
----
  +
  +
I like the one above that prints a message. In that case I think the mark is needed. However, there is a small bug in the implementation that fails to print the message if the current line has trailing whitespace and is the last line or only line in the file that does. Checking also for change in the number of chars in the current line fixes it.
  +
  +
<pre>
  +
function! StripTrailingWhitespace()
  +
normal mZ
  +
let l:chars = col("$")
  +
%s/\s\+$//e
  +
if (line("'Z") != line(".")) || (l:chars != col("$"))
  +
echo "Trailing whitespace stripped\n"
  +
endif
  +
normal `Z
  +
endfunction
  +
  +
autocmd BufWritePre * call StripTrailingWhitespace()
  +
</pre>
  +
  +
=== Remove space but save cursor position ===
  +
I didn't like how I had to use marks to get back to where I was after changing whitespace - it would always leave my cursor at the last change location. Here's a quick fix for that:
  +
<pre>
  +
" Remap for destroying trailing whitespace cleanly
  +
:nnoremap <Leader>w :let _save_pos=getpos(".") <Bar>
  +
\ :let _s=@/ <Bar>
  +
\ :%s/\s\+$//e <Bar>
  +
\ :let @/=_s <Bar>
  +
\ :nohl <Bar>
  +
\ :unlet _s<Bar>
  +
\ :call setpos('.', _save_pos)<Bar>
  +
\ :unlet _save_pos<CR><CR>
  +
</pre>

Revision as of 19:18, 4 January 2020

Tip 878 Printable Monobook Previous Next

created 2005 · complexity intermediate · author Bertram Scharpf · version 6.0


Simple commands to remove unwanted whitespace

In a search, \s finds whitespace (a space or a tab), and \+ finds one or more occurrences.

The following command deletes any trailing whitespace at the end of each line. If no trailing whitespace is found no change occurs, and the e flag means no error is displayed.

:%s/\s\+$//e

The following deletes any leading whitespace at the beginning of each line.

:%s/^\s\+//e
" Same thing (:le = :left = left-align given range; % = all lines):
:%le

With the following mapping a user can press F5 to delete all trailing whitespace. The variable _s is used to save and restore the last search pattern register (so next time the user presses n they will continue their last search), and :nohl is used to switch off search highlighting (so trailing spaces will not be highlighted while the user types). The e flag is used in the substitute command so no error is shown if trailing whitespace is not found. Unlike before, the substitution text must be specified in order to use the required flag.

:nnoremap <silent> <F5> :let _s=@/ <Bar> :%s/\s\+$//e <Bar> :let @/=_s <Bar> :nohl <Bar> :unlet _s <CR>

See Highlighting whitespaces at end of line to display, rather than delete, unwanted whitespace.

Display or remove unwanted whitespace with a script

The following is a more elaborate procedure that can display or remove unwanted whitespace. Here, "unwanted" means any spaces before a tab character, or any space or tab at the end of a line.

function ShowSpaces(...)
  let @/='\v(\s+$)|( +\ze\t)'
  let oldhlsearch=&hlsearch
  if !a:0
    let &hlsearch=!&hlsearch
  else
    let &hlsearch=a:1
  end
  return oldhlsearch
endfunction

function TrimSpaces() range
  let oldhlsearch=ShowSpaces(1)
  execute a:firstline.",".a:lastline."substitute ///gec"
  let &hlsearch=oldhlsearch
endfunction

command -bar -nargs=? ShowSpaces call ShowSpaces(<args>)
command -bar -nargs=0 -range=% TrimSpaces <line1>,<line2>call TrimSpaces()
nnoremap <F12>     :ShowSpaces 1<CR>
nnoremap <S-F12>   m`:TrimSpaces<CR>``
vnoremap <S-F12>   :TrimSpaces<CR>

This is a similar function which similates the manual steps for removing the whitespace.

function StripTrailingWhitespace()
  if !&binary && &filetype != 'diff'
    normal mz
    normal Hmy
    %s/\s\+$//e
    normal 'yz<CR>
    normal `z
  endif
endfunction

However, this has minor side-effects, such as influencing undo history and sometimes changing scroll position.

Automatically removing all trailing whitespace

One way to make sure to remove all trailing whitespace in a file is to set an autocmd in your .vimrc file. Every time the user issues a :w command, Vim will automatically remove all trailing whitespace before saving.

autocmd BufWritePre * %s/\s\+$//e

However, this is a potentially dangerous autocmd to have as it will always strip trailing whitespace from every file a user saves. Sometimes, trailing whitespace is desired, or even essential in a file so be careful when implementing this autocmd.

One method to mitigate this issue in a .vimrc file, where trailing whitespace matters, is to change how .vimrc prepends wrapped lines. For example, add the following into the .vimrc:

set wrap
set linebreak
" note trailing space at end of next line
set showbreak=>\ \ \

Now when saving the .vimrc it will use "> \" instead of "> " to prepend wrapped lines.

A user can also specify a particular filetype in an autocmd so that only that filetype will be changed when saving. The following only changes files with the extension .pl:

autocmd BufWritePre *.pl %s/\s\+$//e

Additionally, a FileType autocommand can be used to restrict the autocmd to certain file types only.

autocmd FileType c,cpp,java,php autocmd BufWritePre <buffer> %s/\s\+$//e

See also

Related scripts

Comments

Here's what I use in my .vimrc:

" Removes trailing spaces
function TrimWhiteSpace()
  %s/\s*$//
  ''
endfunction

set list listchars=trail:.,extends:>
autocmd FileWritePre * call TrimWhiteSpace()
autocmd FileAppendPre * call TrimWhiteSpace()
autocmd FilterWritePre * call TrimWhiteSpace()
autocmd BufWritePre * call TrimWhiteSpace()

map <F2> :call TrimWhiteSpace()<CR>
map! <F2> :call TrimWhiteSpace()<CR>

My preferred setting of list and listchars so that I can see my whitespace instead of removing it:

set list listchars=tab:»·,trail:·

This gives:
»·······text after tab with four spaces after it····

Or try

set list lcs=tab:·⁖,trail:¶

This gives:
·⁖⁖⁖⁖⁖⁖⁖text after tab with four spaces after it¶¶¶¶


There is one occasion where I want to keep my trailing space. But even in those documents, I want to keep it in only in one place, and not every occurrence.

Here is my substitution pattern:

s/\(^--\)\@<!\s*$//

This will eliminate all trailing whitespaces except for the one in an email signature marker (-- ). See wikipedia:Signature block.

In the function in the tip, this expands to:

execute a:firstline.",".a:lastline."substitute /\\(^--\\)\\@<!\\s*$//ge"

Also, I've found the autocmds to work better like this:

autocmd FileWritePre * TrimSpaces
autocmd FileAppendPre * TrimSpaces
autocmd FilterWritePre * TrimSpaces
autocmd BufWritePre * TrimSpaces

(taking advantage of the default range defined in Betram's command definition)


I modified one of the above scripts to let the user know if whitespace was found

" automatically remove trailing whitespace before write
function! StripTrailingWhitespace()
  normal mZ
  %s/\s\+$//e
  if line("'Z") != line(".")
    echo "Stripped whitespace\n"
  endif
  normal `Z
endfunction
autocmd BufWritePre *.cpp,*.hpp,*.i :call StripTrailingWhitespace()

I didn't get the * match to work so I used *.* instead:

autocmd BufWritePre *.* %s/\s\+$//e

Marks are unnecessary, at least in Vim 7. (Yes, that *.{cpp,h,c,etc} syntax is valid. Much better than *.cpp,*.h,*.c,*.etc IMHO.)

autocmd BufWritePre  *.{cpp,h,c,etc}  call StripTrailingWhite()

function! StripTrailingWhite()
    let l:winview = winsaveview()
    silent! %s/\s\+$//
    call winrestview(l:winview)
endfunction

Actually because %s seems like is forcing a redraw line by line (is a guess) (see also option lazyredraw), I get faster result by entering EX mode first:

autocmd BufWritePre <Esc>Q :call StripTailingWhite()<CR>:visual<CR>

This was a guess that worked but my limited knowledge can't answer why.


I like the one above that prints a message. In that case I think the mark is needed. However, there is a small bug in the implementation that fails to print the message if the current line has trailing whitespace and is the last line or only line in the file that does. Checking also for change in the number of chars in the current line fixes it.

function! StripTrailingWhitespace()
  normal mZ
  let l:chars = col("$")
  %s/\s\+$//e
  if (line("'Z") != line(".")) || (l:chars != col("$"))
    echo "Trailing whitespace stripped\n"
  endif
  normal `Z
endfunction

autocmd BufWritePre * call StripTrailingWhitespace()

Remove space but save cursor position

I didn't like how I had to use marks to get back to where I was after changing whitespace - it would always leave my cursor at the last change location. Here's a quick fix for that:

" Remap for destroying trailing whitespace cleanly
:nnoremap <Leader>w :let _save_pos=getpos(".") <Bar>
    \ :let _s=@/ <Bar>
    \ :%s/\s\+$//e <Bar>
    \ :let @/=_s <Bar>
    \ :nohl <Bar>
    \ :unlet _s<Bar>
    \ :call setpos('.', _save_pos)<Bar>
    \ :unlet _save_pos<CR><CR>