[Python-modules-commits] [python-neovim] 01/04: Import python-neovim_0.1.7.orig.tar.gz
Víctor Cuadrado Juan
viccuad-guest at moszumanska.debian.org
Wed Apr 20 14:14:32 UTC 2016
This is an automated email from the git hooks/post-receive script.
viccuad-guest pushed a commit to branch master
in repository python-neovim.
commit f729dd943f0eee2e1133614c74683250704426a9
Author: Víctor Cuadrado Juan <me at viccuad.me>
Date: Wed Apr 20 12:57:17 2016 +0200
Import python-neovim_0.1.7.orig.tar.gz
---
PKG-INFO | 4 +-
README.md | 59 ++++++++++--
neovim.egg-info/PKG-INFO | 4 +-
neovim/__init__.py | 22 +++--
neovim/api/__init__.py | 6 +-
neovim/api/buffer.py | 54 +++++------
neovim/api/common.py | 187 ++++++++++---------------------------
neovim/api/nvim.py | 211 ++++++++++++++++++++++++++++--------------
neovim/api/tabpage.py | 20 ++--
neovim/api/window.py | 37 +++-----
neovim/msgpack_rpc/session.py | 6 +-
neovim/plugin/__init__.py | 6 +-
neovim/plugin/decorators.py | 17 +++-
neovim/plugin/host.py | 82 ++++++++--------
neovim/plugin/script_host.py | 38 +++-----
setup.py | 4 +-
test/test_buffer.py | 10 ++
test/test_client_rpc.py | 16 ++--
test/test_common.py | 16 ++--
test/test_concurrency.py | 18 ++--
test/test_events.py | 12 +--
test/test_vim.py | 6 ++
22 files changed, 425 insertions(+), 410 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index 46a580d..defd180 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,11 +1,11 @@
Metadata-Version: 1.1
Name: neovim
-Version: 0.1.5
+Version: 0.1.7
Summary: Python client to neovim
Home-page: http://github.com/neovim/python-client
Author: Thiago de Arruda
Author-email: tpadilha84 at gmail.com
License: Apache
-Download-URL: https://github.com/neovim/python-client/archive/0.1.5.tar.gz
+Download-URL: https://github.com/neovim/python-client/archive/0.1.7.tar.gz
Description: UNKNOWN
Platform: UNKNOWN
diff --git a/README.md b/README.md
index 14f00a4..ce07b07 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,27 @@ connecting to and scripting Nvim processes through its msgpack-rpc API.
#### Installation
```sh
-pip install neovim
+pip2 install neovim
+pip3 install neovim
```
-You can install the package without being root by adding the `--user` flag. You
-can use `pip2` and `pip3` to explicitly install for python2 and python3,
-respectively.
+If you only use one of python2 or python3, it is enough to install that
+version. You can install the package without being root by adding the `--user`
+flag.
+
+If you follow Neovim master, make sure to upgrade the python-client when you
+upgrade neovim:
+```sh
+pip2 install --upgrade neovim
+pip3 install --upgrade neovim
+```
+
+Alternatively, the master version could be installed by executing the following
+in the root of this repository:
+```sh
+pip2 install .
+pip3 install .
+```
#### Python Plugin API
@@ -84,12 +99,18 @@ to have effect. For details see `:help remote-plugin` in nvim.
#### Development
-Install the master version by cloning this repository and in the root directory
-execute
-
+If you change the code, you need to run
```sh
-pip install .
+pip2 install .
+pip3 install .
+```
+for the changes to have effect. Alternatively you could execute neovim
+with the `$PYTHONPATH` environment variable
+```
+PYTHONPATH=/path/to/python-client nvim
```
+But note this is not completely reliable as installed packages can appear before
+`$PYTHONPATH` in the python search path.
You need to rerun this command if you have changed the code, in order for nvim
to use it for the plugin host.
@@ -97,10 +118,16 @@ to use it for the plugin host.
To run the tests execute
```sh
-NVIM_CHILD_ARGV='["nvim", "-u", "NONE", "--embed"]' nosetests
+nosetests
```
-Alternatively, if you want to see the state of nvim, you could
+This will run the tests in an embedded instance of nvim.
+If you want to test a different version than `nvim` in `$PATH` use
+```sh
+NVIM_CHILD_ARGV='["/path/to/nvim", "-u", "NONE", "--embed"]' nosetests
+```
+
+Alternatively, if you want to see the state of nvim, you could use
```sh
export NVIM_LISTEN_ADDRESS=/tmp/nvimtest
@@ -111,6 +138,18 @@ nosetests
But note you need to restart nvim every time you run the tests! Substitute your
favorite terminal emulator for `xterm`.
+#### Troubleshooting
+
+You can run the plugin host in nvim with logging enabled to debug errors:
+```
+NVIM_PYTHON_LOG_FILE=logfile NVIM_PYTHON_LOG_LEVEL=DEBUG nvim
+```
+As more than one python host process might be started, the log filenames take
+the pattern `logfile_PID` where `PID` is the process id.
+
+If the host cannot start at all, the error could be found in `~/.nvimlog` if
+`nvim` was compiled with logging.
+
#### Usage through the python REPL
A number of different transports are supported, but the simplest way to get
diff --git a/neovim.egg-info/PKG-INFO b/neovim.egg-info/PKG-INFO
index 46a580d..defd180 100644
--- a/neovim.egg-info/PKG-INFO
+++ b/neovim.egg-info/PKG-INFO
@@ -1,11 +1,11 @@
Metadata-Version: 1.1
Name: neovim
-Version: 0.1.5
+Version: 0.1.7
Summary: Python client to neovim
Home-page: http://github.com/neovim/python-client
Author: Thiago de Arruda
Author-email: tpadilha84 at gmail.com
License: Apache
-Download-URL: https://github.com/neovim/python-client/archive/0.1.5.tar.gz
+Download-URL: https://github.com/neovim/python-client/archive/0.1.7.tar.gz
Description: UNKNOWN
Platform: UNKNOWN
diff --git a/neovim/__init__.py b/neovim/__init__.py
index 6fea713..15c7b16 100644
--- a/neovim/__init__.py
+++ b/neovim/__init__.py
@@ -6,18 +6,18 @@ import logging
import os
import sys
-from .api import DecodeHook, Nvim, SessionHook
+from .api import Nvim
+from .compat import IS_PYTHON3
from .msgpack_rpc import (ErrorResponse, child_session, socket_session,
stdio_session, tcp_session)
-from .plugin import (Host, autocmd, command, encoding, function, plugin,
- rpc_export, shutdown_hook)
+from .plugin import (Host, autocmd, command, decode, encoding, function,
+ plugin, rpc_export, shutdown_hook)
__all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session',
- 'start_host', 'autocmd', 'command', 'encoding', 'function',
- 'plugin', 'rpc_export', 'Host', 'DecodeHook', 'Nvim',
- 'SessionHook', 'shutdown_hook', 'attach', 'setup_logging',
- 'ErrorResponse')
+ 'start_host', 'autocmd', 'command', 'encoding', 'decode',
+ 'function', 'plugin', 'rpc_export', 'Host', 'Nvim',
+ 'shutdown_hook', 'attach', 'setup_logging', 'ErrorResponse')
def start_host(session=None):
@@ -64,7 +64,8 @@ def start_host(session=None):
host.start(plugins)
-def attach(session_type, address=None, port=None, path=None, argv=None):
+def attach(session_type, address=None, port=None,
+ path=None, argv=None, decode=None):
"""Provide a nicer interface to create python api sessions.
Previous machinery to create python api sessions is still there. This only
@@ -90,7 +91,10 @@ def attach(session_type, address=None, port=None, path=None, argv=None):
if not session:
raise Exception('Unknown session type "%s"' % session_type)
- return Nvim.from_session(session)
+ if decode is None:
+ decode = IS_PYTHON3
+
+ return Nvim.from_session(session).with_decode(decode)
def setup_logging():
diff --git a/neovim/api/__init__.py b/neovim/api/__init__.py
index 10f2147..7feb889 100644
--- a/neovim/api/__init__.py
+++ b/neovim/api/__init__.py
@@ -5,11 +5,11 @@ instances.
"""
from .buffer import Buffer
-from .common import DecodeHook, SessionHook
+from .common import decode_if_bytes, walk
from .nvim import Nvim, NvimError
from .tabpage import Tabpage
from .window import Window
-__all__ = ('Nvim', 'Buffer', 'Window', 'Tabpage', 'NvimError', 'SessionHook',
- 'DecodeHook')
+__all__ = ('Nvim', 'Buffer', 'Window', 'Tabpage', 'NvimError',
+ 'decode_if_bytes', 'walk')
diff --git a/neovim/api/buffer.py b/neovim/api/buffer.py
index d90280e..ab90b74 100644
--- a/neovim/api/buffer.py
+++ b/neovim/api/buffer.py
@@ -1,5 +1,5 @@
"""API for working with Nvim buffers."""
-from .common import Remote, RemoteMap
+from .common import Remote
from ..compat import IS_PYTHON3
@@ -14,22 +14,11 @@ class Buffer(Remote):
"""A remote Nvim buffer."""
- def __init__(self, session, code_data):
- """Initialize from session and code_data immutable object.
-
- The `code_data` contains serialization information required for
- msgpack-rpc calls. It must be immutable for Buffer equality to work.
- """
- self._session = session
- self.code_data = code_data
- self.vars = RemoteMap(session, 'buffer_get_var', 'buffer_set_var',
- self)
- self.options = RemoteMap(session, 'buffer_get_option',
- 'buffer_set_option', self)
+ _api_prefix = "buffer_"
def __len__(self):
"""Return the number of lines contained in a Buffer."""
- return self._session.request('buffer_line_count', self)
+ return self.request('buffer_line_count')
def __getitem__(self, idx):
"""Get a buffer line or slice by integer index.
@@ -121,7 +110,7 @@ class Buffer(Remote):
def mark(self, name):
"""Return (row, col) tuple for a named mark."""
- return self._session.request('buffer_get_mark', self, name)
+ return self.request('buffer_get_mark', name)
def range(self, start, end):
"""Return a `Range` object, which represents part of the Buffer."""
@@ -132,44 +121,43 @@ class Buffer(Remote):
"""Add a highlight to the buffer."""
if async is None:
async = (src_id != 0)
- return self._session.request('buffer_add_highlight', self, src_id,
- hl_group, line, col_start,
- col_end, async=async)
+ return self.request('buffer_add_highlight', src_id, hl_group,
+ line, col_start, col_end, async=async)
def clear_highlight(self, src_id, line_start=0, line_end=-1, async=True):
"""clear highlights from the buffer."""
- self._session.request('buffer_clear_highlight', self, src_id,
- line_start, line_end, async=async)
+ self.request('buffer_clear_highlight', src_id,
+ line_start, line_end, async=async)
@property
def name(self):
"""Get the buffer name."""
- return self._session.request('buffer_get_name', self)
+ return self.request('buffer_get_name')
@name.setter
def name(self, value):
"""Set the buffer name. BufFilePre/BufFilePost are triggered."""
- return self._session.request('buffer_set_name', self, value)
+ return self.request('buffer_set_name', value)
@property
def valid(self):
"""Return True if the buffer still exists."""
- return self._session.request('buffer_is_valid', self)
+ return self.request('buffer_is_valid')
@property
def number(self):
"""Get the buffer number."""
- return self._session.request('buffer_get_number', self)
+ return self.request('buffer_get_number')
class Range(object):
def __init__(self, buffer, start, end):
self._buffer = buffer
self.start = start - 1
- self.end = end
+ self.end = end - 1
def __len__(self):
- return self.end - self.start
+ return self.end - self.start + 1
def __getitem__(self, idx):
if not isinstance(idx, slice):
@@ -179,7 +167,7 @@ class Range(object):
if start is None:
start = self.start
if end is None:
- end = self.end
+ end = self.end + 1
return self._buffer[start:end]
def __setitem__(self, idx, lines):
@@ -191,26 +179,26 @@ class Range(object):
if start is None:
start = self.start
if end is None:
- end = self.end
+ end = self.end + 1
self._buffer[start:end] = lines
def __iter__(self):
- for i in range(self.start, self.end):
+ for i in range(self.start, self.end + 1):
yield self._buffer[i]
def append(self, lines, i=None):
i = self._normalize_index(i)
if i is None:
- i = self.end
+ i = self.end + 1
self._buffer.append(lines, i)
def _normalize_index(self, index):
if index is None:
return None
if index < 0:
- index = self.end - 1
+ index = self.end
else:
index += self.start
- if index >= self.end:
- index = self.end - 1
+ if index > self.end:
+ index = self.end
return index
diff --git a/neovim/api/common.py b/neovim/api/common.py
index 3a456e3..eb7da90 100644
--- a/neovim/api/common.py
+++ b/neovim/api/common.py
@@ -1,4 +1,5 @@
"""Code shared between the API classes."""
+import functools
class Remote(object):
@@ -10,6 +11,20 @@ class Remote(object):
object handle into consideration.
"""
+ def __init__(self, session, code_data):
+ """Initialize from session and code_data immutable object.
+
+ The `code_data` contains serialization information required for
+ msgpack-rpc calls. It must be immutable for Buffer equality to work.
+ """
+ self._session = session
+ self.code_data = code_data
+ self.api = RemoteApi(self, self._api_prefix)
+ self.vars = RemoteMap(self, self._api_prefix + 'get_var',
+ self._api_prefix + 'set_var')
+ self.options = RemoteMap(self, self._api_prefix + 'get_option',
+ self._api_prefix + 'set_option')
+
def __eq__(self, other):
"""Return True if `self` and `other` are the same object."""
return (hasattr(other, 'code_data') and
@@ -19,6 +34,24 @@ class Remote(object):
"""Return hash based on remote object id."""
return self.code_data.__hash__()
+ def request(self, name, *args, **kwargs):
+ """Wrapper for nvim.request."""
+ return self._session.request(name, self, *args, **kwargs)
+
+
+class RemoteApi(object):
+
+ """Wrapper to allow api methods to be called like python methods."""
+
+ def __init__(self, obj, api_prefix):
+ """Initialize a RemoteApi with object and api prefix."""
+ self._obj = obj
+ self._api_prefix = api_prefix
+
+ def __getattr__(self, name):
+ """Return wrapper to named api method."""
+ return functools.partial(self._obj.request, self._api_prefix + name)
+
class RemoteMap(object):
@@ -31,12 +64,12 @@ class RemoteMap(object):
It is used to provide a dict-like API to vim variables and options.
"""
- def __init__(self, session, get_method, set_method, self_obj=None):
+ def __init__(self, obj, get_method, set_method=None, self_obj=None):
"""Initialize a RemoteMap with session, getter/setter and self_obj."""
- self._get = _wrap(session, get_method, self_obj)
+ self._get = functools.partial(obj.request, get_method)
self._set = None
if set_method:
- self._set = _wrap(session, set_method, self_obj)
+ self._set = functools.partial(obj.request, set_method)
def __getitem__(self, key):
"""Return a map value by key."""
@@ -91,9 +124,9 @@ class RemoteSequence(object):
locally(iteration, indexing, counting, etc).
"""
- def __init__(self, session, method, self_obj=None):
+ def __init__(self, session, method):
"""Initialize a RemoteSequence with session, method and self_obj."""
- self._fetch = _wrap(session, method, self_obj)
+ self._fetch = functools.partial(session.request, method)
def __len__(self):
"""Return the length of the remote sequence."""
@@ -120,146 +153,20 @@ def _identity(obj, session, method, kind):
return obj
-class SessionHook(object):
-
- """Pair of functions to filter objects coming/going from/to Nvim.
-
- Filter functions receive the following arguments:
-
- - obj: The object to process
- - session: The current session object
- - method: The method name
- - kind: Kind of filter, can be one of:
- - 'request' for requests coming from Nvim
- - 'notification' for notifications coming from Nvim
- - 'out-request' for requests going to Nvim
-
- Whatever is returned from the function is used as a replacement for `obj`.
-
- This class also provides a `compose` method for composing hooks.
- """
-
- def __init__(self, from_nvim=_identity, to_nvim=_identity):
- """Initialize a SessionHook with from/to filters."""
- self.from_nvim = from_nvim
- self.to_nvim = to_nvim
-
- def compose(self, other):
- """Compose two SessionHook instances.
-
- This works by composing the individual from/to filters and creating
- a new SessionHook instance with the composed filters.
- """
- def comp(f1, f2):
- if f1 is _identity:
- return f2
- if f2 is _identity:
- return f1
- return lambda o, s, m, k: f1(f2(o, s, m, k), s, m, k)
-
- return SessionHook(comp(other.from_nvim, self.from_nvim),
- comp(other.to_nvim, self.to_nvim))
-
-
-class DecodeHook(SessionHook):
-
- """SessionHook subclass that decodes utf-8 strings coming from Nvim.
-
- This class is useful for python3, where strings are now unicode by
- default(byte strings need to be prefixed with "b").
- """
-
- def __init__(self, encoding='utf-8', encoding_errors='strict'):
- """Initialize with encoding and encoding errors policy."""
- self.encoding = encoding
- self.encoding_errors = encoding_errors
- super(DecodeHook, self).__init__(from_nvim=self._decode_if_bytes)
-
- def _decode_if_bytes(self, obj, session, method, kind):
- if isinstance(obj, bytes):
- return obj.decode(self.encoding, errors=self.encoding_errors)
- return obj
-
- def walk(self, obj):
- """Decode bytes found in obj (any msgpack object).
-
- Uses encoding and policy specified in constructor.
- """
- return walk(self._decode_if_bytes, obj, None, None, None)
-
-
-class SessionFilter(object):
-
- """Wraps a session-like object with a SessionHook instance.
-
- This class can be used as a drop-in replacement for a sessions, the
- difference is that a hook is applied to all data passing through a
- SessionFilter instance.
- """
-
- def __init__(self, session, hook):
- """Initialize with a Session(or SessionFilter) and a hook.
-
- If `session` is already a SessionFilter, it's hook will be extracted
- and composed with `hook`.
- """
- if isinstance(session, SessionFilter):
- self._hook = session._hook.compose(hook)
- self._session = session._session
- else:
- self._hook = hook
- self._session = session
- # Both filters are applied to `walk` so objects are transformed
- # recursively
- self._in = self._hook.from_nvim
- self._out = self._hook.to_nvim
-
- def threadsafe_call(self, fn, *args, **kwargs):
- """Wrapper for Session.threadsafe_call."""
- self._session.threadsafe_call(fn, *args, **kwargs)
-
- def next_message(self):
- """Wrapper for Session.next_message."""
- msg = self._session.next_message()
- if msg:
- return walk(self._in, msg, self, msg[1], msg[0])
-
- def request(self, name, *args, **kwargs):
- """Wrapper for Session.request."""
- args = walk(self._out, args, self, name, 'out-request')
- return walk(self._in, self._session.request(name, *args, **kwargs),
- self, name, 'out-request')
-
- def run(self, request_cb, notification_cb, setup_cb=None):
- """Wrapper for Session.run."""
- def filter_request_cb(name, args):
- result = request_cb(self._in(name, self, name, 'request'),
- walk(self._in, args, self, name, 'request'))
- return walk(self._out, result, self, name, 'request')
-
- def filter_notification_cb(name, args):
- notification_cb(self._in(name, self, name, 'notification'),
- walk(self._in, args, self, name, 'notification'))
-
- self._session.run(filter_request_cb, filter_notification_cb, setup_cb)
-
- def stop(self):
- """Wrapper for Session.stop."""
- self._session.stop()
+def decode_if_bytes(obj, mode=True):
+ """Decode obj if it is bytes."""
+ if mode is True:
+ mode = "strict"
+ if isinstance(obj, bytes):
+ return obj.decode("utf-8", errors=mode)
+ return obj
-def walk(fn, obj, *args):
+def walk(fn, obj, *args, **kwargs):
"""Recursively walk an object graph applying `fn`/`args` to objects."""
if type(obj) in [list, tuple]:
return list(walk(fn, o, *args) for o in obj)
if type(obj) is dict:
return dict((walk(fn, k, *args), walk(fn, v, *args)) for k, v in
obj.items())
- return fn(obj, *args)
-
-
-def _wrap(session, method, self_obj):
- if self_obj is not None:
- return lambda *args: session.request(method, self_obj, *args)
- else:
- return lambda *args: session.request(method, *args)
+ return fn(obj, *args, **kwargs)
diff --git a/neovim/api/nvim.py b/neovim/api/nvim.py
index 9650f31..2b68407 100644
--- a/neovim/api/nvim.py
+++ b/neovim/api/nvim.py
@@ -1,14 +1,15 @@
"""Main Nvim interface."""
import functools
import os
+import sys
from traceback import format_exc, format_stack
from msgpack import ExtType
from .buffer import Buffer
-from .common import (DecodeHook, Remote, RemoteMap, RemoteSequence,
- SessionFilter, SessionHook, walk)
+from .common import (Remote, RemoteApi, RemoteMap, RemoteSequence,
+ decode_if_bytes, walk)
from .tabpage import Tabpage
from .window import Window
from ..compat import IS_PYTHON3
@@ -24,7 +25,7 @@ class Nvim(object):
"""Class that represents a remote Nvim instance.
- This class is main entry point to Nvim remote API, it is a thin wrapper
+ This class is main entry point to Nvim remote API, it is a wrapper
around Session instances.
The constructor of this class must not be called directly. Instead, the
@@ -32,9 +33,10 @@ class Nvim(object):
from a raw `Session` instance.
Subsequent instances for the same session can be created by calling the
- `with_hook` instance method and passing a SessionHook instance. This can
- be useful to have multiple `Nvim` objects that behave differently without
- one affecting the other.
+ `with_decode` instance method to change the decoding behavior or
+ `SubClass.from_nvim(nvim)` where `SubClass` is a subclass of `Nvim`, which
+ is useful for having multiple `Nvim` objects that behave differently
+ without one affecting the other.
"""
@classmethod
@@ -49,9 +51,8 @@ class Nvim(object):
channel_id, metadata = session.request(b'vim_get_api_info')
if IS_PYTHON3:
- hook = DecodeHook()
# decode all metadata strings for python3
- metadata = walk(hook.from_nvim, metadata, None, None, None)
+ metadata = walk(decode_if_bytes, metadata)
types = {
metadata['types']['Buffer']['id']: Buffer,
@@ -59,32 +60,114 @@ class Nvim(object):
metadata['types']['Tabpage']['id']: Tabpage,
}
- return cls(session, channel_id, metadata).with_hook(ExtHook(types))
+ return cls(session, channel_id, metadata, types)
- def __init__(self, session, channel_id, metadata):
+ @classmethod
+ def from_nvim(cls, nvim):
+ """Create a new Nvim instance from an existing instance."""
+ return cls(nvim._session, nvim.channel_id, nvim.metadata,
+ nvim.types, nvim._decode, nvim._err_cb)
+
+ def __init__(self, session, channel_id, metadata, types,
+ decode=False, err_cb=None):
"""Initialize a new Nvim instance. This method is module-private."""
self._session = session
self.channel_id = channel_id
self.metadata = metadata
- self.vars = RemoteMap(session, 'vim_get_var', 'vim_set_var')
- self.vvars = RemoteMap(session, 'vim_get_vvar', None)
- self.options = RemoteMap(session, 'vim_get_option', 'vim_set_option')
- self.buffers = RemoteSequence(session, 'vim_get_buffers')
- self.windows = RemoteSequence(session, 'vim_get_windows')
- self.tabpages = RemoteSequence(session, 'vim_get_tabpages')
- self.current = Current(session)
+ self.types = types
+ self.api = RemoteApi(self, 'vim_')
+ self.vars = RemoteMap(self, 'vim_get_var', 'vim_set_var')
+ self.vvars = RemoteMap(self, 'vim_get_vvar', None)
+ self.options = RemoteMap(self, 'vim_get_option', 'vim_set_option')
+ self.buffers = RemoteSequence(self, 'vim_get_buffers')
+ self.windows = RemoteSequence(self, 'vim_get_windows')
+ self.tabpages = RemoteSequence(self, 'vim_get_tabpages')
+ self.current = Current(self)
+ self.session = CompatibilitySession(self)
self.funcs = Funcs(self)
self.error = NvimError
+ self._decode = decode
+ self._err_cb = err_cb
- def with_hook(self, hook):
- """Initialize a new Nvim instance."""
- return Nvim(SessionFilter(self.session, hook), self.channel_id,
- self.metadata)
+ def _from_nvim(self, obj, decode=None):
+ if decode is None:
+ decode = self._decode
+ if type(obj) is ExtType:
+ cls = self.types[obj.code]
+ return cls(self, (obj.code, obj.data))
+ if decode:
+ obj = decode_if_bytes(obj, decode)
+ return obj
- @property
- def session(self):
- """Return the Session or SessionFilter for a Nvim instance."""
- return self._session
+ def _to_nvim(self, obj):
+ if isinstance(obj, Remote):
+ return ExtType(*obj.code_data)
+ return obj
+
+ def request(self, name, *args, **kwargs):
+ r"""Send an API request or notification to nvim.
+
+ It is rarely needed to call this function directly, as most API
+ functions have python wrapper functions. The `api` object can
+ be also be used to call API functions as methods:
+
+ vim.api.err_write('ERROR\n', async=True)
+ vim.current.buffer.api.get_mark('.')
+
+ is equivalent to
+
+ vim.request('vim_err_write', 'ERROR\n', async=True)
+ vim.request('buffer_get_mark', vim.current.buffer, '.')
+
+
+ Normally a blocking request will be sent. If the `async` flag is
+ present and True, a asynchronous notification is sent instead. This
+ will never block, and the return value or error is ignored.
+ """
+ decode = kwargs.pop('decode', self._decode)
+ args = walk(self._to_nvim, args)
+ res = self._session.request(name, *args, **kwargs)
+ return walk(self._from_nvim, res, decode=decode)
+
+ def next_message(self):
+ """Block until a message(request or notification) is available.
+
+ If any messages were previously enqueued, return the first in queue.
+ If not, run the event loop until one is received.
+ """
+ msg = self._session.next_message()
+ if msg:
+ return walk(self._from_nvim, msg)
+
+ def run_loop(self, request_cb, notification_cb,
+ setup_cb=None, err_cb=None):
+ """Run the event loop to receive requests and notifications from Nvim.
+
+ This should not be called from a plugin running in the host, which
+ already runs the loop and dispatches events to plugins.
+ """
+ def filter_request_cb(name, args):
+ args = walk(self._from_nvim, args)
+ result = request_cb(self._from_nvim(name), args)
+ return walk(self._to_nvim, result)
+
+ def filter_notification_cb(name, args):
+ notification_cb(self._from_nvim(name), walk(self._from_nvim, args))
+
+ if err_cb is None:
+ err_cb = sys.stderr.write
+ self._err_cb = err_cb
+
+ self._session.run(filter_request_cb, filter_notification_cb, setup_cb)
+
+ def stop_loop(self):
+ """Stop the event loop being started with `run_loop`."""
+ self._session.stop()
+
+ def with_decode(self, decode=True):
+ """Initialize a new Nvim instance."""
+ return Nvim(self._session, self.channel_id,
+ self.metadata, self.types, decode, self._err_cb)
def ui_attach(self, width, height, rgb):
"""Register as a remote UI.
@@ -92,57 +175,53 @@ class Nvim(object):
After this method is called, the client will receive redraw
notifications.
"""
- return self._session.request('ui_attach', width, height, rgb)
+ return self.request('ui_attach', width, height, rgb)
def ui_detach(self):
"""Unregister as a remote UI."""
- return self._session.request('ui_detach')
+ return self.request('ui_detach')
def ui_try_resize(self, width, height):
"""Notify nvim that the client window has resized.
If possible, nvim will send a redraw request to resize.
"""
- return self._session.request('ui_try_resize', width, height)
+ return self.request('ui_try_resize', width, height)
def subscribe(self, event):
"""Subscribe to a Nvim event."""
- return self._session.request('vim_subscribe', event)
+ return self.request('vim_subscribe', event)
def unsubscribe(self, event):
"""Unsubscribe to a Nvim event."""
- return self._session.request('vim_unsubscribe', event)
+ return self.request('vim_unsubscribe', event)
- def command(self, string, async=False):
+ def command(self, string, **kwargs):
"""Execute a single ex command."""
- return self._session.request('vim_command', string, async=async)
+ return self.request('vim_command', string, **kwargs)
def command_output(self, string):
"""Execute a single ex command and return the output."""
- return self._session.request('vim_command_output', string)
+ return self.request('vim_command_output', string)
- def eval(self, string, async=False):
+ def eval(self, string, **kwargs):
"""Evaluate a vimscript expression."""
- return self._session.request('vim_eval', string, async=async)
+ return self.request('vim_eval', string, **kwargs)
def call(self, name, *args, **kwargs):
"""Call a vimscript function."""
- for k in kwargs:
- if k != "async":
- raise TypeError(
- "call() got an unexpected keyword argument '{}'".format(k))
- return self._session.request('vim_call_function', name, args, **kwargs)
+ return self.request('vim_call_function', name, args, **kwargs)
def strwidth(self, string):
"""Return the number of display cells `string` occupies.
Tab is counted as one cell.
"""
- return self._session.request('vim_strwidth', string)
+ return self.request('vim_strwidth', string)
def list_runtime_paths(self):
"""Return a list of paths contained in the 'runtimepath' option."""
- return self._session.request('vim_list_runtime_paths')
+ return self.request('vim_list_runtime_paths')
def foreach_rtp(self, cb):
"""Invoke `cb` for each path in 'runtimepath'.
@@ -152,7 +231,7 @@ class Nvim(object):
are no longer paths. If stopped in case callable returned non-None,
vim.foreach_rtp function returns the value returned by callable.
"""
- for path in self._session.request('vim_list_runtime_paths'):
+ for path in self.request('vim_list_runtime_paths'):
try:
if cb(path) is not None:
break
@@ -162,7 +241,7 @@ class Nvim(object):
def chdir(self, dir_path):
"""Run os.chdir, then all appropriate vim stuff."""
os_chdir(dir_path)
- return self._session.request('vim_change_directory', dir_path)
+ return self.request('vim_change_directory', dir_path)
def feedkeys(self, keys, options='', escape_csi=True):
"""Push `keys` to Nvim user input buffer.
@@ -173,7 +252,7 @@ class Nvim(object):
- 't': Handle keys as if typed; otherwise they are handled as if coming
from a mapping. This matters for undo, opening folds, etc.
"""
- return self._session.request('vim_feedkeys', keys, options, escape_csi)
+ return self.request('vim_feedkeys', keys, options, escape_csi)
def input(self, bytes):
"""Push `bytes` to Nvim low level input buffer.
@@ -183,7 +262,7 @@ class Nvim(object):
written(which can be less than what was requested if the buffer is
full).
"""
- return self._session.request('vim_input', bytes)
+ return self.request('vim_input', bytes)
def replace_termcodes(self, string, from_part=False, do_lt=True,
special=True):
@@ -199,16 +278,16 @@ class Nvim(object):
The returned sequences can be used as input to `feedkeys`.
"""
- return self._session.request('vim_replace_termcodes', string,
- from_part, do_lt, special)
+ return self.request('vim_replace_termcodes', string,
+ from_part, do_lt, special)
def out_write(self, msg):
"""Print `msg` as a normal message."""
- return self._session.request('vim_out_write', msg)
+ return self.request('vim_out_write', msg)
- def err_write(self, msg, async=False):
+ def err_write(self, msg, **kwargs):
"""Print `msg` as an error message."""
- return self._session.request('vim_err_write', msg, async=async)
+ return self.request('vim_err_write', msg, **kwargs)
def quit(self, quit_command='qa!'):
"""Send a quit command to Nvim.
@@ -245,13 +324,21 @@ class Nvim(object):
fn(*args, **kwargs)
except Exception as err:
msg = ("error caught while executing async callback:\n"
- "{!r}\n{}\n \nthe call was requested at\n{}"
+ "{0!r}\n{1}\n \nthe call was requested at\n{2}"
.format(err, format_exc(5), call_point))
- self.err_write(msg, async=True)
+ self._err_cb(msg)
raise
self._session.threadsafe_call(handler)
+class CompatibilitySession(object):
+
+ """Helper class for API compatibility."""
+
+ def __init__(self, nvim):
+ self.threadsafe_call = nvim.async_call
+
+
class Current(object):
"""Helper class for emulating vim.current from python-vim."""
@@ -304,23 +391,5 @@ class Funcs(object):
return functools.partial(self._nvim.call, name)
-class ExtHook(SessionHook):
- def __init__(self, types):
- self.types = types
- super(ExtHook, self).__init__(from_nvim=self.from_ext,
- to_nvim=self.to_ext)
-
- def from_ext(self, obj, session, method, kind):
- if type(obj) is ExtType:
- cls = self.types[obj.code]
- return cls(session, (obj.code, obj.data))
- return obj
-
- def to_ext(self, obj, session, method, kind):
- if isinstance(obj, Remote):
- return ExtType(*obj.code_data)
- return obj
-
-
class NvimError(Exception):
pass
diff --git a/neovim/api/tabpage.py b/neovim/api/tabpage.py
index 355ba5c..7742ba3 100644
--- a/neovim/api/tabpage.py
+++ b/neovim/api/tabpage.py
@@ -1,32 +1,30 @@
"""API for working with Nvim tabpages."""
-from .common import Remote, RemoteMap, RemoteSequence
+from .common import Remote, RemoteSequence
__all__ = ('Tabpage')
class Tabpage(Remote):
-
"""A remote Nvim tabpage."""
- def __init__(self, session, code_data):
+ _api_prefix = "tabpage_"
... 693 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-neovim.git
More information about the Python-modules-commits
mailing list