๐Ÿ“ฆ da-x / rvim

๐Ÿ“„ gitutils.vim ยท 190 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190" Git utility functions for rvim configuration

" =============================================================================
" Git commit functions

function EndCommitMessageEdit()
  if len(getbufinfo({'buflisted':1})) == 1
    wq!
  else
    w | bd
  endif
endfunction

function! MyGitCommitHook() abort
  setlocal spell
  startinsert
endfunction

function! MyGitAddAllAmend() abort
  Git commit -a --amend
endfunction

function! MyGitPush() abort
  Git push
endfunction

" =============================================================================
" Git rebase functions

function! MyGitRebaseTodoHook(...) abort
  " Cursor positioning is now handled by the autocmd in init.lua
endfunction

augroup GitRebaseTodoRebinding autocmd!
  autocmd! BufRead git-rebase-todo call MyGitRebaseTodoHook()
augroup END

function! s:rebase_interactive_sink(single_item)
  echomsg a:single_item
  if len(a:single_item) >= 2
    let l:line = a:single_item[1]
    " Extract commit hash from git log --oneline format: "hash message"
    let l:parts = split(l:line, ' ')
    if len(l:parts) > 0
      let l:commit_hash = l:parts[0]
      execute "Git rebase -i " l:commit_hash
    else
      echo "Could not parse commit hash"
    endif
  else
    echo "No commit selected"
  endif
endfunction

function! MyFZFChooseRebaseInteractive()
  " Show only commits in current branch
  let l:branch = system('git branch --show-current 2>/dev/null || git rev-parse --abbrev-ref HEAD 2>/dev/null')
  let l:branch = substitute(l:branch, '\n', '', 'g')
  
  if empty(l:branch)
    echo "Not in a git repository or no commits"
    return
  endif
  
  " Use git log for current branch only
  let l:git_cmd = 'git log --oneline --decorate --color=always ' . shellescape(l:branch)
  
  call fzf#vim#commits({
  \  'source': l:git_cmd,
  \  'sink*': function('s:rebase_interactive_sink'),
  \})
endfunction

" =============================================================================
" Git diff functions

let s:my_fzf_git_diff_hunk_program = expand('<sfile>:p:h')."/bin/fzf-git-diff-hunk-preview"

function! MyFZFDiffHunks(cmd,...) abort
  let l:screen = get(a:, 1, 'half')
  let l:matches = []
  let l:filename = ''
  let l:filename_color = "\x1b[38;2;155;255;155m"
  let l:white = "\x1b[38;2;255;255;255m"
  let l:lnum_color = "\x1b[38;2;77;127;77m"
  let l:grey = "\x1b[38;2;255;255;155m"

  let l:hunknum = 1
  let l:found_change_start = 0
  for l:line in systemlist("git diff " . a:cmd . " | grep -E '^(diff|@@)' -A 4")
    let l:m = matchlist(l:line, '\V\^diff --git a/\(\.\*\) b/\(\.\*\)')
    if len(l:m) != 0
      let l:filename = l:m[2]
      let l:hunknum = 1
      continue
    endif
    let l:m = matchlist(l:line, '\V\^@@ -\[^ ]\+ +\(\[0-9]\+\)\[ ,]\[^@]\*@@\(\.\*\)')
    if len(l:m) != 0
      let l:found_change_start = 0
      let l:line_num = l:m[1]
      let l:title = l:m[2]
      call add(l:matches, [l:hunknum, l:filename, l:line_num, l:title])
      let l:hunknum += 1
      continue
    endif
    if l:found_change_start == 0
      let l:m = matchlist(l:line, '\V\^\[+-]')
      if len(l:m) != 0
        let l:found_change_start = 1
      else
        if len(l:matches) >= 1
          let l:matches[len(l:matches) - 1][2] += 1
        endif
      endif
    endif
  endfor

  let l:i = 0
  while l:i < len(l:matches)
    let [l:hunknum, l:filename, l:line_num, l:title] = l:matches[l:i]
    let l:matches[i] =
        \ printf("%3d " . l:filename_color . "%s"
        \ . l:white. ":" . l:lnum_color. "%d"
        \ . l:white. " %s",
        \ l:hunknum,
        \ l:filename,
        \ l:line_num,
        \ l:title)
    let l:i = l:i + 1
  endwhile

  if len(l:matches) == 0
    if l:screen == 'full'
      execute "normal! :x\<CR>"
    endif
    return
  endif

  let l:options = [
      \"--ansi", "-e", "--no-sort", "--tac",
      \"--preview-window", "down:70%:noborder",
      \"--preview", s:my_fzf_git_diff_hunk_program." '".a:cmd."' {}"
      \]

  if l:screen == 'full'
    let l:down = "100%"
  else
    let l:down = "50%"
  endif

  let l:opts = {}
  function! l:opts.sink(single)
    if len(a:single) == 1
      let l:m = matchlist(a:single[0], '\V\^ \*\(\[0-9]\*\) \(\[^:]\*\):\(\[0-9]\*\)')
      if len(l:m) != 0
        execute "edit" l:m[2]
        call setpos(".", [0, str2nr(l:m[3]), 0, 0])
      endif
    endif
  endfunction

  let l:v = fzf#run(fzf#wrap({
              \ 'source': l:matches,
              \ 'down': l:down,
              \ 'sink*': remove(opts, 'sink'),
              \ 'options': l:options,
              \ }))
endfunction

function GFilesWithPreview()
  call fzf#vim#gitfiles('', {'options': [
        \ '--sync',
        \ '--query', expand('%h'),
        \ '--bind', 'result:transform:
           \  if [[ -n $FZF_QUERY ]]; then ;
           \      echo "track-current+clear-query" ;
           \  else ;
           \      echo "untrack-current+offset-middle+unbind(result)" ;
           \  fi',
        \ '--preview', 'bat -p --color always {}'],
        \ 'window': { 'width': 0.9, 'height': 0.9 }})
endfunction
" =============================================================================
" Git autocommands

augroup GitCommitAutocmds
  autocmd!
  autocmd! FileType gitcommit call MyGitCommitHook()
augroup END