" File: bindzone.vim " Description: Edit Bind zones safely " Author: Emmanuel Bouthenot " Version: 0.3 " Last Modified: May 15, 2020 " License: WTFPLv2 (see http://sam.zoy.org/wtfpl/) " Changelog: " 0.1: Initial Release " 0.2: Make it compatible vim plugins managers " 0.3: Check for named-checkzone only when editing a bind zone file if exists("loadedBindZone") finish endif let loadedBindZone = 1 autocmd FileType bindzone execute('call BindZoneApply()') function BindZoneApply() if executable('named-checkzone') autocmd BufWriteCmd execute('call BindZoneChecker()') else echo "Error while loading bindzone.vim: unable to find 'named-checkzone' executable" endif endfunction function BindUpdateSerial() let s:bufferLines = getbufline(bufnr("%"), 1, "$") let s:lineNumber = 0 for s:line in s:bufferLines let s:lineNumber += 1 let s:serial = matchlist(s:line, '^\(\s*\)\(2\d\{7\}\)\(\d\{2\}\)\(\s*;\s*Serial.*\)$') if s:serial != [] if (strftime("%Y%m%d") == s:serial[2]) let s:newserial = s:serial[2] . s:serial[3]+1 else let s:newserial = strftime("%Y%m%d") . '01' endif call setline(s:lineNumber, s:serial[1] . s:newserial . s:serial[4]) call cursor(s:lineNumber, strlen(s:serial[1] . s:newserial)+1) execute('highlight BindSerial ctermbg=red guibg=red ctermfg=white guifg=white') call matchadd("BindSerial", s:newserial) break endif endfor endfunction nmap :call BindUpdateSerial() function BindZoneChecker() let s:currentFile = expand("%") let s:bufferContents = getbufline(bufnr("%"), 1, "$") let s:domain = matchlist(s:bufferContents, '^\$ORIGIN\s\+\(\S\+\)') if s:domain != [] " If the file isn't writable don't do anything (as it could lock it up) if filewritable(s:currentFile) let s:zoneFile = tempname() exe writefile(s:bufferContents, s:zoneFile) " Check if the zone file got written (prevent disk space full) if filereadable(s:zoneFile) let s:output = system('named-checkzone ' . s:domain[1] . ' ' . s:zoneFile) let s:output = substitute(s:output, s:zoneFile, s:currentFile, 'g') call delete(s:zoneFile) " Check if the zone is correct let s:okMatch = matchstr(s:output, '\nOK\n') if s:okMatch != '' cclose " Avoids the annoying “Press ENTER to …” message if &modified call BindUpdateSerial() endif " Finally, we have to write the file noautocmd w " Avoids the annoying “Press ENTER to …” message redraw else let s:outputLines = split(s:output, "\n") let s:errorLines = [] for s:line in s:outputLines let s:errorLine = matchlist(s:line, '^\(.\+\):\(\d\+\):\s\+\(.*\)$') if s:errorLine != [] call add(s:errorLines, s:currentFile . ':' . s:errorLine[2] . ':' . s:errorLine[3]) endif endfor " if it was impossible to detect errors properly, we still " had them to the error console in a “raw” way if s:errorLines == [] for s:line in s:outputLines call add(s:errorLines, s:currentFile . ':0:' . s:line) endfor endif let s:cFile = tempname() exe writefile(s:errorLines, s:cFile) let s:errorWindowHeight = len(s:errorLines)+2 " Limiting the error window rows if s:errorWindowHeight >= 15 let s:errorWindowHeight = 15 endif let s:oldCpoptions = &cpoptions let s:oldErrorFormat = &errorformat set cpoptions-=F set errorformat=%f:%l:%m execute('cfile ' . s:cFile) execute('botright cwindow ' . s:errorWindowHeight) call delete(s:cFile) let &cpoptions = s:oldCpoptions let &errorformat = s:oldErrorFormat redraw return endif endif endif endif if s:currentFile != '' endif endfunction