neovim / node-client

Nvim Node.js client and plugin host
https://neovim.io/node-client/
MIT License
492 stars 53 forks source link

How to listen to suscribed events #181

Closed w-cantin closed 3 years ago

w-cantin commented 3 years ago

Hello,

How can a node client listen to events that were subscribed using the Neovim.subscribe(event) function from the main API? For example if one wanted to listen to BufEnter events it seems easy to write something like

nvimClient.subscribe("BufEnter") 

but since there are no callbacks or anything it is not clear what to do after. I have a seen a workaround using rpcnotify and nvimClient.on("notification", callbackFunction); shenanigans like in this vscode extension but the subscribe function seems to already solve the problem.

I also found this issue in the go client and it is quite similar to mine. Unfortunately the proposed solution did not really help.

Thank you

smolck commented 3 years ago

You should be able to do something like:

neovim.subscribe('some_notification_name')
neovim.on('notification', (method, args) => {
    switch (method) {
        case 'some_notification_name':
            console.log('got this notification!', args)
            break
        // Other notification handling . . .
     }
})

// Or this, although not 100% sure this works
neovim.subscribe('nvim_buf_detach_event')
neovim.on('nvim_buf_detach_event', (args) => /* do stuff */)

I do this in uivonim (a neovim GUI), see https://github.com/smolck/uivonim/blob/03cc2edb229c495a5180f7778dd026fbafe922e8/src/main/workers/neovim-api.ts#L253

w-cantin commented 3 years ago

The first method you proposed works fine and is actually quite similar to what the vscode neovim extension does too. The only issue with it is that I would prefer not having to play with autocommands and rpcnotify from the neovim process itself.

The second solution

neovim.subscribe('nvim_buf_detach_event')
neovim.on('nvim_buf_detach_event', (args) => /* do stuff */) 

is exactly what I have been trying to do (only for a different event) and unfortunately I can't make it work. Here is what a condensed version of the code I wrote looks like:

const cp = require('child_process');
const attach = require('neovim').attach;

const nvim_proc = cp.spawn('nvim', 
['-u', '~/.config/nvim/vscode-init.vim', '-n', '--embed', '-R',
'--headless' 
], {});

(async function() {
   const nvim = await attach({ proc: nvim_proc });

  await nvim.subscribe("nvim_text_changed_event")
  await nvim.on("nvim_text_changed_event", () => console.log(`event`))

  await nvim.command('edit test.py');
  await nvim.input("iline1<CR><Esc>")

  const currBuf = await nvim.buffer
  let lines = await (currBuf.lines)
  console.log(lines)

  await nvim.input("iline2 <CR><Esc>")
  lines = await (currBuf.lines)
  console.log(lines)
  nvim.quit();
})();

The output console looks like

['line1', '']
['line1', 'line2 ', '']

which means the file is getting modified in neovim properly. I also tried every combination of camelCase/snakecase/with nvim prefix/with _event suffix for event names. I tried for multiple events not just TextChanged but also bufEnter, bufAttach, buf_changedtick_event.

Thank you for your help. By the way your work on uivonim looks really interesting and I'll definitely keep an eye on it.

smolck commented 3 years ago

Okay so yeah, I wasn't convinced the second solution worked. But unless I'm wrong, I don't think this is a problem with node-client's API, but more to do with how the msgpack-rpc API and events work. Meaning that the only way to get an event for, say, when a buffer's text changes is to call an rpcnotify on BufWrite or similar and handle that. You have to do that setup yourself.

I could be wrong though; I'll ask about it on Matrix and see what the response is.

w-cantin commented 3 years ago

Whoa ok I just found another related issue this time for pynvim (I wished I found it earlier...) and I believe one of the core contributor to neovim said that the subscribe functions were useless. Here is his quote:

unfortunately subscribe/unsubscribe are mostly useless and unrelated to the vim "events" (autocommands). Instead see :help autocmd. work to improve this is neovim/neovim#11613 for example

That means using rpcnotify inside autocommands is definitely the way to go. Thank you very much for your help.