comparison plugin/lawrencium.vim @ 0:0a5b490dc35d

Initial commit
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 08 Dec 2011 12:40:55 -0800
parents
children b6e4446ed292
comparison
equal deleted inserted replaced
-1:000000000000 0:0a5b490dc35d
1 " lawrencium.vim - A Mercurial wrapper
2 " Maintainer: Ludovic Chabant <http://ludovic.chabant.com>
3 " Version: 0.1
4
5 " Globals {{{
6
7 if !exists('g:lawrencium_debug')
8 let g:lawrencium_debug = 0
9 endif
10
11 if (exists('g:loaded_lawrencium') || &cp) && !g:lawrencium_debug
12 finish
13 endif
14 let g:loaded_lawrencium = 1
15
16 if !exists('g:lawrencium_hg_executable')
17 let g:lawrencium_hg_executable = 'hg'
18 endif
19
20 if !exists('g:lawrencium_trace')
21 let g:lawrencium_trace = 0
22 endif
23
24 if g:lawrencium_debug
25 echom "Loaded Lawrencium."
26 endif
27
28 " }}}
29
30 " Utility {{{
31
32 " Strips the ending slash in a path.
33 function! s:stripslash(path)
34 return fnamemodify(a:path, ':s?[/\\]$??')
35 endfunction
36
37 " Normalizes the slashes in a path.
38 function! s:normalizepath(path)
39 if exists('+shellslash') && &shellslash
40 return substitute(a:path, '\\', '/', '')
41 elseif has('win32')
42 return substitute(a:path, '/', '\\', '')
43 else
44 return a:path
45 endif
46 endfunction
47
48 " Prints a message if debug tracing is enabled.
49 function! s:trace(message)
50 if g:lawrencium_trace
51 let l:message = "lawrencium: " . a:message
52 echom l:message
53 endif
54 endfunction
55
56 " Throw a Lawrencium exception message.
57 function! s:throw(message)
58 let v:errmsg = "lawrencium: " . a:message
59 throw v:errmsg
60 endfunction
61
62 " Finds the repository root given a path inside that repository.
63 " Throw an error if not repository is found.
64 function! s:find_repo_root(path)
65 let l:path = s:stripslash(a:path)
66 let l:previous_path = ""
67 while l:path != l:previous_path
68 if isdirectory(l:path . '/.hg/store')
69 return simplify(fnamemodify(l:path, ':p'))
70 endif
71 let l:previous_path = l:path
72 let l:path = fnamemodify(l:path, ':h')
73 endwhile
74 call s:throw("No Mercurial repository found above: " . a:path)
75 endfunction
76
77 " }}}
78
79 " Mercurial Repository {{{
80
81 " Let's define a Mercurial repo 'class' using prototype-based object-oriented
82 " programming.
83 "
84 " The prototype dictionary.
85 let s:HgRepo = {}
86
87 " Constructor
88 function! s:HgRepo.New(path) abort
89 let l:newRepo = copy(self)
90 let l:newRepo.root_dir = s:find_repo_root(a:path)
91 call s:trace("Built new Mercurial repository object at : " . l:newRepo.root_dir)
92 return l:newRepo
93 endfunction
94
95 " Gets a full path given a repo-relative path
96 function! s:HgRepo.GetFullPath(path) abort
97 let l:root_dir = self.root_dir
98 if a:path =~# '^[/\\]'
99 let l:root_dir = s:stripslash(l:root_dir)
100 endif
101 return l:root_dir . a:path
102 endfunction
103
104 " Gets a list of files matching a root-relative pattern.
105 " If a flag is passed and is TRUE, a slash will be appended to all
106 " directories.
107 function! s:HgRepo.Glob(pattern, ...) abort
108 let l:root_dir = self.root_dir
109 if (a:pattern =~# '^[/\\]')
110 let l:root_dir = s:stripslash(l:root_dir)
111 endif
112 let l:matches = split(glob(l:root_dir . a:pattern), '\n')
113 if a:0 && a:1
114 for l:idx in range(len(l:matches))
115 if !filereadable(l:matches[l:idx])
116 let l:matches[l:idx] = l:matches[l:idx] . '/'
117 endif
118 endfor
119 endif
120 let l:strip_len = len(l:root_dir)
121 call map(l:matches, 'v:val[l:strip_len : -1]')
122 return l:matches
123 endfunction
124
125 " Runs a Mercurial command in the repo
126 function! s:HgRepo.RunCommand(command, ...) abort
127 let l:hg_command = g:lawrencium_hg_executable . ' --repository ' . shellescape(s:stripslash(self.root_dir))
128 let l:hg_command = l:hg_command . ' ' . a:command . ' ' . join(a:000, ' ')
129 call s:trace("Running Mercurial command: " . l:hg_command)
130 return system(l:hg_command)
131 endfunction
132
133 " Repo cache map
134 let s:buffer_repos = {}
135
136 " Get a cached repo
137 function! s:hg_repo(...) abort
138 " Use the given path, or the mercurial directory of the current buffer.
139 if a:0 == 0
140 if exists('b:mercurial_dir')
141 let l:path = b:mercurial_dir
142 else
143 let l:path = s:find_repo_root(expand('%:p'))
144 endif
145 else
146 let l:path = a:1
147 endif
148 " Find a cache repo instance, or make a new one.
149 if has_key(s:buffer_repos, l:path)
150 return get(s:buffer_repos, l:path)
151 else
152 let l:repo = s:HgRepo.New(l:path)
153 let s:buffer_repos[l:path] = l:repo
154 return l:repo
155 endif
156 endfunction
157
158 " Sets up the current buffer with Lawrencium commands if it contains a file from a Mercurial repo.
159 " If the file is not in a Mercurial repo, just exit silently.
160 function! s:setup_buffer_commands() abort
161 call s:trace("Scanning buffer '" . bufname('%') . "' for Lawrencium setup...")
162 let l:do_setup = 1
163 if exists('b:mercurial_dir')
164 if b:mercurial_dir =~# '/^\s*$/'
165 unlet b:mercurial_dir
166 else
167 let l:do_setup = 0
168 endif
169 endif
170 try
171 let l:repo = s:hg_repo()
172 catch /^lawrencium\:/
173 return
174 endtry
175 let b:mercurial_dir = l:repo.root_dir
176 if exists('b:mercurial_dir') && l:do_setup
177 call s:trace("Setting Mercurial commands for buffer '" . bufname('%'))
178 call s:trace(" with repo : " . expand(b:mercurial_dir))
179 silent doautocmd User Lawrencium
180 endif
181 endfunction
182
183 augroup lawrencium_detect
184 autocmd!
185 autocmd BufNewFile,BufReadPost * call s:setup_buffer_commands()
186 autocmd VimEnter * if expand('<amatch>')==''|call s:setup_buffer_commands()|endif
187 augroup end
188
189 " }}}
190
191 " Commands {{{
192
193 let s:main_commands = []
194
195 function! s:AddMainCommand(command) abort
196 let s:main_commands += [a:command]
197 endfunction
198
199 function! s:DefineMainCommands()
200 for l:command in s:main_commands
201 execute 'command! -buffer ' . l:command
202 endfor
203 endfunction
204
205 augroup lawrencium_main
206 autocmd!
207 autocmd User Lawrencium call s:DefineMainCommands()
208 augroup end
209
210 " }}}
211
212 " HgExecute {{{
213
214 function! s:HgExecute(...) abort
215 let l:repo = s:hg_repo()
216 echo call(l:repo.RunCommand, a:000, l:repo)
217 endfunction
218
219 call s:AddMainCommand("-nargs=* Hg :execute s:HgExecute(<f-args>)")
220
221 " }}}
222
223 " HgStatus {{{
224
225 function! s:HgStatus() abort
226 echo s:hg_repo().RunCommand('status')
227 endfunction
228
229 call s:AddMainCommand("HgStatus :execute s:HgStatus()")
230
231 " }}}
232
233 " Hgcd, Hglcd {{{
234
235 function! s:ListRepoDirs(ArgLead, CmdLine, CursorPos) abort
236 let l:matches = s:hg_repo().Glob(a:ArgLead . '*/')
237 call map(l:matches, 's:normalizepath(v:val)')
238 return l:matches
239 endfunction
240
241 call s:AddMainCommand("-bang -nargs=? -complete=customlist,s:ListRepoDirs Hgcd :cd<bang> `=s:hg_repo().GetFullPath(<q-args>)`")
242 call s:AddMainCommand("-bang -nargs=? -complete=customlist,s:ListRepoDirs Hglcd :lcd<bang> `=s:hg_repo().GetFullPath(<q-args>)`")
243
244 " }}}
245
246 " Hgedit {{{
247
248 function! s:ListRepoFiles(ArgLead, CmdLine, CursorPos) abort
249 let l:matches = s:hg_repo().Glob(a:ArgLead . '*', 1)
250 call map(l:matches, 's:normalizepath(v:val)')
251 return l:matches
252 endfunction
253
254 call s:AddMainCommand("-bang -nargs=? -complete=customlist,s:ListRepoFiles Hgedit :edit<bang> `=s:hg_repo().GetFullPath(<q-args>)`")
255
256 " }}}
257
258 " Autoload Functions {{{
259
260 " Prints a summary of the current repo (if any) that's appropriate for
261 " displaying on the status line.
262 function! lawrencium#statusline(...)
263 if !exists('b:mercurial_dir')
264 return ''
265 endif
266 let l:summary = s:hg_repo().RunCommand('summary')
267 let l:parent_rev = matchstr(l:summary, 'parent\: \d+\:[0-9a-f]+')
268 let l:branch = matchstr(l:summary, 'branch\: [\d\w\-_\.]+')
269 return l:branch . ', ' . l:parent_rev
270 endfunction
271
272 " Rescans the current buffer for setting up Mercurial commands.
273 " Passing '1' as the parameter enables debug traces temporarily.
274 function! lawrencium#rescan(...)
275 if exists('b:mercurial_dir')
276 unlet b:mercurial_dir
277 endif
278 if a:0 && a:1
279 let l:trace_backup = g:lawrencium_trace
280 let g:lawrencium_trace = 1
281 endif
282 call s:setup_buffer_commands()
283 if a:0 && a:1
284 let g:lawrencium_trace = l:trace_backup
285 endif
286 endfunction
287
288 " Enables/disables the debug trace.
289 function! lawrencium#debugtrace(...)
290 let g:lawrencium_trace = (a:0 == 0 || (a:0 && a:1))
291 echom "Lawrencium debug trace is now " . (g:lawrencium_trace ? "enabled." : "disabled.")
292 endfunction
293
294 " }}}
295