Completed
Pull Request — master (#325)
by Björn
25:02
created

Buffer.update_highlights()   A

Complexity

Conditions 3

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 16
ccs 7
cts 7
cp 1
crap 3
rs 9.4285
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
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
        """Add a highlight to the buffer."""
103
        if async is None:
104
            async = (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=True):
109
        """Clear highlights from the buffer."""
110
        self.request('nvim_buf_clear_highlight', src_id,
111
                     line_start, line_end, async=async)
112
113 5
    def update_highlights(self, src_id, hls, clear_start=0, clear_end=-1, clear=False, async=True):
114
        """Add or update highlights in batch to avoid redraws.
115
        A src_id must have been allocated prior to use of this function. Use for instance
116 5
        nvim.new_highlight_source() to get a src_id for your plugin.
117
118 5
        hls should be a list of highlight items. Each item should be a list or tuple on the form
119
        ("GroupName", linenr, col_start, col_end) or ("GroupName", linenr) to highlight an entire line.
120
121 5
        By default existing highlights is preserved. Specify a line range with clear_start and clear_end
122
        to replace highlights in this range. As a shorthand, use clear=True to clear the entire
123 5
        buffer before adding the new highlights.
124
        """
125
        if clear and clear_start is None:
126 5
            clear_start = 0
127
        helpers = self._session._get_lua_helpers()
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _get_lua_helpers 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...
128 5
        helpers.update_highlights(self, src_id, hls, clear_start, clear_end, async=async)
129
130
    @property
131 5
    def name(self):
132
        """Get the buffer name."""
133
        return self.request('nvim_buf_get_name')
134 5
135 5
    @name.setter
136
    def name(self, value):
137
        """Set the buffer name. BufFilePre/BufFilePost are triggered."""
138
        return self.request('nvim_buf_set_name', value)
139
140 5
    @property
141
    def valid(self):
142
        """Return True if the buffer still exists."""
143 5
        return self.request('nvim_buf_is_valid')
144
145
    @property
146
    def number(self):
147
        """Get the buffer number."""
148
        return self.handle
149
150
151
class Range(object):
152
    def __init__(self, buffer, start, end):
153
        self._buffer = buffer
154 5
        self.start = start - 1
155
        self.end = end - 1
156
157
    def __len__(self):
158
        return self.end - self.start + 1
159
160
    def __getitem__(self, idx):
161
        if not isinstance(idx, slice):
162
            return self._buffer[self._normalize_index(idx)]
163
        start = self._normalize_index(idx.start)
164
        end = self._normalize_index(idx.stop)
165
        if start is None:
166 5
            start = self.start
167
        if end is None:
168
            end = self.end + 1
169
        return self._buffer[start:end]
170 5
171
    def __setitem__(self, idx, lines):
172
        if not isinstance(idx, slice):
173
            self._buffer[self._normalize_index(idx)] = lines
174
            return
175
        start = self._normalize_index(idx.start)
176 5
        end = self._normalize_index(idx.stop)
177
        if start is None:
178
            start = self.start
179
        if end is None:
180
            end = self.end
181
        self._buffer[start:end + 1] = lines
182
183
    def __iter__(self):
184
        for i in range(self.start, self.end + 1):
185
            yield self._buffer[i]
186
187
    def append(self, lines, i=None):
188
        i = self._normalize_index(i)
189
        if i is None:
190
            i = self.end + 1
191
        self._buffer.append(lines, i)
192
193
    def _normalize_index(self, index):
194
        if index is None:
195
            return None
196
        if index < 0:
197
            index = self.end
198
        else:
199
            index += self.start
200
            if index > self.end:
201
                index = self.end
202
        return index
203