Skip to content

Commit

Permalink
Feat statemachine (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
trv3wood authored Sep 11, 2024
1 parent 2d55501 commit fcc6ced
Show file tree
Hide file tree
Showing 6 changed files with 878 additions and 14 deletions.
87 changes: 73 additions & 14 deletions src/utils/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ pub struct EditBuffer {
locked_lines: RwLock<HashMap<usize, usize>>,
}

#[allow(unused)]
impl EditBuffer {
pub fn new(buf: Vec<u8>) -> Self {
let mut lines = buf
Expand Down Expand Up @@ -157,6 +156,18 @@ impl EditBuffer {
line.data.len() as u16
}

pub fn get_linesize_abs(&self, line: u16) -> u16 {
let buf = self.buf.read().unwrap();
let line = buf.get(line as usize);
if line.is_none() {
return 0;
}

let line = line.unwrap();

line.data.len() as u16
}

/// 外部接口,本结构体内部方法不应该使用,因为涉及offset计算
pub fn remove_char(&self, x: u16, y: u16) {
let mut buf = self.buf.write().unwrap();
Expand Down Expand Up @@ -379,7 +390,11 @@ impl EditBuffer {

pub fn delete_line(&self, y: usize) {
let mut buffer = self.buf.write().unwrap();
let line = buffer.get(y).unwrap();
let line = buffer.get(y);
if line.is_none() {
return;
}
let line = line.unwrap();
if line.data.is_empty() {
return;
}
Expand All @@ -389,17 +404,20 @@ impl EditBuffer {
}
}

/// 删除 y 行 0..x 的字符
pub fn delete_until_line_beg(&self, x: usize, y: usize) -> Option<usize> {
let mut buffer = self.buf.write().unwrap();
let line = buffer.get_mut(y).unwrap();

if line.data.len() < 2 {
let len = line.data.len();
if len < 2 {
return None;
}
line.data.drain(0..x);
line.data.drain(0..x.min(len - 1));
return Some(x - 1);
}

/// 删除 y 行 x..end 的字符
pub fn delete_until_endl(&self, x: usize, y: usize) -> Option<usize> {
let mut buffer = self.buf.write().unwrap();
let line = buffer.get_mut(y).unwrap();
Expand All @@ -418,13 +436,17 @@ impl EditBuffer {
let mut right = left;
let linesize = self.get_linesize(y) as usize;
let buf = self.buf.read().unwrap();
let line = buf
.get(self.offset.load(Ordering::SeqCst) + y as usize)
.unwrap();
let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) {
Some(line) => line,
None => return x as usize,
};

while left <= right && right < linesize {
let lchar = line[left] as char;
let rchar = line[right] as char;
if rchar.is_ascii_punctuation() && right != x.into() {
break;
}
if !(lchar == ' ' || lchar == '\t') {
left += 1;
right += 1;
Expand All @@ -446,13 +468,17 @@ impl EditBuffer {
let mut right = left;
let linesize = self.get_linesize(y) as usize;
let buf = self.buf.read().unwrap();
let line = buf
.get(self.offset.load(Ordering::SeqCst) + y as usize)
.unwrap();
let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) {
Some(line) => line,
None => return x as usize,
};

while left <= right && right < linesize {
let lchar = line[left] as char;
let rchar = line[right] as char;
if rchar.is_ascii_punctuation() && right != x.into() {
break;
}
if lchar == ' ' || lchar == '\t' {
left += 1;
right += 1;
Expand All @@ -477,14 +503,17 @@ impl EditBuffer {
let mut left = x as i32;
let mut right = left;
let buf = self.buf.read().unwrap();
let line = buf
.get(self.offset.load(Ordering::SeqCst) + y as usize)
.unwrap();

let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) {
Some(line) => line,
None => return Some(x as usize),
};
while left <= right && left >= 0 {
let lchar = line[left as usize] as char;
let rchar = line[right as usize] as char;

if lchar.is_ascii_punctuation() && left != x.into() {
return Some(left as usize);
}
if rchar == ' ' || rchar == '\t' {
left -= 1;
right -= 1;
Expand All @@ -503,6 +532,36 @@ impl EditBuffer {
}
return None;
}
pub fn search_prevw_begin_abs(&self, x: u16, abs_y: u16) -> usize {
let mut left = x as i32;
let mut right = left;
let buf = self.buf.read().unwrap();
let line = buf.get(abs_y as usize).unwrap();
while left <= right && left >= 0 {
let lchar = line[left as usize] as char;
let rchar = line[right as usize] as char;

if lchar.is_ascii_punctuation() && left != x.into() {
return left as usize;
}
if rchar == ' ' || rchar == '\t' {
left -= 1;
right -= 1;
continue;
}

if lchar == ' ' || lchar == '\t' {
if left + 1 == x.into() {
right = left;
continue;
}
return left as usize + 1;
}

left -= 1;
}
return 0;
}
}

bitflags! {
Expand Down
137 changes: 137 additions & 0 deletions src/utils/ui/mode/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use std::{io, sync::MutexGuard};

use crate::utils::{
terminal::TermManager,
ui::{
event::{KeyEventCallback, WarpUiCallBackType},
uicore::{UiCore, CONTENT_WINSIZE},
},
};

pub trait CommonOp: KeyEventCallback {
fn remove_line(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<()> {
TermManager::clear_current_line()?;
TermManager::clear_under_cursor()?;
let y = ui.cursor.y() as usize;
let old_line_count = ui.buffer.line_count();
let old_offset = ui.buffer.offset();

let count = old_line_count - y as usize;
ui.buffer.delete_line(y + ui.buffer.offset() as usize);
ui.render_content(y as u16, count.max(1))?;

if y + old_offset == old_line_count - 1 {
self.up(ui)?;
}

if old_line_count == 1 {
ui.cursor.move_to_columu(0)?;
ui.buffer.insert_char('\n' as u8, 0, 0);
ui.render_content(0, 1)?;
}

Ok(())
}

fn remove_n_line(&self, ui: &mut MutexGuard<UiCore>, n: u16) -> io::Result<()> {
let linecount = ui.buffer.line_count() as u16;
let y = ui.cursor.y();

// 实际能删除的行数
let to_delete = n.min(linecount - y);
for _ in 0..to_delete {
self.remove_line(ui)?;
}
Ok(())
}
fn remove_word(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<()> {
let x = ui.cursor.x();
let y = ui.cursor.y();
let next_word_pos = ui.buffer.search_nextw_begin(x, y);
let linesize = ui.buffer.get_linesize(y);

// 如果下一个单词在当前行,则删除当前单词
if next_word_pos < linesize.into() {
ui.buffer.remove_str(x, y, next_word_pos - x as usize);
} else {
// 如果下一个单词在下一行,则删除当前行剩余部分
self.left(ui)?;
ui.buffer.delete_line(y.into());
self.down(ui)?;
}
ui.render_content(y, 1)?;
return Ok(());
}
fn jump_to_next_word(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
let x = ui.cursor.x();
let y = ui.cursor.y();
let pos = ui.buffer.search_nextw_begin(x, y);
let linesize = ui.buffer.get_linesize(y);
let abs_y = y + ui.buffer.offset() as u16;

if pos < linesize as usize {
// 如果下一个单词在当前行,则移动光标到该单词的起始位置
ui.cursor.move_to_columu(pos as u16)?;
} else if y as usize + ui.buffer.offset() < ui.buffer.line_count() - 1 {
// 如果当前行不是最后一行,则移动到下一行的单词起始位置
let next_word_pos = ui.buffer.search_nextw_begin(0, y + 1) as u16;
let next_linesize = ui.buffer.get_linesize_abs(abs_y + 1);
self.down(ui)?;
ui.cursor
.move_to_columu(next_word_pos.min(next_linesize - 1))?;
ui.cursor.highlight(Some(y))?;
} else {
// 如果当前行是最后一行,则移动到当前行的末尾
ui.cursor.move_to_columu(linesize as u16 - 1)?;
}
return Ok(WarpUiCallBackType::None);
}
fn move_to_line(&self, ui: &mut MutexGuard<UiCore>, line: u16) -> io::Result<()> {
let x = ui.cursor.x();
let y = ui.cursor.y();
let new_y = ui.buffer.goto_line(line as usize);
let new_x = x.min(ui.buffer.get_linesize(new_y)) as u16;
ui.cursor.move_to(new_x, new_y)?;
ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?;
ui.cursor.highlight(Some(y))?;
return Ok(());
}

fn locate_prevw_begin(&self, ui: &mut MutexGuard<UiCore>, x: u16, abs_y: u16) -> (u16, u16) {
// 如果光标已在行首,则尝试移动到上一行的单词首字母
if x == 0 {
if abs_y == 0 {
return (0, 0);
}
let last_y = abs_y - 1;
let end_of_prev_line = ui.buffer.get_linesize_abs(last_y) - 1;
let prev_word_pos = ui.buffer.search_prevw_begin_abs(end_of_prev_line, last_y);
return (prev_word_pos as u16, last_y);
}

let prev_word_pos = ui.buffer.search_prevw_begin_abs(x, abs_y);

return (prev_word_pos as u16, abs_y);
}
fn locate_nextw_ending(&self, ui: &mut MutexGuard<UiCore>, x: u16, y: u16) -> (u16, u16) {
let linesize = ui.buffer.get_linesize(y) as usize;

// y的绝对位置
let abs_y = ui.buffer.offset() as u16 + y;
// 如果光标已经在当前行的末尾或最后一个字符(x + 2),则尝试移动到下一行的末尾或单词末尾
if x as usize + 2 >= linesize {
if abs_y < ui.buffer.line_count() as u16 - 1 {
let next_end_pos = ui.buffer.search_nextw_end(0, y + 1) as u16;
return (next_end_pos, abs_y + 1);
} else {
// 如果已经是最后一行,则保持光标在当前行的末尾
let x = if linesize > 0 { linesize - 1 } else { 0 };
return (x as u16, abs_y);
}
}

let next_end_pos = ui.buffer.search_nextw_end(x, y) as u16;
// 如果下一个单词的末尾在当前行,则移动光标到该单词的末尾
return (next_end_pos.min(linesize as u16 - 1), abs_y);
}
}
2 changes: 2 additions & 0 deletions src/utils/ui/mode/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub mod common;
pub mod mode;
pub mod normal;
12 changes: 12 additions & 0 deletions src/utils/ui/mode/mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use crate::utils::ui::{

use crate::utils::ui::event::WarpUiCallBackType;

use super::normal::Normal;

pub trait InputMode: KeyEventCallback + Debug {
fn mode_type(&self) -> ModeType;

Expand Down Expand Up @@ -105,6 +107,7 @@ pub enum ModeType {
Command,
LastLine,
Insert,
Normal,
}

impl InputMode for Command {
Expand All @@ -122,6 +125,11 @@ impl InputMode for Insert {
ModeType::Insert
}
}
impl InputMode for Normal {
fn mode_type(&self) -> ModeType {
ModeType::Normal
}
}

#[derive(Debug)]
pub struct Command;
Expand Down Expand Up @@ -557,6 +565,10 @@ impl KeyEventCallback for Command {
return Ok(WarpUiCallBackType::None);
}

b"n" => {
return Ok(WarpUiCallBackType::ChangMode(ModeType::Normal));
}

b"H" => {
self.move_to_nlines_of_screen(ui, 0)?;
return Ok(WarpUiCallBackType::None);
Expand Down
Loading

0 comments on commit fcc6ced

Please sign in to comment.