diff --git a/src/app/rendering/terminal_text/mod.rs b/src/app/rendering/terminal_text/mod.rs index 4e7b0c4..89bdf5d 100644 --- a/src/app/rendering/terminal_text/mod.rs +++ b/src/app/rendering/terminal_text/mod.rs @@ -16,6 +16,7 @@ pub struct TerminalText { renderer: TextRenderer, dirty_regions: Vec, cursor: Cursor, + max_scroll_lines: usize, } // TODO @@ -66,12 +67,13 @@ impl TerminalText { index: 0, affinity: glyphon::Affinity::After, }, + max_scroll_lines: 100, } } - fn get_line_bounds(&self, line: usize) -> TextBounds { - // Calculate the bounds for a specific line - if line >= self.buffer.lines.len() { + // Calculate the bounds delimited by the `start` and `end` lines + fn get_text_bounds(&self, start: usize, end: usize) -> TextBounds { + if start >= self.buffer.lines.len() || end > self.buffer.lines.len() { // Return default bounds for invalid line return TextBounds { left: 0, @@ -84,25 +86,24 @@ impl TerminalText { let line_height = self.buffer.metrics().line_height; let viewport_width = self.viewport.resolution().width; - // Use layout_runs to get information about wrapped lines let layout_iter = self.buffer.layout_runs(); let mut top_line = 0; let mut bottom_line = 0; - let mut found_line = false; - // Iterate through layout runs to find our target line + let mut found_start_line = false; + let mut found_end_line = false; + for (visual_line_count, run) in layout_iter.enumerate() { - if run.line_i == line { - // This run belongs to our target line - if !found_line { - // First run of our target line - top_line = visual_line_count; - found_line = true; + if run.line_i == start && !found_start_line { + top_line = visual_line_count; + found_start_line = true; + } + if run.line_i == end { + if !found_end_line { + found_end_line = true; } - // Update bottom line for each run we find for this line bottom_line = visual_line_count + 1; - } else if found_line { - // We've processed all runs for our target line + } else if found_end_line { break; } } @@ -150,14 +151,7 @@ impl TerminalText { } // Add 1 to include partially visible lines at the bottom - let end_line = if self.buffer.lines.is_empty() { - 0 - } else { - // Make sure we include at least the last logical line that has content in the viewport - trace!("Last logical line: {last_logical_line}"); - trace!("Number of lines: {}", self.buffer.lines.len()); - (last_logical_line + 1).min(self.buffer.lines.len()) - }; + let end_line = last_logical_line; trace!("visible line range goes from {start_line} to {end_line}"); @@ -166,9 +160,8 @@ impl TerminalText { fn ensure_visible_text_rendered(&mut self) { let (start_line, end_line) = self.get_visible_line_range(); - for i in start_line..end_line { - self.dirty_regions.push(self.get_line_bounds(i)); - } + self.dirty_regions + .push(self.get_text_bounds(start_line, end_line)); } fn merge_dirty_regions(&self) -> TextBounds { @@ -239,6 +232,14 @@ impl TerminalText { F: FnOnce(&mut Self) -> R, { let result = operation(self); + + let mut scroll = self.buffer.scroll(); + if self.buffer.lines.len() > self.max_scroll_lines { + self.buffer.lines.remove(0); + self.cursor.line -= 1; + } + scroll.line = self.buffer.lines.len(); + self.buffer.set_scroll(scroll); self.buffer.shape_until_scroll(&mut self.font_system, false); self.ensure_visible_text_rendered(); result @@ -309,26 +310,6 @@ impl TerminalText { this.cursor.index = 0; // Create a new line with text after cursor this.buffer.lines.insert(this.cursor.line, new_line); - - // Only adjust scroll if cursor would be outside visible area - let mut scroll = this.buffer.scroll(); - let current_scroll_line = - (scroll.vertical / this.buffer.metrics().line_height).floor() as usize; - let max_visible_lines = - (safe_casts::u32_to_f32_or_max(this.viewport.resolution().height) - / this.buffer.metrics().line_height) - .floor() as usize; - - // Only scroll if cursor would be below visible area - if this.cursor.line >= current_scroll_line + max_visible_lines { - scroll.vertical = - safe_casts::usize_to_f32_or_max(this.cursor.line - max_visible_lines + 1) - * this.buffer.metrics().line_height; - trace!("adjusting scroll to keep cursor visible: {:?}", scroll); - this.buffer.set_scroll(scroll); - } else { - trace!("keeping current scroll: {:?}", scroll); - } }) } @@ -378,11 +359,6 @@ impl TerminalText { ret = true; } - if line > this.buffer.lines.len() { - let mut scroll = this.buffer.scroll(); - scroll.vertical -= 1.0 * this.buffer.metrics().line_height; - this.buffer.set_scroll(scroll); - } ret }) }