Skip to content

Commit

Permalink
Initialize buffers instead of full server load
Browse files Browse the repository at this point in the history
The OmniSharp-roslyn loading issues appear to stem from situations where
multiple buffer-requests are sent before the project is fully
initialized. This results in duplicate "miscellaneous" files, which are
not correctly promoted to "project" files.

Instead, this commit introduces a buffer "initialization" concept, where
an `/updatebuffer` request is always sent as the first request for a
buffer, and no further requests are sent for that buffer until a
response is received (indicating that the server has registered the
file, and there will be no duplicates created).
  • Loading branch information
nickspoons committed Jun 29, 2020
1 parent de51104 commit 4f2e069
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 41 deletions.
11 changes: 5 additions & 6 deletions autoload/OmniSharp.vim
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,20 @@ function! OmniSharp#GetHost(...) abort
let bufnr = a:0 ? a:1 : bufnr('%')
if g:OmniSharp_server_stdio
" Using the stdio server, b:OmniSharp_host is a dict containing the
" sln_or_dir:
" { 'sln_or_dir': '/path/to/solution_or_dir' }
" `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 {
\ 'sln_or_dir': host.sln_or_dir,
\ 'job': OmniSharp#proc#GetJob(host.sln_or_dir)
\}
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'))
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
3 changes: 1 addition & 2 deletions autoload/OmniSharp/actions/workspace.vim
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ let s:attempts = 0

function! OmniSharp#actions#workspace#Get(job) abort
let opts = {
\ 'ResponseHandler': function('s:ProjectsRH', [a:job]),
\ 'AllowUnloaded': 1
\ 'ResponseHandler': function('s:ProjectsRH', [a:job])
\}
let s:attempts += 1
call OmniSharp#stdio#RequestGlobal(a:job, '/projects', opts)
Expand Down
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
10 changes: 2 additions & 8 deletions autoload/OmniSharp/project.vim
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ let s:save_cpo = &cpoptions
set cpoptions&vim

function! OmniSharp#project#CountLoaded() abort
" TODO: stdio guard?
if !g:OmniSharp_server_stdio | return 0 | endif
let host = OmniSharp#GetHost()
return get(OmniSharp#proc#GetJob(host.sln_or_dir), 'projects_loaded', 0)
endfunction

function! OmniSharp#project#CountTotal() abort
" TODO: stdio guard?
if !g:OmniSharp_server_stdio | return 0 | endif
let host = OmniSharp#GetHost()
return get(OmniSharp#proc#GetJob(host.sln_or_dir), 'projects_total', 0)
endfunction
Expand All @@ -22,12 +22,6 @@ function! OmniSharp#project#RegisterLoaded(job) abort
endif
let a:job.loaded = 1
silent doautocmd <nomodeline> User OmniSharpReady

" TODO: Remove this delay once we have better information about
" when the server is completely initialised:
" https://github.com/OmniSharp/omnisharp-roslyn/issues/1521
call timer_start(1000, function('OmniSharp#stdio#ReplayRequests', [a:job]))
" call OmniSharp#stdio#ReplayRequests(a:job)
endfunction

" Listen for stdio server-loaded events
Expand Down
49 changes: 26 additions & 23 deletions autoload/OmniSharp/stdio.vim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ set cpoptions&vim

let s:nextseq = get(s:, 'nextseq', 1001)
let s:requests = get(s:, 'requests', {})
let s:pendingRequests = get(s:, 'pendingRequests', {})

function! OmniSharp#stdio#HandleResponse(job, message) abort
try
Expand Down Expand Up @@ -100,17 +99,37 @@ function! OmniSharp#stdio#Request(command, opts) abort
let [bufnr, lnum, cnum] = s:lastPosition
elseif has_key(a:opts, 'BufNum') && a:opts.BufNum != bufnr('%')
let bufnr = a:opts.BufNum
let lnum = 1
let cnum = 1
let lnum = get(a:opts, 'LineNum', 1)
let cnum = get(a:opts, 'ColNum', 1)
else
let bufnr = bufnr('%')
let lnum = line('.')
let cnum = col('.')
let lnum = get(a:opts, 'LineNum', line('.'))
let cnum = get(a:opts, 'ColNum', col('.'))
endif
let job = OmniSharp#GetHost(bufnr).job
let host = OmniSharp#GetHost(bufnr)
let job = host.job
if !OmniSharp#proc#IsJobRunning(job)
return
endif

if has_key(a:opts, 'Initializing')
" The buffer is being initialized - this request will always be sent
else
if !get(host, 'initialized')
" Replay the request when the buffer has been initialized with the server
let opts = extend(a:opts, {
\ 'BufNum': bufnr,
\ 'LineNum': lnum,
\ 'ColNum': cnum
\})
if has_key(opts, 'UsePreviousPosition')
unlet opts.UsePreviousPosition
endif
call OmniSharp#buffer#Initialize(job, bufnr, a:command, opts)
return 0
endif
endif

if has_key(a:opts, 'SavePosition')
let s:lastPosition = [bufnr, lnum, cnum]
endif
Expand Down Expand Up @@ -156,15 +175,6 @@ function! OmniSharp#stdio#RequestGlobal(job, command, opts) abort
endfunction

function! s:Request(job, body, command, opts, ...) abort
let sep = a:0 ? a:1 : ''
if !has_key(a:opts, 'AllowUnloaded') &&
\ (!has_key(a:job, 'job_id') || !a:job.loaded)
if has_key(a:opts, 'ReplayOnLoad') && !has_key(s:pendingRequests, a:command)
" This request should be replayed when the server is fully loaded
let s:pendingRequests[a:command] = a:opts
endif
return 0
endif
call OmniSharp#log#Log(a:job, 'Request: ' . a:command, 1)

let a:body['Command'] = a:command
Expand All @@ -173,6 +183,7 @@ function! s:Request(job, body, command, opts, ...) abort
if has_key(a:opts, 'Parameters')
call extend(a:body.Arguments, a:opts.Parameters, 'force')
endif
let sep = a:0 ? a:1 : ''
if sep !=# ''
let encodedBody = substitute(json_encode(a:body), sep, '\\r\\n', 'g')
else
Expand All @@ -196,14 +207,6 @@ function! s:Request(job, body, command, opts, ...) abort
return 1
endfunction

function! OmniSharp#stdio#ReplayRequests(job, ...) abort
call OmniSharp#log#Log(a:job, 'Replaying requests')
for key in keys(s:pendingRequests)
call OmniSharp#stdio#Request(key, s:pendingRequests[key])
unlet s:pendingRequests[key]
endfor
endfunction

let &cpoptions = s:save_cpo
unlet s:save_cpo

Expand Down

0 comments on commit 4f2e069

Please sign in to comment.