blob: dcf2908911f757c29acea0d3512ab96516487bad [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001" Plugin to update the %changelog section of RPM spec files
2" Filename: spec.vim
Bram Moolenaar08589172014-03-08 18:38:28 +01003" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
4" Former Maintainer: Gustavo Niemeyer <niemeyer@conectiva.com> (until March 2014)
fundawange4015762024-09-10 21:43:05 +02005" 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
Andreas Schneider4f51f3a2024-10-07 21:02:10 +02008" 2024 Oct 07 by Vim Project: add comment support, #15817
Bram Moolenaar071d4272004-06-13 20:20:40 +00009
10if exists("b:did_ftplugin")
11 finish
12endif
13let b:did_ftplugin = 1
14
Bram Moolenaarb6b046b2011-12-30 13:11:27 +010015let s:cpo_save = &cpo
16set cpo&vim
17
Andreas Schneider4f51f3a2024-10-07 21:02:10 +020018setlocal comments=b:#
19setlocal commentstring=#\ %s
20
21let b:undo_ftplugin = "setlocal comments< commentstring<"
22
Bram Moolenaar071d4272004-06-13 20:20:40 +000023if !exists("no_plugin_maps") && !exists("no_spec_maps")
24 if !hasmapto("<Plug>SpecChangelog")
25 map <buffer> <LocalLeader>c <Plug>SpecChangelog
26 endif
27endif
28
Bram Moolenaar113cb512021-11-07 20:27:04 +000029if !hasmapto("call <SID>SpecChangelog(\"\")<CR>")
30 noremap <buffer> <unique> <script> <Plug>SpecChangelog :call <SID>SpecChangelog("")<CR>
Bram Moolenaar2b8388b2015-02-28 13:11:45 +010031endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000032
Bram Moolenaarf2571c62015-06-09 19:44:55 +020033if !exists("*s:GetRelVer")
34 function! s:GetRelVer()
35 if has('python')
36python << PYEND
37import sys, datetime, shutil, tempfile
38import vim
39
40try:
41 import rpm
42except ImportError:
43 pass
44else:
45 specfile = vim.current.buffer.name
46 if specfile:
Bram Moolenaar82af8712016-06-04 20:20:29 +020047 rpm.delMacro("dist")
Bram Moolenaarf2571c62015-06-09 19:44:55 +020048 spec = rpm.spec(specfile)
Bram Moolenaar82af8712016-06-04 20:20:29 +020049 headers = spec.sourceHeader
50 version = headers["Version"]
51 release = headers["Release"]
Bram Moolenaar2d8ed022022-05-21 13:08:16 +010052 vim.command("let ver = '" + version + "'")
53 vim.command("let rel = '" + release + "'")
Bram Moolenaarf2571c62015-06-09 19:44:55 +020054PYEND
55 endif
56 endfunction
57endif
58
Bram Moolenaar071d4272004-06-13 20:20:40 +000059if !exists("*s:SpecChangelog")
60 function s:SpecChangelog(format)
61 if strlen(a:format) == 0
62 if !exists("g:spec_chglog_format")
Bram Moolenaarf2571c62015-06-09 19:44:55 +020063 let email = input("Name <email address>: ")
Bram Moolenaar071d4272004-06-13 20:20:40 +000064 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 = ""
fundawange4015762024-09-10 21:43:05 +020076 let epoch = ""
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 let ver = ""
78 let rel = ""
79 let nameline = -1
fundawange4015762024-09-10 21:43:05 +020080 let epochline = -1
Bram Moolenaar071d4272004-06-13 20:20:40 +000081 let verline = -1
82 let relline = -1
83 let chgline = -1
84 while (line <= line("$"))
85 let linestr = getline(line)
Bram Moolenaar4072ba52020-12-23 13:56:35 +010086 if name == "" && linestr =~? '^Name:'
Bram Moolenaar071d4272004-06-13 20:20:40 +000087 let nameline = line
88 let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
fundawange4015762024-09-10 21:43:05 +020089 elseif epoch == "" && linestr =~? '^Epoch:'
90 let epochline = line
91 let epoch = substitute(strpart(linestr,6), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
Bram Moolenaar4072ba52020-12-23 13:56:35 +010092 elseif ver == "" && linestr =~? '^Version:'
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 let verline = line
94 let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
Bram Moolenaar4072ba52020-12-23 13:56:35 +010095 elseif rel == "" && linestr =~? '^Release:'
Bram Moolenaar071d4272004-06-13 20:20:40 +000096 let relline = line
97 let rel = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','')
Bram Moolenaar4072ba52020-12-23 13:56:35 +010098 elseif linestr =~? '^%changelog'
Bram Moolenaar071d4272004-06-13 20:20:40 +000099 let chgline = line
100 execute line
101 break
102 endif
103 let line = line+1
104 endwhile
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100105 if nameline != -1 && verline != -1 && relline != -1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000106 let include_release_info = exists("g:spec_chglog_release_info")
107 let name = s:ParseRpmVars(name, nameline)
fundawange4015762024-09-10 21:43:05 +0200108 let epoch = s:ParseRpmVars(epoch, epochline)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109 let ver = s:ParseRpmVars(ver, verline)
110 let rel = s:ParseRpmVars(rel, relline)
111 else
112 let include_release_info = 0
113 endif
Bram Moolenaarf2571c62015-06-09 19:44:55 +0200114
115 call s:GetRelVer()
116
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100117 if chgline == -1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000118 let option = confirm("Can't find %changelog. Create one? ","&End of file\n&Here\n&Cancel",3)
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100119 if option == 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000120 call append(line("$"),"")
121 call append(line("$"),"%changelog")
122 execute line("$")
123 let chgline = line(".")
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100124 elseif option == 2
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125 call append(line("."),"%changelog")
126 normal j
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100127 let chgline = line(".")
Bram Moolenaar071d4272004-06-13 20:20:40 +0000128 endif
129 endif
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100130 if chgline != -1
Bram Moolenaar82af8712016-06-04 20:20:29 +0200131 let tmptime = v:lc_time
132 language time C
fundawange4015762024-09-10 21:43:05 +0200133 if strlen(epoch)
134 let ver = epoch.":".ver
135 endif
Bram Moolenaarf2571c62015-06-09 19:44:55 +0200136 let parsed_format = "* ".strftime(format)." - ".ver."-".rel
Bram Moolenaar82af8712016-06-04 20:20:29 +0200137 execute "language time" tmptime
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138 let release_info = "+ ".name."-".ver."-".rel
139 let wrong_format = 0
140 let wrong_release = 0
141 let insert_line = 0
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100142 if getline(chgline+1) != parsed_format
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143 let wrong_format = 1
144 endif
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100145 if include_release_info && getline(chgline+2) != release_info
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146 let wrong_release = 1
147 endif
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100148 if wrong_format || wrong_release
149 if include_release_info && !wrong_release && !exists("g:spec_chglog_never_increase_release")
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150 let option = confirm("Increase release? ","&Yes\n&No",1)
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100151 if option == 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 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
183endif
184
185if !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)
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100191 if start == -1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192 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)
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100197 if end == -1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198 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
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200203 let definestr = "^[ \t]*%\\(define\\|global\\)[ \t]\\+".varname."[ \t]\\+\\(.*\\)$"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204 let linenum = search(definestr, "bW")
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100205 if linenum != 0
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200206 let ret = ret . substitute(getline(linenum), definestr, "\\2", "")
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207 endif
208 endwhile
209 return ret
210 endfunction
211endif
212
213" The following lines, along with the macros/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
217let b:match_ignorecase = 0
218let b:match_words =
Bram Moolenaar82af8712016-06-04 20:20:29 +0200219 \ '^Name:^%description:^%clean:^%(?:auto)?setup:^%build:^%install:^%files:' .
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 \ '^%package:^%preun:^%postun:^%changelog'
221
Bram Moolenaarb6b046b2011-12-30 13:11:27 +0100222let &cpo = s:cpo_save
223unlet s:cpo_save
224
Andreas Schneider4f51f3a2024-10-07 21:02:10 +0200225let b:undo_ftplugin ..= " | unlet! b:match_ignorecase b:match_words"