started work on text objects
pressing l in normal mode now accepts hints
This commit is contained in:
@@ -69,14 +69,21 @@ impl From<&str> for CharClass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_whitespace(a: &str) -> bool {
|
||||||
|
CharClass::from(a) == CharClass::Whitespace
|
||||||
|
}
|
||||||
|
|
||||||
fn is_other_class_or_ws(a: &str, b: &str) -> bool {
|
fn is_other_class(a: &str, b: &str) -> bool {
|
||||||
let a = CharClass::from(a);
|
let a = CharClass::from(a);
|
||||||
let b = CharClass::from(b);
|
let b = CharClass::from(b);
|
||||||
if a == CharClass::Whitespace || b == CharClass::Whitespace {
|
a != b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_other_class_or_ws(a: &str, b: &str) -> bool {
|
||||||
|
if is_whitespace(a) || is_whitespace(b) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
a != b
|
is_other_class(a, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +251,9 @@ impl LineBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
pub fn into_line(self) -> String {
|
||||||
|
self.buffer
|
||||||
|
}
|
||||||
pub fn slice_from_cursor_to_end_of_line(&self) -> &str {
|
pub fn slice_from_cursor_to_end_of_line(&self) -> &str {
|
||||||
let end = self.end_of_line();
|
let end = self.end_of_line();
|
||||||
&self.buffer[self.cursor..end]
|
&self.buffer[self.cursor..end]
|
||||||
@@ -780,7 +790,82 @@ impl LineBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn eval_text_object(&self, obj: TextObj, bound: Bound) -> Option<Range<usize>> {
|
||||||
|
flog!(DEBUG, obj);
|
||||||
|
flog!(DEBUG, bound);
|
||||||
|
match obj {
|
||||||
|
TextObj::Word(word) => {
|
||||||
|
match word {
|
||||||
|
Word::Big => match bound {
|
||||||
|
Bound::Inside => {
|
||||||
|
let start = self.rfind(is_whitespace)
|
||||||
|
.map(|pos| pos+1)
|
||||||
|
.unwrap_or(0);
|
||||||
|
let end = self.find(is_whitespace)
|
||||||
|
.map(|pos| pos-1)
|
||||||
|
.unwrap_or(self.byte_len());
|
||||||
|
Some(start..end)
|
||||||
|
}
|
||||||
|
Bound::Around => {
|
||||||
|
let start = self.rfind(is_whitespace)
|
||||||
|
.map(|pos| pos+1)
|
||||||
|
.unwrap_or(0);
|
||||||
|
let mut end = self.find(is_whitespace)
|
||||||
|
.unwrap_or(self.byte_len());
|
||||||
|
if end != self.byte_len() {
|
||||||
|
end = self.find_from(end,|c| !is_whitespace(c))
|
||||||
|
.map(|pos| pos-1)
|
||||||
|
.unwrap_or(self.byte_len())
|
||||||
|
}
|
||||||
|
Some(start..end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Word::Normal => match bound {
|
||||||
|
Bound::Inside => {
|
||||||
|
let cur_graph = self.grapheme_at_cursor()?;
|
||||||
|
let start = self.rfind(|c| is_other_class(c, cur_graph))
|
||||||
|
.map(|pos| pos+1)
|
||||||
|
.unwrap_or(0);
|
||||||
|
let end = self.find(|c| is_other_class(c, cur_graph))
|
||||||
|
.map(|pos| pos-1)
|
||||||
|
.unwrap_or(self.byte_len());
|
||||||
|
Some(start..end)
|
||||||
|
}
|
||||||
|
Bound::Around => {
|
||||||
|
let cur_graph = self.grapheme_at_cursor()?;
|
||||||
|
let start = self.rfind(|c| is_other_class(c, cur_graph))
|
||||||
|
.map(|pos| pos+1)
|
||||||
|
.unwrap_or(0);
|
||||||
|
let mut end = self.find(|c| is_other_class(c, cur_graph))
|
||||||
|
.unwrap_or(self.byte_len());
|
||||||
|
if end != self.byte_len() && self.is_whitespace(end) {
|
||||||
|
end = self.find_from(end,|c| !is_whitespace(c))
|
||||||
|
.map(|pos| pos-1)
|
||||||
|
.unwrap_or(self.byte_len())
|
||||||
|
} else {
|
||||||
|
end -= 1;
|
||||||
|
}
|
||||||
|
Some(start..end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextObj::Line => todo!(),
|
||||||
|
TextObj::Sentence => todo!(),
|
||||||
|
TextObj::Paragraph => todo!(),
|
||||||
|
TextObj::DoubleQuote => todo!(),
|
||||||
|
TextObj::SingleQuote => todo!(),
|
||||||
|
TextObj::BacktickQuote => todo!(),
|
||||||
|
TextObj::Paren => todo!(),
|
||||||
|
TextObj::Bracket => todo!(),
|
||||||
|
TextObj::Brace => todo!(),
|
||||||
|
TextObj::Angle => todo!(),
|
||||||
|
TextObj::Tag => todo!(),
|
||||||
|
TextObj::Custom(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn find_word_pos(&self, word: Word, to: To, dir: Direction) -> Option<usize> {
|
pub fn find_word_pos(&self, word: Word, to: To, dir: Direction) -> Option<usize> {
|
||||||
|
// FIXME: This uses a lot of hardcoded +1/-1 offsets, but they need to account for grapheme boundaries
|
||||||
let mut pos = self.cursor;
|
let mut pos = self.cursor;
|
||||||
match word {
|
match word {
|
||||||
Word::Big => {
|
Word::Big => {
|
||||||
@@ -794,22 +879,27 @@ impl LineBuf {
|
|||||||
if self.on_start_of_word(word) {
|
if self.on_start_of_word(word) {
|
||||||
pos += 1;
|
pos += 1;
|
||||||
if pos >= self.byte_len() {
|
if pos >= self.byte_len() {
|
||||||
return None
|
return Some(self.byte_len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ws_pos = self.find_from(pos, |c| CharClass::from(c) == CharClass::Whitespace)?;
|
let Some(ws_pos) = self.find_from(pos, |c| CharClass::from(c) == CharClass::Whitespace) else {
|
||||||
|
return Some(self.byte_len())
|
||||||
|
};
|
||||||
let word_start = self.find_from(ws_pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
let word_start = self.find_from(ws_pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
||||||
Some(word_start)
|
Some(word_start)
|
||||||
}
|
}
|
||||||
To::End => {
|
To::End => {
|
||||||
if self.on_whitespace() {
|
if self.on_whitespace() {
|
||||||
pos = self.find_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
let Some(non_ws_pos) = self.find_from(pos, |c| CharClass::from(c) != CharClass::Whitespace) else {
|
||||||
|
return Some(self.byte_len())
|
||||||
|
};
|
||||||
|
pos = non_ws_pos
|
||||||
}
|
}
|
||||||
match self.on_end_of_word(word) {
|
match self.on_end_of_word(word) {
|
||||||
true => {
|
true => {
|
||||||
pos += 1;
|
pos += 1;
|
||||||
if pos >= self.byte_len() {
|
if pos >= self.byte_len() {
|
||||||
return None
|
return Some(self.byte_len())
|
||||||
}
|
}
|
||||||
let word_start = self.find_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
let word_start = self.find_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
||||||
match self.find_from(word_start, |c| CharClass::from(c) == CharClass::Whitespace) {
|
match self.find_from(word_start, |c| CharClass::from(c) == CharClass::Whitespace) {
|
||||||
@@ -831,12 +921,17 @@ impl LineBuf {
|
|||||||
match to {
|
match to {
|
||||||
To::Start => {
|
To::Start => {
|
||||||
if self.on_whitespace() {
|
if self.on_whitespace() {
|
||||||
pos = self.rfind_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
let Some(non_ws_pos) = self.rfind_from(pos, |c| CharClass::from(c) != CharClass::Whitespace) else {
|
||||||
|
return Some(0)
|
||||||
|
};
|
||||||
|
pos = non_ws_pos
|
||||||
}
|
}
|
||||||
match self.on_start_of_word(word) {
|
match self.on_start_of_word(word) {
|
||||||
true => {
|
true => {
|
||||||
pos = pos.checked_sub(1)?;
|
pos = pos.checked_sub(1)?;
|
||||||
let prev_word_end = self.rfind_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
let Some(prev_word_end) = self.rfind_from(pos, |c| CharClass::from(c) != CharClass::Whitespace) else {
|
||||||
|
return Some(0)
|
||||||
|
};
|
||||||
match self.rfind_from(prev_word_end, |c| CharClass::from(c) == CharClass::Whitespace) {
|
match self.rfind_from(prev_word_end, |c| CharClass::from(c) == CharClass::Whitespace) {
|
||||||
Some(n) => Some(n + 1), // Land on char after whitespace
|
Some(n) => Some(n + 1), // Land on char after whitespace
|
||||||
None => Some(0) // Start of buffer
|
None => Some(0) // Start of buffer
|
||||||
@@ -852,13 +947,17 @@ impl LineBuf {
|
|||||||
}
|
}
|
||||||
To::End => {
|
To::End => {
|
||||||
if self.on_whitespace() {
|
if self.on_whitespace() {
|
||||||
return self.rfind_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)
|
return Some(self.rfind_from(pos, |c| CharClass::from(c) != CharClass::Whitespace).unwrap_or(0))
|
||||||
}
|
}
|
||||||
if self.on_end_of_word(word) {
|
if self.on_end_of_word(word) {
|
||||||
pos = pos.checked_sub(1)?;
|
pos = pos.checked_sub(1)?;
|
||||||
}
|
}
|
||||||
let last_ws = self.rfind_from(pos, |c| CharClass::from(c) == CharClass::Whitespace)?;
|
let Some(last_ws) = self.rfind_from(pos, |c| CharClass::from(c) == CharClass::Whitespace) else {
|
||||||
let prev_word_end = self.rfind_from(last_ws, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
return Some(0)
|
||||||
|
};
|
||||||
|
let Some(prev_word_end) = self.rfind_from(last_ws, |c| CharClass::from(c) != CharClass::Whitespace) else {
|
||||||
|
return Some(0)
|
||||||
|
};
|
||||||
Some(prev_word_end)
|
Some(prev_word_end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -871,13 +970,13 @@ impl LineBuf {
|
|||||||
match to {
|
match to {
|
||||||
To::Start => {
|
To::Start => {
|
||||||
if self.on_whitespace() {
|
if self.on_whitespace() {
|
||||||
return self.find_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)
|
return Some(self.find_from(pos, |c| CharClass::from(c) != CharClass::Whitespace).unwrap_or(self.byte_len()))
|
||||||
}
|
}
|
||||||
if self.on_start_of_word(word) {
|
if self.on_start_of_word(word) {
|
||||||
let cur_char_class = CharClass::from(self.grapheme_at_cursor()?);
|
let cur_char_class = CharClass::from(self.grapheme_at_cursor()?);
|
||||||
pos += 1;
|
pos += 1;
|
||||||
if pos >= self.byte_len() {
|
if pos >= self.byte_len() {
|
||||||
return None
|
return Some(self.byte_len())
|
||||||
}
|
}
|
||||||
let next_char = self.grapheme_at(self.next_pos(1)?)?;
|
let next_char = self.grapheme_at(self.next_pos(1)?)?;
|
||||||
let next_char_class = CharClass::from(next_char);
|
let next_char_class = CharClass::from(next_char);
|
||||||
@@ -886,7 +985,9 @@ impl LineBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let cur_graph = self.grapheme_at(pos)?;
|
let cur_graph = self.grapheme_at(pos)?;
|
||||||
let diff_class_pos = self.find_from(pos, |c| is_other_class_or_ws(c, cur_graph))?;
|
let Some(diff_class_pos) = self.find_from(pos, |c| is_other_class_or_ws(c, cur_graph)) else {
|
||||||
|
return Some(self.byte_len())
|
||||||
|
};
|
||||||
if let CharClass::Whitespace = CharClass::from(self.grapheme_at(diff_class_pos)?) {
|
if let CharClass::Whitespace = CharClass::from(self.grapheme_at(diff_class_pos)?) {
|
||||||
let non_ws_pos = self.find_from(diff_class_pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
let non_ws_pos = self.find_from(diff_class_pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
||||||
Some(non_ws_pos)
|
Some(non_ws_pos)
|
||||||
@@ -897,7 +998,10 @@ impl LineBuf {
|
|||||||
To::End => {
|
To::End => {
|
||||||
flog!(DEBUG,self.buffer);
|
flog!(DEBUG,self.buffer);
|
||||||
if self.on_whitespace() {
|
if self.on_whitespace() {
|
||||||
pos = self.find_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)?;
|
let Some(non_ws_pos) = self.find_from(pos, |c| CharClass::from(c) != CharClass::Whitespace) else {
|
||||||
|
return Some(self.byte_len())
|
||||||
|
};
|
||||||
|
pos = non_ws_pos
|
||||||
}
|
}
|
||||||
match self.on_end_of_word(word) {
|
match self.on_end_of_word(word) {
|
||||||
true => {
|
true => {
|
||||||
@@ -905,7 +1009,7 @@ impl LineBuf {
|
|||||||
let cur_char_class = CharClass::from(self.grapheme_at_cursor()?);
|
let cur_char_class = CharClass::from(self.grapheme_at_cursor()?);
|
||||||
pos += 1;
|
pos += 1;
|
||||||
if pos >= self.byte_len() {
|
if pos >= self.byte_len() {
|
||||||
return None
|
return Some(self.byte_len())
|
||||||
}
|
}
|
||||||
let next_char = self.grapheme_at(self.next_pos(1)?)?;
|
let next_char = self.grapheme_at(self.next_pos(1)?)?;
|
||||||
let next_char_class = CharClass::from(next_char);
|
let next_char_class = CharClass::from(next_char);
|
||||||
@@ -980,7 +1084,7 @@ impl LineBuf {
|
|||||||
}
|
}
|
||||||
To::End => {
|
To::End => {
|
||||||
if self.on_whitespace() {
|
if self.on_whitespace() {
|
||||||
return self.rfind_from(pos, |c| CharClass::from(c) != CharClass::Whitespace)
|
return Some(self.rfind_from(pos, |c| CharClass::from(c) != CharClass::Whitespace).unwrap_or(0))
|
||||||
}
|
}
|
||||||
if self.on_end_of_word(word) {
|
if self.on_end_of_word(word) {
|
||||||
pos = pos.checked_sub(1)?;
|
pos = pos.checked_sub(1)?;
|
||||||
@@ -992,7 +1096,9 @@ impl LineBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let cur_graph = self.grapheme_at(pos)?;
|
let cur_graph = self.grapheme_at(pos)?;
|
||||||
let diff_class_pos = self.rfind_from(pos, |c|is_other_class_or_ws(c, cur_graph))?;
|
let Some(diff_class_pos) = self.rfind_from(pos, |c|is_other_class_or_ws(c, cur_graph)) else {
|
||||||
|
return Some(0)
|
||||||
|
};
|
||||||
if let CharClass::Whitespace = self.grapheme_at(diff_class_pos)?.into() {
|
if let CharClass::Whitespace = self.grapheme_at(diff_class_pos)?.into() {
|
||||||
let prev_word_end = self.rfind_from(diff_class_pos, |c| CharClass::from(c) != CharClass::Whitespace).unwrap_or(0);
|
let prev_word_end = self.rfind_from(diff_class_pos, |c| CharClass::from(c) != CharClass::Whitespace).unwrap_or(0);
|
||||||
Some(prev_word_end)
|
Some(prev_word_end)
|
||||||
@@ -1016,7 +1122,6 @@ impl LineBuf {
|
|||||||
/// Find the first grapheme at or after `pos` for which `op` returns true.
|
/// Find the first grapheme at or after `pos` for which `op` returns true.
|
||||||
/// Returns the byte index of that grapheme in the buffer.
|
/// Returns the byte index of that grapheme in the buffer.
|
||||||
pub fn find_from<F: Fn(&str) -> bool>(&self, pos: usize, op: F) -> Option<usize> {
|
pub fn find_from<F: Fn(&str) -> bool>(&self, pos: usize, op: F) -> Option<usize> {
|
||||||
assert!(is_grapheme_boundary(&self.buffer, pos));
|
|
||||||
|
|
||||||
// Iterate over grapheme indices starting at `pos`
|
// Iterate over grapheme indices starting at `pos`
|
||||||
let slice = &self.slice_from(pos);
|
let slice = &self.slice_from(pos);
|
||||||
@@ -1030,7 +1135,6 @@ impl LineBuf {
|
|||||||
/// Find the last grapheme at or before `pos` for which `op` returns true.
|
/// Find the last grapheme at or before `pos` for which `op` returns true.
|
||||||
/// Returns the byte index of that grapheme in the buffer.
|
/// Returns the byte index of that grapheme in the buffer.
|
||||||
pub fn rfind_from<F: Fn(&str) -> bool>(&self, pos: usize, op: F) -> Option<usize> {
|
pub fn rfind_from<F: Fn(&str) -> bool>(&self, pos: usize, op: F) -> Option<usize> {
|
||||||
assert!(is_grapheme_boundary(&self.buffer, pos));
|
|
||||||
|
|
||||||
// Iterate grapheme boundaries backward up to pos
|
// Iterate grapheme boundaries backward up to pos
|
||||||
let slice = &self.slice_to(pos);
|
let slice = &self.slice_to(pos);
|
||||||
@@ -1058,7 +1162,12 @@ impl LineBuf {
|
|||||||
flog!(DEBUG,motion);
|
flog!(DEBUG,motion);
|
||||||
match motion {
|
match motion {
|
||||||
Motion::WholeLine => MotionKind::Line(0),
|
Motion::WholeLine => MotionKind::Line(0),
|
||||||
Motion::TextObj(text_obj, bound) => todo!(),
|
Motion::TextObj(text_obj, bound) => {
|
||||||
|
let Some(range) = self.eval_text_object(text_obj, bound) else {
|
||||||
|
return MotionKind::Null
|
||||||
|
};
|
||||||
|
MotionKind::range(range)
|
||||||
|
}
|
||||||
Motion::BeginningOfFirstWord => {
|
Motion::BeginningOfFirstWord => {
|
||||||
let (start,_) = self.this_line();
|
let (start,_) = self.this_line();
|
||||||
let first_graph_pos = self.find_from(start, |c| CharClass::from(c) != CharClass::Whitespace).unwrap_or(start);
|
let first_graph_pos = self.find_from(start, |c| CharClass::from(c) != CharClass::Whitespace).unwrap_or(start);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::time::Duration;
|
|||||||
use history::{History, SearchConstraint, SearchKind};
|
use history::{History, SearchConstraint, SearchKind};
|
||||||
use keys::{KeyCode, KeyEvent, ModKeys};
|
use keys::{KeyCode, KeyEvent, ModKeys};
|
||||||
use linebuf::{strip_ansi_codes_and_escapes, LineBuf};
|
use linebuf::{strip_ansi_codes_and_escapes, LineBuf};
|
||||||
use mode::{CmdReplay, ViInsert, ViMode, ViNormal, ViReplace};
|
use mode::{CmdReplay, ModeReport, ViInsert, ViMode, ViNormal, ViReplace};
|
||||||
use term::Terminal;
|
use term::Terminal;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
use vicmd::{Motion, MotionCmd, RegisterName, To, Verb, VerbCmd, ViCmd};
|
use vicmd::{Motion, MotionCmd, RegisterName, To, Verb, VerbCmd, ViCmd};
|
||||||
@@ -130,10 +130,30 @@ impl FernVi {
|
|||||||
}
|
}
|
||||||
pub fn should_accept_hint(&self, event: &KeyEvent) -> bool {
|
pub fn should_accept_hint(&self, event: &KeyEvent) -> bool {
|
||||||
if self.line.at_end_of_buffer() && self.line.has_hint() {
|
if self.line.at_end_of_buffer() && self.line.has_hint() {
|
||||||
matches!(
|
match self.mode.report_mode() {
|
||||||
event,
|
ModeReport::Replace |
|
||||||
KeyEvent(KeyCode::Right, ModKeys::NONE)
|
ModeReport::Insert => {
|
||||||
)
|
matches!(
|
||||||
|
event,
|
||||||
|
KeyEvent(KeyCode::Right, ModKeys::NONE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ModeReport::Visual |
|
||||||
|
ModeReport::Normal => {
|
||||||
|
matches!(
|
||||||
|
event,
|
||||||
|
KeyEvent(KeyCode::Right, ModKeys::NONE)
|
||||||
|
) ||
|
||||||
|
(
|
||||||
|
self.mode.pending_seq().unwrap(/* always Some on normal mode */).is_empty() &&
|
||||||
|
matches!(
|
||||||
|
event,
|
||||||
|
KeyEvent(KeyCode::Char('l'), ModKeys::NONE)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => unimplemented!()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,14 @@ use super::keys::{KeyEvent as E, KeyCode as K, ModKeys as M};
|
|||||||
use super::vicmd::{Anchor, Bound, Dest, Direction, Motion, MotionBuilder, MotionCmd, RegisterName, TextObj, To, Verb, VerbBuilder, VerbCmd, ViCmd, Word};
|
use super::vicmd::{Anchor, Bound, Dest, Direction, Motion, MotionBuilder, MotionCmd, RegisterName, TextObj, To, Verb, VerbBuilder, VerbCmd, ViCmd, Word};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub enum ModeReport {
|
||||||
|
Insert,
|
||||||
|
Normal,
|
||||||
|
Visual,
|
||||||
|
Replace,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug,Clone)]
|
#[derive(Debug,Clone)]
|
||||||
pub enum CmdReplay {
|
pub enum CmdReplay {
|
||||||
ModeReplay { cmds: Vec<ViCmd>, repeat: u16 },
|
ModeReplay { cmds: Vec<ViCmd>, repeat: u16 },
|
||||||
@@ -41,6 +49,7 @@ pub trait ViMode {
|
|||||||
fn move_cursor_on_undo(&self) -> bool;
|
fn move_cursor_on_undo(&self) -> bool;
|
||||||
fn clamp_cursor(&self) -> bool;
|
fn clamp_cursor(&self) -> bool;
|
||||||
fn hist_scroll_start_pos(&self) -> Option<To>;
|
fn hist_scroll_start_pos(&self) -> Option<To>;
|
||||||
|
fn report_mode(&self) -> ModeReport;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default,Debug)]
|
#[derive(Default,Debug)]
|
||||||
@@ -149,6 +158,9 @@ impl ViMode for ViInsert {
|
|||||||
fn hist_scroll_start_pos(&self) -> Option<To> {
|
fn hist_scroll_start_pos(&self) -> Option<To> {
|
||||||
Some(To::End)
|
Some(To::End)
|
||||||
}
|
}
|
||||||
|
fn report_mode(&self) -> ModeReport {
|
||||||
|
ModeReport::Insert
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default,Debug)]
|
#[derive(Default,Debug)]
|
||||||
@@ -252,6 +264,9 @@ impl ViMode for ViReplace {
|
|||||||
fn hist_scroll_start_pos(&self) -> Option<To> {
|
fn hist_scroll_start_pos(&self) -> Option<To> {
|
||||||
Some(To::End)
|
Some(To::End)
|
||||||
}
|
}
|
||||||
|
fn report_mode(&self) -> ModeReport {
|
||||||
|
ModeReport::Replace
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[derive(Default,Debug)]
|
#[derive(Default,Debug)]
|
||||||
pub struct ViNormal {
|
pub struct ViNormal {
|
||||||
@@ -794,6 +809,9 @@ impl ViMode for ViNormal {
|
|||||||
fn hist_scroll_start_pos(&self) -> Option<To> {
|
fn hist_scroll_start_pos(&self) -> Option<To> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
fn report_mode(&self) -> ModeReport {
|
||||||
|
ModeReport::Normal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn common_cmds(key: E) -> Option<ViCmd> {
|
pub fn common_cmds(key: E) -> Option<ViCmd> {
|
||||||
|
|||||||
Reference in New Issue
Block a user