Mercurial > vim-lawrencium
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 {{{ |