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 13if exists("b:did_ftplugin") 14 finish 15endif 16let b:did_ftplugin=1 17 18" {{{1 Local settings (do on every load) 19if exists("g:debchangelog_fold_enable") 20 setlocal foldmethod=expr 21 setlocal foldexpr=DebGetChangelogFold(v:lnum) 22 setlocal foldtext=DebChangelogFoldText() 23endif 24 25" Debian changelogs are not supposed to have any other text width, 26" so the user cannot override this setting 27setlocal tw=78 28setlocal comments=f:* 29 30" Clean unloading 31let b:undo_ftplugin = "setlocal tw< comments< foldmethod< foldexpr< foldtext<" 32" }}}1 33 34if exists("g:did_changelog_ftplugin") 35 finish 36endif 37 38" Don't load another plugin (this is global) 39let 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? 46function <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 54endfunction 55 56" Returns email address, from $DEBEMAIL, $EMAIL or debianemail. 57function <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 67endfunction 68 69" Returns date in RFC822 format. 70function <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 76endfunction 77 78function <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 86endfunction 87 88function <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 99endfunction 100 101" These functions implement the menus 102function 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 121 call setline(1, substitute(getline(1), '-\$\$', '-', '')) 122 if exists("g:debchangelog_fold_enable") 123 foldopen 124 endif 125 call AddEntry() 126endfunction 127 128function 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! 142endfunction 143 144function 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 152endfunction 153 154function Distribution(dist) 155 call setline(1, substitute(getline(1), ") [[:lower:] ]*;", ") " . a:dist . ";", "")) 156endfunction 157 158function Urgency(urg) 159 call setline(1, substitute(getline(1), "urgency=.*$", "urgency=" . a:urg, "")) 160endfunction 161 162function <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 171endfunction 172 173function Unfinalise() 174 call <SID>UnfinaliseMenu() 175 normal 1G 176 call search("^ -- ") 177 call setline(".", " -- ") 178endfunction 179 180function <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 189endfunction 190 191function Finalise() 192 call <SID>FinaliseMenu() 193 normal 1G 194 call search("^ -- ") 195 call setline(".", " -- " . <SID>FullName() . " <" . <SID>Email() . "> " . <SID>Date()) 196endfunction 197 198 199function <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 227endfunction 228 229augroup changelogMenu 230au BufEnter * if &filetype == "debchangelog" | call <SID>MakeMenu() | endif 231au BufLeave * if &filetype == "debchangelog" | silent! aunmenu Changelog | endif 232augroup END 233 234" }}} 235" {{{1 folding 236 237" look for an author name in the [zonestart zoneend] lines searching backward 238function! 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]' 248endfunction 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 252function! 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 264endfunction 265 266function! DebChangelogFoldText() 267 if v:folddashes == '-' " changelog entry fold 268 return foldtext() . ' -- ' . s:getAuthor(v:foldstart, v:foldend) . ' ' 269 endif 270 return foldtext() 271endfunction 272 273function! 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 '=' 285endfunction 286 287if exists("g:debchangelog_fold_enable") 288 silent! foldopen! " unfold the entry the cursor is on (usually the first one) 289endif 290 291" }}} 292 293" {{{1 omnicompletion for Closes: # 294 295if !exists('g:debchangelog_listbugs_severities') 296 let g:debchangelog_listbugs_severities = 'critical,grave,serious,important,normal,minor,wishlist' 297endif 298 299fun! 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 330import vim 331try: 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 350except ImportError: 351 vim.command('echoerr \'python-launchpadlib >= 1.5.4 needs to be installed to use Launchpad bug completion\'') 352EOF 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 377endfun 378 379setlocal omnifunc=DebCompleteBugs 380 381" }}} 382 383" vim: set foldmethod=marker: 384