OmniSharp / omnisharp-vim

Vim omnicompletion (intellisense) and more for C#
http://www.omnisharp.net
MIT License
1.72k stars 168 forks source link

Debug-project and create-debug file features #742

Closed jpfeiffer16 closed 3 years ago

jpfeiffer16 commented 3 years ago

This PR adds two things:

@nickspoons this is not quite finished yet, I just want to get it in so you can get an idea of what I'm thinking and make early course corrections if necessary (and not insignificantly, to light a fire under me to actually get it done.)

I still need to add a vimspector check (I will find a way to share this code with the check in the existing vimspector command.) Also, I am debating whether or not to forge forward with trying to figure out if I can get this to work with .csx files. That would be one of my biggest use-cases so far but the issue I'm running into ATM is that I can't get Vimspector to just work with the file as it is. I have to publish the dll and then run the debugger on that. I'm not sure if that's extraneous logic that we want to have in the project or not (no loss to me if we don't, I've got a personal plugin I use for edge cases like this.)

nickspoons commented 3 years ago

Oh nice, thanks @jpfeiffer16 I'll have a play with it now!

Before even looking at any code:

An OmniSharpDebugProject command Launches Vimspector with an ad-hoc config targeting the current project.

This will not work for any complex use-cases such as passing args or stop-on-entry of course.

Will we eventually be able to add args and maybe even stop-on-entry as command arguments? There's no reason these can't be sent as part of the ad-hoc config, is there? e.g.:

" Debug with args
:OmniSharpDebugProject arg1 arg2
" Use a bang (!) to stop-on-entry
:OmniSharpDebugProject! arg1 arg2

I still need to add a vimspector check (I will find a way to share this code with the check in the existing vimspector command.)

I don't understand what you mean here?

Also, I am debating whether or not to forge forward with trying to figure out if I can get this to work with .csx files

I don't currently use them myself, but if you can get it working it sounds like it would be worth having. I don't really know how they work, is there a /tmp location that a dll is published in to run them?

nickspoons commented 3 years ago

What do you think of this, @jpfeiffer16? This adds the bang for "stopAtEntry" and allows passing args to both of your new commands. I've tested on a simple project and it appears to work well.

This also includes a modification while checks whether host.sln_or_dir is a directory, and if it is the .vimspector.json file is placed there, rather than a level above.

I am not sure how to make a PR on a PR (I know it's possible but it's a bit fiddly) so here's a patch:

diff --git a/autoload/OmniSharp/actions/project.vim b/autoload/OmniSharp/actions/project.vim
index f3a4b90..9214f15 100644
--- a/autoload/OmniSharp/actions/project.vim
+++ b/autoload/OmniSharp/actions/project.vim
@@ -21,9 +21,9 @@ function! s:ProjectRH(Callback, bufnr, response) abort
   call a:Callback()
 endfunction

-function! OmniSharp#actions#project#DebugProject() abort
+function! OmniSharp#actions#project#DebugProject(stopAtEntry, ...) abort
   let bufnr = bufnr('%')
-  function! DebugProjectCb(bufnr) abort
+  function! DebugProjectCb(bufnr, stopAtEntry, args) abort
     let project = getbufvar(a:bufnr, 'OmniSharp_host').project
     if project.ScriptProject is v:null
       call vimspector#LaunchWithConfigurations({
@@ -32,7 +32,8 @@ function! OmniSharp#actions#project#DebugProject() abort
       \    'configuration': {
       \      'request': 'launch', 
       \      'program': project.MsBuildProject.TargetPath,
-      \      'stopAtEntry': v:false
+      \      'args': a:args,
+      \      'stopAtEntry': a:stopAtEntry ? v:true : v:false
       \    }
       \  }
       \})
@@ -52,12 +53,12 @@ function! OmniSharp#actions#project#DebugProject() abort
       \})
     endif
   endfunction
-  call OmniSharp#actions#project#Get(bufnr, function('DebugProjectCb', [bufnr]))
+  call OmniSharp#actions#project#Get(bufnr, function('DebugProjectCb', [bufnr, a:stopAtEntry, a:000]))
 endfunction

-function! OmniSharp#actions#project#CreateDebugConfig() abort
+function! OmniSharp#actions#project#CreateDebugConfig(stopAtEntry, ...) abort
   let bufnr = bufnr('%')
-  function! CreateDebugConfigCb(bufnr) abort
+  function! CreateDebugConfigCb(bufnr, stopAtEntry, args) abort
     let host = getbufvar(a:bufnr, 'OmniSharp_host')
     let contents = [
           \' {',
@@ -74,18 +75,23 @@ function! OmniSharp#actions#project#CreateDebugConfig() abort
           \'       "configuration": {',
           \'         "request": "launch",',
           \'         "program": "'.host.project.MsBuildProject.TargetPath.'",',
-          \'         "args": [],',
-          \'         "stopAtEntry": false',
+          \'         "args": ' . json_encode(a:args) . ',',
+          \'         "stopAtEntry": ' . (a:stopAtEntry ? 'true' : 'false'),
           \'       }',
           \'     }',
           \'   }',
           \' }',
     \ ]
-    let filename = fnamemodify(host.sln_or_dir, ':h:p').'/.vimspector.json'
+    if isdirectory(host.sln_or_dir)
+      let hostdir = host.sln_or_dir
+    else
+      let hostdir = fnamemodify(host.sln_or_dir, ':h:p')
+    endif
+    let filename = hostdir . '/.vimspector.json'
     call writefile(contents, filename)
     execute 'edit ' . filename
   endfunction
-  call OmniSharp#actions#project#Get(bufnr, function('CreateDebugConfigCb', [bufnr]))
+  call OmniSharp#actions#project#Get(bufnr, function('CreateDebugConfigCb', [bufnr, a:stopAtEntry, a:000]))
 endfunction

 let &cpoptions = s:save_cpo
diff --git a/ftplugin/cs/OmniSharp.vim b/ftplugin/cs/OmniSharp.vim
index f5b8750..c50943c 100644
--- a/ftplugin/cs/OmniSharp.vim
+++ b/ftplugin/cs/OmniSharp.vim
@@ -82,8 +82,8 @@ command! -buffer -bar OmniSharpDebugTest call OmniSharp#actions#test#Debug()
 command! -buffer -bar -nargs=* -complete=file OmniSharpRunTestsInFile call OmniSharp#actions#test#RunInFile(<f-args>)
 command! -buffer -bar OmniSharpSignatureHelp call OmniSharp#actions#signature#SignatureHelp()
 command! -buffer -bar OmniSharpTypeLookup call OmniSharp#actions#documentation#TypeLookup()
-command! -buffer -bar OmniSharpDebugProject call OmniSharp#actions#project#DebugProject()
-command! -buffer -bar OmniSharpCreateDebugConfig call OmniSharp#actions#project#CreateDebugConfig()
+command! -buffer -bar -nargs=* -bang OmniSharpDebugProject call OmniSharp#actions#project#DebugProject(<bang>0, <f-args>)
+command! -buffer -bar -nargs=* -bang OmniSharpCreateDebugConfig call OmniSharp#actions#project#CreateDebugConfig(<bang>0, <f-args>)

 nnoremap <buffer> <Plug>(omnisharp_code_format) :OmniSharpCodeFormat<CR>
 nnoremap <buffer> <Plug>(omnisharp_documentation) :OmniSharpDocumentation<CR>
jpfeiffer16 commented 3 years ago

You know, I had not even thought of that. That's a great idea! I'll apply that patch tomorrow!

jpfeiffer16 commented 3 years ago

As to the last point there, I just need to add a check that you actually have vimspector before it tries to debug the project.

As far as the csx stuff goes, I don't really know yet if it puts the binary somewhere. I'm still looking into that. I will keep you updated on that.

jpfeiffer16 commented 3 years ago
jpfeiffer16 commented 3 years ago

@nickspoons . I decided not to hold up this pr with the csx stuff. I'll continue looking into that down the road. I removed it for now.

nickspoons commented 3 years ago

OK, is this ready to merge then?

jpfeiffer16 commented 3 years ago

Yep. It's good to merge

nickspoons commented 3 years ago

Awesome. I've used this already a few times now and it's REALLY useful, thanks @jpfeiffer16!

jpfeiffer16 commented 3 years ago

No problem happy to help! Thank you for the input.