Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,51 +48,52 @@ jobs:
- macos-latest
- ubuntu-latest
version:
- "1.38.x"
- "1.43.x"
- "1.x"
host_version:
- vim: "v9.0.2189"
nvim: "v0.9.4"
- vim: "v9.1.0399"
nvim: "v0.9.5"

runs-on: ${{ matrix.runner }}

steps:
- run: git config --global core.autocrlf false
if: runner.os == 'Windows'

- uses: actions/checkout@v4

- uses: denoland/setup-deno@v1.1.4
with:
deno-version: "${{ matrix.version }}"

- uses: rhysd/action-setup-vim@v1
id: vim
with:
version: "${{ matrix.host_version.vim }}"
- name: Check Vim
run: |
echo ${DENOPS_TEST_VIM}
${DENOPS_TEST_VIM} --version
env:
DENOPS_TEST_VIM: ${{ steps.vim.outputs.executable }}

- uses: rhysd/action-setup-vim@v1
id: nvim
with:
neovim: true
version: "${{ matrix.host_version.nvim }}"
- name: Check Neovim

- name: Export executables
run: |
echo ${DENOPS_TEST_NVIM}
${DENOPS_TEST_NVIM} --version
env:
DENOPS_TEST_NVIM: ${{ steps.nvim.outputs.executable }}
echo "DENOPS_TEST_VIM_EXECUTABLE=${{ steps.vim.outputs.executable }}" >> "$GITHUB_ENV"
echo "DENOPS_TEST_NVIM_EXECUTABLE=${{ steps.nvim.outputs.executable }}" >> "$GITHUB_ENV"

- name: Perform pre-cache
run: deno cache ./denops/@denops-private/mod.ts

- name: Test
run: deno task test:coverage
env:
DENOPS_TEST_DENOPS_PATH: "./"
DENOPS_TEST_VIM_EXECUTABLE: ${{ steps.vim.outputs.executable }}
DENOPS_TEST_NVIM_EXECUTABLE: ${{ steps.nvim.outputs.executable }}
timeout-minutes: 5
timeout-minutes: 10

- run: |
deno task coverage --lcov > coverage.lcov

- uses: codecov/codecov-action@v4
with:
os: ${{ runner.os }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
git config user.name github-actions[bot]
git config user.email github-actions[bot]@users.noreply.github.com
- name: Update dependencies and commit changes
run: deno task -q upgrade:commit --summary ../title.txt --report ../body.md
run: deno task -q update:commit --summary ../title.txt --report ../body.md
- name: Check result
id: result
uses: andstor/file-existence-action@v2
Expand Down
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
<strong>Denops</strong><br>
<sup>An ecosystem for Vim/Neovim enabling developers to write plugins in Deno.</sup>

[![Deno 1.38.5 or above](https://img.shields.io/badge/Deno-Support%201.38.5-yellowgreen.svg?logo=deno)](https://github.com/denoland/deno/tree/v1.38.5)
[![Vim 9.0.2189 or above](https://img.shields.io/badge/Vim-Support%209.0.2189-yellowgreen.svg?logo=vim)](https://github.com/vim/vim/tree/v9.0.2189)
[![Neovim 0.9.4 or above](https://img.shields.io/badge/Neovim-Support%200.9.4-yellowgreen.svg?logo=neovim&logoColor=white)](https://github.com/neovim/neovim/tree/v0.9.4)
[![Deno 1.43.3 or above](https://img.shields.io/badge/Deno-Support%201.43.3-yellowgreen.svg?logo=deno)](https://github.com/denoland/deno/tree/v1.43.3)
[![Vim 9.1.0399 or above](https://img.shields.io/badge/Vim-Support%209.1.0399-yellowgreen.svg?logo=vim)](https://github.com/vim/vim/tree/v9.1.0399)
[![Neovim 0.9.5 or above](https://img.shields.io/badge/Neovim-Support%200.9.5-yellowgreen.svg?logo=neovim&logoColor=white)](https://github.com/neovim/neovim/tree/v0.9.5)

[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![deno land](http://img.shields.io/badge/available%20on-deno.land/x/denops__core-lightgrey.svg?logo=deno)](https://deno.land/x/denops_core)
[![test](https://github.com/vim-denops/denops.vim/actions/workflows/test.yml/badge.svg)](https://github.com/vim-denops/denops.vim/actions/workflows/test.yml)
[![codecov](https://codecov.io/github/vim-denops/denops.vim/branch/main/graph/badge.svg?token=k50SaoYUp0)](https://codecov.io/github/vim-denops/denops.vim)

[![vim help](https://img.shields.io/badge/vim-%3Ah%20denops-orange.svg)](doc/denops.txt)
[![deno doc](https://doc.deno.land/badge.svg)](https://doc.deno.land/https/deno.land/x/denops_core/mod.ts)
[![Documentation](https://img.shields.io/badge/denops-Documentation-yellow.svg)](https://vim-denops.github.io/denops-documentation/)

</div>
Expand Down
8 changes: 1 addition & 7 deletions autoload/denops/_internal/job.vim
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ if has('nvim')
function! s:stop(job) abort
try
call jobstop(a:job)
call jobwait([a:job])
catch /^Vim\%((\a\+)\)\=:E900/
" NOTE:
" Vim does not raise exception even the job has already closed so fail
Expand All @@ -46,7 +45,7 @@ if has('nvim')
call a:callback(a:job, a:status, a:event)
endfunction
else
" https://github.com/neovim/neovim/blob/f629f83/src/nvim/event/process.c#L24-L26
" https://github.com/neovim/neovim/blob/cb24a3907c8d24a898d99042f0f16c8919a2e7ab/src/nvim/event/process.c#L28
let s:KILL_TIMEOUT_MS = 2000

function! s:start(args, options) abort
Expand All @@ -64,11 +63,6 @@ else
function! s:stop(job) abort
call job_stop(a:job)
call timer_start(s:KILL_TIMEOUT_MS, { -> job_stop(a:job, 'kill') })
" Wait until the job is actually closed
while job_status(a:job) ==# 'run'
sleep 10m
endwhile
redraw
endfunction

function! s:out_cb(callback, event, ch, msg) abort
Expand Down
2 changes: 1 addition & 1 deletion autoload/denops/_internal/rpc/nvim.vim
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ endfunction
function! denops#_internal#rpc#nvim#close(chan) abort
call timer_stop(a:chan._healthcheck_timer)
call chanclose(a:chan._id)
call a:chan._on_close(a:chan)
call timer_start(0, { -> a:chan._on_close(a:chan) })
endfunction

function! denops#_internal#rpc#nvim#notify(chan, method, params) abort
Expand Down
17 changes: 11 additions & 6 deletions autoload/denops/_internal/rpc/vim.vim
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,34 @@ function! denops#_internal#rpc#vim#connect(addr, ...) abort
\ 'on_close': { -> 0 },
\}, a:0 ? a:1 : {},
\)
let l:chan = ch_open(a:addr, {
let l:chan = {
\ '_on_close': l:options.on_close,
\}
let l:chan._handle = ch_open(a:addr, {
\ 'mode': 'json',
\ 'drop': 'auto',
\ 'noblock': 1,
\ 'timeout': g:denops#_internal#rpc#vim#timeout,
\ 'close_cb': l:options.on_close,
\ 'close_cb': { -> l:chan._on_close(l:chan) },
\})
if ch_status(l:chan) !=# 'open'
if ch_status(l:chan._handle) !=# 'open'
throw printf('Failed to connect `%s`', a:addr)
endif
return l:chan
endfunction

function! denops#_internal#rpc#vim#close(chan) abort
return ch_close(a:chan)
" NOTE: 'close_cb' specified on `ch_open` is not invoked when `ch_close` called.
call ch_close(a:chan._handle)
call timer_start(0, { -> a:chan._on_close(a:chan) })
endfunction

function! denops#_internal#rpc#vim#notify(chan, method, params) abort
return ch_sendraw(a:chan, json_encode([0, [a:method] + a:params]) . "\n")
return ch_sendraw(a:chan._handle, json_encode([0, [a:method] + a:params]) . "\n")
endfunction

function! denops#_internal#rpc#vim#request(chan, method, params) abort
let [l:ok, l:err] = ch_evalexpr(a:chan, [a:method] + a:params)
let [l:ok, l:err] = ch_evalexpr(a:chan._handle, [a:method] + a:params)
if l:err isnot# v:null
throw l:err
endif
Expand Down
61 changes: 48 additions & 13 deletions autoload/denops/_internal/server/chan.vim
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,28 @@ function! denops#_internal#server#chan#connect(addr, options) abort
\))
endfunction

function! denops#_internal#server#chan#close() abort
" Args:
" options: {
" timeout: number (default: 0)
" }
function! denops#_internal#server#chan#close(options) abort
if s:chan is# v:null
throw '[denops] Channel does not exist yet'
endif
let l:options = extend({
\ 'timeout': 0,
\}, a:options)
let s:closed_on_purpose = 1
call s:rpcclose(s:chan)
let s:chan = v:null
if l:options.timeout ==# 0
return s:force_close(l:options)
endif
if l:options.timeout > 0
let s:force_close_delayer = timer_start(
\ l:options.timeout,
\ { -> s:force_close(l:options) },
\)
endif
call denops#_internal#server#chan#notify('invoke', ['close', []])
endfunction

function! denops#_internal#server#chan#is_connected() abort
Expand All @@ -91,36 +106,56 @@ endfunction

function! s:connect(addr, options) abort
let s:closed_on_purpose = 0
let s:chan = s:rpcconnect(a:addr, {
\ 'on_close': { -> s:on_close(a:options) },
\})
let s:addr = a:addr
let s:options = a:options
let s:chan = s:rpcconnect(a:addr, {
\ 'on_close': { -> s:on_close() },
\})
call denops#_internal#echo#debug(printf('Channel connected (%s)', a:addr))
call s:rpcnotify(s:chan, 'void', [])
endfunction

function! s:on_close(options) abort
function! s:force_close(options) abort
let l:chan = s:chan
let s:chan = v:null
call s:clear_force_close_delayer()
call denops#_internal#echo#warn(printf(
\ 'Channel cannot close gracefully within %d millisec, force close (%s)',
\ a:options.timeout,
\ s:addr,
\))
call s:rpcclose(l:chan)
endfunction

function! s:clear_force_close_delayer() abort
if exists('s:force_close_delayer')
call timer_stop(s:force_close_delayer)
unlet s:force_close_delayer
endif
endfunction

function! s:on_close() abort
let s:chan = v:null
call s:clear_force_close_delayer()
call denops#_internal#echo#debug(printf('Channel closed (%s)', s:addr))
doautocmd <nomodeline> User DenopsClosed
if !a:options.reconnect_on_close || s:closed_on_purpose || s:exiting
if s:chan isnot# v:null || !s:options.reconnect_on_close || s:closed_on_purpose || s:exiting
return
endif
" Reconnect
if s:reconnect_guard(a:options)
if s:reconnect_guard()
return
endif
call denops#_internal#echo#warn('Channel closed. Reconnecting...')
call timer_start(
\ a:options.reconnect_delay,
\ s:options.reconnect_delay,
\ { -> denops#_internal#server#chan#connect(s:addr, s:options) },
\)
endfunction

function! s:reconnect_guard(options) abort
let l:reconnect_threshold = a:options.reconnect_threshold
let l:reconnect_interval = a:options.reconnect_interval
function! s:reconnect_guard() abort
let l:reconnect_threshold = s:options.reconnect_threshold
let l:reconnect_interval = s:options.reconnect_interval
let s:reconnect_count = get(s:, 'reconnect_count', 0) + 1
if s:reconnect_count >= l:reconnect_threshold
call denops#_internal#echo#warn(printf(
Expand Down
2 changes: 1 addition & 1 deletion autoload/denops/_internal/server/proc.vim
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ function! s:on_exit(options, status) abort
let s:job = v:null
call denops#_internal#echo#debug(printf('Server stopped: %s', a:status))
execute printf('doautocmd <nomodeline> User DenopsProcessStopped:%s', a:status)
if !a:options.restart_on_exit || s:stopped_on_purpose || s:exiting
if s:job isnot# v:null || !a:options.restart_on_exit || s:stopped_on_purpose || s:exiting
return
endif
" Restart
Expand Down
4 changes: 2 additions & 2 deletions autoload/denops/_internal/test.vim
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ if has('nvim')
endfunction
else
function! denops#_internal#test#notify(method, params) abort
return denops#_internal#rpc#vim#notify(g:denops_test_channel, a:method, a:params)
return denops#_internal#rpc#vim#notify(#{ _handle: g:denops_test_channel }, a:method, a:params)
endfunction

function! denops#_internal#test#request(method, params) abort
return denops#_internal#rpc#vim#request(g:denops_test_channel, a:method, a:params)
return denops#_internal#rpc#vim#request(#{ _handle: g:denops_test_channel }, a:method, a:params)
endfunction
endif
23 changes: 20 additions & 3 deletions autoload/denops/plugin.vim
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,21 @@ function! denops#plugin#register(name, ...) abort
return denops#plugin#load(a:name, l:script)
endfunction

function! denops#plugin#load(name, script) abort
function! denops#plugin#load(name, script, ...) abort
let l:script = denops#_internal#path#norm(a:script)
let l:args = [a:name, l:script]
let l:args = [a:name, l:script] + a:000
call denops#_internal#echo#debug(printf('load plugin: %s', l:args))
call denops#_internal#server#chan#notify('invoke', ['load', l:args])
endfunction

function! denops#plugin#reload(name) abort
function! denops#plugin#unload(name) abort
let l:args = [a:name]
call denops#_internal#echo#debug(printf('unload plugin: %s', l:args))
call denops#_internal#server#chan#notify('invoke', ['unload', l:args])
endfunction

function! denops#plugin#reload(name, ...) abort
let l:args = [a:name] + a:000
call denops#_internal#echo#debug(printf('reload plugin: %s', l:args))
call denops#_internal#server#chan#notify('invoke', ['reload', l:args])
endfunction
Expand Down Expand Up @@ -135,11 +141,22 @@ function! s:DenopsSystemPluginFail() abort
execute printf('doautocmd <nomodeline> User DenopsPluginFail:%s', l:plugin)
endfunction

function! s:teardown_settled(name) abort
let l:plugin = matchstr(expand('<amatch>'), ':\zs.*')
if has_key(s:loaded_plugins, l:plugin)
call remove(s:loaded_plugins, l:plugin)
endif
execute printf('doautocmd <nomodeline> User %s:%s', a:name, l:plugin)
endfunction

augroup denops_autoload_plugin_internal
autocmd!
autocmd User DenopsSystemPluginPre:* call s:relay_autocmd('DenopsPluginPre')
autocmd User DenopsSystemPluginPost:* ++nested call s:DenopsSystemPluginPost()
autocmd User DenopsSystemPluginFail:* call s:DenopsSystemPluginFail()
autocmd User DenopsSystemPluginUnloadPre:* call s:relay_autocmd('DenopsPluginUnloadPre')
autocmd User DenopsSystemPluginUnloadPost:* ++nested call s:teardown_settled('DenopsPluginUnloadPost')
autocmd User DenopsSystemPluginUnloadFail:* ++nested call s:teardown_settled('DenopsPluginUnloadFail')
autocmd User DenopsClosed let s:loaded_plugins = {}
augroup END

Expand Down
Loading