fix scroll
This commit is contained in:
@@ -16,6 +16,7 @@ pub struct TerminalText {
|
|||||||
renderer: TextRenderer,
|
renderer: TextRenderer,
|
||||||
dirty_regions: Vec<TextBounds>,
|
dirty_regions: Vec<TextBounds>,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
|
max_scroll_lines: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@@ -66,12 +67,13 @@ impl TerminalText {
|
|||||||
index: 0,
|
index: 0,
|
||||||
affinity: glyphon::Affinity::After,
|
affinity: glyphon::Affinity::After,
|
||||||
},
|
},
|
||||||
|
max_scroll_lines: 100,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_line_bounds(&self, line: usize) -> TextBounds {
|
// Calculate the bounds delimited by the `start` and `end` lines
|
||||||
// Calculate the bounds for a specific line
|
fn get_text_bounds(&self, start: usize, end: usize) -> TextBounds {
|
||||||
if line >= self.buffer.lines.len() {
|
if start >= self.buffer.lines.len() || end > self.buffer.lines.len() {
|
||||||
// Return default bounds for invalid line
|
// Return default bounds for invalid line
|
||||||
return TextBounds {
|
return TextBounds {
|
||||||
left: 0,
|
left: 0,
|
||||||
@@ -84,25 +86,24 @@ impl TerminalText {
|
|||||||
let line_height = self.buffer.metrics().line_height;
|
let line_height = self.buffer.metrics().line_height;
|
||||||
let viewport_width = self.viewport.resolution().width;
|
let viewport_width = self.viewport.resolution().width;
|
||||||
|
|
||||||
// Use layout_runs to get information about wrapped lines
|
|
||||||
let layout_iter = self.buffer.layout_runs();
|
let layout_iter = self.buffer.layout_runs();
|
||||||
let mut top_line = 0;
|
let mut top_line = 0;
|
||||||
let mut bottom_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() {
|
for (visual_line_count, run) in layout_iter.enumerate() {
|
||||||
if run.line_i == line {
|
if run.line_i == start && !found_start_line {
|
||||||
// This run belongs to our target line
|
top_line = visual_line_count;
|
||||||
if !found_line {
|
found_start_line = true;
|
||||||
// First run of our target line
|
}
|
||||||
top_line = visual_line_count;
|
if run.line_i == end {
|
||||||
found_line = true;
|
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;
|
bottom_line = visual_line_count + 1;
|
||||||
} else if found_line {
|
} else if found_end_line {
|
||||||
// We've processed all runs for our target line
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,14 +151,7 @@ impl TerminalText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add 1 to include partially visible lines at the bottom
|
// Add 1 to include partially visible lines at the bottom
|
||||||
let end_line = if self.buffer.lines.is_empty() {
|
let end_line = last_logical_line;
|
||||||
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())
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!("visible line range goes from {start_line} to {end_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) {
|
fn ensure_visible_text_rendered(&mut self) {
|
||||||
let (start_line, end_line) = self.get_visible_line_range();
|
let (start_line, end_line) = self.get_visible_line_range();
|
||||||
for i in start_line..end_line {
|
self.dirty_regions
|
||||||
self.dirty_regions.push(self.get_line_bounds(i));
|
.push(self.get_text_bounds(start_line, end_line));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_dirty_regions(&self) -> TextBounds {
|
fn merge_dirty_regions(&self) -> TextBounds {
|
||||||
@@ -239,6 +232,14 @@ impl TerminalText {
|
|||||||
F: FnOnce(&mut Self) -> R,
|
F: FnOnce(&mut Self) -> R,
|
||||||
{
|
{
|
||||||
let result = operation(self);
|
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.buffer.shape_until_scroll(&mut self.font_system, false);
|
||||||
self.ensure_visible_text_rendered();
|
self.ensure_visible_text_rendered();
|
||||||
result
|
result
|
||||||
@@ -309,26 +310,6 @@ impl TerminalText {
|
|||||||
this.cursor.index = 0;
|
this.cursor.index = 0;
|
||||||
// Create a new line with text after cursor
|
// Create a new line with text after cursor
|
||||||
this.buffer.lines.insert(this.cursor.line, new_line);
|
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;
|
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
|
ret
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user