comparison plugin/lawrencium.vim @ 48:85e39bdd7089

Lots of changes that should have gone in other commits (ugh): - merged changes from @soliman - removed the bang edit command setting. The preview windows is not really well suited for some things, so it's been replaced with a normal split window for `Hg!` and `Hgstatus`. - officialized `Hglog`. - fixed some problems on Windows.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 08 Nov 2012 13:58:29 -0800
parents 6a4f5200d8da edc43c59b3b8
children dffb41c2067c
comparison
equal deleted inserted replaced
46:6a4f5200d8da 48:85e39bdd7089
30 30
31 if !exists('g:lawrencium_define_mappings') 31 if !exists('g:lawrencium_define_mappings')
32 let g:lawrencium_define_mappings = 1 32 let g:lawrencium_define_mappings = 1
33 endif 33 endif
34 34
35 if !exists('g:lawrencium_hg_bang_edit_command')
36 let g:lawrencium_hg_bang_edit_command = 'pedit'
37 endif
38
39 " }}} 35 " }}}
40 36
41 " Utility {{{ 37 " Utility {{{
42 38
43 " Strips the ending slash in a path. 39 " Strips the ending slash in a path.
46 endfunction 42 endfunction
47 43
48 " Normalizes the slashes in a path. 44 " Normalizes the slashes in a path.
49 function! s:normalizepath(path) 45 function! s:normalizepath(path)
50 if exists('+shellslash') && &shellslash 46 if exists('+shellslash') && &shellslash
51 return substitute(a:path, '\\', '/', '') 47 return substitute(a:path, '\v/', '\\', 'g')
52 elseif has('win32') 48 elseif has('win32')
53 return substitute(a:path, '/', '\\', '') 49 return substitute(a:path, '\v/', '\\', 'g')
54 else 50 else
55 return a:path 51 return a:path
56 endif 52 endif
53 endfunction
54
55 " Shell-slashes the path (opposite of `normalizepath`).
56 function! s:shellslash(path)
57 if exists('+shellslash') && !&shellslash
58 return substitute(a:path, '\v\\', '/', 'g')
59 else
60 return a:path
61 endif
57 endfunction 62 endfunction
58 63
59 " Like tempname() but with some control over the filename. 64 " Like tempname() but with some control over the filename.
60 function! s:tempname(name, ...) 65 function! s:tempname(name, ...)
61 let l:path = tempname() 66 let l:path = tempname()
109 endfunction 114 endfunction
110 115
111 " Given a Lawrencium path (e.g: 'lawrencium:///repo/root_dir@foo/bar/file.py//34'), extract 116 " Given a Lawrencium path (e.g: 'lawrencium:///repo/root_dir@foo/bar/file.py//34'), extract
112 " the repository root, relative file path and revision number/changeset ID. 117 " the repository root, relative file path and revision number/changeset ID.
113 function! s:parse_lawrencium_path(lawrencium_path) 118 function! s:parse_lawrencium_path(lawrencium_path)
114 let l:repo_path = a:lawrencium_path 119 let l:repo_path = s:shellslash(a:lawrencium_path)
115 if l:repo_path =~? '^lawrencium://' 120 if l:repo_path =~? '\v^lawrencium://'
116 let l:repo_path = strpart(l:repo_path, strlen('lawrencium://')) 121 let l:repo_path = strpart(l:repo_path, strlen('lawrencium://'))
117 endif 122 endif
118 123
119 let l:root_dir = '' 124 let l:root_dir = ''
120 let l:at_idx = stridx(l:repo_path, '@') 125 let l:at_idx = stridx(l:repo_path, '@')
315 execute 'cd! -' 320 execute 'cd! -'
316 endif 321 endif
317 if a:bang 322 if a:bang
318 " Open the output of the command in a temp file. 323 " Open the output of the command in a temp file.
319 let l:temp_file = s:tempname('hg-output-', '.txt') 324 let l:temp_file = s:tempname('hg-output-', '.txt')
320 execute g:lawrencium_hg_bang_edit_command . ' ' . l:temp_file 325 split
321 wincmd p 326 execute 'edit ' . l:temp_file
322 call append(0, split(l:output, '\n')) 327 call append(0, split(l:output, '\n'))
323 call cursor(1, 1) 328 call cursor(1, 1)
324 329
325 " Make it a temp buffer 330 " Make it a temp buffer
326 setlocal bufhidden=delete 331 setlocal bufhidden=delete
417 let l:status_text = l:repo.RunCommand('status') 422 let l:status_text = l:repo.RunCommand('status')
418 if l:status_text ==# '\v%^\s*%$' 423 if l:status_text ==# '\v%^\s*%$'
419 echo "Nothing modified." 424 echo "Nothing modified."
420 endif 425 endif
421 426
422 " Open a new temp buffer in the preview window, jump to it, 427 " Open a new temp buffer in a new window, jump to it,
423 " and paste the `hg status` output in there. 428 " and paste the `hg status` output in there.
424 let l:temp_file = s:tempname('hg-status-', '.txt') 429 let l:temp_file = s:tempname('hg-status-', '.txt')
425 let l:preview_height = &previewheight
426 let l:status_lines = split(l:status_text, '\n') 430 let l:status_lines = split(l:status_text, '\n')
427 execute "setlocal previewheight=" . (len(l:status_lines) + 1) 431 split
428 execute "pedit " . l:temp_file 432 execute "setlocal winfixheight"
429 wincmd p 433 execute "setlocal winheight=" . (len(l:status_lines) + 1)
434 execute "resize " . (len(l:status_lines) + 1)
435 execute "edit " . l:temp_file
430 call append(0, l:status_lines) 436 call append(0, l:status_lines)
431 call cursor(1, 1) 437 call cursor(1, 1)
432 " Make it a nice size.
433 execute "setlocal previewheight=" . l:preview_height
434 " Make sure it's deleted when we exit the window. 438 " Make sure it's deleted when we exit the window.
435 setlocal bufhidden=delete 439 setlocal bufhidden=delete
436 440
437 " Setup the buffer correctly: readonly, and with the correct repo linked 441 " Setup the buffer correctly: readonly, and with the correct repo linked
438 " to it. 442 " to it.
915 let l:filepath = expand('%:p') 919 let l:filepath = expand('%:p')
916 if a:0 == 1 920 if a:0 == 1
917 let l:filepath = a:1 921 let l:filepath = a:1
918 endif 922 endif
919 923
920 " Get the repo and get the command. 924 " Get the repo and run the command.
921 let l:repo = s:hg_repo() 925 let l:repo = s:hg_repo()
922 let l:log_command = l:repo.GetCommand('log', l:filepath, '--template', '"{rev}\t{desc|firstline}\n"') 926 let l:output = l:repo.RunCommand('log', l:filepath, '--template', '"{rev}\t{desc|firstline}\n"')
923 927
924 " Open a new temp buffer in the preview window, jump to it, 928 " Open a new temp buffer in the preview window, jump to it,
925 " and paste the `hg log` output in there. 929 " and paste the `hg log` output in there.
926 let l:temp_file = s:tempname('hg-log-', '.txt') 930 let l:temp_file = s:tempname('hg-log-', '.txt')
927 execute "pedit " . l:temp_file 931 execute "pedit " . l:temp_file
928 wincmd p 932 wincmd P
929 execute "read !" . escape(l:log_command, '%#\') 933 call append(0, split(l:output, '\n'))
934 call cursor(1, 1)
930 935
931 " Setup the buffer correctly: readonly, and with the correct repo linked 936 " Setup the buffer correctly: readonly, and with the correct repo linked
932 " to it, and deleted on close. 937 " to it, and deleted on close.
933 let b:mercurial_dir = l:repo.root_dir 938 let b:mercurial_dir = l:repo.root_dir
934 let b:mercurial_logged_file = l:filepath 939 let b:mercurial_logged_file = l:filepath
944 if g:lawrencium_define_mappings 949 if g:lawrencium_define_mappings
945 nnoremap <buffer> <silent> <cr> :Hglogrevedit<cr> 950 nnoremap <buffer> <silent> <cr> :Hglogrevedit<cr>
946 nnoremap <buffer> <silent> q :bdelete!<cr> 951 nnoremap <buffer> <silent> q :bdelete!<cr>
947 endif 952 endif
948 953
949 " Make sure the file is deleted with the buffer. 954 " Clean up when the log buffer is deleted.
950 autocmd BufDelete <buffer> call s:clean_tempfile(expand('<afile>:p')) 955 autocmd BufDelete <buffer> call s:HgLog_Delete(expand('<afile>:p'))
956 endfunction
957
958 function! s:HgLog_Delete(path)
959 let l:orignr = winnr()
960 let l:origpath = b:mercurial_logged_file
961 " Delete any other buffer opened by this log.
962 " (buffers with Lawrencium paths that match this repo and filename)
963 for nr in range(1, winnr('$'))
964 let l:br = winbufnr(nr)
965 let l:bpath = bufname(l:br)
966 let l:bpath_comps = s:parse_lawrencium_path(l:bpath)
967 if l:bpath_comps['root'] != ''
968 let l:bpath_root = s:normalizepath(l:bpath_comps['root'])
969 let l:bpath_path = s:normalizepath(l:bpath_comps['path'])
970 if l:bpath_root == b:mercurial_dir && l:bpath_path == b:mercurial_logged_file
971 " Go to that window and switch to the previous buffer
972 " from the buffer with the file revision.
973 " Just switching away should delete the buffer since it
974 " has `bufhidden=delete`.
975 echom "Found buffer in window: ".nr
976 execute nr . 'wincmd w'
977 let l:altbufname = s:shellslash(bufname('#'))
978 if l:altbufname =~# '\v^lawrencium://'
979 " This is a special Lawrencium buffer... it could be
980 " a previously shown revision of the file opened with
981 " this very `Hglog`, which we don't want to switch to.
982 " Let's just default to editing the original file
983 " again... not sure what else to do here.
984 execute 'edit ' . l:origpath
985 else
986 bprevious
987 endif
988 endif
989 endif
990 endfor
991 " Restore the current window if we switched away.
992 let l:curnr = winnr()
993 if l:curnr != l:orignr
994 execute l:orignr . 'wincmd w'
995 endif
996
997 " Delete the temp file if it was created somehow.
998 call s:clean_tempfile(a:path)
951 endfunction 999 endfunction
952 1000
953 function! s:HgLog_FileRevEdit(...) 1001 function! s:HgLog_FileRevEdit(...)
954 if a:0 > 0 1002 if a:0 > 0
955 " Revision was given manually. 1003 " Revision was given manually.
957 else 1005 else
958 " Revision should be parsed from the current line in the log. 1006 " Revision should be parsed from the current line in the log.
959 let l:rev = s:HgLog_GetSelectedRev() 1007 let l:rev = s:HgLog_GetSelectedRev()
960 endif 1008 endif
961 let l:path = 'lawrencium://' . b:mercurial_dir . '@' . b:mercurial_logged_file . '//' . l:rev 1009 let l:path = 'lawrencium://' . b:mercurial_dir . '@' . b:mercurial_logged_file . '//' . l:rev
1010 let l:path = fnameescape(l:path)
1011 wincmd p
962 execute 'edit ' . l:path 1012 execute 'edit ' . l:path
1013 setlocal bufhidden=delete
1014 setlocal buftype=nofile
963 endfunction 1015 endfunction
964 1016
965 function! s:HgLog_GetSelectedRev() abort 1017 function! s:HgLog_GetSelectedRev() abort
966 let l:line = getline('.') 1018 let l:line = getline('.')
967 " Behold, Vim's look-ahead regex syntax again! WTF. 1019 " Behold, Vim's look-ahead regex syntax again! WTF.
987 if l:comps['rev'] == '' 1039 if l:comps['rev'] == ''
988 execute 'read !' . escape(l:repo.GetCommand('cat', l:comps['path']), '%#\') 1040 execute 'read !' . escape(l:repo.GetCommand('cat', l:comps['path']), '%#\')
989 else 1041 else
990 execute 'read !' . escape(l:repo.GetCommand('cat', '-r', l:comps['rev'], l:comps['path']), '%#\') 1042 execute 'read !' . escape(l:repo.GetCommand('cat', '-r', l:comps['rev'], l:comps['path']), '%#\')
991 endif 1043 endif
1044 setlocal readonly
1045 setlocal nomodifiable
1046 setlocal nomodified
1047 setlocal bufhidden=delete
992 return '' 1048 return ''
993 endfunction 1049 endfunction
994 1050
995 augroup lawrencium_files 1051 augroup lawrencium_files
996 autocmd! 1052 autocmd!
997 autocmd BufReadCmd lawrencium://**//[0-9a-f][0-9a-f]* exe s:ReadFileRevision(expand('<amatch>')) 1053 autocmd BufReadCmd lawrencium://**//[0-9a-f]* exe s:ReadFileRevision(expand('<amatch>'))
998 augroup END 1054 augroup END
999 1055
1000 " }}} 1056 " }}}
1001 1057
1002 " Autoload Functions {{{ 1058 " Autoload Functions {{{