early implementation of inserting verbatim with ctrl+v

This commit is contained in:
2025-05-28 03:21:51 -04:00
parent d15903fea1
commit f67543c111
3 changed files with 86 additions and 8 deletions

View File

@@ -1144,7 +1144,12 @@ impl LineBuf {
self.insert(ch);
self.apply_motion(motion);
}
Verb::Insert(_) => todo!(),
Verb::Insert(str) => {
for ch in str.chars() {
self.insert(ch);
self.cursor_fwd(1);
}
}
Verb::Breakline(anchor) => todo!(),
Verb::Indent => todo!(),
Verb::Dedent => todo!(),
@@ -1203,14 +1208,23 @@ impl LineBuf {
match n.cmp(&0) {
Ordering::Equal => {
let (start,_) = self.this_line();
if start == 0 {
return
}
self.cursor = start;
}
Ordering::Less => {
let (start,_) = self.select_lines_up(n.unsigned_abs());
if start == 0 {
return
}
self.cursor = start;
}
Ordering::Greater => {
let (_,end) = self.select_lines_down(n.unsigned_abs());
if end == self.byte_len() {
return
}
self.cursor = end.saturating_sub(1);
let (start,_) = self.this_line();
self.cursor = start;
@@ -1264,6 +1278,10 @@ impl LineBuf {
edit.stop_merge();
}
}
if clear_redos {
flog!(DEBUG, "clearing redos");
flog!(DEBUG,cmd);
}
let ViCmd { register, verb, motion, .. } = cmd;

View File

@@ -1,5 +1,6 @@
use std::time::Duration;
use keys::{KeyCode, KeyEvent, ModKeys};
use linebuf::{strip_ansi_codes_and_escapes, LineBuf};
use mode::{CmdReplay, ViInsert, ViMode, ViNormal, ViReplace};
use term::Terminal;
@@ -55,6 +56,10 @@ impl Readline for FernVi {
loop {
let key = self.term.read_key();
if let KeyEvent(KeyCode::Char('V'), ModKeys::CTRL) = key {
self.handle_verbatim();
continue
}
let Some(cmd) = self.mode.handle_key(key) else {
continue
};
@@ -84,6 +89,68 @@ impl FernVi {
last_movement: None,
}
}
pub fn handle_verbatim(&mut self) -> ShResult<()> {
let mut buf = [0u8; 8];
let mut collected = Vec::new();
loop {
let n = self.term.read_byte(&mut buf[..1]);
if n == 0 {
continue;
}
collected.push(buf[0]);
// If it starts with ESC, treat as escape sequence
if collected[0] == 0x1b {
loop {
let n = self.term.peek_byte(&mut buf[..1]);
if n == 0 {
break
}
collected.push(buf[0]);
// Ends a CSI sequence
if (0x40..=0x7e).contains(&buf[0]) {
break;
}
}
let Ok(seq) = std::str::from_utf8(&collected) else {
return Ok(())
};
let cmd = ViCmd {
register: Default::default(),
verb: Some(VerbCmd(1, Verb::Insert(seq.to_string()))),
motion: None,
raw_seq: seq.to_string(),
};
self.line.exec_cmd(cmd)?;
}
// Optional: handle other edge cases, e.g., raw control codes
if collected[0] < 0x20 || collected[0] == 0x7F {
let ctrl_seq = std::str::from_utf8(&collected).unwrap();
let cmd = ViCmd {
register: Default::default(),
verb: Some(VerbCmd(1, Verb::Insert(ctrl_seq.to_string()))),
motion: None,
raw_seq: ctrl_seq.to_string(),
};
self.line.exec_cmd(cmd)?;
break;
}
// Try to parse as UTF-8 if it's a valid Unicode sequence
if let Ok(s) = std::str::from_utf8(&collected) {
if s.chars().count() == 1 {
let ch = s.chars().next().unwrap();
// You got a literal Unicode char
eprintln!("Got char: {:?}", ch);
break;
}
}
}
Ok(())
}
pub fn print_buf(&mut self, refresh: bool) -> ShResult<()> {
let (height,width) = self.term.get_dimensions()?;
if refresh {

View File

@@ -302,7 +302,6 @@ impl ViNormal {
}
pub fn try_parse(&mut self, ch: char) -> Option<ViCmd> {
self.pending_seq.push(ch);
flog!(DEBUG, self.pending_seq);
let mut chars = self.pending_seq.chars().peekable();
let register = 'reg_parse: {
@@ -333,7 +332,6 @@ impl ViNormal {
let Some(ch) = chars_clone.next() else {
break 'verb_parse None
};
flog!(DEBUG, "parsing verb char '{}'",ch);
match ch {
'.' => {
return Some(
@@ -519,7 +517,6 @@ impl ViNormal {
let Some(ch) = chars_clone.next() else {
break 'motion_parse None
};
flog!(DEBUG, "parsing motion char '{}'",ch);
match (ch, &verb) {
('d', Some(VerbCmd(_,Verb::Delete))) |
('c', Some(VerbCmd(_,Verb::Change))) |
@@ -692,15 +689,12 @@ impl ViNormal {
raw_seq: std::mem::take(&mut self.pending_seq)
}
);
flog!(DEBUG, cmd);
cmd
}
CmdState::Pending => {
flog!(DEBUG, "pending sequence: {}", self.pending_seq);
None
}
CmdState::Invalid => {
flog!(DEBUG, "invalid sequence: {}",self.pending_seq);
self.pending_seq.clear();
None
}
@@ -710,7 +704,6 @@ impl ViNormal {
impl ViMode for ViNormal {
fn handle_key(&mut self, key: E) -> Option<ViCmd> {
flog!(DEBUG, key);
match key {
E(K::Char(ch), M::NONE) => self.try_parse(ch),
E(K::Backspace, M::NONE) => {