mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-27 11:43:37 +08:00
Merge branch 'self-insert-notfirst-3.1.1' into Integration_3.1.1
This is the 3.1.1 set of changes to improve pasting behavior. cherry-picked from #6713
This commit is contained in:
commit
4c30e5ad44
|
@ -161,7 +161,7 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
|
|||
bind --preset -M paste \\ "__fish_commandline_insert_escaped \\\ \$__fish_paste_quoted"
|
||||
# Only insert spaces if we're either quoted or not at the beginning of the commandline
|
||||
# - this strips leading spaces if they would trigger histignore.
|
||||
bind --preset -M paste \ 'if set -q __fish_paste_quoted[1]; or string length -q -- (commandline -c); commandline -i " "; end'
|
||||
bind --preset -M paste " " self-insert-notfirst
|
||||
end
|
||||
|
||||
function __fish_commandline_insert_escaped --description 'Insert the first arg escaped if a second arg is given'
|
||||
|
|
|
@ -120,6 +120,8 @@ The following special input functions are available:
|
|||
|
||||
- ``execute`` run the current commandline
|
||||
|
||||
- ``force-repaint`` reexecute the prompt functions without coalescing
|
||||
|
||||
- ``forward-bigword``, move one whitespace-delimited word to the right
|
||||
|
||||
- ``forward-char``, move one character to the right
|
||||
|
@ -160,7 +162,9 @@ The following special input functions are available:
|
|||
|
||||
- ``repaint-mode`` reexecutes the fish_mode_prompt function and redraws the prompt. This is useful for vi-mode. If no fish_mode_prompt exists, it acts like a normal repaint.
|
||||
|
||||
- ``force-repaint`` reexecute the prompt functions without coalescing.
|
||||
- ``self-insert``, inserts the matching sequence into the command line
|
||||
|
||||
- ``self-insert-notfirst``, inserts the matching sequence into the command line, unless the cursor is at the beginning
|
||||
|
||||
- ``suppress-autosuggestion``, remove the current autosuggestion
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ static const input_function_metadata_t input_function_metadata[] = {
|
|||
{readline_cmd_t::history_token_search_backward, L"history-token-search-backward"},
|
||||
{readline_cmd_t::history_token_search_forward, L"history-token-search-forward"},
|
||||
{readline_cmd_t::self_insert, L"self-insert"},
|
||||
{readline_cmd_t::self_insert_notfirst, L"self-insert-notfirst"},
|
||||
{readline_cmd_t::transpose_chars, L"transpose-chars"},
|
||||
{readline_cmd_t::transpose_words, L"transpose-words"},
|
||||
{readline_cmd_t::upcase_word, L"upcase-word"},
|
||||
|
@ -496,7 +497,8 @@ char_event_t inputter_t::readch(bool allow_commands) {
|
|||
|
||||
if (evt.is_readline()) {
|
||||
switch (evt.get_readline()) {
|
||||
case readline_cmd_t::self_insert: {
|
||||
case readline_cmd_t::self_insert:
|
||||
case readline_cmd_t::self_insert_notfirst: {
|
||||
// Typically self-insert is generated by the generic (empty) binding.
|
||||
// However if it is generated by a real sequence, then insert that sequence.
|
||||
for (auto iter = evt.seq.crbegin(); iter != evt.seq.crend(); ++iter) {
|
||||
|
@ -504,7 +506,13 @@ char_event_t inputter_t::readch(bool allow_commands) {
|
|||
}
|
||||
// Issue #1595: ensure we only insert characters, not readline functions. The
|
||||
// common case is that this will be empty.
|
||||
return read_characters_no_readline();
|
||||
char_event_t res = read_characters_no_readline();
|
||||
|
||||
// Hackish: mark the input style.
|
||||
res.input_style = evt.get_readline() == readline_cmd_t::self_insert_notfirst
|
||||
? char_input_style_t::notfirst
|
||||
: char_input_style_t::normal;
|
||||
return res;
|
||||
}
|
||||
case readline_cmd_t::func_and: {
|
||||
if (function_status_) {
|
||||
|
|
|
@ -42,6 +42,7 @@ enum class readline_cmd_t {
|
|||
history_token_search_backward,
|
||||
history_token_search_forward,
|
||||
self_insert,
|
||||
self_insert_notfirst,
|
||||
transpose_chars,
|
||||
transpose_words,
|
||||
upcase_word,
|
||||
|
@ -96,6 +97,16 @@ enum class char_event_type_t : uint8_t {
|
|||
check_exit,
|
||||
};
|
||||
|
||||
/// Hackish: the input style, which describes how char events (only) are applied to the command
|
||||
/// line. Note this is set only after applying bindings; it is not set from readb().
|
||||
enum class char_input_style_t : uint8_t {
|
||||
// Insert characters normally.
|
||||
normal,
|
||||
|
||||
// Insert characters only if the cursor is not at the beginning. Otherwise, discard them.
|
||||
notfirst,
|
||||
};
|
||||
|
||||
class char_event_t {
|
||||
union {
|
||||
/// Set if the type is charc.
|
||||
|
@ -109,6 +120,9 @@ class char_event_t {
|
|||
/// The type of event.
|
||||
char_event_type_t type;
|
||||
|
||||
/// The style to use when inserting characters into the command line.
|
||||
char_input_style_t input_style{char_input_style_t::normal};
|
||||
|
||||
/// The sequence of characters in the input mapping which generated this event.
|
||||
/// Note that the generic self-insert case does not have any characters, so this would be empty.
|
||||
wcstring seq{};
|
||||
|
|
|
@ -1060,6 +1060,7 @@ static bool command_ends_paging(readline_cmd_t c, bool focused_on_search_field)
|
|||
case rl::backward_kill_path_component:
|
||||
case rl::backward_kill_bigword:
|
||||
case rl::self_insert:
|
||||
case rl::self_insert_notfirst:
|
||||
case rl::transpose_chars:
|
||||
case rl::transpose_words:
|
||||
case rl::upcase_word:
|
||||
|
@ -2390,47 +2391,36 @@ struct readline_loop_state_t {
|
|||
/// Read normal characters, inserting them into the command line.
|
||||
/// \return the next unhandled event.
|
||||
maybe_t<char_event_t> reader_data_t::read_normal_chars(readline_loop_state_t &rls) {
|
||||
maybe_t<char_event_t> event_needing_handling = inputter.readch();
|
||||
|
||||
if (!event_is_normal_char(*event_needing_handling) || !can_read(STDIN_FILENO))
|
||||
return event_needing_handling;
|
||||
|
||||
// This is a normal character input.
|
||||
// We are going to handle it directly, accumulating more.
|
||||
char_event_t evt = event_needing_handling.acquire();
|
||||
maybe_t<char_event_t> event_needing_handling{};
|
||||
wcstring accumulated_chars;
|
||||
size_t limit = std::min(rls.nchars - command_line.size(), READAHEAD_MAX);
|
||||
|
||||
wchar_t arr[READAHEAD_MAX + 1] = {};
|
||||
arr[0] = evt.get_char();
|
||||
|
||||
for (size_t i = 1; i < limit; ++i) {
|
||||
if (!can_read(0)) {
|
||||
while (accumulated_chars.size() < limit) {
|
||||
bool allow_commands = (accumulated_chars.empty());
|
||||
auto evt = inputter.readch(allow_commands);
|
||||
if (!event_is_normal_char(evt) || !can_read(STDIN_FILENO)) {
|
||||
event_needing_handling = std::move(evt);
|
||||
break;
|
||||
}
|
||||
// Only allow commands on the first key; otherwise, we might have data we
|
||||
// need to insert on the commandline that the command might need to be able
|
||||
// to see.
|
||||
auto next_event = inputter.readch(false);
|
||||
if (event_is_normal_char(next_event)) {
|
||||
arr[i] = next_event.get_char();
|
||||
} else if (evt.input_style == char_input_style_t::notfirst && accumulated_chars.empty() &&
|
||||
active_edit_line()->position == 0) {
|
||||
// The cursor is at the beginning and nothing is accumulated, so skip this character.
|
||||
continue;
|
||||
} else {
|
||||
// We need to process this in the outer loop.
|
||||
assert(!event_needing_handling && "Should not have an unhandled event");
|
||||
event_needing_handling = next_event;
|
||||
break;
|
||||
accumulated_chars.push_back(evt.get_char());
|
||||
}
|
||||
}
|
||||
|
||||
editable_line_t *el = active_edit_line();
|
||||
insert_string(el, arr);
|
||||
if (!accumulated_chars.empty()) {
|
||||
editable_line_t *el = active_edit_line();
|
||||
insert_string(el, accumulated_chars);
|
||||
|
||||
// End paging upon inserting into the normal command line.
|
||||
if (el == &command_line) {
|
||||
clear_pager();
|
||||
// End paging upon inserting into the normal command line.
|
||||
if (el == &command_line) {
|
||||
clear_pager();
|
||||
}
|
||||
|
||||
// Since we handled a normal character, we don't have a last command.
|
||||
rls.last_cmd.reset();
|
||||
}
|
||||
|
||||
// Since we handled a normal character, we don't have a last command.
|
||||
rls.last_cmd.reset();
|
||||
return event_needing_handling;
|
||||
}
|
||||
|
||||
|
@ -3179,12 +3169,11 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
}
|
||||
break;
|
||||
}
|
||||
// Some commands should have been handled internally by input_readch().
|
||||
case rl::self_insert: {
|
||||
DIE("self-insert should have been handled by inputter_t::readch");
|
||||
}
|
||||
// Some commands should have been handled internally by inputter_t::readch().
|
||||
case rl::self_insert:
|
||||
case rl::self_insert_notfirst:
|
||||
case rl::func_and: {
|
||||
DIE("self-insert should have been handled by inputter_t::readch");
|
||||
DIE("should have been handled by inputter_t::readch");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3298,8 +3287,11 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
} else {
|
||||
// Ordinary char.
|
||||
wchar_t c = event_needing_handling->get_char();
|
||||
if (!fish_reserved_codepoint(c) && (c >= L' ' || c == L'\n' || c == L'\r') &&
|
||||
c != 0x7F) {
|
||||
if (event_needing_handling->input_style == char_input_style_t::notfirst &&
|
||||
active_edit_line()->position == 0) {
|
||||
// This character is skipped.
|
||||
} else if (!fish_reserved_codepoint(c) && (c >= L' ' || c == L'\n' || c == L'\r') &&
|
||||
c != 0x7F) {
|
||||
// Regular character.
|
||||
editable_line_t *el = active_edit_line();
|
||||
insert_char(active_edit_line(), c);
|
||||
|
|
|
@ -299,3 +299,15 @@ expect_prompt -re {nul seen\r\nnul seen\r\nnul seen} {
|
|||
} unmatched {
|
||||
puts stderr "nul not seen"
|
||||
}
|
||||
|
||||
# Test self-insert-notfirst. (#6603)
|
||||
# Here the leading 'q's should be stripped, but the trailing ones not.
|
||||
send "bind q self-insert-notfirst\r"
|
||||
expect_prompt
|
||||
send "qqqecho qqq"
|
||||
send "\r"
|
||||
expect_prompt -re {qqq} {
|
||||
puts "Leading q properly stripped"
|
||||
} unmatched {
|
||||
puts stderr "Leading qs not stripped"
|
||||
}
|
||||
|
|
|
@ -23,3 +23,4 @@ ctrl-o seen
|
|||
ctrl-w stops at :
|
||||
ctrl-w stops at @
|
||||
nul seen
|
||||
Leading q properly stripped
|
||||
|
|
Loading…
Reference in New Issue
Block a user