Codebase list vim-gitgutter / 7ab960ba-64f1-4069-aade-c3e70ed099cd/main
New upstream snapshot. Debian Janitor 1 year, 6 months ago
14 changed file(s) with 847 addition(s) and 413 deletion(s). Raw diff Collapse all Expand all
00 ## vim-gitgutter
11
2 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.
2 A Vim plugin which shows a git diff in the 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.
33
44 The signs are always up to date and the plugin never saves your buffer.
5
6 The name "gitgutter" comes from the Sublime Text 3 plugin which inspired this in 2013.
57
68 Features:
79
1517 * Stage partial hunks.
1618 * Provides a hunk text object.
1719 * Diffs against index (default) or any commit.
20 * Heeds git's "assume unchanged" bit.
1821 * Allows folding all unchanged text.
1922 * Provides fold text showing whether folded lines have been changed.
2023 * Can load all hunk locations into quickfix list or the current window's location list.
3235 * Supports git only. If you work with other version control systems, I recommend [vim-signify](https://github.com/mhinz/vim-signify).
3336 * Relies on the `FocusGained` event. If your terminal doesn't report focus events, either use something like [Terminus][] or set `let g:gitgutter_terminal_reports_focus=0`. For tmux, `set -g focus-events on` in your tmux.conf.
3437
38 Compatibility:
39
40 Compatible back to Vim 7.4, and probably 7.3.
41
3542
3643 ### Screenshot
3744
7077
7178 ### Windows
7279
73 I recommend configuring vim-gitgutter with the full path to your git executable. For example:
74
75 ```viml
80 There is a potential risk on Windows due to `cmd.exe` prioritising the current folder over folders in `PATH`. If you have a file named `git.*` (i.e. with any extension in `PATHEXT`) in your current folder, it will be executed instead of git whenever the plugin calls git.
81
82 You can avoid this risk by configuring the full path to your git executable. For example:
83
84 ```viml
85 " This path probably won't work
7686 let g:gitgutter_git_executable = 'C:\Program Files\Git\bin\git.exe'
7787 ```
7888
79 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.
89 Unfortunately I don't know the correct escaping for the path - if you do, please let me know!
8090
8191
8292 ### Getting started
8696 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.
8797
8898 You cannot unstage a staged hunk.
99
100 After updating the signs, the plugin fires the `GitGutter` User autocommand.
101
102 After staging a hunk or part of a hunk, the plugin fires the `GitGutterStage` User autocommand.
89103
90104
91105 #### Activation
126140
127141 If you switch off both line highlighting and signs, you won't see the sign column.
128142
129 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:
130
131 ```viml
132 let g:gitgutter_max_signs = 500 " default value
133 ```
143 In older Vims (pre 8.1.0614 / Neovim 0.4.0) vim-gitgutter will suppress the signs when a file has more than 500 changes, to avoid slowing down the UI. As soon as the number of changes falls below the limit vim-gitgutter will show the signs again. You can configure the threshold with:
144
145 ```viml
146 let g:gitgutter_max_signs = 500 " default value (Vim < 8.1.0614, Neovim < 0.4.0)
147 let g:gitgutter_max_signs = -1 " default value (otherwise)
148 ```
149
150 You can also remove the limit by setting `g:gitgutter_max_signs = -1`.
134151
135152 #### Hunks
136153
148165 nmap [h <Plug>(GitGutterPrevHunk)
149166 ```
150167
151 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.
168 When you jump between hunks, a message like `Hunk 4 of 11` is shown on the command line. If you want to turn the message off, you can use:
169
170 ```viml
171 let g:gitgutter_show_msg_on_hunk_jumping = 0
172 ```
173
174 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. Use `:copen` (or `:lopen`) to open the quickfix / location list or add a custom command like this:
175
176 ```viml
177 command! Gqf GitGutterQuickFix | copen
178 ```
152179
153180 You can stage or undo an individual hunk when your cursor is in it:
154181
209236 Finally, you can force vim-gitgutter to update its signs across all visible buffers with `:GitGutterAll`.
210237
211238 See the customisation section below for how to change the defaults.
239
240
241 ### Vimdiff
242
243 Use the `GitGutterDiffOrig` command to open a vimdiff view of the current buffer, respecting `g:gitgutter_diff_relative_to` and `:gitgutter_diff_base`.
212244
213245
214246 ### Folding
256288 * How to handle non-gitgutter signs
257289 * The signs' colours and symbols
258290 * Line highlights
291 * Line number highlights (only in Neovim 0.3.2 or higher)
292 * The diff syntax colours used in the preview window
293 * The intra-line diff highlights used in the preview window
259294 * Whether the diff is relative to the index (default) or working tree.
260295 * The base of the diff
261296 * Extra arguments for `git` when running `git diff`
269304 * Whether to clobber or preserve non-gitgutter signs
270305 * The priority of gitgutter's signs.
271306 * Whether to use a floating/popup window for hunk previews
307 * The appearance of a floating/popup window for hunk previews
272308 * Whether to populate the quickfix list or a location list with all hunks
273309
274310 Please note that vim-gitgutter won't override any colours or highlights you've set in your colorscheme.
276312
277313 #### Sign column
278314
279 By default vim-gitgutter will make the sign column look like the line number column.
280
281 To customise your sign column's background color, first tell vim-gitgutter to leave it alone:
282
283 ```viml
284 let g:gitgutter_override_sign_column_highlight = 0
285 ```
286
287 And then either update your colorscheme's `SignColumn` highlight group or set it in your vimrc:
288
289 ```viml
290 highlight SignColumn ctermbg=whatever " terminal Vim
291 highlight SignColumn guibg=whatever " gVim/MacVim
315 Set the `SignColumn` highlight group to change the sign column's colour. For example:
316
317 ```viml
318 " vim-gitgutter used to do this by default:
319 highlight! link SignColumn LineNr
320
321 " or you could do this:
322 highlight SignColumn guibg=whatever ctermbg=whatever
292323 ```
293324
294325 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:
307338
308339 #### Signs' colours and symbols
309340
310 By default vim-gitgutter uses your colourscheme's `Diff*` highlight groups' foreground colours for the signs' foreground colours. For example, your `DiffAdd` foreground colour will be used for the `+` sign's foreground colour.
311
312 The signs' background colours will all be set to the sign column's background colour.
313
314 If you don't like the default colours, you can either fix your colourscheme's `Diff*` highlights or configure your own `GitGutter*` highlight groups. These groups are:
315
316 ```viml
317 GitGutterAdd " an added line (default: links to DiffAdd)
318 GitGutterChange " a changed line (default: links to DiffChange)
319 GitGutterDelete " at least one removed line (default: links to DiffDelete)
320 GitGutterChangeDelete " a changed line followed by at least one removed line (default: links to GitGutterChange)
321 ```
322
323 You can either set these with `highlight GitGutterAdd {key}={arg}...` or link them to existing highlight groups with, say, `highlight link GitGutterAdd MyDiffAdd`.
324
325 To get vim-gitgutter's original colours (based on git-diff's colours in my terminal):
326
327 ```viml
328 highlight GitGutterAdd guifg=#009900 guibg=<X> ctermfg=2 ctermbg=<Y>
329 highlight GitGutterChange guifg=#bbbb00 guibg=<X> ctermfg=3 ctermbg=<Y>
330 highlight GitGutterDelete guifg=#ff2222 guibg=<X> ctermfg=1 ctermbg=<Y>
331 ```
332
333 – where you would replace `<X>` and `<Y>` with the background colour of your `SignColumn` in the gui and the terminal respectively. For example, with the solarized colorscheme and a dark background, `guibg=#073642` and `ctermbg=0`.
341 If you or your colourscheme has defined `GitGutter*` highlight groups, the plugin will use them for the signs' colours.
342
343 If you want the background colours to match the sign column, but don't want to update the `GitGutter*` groups yourself, you can get the plugin to do it:
344
345 ```viml
346 let g:gitgutter_set_sign_backgrounds = 1
347 ```
348
349 If no `GitGutter*` highlight groups exist, the plugin will check the `Diff*` highlight groups. If their foreground colours differ the plugin will use them; if not, these colours will be used:
350
351 ```viml
352 highlight GitGutterAdd guifg=#009900 ctermfg=2
353 highlight GitGutterChange guifg=#bbbb00 ctermfg=3
354 highlight GitGutterDelete guifg=#ff2222 ctermfg=1
355 ```
334356
335357 To customise the symbols, add the following to your `~/.vimrc`:
336358
339361 let g:gitgutter_sign_modified = 'yy'
340362 let g:gitgutter_sign_removed = 'zz'
341363 let g:gitgutter_sign_removed_first_line = '^^'
364 let g:gitgutter_sign_removed_above_and_below = '{'
342365 let g:gitgutter_sign_modified_removed = 'ww'
343366 ```
344367
381404 ```
382405
383406
407 #### The diff syntax colours used in the preview window
408
409 To change the diff syntax colours used in the preview window, set up the `diff*` highlight groups in your colorscheme or `~/.vimrc`:
410
411 ```viml
412 diffAdded " if not set: use GitGutterAdd's foreground colour
413 diffChanged " if not set: use GitGutterChange's foreground colour
414 diffRemoved " if not set: use GitGutterDelete's foreground colour
415 ```
416
417 Note the `diff*` highlight groups are used in any buffer whose `'syntax'` is `diff`.
418
419
420 #### The intra-line diff highlights used in the preview window
421
422 To change the intra-line diff highlights used in the preview window, set up the following highlight groups in your colorscheme or `~/.vimrc`:
423
424 ```viml
425 GitGutterAddIntraLine " default: gui=reverse cterm=reverse
426 GitGutterDeleteIntraLine " default: gui=reverse cterm=reverse
427 ```
428
429 For example, to use `DiffAdd` for intra-line added regions:
430
431 ```viml
432 highlight link GitGutterAddIntraLine DiffAdd
433 ```
434
435
384436 #### Whether the diff is relative to the index or working tree
385437
386438 By default diffs are relative to the index. How you can make them relative to the working tree:
471523 #### To use floating/popup windows for hunk previews
472524
473525 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.
526
527
528 #### The appearance of a floating/popup window for hunk previews
529
530 Set `g:gitgutter_floating_window_options` to a dictionary of the options you want. This dictionary is passed directly to `popup_create()` (Vim) / `nvim_open_win()` (Neovim).
474531
475532
476533 #### To load all hunks into the current window's location list instead of the quickfix list
633690
634691 Your colorscheme is configuring the `SignColumn` highlight group weirdly. Please see the section above on customising the sign column.
635692
636 > Why are the colours in the preview window weird?
637
638 Probably because your colourscheme doesn't configure the `diff{Added,Changed,Removed}` highlight groups. Try this in `after/syntax/diff.vim`:
639
640 ```viml
641 highlight link diffAdded DiffAdd
642 highlight link diffChanged DiffChange
643 highlight link diffRemoved DiffDelete
644 ```
645
646693 > What happens if I also use another plugin which uses signs (e.g. Syntastic)?
647694
648695 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.
658705 * Verify `:echo system("git --version")` succeeds.
659706 * Verify your git config is compatible with the version of git returned by the command above.
660707 * Verify your Vim supports signs (`:echo has('signs')` should give `1`).
661 * Verify your file is being tracked by git and has unstaged changes.
708 * Verify your file is being tracked by git and has unstaged changes. Check whether the plugin thinks git knows about your file: `:echo b:gitgutter.path` should show the path to the file in the repo.
709 * Execute `:sign place group=gitgutter`; you should see a list of signs.
710 - If the signs are listed: this is a colorscheme / highlight problem. Compare `:highlight GitGutterAdd` with `:highlight SignColumn`.
711 - If no signs are listed: the call to git-diff is probably failing. Add `let g:gitgutter_log=1` to your vimrc, restart, reproduce the problem, and look at the `gitgutter.log` file in the plugin's directory.
662712
663713 #### When the whole file is marked as added
664714
680730 * [Smash Into Vim][siv]
681731
682732 This was one of PeepCode's all-time top three bestsellers and is now available at Pluralsight.
683
684 You can read reviews on my [website][airblade].
685733
686734
687735 ### Intellectual Property
00 let s:available = has('nvim') || (
11 \ has('job') && (
2 \ (has('patch-7-4-1826') && !has('gui_running')) ||
3 \ (has('patch-7-4-1850') && has('gui_running')) ||
4 \ (has('patch-7-4-1832') && has('gui_macvim'))
2 \ (has('patch-7.4.1826') && !has('gui_running')) ||
3 \ (has('patch-7.4.1850') && has('gui_running')) ||
4 \ (has('patch-7.4.1832') && has('gui_macvim'))
55 \ )
66 \ )
7
8 let s:jobs = {}
79
810 function! gitgutter#async#available()
911 return s:available
2729 \ 'on_exit': function('s:on_exit_nvim')
2830 \ }))
2931 else
30 call job_start(command, {
32 let job = job_start(command, {
3133 \ 'out_cb': function('s:on_stdout_vim', options),
3234 \ 'err_cb': function('s:on_stderr_vim', options),
3335 \ 'close_cb': function('s:on_exit_vim', options)
3436 \ })
37 let s:jobs[s:job_id(job)] = 1
3538 endif
3639 endfunction
3740
8285
8386 function! s:on_exit_vim(channel) dict abort
8487 let job = ch_getjob(a:channel)
88 let jobid = s:job_id(job)
89 if has_key(s:jobs, jobid) | unlet s:jobs[jobid] | endif
8590 while 1
8691 if job_status(job) == 'dead'
8792 let exit_code = job_info(job).exitval
9499 call self.handler.out(self.buffer, join(self.stdoutbuffer, "\n"))
95100 endif
96101 endfunction
102
103 function! s:job_id(job)
104 " Vim
105 return job_info(a:job).process
106 endfunction
2121 call s:separator()
2222
2323 call s:option('updatetime')
24 call s:option('shell')
25 call s:option('shellcmdflag')
26 call s:option('shellpipe')
27 call s:option('shellquote')
28 call s:option('shellredir')
29 call s:option('shellslash')
30 call s:option('shelltemp')
31 call s:option('shelltype')
32 call s:option('shellxescape')
33 call s:option('shellxquote')
3424 endfunction
3525
3626
5141 endfunction
5242
5343 function! s:grep_version()
54 let v = system('grep --version')
44 let v = system(g:gitgutter_grep.' --version')
5545 call s:output( substitute(v, '\n$', '', '') )
5646
57 let v = system('grep --help')
47 let v = system(g:gitgutter_grep.' --help')
5848 call s:output( substitute(v, '\%x00', '', 'g') )
5949 endfunction
6050
1010 endfunction
1111
1212 let s:c_flag = s:git_supports_command_line_config_override()
13
1413
1514 let s:temp_from = tempname()
1615 let s:temp_buffer = tempname()
7069 " grep is available.
7170 function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort
7271 if gitgutter#utility#repo_path(a:bufnr, 0) == -1
73 throw 'gitgutter author fail'
72 throw 'gitgutter path not set'
7473 endif
7574
7675 if gitgutter#utility#repo_path(a:bufnr, 0) == -2
7776 throw 'gitgutter not tracked'
77 endif
78
79 if gitgutter#utility#repo_path(a:bufnr, 0) == -3
80 throw 'gitgutter assume unchanged'
7881 endif
7982
8083 " Wrap compound commands in parentheses to make Windows happy.
119122 endif
120123
121124 " Write file from index to temporary file.
122 let index_name = g:gitgutter_diff_base.':'.gitgutter#utility#repo_path(a:bufnr, 1)
125 let index_name = gitgutter#utility#get_diff_base(a:bufnr).':'.gitgutter#utility#repo_path(a:bufnr, 1)
123126 let cmd .= g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager show '.index_name.' > '.from_file.' && '
124127
125128 elseif a:from ==# 'working_tree'
127130 endif
128131
129132 " Call git-diff.
130 let cmd .= g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager '.g:gitgutter_git_args
133 let cmd .= g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager'
131134 if s:c_flag
132135 let cmd .= ' -c "diff.autorefreshindex=0"'
133136 let cmd .= ' -c "diff.noprefix=false"'
181184 let modified_lines = gitgutter#diff#process_hunks(a:bufnr, gitgutter#hunk#hunks(a:bufnr))
182185
183186 let signs_count = len(modified_lines)
184 if signs_count > g:gitgutter_max_signs
187 if g:gitgutter_max_signs != -1 && signs_count > g:gitgutter_max_signs
185188 call gitgutter#utility#warn_once(a:bufnr, printf(
186189 \ 'exceeded maximum number of signs (%d > %d, configured by g:gitgutter_max_signs).',
187190 \ signs_count, g:gitgutter_max_signs), 'max_signs')
399402 let bufcontents[0]=''.bufcontents[0]
400403 endif
401404
402 call writefile(bufcontents, a:file, 'b')
405 " The file we are writing to is a temporary file. Sometimes the parent
406 " directory is deleted outside Vim but, because Vim caches the directory
407 " name at startup and does not check for its existence subsequently, Vim
408 " does not realise. This causes E482 errors.
409 try
410 call writefile(bufcontents, a:file, 'b')
411 catch /E482/
412 call mkdir(fnamemodify(a:file, ':h'), '', '0700')
413 call writefile(bufcontents, a:file, 'b')
414 endtry
403415 endfunction
404416
405417
149149 return a:s1[endindex - maxlength + 1 : endindex]
150150 endfunction
151151
152 if $VIM_GITGUTTER_TEST
153 function! gitgutter#diff_highlight#lcs(s1, s2)
154 return s:lcs(a:s1, a:s2)
155 endfunction
156 endif
157
158152
159153 " Returns 0-based index of last character of common prefix
160154 " If there is no common prefix, returns -1.
167161 return -1
168162 endif
169163 for i in range(len)
170 if a:a[i:i] != a:b[i:i]
164 if a:a[i:i] !=# a:b[i:i]
171165 return i - 1
172166 endif
173167 endfor
174168 return i
175169 endfunction
176
177 if $VIM_GITGUTTER_TEST
178 function! gitgutter#diff_highlight#common_prefix(a, b)
179 return s:common_prefix(a:a, a:b)
180 endfunction
181 endif
182170
183171
184172 " Returns 0-based indices of start of common suffix
198186 return [sa+1, sb+1]
199187 endfunction
200188
201 if $VIM_GITGUTTER_TEST
202 function! gitgutter#diff_highlight#common_suffix(a, b, start)
203 return s:common_suffix(a:a, a:b, a:start)
204 endfunction
205 endif
206
207189
208190 " Split a string on another string.
209191 " Assumes 1 occurrence of the delimiter.
216198
217199 return [a:str[:i-1], a:str[i+len(a:delimiter):]]
218200 endfunction
219
220 if $VIM_GITGUTTER_TEST
221 function! gitgutter#diff_highlight#split(str, delimiter)
222 return s:split(a:str, a:delimiter)
223 endfunction
224 endif
6262 endif
6363 endfunction
6464
65
66 function! gitgutter#highlight#define_sign_column_highlight() abort
67 if g:gitgutter_override_sign_column_highlight
68 highlight! link SignColumn LineNr
69 else
70 highlight default link SignColumn LineNr
71 endif
72 endfunction
7365
7466 function! gitgutter#highlight#define_highlights() abort
7567 let [guibg, ctermbg] = s:get_background_colors('SignColumn')
8375 highlight default link GitGutterChangeDeleteInvisible GitGutterChangeInvisible
8476
8577 " When they are visible.
86 " By default use Diff* foreground colors with SignColumn's background.
87 for type in ['Add', 'Change', 'Delete']
88 let [guifg, ctermfg] = s:get_foreground_colors('Diff'.type)
89 execute "highlight GitGutter".type."Default guifg=".guifg." guibg=".guibg." ctermfg=".ctermfg." ctermbg=".ctermbg
90 execute "highlight default link GitGutter".type." GitGutter".type."Default"
78 for type in ["Add", "Change", "Delete"]
79 if hlexists("GitGutter".type) && s:get_foreground_colors("GitGutter".type) != ['NONE', 'NONE']
80 if g:gitgutter_set_sign_backgrounds
81 execute "highlight GitGutter".type." guibg=".guibg." ctermbg=".ctermbg
82 endif
83 continue
84 elseif s:useful_diff_colours()
85 let [guifg, ctermfg] = s:get_foreground_colors('Diff'.type)
86 else
87 let [guifg, ctermfg] = s:get_foreground_fallback_colors(type)
88 endif
89 execute "highlight GitGutter".type." guifg=".guifg." guibg=".guibg." ctermfg=".ctermfg." ctermbg=".ctermbg
9190 endfor
91
92 if hlexists("GitGutterChangeDelete") && g:gitgutter_set_sign_backgrounds
93 execute "highlight GitGutterChangeDelete guibg=".guibg." ctermbg=".ctermbg
94 endif
95
9296 highlight default link GitGutterChangeDelete GitGutterChange
9397
9498 " Highlights used for the whole line.
104108 highlight default link GitGutterChangeDeleteLineNr CursorLineNr
105109
106110 " Highlights used intra line.
107 highlight GitGutterAddIntraLine gui=reverse cterm=reverse
108 highlight GitGutterDeleteIntraLine gui=reverse cterm=reverse
111 highlight default GitGutterAddIntraLine gui=reverse cterm=reverse
112 highlight default GitGutterDeleteIntraLine gui=reverse cterm=reverse
113 " Set diff syntax colours (used in the preview window) - diffAdded,diffChanged,diffRemoved -
114 " to match the signs, if not set aleady.
115 for [dtype,type] in [['Added','Add'], ['Changed','Change'], ['Removed','Delete']]
116 if !hlexists('diff'.dtype)
117 let [guifg, ctermfg] = s:get_foreground_colors('GitGutter'.type)
118 execute "highlight diff".dtype." guifg=".guifg." ctermfg=".ctermfg." guibg=NONE ctermbg=NONE"
119 endif
120 endfor
109121 endfunction
110122
111123 function! gitgutter#highlight#define_signs() abort
162174 sign define GitGutterLineRemovedAboveAndBelow linehl=GitGutterDeleteLine
163175 sign define GitGutterLineModifiedRemoved linehl=GitGutterChangeDeleteLine
164176 else
165 sign define GitGutterLineAdded linehl=
166 sign define GitGutterLineModified linehl=
167 sign define GitGutterLineRemoved linehl=
168 sign define GitGutterLineRemovedFirstLine linehl=
169 sign define GitGutterLineRemovedAboveAndBelow linehl=
170 sign define GitGutterLineModifiedRemoved linehl=
177 sign define GitGutterLineAdded linehl=NONE
178 sign define GitGutterLineModified linehl=NONE
179 sign define GitGutterLineRemoved linehl=NONE
180 sign define GitGutterLineRemovedFirstLine linehl=NONE
181 sign define GitGutterLineRemovedAboveAndBelow linehl=NONE
182 sign define GitGutterLineModifiedRemoved linehl=NONE
171183 endif
172184 endfunction
173185
182194 sign define GitGutterLineRemovedAboveAndBelow numhl=GitGutterDeleteLineNr
183195 sign define GitGutterLineModifiedRemoved numhl=GitGutterChangeDeleteLineNr
184196 else
185 sign define GitGutterLineAdded numhl=
186 sign define GitGutterLineModified numhl=
187 sign define GitGutterLineRemoved numhl=
188 sign define GitGutterLineRemovedFirstLine numhl=
189 sign define GitGutterLineRemovedAboveAndBelow numhl=
190 sign define GitGutterLineModifiedRemoved numhl=
197 sign define GitGutterLineAdded numhl=NONE
198 sign define GitGutterLineModified numhl=NONE
199 sign define GitGutterLineRemoved numhl=NONE
200 sign define GitGutterLineRemovedFirstLine numhl=NONE
201 sign define GitGutterLineRemovedAboveAndBelow numhl=NONE
202 sign define GitGutterLineModifiedRemoved numhl=NONE
191203 endif
192204 catch /E475/
193205 endtry
213225 let guibg = s:get_hl(a:group, 'bg', 'gui')
214226 return [guibg, ctermbg]
215227 endfunction
228
229 function! s:useful_diff_colours()
230 let [guifg_add, ctermfg_add] = s:get_foreground_colors('DiffAdd')
231 let [guifg_del, ctermfg_del] = s:get_foreground_colors('DiffDelete')
232
233 return guifg_add != guifg_del && ctermfg_add != ctermfg_del
234 endfunction
235
236 function! s:get_foreground_fallback_colors(type)
237 if a:type == 'Add'
238 return ['#009900', '2']
239 elseif a:type == 'Change'
240 return ['#bbbb00', '3']
241 elseif a:type == 'Delete'
242 return ['#ff2222', '1']
243 endif
244 endfunction
00 let s:winid = 0
1 let s:preview_bufnr = 0
2 let s:nomodeline = (v:version > 703 || (v:version == 703 && has('patch442'))) ? '<nomodeline>' : ''
13
24 function! gitgutter#hunk#set_hunks(bufnr, hunks) abort
35 call gitgutter#utility#setbufvar(a:bufnr, 'hunks', a:hunks)
4345
4446 function! gitgutter#hunk#next_hunk(count) abort
4547 let bufnr = bufnr('')
46 if gitgutter#utility#is_active(bufnr)
47 let current_line = line('.')
48 let hunk_count = 0
49 for hunk in gitgutter#hunk#hunks(bufnr)
50 if hunk[2] > current_line
51 let hunk_count += 1
52 if hunk_count == a:count
53 execute 'normal!' hunk[2] . 'Gzv'
54 return
48 if !gitgutter#utility#is_active(bufnr) | return | endif
49
50 let hunks = gitgutter#hunk#hunks(bufnr)
51 if empty(hunks)
52 call gitgutter#utility#warn('No hunks in file')
53 return
54 endif
55
56 let current_line = line('.')
57 let hunk_count = 0
58 for hunk in hunks
59 if hunk[2] > current_line
60 let hunk_count += 1
61 if hunk_count == a:count
62 execute 'normal!' hunk[2] . 'Gzv'
63 if g:gitgutter_show_msg_on_hunk_jumping
64 redraw | echo printf('Hunk %d of %d', index(hunks, hunk) + 1, len(hunks))
5565 endif
66 if gitgutter#hunk#is_preview_window_open()
67 call gitgutter#hunk#preview()
68 endif
69 return
5670 endif
57 endfor
58 call gitgutter#utility#warn('No more hunks')
59 endif
71 endif
72 endfor
73 call gitgutter#utility#warn('No more hunks')
6074 endfunction
6175
6276 function! gitgutter#hunk#prev_hunk(count) abort
6377 let bufnr = bufnr('')
64 if gitgutter#utility#is_active(bufnr)
65 let current_line = line('.')
66 let hunk_count = 0
67 for hunk in reverse(copy(gitgutter#hunk#hunks(bufnr)))
68 if hunk[2] < current_line
69 let hunk_count += 1
70 if hunk_count == a:count
71 let target = hunk[2] == 0 ? 1 : hunk[2]
72 execute 'normal!' target . 'Gzv'
73 return
78 if !gitgutter#utility#is_active(bufnr) | return | endif
79
80 let hunks = gitgutter#hunk#hunks(bufnr)
81 if empty(hunks)
82 call gitgutter#utility#warn('No hunks in file')
83 return
84 endif
85
86 let current_line = line('.')
87 let hunk_count = 0
88 for hunk in reverse(copy(hunks))
89 if hunk[2] < current_line
90 let hunk_count += 1
91 if hunk_count == a:count
92 let target = hunk[2] == 0 ? 1 : hunk[2]
93 execute 'normal!' target . 'Gzv'
94 if g:gitgutter_show_msg_on_hunk_jumping
95 redraw | echo printf('Hunk %d of %d', index(hunks, hunk) + 1, len(hunks))
7496 endif
97 if gitgutter#hunk#is_preview_window_open()
98 call gitgutter#hunk#preview()
99 endif
100 return
75101 endif
76 endfor
77 call gitgutter#utility#warn('No previous hunks')
78 endif
102 endif
103 endfor
104 call gitgutter#utility#warn('No previous hunks')
79105 endfunction
80106
81107 " Returns the hunk the cursor is currently in or an empty list if the cursor
222248 let hunk_diff = join(hunk_header + hunk_body, "\n")."\n"
223249
224250 call s:goto_original_window()
225 call s:close_hunk_preview_window()
251 call gitgutter#hunk#close_hunk_preview_window()
226252 call s:stage(hunk_diff)
227253 endif
228254
236262 let g:gitgutter_async = async
237263
238264 call gitgutter#hunk#set_hunks(bufnr, gitgutter#diff#parse_diff(diff))
265 call gitgutter#diff#process_hunks(bufnr, gitgutter#hunk#hunks(bufnr)) " so the hunk summary is updated
239266
240267 if empty(s:current_hunk())
241 call gitgutter#utility#warn('cursor is not in a hunk')
268 call gitgutter#utility#warn('Cursor is not in a hunk')
242269 elseif s:cursor_in_two_hunks()
243270 let choice = input('Choose hunk: upper or lower (u/l)? ')
244271 " Clear input
248275 elseif choice =~ 'l'
249276 call a:op(gitgutter#diff#hunk_diff(bufnr, diff, 1))
250277 else
251 call gitgutter#utility#warn('did not recognise your choice')
278 call gitgutter#utility#warn('Did not recognise your choice')
252279 endif
253280 else
254281 let hunk_diff = gitgutter#diff#hunk_diff(bufnr, diff)
272299 \ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' apply --cached --unidiff-zero - '),
273300 \ diff)
274301 if v:shell_error
275 call gitgutter#utility#warn('patch does not apply')
302 call gitgutter#utility#warn('Patch does not apply')
303 else
304 if exists('#User#GitGutterStage')
305 execute 'doautocmd' s:nomodeline 'User GitGutterStage'
306 endif
276307 endif
277308
278309 " Refresh gitgutter's view of buffer.
349380
350381 return join(lines, "\n")."\n"
351382 endfunction
352
353 if $VIM_GITGUTTER_TEST
354 function! gitgutter#hunk#fix_file_references(filepath, hunk_diff)
355 return s:fix_file_references(a:filepath, a:hunk_diff)
356 endfunction
357 endif
358383
359384
360385 function! s:adjust_hunk_summary(hunk_diff) abort
395420 function! s:open_hunk_preview_window()
396421 if g:gitgutter_preview_win_floating
397422 if exists('*nvim_open_win')
398 call s:close_hunk_preview_window()
423 call gitgutter#hunk#close_hunk_preview_window()
399424
400425 let buf = nvim_create_buf(v:false, v:false)
401426 " Set default width and height for now.
402 let s:winid = nvim_open_win(buf, v:false, {
403 \ 'relative': 'cursor',
404 \ 'row': 1,
405 \ 'col': 0,
406 \ 'width': 42,
407 \ 'height': &previewheight,
408 \ 'style': 'minimal'
409 \ })
427 let s:winid = nvim_open_win(buf, v:false, g:gitgutter_floating_window_options)
410428 call nvim_buf_set_option(buf, 'filetype', 'diff')
411429 call nvim_buf_set_option(buf, 'buftype', 'acwrite')
412430 call nvim_buf_set_option(buf, 'bufhidden', 'delete')
414432 call nvim_buf_set_name(buf, 'gitgutter://hunk-preview')
415433
416434 " Assumes cursor is in original window.
417 autocmd CursorMoved <buffer> ++once call s:close_hunk_preview_window()
435 autocmd CursorMoved <buffer> ++once call gitgutter#hunk#close_hunk_preview_window()
436
437 if g:gitgutter_close_preview_on_escape
438 " Map <Esc> to close the floating preview.
439 nnoremap <buffer> <silent> <Esc> :<C-U>call gitgutter#hunk#close_hunk_preview_window()<CR>
440 " Ensure that when the preview window is closed, the map is removed.
441 autocmd User GitGutterPreviewClosed silent! nunmap <buffer> <Esc>
442 autocmd CursorMoved <buffer> ++once silent! nunmap <buffer> <Esc>
443 execute "autocmd WinClosed <buffer=".winbufnr(s:winid)."> doautocmd" s:nomodeline "User GitGutterPreviewClosed"
444 endif
418445
419446 return
420447 endif
421448
422449 if exists('*popup_create')
423 let s:winid = popup_create('', {
424 \ 'line': 'cursor+1',
425 \ 'col': 'cursor',
426 \ 'moved': 'any',
427 \ })
450 if g:gitgutter_close_preview_on_escape
451 let g:gitgutter_floating_window_options.filter = function('s:close_popup_on_escape')
452 endif
453
454 let s:winid = popup_create('', g:gitgutter_floating_window_options)
428455
429456 call setbufvar(winbufnr(s:winid), '&filetype', 'diff')
430457
432459 endif
433460 endif
434461
462 if exists('&previewpopup')
463 let [previewpopup, &previewpopup] = [&previewpopup, '']
464 endif
465
466 " Specifying where to open the preview window can lead to the cursor going
467 " to an unexpected window when the preview window is closed (#769).
468 silent! noautocmd execute g:gitgutter_preview_win_location 'pedit gitgutter://hunk-preview'
435469 silent! wincmd P
436 if !&previewwindow
437 noautocmd execute g:gitgutter_preview_win_location &previewheight 'new gitgutter://hunk-preview'
438 doautocmd WinEnter
470 setlocal statusline=%{''}
471 doautocmd WinEnter
472 if exists('*win_getid')
439473 let s:winid = win_getid()
440 set previewwindow
441 setlocal filetype=diff buftype=acwrite bufhidden=delete
442 " Reset some defaults in case someone else has changed them.
443 setlocal noreadonly modifiable noswapfile
444 endif
474 else
475 let s:preview_bufnr = bufnr('')
476 endif
477 setlocal filetype=diff buftype=acwrite bufhidden=delete
478 " Reset some defaults in case someone else has changed them.
479 setlocal noreadonly modifiable noswapfile
480 if g:gitgutter_close_preview_on_escape
481 " Ensure cursor goes to the expected window.
482 nnoremap <buffer> <silent> <Esc> :<C-U>wincmd p<Bar>pclose<CR>
483 endif
484
485 if exists('&previewpopup')
486 let &previewpopup=previewpopup
487 endif
488 endfunction
489
490
491 function! s:close_popup_on_escape(winid, key)
492 if a:key == "\<Esc>"
493 call popup_close(a:winid)
494 return 1
495 endif
496 return 0
445497 endfunction
446498
447499
449501 " Preview window: assumes cursor is in preview window.
450502 function! s:populate_hunk_preview_window(header, body)
451503 let body_length = len(a:body)
452 let height = min([body_length, &previewheight])
453504
454505 if g:gitgutter_preview_win_floating
455506 if exists('*nvim_open_win')
507 let height = min([body_length, g:gitgutter_floating_window_options.height])
508
456509 " Assumes cursor is not in previewing window.
457510 call nvim_buf_set_var(winbufnr(s:winid), 'hunk_header', a:header)
511
512 let [_scrolloff, &scrolloff] = [&scrolloff, 0]
458513
459514 let width = max(map(copy(a:body), 'strdisplaywidth(v:val)'))
460515 call nvim_win_set_width(s:winid, width)
461516 call nvim_win_set_height(s:winid, height)
517
518 let &scrolloff=_scrolloff
462519
463520 call nvim_buf_set_lines(winbufnr(s:winid), 0, -1, v:false, [])
464521 call nvim_buf_set_lines(winbufnr(s:winid), 0, -1, v:false, a:body)
485542
486543 else
487544 let b:hunk_header = a:header
488 execute 'resize' height
489545
490546 %delete _
491547 call setline(1, a:body)
492548 setlocal nomodified
549
550 normal! G$
551 let hunk_height = max([body_length, winline()])
552 let height = min([hunk_height, &previewheight])
553 execute 'resize' height
554 1
493555
494556 call clearmatches()
495557 for region in gitgutter#diff_highlight#process(a:body)
505567 function! s:enable_staging_from_hunk_preview_window()
506568 augroup gitgutter_hunk_preview
507569 autocmd!
508 execute 'autocmd BufWriteCmd <buffer='.winbufnr(s:winid).'> GitGutterStageHunk'
570 let bufnr = s:winid != 0 ? winbufnr(s:winid) : s:preview_bufnr
571 execute 'autocmd BufWriteCmd <buffer='.bufnr.'> GitGutterStageHunk'
509572 augroup END
510573 endfunction
511574
516579 endfunction
517580
518581
519 function! s:close_hunk_preview_window()
520 call setbufvar(winbufnr(s:winid), '&modified', 0)
582 function! gitgutter#hunk#close_hunk_preview_window()
583 let bufnr = s:winid != 0 ? winbufnr(s:winid) : s:preview_bufnr
584 call setbufvar(bufnr, '&modified', 0)
521585
522586 if g:gitgutter_preview_win_floating
523587 if win_id2win(s:winid) > 0
528592 endif
529593
530594 let s:winid = 0
531 endfunction
595 let s:preview_bufnr = 0
596 endfunction
597
598
599 function gitgutter#hunk#is_preview_window_open()
600 if g:gitgutter_preview_win_floating
601 if win_id2win(s:winid) > 0
602 execute win_id2win(s:winid).'wincmd c'
603 endif
604 else
605 for i in range(1, winnr('$'))
606 if getwinvar(i, '&previewwindow')
607 return 1
608 endif
609 endfor
610 endif
611 return 0
612 endfunction
2929
3030 function! gitgutter#utility#warn(message) abort
3131 echohl WarningMsg
32 echo 'vim-gitgutter: ' . a:message
32 echo a:message
3333 echohl None
3434 let v:warningmsg = a:message
3535 endfunction
3838 if empty(gitgutter#utility#getbufvar(a:bufnr, a:key))
3939 call gitgutter#utility#setbufvar(a:bufnr, a:key, '1')
4040 echohl WarningMsg
41 redraw | echom 'vim-gitgutter: ' . a:message
41 redraw | echom a:message
4242 echohl None
4343 let v:warningmsg = a:message
4444 endif
4747 " Returns truthy when the buffer's file should be processed; and falsey when it shouldn't.
4848 " This function does not and should not make any system calls.
4949 function! gitgutter#utility#is_active(bufnr) abort
50 return g:gitgutter_enabled &&
51 \ gitgutter#utility#getbufvar(a:bufnr, 'enabled', 1) &&
50 return gitgutter#utility#getbufvar(a:bufnr, 'enabled') &&
5251 \ !pumvisible() &&
5352 \ s:is_file_buffer(a:bufnr) &&
5453 \ s:exists_file(a:bufnr) &&
108107 " * non-empty string - path
109108 " * -1 - pending
110109 " * -2 - not tracked by git
110 " * -3 - assume unchanged
111111 function! gitgutter#utility#repo_path(bufnr, shellesc) abort
112112 let p = gitgutter#utility#getbufvar(a:bufnr, 'path', '')
113113 return a:shellesc ? gitgutter#utility#shellescape(p) : p
116116
117117 let s:set_path_handler = {}
118118
119 function! s:set_path_handler.out(buffer, path) abort
120 let path = s:strip_trailing_new_line(a:path)
121 call gitgutter#utility#setbufvar(a:buffer, 'path', path)
119 function! s:set_path_handler.out(buffer, listing) abort
120 let listing = s:strip_trailing_new_line(a:listing)
121 let [status, path] = [listing[0], listing[2:]]
122 if status =~# '[a-z]'
123 call gitgutter#utility#setbufvar(a:buffer, 'path', -3)
124 else
125 call gitgutter#utility#setbufvar(a:buffer, 'path', path)
126 endif
122127
123128 if type(self.continuation) == type(function('tr'))
124129 call self.continuation()
140145 " * non-empty string - path
141146 " * -1 - pending
142147 " * -2 - not tracked by git
148 " * -3 - assume unchanged
143149
144150 call gitgutter#utility#setbufvar(a:bufnr, 'path', -1)
145 let cmd = gitgutter#utility#cd_cmd(a:bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' ls-files --error-unmatch --full-name -z -- '.gitgutter#utility#shellescape(s:filename(a:bufnr)))
151 let cmd = gitgutter#utility#cd_cmd(a:bufnr,
152 \ g:gitgutter_git_executable.' '.g:gitgutter_git_args.
153 \ ' ls-files -v --error-unmatch --full-name -z -- '.
154 \ gitgutter#utility#shellescape(s:filename(a:bufnr)))
146155
147156 if g:gitgutter_async && gitgutter#async#available() && !has('vim_starting')
148157 let handler = copy(s:set_path_handler)
151160 return 'async'
152161 endif
153162
154 let path = gitgutter#utility#system(cmd)
163 let listing = gitgutter#utility#system(cmd)
164
155165 if v:shell_error
156166 call gitgutter#utility#setbufvar(a:bufnr, 'path', -2)
157 else
158 call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(path))
167 return
168 endif
169
170 let listing = s:strip_trailing_new_line(listing)
171 let [status, path] = [listing[0], listing[2:]]
172 if status =~# '[a-z]'
173 call gitgutter#utility#setbufvar(a:bufnr, 'path', -3)
174 else
175 call gitgutter#utility#setbufvar(a:bufnr, 'path', path)
159176 endif
160177 endfunction
161178
162179
163180 function! gitgutter#utility#cd_cmd(bufnr, cmd) abort
164 let cd = s:unc_path(a:bufnr) ? 'pushd' : (gitgutter#utility#windows() ? 'cd /d' : 'cd')
181 let cd = s:unc_path(a:bufnr) ? 'pushd' : (gitgutter#utility#windows() && s:dos_shell() ? 'cd /d' : 'cd')
165182 return cd.' '.s:dir(a:bufnr).' && '.a:cmd
166183 endfunction
167184
169186 return s:abs_path(a:bufnr, 0) =~ '^\\\\'
170187 endfunction
171188
189 function! s:dos_shell()
190 return &shell == 'cmd.exe' || &shell == 'command.com'
191 endfunction
192
172193 function! s:use_known_shell() abort
173194 if has('unix') && &shell !=# 'sh'
174 let [s:shell, s:shellcmdflag, s:shellredir] = [&shell, &shellcmdflag, &shellredir]
195 let [s:shell, s:shellcmdflag, s:shellredir, s:shellpipe, s:shellquote, s:shellxquote] = [&shell, &shellcmdflag, &shellredir, &shellpipe, &shellquote, &shellxquote]
175196 let &shell = 'sh'
176197 set shellcmdflag=-c shellredir=>%s\ 2>&1
177198 endif
199 if has('win32') && (&shell =~# 'pwsh' || &shell =~# 'powershell')
200 let [s:shell, s:shellcmdflag, s:shellredir, s:shellpipe, s:shellquote, s:shellxquote] = [&shell, &shellcmdflag, &shellredir, &shellpipe, &shellquote, &shellxquote]
201 let &shell = 'cmd.exe'
202 set shellcmdflag=/s\ /c shellredir=>%s\ 2>&1 shellpipe=>%s\ 2>&1 shellquote= shellxquote="
203 endif
178204 endfunction
179205
180206 function! s:restore_shell() abort
181 if has('unix') && exists('s:shell')
182 let [&shell, &shellcmdflag, &shellredir] = [s:shell, s:shellcmdflag, s:shellredir]
183 endif
184 endfunction
185
186 function! gitgutter#utility#set_diff_base_if_fugitive(bufnr)
207 if (has('unix') || has('win32')) && exists('s:shell')
208 let [&shell, &shellcmdflag, &shellredir, &shellpipe, &shellquote, &shellxquote] = [s:shell, s:shellcmdflag, s:shellredir, s:shellpipe, s:shellquote, s:shellxquote]
209 endif
210 endfunction
211
212 function! gitgutter#utility#get_diff_base(bufnr)
187213 let p = resolve(expand('#'.a:bufnr.':p'))
188214 let ml = matchlist(p, '\v^fugitive:/.*/(\x{40,})/')
189215 if !empty(ml) && !empty(ml[1])
190 let g:gitgutter_diff_base = ml[1].'^'
191 endif
216 return ml[1].'^'
217 endif
218 return g:gitgutter_diff_base
192219 endfunction
193220
194221 function! s:abs_path(bufnr, shellesc)
2020 function! gitgutter#process_buffer(bufnr, force) abort
2121 " NOTE a:bufnr is not necessarily the current buffer.
2222
23 if gitgutter#utility#getbufvar(a:bufnr, 'enabled', -1) == -1
24 call gitgutter#utility#setbufvar(a:bufnr, 'enabled', g:gitgutter_enabled)
25 endif
26
2327 if gitgutter#utility#is_active(a:bufnr)
2428
2529 if has('patch-7.4.1559')
3135 if [how] == ['async'] " avoid string-to-number conversion if how is a number
3236 return
3337 endif
34
35 call gitgutter#utility#set_diff_base_if_fugitive(a:bufnr)
3638
3739 if a:force || s:has_fresh_changes(a:bufnr)
3840
4143 let diff = gitgutter#diff#run_diff(a:bufnr, g:gitgutter_diff_relative_to, 0)
4244 catch /gitgutter not tracked/
4345 call gitgutter#debug#log('Not tracked: '.gitgutter#utility#file(a:bufnr))
46 catch /gitgutter assume unchanged/
47 call gitgutter#debug#log('Assume unchanged: '.gitgutter#utility#file(a:bufnr))
4448 catch /gitgutter diff failed/
4549 call gitgutter#debug#log('Diff failed: '.gitgutter#utility#file(a:bufnr))
4650 call gitgutter#hunk#reset(a:bufnr)
5660
5761
5862 function! gitgutter#disable() abort
59 " get list of all buffers (across all tabs)
63 call s:toggle_each_buffer(0)
64 let g:gitgutter_enabled = 0
65 endfunction
66
67 function! gitgutter#enable() abort
68 call s:toggle_each_buffer(1)
69 let g:gitgutter_enabled = 1
70 endfunction
71
72 function s:toggle_each_buffer(enable)
6073 for bufnr in range(1, bufnr('$') + 1)
6174 if buflisted(bufnr)
6275 let file = expand('#'.bufnr.':p')
6376 if !empty(file)
64 call s:clear(bufnr)
77 if a:enable
78 call gitgutter#buffer_enable(bufnr)
79 else
80 call gitgutter#buffer_disable(bufnr)
81 end
6582 endif
6683 endif
6784 endfor
68
69 let g:gitgutter_enabled = 0
70 endfunction
71
72 function! gitgutter#enable() abort
73 let g:gitgutter_enabled = 1
74 call gitgutter#all(1)
7585 endfunction
7686
7787 function! gitgutter#toggle() abort
8393 endfunction
8494
8595
86 function! gitgutter#buffer_disable() abort
87 let bufnr = bufnr('')
96 function! gitgutter#buffer_disable(...) abort
97 let bufnr = a:0 ? a:1 : bufnr('')
8898 call gitgutter#utility#setbufvar(bufnr, 'enabled', 0)
8999 call s:clear(bufnr)
90100 endfunction
91101
92 function! gitgutter#buffer_enable() abort
93 let bufnr = bufnr('')
102 function! gitgutter#buffer_enable(...) abort
103 let bufnr = a:0 ? a:1 : bufnr('')
94104 call gitgutter#utility#setbufvar(bufnr, 'enabled', 1)
95105 call gitgutter#process_buffer(bufnr, 1)
96106 endfunction
97107
98 function! gitgutter#buffer_toggle() abort
99 if gitgutter#utility#getbufvar(bufnr(''), 'enabled', 1)
100 call gitgutter#buffer_disable()
101 else
102 call gitgutter#buffer_enable()
108 function! gitgutter#buffer_toggle(...) abort
109 let bufnr = a:0 ? a:1 : bufnr('')
110 if gitgutter#utility#getbufvar(bufnr, 'enabled', 1)
111 call gitgutter#buffer_disable(bufnr)
112 else
113 call gitgutter#buffer_enable(bufnr)
103114 endif
104115 endfunction
105116
180191 " - this runs synchronously
181192 " - it ignores unsaved changes in buffers
182193 " - it does not change to the repo root
183 function! gitgutter#quickfix()
194 function! gitgutter#quickfix(current_file)
195 let cmd = g:gitgutter_git_executable.' '.g:gitgutter_git_args.' rev-parse --show-cdup'
196 let path_to_repo = get(systemlist(cmd), 0, '')
197 if !empty(path_to_repo) && path_to_repo[-1:] != '/'
198 let path_to_repo .= '/'
199 endif
200
184201 let locations = []
185 let cmd = g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager '.g:gitgutter_git_args.
186 \ ' diff --no-ext-diff --no-color -U0 '.g:gitgutter_diff_args. ' '. g:gitgutter_diff_base
202 let cmd = g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager'.
203 \ ' diff --no-ext-diff --no-color -U0'.
204 \ ' --src-prefix=a/'.path_to_repo.' --dst-prefix=b/'.path_to_repo.' '.
205 \ g:gitgutter_diff_args. ' '. g:gitgutter_diff_base
206 if a:current_file
207 let cmd = cmd.' -- '.expand('%:p')
208 endif
187209 let diff = systemlist(cmd)
188210 let lnum = 0
189211 for line in diff
195217 elseif line =~ '^diff --git "'
196218 let [_, fnamel, _, fnamer] = split(line, '"')
197219 let fname = fnamel ==# fnamer ? fnamel : fnamel[2:]
220 elseif line =~ '^diff --cc [^"]'
221 let fname = line[10:]
222 elseif line =~ '^diff --cc "'
223 let [_, fname] = split(line, '"')
198224 elseif line =~ '^@@'
199225 let lnum = matchlist(line, '+\(\d\+\)')[1]
200226 elseif lnum > 0
208234 call setloclist(0, locations)
209235 endif
210236 endfunction
237
238
239 function! gitgutter#difforig()
240 let bufnr = bufnr('')
241 let path = gitgutter#utility#repo_path(bufnr, 1)
242 let filetype = &filetype
243
244 vertical new
245 set buftype=nofile
246 let &filetype = filetype
247
248 if g:gitgutter_diff_relative_to ==# 'index'
249 let index_name = gitgutter#utility#get_diff_base(bufnr).':'.path
250 let cmd = gitgutter#utility#cd_cmd(bufnr,
251 \ g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager show '.index_name
252 \ )
253 " NOTE: this uses &shell to execute cmd. Perhaps we should use instead
254 " gitgutter#utility's use_known_shell() / restore_shell() functions.
255 silent! execute "read ++edit !" cmd
256 else
257 silent! execute "read ++edit" path
258 endif
259
260 0d_
261 diffthis
262 wincmd p
263 diffthis
264 endfunction
0 vim-gitgutter (0~20200414+git20220824.1.f19b620-1) UNRELEASED; urgency=low
1
2 * New upstream snapshot.
3
4 -- Debian Janitor <janitor@jelmer.uk> Fri, 21 Oct 2022 21:43:59 -0000
5
06 vim-gitgutter (0~20200414-2) unstable; urgency=medium
17
28 * Team upload.
00 *gitgutter.txt* A Vim plugin which shows a git diff in the gutter.
11
22
3 Vim Git Gutter
3 Vim GitGutter
44
55
66 Author: Andy Stewart <https://airbladesoftware.com/>
2626 ===============================================================================
2727 INTRODUCTION *gitgutter-introduction*
2828
29 GitGutter is a Vim plugin which shows a git diff in the 'gutter' (sign column).
29 GitGutter is a Vim plugin which shows a git diff in the sign column.
3030 It shows which lines have been added, modified, or removed. You can also
3131 preview, stage, and undo individual hunks. The plugin also provides a hunk
3232 text object.
3333
3434 The signs are always up to date and the plugin never saves your buffer.
35
36 The name "gitgutter" comes from the Sublime Text 3 plugin which inspired this
37 one in 2013.
3538
3639
3740 ===============================================================================
5962 ===============================================================================
6063 WINDOWS *gitgutter-windows*
6164
62 I recommend configuring vim-gitgutter with the full path to your git executable.
65 There is a potential risk on Windows due to `cmd.exe` prioritising the current
66 folder over folders in `PATH`. If you have a file named `git.*` (i.e. with
67 any extension in `PATHEXT`) in your current folder, it will be executed
68 instead of git whenever the plugin calls git.
69
70 You can avoid this risk by configuring the full path to your git executable.
6371 For example:
6472 >
73 " This path probably won't work
6574 let g:gitgutter_git_executable = 'C:\Program Files\Git\bin\git.exe'
6675 <
67 This is to avoid a problem which occurs if you have file named "git.*" (i.e.
68 with any extension in "PATHEXT") in your current folder. "cmd.exe" prioritises
69 the current folder over folders in 'PATH' and will try to execute your file
70 instead of the "git" binary.
76
77 Unfortunately I don't know the correct escaping for the path - if you do,
78 please let me know!
7179
7280
7381 ===============================================================================
8391
8492 *gitgutter-:GitGutterToggle*
8593 :GitGutterToggle Toggle vim-gitgutter on or off for all buffers.
94
95 *gitgutter-:GitGutterBufferDisable*
96 :GitGutterBufferDisable Turn vim-gitgutter off for current buffer.
97
98 *gitgutter-:GitGutterBufferEnable*
99 :GitGutterBufferEnable Turn vim-gitgutter on for current buffer.
100
101 *gitgutter-:GitGutterBufferToggle*
102 :GitGutterBufferToggle Toggle vim-gitgutter on or off for current buffer.
86103
87104 *gitgutter-:GitGutter*
88105 :GitGutter Update signs for the current buffer. You shouldn't
142159 :GitGutterQuickFix Load all hunks into the |quickfix| list. Note this
143160 ignores any unsaved changes in your buffers. The
144161 |g:gitgutter_use_location_list| option can be set to
145 populate the location list of the current window instead
162 populate the location list of the current window
163 instead. Use |:copen| (or |:lopen|) to open a buffer
164 containing the search results in linked form; or add a
165 custom command like this:
166 >
167 command! Gqf GitGutterQuickFix | copen
168 <
169 *gitgutter-:GitGutterQuickFixCurrentFile*
170 :GitGutterQuickFixCurrentFile Same as :GitGutterQuickFix, but only load hunks for
171 the file in the focused buffer. This has the same
172 functionality as :GitGutterQuickFix when the focused
173 buffer is empty.
146174
147175
148176 Commands for operating on a hunk:~
162190
163191 *gitgutter-:GitGutterPreviewHunk*
164192 :GitGutterPreviewHunk Preview the hunk the cursor is in.
165 Use |:pclose| or |CTRL-W_CTRL-Z| to close the preview
166 window.
167193
168194 To stage part of the hunk, move to the preview window,
169195 delete any lines you do not want to stage, and
170196 |GitGutterStageHunk|.
171197
198 To close a non-floating preview window use |:pclose|
199 or |CTRL-W_z| or |CTRL-W_CTRL-Z|; or normal window-
200 closing (|:quit| or |:close| or |CTRL-W_c|) if your cursor
201 is in the preview window.
202
203 To close a floating window when the cursor is in the
204 original buffer, move the cursor.
205
206 To close a floating window when the cursor is in the
207 floating window use normal window-closing, or move to
208 the original window with |CTRL-W_p|. Alternatively set
209 |g:gitgutter_close_preview_on_escape| and use <Esc>.
210
211 Two functions are available for your own logic:
212 >
213 gitgutter#hunk#is_preview_window_open()
214 gitgutter#hunk#close_hunk_preview_window()
215 <
216
172217 Commands for folds:~
173218
174219 *gitgutter-:GitGutterFold*
175220 :GitGutterFold Fold all unchanged lines. Execute again to undo.
176221
177222
178 ===============================================================================
179 AUTOCOMMAND *gitgutter-autocommand*
223 Other commands:~
224
225 *gitgutter-:GitGutterDiffOrig*
226 :GitGutterDiffOrig Similar to |:DiffOrig| but shows gitgutter's diff.
227
228
229 ===============================================================================
230 AUTOCOMMANDS *gitgutter-autocommands*
180231
181232 User GitGutter~
182233
188239 A dictionary `g:gitgutter_hook_context` is made available during its execution,
189240 which contains an entry `bufnr` that contains the buffer number being updated.
190241
242 User GitGutterStage~
243
244 After staging a hunk or part of a hunk vim-gitgutter fires a |User| |autocmd|
245 with the event GitGutterStage. Staging always happens in the current buffer.
191246
192247 ===============================================================================
193248 MAPPINGS *gitgutter-mappings*
298353 |g:gitgutter_sign_removed|
299354 |g:gitgutter_sign_removed_first_line|
300355 |g:gitgutter_sign_modified_removed|
301 |g:gitgutter_override_sign_column_highlight|
356 |g:gitgutter_set_sign_backgrounds|
357
358 Hunk jumping:~
359
360 |g:gitgutter_show_msg_on_hunk_jumping|
302361
303362 Hunk previews:~
304363
305364 |g:gitgutter_preview_win_floating|
365 |g:gitgutter_floating_window_options|
366 |g:gitgutter_close_preview_on_escape|
306367
307368 Terminal:~
308369
404465 Determines whether or not to show line number highlights.
405466
406467 *g:gitgutter_max_signs*
407 Default: 500
468 Default: 500 (Vim < 8.1.0614, Neovim < 0.4.0)
469 -1 (otherwise)
408470
409471 Sets the maximum number of signs to show in a buffer. Vim is slow at updating
410472 signs, so to avoid slowing down the GUI the number of signs is capped. When
411473 the number of changed lines exceeds this value, the plugin removes all signs
412474 and displays a warning message.
413475
476 When set to -1 the limit is not applied.
477
414478 *g:gitgutter_sign_priority*
415479 Default: 10
416480
427491 *g:gitgutter_sign_modified*
428492 *g:gitgutter_sign_removed*
429493 *g:gitgutter_sign_removed_first_line*
494 *g:gitgutter_sign_removed_above_and_below*
430495 *g:gitgutter_sign_modified_removed*
431496 Defaults:
432497 >
434499 let g:gitgutter_sign_modified = '~'
435500 let g:gitgutter_sign_removed = '_'
436501 let g:gitgutter_sign_removed_first_line = '‾'
502 let g:gitgutter_sign_removed_above_and_below = '_¯'
437503 let g:gitgutter_sign_modified_removed = '~_'
438504 <
439505 You can use unicode characters but not images. Signs must not take up more than
440506 2 columns.
441507
442 *g:gitgutter_override_sign_column_highlight*
443 Default: 1
444
445 Controls whether to make the sign column look like the line-number column (i.e.
446 the |hl-LineNr| highlight group).
447
448 To customise your sign column's background color, first tell vim-gitgutter to
449 leave it alone:
450 >
451 let g:gitgutter_override_sign_column_highlight = 0
452 <
453
454 And then either update your colorscheme's |hlSignColumn| highlight group or set
455 it in your |vimrc|:
456
457 Desired appearance Command ~
458 Same as line-number column highlight clear SignColumn
459 User-defined (terminal Vim) highlight SignColumn ctermbg={whatever}
460 User-defined (graphical Vim) highlight SignColumn guibg={whatever}
461
508 *g:gitgutter_set_sign_backgrounds*
509 Default: 0
510
511 Only applies to existing GitGutter* highlight groups. See
512 |gitgutter-highlights|.
513
514 Controls whether to override the signs' background colours to match the
515 |hl-SignColumn|.
462516
463517 *g:gitgutter_preview_win_floating*
464518 Default: 0 (Vim)
469523 popup windows on Vim you will not be able to stage partial hunks via the
470524 preview window.
471525
526 *g:gitgutter_floating_window_options*
527 Default:
528 >
529 " Vim
530 {
531 \ 'line': 'cursor+1',
532 \ 'col': 'cursor',
533 \ 'moved': 'any'
534 }
535
536 " Neovim
537 {
538 \ 'relative': 'cursor',
539 \ 'row': 1,
540 \ 'col': 0,
541 \ 'width': 42,
542 \ 'height': &previewheight,
543 \ 'style': 'minimal'
544 }
545 <
546 This dictionary is passed directly to |popup_create()| (Vim) or
547 |nvim_open_win()| (Neovim).
548
549 *g:gitgutter_close_preview_on_escape*
550 Default: 0
551
552 Whether pressing <Esc> in a preview window closes it.
553
472554 *g:gitgutter_terminal_reports_focus*
473555 Default: 1
474556
517599 When switched on, the :GitGutterQuickFix command populates the location list
518600 of the current window instead of the global quickfix list.
519601
602 *g:gitgutter_show_msg_on_hunk_jumping*
603 Default: 1
604
605 When switched on, a message like "Hunk 4 of 11" is shown on hunk jumping.
606
520607
521608 ===============================================================================
522609 HIGHLIGHTS *gitgutter-highlights*
523610
524 To change the signs' colours, set up the following highlight groups in your
525 colorscheme or |vimrc|:
526 >
527 GitGutterAdd " an added line
528 GitGutterChange " a changed line
529 GitGutterDelete " at least one removed line
530 GitGutterChangeDelete " a changed line followed by at least one removed line
531 <
532
533 You can either set these with `highlight GitGutterAdd {key}={arg}...` or link
534 them to existing highlight groups with, say:
535 >
536 highlight link GitGutterAdd MyDiffAdd
537 <
611 To change the signs' colours, specify these highlight groups in your |vimrc|:
612 >
613 highlight GitGutterAdd guifg=#009900 ctermfg=2
614 highlight GitGutterChange guifg=#bbbb00 ctermfg=3
615 highlight GitGutterDelete guifg=#ff2222 ctermfg=1
616 <
617
618 See |highlight-guifg| and |highlight-ctermfg| for the values you can use.
619
620 If you do not like the signs' background colours and you do not want to update
621 the GitGutter* highlight groups yourself, you can get the plugin to do it
622 |g:gitgutter_set_sign_backgrounds|.
538623
539624 To change the line highlights, set up the following highlight groups in your
540625 colorscheme or |vimrc|:
561646 >
562647 highlight link GitGutterChangeLineNr Underlined
563648 <
649 To change the diff syntax colours used in the preview window, set up the diff*
650 highlight groups in your colorscheme or |vimrc|:
651 >
652 diffAdded " if not set: use GitGutterAdd's foreground colour
653 diffChanged " if not set: use GitGutterChange's foreground colour
654 diffRemoved " if not set: use GitGutterDelete's foreground colour
655 <
656 Note the diff* highlight groups are used in any buffer whose 'syntax' is
657 "diff".
658
659 To change the intra-line diff highlights used in the preview window, set up
660 the following highlight groups in your colorscheme or |vimrc|:
661 >
662 GitGutterAddIntraLine " default: gui=reverse cterm=reverse
663 GitGutterDeleteIntraLine " default: gui=reverse cterm=reverse
664 <
665 For example, to use |hl-DiffAdd| for intra-line added regions:
666 >
667 highlight link GitGutterAddIntraLine DiffAdd
668 <
564669
565670
566671 ===============================================================================
591696 d. Why are the colours in the sign column weird?
592697
593698 Your colorscheme is configuring the |hl-SignColumn| highlight group weirdly.
594 Please see |g:gitgutter_override_sign_column_highlight| on customising the
595 sign column.
699 Here are two ways you could change the colours:
700 >
701 highlight! link SignColumn LineNr
702 highlight SignColumn guibg=whatever ctermbg=whatever
703 <
596704
597705 e. What happens if I also use another plugin which uses signs (e.g. Syntastic)?
598706
631739 <
632740 If the result is -2, the plugin thinks your file is not tracked by git.
633741
742 6. Check whether the signs have been placed:
743 >
744 :sign place group=gitgutter
745 <
746 If you see a list of signs, this is a colorscheme / highlight problem.
747 Compare these two highlight values:
748 >
749 :highlight GitGutterAdd
750 :highlight SignColumn
751 <
752 If no signs are listed, the call to git-diff is probably failing. Turn on
753 logging by adding the following to your vimrc, restart, reproduce the problem,
754 and examing the gitgutter.log file in the plugin's directory.
755 >
756 let g:gitgutter_log = 1
757 <
634758
635759 When the whole file is marked as added:~
636760
656780 let g:gitgutter_terminal_reports_focus = 0
657781 <
658782
783 vim:tw=78:et:ft=help:norl:
77 " Initialisation {{{
88
99 if v:version < 703 || (v:version == 703 && !has("patch105"))
10 call gitgutter#utility#warn('requires Vim 7.3.105')
10 call gitgutter#utility#warn('Requires Vim 7.3.105')
1111 finish
1212 endif
1313
14 function! s:set(var, default) abort
15 if !exists(a:var)
16 if type(a:default)
17 execute 'let' a:var '=' string(a:default)
18 else
19 execute 'let' a:var '=' a:default
20 endif
21 endif
22 endfunction
23
24 call s:set('g:gitgutter_preview_win_location', 'bo')
14 let s:nomodeline = (v:version > 703 || (v:version == 703 && has('patch442'))) ? '<nomodeline>' : ''
15
16 function! s:obsolete(var)
17 if exists(a:var)
18 call gitgutter#utility#warn(a:var.' is obsolete and has no effect.')
19 endif
20 endfunction
21
22
23 let g:gitgutter_preview_win_location = get(g:, 'gitgutter_preview_win_location', 'bo')
2524 if exists('*nvim_open_win')
26 call s:set('g:gitgutter_preview_win_floating', 1)
25 let g:gitgutter_preview_win_floating = get(g:, 'gitgutter_preview_win_floating', 1)
26 let g:gitgutter_floating_window_options = get(g:, 'gitgutter_floating_window_options', {
27 \ 'relative': 'cursor',
28 \ 'row': 1,
29 \ 'col': 0,
30 \ 'width': 42,
31 \ 'height': &previewheight,
32 \ 'style': 'minimal'
33 \ })
2734 else
28 call s:set('g:gitgutter_preview_win_floating', 0)
29 endif
30 call s:set('g:gitgutter_enabled', 1)
31 call s:set('g:gitgutter_max_signs', 500)
32 call s:set('g:gitgutter_signs', 1)
33 call s:set('g:gitgutter_highlight_lines', 0)
34 call s:set('g:gitgutter_highlight_linenrs', 0)
35 call s:set('g:gitgutter_sign_priority', 10)
35 let default = exists('&previewpopup') ? !empty(&previewpopup) : 0
36 let g:gitgutter_preview_win_floating = get(g:, 'gitgutter_preview_win_floating', default)
37 let g:gitgutter_floating_window_options = get(g:, 'gitgutter_floating_window_options', {
38 \ 'line': 'cursor+1',
39 \ 'col': 'cursor',
40 \ 'moved': 'any'
41 \ })
42 endif
43 let g:gitgutter_enabled = get(g:, 'gitgutter_enabled', 1)
44 if exists('*sign_unplace')
45 let g:gitgutter_max_signs = get(g:, 'gitgutter_max_signs', -1)
46 else
47 let g:gitgutter_max_signs = get(g:, 'gitgutter_max_signs', 500)
48 endif
49 let g:gitgutter_signs = get(g:, 'gitgutter_signs', 1)
50 let g:gitgutter_highlight_lines = get(g:, 'gitgutter_highlight_lines', 0)
51 let g:gitgutter_highlight_linenrs = get(g:, 'gitgutter_highlight_linenrs', 0)
52 let g:gitgutter_sign_priority = get(g:, 'gitgutter_sign_priority', 10)
3653 " Nvim 0.4.0 has an expanding sign column
3754 " The sign_place() function supports sign priority.
3855 if (has('nvim-0.4.0') || exists('*sign_place')) && !exists('g:gitgutter_sign_allow_clobber')
3956 let g:gitgutter_sign_allow_clobber = 1
4057 endif
41 call s:set('g:gitgutter_sign_allow_clobber', 0)
42 call s:set('g:gitgutter_override_sign_column_highlight', 1)
43 call s:set('g:gitgutter_sign_added', '+')
44 call s:set('g:gitgutter_sign_modified', '~')
45 call s:set('g:gitgutter_sign_removed', '_')
58 let g:gitgutter_sign_allow_clobber = get(g:, 'gitgutter_sign_allow_clobber', 0)
59 let g:gitgutter_set_sign_backgrounds = get(g:, 'gitgutter_set_sign_backgrounds', 0)
60 let g:gitgutter_sign_added = get(g:, 'gitgutter_sign_added', '+')
61 let g:gitgutter_sign_modified = get(g:, 'gitgutter_sign_modified', '~')
62 let g:gitgutter_sign_removed = get(g:, 'gitgutter_sign_removed', '_')
4663
4764 if gitgutter#utility#supports_overscore_sign()
48 call s:set('g:gitgutter_sign_removed_first_line', '‾')
65 let g:gitgutter_sign_removed_first_line = get(g:, 'gitgutter_sign_removed_first_line', '‾')
4966 else
50 call s:set('g:gitgutter_sign_removed_first_line', '_^')
51 endif
52
53 call s:set('g:gitgutter_sign_removed_above_and_below', '[')
54 call s:set('g:gitgutter_sign_modified_removed', '~_')
55 call s:set('g:gitgutter_git_args', '')
56 call s:set('g:gitgutter_diff_relative_to', 'index')
57 call s:set('g:gitgutter_diff_args', '')
58 call s:set('g:gitgutter_diff_base', '')
59 call s:set('g:gitgutter_map_keys', 1)
60 call s:set('g:gitgutter_terminal_reports_focus', 1)
61 call s:set('g:gitgutter_async', 1)
62 call s:set('g:gitgutter_log', 0)
63 call s:set('g:gitgutter_use_location_list', 0)
64
65 call s:set('g:gitgutter_git_executable', 'git')
67 let g:gitgutter_sign_removed_first_line = get(g:, 'gitgutter_sign_removed_first_line', '_^')
68 endif
69
70 let g:gitgutter_sign_removed_above_and_below = get(g:, 'gitgutter_sign_removed_above_and_below', '_¯')
71 let g:gitgutter_sign_modified_removed = get(g:, 'gitgutter_sign_modified_removed', '~_')
72 let g:gitgutter_git_args = get(g:, 'gitgutter_git_args', '')
73 let g:gitgutter_diff_relative_to = get(g:, 'gitgutter_diff_relative_to', 'index')
74 let g:gitgutter_diff_args = get(g:, 'gitgutter_diff_args', '')
75 let g:gitgutter_diff_base = get(g:, 'gitgutter_diff_base', '')
76 let g:gitgutter_map_keys = get(g:, 'gitgutter_map_keys', 1)
77 let g:gitgutter_terminal_reports_focus = get(g:, 'gitgutter_terminal_reports_focus', 1)
78 let g:gitgutter_async = get(g:, 'gitgutter_async', 1)
79 let g:gitgutter_log = get(g:, 'gitgutter_log', 0)
80 let g:gitgutter_use_location_list = get(g:, 'gitgutter_use_location_list', 0)
81 let g:gitgutter_close_preview_on_escape = get(g:, 'gitgutter_close_preview_on_escape', 0)
82 let g:gitgutter_show_msg_on_hunk_jumping = get(g:, 'gitgutter_show_msg_on_hunk_jumping', 1)
83
84 let g:gitgutter_git_executable = get(g:, 'gitgutter_git_executable', 'git')
6685 if !executable(g:gitgutter_git_executable)
67 call gitgutter#utility#warn('cannot find git. Please set g:gitgutter_git_executable.')
86 if g:gitgutter_enabled
87 call gitgutter#utility#warn('Cannot find git. Please set g:gitgutter_git_executable.')
88 endif
89 finish
6890 endif
6991
7092 let default_grep = 'grep'
71 call s:set('g:gitgutter_grep', default_grep)
93 let g:gitgutter_grep = get(g:, 'gitgutter_grep', default_grep)
7294 if !empty(g:gitgutter_grep)
7395 if executable(split(g:gitgutter_grep)[0])
7496 if $GREP_OPTIONS =~# '--color=always'
7698 endif
7799 else
78100 if g:gitgutter_grep !=# default_grep
79 call gitgutter#utility#warn('cannot find '.g:gitgutter_grep.'. Please check g:gitgutter_grep.')
101 call gitgutter#utility#warn('Cannot find '.g:gitgutter_grep.'. Please check g:gitgutter_grep.')
80102 endif
81103 let g:gitgutter_grep = ''
82104 endif
83105 endif
84106
85 call gitgutter#highlight#define_sign_column_highlight()
86107 call gitgutter#highlight#define_highlights()
87108 call gitgutter#highlight#define_signs()
88109
109130 command! -bar GitGutterBufferEnable call gitgutter#buffer_enable()
110131 command! -bar GitGutterBufferToggle call gitgutter#buffer_toggle()
111132
112 command! -bar GitGutterQuickFix call gitgutter#quickfix()
133 command! -bar GitGutterQuickFix call gitgutter#quickfix(0)
134 command! -bar GitGutterQuickFixCurrentFile call gitgutter#quickfix(1)
135
136 command! -bar GitGutterDiffOrig call gitgutter#difforig()
113137
114138 " }}}
115139
193217 " Maps {{{
194218
195219 nnoremap <silent> <expr> <Plug>(GitGutterNextHunk) &diff ? ']c' : ":\<C-U>execute v:count1 . 'GitGutterNextHunk'\<CR>"
196 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>"
220 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>"
197221 nnoremap <silent> <expr> <Plug>(GitGutterPrevHunk) &diff ? '[c' : ":\<C-U>execute v:count1 . 'GitGutterPrevHunk'\<CR>"
198 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>"
222 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>"
199223
200224 xnoremap <silent> <Plug>(GitGutterStageHunk) :GitGutterStageHunk<CR>
201 xnoremap <silent> <Plug>GitGutterStageHunk :call gitgutter#utility#warn('please change your map <lt>Plug>GitGutterStageHunk to <lt>Plug>(GitGutterStageHunk)')<CR>
225 xnoremap <silent> <Plug>GitGutterStageHunk :call gitgutter#utility#warn('Please change your map <lt>Plug>GitGutterStageHunk to <lt>Plug>(GitGutterStageHunk)')<CR>
202226 nnoremap <silent> <Plug>(GitGutterStageHunk) :GitGutterStageHunk<CR>
203 nnoremap <silent> <Plug>GitGutterStageHunk :call gitgutter#utility#warn('please change your map <lt>Plug>GitGutterStageHunk to <lt>Plug>(GitGutterStageHunk)')<CR>
227 nnoremap <silent> <Plug>GitGutterStageHunk :call gitgutter#utility#warn('Please change your map <lt>Plug>GitGutterStageHunk to <lt>Plug>(GitGutterStageHunk)')<CR>
204228 nnoremap <silent> <Plug>(GitGutterUndoHunk) :GitGutterUndoHunk<CR>
205 nnoremap <silent> <Plug>GitGutterUndoHunk :call gitgutter#utility#warn('please change your map <lt>Plug>GitGutterUndoHunk to <lt>Plug>(GitGutterUndoHunk)')<CR>
229 nnoremap <silent> <Plug>GitGutterUndoHunk :call gitgutter#utility#warn('Please change your map <lt>Plug>GitGutterUndoHunk to <lt>Plug>(GitGutterUndoHunk)')<CR>
206230 nnoremap <silent> <Plug>(GitGutterPreviewHunk) :GitGutterPreviewHunk<CR>
207 nnoremap <silent> <Plug>GitGutterPreviewHunk :call gitgutter#utility#warn('please change your map <lt>Plug>GitGutterPreviewHunk to <lt>Plug>(GitGutterPreviewHunk)')<CR>
231 nnoremap <silent> <Plug>GitGutterPreviewHunk :call gitgutter#utility#warn('Please change your map <lt>Plug>GitGutterPreviewHunk to <lt>Plug>(GitGutterPreviewHunk)')<CR>
208232
209233 " }}}
210234
211235 function! s:on_bufenter()
212236 call gitgutter#setup_maps()
237
238 " To keep vim's start-up fast, do not process the buffer when vim is starting.
239 " Instead process it a short time later. Normally we would rely on our
240 " CursorHold autocommand to handle this but it turns out CursorHold is not
241 " guaranteed to fire if the user has not typed anything yet; so set up a
242 " timer instead. The disadvantage is that if CursorHold does fire, the
243 " plugin will do a round of unnecessary work; but since there will not have
244 " been any changes to the buffer since the first round, the second round
245 " will be cheap.
246 if has('vim_starting') && !$VIM_GITGUTTER_TEST
247 if exists('*timer_start') && has('lambda')
248 call s:next_tick("call gitgutter#process_buffer(+".bufnr('').", 0)")
249 else
250 call gitgutter#process_buffer(bufnr(''), 0)
251 endif
252 return
253 endif
213254
214255 if exists('t:gitgutter_didtabenter') && t:gitgutter_didtabenter
215256 let t:gitgutter_didtabenter = 0
219260 endif
220261 endfunction
221262
263 function! s:next_tick(cmd)
264 call timer_start(1, {-> execute(a:cmd)})
265 endfunction
266
222267 " Autocommands {{{
223268
224269 augroup gitgutter
228273
229274 autocmd BufEnter * call s:on_bufenter()
230275
276 " Ensure Vim is always checking for CursorMoved to avoid CursorMoved
277 " being fired at the wrong time in floating preview window on Neovim.
278 " See vim/vim#2053.
279 autocmd CursorMoved * execute ''
280
231281 autocmd CursorHold,CursorHoldI * call gitgutter#process_buffer(bufnr(''), 0)
232282 if exists('*timer_start') && has('lambda')
233 autocmd FileChangedShellPost * call timer_start(1, {-> gitgutter#process_buffer(bufnr(''), 1)})
283 autocmd FileChangedShellPost * call s:next_tick("call gitgutter#process_buffer(+".expand('<abuf>').", 1)")
234284 else
235 autocmd FileChangedShellPost * call gitgutter#process_buffer(bufnr(''), 1)
285 autocmd FileChangedShellPost * call gitgutter#process_buffer(+expand('<abuf>'), 1)
236286 endif
237287
238288 " Ensure that all buffers are processed when opening vim with multiple files, e.g.:
252302 " FocusGained gets triggered on startup with Neovim at least already.
253303 " Therefore this tracks also if it was lost before.
254304 let s:focus_was_lost = 0
255 autocmd FocusGained * if s:focus_was_lost | let focus_was_lost = 0 | call gitgutter#all(1) | endif
305 autocmd FocusGained * if s:focus_was_lost | let s:focus_was_lost = 0 | call gitgutter#all(1) | endif
256306 autocmd FocusLost * let s:focus_was_lost = 1
257307
258308 if exists('##VimResume')
259309 autocmd VimResume * call gitgutter#all(1)
260310 endif
261311
262 autocmd ColorScheme * call gitgutter#highlight#define_sign_column_highlight() | call gitgutter#highlight#define_highlights()
312 autocmd ColorScheme * call gitgutter#highlight#define_highlights()
263313
264314 " Disable during :vimgrep
265 autocmd QuickFixCmdPre *vimgrep* let g:gitgutter_enabled = 0
266 autocmd QuickFixCmdPost *vimgrep* let g:gitgutter_enabled = 1
315 autocmd QuickFixCmdPre *vimgrep* let [g:gitgutter_was_enabled, g:gitgutter_enabled] = [g:gitgutter_enabled, 0]
316 autocmd QuickFixCmdPost *vimgrep* let g:gitgutter_enabled = g:gitgutter_was_enabled | unlet g:gitgutter_was_enabled
267317 augroup END
268318
269319 " }}}
204204 endfunction
205205
206206
207 function Test_filename_with_space()
208 call system('touch fix\ ture.txt && git add fix\ ture.txt')
209 edit fix\ ture.txt
210 normal ggo*
211 call s:trigger_gitgutter()
212
213 let expected = [
214 \ {'lnum': 1, 'name': 'GitGutterLineAdded'},
215 \ {'lnum': 2, 'name': 'GitGutterLineAdded'}
216 \ ]
217 call s:assert_signs(expected, 'fix\ ture.txt')
218 endfunction
219
220
207221 function Test_filename_leading_dash()
208222 call system('touch -- -fixture.txt && git add -- -fixture.txt')
209223 edit -fixture.txt
834848
835849
836850 function Test_fix_file_references()
851 let sid = matchstr(execute('filter autoload/gitgutter/hunk.vim scriptnames'), '\d\+')
852 let FixFileReferences = function("<SNR>".sid."_fix_file_references")
853
837854 " No special characters
838855 let hunk_diff = join([
839856 \ 'diff --git a/fixture.txt b/fixture.txt',
854871 \ '+x'
855872 \ ], "\n")."\n"
856873
857 call assert_equal(expected, gitgutter#hunk#fix_file_references(filepath, hunk_diff))
874 call assert_equal(expected, FixFileReferences(filepath, hunk_diff))
858875
859876 " diff.mnemonicPrefix; spaces in filename
860877 let hunk_diff = join([
876893 \ '+x'
877894 \ ], "\n")."\n"
878895
879 call assert_equal(expected, gitgutter#hunk#fix_file_references(filepath, hunk_diff))
896 call assert_equal(expected, FixFileReferences(filepath, hunk_diff))
880897
881898 " Backslashes in filename; quotation marks
882899 let hunk_diff = join([
898915 \ '+x'
899916 \ ], "\n")."\n"
900917
901 call assert_equal(expected, gitgutter#hunk#fix_file_references(filepath, hunk_diff))
918 call assert_equal(expected, FixFileReferences(filepath, hunk_diff))
902919 endfunction
903920
904921
946963 call setline(5, ['A', 'B'])
947964 call setline(9, ['C', 'D'])
948965 write
966 let bufnr1 = bufnr('')
967
968 edit fixture_dos.txt
969 call setline(2, ['A', 'B'])
970 write
971 let bufnr2 = bufnr('')
949972
950973 GitGutterQuickFix
951974
952975 let expected = [
953 \ {'lnum': 5, 'bufnr': bufnr(''), 'text': '-e'},
954 \ {'lnum': 9, 'bufnr': bufnr(''), 'text': '-i'}
976 \ {'lnum': 5, 'bufnr': bufnr1, 'text': '-e'},
977 \ {'lnum': 9, 'bufnr': bufnr1, 'text': '-i'},
978 \ {'lnum': 2, 'bufnr': bufnr2, 'text': "-b\r"}
955979 \ ]
956980
957981 call s:assert_list_of_dicts(expected, getqflist())
982
983 GitGutterQuickFixCurrentFile
984
985 let expected = [
986 \ {'lnum': 2, 'bufnr': bufnr(''), 'text': "-b\r"},
987 \ ]
988
989 call s:assert_list_of_dicts(expected, getqflist())
958990 endfunction
959991
960992
961993 function Test_common_prefix()
994 let sid = matchstr(execute('filter autoload/gitgutter/diff_highlight.vim scriptnames'), '\d\+')
995 let CommonPrefix = function("<SNR>".sid."_common_prefix")
996
962997 " zero length
963 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('', 'foo'))
964 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('foo', ''))
998 call assert_equal(-1, CommonPrefix('', 'foo'))
999 call assert_equal(-1, CommonPrefix('foo', ''))
9651000 " nothing in common
966 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+pqrst'))
967 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('abcde', 'pqrst'))
1001 call assert_equal(-1, CommonPrefix('-abcde', '+pqrst'))
1002 call assert_equal(-1, CommonPrefix('abcde', 'pqrst'))
9681003 " something in common
969 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+abcpq'))
970 call assert_equal(2, gitgutter#diff_highlight#common_prefix('abcde', 'abcpq'))
971 call assert_equal(0, gitgutter#diff_highlight#common_prefix('abc', 'apq'))
1004 call assert_equal(-1, CommonPrefix('-abcde', '+abcpq'))
1005 call assert_equal(2, CommonPrefix('abcde', 'abcpq'))
1006 call assert_equal(0, CommonPrefix('abc', 'apq'))
9721007 " everything in common
973 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+abcde'))
974 call assert_equal(4, gitgutter#diff_highlight#common_prefix('abcde', 'abcde'))
1008 call assert_equal(-1, CommonPrefix('-abcde', '+abcde'))
1009 call assert_equal(4, CommonPrefix('abcde', 'abcde'))
9751010 " different lengths
976 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+abx'))
977 call assert_equal(1, gitgutter#diff_highlight#common_prefix('abcde', 'abx'))
978 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abx', '+abcde'))
979 call assert_equal(1, gitgutter#diff_highlight#common_prefix('abx', 'abcde'))
980 call assert_equal(-1, gitgutter#diff_highlight#common_prefix('-abcde', '+abc'))
981 call assert_equal(2, gitgutter#diff_highlight#common_prefix('abcde', 'abc'))
1011 call assert_equal(-1, CommonPrefix('-abcde', '+abx'))
1012 call assert_equal(1, CommonPrefix('abcde', 'abx'))
1013 call assert_equal(-1, CommonPrefix('-abx', '+abcde'))
1014 call assert_equal(1, CommonPrefix('abx', 'abcde'))
1015 call assert_equal(-1, CommonPrefix('-abcde', '+abc'))
1016 call assert_equal(2, CommonPrefix('abcde', 'abc'))
9821017 endfunction
9831018
9841019
9851020 function Test_common_suffix()
1021 let sid = matchstr(execute('filter autoload/gitgutter/diff_highlight.vim scriptnames'), '\d\+')
1022 let CommonSuffix = function("<SNR>".sid."_common_suffix")
1023
9861024 " nothing in common
987 call assert_equal([6,6], gitgutter#diff_highlight#common_suffix('-abcde', '+pqrst', 0))
1025 call assert_equal([6,6], CommonSuffix('-abcde', '+pqrst', 0))
9881026 " something in common
989 call assert_equal([3,3], gitgutter#diff_highlight#common_suffix('-abcde', '+pqcde', 0))
1027 call assert_equal([3,3], CommonSuffix('-abcde', '+pqcde', 0))
9901028 " everything in common
991 call assert_equal([5,5], gitgutter#diff_highlight#common_suffix('-abcde', '+abcde', 5))
1029 call assert_equal([5,5], CommonSuffix('-abcde', '+abcde', 5))
9921030 " different lengths
993 call assert_equal([4,2], gitgutter#diff_highlight#common_suffix('-abcde', '+xde', 0))
994 call assert_equal([2,4], gitgutter#diff_highlight#common_suffix('-xde', '+abcde', 0))
1031 call assert_equal([4,2], CommonSuffix('-abcde', '+xde', 0))
1032 call assert_equal([2,4], CommonSuffix('-xde', '+abcde', 0))
9951033 endfunction
9961034
9971035
10801118
10811119
10821120 function Test_lcs()
1083 call assert_equal('', gitgutter#diff_highlight#lcs('', 'foo'))
1084 call assert_equal('', gitgutter#diff_highlight#lcs('foo', ''))
1085 call assert_equal('bar', gitgutter#diff_highlight#lcs('foobarbaz', 'bbart'))
1086 call assert_equal('transaction', gitgutter#diff_highlight#lcs('transaction.unexplained_amount', 'amount(transaction)'))
1121 let sid = matchstr(execute('filter autoload/gitgutter/diff_highlight.vim scriptnames'), '\d\+')
1122 let Lcs = function("<SNR>".sid."_lcs")
1123
1124 call assert_equal('', Lcs('', 'foo'))
1125 call assert_equal('', Lcs('foo', ''))
1126 call assert_equal('bar', Lcs('foobarbaz', 'bbart'))
1127 call assert_equal('transaction', Lcs('transaction.unexplained_amount', 'amount(transaction)'))
10871128 endfunction
10881129
10891130
10901131 function Test_split()
1091 call assert_equal(['foo', 'baz'], gitgutter#diff_highlight#split('foobarbaz', 'bar'))
1092 call assert_equal(['', 'barbaz'], gitgutter#diff_highlight#split('foobarbaz', 'foo'))
1093 call assert_equal(['foobar', ''], gitgutter#diff_highlight#split('foobarbaz', 'baz'))
1094 call assert_equal(['1', '2'], gitgutter#diff_highlight#split('1~2', '~'))
1132 let sid = matchstr(execute('filter autoload/gitgutter/diff_highlight.vim scriptnames'), '\d\+')
1133 let Split = function("<SNR>".sid."_split")
1134
1135 call assert_equal(['foo', 'baz'], Split('foobarbaz', 'bar'))
1136 call assert_equal(['', 'barbaz'], Split('foobarbaz', 'foo'))
1137 call assert_equal(['foobar', ''], Split('foobarbaz', 'baz'))
1138 call assert_equal(['1', '2'], Split('1~2', '~'))
10951139 endfunction
10961140
10971141
11101154 call assert_equal(0, gitgutter#fold#is_changed())
11111155 call assert_equal('+- 3 lines: a', gitgutter#fold#foldtext())
11121156 endfunction
1157
1158
1159 function Test_assume_unchanged()
1160 call system("git update-index --assume-unchanged fixture.txt")
1161 unlet b:gitgutter.path " it was already set when fixture.txt was loaded in SetUp()
1162 normal ggo*
1163 call s:trigger_gitgutter()
1164 call s:assert_signs([], 'fixture.txt')
1165 endfunction
+0
-27
unplace.vim less more
0 " Measure how long it takes to unplace signs.
1 "
2 " Source this file with `:source %` or `vim -S unplace.vim`
3
4
5 let num = 500
6 sign define Foo text=*
7
8 new
9
10 call append(0, range(1, num))
11
12 for i in range(1, num)
13 execute "sign place ".i." line=".i." name=Foo buffer=".bufnr('')
14 endfor
15
16 let start = reltime()
17 for i in range(1, num)
18 execute "sign unplace ".i
19 endfor
20 let elapsed = reltime(start)
21
22 bdelete!
23
24 echom split(reltimestr(elapsed))[0]."s to remove ".num." signs"
25 echom string(reltimefloat(elapsed) * 1000 / num).' ms/sign'
26 echom string(float2nr(num / reltimefloat(elapsed))).' sign/s'