Tizen 2.0 Release
[external/vim.git] / runtime / ftplugin / debchangelog.vim
1 " Vim filetype plugin file (GUI menu, folding and completion)
2 " Language:     Debian Changelog
3 " Maintainer:   Debian Vim Maintainers <pkg-vim-maintainers@lists.alioth.debian.org>
4 " Former Maintainers:   Michael Piefel <piefel@informatik.hu-berlin.de>
5 "                       Stefano Zacchiroli <zack@debian.org>
6 " Last Change:  2010-07-11
7 " License:      GNU GPL, version 2.0 or later
8 " URL:          http://hg.debian.org/hg/pkg-vim/vim/file/unstable/runtime/ftplugin/debchangelog.vim
9
10 " Bug completion requires apt-listbugs installed for Debian packages or
11 " python-launchpadlib installed for Ubuntu packages
12
13 if exists("b:did_ftplugin")
14   finish
15 endif
16 let b:did_ftplugin=1
17
18 " {{{1 Local settings (do on every load)
19 if exists("g:debchangelog_fold_enable")
20   setlocal foldmethod=expr
21   setlocal foldexpr=DebGetChangelogFold(v:lnum)
22   setlocal foldtext=DebChangelogFoldText()
23 endif
24
25 " Debian changelogs are not supposed to have any other text width,
26 " so the user cannot override this setting
27 setlocal tw=78
28 setlocal comments=f:* 
29
30 " Clean unloading
31 let b:undo_ftplugin = "setlocal tw< comments< foldmethod< foldexpr< foldtext<"
32 " }}}1
33
34 if exists("g:did_changelog_ftplugin")
35   finish
36 endif
37
38 " Don't load another plugin (this is global)
39 let g:did_changelog_ftplugin = 1
40
41 " {{{1 GUI menu
42
43 " Helper functions returning various data.
44 " Returns full name, either from $DEBFULLNAME or debianfullname.
45 " TODO Is there a way to determine name from anywhere else?
46 function <SID>FullName()
47     if exists("$DEBFULLNAME")
48         return $DEBFULLNAME
49     elseif exists("g:debianfullname")
50         return g:debianfullname
51     else
52         return "Your Name"
53     endif
54 endfunction
55
56 " Returns email address, from $DEBEMAIL, $EMAIL or debianemail.
57 function <SID>Email()
58     if exists("$DEBEMAIL")
59         return $DEBEMAIL
60     elseif exists("$EMAIL")
61         return $EMAIL
62     elseif exists("g:debianemail")
63         return g:debianemail
64     else
65         return "your@email.address"
66     endif
67 endfunction
68
69 " Returns date in RFC822 format.
70 function <SID>Date()
71     let savelang = v:lc_time
72     execute "language time C"
73     let dateandtime = strftime("%a, %d %b %Y %X %z")
74     execute "language time " . savelang
75     return dateandtime
76 endfunction
77
78 function <SID>WarnIfNotUnfinalised()
79     if match(getline("."), " -- [[:alpha:]][[:alnum:].]")!=-1
80         echohl WarningMsg
81         echo "The entry has not been unfinalised before editing."
82         echohl None
83         return 1
84     endif
85     return 0
86 endfunction
87
88 function <SID>Finalised()
89     let savelinenum = line(".")
90     normal 1G
91     call search("^ -- ")
92     if match(getline("."), " -- [[:alpha:]][[:alnum:].]")!=-1
93         let returnvalue = 1
94     else
95         let returnvalue = 0
96     endif
97     execute savelinenum
98     return returnvalue
99 endfunction
100
101 " These functions implement the menus
102 function NewVersion()
103     " The new entry is unfinalised and shall be changed
104     amenu disable Changelog.New\ Version
105     amenu enable Changelog.Add\ Entry
106     amenu enable Changelog.Close\ Bug
107     amenu enable Changelog.Set\ Distribution
108     amenu enable Changelog.Set\ Urgency
109     amenu disable Changelog.Unfinalise
110     amenu enable Changelog.Finalise
111     call append(0, substitute(getline(1), '-\([[:digit:]]\+\))', '-$$\1)', ''))
112     call append(1, "")
113     call append(2, "")
114     call append(3, " -- ")
115     call append(4, "")
116     call Urgency("low")
117     normal 1G0
118     call search(")")
119     normal h
120     normal \ 1
121     call setline(1, substitute(getline(1), '-\$\$', '-', ''))
122     if exists("g:debchangelog_fold_enable")
123         foldopen
124     endif
125     call AddEntry()
126 endfunction
127
128 function AddEntry()
129     normal 1G
130     call search("^ -- ")
131     normal kk
132     call append(".", "  * ")
133     normal jjj
134     let warn=<SID>WarnIfNotUnfinalised()
135     normal kk
136     if warn
137         echohl MoreMsg
138         call input("Hit ENTER")
139         echohl None
140     endif
141     startinsert!
142 endfunction
143
144 function CloseBug()
145     normal 1G
146     call search("^ -- ")
147     let warn=<SID>WarnIfNotUnfinalised()
148     normal kk
149     call append(".", "  *  (closes: #" . input("Bug number to close: ") . ")")
150     normal j^ll
151     startinsert
152 endfunction
153
154 function Distribution(dist)
155     call setline(1, substitute(getline(1), ") [[:lower:] ]*;", ") " . a:dist . ";", ""))
156 endfunction
157
158 function Urgency(urg)
159     call setline(1, substitute(getline(1), "urgency=.*$", "urgency=" . a:urg, ""))
160 endfunction
161
162 function <SID>UnfinaliseMenu()
163     " This means the entry shall be changed
164     amenu disable Changelog.New\ Version
165     amenu enable Changelog.Add\ Entry
166     amenu enable Changelog.Close\ Bug
167     amenu enable Changelog.Set\ Distribution
168     amenu enable Changelog.Set\ Urgency
169     amenu disable Changelog.Unfinalise
170     amenu enable Changelog.Finalise
171 endfunction
172
173 function Unfinalise()
174     call <SID>UnfinaliseMenu()
175     normal 1G
176     call search("^ -- ")
177     call setline(".", " -- ")
178 endfunction
179
180 function <SID>FinaliseMenu()
181     " This means the entry should not be changed anymore
182     amenu enable Changelog.New\ Version
183     amenu disable Changelog.Add\ Entry
184     amenu disable Changelog.Close\ Bug
185     amenu disable Changelog.Set\ Distribution
186     amenu disable Changelog.Set\ Urgency
187     amenu enable Changelog.Unfinalise
188     amenu disable Changelog.Finalise
189 endfunction
190
191 function Finalise()
192     call <SID>FinaliseMenu()
193     normal 1G
194     call search("^ -- ")
195     call setline(".", " -- " . <SID>FullName() . " <" . <SID>Email() . ">  " . <SID>Date())
196 endfunction
197
198
199 function <SID>MakeMenu()
200     amenu &Changelog.&New\ Version                      :call NewVersion()<CR>
201     amenu Changelog.&Add\ Entry                         :call AddEntry()<CR>
202     amenu Changelog.&Close\ Bug                         :call CloseBug()<CR>
203     menu Changelog.-sep-                                <nul>
204
205     amenu Changelog.Set\ &Distribution.&unstable        :call Distribution("unstable")<CR>
206     amenu Changelog.Set\ Distribution.&frozen           :call Distribution("frozen")<CR>
207     amenu Changelog.Set\ Distribution.&stable           :call Distribution("stable")<CR>
208     menu Changelog.Set\ Distribution.-sep-              <nul>
209     amenu Changelog.Set\ Distribution.frozen\ unstable  :call Distribution("frozen unstable")<CR>
210     amenu Changelog.Set\ Distribution.stable\ unstable  :call Distribution("stable unstable")<CR>
211     amenu Changelog.Set\ Distribution.stable\ frozen    :call Distribution("stable frozen")<CR>
212     amenu Changelog.Set\ Distribution.stable\ frozen\ unstable  :call Distribution("stable frozen unstable")<CR>
213
214     amenu Changelog.Set\ &Urgency.&low                  :call Urgency("low")<CR>
215     amenu Changelog.Set\ Urgency.&medium                :call Urgency("medium")<CR>
216     amenu Changelog.Set\ Urgency.&high                  :call Urgency("high")<CR>
217
218     menu Changelog.-sep-                                <nul>
219     amenu Changelog.U&nfinalise                         :call Unfinalise()<CR>
220     amenu Changelog.&Finalise                           :call Finalise()<CR>
221
222     if <SID>Finalised()
223         call <SID>FinaliseMenu()
224     else
225         call <SID>UnfinaliseMenu()
226     endif
227 endfunction
228
229 augroup changelogMenu
230 au BufEnter * if &filetype == "debchangelog" | call <SID>MakeMenu() | endif
231 au BufLeave * if &filetype == "debchangelog" | silent! aunmenu Changelog | endif
232 augroup END
233
234 " }}}
235 " {{{1 folding
236
237 " look for an author name in the [zonestart zoneend] lines searching backward
238 function! s:getAuthor(zonestart, zoneend)
239   let linepos = a:zoneend
240   while linepos >= a:zonestart
241     let line = getline(linepos)
242     if line =~ '^ --'
243       return substitute(line, '^ --\s*\([^<]\+\)\s*.*', '\1', '')
244     endif
245     let linepos -= 1
246   endwhile
247   return '[unknown]'
248 endfunction
249
250 " Look for a package source name searching backward from the givenline and
251 " returns it. Return the empty string if the package name can't be found
252 function! DebGetPkgSrcName(lineno)
253   let lineidx = a:lineno
254   let pkgname = ''
255   while lineidx > 0
256     let curline = getline(lineidx)
257     if curline =~ '^\S'
258       let pkgname = matchlist(curline, '^\(\S\+\).*$')[1]
259       break
260     endif
261     let lineidx = lineidx - 1
262   endwhile
263   return pkgname
264 endfunction
265
266 function! DebChangelogFoldText()
267   if v:folddashes == '-'  " changelog entry fold
268     return foldtext() . ' -- ' . s:getAuthor(v:foldstart, v:foldend) . ' '
269   endif
270   return foldtext()
271 endfunction
272
273 function! DebGetChangelogFold(lnum)
274   let line = getline(a:lnum)
275   if line =~ '^\w\+'
276     return '>1' " beginning of a changelog entry
277   endif
278   if line =~ '^\s\+\[.*\]'
279     return '>2' " beginning of an author-specific chunk
280   endif
281   if line =~ '^ --'
282     return '1'
283   endif
284   return '='
285 endfunction
286
287 if exists("g:debchangelog_fold_enable")
288   silent! foldopen!   " unfold the entry the cursor is on (usually the first one)
289 endif
290
291 " }}}
292
293 " {{{1 omnicompletion for Closes: #
294
295 if !exists('g:debchangelog_listbugs_severities')
296   let g:debchangelog_listbugs_severities = 'critical,grave,serious,important,normal,minor,wishlist'
297 endif
298
299 fun! DebCompleteBugs(findstart, base)
300   if a:findstart
301     let line = getline('.')
302
303     " try to detect whether this is closes: or lp:
304     let g:debchangelog_complete_mode = 'debbugs'
305     let try_colidx = col('.') - 1
306     let colidx = -1 " default to no-completion-possible
307
308     while try_colidx > 0 && line[try_colidx - 1] =~ '\s\|\d\|#\|,\|:'
309       let try_colidx = try_colidx - 1
310       if line[try_colidx] == '#' && colidx == -1
311         " found hash, where we complete from:
312         let colidx = try_colidx
313       elseif line[try_colidx] == ':'
314         if try_colidx > 1 && strpart(line, try_colidx - 2, 3) =~ '\clp:'
315           let g:debchangelog_complete_mode = 'lp'
316         endif
317         break
318       endif
319     endwhile
320     return colidx
321   else " return matches:
322     let bug_lines = []
323     if g:debchangelog_complete_mode == 'lp'
324       if ! has('python')
325         echoerr 'vim must be built with Python support to use LP bug completion'
326         return
327       endif
328       let pkgsrc = DebGetPkgSrcName(line('.'))
329       python << EOF
330 import vim
331 try:
332     from launchpadlib.launchpad import Launchpad
333     from lazr.restfulclient.errors import HTTPError
334     # login anonymously
335     lp = Launchpad.login_anonymously('debchangelog.vim', 'production')
336     ubuntu = lp.distributions['ubuntu']
337     try:
338         sp = ubuntu.getSourcePackage(name=vim.eval('pkgsrc'))
339         status = ('New', 'Incomplete', 'Confirmed', 'Triaged',
340                   'In Progress', 'Fix Committed')
341         tasklist = sp.searchTasks(status=status, order_by='id')
342         liststr = '['
343         for task in tasklist:
344             bug = task.bug
345             liststr += "'#%d - %s'," % (bug.id, bug.title.replace('\'', '\'\''))
346         liststr += ']'
347         vim.command('silent let bug_lines = %s' % liststr.encode('utf-8'))
348     except HTTPError:
349         pass
350 except ImportError:
351     vim.command('echoerr \'python-launchpadlib >= 1.5.4 needs to be installed to use Launchpad bug completion\'')
352 EOF
353     else
354       if ! filereadable('/usr/sbin/apt-listbugs')
355         echoerr 'apt-listbugs not found, you should install it to use Closes bug completion'
356         return
357       endif
358       let pkgsrc = DebGetPkgSrcName(line('.'))
359       let listbugs_output = system('/usr/sbin/apt-listbugs -s ' . g:debchangelog_listbugs_severities . ' list ' . pkgsrc . ' | grep "^ #" 2> /dev/null')
360       let bug_lines = split(listbugs_output, '\n')
361     endif
362     let completions = []
363     for line in bug_lines
364       let parts = matchlist(line, '^\s*\(#\S\+\)\s*-\s*\(.*\)$')
365       " filter only those which match a:base:
366       if parts[1] !~ "^" . a:base
367         continue
368       endif
369       let completion = {}
370       let completion['word'] = parts[1]
371       let completion['menu'] = parts[2]
372       let completion['info'] = parts[0]
373       let completions += [completion]
374     endfor
375     return completions
376   endif
377 endfun
378
379 setlocal omnifunc=DebCompleteBugs
380
381 " }}}
382
383 " vim: set foldmethod=marker: