1
0
зеркало из https://github.com/glebtv/tui-textarea.git synced 2026-09-07 16:05:50 +03:00
Этот коммит содержится в:
rhysd
2022-06-11 22:12:34 +09:00
родитель b3f235ff06
Коммит 8d754dd53d

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

@@ -9,14 +9,20 @@ use tui::style::{Modifier, Style};
use tui::text::{Span, Spans, Text}; use tui::text::{Span, Spans, Text};
use tui::widgets::{Block, Paragraph, Widget}; use tui::widgets::{Block, Paragraph, Widget};
fn spaces(size: usize) -> &'static str {
const SPACES: &str = " ";
&SPACES[..size]
}
pub struct TextArea<'a> { pub struct TextArea<'a> {
lines: Vec<String>, lines: Vec<String>,
block: Option<Block<'a>>, block: Option<Block<'a>>,
style: Style, style: Style,
cursor: (usize, usize), // 0-base cursor: (usize, usize), // 0-base
tab: &'a str, tab_len: u8,
history: History, history: History,
cursor_line_style: Style, cursor_line_style: Style,
line_number_style: Option<Style>,
scroll_top: (AtomicU16, AtomicU16), scroll_top: (AtomicU16, AtomicU16),
yank: String, yank: String,
} }
@@ -47,9 +53,10 @@ impl<'a> TextArea<'a> {
block: None, block: None,
style: Style::default(), style: Style::default(),
cursor: (0, 0), cursor: (0, 0),
tab: " ", tab_len: 4,
history: History::new(50), history: History::new(50),
cursor_line_style: Style::default().add_modifier(Modifier::UNDERLINED), cursor_line_style: Style::default().add_modifier(Modifier::UNDERLINED),
line_number_style: None,
scroll_top: (AtomicU16::new(0), AtomicU16::new(0)), scroll_top: (AtomicU16::new(0), AtomicU16::new(0)),
yank: String::new(), yank: String::new(),
} }
@@ -380,9 +387,9 @@ impl<'a> TextArea<'a> {
} }
pub fn insert_tab(&mut self) { pub fn insert_tab(&mut self) {
if !self.tab.is_empty() { if self.tab_len > 0 {
let len = self.tab.len() - self.cursor.1 % self.tab.len(); let len = self.tab_len as usize - self.cursor.1 % self.tab_len as usize;
self.insert_str(&self.tab[..len]); self.insert_str(spaces(len));
} }
} }
@@ -500,26 +507,41 @@ impl<'a> TextArea<'a> {
} }
pub fn widget(&'a self) -> impl Widget + 'a { pub fn widget(&'a self) -> impl Widget + 'a {
fn num_digits(i: usize) -> usize {
f64::log10(i as f64) as usize + 1
}
let mut lines = Vec::with_capacity(self.lines.len()); let mut lines = Vec::with_capacity(self.lines.len());
let line_number_len = num_digits(self.lines.len());
for (i, l) in self.lines.iter().enumerate() { for (i, l) in self.lines.iter().enumerate() {
let mut spans = vec![];
if let Some(style) = self.line_number_style {
let pad = spaces(line_number_len - num_digits(i + 1) + 1);
spans.push(Span::styled(format!("{}{} ", pad, i + 1), style));
}
if i == self.cursor.0 { if i == self.cursor.0 {
let cursor_style = Style::default().add_modifier(Modifier::REVERSED);
if let Some((i, c)) = l.char_indices().nth(self.cursor.1) { if let Some((i, c)) = l.char_indices().nth(self.cursor.1) {
let j = i + c.len_utf8(); let j = i + c.len_utf8();
lines.push(Spans::from(vec![ spans.extend_from_slice(&[
Span::styled(&l[..i], self.cursor_line_style), Span::styled(&l[..i], self.cursor_line_style),
Span::styled(&l[i..j], Style::default().add_modifier(Modifier::REVERSED)), Span::styled(&l[i..j], cursor_style),
Span::styled(&l[j..], self.cursor_line_style), Span::styled(&l[j..], self.cursor_line_style),
])); ]);
} else { } else {
// When cursor is at the end of line // When cursor is at the end of line
lines.push(Spans::from(vec![ spans.extend_from_slice(&[
Span::styled(l.as_str(), self.cursor_line_style), Span::styled(l.as_str(), self.cursor_line_style),
Span::styled(" ", Style::default().add_modifier(Modifier::REVERSED)), Span::styled(" ", cursor_style),
])); ]);
} }
} else { } else {
lines.push(Spans::from(l.as_str())); spans.push(Span::from(l.as_str()));
} }
lines.push(Spans::from(spans));
} }
let inner = Paragraph::new(Text::from(lines)).style(self.style); let inner = Paragraph::new(Text::from(lines)).style(self.style);
@@ -543,13 +565,8 @@ impl<'a> TextArea<'a> {
self.block = None; self.block = None;
} }
pub fn set_tab(&mut self, tab: &'a str) { pub fn set_tab_length(&mut self, len: u8) {
assert!( self.tab_len = len;
tab.chars().all(|c| c == ' '),
"tab string must consist of spaces but got {:?}",
tab,
);
self.tab = tab;
} }
pub fn set_max_histories(&mut self, max: usize) { pub fn set_max_histories(&mut self, max: usize) {
@@ -560,6 +577,14 @@ impl<'a> TextArea<'a> {
self.cursor_line_style = style; self.cursor_line_style = style;
} }
pub fn set_line_number_style(&mut self, style: Style) {
self.line_number_style = Some(style);
}
pub fn remove_line_number(&mut self) {
self.line_number_style = None;
}
pub fn lines(&'a self) -> &'a [String] { pub fn lines(&'a self) -> &'a [String] {
&self.lines &self.lines
} }