changeset 0:0a5b490dc35d

Initial commit
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 08 Dec 2011 12:40:55 -0800
parents
children 9241ae881b9f
files doc/lawrencium.txt plugin/lawrencium.vim
diffstat 2 files changed, 340 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/lawrencium.txt	Thu Dec 08 12:40:55 2011 -0800
@@ -0,0 +1,45 @@
+*lawrencium.txt*  Mercurial wrapper for VIM
+
+Author:  Ludovic Chabant <http://ludovic.chabant.com>
+License: Same terms as Vim itself (see |license|)
+
+This plugin is only available if 'compatible' is not set.
+
+INTRODUCTION                                    *lawrencium*
+
+When a file from a Mercurial repository is open in a buffer, that buffer gets
+new commands defined.
+
+COMMANDS                                        *lawrencium-commands*
+
+All commands defined by |lawrencium| are local to each buffer.
+
+                                                *lawrencium-:Hg*
+:Hg [args]              Run an arbitrary Mercurial command. Similar to :!hg
+                        [args] but the '--repository' is automatically
+                        specified with the root of the repository the current
+                        file belongs to.
+
+                                                *lawrencium-:Hg!*
+:Hg! [args]             Like |:Hg|, but the output of the command is placed in
+                        a temp file and edited in the |preview-window|.
+
+                                                *lawrencium-:Hgcd*
+:Hgcd [directory]       |:cd| relative to the root of the repository.
+
+                                                *lawrencium-:Hglcd*
+:Hglcd [directory]      |:lcd| relative to the root of the repository.
+
+                                                *lawrencium-:Hgstatus*
+:Hgstatus               Shows the output of 'hg status' in the
+                        |preview-window|.
+
+
+ABOUT                                           *lawrencium-about*
+
+Grab the latest version or report a bug on BitBucket:
+
+http://bitbucket.org/ludovicchabant/lawrencium
+
+
+ vim:tw=78:et:ft=help:norl:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/lawrencium.vim	Thu Dec 08 12:40:55 2011 -0800
@@ -0,0 +1,295 @@
+" lawrencium.vim - A Mercurial wrapper
+" Maintainer:   Ludovic Chabant <http://ludovic.chabant.com>
+" Version:      0.1
+
+" Globals {{{
+
+if !exists('g:lawrencium_debug')
+    let g:lawrencium_debug = 0
+endif
+
+if (exists('g:loaded_lawrencium') || &cp) && !g:lawrencium_debug
+    finish
+endif
+let g:loaded_lawrencium = 1
+
+if !exists('g:lawrencium_hg_executable')
+    let g:lawrencium_hg_executable = 'hg'
+endif
+
+if !exists('g:lawrencium_trace')
+    let g:lawrencium_trace = 0
+endif
+
+if g:lawrencium_debug
+    echom "Loaded Lawrencium."
+endif
+
+" }}}
+
+" Utility {{{
+
+" Strips the ending slash in a path.
+function! s:stripslash(path)
+    return fnamemodify(a:path, ':s?[/\\]$??')
+endfunction
+
+" Normalizes the slashes in a path.
+function! s:normalizepath(path)
+    if exists('+shellslash') && &shellslash
+        return substitute(a:path, '\\', '/', '')
+    elseif has('win32')
+        return substitute(a:path, '/', '\\', '')
+    else
+        return a:path
+    endif
+endfunction
+
+" Prints a message if debug tracing is enabled.
+function! s:trace(message)
+   if g:lawrencium_trace 
+       let l:message = "lawrencium: " . a:message
+       echom l:message
+   endif
+endfunction
+
+" Throw a Lawrencium exception message.
+function! s:throw(message)
+    let v:errmsg = "lawrencium: " . a:message
+    throw v:errmsg
+endfunction
+
+" Finds the repository root given a path inside that repository.
+" Throw an error if not repository is found.
+function! s:find_repo_root(path)
+    let l:path = s:stripslash(a:path)
+    let l:previous_path = ""
+    while l:path != l:previous_path
+        if isdirectory(l:path . '/.hg/store')
+            return simplify(fnamemodify(l:path, ':p'))
+        endif
+        let l:previous_path = l:path
+        let l:path = fnamemodify(l:path, ':h')
+    endwhile
+    call s:throw("No Mercurial repository found above: " . a:path)
+endfunction
+
+" }}}
+
+" Mercurial Repository {{{
+
+" Let's define a Mercurial repo 'class' using prototype-based object-oriented
+" programming.
+"
+" The prototype dictionary.
+let s:HgRepo = {}
+
+" Constructor
+function! s:HgRepo.New(path) abort
+    let l:newRepo = copy(self)
+    let l:newRepo.root_dir = s:find_repo_root(a:path)
+    call s:trace("Built new Mercurial repository object at : " . l:newRepo.root_dir)
+    return l:newRepo
+endfunction
+
+" Gets a full path given a repo-relative path
+function! s:HgRepo.GetFullPath(path) abort
+    let l:root_dir = self.root_dir
+    if a:path =~# '^[/\\]'
+        let l:root_dir = s:stripslash(l:root_dir)
+    endif
+    return l:root_dir . a:path
+endfunction
+
+" Gets a list of files matching a root-relative pattern.
+" If a flag is passed and is TRUE, a slash will be appended to all
+" directories.
+function! s:HgRepo.Glob(pattern, ...) abort
+    let l:root_dir = self.root_dir
+    if (a:pattern =~# '^[/\\]')
+        let l:root_dir = s:stripslash(l:root_dir)
+    endif
+    let l:matches = split(glob(l:root_dir . a:pattern), '\n')
+    if a:0 && a:1
+        for l:idx in range(len(l:matches))
+            if !filereadable(l:matches[l:idx])
+                let l:matches[l:idx] = l:matches[l:idx] . '/'
+            endif
+        endfor
+    endif
+    let l:strip_len = len(l:root_dir)
+    call map(l:matches, 'v:val[l:strip_len : -1]')
+    return l:matches
+endfunction
+
+" Runs a Mercurial command in the repo
+function! s:HgRepo.RunCommand(command, ...) abort
+    let l:hg_command = g:lawrencium_hg_executable . ' --repository ' . shellescape(s:stripslash(self.root_dir))
+    let l:hg_command = l:hg_command . ' ' . a:command . ' ' . join(a:000, ' ')
+    call s:trace("Running Mercurial command: " . l:hg_command)
+    return system(l:hg_command)
+endfunction
+
+" Repo cache map
+let s:buffer_repos = {}
+
+" Get a cached repo
+function! s:hg_repo(...) abort
+    " Use the given path, or the mercurial directory of the current buffer.
+    if a:0 == 0
+        if exists('b:mercurial_dir')
+            let l:path = b:mercurial_dir
+        else
+            let l:path = s:find_repo_root(expand('%:p'))
+        endif
+    else
+        let l:path = a:1
+    endif
+    " Find a cache repo instance, or make a new one.
+    if has_key(s:buffer_repos, l:path)
+        return get(s:buffer_repos, l:path)
+    else
+        let l:repo = s:HgRepo.New(l:path)
+        let s:buffer_repos[l:path] = l:repo
+        return l:repo
+    endif
+endfunction
+
+" Sets up the current buffer with Lawrencium commands if it contains a file from a Mercurial repo.
+" If the file is not in a Mercurial repo, just exit silently.
+function! s:setup_buffer_commands() abort
+    call s:trace("Scanning buffer '" . bufname('%') . "' for Lawrencium setup...")
+    let l:do_setup = 1
+    if exists('b:mercurial_dir')
+        if b:mercurial_dir =~# '/^\s*$/'
+            unlet b:mercurial_dir
+        else
+            let l:do_setup = 0
+        endif
+    endif
+    try
+        let l:repo = s:hg_repo()
+    catch /^lawrencium\:/
+        return
+    endtry
+    let b:mercurial_dir = l:repo.root_dir
+    if exists('b:mercurial_dir') && l:do_setup
+        call s:trace("Setting Mercurial commands for buffer '" . bufname('%'))
+        call s:trace("  with repo : " . expand(b:mercurial_dir))
+        silent doautocmd User Lawrencium
+    endif
+endfunction
+
+augroup lawrencium_detect
+    autocmd!
+    autocmd BufNewFile,BufReadPost *     call s:setup_buffer_commands()
+    autocmd VimEnter               *     if expand('<amatch>')==''|call s:setup_buffer_commands()|endif
+augroup end
+
+" }}}
+
+" Commands {{{
+
+let s:main_commands = []
+
+function! s:AddMainCommand(command) abort
+    let s:main_commands += [a:command]
+endfunction
+
+function! s:DefineMainCommands()
+    for l:command in s:main_commands
+        execute 'command! -buffer ' . l:command
+    endfor
+endfunction
+
+augroup lawrencium_main
+    autocmd!
+    autocmd User Lawrencium call s:DefineMainCommands()
+augroup end
+
+" }}}
+
+" HgExecute {{{
+
+function! s:HgExecute(...) abort
+    let l:repo = s:hg_repo()
+    echo call(l:repo.RunCommand, a:000, l:repo)
+endfunction
+
+call s:AddMainCommand("-nargs=* Hg :execute s:HgExecute(<f-args>)")
+
+" }}}
+
+" HgStatus {{{
+
+function! s:HgStatus() abort
+    echo s:hg_repo().RunCommand('status')
+endfunction
+
+call s:AddMainCommand("HgStatus :execute s:HgStatus()")
+
+" }}}
+
+" Hgcd, Hglcd {{{
+
+function! s:ListRepoDirs(ArgLead, CmdLine, CursorPos) abort
+    let l:matches = s:hg_repo().Glob(a:ArgLead . '*/')
+    call map(l:matches, 's:normalizepath(v:val)')
+    return l:matches
+endfunction
+
+call s:AddMainCommand("-bang -nargs=? -complete=customlist,s:ListRepoDirs Hgcd :cd<bang> `=s:hg_repo().GetFullPath(<q-args>)`")
+call s:AddMainCommand("-bang -nargs=? -complete=customlist,s:ListRepoDirs Hglcd :lcd<bang> `=s:hg_repo().GetFullPath(<q-args>)`")
+
+" }}}
+
+" Hgedit {{{
+
+function! s:ListRepoFiles(ArgLead, CmdLine, CursorPos) abort
+    let l:matches = s:hg_repo().Glob(a:ArgLead . '*', 1)
+    call map(l:matches, 's:normalizepath(v:val)')
+    return l:matches
+endfunction
+
+call s:AddMainCommand("-bang -nargs=? -complete=customlist,s:ListRepoFiles Hgedit :edit<bang> `=s:hg_repo().GetFullPath(<q-args>)`")
+
+" }}}
+
+" Autoload Functions {{{
+
+" Prints a summary of the current repo (if any) that's appropriate for
+" displaying on the status line.
+function! lawrencium#statusline(...)
+    if !exists('b:mercurial_dir')
+        return ''
+    endif
+    let l:summary = s:hg_repo().RunCommand('summary')
+    let l:parent_rev = matchstr(l:summary, 'parent\: \d+\:[0-9a-f]+')
+    let l:branch = matchstr(l:summary, 'branch\: [\d\w\-_\.]+')
+    return l:branch . ', ' . l:parent_rev
+endfunction
+
+" Rescans the current buffer for setting up Mercurial commands.
+" Passing '1' as the parameter enables debug traces temporarily.
+function! lawrencium#rescan(...)
+    if exists('b:mercurial_dir')
+        unlet b:mercurial_dir
+    endif
+    if a:0 && a:1
+        let l:trace_backup = g:lawrencium_trace
+        let g:lawrencium_trace = 1
+    endif
+    call s:setup_buffer_commands()
+    if a:0 && a:1
+        let g:lawrencium_trace = l:trace_backup
+    endif
+endfunction
+
+" Enables/disables the debug trace.
+function! lawrencium#debugtrace(...)
+    let g:lawrencium_trace = (a:0 == 0 || (a:0 && a:1))
+    echom "Lawrencium debug trace is now " . (g:lawrencium_trace ? "enabled." : "disabled.")
+endfunction
+
+" }}}
+