implemented 'gv' to select the previously selected visual selection
This commit is contained in:
@@ -313,7 +313,25 @@ impl History {
|
||||
.append(true)
|
||||
.open(&self.path)?;
|
||||
|
||||
let entries = self.entries.iter_mut().filter(|ent| ent.new && !ent.command.is_empty());
|
||||
let last_file_entry = self.entries
|
||||
.iter()
|
||||
.filter(|ent| !ent.new)
|
||||
.next_back()
|
||||
.map(|ent| ent.command.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
let entries = self.entries
|
||||
.iter_mut()
|
||||
.filter(|ent| {
|
||||
ent.new &&
|
||||
!ent.command.is_empty() &&
|
||||
if self.ignore_dups {
|
||||
ent.command() != last_file_entry
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
let mut data = String::new();
|
||||
for ent in entries {
|
||||
ent.new = false;
|
||||
|
||||
@@ -32,9 +32,10 @@ pub enum MotionKind {
|
||||
ScreenLine(isize)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SelectionAnchor {
|
||||
Start,
|
||||
#[default]
|
||||
End
|
||||
}
|
||||
|
||||
@@ -45,6 +46,12 @@ pub enum SelectionMode {
|
||||
Block(SelectionAnchor)
|
||||
}
|
||||
|
||||
impl Default for SelectionMode {
|
||||
fn default() -> Self {
|
||||
Self::Char(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectionMode {
|
||||
pub fn anchor(&self) -> &SelectionAnchor {
|
||||
match self {
|
||||
@@ -195,6 +202,7 @@ pub struct LineBuf {
|
||||
clamp_cursor: bool,
|
||||
select_mode: Option<SelectionMode>,
|
||||
selected_range: Option<Range<usize>>,
|
||||
last_selected_range: Option<Range<usize>>,
|
||||
first_line_offset: usize,
|
||||
saved_col: Option<usize>,
|
||||
term_dims: (usize,usize), // Height, width
|
||||
@@ -220,7 +228,9 @@ impl LineBuf {
|
||||
}
|
||||
pub fn stop_selecting(&mut self) {
|
||||
self.select_mode = None;
|
||||
self.selected_range = None;
|
||||
if self.selected_range().is_some() {
|
||||
self.last_selected_range = self.selected_range.take();
|
||||
}
|
||||
}
|
||||
pub fn start_selecting(&mut self, mode: SelectionMode) {
|
||||
self.select_mode = Some(mode);
|
||||
@@ -1506,6 +1516,16 @@ impl LineBuf {
|
||||
}
|
||||
}
|
||||
}
|
||||
Verb::VisualModeSelectLast => {
|
||||
if let Some(range) = self.last_selected_range.as_ref() {
|
||||
self.selected_range = Some(range.clone());
|
||||
let mode = self.select_mode.unwrap_or_default();
|
||||
self.cursor = match mode.anchor() {
|
||||
SelectionAnchor::Start => range.start,
|
||||
SelectionAnchor::End => range.end
|
||||
}
|
||||
}
|
||||
}
|
||||
Verb::SwapVisualAnchor => {
|
||||
if let Some(range) = self.selected_range() {
|
||||
if let Some(mut mode) = self.select_mode {
|
||||
@@ -1934,10 +1954,13 @@ impl Display for LineBuf {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut full_buf = self.buffer.clone();
|
||||
if let Some(range) = self.selected_range.clone() {
|
||||
let mode = self.select_mode.unwrap();
|
||||
let mode = self.select_mode.unwrap_or_default();
|
||||
match mode.anchor() {
|
||||
SelectionAnchor::Start => {
|
||||
let inclusive = range.start..=range.end;
|
||||
let mut inclusive = range.start..=range.end;
|
||||
if *inclusive.end() == self.byte_len() {
|
||||
inclusive = range.start..=range.end.saturating_sub(1);
|
||||
}
|
||||
let selected = full_buf[inclusive.clone()].styled(Style::BgWhite | Style::Black);
|
||||
full_buf.replace_range(inclusive, &selected);
|
||||
}
|
||||
|
||||
@@ -88,11 +88,11 @@ impl Readline for FernVi {
|
||||
if cmd.should_submit() {
|
||||
self.term.unposition_cursor()?;
|
||||
self.term.write("\n");
|
||||
let command = self.line.to_string();
|
||||
let command = std::mem::take(&mut self.line).pack_line();
|
||||
if !command.is_empty() {
|
||||
// We're just going to trim the command
|
||||
// reduces clutter in the case of two history commands whose only difference is insignificant whitespace
|
||||
self.history.push(command.trim().to_string());
|
||||
self.history.update_pending_cmd(&command);
|
||||
self.history.save()?;
|
||||
}
|
||||
return Ok(command);
|
||||
@@ -323,6 +323,17 @@ impl FernVi {
|
||||
Verb::ReplaceMode => {
|
||||
Box::new(ViReplace::new().with_count(count as u16))
|
||||
}
|
||||
Verb::VisualModeSelectLast => {
|
||||
if self.mode.report_mode() != ModeReport::Visual {
|
||||
self.line.start_selecting(SelectionMode::Char(SelectionAnchor::End));
|
||||
}
|
||||
let mut mode: Box<dyn ViMode> = Box::new(ViVisual::new());
|
||||
std::mem::swap(&mut mode, &mut self.mode);
|
||||
self.line.set_cursor_clamp(self.mode.clamp_cursor());
|
||||
self.line.set_move_cursor_on_undo(self.mode.move_cursor_on_undo());
|
||||
self.term.write(&mode.cursor_style());
|
||||
return self.line.exec_cmd(cmd)
|
||||
}
|
||||
Verb::VisualMode => {
|
||||
selecting = true;
|
||||
self.line.start_selecting(SelectionMode::Char(SelectionAnchor::End));
|
||||
@@ -331,7 +342,11 @@ impl FernVi {
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
flog!(DEBUG, self.mode.report_mode());
|
||||
flog!(DEBUG, mode.report_mode());
|
||||
std::mem::swap(&mut mode, &mut self.mode);
|
||||
|
||||
flog!(DEBUG, self.mode.report_mode());
|
||||
self.line.set_cursor_clamp(self.mode.clamp_cursor());
|
||||
self.line.set_move_cursor_on_undo(self.mode.move_cursor_on_undo());
|
||||
self.term.write(&mode.cursor_style());
|
||||
|
||||
@@ -358,6 +358,25 @@ impl ViNormal {
|
||||
break 'verb_parse None
|
||||
};
|
||||
match ch {
|
||||
'g' => {
|
||||
if let Some(ch) = chars_clone.peek() {
|
||||
match ch {
|
||||
'v' => {
|
||||
return Some(
|
||||
ViCmd {
|
||||
register,
|
||||
verb: Some(VerbCmd(1, Verb::VisualModeSelectLast)),
|
||||
motion: None,
|
||||
raw_seq: self.take_cmd()
|
||||
}
|
||||
)
|
||||
}
|
||||
_ => break 'verb_parse None
|
||||
}
|
||||
} else {
|
||||
break 'verb_parse None
|
||||
}
|
||||
}
|
||||
'.' => {
|
||||
return Some(
|
||||
ViCmd {
|
||||
@@ -924,6 +943,25 @@ impl ViVisual {
|
||||
break 'verb_parse None
|
||||
};
|
||||
match ch {
|
||||
'g' => {
|
||||
if let Some(ch) = chars_clone.peek() {
|
||||
match ch {
|
||||
'v' => {
|
||||
return Some(
|
||||
ViCmd {
|
||||
register,
|
||||
verb: Some(VerbCmd(1, Verb::VisualModeSelectLast)),
|
||||
motion: None,
|
||||
raw_seq: self.take_cmd()
|
||||
}
|
||||
)
|
||||
}
|
||||
_ => break 'verb_parse None
|
||||
}
|
||||
} else {
|
||||
break 'verb_parse None
|
||||
}
|
||||
}
|
||||
'.' => {
|
||||
return Some(
|
||||
ViCmd {
|
||||
|
||||
@@ -110,6 +110,7 @@ impl ViCmd {
|
||||
Verb::InsertMode |
|
||||
Verb::InsertModeLineBreak(_) |
|
||||
Verb::NormalMode |
|
||||
Verb::VisualModeSelectLast |
|
||||
Verb::VisualMode |
|
||||
Verb::ReplaceMode
|
||||
)
|
||||
@@ -159,7 +160,8 @@ pub enum Verb {
|
||||
NormalMode,
|
||||
VisualMode,
|
||||
VisualModeLine,
|
||||
VisualModeBlock,
|
||||
VisualModeBlock, // dont even know if im going to implement this
|
||||
VisualModeSelectLast,
|
||||
SwapVisualAnchor,
|
||||
JoinLines,
|
||||
InsertChar(char),
|
||||
@@ -241,37 +243,22 @@ impl Verb {
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum Motion {
|
||||
/// Whole current line (not really a movement but a range)
|
||||
WholeLine,
|
||||
TextObj(TextObj, Bound),
|
||||
BeginningOfFirstWord,
|
||||
/// beginning-of-line
|
||||
BeginningOfLine,
|
||||
/// end-of-line
|
||||
EndOfLine,
|
||||
/// backward-word, vi-prev-word
|
||||
BackwardWord(To, Word), // Backward until start of word
|
||||
/// forward-word, vi-end-word, vi-next-word
|
||||
ForwardWord(To, Word), // Forward until start/end of word
|
||||
/// character-search, character-search-backward, vi-char-search
|
||||
BackwardWord(To, Word),
|
||||
ForwardWord(To, Word),
|
||||
CharSearch(Direction,Dest,char),
|
||||
/// backward-char
|
||||
BackwardChar,
|
||||
/// forward-char
|
||||
ForwardChar,
|
||||
/// move to the same column on the previous line
|
||||
LineUp,
|
||||
/// move to the same column on the previous visual line
|
||||
ScreenLineUp,
|
||||
/// move to the same column on the next line
|
||||
LineDown,
|
||||
/// move to the same column on the next visual line
|
||||
ScreenLineDown,
|
||||
/// Whole user input (not really a movement but a range)
|
||||
WholeBuffer,
|
||||
/// beginning-of-register
|
||||
BeginningOfBuffer,
|
||||
/// end-of-register
|
||||
EndOfBuffer,
|
||||
ToColumn(usize),
|
||||
Range(usize,usize),
|
||||
@@ -328,7 +315,7 @@ pub enum TextObj {
|
||||
/// `i<`, `a<`
|
||||
Angle,
|
||||
|
||||
/// `it`, `at` — HTML/XML tags (if you support it)
|
||||
/// `it`, `at` — HTML/XML tags
|
||||
Tag,
|
||||
|
||||
/// Custom user-defined objects maybe?
|
||||
|
||||
Reference in New Issue
Block a user