mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-18 12:01:16 -03:00
Add separation of "preset" bindings
This allows for marking certain bindings as part of a preset, which allows us to - only erase those when switching presets - go back to the preset binding when erasing a user binding - only show user customization if requested - make bare bind statements in config.fish work (!!!11elf!!!) Fixes #5191. Fixes #3699.
This commit is contained in:
102
src/input.cpp
102
src/input.cpp
@@ -142,6 +142,7 @@ wcstring describe_char(wint_t c) {
|
||||
|
||||
/// Mappings for the current input mode.
|
||||
static std::vector<input_mapping_t> mapping_list;
|
||||
static std::vector<input_mapping_t> preset_mapping_list;
|
||||
|
||||
/// Terminfo map list.
|
||||
static std::vector<terminfo_mapping_t> terminfo_mappings;
|
||||
@@ -205,15 +206,17 @@ static bool specification_order_is_less_than(const input_mapping_t &m1, const in
|
||||
|
||||
/// Inserts an input mapping at the correct position. We sort them in descending order by length, so
|
||||
/// that we test longer sequences first.
|
||||
static void input_mapping_insert_sorted(const input_mapping_t &new_mapping) {
|
||||
static void input_mapping_insert_sorted(const input_mapping_t &new_mapping, bool user = true) {
|
||||
auto& ml = user ? mapping_list : preset_mapping_list;
|
||||
|
||||
std::vector<input_mapping_t>::iterator loc = std::lower_bound(
|
||||
mapping_list.begin(), mapping_list.end(), new_mapping, length_is_greater_than);
|
||||
mapping_list.insert(loc, new_mapping);
|
||||
ml.begin(), ml.end(), new_mapping, length_is_greater_than);
|
||||
ml.insert(loc, new_mapping);
|
||||
}
|
||||
|
||||
/// Adds an input mapping.
|
||||
void input_mapping_add(const wchar_t *sequence, const wchar_t *const *commands, size_t commands_len,
|
||||
const wchar_t *mode, const wchar_t *sets_mode) {
|
||||
const wchar_t *mode, const wchar_t *sets_mode, bool user) {
|
||||
CHECK(sequence, );
|
||||
CHECK(commands, );
|
||||
CHECK(mode, );
|
||||
@@ -226,8 +229,10 @@ void input_mapping_add(const wchar_t *sequence, const wchar_t *const *commands,
|
||||
// Remove existing mappings with this sequence.
|
||||
const wcstring_list_t commands_vector(commands, commands + commands_len);
|
||||
|
||||
for (size_t i = 0; i < mapping_list.size(); i++) {
|
||||
input_mapping_t &m = mapping_list.at(i);
|
||||
auto& ml = user ? mapping_list : preset_mapping_list;
|
||||
|
||||
for (size_t i = 0; i < ml.size(); i++) {
|
||||
input_mapping_t &m = ml.at(i);
|
||||
if (m.seq == sequence && m.mode == mode) {
|
||||
m.commands = commands_vector;
|
||||
m.sets_mode = sets_mode;
|
||||
@@ -237,12 +242,12 @@ void input_mapping_add(const wchar_t *sequence, const wchar_t *const *commands,
|
||||
|
||||
// Add a new mapping, using the next order.
|
||||
const input_mapping_t new_mapping = input_mapping_t(sequence, commands_vector, mode, sets_mode);
|
||||
input_mapping_insert_sorted(new_mapping);
|
||||
input_mapping_insert_sorted(new_mapping, user);
|
||||
}
|
||||
|
||||
void input_mapping_add(const wchar_t *sequence, const wchar_t *command, const wchar_t *mode,
|
||||
const wchar_t *sets_mode) {
|
||||
input_mapping_add(sequence, &command, 1, mode, sets_mode);
|
||||
const wchar_t *sets_mode, bool user) {
|
||||
input_mapping_add(sequence, &command, 1, mode, sets_mode, user);
|
||||
}
|
||||
|
||||
/// Handle interruptions to key reading by reaping finshed jobs and propagating the interrupt to the
|
||||
@@ -267,20 +272,20 @@ void init_input() {
|
||||
init_input_terminfo();
|
||||
|
||||
// If we have no keybindings, add a few simple defaults.
|
||||
if (mapping_list.empty()) {
|
||||
input_mapping_add(L"", L"self-insert");
|
||||
input_mapping_add(L"\n", L"execute");
|
||||
input_mapping_add(L"\r", L"execute");
|
||||
input_mapping_add(L"\t", L"complete");
|
||||
input_mapping_add(L"\x3", L"commandline ''");
|
||||
input_mapping_add(L"\x4", L"exit");
|
||||
input_mapping_add(L"\x5", L"bind");
|
||||
input_mapping_add(L"\x7f", L"backward-delete-char");
|
||||
if (preset_mapping_list.empty()) {
|
||||
input_mapping_add(L"", L"self-insert", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\n", L"execute", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\r", L"execute", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\t", L"complete", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\x3", L"commandline ''", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\x4", L"exit", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\x5", L"bind", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\x7f", L"backward-delete-char", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
// Arrows - can't have functions, so *-or-search isn't available.
|
||||
input_mapping_add(L"\x1B[A", L"up-line");
|
||||
input_mapping_add(L"\x1B[B", L"down-line");
|
||||
input_mapping_add(L"\x1B[C", L"forward-char");
|
||||
input_mapping_add(L"\x1B[D", L"backward-char");
|
||||
input_mapping_add(L"\x1B[A", L"up-line", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\x1B[B", L"down-line", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\x1B[C", L"forward-char", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
input_mapping_add(L"\x1B[D", L"backward-char", DEFAULT_BIND_MODE, DEFAULT_BIND_MODE, false);
|
||||
}
|
||||
|
||||
input_initialized = true;
|
||||
@@ -415,16 +420,8 @@ static void input_mapping_execute_matching_or_generic(bool allow_commands) {
|
||||
|
||||
const wcstring bind_mode = input_get_bind_mode();
|
||||
|
||||
for (size_t 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_string(m.seq.c_str(),
|
||||
// ESCAPE_ALL).c_str(),
|
||||
// m.mode.c_str(), m.sets_mode.c_str());
|
||||
|
||||
for (auto& m : mapping_list) {
|
||||
if (m.mode != bind_mode) {
|
||||
// debug(0, L"skipping mapping because mode %ls != %ls\n", m.mode.c_str(),
|
||||
// input_get_bind_mode().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -436,6 +433,21 @@ static void input_mapping_execute_matching_or_generic(bool allow_commands) {
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: This is ugly duplication.
|
||||
for (auto& m : preset_mapping_list) {
|
||||
if (m.mode != bind_mode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.seq.length() == 0) {
|
||||
// Only use this generic if the user list didn't have one.
|
||||
if (!generic) generic = &m;
|
||||
} else if (input_mapping_is_match(m)) {
|
||||
input_mapping_execute(m, allow_commands);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (generic) {
|
||||
input_mapping_execute(*generic, allow_commands);
|
||||
} else {
|
||||
@@ -515,10 +527,10 @@ wint_t input_readch(bool allow_commands) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<input_mapping_name_t> input_mapping_get_names() {
|
||||
std::vector<input_mapping_name_t> input_mapping_get_names(bool user) {
|
||||
// Sort the mappings by the user specification order, so we can return them in the same order
|
||||
// that the user specified them in.
|
||||
std::vector<input_mapping_t> local_list = mapping_list;
|
||||
std::vector<input_mapping_t> local_list = user ? mapping_list : preset_mapping_list;
|
||||
std::sort(local_list.begin(), local_list.end(), specification_order_is_less_than);
|
||||
std::vector<input_mapping_name_t> result;
|
||||
result.reserve(local_list.size());
|
||||
@@ -530,14 +542,25 @@ std::vector<input_mapping_name_t> input_mapping_get_names() {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool input_mapping_erase(const wcstring &sequence, const wcstring &mode) {
|
||||
void input_mapping_clear(const wchar_t *mode, bool user) {
|
||||
auto& ml = user ? mapping_list : preset_mapping_list;
|
||||
for (std::vector<input_mapping_t>::iterator it = ml.begin(), end = ml.end();
|
||||
it != end; ++it) {
|
||||
if (mode == NULL || mode == it->mode) {
|
||||
ml.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool input_mapping_erase(const wcstring &sequence, const wcstring &mode, bool user) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
bool result = false;
|
||||
|
||||
for (std::vector<input_mapping_t>::iterator it = mapping_list.begin(), end = mapping_list.end();
|
||||
auto& ml = user ? mapping_list : preset_mapping_list;
|
||||
for (std::vector<input_mapping_t>::iterator it = ml.begin(), end = ml.end();
|
||||
it != end; ++it) {
|
||||
if (sequence == it->seq && mode == it->mode) {
|
||||
mapping_list.erase(it);
|
||||
ml.erase(it);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
@@ -545,11 +568,12 @@ bool input_mapping_erase(const wcstring &sequence, const wcstring &mode) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool input_mapping_get(const wcstring &sequence, const wcstring &mode, wcstring_list_t *out_cmds,
|
||||
bool input_mapping_get(const wcstring &sequence, const wcstring &mode, wcstring_list_t *out_cmds, bool user,
|
||||
wcstring *out_sets_mode) {
|
||||
bool result = false;
|
||||
for (std::vector<input_mapping_t>::const_iterator it = mapping_list.begin(),
|
||||
end = mapping_list.end();
|
||||
auto& ml = user ? mapping_list : preset_mapping_list;
|
||||
for (std::vector<input_mapping_t>::const_iterator it = ml.begin(),
|
||||
end = ml.end();
|
||||
it != end; ++it) {
|
||||
if (sequence == it->seq && mode == it->mode) {
|
||||
*out_cmds = it->commands;
|
||||
|
||||
Reference in New Issue
Block a user