Completed
Pull Request — master (#219)
by Björn
25:46
created

Buffer.__setitem__()   B

Complexity

Conditions 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 6

Importance

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