diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index b7ed874f70..4b950f9288 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -166,37 +166,24 @@ fn transfer_rows_from_viewport_to_lines_above( count: usize, max_viewport_width: usize, ) -> isize { - let mut next_lines: Vec = vec![]; let mut transferred_rows_count: isize = 0; - for _ in 0..count { - if next_lines.is_empty() { - if !viewport.is_empty() { - let next_line = viewport.remove(0); - transferred_rows_count += - calculate_row_display_height(next_line.width(), max_viewport_width) as isize; - if !next_line.is_canonical { - let mut bottom_canonical_row_and_wraps_in_dst = - get_lines_above_bottom_canonical_row_and_wraps(lines_above); - next_lines.append(&mut bottom_canonical_row_and_wraps_in_dst); - } - next_lines.push(next_line); - next_lines = vec![Row::from_rows(next_lines)]; - } else { - break; // no more rows - } - } - let dropped_line_width = bounded_push(lines_above, sixel_grid, next_lines.remove(0)); + let drained_lines = std::cmp::min(count, viewport.len()); + for next_line in viewport.drain(..drained_lines) { + let mut next_lines: Vec = vec![]; + transferred_rows_count += + calculate_row_display_height(next_line.width(), max_viewport_width) as isize; + if !next_line.is_canonical { + let mut bottom_canonical_row_and_wraps_in_dst = + get_lines_above_bottom_canonical_row_and_wraps(lines_above); + next_lines.append(&mut bottom_canonical_row_and_wraps_in_dst); + } + next_lines.push(next_line); + let dropped_line_width = bounded_push(lines_above, sixel_grid, Row::from_rows(next_lines)); if let Some(width) = dropped_line_width { transferred_rows_count -= calculate_row_display_height(width, max_viewport_width) as isize; } } - if !next_lines.is_empty() { - let excess_rows = Row::from_rows(next_lines).split_to_rows_of_length(max_viewport_width); - for row in excess_rows { - viewport.insert(0, row); - } - } transferred_rows_count } @@ -3379,19 +3366,20 @@ impl Row { self.width = None; } pub fn drain_until(&mut self, x: usize) -> VecDeque { - let mut drained_part: VecDeque = VecDeque::new(); let mut drained_part_len = 0; - while let Some(next_character) = self.columns.remove(0) { + let mut split_pos = 0; + for next_character in self.columns.iter() { // drained_part_len == 0 here is so that if the grid is resized // to a size of 1, we won't drop wide characters if drained_part_len + next_character.width <= x || drained_part_len == 0 { - drained_part.push_back(next_character); drained_part_len += next_character.width; + split_pos += 1 } else { - self.columns.push_front(next_character); // put it back break; } } + // Can't use split_off because it doesn't reduce capacity, causing OOM with long lines + let drained_part = self.columns.drain(..split_pos).collect(); self.width = None; drained_part }