1" Plugin to update the %changelog section of RPM spec files 2" Filename: spec.vim 3" Maintainer: Igor Gnatenko [email protected] 4" Former Maintainer: Gustavo Niemeyer <[email protected]> (until March 2014) 5" Last Change: Sun Mar 2 11:24 MSK 2014 Igor Gnatenko 6 7if exists("b:did_ftplugin") 8 finish 9endif 10let b:did_ftplugin = 1 11 12let s:cpo_save = &cpo 13set cpo&vim 14 15if !exists("no_plugin_maps") && !exists("no_spec_maps") 16 if !hasmapto("<Plug>SpecChangelog") 17 map <buffer> <LocalLeader>c <Plug>SpecChangelog 18 endif 19endif 20 21noremap <buffer> <unique> <script> <Plug>SpecChangelog :call <SID>SpecChangelog("")<CR> 22 23if !exists("*s:SpecChangelog") 24 function s:SpecChangelog(format) 25 if strlen(a:format) == 0 26 if !exists("g:spec_chglog_format") 27 let email = input("Email address: ") 28 let g:spec_chglog_format = "%a %b %d %Y " . l:email 29 echo "\r" 30 endif 31 let format = g:spec_chglog_format 32 else 33 if !exists("g:spec_chglog_format") 34 let g:spec_chglog_format = a:format 35 endif 36 let format = a:format 37 endif 38 let line = 0 39 let name = "" 40 let ver = "" 41 let rel = "" 42 let nameline = -1 43 let verline = -1 44 let relline = -1 45 let chgline = -1 46 while (line <= line("$")) 47 let linestr = getline(line) 48 if (name == "" && linestr =~? '^Name:') 49 let nameline = line 50 let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 51 elseif (ver == "" && linestr =~? '^Version:') 52 let verline = line 53 let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 54 elseif (rel == "" && linestr =~? '^Release:') 55 let relline = line 56 let rel = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 57 elseif (linestr =~? '^%changelog') 58 let chgline = line 59 execute line 60 break 61 endif 62 let line = line+1 63 endwhile 64 if (nameline != -1 && verline != -1 && relline != -1) 65 let include_release_info = exists("g:spec_chglog_release_info") 66 let name = s:ParseRpmVars(name, nameline) 67 let ver = s:ParseRpmVars(ver, verline) 68 let rel = s:ParseRpmVars(rel, relline) 69 else 70 let include_release_info = 0 71 endif 72 if (chgline == -1) 73 let option = confirm("Can't find %changelog. Create one? ","&End of file\n&Here\n&Cancel",3) 74 if (option == 1) 75 call append(line("$"),"") 76 call append(line("$"),"%changelog") 77 execute line("$") 78 let chgline = line(".") 79 elseif (option == 2) 80 call append(line("."),"%changelog") 81 normal j 82 chgline = line(".") 83 endif 84 endif 85 if (chgline != -1) 86 let parsed_format = "* ".strftime(format) 87 let release_info = "+ ".name."-".ver."-".rel 88 let wrong_format = 0 89 let wrong_release = 0 90 let insert_line = 0 91 if (getline(chgline+1) != parsed_format) 92 let wrong_format = 1 93 endif 94 if (include_release_info && getline(chgline+2) != release_info) 95 let wrong_release = 1 96 endif 97 if (wrong_format || wrong_release) 98 if (include_release_info && !wrong_release && !exists("g:spec_chglog_never_increase_release")) 99 let option = confirm("Increase release? ","&Yes\n&No",1) 100 if (option == 1) 101 execute relline 102 normal 103 let rel = substitute(strpart(getline(relline),8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 104 let release_info = "+ ".name."-".ver."-".rel 105 endif 106 endif 107 let n = 0 108 call append(chgline+n, parsed_format) 109 if include_release_info 110 let n = n + 1 111 call append(chgline+n, release_info) 112 endif 113 let n = n + 1 114 call append(chgline+n,"- ") 115 let n = n + 1 116 call append(chgline+n,"") 117 let insert_line = chgline+n 118 else 119 let line = chgline 120 if !exists("g:spec_chglog_prepend") 121 while !(getline(line+2) =~ '^\( *\|\*.*\)$') 122 let line = line+1 123 endwhile 124 endif 125 call append(line+1,"- ") 126 let insert_line = line+2 127 endif 128 execute insert_line 129 startinsert! 130 endif 131 endfunction 132endif 133 134if !exists("*s:ParseRpmVars") 135 function s:ParseRpmVars(str, strline) 136 let end = -1 137 let ret = "" 138 while (1) 139 let start = match(a:str, "\%{", end+1) 140 if (start == -1) 141 let ret = ret . strpart(a:str, end+1) 142 break 143 endif 144 let ret = ret . strpart(a:str, end+1, start-(end+1)) 145 let end = match(a:str, "}", start) 146 if (end == -1) 147 let ret = ret . strpart(a:str, start) 148 break 149 endif 150 let varname = strpart(a:str, start+2, end-(start+2)) 151 execute a:strline 152 let definestr = "^[ \t]*%define[ \t]\\+" . varname . "[ \t]\\+\\(.*\\)$" 153 let linenum = search(definestr, "bW") 154 if (linenum == 0) 155 let definestr = substitute(definestr, "%define", "%global", "") 156 let linenum = search(definestr, "bW") 157 endif 158 if (linenum != -1) 159 let ret = ret . substitute(getline(linenum), definestr, "\\1", "") 160 else 161 let ret = ret . strpart(str, start, end+1-start) 162 endif 163 endwhile 164 return ret 165 endfunction 166endif 167 168" The following lines, along with the macros/matchit.vim plugin, 169" make it easy to navigate the different sections of a spec file 170" with the % key (thanks to Max Ischenko). 171 172let b:match_ignorecase = 0 173let b:match_words = 174 \ '^Name:^%description:^%clean:^%setup:^%build:^%install:^%files:' . 175 \ '^%package:^%preun:^%postun:^%changelog' 176 177let &cpo = s:cpo_save 178unlet s:cpo_save 179 180let b:undo_ftplugin = "unlet! b:match_ignorecase b:match_words" 181