spec.vim 6.2 KB

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