mirror of https://github.com/tstack/lnav.git
[session] stages
This commit is contained in:
parent
5e42b4cb8a
commit
df3df8369c
|
@ -48,8 +48,6 @@ static pcrepp &ansi_regex()
|
|||
|
||||
void scrub_ansi_string(std::string &str, string_attrs_t &sa)
|
||||
{
|
||||
view_colors &vc = view_colors::singleton();
|
||||
|
||||
pcre_context_static<60> context;
|
||||
pcrepp & regex = ansi_regex();
|
||||
pcre_input pi(str);
|
||||
|
@ -62,6 +60,7 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
|
|||
attr_t attrs = 0;
|
||||
auto bg = nonstd::optional<int>();
|
||||
auto fg = nonstd::optional<int>();
|
||||
auto role = nonstd::optional<int>();
|
||||
size_t lpc;
|
||||
|
||||
switch (pi.get_substr_start(&caps[2])[0]) {
|
||||
|
@ -135,8 +134,7 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
|
|||
|
||||
if (sscanf(&(str[caps[1].c_begin]), "%d", &role_int) == 1) {
|
||||
if (role_int >= 0 && role_int < view_colors::VCR__MAX) {
|
||||
attrs = vc.attrs_for_role(
|
||||
(view_colors::role_t) role_int);
|
||||
role = role_int;
|
||||
has_attrs = true;
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +156,9 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
|
|||
if (attrs) {
|
||||
sa.emplace_back(lr, &view_curses::VC_STYLE, attrs);
|
||||
}
|
||||
role | [&lr, &sa](int r) {
|
||||
sa.emplace_back(lr, &view_curses::VC_ROLE, r);
|
||||
};
|
||||
fg | [&lr, &sa](int color) {
|
||||
sa.emplace_back(lr, &view_curses::VC_FOREGROUND, color);
|
||||
};
|
||||
|
|
|
@ -133,27 +133,12 @@ filename_to_tmp_path(const std::string &filename)
|
|||
return tmp_path / fs::path(subdir_name) / basename;
|
||||
}
|
||||
|
||||
void walk_archive_files(const std::string &filename,
|
||||
const std::function<void(
|
||||
const fs::path&,
|
||||
const fs::directory_entry &)>& callback)
|
||||
{
|
||||
auto tmp_path = filename_to_tmp_path(filename);
|
||||
|
||||
extract(filename);
|
||||
|
||||
for (const auto& entry : fs::recursive_directory_iterator(tmp_path)) {
|
||||
if (!entry.is_regular_file()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
callback(tmp_path, entry);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_ARCHIVE_H
|
||||
static int
|
||||
copy_data(const ghc::filesystem::path &path, struct archive *ar, struct archive *aw)
|
||||
copy_data(const ghc::filesystem::path &path,
|
||||
struct archive *ar,
|
||||
struct archive *aw,
|
||||
struct extract_progress *ep)
|
||||
{
|
||||
int r;
|
||||
const void *buff;
|
||||
|
@ -175,6 +160,7 @@ copy_data(const ghc::filesystem::path &path, struct archive *ar, struct archive
|
|||
}
|
||||
|
||||
total += size;
|
||||
ep->ep_out_size.fetch_add(size);
|
||||
|
||||
if ((total - last_space_check) > (1024 * 1024)) {
|
||||
auto tmp_space = ghc::filesystem::space(path);
|
||||
|
@ -187,7 +173,7 @@ copy_data(const ghc::filesystem::path &path, struct archive *ar, struct archive
|
|||
}
|
||||
}
|
||||
|
||||
void extract(const std::string &filename)
|
||||
static void extract(const std::string &filename, const extract_cb &cb)
|
||||
{
|
||||
static int FLAGS = ARCHIVE_EXTRACT_TIME
|
||||
| ARCHIVE_EXTRACT_PERM
|
||||
|
@ -221,7 +207,9 @@ void extract(const std::string &filename)
|
|||
return;
|
||||
}
|
||||
|
||||
log_info("extracting %s to %s", filename.c_str(), tmp_path.c_str());
|
||||
log_info("extracting %s to %s",
|
||||
filename.c_str(),
|
||||
tmp_path.c_str());
|
||||
while (true) {
|
||||
struct archive_entry *entry;
|
||||
auto r = archive_read_next_header(arc, &entry);
|
||||
|
@ -239,6 +227,9 @@ void extract(const std::string &filename)
|
|||
auto_mem<archive_entry> wentry(archive_entry_free);
|
||||
wentry = archive_entry_clone(entry);
|
||||
auto entry_path = tmp_path / fs::path(archive_entry_pathname(entry));
|
||||
auto prog = cb(entry_path,
|
||||
archive_entry_size_is_set(entry) ?
|
||||
archive_entry_size(entry) : -1);
|
||||
archive_entry_copy_pathname(wentry, entry_path.c_str());
|
||||
auto entry_mode = archive_entry_mode(wentry);
|
||||
|
||||
|
@ -249,7 +240,7 @@ void extract(const std::string &filename)
|
|||
log_error("%s", archive_error_string(ext));
|
||||
}
|
||||
else if (archive_entry_size(entry) > 0) {
|
||||
r = copy_data(tmp_path, arc, ext);
|
||||
r = copy_data(tmp_path, arc, ext, prog);
|
||||
if (r < ARCHIVE_OK) {
|
||||
log_error("%s", archive_error_string(ext));
|
||||
}
|
||||
|
@ -271,12 +262,29 @@ void extract(const std::string &filename)
|
|||
auto_fd(open(done_path.c_str(), O_CREAT | O_WRONLY, 0600));
|
||||
|
||||
// TODO return errors
|
||||
}
|
||||
#else
|
||||
void extract(const std::string &filename)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void walk_archive_files(const std::string &filename,
|
||||
const extract_cb &cb,
|
||||
const std::function<void(
|
||||
const fs::path&,
|
||||
const fs::directory_entry &)>& callback)
|
||||
{
|
||||
#if HAVE_ARCHIVE_H
|
||||
|
||||
auto tmp_path = filename_to_tmp_path(filename);
|
||||
|
||||
extract(filename, cb);
|
||||
|
||||
for (const auto& entry : fs::recursive_directory_iterator(tmp_path)) {
|
||||
if (!entry.is_regular_file()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
callback(tmp_path, entry);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,22 +32,38 @@
|
|||
#ifndef lnav_archive_manager_hh
|
||||
#define lnav_archive_manager_hh
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include "ghc/filesystem.hpp"
|
||||
|
||||
namespace archive_manager {
|
||||
|
||||
struct extract_progress {
|
||||
extract_progress(ghc::filesystem::path path,
|
||||
ssize_t total) : ep_path(std::move(path)),
|
||||
ep_total_size(total)
|
||||
{}
|
||||
|
||||
const ghc::filesystem::path ep_path;
|
||||
const ssize_t ep_total_size;
|
||||
std::atomic<size_t> ep_out_size{0};
|
||||
};
|
||||
|
||||
using extract_cb = std::function<extract_progress *(
|
||||
const ghc::filesystem::path &, ssize_t)>;
|
||||
|
||||
bool is_archive(const std::string &filename);
|
||||
|
||||
ghc::filesystem::path filename_to_tmp_path(const std::string &filename);
|
||||
|
||||
void walk_archive_files(const std::string &filename,
|
||||
const extract_cb &cb,
|
||||
const std::function<void(
|
||||
const ghc::filesystem::path&,
|
||||
const ghc::filesystem::directory_entry&)>&);
|
||||
|
||||
void extract(const std::string &filename);
|
||||
const ghc::filesystem::path &,
|
||||
const ghc::filesystem::directory_entry &)> &);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,6 +45,10 @@ std::string file_size(ssize_t value)
|
|||
" ", "K", "M", "G", "T", "P", "E",
|
||||
};
|
||||
|
||||
if (value < 0) {
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
auto exp = floor(std::min(log(value) / LN1024, (double) UNITS.size()));
|
||||
auto divisor = pow(1024, exp);
|
||||
|
||||
|
|
|
@ -89,3 +89,16 @@ size_t unquote(char *dst, const char *str, size_t len)
|
|||
|
||||
return index;
|
||||
}
|
||||
|
||||
void truncate_to(std::string &str, size_t len)
|
||||
{
|
||||
static const std::string ELLIPSIS = "\xE2\x8B\xAF";
|
||||
|
||||
if (str.length() <= len) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t half_width = str.size() / 2 - 1;
|
||||
str.erase(half_width, str.length() - (half_width * 2));
|
||||
str.insert(half_width, ELLIPSIS);
|
||||
}
|
||||
|
|
|
@ -72,4 +72,6 @@ inline bool endswith(const std::string& str, const char (&suffix) [N])
|
|||
return strcmp(&str[str.size() - N], suffix) == 0;
|
||||
}
|
||||
|
||||
void truncate_to(std::string &str, size_t len);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "base/humanize.hh"
|
||||
#include "base/string_util.hh"
|
||||
|
||||
#include "lnav.hh"
|
||||
#include "files_sub_source.hh"
|
||||
|
@ -43,21 +44,23 @@ files_sub_source::files_sub_source()
|
|||
bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case '\t':
|
||||
case KEY_BTAB:
|
||||
case 'q':
|
||||
lnav_data.ld_mode = LNM_PAGING;
|
||||
lnav_data.ld_files_view.reload_data();
|
||||
return true;
|
||||
|
||||
case KEY_ENTER:
|
||||
case '\r': {
|
||||
if (lnav_data.ld_active_files.fc_files.empty()) {
|
||||
auto &fc = lnav_data.ld_active_files;
|
||||
|
||||
if (fc.fc_files.empty() && fc.fc_other_files.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto sel = (int) lv.get_selection();
|
||||
|
||||
sel -= fc.fc_other_files.size();
|
||||
if (sel < 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto& lss = lnav_data.ld_log_source;
|
||||
auto &lf = lnav_data.ld_active_files.fc_files[lv.get_selection()];
|
||||
auto &lf = fc.fc_files[sel];
|
||||
|
||||
if (!lf->is_visible()) {
|
||||
lf->show();
|
||||
|
@ -86,11 +89,20 @@ bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
|
|||
}
|
||||
|
||||
case ' ': {
|
||||
if (lnav_data.ld_active_files.fc_files.empty()) {
|
||||
auto &fc = lnav_data.ld_active_files;
|
||||
|
||||
if (fc.fc_files.empty() && fc.fc_other_files.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto &lf = lnav_data.ld_active_files.fc_files[lv.get_selection()];
|
||||
auto sel = (int) lv.get_selection();
|
||||
|
||||
sel -= fc.fc_other_files.size();
|
||||
if (sel < 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto &lf = fc.fc_files[sel];
|
||||
lf->set_visibility(!lf->is_visible());
|
||||
auto top_view = *lnav_data.ld_view_stack.top();
|
||||
auto tss = top_view->get_sub_source();
|
||||
|
@ -128,7 +140,9 @@ void files_sub_source::list_input_handle_scroll_out(listview_curses &lv)
|
|||
|
||||
size_t files_sub_source::text_line_count()
|
||||
{
|
||||
return lnav_data.ld_active_files.fc_files.size();
|
||||
const auto &fc = lnav_data.ld_active_files;
|
||||
|
||||
return fc.fc_other_files.size() + fc.fc_files.size();
|
||||
}
|
||||
|
||||
size_t files_sub_source::text_line_width(textview_curses &curses)
|
||||
|
@ -140,16 +154,40 @@ void files_sub_source::text_value_for_line(textview_curses &tc, int line,
|
|||
std::string &value_out,
|
||||
text_sub_source::line_flags_t flags)
|
||||
{
|
||||
const auto &lf = lnav_data.ld_active_files.fc_files[line];
|
||||
const auto dim = tc.get_dimensions();
|
||||
const auto &fc = lnav_data.ld_active_files;
|
||||
auto filename_width =
|
||||
std::min(fc.fc_largest_path_length,
|
||||
std::max((size_t) 40, dim.second - 30));
|
||||
|
||||
if (line < fc.fc_other_files.size()) {
|
||||
auto iter = fc.fc_other_files.begin();
|
||||
std::advance(iter, line);
|
||||
auto path = ghc::filesystem::path(iter->first);
|
||||
auto fn = path.filename().string();
|
||||
|
||||
truncate_to(fn, filename_width);
|
||||
value_out = fmt::format(
|
||||
FMT_STRING(" {:<{}} {}"),
|
||||
fn, filename_width, iter->second);
|
||||
return;
|
||||
}
|
||||
|
||||
line -= fc.fc_other_files.size();
|
||||
|
||||
const auto &lf = fc.fc_files[line];
|
||||
auto fn = lf->get_unique_path();
|
||||
char start_time[64] = "", end_time[64] = "";
|
||||
|
||||
if (lf->get_format() != nullptr) {
|
||||
sql_strftime(start_time, sizeof(start_time), lf->front().get_timeval());
|
||||
sql_strftime(end_time, sizeof(end_time), lf->back().get_timeval());
|
||||
}
|
||||
truncate_to(fn, filename_width);
|
||||
value_out = fmt::format(
|
||||
FMT_STRING(" {:<40} {:>8} {} \u2014 {}"),
|
||||
lf->get_unique_path(),
|
||||
FMT_STRING(" {:<{}} {:>8} {} \u2014 {}"),
|
||||
fn,
|
||||
filename_width,
|
||||
humanize::file_size(lf->get_index_size()),
|
||||
start_time,
|
||||
end_time);
|
||||
|
@ -158,10 +196,33 @@ void files_sub_source::text_value_for_line(textview_curses &tc, int line,
|
|||
void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
|
||||
string_attrs_t &value_out)
|
||||
{
|
||||
auto &vcolors = view_colors::singleton();
|
||||
bool selected = lnav_data.ld_mode == LNM_FILES && line == tc.get_selection();
|
||||
int bg = selected ? COLOR_WHITE : COLOR_BLACK;
|
||||
auto &lf = lnav_data.ld_active_files.fc_files[line];
|
||||
const auto &fc = lnav_data.ld_active_files;
|
||||
auto &vcolors = view_colors::singleton();
|
||||
const auto dim = tc.get_dimensions();
|
||||
auto filename_width =
|
||||
std::min(fc.fc_largest_path_length,
|
||||
std::max((size_t) 40, dim.second - 30));
|
||||
|
||||
int fg = selected ? COLOR_BLACK : COLOR_WHITE;
|
||||
value_out.emplace_back(line_range{0, -1}, &view_curses::VC_FOREGROUND,
|
||||
vcolors.ansi_to_theme_color(fg));
|
||||
value_out.emplace_back(line_range{0, -1}, &view_curses::VC_BACKGROUND,
|
||||
vcolors.ansi_to_theme_color(bg));
|
||||
|
||||
if (line < fc.fc_other_files.size()) {
|
||||
if (line == fc.fc_other_files.size() - 1) {
|
||||
value_out.emplace_back(line_range{0, -1},
|
||||
&view_curses::VC_STYLE,
|
||||
A_UNDERLINE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
line -= fc.fc_other_files.size();
|
||||
|
||||
auto &lf = fc.fc_files[line];
|
||||
|
||||
chtype visible = lf->is_visible() ? ACS_DIAMOND : ' ';
|
||||
value_out.emplace_back(line_range{2, 3}, &view_curses::VC_GRAPHIC, visible);
|
||||
|
@ -174,18 +235,14 @@ void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
|
|||
value_out.emplace_back(line_range{0, 1}, &view_curses::VC_GRAPHIC, ACS_RARROW);
|
||||
}
|
||||
|
||||
value_out.emplace_back(line_range{41 + 4, 41 + 10},
|
||||
&view_curses::VC_FOREGROUND,
|
||||
COLOR_WHITE);
|
||||
value_out.emplace_back(line_range{41 + 10, 41 + 12},
|
||||
&view_curses::VC_STYLE,
|
||||
A_BOLD);
|
||||
|
||||
int fg = selected ? COLOR_BLACK : COLOR_WHITE;
|
||||
value_out.emplace_back(line_range{0, -1}, &view_curses::VC_FOREGROUND,
|
||||
vcolors.ansi_to_theme_color(fg));
|
||||
value_out.emplace_back(line_range{0, -1}, &view_curses::VC_BACKGROUND,
|
||||
vcolors.ansi_to_theme_color(bg));
|
||||
auto lr = line_range{
|
||||
(int) filename_width + 3 + 4,
|
||||
(int) filename_width + 3 + 10,
|
||||
};
|
||||
value_out.emplace_back(lr, &view_curses::VC_FOREGROUND, COLOR_WHITE);
|
||||
lr.lr_start = lr.lr_end;
|
||||
lr.lr_end += 2;
|
||||
value_out.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD);
|
||||
}
|
||||
|
||||
size_t files_sub_source::text_size_for_line(textview_curses &tc, int line,
|
||||
|
@ -193,3 +250,34 @@ size_t files_sub_source::text_size_for_line(textview_curses &tc, int line,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
files_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
|
||||
int bottom, vis_line_t line,
|
||||
attr_line_t &value_out)
|
||||
{
|
||||
if (y == 0) {
|
||||
auto &fc = lnav_data.ld_active_files;
|
||||
auto &sp = fc.fc_progress;
|
||||
std::lock_guard<std::mutex> guard(sp->sp_mutex);
|
||||
|
||||
if (!sp->sp_extractions.empty()) {
|
||||
static char PROG[] = "-\\|/";
|
||||
|
||||
const auto& prog = sp->sp_extractions.front();
|
||||
|
||||
value_out.with_ansi_string(fmt::format(
|
||||
"{} Extracting "
|
||||
ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
|
||||
"... {:>8}/{}",
|
||||
PROG[this->fos_counter % sizeof(PROG)],
|
||||
prog.ep_path.filename().string(),
|
||||
humanize::file_size(prog.ep_out_size),
|
||||
humanize::file_size(prog.ep_total_size)));
|
||||
|
||||
this->fos_counter += 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -59,4 +59,12 @@ public:
|
|||
bool fss_filter_state{false};
|
||||
};
|
||||
|
||||
struct files_overlay_source : public list_overlay_source {
|
||||
bool list_value_for_overlay(const listview_curses &lv, int y, int bottom,
|
||||
vis_line_t line,
|
||||
attr_line_t &value_out) override;
|
||||
|
||||
size_t fos_counter{0};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "filter_status_source.hh"
|
||||
|
||||
static auto TOGGLE_MSG = "Press " ANSI_BOLD("TAB") " to edit ";
|
||||
static auto EXIT_MSG = "Press " ANSI_BOLD("TAB") " to exit ";
|
||||
static auto EXIT_MSG = "Press " ANSI_BOLD("q") " to exit ";
|
||||
|
||||
static auto CREATE_HELP = ANSI_BOLD("i") "/" ANSI_BOLD("o") ": Create in/out";
|
||||
static auto ENABLE_HELP = ANSI_BOLD("SPC") ": ";
|
||||
|
@ -45,9 +45,11 @@ static auto JUMP_HELP = ANSI_BOLD("ENTER") ": Jump To";
|
|||
|
||||
filter_status_source::filter_status_source()
|
||||
{
|
||||
this->tss_fields[TSF_TITLE].set_width(9);
|
||||
this->tss_fields[TSF_TITLE].set_width(14);
|
||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_STATUS_TITLE);
|
||||
this->tss_fields[TSF_TITLE].set_value(" Filters ");
|
||||
this->tss_fields[TSF_TITLE].set_value(
|
||||
" " ANSI_ROLE("T") "ext Filters ",
|
||||
view_colors::VCR_STATUS_TITLE_HOTKEY);
|
||||
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
|
||||
|
@ -62,6 +64,18 @@ filter_status_source::filter_status_source()
|
|||
this->tss_fields[TSF_FILTERED].set_share(1);
|
||||
this->tss_fields[TSF_FILTERED].set_role(view_colors::VCR_STATUS);
|
||||
|
||||
this->tss_fields[TSF_FILES_TITLE].set_width(7);
|
||||
this->tss_fields[TSF_FILES_TITLE].set_role(
|
||||
view_colors::VCR_STATUS_DISABLED_TITLE);
|
||||
this->tss_fields[TSF_FILES_TITLE].set_value(
|
||||
" " ANSI_ROLE("F") "iles ",
|
||||
view_colors::VCR_STATUS_HOTKEY);
|
||||
|
||||
this->tss_fields[TSF_FILES_RIGHT_STITCH].set_width(2);
|
||||
this->tss_fields[TSF_FILES_RIGHT_STITCH].set_stitch_value(
|
||||
view_colors::VCR_STATUS,
|
||||
view_colors::VCR_STATUS);
|
||||
|
||||
this->tss_fields[TSF_HELP].right_justify(true);
|
||||
this->tss_fields[TSF_HELP].set_width(20);
|
||||
this->tss_fields[TSF_HELP].set_value(TOGGLE_MSG);
|
||||
|
@ -77,10 +91,55 @@ filter_status_source::filter_status_source()
|
|||
|
||||
size_t filter_status_source::statusview_fields()
|
||||
{
|
||||
if (lnav_data.ld_mode == LNM_FILTER) {
|
||||
this->tss_fields[TSF_HELP].set_value(EXIT_MSG);
|
||||
switch (lnav_data.ld_mode) {
|
||||
case LNM_SEARCH_FILTERS:
|
||||
case LNM_SEARCH_FILES:
|
||||
this->tss_fields[TSF_HELP].set_value("");
|
||||
break;
|
||||
case LNM_FILTER:
|
||||
case LNM_FILES:
|
||||
this->tss_fields[TSF_HELP].set_value(EXIT_MSG);
|
||||
break;
|
||||
default:
|
||||
this->tss_fields[TSF_HELP].set_value(TOGGLE_MSG);
|
||||
break;
|
||||
}
|
||||
|
||||
if (lnav_data.ld_mode == LNM_FILES ||
|
||||
lnav_data.ld_mode == LNM_SEARCH_FILES) {
|
||||
this->tss_fields[TSF_FILES_TITLE].set_value(
|
||||
" " ANSI_ROLE("F") "iles ",
|
||||
view_colors::VCR_STATUS_TITLE_HOTKEY);
|
||||
this->tss_fields[TSF_FILES_TITLE]
|
||||
.set_role(view_colors::VCR_STATUS_TITLE);
|
||||
this->tss_fields[TSF_FILES_RIGHT_STITCH].set_stitch_value(
|
||||
view_colors::VCR_STATUS_STITCH_TITLE_TO_NORMAL,
|
||||
view_colors::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
|
||||
this->tss_fields[TSF_TITLE].set_value(
|
||||
" " ANSI_ROLE("T") "ext Filters ",
|
||||
view_colors::VCR_STATUS_HOTKEY);
|
||||
this->tss_fields[TSF_TITLE]
|
||||
.set_role(view_colors::VCR_STATUS_DISABLED_TITLE);
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
|
||||
view_colors::VCR_STATUS,
|
||||
view_colors::VCR_STATUS);
|
||||
} else {
|
||||
this->tss_fields[TSF_HELP].set_value(TOGGLE_MSG);
|
||||
this->tss_fields[TSF_FILES_TITLE].set_value(
|
||||
" " ANSI_ROLE("F") "iles ",
|
||||
view_colors::VCR_STATUS_HOTKEY);
|
||||
this->tss_fields[TSF_FILES_TITLE]
|
||||
.set_role(view_colors::VCR_STATUS_DISABLED_TITLE);
|
||||
this->tss_fields[TSF_FILES_RIGHT_STITCH].set_stitch_value(
|
||||
view_colors::VCR_STATUS_STITCH_NORMAL_TO_TITLE,
|
||||
view_colors::VCR_STATUS_STITCH_TITLE_TO_NORMAL);
|
||||
this->tss_fields[TSF_TITLE].set_value(
|
||||
" " ANSI_ROLE("T") "ext Filters ",
|
||||
view_colors::VCR_STATUS_TITLE_HOTKEY);
|
||||
this->tss_fields[TSF_TITLE]
|
||||
.set_role(view_colors::VCR_STATUS_TITLE);
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
|
||||
view_colors::VCR_STATUS_STITCH_TITLE_TO_NORMAL,
|
||||
view_colors::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
|
||||
}
|
||||
|
||||
if (this->tss_prompt.empty() && this->tss_error.empty()) {
|
||||
|
@ -164,7 +223,7 @@ void filter_status_source::update_filtered(text_sub_source *tss)
|
|||
this->bss_last_filtered_count = tss->get_filtered_count();
|
||||
timer.start_fade(this->bss_filter_counter, 3);
|
||||
}
|
||||
sf.set_value("%'9d Lines not shown", tss->get_filtered_count());
|
||||
sf.set_value("%'9d Lines not shown ", tss->get_filtered_count());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,13 +281,22 @@ size_t filter_help_status_source::statusview_fields()
|
|||
}
|
||||
} else if (lnav_data.ld_mode == LNM_FILES &&
|
||||
lnav_data.ld_session_loaded) {
|
||||
if (lnav_data.ld_active_files.fc_files.empty()) {
|
||||
const auto &fc = lnav_data.ld_active_files;
|
||||
|
||||
if (fc.fc_files.empty() && fc.fc_other_files.empty()) {
|
||||
this->fss_help.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
auto &lv = lnav_data.ld_files_view;
|
||||
auto sel = lv.get_selection();
|
||||
auto sel = (int) lv.get_selection();
|
||||
|
||||
if (sel < fc.fc_other_files.size()) {
|
||||
this->fss_help.clear();
|
||||
return;
|
||||
}
|
||||
sel -= fc.fc_other_files.size();
|
||||
|
||||
auto &lf = lnav_data.ld_active_files.fc_files[sel];
|
||||
|
||||
this->fss_help.set_value(" %s%s %s",
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _filter_status_source_hh
|
||||
#define _filter_status_source_hh
|
||||
#ifndef lnav_filter_status_source_hh
|
||||
#define lnav_filter_status_source_hh
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -39,6 +39,8 @@ class filter_status_source
|
|||
: public status_data_source {
|
||||
public:
|
||||
typedef enum {
|
||||
TSF_FILES_TITLE,
|
||||
TSF_FILES_RIGHT_STITCH,
|
||||
TSF_TITLE,
|
||||
TSF_STITCH_TITLE,
|
||||
TSF_COUNT,
|
||||
|
|
|
@ -72,12 +72,6 @@ bool filter_sub_source::list_input_handle_key(listview_curses &lv, int ch)
|
|||
}
|
||||
|
||||
switch (ch) {
|
||||
case '\t':
|
||||
case KEY_BTAB:
|
||||
case 'q':
|
||||
lnav_data.ld_mode = LNM_PAGING;
|
||||
lnav_data.ld_filter_view.reload_data();
|
||||
return true;
|
||||
case 'f': {
|
||||
auto top_view = *lnav_data.ld_view_stack.top();
|
||||
auto tss = top_view->get_sub_source();
|
||||
|
|
|
@ -233,15 +233,30 @@
|
|||
"title": "/ui/theme-defs/<theme_name>/status-styles/inactive",
|
||||
"$ref": "#/definitions/style"
|
||||
},
|
||||
"title-hotkey": {
|
||||
"description": "Styling for hotkey highlights in titles",
|
||||
"title": "/ui/theme-defs/<theme_name>/status-styles/title-hotkey",
|
||||
"$ref": "#/definitions/style"
|
||||
},
|
||||
"title": {
|
||||
"description": "Styling for title sections of status bars",
|
||||
"title": "/ui/theme-defs/<theme_name>/status-styles/title",
|
||||
"$ref": "#/definitions/style"
|
||||
},
|
||||
"disabled-title": {
|
||||
"description": "Styling for title sections of status bars",
|
||||
"title": "/ui/theme-defs/<theme_name>/status-styles/disabled-title",
|
||||
"$ref": "#/definitions/style"
|
||||
},
|
||||
"subtitle": {
|
||||
"description": "Styling for subtitle sections of status bars",
|
||||
"title": "/ui/theme-defs/<theme_name>/status-styles/subtitle",
|
||||
"$ref": "#/definitions/style"
|
||||
},
|
||||
"hotkey": {
|
||||
"description": "Styling for hotkey highlights of status bars",
|
||||
"title": "/ui/theme-defs/<theme_name>/status-styles/hotkey",
|
||||
"$ref": "#/definitions/style"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
|
|
@ -321,6 +321,20 @@ void listview_curses::do_update()
|
|||
#endif
|
||||
}
|
||||
|
||||
void listview_curses::shift_selection(int offset)
|
||||
{
|
||||
vis_line_t new_selection = this->lv_selection + vis_line_t(offset);
|
||||
|
||||
if (new_selection >= 0_vl &&
|
||||
new_selection < this->get_inner_height()) {
|
||||
this->set_selection(new_selection);
|
||||
this->scroll_selection_into_view();
|
||||
} else if (!alerter::singleton().chime()) {
|
||||
// XXX Disabling for now...
|
||||
// this->delegate_scroll_out();
|
||||
}
|
||||
}
|
||||
|
||||
static int scroll_polarity(mouse_button_t button)
|
||||
{
|
||||
return button == BUTTON_SCROLL_UP ? -1 : 1;
|
||||
|
|
|
@ -222,17 +222,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void shift_selection(int offset) {
|
||||
vis_line_t new_selection = this->lv_selection + vis_line_t(offset);
|
||||
|
||||
if (new_selection >= 0_vl &&
|
||||
new_selection < this->get_inner_height()) {
|
||||
this->set_selection(new_selection);
|
||||
this->scroll_selection_into_view();
|
||||
} else if (!alerter::singleton().chime()) {
|
||||
this->delegate_scroll_out();
|
||||
}
|
||||
}
|
||||
void shift_selection(int offset);
|
||||
|
||||
vis_line_t get_selection() const {
|
||||
return this->lv_selection;
|
||||
|
@ -544,6 +534,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
std::pair<vis_line_t, unsigned long> get_dimensions() const {
|
||||
unsigned long width;
|
||||
vis_line_t height;
|
||||
|
||||
this->get_dimensions(height, width);
|
||||
return std::make_pair(height, width);
|
||||
}
|
||||
|
||||
/** This method should be called when the data source has changed. */
|
||||
virtual void reload_data();
|
||||
|
||||
|
|
212
src/lnav.cc
212
src/lnav.cc
|
@ -129,6 +129,7 @@
|
|||
#include "fstat_vtab.hh"
|
||||
#include "textfile_highlighters.hh"
|
||||
#include "base/future_util.hh"
|
||||
#include "base/humanize.hh"
|
||||
|
||||
#ifdef HAVE_LIBCURL
|
||||
#include <curl/curl.h>
|
||||
|
@ -404,14 +405,15 @@ private:
|
|||
for (auto &sc : lnav_data.ld_status) {
|
||||
sc.do_update();
|
||||
}
|
||||
if (!lnav_data.ld_session_loaded && lnav_data.ld_mode == LNM_FILES) {
|
||||
auto iter = std::find(lnav_data.ld_active_files.fc_files.begin(),
|
||||
lnav_data.ld_active_files.fc_files.end(), lf);
|
||||
if (lnav_data.ld_mode == LNM_FILES) {
|
||||
auto &fc = lnav_data.ld_active_files;
|
||||
auto iter = std::find(fc.fc_files.begin(),
|
||||
fc.fc_files.end(), lf);
|
||||
|
||||
if (iter != lnav_data.ld_active_files.fc_files.end()) {
|
||||
auto index = std::distance(lnav_data.ld_active_files.fc_files.begin(),
|
||||
iter);
|
||||
lnav_data.ld_files_view.set_selection(vis_line_t(index));
|
||||
if (iter != fc.fc_files.end()) {
|
||||
auto index = std::distance(fc.fc_files.begin(), iter);
|
||||
lnav_data.ld_files_view.set_selection(
|
||||
vis_line_t(fc.fc_other_files.size() + index));
|
||||
lnav_data.ld_files_view.reload_data();
|
||||
lnav_data.ld_files_view.do_update();
|
||||
}
|
||||
|
@ -504,7 +506,8 @@ public:
|
|||
|
||||
auto iter = session_data.sd_file_states.find(lf->get_filename());
|
||||
if (iter != session_data.sd_file_states.end()) {
|
||||
log_debug("found state for log file");
|
||||
log_debug("found state for log file %d",
|
||||
iter->second.fs_is_visible);
|
||||
lf->set_visibility(iter->second.fs_is_visible);
|
||||
}
|
||||
}
|
||||
|
@ -982,10 +985,25 @@ void file_collection::regenerate_unique_file_names()
|
|||
unique_path_generator upg;
|
||||
|
||||
for (const auto& lf : this->fc_files) {
|
||||
upg.add_source(shared_ptr<logfile>(lf));
|
||||
upg.add_source(lf);
|
||||
}
|
||||
|
||||
upg.generate();
|
||||
|
||||
this->fc_largest_path_length = 0;
|
||||
for (const auto& lf : this->fc_files) {
|
||||
const auto& path = lf->get_unique_path();
|
||||
|
||||
if (path.length() > this->fc_largest_path_length) {
|
||||
this->fc_largest_path_length = path.length();
|
||||
}
|
||||
}
|
||||
for (const auto& pair : this->fc_other_files) {
|
||||
auto bn = ghc::filesystem::path(pair.first).filename().string();
|
||||
if (bn.length() > this->fc_largest_path_length) {
|
||||
this->fc_largest_path_length = bn.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void file_collection::merge(const file_collection& other)
|
||||
|
@ -1074,7 +1092,7 @@ file_collection::watch_logfile(const string& filename, logfile_open_options &loo
|
|||
if (this->fc_other_files.find(filename) != this->fc_other_files.end()) {
|
||||
return make_ready_future(retval);
|
||||
}
|
||||
return std::async(std::launch::async, [filename, &loo]() {
|
||||
return std::async(std::launch::async, [filename, &loo, prog=this->fc_progress]() {
|
||||
file_format_t ff = detect_file_format(filename);
|
||||
file_collection retval;
|
||||
|
||||
|
@ -1087,8 +1105,16 @@ file_collection::watch_logfile(const string& filename, logfile_open_options &loo
|
|||
case file_format_t::FF_ARCHIVE: {
|
||||
retval.fc_other_files[filename] = "Archive";
|
||||
archive_manager::walk_archive_files(
|
||||
filename, [&filename, &retval](const auto& tmp_path,
|
||||
const auto& entry) {
|
||||
filename,
|
||||
[prog](const auto& path, const auto total) {
|
||||
std::lock_guard<std::mutex> guard(prog->sp_mutex);
|
||||
prog->sp_extractions.clear();
|
||||
prog->sp_extractions.emplace_back(path, total);
|
||||
|
||||
return &prog->sp_extractions.back();
|
||||
},
|
||||
[&filename, &retval](const auto& tmp_path,
|
||||
const auto& entry) {
|
||||
auto ext = entry.path().extension();
|
||||
if (ext == ".jar" || ext == ".war" || ext == ".zip") {
|
||||
return;
|
||||
|
@ -1116,6 +1142,10 @@ file_collection::watch_logfile(const string& filename, logfile_open_options &loo
|
|||
.with_non_utf_visibility(false)
|
||||
.with_visible_size_limit(128 * 1024);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(prog->sp_mutex);
|
||||
prog->sp_extractions.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1222,6 +1252,11 @@ file_collection file_collection::rescan_files(bool required)
|
|||
} else {
|
||||
fq.push_back(watch_logfile(pair.first, pair.second, required));
|
||||
}
|
||||
|
||||
if (retval.fc_files.size() >= 100) {
|
||||
log_debug("too many new files, breaking...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fq.pop_to();
|
||||
|
@ -1300,6 +1335,51 @@ public:
|
|||
private:
|
||||
};
|
||||
|
||||
static bool handle_config_ui_key(int ch)
|
||||
{
|
||||
nonstd::optional<ln_mode_t> new_mode;
|
||||
|
||||
if (ch == 'F') {
|
||||
new_mode = LNM_FILES;
|
||||
} else if (ch == 'T') {
|
||||
new_mode = LNM_FILTER;
|
||||
}
|
||||
if (!lnav_data.ld_filter_source.fss_editing &&
|
||||
(ch == '\t' || ch == KEY_BTAB)) {
|
||||
if (lnav_data.ld_mode == LNM_FILES) {
|
||||
new_mode = LNM_FILTER;
|
||||
} else {
|
||||
new_mode = LNM_FILES;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == 'q') {
|
||||
lnav_data.ld_mode = LNM_PAGING;
|
||||
} else if (new_mode) {
|
||||
lnav_data.ld_last_config_mode = new_mode.value();
|
||||
lnav_data.ld_mode = new_mode.value();
|
||||
lnav_data.ld_files_view.reload_data();
|
||||
lnav_data.ld_filter_view.reload_data();
|
||||
lnav_data.ld_status[LNS_FILTER].set_needs_update();
|
||||
} else {
|
||||
switch (lnav_data.ld_mode) {
|
||||
case LNM_FILES:
|
||||
if (!lnav_data.ld_files_view.handle_key(ch)) {
|
||||
return handle_paging_key(ch);
|
||||
}
|
||||
break;
|
||||
case LNM_FILTER:
|
||||
if (!lnav_data.ld_filter_view.handle_key(ch)) {
|
||||
return handle_paging_key(ch);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ensure(0);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handle_key(int ch) {
|
||||
lnav_data.ld_input_state.push_back(ch);
|
||||
|
||||
|
@ -1313,23 +1393,8 @@ static bool handle_key(int ch) {
|
|||
return handle_paging_key(ch);
|
||||
|
||||
case LNM_FILTER:
|
||||
if (ch == 'F') {
|
||||
lnav_data.ld_last_config_mode = LNM_FILES;
|
||||
lnav_data.ld_mode = LNM_FILES;
|
||||
lnav_data.ld_files_view.reload_data();
|
||||
} else if (!lnav_data.ld_filter_view.handle_key(ch)) {
|
||||
return handle_paging_key(ch);
|
||||
}
|
||||
break;
|
||||
case LNM_FILES:
|
||||
if (ch == 'T') {
|
||||
lnav_data.ld_last_config_mode = LNM_FILTER;
|
||||
lnav_data.ld_mode = LNM_FILTER;
|
||||
lnav_data.ld_filter_view.reload_data();
|
||||
} else if (!lnav_data.ld_files_view.handle_key(ch)) {
|
||||
return handle_paging_key(ch);
|
||||
}
|
||||
break;
|
||||
return handle_config_ui_key(ch);
|
||||
|
||||
case LNM_COMMAND:
|
||||
case LNM_SEARCH:
|
||||
|
@ -1671,6 +1736,7 @@ static void looper()
|
|||
lnav_data.ld_files_view.set_selectable(true);
|
||||
lnav_data.ld_files_view.set_window(lnav_data.ld_window);
|
||||
lnav_data.ld_files_view.set_show_scrollbar(true);
|
||||
lnav_data.ld_files_view.set_overlay_source(&lnav_data.ld_files_overlay);
|
||||
|
||||
lnav_data.ld_status[LNS_TOP].set_top(0);
|
||||
lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc.get_height() + 1));
|
||||
|
@ -1751,18 +1817,22 @@ static void looper()
|
|||
log_debug("rescan started");
|
||||
file_collection active_copy;
|
||||
active_copy.merge(lnav_data.ld_active_files);
|
||||
active_copy.fc_progress = lnav_data.ld_active_files.fc_progress;
|
||||
future<file_collection> rescan_future =
|
||||
std::async(std::launch::async,
|
||||
&file_collection::rescan_files,
|
||||
active_copy,
|
||||
false);
|
||||
bool initial_rescan_completed = false;
|
||||
int session_stage = 0;
|
||||
|
||||
while (lnav_data.ld_looping) {
|
||||
vector<struct pollfd> pollfds;
|
||||
struct timeval to = { 0, 333000 };
|
||||
int rc;
|
||||
auto poll_to = initial_rescan_completed ?
|
||||
timeval{ 0, 333000 } :
|
||||
timeval{ 0, 0 };
|
||||
size_t starting_view_stack_size = lnav_data.ld_view_stack.vs_views.size();
|
||||
int rc;
|
||||
|
||||
gettimeofday(¤t_time, nullptr);
|
||||
|
||||
|
@ -1770,13 +1840,40 @@ static void looper()
|
|||
|
||||
layout_views();
|
||||
|
||||
if (rescan_future.wait_for(0s) == std::future_status::ready) {
|
||||
auto scan_timeout = initial_rescan_completed ? 0s : 10ms;
|
||||
if (rescan_future.wait_for(scan_timeout) ==
|
||||
std::future_status::ready) {
|
||||
auto new_files = rescan_future.get();
|
||||
if (!initial_rescan_completed &&
|
||||
new_files.fc_file_names.empty()) {
|
||||
new_files.fc_file_names.empty() &&
|
||||
new_files.fc_files.empty()) {
|
||||
initial_rescan_completed = true;
|
||||
|
||||
load_session();
|
||||
if (session_data.sd_save_time) {
|
||||
std::string ago;
|
||||
|
||||
ago = time_ago(session_data.sd_save_time);
|
||||
lnav_data.ld_rl_view->set_value(
|
||||
("restored session from " ANSI_BOLD_START) +
|
||||
ago +
|
||||
(ANSI_NORM "; press Ctrl-R to reset session"));
|
||||
}
|
||||
|
||||
lnav_data.ld_session_loaded = true;
|
||||
session_stage += 1;
|
||||
log_debug("file count %d",
|
||||
lnav_data.ld_active_files.fc_files.size())
|
||||
}
|
||||
update_active_files(new_files);
|
||||
if (!initial_rescan_completed) {
|
||||
auto &fview = lnav_data.ld_files_view;
|
||||
auto height = fview.get_inner_height();
|
||||
|
||||
if (height > 0_vl) {
|
||||
fview.set_selection(height - 1_vl);
|
||||
}
|
||||
}
|
||||
|
||||
active_copy.clear();
|
||||
active_copy.merge(lnav_data.ld_active_files);
|
||||
|
@ -1785,7 +1882,11 @@ static void looper()
|
|||
active_copy,
|
||||
false);
|
||||
}
|
||||
rebuild_indexes();
|
||||
if (initial_rescan_completed) {
|
||||
rebuild_indexes();
|
||||
} else {
|
||||
lnav_data.ld_files_view.set_overlay_needs_update();
|
||||
}
|
||||
|
||||
lnav_data.ld_view_stack.do_update();
|
||||
lnav_data.ld_doc_view.do_update();
|
||||
|
@ -1795,15 +1896,16 @@ static void looper()
|
|||
for (auto &sc : lnav_data.ld_status) {
|
||||
sc.do_update();
|
||||
}
|
||||
rlc.do_update();
|
||||
if (lnav_data.ld_filter_source.fss_editing) {
|
||||
lnav_data.ld_filter_source.fss_match_view.set_needs_update();
|
||||
}
|
||||
switch (lnav_data.ld_mode) {
|
||||
case LNM_FILTER:
|
||||
case LNM_SEARCH_FILTERS:
|
||||
lnav_data.ld_filter_view.set_needs_update();
|
||||
lnav_data.ld_filter_view.do_update();
|
||||
break;
|
||||
case LNM_SEARCH_FILES:
|
||||
case LNM_FILES:
|
||||
lnav_data.ld_files_view.set_needs_update();
|
||||
lnav_data.ld_files_view.do_update();
|
||||
|
@ -1811,6 +1913,10 @@ static void looper()
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (lnav_data.ld_mode != LNM_FILTER &&
|
||||
lnav_data.ld_mode != LNM_FILES) {
|
||||
rlc.do_update();
|
||||
}
|
||||
refresh();
|
||||
|
||||
if (lnav_data.ld_session_loaded) {
|
||||
|
@ -1830,10 +1936,11 @@ static void looper()
|
|||
lnav_data.ld_filter_view.update_poll_set(pollfds);
|
||||
lnav_data.ld_files_view.update_poll_set(pollfds);
|
||||
|
||||
if (lnav_data.ld_input_dispatcher.in_escape()) {
|
||||
to.tv_usec = 15000;
|
||||
if (initial_rescan_completed &&
|
||||
lnav_data.ld_input_dispatcher.in_escape()) {
|
||||
poll_to.tv_usec = 15000;
|
||||
}
|
||||
rc = poll(&pollfds[0], pollfds.size(), to.tv_usec / 1000);
|
||||
rc = poll(&pollfds[0], pollfds.size(), poll_to.tv_usec / 1000);
|
||||
|
||||
gettimeofday(¤t_time, nullptr);
|
||||
lnav_data.ld_input_dispatcher.poll(current_time);
|
||||
|
@ -1935,22 +2042,6 @@ static void looper()
|
|||
initial_build = true;
|
||||
}
|
||||
|
||||
if (!lnav_data.ld_session_loaded) {
|
||||
load_session();
|
||||
if (session_data.sd_save_time) {
|
||||
std::string ago;
|
||||
|
||||
ago = time_ago(session_data.sd_save_time);
|
||||
lnav_data.ld_rl_view->set_value(
|
||||
("restored session from " ANSI_BOLD_START) +
|
||||
ago +
|
||||
(ANSI_NORM "; press Ctrl-R to reset session"));
|
||||
}
|
||||
|
||||
lnav_data.ld_mode = LNM_PAGING;
|
||||
lnav_data.ld_session_loaded = true;
|
||||
}
|
||||
|
||||
if (initial_build) {
|
||||
vector<pair<Result<string, string>, string>> cmd_results;
|
||||
|
||||
|
@ -1965,6 +2056,21 @@ static void looper()
|
|||
last_cmd_result.second);
|
||||
}
|
||||
}
|
||||
|
||||
if (session_stage == 1) {
|
||||
for (size_t view_index = 0;
|
||||
view_index < LNV__MAX;
|
||||
view_index++) {
|
||||
const auto &vs = session_data.sd_view_states[view_index];
|
||||
|
||||
if (vs.vs_top > 0) {
|
||||
lnav_data.ld_views[view_index]
|
||||
.set_top(vis_line_t(vs.vs_top));
|
||||
}
|
||||
}
|
||||
lnav_data.ld_mode = LNM_PAGING;
|
||||
session_stage += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lnav_data.ld_winched) {
|
||||
|
|
26
src/lnav.hh
26
src/lnav.hh
|
@ -70,6 +70,7 @@
|
|||
#include "filter_status_source.hh"
|
||||
#include "preview_status_source.hh"
|
||||
#include "sql_util.hh"
|
||||
#include "archive_manager.hh"
|
||||
|
||||
/** The command modes that are available while viewing a file. */
|
||||
typedef enum {
|
||||
|
@ -184,17 +185,10 @@ private:
|
|||
};
|
||||
|
||||
struct key_repeat_history {
|
||||
key_repeat_history()
|
||||
: krh_key(0),
|
||||
krh_count(0) {
|
||||
this->krh_last_press_time.tv_sec = 0;
|
||||
this->krh_last_press_time.tv_usec = 0;
|
||||
}
|
||||
|
||||
int krh_key;
|
||||
int krh_count;
|
||||
vis_line_t krh_start_line;
|
||||
struct timeval krh_last_press_time;
|
||||
int krh_key{0};
|
||||
int krh_count{0};
|
||||
vis_line_t krh_start_line{0_vl};
|
||||
struct timeval krh_last_press_time{0, 0};
|
||||
|
||||
void update(int ch, vis_line_t top) {
|
||||
struct timeval now, diff;
|
||||
|
@ -217,6 +211,11 @@ struct key_repeat_history {
|
|||
};
|
||||
};
|
||||
|
||||
struct scan_progress {
|
||||
std::mutex sp_mutex;
|
||||
std::list<archive_manager::extract_progress> sp_extractions;
|
||||
};
|
||||
|
||||
struct file_collection {
|
||||
std::map<std::string, std::string> fc_name_to_errors;
|
||||
std::map<std::string, logfile_open_options> fc_file_names;
|
||||
|
@ -226,6 +225,10 @@ struct file_collection {
|
|||
fc_renamed_files;
|
||||
std::set<std::string> fc_closed_files;
|
||||
std::map<std::string, std::string> fc_other_files;
|
||||
std::shared_ptr<scan_progress> fc_progress;
|
||||
size_t fc_largest_path_length{0};
|
||||
|
||||
file_collection() : fc_progress(std::make_shared<scan_progress>()) {}
|
||||
|
||||
void clear() {
|
||||
this->fc_name_to_errors.clear();
|
||||
|
@ -286,6 +289,7 @@ struct _lnav_data {
|
|||
filter_sub_source ld_filter_source;
|
||||
textview_curses ld_filter_view;
|
||||
files_sub_source ld_files_source;
|
||||
files_overlay_source ld_files_overlay;
|
||||
textview_curses ld_files_view;
|
||||
plain_text_source ld_example_source;
|
||||
textview_curses ld_example_view;
|
||||
|
|
|
@ -4123,6 +4123,7 @@ static void search_prompt(vector<string> &args)
|
|||
static void search_filters_prompt(vector<string> &args)
|
||||
{
|
||||
lnav_data.ld_mode = LNM_SEARCH_FILTERS;
|
||||
lnav_data.ld_filter_view.reload_data();
|
||||
add_view_text_possibilities(lnav_data.ld_rl_view,
|
||||
LNM_SEARCH_FILTERS,
|
||||
"*",
|
||||
|
|
|
@ -669,18 +669,36 @@ static struct json_path_container theme_status_styles_handlers = {
|
|||
return &root->lt_style_inactive_status;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
yajlpp::property_handler("title-hotkey")
|
||||
.with_description("Styling for hotkey highlights in titles")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_status_title_hotkey;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
yajlpp::property_handler("title")
|
||||
.with_description("Styling for title sections of status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_status_title;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
yajlpp::property_handler("disabled-title")
|
||||
.with_description("Styling for title sections of status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_status_disabled_title;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
yajlpp::property_handler("subtitle")
|
||||
.with_description("Styling for subtitle sections of status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_status_subtitle;
|
||||
})
|
||||
.with_children(style_config_handlers)
|
||||
.with_children(style_config_handlers),
|
||||
yajlpp::property_handler("hotkey")
|
||||
.with_description("Styling for hotkey highlights of status bars")
|
||||
.with_obj_provider<style_config, lnav_theme>([](const yajlpp_provider_context &ypc, lnav_theme *root) {
|
||||
return &root->lt_style_status_hotkey;
|
||||
})
|
||||
.with_children(style_config_handlers),
|
||||
};
|
||||
|
||||
static struct json_path_container theme_log_level_styles_handlers = {
|
||||
|
|
|
@ -589,8 +589,9 @@ logfile_sub_source::rebuild_result logfile_sub_source::rebuild_index()
|
|||
if (retval == rebuild_result::rr_no_change) {
|
||||
retval = rebuild_result::rr_appended_lines;
|
||||
}
|
||||
if (!this->lss_index.empty()) {
|
||||
logline &new_file_line = lf[ld.ld_lines_indexed - 1];
|
||||
if (!this->lss_index.empty() &&
|
||||
lf.size() > ld.ld_lines_indexed) {
|
||||
logline &new_file_line = lf[ld.ld_lines_indexed];
|
||||
content_line_t cl = this->lss_index.back();
|
||||
logline *last_indexed_line = this->find_line(cl);
|
||||
|
||||
|
|
|
@ -748,11 +748,7 @@ static int read_top_line(yajlpp_parse_context *ypc, long long value)
|
|||
ypc->get_path_fragment(-2));
|
||||
view_index = view_name - lnav_view_strings;
|
||||
if (view_index < LNV__MAX) {
|
||||
textview_curses &tc = lnav_data.ld_views[view_index];
|
||||
|
||||
if (value != -1 && value < tc.get_inner_height()) {
|
||||
tc.set_top(vis_line_t(value));
|
||||
}
|
||||
session_data.sd_view_states[view_index].vs_top = value;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -35,14 +35,21 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "lnav.hh"
|
||||
|
||||
struct file_state {
|
||||
bool fs_is_visible{true};
|
||||
};
|
||||
|
||||
struct view_state {
|
||||
int64_t vs_top{0};
|
||||
};
|
||||
|
||||
struct session_data_t {
|
||||
uint64_t sd_save_time{0};
|
||||
bool sd_time_offset{false};
|
||||
std::map<std::string, file_state> sd_file_states;
|
||||
view_state sd_view_states[LNV__MAX];
|
||||
};
|
||||
|
||||
extern struct session_data_t session_data;
|
||||
|
|
|
@ -44,7 +44,6 @@ void status_field::set_value(std::string value)
|
|||
sa.clear();
|
||||
|
||||
scrub_ansi_string(value, sa);
|
||||
|
||||
this->sf_value.with_string(value);
|
||||
|
||||
if (this->sf_cylon) {
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
sf_role(role) {
|
||||
};
|
||||
|
||||
virtual ~status_field() { };
|
||||
virtual ~status_field() = default;
|
||||
|
||||
/** @param value The new value for this field. */
|
||||
void set_value(std::string value);
|
||||
|
|
|
@ -143,7 +143,10 @@ struct lnav_theme {
|
|||
style_config lt_style_skewed_time;
|
||||
style_config lt_style_offset_time;
|
||||
style_config lt_style_status_title;
|
||||
style_config lt_style_status_title_hotkey;
|
||||
style_config lt_style_status_disabled_title;
|
||||
style_config lt_style_status_subtitle;
|
||||
style_config lt_style_status_hotkey;
|
||||
style_config lt_style_keyword;
|
||||
style_config lt_style_string;
|
||||
style_config lt_style_comment;
|
||||
|
|
|
@ -90,6 +90,11 @@
|
|||
"background-color": "Blue",
|
||||
"bold": true
|
||||
},
|
||||
"disabled-title": {
|
||||
"color": "Black",
|
||||
"background-color": "Silver",
|
||||
"bold": true
|
||||
},
|
||||
"subtitle": {
|
||||
"color": "Black",
|
||||
"background-color": "Teal"
|
||||
|
@ -113,6 +118,17 @@
|
|||
"inactive": {
|
||||
"color": "Silver",
|
||||
"background-color": "Grey37"
|
||||
},
|
||||
"title-hotkey": {
|
||||
"color": "Teal",
|
||||
"background-color": "Blue",
|
||||
"underline": true
|
||||
},
|
||||
"hotkey": {
|
||||
"color": "Purple",
|
||||
"background-color": "Silver",
|
||||
"underline": true,
|
||||
"bold": true
|
||||
}
|
||||
},
|
||||
"log-level-styles": {
|
||||
|
|
|
@ -101,6 +101,11 @@
|
|||
}
|
||||
},
|
||||
"status-styles": {
|
||||
"disabled-title": {
|
||||
"color": "#5394ec",
|
||||
"background-color": "#353535",
|
||||
"bold": true
|
||||
},
|
||||
"title": {
|
||||
"color": "#f6f6f6",
|
||||
"background-color": "#5394ec",
|
||||
|
@ -111,6 +116,16 @@
|
|||
"background-color": "#66d9ee",
|
||||
"bold": true
|
||||
},
|
||||
"title-hotkey": {
|
||||
"color": "$black",
|
||||
"background-color": "#5394ec",
|
||||
"underline": true
|
||||
},
|
||||
"hotkey": {
|
||||
"color": "#fff",
|
||||
"background-color": "#353535",
|
||||
"underline": true
|
||||
},
|
||||
"text": {
|
||||
"color": "#f6f6f6",
|
||||
"background-color": "#353535"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"theme-defs": {
|
||||
"night-owl": {
|
||||
"vars": {
|
||||
"black": "#011627",
|
||||
"red": "#ff6868",
|
||||
"green": "#007f00",
|
||||
"yellow": "#cdcd00",
|
||||
|
@ -125,6 +126,18 @@
|
|||
"inactive": {
|
||||
"color": "#f0f0f0",
|
||||
"background-color": "#0F1F2B"
|
||||
},
|
||||
"hotkey": {
|
||||
"color": "#2d5a80",
|
||||
"background-color": "#162d40",
|
||||
"bold": true,
|
||||
"underline": true
|
||||
},
|
||||
"title-hotkey": {
|
||||
"color": "$black",
|
||||
"background-color": "#2d5a80",
|
||||
"bold": true,
|
||||
"underline": true
|
||||
}
|
||||
},
|
||||
"log-level-styles": {
|
||||
|
|
|
@ -825,6 +825,16 @@ void view_colors::init_roles(const lnav_theme <,
|
|||
this->vc_role_colors[VCR_STATUS_SUBTITLE] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_status_subtitle, lt.lt_style_status, reporter);
|
||||
|
||||
this->vc_role_colors[VCR_STATUS_HOTKEY] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_status_hotkey, lt.lt_style_status,
|
||||
reporter);
|
||||
this->vc_role_colors[VCR_STATUS_TITLE_HOTKEY] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_status_title_hotkey, lt.lt_style_status,
|
||||
reporter);
|
||||
this->vc_role_colors[VCR_STATUS_DISABLED_TITLE] = this->to_attrs(
|
||||
color_pair_base, lt, lt.lt_style_status_disabled_title, lt.lt_style_status,
|
||||
reporter);
|
||||
|
||||
{
|
||||
style_config stitch_sc;
|
||||
|
||||
|
|
|
@ -327,6 +327,9 @@ public:
|
|||
VCR_STATUS_STITCH_NORMAL_TO_SUB,
|
||||
VCR_STATUS_STITCH_TITLE_TO_NORMAL,
|
||||
VCR_STATUS_STITCH_NORMAL_TO_TITLE,
|
||||
VCR_STATUS_TITLE_HOTKEY,
|
||||
VCR_STATUS_DISABLED_TITLE,
|
||||
VCR_STATUS_HOTKEY,
|
||||
VCR_INACTIVE_STATUS,
|
||||
VCR_SCROLLBAR,
|
||||
VCR_SCROLLBAR_ERROR,
|
||||
|
|
Loading…
Reference in New Issue