Skip to content

Commit 22537a2

Browse files
committed
Refactor Remote and implement RemoteApi object
1 parent 6655ced commit 22537a2

File tree

5 files changed

+91
-79
lines changed

5 files changed

+91
-79
lines changed

neovim/api/buffer.py

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""API for working with Nvim buffers."""
2-
from .common import Remote, RemoteMap
2+
from .common import Remote
33
from ..compat import IS_PYTHON3
44

55

@@ -14,22 +14,11 @@ class Buffer(Remote):
1414

1515
"""A remote Nvim buffer."""
1616

17-
def __init__(self, session, code_data):
18-
"""Initialize from session and code_data immutable object.
19-
20-
The `code_data` contains serialization information required for
21-
msgpack-rpc calls. It must be immutable for Buffer equality to work.
22-
"""
23-
self._session = session
24-
self.code_data = code_data
25-
self.vars = RemoteMap(session, 'buffer_get_var', 'buffer_set_var',
26-
self)
27-
self.options = RemoteMap(session, 'buffer_get_option',
28-
'buffer_set_option', self)
17+
_api_prefix = "buffer_"
2918

3019
def __len__(self):
3120
"""Return the number of lines contained in a Buffer."""
32-
return self._session.request('buffer_line_count', self)
21+
return self.request('buffer_line_count')
3322

3423
def __getitem__(self, idx):
3524
"""Get a buffer line or slice by integer index.
@@ -121,7 +110,7 @@ def append(self, lines, index=-1):
121110

122111
def mark(self, name):
123112
"""Return (row, col) tuple for a named mark."""
124-
return self._session.request('buffer_get_mark', self, name)
113+
return self.request('buffer_get_mark', name)
125114

126115
def range(self, start, end):
127116
"""Return a `Range` object, which represents part of the Buffer."""
@@ -132,34 +121,33 @@ def add_highlight(self, hl_group, line, col_start=0,
132121
"""Add a highlight to the buffer."""
133122
if async is None:
134123
async = (src_id != 0)
135-
return self._session.request('buffer_add_highlight', self, src_id,
136-
hl_group, line, col_start,
137-
col_end, async=async)
124+
return self.request('buffer_add_highlight', src_id, hl_group,
125+
line, col_start, col_end, async=async)
138126

139127
def clear_highlight(self, src_id, line_start=0, line_end=-1, async=True):
140128
"""clear highlights from the buffer."""
141-
self._session.request('buffer_clear_highlight', self, src_id,
142-
line_start, line_end, async=async)
129+
self.request('buffer_clear_highlight', src_id,
130+
line_start, line_end, async=async)
143131

144132
@property
145133
def name(self):
146134
"""Get the buffer name."""
147-
return self._session.request('buffer_get_name', self)
135+
return self.request('buffer_get_name')
148136

149137
@name.setter
150138
def name(self, value):
151139
"""Set the buffer name. BufFilePre/BufFilePost are triggered."""
152-
return self._session.request('buffer_set_name', self, value)
140+
return self.request('buffer_set_name', value)
153141

154142
@property
155143
def valid(self):
156144
"""Return True if the buffer still exists."""
157-
return self._session.request('buffer_is_valid', self)
145+
return self.request('buffer_is_valid')
158146

159147
@property
160148
def number(self):
161149
"""Get the buffer number."""
162-
return self._session.request('buffer_get_number', self)
150+
return self.request('buffer_get_number')
163151

164152

165153
class Range(object):

neovim/api/common.py

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Code shared between the API classes."""
2+
import functools
23

34

45
class Remote(object):
@@ -10,6 +11,20 @@ class Remote(object):
1011
object handle into consideration.
1112
"""
1213

14+
def __init__(self, session, code_data):
15+
"""Initialize from session and code_data immutable object.
16+
17+
The `code_data` contains serialization information required for
18+
msgpack-rpc calls. It must be immutable for Buffer equality to work.
19+
"""
20+
self._session = session
21+
self.code_data = code_data
22+
self.api = RemoteApi(self, self._api_prefix)
23+
self.vars = RemoteMap(self, self._api_prefix + 'get_var',
24+
self._api_prefix + 'set_var')
25+
self.options = RemoteMap(self, self._api_prefix + 'get_option',
26+
self._api_prefix + 'set_option')
27+
1328
def __eq__(self, other):
1429
"""Return True if `self` and `other` are the same object."""
1530
return (hasattr(other, 'code_data') and
@@ -19,6 +34,24 @@ def __hash__(self):
1934
"""Return hash based on remote object id."""
2035
return self.code_data.__hash__()
2136

37+
def request(self, name, *args, **kwargs):
38+
"""Wrapper for nvim.request."""
39+
return self._session.request(name, self, *args, **kwargs)
40+
41+
42+
class RemoteApi(object):
43+
44+
"""Wrapper to allow api methods to be called like python methods."""
45+
46+
def __init__(self, obj, api_prefix):
47+
"""Initialize a RemoteApi with object and api prefix."""
48+
self._obj = obj
49+
self._api_prefix = api_prefix
50+
51+
def __getattr__(self, name):
52+
"""Return wrapper to named api method."""
53+
return functools.partial(self._obj.request, self._api_prefix + name)
54+
2255

2356
class RemoteMap(object):
2457

@@ -31,12 +64,12 @@ class RemoteMap(object):
3164
It is used to provide a dict-like API to vim variables and options.
3265
"""
3366

34-
def __init__(self, session, get_method, set_method, self_obj=None):
67+
def __init__(self, obj, get_method, set_method=None, self_obj=None):
3568
"""Initialize a RemoteMap with session, getter/setter and self_obj."""
36-
self._get = _wrap(session, get_method, self_obj)
69+
self._get = functools.partial(obj.request, get_method)
3770
self._set = None
3871
if set_method:
39-
self._set = _wrap(session, set_method, self_obj)
72+
self._set = functools.partial(obj.request, set_method)
4073

4174
def __getitem__(self, key):
4275
"""Return a map value by key."""
@@ -91,9 +124,9 @@ class RemoteSequence(object):
91124
locally(iteration, indexing, counting, etc).
92125
"""
93126

94-
def __init__(self, session, method, self_obj=None):
127+
def __init__(self, session, method):
95128
"""Initialize a RemoteSequence with session, method and self_obj."""
96-
self._fetch = _wrap(session, method, self_obj)
129+
self._fetch = functools.partial(session.request, method)
97130

98131
def __len__(self):
99132
"""Return the length of the remote sequence."""
@@ -155,10 +188,3 @@ def walk(fn, obj, *args):
155188
return dict((walk(fn, k, *args), walk(fn, v, *args)) for k, v in
156189
obj.items())
157190
return fn(obj, *args)
158-
159-
160-
def _wrap(session, method, self_obj):
161-
if self_obj is not None:
162-
return lambda *args: session.request(method, self_obj, *args)
163-
else:
164-
return lambda *args: session.request(method, *args)

neovim/api/nvim.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from msgpack import ExtType
88

99
from .buffer import Buffer
10-
from .common import (DecodeHook, Remote, RemoteMap, RemoteSequence, walk)
10+
from .common import (DecodeHook, Remote, RemoteApi,
11+
RemoteMap, RemoteSequence, walk)
1112
from .tabpage import Tabpage
1213
from .window import Window
1314
from ..compat import IS_PYTHON3
@@ -65,6 +66,7 @@ def __init__(self, session, channel_id, metadata, types, decodehook=None):
6566
self.channel_id = channel_id
6667
self.metadata = metadata
6768
self.types = types
69+
self.api = RemoteApi(self, 'vim_')
6870
self.vars = RemoteMap(self, 'vim_get_var', 'vim_set_var')
6971
self.vvars = RemoteMap(self, 'vim_get_vvar', None)
7072
self.options = RemoteMap(self, 'vim_get_option', 'vim_set_option')
@@ -90,15 +92,24 @@ def _to_nvim(self, obj):
9092
return obj
9193

9294
def request(self, name, *args, **kwargs):
93-
"""Send an API request or notification to nvim.
95+
r"""Send an API request or notification to nvim.
9496
95-
It is rarely needed for a plugin to call this function directly, as high
96-
As most API functions have python wrapper functions.
97+
It is rarely needed to call this function directly, as most API
98+
functions have python wrapper functions. The `api` object can
99+
be also be used to call API functions as methods:
97100
98-
Normally a blocking request will be sent.
99-
If the `async` flag is present and True, a asynchronous notification is
100-
sent instead. This will never block, and the return value or error is
101-
ignored.
101+
vim.api.err_write('ERROR\n', async=True)
102+
vim.current.buffer.api.get_mark('.')
103+
104+
is equivalent to
105+
106+
vim.request('vim_err_write', 'ERROR\n', async=True)
107+
vim.request('buffer_get_mark', vim.current.buffer, '.')
108+
109+
110+
Normally a blocking request will be sent. If the `async` flag is
111+
present and True, a asynchronous notification is sent instead. This
112+
will never block, and the return value or error is ignored.
102113
"""
103114
args = walk(self._to_nvim, args)
104115
res = self._session.request(name, *args, **kwargs)

neovim/api/tabpage.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
11
"""API for working with Nvim tabpages."""
2-
from .common import Remote, RemoteMap, RemoteSequence
2+
from .common import Remote, RemoteSequence
33

44

55
__all__ = ('Tabpage')
66

77

88
class Tabpage(Remote):
9-
109
"""A remote Nvim tabpage."""
1110

12-
def __init__(self, session, code_data):
11+
_api_prefix = "tabpage_"
12+
13+
def __init__(self, *args):
1314
"""Initialize from session and code_data immutable object.
1415
1516
The `code_data` contains serialization information required for
16-
msgpack-rpc calls. It must be immutable for Tabpage equality to work.
17+
msgpack-rpc calls. It must be immutable for Buffer equality to work.
1718
"""
18-
self._session = session
19-
self.code_data = code_data
20-
self.windows = RemoteSequence(session, 'tabpage_get_windows', self)
21-
self.vars = RemoteMap(session, 'tabpage_get_var', 'tabpage_set_var',
22-
self)
19+
super(Tabpage, self).__init__(*args)
20+
self.windows = RemoteSequence(self, 'tabpage_get_windows')
2321

2422
@property
2523
def window(self):
2624
"""Get the `Window` currently focused on the tabpage."""
27-
return self._session.request('tabpage_get_window', self)
25+
return self.request('tabpage_get_window')
2826

2927
@property
3028
def valid(self):
3129
"""Return True if the tabpage still exists."""
32-
return self._session.request('tabpage_is_valid', self)
30+
return self.request('tabpage_is_valid')

neovim/api/window.py

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""API for working with Nvim windows."""
2-
from .common import Remote, RemoteMap
2+
from .common import Remote
33

44

55
__all__ = ('Window')
@@ -9,70 +9,59 @@ class Window(Remote):
99

1010
"""A remote Nvim window."""
1111

12-
def __init__(self, session, code_data):
13-
"""Initialize from session and code_data immutable object.
14-
15-
The `code_data` contains serialization information required for
16-
msgpack-rpc calls. It must be immutable for Window equality to work.
17-
"""
18-
self._session = session
19-
self.code_data = code_data
20-
self.vars = RemoteMap(session, 'window_get_var', 'window_set_var',
21-
self)
22-
self.options = RemoteMap(session, 'window_get_option',
23-
'window_set_option', self)
12+
_api_prefix = "window_"
2413

2514
@property
2615
def buffer(self):
2716
"""Get the `Buffer` currently being displayed by the window."""
28-
return self._session.request('window_get_buffer', self)
17+
return self.request('window_get_buffer')
2918

3019
@property
3120
def cursor(self):
3221
"""Get the (row, col) tuple with the current cursor position."""
33-
return self._session.request('window_get_cursor', self)
22+
return self.request('window_get_cursor')
3423

3524
@cursor.setter
3625
def cursor(self, pos):
3726
"""Set the (row, col) tuple as the new cursor position."""
38-
return self._session.request('window_set_cursor', self, pos)
27+
return self.request('window_set_cursor', pos)
3928

4029
@property
4130
def height(self):
4231
"""Get the window height in rows."""
43-
return self._session.request('window_get_height', self)
32+
return self.request('window_get_height')
4433

4534
@height.setter
4635
def height(self, height):
4736
"""Set the window height in rows."""
48-
return self._session.request('window_set_height', self, height)
37+
return self.request('window_set_height', height)
4938

5039
@property
5140
def width(self):
5241
"""Get the window width in rows."""
53-
return self._session.request('window_get_width', self)
42+
return self.request('window_get_width')
5443

5544
@width.setter
5645
def width(self, width):
5746
"""Set the window height in rows."""
58-
return self._session.request('window_set_width', self, width)
47+
return self.request('window_set_width', width)
5948

6049
@property
6150
def row(self):
6251
"""0-indexed, on-screen window position(row) in display cells."""
63-
return self._session.request('window_get_position', self)[0]
52+
return self.request('window_get_position')[0]
6453

6554
@property
6655
def col(self):
6756
"""0-indexed, on-screen window position(col) in display cells."""
68-
return self._session.request('window_get_position', self)[1]
57+
return self.request('window_get_position')[1]
6958

7059
@property
7160
def tabpage(self):
7261
"""Get the `Tabpage` that contains the window."""
73-
return self._session.request('window_get_tabpage', self)
62+
return self.request('window_get_tabpage')
7463

7564
@property
7665
def valid(self):
7766
"""Return True if the window still exists."""
78-
return self._session.request('window_is_valid', self)
67+
return self.request('window_is_valid')

0 commit comments

Comments
 (0)