diff options
| author | Jonas Maier <jonas@x77.dev> | 2026-05-22 21:26:41 +0200 |
|---|---|---|
| committer | Jonas Maier <jonas@x77.dev> | 2026-05-22 21:26:41 +0200 |
| commit | eeb267c46340d5d47f41cc2440f0b281f9ae9261 (patch) | |
| tree | abcbc6624e0903cc1c7cd919d15a42ebb970692a /src/line/mod.rs | |
| parent | 07daff9331dbdc607584edbf1a8fb3e415c338ea (diff) | |
| download | pish-eeb267c46340d5d47f41cc2440f0b281f9ae9261.tar.gz | |
basic syntax highlighting
Diffstat (limited to 'src/line/mod.rs')
| -rw-r--r-- | src/line/mod.rs | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/line/mod.rs b/src/line/mod.rs new file mode 100644 index 0000000..72f2fe1 --- /dev/null +++ b/src/line/mod.rs @@ -0,0 +1,219 @@ +mod buf; + +use std::io::{self, Write}; + +use crate::cursor::{self, Direction}; +pub use buf::LineBuf; + +pub struct Line { + buf: LineBuf, + dirty: bool, +} + +impl std::ops::Deref for Line { + type Target = LineBuf; + + fn deref(&self) -> &Self::Target { + &self.buf + } +} + +impl Line { + pub fn new() -> Self { + Self { + buf: LineBuf::new(), + dirty: false, + } + } + + pub fn mark_clean(&mut self) { + self.dirty = false; + } + + pub fn is_dirty(&self) -> bool { + self.dirty + } + + pub fn had_contents(&self) -> bool { + self.buf.is_dirty() + } + + pub fn is_empty(&self) -> bool { + self.buf.is_empty() + } + + pub fn cursor_left(&mut self) -> io::Result<()> { + if self.buf.left() { + let mut stdout = io::stdout().lock(); + cursor::fmove_cursor(Direction::Left, 1, &mut stdout)?; + stdout.flush()?; + } + Ok(()) + } + + pub fn cursor_right(&mut self) -> io::Result<()> { + if self.buf.right() { + let mut stdout = io::stdout().lock(); + cursor::fmove_cursor(Direction::Right, 1, &mut stdout)?; + stdout.flush()?; + } + Ok(()) + } + + pub fn move_to_begin(&mut self) -> io::Result<()> { + let mut stdout = io::stdout().lock(); + cursor::fmove_cursor(Direction::Left, self.buf.all_left(), &mut stdout)?; + stdout.flush() + } + + pub fn move_to_end(&mut self) -> io::Result<()> { + let mut stdout = io::stdout().lock(); + cursor::fmove_cursor(Direction::Right, self.buf.all_right(), &mut stdout)?; + stdout.flush() + } + + // move to next + pub fn cursor_left_word(&mut self) -> io::Result<()> { + let mut i = 0; + + // find word + while let Some(b' ') = self.buf.get_left() { + self.buf.left(); + i += 1; + } + + // skip it + while let Some(x) = self.buf.get_left() + && !x.is_ascii_whitespace() + { + self.buf.left(); + i += 1; + } + + let mut stdout = io::stdout().lock(); + cursor::fmove_cursor(Direction::Left, i, &mut stdout)?; + stdout.flush() + } + + pub fn cursor_right_word(&mut self) -> io::Result<()> { + let mut i = 0; + + // find word + while let Some(b' ') = self.buf.get_right() { + self.buf.right(); + i += 1; + } + + // skip it + while let Some(x) = self.buf.get_right() + && !x.is_ascii_whitespace() + { + self.buf.right(); + i += 1; + } + + let mut stdout = io::stdout().lock(); + cursor::fmove_cursor(Direction::Right, i, &mut stdout)?; + stdout.flush() + } +} + +macro_rules! mutating_impls { + ($(pub fn $fun:ident(&mut $self:ident $($arg:tt)*) -> $ty:ty $body:block )*) => { + impl Line {$( + pub fn $fun(&mut $self $($arg)*) -> $ty { + $self.dirty = true; + $body + } + )*} + }; +} + +mutating_impls! { + pub fn clear_prompt(&mut self) -> io::Result<()> { + let mut stdout = io::stdout().lock(); + cursor::fmove_cursor( + Direction::Right, + self.buf.distance_from_right_end(), + &mut stdout, + )?; + for _ in 0..self.buf.len() { + stdout.write_all(b"\x08 \x08")?; + } + self.buf.clear(); + stdout.flush() + } + + pub fn type_bytes(&mut self, bs: &[u8]) -> io::Result<()> { + for b in bs.iter() { + self.buf.add(*b); + } + io::stdout().lock().write_all(&bs)?; + self.buf.display_post(b""); + Ok(()) + } + + pub fn type_byte(&mut self, b: u8) -> io::Result<()> { + self.type_bytes(&[b]) + } + + pub fn del_left(&mut self) -> io::Result<()> { + if self.buf.del_left().is_some() { + cursor::fmove_cursor(Direction::Left, 1, &mut io::stdout())?; + self.buf.display_post(b" "); + } + Ok(()) + } + + pub fn del_right(&mut self) -> io::Result<()> { + self.buf.del_right(); + self.buf.display_post(b" "); + Ok(()) + } + + pub fn del_left_word(&mut self) -> io::Result<()> { + let mut del = 0; + while let Some(x) = self.buf.get_left() + && x == b' ' + { + self.buf.del_left(); + del += 1; + } + while let Some(x) = self.buf.get_left() + && x != b' ' + { + self.buf.del_left(); + del += 1; + } + cursor::fmove_cursor(Direction::Left, del, &mut io::stdout())?; + self.buf.display_post(&vec![b' '; del]); + Ok(()) + } + + pub fn del_right_word(&mut self) -> io::Result<()> { + let mut del = 0; + while let Some(x) = self.buf.get_right() + && x == b' ' + { + self.buf.del_right(); + del += 1; + } + while let Some(x) = self.buf.get_right() + && x != b' ' + { + self.buf.del_right(); + del += 1; + } + self.buf.display_post(&vec![b' '; del]); + Ok(()) + } + + pub fn set_content(&mut self, content: Vec<u8>) -> io::Result<()> { + self.buf.set_content(content); + Ok(()) + } + + pub fn dump(&mut self) -> Vec<u8> { + self.buf.dump() + } +} |
