neovim

package module
v0.0.0-...-88b2531 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2014 License: MIT Imports: 10 Imported by: 0

README

neovim

Build Status

Go package for writing Neovim plugins

go get github.com/myitcv/neovim

This package is very much in alpha as the Neovim API itsef is still in flux. Therefore, expect changes to this API.

Writing plugins

A current, idiomatic example of a plugin written against neovim is neovim-go, a plugin that is designed to help support the editing of Go files.

A further example can be found here; this example demonstrates on-the-fly compiling of a Go file.

Supported platforms

At the time of writing this package has only been written for/tested against Linux.

Support welcomed on other platforms

Tests

Tests currently rely on the NEOVIM_LISTEN_ADDRESS environment variable being set

NEOVIM_LISTEN_ADDRESS=/tmp/neovim go test

Regenerating the API

First get the generator:

go get github.com/myitcv/neovim/_cmd/gen_neovim_api

The API generator relies on nvim being in your $PATH. Here are the various options:

$ ./gen_neovim_api -h
Usage: ./gen_neovim_api [-p] [-g] [-f filename]

  -c=false: custom print
  -f="": file containing the list of API functions to generate
  -g=false: generate code from the API
  -p=false: print the API

One of -p or -g must be supplied

If -g is supplied, -f may also be supplied to provide a list of functions to generate

The -g flag currently outputs to stdout; future work will provide a flag to have it place the generated, formatted source in $GOPATH as appropriate.

Credit

Todo list

  • Delete remote plugin-host branch
  • Neovim hooks up stdin and stdout back to front
  • Remove example_test.go - it is superseded by example and associated tests
  • Ensure that example gives examples (!) of testing API requests, handling requests and events
  • Consider using internal in Go 1.4 for better layout of package
  • Better definition of logging level-based interface for plugins
  • Stop using KillChannel in generated plugin-host; move to Tomb
  • Need some way for plugins to be loaded at startup...
  • Support Go package acting as a server, i.e. receiving requests from Neovim
  • Cleanly handle Neovim instances quitting - need to kill goroutines for reading, subscription manager etc
  • Need a test to confirm we have cleaned up all goroutines
  • Move from log.Fatal to something better....will work now that we have tomb
  • Tidy up use of PanicOnError and ensure all errors that would otherwise have been return use panic if this is set
  • Ensure tests panic if there is an error so we can see the stack
  • Add support for functions that CanFail
  • Get full test coverage; can we auto-generate certain basic tests?
  • Test on more platforms
  • Tidy up the API generator - it's very messy. Very messy
  • Make the API generator optionally write the generated file into the appropriate place in $GOPATH
  • Check our use of types; e.g. what does Integer in the API really map to? uint64?
  • Look into semantics of current decision to make certain channels buffered
  • Look at how we verify at runtime whether the Neovim instance to which we have connected exposes an API with which we (a calling client) was compiled. This handshake will probably need some work on the Neovim side (versioning of the API perhaps?). See comments in this thread
  • More benchmark tests for performance
  • Make notification decoding can be made more efficient (currently uses generic DecodeSlice)
  • Fix function and variable names (there are a few anomalies like Client.GetVvar)

Documentation

Overview

Package neovim implements support for writing Neovim plugins in Go. It also implements a tool for generating the MSGPACK-based API against a Neovim instance.

All API methods are supported, as are notifications. See Subscription for an example of how to register a subscription on a given topic.

Example Plugin

For an example plugin see http://godoc.org/github.com/myitcv/neovim/example

Client

Everything starts from Client:

_, err := neovim.NewUnixClient("unix", nil, &net.UnixAddr{Name: "/tmp/neovim"})
if err != nil {
	log.Fatalf("Could not create new Unix client: %v", errgo.Details(err))
}

See the examples for further usage patterns.

Concurrency

A single Client may safely be used by multiple goroutines. Calls to API methods are blocking by design.

Generating the API

See the github repo for details on re-generating the API.

Compatibility

There are currently no checks to verify a connected Neovim instance exposes the same API against which the neovim package was generated. This is future work (and probably needs some work on the Neovim side).

Errors

Errors returned by this package are created using errgo at http://godoc.org/github.com/juju/errgo. Hence errors may be inspected using functions like errgo.Details for example:

_, err := client.GetCurrentBuffer()
if err != nil {
	log.Fatalf("Could not get current buffer: %v", errgo.Details(err))
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Buffer

type Buffer struct {
	ID uint32
	// contains filtered or unexported fields
}

Buffer represents a Neovim Buffer

Multiple goroutines may invoke methods on a Buffer simultaneously

func (*Buffer) DelLine

func (b *Buffer) DelLine(index int) error

DelLine waiting for documentation from Neovim

func (*Buffer) GetLength

func (b *Buffer) GetLength() (int, error)

GetLength waiting for documentation from Neovim

func (*Buffer) GetLine

func (b *Buffer) GetLine(index int) (string, error)

GetLine waiting for documentation from Neovim

func (*Buffer) GetMark

func (b *Buffer) GetMark(name string) (uint32, error)

GetMark waiting for documentation from Neovim

func (*Buffer) GetName

func (b *Buffer) GetName() (string, error)

GetName waiting for documentation from Neovim

func (*Buffer) GetNumber

func (b *Buffer) GetNumber() (int, error)

GetNumber waiting for documentation from Neovim

func (*Buffer) GetOption

func (b *Buffer) GetOption(name string) (interface{}, error)

GetOption waiting for documentation from Neovim

func (*Buffer) GetSlice

func (b *Buffer) GetSlice(start int, end int, includeStart bool, includeEnd bool) ([]string, error)

GetSlice waiting for documentation from Neovim

func (*Buffer) GetVar

func (b *Buffer) GetVar(name string) (interface{}, error)

GetVar waiting for documentation from Neovim

func (*Buffer) Insert

func (b *Buffer) Insert(lnum int, lines []string) error

Insert waiting for documentation from Neovim

func (*Buffer) IsValid

func (b *Buffer) IsValid() (bool, error)

IsValid waiting for documentation from Neovim

func (*Buffer) SetLine

func (b *Buffer) SetLine(index int, line string) error

SetLine waiting for documentation from Neovim

func (*Buffer) SetName

func (b *Buffer) SetName(name string) error

SetName waiting for documentation from Neovim

func (*Buffer) SetOption

func (b *Buffer) SetOption(name string, value interface{}) error

SetOption waiting for documentation from Neovim

func (*Buffer) SetSlice

func (b *Buffer) SetSlice(start int, end int, includeStart bool, includeEnd bool, replacement []string) error

SetSlice waiting for documentation from Neovim

func (*Buffer) SetVar

func (b *Buffer) SetVar(name string, value interface{}) (interface{}, error)

SetVar waiting for documentation from Neovim

type Client

type Client struct {

	// PanicOnError can be set to have the Client panic when an error would
	// otherwise have been returned via an API method. Note: any attempt to
	// change this option during concurrent use of the Client will be racey.
	// This is useful for debugging.
	PanicOnError bool
	KillChannel  chan struct{}
	// contains filtered or unexported fields
}

A Client represents a connection to a single Neovim instance

func NewClient

func NewClient(c io.ReadWriteCloser, log Logger) (*Client, error)

NewClient creates a new Client

func NewCmdClient

func NewCmdClient(c *exec.Cmd, log Logger) (*Client, error)

NewCmdClient creates a new Client that is linked via stdin/stdout to the supplied exec.Cmd, which is assumed to launch Neovim. The Neovim flag --embedded-mode is added if it is missing, and the exec.Cmd is started as part of creating the client. Calling Close() will close stdin on the embedded Neovim instance, thereby ending the process

func NewUnixClient

func NewUnixClient(_net string, laddr, raddr *net.UnixAddr, log Logger) (*Client, error)

NewUnixClient is a convenience method for creating a new *Client. Method signature matches that of net.DialUnix

func (*Client) ChangeDirectory

func (c *Client) ChangeDirectory(dir string) error

ChangeDirectory waiting for documentation from Neovim

func (*Client) Close

func (c *Client) Close() error

Close cleanly kills the client connection to Neovim

func (*Client) Command

func (c *Client) Command(str string) error

Command waiting for documentation from Neovim

func (*Client) DelCurrentLine

func (c *Client) DelCurrentLine() error

DelCurrentLine waiting for documentation from Neovim

func (*Client) ErrWrite

func (c *Client) ErrWrite(str string) error

ErrWrite waiting for documentation from Neovim

func (*Client) Eval

func (c *Client) Eval(str string) (interface{}, error)

Eval waiting for documentation from Neovim

func (*Client) Feedkeys

func (c *Client) Feedkeys(keys string, mode string) error

Feedkeys waiting for documentation from Neovim

func (*Client) GetBuffers

func (c *Client) GetBuffers() ([]Buffer, error)

GetBuffers waiting for documentation from Neovim

func (*Client) GetCurrentBuffer

func (c *Client) GetCurrentBuffer() (Buffer, error)

GetCurrentBuffer waiting for documentation from Neovim

Example
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"

	"github.com/juju/errgo"
	"github.com/myitcv/neovim"
)

func main() {
	cmd := exec.Command(os.Getenv("NEOVIM_BIN"), "-u", "/dev/null")
	cmd.Dir = "/tmp"

	client, err := neovim.NewCmdClient(cmd, nil)
	if err != nil {
		log.Fatalf("Could not create new client: %v", errgo.Details(err))
	}
	b, err := client.GetCurrentBuffer()
	if err != nil {
		log.Fatalf("Could not get current buffer: %v", errgo.Details(err))
	}
	n, err := b.GetName()
	if err != nil {
		log.Fatalf("Could not get name for buffer %v: %v", b, errgo.Details(err))
	}
	fmt.Printf("Current buffer is: %v %v\n", b.ID, n)

	err = client.Close()
	if err != nil {
		log.Fatalf("Could not close client: %v\n", err)
	}

}
Output:

Current buffer is: 2

func (*Client) GetCurrentLine

func (c *Client) GetCurrentLine() (string, error)

GetCurrentLine waiting for documentation from Neovim

func (*Client) GetCurrentTabpage

func (c *Client) GetCurrentTabpage() (Tabpage, error)

GetCurrentTabpage waiting for documentation from Neovim

func (*Client) GetCurrentWindow

func (c *Client) GetCurrentWindow() (Window, error)

GetCurrentWindow waiting for documentation from Neovim

func (*Client) GetOption

func (c *Client) GetOption(name string) (interface{}, error)

GetOption waiting for documentation from Neovim

func (*Client) GetTabpages

func (c *Client) GetTabpages() ([]Tabpage, error)

GetTabpages waiting for documentation from Neovim

func (*Client) GetVar

func (c *Client) GetVar(name string) (interface{}, error)

GetVar waiting for documentation from Neovim

func (*Client) GetVvar

func (c *Client) GetVvar(name string) (interface{}, error)

GetVvar waiting for documentation from Neovim

func (*Client) GetWindows

func (c *Client) GetWindows() ([]Window, error)

GetWindows waiting for documentation from Neovim

func (*Client) ListRuntimePaths

func (c *Client) ListRuntimePaths() ([]string, error)

ListRuntimePaths waiting for documentation from Neovim

func (*Client) OutWrite

func (c *Client) OutWrite(str string) error

OutWrite waiting for documentation from Neovim

func (*Client) PushKeys

func (c *Client) PushKeys(str string) error

PushKeys waiting for documentation from Neovim

func (*Client) RegisterProvider

func (c *Client) RegisterProvider(m string, r RequestHandler) error

func (*Client) ReplaceTermcodes

func (c *Client) ReplaceTermcodes(str string, fromPart bool, doLt bool, special bool) (string, error)

ReplaceTermcodes waiting for documentation from Neovim

func (*Client) SetCurrentBuffer

func (c *Client) SetCurrentBuffer(buffer Buffer) error

SetCurrentBuffer waiting for documentation from Neovim

func (*Client) SetCurrentLine

func (c *Client) SetCurrentLine(line string) error

SetCurrentLine waiting for documentation from Neovim

func (*Client) SetCurrentTabpage

func (c *Client) SetCurrentTabpage(tabpage Tabpage) error

SetCurrentTabpage waiting for documentation from Neovim

func (*Client) SetCurrentWindow

func (c *Client) SetCurrentWindow(window Window) error

SetCurrentWindow waiting for documentation from Neovim

func (*Client) SetOption

func (c *Client) SetOption(name string, value interface{}) error

SetOption waiting for documentation from Neovim

func (*Client) SetVar

func (c *Client) SetVar(name string, value interface{}) (interface{}, error)

SetVar waiting for documentation from Neovim

func (*Client) Strwidth

func (c *Client) Strwidth(str string) (int, error)

Strwidth waiting for documentation from Neovim

func (*Client) Subscribe

func (c *Client) Subscribe(topic string) (*Subscription, error)

Subscribe subscribes to a topic of events from Neovim. The *Subscription.Events channel will receive SubscriptionEvent's Unsubscribe needs to be called on a different goroutine to the goroutine that handles these SubscriptionEvent's

func (*Client) Unsubscribe

func (c *Client) Unsubscribe(sub *Subscription) error

Unsubscribe unsubscribes from a topic of events from Neovim. This needs to be called on a different goroutine to that which is handling the SubscriptionEvent's

type Logger

type Logger interface {
	Fatal(v ...interface{})
	Fatalf(format string, v ...interface{})
	Fatalln(v ...interface{})
	Flags() int
	Output(calldepth int, s string) error
	Panic(v ...interface{})
	Panicf(format string, v ...interface{})
	Panicln(v ...interface{})
	Prefix() string
	Print(v ...interface{})
	Printf(format string, v ...interface{})
	Println(v ...interface{})
	SetFlags(flag int)
	SetPrefix(prefix string)
}

type Plugin

type Plugin interface {
	Init(*Client, Logger) error
	Shutdown() error
}

type RequestHandler

type RequestHandler func([]interface{}) ([]interface{}, error)

TODO we might modify this to return an encode instead but this would require exposing the enc on Client Needs some thought

type StdWrapper

type StdWrapper struct {
	Stdin  io.WriteCloser
	Stdout io.ReadCloser
}

func (*StdWrapper) Close

func (s *StdWrapper) Close() error

func (*StdWrapper) Read

func (s *StdWrapper) Read(p []byte) (n int, err error)

func (*StdWrapper) Write

func (s *StdWrapper) Write(p []byte) (n int, err error)

type Subscription

type Subscription struct {
	Topic  string
	Events chan *SubscriptionEvent
}

A Subscription represents a subscription to a Neovim event on a particular topic.

Example
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"

	"github.com/juju/errgo"
	"github.com/myitcv/neovim"
)

func main() {
	cmd := exec.Command(os.Getenv("NEOVIM_BIN"), "-u", "/dev/null")
	cmd.Dir = "/tmp"

	client, err := neovim.NewCmdClient(cmd, nil)
	if err != nil {
		log.Fatalf("Could not create new client: %v", errgo.Details(err))
	}
	client.PanicOnError = true

	topic := "topic1"
	sub, err := client.Subscribe(topic)
	if err != nil {
		log.Fatalf("Could not subscribe to topic %v, with respChan %v and errChan %v: %v", sub.Topic, sub, errgo.Details(err))
	}

	unsubbed := make(chan struct{})
	done := make(chan struct{})
	received := make(chan struct{})

	go func() {
	ForLoop:
		for {
			select {
			case e := <-sub.Events:
				if e == nil {
					break ForLoop
				}
				fmt.Printf("We got %v\n", e.Value)
				received <- struct{}{}
			}
		}
		done <- struct{}{}
	}()

	command := fmt.Sprintf(`call send_event(0, "%v", 1)`, topic)
	_ = client.Command(command)

	<-received

	go func() {

		_ = client.Unsubscribe(sub)
		unsubbed <- struct{}{}
	}()

	<-done

	<-unsubbed

	_ = client.Close()

}
Output:

We got [1]

type SubscriptionEvent

type SubscriptionEvent struct {
	Topic string
	Value []interface{}
}

A SubscriptionEvent contains the value Value announced via a notification on topic Topic

type Tabpage

type Tabpage struct {
	ID uint32
	// contains filtered or unexported fields
}

Tabpage represents a Neovim Tabpage

Multiple goroutines may invoke methods on a Tabpage simultaneously

func (*Tabpage) GetVar

func (t *Tabpage) GetVar(name string) (interface{}, error)

GetVar waiting for documentation from Neovim

func (*Tabpage) GetWindow

func (t *Tabpage) GetWindow() (Window, error)

GetWindow waiting for documentation from Neovim

func (*Tabpage) GetWindows

func (t *Tabpage) GetWindows() ([]Window, error)

GetWindows waiting for documentation from Neovim

func (*Tabpage) IsValid

func (t *Tabpage) IsValid() (bool, error)

IsValid waiting for documentation from Neovim

func (*Tabpage) SetVar

func (t *Tabpage) SetVar(name string, value interface{}) (interface{}, error)

SetVar waiting for documentation from Neovim

type Window

type Window struct {
	ID uint32
	// contains filtered or unexported fields
}

Window represents a Neovim Window

Multiple goroutines may invoke methods on a Window simultaneously

func (*Window) GetBuffer

func (w *Window) GetBuffer() (Buffer, error)

GetBuffer waiting for documentation from Neovim

func (*Window) GetCursor

func (w *Window) GetCursor() (uint32, error)

GetCursor waiting for documentation from Neovim

func (*Window) GetHeight

func (w *Window) GetHeight() (int, error)

GetHeight waiting for documentation from Neovim

func (*Window) GetOption

func (w *Window) GetOption(name string) (interface{}, error)

GetOption waiting for documentation from Neovim

func (*Window) GetPosition

func (w *Window) GetPosition() (uint32, error)

GetPosition waiting for documentation from Neovim

func (*Window) GetTabpage

func (w *Window) GetTabpage() (Tabpage, error)

GetTabpage waiting for documentation from Neovim

func (*Window) GetVar

func (w *Window) GetVar(name string) (interface{}, error)

GetVar waiting for documentation from Neovim

func (*Window) GetWidth

func (w *Window) GetWidth() (int, error)

GetWidth waiting for documentation from Neovim

func (*Window) IsValid

func (w *Window) IsValid() (bool, error)

IsValid waiting for documentation from Neovim

func (*Window) SetCursor

func (w *Window) SetCursor(pos uint32) error

SetCursor waiting for documentation from Neovim

func (*Window) SetHeight

func (w *Window) SetHeight(height int) error

SetHeight waiting for documentation from Neovim

func (*Window) SetOption

func (w *Window) SetOption(name string, value interface{}) error

SetOption waiting for documentation from Neovim

func (*Window) SetVar

func (w *Window) SetVar(name string, value interface{}) (interface{}, error)

SetVar waiting for documentation from Neovim

func (*Window) SetWidth

func (w *Window) SetWidth(width int) error

SetWidth waiting for documentation from Neovim

Directories

Path Synopsis
_cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL