Remove the TUI execution info window
[deliverable/binutils-gdb.git] / gdb / testsuite / lib / tuiterm.exp
CommitLineData
c3786b3a
TT
1# Copyright 2019 Free Software Foundation, Inc.
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16# An ANSI terminal emulator for expect.
17
ded631d5
TT
18# The expect "spawn" function puts the tty name into the spawn_out
19# array; but dejagnu doesn't export this globally. So, we have to
20# wrap spawn with our own function, so that we can capture this value.
21# The value is later used in calls to stty.
22rename spawn builtin_spawn
23proc spawn {args} {
24 set result [uplevel builtin_spawn $args]
25 global gdb_spawn_name
26 upvar spawn_out spawn_out
27 set gdb_spawn_name $spawn_out(slave,name)
28 return $result
29}
30
c3786b3a
TT
31namespace eval Term {
32 variable _rows
33 variable _cols
34 variable _chars
35
36 variable _cur_x
37 variable _cur_y
38
39 variable _attrs
40
41 variable _last_char
42
43 # If ARG is empty, return DEF: otherwise ARG. This is useful for
44 # defaulting arguments in CSIs.
45 proc _default {arg def} {
46 if {$arg == ""} {
47 return $def
48 }
49 return $arg
50 }
51
52 # Erase in the line Y from SX to just before EX.
53 proc _clear_in_line {sx ex y} {
54 variable _attrs
55 variable _chars
56 set lattr [array get _attrs]
57 while {$sx < $ex} {
58 set _chars($sx,$y) [list " " $lattr]
59 incr sx
60 }
61 }
62
63 # Erase the lines from SY to just before EY.
64 proc _clear_lines {sy ey} {
65 variable _cols
66 while {$sy < $ey} {
67 _clear_in_line 0 $_cols $sy
68 incr sy
69 }
70 }
71
72 # Beep.
73 proc _ctl_0x07 {} {
74 }
75
76 # Backspace.
77 proc _ctl_0x08 {} {
78 variable _cur_x
79 incr _cur_x -1
80 if {$_cur_x < 0} {
81 variable _cur_y
82 variable _cols
83 set _cur_x [expr {$_cols - 1}]
84 incr _cur_y -1
85 if {$_cur_y < 0} {
86 set _cur_y 0
87 }
88 }
89 }
90
91 # Linefeed.
92 proc _ctl_0x0a {} {
93 variable _cur_y
94 variable _rows
95 incr _cur_y 1
96 if {$_cur_y >= $_rows} {
97 error "FIXME scroll"
98 }
99 }
100
101 # Carriage return.
102 proc _ctl_0x0d {} {
103 variable _cur_x
104 set _cur_x 0
105 }
106
3d235706
TT
107 # Make room for characters.
108 proc _csi_@ {args} {
109 set n [_default [lindex $args 0] 1]
110 variable _cur_x
111 variable _cur_y
112 variable _chars
113 set in_x $_cur_x
114 set out_x [expr {$_cur_x + $n}]
115 for {set i 0} {$i < $n} {incr i} {
116 set _chars($out_x,$_cur_y) $_chars($in_x,$_cur_y)
117 incr in_x
118 incr out_x
119 }
120 }
121
c3786b3a
TT
122 # Cursor Up.
123 proc _csi_A {args} {
124 variable _cur_y
125 set arg [_default [lindex $args 0] 1]
126 set _cur_y [expr {max ($_cur_y - $arg, 0)}]
127 }
128
129 # Cursor Down.
130 proc _csi_B {args} {
131 variable _cur_y
132 variable _rows
133 set arg [_default [lindex $args 0] 1]
134 set _cur_y [expr {min ($_cur_y + $arg, $_rows)}]
135 }
136
137 # Cursor Forward.
138 proc _csi_C {args} {
139 variable _cur_x
140 variable _cols
141 set arg [_default [lindex $args 0] 1]
142 set _cur_x [expr {min ($_cur_x + $arg, $_cols)}]
143 }
144
145 # Cursor Back.
146 proc _csi_D {args} {
147 variable _cur_x
148 set arg [_default [lindex $args 0] 1]
149 set _cur_x [expr {max ($_cur_x - $arg, 0)}]
150 }
151
152 # Cursor Next Line.
153 proc _csi_E {args} {
154 variable _cur_x
155 variable _cur_y
156 variable _rows
157 set arg [_default [lindex $args 0] 1]
158 set _cur_x 0
159 set _cur_y [expr {min ($_cur_y + $arg, $_rows)}]
160 }
161
162 # Cursor Previous Line.
163 proc _csi_F {args} {
164 variable _cur_x
165 variable _cur_y
166 variable _rows
167 set arg [_default [lindex $args 0] 1]
168 set _cur_x 0
169 set _cur_y [expr {max ($_cur_y - $arg, 0)}]
170 }
171
172 # Cursor Horizontal Absolute.
173 proc _csi_G {args} {
174 variable _cur_x
175 variable _cols
176 set arg [_default [lindex $args 0] 1]
177 set _cur_x [expr {min ($arg - 1, $_cols)}]
178 }
179
180 # Move cursor (don't know the official name of this one).
181 proc _csi_H {args} {
182 variable _cur_x
183 variable _cur_y
184 set _cur_y [expr {[_default [lindex $args 0] 1] - 1}]
185 set _cur_x [expr {[_default [lindex $args 1] 1] - 1}]
186 }
187
188 # Cursor Forward Tabulation.
189 proc _csi_I {args} {
190 set n [_default [lindex $args 0] 1]
191 variable _cur_x
192 variable _cols
193 incr _cur_x [expr {$n * 8 - $_cur_x % 8}]
194 if {$_cur_x >= $_cols} {
195 set _cur_x [expr {$_cols - 1}]
196 }
197 }
198
199 # Erase.
200 proc _csi_J {args} {
201 variable _cur_x
202 variable _cur_y
203 variable _rows
204 variable _cols
205 set arg [_default [lindex $args 0] 0]
206 if {$arg == 0} {
207 _clear_in_line $_cur_x $_cols $_cur_y
208 _clear_lines [expr {$_cur_y + 1}] $_rows
209 } elseif {$arg == 1} {
210 _clear_lines 0 [expr {$_cur_y - 1}]
211 _clear_in_line 0 $_cur_x $_cur_y
212 } elseif {$arg == 2} {
213 _clear_lines 0 $_rows
214 }
215 }
216
217 # Erase Line.
218 proc _csi_K {args} {
219 variable _cur_x
220 variable _cur_y
221 variable _cols
222 set arg [_default [lindex $args 0] 0]
223 if {$arg == 0} {
224 # From cursor to end.
225 _clear_in_line $_cur_x $_cols $_cur_y
226 } elseif {$arg == 1} {
227 _clear_in_line 0 $_cur_x $_cur_y
228 } elseif {$arg == 2} {
229 _clear_in_line 0 $_cols $_cur_y
230 }
231 }
232
233 # Delete lines.
234 proc _csi_M {args} {
235 variable _cur_y
236 variable _rows
237 variable _cols
238 variable _chars
239 set count [_default [lindex $args 0] 1]
240 set y $_cur_y
241 set next_y [expr {$y + 1}]
242 while {$count > 0 && $next_y < $_rows} {
243 for {set x 0} {$x < $_cols} {incr x} {
244 set _chars($x,$y) $_chars($x,$next_y)
245 }
246 incr y
247 incr next_y
248 incr count -1
249 }
250 _clear_lines $next_y $_rows
251 }
252
253 # Erase chars.
254 proc _csi_X {args} {
255 set n [_default [lindex $args 0] 1]
3d235706
TT
256 # Erase characters but don't move cursor.
257 variable _cur_x
258 variable _cur_y
259 variable _attrs
260 variable _chars
261 set lattr [array get _attrs]
262 set x $_cur_x
263 for {set i 0} {$i < $n} {incr i} {
264 set _chars($x,$_cur_y) [list " " $lattr]
265 incr x
266 }
c3786b3a
TT
267 }
268
398fdd60
TT
269 # Backward tab stops.
270 proc _csi_Z {args} {
271 set n [_default [lindex $args 0] 1]
272 variable _cur_x
273 set _cur_x [expr {max (int (($_cur_x - 1) / 8) * 8 - ($n - 1) * 8, 0)}]
274 }
275
c3786b3a
TT
276 # Repeat.
277 proc _csi_b {args} {
278 variable _last_char
279 set n [_default [lindex $args 0] 1]
280 _insert [string repeat $_last_char $n]
281 }
282
283 # Line Position Absolute.
284 proc _csi_d {args} {
285 variable _cur_y
286 set _cur_y [expr {[_default [lindex $args 0] 1] - 1}]
287 }
288
289 # Select Graphic Rendition.
290 proc _csi_m {args} {
291 variable _attrs
292 foreach item $args {
293 switch -exact -- $item {
294 "" - 0 {
295 set _attrs(intensity) normal
296 set _attrs(fg) default
297 set _attrs(bg) default
298 set _attrs(underline) 0
299 set _attrs(reverse) 0
300 }
301 1 {
302 set _attrs(intensity) bold
303 }
304 2 {
305 set _attrs(intensity) dim
306 }
307 4 {
308 set _attrs(underline) 1
309 }
310 7 {
311 set _attrs(reverse) 1
312 }
313 22 {
314 set _attrs(intensity) normal
315 }
316 24 {
317 set _attrs(underline) 0
318 }
319 27 {
320 set _attrs(reverse) 1
321 }
322 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 {
323 set _attrs(fg) $item
324 }
325 39 {
326 set _attrs(fg) default
327 }
328 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 {
329 set _attrs(bg) $item
330 }
331 49 {
332 set _attrs(bg) default
333 }
334 }
335 }
336 }
337
338 # Insert string at the cursor location.
339 proc _insert {str} {
340 verbose "INSERT <<$str>>"
341 variable _cur_x
342 variable _cur_y
343 variable _rows
344 variable _cols
345 variable _attrs
346 variable _chars
347 set lattr [array get _attrs]
348 foreach char [split $str {}] {
349 set _chars($_cur_x,$_cur_y) [list $char $lattr]
350 incr _cur_x
351 if {$_cur_x >= $_cols} {
352 set _cur_x 0
353 incr _cur_y
354 if {$_cur_y >= $_rows} {
355 error "FIXME scroll"
356 }
357 }
358 }
359 }
360
361 # Initialize.
362 proc _setup {rows cols} {
363 global stty_init
364 set stty_init "rows $rows columns $cols"
365
366 variable _rows
367 variable _cols
368 variable _cur_x
369 variable _cur_y
370 variable _attrs
371
372 set _rows $rows
373 set _cols $cols
374 set _cur_x 0
375 set _cur_y 0
376 array set _attrs {
377 intensity normal
378 fg default
379 bg default
380 underline 0
381 reverse 0
382 }
383
384 _clear_lines 0 $_rows
385 }
386
387 # Accept some output from gdb and update the screen.
388 proc _accept {} {
389 global expect_out
390 gdb_expect {
391 -re "^\[\x07\x08\x0a\x0d\]" {
392 scan $expect_out(0,string) %c val
393 set hexval [format "%02x" $val]
394 verbose "+++ _ctl_0x${hexval}"
395 _ctl_0x${hexval}
396 exp_continue
397 }
398 -re "^\x1b(\[0-9a-zA-Z\])" {
399 verbose "+++ unsupported escape"
400 error "unsupported escape"
401 }
128d6509 402 -re "^\x1b\\\[(\[0-9;\]*)(\[a-zA-Z@\])" {
c3786b3a
TT
403 set cmd $expect_out(2,string)
404 set params [split $expect_out(1,string) ";"]
405 verbose "+++ _csi_$cmd <<<$expect_out(1,string)>>>"
406 eval _csi_$cmd $params
407 exp_continue
408 }
409 -re "^\[^\x07\x08\x0a\x0d\x1b\]+" {
410 _insert $expect_out(0,string)
411 variable _last_char
412 set _last_char [string index $expect_out(0,string) end]
413 # If the prompt was just inserted, return.
414 variable _cur_x
415 variable _cur_y
416 global gdb_prompt
417 set prev [get_line $_cur_y $_cur_x]
418 if {![regexp -- "$gdb_prompt \$" $prev]} {
419 exp_continue
420 }
421 }
422 }
423 }
424
425 # Like ::clean_restart, but ensures that gdb starts in an
426 # environment where the TUI can work. ROWS and COLS are the size
2b1d00c2
TT
427 # of the terminal. EXECUTABLE, if given, is passed to
428 # clean_restart.
429 proc clean_restart {rows cols {executable {}}} {
c3786b3a
TT
430 global env stty_init
431 save_vars {env(TERM) stty_init} {
432 setenv TERM ansi
433 _setup $rows $cols
2b1d00c2
TT
434 if {$executable == ""} {
435 ::clean_restart
436 } else {
437 ::clean_restart $executable
438 }
c3786b3a
TT
439 }
440 }
441
442 # Start the TUI. Returns 1 on success, 0 if TUI tests should be
443 # skipped.
444 proc enter_tui {} {
445 if {[skip_tui_tests]} {
446 return 0
447 }
448
449 gdb_test_no_output "set tui border-kind ascii"
450 command "tui enable"
451 return 1
452 }
453
454 # Send the command CMD to gdb, then wait for a gdb prompt to be
455 # seen in the TUI. CMD should not end with a newline -- that will
456 # be supplied by this function.
457 proc command {cmd} {
458 send_gdb "$cmd\n"
459 _accept
460 }
461
462 # Return the text of screen line N, without attributes. Lines are
463 # 0-based. If C is given, stop before column C. Columns are also
464 # zero-based.
465 proc get_line {n {c ""}} {
466 set result ""
467 variable _cols
468 variable _chars
469 set c [_default $c $_cols]
470 set x 0
471 while {$x < $c} {
472 append result [lindex $_chars($x,$n) 0]
473 incr x
474 }
475 return $result
476 }
477
478 # Get just the character at (X, Y).
479 proc get_char {x y} {
480 variable _chars
481 return [lindex $_chars($x,$y) 0]
482 }
483
484 # Get the entire screen as a string.
485 proc get_all_lines {} {
486 variable _rows
487 variable _cols
488 variable _chars
489
490 set result ""
491 for {set y 0} {$y < $_rows} {incr y} {
492 for {set x 0} {$x < $_cols} {incr x} {
493 append result [lindex $_chars($x,$y) 0]
494 }
495 append result "\n"
496 }
497
498 return $result
499 }
500
501 # Get the text just before the cursor.
502 proc get_current_line {} {
503 variable _cur_x
504 variable _cur_y
505 return [get_line $_cur_y $_cur_x]
506 }
507
508 # Helper function for check_box. Returns empty string if the box
509 # is found, description of why not otherwise.
510 proc _check_box {x y width height} {
511 set x2 [expr {$x + $width - 1}]
512 set y2 [expr {$y + $height - 1}]
513
514 if {[get_char $x $y] != "+"} {
515 return "ul corner"
516 }
517 if {[get_char $x $y2] != "+"} {
518 return "ll corner"
519 }
520 if {[get_char $x2 $y] != "+"} {
521 return "ur corner"
522 }
523 if {[get_char $x2 $y2] != "+"} {
524 return "lr corner"
525 }
526
527 for {set i [expr {$x + 1}]} {$i < $x2 - 1} {incr i} {
528 # Note we do not check the top border of the box, because
529 # it will contain a title.
530 if {[get_char $i $y2] != "-"} {
531 return "bottom border $i"
532 }
533 }
534 for {set i [expr {$y + 1}]} {$i < $y2 - 1} {incr i} {
535 if {[get_char $x $i] != "|"} {
536 return "left side $i"
537 }
538 if {[get_char $x2 $i] != "|"} {
539 return "right side $i"
540 }
541 }
542
543 return ""
544 }
545
546 # Check for a box at the given coordinates.
547 proc check_box {test_name x y width height} {
548 set why [_check_box $x $y $width $height]
549 if {$why == ""} {
550 pass $test_name
551 } else {
552 dump_screen
553 fail "$test_name ($why)"
554 }
555 }
556
557 # Check whether the text contents of the terminal match the
558 # regular expression. Note that text styling is not considered.
559 proc check_contents {test_name regexp} {
560 set contents [get_all_lines]
561 if {![gdb_assert {[regexp -- $regexp $contents]} $test_name]} {
562 dump_screen
563 }
564 }
565
566 # A debugging function to dump the current screen, with line
567 # numbers.
568 proc dump_screen {} {
569 variable _rows
570 verbose "Screen Dump:"
571 for {set y 0} {$y < $_rows} {incr y} {
572 set fmt [format %5d $y]
573 verbose "$fmt [get_line $y]"
574 }
575 }
ded631d5
TT
576
577 # Resize the terminal.
578 proc resize {rows cols} {
579 variable _chars
580 variable _rows
581 variable _cols
582
583 set old_rows [expr {min ($_rows, $rows)}]
584 set old_cols [expr {min ($_cols, $cols)}]
585
586 # Copy locally.
587 array set local_chars [array get _chars]
588 unset _chars
589
590 set _rows $rows
591 set _cols $cols
592 _clear_lines 0 $_rows
593
594 for {set x 0} {$x < $old_cols} {incr x} {
595 for {set y 0} {$y < $old_rows} {incr y} {
596 set _chars($x,$y) $local_chars($x,$y)
597 }
598 }
599
600 global gdb_spawn_name
601 # Somehow the number of columns transmitted to gdb is one less
602 # than what we request from expect. We hide this weird
603 # details from the caller.
604 stty rows $_rows columns [expr {$_cols + 1}] \
605 < $gdb_spawn_name
606 _accept
607 }
c3786b3a 608}
This page took 0.053145 seconds and 4 git commands to generate.