mirror of
https://github.com/tstack/lnav.git
synced 2024-08-16 16:30:25 +03:00
parent
99c6aabfdd
commit
5b88dbd162
1
NEWS.md
1
NEWS.md
@ -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(¤t_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",
|
||||
|
16
src/lnav.cc
16
src/lnav.cc
@ -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);
|
||||
break;
|
||||
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…
Reference in New Issue
Block a user