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

neovim.api.Buffer.__setitem__()   B

Complexity

Conditions 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 6
Metric Value
cc 6
dl 0
loc 26
ccs 16
cts 16
cp 1
crap 6
rs 7.5384
1
"""API for working with Nvim buffers."""
2 6
from .common import Remote, RemoteMap, RemoteApi, ApiMethod, ApiProperty
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
    get_line_slice = ApiMethod("buffer_get_line_slice")
108 6
    set_line_slice = ApiMethod("buffer_set_line_slice")
109
110 6
    def append(self, lines, index=-1):
111
        """Append a string or list of lines to the buffer."""
112 6
        if isinstance(lines, basestring):
113 6
            lines = [lines]
114 6
        return self._session.request('buffer_insert', self, index, lines)
115
116 6
    mark = ApiMethod("buffer_get_mark")
117
118 6
    def range(self, start, end):
119
        """Return a `Range` object, which represents part of the Buffer."""
120
        return Range(self, start, end)
121
122 6
    def add_highlight(self, hl_group, line, col_start=0,
123
                      col_end=-1, src_id=-1, async=None):
124
        """Add a highlight to the buffer."""
125
        if async is None:
126
            async = (src_id != 0)
127
        return self._session.request('buffer_add_highlight', self, src_id,
128
                                     hl_group, line, col_start,
129
                                     col_end, async=async)
130
131 6
    def clear_highlight(self, src_id, line_start=0, line_end=-1, async=True):
132
        """clear highlights from the buffer."""
133
        self._session.request('buffer_clear_highlight', self, src_id,
134
                              line_start, line_end, async=async)
135
136 6
    name = ApiProperty("buffer_get_name", "buffer_set_name")
137
138 6
    @property
139
    def valid(self):
140
        """Return True if the buffer still exists."""
141 6
        return self._session.request('buffer_is_valid', self)
142
143 6
    @property
144
    def number(self):
145
        """Get the buffer number."""
146 6
        return self._session.request('buffer_get_number', self)
147
148
149 6
class Range(object):
150 6
    def __init__(self, buffer, start, end):
151
        self._buffer = buffer
152
        self.start = start - 1
153
        self.end = end
154
155 6
    def __len__(self):
156
        return self.end - self.start
157
158 6
    def __getitem__(self, idx):
159
        if not isinstance(idx, slice):
160
            return self._buffer[self._normalize_index(idx)]
161
        start = self._normalize_index(idx.start)
162
        end = self._normalize_index(idx.stop)
163
        if start is None:
164
            start = self.start
165
        if end is None:
166
            end = self.end
167
        return self._buffer[start:end]
168
169 6
    def __setitem__(self, idx, lines):
170
        if not isinstance(idx, slice):
171
            self._buffer[self._normalize_index(idx)] = lines
172
            return
173
        start = self._normalize_index(idx.start)
174
        end = self._normalize_index(idx.stop)
175
        if start is None:
176
            start = self.start
177
        if end is None:
178
            end = self.end
179
        self._buffer[start:end] = lines
180
181 6
    def __iter__(self):
182
        for i in range(self.start, self.end):
183
            yield self._buffer[i]
184
185 6
    def append(self, lines, i=None):
186
        i = self._normalize_index(i)
187
        if i is None:
188
            i = self.end
189
        self._buffer.append(lines, i)
190
191 6
    def _normalize_index(self, index):
192
        if index is None:
193
            return None
194
        if index < 0:
195
            index = self.end - 1
196
        else:
197
            index += self.start
198
            if index >= self.end:
199
                index = self.end - 1
200
        return index
201