[mouse] missed adding the view left position to the X coord

pull/1265/head
Tim Stack 2 months ago
parent c3f6887f38
commit c465cc6d54

@ -1,6 +1,19 @@
## lnav v0.12.2 ## lnav v0.12.2
Features: Features:
* Added a `journald://` URL handler that will call `journalctl`
and pass any query parameters as options. For example, the
following command:
```
$ lnav 'journal://?since=yesterday'
```
Will execute the following and capture the output:
```
journalctl --output=json -f --since=yesterday
```
* Added the "last-word" line-format field shortening algorithm * Added the "last-word" line-format field shortening algorithm
from @flicus. from @flicus.
* Added a `stats.hist` PRQL transform that produces a histogram * Added a `stats.hist` PRQL transform that produces a histogram
@ -19,9 +32,9 @@ Features:
lines and then toggle their bookmark status on release; lines and then toggle their bookmark status on release;
- double-clicking will select the underlying token and - double-clicking will select the underlying token and
drag-selecting within a line will select the given text; drag-selecting within a line will select the given text;
- when text is selected: pressing `c` will copy the text to - when text is selected, a menu will pop up that can be used
the clipboard; the text will be used as the suggestion for to filter based on the current text, search for it, or copy
searching/filtering; it to the clipboard;
- clicking in the scroll area will move the view by a page and - clicking in the scroll area will move the view by a page and
dragging the scrollbar will move the view to the given spot; dragging the scrollbar will move the view to the given spot;
- clicking on the breadcrumb bar will select a crumb and - clicking on the breadcrumb bar will select a crumb and

@ -432,9 +432,9 @@ elements will respond to mouse inputs:
lines and then toggle their bookmark status on release; lines and then toggle their bookmark status on release;
* double-clicking will select the underlying token and * double-clicking will select the underlying token and
drag-selecting within a line will select the given text; drag-selecting within a line will select the given text;
* with selected text, pressing :kbd:`c` will copy the text to * when text is selected, a menu will pop up that can be used
the clipboard and it will be used as the suggestion for to filter based on the current text, search for it, or copy
searching/filtering; it to the clipboard;
* clicking in the scroll area will move the view by a page and * clicking in the scroll area will move the view by a page and
dragging the scrollbar will move the view to the given spot; dragging the scrollbar will move the view to the given spot;
* clicking on the breadcrumb bar will select a crumb and * clicking on the breadcrumb bar will select a crumb and
@ -457,7 +457,14 @@ elements will respond to mouse inputs:
still likely to be cases where that is insufficient. still likely to be cases where that is insufficient.
In those cases, you can press :kbd:`F2` to quickly In those cases, you can press :kbd:`F2` to quickly
switch back-and-forth. Or, some terminals have support switch back-and-forth. Or, some terminals have support
for switching using a modifier key, like for switching while a modifier is pressed:
`iTerm <https://iterm2.com/documentation-preferences-profiles-terminal.html>_`
where pressing :kbd:`Option` will allow you to select .. list-table::
text and copy. :header-rows: 1
* - Key
- Terminal
* - :kbd:`Option`
- iTerm, Hyper
* - :kbd:`Fn`
- Terminal.app

@ -575,6 +575,13 @@ inline std::pair<std::string, string_attr_pair> operator"" _info(
VC_ROLE.template value(role_t::VCR_INFO)); VC_ROLE.template value(role_t::VCR_INFO));
} }
inline std::pair<std::string, string_attr_pair> operator"" _status_title(
const char* str, std::size_t len)
{
return std::make_pair(std::string(str, len),
VC_ROLE.template value(role_t::VCR_STATUS_TITLE));
}
inline std::pair<std::string, string_attr_pair> operator"" _symbol( inline std::pair<std::string, string_attr_pair> operator"" _symbol(
const char* str, std::size_t len) const char* str, std::size_t len)
{ {

@ -130,8 +130,7 @@ public:
static const char* token2name(data_token_t token); static const char* token2name(data_token_t token);
struct capture_t { struct capture_t {
capture_t() capture_t() { /* We don't initialize anything since it's a perf hit. */
{ /* We don't initialize anything since it's a perf hit. */
} }
capture_t(int begin, int end) : c_begin(begin), c_end(end) capture_t(int begin, int end) : c_begin(begin), c_end(end)
@ -189,6 +188,14 @@ public:
this->tr_capture.c_end); this->tr_capture.c_end);
} }
string_fragment inner_string_fragment() const
{
return string_fragment::from_byte_range(
this->tr_data,
this->tr_inner_capture.c_begin,
this->tr_inner_capture.c_end);
}
std::string to_string() const std::string to_string() const
{ {
return {&this->tr_data[this->tr_capture.c_begin], return {&this->tr_data[this->tr_capture.c_begin],

@ -31,6 +31,7 @@
#include "base/humanize.time.hh" #include "base/humanize.time.hh"
#include "base/snippet_highlighters.hh" #include "base/snippet_highlighters.hh"
#include "command_executor.hh"
#include "config.h" #include "config.h"
#include "log.annotate.hh" #include "log.annotate.hh"
#include "log_format_ext.hh" #include "log_format_ext.hh"
@ -513,10 +514,10 @@ field_overlay_source::build_meta_line(const listview_curses& lv,
if (!line_meta_opt) { if (!line_meta_opt) {
return; return;
} }
const auto* tc = dynamic_cast<const textview_curses*>(&lv);
auto& vc = view_colors::singleton(); auto& vc = view_colors::singleton();
const auto& line_meta = *(line_meta_opt.value()); const auto& line_meta = *(line_meta_opt.value());
size_t filename_width = this->fos_lss.get_filename_offset(); size_t filename_width = this->fos_lss.get_filename_offset();
const auto* tc = dynamic_cast<const textview_curses*>(&lv);
if (!line_meta.bm_comment.empty()) { if (!line_meta.bm_comment.empty()) {
const auto* lead = line_meta.bm_tags.empty() ? " \u2514 " : " \u251c "; const auto* lead = line_meta.bm_tags.empty() ? " \u2514 " : " \u251c ";
@ -666,6 +667,81 @@ field_overlay_source::list_value_for_overlay(
this->build_meta_line(lv, value_out, row); this->build_meta_line(lv, value_out, row);
} }
std::vector<attr_line_t>
field_overlay_source::list_overlay_menu(const listview_curses& lv,
vis_line_t row)
{
const auto* tc = dynamic_cast<const textview_curses*>(&lv);
std::vector<attr_line_t> retval;
if (!tc->tc_text_selection_active && tc->tc_selected_text) {
const auto& sti = tc->tc_selected_text.value();
if (sti.sti_line == row) {
auto left = std::max(0, sti.sti_x - 2);
this->fos_menu_items.clear();
retval.emplace_back(attr_line_t().pad_to(left).append(
" Filter Other "_status_title));
{
attr_line_t al;
al.append(" ").append("\u2714 IN"_ok).append(" ");
int start = left;
this->fos_menu_items.emplace_back(
1_vl,
line_range{start, start + (int) al.length()},
[this](const std::string& value) {
auto cmd = fmt::format(FMT_STRING(":filter-in {}"),
lnav::pcre2pp::quote(value));
execute_any(*this->fos_lss.get_exec_context(), cmd);
});
start += al.length();
al.append(":mag_right:"_emoji)
.append(" Search ")
.with_attr_for_all(VC_ROLE.value(role_t::VCR_STATUS));
this->fos_menu_items.emplace_back(
1_vl,
line_range{start, start + (int) al.length()},
[this](const std::string& value) {
auto cmd = fmt::format(FMT_STRING("/{}"),
lnav::pcre2pp::quote(value));
execute_any(*this->fos_lss.get_exec_context(), cmd);
});
retval.emplace_back(attr_line_t().pad_to(left).append(al));
}
{
attr_line_t al;
al.append(" ").append("\u2718 OUT"_error).append(" ");
int start = left;
this->fos_menu_items.emplace_back(
2_vl,
line_range{start, start + (int) al.length()},
[this](const std::string& value) {
auto cmd = fmt::format(FMT_STRING(":filter-out {}"),
lnav::pcre2pp::quote(value));
execute_any(*this->fos_lss.get_exec_context(), cmd);
});
start += al.length();
al.append(":clipboard:"_emoji)
.append(" Copy ")
.with_attr_for_all(VC_ROLE.value(role_t::VCR_STATUS));
this->fos_menu_items.emplace_back(
2_vl,
line_range{start, start + (int) al.length()},
[this](const std::string& value) {
execute_any(*this->fos_lss.get_exec_context(),
"|lnav-copy-text");
});
retval.emplace_back(attr_line_t().pad_to(left).append(al));
}
}
}
return retval;
}
nonstd::optional<attr_line_t> nonstd::optional<attr_line_t>
field_overlay_source::list_header_for_overlay(const listview_curses& lv, field_overlay_source::list_header_for_overlay(const listview_curses& lv,
vis_line_t vl) vis_line_t vl)

@ -55,6 +55,9 @@ public:
this->fos_meta_lines_row = -1_vl; this->fos_meta_lines_row = -1_vl;
} }
std::vector<attr_line_t> list_overlay_menu(const listview_curses& lv,
vis_line_t row) override;
nonstd::optional<attr_line_t> list_header_for_overlay( nonstd::optional<attr_line_t> list_header_for_overlay(
const listview_curses& lv, vis_line_t vl) override; const listview_curses& lv, vis_line_t vl) override;
@ -103,6 +106,20 @@ public:
vis_line_t fos_meta_lines_row{0_vl}; vis_line_t fos_meta_lines_row{0_vl};
std::vector<attr_line_t> fos_meta_lines; std::vector<attr_line_t> fos_meta_lines;
std::map<size_t, intern_string_t> fos_row_to_field_name; std::map<size_t, intern_string_t> fos_row_to_field_name;
struct menu_item {
menu_item(vis_line_t line,
line_range range,
std::function<void(const std::string&)> action)
: mi_line(line), mi_range(range), mi_action(std::move(action))
{
}
vis_line_t mi_line;
line_range mi_range;
std::function<void(const std::string&)> mi_action;
};
std::vector<menu_item> fos_menu_items;
}; };
#endif // LNAV_FIELD_OVERLAY_SOURCE_H #endif // LNAV_FIELD_OVERLAY_SOURCE_H

@ -440,7 +440,10 @@ files_overlay_source::list_static_overlay(const listview_curses& lv,
} }
bool bool
files_sub_source::text_handle_mouse(textview_curses& tc, mouse_event& me) files_sub_source::text_handle_mouse(
textview_curses& tc,
const listview_curses::display_line_content_t&,
mouse_event& me)
{ {
if (me.is_click_in(mouse_button_t::BUTTON_LEFT, 1, 3)) { if (me.is_click_in(mouse_button_t::BUTTON_LEFT, 1, 3)) {
this->list_input_handle_key(tc, ' '); this->list_input_handle_key(tc, ' ');

@ -61,7 +61,9 @@ public:
int line, int line,
line_flags_t raw) override; line_flags_t raw) override;
bool text_handle_mouse(textview_curses& tc, mouse_event& me) override; bool text_handle_mouse(textview_curses& tc,
const listview_curses::display_line_content_t&,
mouse_event& me) override;
size_t fss_last_line_len{0}; size_t fss_last_line_len{0};
attr_line_t fss_curr_line; attr_line_t fss_curr_line;

@ -686,7 +686,10 @@ filter_sub_source::list_input_handle_scroll_out(listview_curses& lv)
} }
bool bool
filter_sub_source::text_handle_mouse(textview_curses& tc, mouse_event& me) filter_sub_source::text_handle_mouse(
textview_curses& tc,
const listview_curses::display_line_content_t&,
mouse_event& me)
{ {
if (this->fss_editing) { if (this->fss_editing) {
return true; return true;

@ -72,7 +72,9 @@ public:
int line, int line,
line_flags_t raw) override; line_flags_t raw) override;
bool text_handle_mouse(textview_curses& tc, mouse_event& me) override; bool text_handle_mouse(textview_curses& tc,
const listview_curses::display_line_content_t&,
mouse_event& me) override;
void rl_change(readline_curses* rc); void rl_change(readline_curses* rc);

@ -475,6 +475,28 @@ listview_curses::do_update()
lr.lr_start = this->lv_left; lr.lr_start = this->lv_left;
lr.lr_end = this->lv_left + wrap_width; lr.lr_end = this->lv_left + wrap_width;
auto ov_menu = this->lv_overlay_source->list_overlay_menu(
*this, row);
auto ov_menu_row = 0_vl;
for (auto& ov_menu_line : ov_menu) {
if (y >= bottom) {
break;
}
this->lv_display_lines.push_back(overlay_menu{
ov_menu_row,
});
mvwattrline(this->lv_window,
y,
this->vc_x,
ov_menu_line,
lr,
role_t::VCR_ALT_ROW);
ov_menu_row += 1_vl;
++y;
}
this->lv_overlay_source->list_value_for_overlay( this->lv_overlay_source->list_value_for_overlay(
*this, row, row_overlay_content); *this, row, row_overlay_content);
auto overlay_height = this->get_overlay_height( auto overlay_height = this->get_overlay_height(

@ -114,6 +114,12 @@ public:
return false; return false;
} }
virtual std::vector<attr_line_t> list_overlay_menu(
const listview_curses& lv, vis_line_t line)
{
return {};
}
virtual nonstd::optional<attr_line_t> list_header_for_overlay( virtual nonstd::optional<attr_line_t> list_header_for_overlay(
const listview_curses& lv, vis_line_t line) const listview_curses& lv, vis_line_t line)
{ {
@ -528,6 +534,24 @@ public:
virtual void invoke_scroll() { this->lv_scroll(this); } virtual void invoke_scroll() { this->lv_scroll(this); }
struct main_content {
vis_line_t mc_line;
};
struct static_overlay_content {};
struct overlay_menu {
vis_line_t om_line;
};
struct overlay_content {
vis_line_t oc_line;
};
struct empty_space {};
using display_line_content_t = mapbox::util::variant<main_content,
overlay_menu,
static_overlay_content,
overlay_content,
empty_space>;
protected: protected:
void delegate_scroll_out() void delegate_scroll_out()
{ {
@ -581,20 +605,6 @@ protected:
lv_mode_t lv_mouse_mode{lv_mode_t::NONE}; lv_mode_t lv_mouse_mode{lv_mode_t::NONE};
vis_line_t lv_tail_space{1}; vis_line_t lv_tail_space{1};
struct main_content {
vis_line_t mc_line;
};
struct static_overlay_content {};
struct overlay_content {
vis_line_t oc_line;
};
struct empty_space {};
using display_line_content_t = mapbox::util::variant<main_content,
static_overlay_content,
overlay_content,
empty_space>;
std::vector<display_line_content_t> lv_display_lines; std::vector<display_line_content_t> lv_display_lines;
unsigned int lv_scroll_top{0}; unsigned int lv_scroll_top{0};
unsigned int lv_scroll_bottom{0}; unsigned int lv_scroll_bottom{0};

@ -3022,8 +3022,27 @@ logfile_sub_source::get_anchors()
} }
bool bool
logfile_sub_source::text_handle_mouse(textview_curses& tc, mouse_event& me) logfile_sub_source::text_handle_mouse(
textview_curses& tc,
const listview_curses::display_line_content_t& mouse_line,
mouse_event& me)
{ {
auto* fos = dynamic_cast<field_overlay_source*>(tc.get_overlay_source());
if (mouse_line.is<listview_curses::overlay_menu>() && tc.tc_selected_text) {
auto& om = mouse_line.get<listview_curses::overlay_menu>();
auto& sti = tc.tc_selected_text.value();
for (const auto& mi : fos->fos_menu_items) {
if (om.om_line == mi.mi_line
&& me.is_click_in(mouse_button_t::BUTTON_LEFT, mi.mi_range))
{
mi.mi_action(sti.sti_value);
break;
}
}
}
if (tc.get_overlay_selection() if (tc.get_overlay_selection()
&& me.is_click_in(mouse_button_t::BUTTON_LEFT, 2, 4)) && me.is_click_in(mouse_button_t::BUTTON_LEFT, 2, 4))
{ {

@ -689,7 +689,9 @@ public:
void text_crumbs_for_line(int line, std::vector<breadcrumb::crumb>& crumbs); void text_crumbs_for_line(int line, std::vector<breadcrumb::crumb>& crumbs);
bool text_handle_mouse(textview_curses& tc, mouse_event& me); bool text_handle_mouse(textview_curses& tc,
const listview_curses::display_line_content_t&,
mouse_event& me);
Result<bool, lnav::console::user_message> eval_sql_filter( Result<bool, lnav::console::user_message> eval_sql_filter(
sqlite3_stmt* stmt, iterator ld, logfile::const_iterator ll); sqlite3_stmt* stmt, iterator ld, logfile::const_iterator ll);
@ -702,6 +704,8 @@ public:
void set_exec_context(exec_context* ec) { this->lss_exec_context = ec; } void set_exec_context(exec_context* ec) { this->lss_exec_context = ec; }
exec_context* get_exec_context() const { return this->lss_exec_context; }
static const uint64_t MAX_CONTENT_LINES = (1ULL << 40) - 1; static const uint64_t MAX_CONTENT_LINES = (1ULL << 40) - 1;
static const uint64_t MAX_LINES_PER_FILE = 256 * 1024 * 1024; static const uint64_t MAX_LINES_PER_FILE = 256 * 1024 * 1024;
static const uint64_t MAX_FILES = (MAX_CONTENT_LINES / MAX_LINES_PER_FILE); static const uint64_t MAX_FILES = (MAX_CONTENT_LINES / MAX_LINES_PER_FILE);

@ -43,12 +43,24 @@ quote(const char* unquoted)
for (int lpc = 0; unquoted[lpc]; lpc++) { for (int lpc = 0; unquoted[lpc]; lpc++) {
if (isalnum(unquoted[lpc]) || unquoted[lpc] == '_' if (isalnum(unquoted[lpc]) || unquoted[lpc] == '_'
|| unquoted[lpc] == '-' || unquoted[lpc] == ' '
|| unquoted[lpc] == ':' || unquoted[lpc] == ';'
|| unquoted[lpc] & 0x80) || unquoted[lpc] & 0x80)
{ {
retval.push_back(unquoted[lpc]); retval.push_back(unquoted[lpc]);
} else { } else {
retval.push_back('\\'); retval.push_back('\\');
retval.push_back(unquoted[lpc]); switch (unquoted[lpc]) {
case '\t':
retval.push_back('t');
break;
case '\n':
retval.push_back('n');
break;
default:
retval.push_back(unquoted[lpc]);
break;
}
} }
} }

@ -426,22 +426,24 @@ textview_curses::handle_mouse(mouse_event& me)
: this->lv_display_lines[me.me_y]; : this->lv_display_lines[me.me_y];
this->get_dimensions(height, width); this->get_dimensions(height, width);
auto* sub_delegate = dynamic_cast<text_delegate*>(this->tc_sub_source); if (!mouse_line.is<overlay_menu>()
&& (me.me_button != mouse_button_t::BUTTON_LEFT
if (me.me_button != mouse_button_t::BUTTON_LEFT || me.me_state != mouse_button_state_t::BUTTON_STATE_RELEASED))
|| me.me_state != mouse_button_state_t::BUTTON_STATE_RELEASED)
{ {
this->tc_selected_text = nonstd::nullopt; this->tc_selected_text = nonstd::nullopt;
this->set_needs_update(); this->set_needs_update();
} }
auto* sub_delegate = dynamic_cast<text_delegate*>(this->tc_sub_source);
switch (me.me_state) { switch (me.me_state) {
case mouse_button_state_t::BUTTON_STATE_PRESSED: { case mouse_button_state_t::BUTTON_STATE_PRESSED: {
this->tc_text_selection_active = true;
if (!this->lv_selectable) { if (!this->lv_selectable) {
this->set_selectable(true); this->set_selectable(true);
} }
mouse_line.match( mouse_line.match(
[this, &me, sub_delegate](const main_content& mc) { [this, &me, sub_delegate, &mouse_line](const main_content& mc) {
if (this->vc_enabled) { if (this->vc_enabled) {
if (this->tc_supports_marks if (this->tc_supports_marks
&& me.is_modifier_pressed( && me.is_modifier_pressed(
@ -453,12 +455,14 @@ textview_curses::handle_mouse(mouse_event& me)
this->tc_press_event = me; this->tc_press_event = me;
} }
if (this->tc_delegate != nullptr) { if (this->tc_delegate != nullptr) {
this->tc_delegate->text_handle_mouse(*this, me); this->tc_delegate->text_handle_mouse(
*this, mouse_line, me);
} }
if (sub_delegate != nullptr) { if (sub_delegate != nullptr) {
sub_delegate->text_handle_mouse(*this, me); sub_delegate->text_handle_mouse(*this, mouse_line, me);
} }
}, },
[](const overlay_menu& om) {},
[](const static_overlay_content& soc) { [](const static_overlay_content& soc) {
}, },
@ -472,8 +476,9 @@ textview_curses::handle_mouse(mouse_event& me)
if (!this->lv_selectable) { if (!this->lv_selectable) {
this->set_selectable(true); this->set_selectable(true);
} }
this->tc_text_selection_active = false;
mouse_line.match( mouse_line.match(
[this, &me, sub_delegate](const main_content& mc) { [this, &me, &mouse_line, sub_delegate](const main_content& mc) {
if (this->vc_enabled) { if (this->vc_enabled) {
if (this->tc_supports_marks) { if (this->tc_supports_marks) {
attr_line_t al; attr_line_t al;
@ -481,8 +486,9 @@ textview_curses::handle_mouse(mouse_event& me)
this->textview_value_for_row(mc.mc_line, al); this->textview_value_for_row(mc.mc_line, al);
auto line_sf auto line_sf
= string_fragment::from_str(al.get_string()); = string_fragment::from_str(al.get_string());
auto cursor_sf auto cursor_sf = line_sf.sub_cell_range(
= line_sf.sub_cell_range(me.me_x, me.me_x); this->lv_left + me.me_x,
this->lv_left + me.me_x);
auto ds = data_scanner(line_sf); auto ds = data_scanner(line_sf);
auto tf = this->tc_sub_source->get_text_format(); auto tf = this->tc_sub_source->get_text_format();
while (true) { while (true) {
@ -492,9 +498,10 @@ textview_curses::handle_mouse(mouse_event& me)
} }
auto tok = tok_res.value(); auto tok = tok_res.value();
auto tok_sf = tok.to_string_fragment(); auto tok_sf = tok.inner_string_fragment();
if (tok_sf.contains(cursor_sf)) { if (tok_sf.contains(cursor_sf)) {
this->tc_selected_text = selected_text_info{ this->tc_selected_text = selected_text_info{
me.me_x,
mc.mc_line, mc.mc_line,
line_range{ line_range{
tok_sf.sf_begin, tok_sf.sf_begin,
@ -510,14 +517,18 @@ textview_curses::handle_mouse(mouse_event& me)
this->set_selection_without_context(mc.mc_line); this->set_selection_without_context(mc.mc_line);
} }
if (this->tc_delegate != nullptr) { if (this->tc_delegate != nullptr) {
this->tc_delegate->text_handle_mouse(*this, me); this->tc_delegate->text_handle_mouse(
*this, mouse_line, me);
} }
if (sub_delegate != nullptr) { if (sub_delegate != nullptr) {
sub_delegate->text_handle_mouse(*this, me); sub_delegate->text_handle_mouse(*this, mouse_line, me);
} }
}, },
[](const static_overlay_content& soc) { [](const static_overlay_content& soc) {
},
[](const overlay_menu& om) {
}, },
[](const overlay_content& oc) { [](const overlay_content& oc) {
@ -526,19 +537,24 @@ textview_curses::handle_mouse(mouse_event& me)
break; break;
} }
case mouse_button_state_t::BUTTON_STATE_DRAGGED: { case mouse_button_state_t::BUTTON_STATE_DRAGGED: {
this->tc_text_selection_active = true;
if (!this->vc_enabled) { if (!this->vc_enabled) {
} else if (me.me_y == me.me_press_y) { } else if (me.me_y == me.me_press_y) {
if (mouse_line.is<main_content>()) { if (mouse_line.is<main_content>()) {
auto& mc = mouse_line.get<main_content>(); auto& mc = mouse_line.get<main_content>();
attr_line_t al; attr_line_t al;
auto low_x = std::min(me.me_x, me.me_press_x); auto low_x = std::min(this->lv_left + me.me_x,
auto high_x = std::max(me.me_x, me.me_press_x); this->lv_left + me.me_press_x);
auto high_x = std::max(this->lv_left + me.me_x,
this->lv_left + me.me_press_x);
this->set_selection_without_context(mc.mc_line);
this->textview_value_for_row(mc.mc_line, al); this->textview_value_for_row(mc.mc_line, al);
auto line_sf = string_fragment::from_str(al.get_string()); auto line_sf = string_fragment::from_str(al.get_string());
auto cursor_sf = line_sf.sub_cell_range(low_x, high_x); auto cursor_sf = line_sf.sub_cell_range(low_x, high_x);
if (!cursor_sf.empty()) { if (!cursor_sf.empty()) {
this->tc_selected_text = { this->tc_selected_text = {
me.me_press_x,
mc.mc_line, mc.mc_line,
line_range{ line_range{
cursor_sf.sf_begin, cursor_sf.sf_begin,
@ -561,6 +577,7 @@ textview_curses::handle_mouse(mouse_event& me)
break; break;
} }
case mouse_button_state_t::BUTTON_STATE_RELEASED: { case mouse_button_state_t::BUTTON_STATE_RELEASED: {
this->tc_text_selection_active = false;
if (this->vc_enabled) { if (this->vc_enabled) {
if (this->tc_selection_start) { if (this->tc_selection_start) {
this->toggle_user_mark(&BM_USER, this->toggle_user_mark(&BM_USER,
@ -571,10 +588,14 @@ textview_curses::handle_mouse(mouse_event& me)
this->tc_selection_start = nonstd::nullopt; this->tc_selection_start = nonstd::nullopt;
} }
if (this->tc_delegate != nullptr) { if (this->tc_delegate != nullptr) {
this->tc_delegate->text_handle_mouse(*this, me); this->tc_delegate->text_handle_mouse(*this, mouse_line, me);
} }
if (sub_delegate != nullptr) { if (sub_delegate != nullptr) {
sub_delegate->text_handle_mouse(*this, me); sub_delegate->text_handle_mouse(*this, mouse_line, me);
}
if (mouse_line.is<overlay_menu>()) {
this->tc_selected_text = nonstd::nullopt;
this->set_needs_update();
} }
break; break;
} }

@ -551,7 +551,10 @@ class text_delegate {
public: public:
virtual ~text_delegate() = default; virtual ~text_delegate() = default;
virtual bool text_handle_mouse(textview_curses& tc, mouse_event& me) virtual bool text_handle_mouse(
textview_curses& tc,
const listview_curses::display_line_content_t&,
mouse_event& me)
{ {
return false; return false;
} }
@ -801,12 +804,14 @@ public:
nonstd::optional<role_t> tc_disabled_cursor_role; nonstd::optional<role_t> tc_disabled_cursor_role;
struct selected_text_info { struct selected_text_info {
int sti_x;
int64_t sti_line; int64_t sti_line;
line_range sti_range; line_range sti_range;
std::string sti_value; std::string sti_value;
}; };
nonstd::optional<selected_text_info> tc_selected_text; nonstd::optional<selected_text_info> tc_selected_text;
bool tc_text_selection_active{false};
protected: protected:
class grep_highlighter { class grep_highlighter {

Loading…
Cancel
Save