view vim/bundle/lawrencium/plugin/lawrencium.vim @ 51:a6bc310e7015

First version of lawrencium plugin.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 07 Dec 2011 23:32:39 -0800
parents
children 05fd225bd1a0
line wrap: on
line source

" lawrencium.vim - A Mercurial wrapper
" Maintainer:   Ludovic Chabant <http://ludovic.chabant.com>
" Version:      0.1

if exists('g:loaded_lawrencium') || &cp
    "  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

" Utility {{{

function! s:stripslash(path)
    return fnamemodify(a:path, ':s?[\/]$??')
endfunction

function! s:trace(message)
   if g:lawrencium_trace 
       let l:message = "lawrencium: " . a:message
   endif
endfunction

function! s:throw(message)
    let v:errmsg = "lawrencium: " . a:message
    throw v:errmsg
endfunction

function! s:find_repo_root(path)
    let l:path = s:stripslash(a:path)
    while l:path != ""
        if isdirectory(l:path . '/.hg/store')
            return simplify(fnamemodify(l:path, ':p'))
        endif
        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

" Sets up the current buffer with local variables
function! s:HgRepo.SetupBuffer() abort
    if exists('b:mercurial_dir') && (b:mercurial_dir =~# '/^\s*$/')
        unlet b:mercurial_dir
    endif
    if !exists('b:mercurial_dir')
        let b:mercurial_dir = self.root_dir
    endif
    if exists('b:mercurial_dir')
        call s:trace("Setting Mercurial directory to : " . expand(b:mercurial_dir))
        silent doautocmd User Lawrencium
    endif
endfunction

" Gets a full path given a repo-relative path
function! s:HgRepo.GetFullPath(path) abort
    let l:path = self.root_dir
    if a:path =~# '^/'
        let l:path = s:stripslash(self.root_dir)
    endif
    return l:path . a:path
endfunction

" Runs a Mercurial command in the repo
function! s:HgRepo.RunCommand(command, ...) abort
    let l:hg_command = g:lawrencium_hg_executable . ' --repository ' . shellescape(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'))
            let b:mercurial_dir = l:path
        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

augroup lawrencium_detect
    autocmd!
"    autocmd BufNewFile,BufReadPost *     call s:DetectMercurialRepository(expand('<amatch>:p'))
"    autocmd VimEnter               *     if expand('<amatch>')==''|call s:DetectMercurialRepository(getcwd())|endif
augroup end

" }}}

" Commands {{{

let s:main_commands = []

function! s:AddMainCommand(command) abort
    let s:main_commands += [a:command]
endfunction

function! s:DefineMainCommands()
    for command in s:main_commands
        execute 'command! -buffer '.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:root_dir = s:hg_repo().root_dir
    if (a:ArgLead =~# '^/')
        let l:root_dir = s:stripslash(l:root_dir)
    endif
    let l:matches = split(glob(l:root_dir . a:ArgLead . '*'), '\n')
    let l:strip_len = len(l:root_dir)
    call map(l:matches, 'v:val[l:strip_len : -1] . "/"')
    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>)`")

" }}}

" Autoload Functions {{{

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

" }}}