Commands to move by entire tokens

ja: I'll try to add default bindings in a follow-up PR.

Closes #10738
Closes #2014
This commit is contained in:
Jacob Chapman 2024-09-21 15:55:44 +00:00 committed by Johannes Altmanninger
parent e4c7a522ff
commit a9cee9e755
5 changed files with 127 additions and 3 deletions

View file

@ -177,7 +177,9 @@ New or improved bindings
- :kbd:`shift-enter` now inserts a newline instead of executing the command line. - :kbd:`shift-enter` now inserts a newline instead of executing the command line.
- :kbd:`ctrl-backspace` now deletes the last word instead of only one character. - :kbd:`ctrl-backspace` now deletes the last word instead of only one character.
- :kbd:`ctrl-delete` deletes the next word (same as :kbd:`alt-d`). - :kbd:`ctrl-delete` deletes the next word (same as :kbd:`alt-d`).
- New special input functions ``forward-char-passive`` and ``backward-char-passive`` are like their non-passive variants but do not accept autosuggestions or move focus in the completion pager (:issue:`10398`). - New special input functions:
- ``forward-char-passive`` and ``backward-char-passive`` are like their non-passive variants but do not accept autosuggestions or move focus in the completion pager (:issue:`10398`).
- ``forward-token``, ``backward-token``, ``kill-token``, and ``backward-kill-token`` are similar to the ``*-bigword`` variants but for the whole argument token which includes escaped spaces (:issue:`2014`).
- Vi mode has seen some improvements but continues to suffer from the lack of people working on it. - Vi mode has seen some improvements but continues to suffer from the lack of people working on it.
- Insert-mode :kbd:`ctrl-n` accepts autosuggestions (:issue:`10339`). - Insert-mode :kbd:`ctrl-n` accepts autosuggestions (:issue:`10339`).
- Outside insert mode, the cursor will no longer be placed beyond the last character on the commandline. - Outside insert mode, the cursor will no longer be placed beyond the last character on the commandline.

View file

@ -103,7 +103,7 @@ The following options are available:
Displays help about using this command. Displays help about using this command.
.. _special-input-functions: .. _special-input-functions:
Special input functions Special input functions
----------------------- -----------------------
The following special input functions are available: The following special input functions are available:
@ -125,12 +125,18 @@ The following special input functions are available:
``backward-bigword`` ``backward-bigword``
move one whitespace-delimited word to the left move one whitespace-delimited word to the left
``backward-token``
move one argument to the left
``backward-delete-char`` ``backward-delete-char``
deletes one character of input to the left of the cursor deletes one character of input to the left of the cursor
``backward-kill-bigword`` ``backward-kill-bigword``
move the whitespace-delimited word to the left of the cursor to the killring move the whitespace-delimited word to the left of the cursor to the killring
``backward-kill-token``
move the argument to the left of the cursor to the killring
``backward-kill-line`` ``backward-kill-line``
move everything from the beginning of the line to the cursor to the killring move everything from the beginning of the line to the cursor to the killring
@ -209,6 +215,9 @@ The following special input functions are available:
``forward-bigword`` ``forward-bigword``
move one whitespace-delimited word to the right move one whitespace-delimited word to the right
``forward-token``
move one argument to the right
``forward-char`` ``forward-char``
move one character to the right; or if at the end of the commandline, accept the current autosuggestion. move one character to the right; or if at the end of the commandline, accept the current autosuggestion.
If the completion pager is active, select the next completion instead. If the completion pager is active, select the next completion instead.
@ -253,7 +262,7 @@ The following special input functions are available:
read another character and jump to its next occurence after/before the cursor read another character and jump to its next occurence after/before the cursor
``forward-jump-till`` and ``backward-jump-till`` ``forward-jump-till`` and ``backward-jump-till``
jump to right *before* the next occurence jump to right *before* the next occurrence
``repeat-jump`` and ``repeat-jump-reverse`` ``repeat-jump`` and ``repeat-jump-reverse``
redo the last jump in the same/opposite direction redo the last jump in the same/opposite direction
@ -273,6 +282,9 @@ The following special input functions are available:
``kill-bigword`` ``kill-bigword``
move the next whitespace-delimited word to the killring move the next whitespace-delimited word to the killring
``kill-token``
move the next argument to the killring
``kill-line`` ``kill-line``
move everything from the cursor to the end of the line to the killring move everything from the cursor to the end of the line to the killring

View file

@ -135,7 +135,9 @@ const INPUT_FUNCTION_METADATA: &[InputFunctionMetadata] = &[
make_md(L!("backward-kill-bigword"), ReadlineCmd::BackwardKillBigword), make_md(L!("backward-kill-bigword"), ReadlineCmd::BackwardKillBigword),
make_md(L!("backward-kill-line"), ReadlineCmd::BackwardKillLine), make_md(L!("backward-kill-line"), ReadlineCmd::BackwardKillLine),
make_md(L!("backward-kill-path-component"), ReadlineCmd::BackwardKillPathComponent), make_md(L!("backward-kill-path-component"), ReadlineCmd::BackwardKillPathComponent),
make_md(L!("backward-kill-token"), ReadlineCmd::BackwardKillToken),
make_md(L!("backward-kill-word"), ReadlineCmd::BackwardKillWord), make_md(L!("backward-kill-word"), ReadlineCmd::BackwardKillWord),
make_md(L!("backward-token"), ReadlineCmd::BackwardToken),
make_md(L!("backward-word"), ReadlineCmd::BackwardWord), make_md(L!("backward-word"), ReadlineCmd::BackwardWord),
make_md(L!("begin-selection"), ReadlineCmd::BeginSelection), make_md(L!("begin-selection"), ReadlineCmd::BeginSelection),
make_md(L!("begin-undo-group"), ReadlineCmd::BeginUndoGroup), make_md(L!("begin-undo-group"), ReadlineCmd::BeginUndoGroup),
@ -167,6 +169,7 @@ const INPUT_FUNCTION_METADATA: &[InputFunctionMetadata] = &[
make_md(L!("forward-jump"), ReadlineCmd::ForwardJump), make_md(L!("forward-jump"), ReadlineCmd::ForwardJump),
make_md(L!("forward-jump-till"), ReadlineCmd::ForwardJumpTill), make_md(L!("forward-jump-till"), ReadlineCmd::ForwardJumpTill),
make_md(L!("forward-single-char"), ReadlineCmd::ForwardSingleChar), make_md(L!("forward-single-char"), ReadlineCmd::ForwardSingleChar),
make_md(L!("forward-token"), ReadlineCmd::ForwardToken),
make_md(L!("forward-word"), ReadlineCmd::ForwardWord), make_md(L!("forward-word"), ReadlineCmd::ForwardWord),
make_md(L!("history-pager"), ReadlineCmd::HistoryPager), make_md(L!("history-pager"), ReadlineCmd::HistoryPager),
make_md(L!("history-pager-delete"), ReadlineCmd::HistoryPagerDelete), make_md(L!("history-pager-delete"), ReadlineCmd::HistoryPagerDelete),
@ -184,6 +187,7 @@ const INPUT_FUNCTION_METADATA: &[InputFunctionMetadata] = &[
make_md(L!("kill-inner-line"), ReadlineCmd::KillInnerLine), make_md(L!("kill-inner-line"), ReadlineCmd::KillInnerLine),
make_md(L!("kill-line"), ReadlineCmd::KillLine), make_md(L!("kill-line"), ReadlineCmd::KillLine),
make_md(L!("kill-selection"), ReadlineCmd::KillSelection), make_md(L!("kill-selection"), ReadlineCmd::KillSelection),
make_md(L!("kill-token"), ReadlineCmd::KillToken),
make_md(L!("kill-whole-line"), ReadlineCmd::KillWholeLine), make_md(L!("kill-whole-line"), ReadlineCmd::KillWholeLine),
make_md(L!("kill-word"), ReadlineCmd::KillWord), make_md(L!("kill-word"), ReadlineCmd::KillWord),
make_md(L!("nextd-or-forward-word"), ReadlineCmd::NextdOrForwardWord), make_md(L!("nextd-or-forward-word"), ReadlineCmd::NextdOrForwardWord),

View file

@ -52,6 +52,8 @@ pub enum ReadlineCmd {
BackwardWord, BackwardWord,
ForwardBigword, ForwardBigword,
BackwardBigword, BackwardBigword,
ForwardToken,
BackwardToken,
NextdOrForwardWord, NextdOrForwardWord,
PrevdOrBackwardWord, PrevdOrBackwardWord,
HistorySearchBackward, HistorySearchBackward,
@ -75,9 +77,11 @@ pub enum ReadlineCmd {
KillInnerLine, KillInnerLine,
KillWord, KillWord,
KillBigword, KillBigword,
KillToken,
BackwardKillWord, BackwardKillWord,
BackwardKillPathComponent, BackwardKillPathComponent,
BackwardKillBigword, BackwardKillBigword,
BackwardKillToken,
HistoryTokenSearchBackward, HistoryTokenSearchBackward,
HistoryTokenSearchForward, HistoryTokenSearchForward,
SelfInsert, SelfInsert,

View file

@ -2795,6 +2795,56 @@ impl<'a> Reader<'a> {
self.rls().last_cmd != Some(c), self.rls().last_cmd != Some(c),
); );
} }
rl::BackwardKillToken => {
let Some(new_position) = self.backward_token() else {
return;
};
let (elt, _el) = self.active_edit_line();
if elt == EditableLineTag::Commandline {
self.suppress_autosuggestion = true;
}
let (elt, el) = self.active_edit_line();
self.data.kill(
elt,
new_position..el.position(),
Kill::Prepend,
self.rls().last_cmd != Some(rl::BackwardKillToken),
);
}
rl::BackwardToken => {
let Some(new_position) = self.backward_token() else {
return;
};
let (elt, _el) = self.active_edit_line();
self.update_buff_pos(elt, Some(new_position));
}
rl::KillToken => {
let Some(new_position) = self.forward_token() else {
return;
};
let (elt, _el) = self.active_edit_line();
if elt == EditableLineTag::Commandline {
self.suppress_autosuggestion = true;
}
let (elt, el) = self.active_edit_line();
self.data.kill(
elt,
el.position()..new_position,
Kill::Append,
self.rls().last_cmd != Some(rl::KillToken),
);
}
rl::ForwardToken => {
let Some(new_position) = self.forward_token() else {
return;
};
let (elt, _el) = self.active_edit_line();
self.update_buff_pos(elt, Some(new_position));
}
rl::BackwardWord | rl::BackwardBigword | rl::PrevdOrBackwardWord => { rl::BackwardWord | rl::BackwardBigword | rl::PrevdOrBackwardWord => {
if c == rl::PrevdOrBackwardWord && self.command_line.is_empty() { if c == rl::PrevdOrBackwardWord && self.command_line.is_empty() {
self.eval_bind_cmd(L!("prevd")); self.eval_bind_cmd(L!("prevd"));
@ -3332,6 +3382,54 @@ impl<'a> Reader<'a> {
} }
} }
} }
fn backward_token(&mut self) -> Option<usize> {
let (_elt, el) = self.active_edit_line();
let pos = el.position();
if pos == 0 {
return None;
}
let mut tok = 0..0;
let mut prev_tok = 0..0;
parse_util_token_extent(el.text(), el.position(), &mut tok, Some(&mut prev_tok));
// if we are at the start of a token, go back one
let new_position = if tok.start == pos {
if prev_tok.start == pos {
let cmdsub = parse_util_cmdsubst_extent(el.text(), prev_tok.start);
cmdsub.start.saturating_sub(1)
} else {
prev_tok.start
}
} else {
tok.start
};
Some(new_position)
}
fn forward_token(&self) -> Option<usize> {
let (_elt, el) = self.active_edit_line();
let pos = el.position();
if pos == el.len() {
return None;
}
// If we are not in a token, look for one ahead
let buff_pos = pos
+ el.text()[pos..]
.chars()
.take_while(|c| c.is_ascii_whitespace())
.count();
let mut tok = 0..0;
parse_util_token_extent(el.text(), buff_pos, &mut tok, None);
let new_position = if tok.end == pos { pos + 1 } else { tok.end };
Some(new_position)
}
} }
/// Returns true if the last token is a comment. /// Returns true if the last token is a comment.
@ -4909,6 +5007,8 @@ fn command_ends_paging(c: ReadlineCmd, focused_on_search_field: bool) -> bool {
| rl::BackwardWord | rl::BackwardWord
| rl::ForwardBigword | rl::ForwardBigword
| rl::BackwardBigword | rl::BackwardBigword
| rl::ForwardToken
| rl::BackwardToken
| rl::NextdOrForwardWord | rl::NextdOrForwardWord
| rl::PrevdOrBackwardWord | rl::PrevdOrBackwardWord
| rl::DeleteChar | rl::DeleteChar
@ -4921,9 +5021,11 @@ fn command_ends_paging(c: ReadlineCmd, focused_on_search_field: bool) -> bool {
| rl::KillInnerLine | rl::KillInnerLine
| rl::KillWord | rl::KillWord
| rl::KillBigword | rl::KillBigword
| rl::KillToken
| rl::BackwardKillWord | rl::BackwardKillWord
| rl::BackwardKillPathComponent | rl::BackwardKillPathComponent
| rl::BackwardKillBigword | rl::BackwardKillBigword
| rl::BackwardKillToken
| rl::SelfInsert | rl::SelfInsert
| rl::SelfInsertNotFirst | rl::SelfInsertNotFirst
| rl::TransposeChars | rl::TransposeChars