spec.vim (6345B)
1 " Plugin to update the %changelog section of RPM spec files 2 " Filename: spec.vim 3 " Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com 4 " Former Maintainer: Gustavo Niemeyer <niemeyer@conectiva.com> (until March 2014) 5 " Last Change: 2015 Jun 01 6 " Update by Zdenek Dohnal, 2022 May 17 7 " 2024 Sep 10 by Vim Project: add epoch support for spec changelog, #15537 8 " 2024 Oct 07 by Vim Project: add comment support, #15817 9 10 if exists("b:did_ftplugin") 11 finish 12 endif 13 let b:did_ftplugin = 1 14 15 let s:cpo_save = &cpo 16 set cpo&vim 17 18 setlocal comments=b:# 19 setlocal commentstring=#\ %s 20 21 let b:undo_ftplugin = "setlocal comments< commentstring<" 22 23 if !exists("no_plugin_maps") && !exists("no_spec_maps") 24 if !hasmapto("<Plug>SpecChangelog") 25 map <buffer> <LocalLeader>c <Plug>SpecChangelog 26 endif 27 endif 28 29 if !hasmapto("call <SID>SpecChangelog(\"\")<CR>") 30 noremap <buffer> <unique> <script> <Plug>SpecChangelog :call <SID>SpecChangelog("")<CR> 31 endif 32 33 if !exists("*s:GetRelVer") 34 function! s:GetRelVer() 35 if has('python') 36 python << PYEND 37 import sys, datetime, shutil, tempfile 38 import vim 39 40 try: 41 import rpm 42 except ImportError: 43 pass 44 else: 45 specfile = vim.current.buffer.name 46 if specfile: 47 rpm.delMacro("dist") 48 spec = rpm.spec(specfile) 49 headers = spec.sourceHeader 50 version = headers["Version"] 51 release = headers["Release"] 52 vim.command("let ver = '" + version + "'") 53 vim.command("let rel = '" + release + "'") 54 PYEND 55 endif 56 endfunction 57 endif 58 59 if !exists("*s:SpecChangelog") 60 function s:SpecChangelog(format) 61 if strlen(a:format) == 0 62 if !exists("g:spec_chglog_format") 63 let email = input("Name <email address>: ") 64 let g:spec_chglog_format = "%a %b %d %Y " . l:email 65 echo "\r" 66 endif 67 let format = g:spec_chglog_format 68 else 69 if !exists("g:spec_chglog_format") 70 let g:spec_chglog_format = a:format 71 endif 72 let format = a:format 73 endif 74 let line = 0 75 let name = "" 76 let epoch = "" 77 let ver = "" 78 let rel = "" 79 let nameline = -1 80 let epochline = -1 81 let verline = -1 82 let relline = -1 83 let chgline = -1 84 while (line <= line("$")) 85 let linestr = getline(line) 86 if name == "" && linestr =~? '^Name:' 87 let nameline = line 88 let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 89 elseif epoch == "" && linestr =~? '^Epoch:' 90 let epochline = line 91 let epoch = substitute(strpart(linestr,6), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 92 elseif ver == "" && linestr =~? '^Version:' 93 let verline = line 94 let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 95 elseif rel == "" && linestr =~? '^Release:' 96 let relline = line 97 let rel = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 98 elseif linestr =~? '^%changelog' 99 let chgline = line 100 execute line 101 break 102 endif 103 let line = line+1 104 endwhile 105 if nameline != -1 && verline != -1 && relline != -1 106 let include_release_info = exists("g:spec_chglog_release_info") 107 let name = s:ParseRpmVars(name, nameline) 108 let epoch = s:ParseRpmVars(epoch, epochline) 109 let ver = s:ParseRpmVars(ver, verline) 110 let rel = s:ParseRpmVars(rel, relline) 111 else 112 let include_release_info = 0 113 endif 114 115 call s:GetRelVer() 116 117 if chgline == -1 118 let option = confirm("Can't find %changelog. Create one? ","&End of file\n&Here\n&Cancel",3) 119 if option == 1 120 call append(line("$"),"") 121 call append(line("$"),"%changelog") 122 execute line("$") 123 let chgline = line(".") 124 elseif option == 2 125 call append(line("."),"%changelog") 126 normal j 127 let chgline = line(".") 128 endif 129 endif 130 if chgline != -1 131 let tmptime = v:lc_time 132 language time C 133 if strlen(epoch) 134 let ver = epoch.":".ver 135 endif 136 let parsed_format = "* ".strftime(format)." - ".ver."-".rel 137 execute "language time" tmptime 138 let release_info = "+ ".name."-".ver."-".rel 139 let wrong_format = 0 140 let wrong_release = 0 141 let insert_line = 0 142 if getline(chgline+1) != parsed_format 143 let wrong_format = 1 144 endif 145 if include_release_info && getline(chgline+2) != release_info 146 let wrong_release = 1 147 endif 148 if wrong_format || wrong_release 149 if include_release_info && !wrong_release && !exists("g:spec_chglog_never_increase_release") 150 let option = confirm("Increase release? ","&Yes\n&No",1) 151 if option == 1 152 execute relline 153 normal 154 let rel = substitute(strpart(getline(relline),8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 155 let release_info = "+ ".name."-".ver."-".rel 156 endif 157 endif 158 let n = 0 159 call append(chgline+n, parsed_format) 160 if include_release_info 161 let n = n + 1 162 call append(chgline+n, release_info) 163 endif 164 let n = n + 1 165 call append(chgline+n,"- ") 166 let n = n + 1 167 call append(chgline+n,"") 168 let insert_line = chgline+n 169 else 170 let line = chgline 171 if !exists("g:spec_chglog_prepend") 172 while !(getline(line+2) =~ '^\( *\|\*.*\)$') 173 let line = line+1 174 endwhile 175 endif 176 call append(line+1,"- ") 177 let insert_line = line+2 178 endif 179 execute insert_line 180 startinsert! 181 endif 182 endfunction 183 endif 184 185 if !exists("*s:ParseRpmVars") 186 function s:ParseRpmVars(str, strline) 187 let end = -1 188 let ret = "" 189 while (1) 190 let start = match(a:str, "\%{", end+1) 191 if start == -1 192 let ret = ret . strpart(a:str, end+1) 193 break 194 endif 195 let ret = ret . strpart(a:str, end+1, start-(end+1)) 196 let end = match(a:str, "}", start) 197 if end == -1 198 let ret = ret . strpart(a:str, start) 199 break 200 endif 201 let varname = strpart(a:str, start+2, end-(start+2)) 202 execute a:strline 203 let definestr = "^[ \t]*%\\(define\\|global\\)[ \t]\\+".varname."[ \t]\\+\\(.*\\)$" 204 let linenum = search(definestr, "bW") 205 if linenum != 0 206 let ret = ret . substitute(getline(linenum), definestr, "\\2", "") 207 endif 208 endwhile 209 return ret 210 endfunction 211 endif 212 213 " The following lines, along with the matchit.vim plugin, 214 " make it easy to navigate the different sections of a spec file 215 " with the % key (thanks to Max Ischenko). 216 217 let b:match_ignorecase = 0 218 let b:match_words = 219 \ '^Name:^%description:^%clean:^%(?:auto)?setup:^%build:^%install:^%files:' . 220 \ '^%package:^%preun:^%postun:^%changelog' 221 222 let &cpo = s:cpo_save 223 unlet s:cpo_save 224 225 let b:undo_ftplugin ..= " | unlet! b:match_ignorecase b:match_words"