Completed
Pull Request — master (#328)
by
unknown
20:55
created

Buffer.__repr__()   A

Complexity

Conditions 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
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, 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 __repr__(self):
30
        """Get text representation of the buffer."""
31 5
        return 'Buffer(number=%r, handle=%r)' % (
32
            self.number,
33 5
            self.handle,
34
        )
35
36
    def __len__(self):
37
        """Return the number of lines contained in a Buffer."""
38
        return self.request('nvim_buf_line_count')
39
40
    def __getitem__(self, idx):
41
        """Get a buffer line or slice by integer index.
42
43 5
        Indexes may be negative to specify positions from the end of the
44 5
        buffer. For example, -1 is the last line, -2 is the line before that
45 5
        and so on.
46 5
47 5
        When retrieving slices, omiting indexes(eg: `buffer[:]`) will bring
48 5
        the whole buffer.
49
        """
50 5
        if not isinstance(idx, slice):
51
            i = adjust_index(idx)
52
            return self.request('nvim_buf_get_lines', i, i + 1, True)[0]
53
        start = adjust_index(idx.start, 0)
54
        end = adjust_index(idx.stop, -1)
55
        return self.request('nvim_buf_get_lines', start, end, False)
56
57
    def __setitem__(self, idx, item):
58 5
        """Replace a buffer line or slice by integer index.
59 5
60 5
        Like with `__getitem__`, indexes may be negative.
61 5
62 5
        When replacing slices, omiting indexes(eg: `buffer[:]`) will replace
63 5
        the whole buffer.
64 5
        """
65 5
        if not isinstance(idx, slice):
66
            i = adjust_index(idx)
67 5
            lines = [item] if item is not None else []
68
            return self.request('nvim_buf_set_lines', i, i + 1, True, lines)
69
        lines = item if item is not None else []
70
        start = adjust_index(idx.start, 0)
71
        end = adjust_index(idx.stop, -1)
72
        return self.request('nvim_buf_set_lines', start, end, False, lines)
73
74
    def __iter__(self):
75
        """Iterate lines of a buffer.
76
77
        This will retrieve all lines locally before iteration starts. This
78
        approach is used because for most cases, the gain is much greater by
79 5
        minimizing the number of API calls by transfering all data needed to
80
        work.
81
        """
82
        lines = self[:]
83
        for line in lines:
84 5
            yield line
85
86 5
    def __delitem__(self, idx):
87
        """Delete line or slice of lines from the buffer.
88 5
89 5
        This is the same as __setitem__(idx, [])
90 5
        """
91
        self.__setitem__(idx, None)
92 5
93
    def append(self, lines, index=-1):
94 5
        """Append a string or list of lines to the buffer."""
95
        if isinstance(lines, (basestring, bytes)):
96 5
            lines = [lines]
97
        return self.request('nvim_buf_set_lines', index, index, True, lines)
98
99
    def mark(self, name):
100 5
        """Return (row, col) tuple for a named mark."""
101
        return self.request('nvim_buf_get_mark', name)
102
103
    def range(self, start, end):
104
        """Return a `Range` object, which represents part of the Buffer."""
105
        return Range(self, start, end)
106
107
    def add_highlight(self, hl_group, line, col_start=0,
108 5
                      col_end=-1, src_id=-1, async_=None,
109
                      **kwargs):
110
        """Add a highlight to the buffer."""
111
        async_ = check_async(async_, kwargs, src_id != 0)
112
        return self.request('nvim_buf_add_highlight', src_id, hl_group,
113 5
                            line, col_start, col_end, async_=async_)
114
115
    def clear_highlight(self, src_id, line_start=0, line_end=-1, async_=None,
116 5
                        **kwargs):
117
        """Clear highlights from the buffer."""
118 5
        async_ = check_async(async_, kwargs, True)
119
        self.request('nvim_buf_clear_highlight', src_id,
120
                     line_start, line_end, async_=async_)
121 5
122
    def update_highlights(self, src_id, hls, clear_start=0, clear_end=-1,
123 5
                          clear=False, async_=True):
124
        """Add or update highlights in batch to avoid unnecessary redraws.
125
126 5
        A `src_id` must have been allocated prior to use of this function. Use
127
        for instance `nvim.new_highlight_source()` to get a src_id for your
128 5
        plugin.
129
130
        `hls` should be a list of highlight items. Each item should be a list
131 5
        or tuple on the form `("GroupName", linenr, col_start, col_end)` or
132
        `("GroupName", linenr)` to highlight an entire line.
133
134 5
        By default existing highlights are preserved. Specify a line range with
135 5
        clear_start and clear_end to replace highlights in this range. As a
136
        shorthand, use clear=True to clear the entire buffer before adding the
137
        new highlights.
138
        """
139
        if clear and clear_start is None:
140 5
            clear_start = 0
141
        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...
142
        lua.update_highlights(self, src_id, hls, clear_start, clear_end,
143 5
                              async_=async_)
144
145
    @property
146
    def name(self):
147
        """Get the buffer name."""
148
        return self.request('nvim_buf_get_name')
149
150
    @name.setter
151
    def name(self, value):
152
        """Set the buffer name. BufFilePre/BufFilePost are triggered."""
153
        return self.request('nvim_buf_set_name', value)
154 5
155
    @property
156
    def valid(self):
157
        """Return True if the buffer still exists."""
158
        return self.request('nvim_buf_is_valid')
159
160
    @property
161
    def number(self):
162
        """Get the buffer number."""
163
        return self.handle
164
165
166 5
class Range(object):
167
    def __init__(self, buffer, start, end):
168
        self._buffer = buffer
169
        self.start = start - 1
170 5
        self.end = end - 1
171
172
    def __len__(self):
173
        return self.end - self.start + 1
174
175
    def __getitem__(self, idx):
176 5
        if not isinstance(idx, slice):
177
            return self._buffer[self._normalize_index(idx)]
178
        start = self._normalize_index(idx.start)
179
        end = self._normalize_index(idx.stop)
180
        if start is None:
181
            start = self.start
182
        if end is None:
183
            end = self.end + 1
184
        return self._buffer[start:end]
185
186
    def __setitem__(self, idx, lines):
187
        if not isinstance(idx, slice):
188
            self._buffer[self._normalize_index(idx)] = lines
189
            return
190
        start = self._normalize_index(idx.start)
191
        end = self._normalize_index(idx.stop)
192
        if start is None:
193
            start = self.start
194
        if end is None:
195
            end = self.end
196
        self._buffer[start:end + 1] = lines
197
198
    def __iter__(self):
199
        for i in range(self.start, self.end + 1):
200
            yield self._buffer[i]
201
202
    def append(self, lines, i=None):
203
        i = self._normalize_index(i)
204
        if i is None:
205
            i = self.end + 1
206
        self._buffer.append(lines, i)
207
208
    def _normalize_index(self, index):
209
        if index is None:
210
            return None
211
        if index < 0:
212
            index = self.end
213
        else:
214
            index += self.start
215
            if index > self.end:
216
                index = self.end
217
        return index
218