fix scroll
This commit is contained in:
@@ -16,6 +16,7 @@ pub struct TerminalText {
|
||||
renderer: TextRenderer,
|
||||
dirty_regions: Vec<TextBounds>,
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user