diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index 8f3db773c..b3be69779 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -162,6 +162,10 @@ 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. +- ``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 - ``swap-selection-start-stop``, go to the other end of the highlighted text without changing the selection diff --git a/src/input.cpp b/src/input.cpp index e2600656d..f175046ef 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -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_event_t::style_notfirst + : char_event_t::style_normal; + return res; } case readline_cmd_t::func_and: { if (function_status_) { diff --git a/src/input_common.h b/src/input_common.h index 583886579..7053309ae 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -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, @@ -109,6 +110,17 @@ class char_event_t { /// The type of event. char_event_type_t type; + /// 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 input_style_t : uint8_t { + // Insert characters normally. + style_normal, + + // Insert characters only if the cursor is not at the beginning. Otherwise, discard them. + style_notfirst, + }; + input_style_t input_style{style_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{}; diff --git a/src/reader.cpp b/src/reader.cpp index e33fb8416..ee304eaee 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -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: @@ -3179,12 +3180,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"); } } }