vimserver

Communicate with VIM channels via Node

Usage no npm install needed!

<script type="module">
  import vimserver from 'https://cdn.skypack.dev/vimserver';
</script>

README

VIM Server

Control and interact with VIM from Node using Javascript. Send/receive messages to/from VIM and control Vim with normal, ex, expr, and call commands. Requires VIM 8+

Install

npm i vimserver

Messaging

In Node

const VimServer = require('vimserver')
const { on, connect } = VimServer()

on('add-number', ({ send }, { num }) => send({ result: num + 1 }))

connect(9821)

In VIM

fun! Done(ch, response)
  echom "received from vim server: " . a:response.result
endfun

let ch = ch_open('localhost:9821')
call ch_sendexpr(ch, {'e': 'add-number', 'num': 4}, {'callback': 'Done'})

Executing the above prints the following message in VIM: received from vim server: 5

Control VIM

const VimServer = require('vimserver')
const { on, connect } = VimServer()

on('hack-vim', async ({ expr, normal, call }) => {
  // get number of lines in buffer
  const lineCount = await expr(`line('

)`)
  console.log(`total number of lines in buffer: ${lineCount}`)

  // delete entire buffer
  normal('ggVGd')

  // call a function in VIM with some arguments and get result
  const result = await call.RandomVimFunction(42, Date.now())
})

connect(9821)

API

connect(port, readyFn)

Start server on the following port. In Vim you can connect to the specified port with ch_open()

  • port integer - what port the server should listen on
  • readyFn function (optional) - callback function for when the server has started

on(event, callback)

Register a callback for the specified event

  • event string - name of event to listen to. In VIM you will need to send a dictionary with e key set to the event name. e.g. ch_sendexpr(ch, {'e': 'my-event-name', 'otherData': 66 })
  • callback function - callback function to be called whenever server receives data on event namespace. Callback function receives two arguments:
    • vim object - vim object. see 'vim object' below
    • data object|string|number|array - data received from VIM

Example:

on('my-event-name', (vim, data) => {
  console.log('received data from vim:', data)
  vim.send({ mood: 'happy' })
})

all(callback)

Register a callback that will be called for all messages

  • callback function - callback function to be called whenever server receives data on event namespace. Callback function receives two arguments:
    • vim object - vim object. see 'vim object' below
    • data object|string|number|array - data received from VIM

Example:

all((vim, data) => console.log('received data from vim:', data))

onError(callback)

Register a callback for server errors

  • callback function - register callback to be called whenever server throws an error

Vim object

The Vim object is passed along as the first parameter to on and all callback handlers. You can use the Vim object to send data back to Vim or execute channel commands. See :h channel-commands in Vim for more info.

send(data)

Function used to reply and send data back to Vim. The data will be sent to the callback specified in ch_sendexpr()

  • data object - data to send to Vim

redraw(force)

Redraw the screen. Vim does not automatically redraw the screen on some commands. This allows servers talking over channels to send multiple commands before redrawing. For example, opening a file vim.ex('e ~/stuff.txt') won't actually open the file until you also call vim.redraw()

  • force bool (optional) - clear the screen first

normal(command)

Execute a normal command in VIM

  • command string - equivalent to normal! in Vim

ex(command)

Execute an ex command in VIM

  • command string - commands... you know, like :e /project/myfile.txt

expr(expression)

Execute an expression in VIM and return the result via a Promise. Can be used with async/await or your favorite generator wrapper (tj/co maybe?)

  • expression string - expression to execute. If the expression fails or the encode/xmit from Vim fails, the catch handler of the Promise will be invoked

Example:

// promise
on('ello', vim => vim
  .expr(`line('

)`)
  .then(lines => console.log(lines)))

// async/await
on('ello', async vim => {
  const lines = await vim.expr(`line('

)`)
  console.log(lines)
})

call.

Execute a VIM function specified after the dot with the arguments and return the result via a Promise. Can be used with async/await or your favorite generator wrapper (tj/co maybe?). call. is powered by ES6 Proxies so any getter property invoked on call. will be used as the name of the Vim function.

Example:

// promise
on('ello', vim => vim
  .call.strlen('jedi')
  .then(length => console.log(length)))

// async/await
on('ello', async vim => {
  const length = await vim.call.strlen('sith')
  console.log(length)
})

// don't forget about destructuring!
on('ello', async ({ call }) => {
  const length = await call.strlen(data)
  console.log(length)
})

Contribute

Contributions welcome. Submit an issue or pull request :)