-
Notifications
You must be signed in to change notification settings - Fork 168
Build command with autocomplete for .csproj files
After typing :Make ...<tab>
it should autocomplete to a .csproj/.sln to build, which calls dotnet build
on that .csproj/.sln.
See :help wildmenu
. 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
" `~/.vim/ftplugin/cs.vim`
" Reference: https://github.com/OmniSharp/omnisharp-vim/issues/386
compiler cs
" [re]defines :Make command, with autocomplete to a csproj in the sln
command! -bang -nargs=* -bar -complete=custom,s:DotNetFileComplete Make call asyncrun#run(<bang>0, #{program: 'make'}, <f-args>)
" Or alternatively:
"command! -bang -nargs=* -bar -complete=custom,s:DotNetFileComplete Make AsyncRun -program=make @ <args>
" Or with AsyncDo instead of AsyncRun (a little different):
"command! -bang -nargs=* -bar -complete=custom,s:DotNetFileComplete Make call asyncdo#run(<bang>0, &makeprg, <f-args>)
" Find relevant .csproj files to populate autocomplete list. See `:help command-completion-custom`
" s:DotNetFileComplete() requires the 'project' data from OmniSharp-Roslyn, without better IPC
" in Vim it is best to cache that data earlier, using s:CacheOmniSharpProjectInBuffer()
function! s: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
let host = OmniSharp#GetHost(bufnr('%'))
let csprojs = deepcopy(host.job.projects)
let csprojs_relative = map(csprojs, {index, value -> fnamemodify(value['path'], ':.')})
if has_key(host, 'project')
" Make the first project this file is in first in the sln list
let project = fnamemodify(host['project']['MsBuildProject']['Path'], ':.')
let i = index(csprojs_relative, project)
call remove(csprojs_relative, i)
let matches = join(insert(csprojs_relative, project), "\n")
else
let matches = join(csprojs_relative, "\n")
endif
endif
return matches
endfunction
" `~/.vim/compiler/cs.vim`
if exists("current_compiler")
finish
endif
let current_compiler = "cs"
" As of Vim 8.2, the distribution includes a cs CompilerSet `:help compiler`
" which uses an obsolete frontent, csc.
" This replaces that obsolute frontend with `dotnet build`.
" Considering both dotnet and mono frontends to compiling C#, you may define
" a CompilerSet for mono in `compiler/mono.vim` if you wish, and use with `:compiler mono`
if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif
CompilerSet makeprg=dotnet\ build\ /v:q\ /property:GenerateFullPaths=true\ /clp:ErrorsOnly
CompilerSet errorformat=\ %#%f(%l\\\,%c):\ %m
" `~/.vim/plugin/omnisharp-vim.vim`
" Cache the 'project' data from OmniSharp-Roslyn to each cs buffer
augroup cacheOmniSharpProject
autocmd!
autocmd FileType cs call s:CacheOmniSharpProjectInBuffer()
augroup END
function! s:CacheOmniSharpProjectInBuffer()
if &filetype == 'cs'
let bufnr = bufnr('%')
let host = OmniSharp#GetHost(bufnr)
if !has_key(host, 'project')
" 'project' not in cache, must query from OmniSharp-Roslyn, is async
let l:F = {-> 0}
call OmniSharp#actions#project#Get(bufnr, l:F)
endif
endif
endfunction
This approach optionally depends on an Async plugin, either:
- hauleth/asyncdo.vim, or
- skywind3000/asyncrun.vim (which features real-time population of the QuickFix list).
set wildmenu
somewhere in your vimrc. 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 selection and any args for a given project in a
tempfile()
. So:Make
no args would prefer the cached choice, such as with an argument to build to a custom directory '-o /tmp/build/bin/'.
[Obsolete] Use :OmniSharpDebugProject
and :OmniSharpCreateDebugConfig
instead. The instructions below are obsolete/old.
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 :]
function! WriteVimspectorConfig() abort
let projects = OmniSharp#GetHost().job.projects
let config = { 'configurations': {} }
for project in projects
let config.configurations[project['name']] = {
\ 'adapter': 'netcoredbg',
\ 'configuration': {
\ 'request': 'launch',
\ 'program': project['target'],
\ 'args': [],
\ 'stopAtEntry': v:true
\ }
\}
endfor
let sln_or_dir = OmniSharp#GetHost().sln_or_dir
let slndir = sln_or_dir =~? '\.sln$' ? fnamemodify(sln_or_dir, ':h') : sln_or_dir
let filename = slndir . s:dir_separator . '.vimspector.json'
call writefile([json_encode(config)], filename)
endfunction
- To debug the built executable, call
call vimspector#LaunchWithSettings( #{ configuration: 'project-name' } )
where project-name is the name of the .csproj. - Or
F5
(what the Vimspector continue keymapping is) and select project name from the prompt.