function! build#dir(...) abort if a:0 == 0 " No arguments, find build directories. let s:dirs = split(substitute(globpath('.', 'build*'), '\.\/', '', 'g'), '\n') let l:len = len(s:dirs) if l:len == 0 echoerr 'no build directories found' elseif l:len == 1 " One build directory found, use it. let l:dir = s:dirs[0] unlet s:dirs else " Multiple build directories found, select one. if exists('*popup_menu') " Create popup menu to select the build directory. Callback to this " function on completion, handled in the else branch below. call popup_menu(s:dirs, #{ \ filter: 'popup_filter_menu', \ callback: 'build#dir', \ }) else " Fallback to inputlist when popup_menu is not available. let l:choices = [] let l:index = 1 for l:dir in s:dirs call add(l:choices, string(l:index).': '.l:dir) let l:index += 1 endfor let l:index = inputlist(l:choices) let l:dir = s:dirs[l:index - 1] echomsg ' '.l:dir endif endif else if a:0 == 1 " Single argument, invoked by :BuildDir. let l:dir = a:1 elseif a:0 == 2 " Two arguments, called back by popup_menu(). let l:dirs = s:dirs unlet s:dirs if a:2 == -1 " Selection in popup_menu() was cancelled. return endif let l:dir = l:dirs[a:2 - 1] else echoerr 'build#dir called with too many arguments' endif endif if exists('l:dir') " Set build directory. let l:cwd = substitute(getcwd(), '\\', '\/', 'g') let $BUILD_DIR = l:cwd.'/'.substitute(l:dir, '\/$', '', '') if executable('compdb') " Post-process compile_commands.json with compdb, adds header files to " missing compile_commands.json for more accurate diagnostics. let l:database_dir = l:cwd.'/.vim' let l:compile_commands = l:database_dir.'/compile_commands.json' call systemlist('compdb -p '.$BUILD_DIR.' list > '.l:compile_commands) else let l:database_dir = $BUILD_DIR endif " Read/create .vim/coc-settings.json let l:coc_settings = {} if isdirectory('.vim') let l:coc_settings = json_decode(join(readfile('.vim/coc-settings.json'), '')) else call mkdir('.vim') endif " Update .vim/coc-settings.json with new build directory. let l:coc_settings['clangd.compilationDatabasePath'] = l:database_dir let l:coc_settings['cmake.lsp.buildDirectory'] = $BUILD_DIR call writefile([json_encode(l:coc_settings)], '.vim/coc-settings.json') " Finally restart coc.nvim with new config. CocRestart endif endfunction function! build#targets(ArgLead, CmdLine, CursorPos) abort if !exists('$BUILD_DIR') echoerr 'build directory not set' return '' endif let l:targets = [] if filereadable($BUILD_DIR.'/build.ninja') " Ask ninja for the list of targets and prepare for returning. for l:target in split(system('ninja -C '.$BUILD_DIR.' -t targets'), '\n') call add(l:targets, substitute(l:target, ':.*$', '', '')) endfor elseif filereadable($BUILD_DIR.'/Makefile') " TODO: Support make, it's much less straight forwards than ninja. endif return join(l:targets, "\n") endfunction function! build#run(...) abort if !exists('$BUILD_DIR') call echo#error('build directory not set') return endif let l:build_dir = $BUILD_DIR if filereadable($BUILD_DIR.'/build.ninja') " Execute ninja in a terminal window. execute 'terminal ninja -C '.l:build_dir.' '.join(a:000, ' ') elseif filereadable($BUILD_DIR.'/Makefile') " Execute make in a terminal window. execute 'terminal make -C '.l:build_dir.' '.join(a:000, ' ') endif endfunction