mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 04:43:10 +00:00
Implement bind modes
This commit is contained in:
parent
1efb120248
commit
d1faac58dd
4 changed files with 185 additions and 22 deletions
68
builtin.cpp
68
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") },
|
||||
|
|
62
input.cpp
62
input.cpp
|
@ -61,7 +61,6 @@
|
|||
#include <vector>
|
||||
|
||||
#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<input_mapping_t> 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_mapping_t> 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<mapping_list.size(); i++)
|
||||
{
|
||||
input_mapping_t &m = mapping_list.at(i);
|
||||
if (m.seq == sequence)
|
||||
if (m.seq == sequence && m.mode == mode)
|
||||
{
|
||||
m.command = command;
|
||||
m.new_mode = new_mode;
|
||||
return;
|
||||
}
|
||||
}
|
||||
mapping_list.push_back(input_mapping_t(sequence, command));
|
||||
mapping_list.push_back(input_mapping_t(sequence, command, mode, new_mode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -536,9 +568,18 @@ wint_t input_readch()
|
|||
for (i=0; i<mapping_list.size(); i++)
|
||||
{
|
||||
const input_mapping_t &m = mapping_list.at(i);
|
||||
|
||||
if(wcscmp(m.mode.c_str(), input_get_bind_mode()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
wint_t res = input_try_mapping(m);
|
||||
if (res)
|
||||
{
|
||||
input_set_bind_mode(m.new_mode.c_str());
|
||||
return res;
|
||||
}
|
||||
|
||||
if (m.seq.length() == 0)
|
||||
{
|
||||
|
@ -591,7 +632,7 @@ void input_mapping_get_names(wcstring_list_t &lst)
|
|||
}
|
||||
|
||||
|
||||
bool input_mapping_erase(const wchar_t *sequence)
|
||||
bool input_mapping_erase(const wchar_t *sequence, const wchar_t *mode)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
bool result = false;
|
||||
|
@ -600,7 +641,7 @@ bool input_mapping_erase(const wchar_t *sequence)
|
|||
for (i=0; i<sz; i++)
|
||||
{
|
||||
const input_mapping_t &m = mapping_list.at(i);
|
||||
if (sequence == m.seq)
|
||||
if (sequence == m.seq && mode == m.mode)
|
||||
{
|
||||
if (i != (sz-1))
|
||||
{
|
||||
|
@ -615,7 +656,7 @@ bool input_mapping_erase(const wchar_t *sequence)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool input_mapping_get(const wcstring &sequence, wcstring &cmd)
|
||||
bool input_mapping_get(const wcstring &sequence, wcstring &cmd, wcstring &mode)
|
||||
{
|
||||
size_t i, sz = mapping_list.size();
|
||||
|
||||
|
@ -625,6 +666,7 @@ bool input_mapping_get(const wcstring &sequence, wcstring &cmd)
|
|||
if (sequence == m.seq)
|
||||
{
|
||||
cmd = m.command;
|
||||
mode = m.mode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
21
input.h
21
input.h
|
@ -11,6 +11,9 @@ inputrc information for key bindings.
|
|||
#include <wchar.h>
|
||||
#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.
|
||||
|
|
56
share/functions/fish_vi_key_bindings.fish
Normal file
56
share/functions/fish_vi_key_bindings.fish
Normal file
|
@ -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
|
Loading…
Reference in a new issue