Completed
Pull Request — master (#156)
by Björn
29:44
created

neovim.api.Nvim.new_highlight_source()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1
Metric Value
cc 1
dl 0
loc 2
ccs 1
cts 1
cp 1
crap 1
rs 10
1
"""Main Nvim interface."""
2 6
import functools
3 6
import os
4
5 6
from msgpack import ExtType
0 ignored issues
show
Configuration introduced by
The import msgpack could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
6
7 6
from .buffer import Buffer
8 6
from .common import (DecodeHook, Remote, RemoteMap, RemoteSequence,
9
                     SessionFilter, SessionHook, walk)
10 6
from .tabpage import Tabpage
11 6
from .window import Window
12 6
from ..compat import IS_PYTHON3
13
14
15 6
__all__ = ('Nvim')
16
17
18 6
os_chdir = os.chdir
19
20
21 6
class Nvim(object):
22
23
    """Class that represents a remote Nvim instance.
24
25
    This class is main entry point to Nvim remote API, it is a thin wrapper
26
    around Session instances.
27
28
    The constructor of this class must not be called directly. Instead, the
29
    `from_session` class method should be used to create the first instance
30
    from a raw `Session` instance.
31
32
    Subsequent instances for the same session can be created by calling the
33
    `with_hook` instance method and passing a SessionHook instance. This can
34
    be useful to have multiple `Nvim` objects that behave differently without
35
    one affecting the other.
36
    """
37
38 6
    @classmethod
39
    def from_session(cls, session):
40
        """Create a new Nvim instance for a Session instance.
41
42
        This method must be called to create the first Nvim instance, since it
43
        queries Nvim metadata for type information and sets a SessionHook for
44
        creating specialized objects from Nvim remote handles.
45
        """
46 6
        session.error_wrapper = lambda e: NvimError(e[1])
47 6
        channel_id, metadata = session.request(b'vim_get_api_info')
48
49 6
        if IS_PYTHON3:
50 3
            hook = DecodeHook()
51
            # decode all metadata strings for python3
52 6
            metadata = walk(hook.from_nvim, metadata, None, None, None)
53
54 6
        types = {
55
            metadata['types']['Buffer']['id']: Buffer,
56
            metadata['types']['Window']['id']: Window,
57
            metadata['types']['Tabpage']['id']: Tabpage,
58
        }
59
60 6
        return cls(session, channel_id, metadata).with_hook(ExtHook(types))
61
62 6
    def __init__(self, session, channel_id, metadata):
63
        """Initialize a new Nvim instance. This method is module-private."""
64 6
        self._session = session
65 6
        self.channel_id = channel_id
66 6
        self.metadata = metadata
67 6
        self.vars = RemoteMap(session, 'vim_get_var', 'vim_set_var')
68 6
        self.vvars = RemoteMap(session, 'vim_get_vvar', None)
69 6
        self.options = RemoteMap(session, 'vim_get_option', 'vim_set_option')
70 6
        self.buffers = RemoteSequence(session, 'vim_get_buffers')
71 6
        self.windows = RemoteSequence(session, 'vim_get_windows')
72 6
        self.tabpages = RemoteSequence(session, 'vim_get_tabpages')
73 6
        self.current = Current(session)
74 6
        self.funcs = Funcs(self)
75 6
        self.error = NvimError
76
77 6
    def with_hook(self, hook):
78
        """Initialize a new Nvim instance."""
79 6
        return Nvim(SessionFilter(self.session, hook), self.channel_id,
80
                    self.metadata)
81
82 6
    @property
83
    def session(self):
84
        """Return the Session or SessionFilter for a Nvim instance."""
85 6
        return self._session
86
87 6
    def ui_attach(self, width, height, rgb):
88
        """Register as a remote UI.
89
90
        After this method is called, the client will receive redraw
91
        notifications.
92
        """
93
        return self._session.request('ui_attach', width, height, rgb)
94
95 6
    def ui_detach(self):
96
        """Unregister as a remote UI."""
97
        return self._session.request('ui_detach')
98
99 6
    def ui_try_resize(self, width, height):
100
        """Notify nvim that the client window has resized.
101
102
        If possible, nvim will send a redraw request to resize.
103
        """
104
        return self._session.request('ui_try_resize', width, height)
105
106 6
    def subscribe(self, event):
107
        """Subscribe to a Nvim event."""
108 6
        return self._session.request('vim_subscribe', event)
109
110 6
    def unsubscribe(self, event):
111
        """Unsubscribe to a Nvim event."""
112 6
        return self._session.request('vim_unsubscribe', event)
113
114 6
    def command(self, string, async=False):
115
        """Execute a single ex command."""
116 6
        return self._session.request('vim_command', string, async=async)
117
118 6
    def command_output(self, string):
119
        """Execute a single ex command and return the output."""
120
        return self._session.request('vim_command_output', string)
121
122 6
    def eval(self, string, async=False):
123
        """Evaluate a vimscript expression."""
124 6
        return self._session.request('vim_eval', string, async=async)
125
126 6
    def call(self, name, *args, **kwargs):
127
        """Call a vimscript function."""
128 6
        for k in kwargs:
129 6
            if k != "async":
130
                raise TypeError(
131
                    "call() got an unexpected keyword argument '{}'".format(k))
132 6
        return self._session.request('vim_call_function', name, args, **kwargs)
133
134 6
    def strwidth(self, string):
135
        """Return the number of display cells `string` occupies.
136
137
        Tab is counted as one cell.
138
        """
139 6
        return self._session.request('vim_strwidth', string)
140
141 6
    def list_runtime_paths(self):
142
        """Return a list of paths contained in the 'runtimepath' option."""
143 5
        return self._session.request('vim_list_runtime_paths')
144
145 6
    def foreach_rtp(self, cb):
146
        """Invoke `cb` for each path in 'runtimepath'.
147
148
        Call the given callable for each path in 'runtimepath' until either
149
        callable returns something but None, the exception is raised or there
150
        are no longer paths. If stopped in case callable returned non-None,
151
        vim.foreach_rtp function returns the value returned by callable.
152
        """
153
        for path in self._session.request('vim_list_runtime_paths'):
154
            try:
155
                if cb(path) is not None:
156
                    break
157
            except Exception:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
158
                break
159
160 6
    def chdir(self, dir_path):
161
        """Run os.chdir, then all appropriate vim stuff."""
162 6
        os_chdir(dir_path)
163 6
        return self._session.request('vim_change_directory', dir_path)
164
165 6
    def feedkeys(self, keys, options='', escape_csi=True):
166
        """Push `keys` to Nvim user input buffer.
167
168
        Options can be a string with the following character flags:
169
        - 'm': Remap keys. This is default.
170
        - 'n': Do not remap keys.
171
        - 't': Handle keys as if typed; otherwise they are handled as if coming
172
               from a mapping. This matters for undo, opening folds, etc.
173
        """
174
        return self._session.request('vim_feedkeys', keys, options, escape_csi)
175
176 6
    def input(self, bytes):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in bytes.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
177
        """Push `bytes` to Nvim low level input buffer.
178
179
        Unlike `feedkeys()`, this uses the lowest level input buffer and the
180
        call is not deferred. It returns the number of bytes actually
181
        written(which can be less than what was requested if the buffer is
182
        full).
183
        """
184 6
        return self._session.request('vim_input', bytes)
185
186 6
    def replace_termcodes(self, string, from_part=False, do_lt=True,
187
                          special=True):
188
        r"""Replace any terminal code strings by byte sequences.
189
190
        The returned sequences are Nvim's internal representation of keys,
191
        for example:
192
193
        <esc> -> '\x1b'
194
        <cr>  -> '\r'
195
        <c-l> -> '\x0c'
196
        <up>  -> '\x80ku'
197
198
        The returned sequences can be used as input to `feedkeys`.
199
        """
200
        return self._session.request('vim_replace_termcodes', string,
201
                                     from_part, do_lt, special)
202
203 6
    def out_write(self, msg):
204
        """Print `msg` as a normal message."""
205
        return self._session.request('vim_out_write', msg)
206
207 6
    def err_write(self, msg):
208
        """Print `msg` as an error message."""
209
        return self._session.request('vim_err_write', msg)
210
211 6
    def quit(self, quit_command='qa!'):
212
        """Send a quit command to Nvim.
213
214
        By default, the quit command is 'qa!' which will make Nvim quit without
215
        saving anything.
216
        """
217
        try:
218
            self.command(quit_command)
219
        except IOError:
0 ignored issues
show
Unused Code introduced by
This except handler seems to be unused and could be removed.

Except handlers which only contain pass and do not have an else clause can usually simply be removed:

try:
    raises_exception()
except:  # Could be removed
    pass
Loading history...
220
            # sending a quit command will raise an IOError because the
221
            # connection is closed before a response is received. Safe to
222
            # ignore it.
223
            pass
224
225
    def new_highlight_source(self):
226 6
        return self.current.buffer.add_highlight("",0,0,0,src_id=0)
227
228
229
class Current(object):
230 6
231 6
    """Helper class for emulating vim.current from python-vim."""
232 6
233
    def __init__(self, session):
234 6
        self._session = session
235
        self.range = None
236 6
237
    @property
238 6
    def line(self):
239
        return self._session.request('vim_get_current_line')
240 6
241
    @line.setter
242 6
    def line(self, line):
243
        return self._session.request('vim_set_current_line', line)
244 6
245
    @property
246 6
    def buffer(self):
247
        return self._session.request('vim_get_current_buffer')
248 6
249
    @buffer.setter
250 6
    def buffer(self, buffer):
251
        return self._session.request('vim_set_current_buffer', buffer)
252 6
253
    @property
254 6
    def window(self):
255
        return self._session.request('vim_get_current_window')
256 6
257
    @window.setter
258 6
    def window(self, window):
259
        return self._session.request('vim_set_current_window', window)
260 6
261
    @property
262 6
    def tabpage(self):
263
        return self._session.request('vim_get_current_tabpage')
264 6
265
    @tabpage.setter
266
    def tabpage(self, tabpage):
267 6
        return self._session.request('vim_set_current_tabpage', tabpage)
268
269
270
class Funcs(object):
271 6
272 6
    """Helper class for functional vimscript interface."""
273
274 6
    def __init__(self, nvim):
275 6
        self._nvim = nvim
276
277
    def __getattr__(self, name):
278 6
        return functools.partial(self._nvim.call, name)
279 6
280 6
281 6
class ExtHook(SessionHook):
282
    def __init__(self, types):
283
        self.types = types
284 6
        super(ExtHook, self).__init__(from_nvim=self.from_ext,
285 6
                                      to_nvim=self.to_ext)
286 6
287 6
    def from_ext(self, obj, session, method, kind):
0 ignored issues
show
Unused Code introduced by
The argument kind seems to be unused.
Loading history...
Unused Code introduced by
The argument method seems to be unused.
Loading history...
288 6
        if type(obj) is ExtType:
289
            cls = self.types[obj.code]
290 6
            return cls(session, (obj.code, obj.data))
291 6
        return obj
292 6
293 6
    def to_ext(self, obj, session, method, kind):
0 ignored issues
show
Unused Code introduced by
The argument method seems to be unused.
Loading history...
Unused Code introduced by
The argument kind seems to be unused.
Loading history...
Unused Code introduced by
The argument session seems to be unused.
Loading history...
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
294
        if isinstance(obj, Remote):
295
            return ExtType(*obj.code_data)
296 6
        return obj
297 6
298
299
class NvimError(Exception):
300
    pass
301