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

implement inserting tab character

Этот коммит содержится в:
rhysd
2022-06-09 00:44:41 +09:00
родитель e393c3f90a
Коммит f28fbefd79
2 изменённых файлов: 48 добавлений и 4 удалений

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

@@ -17,8 +17,8 @@ fn main() -> io::Result<()> {
let backend = CrosstermBackend::new(stdout); let backend = CrosstermBackend::new(stdout);
let mut term = Terminal::new(backend)?; let mut term = Terminal::new(backend)?;
let mut textarea = let mut textarea = TextArea::default();
TextArea::default().block(Block::default().borders(Borders::ALL).title("EXAMPLE")); textarea.block(Block::default().borders(Borders::ALL).title("EXAMPLE"));
let layout = Layout::default() let layout = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.constraints([Constraint::Min(1)].as_ref()); .constraints([Constraint::Min(1)].as_ref());

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

@@ -2,6 +2,7 @@ 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};
#[derive(Clone, Copy)]
pub enum Key { pub enum Key {
Char(char), Char(char),
Backspace, Backspace,
@@ -68,6 +69,7 @@ pub struct TextArea<'a> {
block: Option<Block<'a>>, block: Option<Block<'a>>,
style: Style, style: Style,
cursor: (usize, usize), cursor: (usize, usize),
tab: &'a str,
} }
impl<'a> Default for TextArea<'a> { impl<'a> Default for TextArea<'a> {
@@ -77,6 +79,7 @@ impl<'a> Default for TextArea<'a> {
block: None, block: None,
style: Style::default(), style: Style::default(),
cursor: (0, 0), cursor: (0, 0),
tab: " ",
} }
} }
} }
@@ -90,6 +93,7 @@ impl<'a> TextArea<'a> {
match input.key { match input.key {
Key::Char(c) => self.insert_char(c), Key::Char(c) => self.insert_char(c),
Key::Backspace => self.delete_char(), Key::Backspace => self.delete_char(),
Key::Tab => self.insert_tab(),
_ => {} _ => {}
} }
} }
@@ -104,6 +108,23 @@ impl<'a> TextArea<'a> {
} }
} }
pub fn insert_str(&mut self, s: &str) {
// TODO: Consider \n in `s`
let (row, col) = self.cursor;
let line = &mut self.lines[row];
if let Some((i, _)) = line.char_indices().nth(col) {
line.insert_str(i, s);
self.cursor.1 += s.chars().count();
}
}
pub fn insert_tab(&mut self) {
if !self.tab.is_empty() {
let len = self.tab.len() - self.cursor.1 % self.tab.len();
self.insert_str(&self.tab[..len]);
}
}
pub fn delete_char(&mut self) { pub fn delete_char(&mut self) {
let (row, col) = self.cursor; let (row, col) = self.cursor;
let line = &mut self.lines[row]; let line = &mut self.lines[row];
@@ -141,13 +162,36 @@ impl<'a> TextArea<'a> {
p p
} }
pub fn style(mut self, style: Style) -> Self { pub fn style(&mut self, style: Style) -> &mut Self {
self.style = style; self.style = style;
self self
} }
pub fn block(mut self, block: Block<'a>) -> Self { pub fn block(&mut self, block: Block<'a>) -> &mut Self {
self.block = Some(block); self.block = Some(block);
self self
} }
pub fn remove_block(&mut self) -> &mut Self {
self.block = None;
self
}
pub fn tab(&mut self, tab: &'a str) -> &mut Self {
assert!(
tab.chars().all(|c| c == ' '),
"tab string must consist of spaces but got {:?}",
tab,
);
self.tab = tab;
self
}
pub fn lines(&'a self) -> impl Iterator<Item = &'a str> {
self.lines.iter().map(|l| &l[..l.len() - 1]) // Trim last whitespace
}
pub fn cursor(&self) -> (usize, usize) {
self.cursor
}
} }