Line data Source code
1 : /*
2 : Mosh: the mobile shell
3 : Copyright 2012 Keith Winstein
4 :
5 : This program is free software: you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as published by
7 : the Free Software Foundation, either version 3 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public License
16 : along with this program. If not, see <http://www.gnu.org/licenses/>.
17 :
18 : In addition, as a special exception, the copyright holders give
19 : permission to link the code of portions of this program with the
20 : OpenSSL library under certain conditions as described in each
21 : individual source file, and distribute linked combinations including
22 : the two.
23 :
24 : You must obey the GNU General Public License in all respects for all
25 : of the code used other than OpenSSL. If you modify file(s) with this
26 : exception, you may extend this exception to your version of the
27 : file(s), but you are not obligated to do so. If you do not wish to do
28 : so, delete this exception statement from your version. If you delete
29 : this exception statement from all source files in the program, then
30 : also delete it here.
31 : */
32 :
33 : #include <unistd.h>
34 : #include <algorithm>
35 : #include <string>
36 : #include <stdio.h>
37 :
38 : #include "terminaldispatcher.h"
39 : #include "terminalframebuffer.h"
40 : #include "parseraction.h"
41 :
42 : using namespace Terminal;
43 :
44 : /* Terminal functions -- routines activated by CSI, escape or a control char */
45 :
46 2562 : static void clearline( Framebuffer *fb, int row, int start, int end )
47 : {
48 154116 : for ( int col = start; col <= end; col++ ) {
49 151554 : fb->reset_cell( fb->get_mutable_cell( row, col ) );
50 : }
51 2562 : }
52 :
53 : /* erase in line */
54 2522 : static void CSI_EL( Framebuffer *fb, Dispatcher *dispatch )
55 : {
56 2522 : switch ( dispatch->getparam( 0, 0 ) ) {
57 2522 : case 0: /* default: active position to end of line, inclusive */
58 2522 : clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
59 2522 : break;
60 0 : case 1: /* start of screen to active position, inclusive */
61 0 : clearline( fb, -1, 0, fb->ds.get_cursor_col() );
62 0 : break;
63 0 : case 2: /* all of line */
64 0 : fb->reset_row( fb->get_mutable_row( -1 ) );
65 : break;
66 : default:
67 : break;
68 : }
69 2522 : }
70 :
71 : static Function func_CSI_EL( CSI, "K", CSI_EL );
72 :
73 : /* erase in display */
74 216 : static void CSI_ED( Framebuffer *fb, Dispatcher *dispatch ) {
75 216 : switch ( dispatch->getparam( 0, 0 ) ) {
76 38 : case 0: /* active position to end of screen, inclusive */
77 38 : clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
78 906 : for ( int y = fb->ds.get_cursor_row() + 1; y < fb->ds.get_height(); y++ ) {
79 868 : fb->reset_row( fb->get_mutable_row( y ) );
80 : }
81 : break;
82 : case 1: /* start of screen to active position, inclusive */
83 4 : for ( int y = 0; y < fb->ds.get_cursor_row(); y++ ) {
84 2 : fb->reset_row( fb->get_mutable_row( y ) );
85 : }
86 2 : clearline( fb, -1, 0, fb->ds.get_cursor_col() );
87 2 : break;
88 : case 2: /* entire screen */
89 3760 : for ( int y = 0; y < fb->ds.get_height(); y++ ) {
90 3584 : fb->reset_row( fb->get_mutable_row( y ) );
91 : }
92 : break;
93 : default:
94 : break;
95 : }
96 216 : }
97 :
98 : static Function func_CSI_ED( CSI, "J", CSI_ED );
99 :
100 : /* cursor movement -- relative and absolute */
101 3761 : static void CSI_cursormove( Framebuffer *fb, Dispatcher *dispatch )
102 : {
103 3761 : int num = dispatch->getparam( 0, 1 );
104 :
105 3761 : switch ( dispatch->get_dispatch_chars()[ 0 ] ) {
106 0 : case 'A':
107 0 : fb->ds.move_row( -num, true );
108 0 : break;
109 0 : case 'B':
110 0 : fb->ds.move_row( num, true );
111 0 : break;
112 0 : case 'C':
113 0 : fb->ds.move_col( num, true );
114 0 : break;
115 0 : case 'D':
116 0 : fb->ds.move_col( -num, true );
117 0 : break;
118 3761 : case 'H':
119 3761 : case 'f':
120 3761 : fb->ds.move_row( dispatch->getparam( 0, 1 ) - 1 );
121 3761 : fb->ds.move_col( dispatch->getparam( 1, 1 ) - 1 );
122 3761 : break;
123 : default:
124 : break;
125 : }
126 3761 : }
127 :
128 : static Function func_CSI_cursormove_A( CSI, "A", CSI_cursormove );
129 : static Function func_CSI_cursormove_B( CSI, "B", CSI_cursormove );
130 : static Function func_CSI_cursormove_C( CSI, "C", CSI_cursormove );
131 : static Function func_CSI_cursormove_D( CSI, "D", CSI_cursormove );
132 : static Function func_CSI_cursormove_H( CSI, "H", CSI_cursormove );
133 : static Function func_CSI_cursormove_f( CSI, "f", CSI_cursormove );
134 :
135 : /* device attributes */
136 0 : static void CSI_DA( Framebuffer *fb __attribute((unused)), Dispatcher *dispatch )
137 : {
138 0 : dispatch->terminal_to_host.append( "\033[?62c" ); /* plain vt220 */
139 0 : }
140 :
141 : static Function func_CSI_DA( CSI, "c", CSI_DA );
142 :
143 : /* secondary device attributes */
144 0 : static void CSI_SDA( Framebuffer *fb __attribute((unused)), Dispatcher *dispatch )
145 : {
146 0 : dispatch->terminal_to_host.append( "\033[>1;10;0c" ); /* plain vt220 */
147 0 : }
148 :
149 : static Function func_CSI_SDA( CSI, ">c", CSI_SDA );
150 :
151 : /* screen alignment diagnostic */
152 0 : static void Esc_DECALN( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
153 : {
154 0 : for ( int y = 0; y < fb->ds.get_height(); y++ ) {
155 0 : for ( int x = 0; x < fb->ds.get_width(); x++ ) {
156 0 : fb->reset_cell( fb->get_mutable_cell( y, x ) );
157 0 : fb->get_mutable_cell( y, x )->append( 'E' );
158 : }
159 : }
160 0 : }
161 :
162 : static Function func_Esc_DECALN( ESCAPE, "#8", Esc_DECALN );
163 :
164 : /* line feed */
165 23937259 : static void Ctrl_LF( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
166 : {
167 23937259 : fb->move_rows_autoscroll( 1 );
168 23937259 : }
169 :
170 : /* same procedure for index, vertical tab, and form feed control codes */
171 : static Function func_Ctrl_LF( CONTROL, "\x0a", Ctrl_LF );
172 : static Function func_Ctrl_IND( CONTROL, "\x84", Ctrl_LF );
173 : static Function func_Ctrl_VT( CONTROL, "\x0b", Ctrl_LF );
174 : static Function func_Ctrl_FF( CONTROL, "\x0c", Ctrl_LF );
175 :
176 : /* carriage return */
177 23936095 : static void Ctrl_CR( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
178 : {
179 23936095 : fb->ds.move_col( 0 );
180 23936095 : }
181 :
182 : static Function func_Ctrl_CR( CONTROL, "\x0d", Ctrl_CR );
183 :
184 : /* backspace */
185 94 : static void Ctrl_BS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
186 : {
187 94 : fb->ds.move_col( -1, true );
188 94 : }
189 :
190 : static Function func_Ctrl_BS( CONTROL, "\x08", Ctrl_BS );
191 :
192 : /* reverse index -- like a backwards line feed */
193 0 : static void Ctrl_RI( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
194 : {
195 0 : fb->move_rows_autoscroll( -1 );
196 0 : }
197 :
198 : static Function func_Ctrl_RI( CONTROL, "\x8D", Ctrl_RI );
199 :
200 : /* newline */
201 0 : static void Ctrl_NEL( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
202 : {
203 0 : fb->ds.move_col( 0 );
204 0 : fb->move_rows_autoscroll( 1 );
205 0 : }
206 :
207 : static Function func_Ctrl_NEL( CONTROL, "\x85", Ctrl_NEL );
208 :
209 : /* horizontal tab */
210 10 : static void HT_n( Framebuffer *fb, size_t count )
211 : {
212 10 : int col = fb->ds.get_next_tab( count );
213 10 : if ( col == -1 ) { /* no tabs, go to end of line */
214 2 : col = fb->ds.get_width() - 1;
215 : }
216 :
217 : /* A horizontal tab is the only operation that preserves but
218 : does not set the wrap state. It also starts a new grapheme. */
219 :
220 10 : bool wrap_state_save = fb->ds.next_print_will_wrap;
221 10 : fb->ds.move_col( col, false );
222 10 : fb->ds.next_print_will_wrap = wrap_state_save;
223 10 : }
224 :
225 0 : static void Ctrl_HT( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
226 : {
227 0 : HT_n( fb, 1 );
228 0 : }
229 : static Function func_Ctrl_HT( CONTROL, "\x09", Ctrl_HT, false );
230 :
231 10 : static void CSI_CxT( Framebuffer *fb, Dispatcher *dispatch )
232 : {
233 10 : int param = dispatch->getparam( 0, 1 );
234 10 : if ( dispatch->get_dispatch_chars()[ 0 ] == 'Z' ) {
235 6 : param = -param;
236 : }
237 10 : if ( param == 0 ) {
238 : return;
239 : }
240 10 : HT_n( fb, param );
241 : }
242 :
243 : static Function func_CSI_CHT( CSI, "I", CSI_CxT, false );
244 : static Function func_CSI_CBT( CSI, "Z", CSI_CxT, false );
245 :
246 : /* horizontal tab set */
247 0 : static void Ctrl_HTS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
248 : {
249 0 : fb->ds.set_tab();
250 0 : }
251 :
252 : static Function func_Ctrl_HTS( CONTROL, "\x88", Ctrl_HTS );
253 :
254 : /* tabulation clear */
255 0 : static void CSI_TBC( Framebuffer *fb, Dispatcher *dispatch )
256 : {
257 0 : int param = dispatch->getparam( 0, 0 );
258 0 : switch ( param ) {
259 0 : case 0: /* clear this tab stop */
260 0 : fb->ds.clear_tab( fb->ds.get_cursor_col() );
261 0 : break;
262 0 : case 3: /* clear all tab stops */
263 0 : fb->ds.clear_default_tabs();
264 0 : for ( int x = 0; x < fb->ds.get_width(); x++ ) {
265 0 : fb->ds.clear_tab( x );
266 : }
267 : break;
268 : default:
269 : break;
270 : }
271 0 : }
272 :
273 : /* TBC preserves wrap state */
274 : static Function func_CSI_TBC( CSI, "g", CSI_TBC, false );
275 :
276 8616 : static bool *get_DEC_mode( int param, Framebuffer *fb ) {
277 8616 : switch ( param ) {
278 4 : case 1: /* cursor key mode */
279 4 : return &(fb->ds.application_mode_cursor_keys);
280 0 : case 3: /* 80/132. Ignore but clear screen. */
281 : /* clear screen */
282 0 : fb->ds.move_row( 0 );
283 0 : fb->ds.move_col( 0 );
284 0 : for ( int y = 0; y < fb->ds.get_height(); y++ ) {
285 0 : fb->reset_row( fb->get_mutable_row( y ) );
286 : }
287 : return NULL;
288 0 : case 5: /* reverse video */
289 0 : return &(fb->ds.reverse_video);
290 0 : case 6: /* origin */
291 0 : fb->ds.move_row( 0 );
292 0 : fb->ds.move_col( 0 );
293 0 : return &(fb->ds.origin_mode);
294 0 : case 7: /* auto wrap */
295 0 : return &(fb->ds.auto_wrap_mode);
296 8408 : case 25:
297 8408 : return &(fb->ds.cursor_visible);
298 88 : case 1004: /* xterm mouse focus event */
299 88 : return &(fb->ds.mouse_focus_event);
300 0 : case 1007: /* xterm mouse alternate scroll */
301 0 : return &(fb->ds.mouse_alternate_scroll);
302 112 : case 2004: /* bracketed paste */
303 112 : return &(fb->ds.bracketed_paste);
304 : default:
305 : break;
306 : }
307 : return NULL;
308 : }
309 :
310 : /* helper for CSI_DECSM and CSI_DECRM */
311 8616 : static void set_if_available( bool *mode, bool value )
312 : {
313 8612 : if ( mode ) { *mode = value; }
314 : }
315 :
316 : /* set private mode */
317 4220 : static void CSI_DECSM( Framebuffer *fb, Dispatcher *dispatch )
318 : {
319 8440 : for ( int i = 0; i < dispatch->param_count(); i++ ) {
320 4220 : int param = dispatch->getparam( i, 0 );
321 4220 : if (param == 9 || (param >= 1000 && param <= 1003)) {
322 0 : fb->ds.mouse_reporting_mode = (Terminal::DrawState::MouseReportingMode) param;
323 4220 : } else if (param == 1005 || param == 1006 || param == 1015) {
324 0 : fb->ds.mouse_encoding_mode = (Terminal::DrawState::MouseEncodingMode) param;
325 : } else {
326 8438 : set_if_available( get_DEC_mode( param, fb ), true );
327 : }
328 : }
329 4220 : }
330 :
331 : /* clear private mode */
332 5012 : static void CSI_DECRM( Framebuffer *fb, Dispatcher *dispatch )
333 : {
334 10024 : for ( int i = 0; i < dispatch->param_count(); i++ ) {
335 5012 : int param = dispatch->getparam( i, 0 );
336 5012 : if (param == 9 || (param >= 1000 && param <= 1003)) {
337 352 : fb->ds.mouse_reporting_mode = Terminal::DrawState::MOUSE_REPORTING_NONE;
338 4660 : } else if (param == 1005 || param == 1006 || param == 1015) {
339 264 : fb->ds.mouse_encoding_mode = Terminal::DrawState::MOUSE_ENCODING_DEFAULT;
340 : } else {
341 9406 : set_if_available( get_DEC_mode( param, fb ), false );
342 : }
343 : }
344 5012 : }
345 :
346 : /* These functions don't clear wrap state. */
347 : static Function func_CSI_DECSM( CSI, "?h", CSI_DECSM, false );
348 : static Function func_CSI_DECRM( CSI, "?l", CSI_DECRM, false );
349 :
350 0 : static bool *get_ANSI_mode( int param, Framebuffer *fb ) {
351 0 : if ( param == 4 ) { /* insert/replace mode */
352 0 : return &(fb->ds.insert_mode);
353 : }
354 : return NULL;
355 : }
356 :
357 : /* set mode */
358 0 : static void CSI_SM( Framebuffer *fb, Dispatcher *dispatch )
359 : {
360 0 : for ( int i = 0; i < dispatch->param_count(); i++ ) {
361 0 : bool *mode = get_ANSI_mode( dispatch->getparam( i, 0 ), fb );
362 0 : if ( mode ) {
363 0 : *mode = true;
364 : }
365 : }
366 0 : }
367 :
368 : /* clear mode */
369 0 : static void CSI_RM( Framebuffer *fb, Dispatcher *dispatch )
370 : {
371 0 : for ( int i = 0; i < dispatch->param_count(); i++ ) {
372 0 : bool *mode = get_ANSI_mode( dispatch->getparam( i, 0 ), fb );
373 0 : if ( mode ) {
374 0 : *mode = false;
375 : }
376 : }
377 0 : }
378 :
379 : static Function func_CSI_SM( CSI, "h", CSI_SM );
380 : static Function func_CSI_RM( CSI, "l", CSI_RM );
381 :
382 : /* set top and bottom margins */
383 144 : static void CSI_DECSTBM( Framebuffer *fb, Dispatcher *dispatch )
384 : {
385 144 : int top = dispatch->getparam( 0, 1 );
386 144 : int bottom = dispatch->getparam( 1, fb->ds.get_height() );
387 :
388 144 : if ( (bottom <= top)
389 144 : || (top > fb->ds.get_height())
390 288 : || (top == 0 && bottom == 1) ) {
391 : return; /* invalid, xterm ignores */
392 : }
393 :
394 144 : fb->ds.set_scrolling_region( top - 1, bottom - 1 );
395 144 : fb->ds.move_row( 0 );
396 144 : fb->ds.move_col( 0 );
397 : }
398 :
399 : static Function func_CSI_DECSTMB( CSI, "r", CSI_DECSTBM );
400 :
401 : /* terminal bell */
402 0 : static void Ctrl_BEL( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) ) {
403 0 : fb->ring_bell();
404 0 : }
405 :
406 : static Function func_Ctrl_BEL( CONTROL, "\x07", Ctrl_BEL );
407 :
408 : /* select graphics rendition -- e.g., bold, blinking, etc. */
409 14092 : static void CSI_SGR( Framebuffer *fb, Dispatcher *dispatch )
410 : {
411 39422 : for ( int i = 0; i < dispatch->param_count(); i++ ) {
412 25330 : int rendition = dispatch->getparam( i, 0 );
413 : /* We need to special-case the handling of [34]8 ; 5 ; Ps,
414 : because Ps of 0 in that case does not mean reset to default, even
415 : though it means that otherwise (as usually renditions are applied
416 : in order). */
417 38756 : if ((rendition == 38 || rendition == 48) &&
418 35742 : (dispatch->param_count() - i >= 3) &&
419 10412 : (dispatch->getparam( i+1, -1 ) == 5)) {
420 3014 : (rendition == 38) ?
421 1504 : fb->ds.set_foreground_color( dispatch->getparam( i+2, 0 ) ) :
422 1510 : fb->ds.set_background_color( dispatch->getparam( i+2, 0 ) );
423 3014 : i += 2;
424 3014 : continue;
425 : }
426 :
427 : /* True color support: ESC[ ... [34]8;2;<r>;<g>;<b> ... m */
428 29714 : if ( (rendition == 38 || rendition == 48) &&
429 29714 : (dispatch->param_count() - i >= 5) &&
430 7398 : (dispatch->getparam( i+1, -1 ) == 2)) {
431 7398 : unsigned int red = dispatch->getparam(i+2, 0);
432 7398 : unsigned int green = dispatch->getparam(i+3, 0);
433 7398 : unsigned int blue = dispatch->getparam(i+4, 0);
434 7398 : unsigned int color;
435 :
436 7398 : color = Renditions::make_true_color( red, green, blue );
437 :
438 7398 : if ( rendition == 38 ) {
439 3696 : fb->ds.set_foreground_color( color );
440 : } else {
441 3702 : fb->ds.set_background_color( color );
442 : }
443 7398 : i += 4;
444 7398 : continue;
445 7398 : }
446 :
447 25330 : fb->ds.add_rendition( rendition );
448 : }
449 14092 : }
450 :
451 : static Function func_CSI_SGR( CSI, "m", CSI_SGR, false ); /* changing renditions doesn't clear wrap flag */
452 :
453 : /* save and restore cursor */
454 0 : static void Esc_DECSC( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
455 : {
456 0 : fb->ds.save_cursor();
457 0 : }
458 :
459 0 : static void Esc_DECRC( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
460 : {
461 0 : fb->ds.restore_cursor();
462 0 : }
463 :
464 : static Function func_Esc_DECSC( ESCAPE, "7", Esc_DECSC );
465 : static Function func_Esc_DECRC( ESCAPE, "8", Esc_DECRC );
466 :
467 : /* device status report -- e.g., cursor position (used by resize) */
468 0 : static void CSI_DSR( Framebuffer *fb, Dispatcher *dispatch )
469 : {
470 0 : int param = dispatch->getparam( 0, 0 );
471 :
472 0 : switch ( param ) {
473 0 : case 5: /* device status report requested */
474 0 : dispatch->terminal_to_host.append( "\033[0n" );
475 : break;
476 0 : case 6: /* report of active position requested */
477 0 : char cpr[ 32 ];
478 0 : snprintf( cpr, 32, "\033[%d;%dR",
479 0 : fb->ds.get_cursor_row() + 1,
480 0 : fb->ds.get_cursor_col() + 1 );
481 0 : dispatch->terminal_to_host.append( cpr );
482 : break;
483 : default:
484 : break;
485 : }
486 0 : }
487 :
488 : static Function func_CSI_DSR( CSI, "n", CSI_DSR );
489 :
490 : /* insert line */
491 16 : static void CSI_IL( Framebuffer *fb, Dispatcher *dispatch )
492 : {
493 16 : int lines = dispatch->getparam( 0, 1 );
494 :
495 16 : fb->insert_line( fb->ds.get_cursor_row(), lines );
496 :
497 : /* vt220 manual and Ecma-48 say to move to first column */
498 : /* but xterm and gnome-terminal don't */
499 16 : fb->ds.move_col( 0 );
500 16 : }
501 :
502 : static Function func_CSI_IL( CSI, "L", CSI_IL );
503 :
504 : /* delete line */
505 16 : static void CSI_DL( Framebuffer *fb, Dispatcher *dispatch )
506 : {
507 16 : int lines = dispatch->getparam( 0, 1 );
508 :
509 16 : fb->delete_line( fb->ds.get_cursor_row(), lines );
510 :
511 : /* same story -- xterm and gnome-terminal don't
512 : move to first column */
513 16 : fb->ds.move_col( 0 );
514 16 : }
515 :
516 : static Function func_CSI_DL( CSI, "M", CSI_DL );
517 :
518 : /* insert characters */
519 0 : static void CSI_ICH( Framebuffer *fb, Dispatcher *dispatch )
520 : {
521 0 : int cells = dispatch->getparam( 0, 1 );
522 :
523 0 : for ( int i = 0; i < cells; i++ ) {
524 0 : fb->insert_cell( fb->ds.get_cursor_row(), fb->ds.get_cursor_col() );
525 : }
526 0 : }
527 :
528 : static Function func_CSI_ICH( CSI, "@", CSI_ICH );
529 :
530 : /* delete character */
531 0 : static void CSI_DCH( Framebuffer *fb, Dispatcher *dispatch )
532 : {
533 0 : int cells = dispatch->getparam( 0, 1 );
534 :
535 0 : for ( int i = 0; i < cells; i++ ) {
536 0 : fb->delete_cell( fb->ds.get_cursor_row(), fb->ds.get_cursor_col() );
537 : }
538 0 : }
539 :
540 : static Function func_CSI_DCH( CSI, "P", CSI_DCH );
541 :
542 : /* line position absolute */
543 0 : static void CSI_VPA( Framebuffer *fb, Dispatcher *dispatch )
544 : {
545 0 : int row = dispatch->getparam( 0, 1 );
546 0 : fb->ds.move_row( row - 1 );
547 0 : }
548 :
549 : static Function func_CSI_VPA( CSI, "d", CSI_VPA );
550 :
551 : /* character position absolute */
552 0 : static void CSI_HPA( Framebuffer *fb, Dispatcher *dispatch )
553 : {
554 0 : int col = dispatch->getparam( 0, 1 );
555 0 : fb->ds.move_col( col - 1 );
556 0 : }
557 :
558 : static Function func_CSI_CHA( CSI, "G", CSI_HPA ); /* ECMA-48 name: CHA */
559 : static Function func_CSI_HPA( CSI, "\x60", CSI_HPA ); /* ECMA-48 name: HPA */
560 :
561 : /* erase character */
562 0 : static void CSI_ECH( Framebuffer *fb, Dispatcher *dispatch )
563 : {
564 0 : int num = dispatch->getparam( 0, 1 );
565 0 : int limit = fb->ds.get_cursor_col() + num - 1;
566 0 : if ( limit >= fb->ds.get_width() ) {
567 0 : limit = fb->ds.get_width() - 1;
568 : }
569 :
570 0 : clearline( fb, -1, fb->ds.get_cursor_col(), limit );
571 0 : }
572 :
573 : static Function func_CSI_ECH( CSI, "X", CSI_ECH );
574 :
575 : /* reset to initial state */
576 0 : static void Esc_RIS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
577 : {
578 0 : fb->reset();
579 0 : }
580 :
581 : static Function func_Esc_RIS( ESCAPE, "c", Esc_RIS );
582 :
583 : /* soft reset */
584 0 : static void CSI_DECSTR( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
585 : {
586 0 : fb->soft_reset();
587 0 : }
588 :
589 : static Function func_CSI_DECSTR( CSI, "!p", CSI_DECSTR );
590 :
591 : /* xterm uses an Operating System Command to set the window title */
592 0 : void Dispatcher::OSC_dispatch( const Parser::OSC_End *act __attribute((unused)), Framebuffer *fb )
593 : {
594 : /* handle osc copy clipboard sequence 52;c; */
595 0 : if ( OSC_string.size() >= 5 && OSC_string[ 0 ] == L'5' &&
596 0 : OSC_string[ 1 ] == L'2' && OSC_string[ 2 ] == L';' &&
597 0 : OSC_string[ 3 ] == L'c' && OSC_string[ 4 ] == L';') {
598 0 : Terminal::Framebuffer::title_type clipboard(
599 0 : OSC_string.begin() + 5, OSC_string.end() );
600 0 : fb->set_clipboard( clipboard );
601 : /* handle osc terminal title sequence */
602 0 : } else if ( OSC_string.size() >= 1 ) {
603 0 : long cmd_num = -1;
604 0 : int offset = 0;
605 0 : if ( OSC_string[ 0 ] == L';' ) {
606 : /* OSC of the form "\033];<title>\007" */
607 : cmd_num = 0; /* treat it as as a zero */
608 : offset = 1;
609 0 : } else if ( (OSC_string.size() >= 2) && (OSC_string[ 1 ] == L';') ) {
610 : /* OSC of the form "\033]X;<title>\007" where X can be:
611 : * 0: set icon name and window title
612 : * 1: set icon name
613 : * 2: set window title */
614 0 : cmd_num = OSC_string[ 0 ] - L'0';
615 0 : offset = 2;
616 : }
617 0 : bool set_icon = cmd_num == 0 || cmd_num == 1;
618 0 : bool set_title = cmd_num == 0 || cmd_num == 2;
619 0 : if ( set_icon || set_title ) {
620 0 : fb->set_title_initialized();
621 0 : int title_length = std::min(OSC_string.size(), (size_t)256);
622 0 : Terminal::Framebuffer::title_type newtitle( OSC_string.begin() + offset, OSC_string.begin() + title_length );
623 0 : if ( set_icon ) { fb->set_icon_name( newtitle ); }
624 0 : if ( set_title ) { fb->set_window_title( newtitle ); }
625 0 : }
626 : }
627 0 : }
628 :
629 : /* scroll down or terminfo indn */
630 2 : static void CSI_SD( Framebuffer *fb, Dispatcher *dispatch )
631 : {
632 2 : fb->scroll( dispatch->getparam( 0, 1 ) );
633 2 : }
634 :
635 : static Function func_CSI_SD( CSI, "S", CSI_SD );
636 :
637 : /* scroll up or terminfo rin */
638 2 : static void CSI_SU( Framebuffer *fb, Dispatcher *dispatch )
639 : {
640 2 : fb->scroll( -dispatch->getparam( 0, 1 ) );
641 2 : }
642 :
643 : static Function func_CSI_SU( CSI, "T", CSI_SU );
|