aboutsummaryrefslogtreecommitdiff
path: root/plugin/strip_trailing_whitespace.vim
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/strip_trailing_whitespace.vim')
-rw-r--r--plugin/strip_trailing_whitespace.vim152
1 files changed, 90 insertions, 62 deletions
diff --git a/plugin/strip_trailing_whitespace.vim b/plugin/strip_trailing_whitespace.vim
index de08fae..75438d9 100644
--- a/plugin/strip_trailing_whitespace.vim
+++ b/plugin/strip_trailing_whitespace.vim
@@ -1,6 +1,7 @@
"
-" strip_trailing_whitespace.vim: User-defined key mapping to strip trailing
-" whitespace in the whole document.
+" strip_trailing_whitespace.vim: User command to strip both horizontal and
+" vertical whitespace in a buffer, with optional range, reporting both
+" accurately and restoring the cursor afterwards.
"
" Author: Tom Ryder <tom@sanctum.geek.nz>
" License: Same as Vim itself
@@ -8,88 +9,115 @@
if exists('g:loaded_strip_trailing_whitespace') || &compatible
finish
endif
-if v:version < 600
+if !has('user_commands') || v:version < 600
finish
endif
let g:loaded_strip_trailing_whitespace = 1
-" Define function for stripping whitespace
-function! s:StripTrailingWhitespace()
+" Wrapper function to strip both horizontal and vertical trailing whitespace,
+" return the cursor to its previous position, and report changes
+function s:Strip(start, end) abort
- " Line number of last line that had non-whitespace characters on it
- let l:cutoff = 1
+ " Save cursor position
+ let l:line = line('.')
+ let l:col = col('.')
- " Tracking lines trimmed between non-whitespace lines and then totalling
- let l:trimmed_buffer = 0
- let l:trimmed = 0
+ " Strip horizontal space
+ let l:horizontal = s:StripHorizontal(a:start, a:end)
+ let l:msg = l:horizontal.' trimmed'
+ let l:changed = l:horizontal > 0
- " Line number of the file's last line
- let l:last = line('$')
+ " If we're going to the end, strip vertical space
+ if a:end == line('$')
+ let l:vertical = s:StripVertical()
+ let l:msg = l:msg.', '.l:vertical.' deleted'
+ let l:changed = l:changed || l:vertical > 0
+ endif
- " Iterate over the lines
- let l:li = 1
- while l:li <= l:last
+ " Return the cursor
+ call s:Cursor(l:line, l:col)
- " Get the line text
- let l:line = getline(l:li)
+ " Report what changed
+ echomsg l:msg
- " If the current line contains trailing whitespace, substitute it out
- if l:line =~# '\s\+$'
- call setline(l:li, substitute(l:line, '\s\+$', '', ''))
- let l:trimmed_buffer = l:trimmed_buffer + 1
- endif
+ " Return whether anything changed
+ return l:changed
+
+endfunction
- " If this line has any non-whitespace characters on it, update our cutoff
- " point using its index, and push the trimmed lines we've counted since
- " the last non-whitespace line onto the trimmed total
- if l:line =~# '\S' || l:last == 1
- let l:cutoff = l:li
- let l:trimmed = l:trimmed + l:trimmed_buffer
- let l:trimmed_buffer = 0
+" Strip horizontal trailing whitespace, return the number of lines changed
+function s:StripHorizontal(start, end) abort
+
+ " Start a count of lines trimmed
+ let l:count = 0
+
+ " Iterate through buffer
+ let l:num = 1
+ while l:num <= line('$')
+
+ " If the line has trailing whitespace, strip it off and bump the count
+ let l:line = getline(l:num)
+ if l:line =~# '\s\+$'
+ call setline(l:num, substitute(l:line, '\s*$', '', ''))
+ let l:count = l:count + 1
endif
- " Increment the line counter for the next iteration
- let l:li = l:li + 1
+ " Bump for next iteration
+ let l:num = l:num + 1
endwhile
- " If the last non-whitespace line was before the last line proper, we can
- " delete all lines after it
- let l:deleted = 0
- if l:cutoff < l:last
-
- " Get the current line and column so we can return to it
- " (Yes I know about winsaveview() and winrestview(); I want this to work
- " even on very old versions of Vim if possible)
- let l:cursor_line = line('.')
- let l:cursor_col = col('.')
-
- " Delete the rest of the lines, which will move the cursor
- silent execute l:cutoff + 1 . ',$ delete _'
-
- " Return the cursor to the saved position (Vim 6.0 fallback)
- if exists('*cursor')
- call cursor(l:cursor_line, l:cursor_col)
- else
- execute 'normal! '
- \ . l:cursor_line . 'G'
- \ . l:cursor_col . '|'
+ " Return the number of lines trimmed
+ return l:count
+
+endfunction
+
+" Strip trailing vertical whitespace, return the number of lines changed
+function s:StripVertical() abort
+
+ " Store the number of the last line we found with non-whitespace characters
+ " on it; start at 1 because even if it's empty it's never trailing
+ let l:eof = 1
+
+ " Iterate through buffer
+ let l:num = 1
+ while l:num <= line('$')
+
+ " If the line has any non-whitespace characters in it, update our pointer
+ " to the end of the file text
+ let l:line = getline(l:num)
+ if l:line =~# '\S'
+ let l:eof = l:num
endif
- " Record the number of lines deleted
- let l:deleted = l:last - l:cutoff
+ " Bump for next iteration
+ let l:num = l:num + 1
+ endwhile
+
+ " Get the number of lines to delete; if there are any, build a range and
+ " remove them with :delete, suppressing its normal output (we'll do it)
+ let l:count = line('$') - l:eof
+ if l:count
+ let l:range = (l:eof + 1).',$'
+ silent execute l:range.'delete'
endif
- " Print what we did
- echomsg l:trimmed . ' trimmed, ' . l:deleted . ' deleted'
+ " Return the number of lines deleted
+ return l:count
- " Return the number of affected lines
- return l:trimmed + l:deleted
+endfunction
+" Position the cursor; use cursor() if we have it, :normal if not (Vim 6.0)
+function s:Cursor(line, col) abort
+ if exists('*cursor')
+ return cursor(a:line, a:col)
+ else
+ execute 'normal! '.a:line.'G'.a:col.'|'
+ return 1
+ endif
endfunction
-" Create mapping proxy to the function just defined
-nnoremap <silent> <unique>
- \ <Plug>(StripTrailingWhitespace)
- \ :<C-U>call <SID>StripTrailingWhitespace()<CR>
+" User command for the above
+command! -range=% StripTrailingWhitespace
+ \ call <SID>Strip(<line1>, <line2>)