bindzone.vim 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. " File: bindzone.vim
  2. " Description: Edit Bind zones safely
  3. " Author: Emmanuel Bouthenot <kolter@openics.org>
  4. " Version: 0.3
  5. " Last Modified: May 15, 2020
  6. " License: WTFPLv2 (see http://sam.zoy.org/wtfpl/)
  7. " Changelog:
  8. " 0.1: Initial Release
  9. " 0.2: Make it compatible vim plugins managers
  10. " 0.3: Check for named-checkzone only when editing a bind zone file
  11. if exists("loadedBindZone")
  12. finish
  13. endif
  14. let loadedBindZone = 1
  15. autocmd FileType bindzone execute('call BindZoneApply()')
  16. function BindZoneApply()
  17. if executable('named-checkzone')
  18. autocmd BufWriteCmd <buffer> execute('call BindZoneChecker()')
  19. else
  20. echo "Error while loading bindzone.vim: unable to find 'named-checkzone' executable"
  21. endif
  22. endfunction
  23. function BindUpdateSerial()
  24. let s:bufferLines = getbufline(bufnr("%"), 1, "$")
  25. let s:lineNumber = 0
  26. for s:line in s:bufferLines
  27. let s:lineNumber += 1
  28. let s:serial = matchlist(s:line, '^\(\s*\)\(2\d\{7\}\)\(\d\{2\}\)\(\s*;\s*Serial.*\)$')
  29. if s:serial != []
  30. if (strftime("%Y%m%d") == s:serial[2])
  31. let s:newserial = s:serial[2] . s:serial[3]+1
  32. else
  33. let s:newserial = strftime("%Y%m%d") . '01'
  34. endif
  35. call setline(s:lineNumber, s:serial[1] . s:newserial . s:serial[4])
  36. call cursor(s:lineNumber, strlen(s:serial[1] . s:newserial)+1)
  37. execute('highlight BindSerial ctermbg=red guibg=red ctermfg=white guifg=white')
  38. call matchadd("BindSerial", s:newserial)
  39. break
  40. endif
  41. endfor
  42. endfunction
  43. nmap <C-_> :call BindUpdateSerial()<CR>
  44. function BindZoneChecker()
  45. let s:currentFile = expand("%")
  46. let s:bufferContents = getbufline(bufnr("%"), 1, "$")
  47. let s:domain = matchlist(s:bufferContents, '^\$ORIGIN\s\+\(\S\+\)')
  48. if s:domain != []
  49. " If the file isn't writable don't do anything (as it could lock it up)
  50. if filewritable(s:currentFile)
  51. let s:zoneFile = tempname()
  52. exe writefile(s:bufferContents, s:zoneFile)
  53. " Check if the zone file got written (prevent disk space full)
  54. if filereadable(s:zoneFile)
  55. let s:output = system('named-checkzone ' . s:domain[1] . ' ' . s:zoneFile)
  56. let s:output = substitute(s:output, s:zoneFile, s:currentFile, 'g')
  57. call delete(s:zoneFile)
  58. " Check if the zone is correct
  59. let s:okMatch = matchstr(s:output, '\nOK\n')
  60. if s:okMatch != ''
  61. cclose
  62. " Avoids the annoying “Press ENTER to …” message
  63. if &modified
  64. call BindUpdateSerial()
  65. endif
  66. " Finally, we have to write the file
  67. noautocmd w
  68. " Avoids the annoying “Press ENTER to …” message
  69. redraw
  70. else
  71. let s:outputLines = split(s:output, "\n")
  72. let s:errorLines = []
  73. for s:line in s:outputLines
  74. let s:errorLine = matchlist(s:line, '^\(.\+\):\(\d\+\):\s\+\(.*\)$')
  75. if s:errorLine != []
  76. call add(s:errorLines, s:currentFile . ':' . s:errorLine[2] . ':' . s:errorLine[3])
  77. endif
  78. endfor
  79. " if it was impossible to detect errors properly, we still
  80. " had them to the error console in a “raw” way
  81. if s:errorLines == []
  82. for s:line in s:outputLines
  83. call add(s:errorLines, s:currentFile . ':0:' . s:line)
  84. endfor
  85. endif
  86. let s:cFile = tempname()
  87. exe writefile(s:errorLines, s:cFile)
  88. let s:errorWindowHeight = len(s:errorLines)+2
  89. " Limiting the error window rows
  90. if s:errorWindowHeight >= 15
  91. let s:errorWindowHeight = 15
  92. endif
  93. let s:oldCpoptions = &cpoptions
  94. let s:oldErrorFormat = &errorformat
  95. set cpoptions-=F
  96. set errorformat=%f:%l:%m
  97. execute('cfile ' . s:cFile)
  98. execute('botright cwindow ' . s:errorWindowHeight)
  99. call delete(s:cFile)
  100. let &cpoptions = s:oldCpoptions
  101. let &errorformat = s:oldErrorFormat
  102. redraw
  103. return
  104. endif
  105. endif
  106. endif
  107. endif
  108. if s:currentFile != ''
  109. endif
  110. endfunction