Skip to content

Commit 2484032

Browse files
committed
👍 change denops#server#start and ...#stop to asynchronous
- Add new `denops-variable`: - `g:denops#server#close_timeout` - Add new state for `denops#server#status()`: - `closing` - `closed` - Change behavior `denops-function`: - `denops#server#start()` can now be called even when status is `closing`. In that case, the status will become `stopped` and then restart asynchronously. - `denops#server#stop()` is changed to asynchronously. It waits for the server to close gracefully, and force terminate if timeouted. - `denops#server#restart()` is changed to asynchronously. Perform the stop and start steps above.
1 parent 7fcd0c3 commit 2484032

File tree

10 files changed

+1085
-136
lines changed

10 files changed

+1085
-136
lines changed

autoload/denops/_internal/job.vim

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ if has('nvim')
3030
function! s:stop(job) abort
3131
try
3232
call jobstop(a:job)
33-
call jobwait([a:job])
3433
catch /^Vim\%((\a\+)\)\=:E900/
3534
" NOTE:
3635
" Vim does not raise exception even the job has already closed so fail
@@ -58,24 +57,23 @@ else
5857
\ 'err_cb': funcref('s:out_cb', [a:options.on_stderr, 'stderr']),
5958
\ 'exit_cb': funcref('s:exit_cb', [a:options.on_exit, 'exit']),
6059
\}
61-
return job_start(a:args, l:options)
60+
let l:job = job_start(a:args, l:options)
61+
if l:job->job_status() !=# "run"
62+
throw printf("Invalid value for argument cmd: '%s' is not executable", a:args[0])
63+
endif
64+
return l:job
6265
endfunction
6366

6467
function! s:stop(job) abort
6568
call job_stop(a:job)
6669
call timer_start(s:KILL_TIMEOUT_MS, { -> job_stop(a:job, 'kill') })
67-
" Wait until the job is actually closed
68-
while job_status(a:job) ==# 'run'
69-
sleep 10m
70-
endwhile
71-
redraw
7270
endfunction
7371

74-
function! s:out_cb(callback, event, ch, msg) abort
75-
call a:callback(a:ch, a:msg, a:event)
72+
function! s:out_cb(callback, event, job, msg) abort
73+
call a:callback(a:job, a:msg, a:event)
7674
endfunction
7775

78-
function! s:exit_cb(callback, event, ch, status) abort
79-
call a:callback(a:ch, a:status, a:event)
76+
function! s:exit_cb(callback, event, job, status) abort
77+
call a:callback(a:job, a:status, a:event)
8078
endfunction
8179
endif

autoload/denops/_internal/server/chan.vim

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ function! denops#_internal#server#chan#connect(addr, options) abort
2828
endif
2929
let l:retry_threshold = a:options.retry_threshold
3030
let l:retry_interval = a:options.retry_interval
31-
let l:previous_exception = ''
32-
for l:i in range(l:retry_threshold)
31+
let l:i = 1
32+
while v:true
3333
call denops#_internal#echo#debug(printf(
3434
\ 'Connecting to channel `%s` [%d/%d]',
3535
\ a:addr,
36-
\ l:i + 1,
37-
\ l:retry_threshold + 1,
36+
\ l:i,
37+
\ l:retry_threshold,
3838
\))
3939
try
4040
call s:connect(a:addr, a:options)
@@ -43,28 +43,45 @@ function! denops#_internal#server#chan#connect(addr, options) abort
4343
call denops#_internal#echo#debug(printf(
4444
\ 'Failed to connect channel `%s` [%d/%d]: %s',
4545
\ a:addr,
46-
\ l:i + 1,
47-
\ l:retry_threshold + 1,
46+
\ l:i,
47+
\ l:retry_threshold,
4848
\ v:exception,
4949
\))
50-
let l:previous_exception = v:exception
50+
if l:i >= l:retry_threshold
51+
call denops#_internal#echo#error(printf(
52+
\ 'Failed to connect channel `%s`: %s',
53+
\ a:addr,
54+
\ v:exception,
55+
\))
56+
return
57+
endif
5158
endtry
5259
execute printf('sleep %dm', l:retry_interval)
53-
endfor
54-
call denops#_internal#echo#error(printf(
55-
\ 'Failed to connect channel `%s`: %s',
56-
\ a:addr,
57-
\ l:previous_exception,
58-
\))
60+
endwhile
5961
endfunction
6062

61-
function! denops#_internal#server#chan#close() abort
63+
" Args:
64+
" options: {
65+
" timeout: number (default: 0)
66+
" }
67+
function! denops#_internal#server#chan#close(options) abort
6268
if s:chan is# v:null
6369
throw '[denops] Channel does not exist yet'
6470
endif
71+
let l:options = extend({
72+
\ 'timeout': 0,
73+
\}, a:options)
6574
let s:closed_on_purpose = 1
66-
call s:rpcclose(s:chan)
67-
let s:chan = v:null
75+
if l:options.timeout ==# 0
76+
return s:force_close(l:options)
77+
endif
78+
if l:options.timeout > 0
79+
let s:force_close_delayer = timer_start(
80+
\ l:options.timeout,
81+
\ { -> s:force_close(l:options) },
82+
\)
83+
endif
84+
call denops#_internal#server#chan#notify('invoke', ['close', []])
6885
endfunction
6986

7087
function! denops#_internal#server#chan#is_connected() abort
@@ -91,36 +108,56 @@ endfunction
91108

92109
function! s:connect(addr, options) abort
93110
let s:closed_on_purpose = 0
94-
let s:chan = s:rpcconnect(a:addr, {
95-
\ 'on_close': { -> s:on_close(a:options) },
96-
\})
97111
let s:addr = a:addr
98112
let s:options = a:options
113+
let s:chan = s:rpcconnect(a:addr, {
114+
\ 'on_close': { -> s:on_close() },
115+
\})
99116
call denops#_internal#echo#debug(printf('Channel connected (%s)', a:addr))
100117
call s:rpcnotify(s:chan, 'void', [])
101118
endfunction
102119

103-
function! s:on_close(options) abort
120+
function! s:force_close(options) abort
121+
let l:chan = s:chan
122+
let s:chan = v:null
123+
call s:clear_force_close_delayer()
124+
call denops#_internal#echo#warn(printf(
125+
\ 'Channel cannot close gracefully within %d millisec, force close (%s)',
126+
\ a:options.timeout,
127+
\ s:addr,
128+
\))
129+
call s:rpcclose(l:chan)
130+
endfunction
131+
132+
function! s:clear_force_close_delayer() abort
133+
if exists('s:force_close_delayer')
134+
call timer_stop(s:force_close_delayer)
135+
unlet s:force_close_delayer
136+
endif
137+
endfunction
138+
139+
function! s:on_close() abort
104140
let s:chan = v:null
141+
call s:clear_force_close_delayer()
105142
call denops#_internal#echo#debug(printf('Channel closed (%s)', s:addr))
106143
doautocmd <nomodeline> User DenopsClosed
107-
if !a:options.reconnect_on_close || s:closed_on_purpose || s:exiting
144+
if s:chan isnot# v:null || !s:options.reconnect_on_close || s:closed_on_purpose || s:exiting
108145
return
109146
endif
110147
" Reconnect
111-
if s:reconnect_guard(a:options)
148+
if s:reconnect_guard()
112149
return
113150
endif
114151
call denops#_internal#echo#warn('Channel closed. Reconnecting...')
115152
call timer_start(
116-
\ a:options.reconnect_delay,
153+
\ s:options.reconnect_delay,
117154
\ { -> denops#_internal#server#chan#connect(s:addr, s:options) },
118155
\)
119156
endfunction
120157

121-
function! s:reconnect_guard(options) abort
122-
let l:reconnect_threshold = a:options.reconnect_threshold
123-
let l:reconnect_interval = a:options.reconnect_interval
158+
function! s:reconnect_guard() abort
159+
let l:reconnect_threshold = s:options.reconnect_threshold
160+
let l:reconnect_interval = s:options.reconnect_interval
124161
let s:reconnect_count = get(s:, 'reconnect_count', 0) + 1
125162
if s:reconnect_count >= l:reconnect_threshold
126163
call denops#_internal#echo#warn(printf(

autoload/denops/_internal/server/proc.vim

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,34 @@ function! denops#_internal#server#proc#start(options) abort
2222
endif
2323
let l:retry_interval = a:options.retry_interval
2424
let l:retry_threshold = a:options.retry_threshold
25-
let l:previous_exception = ''
26-
for l:i in range(l:retry_threshold)
25+
let l:i = 1
26+
while v:true
2727
call denops#_internal#echo#debug(printf(
2828
\ 'Spawn server [%d/%d]',
29-
\ l:i + 1,
30-
\ l:retry_threshold + 1,
29+
\ l:i,
30+
\ l:retry_threshold,
3131
\))
3232
try
3333
call s:start(a:options)
3434
return v:true
3535
catch
3636
call denops#_internal#echo#debug(printf(
3737
\ 'Failed to spawn server [%d/%d]: %s',
38-
\ l:i + 1,
39-
\ l:retry_threshold + 1,
38+
\ l:i,
39+
\ l:retry_threshold,
4040
\ v:exception,
4141
\))
42-
let l:previous_exception = v:exception
42+
if l:i >= l:retry_threshold
43+
call denops#_internal#echo#error(printf(
44+
\ 'Failed to spawn server: %s',
45+
\ v:exception,
46+
\))
47+
return
48+
endif
4349
endtry
4450
execute printf('sleep %dm', l:retry_interval)
45-
endfor
46-
call denops#_internal#echo#error(printf(
47-
\ 'Failed to spawn server: %s',
48-
\ l:previous_exception,
49-
\))
51+
let l:i += 1
52+
endwhile
5053
endfunction
5154

5255
function! denops#_internal#server#proc#stop() abort
@@ -116,7 +119,7 @@ function! s:on_exit(options, status) abort
116119
let s:job = v:null
117120
call denops#_internal#echo#debug(printf('Server stopped: %s', a:status))
118121
execute printf('doautocmd <nomodeline> User DenopsProcessStopped:%s', a:status)
119-
if !a:options.restart_on_exit || s:stopped_on_purpose || s:exiting
122+
if s:job isnot# v:null || !a:options.restart_on_exit || s:stopped_on_purpose || s:exiting
120123
return
121124
endif
122125
" Restart

0 commit comments

Comments
 (0)