diff options
Diffstat (limited to '')
-rw-r--r-- | src/breadcrumb_curses.cc | 278 |
1 files changed, 180 insertions, 98 deletions
diff --git a/src/breadcrumb_curses.cc b/src/breadcrumb_curses.cc index 6481e6b..6232221 100644 --- a/src/breadcrumb_curses.cc +++ b/src/breadcrumb_curses.cc @@ -31,15 +31,19 @@ #include "base/itertools.hh" #include "itertools.similar.hh" -#include "log_format_fwd.hh" -#include "logfile.hh" using namespace lnav::roles::literals; +void +breadcrumb_curses::no_op_action(breadcrumb_curses&) +{ +} + breadcrumb_curses::breadcrumb_curses() { this->bc_match_search_overlay.sos_parent = this; this->bc_match_source.set_reverse_selection(true); + this->bc_match_view.set_title("breadcrumb popup"); this->bc_match_view.set_selectable(true); this->bc_match_view.set_overlay_source(&this->bc_match_search_overlay); this->bc_match_view.set_sub_source(&this->bc_match_source); @@ -49,11 +53,11 @@ breadcrumb_curses::breadcrumb_curses() this->add_child_view(&this->bc_match_view); } -void +bool breadcrumb_curses::do_update() { if (!this->bc_line_source) { - return; + return false; } size_t crumb_index = 0; @@ -66,44 +70,49 @@ breadcrumb_curses::do_update() { this->bc_last_selected_crumb = crumbs.size() - 1; } + this->bc_displayed_crumbs.clear(); attr_line_t crumbs_line; for (const auto& crumb : crumbs) { - auto accum_width - = utf8_string_length(crumbs_line.get_string()).template unwrap(); - auto elem_width = utf8_string_length(crumb.c_display_value.get_string()) - .template unwrap(); + auto accum_width = crumbs_line.column_width(); + auto elem_width = crumb.c_display_value.column_width(); auto is_selected = this->bc_selected_crumb && (crumb_index == this->bc_selected_crumb.value()); if (is_selected && ((accum_width + elem_width) > width)) { crumbs_line.clear(); - crumbs_line.append("\u22ef\u276d"_breadcrumb); + crumbs_line.append("\u22ef\uff1a"_breadcrumb); accum_width = 2; } + line_range crumb_range; + crumb_range.lr_start = (int) crumbs_line.length(); crumbs_line.append(crumb.c_display_value); + crumb_range.lr_end = (int) crumbs_line.length(); if (is_selected) { sel_crumb_offset = accum_width; crumbs_line.get_attrs().emplace_back( - line_range{ - (int) (crumbs_line.length() - - crumb.c_display_value.length()), - (int) crumbs_line.length(), - }, - VC_STYLE.template value(text_attrs{A_REVERSE})); + crumb_range, VC_STYLE.template value(text_attrs{A_REVERSE})); } + + this->bc_displayed_crumbs.emplace_back( + line_range{(int) accum_width, + (int) (accum_width + elem_width), + line_range::unit::codepoint}, + crumb_index); crumb_index += 1; - crumbs_line.append("\u276d"_breadcrumb); + crumbs_line.append(" \uff1a"_breadcrumb); } line_range lr{0, static_cast<int>(width)}; view_curses::mvwattrline( - this->bc_window, this->bc_y, 0, crumbs_line, lr, role_t::VCR_STATUS); + this->bc_window, this->vc_y, 0, crumbs_line, lr, role_t::VCR_STATUS); if (this->bc_selected_crumb) { this->bc_match_view.set_x(sel_crumb_offset); } view_curses::do_update(); + + return true; } void @@ -123,13 +132,7 @@ breadcrumb_curses::reload_data() [](const auto& elem) { return elem.p_key; }, this->bc_current_search, 128) - | lnav::itertools::sort_with([](const auto& lhs, const auto& rhs) { - return strnatcasecmp(lhs.p_key.size(), - lhs.p_key.data(), - rhs.p_key.size(), - rhs.p_key.data()) - < 0; - }); + | lnav::itertools::sort_with(breadcrumb::possibility::sort_cmp); if (selected_crumb_ref.c_key.is<std::string>() && selected_crumb_ref.c_expected_input != breadcrumb::crumb::expected_input_t::anything) @@ -175,6 +178,9 @@ breadcrumb_curses::reload_data() this->bc_match_view.set_needs_update(); this->bc_match_view.set_selection( vis_line_t(selected_value.value_or(-1_vl))); + if (selected_value) { + this->bc_match_view.set_top(vis_line_t(selected_value.value())); + } this->bc_match_view.reload_data(); this->set_needs_update(); } @@ -182,6 +188,7 @@ breadcrumb_curses::reload_data() void breadcrumb_curses::focus() { + this->bc_match_view.set_y(this->vc_y + 1); this->bc_focused_crumbs = this->bc_line_source(); if (this->bc_focused_crumbs.empty()) { return; @@ -217,7 +224,7 @@ breadcrumb_curses::handle_key(int ch) bool retval = false; switch (ch) { - case KEY_CTRL_A: + case KEY_CTRL('a'): if (this->bc_selected_crumb) { this->bc_selected_crumb = 0; this->bc_current_search.clear(); @@ -225,7 +232,7 @@ breadcrumb_curses::handle_key(int ch) } retval = true; break; - case KEY_CTRL_E: + case KEY_CTRL('e'): if (this->bc_selected_crumb) { this->bc_selected_crumb = this->bc_focused_crumbs.size() - 1; this->bc_current_search.clear(); @@ -278,22 +285,26 @@ breadcrumb_curses::handle_key(int ch) retval = true; break; case KEY_NPAGE: - this->bc_match_view.shift_selection(3); + this->bc_match_view.shift_selection( + listview_curses::shift_amount_t::down_page); retval = true; break; case KEY_PPAGE: - this->bc_match_view.shift_selection(-3); + this->bc_match_view.shift_selection( + listview_curses::shift_amount_t::up_page); retval = true; break; case KEY_UP: - this->bc_match_view.shift_selection(-1); + this->bc_match_view.shift_selection( + listview_curses::shift_amount_t::up_line); retval = true; break; case KEY_DOWN: - this->bc_match_view.shift_selection(1); + this->bc_match_view.shift_selection( + listview_curses::shift_amount_t::down_line); retval = true; break; - case 0x7f: + case KEY_DELETE: case KEY_BACKSPACE: if (!this->bc_current_search.empty()) { this->bc_current_search.pop_back(); @@ -305,6 +316,8 @@ breadcrumb_curses::handle_key(int ch) case '\r': this->perform_selection(perform_behavior_t::always); break; + case KEY_ESCAPE: + break; default: if (isprint(ch)) { this->bc_current_search.push_back(ch); @@ -371,40 +384,55 @@ breadcrumb_curses::perform_selection( } bool -breadcrumb_curses::search_overlay_source::list_value_for_overlay( - const listview_curses& lv, - int y, - int bottom, - vis_line_t line, - attr_line_t& value_out) +breadcrumb_curses::search_overlay_source::list_static_overlay( + const listview_curses& lv, int y, int bottom, attr_line_t& value_out) { - if (y == 0) { - auto* parent = this->sos_parent; - auto sel_opt = parent->bc_focused_crumbs - | lnav::itertools::nth(parent->bc_selected_crumb); - auto exp_input = sel_opt - | lnav::itertools::map(&breadcrumb::crumb::c_expected_input) - | lnav::itertools::unwrap_or( - breadcrumb::crumb::expected_input_t::exact); - - value_out.with_attr_for_all(VC_STYLE.value(text_attrs{A_UNDERLINE})); - - if (!parent->bc_current_search.empty()) { - value_out = parent->bc_current_search; - - role_t combobox_role = role_t::VCR_STATUS; - switch (exp_input) { - case breadcrumb::crumb::expected_input_t::exact: - if (parent->bc_similar_values.empty()) { - combobox_role = role_t::VCR_ALERT_STATUS; - } - break; - case breadcrumb::crumb::expected_input_t::index: { - size_t index; + if (y != 0) { + return false; + } + auto* parent = this->sos_parent; + auto sel_opt = parent->bc_focused_crumbs + | lnav::itertools::nth(parent->bc_selected_crumb); + auto exp_input = sel_opt + | lnav::itertools::map(&breadcrumb::crumb::c_expected_input) + | lnav::itertools::unwrap_or( + breadcrumb::crumb::expected_input_t::exact); + + value_out.with_attr_for_all(VC_STYLE.value(text_attrs{A_UNDERLINE})); - if (sscanf(parent->bc_current_search.c_str(), "%zu", &index) - != 1 - || index < 0 + if (!parent->bc_current_search.empty()) { + value_out = parent->bc_current_search; + + role_t combobox_role = role_t::VCR_STATUS; + switch (exp_input) { + case breadcrumb::crumb::expected_input_t::exact: + if (parent->bc_similar_values.empty()) { + combobox_role = role_t::VCR_ALERT_STATUS; + } + break; + case breadcrumb::crumb::expected_input_t::index: { + size_t index; + + if (sscanf(parent->bc_current_search.c_str(), "%zu", &index) + != 1 + || index < 0 + || (index + >= (sel_opt | lnav::itertools::map([](const auto& cr) { + return cr->c_possible_range.value_or(0); + }) + | lnav::itertools::unwrap_or(size_t{0})))) + { + combobox_role = role_t::VCR_ALERT_STATUS; + } + break; + } + case breadcrumb::crumb::expected_input_t::index_or_exact: { + size_t index; + + if (sscanf(parent->bc_current_search.c_str(), "%zu", &index) + == 1) + { + if (index < 0 || (index >= (sel_opt | lnav::itertools::map([](const auto& cr) { @@ -414,48 +442,102 @@ breadcrumb_curses::search_overlay_source::list_value_for_overlay( { combobox_role = role_t::VCR_ALERT_STATUS; } - break; + } else if (parent->bc_similar_values.empty()) { + combobox_role = role_t::VCR_ALERT_STATUS; } - case breadcrumb::crumb::expected_input_t::index_or_exact: { - size_t index; - - if (sscanf(parent->bc_current_search.c_str(), "%zu", &index) - == 1) - { - if (index < 0 - || (index - >= (sel_opt - | lnav::itertools::map([](const auto& cr) { - return cr->c_possible_range.value_or( - 0); - }) - | lnav::itertools::unwrap_or(size_t{0})))) - { - combobox_role = role_t::VCR_ALERT_STATUS; - } - } else if (parent->bc_similar_values.empty()) { - combobox_role = role_t::VCR_ALERT_STATUS; - } - break; - } - case breadcrumb::crumb::expected_input_t::anything: - break; + break; } - value_out.with_attr_for_all(VC_ROLE.value(combobox_role)); + case breadcrumb::crumb::expected_input_t::anything: + break; + } + value_out.with_attr_for_all(VC_ROLE.value(combobox_role)); + return true; + } + if (parent->bc_selected_crumb) { + auto& selected_crumb_ref + = parent->bc_focused_crumbs[parent->bc_selected_crumb.value()]; + + if (!selected_crumb_ref.c_search_placeholder.empty()) { + value_out = selected_crumb_ref.c_search_placeholder; + value_out.with_attr_for_all( + VC_ROLE.value(role_t::VCR_INACTIVE_STATUS)); return true; } - if (parent->bc_selected_crumb) { - auto& selected_crumb_ref - = parent->bc_focused_crumbs[parent->bc_selected_crumb.value()]; - - if (!selected_crumb_ref.c_search_placeholder.empty()) { - value_out = selected_crumb_ref.c_search_placeholder; - value_out.with_attr_for_all( - VC_ROLE.value(role_t::VCR_INACTIVE_STATUS)); + } + + return false; +} + +bool +breadcrumb_curses::handle_mouse(mouse_event& me) +{ + if (me.me_state == mouse_button_state_t::BUTTON_STATE_PRESSED + && this->bc_focused_crumbs.empty()) + { + this->focus(); + this->on_focus(*this); + this->do_update(); + } + + auto find_res = this->bc_displayed_crumbs + | lnav::itertools::find_if([&me](const auto& elem) { + return me.me_button == mouse_button_t::BUTTON_LEFT + && elem.dc_range.contains(me.me_x); + }); + + if (!this->bc_focused_crumbs.empty()) { + if (me.me_y > 0 || !find_res + || find_res.value()->dc_index == this->bc_selected_crumb) + { + if (view_curses::handle_mouse(me)) { + if (me.me_y > 0 + && (me.me_state + == mouse_button_state_t::BUTTON_STATE_DOUBLE_CLICK + || me.me_state + == mouse_button_state_t::BUTTON_STATE_RELEASED)) + { + this->perform_selection(perform_behavior_t::if_different); + this->blur(); + this->reload_data(); + this->on_blur(*this); + this->bc_initial_mouse_event = true; + } return true; } } + if (!this->bc_initial_mouse_event + && me.me_state == mouse_button_state_t::BUTTON_STATE_RELEASED + && me.me_y == 0 && find_res + && find_res.value()->dc_index == this->bc_selected_crumb.value()) + { + this->blur(); + this->reload_data(); + this->on_blur(*this); + this->bc_initial_mouse_event = true; + return true; + } } - return false; + if (me.me_state == mouse_button_state_t::BUTTON_STATE_RELEASED) { + this->bc_initial_mouse_event = false; + } + + if (me.me_y != 0) { + return true; + } + + if (find_res) { + auto crumb_index = find_res.value()->dc_index; + + if (this->bc_selected_crumb) { + this->blur(); + this->focus(); + this->reload_data(); + this->bc_selected_crumb = crumb_index; + this->bc_current_search.clear(); + this->reload_data(); + } + } + + return true; } |