1
0
mirror of https://github.com/amix/vimrc synced 2025-07-06 16:05:01 +08:00

Merge branch 'pr/2'

This commit is contained in:
geezuslucifer@gmail.com
2020-03-20 10:10:45 -05:00
1315 changed files with 30338 additions and 18193 deletions

View File

@ -1,6 +1,6 @@
## vim-gitgutter
A Vim plugin which shows a git diff in the 'gutter' (sign column). It shows which lines have been added, modified, or removed. You can also preview, stage, and undo individual hunks. The plugin also provides a hunk text object.
A Vim plugin which shows a git diff in the 'gutter' (sign column). It shows which lines have been added, modified, or removed. You can also preview, stage, and undo individual hunks; and stage partial hunks. The plugin also provides a hunk text object.
The signs are always up to date and the plugin never saves your buffer.
@ -12,12 +12,17 @@ Features:
* Never saves the buffer.
* Quick jumping between blocks of changed lines ("hunks").
* Stage/undo/preview individual hunks.
* Previews highlight intra-line changes.
* Stage partial hunks.
* Provides a hunk text object.
* Diffs against index (default) or any commit.
* Allows folding all unchanged text.
* Provides fold text showing whether folded lines have been changed.
* Can load all hunk locations into quickfix list or the current window's location list.
* Handles line endings correctly, even with repos that do CRLF conversion.
* Optional line highlighting.
* Fully customisable (signs, sign column, line highlights, mappings, extra git-diff arguments, etc).
* Optional line number highlighting. (Only available in Neovim 0.3.2 or higher)
* Fully customisable (signs, sign column, line (number) highlights, mappings, extra git-diff arguments, etc).
* Can be toggled on/off, globally or per buffer.
* Preserves signs from other plugins.
* Easy to integrate diff stats into status line; built-in integration with [vim-airline](https://github.com/bling/vim-airline/).
@ -31,81 +36,53 @@ Constraints:
### Screenshot
![screenshot](https://raw.github.com/airblade/vim-gitgutter/master/screenshot.png)
![screenshot](./screenshot.png?raw=true)
In the screenshot above you can see:
* Line 15 has been modified.
* Lines 21-24 are new.
* A line or lines were removed between lines 25 and 26.
* Lines 183-184 are new.
* Lines 186-187 have been modified.
* The preview for the modified lines highlights changed regions within the line.
### Installation
Before installation, please check your Vim supports signs by running `:echo has('signs')`. `1` means you're all set; `0` means you need to install a Vim with signs support. If you're compiling Vim yourself you need the 'big' or 'huge' feature set. MacVim supports signs.
Install using your favourite package manager, or use Vim's built-in package support.
You install vim-gitgutter like any other vim plugin.
##### Pathogen
Vim:
```
cd ~/.vim/bundle
git clone git://github.com/airblade/vim-gitgutter.git
mkdir -p ~/.vim/pack/airblade/start
cd ~/.vim/pack/airblade/start
git clone https://github.com/airblade/vim-gitgutter.git
vim -u NONE -c "helptags vim-gitgutter/doc" -c q
```
##### Voom
Neovim:
Edit your plugin manifest (`voom edit`) and add:
```
airblade/vim-gitgutter
mkdir -p ~/.config/nvim/pack/airblade/start
cd ~/.config/nvim/pack/airblade/start
git clone https://github.com/airblade/vim-gitgutter.git
nvim -u NONE -c "helptags vim-gitgutter/doc" -c q
```
##### VimPlug
Place this in your .vimrc:
### Windows
I recommend configuring vim-gitgutter with the full path to your git executable. For example:
```viml
Plug 'airblade/vim-gitgutter'
let g:gitgutter_git_executable = 'C:\Program Files\Git\bin\git.exe'
```
Then run the following in Vim:
```
:source %
:PlugInstall
```
##### NeoBundle
Place this in your .vimrc:
```viml
NeoBundle 'airblade/vim-gitgutter'
```
Then run the following in Vim:
```
:source %
:NeoBundleInstall
```
##### No plugin manager
Copy vim-gitgutter's subdirectories into your vim configuration directory:
```
cd /tmp && git clone git://github.com/airblade/vim-gitgutter.git
cp -r vim-gitgutter/* ~/.vim/
```
See `:help add-global-plugin`.
This is to avoid a problem which occurs if you have file named `git.*` (i.e. with any extension in `PATHEXT`) in your current folder. `cmd.exe` prioritises the current folder over folders in `PATH` and will try to execute your file instead of the `git` binary.
### Getting started
When you make a change to a file tracked by git, the diff markers should appear automatically. The delay is governed by vim's `updatetime` option; the default value is `4000`, i.e. 4 seconds, but I suggest reducing it to around 100ms (add `set updatetime=100` to your vimrc).
When you make a change to a file tracked by git, the diff markers should appear automatically. The delay is governed by vim's `updatetime` option; the default value is `4000`, i.e. 4 seconds, but I suggest reducing it to around 100ms (add `set updatetime=100` to your vimrc). Note `updatetime` also controls the delay before vim writes its swap file (see `:help updatetime`).
You can jump between hunks with `[c` and `]c`. You can preview, stage, and undo hunks with `<leader>hp`, `<leader>hs`, and `<leader>hu` respectively.
@ -138,9 +115,17 @@ And you can turn line highlighting on and off (defaults to off):
* turn off with `:GitGutterLineHighlightsDisable`
* toggle with `:GitGutterLineHighlightsToggle`.
Note that if you have line highlighting on and signs off, you will have an empty sign column more accurately, a sign column with invisible signs. This is because line highlighting requires signs and Vim always shows the sign column even if the signs are invisible.
Note that if you have line highlighting on and signs off, you will have an empty sign column more accurately, a sign column with invisible signs. This is because line highlighting requires signs and Vim/NeoVim always shows the sign column when there are signs even if the signs are invisible.
If you switch off both line highlighting and signs, you won't see the sign column. That is unless you configure the sign column always to be there (see Sign Column section).
With Neovim 0.3.2 or higher, you can turn line number highlighting on and off (defaults to off):
* turn on with `:GitGutterLineNrHighlightsEnable`
* turn off with `:GitGutterLineNrHighlightsDisable`
* toggle with `:GitGutterLineNrHighlightsToggle`.
The same caveat applies to line number highlighting as to line highlighting just above.
If you switch off both line highlighting and signs, you won't see the sign column.
To keep your Vim snappy, vim-gitgutter will suppress the signs when a file has more than 500 changes. As soon as the number of changes falls below the limit vim-gitgutter will show the signs again. You can configure the threshold with:
@ -160,30 +145,46 @@ Both of those take a preceding count.
To set your own mappings for these, for example `]h` and `[h`:
```viml
nmap ]h <Plug>GitGutterNextHunk
nmap [h <Plug>GitGutterPrevHunk
nmap ]h <Plug>(GitGutterNextHunk)
nmap [h <Plug>(GitGutterPrevHunk)
```
You can load all your hunks into the quickfix list with `:GitGutterQuickFix`. Note this ignores any unsaved changes in your buffers. If the option `g:gitgutter_use_location_list` is set, this command will load hunks into the current window's location list instead.
You can stage or undo an individual hunk when your cursor is in it:
* stage the hunk with `<Leader>hs` or
* undo it with `<Leader>hu`.
To stage part of an additions-only hunk by:
* either visually selecting the part you want and staging with your mapping, e.g. `<Leader>hs`;
* or using a range with the `GitGutterStageHunk` command, e.g. `:42,45GitGutterStageHunk`.
To stage part of any hunk:
* preview the hunk, e.g. `<Leader>hp`;
* move to the preview window, e.g. `:wincmd P`;
* delete the lines you do not want to stage;
* stage the remaining lines: either write (`:w`) the window or stage via `<Leader>hs` or `:GitGutterStageHunk`.
Note the above workflow is not possible if you have opted in to preview hunks with Vim's popup windows.
See the FAQ if you want to unstage staged changes.
The `.` command will work with both these if you install [repeat.vim](https://github.com/tpope/vim-repeat).
To set your own mappings for these, for example if you prefer the mnemonics hunk-add and hunk-revert:
To set your own mappings for these, for example if you prefer `g`-based maps:
```viml
nmap <Leader>ha <Plug>GitGutterStageHunk
nmap <Leader>hr <Plug>GitGutterUndoHunk
nmap ghs <Plug>(GitGutterStageHunk)
nmap ghu <Plug>(GitGutterUndoHunk)
```
And you can preview a hunk's changes with `<Leader>hp`. You can of course change this mapping, e.g:
And you can preview a hunk's changes with `<Leader>hp`. The location of the preview window is configured with `g:gitgutter_preview_win_location` (default `'bo'`). You can of course change this mapping, e.g:
```viml
nmap <Leader>hv <Plug>GitGutterPreviewHunk
nmap ghp <Plug>(GitGutterPreviewHunk)
```
A hunk text object is provided which works in visual and operator-pending modes.
@ -194,10 +195,10 @@ A hunk text object is provided which works in visual and operator-pending modes.
To re-map these, for example to `ih` and `ah`:
```viml
omap ih <Plug>GitGutterTextObjectInnerPending
omap ah <Plug>GitGutterTextObjectOuterPending
xmap ih <Plug>GitGutterTextObjectInnerVisual
xmap ah <Plug>GitGutterTextObjectOuterVisual
omap ih <Plug>(GitGutterTextObjectInnerPending)
omap ah <Plug>(GitGutterTextObjectOuterPending)
xmap ih <Plug>(GitGutterTextObjectInnerVisual)
xmap ah <Plug>(GitGutterTextObjectOuterVisual)
```
If you don't want vim-gitgutter to set up any mappings at all, use this:
@ -217,6 +218,35 @@ Use the `GitGutterFold` command to fold all unchanged lines, leaving just the hu
Execute `GitGutterFold` a second time to restore the previous view.
Use `gitgutter#fold#foldtext()` to augment the default `foldtext()` with an indicator of whether the folded lines have been changed.
```viml
set foldtext=gitgutter#fold#foldtext()
```
For a closed fold with changed lines:
```
Default foldtext(): +-- 45 lines: abcdef
gitgutter#fold#foldtext(): +-- 45 lines (*): abcdef
```
You can use `gitgutter#fold#is_changed()` in your own `foldtext` expression to find out whether the folded lines have been changed.
### Status line
Call the `GitGutterGetHunkSummary()` function from your status line to get a list of counts of added, modified, and removed lines in the current buffer. For example:
```viml
" Your vimrc
function! GitStatus()
let [a,m,r] = GitGutterGetHunkSummary()
return printf('+%d ~%d -%d', a, m, r)
endfunction
set statusline+=%{GitStatus()}
```
### Customisation
@ -224,18 +254,23 @@ You can customise:
* The sign column's colours
* Whether or not the sign column is shown when there aren't any signs (defaults to no)
* How to handle non-gitgutter signs
* The signs' colours and symbols
* Line highlights
* Whether the diff is relative to the index (default) or working tree.
* The base of the diff
* Extra arguments for `git` when running `git diff`
* Extra arguments for `git diff`
* Key mappings
* Whether or not vim-gitgutter is on initially (defaults to on)
* Whether or not signs are shown (defaults to yes)
* Whether or not line highlighting is on initially (defaults to off)
* Whether or not vim-gitgutter runs in "realtime" (defaults to yes)
* Whether or not vim-gitgutter runs eagerly (defaults to yes)
* Whether or not vim-gitgutter runs asynchronously (defaults to yes)
* Whether vim-gitgutter is on initially (defaults to on)
* Whether signs are shown (defaults to yes)
* Whether line highlighting is on initially (defaults to off)
* Whether line number highlighting is on initially (defaults to off)
* Whether vim-gitgutter runs asynchronously (defaults to yes)
* Whether to clobber or preserve non-gitgutter signs
* The priority of gitgutter's signs.
* Whether to use a floating/popup window for hunk previews
* Whether to populate the quickfix list or a location list with all hunks
Please note that vim-gitgutter won't override any colours or highlights you've set in your colorscheme.
@ -260,11 +295,14 @@ highlight SignColumn guibg=whatever " gVim/MacVim
By default the sign column will appear when there are signs to show and disappear when there aren't. To always have the sign column, add to your vimrc:
```viml
if exists('&signcolumn') " Vim 7.4.2201
set signcolumn=yes
else
let g:gitgutter_sign_column_always = 1
endif
" Vim 7.4.2201
set signcolumn=yes
```
GitGutter can preserve or ignore non-gitgutter signs. For Vim v8.1.0614 and later you can set gitgutter's signs' priorities with `g:gitgutter_sign_priority`, so gitgutter defaults to clobbering other signs. For Neovim v0.4.0 and later you can set an expanding sign column so gitgutter again defaults to clobbering other signs. Otherwise, gitgutter defaults to preserving other signs. You can configure this with:
```viml
let g:gitgutter_sign_allow_clobber = 1
```
@ -324,6 +362,35 @@ highlight link GitGutterChangeLine DiffText
```
#### Line number highlights
NOTE: This feature requires Neovim 0.3.2 or higher.
Similarly to the signs' colours, set up the following highlight groups in your colorscheme or `~/.vimrc`:
```viml
GitGutterAddLineNr " default: links to CursorLineNr
GitGutterChangeLineNr " default: links to CursorLineNr
GitGutterDeleteLineNr " default: links to CursorLineNr
GitGutterChangeDeleteLineNr " default: links to CursorLineNr
```
Maybe you think `CursorLineNr` is a bit annoying. For example, you could use `Underlined` for this:
```viml
highlight link GitGutterChangeLineNr Underlined
```
#### Whether the diff is relative to the index or working tree
By default diffs are relative to the index. How you can make them relative to the working tree:
```viml
let g:gitgutter_diff_relative_to = 'working_tree'
```
#### The base of the diff
By default buffers are diffed against the index. However you can diff against any commit by setting:
@ -332,6 +399,8 @@ By default buffers are diffed against the index. However you can diff against a
let g:gitgutter_diff_base = '<commit SHA>'
```
This setting is ignored when the diffs are relative to the working tree.
#### Extra arguments for `git` when running `git diff`
@ -384,6 +453,11 @@ Add `let g:gitgutter_signs = 0` to your `~/.vimrc`.
Add `let g:gitgutter_highlight_lines = 1` to your `~/.vimrc`.
#### To turn on line number highlighting by default
Add `let g:gitgutter_highlight_linenrs = 1` to your `~/.vimrc`.
#### To turn off asynchronous updates
By default diffs are run asynchronously. To run diffs synchronously instead:
@ -393,6 +467,16 @@ let g:gitgutter_async = 0
```
#### To use floating/popup windows for hunk previews
Add `let g:gitgutter_preview_win_floating = 1` to your `~/.vimrc`. Note that on Vim this prevents you staging (partial) hunks via the preview window.
#### To load all hunks into the current window's location list instead of the quickfix list
Add `let g:gitgutter_use_location_list = 1` to your `~/.vimrc`.
### Extensions
#### Operate on every line in a hunk
@ -451,9 +535,27 @@ Let's say, for example, you want to remove trailing whitespace from all changed
```
#### Cycle through hunks in current buffer
This is like `:GitGutterNextHunk` but when it gets to the last hunk in the buffer it cycles around to the first.
```viml
function! GitGutterNextHunkCycle()
let line = line('.')
silent! GitGutterNextHunk
if line('.') == line
1
GitGutterNextHunk
endif
endfunction
```
#### Cycle through hunks in all buffers
`]c` and `[c` jump from one hunk to the next in the current buffer. You can use this code to jump to the next hunk no matter which buffer it's in.
You can use `:GitGutterQuickFix` to load all hunks into the quickfix list or the current window's location list.
Alternatively, given that`]c` and `[c` jump from one hunk to the next in the current buffer, you can use this code to jump to the next hunk no matter which buffer it's in.
```viml
function! NextHunkAllBuffers()
@ -470,7 +572,7 @@ function! NextHunkAllBuffers()
return
endif
if !empty(GitGutterGetHunks())
normal! 1G
1
GitGutterNextHunk
return
endif
@ -524,15 +626,25 @@ autocmd BufWritePost * GitGutter
> Why can't I unstage staged changes?
This plugin is for showing changes between the working tree and the index (and staging/undoing those changes). Unstaging a staged hunk would require showing changes between the index and HEAD, which is out of scope.
This plugin is for showing changes between the buffer and the index (and staging/undoing those changes). Unstaging a staged hunk would require showing changes between the index and HEAD, which is out of scope.
> Why are the colours in the sign column weird?
Your colorscheme is configuring the `SignColumn` highlight group weirdly. Please see the section above on customising the sign column.
> Why are the colours in the preview window weird?
Probably because your colourscheme doesn't configure the `diff{Added,Changed,Removed}` highlight groups. Try this in `after/syntax/diff.vim`:
```viml
highlight link diffAdded DiffAdd
highlight link diffChanged DiffChange
highlight link diffRemoved DiffDelete
```
> What happens if I also use another plugin which uses signs (e.g. Syntastic)?
Vim only allows one sign per line. Before adding a sign to a line, vim-gitgutter checks whether a sign has already been added by somebody else. If so it doesn't do anything. In other words vim-gitgutter won't overwrite another plugin's signs. It also won't remove another plugin's signs.
You can configure whether GitGutter preserves or clobbers other signs using `g:gitgutter_sign_allow_clobber`. Set to `1` to clobber other signs (default on Vim >= 8.1.0614 and NeoVim >= 0.4.0) or `0` to preserve them.
### Troubleshooting
@ -553,7 +665,7 @@ Here are some things you can check:
#### When signs take a few seconds to appear
* Try reducing `updatetime`, e.g. `set updatetime=100`.
* Try reducing `updatetime`, e.g. `set updatetime=100`. Note this also controls the delay before vim writes its swap file.
#### When signs don't update after focusing Vim

View File

@ -25,8 +25,11 @@ function! gitgutter#process_buffer(bufnr, force) abort
if gitgutter#utility#is_active(a:bufnr)
<<<<<<< HEAD
call s:setup_maps(a:bufnr)
=======
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
if has('patch-7.4.1559')
let l:Callback = function('gitgutter#process_buffer', [a:bufnr, a:force])
else
@ -41,7 +44,7 @@ function! gitgutter#process_buffer(bufnr, force) abort
let diff = ''
try
let diff = gitgutter#diff#run_diff(a:bufnr, 'index', 0)
let diff = gitgutter#diff#run_diff(a:bufnr, g:gitgutter_diff_relative_to, 0)
catch /gitgutter not tracked/
call gitgutter#debug#log('Not tracked: '.gitgutter#utility#file(a:bufnr))
catch /gitgutter diff failed/
@ -108,45 +111,76 @@ endfunction
" }}}
<<<<<<< HEAD
function! s:setup_maps(bufnr)
=======
function! gitgutter#setup_maps()
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
if !g:gitgutter_map_keys
return
endif
<<<<<<< HEAD
if gitgutter#utility#getbufvar(a:bufnr, 'mapped', 0)
return
endif
if !hasmapto('<Plug>GitGutterPrevHunk') && maparg('[c', 'n') ==# ''
nmap <buffer> [c <Plug>GitGutterPrevHunk
endif
if !hasmapto('<Plug>GitGutterNextHunk') && maparg(']c', 'n') ==# ''
nmap <buffer> ]c <Plug>GitGutterNextHunk
=======
" Note hasmapto() and maparg() operate on the current buffer.
let bufnr = bufnr('')
if gitgutter#utility#getbufvar(bufnr, 'mapped', 0)
return
endif
if !hasmapto('<Plug>GitGutterStageHunk') && maparg('<Leader>hs', 'n') ==# ''
nmap <buffer> <Leader>hs <Plug>GitGutterStageHunk
if !hasmapto('<Plug>(GitGutterPrevHunk)') && maparg('[c', 'n') ==# ''
nmap <buffer> [c <Plug>(GitGutterPrevHunk)
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endif
if !hasmapto('<Plug>GitGutterUndoHunk') && maparg('<Leader>hu', 'n') ==# ''
nmap <buffer> <Leader>hu <Plug>GitGutterUndoHunk
endif
if !hasmapto('<Plug>GitGutterPreviewHunk') && maparg('<Leader>hp', 'n') ==# ''
nmap <buffer> <Leader>hp <Plug>GitGutterPreviewHunk
if !hasmapto('<Plug>(GitGutterNextHunk)') && maparg(']c', 'n') ==# ''
nmap <buffer> ]c <Plug>(GitGutterNextHunk)
endif
if !hasmapto('<Plug>GitGutterTextObjectInnerPending') && maparg('ic', 'o') ==# ''
omap <buffer> ic <Plug>GitGutterTextObjectInnerPending
if !hasmapto('<Plug>(GitGutterStageHunk)', 'v') && maparg('<Leader>hs', 'x') ==# ''
xmap <buffer> <Leader>hs <Plug>(GitGutterStageHunk)
endif
if !hasmapto('<Plug>GitGutterTextObjectOuterPending') && maparg('ac', 'o') ==# ''
omap <buffer> ac <Plug>GitGutterTextObjectOuterPending
if !hasmapto('<Plug>(GitGutterStageHunk)', 'n') && maparg('<Leader>hs', 'n') ==# ''
nmap <buffer> <Leader>hs <Plug>(GitGutterStageHunk)
endif
if !hasmapto('<Plug>GitGutterTextObjectInnerVisual') && maparg('ic', 'x') ==# ''
xmap <buffer> ic <Plug>GitGutterTextObjectInnerVisual
if !hasmapto('<Plug>(GitGutterUndoHunk)') && maparg('<Leader>hu', 'n') ==# ''
nmap <buffer> <Leader>hu <Plug>(GitGutterUndoHunk)
endif
if !hasmapto('<Plug>GitGutterTextObjectOuterVisual') && maparg('ac', 'x') ==# ''
xmap <buffer> ac <Plug>GitGutterTextObjectOuterVisual
if !hasmapto('<Plug>(GitGutterPreviewHunk)') && maparg('<Leader>hp', 'n') ==# ''
nmap <buffer> <Leader>hp <Plug>(GitGutterPreviewHunk)
endif
if !hasmapto('<Plug>(GitGutterTextObjectInnerPending)') && maparg('ic', 'o') ==# ''
omap <buffer> ic <Plug>(GitGutterTextObjectInnerPending)
endif
if !hasmapto('<Plug>(GitGutterTextObjectOuterPending)') && maparg('ac', 'o') ==# ''
omap <buffer> ac <Plug>(GitGutterTextObjectOuterPending)
endif
if !hasmapto('<Plug>(GitGutterTextObjectInnerVisual)') && maparg('ic', 'x') ==# ''
xmap <buffer> ic <Plug>(GitGutterTextObjectInnerVisual)
endif
if !hasmapto('<Plug>(GitGutterTextObjectOuterVisual)') && maparg('ac', 'x') ==# ''
xmap <buffer> ac <Plug>(GitGutterTextObjectOuterVisual)
endif
call gitgutter#utility#setbufvar(bufnr, 'mapped', 1)
endfunction
function! s:setup_path(bufnr, continuation)
let p = gitgutter#utility#repo_path(a:bufnr, 0)
if type(p) == s:t_string && !empty(p) " if path is known
return
endif
<<<<<<< HEAD
call gitgutter#utility#setbufvar(a:bufnr, 'mapped', 1)
endfunction
@ -157,6 +191,8 @@ function! s:setup_path(bufnr, continuation)
return
endif
=======
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
return gitgutter#utility#set_repo_path(a:bufnr, a:continuation)
endfunction
@ -170,8 +206,44 @@ endfunction
function! s:clear(bufnr)
call gitgutter#sign#clear_signs(a:bufnr)
call gitgutter#sign#remove_dummy_sign(a:bufnr, 1)
call gitgutter#hunk#reset(a:bufnr)
call s:reset_tick(a:bufnr)
call gitgutter#utility#setbufvar(a:bufnr, 'path', '')
<<<<<<< HEAD
=======
endfunction
" Note:
" - this runs synchronously
" - it ignores unsaved changes in buffers
" - it does not change to the repo root
function! gitgutter#quickfix()
let locations = []
let cmd = g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager '.g:gitgutter_git_args.
\ ' diff --no-ext-diff --no-color -U0 '.g:gitgutter_diff_args
let diff = systemlist(cmd)
let lnum = 0
for line in diff
if line =~ '^diff --git [^"]'
let paths = line[11:]
let mid = (len(paths) - 1) / 2
let [fnamel, fnamer] = [paths[:mid-1], paths[mid+1:]]
let fname = fnamel ==# fnamer ? fnamel : fnamel[2:]
elseif line =~ '^diff --git "'
let [_, fnamel, _, fnamer] = split(line, '"')
let fname = fnamel ==# fnamer ? fnamel : fnamel[2:]
elseif line =~ '^@@'
let lnum = matchlist(line, '+\(\d\+\)')[1]
elseif lnum > 0
call add(locations, {'filename': fname, 'lnum': lnum, 'text': line})
let lnum = 0
endif
endfor
if !g:gitgutter_use_location_list
call setqflist(locations)
else
call setloclist(0, locations)
endif
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction

View File

@ -4,7 +4,11 @@ let s:hunk_re = '^@@ -\(\d\+\),\?\(\d*\) +\(\d\+\),\?\(\d*\) @@'
" True for git v1.7.2+.
function! s:git_supports_command_line_config_override() abort
<<<<<<< HEAD
call system(g:gitgutter_git_executable.' '.g:gitgutter_git_args.' -c foo.bar=baz --version')
=======
call gitgutter#utility#system(g:gitgutter_git_executable.' '.g:gitgutter_git_args.' -c foo.bar=baz --version')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
return !v:shell_error
endfunction
@ -187,7 +191,7 @@ function! gitgutter#diff#handler(bufnr, diff) abort
call gitgutter#sign#clear_signs(a:bufnr)
else
if g:gitgutter_signs || g:gitgutter_highlight_lines
if g:gitgutter_signs || g:gitgutter_highlight_lines || g:gitgutter_highlight_linenrs
call gitgutter#sign#update_signs(a:bufnr, modified_lines)
endif
endif
@ -385,6 +389,10 @@ function! s:write_buffer(bufnr, file)
call map(bufcontents, 'v:val."\r"')
endif
if getbufvar(a:bufnr, '&endofline')
call add(bufcontents, '')
endif
let fenc = getbufvar(a:bufnr, '&fileencoding')
if fenc !=# &encoding
call map(bufcontents, 'iconv(v:val, &encoding, "'.fenc.'")')
@ -394,7 +402,7 @@ function! s:write_buffer(bufnr, file)
let bufcontents[0]=''.bufcontents[0]
endif
call writefile(bufcontents, a:file)
call writefile(bufcontents, a:file, 'b')
endfunction

View File

@ -0,0 +1,225 @@
" This is the minimum number of characters required between regions of change
" in a line. It's somewhat arbitrary: higher values mean less visual busyness;
" lower values mean more detail.
let s:gap_between_regions = 5
" Calculates the changed portions of lines.
"
" Based on:
"
" - diff-highlight (included with git)
" https://github.com/git/git/blob/master/contrib/diff-highlight/DiffHighlight.pm
"
" - Diff Strategies, Neil Fraser
" https://neil.fraser.name/writing/diff/
" Returns a list of intra-line changed regions.
" Each element is a list:
"
" [
" line number (1-based),
" type ('+' or '-'),
" start column (1-based, inclusive),
" stop column (1-based, inclusive),
" ]
"
" Args:
" hunk_body - list of lines
function! gitgutter#diff_highlight#process(hunk_body)
" Check whether we have the same number of lines added as removed.
let [removed, added] = [0, 0]
for line in a:hunk_body
if line[0] == '-'
let removed += 1
elseif line[0] == '+'
let added += 1
endif
endfor
if removed != added
return []
endif
let regions = []
for i in range(removed)
" pair lines by position
let rline = a:hunk_body[i]
let aline = a:hunk_body[i + removed]
call s:diff(rline, aline, i, i+removed, 0, 0, regions, 1)
endfor
return regions
endfunction
function! s:diff(rline, aline, rlinenr, alinenr, rprefix, aprefix, regions, whole_line)
" diff marker does not count as a difference in prefix
let start = a:whole_line ? 1 : 0
let prefix = s:common_prefix(a:rline[start:], a:aline[start:])
if a:whole_line
let prefix += 1
endif
let [rsuffix, asuffix] = s:common_suffix(a:rline, a:aline, prefix+1)
" region of change (common prefix and suffix removed)
let rtext = a:rline[prefix+1:rsuffix-1]
let atext = a:aline[prefix+1:asuffix-1]
" singular insertion
if empty(rtext)
if !a:whole_line || len(atext) != len(a:aline) " not whole line
call add(a:regions, [a:alinenr+1, '+', a:aprefix+prefix+1+1, a:aprefix+asuffix+1-1])
endif
return
endif
" singular deletion
if empty(atext)
if !a:whole_line || len(rtext) != len(a:rline) " not whole line
call add(a:regions, [a:rlinenr+1, '-', a:rprefix+prefix+1+1, a:rprefix+rsuffix+1-1])
endif
return
endif
" two insertions
let j = stridx(atext, rtext)
if j != -1
call add(a:regions, [a:alinenr+1, '+', a:aprefix+prefix+1+1, a:aprefix+prefix+j+1])
call add(a:regions, [a:alinenr+1, '+', a:aprefix+prefix+1+1+j+len(rtext), a:aprefix+asuffix+1-1])
return
endif
" two deletions
let j = stridx(rtext, atext)
if j != -1
call add(a:regions, [a:rlinenr+1, '-', a:rprefix+prefix+1+1, a:rprefix+prefix+j+1])
call add(a:regions, [a:rlinenr+1, '-', a:rprefix+prefix+1+1+j+len(atext), a:rprefix+rsuffix+1-1])
return
endif
" two edits
let lcs = s:lcs(rtext, atext)
" TODO do we need to ensure we don't get more than 2 elements when splitting?
if len(lcs) > s:gap_between_regions
let redits = s:split(rtext, lcs)
let aedits = s:split(atext, lcs)
call s:diff(redits[0], aedits[0], a:rlinenr, a:alinenr, a:rprefix+prefix+1, a:aprefix+prefix+1, a:regions, 0)
call s:diff(redits[1], aedits[1], a:rlinenr, a:alinenr, a:rprefix+prefix+1+len(redits[0])+len(lcs), a:aprefix+prefix+1+len(aedits[0])+len(lcs), a:regions, 0)
return
endif
" fall back to highlighting entire changed area
" if a change (but not the whole line)
if !a:whole_line || ((prefix != 0 || rsuffix != len(a:rline)) && prefix+1 < rsuffix)
call add(a:regions, [a:rlinenr+1, '-', a:rprefix+prefix+1+1, a:rprefix+rsuffix+1-1])
endif
" if a change (but not the whole line)
if !a:whole_line || ((prefix != 0 || asuffix != len(a:aline)) && prefix+1 < asuffix)
call add(a:regions, [a:alinenr+1, '+', a:aprefix+prefix+1+1, a:aprefix+asuffix+1-1])
endif
endfunction
function! s:lcs(s1, s2)
if empty(a:s1) || empty(a:s2)
return ''
endif
let matrix = map(repeat([repeat([0], len(a:s2)+1)], len(a:s1)+1), 'copy(v:val)')
let maxlength = 0
let endindex = len(a:s1)
for i in range(1, len(a:s1))
for j in range(1, len(a:s2))
if a:s1[i-1] ==# a:s2[j-1]
let matrix[i][j] = 1 + matrix[i-1][j-1]
if matrix[i][j] > maxlength
let maxlength = matrix[i][j]
let endindex = i - 1
endif
endif
endfor
endfor
return a:s1[endindex - maxlength + 1 : endindex]
endfunction
if $VIM_GITGUTTER_TEST
function! gitgutter#diff_highlight#lcs(s1, s2)
return s:lcs(a:s1, a:s2)
endfunction
endif
" Returns 0-based index of last character of common prefix
" If there is no common prefix, returns -1.
"
" a, b - strings
"
function! s:common_prefix(a, b)
let len = min([len(a:a), len(a:b)])
if len == 0
return -1
endif
for i in range(len)
if a:a[i:i] != a:b[i:i]
return i - 1
endif
endfor
return i
endfunction
if $VIM_GITGUTTER_TEST
function! gitgutter#diff_highlight#common_prefix(a, b)
return s:common_prefix(a:a, a:b)
endfunction
endif
" Returns 0-based indices of start of common suffix
"
" a, b - strings
" start - 0-based index to start from
function! s:common_suffix(a, b, start)
let [sa, sb] = [len(a:a), len(a:b)]
while sa >= a:start && sb >= a:start
if a:a[sa] ==# a:b[sb]
let sa -= 1
let sb -= 1
else
break
endif
endwhile
return [sa+1, sb+1]
endfunction
if $VIM_GITGUTTER_TEST
function! gitgutter#diff_highlight#common_suffix(a, b, start)
return s:common_suffix(a:a, a:b, a:start)
endfunction
endif
" Split a string on another string.
" Assumes 1 occurrence of the delimiter.
function! s:split(str, delimiter)
let i = stridx(a:str, a:delimiter)
if i == 0
return ['', a:str[len(a:delimiter):]]
endif
return [a:str[:i-1], a:str[i+len(a:delimiter):]]
endfunction
if $VIM_GITGUTTER_TEST
function! gitgutter#diff_highlight#split(str, delimiter)
return s:split(a:str, a:delimiter)
endfunction
endif

View File

@ -31,6 +31,37 @@ function! gitgutter#fold#level(lnum)
endfunction
function! gitgutter#fold#foldtext()
if !gitgutter#fold#is_changed()
return foldtext()
endif
return substitute(foldtext(), ':', ' (*):', '')
endfunction
" Returns 1 if any of the folded lines have been changed
" (added, removed, or modified), 0 otherwise.
function! gitgutter#fold#is_changed()
for hunk in gitgutter#hunk#hunks(bufnr(''))
let hunk_begin = hunk[2]
let hunk_end = hunk[2] + (hunk[3] == 0 ? 1 : hunk[3])
if hunk_end < v:foldstart
continue
endif
if hunk_begin > v:foldend
break
endif
return 1
endfor
return 0
endfunction
" A line in a hunk has a fold level of 0.
" A line within 3 lines of a hunk has a fold level of 1.
" All other lines have a fold level of 2.

View File

@ -4,7 +4,6 @@ function! gitgutter#highlight#line_disable() abort
if !g:gitgutter_signs
call gitgutter#sign#clear_signs(bufnr(''))
call gitgutter#sign#remove_dummy_sign(bufnr(''), 0)
endif
redraw!
@ -32,6 +31,39 @@ function! gitgutter#highlight#line_toggle() abort
endfunction
function! gitgutter#highlight#linenr_disable() abort
let g:gitgutter_highlight_linenrs = 0
call s:define_sign_linenr_highlights()
if !g:gitgutter_signs
call gitgutter#sign#clear_signs(bufnr(''))
endif
redraw!
endfunction
function! gitgutter#highlight#linenr_enable() abort
let old_highlight_linenrs = g:gitgutter_highlight_linenrs
let g:gitgutter_highlight_linenrs = 1
call s:define_sign_linenr_highlights()
if !old_highlight_linenrs && !g:gitgutter_signs
call gitgutter#all(1)
endif
redraw!
endfunction
function! gitgutter#highlight#linenr_toggle() abort
if g:gitgutter_highlight_linenrs
call gitgutter#highlight#linenr_disable()
else
call gitgutter#highlight#linenr_enable()
endif
endfunction
function! gitgutter#highlight#define_sign_column_highlight() abort
if g:gitgutter_override_sign_column_highlight
highlight! link SignColumn LineNr
@ -66,6 +98,15 @@ function! gitgutter#highlight#define_highlights() abort
highlight default link GitGutterChangeLine DiffChange
highlight default link GitGutterDeleteLine DiffDelete
highlight default link GitGutterChangeDeleteLine GitGutterChangeLine
highlight default link GitGutterAddLineNr CursorLineNr
highlight default link GitGutterChangeLineNr CursorLineNr
highlight default link GitGutterDeleteLineNr CursorLineNr
highlight default link GitGutterChangeDeleteLineNr CursorLineNr
" Highlights used intra line.
highlight GitGutterAddIntraLine gui=reverse cterm=reverse
highlight GitGutterDeleteIntraLine gui=reverse cterm=reverse
endfunction
function! gitgutter#highlight#define_signs() abort
@ -75,11 +116,11 @@ function! gitgutter#highlight#define_signs() abort
sign define GitGutterLineRemovedFirstLine
sign define GitGutterLineRemovedAboveAndBelow
sign define GitGutterLineModifiedRemoved
sign define GitGutterDummy
call s:define_sign_text()
call gitgutter#highlight#define_sign_text_highlights()
call s:define_sign_line_highlights()
call s:define_sign_linenr_highlights()
endfunction
function! s:define_sign_text() abort
@ -131,6 +172,32 @@ function! s:define_sign_line_highlights() abort
endif
endfunction
<<<<<<< HEAD
=======
function! s:define_sign_linenr_highlights() abort
if has('nvim-0.3.2')
try
if g:gitgutter_highlight_linenrs
sign define GitGutterLineAdded numhl=GitGutterAddLineNr
sign define GitGutterLineModified numhl=GitGutterChangeLineNr
sign define GitGutterLineRemoved numhl=GitGutterDeleteLineNr
sign define GitGutterLineRemovedFirstLine numhl=GitGutterDeleteLineNr
sign define GitGutterLineRemovedAboveAndBelow numhl=GitGutterDeleteLineNr
sign define GitGutterLineModifiedRemoved numhl=GitGutterChangeDeleteLineNr
else
sign define GitGutterLineAdded numhl=
sign define GitGutterLineModified numhl=
sign define GitGutterLineRemoved numhl=
sign define GitGutterLineRemovedFirstLine numhl=
sign define GitGutterLineRemovedAboveAndBelow numhl=
sign define GitGutterLineModifiedRemoved numhl=
endif
catch /E475/
endtry
endif
endfunction
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
function! s:get_hl(group, what, mode) abort
let r = synIDattr(synIDtrans(hlID(a:group)), a:what, a:mode)
if empty(r) || r == -1

View File

@ -1,3 +1,5 @@
let s:winid = 0
function! gitgutter#hunk#set_hunks(bufnr, hunks) abort
call gitgutter#utility#setbufvar(a:bufnr, 'hunks', a:hunks)
call s:reset_summary(a:bufnr)
@ -169,29 +171,63 @@ function! gitgutter#hunk#text_object(inner) abort
endfunction
function! gitgutter#hunk#stage() abort
call s:hunk_op(function('s:stage'))
silent! call repeat#set("\<Plug>GitGutterStageHunk", -1)
function! gitgutter#hunk#stage(...) abort
if a:0 && (a:1 != 1 || a:2 != line('$'))
call s:hunk_op(function('s:stage'), a:1, a:2)
else
call s:hunk_op(function('s:stage'))
endif
silent! call repeat#set("\<Plug>(GitGutterStageHunk)", -1)
endfunction
function! gitgutter#hunk#undo() abort
call s:hunk_op(function('s:undo'))
silent! call repeat#set("\<Plug>GitGutterUndoHunk", -1)
silent! call repeat#set("\<Plug>(GitGutterUndoHunk)", -1)
endfunction
function! gitgutter#hunk#preview() abort
call s:hunk_op(function('s:preview'))
silent! call repeat#set("\<Plug>GitGutterPreviewHunk", -1)
silent! call repeat#set("\<Plug>(GitGutterPreviewHunk)", -1)
endfunction
function! s:hunk_op(op)
function! s:hunk_op(op, ...)
let bufnr = bufnr('')
if s:in_hunk_preview_window()
if string(a:op) =~ '_stage'
" combine hunk-body in preview window with updated hunk-header
let hunk_body = getline(1, '$')
let [removed, added] = [0, 0]
for line in hunk_body
if line[0] == '-'
let removed += 1
elseif line[0] == '+'
let added += 1
endif
endfor
let hunk_header = b:hunk_header
" from count
let hunk_header[4] = substitute(hunk_header[4], '\(-\d\+\)\(,\d\+\)\?', '\=submatch(1).",".removed', '')
" to count
let hunk_header[4] = substitute(hunk_header[4], '\(+\d\+\)\(,\d\+\)\?', '\=submatch(1).",".added', '')
let hunk_diff = join(hunk_header + hunk_body, "\n")."\n"
call s:goto_original_window()
call s:close_hunk_preview_window()
call s:stage(hunk_diff)
endif
return
endif
if gitgutter#utility#is_active(bufnr)
" Get a (synchronous) diff.
let [async, g:gitgutter_async] = [g:gitgutter_async, 0]
let diff = gitgutter#diff#run_diff(bufnr, 'index', 1)
let diff = gitgutter#diff#run_diff(bufnr, g:gitgutter_diff_relative_to, 1)
let g:gitgutter_async = async
call gitgutter#hunk#set_hunks(bufnr, gitgutter#diff#parse_diff(diff))
@ -210,7 +246,14 @@ function! s:hunk_op(op)
call gitgutter#utility#warn('did not recognise your choice')
endif
else
call a:op(gitgutter#diff#hunk_diff(bufnr, diff))
let hunk_diff = gitgutter#diff#hunk_diff(bufnr, diff)
if a:0
let hunk_first_line = s:current_hunk()[2]
let hunk_diff = s:part_of_diff(hunk_diff, a:1-hunk_first_line, a:2-hunk_first_line)
endif
call a:op(hunk_diff)
endif
endif
endfunction
@ -223,6 +266,9 @@ function! s:stage(hunk_diff)
call gitgutter#utility#system(
\ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' apply --cached --unidiff-zero - '),
\ diff)
if v:shell_error
call gitgutter#utility#warn('patch does not apply')
endif
" Refresh gitgutter's view of buffer.
call gitgutter#process_buffer(bufnr, 1)
@ -232,7 +278,7 @@ endfunction
function! s:undo(hunk_diff)
" Apply reverse patch to buffer.
let hunk = gitgutter#diff#parse_hunk(split(a:hunk_diff, '\n')[4])
let lines = map(split(a:hunk_diff, '\n')[5:], 'v:val[1:]')
let lines = map(split(a:hunk_diff, '\r\?\n')[5:], 'v:val[1:]')
let lnum = hunk[2]
let added_only = hunk[1] == 0 && hunk[3] > 0
let removed_only = hunk[1] > 0 && hunk[3] == 0
@ -249,25 +295,29 @@ endfunction
function! s:preview(hunk_diff)
let hunk_lines = split(s:discard_header(a:hunk_diff), "\n")
let hunk_lines_length = len(hunk_lines)
let previewheight = min([hunk_lines_length, &previewheight])
let lines = split(a:hunk_diff, '\r\?\n')
let header = lines[0:4]
let body = lines[5:]
silent! wincmd P
if !&previewwindow
noautocmd execute 'bo' previewheight 'new'
set previewwindow
else
execute 'resize' previewheight
call s:open_hunk_preview_window()
call s:populate_hunk_preview_window(header, body)
call s:enable_staging_from_hunk_preview_window()
if &previewwindow
call s:goto_original_window()
endif
endfunction
setlocal noreadonly modifiable filetype=diff buftype=nofile bufhidden=delete noswapfile
execute "%delete_"
call append(0, hunk_lines)
normal! gg
setlocal readonly nomodifiable
noautocmd wincmd p
" Returns a new hunk diff using the specified lines from the given one.
" Assumes all lines are additions.
" a:first, a:last - 0-based indexes into the body of the hunk.
function! s:part_of_diff(hunk_diff, first, last)
let diff_lines = split(a:hunk_diff, '\n', 1)
" adjust 'to' line count in header
let diff_lines[4] = substitute(diff_lines[4], '\(+\d\+\)\(,\d\+\)\?', '\=submatch(1).",".(a:last-a:first+1)', '')
return join(diff_lines[0:4] + diff_lines[5+a:first:5+a:last], "\n")."\n"
endfunction
@ -305,16 +355,11 @@ endif
function! s:adjust_hunk_summary(hunk_diff) abort
let line_adjustment = s:line_adjustment_for_current_hunk()
let diff = split(a:hunk_diff, '\n', 1)
let diff[4] = substitute(diff[4], '+\@<=\(\d\+\)', '\=submatch(1)+line_adjustment', '')
let diff[4] = substitute(diff[4], '+\zs\(\d\+\)', '\=submatch(1)+line_adjustment', '')
return join(diff, "\n")
endfunction
function! s:discard_header(hunk_diff)
return join(split(a:hunk_diff, '\n', 1)[5:], "\n")
endfunction
" Returns the number of lines the current hunk is offset from where it would
" be if any changes above it in the file didn't exist.
function! s:line_adjustment_for_current_hunk() abort
@ -330,3 +375,150 @@ function! s:line_adjustment_for_current_hunk() abort
return adj
endfunction
function! s:in_hunk_preview_window()
if g:gitgutter_preview_win_floating
return win_id2win(s:winid) == winnr()
else
return &previewwindow
endif
endfunction
" Floating window: does not move cursor to floating window.
" Preview window: moves cursor to preview window.
function! s:open_hunk_preview_window()
if g:gitgutter_preview_win_floating
if exists('*nvim_open_win')
call s:close_hunk_preview_window()
let buf = nvim_create_buf(v:false, v:false)
" Set default width and height for now.
let s:winid = nvim_open_win(buf, v:false, {
\ 'relative': 'cursor',
\ 'row': 1,
\ 'col': 0,
\ 'width': 42,
\ 'height': &previewheight,
\ 'style': 'minimal'
\ })
call nvim_buf_set_option(buf, 'filetype', 'diff')
call nvim_buf_set_option(buf, 'buftype', 'acwrite')
call nvim_buf_set_option(buf, 'bufhidden', 'delete')
call nvim_buf_set_option(buf, 'swapfile', v:false)
call nvim_buf_set_name(buf, 'gitgutter://hunk-preview')
" Assumes cursor is in original window.
autocmd CursorMoved <buffer> ++once call s:close_hunk_preview_window()
return
endif
if exists('*popup_create')
let s:winid = popup_create('', {
\ 'line': 'cursor+1',
\ 'col': 'cursor',
\ 'moved': 'any',
\ })
call setbufvar(winbufnr(s:winid), '&filetype', 'diff')
return
endif
endif
silent! wincmd P
if !&previewwindow
noautocmd execute g:gitgutter_preview_win_location &previewheight 'new gitgutter://hunk-preview'
let s:winid = win_getid()
set previewwindow
setlocal filetype=diff buftype=acwrite bufhidden=delete
" Reset some defaults in case someone else has changed them.
setlocal noreadonly modifiable noswapfile
endif
endfunction
" Floating window: does not care where cursor is.
" Preview window: assumes cursor is in preview window.
function! s:populate_hunk_preview_window(header, body)
let body_length = len(a:body)
let height = min([body_length, &previewheight])
if g:gitgutter_preview_win_floating
if exists('*nvim_open_win')
" Assumes cursor is not in previewing window.
call nvim_buf_set_var(winbufnr(s:winid), 'hunk_header', a:header)
let width = max(map(copy(a:body), 'strdisplaywidth(v:val)'))
call nvim_win_set_width(s:winid, width)
call nvim_win_set_height(s:winid, height)
call nvim_buf_set_lines(winbufnr(s:winid), 0, -1, v:false, [])
call nvim_buf_set_lines(winbufnr(s:winid), 0, -1, v:false, a:body)
call nvim_buf_set_option(winbufnr(s:winid), 'modified', v:false)
let ns_id = nvim_create_namespace('GitGutter')
call nvim_buf_clear_namespace(winbufnr(s:winid), ns_id, 0, -1)
for region in gitgutter#diff_highlight#process(a:body)
let group = region[1] == '+' ? 'GitGutterAddIntraLine' : 'GitGutterDeleteIntraLine'
call nvim_buf_add_highlight(winbufnr(s:winid), ns_id, group, region[0]-1, region[2]-1, region[3])
endfor
call nvim_win_set_cursor(s:winid, [1,0])
endif
if exists('*popup_create')
call popup_settext(s:winid, a:body)
for region in gitgutter#diff_highlight#process(a:body)
let group = region[1] == '+' ? 'GitGutterAddIntraLine' : 'GitGutterDeleteIntraLine'
call win_execute(s:winid, "call matchaddpos('".group."', [[".region[0].", ".region[2].", ".(region[3]-region[2]+1)."]])")
endfor
endif
else
let b:hunk_header = a:header
execute 'resize' height
%delete _
call setline(1, a:body)
setlocal nomodified
call clearmatches()
for region in gitgutter#diff_highlight#process(a:body)
let group = region[1] == '+' ? 'GitGutterAddIntraLine' : 'GitGutterDeleteIntraLine'
call matchaddpos(group, [[region[0], region[2], region[3]-region[2]+1]])
endfor
1
endif
endfunction
function! s:enable_staging_from_hunk_preview_window()
augroup gitgutter_hunk_preview
autocmd!
execute 'autocmd BufWriteCmd <buffer='.winbufnr(s:winid).'> GitGutterStageHunk'
augroup END
endfunction
function! s:goto_original_window()
noautocmd wincmd p
endfunction
function! s:close_hunk_preview_window()
call setbufvar(winbufnr(s:winid), '&modified', 0)
if g:gitgutter_preview_win_floating
if win_id2win(s:winid) > 0
execute win_id2win(s:winid).'wincmd c'
endif
else
pclose
endif
let s:winid = 0
endfunction

View File

@ -1,11 +1,6 @@
" Vim doesn't namespace sign ids so every plugin shares the same
" namespace. Sign ids are simply integers so to avoid clashes with other
" signs we guess at a clear run.
"
" Note also we currently never reset s:next_sign_id.
" For older Vims without sign_place() the plugin has to manaage the sign ids.
let s:first_sign_id = 3000
let s:next_sign_id = s:first_sign_id
let s:dummy_sign_id = s:first_sign_id - 1
" Remove-all-signs optimisation requires Vim 7.3.596+.
let s:supports_star = v:version > 703 || (v:version == 703 && has("patch596"))
@ -16,7 +11,7 @@ function! gitgutter#sign#enable() abort
let g:gitgutter_signs = 1
call gitgutter#highlight#define_sign_text_highlights()
if !old_signs && !g:gitgutter_highlight_lines
if !old_signs && !g:gitgutter_highlight_lines && !g:gitgutter_highlight_linenrs
call gitgutter#all(1)
endif
endfunction
@ -25,9 +20,8 @@ function! gitgutter#sign#disable() abort
let g:gitgutter_signs = 0
call gitgutter#highlight#define_sign_text_highlights()
if !g:gitgutter_highlight_lines
if !g:gitgutter_highlight_lines && !g:gitgutter_highlight_linenrs
call gitgutter#sign#clear_signs(bufnr(''))
call gitgutter#sign#remove_dummy_sign(bufnr(''), 0)
endif
endfunction
@ -40,8 +34,14 @@ function! gitgutter#sign#toggle() abort
endfunction
" Removes gitgutter's signs (excluding dummy sign) from the buffer being processed.
" Removes gitgutter's signs from the buffer being processed.
function! gitgutter#sign#clear_signs(bufnr) abort
if exists('*sign_unplace')
call sign_unplace('gitgutter', {'buffer': a:bufnr})
return
endif
call s:find_current_signs(a:bufnr)
let sign_ids = map(values(gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs')), 'v:val.id')
@ -55,37 +55,42 @@ endfunction
" modified_lines: list of [<line_number (number)>, <name (string)>]
" where name = 'added|removed|modified|modified_removed'
function! gitgutter#sign#update_signs(bufnr, modified_lines) abort
if exists('*sign_unplace')
" Vim is (hopefully) now quick enough to remove all signs then place new ones.
call sign_unplace('gitgutter', {'buffer': a:bufnr})
let modified_lines = s:handle_double_hunk(a:modified_lines)
let signs = map(copy(modified_lines), '{'.
\ '"buffer": a:bufnr,'.
\ '"group": "gitgutter",'.
\ '"name": s:highlight_name_for_change(v:val[1]),'.
\ '"lnum": v:val[0],'.
\ '"priority": g:gitgutter_sign_priority'.
\ '}')
if exists('*sign_placelist')
call sign_placelist(signs)
return
endif
for sign in signs
call sign_place(0, sign.group, sign.name, sign.buffer, {'lnum': sign.lnum, 'priority': sign.priority})
endfor
return
endif
" Derive a delta between the current signs and the ones we want.
" Remove signs from lines that no longer need a sign.
" Upsert the remaining signs.
call s:find_current_signs(a:bufnr)
let new_gitgutter_signs_line_numbers = map(copy(a:modified_lines), 'v:val[0]')
let obsolete_signs = s:obsolete_gitgutter_signs_to_remove(a:bufnr, new_gitgutter_signs_line_numbers)
let flicker_possible = s:remove_all_old_signs && !empty(a:modified_lines)
if flicker_possible
call s:add_dummy_sign(a:bufnr)
endif
call s:remove_signs(a:bufnr, obsolete_signs, s:remove_all_old_signs)
call s:upsert_new_gitgutter_signs(a:bufnr, a:modified_lines)
if flicker_possible
call gitgutter#sign#remove_dummy_sign(a:bufnr, 0)
endif
endfunction
function! s:add_dummy_sign(bufnr) abort
if !gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign')
execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . a:bufnr
call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', 1)
endif
endfunction
function! gitgutter#sign#remove_dummy_sign(bufnr, force) abort
if gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign') && (a:force || !g:gitgutter_sign_column_always)
execute "sign unplace" s:dummy_sign_id "buffer=" . a:bufnr
call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', 0)
endif
endfunction
@ -96,40 +101,52 @@ endfunction
function! s:find_current_signs(bufnr) abort
let gitgutter_signs = {} " <line_number (string)>: {'id': <id (number)>, 'name': <name (string)>}
let other_signs = [] " [<line_number (number),...]
let dummy_sign_placed = 0
if !g:gitgutter_sign_allow_clobber
let other_signs = [] " [<line_number (number),...]
endif
redir => signs
silent execute "sign place buffer=" . a:bufnr
redir END
if exists('*getbufinfo')
let bufinfo = getbufinfo(a:bufnr)[0]
let signs = has_key(bufinfo, 'signs') ? bufinfo.signs : []
else
let signs = []
for sign_line in filter(split(signs, '\n')[2:], 'v:val =~# "="')
" Typical sign line: line=88 id=1234 name=GitGutterLineAdded
" We assume splitting is faster than a regexp.
let components = split(sign_line)
let name = split(components[2], '=')[1]
if name =~# 'GitGutterDummy'
let dummy_sign_placed = 1
else
let line_number = str2nr(split(components[0], '=')[1])
if name =~# 'GitGutter'
let id = str2nr(split(components[1], '=')[1])
" Remove orphaned signs (signs placed on lines which have been deleted).
" (When a line is deleted its sign lingers. Subsequent lines' signs'
" line numbers are decremented appropriately.)
if has_key(gitgutter_signs, line_number)
execute "sign unplace" gitgutter_signs[line_number].id
endif
let gitgutter_signs[line_number] = {'id': id, 'name': name}
else
call add(other_signs, line_number)
redir => signlines
silent execute "sign place buffer=" . a:bufnr
redir END
for signline in filter(split(signlines, '\n')[2:], 'v:val =~# "="')
" Typical sign line before v8.1.0614: line=88 id=1234 name=GitGutterLineAdded
" We assume splitting is faster than a regexp.
let components = split(signline)
call add(signs, {
\ 'lnum': str2nr(split(components[0], '=')[1]),
\ 'id': str2nr(split(components[1], '=')[1]),
\ 'name': split(components[2], '=')[1]
\ })
endfor
endif
for sign in signs
if sign.name =~# 'GitGutter'
" Remove orphaned signs (signs placed on lines which have been deleted).
" (When a line is deleted its sign lingers. Subsequent lines' signs'
" line numbers are decremented appropriately.)
if has_key(gitgutter_signs, sign.lnum)
execute "sign unplace" gitgutter_signs[sign.lnum].id
endif
end
let gitgutter_signs[sign.lnum] = {'id': sign.id, 'name': sign.name}
else
if !g:gitgutter_sign_allow_clobber
call add(other_signs, sign.lnum)
endif
endif
endfor
call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', dummy_sign_placed)
call gitgutter#utility#setbufvar(a:bufnr, 'gitgutter_signs', gitgutter_signs)
call gitgutter#utility#setbufvar(a:bufnr, 'other_signs', other_signs)
if !g:gitgutter_sign_allow_clobber
call gitgutter#utility#setbufvar(a:bufnr, 'other_signs', other_signs)
endif
endfunction
@ -152,12 +169,8 @@ endfunction
function! s:remove_signs(bufnr, sign_ids, all_signs) abort
if a:all_signs && s:supports_star && empty(gitgutter#utility#getbufvar(a:bufnr, 'other_signs'))
let dummy_sign_present = gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign')
if a:all_signs && s:supports_star && (g:gitgutter_sign_allow_clobber || empty(gitgutter#utility#getbufvar(a:bufnr, 'other_signs')))
execute "sign unplace * buffer=" . a:bufnr
if dummy_sign_present
execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . a:bufnr
endif
else
for id in a:sign_ids
execute "sign unplace" id
@ -167,21 +180,16 @@ endfunction
function! s:upsert_new_gitgutter_signs(bufnr, modified_lines) abort
let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs')
if !g:gitgutter_sign_allow_clobber
let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs')
endif
let old_gitgutter_signs = gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs')
" Handle special case where the first line is the site of two hunks:
" lines deleted above at the start of the file, and lines deleted
" immediately below.
if a:modified_lines[0:1] == [[1, 'removed_first_line'], [1, 'removed']]
let modified_lines = [[1, 'removed_above_and_below']] + a:modified_lines[2:]
else
let modified_lines = a:modified_lines
endif
let modified_lines = s:handle_double_hunk(a:modified_lines)
for line in modified_lines
let line_number = line[0] " <number>
if index(other_signs, line_number) == -1 " don't clobber others' signs
if g:gitgutter_sign_allow_clobber || index(other_signs, line_number) == -1 " don't clobber others' signs
let name = s:highlight_name_for_change(line[1])
if !has_key(old_gitgutter_signs, line_number) " insert
let id = s:next_sign_id()
@ -198,6 +206,18 @@ function! s:upsert_new_gitgutter_signs(bufnr, modified_lines) abort
endfunction
" Handle special case where the first line is the site of two hunks:
" lines deleted above at the start of the file, and lines deleted
" immediately below.
function! s:handle_double_hunk(modified_lines)
if a:modified_lines[0:1] == [[1, 'removed_first_line'], [1, 'removed']]
return [[1, 'removed_above_and_below']] + a:modified_lines[2:]
endif
return a:modified_lines
endfunction
function! s:next_sign_id() abort
let next_id = s:next_sign_id
let s:next_sign_id += 1

View File

@ -13,9 +13,11 @@ CONTENTS *gitgutter*
Introduction ................. |gitgutter-introduction|
Installation ................. |gitgutter-installation|
Windows ................. |gitgutter-windows|
Commands ..................... |gitgutter-commands|
Mappings ..................... |gitgutter-mappings|
Autocommand .................. |gitgutter-autocommand|
Status line .................. |gitgutter-statusline|
Options ...................... |gitgutter-options|
Highlights ................... |gitgutter-highlights|
FAQ .......................... |gitgutter-faq|
@ -36,47 +38,37 @@ The signs are always up to date and the plugin never saves your buffer.
===============================================================================
INSTALLATION *gitgutter-installation*
Pathogen:~
>
cd ~/.vim/bundle
git clone git://github.com/airblade/vim-gitgutter.git
<
Voom:~
Use your favourite package manager, or use Vim's built-in package support.
Edit your plugin manifest (`voom edit`) and add:
Vim:~
>
airblade/vim-gitgutter
mkdir -p ~/.vim/pack/airblade/start
cd ~/.vim/pack/airblade/start
git clone https://github.com/airblade/vim-gitgutter.git
vim -u NONE -c "helptags vim-gitgutter/doc" -c q
<
VimPlug:~
Place this in your .vimrc:
Neovim:~
>
Plug 'airblade/vim-gitgutter'
mkdir -p ~/.config/nvim/pack/airblade/start
cd ~/.config/nvim/pack/airblade/start
git clone https://github.com/airblade/vim-gitgutter.git
nvim -u NONE -c "helptags vim-gitgutter/doc" -c q
<
Then run the following in Vim:
>
:source %
:PlugInstall
<
NeoBundle:~
Place this in your .vimrc:
>
NeoBundle 'airblade/vim-gitgutter'
<
Then run the following in Vim:
>
:source %
:NeoBundleInstall
<
No plugin manager:~
Copy vim-gitgutter's subdirectories into your vim configuration directory:
===============================================================================
WINDOWS *gitgutter-windows*
I recommend configuring vim-gitgutter with the full path to your git executable.
For example:
>
cd tmp && git clone git://github.com/airblade/vim-gitgutter.git
cp vim-gitgutter/* ~/.vim/
let g:gitgutter_git_executable = 'C:\Program Files\Git\bin\git.exe'
<
See |add-global-plugin|.
This is to avoid a problem which occurs if you have file named "git.*" (i.e.
with any extension in "PATHEXT") in your current folder. "cmd.exe" prioritises
the current folder over folders in 'PATH' and will try to execute your file
instead of the "git" binary.
===============================================================================
@ -126,6 +118,19 @@ Commands for turning line highlighting on and off (defaults to off):~
:GitGutterLineHighlightsToggle Turn line highlighting on or off.
Commands for turning line number highlighting on and off (defaults to off):~
NOTE: This feature requires Neovim 0.3.2 or higher.
*gitgutter-:GitGutterLineNrHighlightsEnable*
:GitGutterLineNrHighlightsEnable Turn on line highlighting.
*gitgutter-:GitGutterLineNrHighlightsDisable*
:GitGutterLineNrHighlightsDisable Turn off line highlighting.
*gitgutter-:GitGutterLineNrHighlightsToggle*
:GitGutterLineNrHighlightsToggle Turn line highlighting on or off.
Commands for jumping between hunks:~
*gitgutter-:GitGutterNextHunk*
@ -134,11 +139,24 @@ Commands for jumping between hunks:~
*gitgutter-:GitGutterPrevHunk*
:GitGutterPrevHunk Jump to the previous [count] hunk.
*gitgutter-:GitGutterQuickFix*
:GitGutterQuickFix Load all hunks into the |quickfix| list. Note this
ignores any unsaved changes in your buffers. The
|g:gitgutter_use_location_list| option can be set to
populate the location list of the current window instead
Commands for operating on a hunk:~
*gitgutter-:GitGutterStageHunk*
:GitGutterStageHunk Stage the hunk the cursor is in.
:GitGutterStageHunk Stage the hunk the cursor is in. Use a visual selection
to stage part of an (additions-only) hunk; or use a
range.
To stage part of any hunk, first |GitGutterPreviewHunk|
it, then move to the preview window, delete the lines
you do not want to stage, and |write| or
|GitGutterStageHunk|.
*gitgutter-:GitGutterUndoHunk*
:GitGutterUndoHunk Undo the hunk the cursor is in.
@ -148,6 +166,10 @@ Commands for operating on a hunk:~
Use |:pclose| or |CTRL-W_CTRL-Z| to close the preview
window.
To stage part of the hunk, move to the preview window,
delete any lines you do not want to stage, and
|GitGutterStageHunk|.
Commands for folds:~
*gitgutter-:GitGutterFold*
@ -191,9 +213,9 @@ These can be repeated with `.` if you have vim-repeat installed.
You can change these mappings like this:
>
nmap ghp <Plug>GitGutterPreviewHunk
nmap ghs <Plug>GitGutterStageHunk
nmap ghu <Plug>GitGutterUndoHunk
nmap ghp <Plug>(GitGutterPreviewHunk)
nmap ghs <Plug>(GitGutterStageHunk)
nmap ghu <Plug>(GitGutterUndoHunk)
<
Hunk jumping:~
@ -206,8 +228,8 @@ Hunk jumping:~
You can change these mappings like this:
>
nmap [c <Plug>GitGutterPrevHunk
nmap ]c <Plug>GitGutterNextHunk
nmap [c <Plug>(GitGutterPrevHunk)
nmap ]c <Plug>(GitGutterNextHunk)
<
Hunk text object:~
@ -216,10 +238,27 @@ Hunk text object:~
"ic" operates on the current hunk's lines. "ac" does the same but also includes
trailing empty lines.
>
omap ic <Plug>GitGutterTextObjectInnerPending
omap ac <Plug>GitGutterTextObjectOuterPending
xmap ic <Plug>GitGutterTextObjectInnerVisual
xmap ac <Plug>GitGutterTextObjectOuterVisual
omap ic <Plug>(GitGutterTextObjectInnerPending)
omap ac <Plug>(GitGutterTextObjectOuterPending)
xmap ic <Plug>(GitGutterTextObjectInnerVisual)
xmap ac <Plug>(GitGutterTextObjectOuterVisual)
<
===============================================================================
STATUS LINE *gitgutter-statusline*
Call the `GitGutterGetHunkSummary()` function from your status line to get a
list of counts of added, modified, and removed lines in the current buffer.
For example:
>
" Your vimrc
function! GitStatus()
let [a,m,r] = GitGutterGetHunkSummary()
return printf('+%d ~%d -%d', a, m, r)
endfunction
set statusline+=%{GitStatus()}
<
@ -228,7 +267,8 @@ OPTIONS *gitgutter-options*
The most important option is 'updatetime' which determines how long (in
milliseconds) the plugin will wait after you stop typing before it updates the
signs. Vim's default is 4000. I recommend 100.
signs. Vim's default is 4000. I recommend 100. Note this also controls how
long vim waits before writing its swap file.
Most important option:~
@ -239,6 +279,7 @@ Git:~
|g:gitgutter_git_executable|
|g:gitgutter_git_args|
|g:gitgutter_diff_args|
|g:gitgutter_diff_relative_to|
|g:gitgutter_diff_base|
Grep:~
@ -249,15 +290,21 @@ Signs:~
|g:gitgutter_signs|
|g:gitgutter_highlight_lines|
|g:gitgutter_highlight_linenrs|
|g:gitgutter_max_signs|
|g:gitgutter_sign_priority|
|g:gitgutter_sign_allow_clobber|
|g:gitgutter_sign_added|
|g:gitgutter_sign_modified|
|g:gitgutter_sign_removed|
|g:gitgutter_sign_removed_first_line|
|g:gitgutter_sign_modified_removed|
|g:gitgutter_sign_column_always|
|g:gitgutter_override_sign_column_highlight|
Hunk previews:~
|g:gitgutter_preview_win_floating|
Terminal:~
|g:gitgutter_terminal_reports_focus|
@ -268,8 +315,16 @@ General:~
|g:gitgutter_map_keys|
|g:gitgutter_async|
|g:gitgutter_log|
|g:gitgutter_use_location_list|
*g:gitgutter_preview_win_location*
Default: 'bo'
This option determines where the preview window pops up as a result of the
:GitGutterPreviewHunk command. Other plausible values are 'to', 'bel', 'abo'.
See the end of the |opening-window| docs.
*g:gitgutter_git_executable*
Default: 'git'
@ -293,6 +348,15 @@ Use this option to pass any extra arguments to git-diff. For example:
let g:gitgutter_diff_args = '-w'
<
*g:gitgutter_diff_relative_to*
Default: empty
By default buffers are diffed against the index. Use this option to diff against
the working tree. For example:
>
let g:gitgutter_diff_relative_to = 'working_tree'
<
*g:gitgutter_diff_base*
Default: empty
@ -302,6 +366,9 @@ a revision instead. For example:
let g:gitgutter_diff_base = '<some commit SHA>'
<
This setting is ignore when the diff is relative to the working tree
(|g:gitgutter_diff_relative_to|).
*g:gitgutter_grep*
Default: 'grep'
@ -329,6 +396,11 @@ Default: 0
Determines whether or not to show line highlights.
*g:gitgutter_highlight_linenrs*
Default: 0
Determines whether or not to show line number highlights.
*g:gitgutter_max_signs*
Default: 500
@ -337,6 +409,18 @@ signs, so to avoid slowing down the GUI the number of signs is capped. When
the number of changed lines exceeds this value, the plugin removes all signs
and displays a warning message.
*g:gitgutter_sign_priority*
Default: 10
Sets the |sign-priority| gitgutter assigns to its signs.
*g:gitgutter_sign_allow_clobber*
Default: 0 (Vim < 8.1.0614, Neovim < 0.4.0)
1 (otherwise)
Determines whether gitgutter preserves non-gitgutter signs. When 1, gitgutter
will not preserve non-gitgutter signs.
*g:gitgutter_sign_added*
*g:gitgutter_sign_modified*
*g:gitgutter_sign_removed*
@ -353,17 +437,6 @@ Defaults:
You can use unicode characters but not images. Signs must not take up more than
2 columns.
*g:gitgutter_sign_column_always*
Default: 0
This legacy option controls whether the sign column should always be shown, even
if there are no signs to display.
From Vim 7.4.2201, use 'signcolumn' instead:
>
set signcolumn=yes
<
*g:gitgutter_override_sign_column_highlight*
Default: 1
@ -385,6 +458,15 @@ it in your |vimrc|:
User-defined (graphical Vim) highlight SignColumn guibg={whatever}
*g:gitgutter_preview_win_floating*
Default: 0 (Vim)
0 (NeoVim which does not support floating windows)
1 (NeoVim which does support floating windows)
Whether to use floating/popup windows for hunk previews. Note that if you use
popup windows on Vim you will not be able to stage partial hunks via the
preview window.
*g:gitgutter_terminal_reports_focus*
Default: 1
@ -413,7 +495,7 @@ Controls whether or not the plugin is on at startup.
*g:gitgutter_map_keys*
Default: 1
Controls whether or not the plugin provides mappings. See |gitgutter-mapppings|.
Controls whether or not the plugin provides mappings. See |gitgutter-mappings|.
*g:gitgutter_async*
Default: 1
@ -427,6 +509,12 @@ Default: 0
When switched on, the plugin logs to gitgutter.log in the directory where it is
installed. Additionally it logs channel activity to channel.log.
*g:gitgutter_use_location_list*
Default: 0
When switched on, the :GitGutterQuickFix command populates the location list
of the current window instead of the global quickfix list.
===============================================================================
HIGHLIGHTS *gitgutter-highlights*
@ -457,7 +545,19 @@ colorscheme or |vimrc|:
For example, to use |hl-DiffText| instead of |hl-DiffChange|:
>
highlight link GitGutterChangeLine DiffChange
highlight link GitGutterChangeLine DiffText
<
To change the line number highlights, set up the following highlight groups in
your colorscheme or |vimrc|:
>
GitGutterAddLineNr " default: links to CursorLineNr
GitGutterChangeLineNr " default: links to CursorLineNr
GitGutterDeleteLineNr " default: links to CursorLineNr
GitGutterChangeDeleteLineNr " default: links to CursorLineNr
<
For example, to use |hl-Underlined| instead of |hl-CursorLineNr|:
>
highlight link GitGutterChangeLineNr Underlined
<
@ -543,6 +643,8 @@ Try reducing 'updatetime':
set updatetime=100
<
Note this also controls how long vim waits before writing its swap file.
When signs don't update after focusing Vim:~

View File

@ -22,17 +22,24 @@ function! s:set(var, default) abort
endif
endfunction
call s:set('g:gitgutter_preview_win_location', 'bo')
if exists('*nvim_open_win')
call s:set('g:gitgutter_preview_win_floating', 1)
else
call s:set('g:gitgutter_preview_win_floating', 0)
endif
call s:set('g:gitgutter_enabled', 1)
call s:set('g:gitgutter_max_signs', 500)
call s:set('g:gitgutter_signs', 1)
call s:set('g:gitgutter_highlight_lines', 0)
call s:set('g:gitgutter_sign_column_always', 0)
if g:gitgutter_sign_column_always && exists('&signcolumn')
" Vim 7.4.2201.
set signcolumn=yes
let g:gitgutter_sign_column_always = 0
call gitgutter#utility#warn('please replace "let g:gitgutter_sign_column_always=1" with "set signcolumn=yes"')
call s:set('g:gitgutter_highlight_linenrs', 0)
call s:set('g:gitgutter_sign_priority', 10)
" Nvim 0.4.0 has an expanding sign column
" The sign_place() function supports sign priority.
if (has('nvim-0.4.0') || exists('*sign_place')) && !exists('g:gitgutter_sign_allow_clobber')
let g:gitgutter_sign_allow_clobber = 1
endif
call s:set('g:gitgutter_sign_allow_clobber', 0)
call s:set('g:gitgutter_override_sign_column_highlight', 1)
call s:set('g:gitgutter_sign_added', '+')
call s:set('g:gitgutter_sign_modified', '~')
@ -47,12 +54,14 @@ endif
call s:set('g:gitgutter_sign_removed_above_and_below', '[')
call s:set('g:gitgutter_sign_modified_removed', '~_')
call s:set('g:gitgutter_git_args', '')
call s:set('g:gitgutter_diff_relative_to', 'index')
call s:set('g:gitgutter_diff_args', '')
call s:set('g:gitgutter_diff_base', '')
call s:set('g:gitgutter_map_keys', 1)
call s:set('g:gitgutter_terminal_reports_focus', 1)
call s:set('g:gitgutter_async', 1)
call s:set('g:gitgutter_log', 0)
call s:set('g:gitgutter_use_location_list', 0)
call s:set('g:gitgutter_git_executable', 'git')
if !executable(g:gitgutter_git_executable)
@ -101,6 +110,8 @@ command! -bar GitGutterBufferDisable call gitgutter#buffer_disable()
command! -bar GitGutterBufferEnable call gitgutter#buffer_enable()
command! -bar GitGutterBufferToggle call gitgutter#buffer_toggle()
command! -bar GitGutterQuickFix call gitgutter#quickfix()
" }}}
" Line highlights {{{
@ -111,6 +122,12 @@ command! -bar GitGutterLineHighlightsToggle call gitgutter#highlight#line_toggl
" }}}
" 'number' column highlights {{{
command! -bar GitGutterLineNrHighlightsDisable call gitgutter#highlight#linenr_disable()
command! -bar GitGutterLineNrHighlightsEnable call gitgutter#highlight#linenr_enable()
command! -bar GitGutterLineNrHighlightsToggle call gitgutter#highlight#linenr_toggle()
" }}}
" Signs {{{
command! -bar GitGutterSignsEnable call gitgutter#sign#enable()
@ -124,15 +141,15 @@ command! -bar GitGutterSignsToggle call gitgutter#sign#toggle()
command! -bar -count=1 GitGutterNextHunk call gitgutter#hunk#next_hunk(<count>)
command! -bar -count=1 GitGutterPrevHunk call gitgutter#hunk#prev_hunk(<count>)
command! -bar GitGutterStageHunk call gitgutter#hunk#stage()
command! -bar -range=% GitGutterStageHunk call gitgutter#hunk#stage(<line1>,<line2>)
command! -bar GitGutterUndoHunk call gitgutter#hunk#undo()
command! -bar GitGutterPreviewHunk call gitgutter#hunk#preview()
" Hunk text object
onoremap <silent> <Plug>GitGutterTextObjectInnerPending :<C-U>call gitgutter#hunk#text_object(1)<CR>
onoremap <silent> <Plug>GitGutterTextObjectOuterPending :<C-U>call gitgutter#hunk#text_object(0)<CR>
xnoremap <silent> <Plug>GitGutterTextObjectInnerVisual :<C-U>call gitgutter#hunk#text_object(1)<CR>
xnoremap <silent> <Plug>GitGutterTextObjectOuterVisual :<C-U>call gitgutter#hunk#text_object(0)<CR>
onoremap <silent> <Plug>(GitGutterTextObjectInnerPending) :<C-U>call gitgutter#hunk#text_object(1)<CR>
onoremap <silent> <Plug>(GitGutterTextObjectOuterPending) :<C-U>call gitgutter#hunk#text_object(0)<CR>
xnoremap <silent> <Plug>(GitGutterTextObjectInnerVisual) :<C-U>call gitgutter#hunk#text_object(1)<CR>
xnoremap <silent> <Plug>(GitGutterTextObjectOuterVisual) :<C-U>call gitgutter#hunk#text_object(0)<CR>
" Returns the git-diff hunks for the file or an empty list if there
@ -176,16 +193,25 @@ command! -bar GitGutterDebug call gitgutter#debug#debug()
" Maps {{{
nnoremap <silent> <expr> <Plug>GitGutterNextHunk &diff ? ']c' : ":\<C-U>execute v:count1 . 'GitGutterNextHunk'\<CR>"
nnoremap <silent> <expr> <Plug>GitGutterPrevHunk &diff ? '[c' : ":\<C-U>execute v:count1 . 'GitGutterPrevHunk'\<CR>"
nnoremap <silent> <expr> <Plug>(GitGutterNextHunk) &diff ? ']c' : ":\<C-U>execute v:count1 . 'GitGutterNextHunk'\<CR>"
nnoremap <silent> <expr> <Plug>GitGutterNextHunk &diff ? ']c' : ":\<C-U>call gitgutter#utility#warn('please change your map \<lt>Plug>GitGutterNextHunk to \<lt>Plug>(GitGutterNextHunk)')\<CR>"
nnoremap <silent> <expr> <Plug>(GitGutterPrevHunk) &diff ? '[c' : ":\<C-U>execute v:count1 . 'GitGutterPrevHunk'\<CR>"
nnoremap <silent> <expr> <Plug>GitGutterPrevHunk &diff ? '[c' : ":\<C-U>call gitgutter#utility#warn('please change your map \<lt>Plug>GitGutterPrevHunk to \<lt>Plug>(GitGutterPrevHunk)')\<CR>"
nnoremap <silent> <Plug>GitGutterStageHunk :GitGutterStageHunk<CR>
nnoremap <silent> <Plug>GitGutterUndoHunk :GitGutterUndoHunk<CR>
nnoremap <silent> <Plug>GitGutterPreviewHunk :GitGutterPreviewHunk<CR>
xnoremap <silent> <Plug>(GitGutterStageHunk) :GitGutterStageHunk<CR>
xnoremap <silent> <Plug>GitGutterStageHunk :call gitgutter#utility#warn('please change your map <lt>Plug>GitGutterStageHunk to <lt>Plug>(GitGutterStageHunk)')<CR>
nnoremap <silent> <Plug>(GitGutterStageHunk) :GitGutterStageHunk<CR>
nnoremap <silent> <Plug>GitGutterStageHunk :call gitgutter#utility#warn('please change your map <lt>Plug>GitGutterStageHunk to <lt>Plug>(GitGutterStageHunk)')<CR>
nnoremap <silent> <Plug>(GitGutterUndoHunk) :GitGutterUndoHunk<CR>
nnoremap <silent> <Plug>GitGutterUndoHunk :call gitgutter#utility#warn('please change your map <lt>Plug>GitGutterUndoHunk to <lt>Plug>(GitGutterUndoHunk)')<CR>
nnoremap <silent> <Plug>(GitGutterPreviewHunk) :GitGutterPreviewHunk<CR>
nnoremap <silent> <Plug>GitGutterPreviewHunk :call gitgutter#utility#warn('please change your map <lt>Plug>GitGutterPreviewHunk to <lt>Plug>(GitGutterPreviewHunk)')<CR>
" }}}
function! s:on_bufenter()
call gitgutter#setup_maps()
if exists('t:gitgutter_didtabenter') && t:gitgutter_didtabenter
let t:gitgutter_didtabenter = 0
call gitgutter#all(!g:gitgutter_terminal_reports_focus)
@ -204,7 +230,11 @@ augroup gitgutter
autocmd BufEnter * call s:on_bufenter()
autocmd CursorHold,CursorHoldI * call gitgutter#process_buffer(bufnr(''), 0)
autocmd FileChangedShellPost * call gitgutter#process_buffer(bufnr(''), 1)
if exists('*timer_start') && has('lambda')
autocmd FileChangedShellPost * call timer_start(1, {-> gitgutter#process_buffer(bufnr(''), 1)})
else
autocmd FileChangedShellPost * call gitgutter#process_buffer(bufnr(''), 1)
endif
" Ensure that all buffers are processed when opening vim with multiple files, e.g.:
"
@ -214,6 +244,11 @@ augroup gitgutter
autocmd ShellCmdPost * call gitgutter#all(1)
autocmd BufLeave term://* call gitgutter#all(1)
<<<<<<< HEAD
=======
autocmd User FugitiveChanged call gitgutter#all(1)
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
autocmd BufFilePre * GitGutterBufferDisable
autocmd BufFilePost * GitGutterBufferEnable

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 587 KiB

View File

@ -0,0 +1,11 @@
a
b
c
d
e
f
g
h
i
j

View File

@ -10,7 +10,7 @@ $VIM -u NONE -U NONE -N \
--cmd 'source ../plugin/gitgutter.vim' \
-S runner.vim \
test_*.vim \
$*
"$@"
cat messages.log

View File

@ -6,29 +6,40 @@ let s:bufnr = bufnr('')
" Helpers
"
function s:signs(filename)
redir => signs
silent execute 'sign place'
redir END
" Ignores unexpected keys in actual.
function s:assert_list_of_dicts(expected, actual)
if empty(a:expected)
call assert_equal([], a:actual)
return
endif
let signs = split(signs, '\n')
let expected_keys = keys(a:expected[0])
" filter out signs for this test file
" assumes a:filename's signs are last set listed
let i = index(signs, 'Signs for '.a:filename.':')
let signs = (i > -1 ? signs[i+1:] : [])
for dict in a:actual
for k in keys(dict)
if index(expected_keys, k) == -1
call remove(dict, k)
endif
endfor
endfor
call map(signs, {_, v -> substitute(v, ' ', '', '')})
return signs
call assert_equal(a:expected, a:actual)
endfunction
function s:git_diff()
return split(system('git diff -U0 fixture.txt'), '\n')
" Ignores unexpected keys.
"
" expected - list of signs
function s:assert_signs(expected, filename)
let actual = sign_getplaced(a:filename, {'group': 'gitgutter'})[0].signs
call s:assert_list_of_dicts(a:expected, actual)
endfunction
function s:git_diff_staged()
return split(system('git diff -U0 --staged fixture.txt'), '\n')
function s:git_diff(...)
return split(system('git diff -U0 '.(a:0 ? a:1 : 'fixture.txt')), '\n')
endfunction
function s:git_diff_staged(...)
return split(system('git diff -U0 --staged '.(a:0 ? a:1 : 'fixture.txt')), '\n')
endfunction
function s:trigger_gitgutter()
@ -44,11 +55,16 @@ function SetUp()
call system("git init ".s:test_repo.
\ " && cd ".s:test_repo.
\ " && cp ../fixture.txt .".
\ " && cp ../fixture_dos.txt .".
\ " && git add . && git commit -m 'initial'".
\ " && git config diff.mnemonicPrefix false")
execute ':cd' s:test_repo
edit! fixture.txt
call gitgutter#sign#reset()
" FIXME why won't vim autoload the file?
execute 'source' '../../autoload/gitgutter/diff_highlight.vim'
execute 'source' '../../autoload/gitgutter/fold.vim'
endfunction
function TearDown()
@ -71,8 +87,13 @@ function Test_add_lines()
normal ggo*
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=2 id=3000 name=GitGutterLineAdded priority=10"]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 2, 'name': 'GitGutterLineAdded', 'group': 'gitgutter', 'priority': 10}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -83,8 +104,13 @@ function Test_add_lines_fish()
normal ggo*
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=2 id=3000 name=GitGutterLineAdded priority=10"]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 2, 'name': 'GitGutterLineAdded'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
let &shell = _shell
endfunction
@ -94,8 +120,13 @@ function Test_modify_lines()
normal ggi*
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=1 id=3000 name=GitGutterLineModified priority=10"]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 1, 'name': 'GitGutterLineModified'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -103,8 +134,13 @@ function Test_remove_lines()
execute '5d'
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=4 id=3000 name=GitGutterLineRemoved priority=10"]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 4, 'name': 'GitGutterLineRemoved'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -112,8 +148,25 @@ function Test_remove_first_lines()
execute '1d'
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=1 id=3000 name=GitGutterLineRemovedFirstLine priority=10"]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 1, 'name': 'GitGutterLineRemovedFirstLine'}]
call s:assert_signs(expected, 'fixture.txt')
endfunction
function Test_priority()
let g:gitgutter_sign_priority = 5
execute '1d'
call s:trigger_gitgutter()
call s:assert_signs([{'priority': 5}], 'fixture.txt')
let g:gitgutter_sign_priority = 10
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -122,8 +175,13 @@ function Test_overlapping_hunks()
execute '1d'
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=1 id=3000 name=GitGutterLineRemovedAboveAndBelow priority=10"]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 1, 'name': 'GitGutterLineRemovedAboveAndBelow'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -132,8 +190,13 @@ function Test_edit_file_with_same_name_as_a_branch()
call system('git checkout -b fixture.txt')
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=5 id=3000 name=GitGutterLineModified priority=10"]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 5, 'name': 'GitGutterLineModified'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -144,8 +207,13 @@ function Test_file_added_to_git()
normal ihello
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=1 id=3000 name=GitGutterLineAdded priority=10"]
call assert_equal(expected, s:signs('fileAddedToGit.tmp'))
=======
let expected = [{'lnum': 1, 'name': 'GitGutterLineAdded'}]
call s:assert_signs(expected, 'fileAddedToGit.tmp')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -156,10 +224,15 @@ function Test_filename_with_equals()
call s:trigger_gitgutter()
let expected = [
<<<<<<< HEAD
\ 'line=1 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=2 id=3001 name=GitGutterLineAdded priority=10'
=======
\ {'lnum': 1, 'name': 'GitGutterLineAdded'},
\ {'lnum': 2, 'name': 'GitGutterLineAdded'}
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
\ ]
call assert_equal(expected, s:signs('=fixture=.txt'))
call s:assert_signs(expected, '=fixture=.txt')
endfunction
@ -170,10 +243,15 @@ function Test_filename_with_square_brackets()
call s:trigger_gitgutter()
let expected = [
<<<<<<< HEAD
\ 'line=1 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=2 id=3001 name=GitGutterLineAdded priority=10'
=======
\ {'lnum': 1, 'name': 'GitGutterLineAdded'},
\ {'lnum': 2, 'name': 'GitGutterLineAdded'}
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
\ ]
call assert_equal(expected, s:signs('fix[tu]re.txt'))
call s:assert_signs(expected, 'fix[tu]re.txt')
endfunction
@ -184,10 +262,15 @@ function Test_filename_leading_dash()
call s:trigger_gitgutter()
let expected = [
<<<<<<< HEAD
\ 'line=1 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=2 id=3001 name=GitGutterLineAdded priority=10'
=======
\ {'lnum': 1, 'name': 'GitGutterLineAdded'},
\ {'lnum': 2, 'name': 'GitGutterLineAdded'}
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
\ ]
call assert_equal(expected, s:signs('-fixture.txt'))
call s:assert_signs(expected, '-fixture.txt')
endfunction
@ -198,10 +281,15 @@ function Test_filename_umlaut()
call s:trigger_gitgutter()
let expected = [
<<<<<<< HEAD
\ 'line=1 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=2 id=3001 name=GitGutterLineAdded priority=10'
=======
\ {'lnum': 1, 'name': 'GitGutterLineAdded'},
\ {'lnum': 2, 'name': 'GitGutterLineAdded'}
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
\ ]
call assert_equal(expected, s:signs('fixtüre.txt'))
call s:assert_signs(expected, 'fixtüre.txt')
endfunction
@ -213,8 +301,13 @@ function Test_follow_symlink()
6d
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ['line=5 id=3000 name=GitGutterLineRemoved priority=10']
call assert_equal(expected, s:signs('symlink'))
=======
let expected = [{'lnum': 5, 'name': 'GitGutterLineRemoved'}]
call s:assert_signs(expected, 'symlink')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -255,7 +348,7 @@ endfunction
function Test_no_modifications()
call assert_equal([], s:signs('fixture.txt'))
call s:assert_signs([], 'fixture.txt')
endfunction
@ -265,8 +358,13 @@ function Test_orphaned_signs()
6d
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ['line=6 id=3001 name=GitGutterLineAdded priority=10']
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 6, 'name': 'GitGutterLineAdded'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -275,7 +373,7 @@ function Test_untracked_file_outside_repo()
call system('touch '.tmp)
execute 'edit '.tmp
call assert_equal([], s:signs(tmp))
call s:assert_signs([], tmp)
endfunction
@ -286,7 +384,7 @@ function Test_untracked_file_within_repo()
normal ggo*
call s:trigger_gitgutter()
call assert_equal([], s:signs(tmp))
call s:assert_signs([], tmp)
call assert_equal(-2, b:gitgutter.path)
call system('rm '.tmp)
@ -300,28 +398,56 @@ function Test_untracked_file_square_brackets_within_repo()
normal ggo*
call s:trigger_gitgutter()
call assert_equal([], s:signs(tmp))
call s:assert_signs([], tmp)
call system('rm '.tmp)
endfunction
function Test_hunk_outside_noop()
normal 5G
5
GitGutterStageHunk
call assert_equal([], s:signs('fixture.txt'))
call s:assert_signs([], 'fixture.txt')
call assert_equal([], s:git_diff())
call assert_equal([], s:git_diff_staged())
GitGutterUndoHunk
call assert_equal([], s:signs('fixture.txt'))
call s:assert_signs([], 'fixture.txt')
call assert_equal([], s:git_diff())
call assert_equal([], s:git_diff_staged())
endfunction
function Test_preview()
normal 5Gi*
GitGutterPreviewHunk
wincmd P
call assert_equal(2, line('$'))
call assert_equal('-e', getline(1))
call assert_equal('+*e', getline(2))
wincmd p
endfunction
function Test_preview_dos()
edit! fixture_dos.txt
normal 5Gi*
GitGutterPreviewHunk
wincmd P
call assert_equal(2, line('$'))
call assert_equal('-e', getline(1))
call assert_equal('+*e', getline(2))
wincmd p
endfunction
function Test_hunk_stage()
let _shell = &shell
set shell=foo
@ -332,7 +458,7 @@ function Test_hunk_stage()
call assert_equal('foo', &shell)
let &shell = _shell
call assert_equal([], s:signs('fixture.txt'))
call s:assert_signs([], 'fixture.txt')
" Buffer is unsaved
let expected = [
@ -372,11 +498,17 @@ function Test_hunk_stage_nearby_hunk()
GitGutterStageHunk
let expected = [
<<<<<<< HEAD
\ 'line=3 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=4 id=3001 name=GitGutterLineAdded priority=10',
\ 'line=5 id=3002 name=GitGutterLineAdded priority=10'
=======
\ {'lnum': 3, 'name': 'GitGutterLineAdded'},
\ {'lnum': 4, 'name': 'GitGutterLineAdded'},
\ {'lnum': 5, 'name': 'GitGutterLineAdded'}
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
\ ]
call assert_equal(expected, s:signs('fixture.txt'))
call s:assert_signs(expected, 'fixture.txt')
" Buffer is unsaved
let expected = [
@ -417,6 +549,203 @@ function Test_hunk_stage_nearby_hunk()
endfunction
function Test_hunk_stage_partial_visual_added()
call append(5, ['A','B','C','D'])
execute "normal 7GVj:GitGutterStageHunk\<CR>"
let expected = [
\ {'lnum': 6, 'name': 'GitGutterLineAdded'},
\ {'lnum': 9, 'name': 'GitGutterLineAdded'},
\ ]
call s:assert_signs(expected, 'fixture.txt')
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index 8a7026e..f5c6aff 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -6,2 +5,0 @@ e',
\ '-B',
\ '-C',
\ ]
call assert_equal(expected, s:git_diff())
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index f5c6aff..8a7026e 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -5,0 +6,2 @@ e',
\ '+B',
\ '+C',
\ ]
call assert_equal(expected, s:git_diff_staged())
endfunction
function Test_hunk_stage_partial_cmd_added()
call append(5, ['A','B','C','D'])
6
7,8GitGutterStageHunk
let expected = [
\ {'lnum': 6, 'name': 'GitGutterLineAdded'},
\ {'lnum': 9, 'name': 'GitGutterLineAdded'},
\ ]
call s:assert_signs(expected, 'fixture.txt')
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index 8a7026e..f5c6aff 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -6,2 +5,0 @@ e',
\ '-B',
\ '-C',
\ ]
call assert_equal(expected, s:git_diff())
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index f5c6aff..8a7026e 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -5,0 +6,2 @@ e',
\ '+B',
\ '+C',
\ ]
call assert_equal(expected, s:git_diff_staged())
endfunction
function Test_hunk_stage_partial_preview_added()
call append(5, ['A','B','C','D'])
6
GitGutterPreviewHunk
wincmd P
" remove C and A so we stage B and D
3delete
1delete
GitGutterStageHunk
write
let expected = [
\ {'lnum': 6, 'name': 'GitGutterLineAdded'},
\ {'lnum': 8, 'name': 'GitGutterLineAdded'},
\ ]
call s:assert_signs(expected, 'fixture.txt')
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index 975852f..3dd23a3 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -5,0 +6 @@ e',
\ '+A',
\ '@@ -6,0 +8 @@ B',
\ '+C',
\ ]
call assert_equal(expected, s:git_diff())
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index f5c6aff..975852f 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -5,0 +6,2 @@ e',
\ '+B',
\ '+D',
\ ]
call assert_equal(expected, s:git_diff_staged())
endfunction
function Test_hunk_stage_preview_write()
call append(5, ['A','B','C','D'])
6
GitGutterPreviewHunk
wincmd P
" preview window
call feedkeys(":w\<CR>", 'tx')
" original window
write
call s:assert_signs([], 'fixture.txt')
call assert_equal([], s:git_diff())
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index f5c6aff..3dd23a3 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -5,0 +6,4 @@ e',
\ '+A',
\ '+B',
\ '+C',
\ '+D',
\ ]
call assert_equal(expected, s:git_diff_staged())
endfunction
function Test_hunk_stage_partial_preview_added_removed()
4,5delete
call append(3, ['A','B','C','D'])
4
GitGutterPreviewHunk
wincmd P
" -d
" -e
" +A
" +B
" +C
" +D
" remove D and d so they do not get staged
6delete
1delete
GitGutterStageHunk
write
let expected = [
\ {'lnum': 3, 'name': 'GitGutterLineRemoved'},
\ {'lnum': 7, 'name': 'GitGutterLineAdded'},
\ ]
call s:assert_signs(expected, 'fixture.txt')
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index 9a19589..e63fb0a 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -4 +3,0 @@ c',
\ '-d',
\ '@@ -7,0 +7 @@ C',
\ '+D',
\ ]
call assert_equal(expected, s:git_diff())
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index f5c6aff..9a19589 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -5 +5,3 @@ d',
\ '-e',
\ '+A',
\ '+B',
\ '+C',
\ ]
call assert_equal(expected, s:git_diff_staged())
endfunction
function Test_hunk_undo()
let _shell = &shell
set shell=foo
@ -427,9 +756,23 @@ function Test_hunk_undo()
call assert_equal('foo', &shell)
let &shell = _shell
call assert_equal([], s:signs('fixture.txt'))
call s:assert_signs([], 'fixture.txt')
call assert_equal([], s:git_diff())
call assert_equal([], s:git_diff_staged())
call assert_equal('e', getline(5))
endfunction
function Test_hunk_undo_dos()
edit! fixture_dos.txt
normal 5Gi*
GitGutterUndoHunk
call s:assert_signs([], 'fixture_dos.txt')
call assert_equal([], s:git_diff('fixture_dos.txt'))
call assert_equal([], s:git_diff_staged('fixture_dos.txt'))
call assert_equal('e', getline(5))
endfunction
@ -442,11 +785,17 @@ function Test_undo_nearby_hunk()
call s:trigger_gitgutter()
let expected = [
<<<<<<< HEAD
\ 'line=3 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=4 id=3001 name=GitGutterLineAdded priority=10',
\ 'line=5 id=3002 name=GitGutterLineAdded priority=10'
=======
\ {'lnum': 3, 'name': 'GitGutterLineAdded'},
\ {'lnum': 4, 'name': 'GitGutterLineAdded'},
\ {'lnum': 5, 'name': 'GitGutterLineAdded'}
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
\ ]
call assert_equal(expected, s:signs('fixture.txt'))
call s:assert_signs(expected, 'fixture.txt')
call assert_equal([], s:git_diff())
@ -485,10 +834,15 @@ function Test_overlapping_hunk_op()
GitGutterUndoHunk
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = [
\ 'line=2 id=3000 name=GitGutterLineRemoved priority=10',
\ ]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 2, 'name': 'GitGutterLineRemoved'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
" Undo lower
@ -499,10 +853,15 @@ function Test_overlapping_hunk_op()
GitGutterUndoHunk
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = [
\ 'line=1 id=3000 name=GitGutterLineRemovedFirstLine priority=10',
\ ]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 1, 'name': 'GitGutterLineRemovedFirstLine'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
endfunction
@ -512,8 +871,13 @@ function Test_write_option()
normal ggo*
call s:trigger_gitgutter()
<<<<<<< HEAD
let expected = ["line=2 id=3000 name=GitGutterLineAdded priority=10"]
call assert_equal(expected, s:signs('fixture.txt'))
=======
let expected = [{'lnum': 2, 'name': 'GitGutterLineAdded'}]
call s:assert_signs(expected, 'fixture.txt')
>>>>>>> 27ad0d07862847896f691309a544a206783c94d6
set write
endfunction
@ -525,7 +889,7 @@ function Test_inner_text_object()
normal dic
call s:trigger_gitgutter()
call assert_equal([], s:signs('fixture.txt'))
call s:assert_signs([], 'fixture.txt')
call assert_equal(readfile('fixture.txt'), getline(1,'$'))
" Excludes trailing lines
@ -543,7 +907,7 @@ function Test_around_text_object()
normal dac
call s:trigger_gitgutter()
call assert_equal([], s:signs('fixture.txt'))
call s:assert_signs([], 'fixture.txt')
call assert_equal(readfile('fixture.txt'), getline(1,'$'))
" Includes trailing lines
@ -646,7 +1010,7 @@ function Test_encoding()
call s:trigger_gitgutter()
call assert_equal([], s:signs('cp932.txt'))
call s:assert_signs([], 'cp932.txt')
endfunction
@ -656,7 +1020,7 @@ function Test_empty_file()
edit empty.txt
call s:trigger_gitgutter()
call assert_equal([], s:signs('empty.txt'))
call s:assert_signs([], 'empty.txt')
" File consisting only of a newline
@ -664,7 +1028,7 @@ function Test_empty_file()
edit newline.txt
call s:trigger_gitgutter()
call assert_equal([], s:signs('newline.txt'))
call s:assert_signs([], 'newline.txt')
" 1 line file without newline
@ -674,7 +1038,177 @@ function Test_empty_file()
edit! oneline.txt
call s:trigger_gitgutter()
call assert_equal([], s:signs('oneline.txt'))
call s:assert_signs([], 'oneline.txt')
set eol fixeol
endfunction
function Test_quickfix()
call setline(5, ['A', 'B'])
call setline(9, ['C', 'D'])
write
GitGutterQuickFix
let expected = [
\ {'lnum': 5, 'bufnr': bufnr(''), 'text': '-e'},
\ {'lnum': 9, 'bufnr': bufnr(''), 'text': '-i'}
\ ]
call s:assert_list_of_dicts(expected, getqflist())
endfunction
function Test_common_prefix()
" zero length
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('', 'foo'))
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('foo', ''))
" nothing in common
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+pqrst'))
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('abcde', 'pqrst'))
" something in common
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+abcpq'))
call assert_equal(2, gitgutter#diff_highlight#common_prefix('abcde', 'abcpq'))
call assert_equal(0, gitgutter#diff_highlight#common_prefix('abc', 'apq'))
" everything in common
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+abcde'))
call assert_equal(4, gitgutter#diff_highlight#common_prefix('abcde', 'abcde'))
" different lengths
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+abx'))
call assert_equal(1, gitgutter#diff_highlight#common_prefix('abcde', 'abx'))
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abx', '+abcde'))
call assert_equal(1, gitgutter#diff_highlight#common_prefix('abx', 'abcde'))
call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+abc'))
call assert_equal(2, gitgutter#diff_highlight#common_prefix('abcde', 'abc'))
endfunction
function Test_common_suffix()
" nothing in common
call assert_equal([6,6], gitgutter#diff_highlight#common_suffix('-abcde', '+pqrst', 0))
" something in common
call assert_equal([3,3], gitgutter#diff_highlight#common_suffix('-abcde', '+pqcde', 0))
" everything in common
call assert_equal([5,5], gitgutter#diff_highlight#common_suffix('-abcde', '+abcde', 5))
" different lengths
call assert_equal([4,2], gitgutter#diff_highlight#common_suffix('-abcde', '+xde', 0))
call assert_equal([2,4], gitgutter#diff_highlight#common_suffix('-xde', '+abcde', 0))
endfunction
" Note the order of lists within the overall returned list does not matter.
function Test_diff_highlight()
" Ignores mismatched number of added and removed lines.
call assert_equal([], gitgutter#diff_highlight#process(['-foo']))
call assert_equal([], gitgutter#diff_highlight#process(['+foo']))
call assert_equal([], gitgutter#diff_highlight#process(['-foo','-bar','+baz']))
" everything changed
let hunk = ['-foo', '+cat']
let expected = []
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" change in middle
let hunk = ['-foo bar baz', '+foo zip baz']
let expected = [[1, '-', 6, 8], [2, '+', 6, 8]]
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" change at start
let hunk = ['-foo bar baz', '+zip bar baz']
let expected = [[1, '-', 2, 4], [2, '+', 2, 4]]
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" change at end
let hunk = ['-foo bar baz', '+foo bar zip']
let expected = [[1, '-', 10, 12], [2, '+', 10, 12]]
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" removed in middle
let hunk = ['-foo bar baz', '+foo baz']
let expected = [[1, '-', 8, 11]]
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" added in middle
let hunk = ['-foo baz', '+foo bar baz']
let expected = [[2, '+', 8, 11]]
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" two insertions at start
let hunk = ['-foo bar baz', '+(foo) bar baz']
let expected = [[2, '+', 2, 2], [2, '+', 6, 6]]
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" two insertions in middle
let hunk = ['-foo bar baz', '+foo (bar) baz']
let expected = [[2, '+', 6, 6], [2, '+', 10, 10]]
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" two insertions at end
let hunk = ['-foo bar baz', '+foo bar (baz)']
let expected = [[2, '+', 10, 10], [2, '+', 14, 14]]
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
" singular insertion
let hunk = ['-The cat in the hat.', '+The furry cat in the hat.']
call assert_equal([[2, '+', 6, 11]], gitgutter#diff_highlight#process(hunk))
" singular deletion
let hunk = ['-The cat in the hat.', '+The cat.']
call assert_equal([[1, '-', 9, 19]], gitgutter#diff_highlight#process(hunk))
" two insertions
let hunk = ['-The cat in the hat.', '+The furry cat in the teal hat.']
call assert_equal([[2, '+', 6, 11], [2, '+', 22, 26]], gitgutter#diff_highlight#process(hunk))
" two deletions
let hunk = ['-The furry cat in the teal hat.', '+The cat in the hat.']
call assert_equal([[1, '-', 6, 11], [1, '-', 22, 26]], gitgutter#diff_highlight#process(hunk))
" two edits
let hunk = ['-The cat in the hat.', '+The ox in the box.']
call assert_equal([[1, '-', 6, 8], [2, '+', 6, 7], [1, '-', 17, 19], [2, '+', 16, 18]], gitgutter#diff_highlight#process(hunk))
" Requires s:gap_between_regions = 2 to pass.
" let hunk = ['-foo: bar.zap', '+foo: quux(bar)']
" call assert_equal([[2, '+', 7, 11], [1, '-', 10, 13], [2, '+', 15, 15]], gitgutter#diff_highlight#process(hunk))
let hunk = ['-gross_value: transaction.unexplained_amount', '+gross_value: amount(transaction)']
call assert_equal([[2, '+', 15, 21], [1, '-', 26, 44], [2, '+', 33, 33]], gitgutter#diff_highlight#process(hunk))
let hunk = ['-gem "contact_sport", "~> 1.0.2"', '+gem ("contact_sport"), "~> 1.2"']
call assert_equal([[2, '+', 6, 6], [2, '+', 22, 22], [1, '-', 28, 29]], gitgutter#diff_highlight#process(hunk))
endfunction
function Test_lcs()
call assert_equal('', gitgutter#diff_highlight#lcs('', 'foo'))
call assert_equal('', gitgutter#diff_highlight#lcs('foo', ''))
call assert_equal('bar', gitgutter#diff_highlight#lcs('foobarbaz', 'bbart'))
call assert_equal('transaction', gitgutter#diff_highlight#lcs('transaction.unexplained_amount', 'amount(transaction)'))
endfunction
function Test_split()
call assert_equal(['foo', 'baz'], gitgutter#diff_highlight#split('foobarbaz', 'bar'))
call assert_equal(['', 'barbaz'], gitgutter#diff_highlight#split('foobarbaz', 'foo'))
call assert_equal(['foobar', ''], gitgutter#diff_highlight#split('foobarbaz', 'baz'))
call assert_equal(['1', '2'], gitgutter#diff_highlight#split('1~2', '~'))
endfunction
function Test_foldtext()
8d
call s:trigger_gitgutter()
call assert_equal(0, gitgutter#fold#is_changed())
let v:foldstart = 5
let v:foldend = 9
call assert_equal(1, gitgutter#fold#is_changed())
call assert_equal('+- 5 lines (*): e', gitgutter#fold#foldtext())
let v:foldstart = 1
let v:foldend = 3
call assert_equal(0, gitgutter#fold#is_changed())
call assert_equal('+- 3 lines: a', gitgutter#fold#foldtext())
endfunction