Configuration options for gitv plugin.
[profile.git] / .vim / autoload / gundo.vim
1 " ============================================================================
2 " File:        gundo.vim
3 " Description: vim global plugin to visualize your undo tree
4 " Maintainer:  Steve Losh <steve@stevelosh.com>
5 " License:     GPLv2+ -- look it up.
6 " Notes:       Much of this code was thiefed from Mercurial, and the rest was
7 "              heavily inspired by scratch.vim and histwin.vim.
8 "
9 " ============================================================================
10
11
12 "{{{ Init
13
14 if v:version < '703'"{{{
15     function! s:GundoDidNotLoad()
16         echohl WarningMsg|echomsg "Gundo unavailable: requires Vim 7.3+"|echohl None
17     endfunction
18     command! -nargs=0 GundoToggle call s:GundoDidNotLoad()
19     finish
20 endif"}}}
21
22 if !exists('g:gundo_width')"{{{
23     let g:gundo_width = 45
24 endif"}}}
25 if !exists('g:gundo_preview_height')"{{{
26     let g:gundo_preview_height = 15
27 endif"}}}
28 if !exists('g:gundo_preview_bottom')"{{{
29     let g:gundo_preview_bottom = 0
30 endif"}}}
31 if !exists('g:gundo_right')"{{{
32     let g:gundo_right = 0
33 endif"}}}
34 if !exists('g:gundo_help')"{{{
35     let g:gundo_help = 1
36 endif"}}}
37 if !exists("g:gundo_map_move_older")"{{{
38     let g:gundo_map_move_older = 'j'
39 endif"}}}
40 if !exists("g:gundo_map_move_newer")"{{{
41     let g:gundo_map_move_newer = 'k'
42 endif"}}}
43 if !exists("g:gundo_close_on_revert")"{{{
44     let g:gundo_close_on_revert = 0
45 endif"}}}
46 if !exists("g:gundo_prefer_python3")"{{{
47     let g:gundo_prefer_python3 = 0
48 endif"}}}
49
50 let s:has_supported_python = 0
51 if g:gundo_prefer_python3 && has('python3')"{{{
52     let s:has_supported_python = 2
53 elseif has('python')"
54     let s:has_supported_python = 1
55 endif
56
57 if !s:has_supported_python
58     function! s:GundoDidNotLoad()
59         echohl WarningMsg|echomsg "Gundo requires Vim to be compiled with Python 2.4+"|echohl None
60     endfunction
61     command! -nargs=0 GundoToggle call s:GundoDidNotLoad()
62     finish
63 endif"}}}
64
65 let s:plugin_path = escape(expand('<sfile>:p:h'), '\')
66 "}}}
67
68 "{{{ Gundo utility functions
69
70 function! s:GundoGetTargetState()"{{{
71     let target_line = matchstr(getline("."), '\v\[[0-9]+\]')
72     return matchstr(target_line, '\v[0-9]+')
73 endfunction"}}}
74
75 function! s:GundoGoToWindowForBufferName(name)"{{{
76     if bufwinnr(bufnr(a:name)) != -1
77         exe bufwinnr(bufnr(a:name)) . "wincmd w"
78         return 1
79     else
80         return 0
81     endif
82 endfunction"}}}
83
84 function! s:GundoIsVisible()"{{{
85     if bufwinnr(bufnr("__Gundo__")) != -1 || bufwinnr(bufnr("__Gundo_Preview__")) != -1
86         return 1
87     else
88         return 0
89     endif
90 endfunction"}}}
91
92 function! s:GundoInlineHelpLength()"{{{
93     if g:gundo_help
94         return 6
95     else
96         return 0
97     endif
98 endfunction"}}}
99
100 "}}}
101
102 "{{{ Gundo buffer settings
103
104 function! s:GundoMapGraph()"{{{
105     exec 'nnoremap <script> <silent> <buffer> ' . g:gundo_map_move_older . " :call <sid>GundoMove(1)<CR>"
106     exec 'nnoremap <script> <silent> <buffer> ' . g:gundo_map_move_newer . " :call <sid>GundoMove(-1)<CR>"
107     nnoremap <script> <silent> <buffer> <CR>          :call <sid>GundoRevert()<CR>
108     nnoremap <script> <silent> <buffer> o             :call <sid>GundoRevert()<CR>
109     nnoremap <script> <silent> <buffer> <down>        :call <sid>GundoMove(1)<CR>
110     nnoremap <script> <silent> <buffer> <up>          :call <sid>GundoMove(-1)<CR>
111     nnoremap <script> <silent> <buffer> gg            gg:call <sid>GundoMove(1)<CR>
112     nnoremap <script> <silent> <buffer> P             :call <sid>GundoPlayTo()<CR>
113     nnoremap <script> <silent> <buffer> p             :call <sid>GundoRenderChangePreview()<CR>
114     nnoremap <script> <silent> <buffer> q             :call <sid>GundoClose()<CR>
115     cabbrev  <script> <silent> <buffer> q             call <sid>GundoClose()
116     cabbrev  <script> <silent> <buffer> quit          call <sid>GundoClose()
117     nnoremap <script> <silent> <buffer> <2-LeftMouse> :call <sid>GundoMouseDoubleClick()<CR>
118 endfunction"}}}
119
120 function! s:GundoMapPreview()"{{{
121     nnoremap <script> <silent> <buffer> q     :call <sid>GundoClose()<CR>
122     cabbrev  <script> <silent> <buffer> q     call <sid>GundoClose()
123     cabbrev  <script> <silent> <buffer> quit  call <sid>GundoClose()
124 endfunction"}}}
125
126 function! s:GundoSettingsGraph()"{{{
127     setlocal buftype=nofile
128     setlocal bufhidden=hide
129     setlocal noswapfile
130     setlocal nobuflisted
131     setlocal nomodifiable
132     setlocal filetype=gundo
133     setlocal nolist
134     setlocal nonumber
135     setlocal norelativenumber
136     setlocal nowrap
137     call s:GundoSyntaxGraph()
138     call s:GundoMapGraph()
139 endfunction"}}}
140
141 function! s:GundoSettingsPreview()"{{{
142     setlocal buftype=nofile
143     setlocal bufhidden=hide
144     setlocal noswapfile
145     setlocal nobuflisted
146     setlocal nomodifiable
147     setlocal filetype=diff
148     setlocal nonumber
149     setlocal norelativenumber
150     setlocal nowrap
151     setlocal foldlevel=20
152     setlocal foldmethod=diff
153     call s:GundoMapPreview()
154 endfunction"}}}
155
156 function! s:GundoSyntaxGraph()"{{{
157     let b:current_syntax = 'gundo'
158
159     syn match GundoCurrentLocation '@'
160     syn match GundoHelp '\v^".*$'
161     syn match GundoNumberField '\v\[[0-9]+\]'
162     syn match GundoNumber '\v[0-9]+' contained containedin=GundoNumberField
163
164     hi def link GundoCurrentLocation Keyword
165     hi def link GundoHelp Comment
166     hi def link GundoNumberField Comment
167     hi def link GundoNumber Identifier
168 endfunction"}}}
169
170 "}}}
171
172 "{{{ Gundo buffer/window management
173
174 function! s:GundoResizeBuffers(backto)"{{{
175     call s:GundoGoToWindowForBufferName('__Gundo__')
176     exe "vertical resize " . g:gundo_width
177
178     call s:GundoGoToWindowForBufferName('__Gundo_Preview__')
179     exe "resize " . g:gundo_preview_height
180
181     exe a:backto . "wincmd w"
182 endfunction"}}}
183
184 function! s:GundoOpenGraph()"{{{
185     let existing_gundo_buffer = bufnr("__Gundo__")
186
187     if existing_gundo_buffer == -1
188         call s:GundoGoToWindowForBufferName('__Gundo_Preview__')
189         exe "new __Gundo__"
190         if g:gundo_preview_bottom
191             if g:gundo_right
192                 wincmd L
193             else
194                 wincmd H
195             endif
196         endif
197         call s:GundoResizeBuffers(winnr())
198     else
199         let existing_gundo_window = bufwinnr(existing_gundo_buffer)
200
201         if existing_gundo_window != -1
202             if winnr() != existing_gundo_window
203                 exe existing_gundo_window . "wincmd w"
204             endif
205         else
206             call s:GundoGoToWindowForBufferName('__Gundo_Preview__')
207             if g:gundo_preview_bottom
208                 if g:gundo_right
209                     exe "botright vsplit +buffer" . existing_gundo_buffer
210                 else
211                     exe "topleft vsplit +buffer" . existing_gundo_buffer
212                 endif
213             else
214                 exe "split +buffer" . existing_gundo_buffer
215             endif
216             call s:GundoResizeBuffers(winnr())
217         endif
218     endif
219     if exists("g:gundo_tree_statusline")
220         let &l:statusline = g:gundo_tree_statusline
221     endif
222 endfunction"}}}
223
224 function! s:GundoOpenPreview()"{{{
225     let existing_preview_buffer = bufnr("__Gundo_Preview__")
226
227     if existing_preview_buffer == -1
228         if g:gundo_preview_bottom
229             exe "botright new __Gundo_Preview__"
230         else
231             if g:gundo_right
232                 exe "botright vnew __Gundo_Preview__"
233             else
234                 exe "topleft vnew __Gundo_Preview__"
235             endif
236         endif
237     else
238         let existing_preview_window = bufwinnr(existing_preview_buffer)
239
240         if existing_preview_window != -1
241             if winnr() != existing_preview_window
242                 exe existing_preview_window . "wincmd w"
243             endif
244         else
245             if g:gundo_preview_bottom
246                 exe "botright split +buffer" . existing_preview_buffer
247             else
248                 if g:gundo_right
249                     exe "botright vsplit +buffer" . existing_preview_buffer
250                 else
251                     exe "topleft vsplit +buffer" . existing_preview_buffer
252                 endif
253             endif
254         endif
255     endif
256     if exists("g:gundo_preview_statusline")
257         let &l:statusline = g:gundo_preview_statusline
258     endif
259 endfunction"}}}
260
261 function! s:GundoClose()"{{{
262     if s:GundoGoToWindowForBufferName('__Gundo__')
263         quit
264     endif
265
266     if s:GundoGoToWindowForBufferName('__Gundo_Preview__')
267         quit
268     endif
269
270     exe bufwinnr(g:gundo_target_n) . "wincmd w"
271 endfunction"}}}
272
273 function! s:GundoOpen()"{{{
274     if !exists('g:gundo_py_loaded')
275         if s:has_supported_python == 2 && g:gundo_prefer_python3
276             exe 'py3file ' . s:plugin_path . '/gundo.py'
277             python3 initPythonModule()
278         else
279             exe 'pyfile ' . s:plugin_path . '/gundo.py'
280             python initPythonModule()
281         endif
282
283         if !s:has_supported_python
284             function! s:GundoDidNotLoad()
285                 echohl WarningMsg|echomsg "Gundo unavailable: requires Vim 7.3+"|echohl None
286             endfunction
287             command! -nargs=0 GundoToggle call s:GundoDidNotLoad()
288             call s:GundoDidNotLoad()
289             return
290         endif"
291
292         let g:gundo_py_loaded = 1
293     endif
294
295     " Save `splitbelow` value and set it to default to avoid problems with
296     " positioning new windows.
297     let saved_splitbelow = &splitbelow
298     let &splitbelow = 0
299
300     call s:GundoOpenPreview()
301     exe bufwinnr(g:gundo_target_n) . "wincmd w"
302
303     call s:GundoRenderGraph()
304     call s:GundoRenderPreview()
305
306     " Restore `splitbelow` value.
307     let &splitbelow = saved_splitbelow
308 endfunction"}}}
309
310 function! s:GundoToggle()"{{{
311     if s:GundoIsVisible()
312         call s:GundoClose()
313     else
314         let g:gundo_target_n = bufnr('')
315         let g:gundo_target_f = @%
316         call s:GundoOpen()
317     endif
318 endfunction"}}}
319
320 function! s:GundoShow()"{{{
321     call s:GundoOpen()
322 endfunction"}}}
323
324 function! s:GundoHide()"{{{
325     call s:GundoClose()
326 endfunction"}}}
327
328 "}}}
329
330 "{{{ Gundo mouse handling
331
332 function! s:GundoMouseDoubleClick()"{{{
333     let start_line = getline('.')
334
335     if stridx(start_line, '[') == -1
336         return
337     else
338         call s:GundoRevert()
339     endif
340 endfunction"}}}
341
342 "}}}
343
344 "{{{ Gundo movement
345
346 function! s:GundoMove(direction) range"{{{
347     let start_line = getline('.')
348     if v:count1 == 0
349         let move_count = 1
350     else
351         let move_count = v:count1
352     endif
353     let distance = 2 * move_count
354
355     " If we're in between two nodes we move by one less to get back on track.
356     if stridx(start_line, '[') == -1
357         let distance = distance - 1
358     endif
359
360     let target_n = line('.') + (distance * a:direction)
361
362     " Bound the movement to the graph.
363     if target_n <= s:GundoInlineHelpLength() - 1
364         call cursor(s:GundoInlineHelpLength(), 0)
365     else
366         call cursor(target_n, 0)
367     endif
368
369     let line = getline('.')
370
371     " Move to the node, whether it's an @ or an o
372     let idx1 = stridx(line, '@')
373     let idx2 = stridx(line, 'o')
374     if idx1 != -1
375         call cursor(0, idx1 + 1)
376     else
377         call cursor(0, idx2 + 1)
378     endif
379
380     call s:GundoRenderPreview()
381 endfunction"}}}
382
383 "}}}
384
385 "{{{ Gundo rendering
386
387 function! s:GundoRenderGraph()"{{{
388     if s:has_supported_python == 2 && g:gundo_prefer_python3
389         python3 GundoRenderGraph()
390     else
391         python GundoRenderGraph()
392     endif
393 endfunction"}}}
394
395 function! s:GundoRenderPreview()"{{{
396     if s:has_supported_python == 2 && g:gundo_prefer_python3
397         python3 GundoRenderPreview()
398     else
399         python GundoRenderPreview()
400     endif
401 endfunction"}}}
402
403 function! s:GundoRenderChangePreview()"{{{
404     if s:has_supported_python == 2 && g:gundo_prefer_python3
405         python3 GundoRenderChangePreview()
406     else
407         python GundoRenderChangePreview()
408     endif
409 endfunction"}}}
410
411 "}}}
412
413 "{{{ Gundo undo/redo
414
415 function! s:GundoRevert()"{{{
416     if s:has_supported_python == 2 && g:gundo_prefer_python3
417         python3 GundoRevert()
418     else
419         python GundoRevert()
420     endif
421 endfunction"}}}
422
423 function! s:GundoPlayTo()"{{{
424     if s:has_supported_python == 2 && g:gundo_prefer_python3
425         python3 GundoPlayTo()
426     else
427         python GundoPlayTo()
428     endif
429 endfunction"}}}
430
431 "}}}
432
433 "{{{ Misc
434
435 function! gundo#GundoToggle()"{{{
436     call s:GundoToggle()
437 endfunction"}}}
438
439 function! gundo#GundoRenderGraph()"{{{
440     call s:GundoRenderGraph()
441 endfunction"}}}
442
443 augroup GundoAug
444     autocmd!
445     autocmd BufNewFile __Gundo__ call s:GundoSettingsGraph()
446     autocmd BufNewFile __Gundo_Preview__ call s:GundoSettingsPreview()
447 augroup END
448
449 "}}}