implemented rot13 with 'g?'

This commit is contained in:
2025-05-31 01:52:27 -04:00
parent 25ec8c72be
commit 275d902849
3 changed files with 97 additions and 16 deletions

View File

@@ -21,6 +21,7 @@ pub enum MotionKind {
Forward(usize), Forward(usize),
To(usize), // Land just before To(usize), // Land just before
On(usize), // Land directly on On(usize), // Land directly on
Before(usize), // Had to make a separate one for char searches, for some reason
Backward(usize), Backward(usize),
Range((usize,usize)), Range((usize,usize)),
Line(isize), // positive = up line, negative = down line Line(isize), // positive = up line, negative = down line
@@ -1268,24 +1269,36 @@ impl LineBuf {
} }
} }
Motion::CharSearch(direction, dest, ch) => { Motion::CharSearch(direction, dest, ch) => {
let ch = format!("{ch}");
let saved_cursor = self.cursor;
match direction { match direction {
Direction::Forward => { Direction::Forward => {
let Some(pos) = self.slice_from_cursor().find(ch) else { if self.grapheme_at_cursor().is_some_and(|c| c == ch) {
self.cursor_fwd(1);
}
let Some(pos) = self.find(|c| c == ch) else {
self.cursor = saved_cursor;
return MotionKind::Null return MotionKind::Null
}; };
self.cursor = saved_cursor;
match dest { match dest {
Dest::On => MotionKind::To(pos), Dest::On => MotionKind::On(pos),
Dest::Before => MotionKind::To(pos.saturating_sub(1)), Dest::Before => MotionKind::Before(pos),
Dest::After => todo!(), Dest::After => todo!(),
} }
} }
Direction::Backward => { Direction::Backward => {
let Some(pos) = self.slice_to_cursor().rfind(ch) else { if self.grapheme_at_cursor().is_some_and(|c| c == ch) {
self.cursor_back(1);
}
let Some(pos) = self.rfind(|c| c == ch) else {
self.cursor = saved_cursor;
return MotionKind::Null return MotionKind::Null
}; };
self.cursor = saved_cursor;
match dest { match dest {
Dest::On => MotionKind::To(pos), Dest::On => MotionKind::On(pos),
Dest::Before => MotionKind::To(pos + 1), Dest::Before => MotionKind::Before(pos),
Dest::After => todo!(), Dest::After => todo!(),
} }
} }
@@ -1396,6 +1409,15 @@ impl LineBuf {
let range = mk_range_inclusive(self.cursor, *n); let range = mk_range_inclusive(self.cursor, *n);
Some(range) Some(range)
} }
MotionKind::Before(n) => {
let n = match n.cmp(&self.cursor) {
Ordering::Less => (n + 1).min(self.byte_len()),
Ordering::Equal => n.saturating_sub(1),
Ordering::Greater => *n
};
let range = mk_range_inclusive(n, self.cursor);
Some(range)
}
MotionKind::Backward(n) => { MotionKind::Backward(n) => {
let pos = self.prev_pos(*n)?; let pos = self.prev_pos(*n)?;
let range = pos..self.cursor; let range = pos..self.cursor;
@@ -1512,6 +1534,7 @@ impl LineBuf {
Anchor::Before => { Anchor::Before => {
if self.grapheme_at(self.cursor.saturating_sub(1)).is_some() { if self.grapheme_at(self.cursor.saturating_sub(1)).is_some() {
self.buffer.remove(self.cursor.saturating_sub(1)); self.buffer.remove(self.cursor.saturating_sub(1));
self.cursor_back(1);
} }
} }
} }
@@ -1550,7 +1573,8 @@ impl LineBuf {
let Some(range) = self.get_range_from_motion(&verb, &motion) else { let Some(range) = self.get_range_from_motion(&verb, &motion) else {
return Ok(()) return Ok(())
}; };
let new_range = format!("{c}"); let delta = range.end - range.start;
let new_range = format!("{c}").repeat(delta);
let cursor_pos = range.end; let cursor_pos = range.end;
self.buffer.replace_range(range, &new_range); self.buffer.replace_range(range, &new_range);
self.cursor = cursor_pos self.cursor = cursor_pos
@@ -1712,6 +1736,14 @@ impl LineBuf {
}; };
self.dedent_lines(range) self.dedent_lines(range)
} }
Verb::Rot13 => {
let Some(range) = self.get_range_from_motion(&verb, &motion) else {
return Ok(())
};
let slice = &self.buffer[range.clone()];
let rot13 = rot13(slice);
self.buffer.replace_range(range, &rot13);
}
Verb::Equalize => todo!(), // I fear this one Verb::Equalize => todo!(), // I fear this one
Verb::Builder(verb_builder) => todo!(), Verb::Builder(verb_builder) => todo!(),
Verb::EndOfFile => { Verb::EndOfFile => {
@@ -1761,14 +1793,33 @@ impl LineBuf {
} }
} }
} }
MotionKind::On(n) | MotionKind::To(n) |
MotionKind::To(n) => { MotionKind::On(n) => {
if n > self.byte_len() { if n > self.byte_len() {
self.cursor = self.byte_len(); self.cursor = self.byte_len();
} else { } else {
self.cursor = n self.cursor = n
} }
} }
MotionKind::Before(n) => {
if n > self.byte_len() {
self.cursor = self.byte_len();
} else {
match n.cmp(&self.cursor) {
Ordering::Less => {
let n = (n + 1).min(self.byte_len());
self.cursor = n
}
Ordering::Equal => {
self.cursor = n
}
Ordering::Greater => {
let n = n.saturating_sub(1);
self.cursor = n
}
}
}
}
MotionKind::Range(range) => { MotionKind::Range(range) => {
assert!((0..self.byte_len()).contains(&range.0)); assert!((0..self.byte_len()).contains(&range.0));
if self.cursor != range.0 { if self.cursor != range.0 {
@@ -1834,10 +1885,7 @@ impl LineBuf {
mode.invert_anchor(); mode.invert_anchor();
flog!(DEBUG,start,end); flog!(DEBUG,start,end);
std::mem::swap(&mut start, &mut end); std::mem::swap(&mut start, &mut end);
match mode.anchor() {
SelectionAnchor::Start => end += 1,
SelectionAnchor::End => start -= 1,
}
self.select_mode = Some(mode); self.select_mode = Some(mode);
flog!(DEBUG,start,end); flog!(DEBUG,start,end);
flog!(DEBUG,mode); flog!(DEBUG,mode);
@@ -2003,6 +2051,22 @@ pub fn strip_ansi_codes_and_escapes(s: &str) -> String {
out out
} }
pub fn rot13(input: &str) -> String {
input.chars()
.map(|c| {
if c.is_ascii_lowercase() {
let offset = b'a';
(((c as u8 - offset + 13) % 26) + offset) as char
} else if c.is_ascii_uppercase() {
let offset = b'A';
(((c as u8 - offset + 13) % 26) + offset) as char
} else {
c
}
})
.collect()
}
pub fn is_grapheme_boundary(s: &str, pos: usize) -> bool { pub fn is_grapheme_boundary(s: &str, pos: usize) -> bool {
s.is_char_boundary(pos) && s.grapheme_indices(true).any(|(i,_)| i == pos) s.is_char_boundary(pos) && s.grapheme_indices(true).any(|(i,_)| i == pos)
} }

View File

@@ -371,6 +371,11 @@ impl ViNormal {
} }
) )
} }
'?' => {
chars_clone.next();
chars = chars_clone;
break 'verb_parse Some(VerbCmd(count, Verb::Rot13));
}
_ => break 'verb_parse None _ => break 'verb_parse None
} }
} else { } else {
@@ -600,6 +605,7 @@ impl ViNormal {
break 'motion_parse None break 'motion_parse None
}; };
match (ch, &verb) { match (ch, &verb) {
('?', Some(VerbCmd(_,Verb::Rot13))) |
('d', Some(VerbCmd(_,Verb::Delete))) | ('d', Some(VerbCmd(_,Verb::Delete))) |
('c', Some(VerbCmd(_,Verb::Change))) | ('c', Some(VerbCmd(_,Verb::Change))) |
('y', Some(VerbCmd(_,Verb::Yank))) | ('y', Some(VerbCmd(_,Verb::Yank))) |
@@ -764,15 +770,14 @@ impl ViNormal {
match self.validate_combination(verb_ref, motion_ref) { match self.validate_combination(verb_ref, motion_ref) {
CmdState::Complete => { CmdState::Complete => {
let cmd = Some( Some(
ViCmd { ViCmd {
register, register,
verb, verb,
motion, motion,
raw_seq: std::mem::take(&mut self.pending_seq) raw_seq: std::mem::take(&mut self.pending_seq)
} }
); )
cmd
} }
CmdState::Pending => { CmdState::Pending => {
None None
@@ -956,6 +961,16 @@ impl ViVisual {
} }
) )
} }
'?' => {
return Some(
ViCmd {
register,
verb: Some(VerbCmd(1, Verb::Rot13)),
motion: None,
raw_seq: self.take_cmd()
}
)
}
_ => break 'verb_parse None _ => break 'verb_parse None
} }
} else { } else {

View File

@@ -171,6 +171,7 @@ pub enum Verb {
Dedent, Dedent,
Equalize, Equalize,
AcceptLine, AcceptLine,
Rot13, // lol
Builder(VerbBuilder), Builder(VerbBuilder),
EndOfFile EndOfFile
} }
@@ -229,6 +230,7 @@ impl Verb {
Self::InsertChar(_) | Self::InsertChar(_) |
Self::Insert(_) | Self::Insert(_) |
Self::Breakline(_) | Self::Breakline(_) |
Self::Rot13 |
Self::EndOfFile Self::EndOfFile
) )
} }