Skip to content

Commit

Permalink
Merge pull request #598 from nickspoons/project-management
Browse files Browse the repository at this point in the history
Project management
  • Loading branch information
nickspoons authored Jul 7, 2020
2 parents 3b948c6 + c5b41ef commit a7ea2dc
Show file tree
Hide file tree
Showing 23 changed files with 663 additions and 345 deletions.
205 changes: 92 additions & 113 deletions README.md

Large diffs are not rendered by default.

48 changes: 29 additions & 19 deletions autoload/OmniSharp.vim
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,39 @@ set cpoptions&vim
if !g:OmniSharp_server_stdio
" Load python helper functions
call OmniSharp#py#Bootstrap()
let g:OmniSharp_py_err = {}
endif

function! OmniSharp#GetHost(...) abort
let bufnr = a:0 ? a:1 : bufnr('%')
if empty(getbufvar(bufnr, 'OmniSharp_host'))
let sln_or_dir = OmniSharp#FindSolutionOrDir(1, bufnr)
if g:OmniSharp_server_stdio
let host = {
\ 'job': OmniSharp#proc#GetJob(sln_or_dir),
\ 'sln_or_dir': sln_or_dir
\}
else
if g:OmniSharp_server_stdio
" Using the stdio server, b:OmniSharp_host is a dict containing the
" `sln_or_dir` and an `initialized` flag indicating whether this buffer has
" successfully been registered with the server:
" { 'sln_or_dir': '/path/to/solution_or_dir', 'initialized': 1 }
let host = getbufvar(bufnr, 'OmniSharp_host', {})
if get(host, 'sln_or_dir', '') ==# ''
let host.sln_or_dir = OmniSharp#FindSolutionOrDir(1, bufnr)
let host.initialized = 0
call setbufvar(bufnr, 'OmniSharp_host', host)
endif
" The returned dict includes the job, but the job is _not_ part of
" b:OmniSharp_host. It is important to always fetch the job from
" OmniSharp#proc#GetJob, ensuring that the job properties (job.job_id,
" job.loaded, job.pid etc.) are always correct and up-to-date.
return extend(copy(host), { 'job': OmniSharp#proc#GetJob(host.sln_or_dir) })
else
" Using the HTTP server, b:OmniSharp_host is a localhost URL
if empty(getbufvar(bufnr, 'OmniSharp_host'))
let sln_or_dir = OmniSharp#FindSolutionOrDir(1, bufnr)
let port = OmniSharp#py#GetPort(sln_or_dir)
if port == 0
return ''
endif
let host = get(g:, 'OmniSharp_host', 'http://localhost:' . port)
call setbufvar(bufnr, 'OmniSharp_host', host)
endif
call setbufvar(bufnr, 'OmniSharp_host', host)
return getbufvar(bufnr, 'OmniSharp_host')
endif
if g:OmniSharp_server_stdio
let host = getbufvar(bufnr, 'OmniSharp_host')
if !OmniSharp#proc#IsJobRunning(host.job)
let host.job = OmniSharp#proc#GetJob(host.sln_or_dir)
endif
endif
return getbufvar(bufnr, 'OmniSharp_host')
endfunction


Expand Down Expand Up @@ -295,6 +300,12 @@ function! OmniSharp#StartServer(...) abort

" Optionally perform check if server is already running
if check_is_running
let job = OmniSharp#proc#GetJob(sln_or_dir)
if type(job) == type({}) && get(job, 'stopped')
" The job has been manually stopped - do not start it again until
" instructed
return
endif
let running = OmniSharp#proc#IsJobRunning(sln_or_dir)
if !g:OmniSharp_server_stdio
" If the port is hardcoded, we should check if any other vim instances
Expand Down Expand Up @@ -324,10 +335,9 @@ function! s:StartServer(sln_or_dir) abort
return
endif

let job = OmniSharp#proc#Start(command, a:sln_or_dir)
call OmniSharp#proc#Start(command, a:sln_or_dir)
if g:OmniSharp_server_stdio
let b:OmniSharp_host = {
\ 'job': job,
\ 'sln_or_dir': a:sln_or_dir
\}
endif
Expand Down
11 changes: 9 additions & 2 deletions autoload/OmniSharp/actions/buffer.vim
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ set cpoptions&vim
" returned (synchronously or asynchronously)
function! OmniSharp#actions#buffer#Update(...) abort
let opts = a:0 && a:1 isnot 0 ? { 'Callback': a:1 } : {}
if !OmniSharp#IsServerRunning() | return | endif
let initializing = a:0 > 1
if bufname('%') ==# '' || OmniSharp#FugitiveCheck() | return | endif
if b:changedtick != get(b:, 'OmniSharp_UpdateChangeTick', -1)
if initializing || b:changedtick != get(b:, 'OmniSharp_UpdateChangeTick', -1)
let b:OmniSharp_UpdateChangeTick = b:changedtick
if g:OmniSharp_server_stdio
if initializing
let opts.Initializing = 1
endif
call s:StdioUpdate(opts)
else
if !OmniSharp#IsServerRunning() | return | endif
call OmniSharp#py#Eval('updateBuffer()')
call OmniSharp#py#CheckForError()
if has_key(opts, 'Callback')
Expand All @@ -25,6 +29,9 @@ function! s:StdioUpdate(opts) abort
let opts = {
\ 'ResponseHandler': function('s:StdioUpdateRH', [a:opts])
\}
if has_key(a:opts, 'Initializing')
let opts.Initializing = 1
endif
call OmniSharp#stdio#Request('/updatebuffer', opts)
endfunction

Expand Down
34 changes: 19 additions & 15 deletions autoload/OmniSharp/actions/diagnostics.vim
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function! OmniSharp#actions#diagnostics#Check(...) abort
endif
if g:OmniSharp_server_stdio
let Callback = function('s:CBCodeCheck', [opts])
call OmniSharp#actions#diagnostics#StdioCheck({}, Callback)
call OmniSharp#actions#diagnostics#StdioCheck(bufnr('%'), Callback)
else
let codecheck = OmniSharp#py#Eval('codeCheck()')
if OmniSharp#py#CheckForError() | return | endif
Expand All @@ -27,7 +27,12 @@ function! OmniSharp#actions#diagnostics#CheckGlobal(...) abort
if bufname('%') ==# '' || OmniSharp#FugitiveCheck() | return [] | endif
" Place the results in the quickfix window, if possible
if g:OmniSharp_server_stdio
call s:StdioCheckGlobal(function('s:CBGlobalCodeCheck'))
let Callback = function('s:CBGlobalCodeCheck')
let opts = {
\ 'ResponseHandler': function('s:StdioCheckRH', [Callback])
\}
let job = OmniSharp#GetHost().job
call OmniSharp#stdio#RequestGlobal(job, '/codecheck', opts)
else
let quickfixes = OmniSharp#py#Eval('globalCodeCheck()')
if OmniSharp#py#CheckForError() | return | endif
Expand All @@ -38,43 +43,42 @@ endfunction
" Normally this function would be named 's:StdioCheck`, but it is accessed
" directly from autoload/ale/sources/OmniSharp.vim so requires a full autoload
" function name.
function! OmniSharp#actions#diagnostics#StdioCheck(opts, Callback) abort
function! OmniSharp#actions#diagnostics#StdioCheck(bufnr, Callback) abort
let opts = {
\ 'ResponseHandler': function('s:StdioCheckRH', [a:Callback]),
\ 'BufNum': a:bufnr,
\ 'ReplayOnLoad': 1
\}
call extend(opts, a:opts, 'force')
call OmniSharp#stdio#Request('/codecheck', opts)
endfunction

function! s:StdioCheckGlobal(Callback) abort
let opts = {
\ 'ResponseHandler': function('s:StdioCheckRH', [a:Callback])
\}
call OmniSharp#stdio#RequestSend({}, '/codecheck', opts)
endfunction

function! s:StdioCheckRH(Callback, response) abort
if !a:response.Success | return | endif
call a:Callback(OmniSharp#locations#Parse(a:response.Body.QuickFixes,
\ function("s:DiagnosticQuickfixFixup")))
\ function('s:DiagnosticQuickfixFixup')))
endfunction

function! s:DiagnosticQuickfixFixup(quickfix) abort
let exclude_paths = get(g:, 'OmniSharp_diagnostic_exclude_paths', [])
if len(exclude_paths) && has_key(a:quickfix, 'FileName')
for exclude_path in exclude_paths
if match(a:quickfix.FileName, exclude_path) > 0
return
return {}
endif
endfor
endif

let overrides = get(g:, 'OmniSharp_diagnostic_overrides', {})
let diag_id = get(a:quickfix, 'Id', '-')
if index(keys(overrides), diag_id) >= 0
if diag_id =~# '.FadeOut$'
" Some analyzers such as roslynator provide 2 diagnostics: one to mark
" the start of the issue location and another to mark the end, e.g.
" `RCS1124FadeOut`. We never make use of these FadeOut diagnostics, as
" we can extract start and end locations from the main diagnostic.
return {}
elseif index(keys(overrides), diag_id) >= 0
if overrides[diag_id].type ==? 'None'
return
return {}
endif
call extend(a:quickfix, overrides[diag_id])
endif
Expand Down
9 changes: 5 additions & 4 deletions autoload/OmniSharp/actions/highlight.vim
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
let s:save_cpo = &cpoptions
set cpoptions&vim

function! OmniSharp#actions#highlight#Buffer() abort
if bufname('%') ==# '' || OmniSharp#FugitiveCheck() | return | endif
let opts = { 'BufNum': bufnr('%') }
function! OmniSharp#actions#highlight#Buffer(...) abort
let bufnr = a:0 ? a:1 : bufnr('%')
if bufname(bufnr) ==# '' || OmniSharp#FugitiveCheck() | return | endif
if g:OmniSharp_server_stdio &&
\ (has('textprop') || exists('*nvim_create_namespace'))
call s:StdioHighlight(opts.BufNum)
call s:StdioHighlight(bufnr)
else
" Full semantic highlighting not supported - highlight types instead
call OmniSharp#actions#highlight_types#Buffer()
Expand All @@ -17,6 +17,7 @@ function! s:StdioHighlight(bufnr) abort
let buftick = getbufvar(a:bufnr, 'changedtick')
let opts = {
\ 'ResponseHandler': function('s:HighlightRH', [a:bufnr, buftick]),
\ 'BufNum': a:bufnr,
\ 'ReplayOnLoad': 1
\}
call OmniSharp#stdio#Request('/v2/highlight', opts)
Expand Down
18 changes: 11 additions & 7 deletions autoload/OmniSharp/actions/highlight_types.vim
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,23 @@ set cpoptions&vim
function! OmniSharp#actions#highlight_types#Buffer() abort
if bufname('%') ==# '' || OmniSharp#FugitiveCheck() | return | endif
call OmniSharp#actions#highlight_types#Initialise()
let opts = { 'BufNum': bufnr('%') }
let bufnr = bufnr('%')
if g:OmniSharp_server_stdio
let Callback = function('s:CBHighlightBuffer', [opts])
call s:StdioFindHighlightTypes(Callback)
let Callback = function('s:CBHighlightBuffer', [bufnr])
call s:StdioFindHighlightTypes(bufnr, Callback)
else
if !OmniSharp#IsServerRunning() | return | endif
let hltypes = OmniSharp#py#Eval('findHighlightTypes()')
if OmniSharp#py#CheckForError() | return | endif
call s:CBHighlightBuffer(opts, hltypes)
call s:CBHighlightBuffer(bufnr, hltypes)
endif
endfunction

function! s:StdioFindHighlightTypes(Callback) abort
function! s:StdioFindHighlightTypes(bufnr, Callback) abort
let bufferLines = getline(1, '$')
let opts = {
\ 'ResponseHandler': function('s:FindHighlightTypesRH', [a:Callback, bufferLines]),
\ 'BufNum': a:bufnr,
\ 'ReplayOnLoad': 1
\}
call OmniSharp#stdio#Request('/highlight', opts)
Expand Down Expand Up @@ -68,12 +69,15 @@ function! s:FindHighlightTypesRH(Callback, bufferLines, response) abort
call a:Callback(hltypes)
endfunction

function! s:CBHighlightBuffer(opts, hltypes) abort
function! s:CBHighlightBuffer(bufnr, hltypes) abort
if has_key(a:hltypes, 'error')
echohl WarningMsg | echom a:hltypes.error | echohl None
return
endif
if bufnr('%') != a:opts.BufNum | return | endif
" matchadd() only works in the current window/buffer, so if the user has
" navigated away from the buffer where the request was made, this response can
" not be applied
if bufnr('%') != a:bufnr | return | endif

let b:OmniSharp_hl_matches = get(b:, 'OmniSharp_hl_matches', [])

Expand Down
2 changes: 1 addition & 1 deletion autoload/OmniSharp/actions/signature.vim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function! OmniSharp#actions#signature#SignatureHelp(...) abort
else
let response = OmniSharp#py#Eval('signatureHelp()')
if OmniSharp#py#CheckForError() | return | endif
call s:CBSignatureHelp(response)
call s:CBSignatureHelp(opts, response)
endif
endfunction

Expand Down
5 changes: 4 additions & 1 deletion autoload/OmniSharp/actions/usages.vim
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ endfunction

function! s:StdioFind(Callback) abort
let opts = {
\ 'ResponseHandler': function('s:StdioFindRH', [a:Callback])
\ 'ResponseHandler': function('s:StdioFindRH', [a:Callback]),
\ 'Parameters': {
\ 'ExcludeDefinition': 1
\ }
\}
call OmniSharp#stdio#Request('/findusages', opts)
endfunction
Expand Down
38 changes: 38 additions & 0 deletions autoload/OmniSharp/actions/workspace.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
let s:save_cpo = &cpoptions
set cpoptions&vim

let s:attempts = 0

function! OmniSharp#actions#workspace#Get(job) abort
let opts = {
\ 'ResponseHandler': function('s:ProjectsRH', [a:job])
\}
let s:attempts += 1
call OmniSharp#stdio#RequestGlobal(a:job, '/projects', opts)
endfunction

function! s:ProjectsRH(job, response) abort
" If this request fails, retry up to 5 times
if !a:response.Success
if s:attempts < 5
call OmniSharp#actions#workspace#Get(a:job)
endif
return
endif
" If no projects have been loaded by the time this callback is reached, there
" are no projects and the job can be marked as ready
let projects = get(get(a:response.Body, 'MsBuild', {}), 'Projects', {})
let a:job.projects = map(projects,
\ {_,project -> {"name": project.AssemblyName, "path": project.Path}})
if get(a:job, 'projects_total', 0) > 0
call OmniSharp#log#Log(a:job, 'Workspace complete: ' . a:job.projects_total . ' project(s)')
else
call OmniSharp#log#Log(a:job, 'Workspace complete: no projects')
call OmniSharp#project#RegisterLoaded(a:job)
endif
endfunction

let &cpoptions = s:save_cpo
unlet s:save_cpo

" vim:et:sw=2:sts=2
26 changes: 26 additions & 0 deletions autoload/OmniSharp/buffer.vim
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
let s:save_cpo = &cpoptions
set cpoptions&vim

function! OmniSharp#buffer#Initialize(job, bufnr, command, opts) abort
let a:job.pending_requests = get(a:job, 'pending_requests', {})
let host = getbufvar(a:bufnr, 'OmniSharp_host')
if get(host, 'initialized') | return | endif
let a:job.pending_requests[a:bufnr] = get(a:job.pending_requests, a:bufnr, {})
" More recent requests to the same command replace older pending requests
let a:job.pending_requests[a:bufnr][a:command] = a:opts
if has_key(OmniSharp#GetHost(a:bufnr), 'initializing') | return | endif
let host.initializing = 1
let Callback = function('s:CBInitialize', [a:job, a:bufnr, host])
call OmniSharp#actions#buffer#Update(Callback, 1)
endfunction

function! s:CBInitialize(job, bufnr, host) abort
let a:host.initialized = 1
unlet a:host.initializing
call OmniSharp#log#Log(a:job, 'Replaying requests for buffer ' . a:bufnr)
for key in keys(a:job.pending_requests[a:bufnr])
call OmniSharp#stdio#Request(key, a:job.pending_requests[a:bufnr][key])
unlet a:job.pending_requests[a:bufnr][key]
if empty(a:job.pending_requests[a:bufnr])
unlet a:job.pending_requests[a:bufnr]
endif
endfor
endfunction

function! OmniSharp#buffer#PerformChanges(opts, response) abort
if !a:response.Success | return | endif
let changes = get(a:response.Body, 'Changes', [])
Expand Down
3 changes: 1 addition & 2 deletions autoload/OmniSharp/locations.vim
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function! OmniSharp#locations#Parse(quickfixes, ...) abort
let locations = []
for quickfix in a:quickfixes
let quickfix = a:0 ? a:1(quickfix) : quickfix
if type(quickfix) == 0
if empty(quickfix)
continue
endif

Expand All @@ -50,7 +50,6 @@ function! OmniSharp#locations#Parse(quickfixes, ...) abort
let location.end_col = quickfix.EndColumn - 1
endif


if has_key(quickfix, 'type')
let location.type = get(quickfix, 'type')
if has_key(quickfix, 'subtype')
Expand Down
Loading

0 comments on commit a7ea2dc

Please sign in to comment.