Mercurial > hg > mercurial-crew-with-dirclash
view contrib/vim/hgcommand.vim @ 2593:0a30407fff72
merge with crew.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Tue, 11 Jul 2006 13:47:51 -0700 |
parents | 457846f400e8 |
children | f80057407c07 |
line wrap: on
line source
" vim600: set foldmethod=marker: " " Vim plugin to assist in working with HG-controlled files. " " Last Change: 2006/02/22 " Version: 1.76 " Maintainer: Mathieu Clabaut <mathieu.clabaut@gmail.com> " License: This file is placed in the public domain. " Credits: {{{1 " Bob Hiestand <bob.hiestand@gmail.com> for the fabulous " cvscommand.vim from which this script was directly created by " means of sed commands and minor tweaks. " Section: Documentation {{{1 " " Provides functions to invoke various HG commands on the current file " (either the current buffer, or, in the case of an directory buffer, the file " on the current line). The output of the commands is captured in a new " scratch window. For convenience, if the functions are invoked on a HG " output window, the original file is used for the hg operation instead after " the window is split. This is primarily useful when running HGCommit and " you need to see the changes made, so that HGDiff is usable and shows up in " another window. " " Command documentation {{{2 " " HGAdd Performs "hg add" on the current file. " " HGAnnotate Performs "hg annotate" on the current file. If an " argument is given, the argument is used as a revision " number to display. If not given an argument, it uses the " most recent version of the file on the current branch. " Additionally, if the current buffer is a HGAnnotate buffer " already, the version number on the current line is used. " " If the 'HGCommandAnnotateParent' variable is set to a " non-zero value, the version previous to the one on the " current line is used instead. This allows one to navigate " back to examine the previous version of a line. " " HGCommit[!] If called with arguments, this performs "hg commit" using " the arguments as the log message. " " If '!' is used, an empty log message is committed. " " If called with no arguments, this is a two-step command. " The first step opens a buffer to accept a log message. " When that buffer is written, it is automatically closed and " the file is committed using the information from that log " message. The commit can be abandoned if the log message " buffer is deleted or wiped before being written. " " HGDiff With no arguments, this performs "hg diff" on the current " file. With one argument, "hg diff" is performed on the " current file against the specified revision. With two " arguments, hg diff is performed between the specified " revisions of the current file. This command uses the " 'HGCommandDiffOpt' variable to specify diff options. If " that variable does not exist, then 'wbBc' is assumed. If " you wish to have no options, then set it to the empty " string. " " HGGotoOriginal Returns the current window to the source buffer if the " current buffer is a HG output buffer. " " HGLog Performs "hg log" on the current file. " " HGRevert Replaces the modified version of the current file with the " most recent version from the repository. " " HGReview Retrieves a particular version of the current file. If no " argument is given, the most recent version of the file on " the current branch is retrieved. The specified revision is " retrieved into a new buffer. " " HGStatus Performs "hg status" on the current file. " " HGUpdate Performs "hg update" on the current file. " " HGVimDiff With no arguments, this prompts the user for a revision and " then uses vimdiff to display the differences between the " current file and the specified revision. If no revision is " specified, the most recent version of the file on the " current branch is used. With one argument, that argument " is used as the revision as above. With two arguments, the " differences between the two revisions is displayed using " vimdiff. " " With either zero or one argument, the original buffer is used " to perform the vimdiff. When the other buffer is closed, the " original buffer will be returned to normal mode. " " Once vimdiff mode is started using the above methods, " additional vimdiff buffers may be added by passing a single " version argument to the command. There may be up to 4 " vimdiff buffers total. " " Using the 2-argument form of the command resets the vimdiff " to only those 2 versions. Additionally, invoking the " command on a different file will close the previous vimdiff " buffers. " " " Mapping documentation: {{{2 " " By default, a mapping is defined for each command. User-provided mappings " can be used instead by mapping to <Plug>CommandName, for instance: " " nnoremap ,ca <Plug>HGAdd " " The default mappings are as follow: " " <Leader>hga HGAdd " <Leader>hgn HGAnnotate " <Leader>hgc HGCommit " <Leader>hgd HGDiff " <Leader>hgg HGGotoOriginal " <Leader>hgG HGGotoOriginal! " <Leader>hgl HGLog " <Leader>hgr HGReview " <Leader>hgs HGStatus " <Leader>hgu HGUpdate " <Leader>hgv HGVimDiff " " Options documentation: {{{2 " " Several variables are checked by the script to determine behavior as follow: " " HGCommandAnnotateParent " This variable, if set to a non-zero value, causes the zero-argument form " of HGAnnotate when invoked on a HGAnnotate buffer to go to the version " previous to that displayed on the current line. If not set, it defaults " to 0. " " HGCommandCommitOnWrite " This variable, if set to a non-zero value, causes the pending hg commit " to take place immediately as soon as the log message buffer is written. " If set to zero, only the HGCommit mapping will cause the pending commit " to occur. If not set, it defaults to 1. " " HGCommandDeleteOnHide " This variable, if set to a non-zero value, causes the temporary HG result " buffers to automatically delete themselves when hidden. " " HGCommandDiffOpt " This variable, if set, determines the options passed to the diff command " of HG. If not set, it defaults to 'wbBc'. " " HGCommandDiffSplit " This variable overrides the HGCommandSplit variable, but only for buffers " created with HGVimDiff. " " HGCommandEdit " This variable controls whether the original buffer is replaced ('edit') or " split ('split'). If not set, it defaults to 'edit'. " " HGCommandEnableBufferSetup " This variable, if set to a non-zero value, activates HG buffer management " mode. This mode means that two buffer variables, 'HGRevision' and " 'HGBranch', are set if the file is HG-controlled. This is useful for " displaying version information in the status bar. " " HGCommandInteractive " This variable, if set to a non-zero value, causes appropriate functions (for " the moment, only HGReview) to query the user for a revision to use " instead of the current revision if none is specified. " " HGCommandNameMarker " This variable, if set, configures the special attention-getting characters " that appear on either side of the hg buffer type in the buffer name. " This has no effect unless 'HGCommandNameResultBuffers' is set to a true " value. If not set, it defaults to '_'. " " HGCommandNameResultBuffers " This variable, if set to a true value, causes the hg result buffers to be " named in the old way ('<source file name> _<hg command>_'). If not set " or set to a false value, the result buffer is nameless. " " HGCommandSplit " This variable controls the orientation of the various window splits that " may occur (such as with HGVimDiff, when using a HG command on a HG " command buffer, or when the 'HGCommandEdit' variable is set to 'split'. " If set to 'horizontal', the resulting windows will be on stacked on top of " one another. If set to 'vertical', the resulting windows will be " side-by-side. If not set, it defaults to 'horizontal' for all but " HGVimDiff windows. " " Event documentation {{{2 " For additional customization, hgcommand.vim uses User event autocommand " hooks. Each event is in the HGCommand group, and different patterns " match the various hooks. " " For instance, the following could be added to the vimrc to provide a 'q' " mapping to quit a HG buffer: " " augroup HGCommand " au HGCommand User HGBufferCreated silent! nmap <unique> <buffer> q :bwipeout<cr> " augroup END " " The following hooks are available: " " HGBufferCreated This event is fired just after a hg command " result buffer is created and filled with the " result of a hg command. It is executed within " the context of the new buffer. " " HGBufferSetup This event is fired just after HG buffer setup " occurs, if enabled. " " HGPluginInit This event is fired when the HGCommand plugin " first loads. " " HGPluginFinish This event is fired just after the HGCommand " plugin loads. " " HGVimDiffFinish This event is fired just after the HGVimDiff " command executes to allow customization of, " for instance, window placement and focus. " " Section: Plugin header {{{1 " loaded_hgcommand is set to 1 when the initialization begins, and 2 when it " completes. This allows various actions to only be taken by functions after " system initialization. if exists("loaded_hgcommand") finish endif let loaded_hgcommand = 1 if v:version < 602 echohl WarningMsg|echomsg "HGCommand 1.69 or later requires VIM 6.2 or later"|echohl None finish endif " Section: Event group setup {{{1 augroup HGCommand augroup END " Section: Plugin initialization {{{1 silent do HGCommand User HGPluginInit " Section: Script variable initialization {{{1 let s:HGCommandEditFileRunning = 0 unlet! s:vimDiffRestoreCmd unlet! s:vimDiffSourceBuffer unlet! s:vimDiffBufferCount unlet! s:vimDiffScratchList " Section: Utility functions {{{1 " Function: s:HGResolveLink() {{{2 " Fully resolve the given file name to remove shortcuts or symbolic links. function! s:HGResolveLink(fileName) let resolved = resolve(a:fileName) if resolved != a:fileName let resolved = s:HGResolveLink(resolved) endif return resolved endfunction " Function: s:HGChangeToCurrentFileDir() {{{2 " Go to the directory in which the current HG-controlled file is located. " If this is a HG command buffer, first switch to the original file. function! s:HGChangeToCurrentFileDir(fileName) let oldCwd=getcwd() let fileName=s:HGResolveLink(a:fileName) let newCwd=fnamemodify(fileName, ':h') if strlen(newCwd) > 0 execute 'cd' escape(newCwd, ' ') endif return oldCwd endfunction " Function: s:HGGetOption(name, default) {{{2 " Grab a user-specified option to override the default provided. Options are " searched in the window, buffer, then global spaces. function! s:HGGetOption(name, default) if exists("s:" . a:name . "Override") execute "return s:".a:name."Override" elseif exists("w:" . a:name) execute "return w:".a:name elseif exists("b:" . a:name) execute "return b:".a:name elseif exists("g:" . a:name) execute "return g:".a:name else return a:default endif endfunction " Function: s:HGEditFile(name, origBuffNR) {{{2 " Wrapper around the 'edit' command to provide some helpful error text if the " current buffer can't be abandoned. If name is provided, it is used; " otherwise, a nameless scratch buffer is used. " Returns: 0 if successful, -1 if an error occurs. function! s:HGEditFile(name, origBuffNR) "Name parameter will be pasted into expression. let name = escape(a:name, ' *?\') let editCommand = s:HGGetOption('HGCommandEdit', 'edit') if editCommand != 'edit' if s:HGGetOption('HGCommandSplit', 'horizontal') == 'horizontal' if name == "" let editCommand = 'rightbelow new' else let editCommand = 'rightbelow split ' . name endif else if name == "" let editCommand = 'vert rightbelow new' else let editCommand = 'vert rightbelow split ' . name endif endif else if name == "" let editCommand = 'enew' else let editCommand = 'edit ' . name endif endif " Protect against useless buffer set-up let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 try execute editCommand finally let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning - 1 endtry let b:HGOrigBuffNR=a:origBuffNR let b:HGCommandEdit='split' endfunction " Function: s:HGCreateCommandBuffer(cmd, cmdName, statusText, filename) {{{2 " Creates a new scratch buffer and captures the output from execution of the " given command. The name of the scratch buffer is returned. function! s:HGCreateCommandBuffer(cmd, cmdName, statusText, origBuffNR) let fileName=bufname(a:origBuffNR) let resultBufferName='' if s:HGGetOption("HGCommandNameResultBuffers", 0) let nameMarker = s:HGGetOption("HGCommandNameMarker", '_') if strlen(a:statusText) > 0 let bufName=a:cmdName . ' -- ' . a:statusText else let bufName=a:cmdName endif let bufName=fileName . ' ' . nameMarker . bufName . nameMarker let counter=0 let resultBufferName = bufName while buflisted(resultBufferName) let counter=counter + 1 let resultBufferName=bufName . ' (' . counter . ')' endwhile endif let hgCommand = s:HGGetOption("HGCommandHGExec", "hg") . " " . a:cmd echomsg "DBG :".hgCommand let hgOut = system(hgCommand) " HACK: diff command does not return proper error codes if v:shell_error && a:cmdName != 'hgdiff' if strlen(hgOut) == 0 echoerr "HG command failed" else echoerr "HG command failed: " . hgOut endif return -1 endif if strlen(hgOut) == 0 " Handle case of no output. In this case, it is important to check the " file status, especially since hg edit/unedit may change the attributes " of the file with no visible output. echomsg "No output from HG command" checktime return -1 endif if s:HGEditFile(resultBufferName, a:origBuffNR) == -1 return -1 endif set buftype=nofile set noswapfile set filetype= if s:HGGetOption("HGCommandDeleteOnHide", 0) set bufhidden=delete endif silent 0put=hgOut " The last command left a blank line at the end of the buffer. If the " last line is folded (a side effect of the 'put') then the attempt to " remove the blank line will kill the last fold. " " This could be fixed by explicitly detecting whether the last line is " within a fold, but I prefer to simply unfold the result buffer altogether. if has('folding') normal zR endif $d 1 " Define the environment and execute user-defined hooks. let b:HGSourceFile=fileName let b:HGCommand=a:cmdName if a:statusText != "" let b:HGStatusText=a:statusText endif silent do HGCommand User HGBufferCreated return bufnr("%") endfunction " Function: s:HGBufferCheck(hgBuffer) {{{2 " Attempts to locate the original file to which HG operations were applied " for a given buffer. function! s:HGBufferCheck(hgBuffer) let origBuffer = getbufvar(a:hgBuffer, "HGOrigBuffNR") if origBuffer if bufexists(origBuffer) return origBuffer else " Original buffer no longer exists. return -1 endif else " No original buffer return a:hgBuffer endif endfunction " Function: s:HGCurrentBufferCheck() {{{2 " Attempts to locate the original file to which HG operations were applied " for the current buffer. function! s:HGCurrentBufferCheck() return s:HGBufferCheck(bufnr("%")) endfunction " Function: s:HGToggleDeleteOnHide() {{{2 " Toggles on and off the delete-on-hide behavior of HG buffers function! s:HGToggleDeleteOnHide() if exists("g:HGCommandDeleteOnHide") unlet g:HGCommandDeleteOnHide else let g:HGCommandDeleteOnHide=1 endif endfunction " Function: s:HGDoCommand(hgcmd, cmdName, statusText) {{{2 " General skeleton for HG function execution. " Returns: name of the new command buffer containing the command results function! s:HGDoCommand(cmd, cmdName, statusText) let hgBufferCheck=s:HGCurrentBufferCheck() if hgBufferCheck == -1 echo "Original buffer no longer exists, aborting." return -1 endif let fileName=bufname(hgBufferCheck) if isdirectory(fileName) let fileName=fileName . "/" . getline(".") endif let realFileName = fnamemodify(s:HGResolveLink(fileName), ':t') let oldCwd=s:HGChangeToCurrentFileDir(fileName) try " TODO "if !filereadable('HG/Root') "throw fileName . ' is not a HG-controlled file.' "endif let fullCmd = a:cmd . ' "' . realFileName . '"' "echomsg "DEBUG".fullCmd let resultBuffer=s:HGCreateCommandBuffer(fullCmd, a:cmdName, a:statusText, hgBufferCheck) return resultBuffer catch echoerr v:exception return -1 finally execute 'cd' escape(oldCwd, ' ') endtry endfunction " Function: s:HGGetStatusVars(revision, branch, repository) {{{2 " " Obtains a HG revision number and branch name. The 'revisionVar', " 'branchVar'and 'repositoryVar' arguments, if non-empty, contain the names of variables to hold " the corresponding results. " " Returns: string to be exec'd that sets the multiple return values. function! s:HGGetStatusVars(revisionVar, branchVar, repositoryVar) let hgBufferCheck=s:HGCurrentBufferCheck() if hgBufferCheck == -1 return "" endif let fileName=bufname(hgBufferCheck) let realFileName = fnamemodify(s:HGResolveLink(fileName), ':t') let oldCwd=s:HGChangeToCurrentFileDir(fileName) try ""TODO "if !filereadable('HG/Root') "return "" "endif let hgCommand = s:HGGetOption("HGCommandHGExec", "hg") . " status -mardui " . fileName let statustext=system(hgCommand) if(v:shell_error) return "" endif if match(statustext, '^[?I]') >= 0 let revision="NEW" elseif match(statustext, '^[R]') >= 0 let revision="REMOVED" elseif match(statustext, '^[D]') >= 0 let revision="DELETED" elseif match(statustext, '^[A]') >= 0 let revision="ADDED" endif let hgCommand = s:HGGetOption("HGCommandHGExec", "hg") . " parents -b " let statustext=system(hgCommand) if(v:shell_error) return "" endif if exists('revision') let returnExpression = "let " . a:revisionVar . "='" . revision . "'" else let revision=substitute(statustext, '^changeset:\s*\(\d\+\):.*\_$\_.*$', '\1', "") let returnExpression = "let " . a:revisionVar . "='" . revision . "'" endif if a:branchVar != "" && match(statustext, '^\_.*\_^branch:') >= 0 let branch=substitute(statustext, '^\_.*\_^branch:\s*\(\S\+\)\n\_.*$', '\1', "") let returnExpression=returnExpression . " | let " . a:branchVar . "='" . branch . "'" endif if a:repositoryVar != "" let hgCommand = s:HGGetOption("HGCommandHGExec", "hg") . " root " let roottext=system(hgCommand) let repository=substitute(roottext,'^.*/\([^/\n\r]*\)\n\_.*$','\1','') let returnExpression=returnExpression . " | let " . a:repositoryVar . "='" . repository . "'" endif return returnExpression finally execute 'cd' escape(oldCwd, ' ') endtry endfunction " Function: s:HGSetupBuffer() {{{2 " Attempts to set the b:HGBranch, b:HGRevision and b:HGRepository variables. function! s:HGSetupBuffer() if (exists("b:HGBufferSetup") && b:HGBufferSetup) " This buffer is already set up. return endif if !s:HGGetOption("HGCommandEnableBufferSetup", 0) \ || @% == "" \ || s:HGCommandEditFileRunning > 0 \ || exists("b:HGOrigBuffNR") unlet! b:HGRevision unlet! b:HGBranch unlet! b:HGRepository return endif if !filereadable(expand("%")) return -1 endif let revision="" let branch="" let repository="" exec s:HGGetStatusVars('revision', 'branch', 'repository') "echomsg "DBG ".revision."#".branch."#".repository if revision != "" let b:HGRevision=revision else unlet! b:HGRevision endif if branch != "" let b:HGBranch=branch else unlet! b:HGBranch endif if repository != "" let b:HGRepository=repository else unlet! b:HGRepository endif silent do HGCommand User HGBufferSetup let b:HGBufferSetup=1 endfunction " Function: s:HGMarkOrigBufferForSetup(hgbuffer) {{{2 " Resets the buffer setup state of the original buffer for a given HG buffer. " Returns: The HG buffer number in a passthrough mode. function! s:HGMarkOrigBufferForSetup(hgBuffer) checktime if a:hgBuffer != -1 let origBuffer = s:HGBufferCheck(a:hgBuffer) "This should never not work, but I'm paranoid if origBuffer != a:hgBuffer call setbufvar(origBuffer, "HGBufferSetup", 0) endif endif return a:hgBuffer endfunction " Function: s:HGOverrideOption(option, [value]) {{{2 " Provides a temporary override for the given HG option. If no value is " passed, the override is disabled. function! s:HGOverrideOption(option, ...) if a:0 == 0 unlet! s:{a:option}Override else let s:{a:option}Override = a:1 endif endfunction " Function: s:HGWipeoutCommandBuffers() {{{2 " Clears all current HG buffers of the specified type for a given source. function! s:HGWipeoutCommandBuffers(originalBuffer, hgCommand) let buffer = 1 while buffer <= bufnr('$') if getbufvar(buffer, 'HGOrigBuffNR') == a:originalBuffer if getbufvar(buffer, 'HGCommand') == a:hgCommand execute 'bw' buffer endif endif let buffer = buffer + 1 endwhile endfunction " Section: Public functions {{{1 " Function: HGGetRevision() {{{2 " Global function for retrieving the current buffer's HG revision number. " Returns: Revision number or an empty string if an error occurs. function! HGGetRevision() let revision="" exec s:HGGetStatusVars('revision', '', '') return revision endfunction " Function: HGDisableBufferSetup() {{{2 " Global function for deactivating the buffer autovariables. function! HGDisableBufferSetup() let g:HGCommandEnableBufferSetup=0 silent! augroup! HGCommandPlugin endfunction " Function: HGEnableBufferSetup() {{{2 " Global function for activating the buffer autovariables. function! HGEnableBufferSetup() let g:HGCommandEnableBufferSetup=1 augroup HGCommandPlugin au! au BufEnter * call s:HGSetupBuffer() augroup END " Only auto-load if the plugin is fully loaded. This gives other plugins a " chance to run. if g:loaded_hgcommand == 2 call s:HGSetupBuffer() endif endfunction " Function: HGGetStatusLine() {{{2 " Default (sample) status line entry for HG files. This is only useful if " HG-managed buffer mode is on (see the HGCommandEnableBufferSetup variable " for how to do this). function! HGGetStatusLine() if exists('b:HGSourceFile') " This is a result buffer let value='[' . b:HGCommand . ' ' . b:HGSourceFile if exists('b:HGStatusText') let value=value . ' ' . b:HGStatusText endif let value = value . ']' return value endif if exists('b:HGRevision') \ && b:HGRevision != '' \ && exists('b:HGBranch') \ && b:HGBranch != '' \ && exists('b:HGRepository') \ && b:HGRepository != '' \ && exists('g:HGCommandEnableBufferSetup') \ && g:HGCommandEnableBufferSetup return '[HG ' . b:HGRepository . '/' . b:HGBranch .'/' . b:HGRevision . ']' else return '' endif endfunction " Section: HG command functions {{{1 " Function: s:HGAdd() {{{2 function! s:HGAdd() return s:HGMarkOrigBufferForSetup(s:HGDoCommand('add', 'hgadd', '')) endfunction " Function: s:HGAnnotate(...) {{{2 function! s:HGAnnotate(...) if a:0 == 0 if &filetype == "HGAnnotate" " This is a HGAnnotate buffer. Perform annotation of the version " indicated by the current line. let revision = substitute(getline("."),'\(^[0-9]*\):.*','\1','') if s:HGGetOption('HGCommandAnnotateParent', 0) != 0 && revision > 0 let revision = revision - 1 endif else let revision=HGGetRevision() if revision == "" echoerr "Unable to obtain HG version information." return -1 endif endif else let revision=a:1 endif if revision == "NEW" echo "No annotatation available for new file." return -1 endif let resultBuffer=s:HGDoCommand('annotate -ndu -r ' . revision, 'hgannotate', revision) echomsg "DBG: ".resultBuffer if resultBuffer != -1 set filetype=HGAnnotate endif return resultBuffer endfunction " Function: s:HGCommit() {{{2 function! s:HGCommit(...) " Handle the commit message being specified. If a message is supplied, it " is used; if bang is supplied, an empty message is used; otherwise, the " user is provided a buffer from which to edit the commit message. if a:2 != "" || a:1 == "!" return s:HGMarkOrigBufferForSetup(s:HGDoCommand('commit -m "' . a:2 . '"', 'hgcommit', '')) endif let hgBufferCheck=s:HGCurrentBufferCheck() if hgBufferCheck == -1 echo "Original buffer no longer exists, aborting." return -1 endif " Protect against windows' backslashes in paths. They confuse exec'd " commands. let shellSlashBak = &shellslash try set shellslash let messageFileName = tempname() let fileName=bufname(hgBufferCheck) let realFilePath=s:HGResolveLink(fileName) let newCwd=fnamemodify(realFilePath, ':h') if strlen(newCwd) == 0 " Account for autochdir being in effect, which will make this blank, but " we know we'll be in the current directory for the original file. let newCwd = getcwd() endif let realFileName=fnamemodify(realFilePath, ':t') if s:HGEditFile(messageFileName, hgBufferCheck) == -1 return endif " Protect against case and backslash issues in Windows. let autoPattern = '\c' . messageFileName " Ensure existance of group augroup HGCommit augroup END execute 'au HGCommit BufDelete' autoPattern 'call delete("' . messageFileName . '")' execute 'au HGCommit BufDelete' autoPattern 'au! HGCommit * ' autoPattern " Create a commit mapping. The mapping must clear all autocommands in case " it is invoked when HGCommandCommitOnWrite is active, as well as to not " invoke the buffer deletion autocommand. execute 'nnoremap <silent> <buffer> <Plug>HGCommit '. \ ':au! HGCommit * ' . autoPattern . '<CR>'. \ ':g/^HG:/d<CR>'. \ ':update<CR>'. \ ':call <SID>HGFinishCommit("' . messageFileName . '",' . \ '"' . newCwd . '",' . \ '"' . realFileName . '",' . \ hgBufferCheck . ')<CR>' silent 0put ='HG: ----------------------------------------------------------------------' silent put =\"HG: Enter Log. Lines beginning with `HG:' are removed automatically\" silent put ='HG: Type <leader>cc (or your own <Plug>HGCommit mapping)' if s:HGGetOption('HGCommandCommitOnWrite', 1) == 1 execute 'au HGCommit BufWritePre' autoPattern 'g/^HG:/d' execute 'au HGCommit BufWritePost' autoPattern 'call s:HGFinishCommit("' . messageFileName . '", "' . newCwd . '", "' . realFileName . '", ' . hgBufferCheck . ') | au! * ' autoPattern silent put ='HG: or write this buffer' endif silent put ='HG: to finish this commit operation' silent put ='HG: ----------------------------------------------------------------------' $ let b:HGSourceFile=fileName let b:HGCommand='HGCommit' set filetype=hg finally let &shellslash = shellSlashBak endtry endfunction " Function: s:HGDiff(...) {{{2 function! s:HGDiff(...) if a:0 == 1 let revOptions = '-r' . a:1 let caption = a:1 . ' -> current' elseif a:0 == 2 let revOptions = '-r' . a:1 . ' -r' . a:2 let caption = a:1 . ' -> ' . a:2 else let revOptions = '' let caption = '' endif let hgdiffopt=s:HGGetOption('HGCommandDiffOpt', 'w') if hgdiffopt == "" let diffoptionstring="" else let diffoptionstring=" -" . hgdiffopt . " " endif let resultBuffer = s:HGDoCommand('diff ' . diffoptionstring . revOptions , 'hgdiff', caption) if resultBuffer != -1 set filetype=diff endif return resultBuffer endfunction " Function: s:HGGotoOriginal(["!]) {{{2 function! s:HGGotoOriginal(...) let origBuffNR = s:HGCurrentBufferCheck() if origBuffNR > 0 let origWinNR = bufwinnr(origBuffNR) if origWinNR == -1 execute 'buffer' origBuffNR else execute origWinNR . 'wincmd w' endif if a:0 == 1 if a:1 == "!" let buffnr = 1 let buffmaxnr = bufnr("$") while buffnr <= buffmaxnr if getbufvar(buffnr, "HGOrigBuffNR") == origBuffNR execute "bw" buffnr endif let buffnr = buffnr + 1 endwhile endif endif endif endfunction " Function: s:HGFinishCommit(messageFile, targetDir, targetFile) {{{2 function! s:HGFinishCommit(messageFile, targetDir, targetFile, origBuffNR) if filereadable(a:messageFile) let oldCwd=getcwd() if strlen(a:targetDir) > 0 execute 'cd' escape(a:targetDir, ' ') endif let resultBuffer=s:HGCreateCommandBuffer('commit -F "' . a:messageFile . '" "'. a:targetFile . '"', 'hgcommit', '', a:origBuffNR) execute 'cd' escape(oldCwd, ' ') execute 'bw' escape(a:messageFile, ' *?\') silent execute 'call delete("' . a:messageFile . '")' return s:HGMarkOrigBufferForSetup(resultBuffer) else echoerr "Can't read message file; no commit is possible." return -1 endif endfunction " Function: s:HGLog() {{{2 function! s:HGLog(...) if a:0 == 0 let versionOption = "" let caption = '' else let versionOption=" -r" . a:1 let caption = a:1 endif let resultBuffer=s:HGDoCommand('log' . versionOption, 'hglog', caption) if resultBuffer != "" set filetype=rcslog endif return resultBuffer endfunction " Function: s:HGRevert() {{{2 function! s:HGRevert() return s:HGMarkOrigBufferForSetup(s:HGDoCommand('revert', 'hgrevert', '')) endfunction " Function: s:HGReview(...) {{{2 function! s:HGReview(...) if a:0 == 0 let versiontag="" if s:HGGetOption('HGCommandInteractive', 0) let versiontag=input('Revision: ') endif if versiontag == "" let versiontag="(current)" let versionOption="" else let versionOption=" -r " . versiontag . " " endif else let versiontag=a:1 let versionOption=" -r " . versiontag . " " endif let resultBuffer = s:HGDoCommand('cat' . versionOption, 'hgreview', versiontag) if resultBuffer > 0 let &filetype=getbufvar(b:HGOrigBuffNR, '&filetype') endif return resultBuffer endfunction " Function: s:HGStatus() {{{2 function! s:HGStatus() return s:HGDoCommand('status', 'hgstatus', '') endfunction " Function: s:HGUpdate() {{{2 function! s:HGUpdate() return s:HGMarkOrigBufferForSetup(s:HGDoCommand('update', 'update', '')) endfunction " Function: s:HGVimDiff(...) {{{2 function! s:HGVimDiff(...) let originalBuffer = s:HGCurrentBufferCheck() let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 try " If there's already a VimDiff'ed window, restore it. " There may only be one HGVimDiff original window at a time. if exists("s:vimDiffSourceBuffer") && s:vimDiffSourceBuffer != originalBuffer " Clear the existing vimdiff setup by removing the result buffers. call s:HGWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff') endif " Split and diff if(a:0 == 2) " Reset the vimdiff system, as 2 explicit versions were provided. if exists('s:vimDiffSourceBuffer') call s:HGWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff') endif let resultBuffer = s:HGReview(a:1) if resultBuffer < 0 echomsg "Can't open HG revision " . a:1 return resultBuffer endif let b:HGCommand = 'vimdiff' diffthis let s:vimDiffBufferCount = 1 let s:vimDiffScratchList = '{'. resultBuffer . '}' " If no split method is defined, cheat, and set it to vertical. try call s:HGOverrideOption('HGCommandSplit', s:HGGetOption('HGCommandDiffSplit', s:HGGetOption('HGCommandSplit', 'vertical'))) let resultBuffer=s:HGReview(a:2) finally call s:HGOverrideOption('HGCommandSplit') endtry if resultBuffer < 0 echomsg "Can't open HG revision " . a:1 return resultBuffer endif let b:HGCommand = 'vimdiff' diffthis let s:vimDiffBufferCount = 2 let s:vimDiffScratchList = s:vimDiffScratchList . '{'. resultBuffer . '}' else " Add new buffer try " Force splitting behavior, otherwise why use vimdiff? call s:HGOverrideOption("HGCommandEdit", "split") call s:HGOverrideOption("HGCommandSplit", s:HGGetOption('HGCommandDiffSplit', s:HGGetOption('HGCommandSplit', 'vertical'))) if(a:0 == 0) let resultBuffer=s:HGReview() else let resultBuffer=s:HGReview(a:1) endif finally call s:HGOverrideOption("HGCommandEdit") call s:HGOverrideOption("HGCommandSplit") endtry if resultBuffer < 0 echomsg "Can't open current HG revision" return resultBuffer endif let b:HGCommand = 'vimdiff' diffthis if !exists('s:vimDiffBufferCount') " New instance of vimdiff. let s:vimDiffBufferCount = 2 let s:vimDiffScratchList = '{' . resultBuffer . '}' " This could have been invoked on a HG result buffer, not the " original buffer. wincmd W execute 'buffer' originalBuffer " Store info for later original buffer restore let s:vimDiffRestoreCmd = \ "call setbufvar(".originalBuffer.", \"&diff\", ".getbufvar(originalBuffer, '&diff').")" \ . "|call setbufvar(".originalBuffer.", \"&foldcolumn\", ".getbufvar(originalBuffer, '&foldcolumn').")" \ . "|call setbufvar(".originalBuffer.", \"&foldenable\", ".getbufvar(originalBuffer, '&foldenable').")" \ . "|call setbufvar(".originalBuffer.", \"&foldmethod\", '".getbufvar(originalBuffer, '&foldmethod')."')" \ . "|call setbufvar(".originalBuffer.", \"&scrollbind\", ".getbufvar(originalBuffer, '&scrollbind').")" \ . "|call setbufvar(".originalBuffer.", \"&wrap\", ".getbufvar(originalBuffer, '&wrap').")" \ . "|if &foldmethod=='manual'|execute 'normal zE'|endif" diffthis wincmd w else " Adding a window to an existing vimdiff let s:vimDiffBufferCount = s:vimDiffBufferCount + 1 let s:vimDiffScratchList = s:vimDiffScratchList . '{' . resultBuffer . '}' endif endif let s:vimDiffSourceBuffer = originalBuffer " Avoid executing the modeline in the current buffer after the autocommand. let currentBuffer = bufnr('%') let saveModeline = getbufvar(currentBuffer, '&modeline') try call setbufvar(currentBuffer, '&modeline', 0) silent do HGCommand User HGVimDiffFinish finally call setbufvar(currentBuffer, '&modeline', saveModeline) endtry return resultBuffer finally let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning - 1 endtry endfunction " Section: Command definitions {{{1 " Section: Primary commands {{{2 com! HGAdd call s:HGAdd() com! -nargs=? HGAnnotate call s:HGAnnotate(<f-args>) com! -bang -nargs=? HGCommit call s:HGCommit(<q-bang>, <q-args>) com! -nargs=* HGDiff call s:HGDiff(<f-args>) com! -bang HGGotoOriginal call s:HGGotoOriginal(<q-bang>) com! -nargs=? HGLog call s:HGLog(<f-args>) com! HGRevert call s:HGRevert() com! -nargs=? HGReview call s:HGReview(<f-args>) com! HGStatus call s:HGStatus() com! HGUpdate call s:HGUpdate() com! -nargs=* HGVimDiff call s:HGVimDiff(<f-args>) " Section: HG buffer management commands {{{2 com! HGDisableBufferSetup call HGDisableBufferSetup() com! HGEnableBufferSetup call HGEnableBufferSetup() " Allow reloading hgcommand.vim com! HGReload unlet! loaded_hgcommand | runtime plugin/hgcommand.vim " Section: Plugin command mappings {{{1 nnoremap <silent> <Plug>HGAdd :HGAdd<CR> nnoremap <silent> <Plug>HGAnnotate :HGAnnotate<CR> nnoremap <silent> <Plug>HGCommit :HGCommit<CR> nnoremap <silent> <Plug>HGDiff :HGDiff<CR> nnoremap <silent> <Plug>HGGotoOriginal :HGGotoOriginal<CR> nnoremap <silent> <Plug>HGClearAndGotoOriginal :HGGotoOriginal!<CR> nnoremap <silent> <Plug>HGLog :HGLog<CR> nnoremap <silent> <Plug>HGRevert :HGRevert<CR> nnoremap <silent> <Plug>HGReview :HGReview<CR> nnoremap <silent> <Plug>HGStatus :HGStatus<CR> nnoremap <silent> <Plug>HGUpdate :HGUpdate<CR> nnoremap <silent> <Plug>HGVimDiff :HGVimDiff<CR> nnoremap <silent> <Plug>HGWatchers :HGWatchers<CR> nnoremap <silent> <Plug>HGWatchAdd :HGWatchAdd<CR> nnoremap <silent> <Plug>HGWatchOn :HGWatchOn<CR> nnoremap <silent> <Plug>HGWatchOff :HGWatchOff<CR> nnoremap <silent> <Plug>HGWatchRemove :HGWatchRemove<CR> " Section: Default mappings {{{1 if !hasmapto('<Plug>HGAdd') nmap <unique> <Leader>hga <Plug>HGAdd endif if !hasmapto('<Plug>HGAnnotate') nmap <unique> <Leader>hgn <Plug>HGAnnotate endif if !hasmapto('<Plug>HGClearAndGotoOriginal') nmap <unique> <Leader>hgG <Plug>HGClearAndGotoOriginal endif if !hasmapto('<Plug>HGCommit') nmap <unique> <Leader>hgc <Plug>HGCommit endif if !hasmapto('<Plug>HGDiff') nmap <unique> <Leader>hgd <Plug>HGDiff endif if !hasmapto('<Plug>HGGotoOriginal') nmap <unique> <Leader>hgg <Plug>HGGotoOriginal endif if !hasmapto('<Plug>HGLog') nmap <unique> <Leader>hgl <Plug>HGLog endif if !hasmapto('<Plug>HGRevert') nmap <unique> <Leader>hgq <Plug>HGRevert endif if !hasmapto('<Plug>HGReview') nmap <unique> <Leader>hgr <Plug>HGReview endif if !hasmapto('<Plug>HGStatus') nmap <unique> <Leader>hgs <Plug>HGStatus endif if !hasmapto('<Plug>HGUpdate') nmap <unique> <Leader>hgu <Plug>HGUpdate endif if !hasmapto('<Plug>HGVimDiff') nmap <unique> <Leader>hgv <Plug>HGVimDiff endif " Section: Menu items {{{1 silent! aunmenu Plugin.HG amenu <silent> &Plugin.HG.&Add <Plug>HGAdd amenu <silent> &Plugin.HG.A&nnotate <Plug>HGAnnotate amenu <silent> &Plugin.HG.&Commit <Plug>HGCommit amenu <silent> &Plugin.HG.&Diff <Plug>HGDiff amenu <silent> &Plugin.HG.&Log <Plug>HGLog amenu <silent> &Plugin.HG.Revert <Plug>HGRevert amenu <silent> &Plugin.HG.&Review <Plug>HGReview amenu <silent> &Plugin.HG.&Status <Plug>HGStatus amenu <silent> &Plugin.HG.&Update <Plug>HGUpdate amenu <silent> &Plugin.HG.&VimDiff <Plug>HGVimDiff amenu <silent> &Plugin.HG.&Watchers <Plug>HGWatchers amenu <silent> &Plugin.HG.WatchAdd <Plug>HGWatchAdd amenu <silent> &Plugin.HG.WatchOn <Plug>HGWatchOn amenu <silent> &Plugin.HG.WatchOff <Plug>HGWatchOff amenu <silent> &Plugin.HG.WatchRemove <Plug>HGWatchRemove " Section: Autocommands to restore vimdiff state {{{1 function! s:HGVimDiffRestore(vimDiffBuff) let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 try if exists("s:vimDiffSourceBuffer") if a:vimDiffBuff == s:vimDiffSourceBuffer " Original file is being removed. unlet! s:vimDiffSourceBuffer unlet! s:vimDiffBufferCount unlet! s:vimDiffRestoreCmd unlet! s:vimDiffScratchList elseif match(s:vimDiffScratchList, '{' . a:vimDiffBuff . '}') >= 0 let s:vimDiffScratchList = substitute(s:vimDiffScratchList, '{' . a:vimDiffBuff . '}', '', '') let s:vimDiffBufferCount = s:vimDiffBufferCount - 1 if s:vimDiffBufferCount == 1 && exists('s:vimDiffRestoreCmd') " All scratch buffers are gone, reset the original. " Only restore if the source buffer is still in Diff mode let sourceWinNR=bufwinnr(s:vimDiffSourceBuffer) if sourceWinNR != -1 " The buffer is visible in at least one window let currentWinNR = winnr() while winbufnr(sourceWinNR) != -1 if winbufnr(sourceWinNR) == s:vimDiffSourceBuffer execute sourceWinNR . 'wincmd w' if getwinvar('', "&diff") execute s:vimDiffRestoreCmd endif endif let sourceWinNR = sourceWinNR + 1 endwhile execute currentWinNR . 'wincmd w' else " The buffer is hidden. It must be visible in order to set the " diff option. let currentBufNR = bufnr('') execute "hide buffer" s:vimDiffSourceBuffer if getwinvar('', "&diff") execute s:vimDiffRestoreCmd endif execute "hide buffer" currentBufNR endif unlet s:vimDiffRestoreCmd unlet s:vimDiffSourceBuffer unlet s:vimDiffBufferCount unlet s:vimDiffScratchList elseif s:vimDiffBufferCount == 0 " All buffers are gone. unlet s:vimDiffSourceBuffer unlet s:vimDiffBufferCount unlet s:vimDiffScratchList endif endif endif finally let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning - 1 endtry endfunction augroup HGVimDiffRestore au! au BufUnload * call s:HGVimDiffRestore(expand("<abuf>")) augroup END " Section: Optional activation of buffer management {{{1 if s:HGGetOption('HGCommandEnableBufferSetup', 0) call HGEnableBufferSetup() endif " Section: Plugin completion {{{1 let loaded_hgcommand=2 silent do HGCommand User HGPluginFinish " vim:se expandtab sts=2 sw=2: