@@ -452,6 +452,62 @@ where
452452 Ok ( ( ) )
453453 }
454454
455+ /// Insert fully-rendered rows above the inline viewport without using scroll regions.
456+ pub ( crate ) fn insert_buffer_before_viewport_without_scroll_region (
457+ & mut self ,
458+ buffer : Buffer ,
459+ ) -> io:: Result < ( ) > {
460+ let height = buffer. area . height ;
461+ if height == 0 {
462+ return Ok ( ( ) ) ;
463+ }
464+
465+ let screen_height = self . size ( ) ?. height ;
466+ if screen_height == 0 {
467+ return Ok ( ( ) ) ;
468+ }
469+
470+ if self . viewport_area . bottom ( ) . saturating_add ( height) <= screen_height {
471+ self . draw_buffer_lines (
472+ self . viewport_area . top ( ) ,
473+ height,
474+ buffer. area . width ,
475+ buffer. content . as_slice ( ) ,
476+ ) ?;
477+ self . set_viewport_area ( Rect {
478+ y : self . viewport_area . y . saturating_add ( height) ,
479+ ..self . viewport_area
480+ } ) ;
481+ self . clear ( ) ?;
482+ return Ok ( ( ) ) ;
483+ }
484+
485+ let mut cells = buffer. content . as_slice ( ) ;
486+ let bottom = screen_height. saturating_sub ( 1 ) ;
487+ // VTE records scrollback when a row scrolls offscreen, not when that row is later
488+ // repainted by absolute cursor movement. Stream each rendered row through the bottom
489+ // line so the terminal saves the row's actual cells into history.
490+ while !cells. is_empty ( ) {
491+ cells =
492+ self . draw_buffer_lines ( bottom, /*lines_to_draw*/ 1 , buffer. area . width , cells) ?;
493+ self . scroll_up_with_append_lines ( /*lines_to_scroll*/ 1 ) ?;
494+ }
495+
496+ let viewport_height = self . viewport_area . height . min ( screen_height) ;
497+ for _ in 1 ..viewport_height {
498+ self . scroll_up_with_append_lines ( /*lines_to_scroll*/ 1 ) ?;
499+ }
500+
501+ self . set_viewport_area ( Rect {
502+ y : screen_height. saturating_sub ( viewport_height) ,
503+ height : viewport_height,
504+ ..self . viewport_area
505+ } ) ;
506+ self . clear ( ) ?;
507+
508+ Ok ( ( ) )
509+ }
510+
455511 /// Clear the entire visible screen (not just the viewport) and force a full redraw.
456512 pub fn clear_visible_screen ( & mut self ) -> io:: Result < ( ) > {
457513 let home = Position { x : 0 , y : 0 } ;
@@ -507,6 +563,37 @@ where
507563 pub fn size ( & self ) -> io:: Result < Size > {
508564 self . backend . size ( )
509565 }
566+
567+ fn draw_buffer_lines < ' a > (
568+ & mut self ,
569+ y_offset : u16 ,
570+ lines_to_draw : u16 ,
571+ width : u16 ,
572+ cells : & ' a [ Cell ] ,
573+ ) -> io:: Result < & ' a [ Cell ] > {
574+ let width = usize:: from ( width) ;
575+ let ( to_draw, remainder) = cells. split_at ( width * lines_to_draw as usize ) ;
576+ if lines_to_draw > 0 {
577+ let iter = to_draw
578+ . iter ( )
579+ . enumerate ( )
580+ . map ( |( i, cell) | ( ( i % width) as u16 , y_offset + ( i / width) as u16 , cell) ) ;
581+ self . backend . draw ( iter) ?;
582+ Backend :: flush ( & mut self . backend ) ?;
583+ }
584+ Ok ( remainder)
585+ }
586+
587+ fn scroll_up_with_append_lines ( & mut self , lines_to_scroll : u16 ) -> io:: Result < ( ) > {
588+ if lines_to_scroll > 0 {
589+ self . backend . set_cursor_position ( Position :: new (
590+ /*x*/ 0 ,
591+ /*y*/ self . size ( ) ?. height . saturating_sub ( 1 ) ,
592+ ) ) ?;
593+ self . backend . append_lines ( lines_to_scroll) ?;
594+ }
595+ Ok ( ( ) )
596+ }
510597}
511598
512599use ratatui:: buffer:: Cell ;
0 commit comments