|
17 | 17 | # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
18 | 18 | # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
19 | 19 |
|
20 |
| -import curses |
21 | 20 | import termios
|
22 | 21 |
|
23 | 22 |
|
24 |
| -class InvalidTerminal(RuntimeError): |
25 |
| - pass |
26 |
| - |
27 |
| - |
28 | 23 | class TermState:
|
29 | 24 | def __init__(self, tuples):
|
30 | 25 | (
|
@@ -60,212 +55,20 @@ def tcsetattr(fd, when, attrs):
|
60 | 55 | termios.tcsetattr(fd, when, attrs.as_list())
|
61 | 56 |
|
62 | 57 |
|
63 |
| -class TermCapability: |
64 |
| - """Base class for all terminal capabilities we need""" |
65 |
| - |
66 |
| - def __init__(self, buffer): |
67 |
| - self._buffer = buffer |
68 |
| - self._args = [] |
69 |
| - |
70 |
| - self._bytes = curses.tigetstr(self.name) |
71 |
| - if self._bytes is None and not self.optional: |
72 |
| - raise InvalidTerminal( |
73 |
| - f"terminal doesn't have the required {self.name!r} capability" |
74 |
| - ) |
75 |
| - |
76 |
| - self.supported = self._bytes is not None |
77 |
| - |
78 |
| - def __call__(self, *args): |
79 |
| - if self.supported: |
80 |
| - self._args = args |
81 |
| - self._buffer.push(self) |
82 |
| - |
83 |
| - def text(self): |
84 |
| - return curses.tparm(self._bytes, *self._args) |
85 |
| - |
86 |
| - |
87 |
| -class Bell(TermCapability): |
88 |
| - """Audible signal (bell)""" |
89 |
| - |
90 |
| - name = "bel" |
91 |
| - optional = False |
92 |
| - |
93 |
| - |
94 |
| -class CursorInvisible(TermCapability): |
95 |
| - """Make cursor invisible""" |
96 |
| - |
97 |
| - name = "civis" |
98 |
| - optional = True |
99 |
| - |
100 |
| - |
101 |
| -class ClearScreen(TermCapability): |
102 |
| - """Clear screen and home cursor""" |
103 |
| - |
104 |
| - name = "clear" |
105 |
| - optional = False |
106 |
| - |
107 |
| - |
108 |
| -class CursorNormal(TermCapability): |
109 |
| - """Make cursor appear normal (undo civis/cvvis)""" |
110 |
| - |
111 |
| - name = "cnorm" |
112 |
| - optional = True |
113 |
| - |
114 |
| - |
115 |
| -class ParmLeftCursor(TermCapability): |
116 |
| - """Move #1 characters to the left""" |
117 |
| - |
118 |
| - name = "cub" |
119 |
| - optional = True |
120 |
| - |
121 |
| - |
122 |
| -class CursorLeft(TermCapability): |
123 |
| - """Move left one space""" |
124 |
| - |
125 |
| - name = "cub1" |
126 |
| - optional = True |
127 |
| - |
128 |
| - def text(self): |
129 |
| - assert len(self._args) == 1 # cursor_down needs to have been called with dx |
130 |
| - return curses.tparm(self._args[0] * self._bytes) |
131 |
| - |
132 |
| - |
133 |
| -class ParmDownCursor(TermCapability): |
134 |
| - """Down #1 lines""" |
135 |
| - |
136 |
| - name = "cud" |
137 |
| - optional = True |
138 |
| - |
139 |
| - |
140 |
| -class CursorDown(TermCapability): |
141 |
| - """Down one line""" |
142 |
| - |
143 |
| - name = "cud1" |
144 |
| - optional = True |
145 |
| - |
146 |
| - def text(self): |
147 |
| - assert len(self._args) == 1 # cursor_down needs to have been called with dy |
148 |
| - return curses.tparm(self._args[0] * self._bytes) |
149 |
| - |
150 |
| - |
151 |
| -class ParmRightCursor(TermCapability): |
152 |
| - """Move #1 characters to the right""" |
153 |
| - |
154 |
| - name = "cuf" |
155 |
| - optional = True |
156 |
| - |
157 |
| - |
158 |
| -class CursorRight(TermCapability): |
159 |
| - """Non-destructive space (move right one space)""" |
160 |
| - |
161 |
| - name = "cuf1" |
162 |
| - optional = True |
163 |
| - |
164 |
| - def text(self): |
165 |
| - assert len(self._args) == 1 # cursor_down needs to have been called with dx |
166 |
| - return curses.tparm(self._args[0] * self._bytes) |
167 |
| - |
168 |
| - |
169 |
| -class CursorAddress(TermCapability): |
170 |
| - """Move to row #1 columns #2""" |
171 |
| - |
172 |
| - name = "cup" |
173 |
| - optional = False |
174 |
| - |
175 |
| - |
176 |
| -class ParmUpCursor(TermCapability): |
177 |
| - """Up #1 lines""" |
178 |
| - |
179 |
| - name = "cuu" |
180 |
| - optional = True |
181 |
| - |
182 |
| - |
183 |
| -class CursorUp(TermCapability): |
184 |
| - """Up 1 line""" |
185 |
| - |
186 |
| - name = "cuu1" |
187 |
| - optional = True |
188 |
| - |
189 |
| - def text(self): |
190 |
| - assert len(self._args) == 1 # cursor_down needs to have been called with dy |
191 |
| - return curses.tparm(self._args[0] * self._bytes) |
192 |
| - |
193 |
| - |
194 |
| -class ParmDeleteCharacter(TermCapability): |
195 |
| - """Delete #1 characters""" |
196 |
| - |
197 |
| - name = "dch" |
198 |
| - optional = True |
199 |
| - |
200 |
| - |
201 |
| -class DeleteCharacter(TermCapability): |
202 |
| - """Delete character""" |
203 |
| - |
204 |
| - name = "dch1" |
205 |
| - optional = True |
206 |
| - |
207 |
| - |
208 |
| -class ClearEol(TermCapability): |
209 |
| - """Clear to end of line""" |
210 |
| - |
211 |
| - name = "el" |
212 |
| - optional = False |
213 |
| - |
214 |
| - |
215 |
| -class ColumnAddress(TermCapability): |
216 |
| - """Horizontal position #1, absolute""" |
217 |
| - |
218 |
| - name = "hpa" |
219 |
| - optional = True |
220 |
| - |
221 |
| - |
222 |
| -class ParmInsertCharacter(TermCapability): |
223 |
| - """Insert #1 characters""" |
224 |
| - |
225 |
| - name = "ich" |
226 |
| - optional = True |
227 |
| - |
228 |
| - |
229 |
| -class InsertCharacter(TermCapability): |
230 |
| - """Insert character""" |
231 |
| - |
232 |
| - name = "ich1" |
233 |
| - optional = True |
234 |
| - |
235 |
| - |
236 |
| -class ScrollForward(TermCapability): |
237 |
| - """Scroll text up""" |
238 |
| - |
239 |
| - name = "ind" |
240 |
| - optional = True |
241 |
| - |
242 |
| - |
243 |
| -class PadChar(TermCapability): |
244 |
| - """Padding char (instead of null)""" |
245 |
| - |
246 |
| - name = "pad" |
247 |
| - optional = True |
248 |
| - |
249 |
| - def text(self, nchars): |
250 |
| - return self._bytes * nchars |
251 |
| - |
252 |
| - |
253 |
| -class ScrollReverse(TermCapability): |
254 |
| - """Scroll text down""" |
255 |
| - |
256 |
| - name = "ri" |
257 |
| - optional = True |
258 |
| - |
259 |
| - |
260 |
| -class KeypadLocal(TermCapability): |
261 |
| - """Leave 'keyboard_transmit' mode""" |
| 58 | +class Term(TermState): |
| 59 | + TS__init__ = TermState.__init__ |
262 | 60 |
|
263 |
| - name = "rmkx" |
264 |
| - optional = True |
| 61 | + def __init__(self, fd=0): |
| 62 | + self.TS__init__(termios.tcgetattr(fd)) |
| 63 | + self.fd = fd |
| 64 | + self.stack = [] |
265 | 65 |
|
| 66 | + def save(self): |
| 67 | + self.stack.append(self.as_list()) |
266 | 68 |
|
267 |
| -class KeypadXmit(TermCapability): |
268 |
| - """Enter 'keyboard_transmit' mode""" |
| 69 | + def set(self, when=termios.TCSANOW): |
| 70 | + termios.tcsetattr(self.fd, when, self.as_list()) |
269 | 71 |
|
270 |
| - name = "smkx" |
271 |
| - optional = True |
| 72 | + def restore(self): |
| 73 | + self.TS__init__(self.stack.pop()) |
| 74 | + self.set() |
0 commit comments