From aaa8acf5a286122ff7ab51aca2ccf98be4317d1b Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Wed, 6 Jan 2021 00:23:32 +0000 Subject: [PATCH] Update build#dir() to open a popup_menu() Use `popup_menu()` in `build#dir()` when the `:BuildDir` command is uses without an argument to specify a build directory. If there are no build directories, print an error message. If there is a single build directory, use it. If there are multiple build directories use `popup_menu()` to prompt the user to select the desired build directory. Update `build#targets()` and `build#run()` with comments and error messages. --- autoload/build.vim | 62 ++++++++++++++++++++++++++++++++++++++++----- plugin/commands.vim | 2 +- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/autoload/build.vim b/autoload/build.vim index 1402136..cbc4ff6 100644 --- a/autoload/build.vim +++ b/autoload/build.vim @@ -1,27 +1,75 @@ -function! build#dir(dir) abort - let l:cwd = getcwd() - let $BUILD_DIR = l:cwd.'/'.a:dir - let g:ycm_clangd_args = ['--compile-commands-dir='.$BUILD_DIR] - YcmRestartServer +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, create popup menu to select one. + " Set the callback to this function on completion, handled below. + call popup_menu(s:dirs, #{ + \ filter: 'popup_filter_menu', + \ callback: 'build#dir', + \ }) + 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 and restart YouCompleteMe. + let $BUILD_DIR = getcwd().'/'.substitute(l:dir, '\/$', '', '') + let g:ycm_clangd_args = ['--compile-commands-dir='.$BUILD_DIR] + YcmRestartServer + 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 + " TODO: Support make, it's much less straight forwards than ninja. endif return join(l:targets, "\n") endfunction function! build#run(...) abort - let l:build_dir = substitute($BUILD_DIR, '\/$', '', '') + 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 diff --git a/plugin/commands.vim b/plugin/commands.vim index ae009cc..653f061 100644 --- a/plugin/commands.vim +++ b/plugin/commands.vim @@ -31,5 +31,5 @@ command! -nargs=+ -complete=file Debug call do#debug() command! TodoFile lvimgrep /todo/ % " Change build directory -command! -nargs=1 -complete=dir BuildDir call build#dir() +command! -nargs=? -complete=dir BuildDir call build#dir() command! -nargs=* -complete=custom,build#targets Build call build#run()