diff --git a/builtin.cpp b/builtin.cpp index 335b81ce5..0d7ed2222 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -413,27 +413,38 @@ static void builtin_bind_list(const wchar_t *bind_mode) { wcstring seq = lst.at(i); - wcstring ecmd; + std::vector ecmds; wcstring mode; + wcstring new_mode; - input_mapping_get(seq, ecmd, mode); + input_mapping_get(seq, ecmds, mode, new_mode); if(bind_mode != NULL && wcscmp(mode.c_str(), bind_mode)) { continue; } - ecmd = escape_string(ecmd, 1); - wcstring tname; if (input_terminfo_get_name(seq, tname)) { - append_format(stdout_buffer, L"bind -k %ls %ls (in mode `%ls')\n", tname.c_str(), ecmd.c_str(), mode.c_str()); + append_format(stdout_buffer, L"bind -k %ls -M %ls -m %ls", tname.c_str(), mode.c_str(), new_mode.c_str()); + for(int i = 0; i < ecmds.size(); i++) + { + wcstring ecmd = ecmds.at(i); + append_format(stdout_buffer, L" %ls", escape(ecmd.c_str(), 1)); + } + append_format(stdout_buffer, L"\n"); } else { const wcstring eseq = escape_string(seq, 1); - append_format(stdout_buffer, L"bind %ls %ls (in mode `%ls')\n", eseq.c_str(), ecmd.c_str(), mode.c_str()); + append_format(stdout_buffer, L"bind -k %ls -M %ls -m %ls", eseq.c_str(), mode.c_str(), new_mode.c_str()); + for(int i = 0; i < ecmds.size(); i++) + { + wcstring ecmd = ecmds.at(i); + append_format(stdout_buffer, L" %ls", escape(ecmd.c_str(), 1)); + } + append_format(stdout_buffer, L"\n"); } } } @@ -474,7 +485,8 @@ static void builtin_bind_function_names() /** Add specified key binding. */ -static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, const wchar_t *mode, const wchar_t *new_mode, int terminfo) +static int builtin_bind_add(const wchar_t *seq, const wchar_t **cmds, size_t cmds_len, + const wchar_t *mode, const wchar_t *new_mode, int terminfo) { if (terminfo) @@ -482,7 +494,7 @@ static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, const wchar_ wcstring seq2; if (input_terminfo_get_sequence(seq, &seq2)) { - input_mapping_add(seq2.c_str(), cmd, mode, new_mode); + input_mapping_add(seq2.c_str(), cmds, cmds_len, mode, new_mode); } else { @@ -515,7 +527,7 @@ static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, const wchar_ } else { - input_mapping_add(seq, cmd, mode, new_mode); + input_mapping_add(seq, cmds, cmds_len, mode, new_mode); } return 0; @@ -718,18 +730,19 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) break; } - case 2: + case 1: { - builtin_bind_add(argv[woptind], argv[woptind+1], bind_mode, new_bind_mode, use_terminfo); + res = STATUS_BUILTIN_ERROR; + append_format(stderr_buffer, _(L"%ls: Expected zero or at least two parameters, got %d"), argv[0], argc-woptind); break; } default: { - res = STATUS_BUILTIN_ERROR; - append_format(stderr_buffer, _(L"%ls: Expected zero or two parameters, got %d"), argv[0], argc-woptind); + builtin_bind_add(argv[woptind], (const wchar_t **)argv + (woptind + 1), argc - (woptind + 1), bind_mode, new_bind_mode, use_terminfo); break; } + } break; } diff --git a/input.cpp b/input.cpp index 035188e3b..1c32260c8 100644 --- a/input.cpp +++ b/input.cpp @@ -64,16 +64,17 @@ /** Struct representing a keybinding. Returned by input_get_mappings. */ + struct input_mapping_t { wcstring seq; /**< Character sequence which generates this event */ - wcstring command; /**< command that should be evaluated by this mapping */ + std::vector commands; /**< commands that should be evaluated by this mapping */ wcstring mode; /**< mode in which this command should be evaluated */ wcstring new_mode; /** new mode that should be switched to after command evaluation */ - input_mapping_t(const wcstring &s, const wcstring &c, + input_mapping_t(const wcstring &s, const std::vector &c, const wcstring &m = DEFAULT_BIND_MODE, - const wcstring &nm = DEFAULT_BIND_MODE) : seq(s), command(c), mode(m), new_mode(nm) {} + const wcstring &nm = DEFAULT_BIND_MODE) : seq(s), commands(c), mode(m), new_mode(nm) {} }; /** @@ -285,27 +286,35 @@ bool input_set_bind_mode(const wchar_t *bm) Returns the function description for the given function code. */ -void input_mapping_add(const wchar_t *sequence, const wchar_t *command, +void input_mapping_add(const wchar_t *sequence, const wchar_t **commands, size_t commands_len, const wchar_t *mode, const wchar_t *new_mode) { CHECK(sequence,); - CHECK(command,); + CHECK(commands,); CHECK(mode,); CHECK(new_mode,); // debug( 0, L"Add mapping from %ls to %ls in mode %ls", escape(sequence, 1), escape(command, 1 ), mode); + std::vector commands_vector(commands, commands + commands_len); + for (size_t i=0; i= 0; i--) { - switch (code) - { + wcstring command = m.commands.at(i); + wchar_t code = input_function_get_code(command); + if (code != (wchar_t)-1) + { + input_unreadch(code); + } + else + { + /* + This key sequence is bound to a command, which + is sent to the parser for evaluation. + */ + int last_status = proc_get_last_status(); + parser_t::principal_parser().eval(command.c_str(), io_chain_t(), TOP); - case R_SELF_INSERT: - { - return seq[0]; - } - - default: - { - return code; - } + proc_set_last_status(last_status); + input_unreadch(R_NULL); } } - else - { - /* - This key sequence is bound to a command, which - is sent to the parser for evaluation. - */ - int last_status = proc_get_last_status(); - - parser_t::principal_parser().eval(m.command.c_str(), io_chain_t(), TOP); - - proc_set_last_status(last_status); - - /* - We still need to return something to the caller, R_NULL - tells the reader that no key press needs to be handled, - and no repaint is needed. - - Bindings that produce output should emit a R_REPAINT - function by calling 'commandline -f repaint' to tell - fish that a repaint is in order. - */ - - return R_NULL; - - } + input_set_bind_mode(m.new_mode.c_str()); } @@ -500,22 +491,12 @@ static wint_t input_exec_binding(const input_mapping_t &m, const wcstring &seq) /** Try reading the specified function mapping */ -static wint_t input_try_mapping(const input_mapping_t &m) +static bool input_mapping_is_match(const input_mapping_t &m) { - wint_t c=0; + wint_t c = 0; int j; - /* - Check if the actual function code of this mapping is on the stack - */ - c = input_common_readch(0); - if (c == input_function_get_code(m.command)) - { - return input_exec_binding(m, m.seq); - } - input_unreadch(c); - - //debug(0, L"trying mapping %ls (%ls)\n", escape(m.seq.c_str(), 1), m.command.c_str()); + //debug(0, L"trying mapping %ls\n", escape(m.seq.c_str(), 1)); const wchar_t *str = m.seq.c_str(); for (j=0; str[j] != L'\0'; j++) { @@ -532,7 +513,7 @@ static wint_t input_try_mapping(const input_mapping_t &m) { //debug(0, L"matched mapping %ls (%ls)\n", escape(m.seq.c_str(), 1), m.command.c_str()); /* We matched the entire sequence */ - return input_exec_binding(m, m.seq); + return true; } else { @@ -547,7 +528,7 @@ static wint_t input_try_mapping(const input_mapping_t &m) } } - return 0; + return false; } @@ -556,6 +537,48 @@ void input_unreadch(wint_t ch) input_common_unreadch(ch); } +static void input_mapping_execute_matching_or_generic() +{ + const input_mapping_t *generic = NULL; + + for (int i = 0; i < mapping_list.size(); i++) + { + const input_mapping_t &m = mapping_list.at(i); + + //debug(0, L"trying mapping (%ls,%ls,%ls)\n", escape(m.seq.c_str(), 1), + // m.mode.c_str(), m.new_mode.c_str()); + + if(wcscmp(m.mode.c_str(), input_get_bind_mode())) + { + //debug(0, L"skipping mapping because mode %ls != %ls\n", m.mode.c_str(), input_get_bind_mode()); + continue; + } + + if (m.seq.length() == 0) + { + generic = &m; + } + else if(input_mapping_is_match(m)) + { + input_mapping_execute(m); + return; + } + } + + if (generic) + { + input_mapping_execute(*generic); + } + else + { + //debug(0, L"no generic found, ignoring..."); + wchar_t c = input_common_readch(0); + if (c == R_EOF) + input_common_unreadch(c); + } +} + + wint_t input_readch() { size_t i; @@ -573,61 +596,30 @@ wint_t input_readch() while (1) { - const input_mapping_t *generic = 0; - for (i=0; i= R_MIN && c <= R_MAX) { - return WEOF; + switch (c) + { + case R_EOF: /* If it's closed, then just return */ + { + return WEOF; + } + case R_SELF_INSERT: + { + return input_common_readch(0); + } + default: + { + return c; + } + } + } + else + { + input_unreadch(c); + input_mapping_execute_matching_or_generic(); } } } @@ -669,7 +661,7 @@ bool input_mapping_erase(const wchar_t *sequence, const wchar_t *mode) return result; } -bool input_mapping_get(const wcstring &sequence, wcstring &cmd, wcstring &mode) +bool input_mapping_get(const wcstring &sequence, std::vector &cmds, wcstring &mode, wcstring &new_mode) { size_t i, sz = mapping_list.size(); @@ -678,8 +670,9 @@ bool input_mapping_get(const wcstring &sequence, wcstring &cmd, wcstring &mode) const input_mapping_t &m = mapping_list.at(i); if (sequence == m.seq) { - cmd = m.command; + cmds = m.commands; mode = m.mode; + new_mode = m.new_mode; return true; } } diff --git a/input.h b/input.h index c825c9eb6..fdcb82b45 100644 --- a/input.h +++ b/input.h @@ -60,10 +60,13 @@ enum R_UP_LINE, R_DOWN_LINE, R_SUPPRESS_AUTOSUGGESTION, - R_ACCEPT_AUTOSUGGESTION + R_ACCEPT_AUTOSUGGESTION, } ; +#define R_MIN R_NULL +#define R_MAX R_ACCEPT_AUTOSUGGESTION + /** Initialize the terminal by calling setupterm, and set up arrays used by readch to detect escape sequences for special keys. @@ -110,6 +113,9 @@ void input_mapping_add(const wchar_t *sequence, const wchar_t *command, const wchar_t *mode = DEFAULT_BIND_MODE, const wchar_t *new_mode = DEFAULT_BIND_MODE); +void input_mapping_add(const wchar_t *sequence, const wchar_t **commands, size_t commands_len, + const wchar_t *mode = DEFAULT_BIND_MODE, const wchar_t *new_mode = DEFAULT_BIND_MODE); + /** Insert all mapping names into the specified wcstring_list_t */ @@ -123,7 +129,7 @@ bool input_mapping_erase(const wchar_t *sequence, const wchar_t *mode = DEFAULT_ /** Gets the command bound to the specified key sequence. Returns true if it exists, false if not. */ -bool input_mapping_get(const wcstring &sequence, wcstring &cmd, wcstring &mode); +bool input_mapping_get(const wcstring &sequence, std::vector &cmds, wcstring &mode, wcstring &new_mode); /** Return the current bind mode diff --git a/share/functions/fish_vi_key_bindings.fish b/share/functions/fish_vi_key_bindings.fish index 511e045ab..ef4f40e0e 100644 --- a/share/functions/fish_vi_key_bindings.fish +++ b/share/functions/fish_vi_key_bindings.fish @@ -17,7 +17,7 @@ function fish_vi_key_bindings -d "vi-like key bindings for fish" bind -k left backward-char bind \n execute bind -m insert i force-repaint - bind -m insert a forward-char + bind -m insert a forward-char force-repaint bind \x24 end-of-line bind \x5e beginning-of-line