Completed
Pull Request — master (#179)
by Björn
02:36
created

neovim.api.Buffer.__len__()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1
Metric Value
cc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
"""API for working with Nvim buffers."""
2 6
from .common import Remote, RemoteMap, RemoteApi
3 6
from ..compat import IS_PYTHON3
4
5
6 6
__all__ = ('Buffer')
7
8
9 6
if IS_PYTHON3:
10 3
    basestring = str
11
12
13 6
class Buffer(Remote):
14
15
    """A remote Nvim buffer."""
16
17 6
    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 6
        self._session = session
24 6
        self.code_data = code_data
25 6
        self.api = RemoteApi(session, 'buffer_', (self,))
26 6
        self.vars = RemoteMap(session, 'buffer_get_var', 'buffer_set_var',
27
                              self)
28 6
        self.options = RemoteMap(session, 'buffer_get_option',
29
                                 'buffer_set_option', self)
30
31 6
    def __len__(self):
32
        """Return the number of lines contained in a Buffer."""
33 6
        return self._session.request('buffer_line_count', self)
34
35 6
    def __getitem__(self, idx):
36
        """Get a buffer line or slice by integer index.
37
38
        Indexes may be negative to specify positions from the end of the
39
        buffer. For example, -1 is the last line, -2 is the line before that
40
        and so on.
41
42
        When retrieving slices, omiting indexes(eg: `buffer[:]`) will bring
43
        the whole buffer.
44
        """
45 6
        if not isinstance(idx, slice):
46 6
            return self._session.request('buffer_get_line', self, idx)
47 6
        include_end = False
48 6
        start = idx.start
49 6
        end = idx.stop
50 6
        if start is None:
51 6
            start = 0
52 6
        if end is None:
53 6
            end = -1
54 6
            include_end = True
55 6
        return self._session.request('buffer_get_line_slice', self, start, end,
56
                                     True, include_end)
57
58 6
    def __setitem__(self, idx, lines):
59
        """Replace a buffer line or slice by integer index.
60
61
        Like with `__getitem__`, indexes may be negative.
62
63
        When replacing slices, omiting indexes(eg: `buffer[:]`) will replace
64
        the whole buffer.
65
        """
66 6
        if not isinstance(idx, slice):
67 6
            if lines is None:
68 6
                return self._session.request('buffer_del_line', self, idx)
69
            else:
70 6
                return self._session.request('buffer_set_line', self, idx,
71
                                             lines)
72 6
        if lines is None:
73 6
            lines = []
74 6
        include_end = False
75 6
        start = idx.start
76 6
        end = idx.stop
77 6
        if start is None:
78 6
            start = 0
79 6
        if end is None:
80 6
            end = -1
81 6
            include_end = True
82 6
        return self._session.request('buffer_set_line_slice', self, start, end,
83
                                     True, include_end, lines)
84
85 6
    def __iter__(self):
86
        """Iterate lines of a buffer.
87
88
        This will retrieve all lines locally before iteration starts. This
89
        approach is used because for most cases, the gain is much greater by
90
        minimizing the number of API calls by transfering all data needed to
91
        work.
92
        """
93
        lines = self[:]
94
        for line in lines:
95
            yield line
96
97 6
    def __delitem__(self, idx):
98
        """Delete line or slice of lines from the buffer.
99
100
        This is the same as __setitem__(idx, [])
101
        """
102 6
        if not isinstance(idx, slice):
103 6
            self.__setitem__(idx, None)
104
        else:
105 6
            self.__setitem__(idx, [])
106
107 6
    def get_line_slice(self, start, stop, start_incl, end_incl):
108
        """More flexible wrapper for retrieving slices."""
109
        return self._session.request('buffer_get_line_slice', self, start,
110
                                     stop, start_incl, end_incl)
111
112 6
    def set_line_slice(self, start, stop, start_incl, end_incl, lines):
113
        """More flexible wrapper for replacing slices."""
114
        return self._session.request('buffer_set_line_slice', self, start,
115
                                     stop, start_incl, end_incl, lines)
116
117 6
    def append(self, lines, index=-1):
118
        """Append a string or list of lines to the buffer."""
119 6
        if isinstance(lines, basestring):
120 6
            lines = [lines]
121 6
        return self._session.request('buffer_insert', self, index, lines)
122
123 6
    def mark(self, name):
124
        """Return (row, col) tuple for a named mark."""
125 6
        return self._session.request('buffer_get_mark', self, name)
126
127 6
    def range(self, start, end):
128
        """Return a `Range` object, which represents part of the Buffer."""
129
        return Range(self, start, end)
130
131 6
    def add_highlight(self, hl_group, line, col_start=0,
132
                      col_end=-1, src_id=-1, async=None):
133
        """Add a highlight to the buffer."""
134
        if async is None:
135
            async = (src_id != 0)
136
        return self._session.request('buffer_add_highlight', self, src_id,
137
                                     hl_group, line, col_start,
138
                                     col_end, async=async)
139
140 6
    def clear_highlight(self, src_id, line_start=0, line_end=-1, async=True):
141
        """clear highlights from the buffer."""
142
        self._session.request('buffer_clear_highlight', self, src_id,
143
                              line_start, line_end, async=async)
144
145 6
    @property
146
    def name(self):
147
        """Get the buffer name."""
148 6
        return self._session.request('buffer_get_name', self)
149
150 6
    @name.setter
151
    def name(self, value):
152
        """Set the buffer name. BufFilePre/BufFilePost are triggered."""
153 6
        return self._session.request('buffer_set_name', self, value)
154
155 6
    @property
156
    def valid(self):
157
        """Return True if the buffer still exists."""
158 6
        return self._session.request('buffer_is_valid', self)
159
160 6
    @property
161
    def number(self):
162
        """Get the buffer number."""
163 6
        return self._session.request('buffer_get_number', self)
164
165
166 6
class Range(object):
167 6
    def __init__(self, buffer, start, end):
168
        self._buffer = buffer
169
        self.start = start - 1
170
        self.end = end
171
172 6
    def __len__(self):
173
        return self.end - self.start
174
175 6
    def __getitem__(self, idx):
176
        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
184
        return self._buffer[start:end]
185
186 6
    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] = lines
197
198 6
    def __iter__(self):
199
        for i in range(self.start, self.end):
200
            yield self._buffer[i]
201
202 6
    def append(self, lines, i=None):
203
        i = self._normalize_index(i)
204
        if i is None:
205
            i = self.end
206
        self._buffer.append(lines, i)
207
208 6
    def _normalize_index(self, index):
209
        if index is None:
210
            return None
211
        if index < 0:
212
            index = self.end - 1
213
        else:
214
            index += self.start
215
            if index >= self.end:
216
                index = self.end - 1
217
        return index
218