|
| 1 | +use std::{io, sync::MutexGuard}; |
| 2 | + |
| 3 | +use crate::utils::{ |
| 4 | + terminal::TermManager, |
| 5 | + ui::{ |
| 6 | + event::{KeyEventCallback, WarpUiCallBackType}, |
| 7 | + uicore::{UiCore, CONTENT_WINSIZE}, |
| 8 | + }, |
| 9 | +}; |
| 10 | + |
| 11 | +pub trait CommonOp: KeyEventCallback { |
| 12 | + fn remove_line(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<()> { |
| 13 | + TermManager::clear_current_line()?; |
| 14 | + TermManager::clear_under_cursor()?; |
| 15 | + let y = ui.cursor.y() as usize; |
| 16 | + let old_line_count = ui.buffer.line_count(); |
| 17 | + let old_offset = ui.buffer.offset(); |
| 18 | + |
| 19 | + let count = old_line_count - y as usize; |
| 20 | + ui.buffer.delete_line(y + ui.buffer.offset() as usize); |
| 21 | + ui.render_content(y as u16, count.max(1))?; |
| 22 | + |
| 23 | + if y + old_offset == old_line_count - 1 { |
| 24 | + self.up(ui)?; |
| 25 | + } |
| 26 | + |
| 27 | + if old_line_count == 1 { |
| 28 | + ui.cursor.move_to_columu(0)?; |
| 29 | + ui.buffer.insert_char('\n' as u8, 0, 0); |
| 30 | + ui.render_content(0, 1)?; |
| 31 | + } |
| 32 | + |
| 33 | + Ok(()) |
| 34 | + } |
| 35 | + |
| 36 | + fn remove_n_line(&self, ui: &mut MutexGuard<UiCore>, n: u16) -> io::Result<()> { |
| 37 | + let linecount = ui.buffer.line_count() as u16; |
| 38 | + let y = ui.cursor.y(); |
| 39 | + |
| 40 | + // 实际能删除的行数 |
| 41 | + let to_delete = n.min(linecount - y); |
| 42 | + for _ in 0..to_delete { |
| 43 | + self.remove_line(ui)?; |
| 44 | + } |
| 45 | + Ok(()) |
| 46 | + } |
| 47 | + fn remove_word(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<()> { |
| 48 | + let x = ui.cursor.x(); |
| 49 | + let y = ui.cursor.y(); |
| 50 | + let next_word_pos = ui.buffer.search_nextw_begin(x, y); |
| 51 | + let linesize = ui.buffer.get_linesize(y); |
| 52 | + |
| 53 | + // 如果下一个单词在当前行,则删除当前单词 |
| 54 | + if next_word_pos < linesize.into() { |
| 55 | + ui.buffer.remove_str(x, y, next_word_pos - x as usize); |
| 56 | + } else { |
| 57 | + // 如果下一个单词在下一行,则删除当前行剩余部分 |
| 58 | + self.left(ui)?; |
| 59 | + ui.buffer.delete_line(y.into()); |
| 60 | + self.down(ui)?; |
| 61 | + } |
| 62 | + ui.render_content(y, 1)?; |
| 63 | + return Ok(()); |
| 64 | + } |
| 65 | + fn jump_to_next_word(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> { |
| 66 | + let x = ui.cursor.x(); |
| 67 | + let y = ui.cursor.y(); |
| 68 | + let pos = ui.buffer.search_nextw_begin(x, y); |
| 69 | + let linesize = ui.buffer.get_linesize(y); |
| 70 | + let abs_y = y + ui.buffer.offset() as u16; |
| 71 | + |
| 72 | + if pos < linesize as usize { |
| 73 | + // 如果下一个单词在当前行,则移动光标到该单词的起始位置 |
| 74 | + ui.cursor.move_to_columu(pos as u16)?; |
| 75 | + } else if y as usize + ui.buffer.offset() < ui.buffer.line_count() - 1 { |
| 76 | + // 如果当前行不是最后一行,则移动到下一行的单词起始位置 |
| 77 | + let next_word_pos = ui.buffer.search_nextw_begin(0, y + 1) as u16; |
| 78 | + let next_linesize = ui.buffer.get_linesize_abs(abs_y + 1); |
| 79 | + self.down(ui)?; |
| 80 | + ui.cursor |
| 81 | + .move_to_columu(next_word_pos.min(next_linesize - 1))?; |
| 82 | + ui.cursor.highlight(Some(y))?; |
| 83 | + } else { |
| 84 | + // 如果当前行是最后一行,则移动到当前行的末尾 |
| 85 | + ui.cursor.move_to_columu(linesize as u16 - 1)?; |
| 86 | + } |
| 87 | + return Ok(WarpUiCallBackType::None); |
| 88 | + } |
| 89 | + fn move_to_line(&self, ui: &mut MutexGuard<UiCore>, line: u16) -> io::Result<()> { |
| 90 | + let x = ui.cursor.x(); |
| 91 | + let y = ui.cursor.y(); |
| 92 | + let new_y = ui.buffer.goto_line(line as usize); |
| 93 | + let new_x = x.min(ui.buffer.get_linesize(new_y)) as u16; |
| 94 | + ui.cursor.move_to(new_x, new_y)?; |
| 95 | + ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; |
| 96 | + ui.cursor.highlight(Some(y))?; |
| 97 | + return Ok(()); |
| 98 | + } |
| 99 | + |
| 100 | + fn locate_prevw_begin(&self, ui: &mut MutexGuard<UiCore>, x: u16, abs_y: u16) -> (u16, u16) { |
| 101 | + // 如果光标已在行首,则尝试移动到上一行的单词首字母 |
| 102 | + if x == 0 { |
| 103 | + if abs_y == 0 { |
| 104 | + return (0, 0); |
| 105 | + } |
| 106 | + let last_y = abs_y - 1; |
| 107 | + let end_of_prev_line = ui.buffer.get_linesize_abs(last_y) - 1; |
| 108 | + let prev_word_pos = ui.buffer.search_prevw_begin_abs(end_of_prev_line, last_y); |
| 109 | + return (prev_word_pos as u16, last_y); |
| 110 | + } |
| 111 | + |
| 112 | + let prev_word_pos = ui.buffer.search_prevw_begin_abs(x, abs_y); |
| 113 | + |
| 114 | + return (prev_word_pos as u16, abs_y); |
| 115 | + } |
| 116 | + fn locate_nextw_ending(&self, ui: &mut MutexGuard<UiCore>, x: u16, y: u16) -> (u16, u16) { |
| 117 | + let linesize = ui.buffer.get_linesize(y) as usize; |
| 118 | + |
| 119 | + // y的绝对位置 |
| 120 | + let abs_y = ui.buffer.offset() as u16 + y; |
| 121 | + // 如果光标已经在当前行的末尾或最后一个字符(x + 2),则尝试移动到下一行的末尾或单词末尾 |
| 122 | + if x as usize + 2 >= linesize { |
| 123 | + if abs_y < ui.buffer.line_count() as u16 - 1 { |
| 124 | + let next_end_pos = ui.buffer.search_nextw_end(0, y + 1) as u16; |
| 125 | + return (next_end_pos, abs_y + 1); |
| 126 | + } else { |
| 127 | + // 如果已经是最后一行,则保持光标在当前行的末尾 |
| 128 | + let x = if linesize > 0 { linesize - 1 } else { 0 }; |
| 129 | + return (x as u16, abs_y); |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + let next_end_pos = ui.buffer.search_nextw_end(x, y) as u16; |
| 134 | + // 如果下一个单词的末尾在当前行,则移动光标到该单词的末尾 |
| 135 | + return (next_end_pos.min(linesize as u16 - 1), abs_y); |
| 136 | + } |
| 137 | +} |
0 commit comments