diff --git a/builtin.cpp b/builtin.cpp index a57218900..dfee2c0a3 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -414,18 +414,20 @@ static void builtin_bind_list() wcstring seq = lst.at(i); wcstring ecmd; - input_mapping_get(seq, ecmd); + wcstring mode; + + input_mapping_get(seq, ecmd, mode); ecmd = escape_string(ecmd, 1); wcstring tname; if (input_terminfo_get_name(seq, tname)) { - append_format(stdout_buffer, L"bind -k %ls %ls\n", tname.c_str(), ecmd.c_str()); + append_format(stdout_buffer, L"bind -k %ls %ls (in mode `%ls')\n", tname.c_str(), ecmd.c_str(), mode.c_str()); } else { const wcstring eseq = escape_string(seq, 1); - append_format(stdout_buffer, L"bind %ls %ls\n", eseq.c_str(), ecmd.c_str()); + append_format(stdout_buffer, L"bind %ls %ls (in mode `%ls')\n", eseq.c_str(), ecmd.c_str(), mode.c_str()); } } } @@ -466,7 +468,7 @@ static void builtin_bind_function_names() /** Add specified key binding. */ -static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, int terminfo) +static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, const wchar_t *mode, const wchar_t *new_mode, int terminfo) { if (terminfo) @@ -474,7 +476,7 @@ static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, int terminfo wcstring seq2; if (input_terminfo_get_sequence(seq, &seq2)) { - input_mapping_add(seq2.c_str(), cmd); + input_mapping_add(seq2.c_str(), cmd, mode, new_mode); } else { @@ -507,7 +509,7 @@ static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, int terminfo } else { - input_mapping_add(seq, cmd); + input_mapping_add(seq, cmd, mode, new_mode); } return 0; @@ -566,6 +568,9 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) int res = STATUS_BUILTIN_OK; int all = 0; + const wchar_t *bind_mode = DEFAULT_BIND_MODE; + const wchar_t *new_bind_mode = DEFAULT_BIND_MODE; + int use_terminfo = 0; woptind=0; @@ -597,6 +602,14 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) L"key-names", no_argument, 0, 'K' } , + { + L"mode", required_argument, 0, 'M' + } + , + { + L"new-mode", required_argument, 0, 'm' + } + , { 0, 0, 0, 0 } @@ -608,7 +621,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) int opt_index = 0; int opt = wgetopt_long(argc, argv, - L"aehkKf", + L"aehkKfM:m:", long_options, &opt_index); @@ -636,7 +649,6 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) mode = BIND_ERASE; break; - case 'h': builtin_print_help(parser, argv[0], stdout_buffer); return STATUS_BUILTIN_OK; @@ -653,10 +665,19 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) mode = BIND_FUNCTION_NAMES; break; + case 'M': + bind_mode = woptarg; + break; + + case 'm': + new_bind_mode = woptarg; + break; + case '?': builtin_unknown_option(parser, argv[0], argv[woptind-1]); return STATUS_BUILTIN_ERROR; + } } @@ -682,7 +703,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) case 2: { - builtin_bind_add(argv[woptind], argv[woptind+1], use_terminfo); + builtin_bind_add(argv[woptind], argv[woptind+1], bind_mode, new_bind_mode, use_terminfo); break; } @@ -721,6 +742,34 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) return res; } + +/** + The bind mode builtin +*/ +static int builtin_bind_mode(parser_t &parser, wchar_t **argv) +{ + int res = STATUS_BUILTIN_OK; + int argc = builtin_count_args(argv); + + switch (argc) + { + case 1: + { + append_format(stdout_buffer, L"%ls\n", input_get_bind_mode()); + break; + } + + default: + { + res = STATUS_BUILTIN_ERROR; + append_format(stderr_buffer, _(L"%ls: Expected no parameters, got %d"), argv[0], argc); + break; + } + } + return res; +} + + /** The block builtin, used for temporarily blocking events */ @@ -3979,6 +4028,7 @@ static const builtin_data_t builtin_datas[]= { L"begin", &builtin_begin, N_(L"Create a block of code") }, { L"bg", &builtin_bg, N_(L"Send job to background") }, { L"bind", &builtin_bind, N_(L"Handle fish key bindings") }, + { L"bind_mode", &builtin_bind_mode, N_(L"Set or get the current bind mode") }, { L"block", &builtin_block, N_(L"Temporarily block delivery of events") }, { L"break", &builtin_break_continue, N_(L"Stop the innermost loop") }, { L"breakpoint", &builtin_breakpoint, N_(L"Temporarily halt execution of a script and launch an interactive debug prompt") }, diff --git a/input.cpp b/input.cpp index 51f658afc..fc55ff9bb 100644 --- a/input.cpp +++ b/input.cpp @@ -61,7 +61,6 @@ #include #define DEFAULT_TERM L"ansi" - /** Struct representing a keybinding. Returned by input_get_mappings. */ @@ -69,9 +68,12 @@ struct input_mapping_t { wcstring seq; /**< Character sequence which generates this event */ wcstring command; /**< command 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) : seq(s), command(c) {} + input_mapping_t(const wcstring &s, const wcstring &c, + const wcstring &m = DEFAULT_BIND_MODE, + const wcstring &nm = DEFAULT_BIND_MODE) : seq(s), command(c), mode(m), new_mode(nm) {} }; /** @@ -226,6 +228,9 @@ static const wchar_t code_arr[] = /** Mappings for the current input mode */ static std::vector mapping_list; +#define MAX_BIND_MODE_NAME_SIZE 512 +static wchar_t bind_mode[MAX_BIND_MODE_NAME_SIZE] = DEFAULT_BIND_MODE; + /* Terminfo map list */ static std::vector terminfo_mappings; @@ -248,28 +253,55 @@ static bool is_init = false; */ static void input_terminfo_init(); +/** + Return the current bind mode +*/ +const wchar_t *input_get_bind_mode() +{ + return bind_mode; +} + +/** + Set the current bind mode +*/ +bool input_set_bind_mode(const wchar_t *bm) +{ + int len = wcslen(bm) * sizeof(wchar_t); + if(len >= MAX_BIND_MODE_NAME_SIZE) + { + return false; + } + memset(bind_mode, 0, MAX_BIND_MODE_NAME_SIZE); + memcpy(bind_mode, bm, len); + + return true; +} /** 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 *command, + const wchar_t *mode, const wchar_t *new_mode) { CHECK(sequence,); CHECK(command,); + CHECK(mode,); + CHECK(new_mode,); - // debug( 0, L"Add mapping from %ls to %ls", escape(sequence, 1), escape(command, 1 ) ); + // debug( 0, L"Add mapping from %ls to %ls in mode %ls", escape(sequence, 1), escape(command, 1 ), mode); for (size_t i=0; i #include "input_common.h" + +#define DEFAULT_BIND_MODE L"default" + /** Key codes for inputrc-style keyboard functions that are passed on to the caller of input_read() @@ -102,7 +105,9 @@ void input_unreadch(wint_t ch); \param sequence the sequence to bind \param command an input function that will be run whenever the key sequence occurs */ -void input_mapping_add(const wchar_t *sequence, const wchar_t *command); +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); /** Insert all mapping names into the specified wcstring_list_t @@ -112,12 +117,22 @@ void input_mapping_get_names(wcstring_list_t &lst); /** Erase binding for specified key sequence */ -bool input_mapping_erase(const wchar_t *sequence); +bool input_mapping_erase(const wchar_t *sequence, const wchar_t *mode = DEFAULT_BIND_MODE); /** 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); +bool input_mapping_get(const wcstring &sequence, wcstring &cmd, wcstring &mode); + +/** + Return the current bind mode +*/ +const wchar_t *input_get_bind_mode(); + +/** + Set the current bind mode +*/ +bool input_set_bind_mode(const wchar_t *bind_mode); /** Return the sequence for the terminfo variable of the specified name. diff --git a/share/functions/fish_vi_key_bindings.fish b/share/functions/fish_vi_key_bindings.fish new file mode 100644 index 000000000..245e2cc4f --- /dev/null +++ b/share/functions/fish_vi_key_bindings.fish @@ -0,0 +1,56 @@ +function nothing +end + +function fish_vi_key_bindings -d "vi-like key bindings for fish" + + bind --erase --all + + # + # command (default) mode + # + + bind \cd exit + bind : exit + + bind h backward-char + bind l forward-char + bind \e\[C forward-char + bind \e\[D backward-char + bind -k right forward-char + bind -k left backward-char + bind \n execute + bind -m insert i nothing + bind -m insert a forward-char + + bind \x24 end-of-line + bind \x5e beginning-of-line + bind \e\[H beginning-of-line + bind \e\[F end-of-line + + bind k up-or-search + bind j down-or-search + bind \e\[A up-or-search + bind \e\[B down-or-search + bind -k down down-or-search + bind -k up up-or-search + + bind b backward-word + bind B backward-word + bind w forward-word + bind W backward-word + + bind y yank + bind p yank-pop + + # + # insert mode + # + + bind -M insert "" self-insert + bind -M insert \n execute + + bind -M insert -k dc delete-char + bind -M insert -k backspace backward-delete-char + bind -M insert -m default \e nothing + bind -M insert \t complete +end