зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-06 23:55:49 +03:00
render only displayed lines in Paragraph
by handling vertical scroll by ourselves
Этот коммит содержится в:
@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicU32, Ordering};
|
|||||||
use tui::buffer::Buffer;
|
use tui::buffer::Buffer;
|
||||||
use tui::layout::Rect;
|
use tui::layout::Rect;
|
||||||
use tui::text::Text;
|
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
|
// &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
|
// 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> {
|
pub struct Renderer<'a>(&'a TextArea<'a>);
|
||||||
scroll_top: &'a ScrollTop,
|
|
||||||
cursor: (u16, u16),
|
|
||||||
block: Option<Block<'a>>,
|
|
||||||
inner: Paragraph<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Renderer<'a> {
|
impl<'a> Renderer<'a> {
|
||||||
pub fn new(textarea: &'a TextArea<'a>) -> Self {
|
pub fn new(textarea: &'a TextArea<'a>) -> Self {
|
||||||
let lnum_len = num_digits(textarea.lines().len());
|
Self(textarea)
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Renderer<'a> {
|
impl<'a> Widget for Renderer<'a> {
|
||||||
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
let inner_area = if let Some(b) = self.block.take() {
|
let inner_area = if let Some(b) = self.0.block() {
|
||||||
let area = b.inner(area);
|
b.inner(area)
|
||||||
self.inner = self.inner.block(b);
|
|
||||||
area
|
|
||||||
} else {
|
} else {
|
||||||
area
|
area
|
||||||
};
|
};
|
||||||
@@ -84,18 +62,34 @@ impl<'a> Widget for Renderer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (top_row, top_col) = self.scroll_top.load();
|
let cursor = self.0.cursor();
|
||||||
let row = next_scroll_top(top_row, self.cursor.0, inner_area.height);
|
let (top_row, top_col) = self.0.scroll_top.load();
|
||||||
let col = next_scroll_top(top_col, self.cursor.1, inner_area.width);
|
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);
|
let lnum_len = num_digits(self.0.lines().len());
|
||||||
if scroll != (0, 0) {
|
let lines: Vec<_> = self
|
||||||
self.inner = self.inner.scroll(scroll);
|
.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
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user