1
0
зеркало из https://github.com/glebtv/tui-textarea.git synced 2026-09-03 14:26:17 +03:00

render only displayed lines in Paragraph

by handling vertical scroll by ourselves
Этот коммит содержится в:
rhysd
2022-07-17 03:22:09 +09:00
родитель b56f252f08
Коммит 40e4bfbe15

Просмотреть файл

@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicU32, Ordering};
use tui::buffer::Buffer;
use tui::layout::Rect;
use tui::text::Text;
use tui::widgets::{Block, Paragraph, Widget};
use tui::widgets::{Paragraph, Widget};
// &mut 'a (u16, u16) is not available since TextAreaWidget instance totally takes over the ownership of TextArea
// instance. In the case, the TextArea instance cannot be accessed from any other objects since it is mutablly
@@ -36,40 +36,18 @@ impl ScrollTop {
}
}
pub struct Renderer<'a> {
scroll_top: &'a ScrollTop,
cursor: (u16, u16),
block: Option<Block<'a>>,
inner: Paragraph<'a>,
}
pub struct Renderer<'a>(&'a TextArea<'a>);
impl<'a> Renderer<'a> {
pub fn new(textarea: &'a TextArea<'a>) -> Self {
let lnum_len = num_digits(textarea.lines().len());
let lines: Vec<_> = textarea
.lines()
.iter()
.map(String::as_str)
.enumerate()
.map(|(row, line)| textarea.line_spans(line, row, lnum_len))
.collect();
let inner = Paragraph::new(Text::from(lines)).style(textarea.style());
let cursor = textarea.cursor();
Self {
scroll_top: &textarea.scroll_top,
cursor: (cursor.0 as u16, cursor.1 as u16),
block: textarea.block().cloned(),
inner,
}
Self(textarea)
}
}
impl<'a> Widget for Renderer<'a> {
fn render(mut self, area: Rect, buf: &mut Buffer) {
let inner_area = if let Some(b) = self.block.take() {
let area = b.inner(area);
self.inner = self.inner.block(b);
area
fn render(self, area: Rect, buf: &mut Buffer) {
let inner_area = if let Some(b) = self.0.block() {
b.inner(area)
} else {
area
};
@@ -84,18 +62,34 @@ impl<'a> Widget for Renderer<'a> {
}
}
let (top_row, top_col) = self.scroll_top.load();
let row = next_scroll_top(top_row, self.cursor.0, inner_area.height);
let col = next_scroll_top(top_col, self.cursor.1, inner_area.width);
let cursor = self.0.cursor();
let (top_row, top_col) = self.0.scroll_top.load();
let row = next_scroll_top(top_row, cursor.0 as u16, inner_area.height);
let col = next_scroll_top(top_col, cursor.1 as u16, inner_area.width);
let scroll = (row, col);
if scroll != (0, 0) {
self.inner = self.inner.scroll(scroll);
let lnum_len = num_digits(self.0.lines().len());
let lines: Vec<_> = self
.0
.lines()
.iter()
.map(String::as_str)
.enumerate()
.skip(row as usize)
.take(inner_area.height as usize)
.map(|(row, line)| self.0.line_spans(line, row, lnum_len))
.collect();
let mut inner = Paragraph::new(Text::from(lines)).style(self.0.style());
if let Some(b) = self.0.block() {
inner = inner.block(b.clone());
}
if col != 0 {
inner = inner.scroll((0, col));
}
// Store scroll top position for rendering on the next tick
self.scroll_top.store(row, col);
self.0.scroll_top.store(row, col);
self.inner.render(area, buf);
inner.render(area, buf);
}
}