@@ -480,23 +480,40 @@ class Window {
480
480
481
481
// Curses doesn't allow direct output of color escape sequences, but that's
482
482
// how we get source lines from the Highligher class. Read the line and
483
- // convert color escape sequences to curses color attributes.
484
- void OutputColoredStringTruncated (int right_pad, StringRef string,
483
+ // convert color escape sequences to curses color attributes. Use
484
+ // first_skip_count to skip leading visible characters. Returns false if all
485
+ // visible characters were skipped due to first_skip_count.
486
+ bool OutputColoredStringTruncated (int right_pad, StringRef string,
487
+ size_t skip_first_count,
485
488
bool use_blue_background) {
486
489
attr_t saved_attr;
487
490
short saved_pair;
491
+ bool result = false ;
488
492
wattr_get (m_window, &saved_attr, &saved_pair, nullptr );
489
493
if (use_blue_background)
490
494
::wattron (m_window, COLOR_PAIR(WhiteOnBlue));
491
495
while (!string.empty ()) {
492
496
size_t esc_pos = string.find (' \x1b ' );
493
497
if (esc_pos == StringRef::npos) {
494
- PutCStringTruncated (right_pad, string.data (), string.size ());
498
+ string = string.substr (skip_first_count);
499
+ if (!string.empty ()) {
500
+ PutCStringTruncated (right_pad, string.data (), string.size ());
501
+ result = true ;
502
+ }
495
503
break ;
496
504
}
497
505
if (esc_pos > 0 ) {
498
- PutCStringTruncated (right_pad, string.data (), esc_pos);
499
- string = string.drop_front (esc_pos);
506
+ if (skip_first_count > 0 ) {
507
+ int skip = std::min (esc_pos, skip_first_count);
508
+ string = string.substr (skip);
509
+ skip_first_count -= skip;
510
+ esc_pos -= skip;
511
+ }
512
+ if (esc_pos > 0 ) {
513
+ PutCStringTruncated (right_pad, string.data (), esc_pos);
514
+ result = true ;
515
+ string = string.drop_front (esc_pos);
516
+ }
500
517
}
501
518
bool consumed = string.consume_front (" \x1b " );
502
519
assert (consumed);
@@ -531,6 +548,7 @@ class Window {
531
548
}
532
549
}
533
550
wattr_set (m_window, saved_attr, saved_pair, nullptr );
551
+ return result;
534
552
}
535
553
536
554
void Touch () {
@@ -3379,7 +3397,8 @@ class SourceFileWindowDelegate : public WindowDelegate {
3379
3397
m_disassembly_scope (nullptr ), m_disassembly_sp(), m_disassembly_range(),
3380
3398
m_title(), m_line_width(4 ), m_selected_line(0 ), m_pc_line(0 ),
3381
3399
m_stop_id(0 ), m_frame_idx(UINT32_MAX), m_first_visible_line(0 ),
3382
- m_min_x(0 ), m_min_y(0 ), m_max_x(0 ), m_max_y(0 ) {}
3400
+ m_first_visible_column(0 ), m_min_x(0 ), m_min_y(0 ), m_max_x(0 ),
3401
+ m_max_y(0 ) {}
3383
3402
3384
3403
~SourceFileWindowDelegate () override = default ;
3385
3404
@@ -3396,6 +3415,8 @@ class SourceFileWindowDelegate : public WindowDelegate {
3396
3415
{KEY_RETURN, " Run to selected line with one shot breakpoint" },
3397
3416
{KEY_UP, " Select previous source line" },
3398
3417
{KEY_DOWN, " Select next source line" },
3418
+ {KEY_LEFT, " Scroll to the left" },
3419
+ {KEY_RIGHT, " Scroll to the right" },
3399
3420
{KEY_PPAGE, " Page up" },
3400
3421
{KEY_NPAGE, " Page down" },
3401
3422
{' b' , " Set breakpoint on selected source/disassembly line" },
@@ -3650,7 +3671,15 @@ class SourceFileWindowDelegate : public WindowDelegate {
3650
3671
StringRef line = lineStream.GetString ();
3651
3672
if (line.endswith (" \n " ))
3652
3673
line = line.drop_back ();
3653
- window.OutputColoredStringTruncated (1 , line, is_pc_line);
3674
+ bool wasWritten = window.OutputColoredStringTruncated (
3675
+ 1 , line, m_first_visible_column, line_is_selected);
3676
+ if (line_is_selected && !wasWritten) {
3677
+ // Draw an empty space to show the selected line if empty,
3678
+ // or draw '<' if nothing is visible because of scrolling too much
3679
+ // to the right.
3680
+ window.PutCStringTruncated (
3681
+ 1 , line.empty () && m_first_visible_column == 0 ? " " : " <" );
3682
+ }
3654
3683
3655
3684
if (is_pc_line && frame_sp &&
3656
3685
frame_sp->GetConcreteFrameIndex () == 0 ) {
@@ -3801,7 +3830,9 @@ class SourceFileWindowDelegate : public WindowDelegate {
3801
3830
strm.Printf (" %s" , mnemonic);
3802
3831
3803
3832
int right_pad = 1 ;
3804
- window.PutCStringTruncated (right_pad, strm.GetData ());
3833
+ window.PutCStringTruncated (
3834
+ right_pad,
3835
+ strm.GetString ().substr (m_first_visible_column).data ());
3805
3836
3806
3837
if (is_pc_line && frame_sp &&
3807
3838
frame_sp->GetConcreteFrameIndex () == 0 ) {
@@ -3896,6 +3927,15 @@ class SourceFileWindowDelegate : public WindowDelegate {
3896
3927
}
3897
3928
return eKeyHandled;
3898
3929
3930
+ case KEY_LEFT:
3931
+ if (m_first_visible_column > 0 )
3932
+ --m_first_visible_column;
3933
+ return eKeyHandled;
3934
+
3935
+ case KEY_RIGHT:
3936
+ ++m_first_visible_column;
3937
+ return eKeyHandled;
3938
+
3899
3939
case ' \r ' :
3900
3940
case ' \n ' :
3901
3941
case KEY_ENTER:
@@ -4127,6 +4167,7 @@ class SourceFileWindowDelegate : public WindowDelegate {
4127
4167
uint32_t m_stop_id;
4128
4168
uint32_t m_frame_idx;
4129
4169
int m_first_visible_line;
4170
+ int m_first_visible_column;
4130
4171
int m_min_x;
4131
4172
int m_min_y;
4132
4173
int m_max_x;
0 commit comments