1 | """Common code for graphical and text UIs.""" |
||
2 | from neovim.compat import IS_PYTHON3 |
||
3 | |||
4 | |||
5 | __all__ = ('Screen',) |
||
6 | |||
7 | |||
8 | if not IS_PYTHON3: |
||
9 | range = xrange # NOQA |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() |
|||
10 | |||
11 | |||
12 | class Cell(object): |
||
13 | def __init__(self): |
||
14 | self.text = ' ' |
||
15 | self.attrs = None |
||
16 | |||
17 | def __repr__(self): |
||
18 | return self.text |
||
19 | |||
20 | def get(self): |
||
21 | return self.text, self.attrs |
||
22 | |||
23 | def set(self, text, attrs): |
||
24 | self.text = text |
||
25 | self.attrs = attrs |
||
26 | |||
27 | def copy(self, other): |
||
28 | other.text = self.text |
||
29 | other.attrs = self.attrs |
||
30 | |||
31 | |||
32 | class Screen(object): |
||
33 | |||
34 | """Store nvim screen state.""" |
||
35 | |||
36 | def __init__(self, columns, rows): |
||
37 | """Initialize the Screen instance.""" |
||
38 | self.columns = columns |
||
39 | self.rows = rows |
||
40 | self.row = 0 |
||
41 | self.col = 0 |
||
42 | self.top = 0 |
||
43 | self.bot = rows - 1 |
||
44 | self.left = 0 |
||
45 | self.right = columns - 1 |
||
46 | self._cells = [[Cell() for c in range(columns)] for r in range(rows)] |
||
47 | |||
48 | def clear(self): |
||
49 | """Clear the screen.""" |
||
50 | self._clear_region(self.top, self.bot, self.left, self.right) |
||
51 | |||
52 | def eol_clear(self): |
||
53 | """Clear from the cursor position to the end of the scroll region.""" |
||
54 | self._clear_region(self.row, self.row, self.col, self.right) |
||
55 | |||
56 | def cursor_goto(self, row, col): |
||
57 | """Change the virtual cursor position.""" |
||
58 | self.row = row |
||
59 | self.col = col |
||
60 | |||
61 | def set_scroll_region(self, top, bot, left, right): |
||
62 | """Change scroll region.""" |
||
63 | self.top = top |
||
64 | self.bot = bot |
||
65 | self.left = left |
||
66 | self.right = right |
||
67 | |||
68 | def scroll(self, count): |
||
69 | """Shift scroll region.""" |
||
70 | top, bot = self.top, self.bot |
||
71 | left, right = self.left, self.right |
||
72 | if count > 0: |
||
73 | start = top |
||
74 | stop = bot - count + 1 |
||
75 | step = 1 |
||
76 | else: |
||
77 | start = bot |
||
78 | stop = top - count - 1 |
||
79 | step = -1 |
||
80 | # shift the cells |
||
81 | for row in range(start, stop, step): |
||
82 | target_row = self._cells[row] |
||
83 | source_row = self._cells[row + count] |
||
84 | for col in range(left, right + 1): |
||
85 | tgt = target_row[col] |
||
86 | source_row[col].copy(tgt) |
||
87 | # clear invalid cells |
||
88 | for row in range(stop, stop + count, step): |
||
89 | self._clear_region(row, row, left, right) |
||
90 | |||
91 | def put(self, text, attrs): |
||
92 | """Put character on virtual cursor position.""" |
||
93 | cell = self._cells[self.row][self.col] |
||
94 | cell.set(text, attrs) |
||
95 | self.cursor_goto(self.row, self.col + 1) |
||
96 | |||
97 | def get_cell(self, row, col): |
||
98 | """Get text, attrs at row, col.""" |
||
99 | return self._cells[row][col].get() |
||
100 | |||
101 | def get_cursor(self): |
||
102 | """Get text, attrs at the virtual cursor position.""" |
||
103 | return self.get_cell(self.row, self.col) |
||
104 | |||
105 | def iter(self, startrow, endrow, startcol, endcol): |
||
106 | """Extract text/attrs at row, startcol-endcol.""" |
||
107 | for row in range(startrow, endrow + 1): |
||
108 | r = self._cells[row] |
||
109 | cell = r[startcol] |
||
110 | curcol = startcol |
||
111 | attrs = cell.attrs |
||
112 | buf = [cell.text] |
||
113 | for col in range(startcol + 1, endcol + 1): |
||
114 | cell = r[col] |
||
115 | if cell.attrs != attrs or not cell.text: |
||
116 | yield row, curcol, ''.join(buf), attrs |
||
117 | attrs = cell.attrs |
||
118 | buf = [cell.text] |
||
119 | curcol = col |
||
120 | if not cell.text: |
||
121 | # glyph uses two cells, yield a separate entry |
||
122 | yield row, curcol, '', None |
||
123 | curcol += 1 |
||
124 | else: |
||
125 | buf.append(cell.text) |
||
126 | if buf: |
||
127 | yield row, curcol, ''.join(buf), attrs |
||
128 | |||
129 | def _clear_region(self, top, bot, left, right): |
||
130 | for rownum in range(top, bot + 1): |
||
131 | row = self._cells[rownum] |
||
132 | for colnum in range(left, right + 1): |
||
133 | cell = row[colnum] |
||
134 | cell.set(' ', None) |
||
135 |