blob: aa657a9b97e1edcaf3c61d518f5a47a54c75aaaa [file] [log] [blame]
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00001" Vim filetype plugin file (GUI menu, folding and completion)
Bram Moolenaar00a927d2010-05-14 23:24:24 +02002" Language: Debian Changelog
Bram Moolenaar2ecbe532022-07-29 21:36:21 +01003" Maintainer: Debian Vim Maintainers <team+vim@tracker.debian.org>
Bram Moolenaar00a927d2010-05-14 23:24:24 +02004" Former Maintainers: Michael Piefel <piefel@informatik.hu-berlin.de>
5" Stefano Zacchiroli <zack@debian.org>
James McCoy7b7cda62023-10-26 17:14:30 -04006" Last Change: 2023 Aug 18
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01007" License: Vim License
Bram Moolenaarbe4e0162023-02-02 13:59:48 +00008" URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/ftplugin/debchangelog.vim
Bram Moolenaarbd2ac7e2006-04-28 22:34:45 +00009
Bram Moolenaarc236c162008-07-13 17:41:49 +000010" Bug completion requires apt-listbugs installed for Debian packages or
Bram Moolenaar00a927d2010-05-14 23:24:24 +020011" python-launchpadlib installed for Ubuntu packages
Bram Moolenaarc236c162008-07-13 17:41:49 +000012
Bram Moolenaar85eee132018-05-06 17:57:30 +020013if exists('b:did_ftplugin')
Bram Moolenaarbd2ac7e2006-04-28 22:34:45 +000014 finish
15endif
Bram Moolenaar9964e462007-05-05 17:54:07 +000016let b:did_ftplugin=1
Bram Moolenaarbd2ac7e2006-04-28 22:34:45 +000017
18" {{{1 Local settings (do on every load)
Bram Moolenaar85eee132018-05-06 17:57:30 +020019if exists('g:debchangelog_fold_enable')
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000020 setlocal foldmethod=expr
21 setlocal foldexpr=DebGetChangelogFold(v:lnum)
22 setlocal foldtext=DebChangelogFoldText()
23endif
Bram Moolenaarbd2ac7e2006-04-28 22:34:45 +000024
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
Bram Moolenaar85eee132018-05-06 17:57:30 +020031let b:undo_ftplugin = 'setlocal tw< comments< foldmethod< foldexpr< foldtext<'
Bram Moolenaarbd2ac7e2006-04-28 22:34:45 +000032" }}}1
Bram Moolenaar071d4272004-06-13 20:20:40 +000033
Bram Moolenaar85eee132018-05-06 17:57:30 +020034if exists('g:did_changelog_ftplugin')
Bram Moolenaar071d4272004-06-13 20:20:40 +000035 finish
36endif
37
Bram Moolenaarbe4e0162023-02-02 13:59:48 +000038" Don't load another plugin (this is global)
39let g:did_changelog_ftplugin = 1
40
Bram Moolenaar2ecbe532022-07-29 21:36:21 +010041" Make sure the '<' and 'C' flags are not included in 'cpoptions', otherwise
42" <CR> would not be recognized. See ":help 'cpoptions'".
43let s:cpo_save = &cpo
44set cpo&vim
45
Bram Moolenaarf193fff2006-04-27 00:02:13 +000046" {{{1 GUI menu
47
Bram Moolenaar071d4272004-06-13 20:20:40 +000048" Helper functions returning various data.
49" Returns full name, either from $DEBFULLNAME or debianfullname.
50" TODO Is there a way to determine name from anywhere else?
51function <SID>FullName()
Bram Moolenaar85eee132018-05-06 17:57:30 +020052 if exists('$DEBFULLNAME')
Bram Moolenaar071d4272004-06-13 20:20:40 +000053 return $DEBFULLNAME
Bram Moolenaar85eee132018-05-06 17:57:30 +020054 elseif exists('g:debianfullname')
Bram Moolenaar071d4272004-06-13 20:20:40 +000055 return g:debianfullname
56 else
Bram Moolenaar85eee132018-05-06 17:57:30 +020057 return 'Your Name'
Bram Moolenaar071d4272004-06-13 20:20:40 +000058 endif
59endfunction
60
61" Returns email address, from $DEBEMAIL, $EMAIL or debianemail.
62function <SID>Email()
Bram Moolenaar85eee132018-05-06 17:57:30 +020063 if exists('$DEBEMAIL')
Bram Moolenaar071d4272004-06-13 20:20:40 +000064 return $DEBEMAIL
Bram Moolenaar85eee132018-05-06 17:57:30 +020065 elseif exists('$EMAIL')
Bram Moolenaar071d4272004-06-13 20:20:40 +000066 return $EMAIL
Bram Moolenaar85eee132018-05-06 17:57:30 +020067 elseif exists('g:debianemail')
Bram Moolenaarae5bce12005-08-15 21:41:48 +000068 return g:debianemail
Bram Moolenaar071d4272004-06-13 20:20:40 +000069 else
Bram Moolenaar85eee132018-05-06 17:57:30 +020070 return 'your@email.address'
Bram Moolenaar071d4272004-06-13 20:20:40 +000071 endif
72endfunction
73
74" Returns date in RFC822 format.
75function <SID>Date()
76 let savelang = v:lc_time
Bram Moolenaar85eee132018-05-06 17:57:30 +020077 execute 'language time C'
78 let dateandtime = strftime('%a, %d %b %Y %X %z')
79 execute 'language time ' . savelang
Bram Moolenaar071d4272004-06-13 20:20:40 +000080 return dateandtime
81endfunction
82
83function <SID>WarnIfNotUnfinalised()
Bram Moolenaar85eee132018-05-06 17:57:30 +020084 if match(getline('.'), ' -- [[:alpha:]][[:alnum:].]')!=-1
Bram Moolenaar071d4272004-06-13 20:20:40 +000085 echohl WarningMsg
Bram Moolenaar85eee132018-05-06 17:57:30 +020086 echo 'The entry has not been unfinalised before editing.'
Bram Moolenaar071d4272004-06-13 20:20:40 +000087 echohl None
88 return 1
89 endif
90 return 0
91endfunction
92
93function <SID>Finalised()
Bram Moolenaar85eee132018-05-06 17:57:30 +020094 let savelinenum = line('.')
95 1
96 call search('^ -- ')
97 if match(getline('.'), ' -- [[:alpha:]][[:alnum:].]')!=-1
Bram Moolenaar071d4272004-06-13 20:20:40 +000098 let returnvalue = 1
99 else
100 let returnvalue = 0
101 endif
102 execute savelinenum
103 return returnvalue
104endfunction
105
106" These functions implement the menus
107function NewVersion()
108 " The new entry is unfinalised and shall be changed
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100109 amenu disable &Changelog.&New\ Version
110 amenu enable &Changelog.&Add\ Entry
111 amenu enable &Changelog.&Close\ Bug
112 amenu enable &Changelog.Set\ &Distribution
113 amenu enable &Changelog.Set\ &Urgency
114 amenu disable &Changelog.U&nfinalise
115 amenu enable &Changelog.&Finalise
Bram Moolenaarbd2ac7e2006-04-28 22:34:45 +0000116 call append(0, substitute(getline(1), '-\([[:digit:]]\+\))', '-$$\1)', ''))
Bram Moolenaar85eee132018-05-06 17:57:30 +0200117 call append(1, '')
118 call append(2, '')
119 call append(3, ' -- ')
120 call append(4, '')
121 call Urgency('low')
122 normal! 1G0
123 call search(')')
124 normal! h
Viktor Szépe3fc7a7e2023-08-23 21:20:00 +0200125 " ':normal' doesn't support key annotation (<c-a>) directly.
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100126 " Vim's manual recommends using ':exe' to use key annotation indirectly (backslash-escaping needed though).
127 exe "normal! \<c-a>"
Bram Moolenaarbd2ac7e2006-04-28 22:34:45 +0000128 call setline(1, substitute(getline(1), '-\$\$', '-', ''))
Bram Moolenaar85eee132018-05-06 17:57:30 +0200129 if exists('g:debchangelog_fold_enable')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000130 foldopen
131 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132 call AddEntry()
133endfunction
134
135function AddEntry()
Bram Moolenaar85eee132018-05-06 17:57:30 +0200136 1
137 call search('^ -- ')
138 .-2
139 call append('.', ' * ')
140 .+3
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141 let warn=<SID>WarnIfNotUnfinalised()
Bram Moolenaar85eee132018-05-06 17:57:30 +0200142 .-2
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143 if warn
144 echohl MoreMsg
Bram Moolenaar85eee132018-05-06 17:57:30 +0200145 call input('Hit ENTER')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146 echohl None
147 endif
148 startinsert!
149endfunction
150
151function CloseBug()
Bram Moolenaar85eee132018-05-06 17:57:30 +0200152 1
153 call search('^ -- ')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154 let warn=<SID>WarnIfNotUnfinalised()
Bram Moolenaar85eee132018-05-06 17:57:30 +0200155 .-2
156 call append('.', ' * (closes: #' . input('Bug number to close: ') . ')')
157 normal! j^ll
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158 startinsert
159endfunction
160
161function Distribution(dist)
Bram Moolenaar85eee132018-05-06 17:57:30 +0200162 call setline(1, substitute(getline(1), ') *\%(UNRELEASED\|\l\+\);', ') ' . a:dist . ';', ''))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163endfunction
164
165function Urgency(urg)
Bram Moolenaar85eee132018-05-06 17:57:30 +0200166 call setline(1, substitute(getline(1), 'urgency=.*$', 'urgency=' . a:urg, ''))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167endfunction
168
169function <SID>UnfinaliseMenu()
170 " This means the entry shall be changed
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100171 amenu disable &Changelog.&New\ Version
172 amenu enable &Changelog.&Add\ Entry
173 amenu enable &Changelog.&Close\ Bug
174 amenu enable &Changelog.Set\ &Distribution
175 amenu enable &Changelog.Set\ &Urgency
176 amenu disable &Changelog.U&nfinalise
177 amenu enable &Changelog.&Finalise
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178endfunction
179
180function Unfinalise()
181 call <SID>UnfinaliseMenu()
Bram Moolenaar85eee132018-05-06 17:57:30 +0200182 1
183 call search('^ -- ')
184 call setline('.', ' -- ')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185endfunction
186
187function <SID>FinaliseMenu()
188 " This means the entry should not be changed anymore
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100189 amenu enable &Changelog.&New\ Version
190 amenu disable &Changelog.&Add\ Entry
191 amenu disable &Changelog.&Close\ Bug
192 amenu disable &Changelog.Set\ &Distribution
193 amenu disable &Changelog.Set\ &Urgency
194 amenu enable &Changelog.U&nfinalise
195 amenu disable &Changelog.&Finalise
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196endfunction
197
198function Finalise()
199 call <SID>FinaliseMenu()
Bram Moolenaar85eee132018-05-06 17:57:30 +0200200 1
201 call search('^ -- ')
202 call setline('.', ' -- ' . <SID>FullName() . ' <' . <SID>Email() . '> ' . <SID>Date())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203endfunction
204
205
206function <SID>MakeMenu()
207 amenu &Changelog.&New\ Version :call NewVersion()<CR>
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100208 amenu &Changelog.&Add\ Entry :call AddEntry()<CR>
209 amenu &Changelog.&Close\ Bug :call CloseBug()<CR>
210 menu &Changelog.-sep- <nul>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100212 amenu &Changelog.Set\ &Distribution.&unstable :call Distribution("unstable")<CR>
213 amenu &Changelog.Set\ &Distribution.&frozen :call Distribution("frozen")<CR>
214 amenu &Changelog.Set\ &Distribution.&stable :call Distribution("stable")<CR>
215 menu &Changelog.Set\ &Distribution.-sep- <nul>
216 amenu &Changelog.Set\ &Distribution.frozen\ unstable :call Distribution("frozen unstable")<CR>
217 amenu &Changelog.Set\ &Distribution.stable\ unstable :call Distribution("stable unstable")<CR>
218 amenu &Changelog.Set\ &Distribution.stable\ frozen :call Distribution("stable frozen")<CR>
219 amenu &Changelog.Set\ &Distribution.stable\ frozen\ unstable :call Distribution("stable frozen unstable")<CR>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100221 amenu &Changelog.Set\ &Urgency.&low :call Urgency("low")<CR>
222 amenu &Changelog.Set\ &Urgency.&medium :call Urgency("medium")<CR>
223 amenu &Changelog.Set\ &Urgency.&high :call Urgency("high")<CR>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100225 menu &Changelog.-sep- <nul>
226 amenu &Changelog.U&nfinalise :call Unfinalise()<CR>
227 amenu &Changelog.&Finalise :call Finalise()<CR>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228
229 if <SID>Finalised()
230 call <SID>FinaliseMenu()
231 else
232 call <SID>UnfinaliseMenu()
233 endif
234endfunction
235
236augroup changelogMenu
237au BufEnter * if &filetype == "debchangelog" | call <SID>MakeMenu() | endif
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100238au BufLeave * if &filetype == "debchangelog" | silent! aunmenu &Changelog | endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000239augroup END
240
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000241" }}}
242" {{{1 folding
243
Bram Moolenaar9964e462007-05-05 17:54:07 +0000244" look for an author name in the [zonestart zoneend] lines searching backward
245function! s:getAuthor(zonestart, zoneend)
246 let linepos = a:zoneend
247 while linepos >= a:zonestart
248 let line = getline(linepos)
Bram Moolenaar85eee132018-05-06 17:57:30 +0200249 if line =~# '^ --'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000250 return substitute(line, '^ --\s*\([^<]\+\)\s*.*', '\1', '')
251 endif
252 let linepos -= 1
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000253 endwhile
Bram Moolenaar9964e462007-05-05 17:54:07 +0000254 return '[unknown]'
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000255endfunction
256
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000257" Look for a package source name searching backward from the givenline and
258" returns it. Return the empty string if the package name can't be found
259function! DebGetPkgSrcName(lineno)
260 let lineidx = a:lineno
261 let pkgname = ''
262 while lineidx > 0
263 let curline = getline(lineidx)
Bram Moolenaar85eee132018-05-06 17:57:30 +0200264 if curline =~# '^\S'
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000265 let pkgname = matchlist(curline, '^\(\S\+\).*$')[1]
266 break
267 endif
268 let lineidx = lineidx - 1
269 endwhile
270 return pkgname
271endfunction
272
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000273function! DebChangelogFoldText()
Bram Moolenaar85eee132018-05-06 17:57:30 +0200274 if v:folddashes ==# '-' " changelog entry fold
Bram Moolenaar9964e462007-05-05 17:54:07 +0000275 return foldtext() . ' -- ' . s:getAuthor(v:foldstart, v:foldend) . ' '
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000276 endif
277 return foldtext()
278endfunction
279
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000280function! DebGetChangelogFold(lnum)
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000281 let line = getline(a:lnum)
Bram Moolenaar85eee132018-05-06 17:57:30 +0200282 if line =~# '^\w\+'
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000283 return '>1' " beginning of a changelog entry
284 endif
Bram Moolenaar85eee132018-05-06 17:57:30 +0200285 if line =~# '^\s\+\[.*\]'
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000286 return '>2' " beginning of an author-specific chunk
287 endif
Bram Moolenaar85eee132018-05-06 17:57:30 +0200288 if line =~# '^ --'
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000289 return '1'
290 endif
291 return '='
292endfunction
293
Bram Moolenaar85eee132018-05-06 17:57:30 +0200294if exists('g:debchangelog_fold_enable')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000295 silent! foldopen! " unfold the entry the cursor is on (usually the first one)
296endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000297
298" }}}
299
300" {{{1 omnicompletion for Closes: #
301
302if !exists('g:debchangelog_listbugs_severities')
303 let g:debchangelog_listbugs_severities = 'critical,grave,serious,important,normal,minor,wishlist'
304endif
305
306fun! DebCompleteBugs(findstart, base)
307 if a:findstart
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000308 let line = getline('.')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000309
310 " try to detect whether this is closes: or lp:
311 let g:debchangelog_complete_mode = 'debbugs'
312 let try_colidx = col('.') - 1
313 let colidx = -1 " default to no-completion-possible
314
Bram Moolenaar85eee132018-05-06 17:57:30 +0200315 while try_colidx > 0 && line[try_colidx - 1] =~# '\s\|\d\|#\|,\|:'
Bram Moolenaarc236c162008-07-13 17:41:49 +0000316 let try_colidx = try_colidx - 1
Bram Moolenaar85eee132018-05-06 17:57:30 +0200317 if line[try_colidx] ==# '#' && colidx == -1
Bram Moolenaarc236c162008-07-13 17:41:49 +0000318 " found hash, where we complete from:
319 let colidx = try_colidx
Bram Moolenaar85eee132018-05-06 17:57:30 +0200320 elseif line[try_colidx] ==# ':'
321 if try_colidx > 1 && strpart(line, try_colidx - 2, 3) =~? '\clp:'
Bram Moolenaarc236c162008-07-13 17:41:49 +0000322 let g:debchangelog_complete_mode = 'lp'
323 endif
324 break
325 endif
326 endwhile
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000327 return colidx
Bram Moolenaarc236c162008-07-13 17:41:49 +0000328 else " return matches:
329 let bug_lines = []
Bram Moolenaar85eee132018-05-06 17:57:30 +0200330 if g:debchangelog_complete_mode ==? 'lp'
Bram Moolenaarc236c162008-07-13 17:41:49 +0000331 if ! has('python')
332 echoerr 'vim must be built with Python support to use LP bug completion'
333 return
334 endif
335 let pkgsrc = DebGetPkgSrcName(line('.'))
336 python << EOF
337import vim
338try:
Bram Moolenaar00a927d2010-05-14 23:24:24 +0200339 from launchpadlib.launchpad import Launchpad
340 from lazr.restfulclient.errors import HTTPError
341 # login anonymously
342 lp = Launchpad.login_anonymously('debchangelog.vim', 'production')
343 ubuntu = lp.distributions['ubuntu']
344 try:
345 sp = ubuntu.getSourcePackage(name=vim.eval('pkgsrc'))
346 status = ('New', 'Incomplete', 'Confirmed', 'Triaged',
347 'In Progress', 'Fix Committed')
348 tasklist = sp.searchTasks(status=status, order_by='id')
349 liststr = '['
350 for task in tasklist:
351 bug = task.bug
352 liststr += "'#%d - %s'," % (bug.id, bug.title.replace('\'', '\'\''))
353 liststr += ']'
354 vim.command('silent let bug_lines = %s' % liststr.encode('utf-8'))
355 except HTTPError:
356 pass
Bram Moolenaarc236c162008-07-13 17:41:49 +0000357except ImportError:
Bram Moolenaar00a927d2010-05-14 23:24:24 +0200358 vim.command('echoerr \'python-launchpadlib >= 1.5.4 needs to be installed to use Launchpad bug completion\'')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000359EOF
360 else
361 if ! filereadable('/usr/sbin/apt-listbugs')
362 echoerr 'apt-listbugs not found, you should install it to use Closes bug completion'
363 return
364 endif
365 let pkgsrc = DebGetPkgSrcName(line('.'))
366 let listbugs_output = system('/usr/sbin/apt-listbugs -s ' . g:debchangelog_listbugs_severities . ' list ' . pkgsrc . ' | grep "^ #" 2> /dev/null')
367 let bug_lines = split(listbugs_output, '\n')
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000368 endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000369 let completions = []
370 for line in bug_lines
371 let parts = matchlist(line, '^\s*\(#\S\+\)\s*-\s*\(.*\)$')
Bram Moolenaarc236c162008-07-13 17:41:49 +0000372 " filter only those which match a:base:
Bram Moolenaar85eee132018-05-06 17:57:30 +0200373 if parts[1] !~ '^' . a:base
Bram Moolenaarc236c162008-07-13 17:41:49 +0000374 continue
375 endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000376 let completion = {}
377 let completion['word'] = parts[1]
378 let completion['menu'] = parts[2]
379 let completion['info'] = parts[0]
380 let completions += [completion]
381 endfor
382 return completions
383 endif
384endfun
385
386setlocal omnifunc=DebCompleteBugs
Bram Moolenaar9964e462007-05-05 17:54:07 +0000387
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000388" }}}
389
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100390" Restore the previous value of 'cpoptions'.
391let &cpo = s:cpo_save
392unlet s:cpo_save
393
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000394" vim: set foldmethod=marker: