func (b *Batch) ExecLua(code string, result interface{}, args ...interface{}) {
	if args == nil {
		args = []interface{}{}
	}
	b.call("nvim_exec_lua", result, code, args)
}
ExecLua execute Lua code.

The code arg is Lua code to execute.

The args arg is arguments to the code.

Parameters (if any) are available as "..." inside the chunk. The chunk can return a value.
package nvim
import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"os/exec"
	"reflect"
	"strings"
	"sync"
	"syscall"
	"time"
	"github.com/neovim/go-client/msgpack"
	"github.com/neovim/go-client/msgpack/rpc"
)
var embedProcAttr *syscall.SysProcAttr
type Nvim struct {
	ep *rpc.Endpoint
	cmd         *exec.Cmd
	serveCh     chan error
	channelID   int
	channelIDMu sync.Mutex
	readMu sync.Mutex
}
func (v *Nvim) Serve() error {
	v.readMu.Lock()
	defer v.readMu.Unlock()
	return v.ep.Serve()
}
func (v *Nvim) startServe() {
	v.serveCh = make(chan error, 1)
	go func() {
		v.serveCh <- v.Serve()
		close(v.serveCh)
	}()
}
func (v *Nvim) Close() error {
	if v.cmd != nil && v.cmd.Process != nil {
		t := time.AfterFunc(10*time.Second, func() { v.cmd.Process.Kill() })
		defer t.Stop()
	}
	err := v.ep.Close()
	if v.cmd != nil {
		v.readMu.Lock()
		defer v.readMu.Unlock()
		errWait := v.cmd.Wait()
		if err == nil {
			err = errWait
		}
	}
	if v.serveCh != nil {
		var errServe error
		select {
		case errServe = <-v.serveCh:
		case <-time.After(10 * time.Second):
			errServe = errors.New("nvim: Serve did not exit")
		}
		if err == nil {
			err = errServe
		}
	}
	return err
}
func New(r io.Reader, w io.Writer, c io.Closer, logf func(string, ...interface{})) (*Nvim, error) {
	ep, err := rpc.NewEndpoint(r, w, c, rpc.WithLogf(logf), withExtensions())
	if err != nil {
		return nil, err
	}
	return &Nvim{ep: ep}, nil
}
type ChildProcessOption struct {
	f func(*childProcessOptions)
}
type childProcessOptions struct {
	ctx     context.Context
	logf    func(string, ...interface{})
	command string
	dir     string
	args    []string
	env     []string
	serve   bool
}
func ChildProcessArgs(args ...string) ChildProcessOption {
	return ChildProcessOption{func(cpos *childProcessOptions) {
		cpos.args = args
	}}
}
func ChildProcessCommand(command string) ChildProcessOption {
	return ChildProcessOption{func(cpos *childProcessOptions) {
		cpos.command = command
	}}
}
func ChildProcessContext(ctx context.Context) ChildProcessOption {
	return ChildProcessOption{func(cpos *childProcessOptions) {
		cpos.ctx = ctx
	}}
}
func ChildProcessDir(dir string) ChildProcessOption {
	return ChildProcessOption{func(cpos *childProcessOptions) {
		cpos.dir = dir
	}}
}
func ChildProcessEnv(env []string) ChildProcessOption {
	return ChildProcessOption{func(cpos *childProcessOptions) {
		cpos.env = env
	}}
}
func ChildProcessServe(serve bool) ChildProcessOption {
	return ChildProcessOption{func(cpos *childProcessOptions) {
		cpos.serve = serve
	}}
}
func ChildProcessLogf(logf func(string, ...interface{})) ChildProcessOption {
	return ChildProcessOption{func(cpos *childProcessOptions) {
		cpos.logf = logf
	}}
}
func NewChildProcess(options ...ChildProcessOption) (*Nvim, error) {
	cpos := &childProcessOptions{
		serve:   true,
		logf:    log.Printf,
		command: "nvim",
		ctx:     context.Background(),
	}
	for _, cpo := range options {
		cpo.f(cpos)
	}
	cmd := exec.CommandContext(cpos.ctx, cpos.command, cpos.args...)
	cmd.Env = cpos.env
	cmd.Dir = cpos.dir
	cmd.SysProcAttr = embedProcAttr
	inw, err := cmd.StdinPipe()
	if err != nil {
		return nil, err
	}
	outr, err := cmd.StdoutPipe()
	if err != nil {
		inw.Close()
		return nil, err
	}
	err = cmd.Start()
	if err != nil {
		return nil, err
	}
	v, _ := New(outr, inw, inw, cpos.logf)
	v.cmd = cmd
	if cpos.serve {
		v.startServe()
	}
	return v, nil
}
type EmbedOptions struct {
	Logf func(string, ...interface{})
	Dir string
	Path string
	Args []string
	Env []string
}
func NewEmbedded(options *EmbedOptions) (*Nvim, error) {
	if options == nil {
		options = &EmbedOptions{}
	}
	path := options.Path
	if path == "" {
		path = "nvim"
	}
	return NewChildProcess(
		ChildProcessArgs(append([]string{"--embed"}, options.Args...)...),
		ChildProcessCommand(path),
		ChildProcessEnv(options.Env),
		ChildProcessDir(options.Dir),
		ChildProcessServe(false))
}
type DialOption struct {
	f func(*dialOptions)
}
type dialOptions struct {
	ctx     context.Context
	logf    func(string, ...interface{})
	netDial func(ctx context.Context, network, address string) (net.Conn, error)
	serve   bool
}
func DialContext(ctx context.Context) DialOption {
	return DialOption{func(dos *dialOptions) {
		dos.ctx = ctx
	}}
}
func DialNetDial(f func(ctx context.Context, network, address string) (net.Conn, error)) DialOption {
	return DialOption{func(dos *dialOptions) {
		dos.netDial = f
	}}
}
func DialServe(serve bool) DialOption {
	return DialOption{func(dos *dialOptions) {
		dos.serve = serve
	}}
}
func DialLogf(logf func(string, ...interface{})) DialOption {
	return DialOption{func(dos *dialOptions) {
		dos.logf = logf
	}}
}
func Dial(address string, options ...DialOption) (*Nvim, error) {
	var d net.Dialer
	dos := &dialOptions{
		ctx:     context.Background(),
		logf:    log.Printf,
		netDial: d.DialContext,
		serve:   true,
	}
	for _, do := range options {
		do.f(dos)
	}
	network := "unix"
	if strings.Contains(address, ":") {
		network = "tcp"
	}
	c, err := dos.netDial(dos.ctx, network, address)
	if err != nil {
		return nil, err
	}
	v, err := New(c, c, c, dos.logf)
	if err != nil {
		c.Close()
		return nil, err
	}
	if dos.serve {
		v.startServe()
	}
	return v, err
}
func (v *Nvim) RegisterHandler(method string, fn interface{}) error {
	var args []interface{}
	t := reflect.TypeOf(fn)
	if t.Kind() == reflect.Func && t.NumIn() > 0 && t.In(0) == reflect.TypeOf(v) {
		args = append(args, v)
	}
	return v.ep.Register(method, fn, args...)
}
func (v *Nvim) ChannelID() int {
	v.channelIDMu.Lock()
	defer v.channelIDMu.Unlock()
	if v.channelID != 0 {
		return v.channelID
	}
	var info struct {
		ChannelID int         `msgpack:",array"`
		Info      interface{} `msgpack:"-"`
	}
	if err := v.ep.Call("nvim_get_api_info", &info); err != nil {
	}
	v.channelID = info.ChannelID
	return v.channelID
}
func (v *Nvim) call(sm string, result interface{}, args ...interface{}) error {
	return fixError(sm, v.ep.Call(sm, result, args...))
}
func (v *Nvim) NewBatch() *Batch {
	b := &Batch{ep: v.ep}
	b.enc = msgpack.NewEncoder(&b.buf)
	return b
}
type Batch struct {
	err     error
	ep      *rpc.Endpoint
	enc     *msgpack.Encoder
	sms     []string
	results []interface{}
	buf     bytes.Buffer
}
func (b *Batch) Execute() error {
	defer func() {
		b.buf.Reset()
		b.sms = b.sms[:0]
		b.results = b.results[:0]
		b.err = nil
	}()
	if b.err != nil {
		return b.err
	}
	result := struct {
		Results []interface{} `msgpack:",array"`
		Error   *struct {
			Index   int `msgpack:",array"`
			Type    int
			Message string
		}
	}{
		b.results,
		nil,
	}
	err := b.ep.Call("nvim_call_atomic", &result, &batchArg{n: len(b.sms), p: b.buf.Bytes()})
	if err != nil {
		return err
	}
	e := result.Error
	if e == nil {
		return nil
	}
	if e.Index < 0 || e.Index >= len(b.sms) ||
		(e.Type != exceptionError && e.Type != validationError) {
		return fmt.Errorf("nvim:nvim_call_atomic %d %d %s", e.Index, e.Type, e.Message)
	}
	errorType := "exception"
	if e.Type == validationError {
		errorType = "validation"
	}
	return &BatchError{
		Index: e.Index,
		Err:   fmt.Errorf("nvim:%s %s: %s", b.sms[e.Index], errorType, e.Message),
	}
}
var emptyArgs = []interface{}{}
func (b *Batch) call(sm string, result interface{}, args ...interface{}) {
	if b.err != nil {
		return
	}
	if args == nil {
		args = emptyArgs
	}
	b.sms = append(b.sms, sm)
	b.results = append(b.results, result)
	b.enc.PackArrayLen(2)
	b.enc.PackString(sm)
	b.err = b.enc.Encode(args)
}
type batchArg struct {
	n int
	p []byte
}
var _ msgpack.Marshaler = (*batchArg)(nil)
func (a *batchArg) MarshalMsgPack(enc *msgpack.Encoder) error {
	enc.PackArrayLen(int64(a.n))
	return enc.PackRaw(a.p)
}
type BatchError struct {
	Err error
	Index int
}
func (e *BatchError) Error() string {
	return e.Err.Error()
}
func fixError(sm string, err error) error {
	if e, ok := err.(rpc.Error); ok {
		if a, ok := e.Value.([]interface{}); ok && len(a) == 2 {
			switch a[0] {
			case int64(exceptionError), uint64(exceptionError):
				return fmt.Errorf("nvim:%s exception: %v", sm, a[1])
			case int64(validationError), uint64(validationError):
				return fmt.Errorf("nvim:%s validation: %v", sm, a[1])
			}
		}
	}
	return err
}
type ErrorList []error
func (el ErrorList) Error() string {
	return el[0].Error()
}
func (v *Nvim) Request(procedure string, result interface{}, args ...interface{}) error {
	return v.call(procedure, result, args...)
}
func (b *Batch) Request(procedure string, result interface{}, args ...interface{}) {
	b.call(procedure, result, args...)
}
func (v *Nvim) Call(fname string, result interface{}, args ...interface{}) error {
	if args == nil {
		args = []interface{}{}
	}
	return v.call("nvim_call_function", result, fname, args)
}
func (b *Batch) Call(fname string, result interface{}, args ...interface{}) {
	if args == nil {
		args = []interface{}{}
	}
	b.call("nvim_call_function", result, fname, args)
}
func (v *Nvim) CallDict(dict []interface{}, fname string, result interface{}, args ...interface{}) error {
	if args == nil {
		args = []interface{}{}
	}
	return v.call("nvim_call_dict_function", result, fname, dict, args)
}
func (b *Batch) CallDict(dict []interface{}, fname string, result interface{}, args ...interface{}) {
	if args == nil {
		args = []interface{}{}
	}
	b.call("nvim_call_dict_function", result, fname, dict, args)
}
func (v *Nvim) ExecLua(code string, result interface{}, args ...interface{}) error {
	if args == nil {
		args = []interface{}{}
	}
	return v.call("nvim_exec_lua", result, code, args)
}