mirror of
https://github.com/tstack/lnav.git
synced 2024-09-11 13:05:51 +03:00
parent
1a932f3a41
commit
153b59ea8a
1
NEWS
1
NEWS
@ -32,6 +32,7 @@ lnav v0.8.5:
|
||||
strong fuzzy match. If there are multiple matches, as would happen
|
||||
with ":dfil", readline's menu-complete behavior will be engaged and
|
||||
you can press TAB cycle through the options.
|
||||
* The current term is now shown in the bottom status bar.
|
||||
* Some initial help text is now shown for the search and SQL prompts to
|
||||
refresh the memory.
|
||||
* When entering the ":comment" command for a line with a comment, the
|
||||
|
@ -40,7 +40,7 @@ Above and below the main body are status lines that display:
|
||||
* the log format for the top line;
|
||||
* the current view;
|
||||
* the line number for the top line in the display;
|
||||
* the current search hit and the total number of hits;
|
||||
* the current search hit, the total number of hits, and the search term;
|
||||
|
||||
If the view supports filtering, there will be a status line showing the
|
||||
following:
|
||||
|
@ -2,6 +2,7 @@
|
||||
set(diag_STAT_SRCS
|
||||
ansi_scrubber.cc
|
||||
bookmarks.cc
|
||||
bottom_status_source.cc
|
||||
collation-functions.cc
|
||||
command_executor.cc
|
||||
curl_looper.cc
|
||||
|
@ -277,6 +277,7 @@ endif
|
||||
libdiag_a_SOURCES = \
|
||||
ansi_scrubber.cc \
|
||||
bookmarks.cc \
|
||||
bottom_status_source.cc \
|
||||
collation-functions.cc \
|
||||
command_executor.cc \
|
||||
curl_looper.cc \
|
||||
|
182
src/bottom_status_source.cc
Normal file
182
src/bottom_status_source.cc
Normal file
@ -0,0 +1,182 @@
|
||||
/**
|
||||
* Copyright (c) 2019, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bottom_status_source.hh"
|
||||
|
||||
|
||||
bottom_status_source::bottom_status_source()
|
||||
: line_number_wire(*this, &bottom_status_source::update_line_number),
|
||||
percent_wire(*this, &bottom_status_source::update_percent),
|
||||
marks_wire(*this, &bottom_status_source::update_marks),
|
||||
bss_prompt(1024, view_colors::VCR_STATUS),
|
||||
bss_error(1024, view_colors::VCR_ALERT_STATUS)
|
||||
{
|
||||
this->bss_fields[BSF_LINE_NUMBER].set_min_width(10);
|
||||
this->bss_fields[BSF_LINE_NUMBER].set_share(1000);
|
||||
this->bss_fields[BSF_PERCENT].set_width(5);
|
||||
this->bss_fields[BSF_PERCENT].set_left_pad(1);
|
||||
this->bss_fields[BSF_HITS].set_min_width(10);
|
||||
this->bss_fields[BSF_HITS].set_share(5);
|
||||
this->bss_fields[BSF_SEARCH_TERM].set_min_width(10);
|
||||
this->bss_fields[BSF_SEARCH_TERM].set_share(1);
|
||||
this->bss_fields[BSF_LOADING].set_width(13);
|
||||
this->bss_fields[BSF_LOADING].set_cylon(true);
|
||||
this->bss_fields[BSF_LOADING].right_justify(true);
|
||||
this->bss_fields[BSF_HELP].set_width(14);
|
||||
this->bss_fields[BSF_HELP].set_value("?:View Help");
|
||||
this->bss_fields[BSF_HELP].right_justify(true);
|
||||
this->bss_prompt.set_left_pad(1);
|
||||
this->bss_prompt.set_min_width(35);
|
||||
this->bss_prompt.set_share(1);
|
||||
this->bss_error.set_left_pad(1);
|
||||
this->bss_error.set_min_width(35);
|
||||
this->bss_error.set_share(1);
|
||||
}
|
||||
|
||||
void bottom_status_source::update_line_number(listview_curses *lc)
|
||||
{
|
||||
status_field &sf = this->bss_fields[BSF_LINE_NUMBER];
|
||||
|
||||
if (lc->get_inner_height() == 0) {
|
||||
sf.set_value(" L0");
|
||||
}
|
||||
else {
|
||||
sf.set_value(" L%'d", (int) lc->get_top());
|
||||
}
|
||||
}
|
||||
|
||||
void bottom_status_source::update_search_term(textview_curses &tc)
|
||||
{
|
||||
auto &sf = this->bss_fields[BSF_SEARCH_TERM];
|
||||
auto search_term = tc.get_last_search();
|
||||
|
||||
if (search_term.empty()) {
|
||||
sf.clear();
|
||||
} else {
|
||||
sf.set_value("\"%s\"", search_term.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void bottom_status_source::update_percent(listview_curses *lc)
|
||||
{
|
||||
status_field &sf = this->bss_fields[BSF_PERCENT];
|
||||
vis_line_t top = lc->get_top();
|
||||
vis_line_t bottom, height;
|
||||
unsigned long width;
|
||||
double percent;
|
||||
|
||||
lc->get_dimensions(height, width);
|
||||
|
||||
if (lc->get_inner_height() > 0) {
|
||||
bottom = std::min(top + height - vis_line_t(1),
|
||||
vis_line_t(lc->get_inner_height() - 1));
|
||||
percent = (double)(bottom + 1);
|
||||
percent /= (double)lc->get_inner_height();
|
||||
percent *= 100.0;
|
||||
}
|
||||
else {
|
||||
percent = 0.0;
|
||||
}
|
||||
sf.set_value("%3d%% ", (int)percent);
|
||||
}
|
||||
|
||||
void bottom_status_source::update_marks(listview_curses *lc)
|
||||
{
|
||||
auto *tc = static_cast<textview_curses *>(lc);
|
||||
vis_bookmarks &bm = tc->get_bookmarks();
|
||||
status_field &sf = this->bss_fields[BSF_HITS];
|
||||
|
||||
if (bm.find(&textview_curses::BM_SEARCH) != bm.end()) {
|
||||
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_SEARCH];
|
||||
|
||||
if (!bv.empty()) {
|
||||
bookmark_vector<vis_line_t>::iterator lb;
|
||||
|
||||
lb = std::lower_bound(bv.begin(), bv.end(), tc->get_top());
|
||||
if (lb != bv.end() && *lb == tc->get_top()) {
|
||||
sf.set_value(
|
||||
" Hit %'d of %'d for ",
|
||||
std::distance(bv.begin(), lb) + 1, tc->get_match_count());
|
||||
} else {
|
||||
sf.set_value(" %'d hits for ", tc->get_match_count());
|
||||
}
|
||||
} else {
|
||||
sf.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
sf.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void bottom_status_source::update_hits(textview_curses *tc)
|
||||
{
|
||||
status_field & sf = this->bss_fields[BSF_HITS];
|
||||
view_colors::role_t new_role;
|
||||
|
||||
if (tc->is_searching()) {
|
||||
this->bss_hit_spinner += 1;
|
||||
if (this->bss_hit_spinner % 2) {
|
||||
new_role = view_colors::VCR_ACTIVE_STATUS;
|
||||
}
|
||||
else{
|
||||
new_role = view_colors::VCR_ACTIVE_STATUS2;
|
||||
}
|
||||
sf.set_cylon(true);
|
||||
}
|
||||
else {
|
||||
new_role = view_colors::VCR_STATUS;
|
||||
sf.set_cylon(false);
|
||||
}
|
||||
// this->bss_error.clear();
|
||||
sf.set_role(new_role);
|
||||
this->update_marks(tc);
|
||||
}
|
||||
|
||||
void bottom_status_source::update_loading(off_t off, size_t total)
|
||||
{
|
||||
status_field &sf = this->bss_fields[BSF_LOADING];
|
||||
|
||||
if (total == 0 || (size_t)off == total) {
|
||||
sf.set_role(view_colors::VCR_STATUS);
|
||||
sf.clear();
|
||||
}
|
||||
else {
|
||||
int pct = (int)(((double)off / (double)total) * 100.0);
|
||||
|
||||
if (this->bss_load_percent != pct) {
|
||||
this->bss_load_percent = pct;
|
||||
|
||||
sf.set_role(view_colors::VCR_ACTIVE_STATUS2);
|
||||
sf.set_value(" Loading %2d%% ", pct);
|
||||
}
|
||||
}
|
||||
}
|
@ -49,38 +49,14 @@ public:
|
||||
BSF_LINE_NUMBER,
|
||||
BSF_PERCENT,
|
||||
BSF_HITS,
|
||||
BSF_SEARCH_TERM,
|
||||
BSF_LOADING,
|
||||
BSF_HELP,
|
||||
|
||||
BSF__MAX
|
||||
} field_t;
|
||||
|
||||
bottom_status_source()
|
||||
: line_number_wire(*this, &bottom_status_source::update_line_number),
|
||||
percent_wire(*this, &bottom_status_source::update_percent),
|
||||
marks_wire(*this, &bottom_status_source::update_marks),
|
||||
bss_prompt(1024, view_colors::VCR_STATUS),
|
||||
bss_error(1024, view_colors::VCR_ALERT_STATUS),
|
||||
bss_hit_spinner(0),
|
||||
bss_load_percent(0)
|
||||
{
|
||||
this->bss_fields[BSF_LINE_NUMBER].set_width(14);
|
||||
this->bss_fields[BSF_PERCENT].set_width(5);
|
||||
this->bss_fields[BSF_PERCENT].set_left_pad(1);
|
||||
this->bss_fields[BSF_HITS].set_width(36);
|
||||
this->bss_fields[BSF_LOADING].set_width(13);
|
||||
this->bss_fields[BSF_LOADING].set_cylon(true);
|
||||
this->bss_fields[BSF_LOADING].right_justify(true);
|
||||
this->bss_fields[BSF_HELP].set_width(14);
|
||||
this->bss_fields[BSF_HELP].set_value("?:View Help");
|
||||
this->bss_fields[BSF_HELP].right_justify(true);
|
||||
this->bss_prompt.set_left_pad(1);
|
||||
this->bss_prompt.set_min_width(35);
|
||||
this->bss_prompt.set_share(1);
|
||||
this->bss_error.set_left_pad(1);
|
||||
this->bss_error.set_min_width(35);
|
||||
this->bss_error.set_share(1);
|
||||
};
|
||||
bottom_status_source();
|
||||
|
||||
virtual ~bottom_status_source() { };
|
||||
|
||||
@ -127,113 +103,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void update_line_number(listview_curses *lc)
|
||||
{
|
||||
status_field &sf = this->bss_fields[BSF_LINE_NUMBER];
|
||||
void update_line_number(listview_curses *lc);
|
||||
|
||||
if (lc->get_inner_height() == 0) {
|
||||
sf.set_value(" L0");
|
||||
}
|
||||
else {
|
||||
sf.set_value(" L%'d", (int)lc->get_top());
|
||||
}
|
||||
};
|
||||
void update_search_term(textview_curses &tc);
|
||||
|
||||
void update_percent(listview_curses *lc)
|
||||
{
|
||||
status_field &sf = this->bss_fields[BSF_PERCENT];
|
||||
vis_line_t top = lc->get_top();
|
||||
vis_line_t bottom, height;
|
||||
unsigned long width;
|
||||
double percent;
|
||||
void update_percent(listview_curses *lc);
|
||||
|
||||
lc->get_dimensions(height, width);
|
||||
void update_marks(listview_curses *lc);
|
||||
|
||||
if (lc->get_inner_height() > 0) {
|
||||
bottom = std::min(top + height - vis_line_t(1),
|
||||
vis_line_t(lc->get_inner_height() - 1));
|
||||
percent = (double)(bottom + 1);
|
||||
percent /= (double)lc->get_inner_height();
|
||||
percent *= 100.0;
|
||||
}
|
||||
else {
|
||||
percent = 0.0;
|
||||
}
|
||||
sf.set_value("%3d%%", (int)percent);
|
||||
};
|
||||
void update_hits(textview_curses *tc);
|
||||
|
||||
void update_marks(listview_curses *lc)
|
||||
{
|
||||
textview_curses *tc = static_cast<textview_curses *>(lc);
|
||||
vis_bookmarks &bm = tc->get_bookmarks();
|
||||
status_field &sf = this->bss_fields[BSF_HITS];
|
||||
|
||||
if (bm.find(&textview_curses::BM_SEARCH) != bm.end()) {
|
||||
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_SEARCH];
|
||||
bookmark_vector<vis_line_t>::iterator lb;
|
||||
|
||||
lb = std::lower_bound(bv.begin(), bv.end(), tc->get_top());
|
||||
if (lb != bv.end() && *lb == tc->get_top()) {
|
||||
sf.set_value(" Hit %'d of %'d",
|
||||
std::distance(bv.begin(), lb) + 1, tc->get_match_count());
|
||||
} else {
|
||||
sf.set_value("%'9d hits", tc->get_match_count());
|
||||
}
|
||||
}
|
||||
else {
|
||||
sf.clear();
|
||||
}
|
||||
};
|
||||
|
||||
void update_hits(textview_curses *tc)
|
||||
{
|
||||
status_field & sf = this->bss_fields[BSF_HITS];
|
||||
view_colors::role_t new_role;
|
||||
|
||||
if (tc->is_searching()) {
|
||||
this->bss_hit_spinner += 1;
|
||||
if (this->bss_hit_spinner % 2) {
|
||||
new_role = view_colors::VCR_ACTIVE_STATUS;
|
||||
}
|
||||
else{
|
||||
new_role = view_colors::VCR_ACTIVE_STATUS2;
|
||||
}
|
||||
sf.set_cylon(true);
|
||||
}
|
||||
else {
|
||||
new_role = view_colors::VCR_STATUS;
|
||||
sf.set_cylon(false);
|
||||
}
|
||||
// this->bss_error.clear();
|
||||
sf.set_role(new_role);
|
||||
this->update_marks(tc);
|
||||
};
|
||||
|
||||
void update_loading(off_t off, size_t total)
|
||||
{
|
||||
status_field &sf = this->bss_fields[BSF_LOADING];
|
||||
|
||||
if (total == 0 || (size_t)off == total) {
|
||||
sf.set_role(view_colors::VCR_STATUS);
|
||||
sf.clear();
|
||||
}
|
||||
else {
|
||||
int pct = (int)(((double)off / (double)total) * 100.0);
|
||||
|
||||
if (this->bss_load_percent != pct) {
|
||||
this->bss_load_percent = pct;
|
||||
|
||||
sf.set_role(view_colors::VCR_ACTIVE_STATUS2);
|
||||
sf.set_value(" Loading %2d%% ", pct);
|
||||
}
|
||||
}
|
||||
};
|
||||
void update_loading(off_t off, size_t total);
|
||||
|
||||
private:
|
||||
status_field bss_prompt;
|
||||
status_field bss_error;
|
||||
status_field bss_fields[BSF__MAX];
|
||||
int bss_hit_spinner;
|
||||
int bss_load_percent;
|
||||
int bss_hit_spinner{0};
|
||||
int bss_load_percent{0};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -57,7 +57,7 @@ filter_status_source::filter_status_source()
|
||||
this->tss_fields[TSF_FILTERED].set_role(view_colors::VCR_BOLD_STATUS);
|
||||
|
||||
this->tss_fields[TSF_HELP].right_justify(true);
|
||||
this->tss_fields[TSF_HELP].set_min_width(80);
|
||||
this->tss_fields[TSF_HELP].set_min_width(40);
|
||||
this->tss_fields[TSF_HELP].set_width(1024);
|
||||
this->tss_fields[TSF_HELP].set_value(TOGGLE_MSG);
|
||||
this->tss_fields[TSF_HELP].set_left_pad(1);
|
||||
|
@ -142,7 +142,7 @@ Above and below the main body are status lines that display:
|
||||
* the log format for the top line;
|
||||
* the current view;
|
||||
* the line number for the top line in the display;
|
||||
* the current search hit and the total number of hits;
|
||||
* the current search hit, the total number of hits, and the search term;
|
||||
|
||||
If the view supports filtering, there will be a status line showing the
|
||||
following:
|
||||
|
@ -1434,6 +1434,10 @@ static void looper()
|
||||
set_scroll_action(sb.get_functor());
|
||||
lnav_data.ld_views[lpc].set_search_action(
|
||||
textview_curses::action(update_hits));
|
||||
using std::placeholders::_1;
|
||||
lnav_data.ld_views[lpc].tc_search_event_handler =
|
||||
std::bind(&bottom_status_source::update_search_term,
|
||||
&lnav_data.ld_bottom_source, _1);
|
||||
}
|
||||
|
||||
lnav_data.ld_doc_view.set_window(lnav_data.ld_window);
|
||||
|
@ -31,10 +31,35 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "statusview_curses.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void status_field::set_value(std::string value)
|
||||
{
|
||||
string_attrs_t &sa = this->sf_value.get_attrs();
|
||||
|
||||
sa.clear();
|
||||
|
||||
scrub_ansi_string(value, sa);
|
||||
|
||||
this->sf_value.with_string(value);
|
||||
|
||||
if (this->sf_cylon) {
|
||||
struct line_range lr(this->sf_cylon_pos, this->sf_width);
|
||||
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_STYLE,
|
||||
view_colors::ansi_color_pair(COLOR_WHITE, COLOR_GREEN) | A_BOLD));
|
||||
|
||||
this->sf_cylon_pos += 1;
|
||||
if (this->sf_cylon_pos > this->sf_width) {
|
||||
this->sf_cylon_pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void statusview_curses::do_update()
|
||||
{
|
||||
int top, attrs, field, field_count, left = 0, right;
|
||||
@ -46,9 +71,7 @@ void statusview_curses::do_update()
|
||||
}
|
||||
|
||||
getmaxyx(this->sc_window, height, width);
|
||||
if (width != this->sc_last_width) {
|
||||
this->window_change();
|
||||
}
|
||||
this->window_change();
|
||||
|
||||
top = this->sc_top < 0 ? height + this->sc_top : this->sc_top;
|
||||
right = width;
|
||||
@ -92,6 +115,16 @@ void statusview_curses::do_update()
|
||||
x = left;
|
||||
left += sf.get_width();
|
||||
}
|
||||
|
||||
if (val.length() > sf.get_width() && val.length() > 11) {
|
||||
static const std::string MIDSUB = " .. ";
|
||||
|
||||
size_t half_width = sf.get_width() / 2 - MIDSUB.size() / 2;
|
||||
|
||||
val.erase(half_width, val.length() - (half_width * 2));
|
||||
val.insert(half_width, MIDSUB);
|
||||
}
|
||||
|
||||
mvwattrline(this->sc_window,
|
||||
top, x,
|
||||
val,
|
||||
@ -109,39 +142,48 @@ void statusview_curses::window_change()
|
||||
}
|
||||
|
||||
int field_count = this->sc_source->statusview_fields();
|
||||
int remaining, total_shares = 0;
|
||||
int total_shares = 0;
|
||||
unsigned long width, height;
|
||||
double remaining = 0;
|
||||
vector<status_field *> resizable;
|
||||
|
||||
getmaxyx(this->sc_window, height, width);
|
||||
// Silence the compiler. Remove this if height is used at a later stage.
|
||||
(void)height;
|
||||
remaining = width - 4;
|
||||
for (int field = 0; field < field_count; field++) {
|
||||
status_field &sf = this->sc_source->statusview_value_for_field(
|
||||
field);
|
||||
remaining = width - 2;
|
||||
|
||||
remaining -=
|
||||
sf.get_share() ? sf.get_min_width() : sf.get_width();
|
||||
remaining -= 1;
|
||||
for (int field = 0; field < field_count; field++) {
|
||||
auto &sf = this->sc_source->statusview_value_for_field(field);
|
||||
|
||||
remaining -= sf.get_share() ? sf.get_min_width() : sf.get_width();
|
||||
total_shares += sf.get_share();
|
||||
if (sf.get_share()) {
|
||||
resizable.emplace_back(&sf);
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining < 2) {
|
||||
remaining = 0;
|
||||
}
|
||||
|
||||
for (int field = 0; field < field_count; field++) {
|
||||
status_field &sf = this->sc_source->statusview_value_for_field(
|
||||
field);
|
||||
stable_sort(begin(resizable), end(resizable), [](auto l, auto r) {
|
||||
return r->get_share() < l->get_share();
|
||||
});
|
||||
for (auto sf : resizable) {
|
||||
double divisor = total_shares / sf->get_share();
|
||||
int available = remaining / divisor;
|
||||
int actual_width;
|
||||
|
||||
if (sf.get_share()) {
|
||||
int actual_width;
|
||||
|
||||
actual_width = sf.get_min_width();
|
||||
actual_width += remaining / (sf.get_share() / total_shares);
|
||||
|
||||
sf.set_width(actual_width);
|
||||
if (sf->get_value().length() < (sf->get_min_width() + available)) {
|
||||
actual_width = std::max((int) sf->get_min_width(),
|
||||
(int) sf->get_value().length());
|
||||
} else {
|
||||
actual_width = sf->get_min_width() + available;
|
||||
}
|
||||
remaining -= (actual_width - sf->get_min_width());
|
||||
total_shares -= sf->get_share();
|
||||
|
||||
sf->set_width(actual_width);
|
||||
}
|
||||
|
||||
this->sc_last_width = width;
|
||||
|
@ -51,59 +51,13 @@ public:
|
||||
status_field(int width = 1,
|
||||
view_colors::role_t role = view_colors::VCR_STATUS)
|
||||
: sf_width(width),
|
||||
sf_min_width(0),
|
||||
sf_right_justify(false),
|
||||
sf_cylon(false),
|
||||
sf_cylon_pos(0),
|
||||
sf_role(role),
|
||||
sf_share(0),
|
||||
sf_left_pad(0) { };
|
||||
sf_role(role) {
|
||||
};
|
||||
|
||||
virtual ~status_field() { };
|
||||
|
||||
/** @param value The new value for this field. */
|
||||
void set_value(std::string value)
|
||||
{
|
||||
string_attrs_t &sa = this->sf_value.get_attrs();
|
||||
|
||||
sa.clear();
|
||||
|
||||
scrub_ansi_string(value, sa);
|
||||
|
||||
if (value.size() > this->get_width()) {
|
||||
if (value.size() <= 11) {
|
||||
value.resize(11);
|
||||
}
|
||||
else {
|
||||
static const std::string MIDSUB = " .. ";
|
||||
|
||||
size_t half_width = this->get_width() / 2 -
|
||||
MIDSUB.size() / 2;
|
||||
std::string abbrev;
|
||||
|
||||
abbrev.append(value, 0, half_width);
|
||||
abbrev.append(MIDSUB);
|
||||
abbrev.append(value,
|
||||
value.size() - half_width,
|
||||
std::string::npos);
|
||||
value = abbrev;
|
||||
}
|
||||
}
|
||||
|
||||
this->sf_value.with_string(value);
|
||||
|
||||
if (this->sf_cylon) {
|
||||
struct line_range lr(this->sf_cylon_pos, this->sf_width);
|
||||
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_STYLE,
|
||||
view_colors::ansi_color_pair(COLOR_WHITE, COLOR_GREEN) | A_BOLD));
|
||||
|
||||
this->sf_cylon_pos += 1;
|
||||
if (this->sf_cylon_pos > this->sf_width) {
|
||||
this->sf_cylon_pos = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
void set_value(std::string value);;
|
||||
|
||||
/**
|
||||
* Set the new value for this field using a formatted string.
|
||||
@ -172,14 +126,14 @@ public:
|
||||
|
||||
protected:
|
||||
size_t sf_width; /*< The maximum display width, in chars. */
|
||||
size_t sf_min_width; /*< The minimum display width, in chars. */
|
||||
bool sf_right_justify;
|
||||
bool sf_cylon;
|
||||
size_t sf_cylon_pos;
|
||||
size_t sf_min_width{0}; /*< The minimum display width, in chars. */
|
||||
bool sf_right_justify{false};
|
||||
bool sf_cylon{false};
|
||||
size_t sf_cylon_pos{0};
|
||||
attr_line_t sf_value; /*< The value to display for this field. */
|
||||
view_colors::role_t sf_role; /*< The color role for this field. */
|
||||
int sf_share;
|
||||
size_t sf_left_pad;
|
||||
int sf_share{0};
|
||||
size_t sf_left_pad{0};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -445,6 +445,9 @@ void textview_curses::execute_search(const std::string ®ex_orig)
|
||||
}
|
||||
|
||||
this->tc_last_search = regex;
|
||||
if (this->tc_search_event_handler) {
|
||||
this->tc_search_event_handler(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void text_time_translator::scroll_invoked(textview_curses *tc)
|
||||
|
@ -924,6 +924,8 @@ public:
|
||||
listview_curses::invoke_scroll();
|
||||
}
|
||||
|
||||
std::function<void(textview_curses &)> tc_search_event_handler;
|
||||
|
||||
protected:
|
||||
|
||||
class grep_highlighter {
|
||||
|
@ -142,7 +142,7 @@ Above and below the main body are status lines that display:
|
||||
* the log format for the top line;
|
||||
* the current view;
|
||||
* the line number for the top line in the display;
|
||||
* the current search hit and the total number of hits;
|
||||
* the current search hit, the total number of hits, and the search term;
|
||||
|
||||
If the view supports filtering, there will be a status line showing the
|
||||
following:
|
||||
|
Loading…
Reference in New Issue
Block a user