mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 21:33:09 +00:00
Vi mode: avoid placing cursor beyond last character
Today fish_cursor_selection_mode controls whether selection mode includes the cursor. Since it's by default only used for Vi mode, perhaps use it to also decide whether it should be allowed to select one-past the last character. Not allowing to select to select one-past the last character is much nicer in Vi mode. Unfortunately Vi mode sometimes needs to temporarily select past end (using forward-single-char and such), so reset fish_cursor_selection_mode for the duration of the binding. Also fix other things like cursor placement after yank/yank-pop. Closes #10286 Closes #3299
This commit is contained in:
parent
bffc9515a8
commit
d51f669647
4 changed files with 133 additions and 34 deletions
|
@ -65,12 +65,12 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
||||||
bind -s --preset -M default l forward-char
|
bind -s --preset -M default l forward-char
|
||||||
bind -s --preset -m insert \n execute
|
bind -s --preset -m insert \n execute
|
||||||
bind -s --preset -m insert \r execute
|
bind -s --preset -m insert \r execute
|
||||||
bind -s --preset -m insert o insert-line-under repaint-mode
|
bind -s --preset -m insert o 'set fish_cursor_end_mode exclusive' insert-line-under repaint-mode
|
||||||
bind -s --preset -m insert O insert-line-over repaint-mode
|
bind -s --preset -m insert O 'set fish_cursor_end_modefish_cursor_end_modeexclusive' insert-line-over repaint-mode
|
||||||
bind -s --preset -m insert i repaint-mode
|
bind -s --preset -m insert i repaint-mode
|
||||||
bind -s --preset -m insert I beginning-of-line repaint-mode
|
bind -s --preset -m insert I beginning-of-line repaint-mode
|
||||||
bind -s --preset -m insert a forward-single-char repaint-mode
|
bind -s --preset -m insert a 'set fish_cursor_end_mode exclusive' forward-single-char repaint-mode
|
||||||
bind -s --preset -m insert A end-of-line repaint-mode
|
bind -s --preset -m insert A 'set fish_cursor_end_mode exclusive' end-of-line repaint-mode
|
||||||
bind -s --preset -m visual v begin-selection repaint-mode
|
bind -s --preset -m visual v begin-selection repaint-mode
|
||||||
|
|
||||||
bind -s --preset gg beginning-of-buffer
|
bind -s --preset gg beginning-of-buffer
|
||||||
|
@ -98,8 +98,8 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
||||||
bind -s --preset gE backward-bigword
|
bind -s --preset gE backward-bigword
|
||||||
bind -s --preset w forward-word forward-single-char
|
bind -s --preset w forward-word forward-single-char
|
||||||
bind -s --preset W forward-bigword forward-single-char
|
bind -s --preset W forward-bigword forward-single-char
|
||||||
bind -s --preset e forward-single-char forward-word backward-char
|
bind -s --preset e 'set fish_cursor_end_mode exclusive' forward-single-char forward-word backward-char 'set fish_cursor_end_mode inclusive'
|
||||||
bind -s --preset E forward-single-char forward-bigword backward-char
|
bind -s --preset E 'set fish_cursor_end_mode exclusive' forward-single-char forward-bigword backward-char 'set fish_cursor_end_mode inclusive'
|
||||||
|
|
||||||
bind -s --preset -M insert \cn accept-autosuggestion
|
bind -s --preset -M insert \cn accept-autosuggestion
|
||||||
|
|
||||||
|
@ -112,10 +112,10 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
||||||
# Vi moves the cursor back if, after deleting, it is at EOL.
|
# Vi moves the cursor back if, after deleting, it is at EOL.
|
||||||
# To emulate that, move forward, then backward, which will be a NOP
|
# To emulate that, move forward, then backward, which will be a NOP
|
||||||
# if there is something to move forward to.
|
# if there is something to move forward to.
|
||||||
bind -s --preset -M default x delete-char forward-single-char backward-char
|
bind -s --preset -M default x delete-char 'set fish_cursor_end_mode exclusive' forward-single-char backward-char 'set fish_cursor_end_mode inclusive'
|
||||||
bind -s --preset -M default X backward-delete-char
|
bind -s --preset -M default X backward-delete-char
|
||||||
bind -s --preset -M insert -k dc delete-char forward-single-char backward-char
|
bind -s --preset -M insert -k dc delete-char forward-single-char backward-char
|
||||||
bind -s --preset -M default -k dc delete-char forward-single-char backward-char
|
bind -s --preset -M default -k dc delete-char 'set fish_cursor_end_mode exclusive' forward-single-char backward-char 'set fish_cursor_end_mode inclusive'
|
||||||
|
|
||||||
# Backspace deletes a char in insert mode, but not in normal/default mode.
|
# Backspace deletes a char in insert mode, but not in normal/default mode.
|
||||||
bind -s --preset -M insert -k backspace backward-delete-char
|
bind -s --preset -M insert -k backspace backward-delete-char
|
||||||
|
@ -225,13 +225,13 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
||||||
# in vim p means paste *after* current character, so go forward a char before pasting
|
# in vim p means paste *after* current character, so go forward a char before pasting
|
||||||
# also in vim, P means paste *at* current position (like at '|' with cursor = line),
|
# also in vim, P means paste *at* current position (like at '|' with cursor = line),
|
||||||
# \ so there's no need to go back a char, just paste it without moving
|
# \ so there's no need to go back a char, just paste it without moving
|
||||||
bind -s --preset p forward-char yank
|
bind -s --preset p 'set -g fish_cursor_end_mode exclusive' forward-char 'set -g fish_cursor_end_modefish_cursor_end_modeinclusive' yank
|
||||||
bind -s --preset P yank
|
bind -s --preset P yank
|
||||||
bind -s --preset gp yank-pop
|
bind -s --preset gp yank-pop
|
||||||
|
|
||||||
# same vim 'pasting' note as upper
|
# same vim 'pasting' note as upper
|
||||||
bind -s --preset '"*p' forward-char "commandline -i ( xsel -p; echo )[1]"
|
bind -s --preset '"*p' 'set -g fish_cursor_end_mode exclusive' forward-char 'set -g fish_cursor_end_mode inclusive' fish_clipboard_paste
|
||||||
bind -s --preset '"*P' "commandline -i ( xsel -p; echo )[1]"
|
bind -s --preset '"*P' fish_clipboard_paste
|
||||||
|
|
||||||
#
|
#
|
||||||
# Lowercase r, enters replace_one mode
|
# Lowercase r, enters replace_one mode
|
||||||
|
@ -267,8 +267,8 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
||||||
bind -s --preset -M visual gE backward-bigword
|
bind -s --preset -M visual gE backward-bigword
|
||||||
bind -s --preset -M visual w forward-word
|
bind -s --preset -M visual w forward-word
|
||||||
bind -s --preset -M visual W forward-bigword
|
bind -s --preset -M visual W forward-bigword
|
||||||
bind -s --preset -M visual e forward-word
|
bind -s --preset -M visual e 'set fish_cursor_end_mode exclusive' forward-single-char forward-word backward-char 'set fish_cursor_end_mode inclusive'
|
||||||
bind -s --preset -M visual E forward-bigword
|
bind -s --preset -M visual E 'set fish_cursor_end_mode exclusive' forward-single-char forward-bigword backward-char 'set fish_cursor_end_mode inclusive'
|
||||||
bind -s --preset -M visual o swap-selection-start-stop repaint-mode
|
bind -s --preset -M visual o swap-selection-start-stop repaint-mode
|
||||||
|
|
||||||
bind -s --preset -M visual f forward-jump
|
bind -s --preset -M visual f forward-jump
|
||||||
|
@ -306,7 +306,22 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
||||||
# Therefore it needs to be before setting fish_bind_mode.
|
# Therefore it needs to be before setting fish_bind_mode.
|
||||||
fish_vi_cursor
|
fish_vi_cursor
|
||||||
set -g fish_cursor_selection_mode inclusive
|
set -g fish_cursor_selection_mode inclusive
|
||||||
|
function __fish_vi_key_bindings_on_mode_change --on-variable fish_bind_mode
|
||||||
|
switch $fish_bind_mode
|
||||||
|
case insert
|
||||||
|
set -g fish_cursor_end_mode exclusive
|
||||||
|
case '*'
|
||||||
|
set -g fish_cursor_end_mode inclusive
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function __fish_vi_key_bindings_remove_handlers --on-variable __fish_active_key_bindings
|
||||||
|
functions --erase __fish_vi_key_bindings_remove_handlers
|
||||||
|
functions --erase __fish_vi_key_bindings_on_mode_change
|
||||||
|
functions --erase fish_vi_cursor_handle
|
||||||
|
functions --erase fish_vi_cursor_handle_preexec
|
||||||
|
set -e -g fish_cursor_end_mode
|
||||||
|
set -e -g fish_cursor_selection_mode
|
||||||
|
end
|
||||||
|
|
||||||
set fish_bind_mode $init_mode
|
set fish_bind_mode $init_mode
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -123,6 +123,7 @@ impl EditableLine {
|
||||||
self.position
|
self.position
|
||||||
}
|
}
|
||||||
pub fn set_position(&mut self, position: usize) {
|
pub fn set_position(&mut self, position: usize) {
|
||||||
|
assert!(position <= self.len());
|
||||||
self.position = position;
|
self.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ use crate::input_common::{update_wait_on_escape_ms, update_wait_on_sequence_key_
|
||||||
use crate::output::ColorSupport;
|
use crate::output::ColorSupport;
|
||||||
use crate::proc::is_interactive_session;
|
use crate::proc::is_interactive_session;
|
||||||
use crate::reader::{
|
use crate::reader::{
|
||||||
reader_change_cursor_selection_mode, reader_change_history, reader_schedule_prompt_repaint,
|
reader_change_cursor_end_mode, reader_change_cursor_selection_mode, reader_change_history,
|
||||||
reader_set_autosuggestion_enabled,
|
reader_schedule_prompt_repaint, reader_set_autosuggestion_enabled,
|
||||||
};
|
};
|
||||||
use crate::screen::screen_set_midnight_commander_hack;
|
use crate::screen::screen_set_midnight_commander_hack;
|
||||||
use crate::screen::LAYOUT_CACHE_SHARED;
|
use crate::screen::LAYOUT_CACHE_SHARED;
|
||||||
|
@ -85,6 +85,10 @@ static VAR_DISPATCH_TABLE: once_cell::sync::Lazy<VarDispatchTable> =
|
||||||
L!("fish_cursor_selection_mode"),
|
L!("fish_cursor_selection_mode"),
|
||||||
handle_fish_cursor_selection_mode_change,
|
handle_fish_cursor_selection_mode_change,
|
||||||
);
|
);
|
||||||
|
table.add_anon(
|
||||||
|
L!("fish_cursor_end_mode"),
|
||||||
|
handle_fish_cursor_end_mode_change,
|
||||||
|
);
|
||||||
|
|
||||||
table
|
table
|
||||||
});
|
});
|
||||||
|
@ -259,6 +263,24 @@ fn handle_fish_cursor_selection_mode_change(vars: &EnvStack) {
|
||||||
reader_change_cursor_selection_mode(mode);
|
reader_change_cursor_selection_mode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_fish_cursor_end_mode_change(vars: &EnvStack) {
|
||||||
|
use crate::reader::CursorEndMode;
|
||||||
|
|
||||||
|
let inclusive = vars
|
||||||
|
.get(L!("fish_cursor_end_mode"))
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| v.as_string())
|
||||||
|
.map(|v| v == "inclusive")
|
||||||
|
.unwrap_or(false);
|
||||||
|
let mode = if inclusive {
|
||||||
|
CursorEndMode::Inclusive
|
||||||
|
} else {
|
||||||
|
CursorEndMode::Exclusive
|
||||||
|
};
|
||||||
|
|
||||||
|
reader_change_cursor_end_mode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_autosuggestion_change(vars: &EnvStack) {
|
fn handle_autosuggestion_change(vars: &EnvStack) {
|
||||||
reader_set_autosuggestion_enabled(vars);
|
reader_set_autosuggestion_enabled(vars);
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,6 +338,12 @@ pub enum CursorSelectionMode {
|
||||||
Inclusive,
|
Inclusive,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub enum CursorEndMode {
|
||||||
|
Exclusive,
|
||||||
|
Inclusive,
|
||||||
|
}
|
||||||
|
|
||||||
/// A mode for calling the reader_kill function.
|
/// A mode for calling the reader_kill function.
|
||||||
enum Kill {
|
enum Kill {
|
||||||
/// In this mode, the new string is appended to the current contents of the kill buffer.
|
/// In this mode, the new string is appended to the current contents of the kill buffer.
|
||||||
|
@ -500,6 +506,7 @@ pub struct ReaderData {
|
||||||
|
|
||||||
/// The cursor selection mode.
|
/// The cursor selection mode.
|
||||||
cursor_selection_mode: CursorSelectionMode,
|
cursor_selection_mode: CursorSelectionMode,
|
||||||
|
cursor_end_mode: CursorEndMode,
|
||||||
|
|
||||||
/// The selection data. If this is not none, then we have an active selection.
|
/// The selection data. If this is not none, then we have an active selection.
|
||||||
selection: Option<SelectionData>,
|
selection: Option<SelectionData>,
|
||||||
|
@ -814,7 +821,28 @@ pub fn reader_change_history(name: &wstr) {
|
||||||
pub fn reader_change_cursor_selection_mode(selection_mode: CursorSelectionMode) {
|
pub fn reader_change_cursor_selection_mode(selection_mode: CursorSelectionMode) {
|
||||||
// We don't need to _change_ if we're not initialized yet.
|
// We don't need to _change_ if we're not initialized yet.
|
||||||
if let Some(data) = current_data() {
|
if let Some(data) = current_data() {
|
||||||
|
if data.cursor_selection_mode == selection_mode {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let invalidates_selection = data.selection.is_some();
|
||||||
data.cursor_selection_mode = selection_mode;
|
data.cursor_selection_mode = selection_mode;
|
||||||
|
if invalidates_selection {
|
||||||
|
data.update_buff_pos(EditableLineTag::Commandline, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reader_change_cursor_end_mode(end_mode: CursorEndMode) {
|
||||||
|
// We don't need to _change_ if we're not initialized yet.
|
||||||
|
if let Some(data) = current_data() {
|
||||||
|
if data.cursor_end_mode == end_mode {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let invalidates_end = data.selection.is_some();
|
||||||
|
data.cursor_end_mode = end_mode;
|
||||||
|
if invalidates_end {
|
||||||
|
data.update_buff_pos(EditableLineTag::Commandline, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,6 +1055,7 @@ impl ReaderData {
|
||||||
history_pager_history_index_start: usize::MAX,
|
history_pager_history_index_start: usize::MAX,
|
||||||
history_pager_history_index_end: usize::MAX,
|
history_pager_history_index_end: usize::MAX,
|
||||||
cursor_selection_mode: CursorSelectionMode::Exclusive,
|
cursor_selection_mode: CursorSelectionMode::Exclusive,
|
||||||
|
cursor_end_mode: CursorEndMode::Exclusive,
|
||||||
selection: Default::default(),
|
selection: Default::default(),
|
||||||
left_prompt_buff: Default::default(),
|
left_prompt_buff: Default::default(),
|
||||||
mode_prompt_buff: Default::default(),
|
mode_prompt_buff: Default::default(),
|
||||||
|
@ -1159,13 +1188,24 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the cursor position.
|
/// Update the cursor position.
|
||||||
fn update_buff_pos(&mut self, elt: EditableLineTag, new_pos: Option<usize>) {
|
fn update_buff_pos(&mut self, elt: EditableLineTag, mut new_pos: Option<usize>) -> bool {
|
||||||
|
if self.cursor_end_mode == CursorEndMode::Inclusive {
|
||||||
|
let el = self.edit_line(elt);
|
||||||
|
let mut pos = new_pos.unwrap_or(el.position());
|
||||||
|
if !el.is_empty() && pos == el.len() {
|
||||||
|
pos = el.len() - 1;
|
||||||
|
if el.position() == pos {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
new_pos = Some(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(pos) = new_pos {
|
if let Some(pos) = new_pos {
|
||||||
self.edit_line_mut(elt).set_position(pos);
|
self.edit_line_mut(elt).set_position(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if elt != EditableLineTag::Commandline {
|
if elt != EditableLineTag::Commandline {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
let buff_pos = self.command_line.position();
|
let buff_pos = self.command_line.position();
|
||||||
let target_char = if self.cursor_selection_mode == CursorSelectionMode::Inclusive {
|
let target_char = if self.cursor_selection_mode == CursorSelectionMode::Inclusive {
|
||||||
|
@ -1174,7 +1214,7 @@ impl ReaderData {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let Some(selection) = self.selection.as_mut() else {
|
let Some(selection) = self.selection.as_mut() else {
|
||||||
return;
|
return true;
|
||||||
};
|
};
|
||||||
if selection.begin <= buff_pos {
|
if selection.begin <= buff_pos {
|
||||||
selection.start = selection.begin;
|
selection.start = selection.begin;
|
||||||
|
@ -1183,6 +1223,7 @@ impl ReaderData {
|
||||||
selection.start = buff_pos;
|
selection.start = buff_pos;
|
||||||
selection.stop = selection.begin + target_char;
|
selection.stop = selection.begin + target_char;
|
||||||
}
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2025,7 +2066,7 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
rl::EndOfLine => {
|
rl::EndOfLine => {
|
||||||
let (_elt, el) = self.active_edit_line();
|
let (_elt, el) = self.active_edit_line();
|
||||||
if el.position() == el.len() {
|
if self.is_at_end(el) {
|
||||||
self.accept_autosuggestion(true, false, MoveWordStyle::Punctuation);
|
self.accept_autosuggestion(true, false, MoveWordStyle::Punctuation);
|
||||||
} else {
|
} else {
|
||||||
loop {
|
loop {
|
||||||
|
@ -2040,7 +2081,9 @@ impl ReaderData {
|
||||||
}
|
}
|
||||||
position
|
position
|
||||||
};
|
};
|
||||||
self.update_buff_pos(self.active_edit_line_tag(), Some(position + 1));
|
if !self.update_buff_pos(self.active_edit_line_tag(), Some(position + 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2255,17 +2298,24 @@ impl ReaderData {
|
||||||
let yank_str = kill_yank();
|
let yank_str = kill_yank();
|
||||||
self.insert_string(self.active_edit_line_tag(), &yank_str);
|
self.insert_string(self.active_edit_line_tag(), &yank_str);
|
||||||
rls.yank_len = yank_str.len();
|
rls.yank_len = yank_str.len();
|
||||||
|
if self.cursor_end_mode == CursorEndMode::Inclusive {
|
||||||
|
let (_elt, el) = self.active_edit_line();
|
||||||
|
self.update_buff_pos(self.active_edit_line_tag(), Some(el.position() - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rl::YankPop => {
|
rl::YankPop => {
|
||||||
if rls.yank_len != 0 {
|
if rls.yank_len != 0 {
|
||||||
let (elt, el) = self.active_edit_line();
|
let (elt, el) = self.active_edit_line();
|
||||||
let yank_str = kill_yank_rotate();
|
let yank_str = kill_yank_rotate();
|
||||||
let new_yank_len = yank_str.len();
|
let new_yank_len = yank_str.len();
|
||||||
self.replace_substring(
|
let bias = if self.cursor_end_mode == CursorEndMode::Inclusive {
|
||||||
elt,
|
1
|
||||||
el.position() - rls.yank_len..el.position(),
|
} else {
|
||||||
yank_str,
|
0
|
||||||
);
|
};
|
||||||
|
let begin = el.position() + bias - rls.yank_len;
|
||||||
|
let end = el.position() + bias;
|
||||||
|
self.replace_substring(elt, begin..end, yank_str);
|
||||||
self.update_buff_pos(elt, None);
|
self.update_buff_pos(elt, None);
|
||||||
rls.yank_len = new_yank_len;
|
rls.yank_len = new_yank_len;
|
||||||
self.suppress_autosuggestion = true;
|
self.suppress_autosuggestion = true;
|
||||||
|
@ -2448,14 +2498,14 @@ impl ReaderData {
|
||||||
let (elt, el) = self.active_edit_line();
|
let (elt, el) = self.active_edit_line();
|
||||||
if self.is_navigating_pager_contents() {
|
if self.is_navigating_pager_contents() {
|
||||||
self.select_completion_in_direction(SelectionMotion::East, false);
|
self.select_completion_in_direction(SelectionMotion::East, false);
|
||||||
} else if el.position() != el.len() {
|
} else if self.is_at_end(el) {
|
||||||
self.update_buff_pos(elt, Some(el.position() + 1));
|
|
||||||
} else {
|
|
||||||
self.accept_autosuggestion(
|
self.accept_autosuggestion(
|
||||||
/*full=*/ c != rl::ForwardSingleChar,
|
/*full=*/ c != rl::ForwardSingleChar,
|
||||||
/*single=*/ c == rl::ForwardSingleChar,
|
/*single=*/ c == rl::ForwardSingleChar,
|
||||||
MoveWordStyle::Punctuation,
|
MoveWordStyle::Punctuation,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
self.update_buff_pos(elt, Some(el.position() + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl::BackwardKillWord | rl::BackwardKillPathComponent | rl::BackwardKillBigword => {
|
rl::BackwardKillWord | rl::BackwardKillPathComponent | rl::BackwardKillBigword => {
|
||||||
|
@ -2539,10 +2589,10 @@ impl ReaderData {
|
||||||
MoveWordStyle::Whitespace
|
MoveWordStyle::Whitespace
|
||||||
};
|
};
|
||||||
let (elt, el) = self.active_edit_line();
|
let (elt, el) = self.active_edit_line();
|
||||||
if el.position() != el.len() {
|
if self.is_at_end(el) {
|
||||||
self.move_word(elt, MoveWordDir::Right, /*erase=*/ false, style, false);
|
|
||||||
} else {
|
|
||||||
self.accept_autosuggestion(false, false, style);
|
self.accept_autosuggestion(false, false, style);
|
||||||
|
} else {
|
||||||
|
self.move_word(elt, MoveWordDir::Right, /*erase=*/ false, style, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl::BeginningOfHistory | rl::EndOfHistory => {
|
rl::BeginningOfHistory | rl::EndOfHistory => {
|
||||||
|
@ -2836,7 +2886,9 @@ impl ReaderData {
|
||||||
if el.position() == 0 || el.text().as_char_slice()[el.position() - 1] == '\n' {
|
if el.position() == 0 || el.text().as_char_slice()[el.position() - 1] == '\n' {
|
||||||
break elt;
|
break elt;
|
||||||
}
|
}
|
||||||
self.update_buff_pos(elt, Some(el.position() - 1));
|
if !self.update_buff_pos(elt, Some(el.position() - 1)) {
|
||||||
|
break elt;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.insert_char(elt, '\n');
|
self.insert_char(elt, '\n');
|
||||||
let (elt, el) = self.active_edit_line();
|
let (elt, el) = self.active_edit_line();
|
||||||
|
@ -2849,7 +2901,9 @@ impl ReaderData {
|
||||||
{
|
{
|
||||||
break elt;
|
break elt;
|
||||||
}
|
}
|
||||||
self.update_buff_pos(elt, Some(el.position() + 1));
|
if !self.update_buff_pos(elt, Some(el.position() + 1)) {
|
||||||
|
break elt;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.insert_char(elt, '\n');
|
self.insert_char(elt, '\n');
|
||||||
}
|
}
|
||||||
|
@ -3907,6 +3961,13 @@ impl ReaderData {
|
||||||
debounce_autosuggestions().perform_with_completion(performer, completion);
|
debounce_autosuggestions().perform_with_completion(performer, completion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_at_end(&self, el: &EditableLine) -> bool {
|
||||||
|
match self.cursor_end_mode {
|
||||||
|
CursorEndMode::Exclusive => el.position() == el.len(),
|
||||||
|
CursorEndMode::Inclusive => el.position() + 1 >= el.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Accept any autosuggestion by replacing the command line with it. If full is true, take the whole
|
// Accept any autosuggestion by replacing the command line with it. If full is true, take the whole
|
||||||
// thing; if it's false, then respect the passed in style.
|
// thing; if it's false, then respect the passed in style.
|
||||||
fn accept_autosuggestion(
|
fn accept_autosuggestion(
|
||||||
|
|
Loading…
Reference in a new issue