Completed
Push — master ( 13f763...d9aed9 )
by Björn
30:55 queued 05:49
created

Buffer.update_highlights()   A

Complexity

Conditions 3

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3.009

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 22
ccs 9
cts 10
cp 0.9
crap 3.009
rs 9.2
c 0
b 0
f 0
1
"""API for working with a Nvim Buffer."""
2 5
from .common import Remote
3 5
from ..compat import IS_PYTHON3, check_async
4
5
6 5
__all__ = ('Buffer')
7
8
9 5
if IS_PYTHON3:
10 3
    basestring = str
11
12
13 5
def adjust_index(idx, default=None):
14
    """Convert from python indexing convention to nvim indexing convention."""
15 5
    if idx is None:
16 5
        return default
17 5
    elif idx < 0:
18 5
        return idx - 1
19
    else:
20 5
        return idx
21
22
23 5
class Buffer(Remote):
24
25
    """A remote Nvim buffer."""
26
27 5
    _api_prefix = "nvim_buf_"
28
29 5
    def __len__(self):
30
        """Return the number of lines contained in a Buffer."""
31 5
        return self.request('nvim_buf_line_count')
32
33 5
    def __getitem__(self, idx):
34
        """Get a buffer line or slice by integer index.
35
36
        Indexes may be negative to specify positions from the end of the
37
        buffer. For example, -1 is the last line, -2 is the line before that
38
        and so on.
39
40
        When retrieving slices, omiting indexes(eg: `buffer[:]`) will bring
41
        the whole buffer.
42
        """
43 5
        if not isinstance(idx, slice):
44 5
            i = adjust_index(idx)
45 5
            return self.request('nvim_buf_get_lines', i, i + 1, True)[0]
46 5
        start = adjust_index(idx.start, 0)
47 5
        end = adjust_index(idx.stop, -1)
48 5
        return self.request('nvim_buf_get_lines', start, end, False)
49
50 5
    def __setitem__(self, idx, item):
51
        """Replace a buffer line or slice by integer index.
52
53
        Like with `__getitem__`, indexes may be negative.
54
55
        When replacing slices, omiting indexes(eg: `buffer[:]`) will replace
56
        the whole buffer.
57
        """
58 5
        if not isinstance(idx, slice):
59 5
            i = adjust_index(idx)
60 5
            lines = [item] if item is not None else []
61 5
            return self.request('nvim_buf_set_lines', i, i + 1, True, lines)
62 5
        lines = item if item is not None else []
63 5
        start = adjust_index(idx.start, 0)
64 5
        end = adjust_index(idx.stop, -1)
65 5
        return self.request('nvim_buf_set_lines', start, end, False, lines)
66
67 5
    def __iter__(self):
68
        """Iterate lines of a buffer.
69
70
        This will retrieve all lines locally before iteration starts. This
71
        approach is used because for most cases, the gain is much greater by
72
        minimizing the number of API calls by transfering all data needed to
73
        work.
74
        """
75
        lines = self[:]
76
        for line in lines:
77
            yield line
78
79 5
    def __delitem__(self, idx):
80
        """Delete line or slice of lines from the buffer.
81
82
        This is the same as __setitem__(idx, [])
83
        """
84 5
        self.__setitem__(idx, None)
85
86 5
    def append(self, lines, index=-1):
87
        """Append a string or list of lines to the buffer."""
88 5
        if isinstance(lines, (basestring, bytes)):
89 5
            lines = [lines]
90 5
        return self.request('nvim_buf_set_lines', index, index, True, lines)
91
92 5
    def mark(self, name):
93
        """Return (row, col) tuple for a named mark."""
94 5
        return self.request('nvim_buf_get_mark', name)
95
96 5
    def range(self, start, end):
97
        """Return a `Range` object, which represents part of the Buffer."""
98
        return Range(self, start, end)
99
100 5
    def add_highlight(self, hl_group, line, col_start=0,
101
                      col_end=-1, src_id=-1, async_=None,
102
                      **kwargs):
103
        """Add a highlight to the buffer."""
104
        async_ = check_async(async_, kwargs, src_id != 0)
105
        return self.request('nvim_buf_add_highlight', src_id, hl_group,
106
                            line, col_start, col_end, async_=async_)
107
108 5
    def clear_highlight(self, src_id, line_start=0, line_end=-1, async_=None,
109
                        **kwargs):
110
        """Clear highlights from the buffer."""
111
        async_ = check_async(async_, kwargs, True)
112
        self.request('nvim_buf_clear_highlight', src_id,
113 5
                     line_start, line_end, async_=async_)
114
115
    def update_highlights(self, src_id, hls, clear_start=0, clear_end=-1,
116 5
                          clear=False, async_=True):
117
        """Add or update highlights in batch to avoid unnecessary redraws.
118 5
119
        A `src_id` must have been allocated prior to use of this function. Use
120
        for instance `nvim.new_highlight_source()` to get a src_id for your
121 5
        plugin.
122
123 5
        `hls` should be a list of highlight items. Each item should be a list
124
        or tuple on the form `("GroupName", linenr, col_start, col_end)` or
125
        `("GroupName", linenr)` to highlight an entire line.
126 5
127
        By default existing highlights are preserved. Specify a line range with
128 5
        clear_start and clear_end to replace highlights in this range. As a
129
        shorthand, use clear=True to clear the entire buffer before adding the
130
        new highlights.
131 5
        """
132
        if clear and clear_start is None:
133
            clear_start = 0
134 5
        lua = self._session._get_lua_private()
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _get_lua_private was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
135 5
        lua.update_highlights(self, src_id, hls, clear_start, clear_end,
136
                              async_=async_)
137
138
    @property
139
    def name(self):
140 5
        """Get the buffer name."""
141
        return self.request('nvim_buf_get_name')
142
143 5
    @name.setter
144
    def name(self, value):
145
        """Set the buffer name. BufFilePre/BufFilePost are triggered."""
146
        return self.request('nvim_buf_set_name', value)
147
148
    @property
149
    def valid(self):
150
        """Return True if the buffer still exists."""
151
        return self.request('nvim_buf_is_valid')
152
153
    @property
154 5
    def number(self):
155
        """Get the buffer number."""
156
        return self.handle
157
158
159
class Range(object):
160
    def __init__(self, buffer, start, end):
161
        self._buffer = buffer
162
        self.start = start - 1
163
        self.end = end - 1
164
165
    def __len__(self):
166 5
        return self.end - self.start + 1
167
168
    def __getitem__(self, idx):
169
        if not isinstance(idx, slice):
170 5
            return self._buffer[self._normalize_index(idx)]
171
        start = self._normalize_index(idx.start)
172
        end = self._normalize_index(idx.stop)
173
        if start is None:
174
            start = self.start
175
        if end is None:
176 5
            end = self.end + 1
177
        return self._buffer[start:end]
178
179
    def __setitem__(self, idx, lines):
180
        if not isinstance(idx, slice):
181
            self._buffer[self._normalize_index(idx)] = lines
182
            return
183
        start = self._normalize_index(idx.start)
184
        end = self._normalize_index(idx.stop)
185
        if start is None:
186
            start = self.start
187
        if end is None:
188
            end = self.end
189
        self._buffer[start:end + 1] = lines
190
191
    def __iter__(self):
192
        for i in range(self.start, self.end + 1):
193
            yield self._buffer[i]
194
195
    def append(self, lines, i=None):
196
        i = self._normalize_index(i)
197
        if i is None:
198
            i = self.end + 1
199
        self._buffer.append(lines, i)
200
201
    def _normalize_index(self, index):
202
        if index is None:
203
            return None
204
        if index < 0:
205
            index = self.end
206
        else:
207
            index += self.start
208
            if index > self.end:
209
                index = self.end
210
        return index
211