2018-11-09 17:45:19 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2018, 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;
|
2022-03-16 22:38:08 +00:00
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
2018-11-09 17:45:19 +00:00
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
#include "view_helpers.hh"
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-05-11 04:58:32 +00:00
|
|
|
#include "base/humanize.hh"
|
|
|
|
#include "base/itertools.hh"
|
2022-03-16 22:38:08 +00:00
|
|
|
#include "config.h"
|
2022-05-23 03:44:18 +00:00
|
|
|
#include "document.sections.hh"
|
2022-03-16 22:38:08 +00:00
|
|
|
#include "environ_vtab.hh"
|
2022-08-03 23:05:37 +00:00
|
|
|
#include "filter_sub_source.hh"
|
2022-05-23 03:44:18 +00:00
|
|
|
#include "help-md.h"
|
2022-05-11 04:58:32 +00:00
|
|
|
#include "intervaltree/IntervalTree.h"
|
2018-11-09 17:45:19 +00:00
|
|
|
#include "lnav.hh"
|
2022-04-30 20:05:42 +00:00
|
|
|
#include "lnav.indexing.hh"
|
2022-05-23 03:44:18 +00:00
|
|
|
#include "md2attr_line.hh"
|
|
|
|
#include "md4cpp.hh"
|
2018-11-09 17:45:19 +00:00
|
|
|
#include "pretty_printer.hh"
|
|
|
|
#include "shlex.hh"
|
2022-03-16 22:38:08 +00:00
|
|
|
#include "sql_help.hh"
|
|
|
|
#include "sql_util.hh"
|
2022-08-29 01:55:32 +00:00
|
|
|
#include "static_file_vtab.hh"
|
2022-05-11 04:58:32 +00:00
|
|
|
#include "view_helpers.crumbs.hh"
|
2022-03-13 22:49:41 +00:00
|
|
|
#include "view_helpers.examples.hh"
|
2022-04-30 20:05:42 +00:00
|
|
|
#include "view_helpers.hist.hh"
|
2022-03-16 22:38:08 +00:00
|
|
|
#include "vtab_module.hh"
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-05-11 04:58:32 +00:00
|
|
|
using namespace std::chrono_literals;
|
2022-05-23 03:44:18 +00:00
|
|
|
using namespace lnav::roles::literals;
|
2022-05-11 04:58:32 +00:00
|
|
|
|
2022-03-31 15:59:19 +00:00
|
|
|
const char* lnav_view_strings[LNV__MAX + 1] = {
|
|
|
|
"log",
|
|
|
|
"text",
|
|
|
|
"help",
|
|
|
|
"histogram",
|
|
|
|
"db",
|
|
|
|
"schema",
|
|
|
|
"pretty",
|
|
|
|
"spectro",
|
|
|
|
|
|
|
|
nullptr,
|
|
|
|
};
|
2021-08-24 05:25:38 +00:00
|
|
|
|
2022-04-30 20:05:42 +00:00
|
|
|
const char* lnav_view_titles[LNV__MAX] = {
|
|
|
|
"LOG",
|
|
|
|
"TEXT",
|
|
|
|
"HELP",
|
|
|
|
"HIST",
|
|
|
|
"DB",
|
|
|
|
"SCHEMA",
|
|
|
|
"PRETTY",
|
|
|
|
"SPECTRO",
|
|
|
|
};
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
nonstd::optional<lnav_view_t>
|
|
|
|
view_from_string(const char* name)
|
2021-08-24 05:25:38 +00:00
|
|
|
{
|
|
|
|
if (name == nullptr) {
|
|
|
|
return nonstd::nullopt;
|
|
|
|
}
|
|
|
|
|
2022-05-11 04:58:32 +00:00
|
|
|
auto* view_name_iter
|
2022-03-31 15:59:19 +00:00
|
|
|
= std::find_if(std::begin(lnav_view_strings),
|
|
|
|
std::end(lnav_view_strings),
|
|
|
|
[&](const char* v) {
|
|
|
|
return v != nullptr && strcasecmp(v, name) == 0;
|
|
|
|
});
|
2021-08-24 05:25:38 +00:00
|
|
|
|
2022-03-31 15:59:19 +00:00
|
|
|
if (view_name_iter == std::end(lnav_view_strings)) {
|
2021-08-24 05:25:38 +00:00
|
|
|
return nonstd::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lnav_view_t(view_name_iter - lnav_view_strings);
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
static void
|
|
|
|
open_schema_view()
|
2018-11-09 17:45:19 +00:00
|
|
|
{
|
2022-03-16 22:38:08 +00:00
|
|
|
textview_curses* schema_tc = &lnav_data.ld_views[LNV_SCHEMA];
|
2022-03-31 15:59:19 +00:00
|
|
|
std::string schema;
|
2018-11-09 17:45:19 +00:00
|
|
|
|
|
|
|
dump_sqlite_schema(lnav_data.ld_db, schema);
|
|
|
|
|
|
|
|
schema += "\n\n-- Virtual Table Definitions --\n\n";
|
|
|
|
schema += ENVIRON_CREATE_STMT;
|
2022-08-29 01:55:32 +00:00
|
|
|
schema += STATIC_FILE_CREATE_STMT;
|
2018-11-09 17:45:19 +00:00
|
|
|
schema += vtab_module_schemas;
|
2022-03-16 22:38:08 +00:00
|
|
|
for (const auto& vtab_iter : *lnav_data.ld_vtab_manager) {
|
2018-11-09 17:45:19 +00:00
|
|
|
schema += "\n" + vtab_iter.second->get_table_statement();
|
|
|
|
}
|
|
|
|
|
|
|
|
delete schema_tc->get_sub_source();
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
auto* pts = new plain_text_source(schema);
|
2019-06-15 13:32:02 +00:00
|
|
|
pts->set_text_format(text_format_t::TF_SQL);
|
2018-11-09 17:45:19 +00:00
|
|
|
|
|
|
|
schema_tc->set_sub_source(pts);
|
2021-08-26 16:05:26 +00:00
|
|
|
schema_tc->redo_search();
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
|
2022-05-11 04:58:32 +00:00
|
|
|
class pretty_sub_source : public plain_text_source {
|
|
|
|
public:
|
|
|
|
void text_crumbs_for_line(int line,
|
|
|
|
std::vector<breadcrumb::crumb>& crumbs) override
|
|
|
|
{
|
|
|
|
text_sub_source::text_crumbs_for_line(line, crumbs);
|
|
|
|
|
2022-06-05 05:58:19 +00:00
|
|
|
if (line < 0 || static_cast<size_t>(line) > this->tds_lines.size()) {
|
2022-05-11 04:58:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto& tl = this->tds_lines[line];
|
|
|
|
const auto initial_size = crumbs.size();
|
2022-05-23 03:44:18 +00:00
|
|
|
lnav::document::hier_node* root_node{nullptr};
|
2022-05-11 04:58:32 +00:00
|
|
|
|
|
|
|
this->pss_hier_tree->template visit_overlapping(
|
|
|
|
tl.tl_offset,
|
|
|
|
[&root_node](const auto& hier_iv) { root_node = hier_iv.value; });
|
|
|
|
this->pss_interval_tree->visit_overlapping(
|
|
|
|
tl.tl_offset,
|
|
|
|
tl.tl_offset + tl.tl_value.length(),
|
|
|
|
[&crumbs, root_node, this, initial_size](const auto& iv) {
|
|
|
|
auto path = crumbs | lnav::itertools::skip(initial_size)
|
|
|
|
| lnav::itertools::map(&breadcrumb::crumb::c_key)
|
|
|
|
| lnav::itertools::append(iv.value);
|
|
|
|
auto poss_provider = [root_node, path]() {
|
|
|
|
std::vector<breadcrumb::possibility> retval;
|
2022-05-23 03:44:18 +00:00
|
|
|
auto curr_node = lnav::document::hier_node::lookup_path(
|
2022-05-11 04:58:32 +00:00
|
|
|
root_node, path);
|
|
|
|
if (curr_node) {
|
|
|
|
auto* parent_node = curr_node.value()->hn_parent;
|
|
|
|
|
|
|
|
if (parent_node != nullptr) {
|
|
|
|
for (const auto& sibling :
|
2022-08-01 21:56:48 +00:00
|
|
|
parent_node->hn_named_children)
|
|
|
|
{
|
2022-05-11 04:58:32 +00:00
|
|
|
retval.template emplace_back(sibling.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
auto path_performer =
|
|
|
|
[this, root_node, path](
|
|
|
|
const breadcrumb::crumb::key_t& value) {
|
2022-05-23 03:44:18 +00:00
|
|
|
auto curr_node = lnav::document::hier_node::lookup_path(
|
2022-05-11 04:58:32 +00:00
|
|
|
root_node, path);
|
|
|
|
if (!curr_node) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto* parent_node = curr_node.value()->hn_parent;
|
|
|
|
|
|
|
|
if (parent_node == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
value.template match(
|
|
|
|
[this, parent_node](const std::string& str) {
|
|
|
|
auto sib_iter
|
|
|
|
= parent_node->hn_named_children.find(str);
|
|
|
|
if (sib_iter
|
|
|
|
!= parent_node->hn_named_children.end()) {
|
|
|
|
this->line_for_offset(
|
|
|
|
sib_iter->second->hn_start)
|
|
|
|
| [](const auto new_top) {
|
|
|
|
lnav_data.ld_views[LNV_PRETTY]
|
|
|
|
.set_top(new_top);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[this, parent_node](size_t index) {
|
|
|
|
if (index >= parent_node->hn_children.size()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto sib
|
|
|
|
= parent_node->hn_children[index].get();
|
|
|
|
this->line_for_offset(sib->hn_start) |
|
|
|
|
[](const auto new_top) {
|
|
|
|
lnav_data.ld_views[LNV_PRETTY].set_top(
|
|
|
|
new_top);
|
|
|
|
};
|
|
|
|
});
|
|
|
|
};
|
|
|
|
crumbs.template emplace_back(iv.value,
|
|
|
|
std::move(poss_provider),
|
|
|
|
std::move(path_performer));
|
|
|
|
auto curr_node
|
2022-05-23 03:44:18 +00:00
|
|
|
= lnav::document::hier_node::lookup_path(root_node, path);
|
2022-05-11 04:58:32 +00:00
|
|
|
if (curr_node
|
|
|
|
&& curr_node.value()->hn_parent->hn_children.size()
|
|
|
|
!= curr_node.value()
|
|
|
|
->hn_parent->hn_named_children.size())
|
|
|
|
{
|
2022-05-23 03:44:18 +00:00
|
|
|
auto node = lnav::document::hier_node::lookup_path(
|
2022-05-11 04:58:32 +00:00
|
|
|
root_node, path);
|
|
|
|
|
|
|
|
crumbs.back().c_expected_input
|
|
|
|
= curr_node.value()
|
|
|
|
->hn_parent->hn_named_children.empty()
|
|
|
|
? breadcrumb::crumb::expected_input_t::index
|
|
|
|
: breadcrumb::crumb::expected_input_t::index_or_exact;
|
|
|
|
crumbs.back().with_possible_range(
|
|
|
|
node | lnav::itertools::map([](const auto hn) {
|
|
|
|
return hn->hn_parent->hn_children.size();
|
|
|
|
})
|
|
|
|
| lnav::itertools::unwrap_or(size_t{0}));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
auto path = crumbs | lnav::itertools::skip(initial_size)
|
|
|
|
| lnav::itertools::map(&breadcrumb::crumb::c_key);
|
2022-05-23 03:44:18 +00:00
|
|
|
auto node = lnav::document::hier_node::lookup_path(root_node, path);
|
2022-05-11 04:58:32 +00:00
|
|
|
|
|
|
|
if (node && !node.value()->hn_children.empty()) {
|
|
|
|
auto poss_provider = [curr_node = node.value()]() {
|
|
|
|
std::vector<breadcrumb::possibility> retval;
|
|
|
|
for (const auto& child : curr_node->hn_named_children) {
|
|
|
|
retval.template emplace_back(child.first);
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
auto path_performer = [this, curr_node = node.value()](
|
|
|
|
const breadcrumb::crumb::key_t& value) {
|
|
|
|
value.template match(
|
|
|
|
[this, curr_node](const std::string& str) {
|
|
|
|
auto child_iter
|
|
|
|
= curr_node->hn_named_children.find(str);
|
|
|
|
if (child_iter != curr_node->hn_named_children.end()) {
|
|
|
|
this->line_for_offset(child_iter->second->hn_start)
|
|
|
|
| [](const auto new_top) {
|
|
|
|
lnav_data.ld_views[LNV_PRETTY].set_top(
|
|
|
|
new_top);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[this, curr_node](size_t index) {
|
|
|
|
auto* child = curr_node->hn_children[index].get();
|
|
|
|
this->line_for_offset(child->hn_start) |
|
|
|
|
[](const auto new_top) {
|
|
|
|
lnav_data.ld_views[LNV_PRETTY].set_top(new_top);
|
|
|
|
};
|
|
|
|
});
|
|
|
|
};
|
|
|
|
crumbs.emplace_back("", "\u22ef", poss_provider, path_performer);
|
|
|
|
crumbs.back().c_expected_input
|
|
|
|
= node.value()->hn_named_children.empty()
|
|
|
|
? breadcrumb::crumb::expected_input_t::index
|
|
|
|
: breadcrumb::crumb::expected_input_t::index_or_exact;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
using hier_tree_t
|
2022-05-23 03:44:18 +00:00
|
|
|
= interval_tree::IntervalTree<file_off_t, lnav::document::hier_node*>;
|
2022-05-11 04:58:32 +00:00
|
|
|
using hier_interval_t
|
2022-05-23 03:44:18 +00:00
|
|
|
= interval_tree::Interval<file_off_t, lnav::document::hier_node*>;
|
2022-05-11 04:58:32 +00:00
|
|
|
|
2022-05-23 03:44:18 +00:00
|
|
|
std::shared_ptr<lnav::document::sections_tree_t> pss_interval_tree;
|
|
|
|
std::vector<std::unique_ptr<lnav::document::hier_node>> pss_hier_nods;
|
2022-05-11 04:58:32 +00:00
|
|
|
std::shared_ptr<hier_tree_t> pss_hier_tree;
|
|
|
|
};
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
static void
|
|
|
|
open_pretty_view()
|
2018-11-09 17:45:19 +00:00
|
|
|
{
|
2022-03-16 22:38:08 +00:00
|
|
|
static const char* NOTHING_MSG = "Nothing to pretty-print";
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-05-11 04:58:32 +00:00
|
|
|
auto* top_tc = *lnav_data.ld_view_stack.top();
|
|
|
|
auto* pretty_tc = &lnav_data.ld_views[LNV_PRETTY];
|
|
|
|
auto* log_tc = &lnav_data.ld_views[LNV_LOG];
|
|
|
|
auto* text_tc = &lnav_data.ld_views[LNV_TEXT];
|
2018-11-09 17:45:19 +00:00
|
|
|
attr_line_t full_text;
|
|
|
|
|
|
|
|
delete pretty_tc->get_sub_source();
|
2019-04-18 11:26:24 +00:00
|
|
|
pretty_tc->set_sub_source(nullptr);
|
2018-11-09 17:45:19 +00:00
|
|
|
if (top_tc->get_inner_height() == 0) {
|
|
|
|
pretty_tc->set_sub_source(new plain_text_source(NOTHING_MSG));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-23 03:44:18 +00:00
|
|
|
std::vector<lnav::document::section_interval_t> all_intervals;
|
|
|
|
std::vector<std::unique_ptr<lnav::document::hier_node>> hier_nodes;
|
2022-05-11 04:58:32 +00:00
|
|
|
std::vector<pretty_sub_source::hier_interval_t> hier_tree_vec;
|
2018-11-09 17:45:19 +00:00
|
|
|
if (top_tc == log_tc) {
|
2022-08-02 18:25:19 +00:00
|
|
|
auto& lss = lnav_data.ld_log_source;
|
2018-11-09 17:45:19 +00:00
|
|
|
bool first_line = true;
|
|
|
|
|
2022-08-02 18:25:19 +00:00
|
|
|
for (auto vl = log_tc->get_top(); vl <= log_tc->get_bottom(); ++vl) {
|
2018-11-09 17:45:19 +00:00
|
|
|
content_line_t cl = lss.at(vl);
|
2022-03-31 15:59:19 +00:00
|
|
|
auto lf = lss.find(cl);
|
2018-11-09 17:45:19 +00:00
|
|
|
auto ll = lf->begin() + cl;
|
|
|
|
shared_buffer_ref sbr;
|
|
|
|
|
2020-12-06 05:51:46 +00:00
|
|
|
if (!first_line && !ll->is_message()) {
|
2018-11-09 17:45:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto ll_start = lf->message_start(ll);
|
|
|
|
attr_line_t al;
|
|
|
|
|
2022-05-11 04:58:32 +00:00
|
|
|
vl -= vis_line_t(std::distance(ll_start, ll));
|
2022-03-16 22:38:08 +00:00
|
|
|
lss.text_value_for_line(
|
|
|
|
*log_tc,
|
|
|
|
vl,
|
|
|
|
al.get_string(),
|
|
|
|
text_sub_source::RF_FULL | text_sub_source::RF_REWRITE);
|
2018-11-09 17:45:19 +00:00
|
|
|
lss.text_attrs_for_line(*log_tc, vl, al.get_attrs());
|
2022-08-09 06:14:02 +00:00
|
|
|
scrub_ansi_string(al.get_string(), &al.get_attrs());
|
2020-12-07 07:52:09 +00:00
|
|
|
if (log_tc->get_hide_fields()) {
|
|
|
|
al.apply_hide();
|
|
|
|
}
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-05-11 04:58:32 +00:00
|
|
|
const auto orig_lr
|
2022-03-16 22:38:08 +00:00
|
|
|
= find_string_attr_range(al.get_attrs(), &SA_ORIGINAL_LINE);
|
2022-05-11 04:58:32 +00:00
|
|
|
const auto body_lr
|
|
|
|
= find_string_attr_range(al.get_attrs(), &SA_BODY);
|
|
|
|
auto orig_al = al.subline(orig_lr.lr_start, orig_lr.length());
|
|
|
|
auto prefix_al = al.subline(0, orig_lr.lr_start);
|
2018-11-09 17:45:19 +00:00
|
|
|
attr_line_t pretty_al;
|
2022-03-31 15:59:19 +00:00
|
|
|
std::vector<attr_line_t> pretty_lines;
|
2022-05-11 04:58:32 +00:00
|
|
|
data_scanner ds(orig_al.get_string(),
|
|
|
|
body_lr.is_valid()
|
|
|
|
? body_lr.lr_start - orig_lr.lr_start
|
|
|
|
: orig_lr.lr_start);
|
|
|
|
pretty_printer pp(&ds, orig_al.get_attrs());
|
|
|
|
auto start_off = full_text.length();
|
|
|
|
|
|
|
|
if (body_lr.is_valid()) {
|
|
|
|
// TODO: dump more details of the line in the output.
|
|
|
|
pp.append_to(pretty_al);
|
|
|
|
} else {
|
|
|
|
pretty_al = orig_al;
|
|
|
|
}
|
2018-11-09 17:45:19 +00:00
|
|
|
|
|
|
|
pretty_al.split_lines(pretty_lines);
|
|
|
|
|
2022-05-11 04:58:32 +00:00
|
|
|
auto curr_intervals = pp.take_intervals();
|
|
|
|
auto line_hier_root = pp.take_hier_root();
|
|
|
|
auto line_off = 0;
|
2022-03-16 22:38:08 +00:00
|
|
|
for (auto& pretty_line : pretty_lines) {
|
|
|
|
if (pretty_line.empty() && &pretty_line == &pretty_lines.back())
|
|
|
|
{
|
2018-11-09 17:45:19 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
pretty_line.insert(0, prefix_al);
|
|
|
|
pretty_line.append("\n");
|
2022-05-11 04:58:32 +00:00
|
|
|
for (auto& interval : curr_intervals) {
|
|
|
|
if (line_off <= interval.start) {
|
|
|
|
interval.start += prefix_al.length();
|
|
|
|
interval.stop += prefix_al.length();
|
|
|
|
} else if (line_off < interval.stop) {
|
|
|
|
interval.stop += prefix_al.length();
|
|
|
|
}
|
|
|
|
}
|
2022-05-23 03:44:18 +00:00
|
|
|
lnav::document::hier_node::depth_first(
|
2022-05-11 04:58:32 +00:00
|
|
|
line_hier_root.get(),
|
|
|
|
[line_off, prefix_len = prefix_al.length()](auto* hn) {
|
|
|
|
if (line_off <= hn->hn_start) {
|
|
|
|
hn->hn_start += prefix_len;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
line_off += pretty_line.length();
|
2018-11-09 17:45:19 +00:00
|
|
|
full_text.append(pretty_line);
|
|
|
|
}
|
|
|
|
|
|
|
|
first_line = false;
|
2022-05-11 04:58:32 +00:00
|
|
|
for (auto& interval : curr_intervals) {
|
|
|
|
interval.start += start_off;
|
|
|
|
interval.stop += start_off;
|
|
|
|
}
|
2022-05-23 03:44:18 +00:00
|
|
|
lnav::document::hier_node::depth_first(
|
2022-05-11 04:58:32 +00:00
|
|
|
line_hier_root.get(),
|
|
|
|
[start_off](auto* hn) { hn->hn_start += start_off; });
|
|
|
|
hier_nodes.emplace_back(std::move(line_hier_root));
|
|
|
|
hier_tree_vec.emplace_back(
|
|
|
|
start_off, full_text.length(), hier_nodes.back().get());
|
|
|
|
all_intervals.insert(
|
|
|
|
all_intervals.end(),
|
|
|
|
std::make_move_iterator(curr_intervals.begin()),
|
|
|
|
std::make_move_iterator(curr_intervals.end()));
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!full_text.empty()) {
|
|
|
|
full_text.erase(full_text.length() - 1, 1);
|
|
|
|
}
|
2022-03-16 22:38:08 +00:00
|
|
|
} else if (top_tc == text_tc) {
|
2022-05-11 04:58:32 +00:00
|
|
|
if (text_tc->listview_rows(*text_tc)) {
|
2022-08-03 20:46:36 +00:00
|
|
|
std::vector<attr_line_t> rows;
|
|
|
|
rows.resize(text_tc->get_bottom() - text_tc->get_top() + 1);
|
|
|
|
text_tc->listview_value_for_rows(
|
|
|
|
*text_tc, text_tc->get_top(), rows);
|
|
|
|
attr_line_t orig_al;
|
|
|
|
|
|
|
|
for (const auto& row : rows) {
|
|
|
|
orig_al.append(row);
|
2022-05-11 04:58:32 +00:00
|
|
|
}
|
2022-08-03 20:46:36 +00:00
|
|
|
|
|
|
|
data_scanner ds(orig_al.get_string());
|
2018-11-09 17:45:19 +00:00
|
|
|
string_attrs_t sa;
|
2022-08-03 20:46:36 +00:00
|
|
|
pretty_printer pp(&ds, orig_al.get_attrs());
|
2018-11-09 17:45:19 +00:00
|
|
|
|
|
|
|
pp.append_to(full_text);
|
2022-05-11 04:58:32 +00:00
|
|
|
all_intervals = pp.take_intervals();
|
|
|
|
hier_nodes.emplace_back(pp.take_hier_root());
|
|
|
|
hier_tree_vec.emplace_back(
|
|
|
|
0, full_text.length(), hier_nodes.back().get());
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-11 04:58:32 +00:00
|
|
|
auto* pts = new pretty_sub_source();
|
2022-05-23 03:44:18 +00:00
|
|
|
pts->pss_interval_tree = std::make_shared<lnav::document::sections_tree_t>(
|
2022-05-11 04:58:32 +00:00
|
|
|
std::move(all_intervals));
|
|
|
|
pts->pss_hier_nods = std::move(hier_nodes);
|
|
|
|
pts->pss_hier_tree = std::make_shared<pretty_sub_source::hier_tree_t>(
|
|
|
|
std::move(hier_tree_vec));
|
2018-11-09 17:45:19 +00:00
|
|
|
pts->replace_with(full_text);
|
|
|
|
pretty_tc->set_sub_source(pts);
|
|
|
|
if (lnav_data.ld_last_pretty_print_top != log_tc->get_top()) {
|
2022-06-22 18:25:11 +00:00
|
|
|
pretty_tc->set_top(0_vl);
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
lnav_data.ld_last_pretty_print_top = log_tc->get_top();
|
|
|
|
pretty_tc->redo_search();
|
|
|
|
}
|
|
|
|
|
2022-05-23 03:44:18 +00:00
|
|
|
template<typename T>
|
|
|
|
static void
|
|
|
|
ignore_case(const T&)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
static void
|
|
|
|
build_all_help_text()
|
2018-11-09 17:45:19 +00:00
|
|
|
{
|
|
|
|
if (!lnav_data.ld_help_source.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-23 03:44:18 +00:00
|
|
|
shlex lexer(help_md.to_string_fragment());
|
2022-03-31 15:59:19 +00:00
|
|
|
std::string sub_help_text;
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
lexer.with_ignore_quotes(true).eval(
|
2023-07-11 04:39:01 +00:00
|
|
|
sub_help_text,
|
|
|
|
scoped_resolver{&lnav_data.ld_exec_context.ec_global_vars});
|
2022-05-23 03:44:18 +00:00
|
|
|
|
|
|
|
md2attr_line mdal;
|
|
|
|
auto parse_res = md4cpp::parse(sub_help_text, mdal);
|
|
|
|
attr_line_t all_help_text = parse_res.unwrap();
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-03-31 15:59:19 +00:00
|
|
|
std::map<std::string, help_text*> sql_funcs;
|
|
|
|
std::map<std::string, help_text*> sql_keywords;
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
for (const auto& iter : sqlite_function_help) {
|
2018-11-09 17:45:19 +00:00
|
|
|
switch (iter.second->ht_context) {
|
2019-05-08 12:30:59 +00:00
|
|
|
case help_context_t::HC_SQL_FUNCTION:
|
|
|
|
case help_context_t::HC_SQL_TABLE_VALUED_FUNCTION:
|
2018-11-09 17:45:19 +00:00
|
|
|
sql_funcs[iter.second->ht_name] = iter.second;
|
|
|
|
break;
|
2019-05-08 12:30:59 +00:00
|
|
|
case help_context_t::HC_SQL_KEYWORD:
|
2018-11-09 17:45:19 +00:00
|
|
|
sql_keywords[iter.second->ht_name] = iter.second;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-23 03:44:18 +00:00
|
|
|
all_help_text.append("\n").append("Command Reference"_h2);
|
|
|
|
|
|
|
|
for (const auto& cmd : lnav_commands) {
|
|
|
|
if (cmd.second->c_help.ht_summary == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
all_help_text.append(2, '\n');
|
|
|
|
format_help_text_for_term(cmd.second->c_help, 70, all_help_text);
|
|
|
|
if (!cmd.second->c_help.ht_example.empty()) {
|
|
|
|
all_help_text.append("\n");
|
|
|
|
format_example_text_for_term(
|
|
|
|
cmd.second->c_help, eval_example, 90, all_help_text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
all_help_text.append("\n").append("SQL Reference"_h2);
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
for (const auto& iter : sql_funcs) {
|
2018-11-09 17:45:19 +00:00
|
|
|
all_help_text.append(2, '\n');
|
2022-05-23 03:44:18 +00:00
|
|
|
format_help_text_for_term(*iter.second, 70, all_help_text);
|
2018-11-09 17:45:19 +00:00
|
|
|
if (!iter.second->ht_example.empty()) {
|
|
|
|
all_help_text.append(1, '\n');
|
2022-03-16 22:38:08 +00:00
|
|
|
format_example_text_for_term(
|
|
|
|
*iter.second, eval_example, 90, all_help_text);
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
for (const auto& iter : sql_keywords) {
|
2018-11-09 17:45:19 +00:00
|
|
|
all_help_text.append(2, '\n');
|
2022-05-23 03:44:18 +00:00
|
|
|
format_help_text_for_term(*iter.second, 70, all_help_text);
|
2018-11-09 17:45:19 +00:00
|
|
|
if (!iter.second->ht_example.empty()) {
|
|
|
|
all_help_text.append(1, '\n');
|
2022-03-16 22:38:08 +00:00
|
|
|
format_example_text_for_term(
|
|
|
|
*iter.second, eval_example, 79, all_help_text);
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lnav_data.ld_help_source.replace_with(all_help_text);
|
2021-08-26 16:05:26 +00:00
|
|
|
lnav_data.ld_views[LNV_HELP].redo_search();
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
|
2022-08-03 23:05:37 +00:00
|
|
|
bool
|
|
|
|
handle_winch()
|
|
|
|
{
|
|
|
|
static auto* filter_source = injector::get<filter_sub_source*>();
|
|
|
|
|
|
|
|
if (!lnav_data.ld_winched) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct winsize size;
|
|
|
|
|
|
|
|
lnav_data.ld_winched = false;
|
|
|
|
|
|
|
|
if (ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) {
|
|
|
|
resizeterm(size.ws_row, size.ws_col);
|
|
|
|
}
|
|
|
|
if (lnav_data.ld_rl_view != nullptr) {
|
|
|
|
lnav_data.ld_rl_view->do_update();
|
|
|
|
lnav_data.ld_rl_view->window_change();
|
|
|
|
}
|
|
|
|
filter_source->fss_editor->window_change();
|
|
|
|
for (auto& sc : lnav_data.ld_status) {
|
|
|
|
sc.window_change();
|
|
|
|
}
|
|
|
|
lnav_data.ld_view_stack.set_needs_update();
|
|
|
|
lnav_data.ld_doc_view.set_needs_update();
|
|
|
|
lnav_data.ld_example_view.set_needs_update();
|
|
|
|
lnav_data.ld_match_view.set_needs_update();
|
|
|
|
lnav_data.ld_filter_view.set_needs_update();
|
|
|
|
lnav_data.ld_files_view.set_needs_update();
|
|
|
|
lnav_data.ld_spectro_details_view.set_needs_update();
|
|
|
|
lnav_data.ld_user_message_view.set_needs_update();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
void
|
|
|
|
layout_views()
|
2018-11-09 17:45:19 +00:00
|
|
|
{
|
|
|
|
unsigned long width, height;
|
|
|
|
|
|
|
|
getmaxyx(lnav_data.ld_window, height, width);
|
|
|
|
int doc_height;
|
|
|
|
bool doc_side_by_side = width > (90 + 60);
|
2022-03-16 22:38:08 +00:00
|
|
|
bool preview_status_open
|
|
|
|
= !lnav_data.ld_preview_status_source.get_description().empty();
|
2018-11-11 06:55:08 +00:00
|
|
|
bool filter_status_open = false;
|
2022-07-05 18:06:37 +00:00
|
|
|
auto is_spectro = false;
|
2018-11-11 06:55:08 +00:00
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
lnav_data.ld_view_stack.top() | [&](auto tc) {
|
2022-07-05 18:06:37 +00:00
|
|
|
is_spectro = (tc == &lnav_data.ld_views[LNV_SPECTRO]);
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
text_sub_source* tss = tc->get_sub_source();
|
2018-11-11 06:55:08 +00:00
|
|
|
|
|
|
|
if (tss == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tss->tss_supports_filtering) {
|
|
|
|
filter_status_open = true;
|
|
|
|
}
|
|
|
|
};
|
2018-11-09 17:45:19 +00:00
|
|
|
|
|
|
|
if (doc_side_by_side) {
|
2022-03-16 22:38:08 +00:00
|
|
|
doc_height = std::max(lnav_data.ld_doc_source.text_line_count(),
|
|
|
|
lnav_data.ld_example_source.text_line_count());
|
2018-11-09 17:45:19 +00:00
|
|
|
} else {
|
2022-03-16 22:38:08 +00:00
|
|
|
doc_height = lnav_data.ld_doc_source.text_line_count()
|
|
|
|
+ lnav_data.ld_example_source.text_line_count();
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
int preview_height = lnav_data.ld_preview_hidden
|
|
|
|
? 0
|
|
|
|
: lnav_data.ld_preview_source.text_line_count();
|
2018-11-09 17:45:19 +00:00
|
|
|
int match_rows = lnav_data.ld_match_source.text_line_count();
|
2022-03-31 15:59:19 +00:00
|
|
|
int match_height = std::min((unsigned long) match_rows, (height - 4) / 2);
|
2018-11-09 17:45:19 +00:00
|
|
|
|
|
|
|
lnav_data.ld_match_view.set_height(vis_line_t(match_height));
|
|
|
|
|
2022-04-12 23:07:13 +00:00
|
|
|
int um_rows = lnav_data.ld_user_message_source.text_line_count();
|
|
|
|
if (um_rows > 0
|
|
|
|
&& std::chrono::steady_clock::now()
|
|
|
|
> lnav_data.ld_user_message_expiration)
|
|
|
|
{
|
|
|
|
lnav_data.ld_user_message_source.clear();
|
|
|
|
um_rows = 0;
|
|
|
|
}
|
|
|
|
int um_height = std::min((unsigned long) um_rows, (height - 4) / 2);
|
|
|
|
|
|
|
|
lnav_data.ld_user_message_view.set_height(vis_line_t(um_height));
|
|
|
|
|
|
|
|
if (doc_height + 14
|
|
|
|
> ((int) height - match_height - um_height - preview_height - 2))
|
|
|
|
{
|
2018-11-09 17:45:19 +00:00
|
|
|
preview_height = 0;
|
|
|
|
preview_status_open = false;
|
|
|
|
}
|
|
|
|
|
2022-04-12 23:07:13 +00:00
|
|
|
if (doc_height + 14 > ((int) height - match_height - um_height - 2)) {
|
2020-12-14 05:11:07 +00:00
|
|
|
doc_height = lnav_data.ld_doc_source.text_line_count();
|
2022-04-12 23:07:13 +00:00
|
|
|
if (doc_height + 14 > ((int) height - match_height - um_height - 2)) {
|
2020-12-14 05:11:07 +00:00
|
|
|
doc_height = 0;
|
|
|
|
}
|
2020-12-08 21:24:29 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 17:45:19 +00:00
|
|
|
bool doc_open = doc_height > 0;
|
2022-04-30 20:05:42 +00:00
|
|
|
bool filters_open = (lnav_data.ld_mode == ln_mode_t::FILTER
|
|
|
|
|| lnav_data.ld_mode == ln_mode_t::FILES
|
|
|
|
|| lnav_data.ld_mode == ln_mode_t::SEARCH_FILTERS
|
|
|
|
|| lnav_data.ld_mode == ln_mode_t::SEARCH_FILES)
|
2022-03-16 22:38:08 +00:00
|
|
|
&& !preview_status_open && !doc_open;
|
2022-05-11 04:58:32 +00:00
|
|
|
bool breadcrumb_open = (lnav_data.ld_mode == ln_mode_t::BREADCRUMBS);
|
2021-06-11 06:01:05 +00:00
|
|
|
int filter_height = filters_open ? 5 : 0;
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
int bottom_height = (doc_open ? 1 : 0) + doc_height
|
|
|
|
+ (preview_status_open ? 1 : 0) + preview_height + 1 // bottom status
|
2022-07-05 18:06:37 +00:00
|
|
|
+ match_height + um_height + lnav_data.ld_rl_view->get_height()
|
|
|
|
+ (is_spectro && !doc_open ? 5 : 0);
|
2022-03-16 22:38:08 +00:00
|
|
|
|
|
|
|
for (auto& tc : lnav_data.ld_views) {
|
|
|
|
tc.set_height(vis_line_t(-(bottom_height + (filter_status_open ? 1 : 0)
|
|
|
|
+ (filters_open ? 1 : 0) + filter_height)));
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
2018-11-11 06:55:08 +00:00
|
|
|
lnav_data.ld_status[LNS_FILTER].set_visible(filter_status_open);
|
2018-11-09 17:45:19 +00:00
|
|
|
lnav_data.ld_status[LNS_FILTER].set_enabled(filters_open);
|
2019-02-14 05:54:40 +00:00
|
|
|
lnav_data.ld_status[LNS_FILTER].set_top(
|
|
|
|
-(bottom_height + filter_height + 1 + (filters_open ? 1 : 0)));
|
|
|
|
lnav_data.ld_status[LNS_FILTER_HELP].set_visible(filters_open);
|
2022-03-16 22:38:08 +00:00
|
|
|
lnav_data.ld_status[LNS_FILTER_HELP].set_top(
|
|
|
|
-(bottom_height + filter_height + 1));
|
2022-04-12 23:07:13 +00:00
|
|
|
lnav_data.ld_status[LNS_BOTTOM].set_top(-(match_height + um_height + 2));
|
2022-05-11 04:58:32 +00:00
|
|
|
lnav_data.ld_status[LNS_BOTTOM].set_enabled(!filters_open
|
|
|
|
&& !breadcrumb_open);
|
2018-11-09 17:45:19 +00:00
|
|
|
lnav_data.ld_status[LNS_DOC].set_top(height - bottom_height);
|
|
|
|
lnav_data.ld_status[LNS_DOC].set_visible(doc_open);
|
2022-03-16 22:38:08 +00:00
|
|
|
lnav_data.ld_status[LNS_PREVIEW].set_top(height - bottom_height
|
|
|
|
+ (doc_open ? 1 : 0) + doc_height);
|
2018-11-09 17:45:19 +00:00
|
|
|
lnav_data.ld_status[LNS_PREVIEW].set_visible(preview_status_open);
|
2022-07-05 18:06:37 +00:00
|
|
|
lnav_data.ld_status[LNS_SPECTRO].set_top(height - bottom_height - 1);
|
|
|
|
lnav_data.ld_status[LNS_SPECTRO].set_visible(is_spectro);
|
|
|
|
lnav_data.ld_status[LNS_SPECTRO].set_enabled(lnav_data.ld_mode
|
|
|
|
== ln_mode_t::SPECTRO_DETAILS);
|
2018-11-09 17:45:19 +00:00
|
|
|
|
|
|
|
if (!doc_open || doc_side_by_side) {
|
|
|
|
lnav_data.ld_doc_view.set_height(vis_line_t(doc_height));
|
|
|
|
} else {
|
2022-03-16 22:38:08 +00:00
|
|
|
lnav_data.ld_doc_view.set_height(
|
|
|
|
vis_line_t(lnav_data.ld_doc_source.text_line_count()));
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
lnav_data.ld_doc_view.set_y(height - bottom_height + 1);
|
|
|
|
|
|
|
|
if (!doc_open || doc_side_by_side) {
|
|
|
|
lnav_data.ld_example_view.set_height(vis_line_t(doc_height));
|
2021-06-21 04:58:45 +00:00
|
|
|
lnav_data.ld_example_view.set_x(doc_open ? 90 : 0);
|
2018-11-09 17:45:19 +00:00
|
|
|
lnav_data.ld_example_view.set_y(height - bottom_height + 1);
|
|
|
|
} else {
|
2022-03-16 22:38:08 +00:00
|
|
|
lnav_data.ld_example_view.set_height(
|
|
|
|
vis_line_t(lnav_data.ld_example_source.text_line_count()));
|
2018-11-09 17:45:19 +00:00
|
|
|
lnav_data.ld_example_view.set_x(0);
|
2022-03-16 22:38:08 +00:00
|
|
|
lnav_data.ld_example_view.set_y(
|
|
|
|
height - bottom_height + lnav_data.ld_doc_view.get_height() + 1);
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lnav_data.ld_filter_view.set_height(vis_line_t(filter_height));
|
|
|
|
lnav_data.ld_filter_view.set_y(height - bottom_height - filter_height);
|
|
|
|
lnav_data.ld_filter_view.set_width(width);
|
|
|
|
|
2020-10-29 04:21:57 +00:00
|
|
|
lnav_data.ld_files_view.set_height(vis_line_t(filter_height));
|
|
|
|
lnav_data.ld_files_view.set_y(height - bottom_height - filter_height);
|
|
|
|
lnav_data.ld_files_view.set_width(width);
|
|
|
|
|
2018-11-09 17:45:19 +00:00
|
|
|
lnav_data.ld_preview_view.set_height(vis_line_t(preview_height));
|
2022-03-16 22:38:08 +00:00
|
|
|
lnav_data.ld_preview_view.set_y(height - bottom_height + 1
|
|
|
|
+ (doc_open ? 1 : 0) + doc_height);
|
2022-04-12 23:07:13 +00:00
|
|
|
lnav_data.ld_user_message_view.set_y(
|
|
|
|
height - lnav_data.ld_rl_view->get_height() - match_height - um_height);
|
2022-07-05 18:06:37 +00:00
|
|
|
|
|
|
|
lnav_data.ld_spectro_details_view.set_y(height - bottom_height);
|
|
|
|
lnav_data.ld_spectro_details_view.set_height(
|
|
|
|
is_spectro && !doc_open ? 5_vl : 0_vl);
|
|
|
|
lnav_data.ld_spectro_details_view.set_width(width);
|
|
|
|
lnav_data.ld_spectro_details_view.set_title("spectro-details");
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
lnav_data.ld_match_view.set_y(height - lnav_data.ld_rl_view->get_height()
|
|
|
|
- match_height);
|
2018-11-09 17:45:19 +00:00
|
|
|
lnav_data.ld_rl_view->set_width(width);
|
|
|
|
}
|
|
|
|
|
2022-04-30 20:05:42 +00:00
|
|
|
void
|
|
|
|
update_hits(textview_curses* tc)
|
|
|
|
{
|
|
|
|
if (isendwin()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto top_tc = lnav_data.ld_view_stack.top();
|
|
|
|
|
|
|
|
if (top_tc && tc == *top_tc) {
|
|
|
|
lnav_data.ld_bottom_source.update_hits(tc);
|
|
|
|
|
|
|
|
if (lnav_data.ld_mode == ln_mode_t::SEARCH) {
|
|
|
|
const auto MAX_MATCH_COUNT = 10_vl;
|
|
|
|
const auto PREVIEW_SIZE = MAX_MATCH_COUNT + 1_vl;
|
|
|
|
|
|
|
|
int preview_count = 0;
|
|
|
|
|
|
|
|
vis_bookmarks& bm = tc->get_bookmarks();
|
|
|
|
const auto& bv = bm[&textview_curses::BM_SEARCH];
|
|
|
|
auto vl = tc->get_top();
|
|
|
|
unsigned long width;
|
|
|
|
vis_line_t height;
|
|
|
|
attr_line_t all_matches;
|
|
|
|
char linebuf[64];
|
|
|
|
int last_line = tc->get_inner_height();
|
|
|
|
|
|
|
|
snprintf(linebuf, sizeof(linebuf), "%d", last_line);
|
2023-06-28 18:15:15 +00:00
|
|
|
auto max_line_width = static_cast<int>(strlen(linebuf));
|
2022-04-30 20:05:42 +00:00
|
|
|
|
|
|
|
tc->get_dimensions(height, width);
|
|
|
|
vl += height;
|
|
|
|
if (vl > PREVIEW_SIZE) {
|
|
|
|
vl -= PREVIEW_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto prev_vl = bv.prev(tc->get_top());
|
|
|
|
|
2022-06-29 18:04:37 +00:00
|
|
|
if (prev_vl) {
|
2023-06-28 18:15:15 +00:00
|
|
|
if (prev_vl.value() < 0_vl
|
|
|
|
|| prev_vl.value() >= tc->get_inner_height())
|
|
|
|
{
|
|
|
|
log_error("stale search bookmark for %s: %d",
|
|
|
|
tc->get_title().c_str(),
|
|
|
|
prev_vl.value());
|
|
|
|
} else {
|
|
|
|
attr_line_t al;
|
|
|
|
|
|
|
|
tc->textview_value_for_row(prev_vl.value(), al);
|
|
|
|
if (preview_count > 0) {
|
|
|
|
all_matches.append("\n");
|
|
|
|
}
|
|
|
|
snprintf(linebuf,
|
|
|
|
sizeof(linebuf),
|
|
|
|
"L%*d: ",
|
|
|
|
max_line_width,
|
|
|
|
(int) prev_vl.value());
|
|
|
|
all_matches.append(linebuf).append(al);
|
|
|
|
preview_count += 1;
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-29 18:04:37 +00:00
|
|
|
nonstd::optional<vis_line_t> next_vl;
|
|
|
|
while ((next_vl = bv.next(vl)) && preview_count < MAX_MATCH_COUNT) {
|
2023-06-28 18:15:15 +00:00
|
|
|
if (next_vl.value() < 0_vl
|
|
|
|
|| next_vl.value() >= tc->get_inner_height())
|
|
|
|
{
|
|
|
|
log_error("stale search bookmark for %s: %d",
|
|
|
|
tc->get_title().c_str(),
|
|
|
|
next_vl.value());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-04-30 20:05:42 +00:00
|
|
|
attr_line_t al;
|
|
|
|
|
2022-06-29 18:04:37 +00:00
|
|
|
vl = next_vl.value();
|
2022-04-30 20:05:42 +00:00
|
|
|
tc->textview_value_for_row(vl, al);
|
|
|
|
if (preview_count > 0) {
|
|
|
|
all_matches.append("\n");
|
|
|
|
}
|
|
|
|
snprintf(linebuf,
|
|
|
|
sizeof(linebuf),
|
|
|
|
"L%*d: ",
|
|
|
|
max_line_width,
|
|
|
|
(int) vl);
|
|
|
|
all_matches.append(linebuf).append(al);
|
|
|
|
preview_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (preview_count > 0) {
|
|
|
|
lnav_data.ld_preview_status_source.get_description().set_value(
|
|
|
|
"Matching lines for search");
|
|
|
|
lnav_data.ld_preview_source.replace_with(all_matches)
|
|
|
|
.set_text_format(text_format_t::TF_UNKNOWN);
|
|
|
|
lnav_data.ld_preview_view.set_needs_update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 15:59:19 +00:00
|
|
|
static std::unordered_map<std::string, attr_line_t> EXAMPLE_RESULTS;
|
2019-05-08 12:30:59 +00:00
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
void
|
|
|
|
execute_examples()
|
2018-11-09 17:45:19 +00:00
|
|
|
{
|
2022-03-16 22:38:08 +00:00
|
|
|
db_label_source& dls = lnav_data.ld_db_row_source;
|
|
|
|
db_overlay_source& dos = lnav_data.ld_db_overlay;
|
|
|
|
textview_curses& db_tc = lnav_data.ld_views[LNV_DB];
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2023-07-14 04:56:11 +00:00
|
|
|
auto old_width = dls.dls_max_column_width;
|
|
|
|
dls.dls_max_column_width = 15;
|
2022-03-16 22:38:08 +00:00
|
|
|
for (auto& help_iter : sqlite_function_help) {
|
2023-07-14 04:56:11 +00:00
|
|
|
auto& ht = *(help_iter.second);
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
for (auto& ex : ht.ht_example) {
|
2022-03-31 15:59:19 +00:00
|
|
|
std::string alt_msg;
|
2019-05-08 12:30:59 +00:00
|
|
|
attr_line_t result;
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2020-05-07 14:08:59 +00:00
|
|
|
if (!ex.he_cmd) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-09 17:45:19 +00:00
|
|
|
switch (ht.ht_context) {
|
2020-12-08 21:24:29 +00:00
|
|
|
case help_context_t::HC_SQL_KEYWORD:
|
|
|
|
case help_context_t::HC_SQL_INFIX:
|
2019-05-08 12:30:59 +00:00
|
|
|
case help_context_t::HC_SQL_FUNCTION:
|
|
|
|
case help_context_t::HC_SQL_TABLE_VALUED_FUNCTION: {
|
2021-01-18 07:29:08 +00:00
|
|
|
exec_context ec;
|
|
|
|
|
2018-11-09 17:45:19 +00:00
|
|
|
execute_sql(ec, ex.he_cmd, alt_msg);
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
if (dls.dls_rows.size() == 1 && dls.dls_rows[0].size() == 1)
|
|
|
|
{
|
2019-05-08 12:30:59 +00:00
|
|
|
result.append(dls.dls_rows[0][0]);
|
2018-11-09 17:45:19 +00:00
|
|
|
} else {
|
|
|
|
attr_line_t al;
|
2022-03-16 22:38:08 +00:00
|
|
|
dos.list_value_for_overlay(db_tc, 0, 1, 0_vl, al);
|
2019-05-08 12:30:59 +00:00
|
|
|
result.append(al);
|
2022-03-16 22:38:08 +00:00
|
|
|
for (int lpc = 0; lpc < (int) dls.text_line_count();
|
2022-08-01 21:56:48 +00:00
|
|
|
lpc++)
|
|
|
|
{
|
2018-11-09 17:45:19 +00:00
|
|
|
al.clear();
|
2022-03-16 22:38:08 +00:00
|
|
|
dls.text_value_for_line(
|
|
|
|
db_tc, lpc, al.get_string(), false);
|
|
|
|
dls.text_attrs_for_line(db_tc, lpc, al.get_attrs());
|
2020-12-23 23:01:21 +00:00
|
|
|
std::replace(al.get_string().begin(),
|
|
|
|
al.get_string().end(),
|
|
|
|
'\n',
|
|
|
|
' ');
|
2022-03-16 22:38:08 +00:00
|
|
|
result.append("\n").append(al);
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-08 12:30:59 +00:00
|
|
|
EXAMPLE_RESULTS[ex.he_cmd] = result;
|
|
|
|
|
2023-07-10 17:35:18 +00:00
|
|
|
log_trace("example: %s", ex.he_cmd);
|
|
|
|
log_trace("example result: %s",
|
2019-05-08 12:30:59 +00:00
|
|
|
result.get_string().c_str());
|
2018-11-09 17:45:19 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
log_warning("Not executing example: %s", ex.he_cmd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-14 04:56:11 +00:00
|
|
|
dls.dls_max_column_width = old_width;
|
2018-11-09 17:45:19 +00:00
|
|
|
|
|
|
|
dls.clear();
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
attr_line_t
|
|
|
|
eval_example(const help_text& ht, const help_example& ex)
|
2019-05-08 12:30:59 +00:00
|
|
|
{
|
|
|
|
auto iter = EXAMPLE_RESULTS.find(ex.he_cmd);
|
|
|
|
|
|
|
|
if (iter != EXAMPLE_RESULTS.end()) {
|
|
|
|
return iter->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
bool
|
|
|
|
toggle_view(textview_curses* toggle_tc)
|
2018-11-09 17:45:19 +00:00
|
|
|
{
|
2022-03-16 22:38:08 +00:00
|
|
|
textview_curses* tc = lnav_data.ld_view_stack.top().value_or(nullptr);
|
|
|
|
bool retval = false;
|
2018-11-09 17:45:19 +00:00
|
|
|
|
2022-03-31 15:59:19 +00:00
|
|
|
require(toggle_tc != nullptr);
|
2018-11-09 17:45:19 +00:00
|
|
|
require(toggle_tc >= &lnav_data.ld_views[0]);
|
|
|
|
require(toggle_tc < &lnav_data.ld_views[LNV__MAX]);
|
|
|
|
|
|
|
|
if (tc == toggle_tc) {
|
2021-08-26 16:05:26 +00:00
|
|
|
if (lnav_data.ld_view_stack.size() == 1) {
|
2018-11-09 17:45:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
lnav_data.ld_last_view = tc;
|
2021-08-26 16:05:26 +00:00
|
|
|
lnav_data.ld_view_stack.pop_back();
|
2022-03-16 22:38:08 +00:00
|
|
|
} else {
|
2022-08-03 17:55:18 +00:00
|
|
|
if (toggle_tc == &lnav_data.ld_views[LNV_LOG]
|
|
|
|
|| toggle_tc == &lnav_data.ld_views[LNV_TEXT])
|
|
|
|
{
|
|
|
|
rescan_files(true);
|
|
|
|
rebuild_indexes_repeatedly();
|
|
|
|
} else if (toggle_tc == &lnav_data.ld_views[LNV_SCHEMA]) {
|
2018-11-09 17:45:19 +00:00
|
|
|
open_schema_view();
|
2022-03-16 22:38:08 +00:00
|
|
|
} else if (toggle_tc == &lnav_data.ld_views[LNV_PRETTY]) {
|
2018-11-09 17:45:19 +00:00
|
|
|
open_pretty_view();
|
2022-03-16 22:38:08 +00:00
|
|
|
} else if (toggle_tc == &lnav_data.ld_views[LNV_HISTOGRAM]) {
|
2018-11-09 17:45:19 +00:00
|
|
|
// Rebuild to reflect changes in marks.
|
|
|
|
rebuild_hist();
|
2022-03-16 22:38:08 +00:00
|
|
|
} else if (toggle_tc == &lnav_data.ld_views[LNV_HELP]) {
|
2018-11-09 17:45:19 +00:00
|
|
|
build_all_help_text();
|
2022-08-01 21:56:48 +00:00
|
|
|
if (lnav_data.ld_rl_view != nullptr) {
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_1(q, "to return to the previous view"));
|
|
|
|
}
|
2018-11-09 17:45:19 +00:00
|
|
|
}
|
|
|
|
lnav_data.ld_last_view = nullptr;
|
2021-08-26 16:05:26 +00:00
|
|
|
lnav_data.ld_view_stack.push_back(toggle_tc);
|
2018-11-09 17:45:19 +00:00
|
|
|
retval = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensure that the view is on the top of the view stack.
|
|
|
|
*
|
|
|
|
* @param expected_tc The text view that should be on top.
|
|
|
|
* @return True if the view was already on the top of the stack.
|
|
|
|
*/
|
2022-03-16 22:38:08 +00:00
|
|
|
bool
|
|
|
|
ensure_view(textview_curses* expected_tc)
|
2018-11-09 17:45:19 +00:00
|
|
|
{
|
2022-03-16 22:38:08 +00:00
|
|
|
textview_curses* tc = lnav_data.ld_view_stack.top().value_or(nullptr);
|
2018-11-09 17:45:19 +00:00
|
|
|
bool retval = true;
|
|
|
|
|
|
|
|
if (tc != expected_tc) {
|
|
|
|
toggle_view(expected_tc);
|
|
|
|
retval = false;
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
2021-01-17 06:23:20 +00:00
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
bool
|
|
|
|
ensure_view(lnav_view_t expected)
|
2022-03-13 22:49:41 +00:00
|
|
|
{
|
2022-05-11 04:58:32 +00:00
|
|
|
require(expected >= 0);
|
|
|
|
require(expected < LNV__MAX);
|
|
|
|
|
2022-03-13 22:49:41 +00:00
|
|
|
return ensure_view(&lnav_data.ld_views[expected]);
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
nonstd::optional<vis_line_t>
|
2022-06-29 18:04:37 +00:00
|
|
|
next_cluster(nonstd::optional<vis_line_t> (bookmark_vector<vis_line_t>::*f)(
|
|
|
|
vis_line_t) const,
|
2022-03-16 22:38:08 +00:00
|
|
|
const bookmark_type_t* bt,
|
|
|
|
const vis_line_t top)
|
2021-01-17 06:23:20 +00:00
|
|
|
{
|
2022-07-05 18:06:37 +00:00
|
|
|
auto* tc = get_textview_for_mode(lnav_data.ld_mode);
|
|
|
|
auto& bm = tc->get_bookmarks();
|
|
|
|
auto& bv = bm[bt];
|
2021-01-17 06:23:20 +00:00
|
|
|
bool top_is_marked = binary_search(bv.begin(), bv.end(), top);
|
2022-06-29 18:04:37 +00:00
|
|
|
vis_line_t last_top(top), tc_height;
|
|
|
|
nonstd::optional<vis_line_t> new_top = top;
|
2021-01-17 06:23:20 +00:00
|
|
|
unsigned long tc_width;
|
|
|
|
int hit_count = 0;
|
|
|
|
|
|
|
|
tc->get_dimensions(tc_height, tc_width);
|
|
|
|
|
2022-06-29 18:04:37 +00:00
|
|
|
while ((new_top = (bv.*f)(new_top.value()))) {
|
|
|
|
int diff = new_top.value() - last_top;
|
2021-01-17 06:23:20 +00:00
|
|
|
|
|
|
|
hit_count += 1;
|
2023-06-16 04:28:20 +00:00
|
|
|
if (tc->is_selectable() || !top_is_marked || diff > 1) {
|
2021-01-17 06:23:20 +00:00
|
|
|
return new_top;
|
2022-03-31 15:59:19 +00:00
|
|
|
}
|
2022-06-29 18:04:37 +00:00
|
|
|
if (hit_count > 1 && std::abs(new_top.value() - top) >= tc_height) {
|
|
|
|
return vis_line_t(new_top.value() - diff);
|
2022-03-31 15:59:19 +00:00
|
|
|
}
|
|
|
|
if (diff < -1) {
|
2022-06-29 18:04:37 +00:00
|
|
|
last_top = new_top.value();
|
|
|
|
while ((new_top = (bv.*f)(new_top.value()))) {
|
|
|
|
if ((std::abs(last_top - new_top.value()) > 1)
|
2022-03-16 22:38:08 +00:00
|
|
|
|| (hit_count > 1
|
2022-06-29 18:04:37 +00:00
|
|
|
&& (std::abs(top - new_top.value()) >= tc_height)))
|
2022-03-16 22:38:08 +00:00
|
|
|
{
|
2021-01-17 06:23:20 +00:00
|
|
|
break;
|
|
|
|
}
|
2022-06-29 18:04:37 +00:00
|
|
|
last_top = new_top.value();
|
2021-01-17 06:23:20 +00:00
|
|
|
}
|
|
|
|
return last_top;
|
|
|
|
}
|
2022-06-29 18:04:37 +00:00
|
|
|
last_top = new_top.value();
|
2021-01-17 06:23:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (last_top != top) {
|
|
|
|
return last_top;
|
|
|
|
}
|
|
|
|
|
2021-05-14 05:00:26 +00:00
|
|
|
return nonstd::nullopt;
|
2021-01-17 06:23:20 +00:00
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
bool
|
2022-06-29 18:04:37 +00:00
|
|
|
moveto_cluster(nonstd::optional<vis_line_t> (bookmark_vector<vis_line_t>::*f)(
|
|
|
|
vis_line_t) const,
|
2022-03-16 22:38:08 +00:00
|
|
|
const bookmark_type_t* bt,
|
|
|
|
vis_line_t top)
|
2021-01-17 06:23:20 +00:00
|
|
|
{
|
2022-03-16 22:38:08 +00:00
|
|
|
textview_curses* tc = get_textview_for_mode(lnav_data.ld_mode);
|
2021-05-14 05:00:26 +00:00
|
|
|
auto new_top = next_cluster(f, bt, top);
|
2021-01-17 06:23:20 +00:00
|
|
|
|
2021-05-14 05:00:26 +00:00
|
|
|
if (!new_top) {
|
2023-06-16 04:28:20 +00:00
|
|
|
new_top = next_cluster(f, bt, tc->get_selection());
|
2021-01-17 06:23:20 +00:00
|
|
|
}
|
|
|
|
if (new_top != -1) {
|
2022-03-16 22:38:08 +00:00
|
|
|
tc->get_sub_source()->get_location_history() |
|
|
|
|
[new_top](auto lh) { lh->loc_history_append(new_top.value()); };
|
2021-01-17 06:23:20 +00:00
|
|
|
|
|
|
|
if (tc->is_selectable()) {
|
2021-05-14 05:00:26 +00:00
|
|
|
tc->set_selection(new_top.value());
|
2021-01-17 06:23:20 +00:00
|
|
|
} else {
|
2021-05-14 05:00:26 +00:00
|
|
|
tc->set_top(new_top.value());
|
2021-01-17 06:23:20 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-03 17:55:18 +00:00
|
|
|
alerter::singleton().chime("unable to find next bookmark");
|
2021-01-17 06:23:20 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:38:08 +00:00
|
|
|
vis_line_t
|
|
|
|
search_forward_from(textview_curses* tc)
|
2021-01-17 06:23:20 +00:00
|
|
|
{
|
2023-06-16 04:28:20 +00:00
|
|
|
vis_line_t height, retval = tc->get_selection();
|
2021-01-17 06:23:20 +00:00
|
|
|
|
2023-06-16 04:55:42 +00:00
|
|
|
if (!tc->is_selectable()) {
|
|
|
|
auto& krh = lnav_data.ld_key_repeat_history;
|
|
|
|
unsigned long width;
|
2021-01-17 06:23:20 +00:00
|
|
|
|
2023-06-16 04:55:42 +00:00
|
|
|
tc->get_dimensions(height, width);
|
|
|
|
|
|
|
|
if (krh.krh_count > 1 && retval > (krh.krh_start_line + (1.5 * height)))
|
|
|
|
{
|
|
|
|
retval += vis_line_t(0.90 * height);
|
|
|
|
}
|
2021-01-17 06:23:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
2022-04-30 20:05:42 +00:00
|
|
|
|
|
|
|
textview_curses*
|
|
|
|
get_textview_for_mode(ln_mode_t mode)
|
|
|
|
{
|
|
|
|
switch (mode) {
|
|
|
|
case ln_mode_t::SEARCH_FILTERS:
|
|
|
|
case ln_mode_t::FILTER:
|
|
|
|
return &lnav_data.ld_filter_view;
|
|
|
|
case ln_mode_t::SEARCH_FILES:
|
|
|
|
case ln_mode_t::FILES:
|
|
|
|
return &lnav_data.ld_files_view;
|
2022-07-05 18:06:37 +00:00
|
|
|
case ln_mode_t::SPECTRO_DETAILS:
|
|
|
|
case ln_mode_t::SEARCH_SPECTRO_DETAILS:
|
|
|
|
return &lnav_data.ld_spectro_details_view;
|
2022-04-30 20:05:42 +00:00
|
|
|
default:
|
|
|
|
return *lnav_data.ld_view_stack.top();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hist_index_delegate::hist_index_delegate(hist_source2& hs, textview_curses& tc)
|
|
|
|
: hid_source(hs), hid_view(tc)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
hist_index_delegate::index_start(logfile_sub_source& lss)
|
|
|
|
{
|
|
|
|
this->hid_source.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
hist_index_delegate::index_line(logfile_sub_source& lss,
|
|
|
|
logfile* lf,
|
|
|
|
logfile::iterator ll)
|
|
|
|
{
|
|
|
|
if (ll->is_continued() || ll->get_time() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hist_source2::hist_type_t ht;
|
|
|
|
|
|
|
|
switch (ll->get_msg_level()) {
|
|
|
|
case LEVEL_FATAL:
|
|
|
|
case LEVEL_CRITICAL:
|
|
|
|
case LEVEL_ERROR:
|
|
|
|
ht = hist_source2::HT_ERROR;
|
|
|
|
break;
|
|
|
|
case LEVEL_WARNING:
|
|
|
|
ht = hist_source2::HT_WARNING;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ht = hist_source2::HT_NORMAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->hid_source.add_value(ll->get_time(), ht);
|
|
|
|
if (ll->is_marked() || ll->is_expr_marked()) {
|
|
|
|
this->hid_source.add_value(ll->get_time(), hist_source2::HT_MARK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
hist_index_delegate::index_complete(logfile_sub_source& lss)
|
|
|
|
{
|
|
|
|
this->hid_view.reload_data();
|
2022-07-06 18:56:29 +00:00
|
|
|
lnav_data.ld_views[LNV_SPECTRO].reload_data();
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
2022-05-11 04:58:32 +00:00
|
|
|
|
|
|
|
static std::vector<breadcrumb::possibility>
|
|
|
|
view_title_poss()
|
|
|
|
{
|
|
|
|
std::vector<breadcrumb::possibility> retval;
|
|
|
|
|
|
|
|
for (int view_index = 0; view_index < LNV__MAX; view_index++) {
|
|
|
|
attr_line_t display_value{lnav_view_titles[view_index]};
|
|
|
|
nonstd::optional<size_t> quantity;
|
|
|
|
std::string units;
|
|
|
|
|
|
|
|
switch (view_index) {
|
|
|
|
case LNV_LOG:
|
|
|
|
quantity = lnav_data.ld_log_source.file_count();
|
|
|
|
units = "file";
|
|
|
|
break;
|
|
|
|
case LNV_TEXT:
|
|
|
|
quantity = lnav_data.ld_text_source.size();
|
|
|
|
units = "file";
|
|
|
|
break;
|
|
|
|
case LNV_DB:
|
|
|
|
quantity = lnav_data.ld_db_row_source.dls_rows.size();
|
|
|
|
units = "row";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quantity) {
|
|
|
|
display_value.pad_to(8)
|
|
|
|
.append(" (")
|
|
|
|
.append(lnav::roles::number(
|
|
|
|
quantity.value() == 0 ? "no"
|
|
|
|
: fmt::to_string(quantity.value())))
|
2022-07-07 05:19:39 +00:00
|
|
|
.appendf(FMT_STRING(" {}{})"),
|
|
|
|
units,
|
|
|
|
quantity.value() == 1 ? "" : "s");
|
2022-05-11 04:58:32 +00:00
|
|
|
}
|
|
|
|
retval.emplace_back(lnav_view_titles[view_index], display_value);
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_performer(const breadcrumb::crumb::key_t& view_name)
|
|
|
|
{
|
|
|
|
auto* view_title_iter = std::find_if(
|
|
|
|
std::begin(lnav_view_titles),
|
|
|
|
std::end(lnav_view_titles),
|
|
|
|
[&](const char* v) {
|
|
|
|
return strcasecmp(v, view_name.get<std::string>().c_str()) == 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (view_title_iter != std::end(lnav_view_titles)) {
|
|
|
|
ensure_view(lnav_view_t(view_title_iter - lnav_view_titles));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<breadcrumb::crumb>
|
|
|
|
lnav_crumb_source()
|
|
|
|
{
|
|
|
|
std::vector<breadcrumb::crumb> retval;
|
|
|
|
|
|
|
|
auto top_view_opt = lnav_data.ld_view_stack.top();
|
|
|
|
if (!top_view_opt) {
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* top_view = top_view_opt.value();
|
|
|
|
auto view_index = top_view - lnav_data.ld_views;
|
|
|
|
retval.emplace_back(
|
|
|
|
lnav_view_titles[view_index],
|
|
|
|
attr_line_t().append(lnav::roles::status_title(
|
|
|
|
fmt::format(FMT_STRING(" {} "), lnav_view_titles[view_index]))),
|
|
|
|
view_title_poss,
|
|
|
|
view_performer);
|
|
|
|
|
|
|
|
auto* tss = top_view->get_sub_source();
|
|
|
|
if (tss != nullptr) {
|
2023-06-20 18:06:35 +00:00
|
|
|
tss->text_crumbs_for_line(top_view->get_selection(), retval);
|
2022-05-11 04:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|