Completed
Pull Request — master (#190)
by Björn
22:30
created

Buffer.__setitem__()   A

Complexity

Conditions 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

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