[keymap] handle invalid command better

Related to #1258
master
Tim Stack 2 weeks ago
parent 99c6aabfdd
commit 5b88dbd162

@ -90,6 +90,7 @@ Interface changes:
can now hide/show fields by moving the cursor line to the
given field and pressing the space bar or by clicking on
the diamond with the mouse.
* The `sv` keymap binds `§` to focus the breadcrumb bar.
Bug Fixes:
* With the recent xz backdoor shenanigans, it seems like a good

@ -803,7 +803,7 @@
"title": "/ui/keymap-defs/<keymap_name>/<key_seq>/command",
"description": "The command to execute for the given key sequence. Use a script to execute more complicated operations.",
"type": "string",
"pattern": "^[:|;].*",
"pattern": "^$|^[:|;].*",
"examples": [
":goto next hour"
]

@ -785,6 +785,17 @@ execute_from_file(exec_context& ec,
Result<std::string, lnav::console::user_message>
execute_any(exec_context& ec, const std::string& cmdline_with_mode)
{
if (cmdline_with_mode.empty()) {
auto um = lnav::console::user_message::error("empty command")
.with_help(
"a command should start with ':', ';', '/', '|' and "
"followed by the operation to perform");
if (!ec.ec_source.empty()) {
um.with_snippet(ec.ec_source.back());
}
return Err(um);
}
std::string retval, alt_msg, cmdline = cmdline_with_mode.substr(1);
auto _cleanup = finally([&ec] {
if (ec.is_read_write() &&

@ -166,8 +166,12 @@ handle_keyseq(const char* keyseq)
vars["keyseq"] = keyseq;
const auto& kc = iter->second;
log_debug("executing key sequence %s: %s", keyseq, kc.kc_cmd.c_str());
auto result = execute_any(ec, kc.kc_cmd);
log_debug(
"executing key sequence %s: %s", keyseq, kc.kc_cmd.pp_value.c_str());
auto sg = ec.enter_source(kc.kc_cmd.pp_location.sl_source,
kc.kc_cmd.pp_location.sl_line_number,
kc.kc_cmd.pp_value);
auto result = execute_any(ec, kc.kc_cmd.pp_value);
if (result.isOk()) {
lnav_data.ld_rl_view->set_value(result.unwrap());
} else {
@ -194,7 +198,7 @@ handle_keyseq(const char* keyseq)
}
bool
handle_paging_key(int ch)
handle_paging_key(int ch, const char* keyseq)
{
if (lnav_data.ld_view_stack.empty()) {
return false;
@ -211,8 +215,7 @@ handle_paging_key(int ch)
}
}
auto keyseq = fmt::format(FMT_STRING("x{:02x}"), ch);
if (handle_keyseq(keyseq.c_str())) {
if (handle_keyseq(keyseq)) {
return true;
}

@ -31,6 +31,6 @@
#define LNAV_HOTKEYS_H
bool handle_keyseq(const char* keyseq);
bool handle_paging_key(int ch);
bool handle_paging_key(int ch, const char* keyseq);
#endif // LNAV_HOTKEYS_H

@ -102,8 +102,12 @@ input_dispatcher::new_input(const struct timeval& current_time, int ch)
for (int lpc = 0; this->id_escape_buffer[lpc];
lpc++)
{
snprintf(keyseq.data(),
keyseq.size(),
"x%02x",
this->id_escape_buffer[lpc] & 0xff);
handled = this->id_key_handler(
this->id_escape_buffer[lpc]);
this->id_escape_buffer[lpc], keyseq.data());
}
this->id_escape_index = 0;
break;
@ -121,6 +125,13 @@ input_dispatcher::new_input(const struct timeval& current_time, int ch)
{
this->id_escape_index = 0;
}
} else if (ch > 0xff) {
if (KEY_F(0) <= ch && ch <= KEY_F(64)) {
snprintf(keyseq.data(), keyseq.size(), "f%d", ch - KEY_F0);
} else {
snprintf(keyseq.data(), keyseq.size(), "n%04o", ch);
}
handled = this->id_key_handler(ch, keyseq.data());
} else {
auto seq_size = utf::utf8::char_size([ch]() {
return std::make_pair(ch, 16);
@ -128,7 +139,7 @@ input_dispatcher::new_input(const struct timeval& current_time, int ch)
if (seq_size == 1) {
snprintf(keyseq.data(), keyseq.size(), "x%02x", ch & 0xff);
handled = this->id_key_handler(ch);
handled = this->id_key_handler(ch, keyseq.data());
} else {
this->reset_escape_buffer(ch, current_time, seq_size);
}
@ -150,7 +161,8 @@ input_dispatcher::poll(const struct timeval& current_time)
timersub(&current_time, &this->id_escape_start_time, &diff);
if (escape_threshold < diff) {
this->id_key_handler(KEY_ESCAPE);
static const char ESC_KEYSEQ[] = "\x1b";
this->id_key_handler(KEY_ESCAPE, ESC_KEYSEQ);
this->id_escape_index = 0;
}
}

@ -53,7 +53,7 @@ public:
};
std::function<escape_match_t(const char*)> id_escape_matcher;
std::function<bool(int)> id_key_handler;
std::function<bool(int, const char*)> id_key_handler;
std::function<void(const char*)> id_escape_handler;
std::function<void()> id_mouse_handler;
std::function<void(const char*)> id_unhandled_handler;

@ -22,7 +22,8 @@
"command": ";UPDATE lnav_views SET paused = 1 - paused"
},
"x60": {
"id": ""
"id": "",
"command": ":prompt breadcrumb"
},
"xc2xa7": {
"id": "org.lnav.key.breadcrumb.focus",

@ -367,7 +367,7 @@ sigchld(int sig)
}
static void
handle_rl_key(int ch)
handle_rl_key(int ch, const char* keyseq)
{
switch (ch) {
case KEY_F(2):
@ -379,7 +379,7 @@ handle_rl_key(int ch)
case KEY_PPAGE:
case KEY_NPAGE:
case KEY_CTRL('p'):
handle_paging_key(ch);
handle_paging_key(ch, keyseq);
break;
case KEY_CTRL(']'):
@ -675,7 +675,7 @@ update_view_position(listview_curses* lv)
}
static bool
handle_config_ui_key(int ch)
handle_config_ui_key(int ch, const char* keyseq)
{
bool retval = false;
@ -730,14 +730,14 @@ handle_config_ui_key(int ch)
lnav_data.ld_filter_view.reload_data();
lnav_data.ld_status[LNS_FILTER].set_needs_update();
} else {
return handle_paging_key(ch);
return handle_paging_key(ch, keyseq);
}
return true;
}
static bool
handle_key(int ch)
handle_key(int ch, const char* keyseq)
{
static auto* breadcrumb_view = injector::get<breadcrumb_curses*>();
@ -749,7 +749,7 @@ handle_key(int ch)
default: {
switch (lnav_data.ld_mode) {
case ln_mode_t::PAGING:
return handle_paging_key(ch);
return handle_paging_key(ch, keyseq);
case ln_mode_t::BREADCRUMBS:
if (ch == '`' || !breadcrumb_view->handle_key(ch)) {
@ -761,7 +761,7 @@ handle_key(int ch)
case ln_mode_t::FILTER:
case ln_mode_t::FILES:
return handle_config_ui_key(ch);
return handle_config_ui_key(ch, keyseq);
case ln_mode_t::SPECTRO_DETAILS: {
if (ch == '\t' || ch == 'q') {
@ -800,7 +800,7 @@ handle_key(int ch)
case ln_mode_t::SQL:
case ln_mode_t::EXEC:
case ln_mode_t::USER:
handle_rl_key(ch);
handle_rl_key(ch, keyseq);
break;
case ln_mode_t::BUSY:

@ -5971,9 +5971,7 @@ readline_context::command_t STD_COMMANDS[] = {
"The initial value to fill in for the prompt")
.optional())
.with_example({
"To open the command prompt with 'filter-in' already "
"filled "
"in",
"To open the command prompt with 'filter-in' already filled in",
"command : 'filter-in '",
})
.with_example({

@ -498,7 +498,7 @@ static const struct json_path_container key_command_handlers = {
.with_description(
"The command to execute for the given key sequence. Use a script "
"to execute more complicated operations.")
.with_pattern("^[:|;].*")
.with_pattern("^$|^[:|;].*")
.with_example(":goto next hour")
.for_field(&key_command::kc_cmd),
yajlpp::property_handler("alt-msg")
@ -520,6 +520,14 @@ static const struct json_path_container keymap_def_handlers = {
[](const yajlpp_provider_context& ypc, key_map* km) {
auto& retval = km->km_seq_to_cmd[ypc.get_substr("key_seq")];
if (ypc.ypc_parse_context != nullptr) {
retval.kc_cmd.pp_path
= ypc.ypc_parse_context->get_full_path();
retval.kc_cmd.pp_location.sl_source
= ypc.ypc_parse_context->ypc_source;
retval.kc_cmd.pp_location.sl_line_number
= ypc.ypc_parse_context->get_line_number();
}
return &retval;
})
.with_path_provider<key_map>(
@ -1570,8 +1578,12 @@ public:
for (const auto& pair :
lnav_config.lc_ui_keymaps[lnav_config.lc_ui_keymap].km_seq_to_cmd)
{
lnav_config.lc_active_keymap.km_seq_to_cmd[pair.first]
= pair.second;
if (pair.second.kc_cmd.pp_value.empty()) {
lnav_config.lc_active_keymap.km_seq_to_cmd.erase(pair.first);
} else {
lnav_config.lc_active_keymap.km_seq_to_cmd[pair.first]
= pair.second;
}
}
auto& ec = injector::get<exec_context&>();
@ -1580,31 +1592,52 @@ public:
continue;
}
auto keyseq_sf = string_fragment::from_str(pair.first);
std::string keystr;
auto sv = string_fragment::from_str(pair.first).to_string_view();
while (!sv.empty()) {
if (keyseq_sf.startswith("f")) {
auto sv = keyseq_sf.to_string_view();
int32_t value;
auto scan_res = scn::scan(sv, "x{:2x}", value);
auto scan_res = scn::scan(sv, "f{}", value);
if (!scan_res) {
throw "invalid hex input";
log_error("invalid function key sequence: %s", keyseq_sf);
continue;
}
auto ch = (char) (value & 0xff);
switch (ch) {
case '\t':
keystr.append("TAB");
break;
case '\r':
keystr.append("ENTER");
break;
default:
keystr.push_back(ch);
if (value < 0 || value > 64) {
log_error("invalid function key number: %s", keyseq_sf);
continue;
}
keystr = toupper(pair.first);
} else {
auto sv
= string_fragment::from_str(pair.first).to_string_view();
while (!sv.empty()) {
int32_t value;
auto scan_res = scn::scan(sv, "x{:2x}", value);
if (!scan_res) {
log_error("invalid key sequence: %s",
pair.first.c_str());
break;
}
auto ch = (char) (value & 0xff);
switch (ch) {
case '\t':
keystr.append("TAB");
break;
case '\r':
keystr.append("ENTER");
break;
default:
keystr.push_back(ch);
break;
}
sv = scan_res.range_as_string_view();
}
sv = scan_res.range_as_string_view();
}
ec.ec_global_vars[pair.second.kc_id] = keystr;
if (!keystr.empty()) {
ec.ec_global_vars[pair.second.kc_id] = keystr;
}
}
}
};
@ -1908,7 +1941,7 @@ save_config()
void
reload_config(std::vector<lnav::console::user_message>& errors)
{
lnav_config_listener* curr = lnav_config_listener::LISTENER_LIST;
auto* curr = lnav_config_listener::LISTENER_LIST;
while (curr != nullptr) {
auto reporter = [&errors](const void* cfg_value,

@ -81,7 +81,7 @@ void install_extra_formats();
struct key_command {
std::string kc_id;
std::string kc_cmd;
positioned_property<std::string> kc_cmd;
std::string kc_alt_msg;
};

@ -5118,7 +5118,7 @@
},
"x60": {
"id": "",
"command": "",
"command": ":prompt breadcrumb",
"alt-msg": ""
},
"xc2xa4": {

@ -155,10 +155,11 @@
/ui/keymap-defs/sv/x26/command -> sv-keymap.json:16
/ui/keymap-defs/sv/x2b/command -> sv-keymap.json:22
/ui/keymap-defs/sv/x3d/command -> sv-keymap.json:19
/ui/keymap-defs/sv/x60/command -> sv-keymap.json:26
/ui/keymap-defs/sv/x60/id -> sv-keymap.json:25
/ui/keymap-defs/sv/xc2xa4/command -> sv-keymap.json:10
/ui/keymap-defs/sv/xc2xa7/command -> sv-keymap.json:29
/ui/keymap-defs/sv/xc2xa7/id -> sv-keymap.json:28
/ui/keymap-defs/sv/xc2xa7/command -> sv-keymap.json:30
/ui/keymap-defs/sv/xc2xa7/id -> sv-keymap.json:29
/ui/keymap-defs/sv/xe2x82xac/command -> sv-keymap.json:13
/ui/keymap-defs/uk/x22/command -> uk-keymap.json:7
/ui/keymap-defs/uk/xc2xa3/command -> uk-keymap.json:10

Loading…
Cancel
Save