Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Channel is wired with call command #3852

Open
chemzqm opened this issue Jan 23, 2019 · 7 comments
Open

Channel is wired with call command #3852

chemzqm opened this issue Jan 23, 2019 · 7 comments

Comments

@chemzqm
Copy link

chemzqm commented Jan 23, 2019

Consider following code:

let s:activated = 0

function! s:getchar()
  let ch = getchar()
  return (type(ch) == 0 ? nr2char(ch) : ch)
endfunction

function! Start()
  let s:activated = 1
  while s:activated
    let ch = s:getchar()
    if ch ==# "\u26d4"
      break
    endif
    echo ch
  endwhile
  let s:activated = 0
endfunction

call timer_start(1000, {-> feedkeys("\u26d4", 'in')})

call Start()

It works as expected, vim could receive \u26d4 and exit the blocked while.

But when the call Start() is called from channel by send ['call', 'Start', []] to vim, vim couldn't receive \u26d4 any more.

One workaround is wrap the Start function with a timer, like:

function! MyStart()
  call timer_start(0, {-> Start()})
endfunction

And call this function from channel.

@mattn
Copy link
Member

mattn commented Feb 13, 2019

But when the call Start() is called from channel by send ['call', 'Start', []] to vim, vim couldn't receive \u26d4 any more.

Do you mean terminal-api ?

@chemzqm
Copy link
Author

chemzqm commented Feb 13, 2019

Not terminal, I mean start a channel by :call ch_open() and use call command like ["call", {func name}, {argument list}]

@mattn
Copy link
Member

mattn commented Feb 13, 2019

timer_start, ch_open, or job_start return timer, channel, job. Those return value must be hold with set to variable since it will be removed by GC.

let s:timer = timer_start(...)

@chemzqm
Copy link
Author

chemzqm commented Feb 14, 2019

It's not problem of GC, the function works as expected when I wrap it in timer_start, but doesn't work when I send ['call', 'Start', []] through channel.

@mattn
Copy link
Member

mattn commented Feb 14, 2019

Could you please provide code that does not work?

@chemzqm
Copy link
Author

chemzqm commented Feb 15, 2019

mini.vim:

set nocompatible
filetype plugin indent on
syntax on

let s:activated = 0
function! s:getchar()
  let ch = getchar()
  return (type(ch) == 0 ? nr2char(ch) : ch)
endfunction

function! Start()
  let s:activated = 1
  while s:activated
    let ch = s:getchar()
    if ch ==# "\u26d4"
      echom 'succeed'
      break
    endif
    echo ch
  endwhile
  let s:activated = 0
endfunction

call timer_start(1000, {-> feedkeys("\u26d4", 'in')})
" start node server
let file = expand('<sfile>:h').'/server.js'
let cmd = ['node', file]
let options = {
      \ 'noblock': 1,
      \ 'in_mode': 'json',
      \ 'out_mode': 'json',
      \ 'err_mode': 'nl',
      \ 'timeout': 3000,
      \}
let job = job_start(cmd, options)
let status = ch_status(job)
if status !=# 'open'
  echohl Error | echon 'Failed to server server' | echohl None
  finish
endif

"call Start()

server.js

function send(arr) {
  process.stdout.write(JSON.stringify(arr) + '\n')
}
send(['call', 'Start', []])

Save mini.vim and server.js in same folder, and run vim -u NORC and run :source mini.vim.
It would echo succeed if Start is called in vim script instead of send command by server.

@mattn
Copy link
Member

mattn commented Feb 15, 2019

Thanks provide code. I understand what is your problem. This is known behavior. You can not use getchar() or input() in callback on channel. You can do with making wrapper.

function send(arr) {
  process.stdout.write(JSON.stringify(arr) + '\n')
}
send(['call', 'FireStart', []])
set nocompatible
filetype plugin indent on
syntax on

let s:activated = 0
function! s:getchar()
  let ch = getchar(0)
  return (type(ch) == 0 ? nr2char(ch) : ch)
endfunction

function! FireStart()
  call timer_start(1, function('Start'))
endfunction

function! Start(...)
  let s:activated = 1
  while s:activated
    let ch = s:getchar()
    if ch ==# "\u26d4"
      echom 'succeed'
      break
    endif
    echo ch
    sleep 1m
  endwhile
  let s:activated = 0
endfunction

call timer_start(1000, {-> feedkeys("\u26d4", 'in')})
" start node server
let file = expand('<sfile>:h').'/server.js'
let cmd = ['node', file]
let options = {
      \ 'noblock': 1,
      \ 'in_mode': 'json',
      \ 'out_mode': 'json',
      \ 'err_mode': 'nl',
      \ 'timeout': 3000,
      \}
let job = job_start(cmd, options)
let status = ch_status(job)
if status !=# 'open'
  echohl Error | echon 'Failed to server server' | echohl None
  finish
endif

"call Start()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants