-
Notifications
You must be signed in to change notification settings - Fork 166
Build command with autocomplete for .csproj files
I needed a way to make a specific .csproj instead of every project in the .sln.
So I made it so the <tab>
key should autocomplete to a .csproj.
E.g. typing :Make <tab>
will result in a menu of options, or only one option if only one .csproj was found in the search space:
:Make Content.Shared/Content.Shared.csproj
:Make
BuildChecker/BuildChecker.csproj Content.Shared/Content.Shared.csproj
Content.Server.Database/Content.Server.Database.csproj
See :help wildmenu
.
The only plugin this approach depends on is something which defines asyncdo#run(), either hauleth/asyncdo.vim or an alternative like skywind3000/asyncrun.vim which features real-time population of the QuickFix list.
~/.vim/plugin/asyncdo.vim
:
"First a generalized way to have the makeprg be called async, not just C#.
"I think I found this on ThePrimeagen YouTube channel or other YouTube video.
"Not necessary for C# but is a generalized approach to calling make Async within Vim with args.
"Display status of :AsyncDo (asyncdo#run) in status line:
let &statusline .= "%{exists('g:asyncdo')?'runing':''}"
"Make makeprg (:make) run async
command! -bang -nargs=* -complete=file Make call asyncdo#run(<bang>0, &makeprg, <f-args>)
"Make :grep run async
command! -bang -nargs=* -complete=dir Grep call asyncdo#run(
\ <bang>0,
\ { 'job': &grepprg, 'errorformat': &grepformat },
\ <f-args>)
~/.vim/ftplugin/cs.vim
:
"Reference: https://github.com/OmniSharp/omnisharp-vim/issues/386
compiler dotnet
" automatically open quickfix window after build is completed
augroup QUICKFIX_CS
autocmd!
autocmd QuickFixCmdPost [^l]* nested cwindow
autocmd QuickFixCmdPost l* nested lwindow
augroup END
~/.vim/compiler/dotnet.vim
:
if exists("current_compiler")
finish
endif
let current_compiler = "dotnet"
setlocal makeprg=dotnet\ build\ /v:q\ /property:GenerateFullPaths=true\ /clp:ErrorsOnly
setlocal errorformat=\ %#%f(%l\\\,%c):\ %m
set wildmenu
let s:omnisharp_ready=0
augroup OMNISHARP_READY
autocmd!
autocmd User OmniSharpReady let s:omnisharp_ready=1
augroup END
"Redefines earlier :Make command for .cs files.
command! -bang -nargs=* -complete=customlist,DotNetFileComplete Make call asyncdo#run(<bang>0, &makeprg, <f-args>)
"Find relevant .csproj files to populate autocomplete list
":help command-completion-custom
fun DotNetFileComplete(A,L,P)
let searchdir=expand('%:.:h')
let matches=''
"If we're not relative to the cwd (e.g. in :help), don't try to search
if fnamemodify(searchdir,':p:h') !=? searchdir
"First try to find match from current file's folder and search up to . (cwd)
let matches=split(globpath(searchdir,'*.csproj'),'\n')
while '.' !=# searchdir && empty(matches)
let searchdir=fnamemodify(searchdir,':h')
let matches=split(globpath(searchdir,'*.csproj'),'\n')
endwhile
if empty(matches)
if s:omnisharp_ready
"Query for all .csproj files associated with OmniSharp sln
let csprojs=deepcopy(OmniSharp#proc#GetJob(OmniSharp#GetHost().sln_or_dir).projects)
let matches=map(csprojs, {index, value -> fnamemodify(value['path'],':.')})
else
"Omnisharp-vim not started, try solution directory subdirectories:
let matches=split(globpath('**','*.csproj'),'\n')
endif
endif
endif
return matches
endfun
If you have many .csproj files in your .sln, then maybe setting the vertical option in :help wildmode
may help navigation.
The DotNetFileComplete
function above could use generalized refinement:
- Maybe some caching of the result/selection and any other args for a given directory in a
tempfile()
. So:Make
no args would prefer the cached choice. Such caching the argument to build to a custom directory "-o /tmp/build/bin/" - The test to see if we're in :help (file open not relative to cwd) to avoid an infinite loop is not great. Pity findfile with built-in support for an upwards-search doesn't work with wildcards.
Vimspector appears to be the best option for debugging in Vim. Vimspector requires the configuration file .vimspector.json
in order to know what to debug. The following function will use information available from OmniSharp to build said configuration file in the .sln folder:
let s:dir_separator = fnamemodify('.', ':p')[-1 :]
augroup OMNISHARP_READY_CONFIG
autocmd!
autocmd User OmniSharpReady call WriteVimspectorConfig()
augroup END
fun WriteVimspectorConfig()
let csprojs=deepcopy(OmniSharp#proc#GetJob(OmniSharp#GetHost().sln_or_dir).projects)
let configurations=map(csprojs, {index,
\ value -> { value['name']: {
\ "adapter":"netcoredbg",
\ "configuration:": {
\ "request":"launch",
\ "program":"${workspaceRoot}".s:dir_separator.fnamemodify(value['target'],':.'),
\ "args":[],
\ "stopAtEntry":"true",
\ "cwd":"${workspaceRoot}",
\ "env":{}}}}})
let dict={"configurations":configurations}
let vimspector_json=json_encode(dict)
call writefile([vimspector_json],".vimspector.json")
endfun
To debug the built executable, call call vimspector#LaunchWithSettings( #{ configuration: 'project-name' } )
where project-name is the name of the .csproj. Or F5
or what Vimspector continue keymapping is, and select project name from the prompt.
Calling WriteVimspectorConfig() on OmniSharpReady doesn't seem to work.