зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-03 06:16:17 +03:00
Merge branch 'perf'
``` group base main ----- ---- ---- cursor::char::back 1.00 32.8±0.63ms ? ?/sec 1.15 37.7±0.81ms ? ?/sec cursor::char::down 1.00 29.9±0.62ms ? ?/sec 1.19 35.6±0.82ms ? ?/sec cursor::char::forward 1.00 31.8±0.74ms ? ?/sec 1.06 33.8±0.90ms ? ?/sec cursor::char::up 1.00 30.3±0.86ms ? ?/sec 1.02 30.8±0.73ms ? ?/sec cursor::edge::head_end 1.00 33.2±0.63ms ? ?/sec 1.03 34.3±0.84ms ? ?/sec cursor::edge::top_bottom 1.00 31.5±0.81ms ? ?/sec 1.11 34.9±0.82ms ? ?/sec cursor::paragraph::down 1.00 30.1±0.83ms ? ?/sec 1.19 35.7±0.76ms ? ?/sec cursor::paragraph::up 1.00 30.0±0.68ms ? ?/sec 1.03 30.9±0.63ms ? ?/sec cursor::word::back 1.00 30.4±0.61ms ? ?/sec 1.05 32.1±0.64ms ? ?/sec cursor::word::forward 1.00 31.9±0.65ms ? ?/sec 1.18 37.7±0.89ms ? ?/sec delete::char 1.00 3.4±0.10ms ? ?/sec 4.48 15.3±0.82ms ? ?/sec delete::line 1.00 1243.4±42.36µs ? ?/sec 7.71 9.6±0.38ms ? ?/sec delete::word 1.00 2.7±0.10ms ? ?/sec 5.35 14.2±0.37ms ? ?/sec insert::append::10_lorem 1.00 327.2±4.89ms ? ?/sec 1.00 327.6±4.92ms ? ?/sec insert::append::1_lorem 1.00 7.0±0.16ms ? ?/sec 1.00 7.0±0.15ms ? ?/sec insert::append::50_lorem 1.00 3.1±0.02s ? ?/sec 2.24 7.0±0.03s ? ?/sec insert::random::10_lorem 1.00 133.8±2.78ms ? ?/sec 1.90 254.6±3.95ms ? ?/sec insert::random::1_lorem 1.00 6.7±0.16ms ? ?/sec 1.01 6.8±0.14ms ? ?/sec insert::random::50_lorem 1.00 709.0±7.70ms ? ?/sec 5.97 4.2±0.03s ? ?/sec search::back_long 1.00 4.3±0.15ms ? ?/sec 3.02 13.0±0.49ms ? ?/sec search::back_short 1.01 4.3±0.14ms ? ?/sec 1.00 4.2±0.10ms ? ?/sec search::forward_long 1.00 4.4±0.14ms ? ?/sec 2.37 10.5±0.29ms ? ?/sec search::forward_short 1.02 4.2±0.14ms ? ?/sec 1.00 4.1±0.10ms ? ?/sec ```
Этот коммит содержится в:
@@ -1,10 +1,11 @@
|
||||
use crate::textarea::TextArea;
|
||||
use crate::util::num_digits;
|
||||
use std::cmp;
|
||||
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 +37,30 @@ 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)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn text(&self, top_row: usize, height: usize) -> Text<'a> {
|
||||
let lines_len = self.0.lines().len();
|
||||
let lnum_len = num_digits(lines_len);
|
||||
let bottom_row = cmp::min(top_row + height, lines_len);
|
||||
let mut lines = Vec::with_capacity(bottom_row - top_row);
|
||||
for (i, line) in self.0.lines()[top_row..bottom_row].iter().enumerate() {
|
||||
lines.push(self.0.line_spans(line.as_str(), top_row + i, lnum_len));
|
||||
}
|
||||
Text::from(lines)
|
||||
}
|
||||
}
|
||||
|
||||
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 +75,23 @@ 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 top_row = next_scroll_top(top_row, cursor.0 as u16, inner_area.height);
|
||||
let top_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 text = self.text(top_row as usize, inner_area.height as usize);
|
||||
let mut inner = Paragraph::new(text).style(self.0.style());
|
||||
if let Some(b) = self.0.block() {
|
||||
inner = inner.block(b.clone());
|
||||
}
|
||||
if top_col != 0 {
|
||||
inner = inner.scroll((0, top_col));
|
||||
}
|
||||
|
||||
// Store scroll top position for rendering on the next tick
|
||||
self.scroll_top.store(row, col);
|
||||
self.0.scroll_top.store(top_row, top_col);
|
||||
|
||||
self.inner.render(area, buf);
|
||||
inner.render(area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user