mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-03-27 14:45:13 +08:00
Implement bind modes
This commit is contained in:
parent
1efb120248
commit
d1faac58dd
68
builtin.cpp
68
builtin.cpp
@ -414,18 +414,20 @@ static void builtin_bind_list()
|
|||||||
wcstring seq = lst.at(i);
|
wcstring seq = lst.at(i);
|
||||||
|
|
||||||
wcstring ecmd;
|
wcstring ecmd;
|
||||||
input_mapping_get(seq, ecmd);
|
wcstring mode;
|
||||||
|
|
||||||
|
input_mapping_get(seq, ecmd, mode);
|
||||||
ecmd = escape_string(ecmd, 1);
|
ecmd = escape_string(ecmd, 1);
|
||||||
|
|
||||||
wcstring tname;
|
wcstring tname;
|
||||||
if (input_terminfo_get_name(seq, 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
|
else
|
||||||
{
|
{
|
||||||
const wcstring eseq = escape_string(seq, 1);
|
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.
|
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)
|
if (terminfo)
|
||||||
@ -474,7 +476,7 @@ static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, int terminfo
|
|||||||
wcstring seq2;
|
wcstring seq2;
|
||||||
if (input_terminfo_get_sequence(seq, &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
|
else
|
||||||
{
|
{
|
||||||
@ -507,7 +509,7 @@ static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, int terminfo
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
input_mapping_add(seq, cmd);
|
input_mapping_add(seq, cmd, mode, new_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -566,6 +568,9 @@ static int builtin_bind(parser_t &parser, wchar_t **argv)
|
|||||||
int res = STATUS_BUILTIN_OK;
|
int res = STATUS_BUILTIN_OK;
|
||||||
int all = 0;
|
int all = 0;
|
||||||
|
|
||||||
|
const wchar_t *bind_mode = DEFAULT_BIND_MODE;
|
||||||
|
const wchar_t *new_bind_mode = DEFAULT_BIND_MODE;
|
||||||
|
|
||||||
int use_terminfo = 0;
|
int use_terminfo = 0;
|
||||||
|
|
||||||
woptind=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"key-names", no_argument, 0, 'K'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
{
|
||||||
|
L"mode", required_argument, 0, 'M'
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
L"new-mode", required_argument, 0, 'm'
|
||||||
|
}
|
||||||
|
,
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
@ -608,7 +621,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv)
|
|||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
int opt = wgetopt_long(argc,
|
int opt = wgetopt_long(argc,
|
||||||
argv,
|
argv,
|
||||||
L"aehkKf",
|
L"aehkKfM:m:",
|
||||||
long_options,
|
long_options,
|
||||||
&opt_index);
|
&opt_index);
|
||||||
|
|
||||||
@ -636,7 +649,6 @@ static int builtin_bind(parser_t &parser, wchar_t **argv)
|
|||||||
mode = BIND_ERASE;
|
mode = BIND_ERASE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||||
return STATUS_BUILTIN_OK;
|
return STATUS_BUILTIN_OK;
|
||||||
@ -653,10 +665,19 @@ static int builtin_bind(parser_t &parser, wchar_t **argv)
|
|||||||
mode = BIND_FUNCTION_NAMES;
|
mode = BIND_FUNCTION_NAMES;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'M':
|
||||||
|
bind_mode = woptarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
new_bind_mode = woptarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
|
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
|
||||||
return STATUS_BUILTIN_ERROR;
|
return STATUS_BUILTIN_ERROR;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -682,7 +703,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv)
|
|||||||
|
|
||||||
case 2:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,6 +742,34 @@ static int builtin_bind(parser_t &parser, wchar_t **argv)
|
|||||||
return res;
|
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
|
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"begin", &builtin_begin, N_(L"Create a block of code") },
|
||||||
{ L"bg", &builtin_bg, N_(L"Send job to background") },
|
{ L"bg", &builtin_bg, N_(L"Send job to background") },
|
||||||
{ L"bind", &builtin_bind, N_(L"Handle fish key bindings") },
|
{ 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"block", &builtin_block, N_(L"Temporarily block delivery of events") },
|
||||||
{ L"break", &builtin_break_continue, N_(L"Stop the innermost loop") },
|
{ 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") },
|
{ 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>
|
#include <vector>
|
||||||
|
|
||||||
#define DEFAULT_TERM L"ansi"
|
#define DEFAULT_TERM L"ansi"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Struct representing a keybinding. Returned by input_get_mappings.
|
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 seq; /**< Character sequence which generates this event */
|
||||||
wcstring command; /**< command that should be evaluated by this mapping */
|
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,
|
||||||
input_mapping_t(const wcstring &s, const wcstring &c) : seq(s), command(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 */
|
/** Mappings for the current input mode */
|
||||||
static std::vector<input_mapping_t> mapping_list;
|
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 */
|
/* Terminfo map list */
|
||||||
static std::vector<terminfo_mapping_t> terminfo_mappings;
|
static std::vector<terminfo_mapping_t> terminfo_mappings;
|
||||||
|
|
||||||
@ -248,28 +253,55 @@ static bool is_init = false;
|
|||||||
*/
|
*/
|
||||||
static void input_terminfo_init();
|
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.
|
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(sequence,);
|
||||||
CHECK(command,);
|
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++)
|
for (size_t i=0; i<mapping_list.size(); i++)
|
||||||
{
|
{
|
||||||
input_mapping_t &m = mapping_list.at(i);
|
input_mapping_t &m = mapping_list.at(i);
|
||||||
if (m.seq == sequence)
|
if (m.seq == sequence && m.mode == mode)
|
||||||
{
|
{
|
||||||
m.command = command;
|
m.command = command;
|
||||||
|
m.new_mode = new_mode;
|
||||||
return;
|
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++)
|
for (i=0; i<mapping_list.size(); i++)
|
||||||
{
|
{
|
||||||
const input_mapping_t &m = mapping_list.at(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);
|
wint_t res = input_try_mapping(m);
|
||||||
if (res)
|
if (res)
|
||||||
|
{
|
||||||
|
input_set_bind_mode(m.new_mode.c_str());
|
||||||
return res;
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
if (m.seq.length() == 0)
|
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();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
@ -600,7 +641,7 @@ bool input_mapping_erase(const wchar_t *sequence)
|
|||||||
for (i=0; i<sz; i++)
|
for (i=0; i<sz; i++)
|
||||||
{
|
{
|
||||||
const input_mapping_t &m = mapping_list.at(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))
|
if (i != (sz-1))
|
||||||
{
|
{
|
||||||
@ -615,7 +656,7 @@ bool input_mapping_erase(const wchar_t *sequence)
|
|||||||
return result;
|
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();
|
size_t i, sz = mapping_list.size();
|
||||||
|
|
||||||
@ -625,6 +666,7 @@ bool input_mapping_get(const wcstring &sequence, wcstring &cmd)
|
|||||||
if (sequence == m.seq)
|
if (sequence == m.seq)
|
||||||
{
|
{
|
||||||
cmd = m.command;
|
cmd = m.command;
|
||||||
|
mode = m.mode;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
input.h
21
input.h
@ -11,6 +11,9 @@ inputrc information for key bindings.
|
|||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include "input_common.h"
|
#include "input_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFAULT_BIND_MODE L"default"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Key codes for inputrc-style keyboard functions that are passed on
|
Key codes for inputrc-style keyboard functions that are passed on
|
||||||
to the caller of input_read()
|
to the caller of input_read()
|
||||||
@ -102,7 +105,9 @@ void input_unreadch(wint_t ch);
|
|||||||
\param sequence the sequence to bind
|
\param sequence the sequence to bind
|
||||||
\param command an input function that will be run whenever the key sequence occurs
|
\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
|
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
|
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.
|
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.
|
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…
x
Reference in New Issue
Block a user