airblade / airblade/vim-gitgutter

[Bug] Preview and stage doesn't work in vim on windows

Open
#896 16 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Vim Script
Stars
8.5k
Forks
299
PR merge metrics
No merged PRs in 30d

Description

What is the latest commit SHA in your installed vim-gitgutter?
7b0b5098e3e57be86bb96cfbf2b8902381eef57c

What vim/nvim version are you on?
vim 9.1

Description

Using hunk preview <leader>hp or hunk stash <leader>hs result in an error.

Error detected while processing function gitgutter#hunk#preview[3]..<SNR>95_hunk_op[38]..gitgutter#diff#run_diff[92]..gitgutter#utility#system:
line    5:
E282: Cannot read from "C:\Users\daniel\AppData\Local\Temp\V3FE0C7.tmp"
Error detected while processing function gitgutter#hunk#preview[3]..<SNR>95_hunk_op[38]..gitgutter#diff#run_diff:
line   92:
E714: List required
Cursor is not in a hunk

The annoying part is that after the error happens other commands like GitGutterNext/PrevHunk will start failing mentioning that there are no hunks in the file. Fortunately disabling and enabling GitGutter fixes that.

Log:

  0.185444 function <SNR>50_on_exit_vim[13]..8[10]..gitgutter#process_buffer[23]..gitgutter#diff#run_diff[85]..gitgutter#async#execute[1]:
  0.185444 [async] (git -C "C:\Users\daniel\vim-config" --no-pager show --textconv :vimonly.vim > C:\Users\daniel\AppData\Local\Temp\V1T3270.tmp.1.1.vim || exit 0) && (git -C "C:\Users\daniel\vim-config" --no-pager -c "diff.autorefreshindex=0" -c "diff.noprefix=false" -c "core.safecrlf=false" diff --no-ext-diff --no-color -U0  -- C:\Users\daniel\AppData\Local\Temp\V1T3270.tmp.1.1.vim C:\Users\daniel\AppData\Local\Temp\V2M3271.tmp.1.1.vim | grep "^@@ " || exit 0)

I found that the error occurs in "autoload/gitgutter/utility.vim" in the gitgutter#utility#cmd function when calling system().

I copied a command and ran it manually

:echo system('(git -C "C:\Users\daniel\vim-config" --no-pager show --textconv :vimonly.vim > C:\Users\daniel\AppData\Local\Temp\VHPDA96.tmp.1.3.vim || exit 0) && (git -C "C:\Users\daniel\vim-config" --no-pager -c "diff.autorefreshindex=0" -c "diff.noprefix=false" -c "core.safecrlf=false" diff --no-ext-diff --no-color -U0  -- C:\Users\daniel\AppData\Local\Temp\VHPDA96.tmp.1.3.vim C:\Users\daniel\AppData\Local\Temp\VIIDA97.tmp.1.3.vim || exit 0)')

and I get this output (temporary file name changes on each run):

E282: Cannot read from "C:\Users\daniel\AppData\Local\Temp\VRRAD8F.tmp"

I found that adding a shellescape before the command is built fix the issue with the preview

diff --git a/autoload/gitgutter/diff.vim b/autoload/gitgutter/diff.vim
index 484b89d..342ea6c 100644
--- a/autoload/gitgutter/diff.vim
+++ b/autoload/gitgutter/diff.vim
@@ -143,6 +143,7 @@ function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort
   let cmd .= ' || exit 0'

   let cmd .= ')'
+  let cmd = shellescape(cmd)

However it looks like that doesn't play nice with other commands as the symbols on the left does not show up with that change.

The log with the escaped command:

2228.508829 FocusGained Autocommands for "*"..function gitgutter#all[8]..gitgutter#process_buffer[23]..gitgutter#diff#run_diff[86]..gitgutter#async#execute[1]:
2228.508829 [async] "(git -C ""C:\Users\daniel\vim-config"" --no-pager show --textconv :vimonly.vim > C:\Users\daniel\AppData\Local\Temp\VHP1BE3.tmp.1.15.vim || exit 0) && (git -C ""C:\Users\daniel\vim-config"" --no-pager -c ""diff.autorefreshindex=0"" -c ""diff.noprefix=false"" -c ""core.safecrlf=false"" diff --no-ext-diff --no-color -U0  -- C:\Users\daniel\AppData\Local\Temp\VHP1BE3.tmp.1.15.vim C:\Users\daniel\AppData\Local\Temp\VII1BE4.tmp.1.15.vim | grep ""^@@ "" || exit 0)"

Experimenting with the command I noticed that if the parenthesis are omitted, it doesn't need shellescape

:echo system('git -C "C:\Users\daniel\vim-config" --no-pager show --textconv :vimonly.vim > C:\Users\daniel\AppData\Local\Temp\VHPDA96.tmp.1.3.vim || exit 0')

if the same command is called with the wrapping parenthesis but without shellescape, then created temporary file is empty

:echo system('(git -C "C:\Users\daniel\vim-config" --no-pager show --textconv :vimonly.vim > C:\Users\daniel\AppData\Local\Temp\VHPDA96.tmp.1.3.vim || exit 0)')
System information
  • Windows 11 Build 22631
  • Vim 9.1 from scoop

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in autoload/gitgutter/diff.vim, especially gitgutter#diff#run_diff, and inspect how it builds the parenthesized Windows command before gitgutter#utility#cmd calls system(). Reproduce hunk preview and staging on Windows with the reported Vim and Git commands, then verify that the temporary files are read correctly and that preview, staging, and subsequent hunk navigation continue to show the expected markers.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, vim
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.