├── LICENSE.txt ├── README.md ├── autoload └── uniformity.vim └── plugin └── uniformity.vim /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Michael Kropat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uniformity.vim 2 | 3 | *Safely make whitespace across your project consistent* 4 | 5 | __uniformity.vim__ is a tool for batch updating whitespace across a project. 6 | Because it's a batch tool intended to be run infrequently, it may be of use to 7 | you [even if you don't normally use Vim](#why-vim). 8 | 9 | By whitespace, I'm talking about changing indentation: 10 | 11 | - 2-spaces to 4-spaces 12 | - 4-spaces to 2-spaces 13 | - Spaces to tabs 14 | - Anything to anything really 15 | 16 | But I'm also talking about: 17 | 18 | - Stripping traililng whitespace 19 | - Stripping zero-width Unicode characters 20 | - [Changing line 21 | endings](http://vimdoc.sourceforge.net/htmldoc/options.html#'fileformat') 22 | (Windows → *nix, *nix → Windows, etc.) 23 | - [Changing the file 24 | encoding](http://vimdoc.sourceforge.net/htmldoc/options.html#'fileencoding') 25 | - Adding or removing the [UTF 26 | BOM](https://en.wikipedia.org/wiki/Byte_order_mark) 27 | 28 | ### Is uniformity.vim right for you? 29 | 30 | Depending on what you're trying to do, __there's a decent chance you don't even 31 | need uniformity.vim__: 32 | 33 | - Do you want to change what whitespace Vim uses for any new files you create? 34 | Take a look at the [built-in Vim 35 | settings](http://vim.wikia.com/wiki/Indenting_source_code) 36 | - Do you want Vim to re-indent your files [based on what it thinks your code 37 | should look 38 | like](http://vimdoc.sourceforge.net/htmldoc/indent.html#C-indenting)? Try 39 | [`gg=G`](http://vim.wikia.com/wiki/Fix_indentation). 40 | - Do you want to change both leading and non-leading whitespace in the file? 41 | Try [this trick](http://stackoverflow.com/a/16892086/27581). 42 | 43 | On the other hand... 44 | 45 | Do you want to conservatively change whitespace so that only leading 46 | indentation is changed (to minimize the risk of messing up formatting)? 47 | __uniformity.vim__ might be the right tool for the job. 48 | 49 | While batch updating indentation across a project, do you want to also strip 50 | trailing whitespace, convert line endings, and convert all the files to a 51 | single encoding? __uniformity.vim__ might be the right tool for the job. 52 | 53 | ### Getting Started 54 | 55 | #### Pre-requisites 56 | 57 | __uniformity.vim__ requires that the 58 | [__sleuth.vim__](https://github.com/tpope/vim-sleuth) plugin be installed. 59 | This is necessary because __uniformity.vim__ relies on the 60 | [`shiftwidth`](http://vimdoc.sourceforge.net/htmldoc/options.html#'shiftwidth') 61 | setting of the buffer to reflect the current indentation of the file so it can 62 | know how to change each line. 63 | 64 | #### Installation 65 | 66 | You'll want to use a plugin manager. The instructions assume you're using 67 | [__vim-plug__](https://github.com/junegunn/vim-plug). 68 | 69 | Include the following lines in your 70 | [`.vimrc`](http://vim.wikia.com/wiki/Open_vimrc_file): 71 | 72 | ```viml 73 | call plug#begin('~/.vim/plugged') 74 | 75 | Plug 'tpope/vim-sleuth' 76 | Plug 'mkropat/vim-uniformity' 77 | 78 | call plug#end() 79 | ``` 80 | 81 | Restart Vim, then run `:PlugInstall` to complete the installation. 82 | 83 | #### Configuration 84 | 85 | Include the following lines in your 86 | [`.vimrc`](http://vim.wikia.com/wiki/Open_vimrc_file): 87 | 88 | ```viml 89 | let g:uniformity_indent = ' ' 90 | let g:uniformity_strip_trailing_whitespace = 1 91 | let g:uniformity_strip_zerowidth_chars = 0 92 | let g:uniformity_bomb = 0 93 | let g:uniformity_fileencoding = 'utf-8' 94 | let g:uniformity_fileformat = 'unix' 95 | ``` 96 | 97 | Change each setting as desired. You may omit any setting to have it not take 98 | effect. After you're satisfied, load in the settings by restarting Vim or by 99 | running [`:source 100 | %`](http://vimdoc.sourceforge.net/htmldoc/repeat.html#:source). 101 | 102 | Here's the full reference of what each option does: 103 | 104 | Setting | Description 105 | -----------------------------------------|---------------------- 106 | `g:uniformity_indent` | The string that represents one level of desired indentation, such as a string that contains 2-spaces, 4-spaces, or a tab character. (To insert a tab character, you can use [this trick](http://stackoverflow.com/a/4781099/27581).) 107 | `g:uniformity_strip_trailing_whitespace` | If set to `1`, [trailing whitespace](http://blog.codinghorror.com/whitespace-the-silent-killer/) will be stripped 108 | `g:uniformity_strip_zerowidth_chars` | If set to `1`, [zero-width Unicode characters](http://stackoverflow.com/a/11305926/27581) will be stripped 109 | `g:uniformity_bomb` | What to set [`'bomb'`](http://vimdoc.sourceforge.net/htmldoc/options.html#'bomb') to 110 | `g:uniformity_fileencoding` | What to set [`'fileencoding'`](http://vimdoc.sourceforge.net/htmldoc/options.html#'fileencoding') to 111 | `g:uniformity_fileformat` | What to set [`'fileformat'`](http://vimdoc.sourceforge.net/htmldoc/options.html#'fileformat') to 112 | 113 | #### Usage 114 | 115 | To update the whitespace formatting in a single file, run: 116 | 117 | :Uniform 118 | 119 | If the changes look good, save the file: 120 | 121 | :update 122 | 123 | To update all the files in a project, we can use 124 | [`:argdo`](http://vimdoc.sourceforge.net/htmldoc/editing.html#:argdo). First 125 | [`:lcd`](http://vimdoc.sourceforge.net/htmldoc/editing.html#:lcd) to the 126 | project directory, then add all the files you're interested to the [*argument 127 | list*](http://vimdoc.sourceforge.net/htmldoc/editing.html#argument-list) with 128 | something like: 129 | 130 | :args **\*.c **\*.h 131 | 132 | (Replace `*.c` and `*.h` with the extensions of the files that you are 133 | interested in.) 134 | 135 | To incrementally build up the *argument list*, check out 136 | [`:argadd`](http://vimdoc.sourceforge.net/htmldoc/editing.html#:argadd). To 137 | exclude specific files or directories, check out 138 | [`:argdelete`](http://vimdoc.sourceforge.net/htmldoc/editing.html#:argdelete). 139 | You can view the contents of the *argument list* at any time by running 140 | [`:args`](http://vimdoc.sourceforge.net/htmldoc/editing.html#:args). 141 | 142 | Once you are satisifed that the *argument list* contains all the files you want 143 | to act on, run: 144 | 145 | :argdo Uniform 146 | :argdo update 147 | 148 | These commands will run through every file in the *argument list*, update the 149 | whitespace in every file, then save all the files. 150 | 151 | __Tip__: if you have a lot of files and you don't want to be prompted after 152 | every screenful of results, try [`:set 153 | nomore`](http://vimdoc.sourceforge.net/htmldoc/options.html#'more') 154 | 155 | If you find `:argdo` cumbersome, you could also try 156 | [`:bufdo`](http://vimdoc.sourceforge.net/htmldoc/windows.html#:bufdo), 157 | [`:tabdo`](http://vimdoc.sourceforge.net/htmldoc/tabpage.html#:tabdo) or 158 | [`:windo`](http://vimdoc.sourceforge.net/htmldoc/windows.html#:windo). Or 159 | better yet, write a plugin that does it better and I will gladly update this 160 | README to point to it. 161 | 162 | ### Notes 163 | 164 | #### Why Vim? 165 | 166 | When writing a tool for batch processing a bunch of files, I typically don't 167 | reach for a graphical/visual app like Vim as my first choice. However, Vim 168 | offers so much needed functionality out-of-the-box, [I can't imagine a simpler 169 | way to get the same 170 | functionality](https://github.com/mkropat/vim-uniformity/blob/master/autoload/uniformity.vim): 171 | 172 | - Vim has tried-and-true support for loading in files in any number of combinations of line endings and file encodings 173 | - Vim has a workable, albeit clunky, means for working with all the files in a project (`:argdo`, etc.) 174 | - With [__sleuth.vim__](https://github.com/tpope/vim-sleuth), Vim has a tested library for auto-detecting the indentation settings of a file 175 | - Vim works cross-platform 176 | -------------------------------------------------------------------------------- /autoload/uniformity.vim: -------------------------------------------------------------------------------- 1 | function! uniformity#Uniform() abort 2 | if exists('g:uniformity_bomb') 3 | call setbufvar('', '&bomb', g:uniformity_bomb) 4 | endif 5 | 6 | if exists('g:uniformity_fileencoding') 7 | call setbufvar('', '&fileencoding', g:uniformity_fileencoding) 8 | endif 9 | 10 | if exists('g:uniformity_fileformat') 11 | call setbufvar('', '&fileformat', g:uniformity_fileformat) 12 | endif 13 | 14 | let do_indent = exists('g:uniformity_indent') && strlen(g:uniformity_indent) 15 | let do_trailing = exists('g:uniformity_strip_trailing_whitespace') && g:uniformity_strip_trailing_whitespace 16 | let do_zerowidth = exists('g:uniformity_strip_zerowidth_chars') && g:uniformity_strip_zerowidth_chars 17 | 18 | for lnum in range(1, line('$')) 19 | let line = getline(lnum) 20 | 21 | if do_indent 22 | let line = s:ReplaceLineIndent(line, &shiftwidth, g:uniformity_indent) 23 | endif 24 | 25 | if do_trailing 26 | let line = s:StripTrailingWhitespace(line) 27 | endif 28 | 29 | if do_zerowidth 30 | let line = s:StripZerowidthChars(line) 31 | endif 32 | 33 | call setline(lnum, line) 34 | endfor 35 | 36 | if do_indent 37 | call setbufvar('', '&shiftwidth', s:GetWhitespaceLength(g:uniformity_indent)) 38 | endif 39 | endfunction 40 | 41 | function! s:ReplaceLineIndent(line, buf_indent_length, target_indent) 42 | let leading_length = s:GetWhitespaceLength(matchstr(a:line, '^\s*')) 43 | 44 | let depth = leading_length / a:buf_indent_length 45 | let remainder = leading_length % a:buf_indent_length 46 | 47 | let new_indent = repeat(a:target_indent, depth) . repeat(' ', remainder) 48 | 49 | return substitute(a:line, '^\s*', new_indent, '') 50 | endfunction 51 | 52 | function! s:StripTrailingWhitespace(line) 53 | return substitute(a:line, '\s*\r*$', '', '') 54 | endfunction 55 | 56 | function! s:StripZerowidthChars(line) 57 | return substitute(a:line, '[​‌‍]', '', 'g') 58 | endfunction 59 | 60 | function! s:GetWhitespaceLength(whitespace) 61 | return strlen(substitute(a:whitespace, ' ', repeat(' ', &tabstop), 'g')) 62 | endfunction 63 | -------------------------------------------------------------------------------- /plugin/uniformity.vim: -------------------------------------------------------------------------------- 1 | command! Uniform call uniformity#Uniform() 2 | --------------------------------------------------------------------------------