Implement bind modes

This commit is contained in:
Julian Aron Prenner 2013-12-31 01:52:41 +01:00
parent 1efb120248
commit d1faac58dd
4 changed files with 185 additions and 22 deletions

View file

@ -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") },

View file

@ -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
View file

@ -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.

View 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