comparison plugin/lawrencium.vim @ 55:6a61724190ea

Improvements to Lawrencium paths: - `parse_lawrencium_path` only optionally converts paths to absolute or relative paths. - Added ability to get a relative path from a repo object. - `GetLawrenciumPath` converts path to repo-relative by default, but that can be overridden. Improvements to `Hglog`: - Added `Hgrepolog` command. - Fixed clean-up problems. Miscellaneous: - Removed auto-completion from `Hgdiff` and `Hgdiffsum` command families since the only allowed parameters are revision numbers/hashes/specs. - Code clean-up for `Hgdiff`.
author Ludovic Chabant <ludovic@chabant.com>
date Mon, 12 Nov 2012 11:37:56 -0800
parents b7caa6693c39
children 220c9508ff62
comparison
equal deleted inserted replaced
54:ec0368535216 55:6a61724190ea
113 call s:throw("No Mercurial repository found above: " . a:path) 113 call s:throw("No Mercurial repository found above: " . a:path)
114 endfunction 114 endfunction
115 115
116 " Given a Lawrencium path (e.g: 'lawrencium:///repo/root_dir//foo/bar/file.py//rev=34'), extract 116 " Given a Lawrencium path (e.g: 'lawrencium:///repo/root_dir//foo/bar/file.py//rev=34'), extract
117 " the repository root, relative file path and revision number/changeset ID. 117 " the repository root, relative file path and revision number/changeset ID.
118 function! s:parse_lawrencium_path(lawrencium_path) 118 function! s:parse_lawrencium_path(lawrencium_path, ...)
119 let l:repo_path = s:shellslash(a:lawrencium_path) 119 let l:repo_path = s:shellslash(a:lawrencium_path)
120 if l:repo_path =~? '\v^lawrencium://' 120 if l:repo_path =~? '\v^lawrencium://'
121 let l:repo_path = strpart(l:repo_path, strlen('lawrencium://')) 121 let l:repo_path = strpart(l:repo_path, strlen('lawrencium://'))
122 endif 122 endif
123 123
140 let l:value = strpart(l:action, l:equalidx + 1) 140 let l:value = strpart(l:action, l:equalidx + 1)
141 let l:action = strpart(l:action, 0, l:equalidx) 141 let l:action = strpart(l:action, 0, l:equalidx)
142 endif 142 endif
143 endif 143 endif
144 144
145 execute 'cd! ' . l:root_dir 145 if a:0 > 0
146 let l:absolute_repo_path = fnamemodify(l:repo_path, ':p') 146 execute 'cd! ' . l:root_dir
147 let l:relative_repo_path = fnamemodify(l:repo_path, ':.') 147 if a:1 == 'relative'
148 execute 'cd! -' 148 let l:repo_path = fnamemodify(l:repo_path, ':.')
149 elseif a:1 == 'absolute'
150 let l:repo_path = fnamemodify(l:repo_path, ':p')
151 endif
152 execute 'cd! -'
153 endif
149 154
150 let l:result = { 'root': l:root_dir, 'path': l:absolute_repo_path, 'relpath': l:relative_repo_path, 'action': l:action, 'value': l:value } 155 let l:result = { 'root': l:root_dir, 'path': l:repo_path, 'action': l:action, 'value': l:value }
151 return l:result 156 return l:result
152 endfunction 157 endfunction
153 158
154 " }}} 159 " }}}
155 160
174 let l:root_dir = self.root_dir 179 let l:root_dir = self.root_dir
175 if a:path =~# '\v^[/\\]' 180 if a:path =~# '\v^[/\\]'
176 let l:root_dir = s:stripslash(l:root_dir) 181 let l:root_dir = s:stripslash(l:root_dir)
177 endif 182 endif
178 return l:root_dir . a:path 183 return l:root_dir . a:path
184 endfunction
185
186 function! s:HgRepo.GetRelativePath(path) abort
187 execute 'cd! ' . self.root_dir
188 let l:relative_path = fnamemodify(a:path, ':.')
189 execute 'cd! -'
190 return l:relative_path
179 endfunction 191 endfunction
180 192
181 " Gets a list of files matching a root-relative pattern. 193 " Gets a list of files matching a root-relative pattern.
182 " If a flag is passed and is TRUE, a slash will be appended to all 194 " If a flag is passed and is TRUE, a slash will be appended to all
183 " directories. 195 " directories.
228 call s:trace("Running Mercurial command: " . l:hg_command) 240 call s:trace("Running Mercurial command: " . l:hg_command)
229 execute 'read !' . escape(l:hg_command, '%#\') 241 execute 'read !' . escape(l:hg_command, '%#\')
230 endfunction 242 endfunction
231 243
232 " Build a Lawrencium path for the given file and action. 244 " Build a Lawrencium path for the given file and action.
233 function! s:HgRepo.GetLawrenciumPath(path, action, value) abort 245 " By default, the given path will be made relative to the repository root,
234 execute 'cd! ' . self.root_dir 246 " unless '0' is passed as the 4th argument.
235 let l:relative_path = fnamemodify(a:path, ':.') 247 function! s:HgRepo.GetLawrenciumPath(path, action, value, ...) abort
236 execute 'cd! -' 248 let l:path = a:path
237 249 if a:0 == 0 || !a:1
238 let l:result = 'lawrencium://' . s:stripslash(self.root_dir) . '//' . l:relative_path 250 let l:path = self.GetRelativePath(a:path)
251 endif
252 let l:result = 'lawrencium://' . s:stripslash(self.root_dir) . '//' . l:path
239 if a:action !=? '' 253 if a:action !=? ''
240 let l:result = l:result . '//' . a:action 254 let l:result = l:result . '//' . a:action
241 if a:value !=? '' 255 if a:value !=? ''
242 let l:result = l:result . '=' . a:value 256 let l:result = l:result . '=' . a:value
243 endif 257 endif
669 683
670 call s:AddMainCommand("-bang -nargs=? -complete=customlist,s:ListRepoFiles Hgedit :call s:HgEdit(<bang>0, <f-args>)") 684 call s:AddMainCommand("-bang -nargs=? -complete=customlist,s:ListRepoFiles Hgedit :call s:HgEdit(<bang>0, <f-args>)")
671 685
672 " }}} 686 " }}}
673 687
674 " Hgdiff {{{ 688 " Hgdiff, Hgvdiff {{{
675 689
676 function! s:HgDiff(filename, vertical, ...) abort 690 function! s:HgDiff(filename, vertical, ...) abort
677 " Default revisions to diff: the working directory (null string) 691 " Default revisions to diff: the working directory (null string)
678 " and the parent of the working directory (using Mercurial's revsets syntax). 692 " and the parent of the working directory (using Mercurial's revsets syntax).
693 " Otherwise, use the 1 or 2 revisions specified as extra parameters.
679 let l:rev1 = '' 694 let l:rev1 = ''
680 let l:rev2 = 'p1()' 695 let l:rev2 = 'p1()'
681 if a:0 == 1 696 if a:0 == 1
682 let l:rev2 = a:1 697 let l:rev2 = a:1
683 elseif a:0 == 2 698 elseif a:0 == 2
794 augroup lawrencium_diff 809 augroup lawrencium_diff
795 autocmd! 810 autocmd!
796 autocmd BufWinLeave * call s:HgDiff_CleanUp() 811 autocmd BufWinLeave * call s:HgDiff_CleanUp()
797 augroup end 812 augroup end
798 813
799 call s:AddMainCommand("-nargs=* -complete=customlist,s:ListRepoFiles Hgdiff :call s:HgDiff('%:p', 0, <f-args>)") 814 call s:AddMainCommand("-nargs=* Hgdiff :call s:HgDiff('%:p', 0, <f-args>)")
800 call s:AddMainCommand("-nargs=* -complete=customlist,s:ListRepoFiles Hgvdiff :call s:HgDiff('%:p', 1, <f-args>)") 815 call s:AddMainCommand("-nargs=* Hgvdiff :call s:HgDiff('%:p', 1, <f-args>)")
801 816
802 " }}} 817 " }}}
803 818
804 " HgdiffSummary {{{ 819 " Hgdiffsum, Hgdiffsumsplit, Hgvdiffsumsplit {{{
805 820
806 function! s:HgDiffSummary(split, filename, ...) abort 821 function! s:HgDiffSummary(filename, split, ...) abort
807 " Default revisions to diff: the working directory (null string) 822 " Default revisions to diff: the working directory (null string)
808 " and the parent of the working directory (using Mercurial's revsets syntax). 823 " and the parent of the working directory (using Mercurial's revsets syntax).
824 " Otherwise, use the 1 or 2 revisions specified as extra parameters.
809 let l:revs = '' 825 let l:revs = ''
810 if a:0 == 1 826 if a:0 == 1
811 let l:revs = a:1 827 let l:revs = a:1
812 elseif a:0 >= 2 828 elseif a:0 >= 2
813 let l:revs = a:1 . ',' . a:2 829 let l:revs = a:1 . ',' . a:2
828 " Open all folds by default. 844 " Open all folds by default.
829 " TODO: maybe set `nofoldenable` instead? 845 " TODO: maybe set `nofoldenable` instead?
830 %foldopen! 846 %foldopen!
831 endfunction 847 endfunction
832 848
833 call s:AddMainCommand("-nargs=* -complete=customlist,s:ListRepoFiles Hgdiffsum :call s:HgDiffSummary(0, '%:p', <f-args>)") 849 call s:AddMainCommand("-nargs=* Hgdiffsum :call s:HgDiffSummary('%:p', 0, <f-args>)")
834 call s:AddMainCommand("-nargs=* -complete=customlist,s:ListRepoFiles Hgdiffsumsplit :call s:HgDiffSummary(1, '%:p', <f-args>)") 850 call s:AddMainCommand("-nargs=* Hgdiffsumsplit :call s:HgDiffSummary('%:p', 1, <f-args>)")
835 call s:AddMainCommand("-nargs=* -complete=customlist,s:ListRepoFiles Hgvdiffsumsplit :call s:HgDiffSummary(2, '%:p', <f-args>)") 851 call s:AddMainCommand("-nargs=* Hgvdiffsumsplit :call s:HgDiffSummary('%:p', 2, <f-args>)")
836 852
837 " }}} 853 " }}}
838 854
839 " Hgcommit {{{ 855 " Hgcommit {{{
840 856
969 985
970 call s:AddMainCommand("-bang -nargs=* -complete=customlist,s:ListRepoFiles Hgrevert :call s:HgRevert(<bang>0, <f-args>)") 986 call s:AddMainCommand("-bang -nargs=* -complete=customlist,s:ListRepoFiles Hgrevert :call s:HgRevert(<bang>0, <f-args>)")
971 987
972 " }}} 988 " }}}
973 989
974 " Hglog {{{ 990 " Hglog, Hgrepolog {{{
975 991
976 let s:log_style_file = expand("<sfile>:h:h") . "/resources/hg_log.style" 992 let s:log_style_file = expand("<sfile>:h:h") . "/resources/hg_log.style"
977 993
978 function! s:HgLog(...) abort 994 function! s:HgLog(is_file, ...) abort
979 let l:filepath = expand('%:p') 995 " Get the file or directory to get the log from, or figure out
996 " some nice defaults (the current file, or the whole repository).
997 if a:is_file
998 let l:log_path = expand('%:p')
999 else
1000 let l:log_path = '.'
1001 endif
1002
1003 " If the file or directory is specified, get the absolute path.
1004 let l:repo = s:hg_repo()
980 if a:0 == 1 1005 if a:0 == 1
981 let l:filepath = a:1 1006 let l:log_path = l:repo.GetFullPath(a:1)
982 endif 1007 endif
983 1008
984 " Get the repo and run the command. 1009 " Run the command.
985 let l:repo = s:hg_repo() 1010 if l:log_path == '.'
986 let l:output = l:repo.RunCommand('log', '--style', shellescape(s:log_style_file), l:filepath) 1011 let l:output = l:repo.RunCommand('log', '--style', shellescape(s:log_style_file))
1012 else
1013 let l:output = l:repo.RunCommand('log', '--style', shellescape(s:log_style_file), l:log_path)
1014 endif
1015
1016 " Remember the file that opened this log.
1017 let l:original_path = expand('%:p')
987 1018
988 " Open a new temp buffer in the preview window, jump to it, 1019 " Open a new temp buffer in the preview window, jump to it,
989 " and paste the `hg log` output in there. 1020 " and paste the `hg log` output in there.
990 let l:temp_file = s:tempname('hg-log-', '.txt') 1021 let l:temp_file = s:tempname('hg-log-', '.txt')
991 execute "pedit " . l:temp_file 1022 execute "pedit " . l:temp_file
994 call cursor(1, 1) 1025 call cursor(1, 1)
995 1026
996 " Setup the buffer correctly: readonly, and with the correct repo linked 1027 " Setup the buffer correctly: readonly, and with the correct repo linked
997 " to it, and deleted on close. 1028 " to it, and deleted on close.
998 let b:mercurial_dir = l:repo.root_dir 1029 let b:mercurial_dir = l:repo.root_dir
999 let b:mercurial_logged_file = l:filepath 1030 let b:lawrencium_logged_path = l:repo.GetRelativePath(l:log_path)
1031 let b:lawrencium_original_path = l:original_path
1000 setlocal bufhidden=delete 1032 setlocal bufhidden=delete
1001 setlocal buftype=nofile 1033 setlocal buftype=nofile
1002 setlocal filetype=hglog 1034 setlocal filetype=hglog
1003 1035
1004 " Make commands available. 1036 " Make commands available.
1005 call s:DefineMainCommands() 1037 call s:DefineMainCommands()
1006 1038
1007 " Add some other nice commands and mappings. 1039 " Add some other nice commands and mappings.
1008 command! -buffer -nargs=? Hglogrevedit :call s:HgLog_FileRevEdit(<f-args>)
1009 command! -buffer -nargs=* Hglogdiff :call s:HgLog_Diff(<f-args>) 1040 command! -buffer -nargs=* Hglogdiff :call s:HgLog_Diff(<f-args>)
1041 if a:is_file
1042 command! -buffer -nargs=? Hglogrevedit :call s:HgLog_FileRevEdit(<f-args>)
1043 endif
1010 1044
1011 if g:lawrencium_define_mappings 1045 if g:lawrencium_define_mappings
1012 nnoremap <buffer> <silent> <cr> :Hglogrevedit<cr> 1046 nnoremap <buffer> <silent> <cr> :Hglogdiff<cr>
1013 nnoremap <buffer> <silent> <C-D> :Hglogdiff<cr>
1014 nnoremap <buffer> <silent> q :bdelete!<cr> 1047 nnoremap <buffer> <silent> q :bdelete!<cr>
1048 if a:is_file
1049 nnoremap <buffer> <silent> <C-E> :Hglogrevedit<cr>
1050 endif
1015 endif 1051 endif
1016 1052
1017 " Clean up when the log buffer is deleted. 1053 " Clean up when the log buffer is deleted.
1018 autocmd BufDelete <buffer> call s:HgLog_Delete(expand('<afile>:p')) 1054 execute 'autocmd BufDelete <buffer> call s:HgLog_Delete(' . a:is_file . ', "' . fnameescape(l:temp_file) . '")'
1019 endfunction 1055 endfunction
1020 1056
1021 function! s:HgLog_Delete(path) 1057 function! s:HgLog_Delete(was_file, path)
1058 let l:repo = s:hg_repo()
1022 let l:orignr = winnr() 1059 let l:orignr = winnr()
1023 let l:origpath = b:mercurial_logged_file 1060 let l:origedit = b:lawrencium_original_path
1024 let l:origroot = s:stripslash(b:mercurial_dir) 1061 let l:origroot = s:stripslash(b:mercurial_dir)
1062 let l:origpath = s:stripslash(b:lawrencium_logged_path)
1063 call s:trace("Cleaning up '" . a:path . "', opened from '" . l:origedit . "'")
1025 " Delete any other buffer opened by this log. 1064 " Delete any other buffer opened by this log.
1026 " (buffers with Lawrencium paths that match this repo and filename) 1065 " (buffers with Lawrencium paths that match this repo and filename)
1027 for nr in range(1, winnr('$')) 1066 for nr in range(1, winnr('$'))
1028 let l:br = winbufnr(nr) 1067 let l:br = winbufnr(nr)
1029 let l:bpath = bufname(l:br) 1068 let l:bpath = bufname(l:br)
1030 let l:bpath_comps = s:parse_lawrencium_path(l:bpath) 1069 let l:bpath_comps = s:parse_lawrencium_path(l:bpath)
1031 if l:bpath_comps['root'] != '' 1070 if l:bpath_comps['root'] != ''
1032 let l:bpath_root = s:normalizepath(l:bpath_comps['root']) 1071 let l:bpath_root = s:normalizepath(l:bpath_comps['root'])
1033 let l:bpath_path = s:normalizepath(l:bpath_comps['path']) 1072 let l:bpath_path = s:normalizepath(s:stripslash(l:bpath_comps['path']))
1073 call s:trace("Comparing '".l:bpath_path."' and '".l:origpath."' for cleanup.")
1034 if l:bpath_root == l:origroot && l:bpath_path == l:origpath 1074 if l:bpath_root == l:origroot && l:bpath_path == l:origpath
1035 " Go to that window and switch to the previous buffer 1075 " Go to that window and switch to the previous buffer
1036 " from the buffer with the file revision. 1076 " from the buffer with the file revision.
1037 " Just switching away should delete the buffer since it 1077 " Just switching away should delete the buffer since it
1038 " has `bufhidden=delete`. 1078 " has `bufhidden=delete`.
1041 if l:altbufname =~# '\v^lawrencium://' 1081 if l:altbufname =~# '\v^lawrencium://'
1042 " This is a special Lawrencium buffer... it could be 1082 " This is a special Lawrencium buffer... it could be
1043 " a previously shown revision of the file opened with 1083 " a previously shown revision of the file opened with
1044 " this very `Hglog`, which we don't want to switch to. 1084 " this very `Hglog`, which we don't want to switch to.
1045 " Let's just default to editing the original file 1085 " Let's just default to editing the original file
1046 " again... not sure what else to do here. 1086 " again... not sure what else to do here...
1047 execute 'edit ' . l:origpath 1087 call s:trace("Reverting to editing: " . l:origedit)
1088 execute 'edit ' . l:origedit
1048 else 1089 else
1049 bprevious 1090 bprevious
1050 endif 1091 endif
1051 endif 1092 endif
1052 endif 1093 endif
1068 else 1109 else
1069 " Revision should be parsed from the current line in the log. 1110 " Revision should be parsed from the current line in the log.
1070 let l:rev = s:HgLog_GetSelectedRev() 1111 let l:rev = s:HgLog_GetSelectedRev()
1071 endif 1112 endif
1072 let l:repo = s:hg_repo() 1113 let l:repo = s:hg_repo()
1073 let l:path = l:repo.GetLawrenciumPath(b:mercurial_logged_file, 'rev', l:rev) 1114 let l:path = l:repo.GetLawrenciumPath(b:lawrencium_logged_path, 'rev', l:rev)
1074 wincmd p 1115 wincmd p
1075 execute 'edit ' . fnameescape(l:path) 1116 execute 'edit ' . fnameescape(l:path)
1076 endfunction 1117 endfunction
1077 1118
1078 function! s:HgLog_Diff(...) abort 1119 function! s:HgLog_Diff(...) abort
1082 let l:revs = a:1 1123 let l:revs = a:1
1083 else 1124 else
1084 let l:revs = s:HgLog_GetSelectedRev() 1125 let l:revs = s:HgLog_GetSelectedRev()
1085 endif 1126 endif
1086 let l:repo = s:hg_repo() 1127 let l:repo = s:hg_repo()
1087 let l:path = l:repo.GetLawrenciumPath(b:mercurial_logged_file, 'diff', l:revs) 1128 let l:path = l:repo.GetLawrenciumPath(b:lawrencium_logged_path, 'diff', l:revs)
1088 wincmd p 1129 wincmd p
1089 execute 'edit ' . fnameescape(l:path) 1130 execute 'edit ' . fnameescape(l:path)
1090 endfunction 1131 endfunction
1091 1132
1092 function! s:HgLog_GetSelectedRev(...) abort 1133 function! s:HgLog_GetSelectedRev(...) abort
1101 call s:throw("Can't parse revision number from line: " . l:line) 1142 call s:throw("Can't parse revision number from line: " . l:line)
1102 endif 1143 endif
1103 return l:rev 1144 return l:rev
1104 endfunction 1145 endfunction
1105 1146
1106 call s:AddMainCommand("-nargs=? -complete=customlist,s:ListRepoFiles Hglog :call s:HgLog(<f-args>)") 1147 call s:AddMainCommand("-nargs=? -complete=customlist,s:ListRepoDirs Hgrepolog :call s:HgLog(0, <f-args>)")
1148 call s:AddMainCommand("-nargs=? -complete=customlist,s:ListRepoFiles Hglog :call s:HgLog(1, <f-args>)")
1107 1149
1108 " }}} 1150 " }}}
1109 1151
1110 " Lawrencium files {{{ 1152 " Lawrencium files {{{
1111 1153
1115 if l:comps['root'] == '' 1157 if l:comps['root'] == ''
1116 call s:throw("Can't get repository root from: " . a:path) 1158 call s:throw("Can't get repository root from: " . a:path)
1117 endif 1159 endif
1118 1160
1119 let l:repo = s:hg_repo(l:comps['root']) 1161 let l:repo = s:hg_repo(l:comps['root'])
1162 let l:full_path = l:repo.root_dir . l:comps['path']
1120 if l:comps['action'] == 'rev' 1163 if l:comps['action'] == 'rev'
1121 " Read revision (`hg cat`) 1164 " Read revision (`hg cat`)
1122 if l:comps['value'] == '' 1165 if l:comps['value'] == ''
1123 call l:repo.ReadCommandOutput('cat', l:comps['path']) 1166 call l:repo.ReadCommandOutput('cat', l:full_path)
1124 else 1167 else
1125 call l:repo.ReadCommandOutput('cat', '-r', l:comps['value'], l:comps['path']) 1168 call l:repo.ReadCommandOutput('cat', '-r', l:comps['value'], l:full_path)
1126 endif 1169 endif
1127 elseif l:comps['action'] == 'diff' 1170 elseif l:comps['action'] == 'diff'
1128 " Diff revisions (`hg diff`) 1171 " Diff revisions (`hg diff`)
1172 let l:diffargs = []
1129 let l:commaidx = stridx(l:comps['value'], ',') 1173 let l:commaidx = stridx(l:comps['value'], ',')
1130 if l:commaidx > 0 1174 if l:commaidx > 0
1131 let l:rev1 = strpart(l:comps['value'], 0, l:commaidx) 1175 let l:rev1 = strpart(l:comps['value'], 0, l:commaidx)
1132 let l:rev2 = strpart(l:comps['value'], l:commaidx + 1) 1176 let l:rev2 = strpart(l:comps['value'], l:commaidx + 1)
1133 if l:rev1 == '-' 1177 if l:rev1 == '-'
1134 call l:repo.ReadCommandOutput('diff', '-r', l:rev2, l:comps['path']) 1178 let l:diffargs = [ '-r', l:rev2 ]
1135 elseif l:rev2 == '-' 1179 elseif l:rev2 == '-'
1136 call l:repo.ReadCommandOutput('diff', '-r', l:rev1, l:comps['path']) 1180 let l:diffargs = [ '-r', l:rev1 ]
1137 else 1181 else
1138 call l:repo.ReadCommandOutput('diff', '-r', l:rev1, '-r', l:rev2, l:comps['path']) 1182 let l:diffargs = [ '-r', l:rev1, '-r', l:rev2 ]
1139 endif 1183 endif
1140 elseif l:comps['value'] != '' 1184 elseif l:comps['value'] != ''
1141 call l:repo.ReadCommandOutput('diff', '-c', l:comps['value'], l:comps['path']) 1185 let l:diffargs = [ '-c', l:comps['value'] ]
1142 else 1186 else
1143 call l:repo.ReadCommandOutput('diff', l:comps['path']) 1187 let l:diffargs = []
1144 endif 1188 endif
1189 if l:comps['path'] != '' && l:comps['path'] != '.'
1190 call add(l:diffargs, l:full_path)
1191 endif
1192 call l:repo.ReadCommandOutput('diff', l:diffargs)
1145 setlocal filetype=diff 1193 setlocal filetype=diff
1146 endif 1194 endif
1147 1195
1148 " Setup the new buffer. 1196 " Setup the new buffer.
1149 setlocal readonly 1197 setlocal readonly