mirror of
https://github.com/tstack/lnav
synced 2024-11-01 21:40:34 +00:00
[fini] fix a destruction ordering issue
This commit is contained in:
parent
59ec0b4794
commit
93a53c4224
@ -12,7 +12,7 @@ install:
|
||||
- C:\%cygwin%\%cygsetup% -qnNdOX -R C:/%cygwin% -l C:/%cygwin%/var/cache/setup -P libpcre2-devel -P libncurses-devel -P libreadline-devel -P zlib-devel -P libbz2-devel -P libsqlite3-devel -P libcurl-devel -P libarchive-devel
|
||||
|
||||
build_script:
|
||||
- C:\%cygwin%\bin\sh -lc "uname -a && gcc --version && cd /cygdrive/c/projects/lnav && ./autogen.sh && ./configure && make && strip src/lnav.exe && ldd src/lnav.exe"
|
||||
- C:\%cygwin%\bin\sh -lc "uname -a && gcc --version && cd /cygdrive/c/projects/lnav && ./autogen.sh && ./configure && make -j4 && strip src/lnav.exe && ldd src/lnav.exe"
|
||||
|
||||
artifacts:
|
||||
- path: src\lnav.exe
|
||||
|
@ -310,6 +310,7 @@ noinst_HEADERS = \
|
||||
time_T.hh \
|
||||
timer.hh \
|
||||
top_status_source.hh \
|
||||
top_status_source.cfg.hh \
|
||||
unique_path.hh \
|
||||
url_loader.hh \
|
||||
view_curses.hh \
|
||||
|
@ -68,6 +68,54 @@ struct noop_func {
|
||||
namespace lnav {
|
||||
namespace func {
|
||||
|
||||
class scoped_cb {
|
||||
public:
|
||||
class guard {
|
||||
public:
|
||||
explicit guard(scoped_cb* owner) : g_owner(owner) {}
|
||||
|
||||
guard(const guard&) = delete;
|
||||
guard& operator=(const guard&) = delete;
|
||||
|
||||
guard(guard&& gu) noexcept : g_owner(std::exchange(gu.g_owner, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
guard& operator=(guard&& gu) noexcept
|
||||
{
|
||||
this->g_owner = std::exchange(gu.g_owner, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~guard()
|
||||
{
|
||||
if (this->g_owner != nullptr) {
|
||||
this->g_owner->s_callback = {};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
scoped_cb* g_owner;
|
||||
};
|
||||
|
||||
guard install(std::function<void()> cb)
|
||||
{
|
||||
this->s_callback = std::move(cb);
|
||||
|
||||
return guard{this};
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
if (s_callback) {
|
||||
s_callback();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> s_callback;
|
||||
};
|
||||
|
||||
template<typename Fn,
|
||||
typename... Args,
|
||||
std::enable_if_t<std::is_member_pointer<std::decay_t<Fn>>{}, int> = 0>
|
||||
|
@ -90,6 +90,28 @@ struct bind : singleton_storage<T, Annotations...> {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct lifetime {
|
||||
~lifetime()
|
||||
{
|
||||
singleton_storage<T, Annotations...>::ss_owner = nullptr;
|
||||
singleton_storage<T, Annotations...>::ss_data = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename I = T,
|
||||
std::enable_if_t<has_injectable<I>::value, bool> = true>
|
||||
static lifetime to_scoped_singleton() noexcept
|
||||
{
|
||||
typename I::injectable* i = nullptr;
|
||||
singleton_storage<T, Annotations...>::ss_owner
|
||||
= create_from_injectable<I>(i)();
|
||||
singleton_storage<T, Annotations...>::ss_data
|
||||
= singleton_storage<T, Annotations...>::ss_owner.get();
|
||||
singleton_storage<T, Annotations...>::ss_scope = scope::singleton;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static bool to_instance(T* (*f)(Args...)) noexcept
|
||||
{
|
||||
|
@ -55,16 +55,21 @@ void force_linking(Annotation anno);
|
||||
template<class...>
|
||||
using void_t = void;
|
||||
|
||||
template<class, class = void>
|
||||
struct has_injectable : std::false_type {
|
||||
template<typename T, typename... Annotations>
|
||||
struct with_annotations {
|
||||
T value;
|
||||
};
|
||||
|
||||
template<class, class = void>
|
||||
struct has_injectable : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct has_injectable<T, void_t<typename T::injectable>> : std::true_type {
|
||||
};
|
||||
struct has_injectable<T, void_t<typename T::injectable>> : std::true_type {};
|
||||
|
||||
template<typename T, typename... Annotations>
|
||||
struct singleton_storage {
|
||||
static scope get_scope() { return ss_scope; }
|
||||
|
||||
static T* get()
|
||||
{
|
||||
static int _[] = {0, (force_linking(Annotations{}), 0)...};
|
||||
@ -158,20 +163,16 @@ get()
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct is_shared_ptr : std::false_type {
|
||||
};
|
||||
struct is_shared_ptr : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {
|
||||
};
|
||||
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_vector : std::false_type {
|
||||
};
|
||||
struct is_vector : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_vector<std::vector<T>> : std::true_type {
|
||||
};
|
||||
struct is_vector<std::vector<T>> : std::true_type {};
|
||||
|
||||
template<typename I, typename R, typename... IArgs, typename... Args>
|
||||
std::function<std::shared_ptr<I>()> create_from_injectable(R (*)(IArgs...),
|
||||
@ -179,22 +180,28 @@ std::function<std::shared_ptr<I>()> create_from_injectable(R (*)(IArgs...),
|
||||
|
||||
template<typename T,
|
||||
typename... Args,
|
||||
std::enable_if_t<has_injectable<typename T::element_type>::value,
|
||||
bool> = true,
|
||||
std::enable_if_t<has_injectable<typename T::element_type>::value, bool>
|
||||
= true,
|
||||
std::enable_if_t<is_shared_ptr<T>::value, bool> = true>
|
||||
T
|
||||
get(Args&... args)
|
||||
{
|
||||
typename T::element_type::injectable* i = nullptr;
|
||||
|
||||
if (singleton_storage<typename T::element_type>::get_scope()
|
||||
== scope::singleton)
|
||||
{
|
||||
return singleton_storage<typename T::element_type>::get_owner();
|
||||
}
|
||||
return create_from_injectable<typename T::element_type>(i, args...)();
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename... Annotations,
|
||||
std::enable_if_t<!has_injectable<typename T::element_type>::value,
|
||||
bool> = true,
|
||||
std::enable_if_t<is_shared_ptr<T>::value, bool> = true>
|
||||
template<
|
||||
typename T,
|
||||
typename... Annotations,
|
||||
std::enable_if_t<!has_injectable<typename T::element_type>::value, bool>
|
||||
= true,
|
||||
std::enable_if_t<is_shared_ptr<T>::value, bool> = true>
|
||||
T
|
||||
get()
|
||||
{
|
||||
|
@ -34,8 +34,6 @@
|
||||
|
||||
struct last_relative_time_tag {};
|
||||
|
||||
struct sqlite_db_tag {};
|
||||
|
||||
struct sql_cmd_map_tag {};
|
||||
|
||||
enum {
|
||||
|
@ -66,8 +66,6 @@ SELECT count(*) AS total, min(log_line) AS log_line, log_msg_format
|
||||
int
|
||||
sql_progress(const struct log_cursor& lc)
|
||||
{
|
||||
static sig_atomic_t sql_counter = 0;
|
||||
|
||||
ssize_t total = lnav_data.ld_log_source.text_line_count();
|
||||
off_t off = lc.lc_curr_line;
|
||||
|
||||
@ -83,42 +81,11 @@ sql_progress(const struct log_cursor& lc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static sig_atomic_t sql_counter = 0;
|
||||
|
||||
if (ui_periodic_timer::singleton().time_to_update(sql_counter)) {
|
||||
struct timeval current_time = {0, 0};
|
||||
int ch;
|
||||
|
||||
while ((ch = getch()) != ERR) {
|
||||
if (current_time.tv_sec == 0) {
|
||||
gettimeofday(¤t_time, nullptr);
|
||||
}
|
||||
lnav_data.ld_user_message_source.clear();
|
||||
|
||||
alerter::singleton().new_input(ch);
|
||||
|
||||
lnav_data.ld_input_dispatcher.new_input(current_time, ch);
|
||||
|
||||
lnav_data.ld_view_stack.top() | [ch](auto tc) {
|
||||
lnav_data.ld_key_repeat_history.update(ch, tc->get_top());
|
||||
};
|
||||
|
||||
if (!lnav_data.ld_looping) {
|
||||
// No reason to keep processing input after the
|
||||
// user has quit. The view stack will also be
|
||||
// empty, which will cause issues.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lnav_data.ld_bottom_source.update_loading(off, total);
|
||||
lnav_data.ld_top_source.update_time();
|
||||
lnav_data.ld_status[LNS_TOP].do_update();
|
||||
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
||||
lnav_data.ld_rl_view->do_update();
|
||||
if (handle_winch()) {
|
||||
layout_views();
|
||||
lnav_data.ld_view_stack.do_update();
|
||||
}
|
||||
refresh();
|
||||
lnav_data.ld_status_refresher();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -132,9 +99,7 @@ sql_progress_finished()
|
||||
}
|
||||
|
||||
lnav_data.ld_bottom_source.update_loading(0, 0);
|
||||
lnav_data.ld_top_source.update_time();
|
||||
lnav_data.ld_status[LNS_TOP].do_update();
|
||||
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
||||
lnav_data.ld_status_refresher();
|
||||
lnav_data.ld_views[LNV_DB].redo_search();
|
||||
}
|
||||
|
||||
|
101
src/lnav.cc
101
src/lnav.cc
@ -230,8 +230,7 @@ static auto bound_active_files = injector::bind<file_collection>::to_instance(
|
||||
+[]() { return &lnav_data.ld_active_files; });
|
||||
|
||||
static auto bound_sqlite_db
|
||||
= injector::bind<auto_mem<sqlite3, sqlite_close_wrapper>,
|
||||
sqlite_db_tag>::to_instance(&lnav_data.ld_db);
|
||||
= injector::bind<auto_sqlite3>::to_instance(&lnav_data.ld_db);
|
||||
|
||||
static auto bound_lnav_flags
|
||||
= injector::bind<unsigned long, lnav_flags_tag>::to_instance(
|
||||
@ -264,12 +263,6 @@ force_linking(last_relative_time_tag anno)
|
||||
{
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
force_linking(sqlite_db_tag anno)
|
||||
{
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
force_linking(lnav_flags_tag anno)
|
||||
@ -1005,6 +998,55 @@ wait_for_pipers()
|
||||
}
|
||||
}
|
||||
|
||||
struct refresh_status_bars {
|
||||
refresh_status_bars(std::shared_ptr<top_status_source> top_source)
|
||||
: rsb_top_source(std::move(top_source))
|
||||
{
|
||||
}
|
||||
|
||||
using injectable
|
||||
= refresh_status_bars(std::shared_ptr<top_status_source> top_source);
|
||||
|
||||
void doit() const
|
||||
{
|
||||
struct timeval current_time {};
|
||||
int ch;
|
||||
|
||||
gettimeofday(¤t_time, nullptr);
|
||||
while ((ch = getch()) != ERR) {
|
||||
lnav_data.ld_user_message_source.clear();
|
||||
|
||||
alerter::singleton().new_input(ch);
|
||||
|
||||
lnav_data.ld_input_dispatcher.new_input(current_time, ch);
|
||||
|
||||
lnav_data.ld_view_stack.top() | [ch](auto tc) {
|
||||
lnav_data.ld_key_repeat_history.update(ch, tc->get_top());
|
||||
};
|
||||
|
||||
if (!lnav_data.ld_looping) {
|
||||
// No reason to keep processing input after the
|
||||
// user has quit. The view stack will also be
|
||||
// empty, which will cause issues.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->rsb_top_source->update_time(current_time);
|
||||
for (auto& sc : lnav_data.ld_status) {
|
||||
sc.do_update();
|
||||
}
|
||||
lnav_data.ld_rl_view->do_update();
|
||||
if (handle_winch()) {
|
||||
layout_views();
|
||||
lnav_data.ld_view_stack.do_update();
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
std::shared_ptr<top_status_source> rsb_top_source;
|
||||
};
|
||||
|
||||
static void
|
||||
looper()
|
||||
{
|
||||
@ -1340,10 +1382,15 @@ looper()
|
||||
lnav_data.ld_spectro_source->ss_exec_context
|
||||
= &lnav_data.ld_exec_context;
|
||||
|
||||
auto top_status_lifetime
|
||||
= injector::bind<top_status_source>::to_scoped_singleton();
|
||||
|
||||
auto top_source = injector::get<std::shared_ptr<top_status_source>>();
|
||||
|
||||
lnav_data.ld_status[LNS_TOP].set_top(0);
|
||||
lnav_data.ld_status[LNS_TOP].set_default_role(
|
||||
role_t::VCR_INACTIVE_STATUS);
|
||||
lnav_data.ld_status[LNS_TOP].set_data_source(&lnav_data.ld_top_source);
|
||||
lnav_data.ld_status[LNS_TOP].set_data_source(top_source.get());
|
||||
lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc->get_height() + 1));
|
||||
for (auto& stat_bar : lnav_data.ld_status) {
|
||||
stat_bar.set_window(lnav_data.ld_window);
|
||||
@ -1381,7 +1428,7 @@ looper()
|
||||
};
|
||||
|
||||
{
|
||||
input_dispatcher& id = lnav_data.ld_input_dispatcher;
|
||||
auto& id = lnav_data.ld_input_dispatcher;
|
||||
|
||||
id.id_escape_matcher = match_escape_seq;
|
||||
id.id_escape_handler = handle_keyseq;
|
||||
@ -1412,7 +1459,15 @@ looper()
|
||||
};
|
||||
}
|
||||
|
||||
ui_periodic_timer& timer = ui_periodic_timer::singleton();
|
||||
auto refresher_lifetime
|
||||
= injector::bind<refresh_status_bars>::to_scoped_singleton();
|
||||
|
||||
auto refresher = injector::get<std::shared_ptr<refresh_status_bars>>();
|
||||
|
||||
auto refresh_guard = lnav_data.ld_status_refresher.install(
|
||||
[refresher]() { refresher->doit(); });
|
||||
|
||||
auto& timer = ui_periodic_timer::singleton();
|
||||
struct timeval current_time;
|
||||
|
||||
static sig_atomic_t index_counter;
|
||||
@ -1450,7 +1505,7 @@ looper()
|
||||
|
||||
gettimeofday(¤t_time, nullptr);
|
||||
|
||||
lnav_data.ld_top_source.update_time(current_time);
|
||||
top_source->update_time(current_time);
|
||||
lnav_data.ld_preview_view.set_needs_update();
|
||||
|
||||
layout_views();
|
||||
@ -1562,7 +1617,7 @@ looper()
|
||||
lnav_data.ld_user_message_view.do_update();
|
||||
if (ui_clock::now() >= next_status_update_time) {
|
||||
echo_views_stmt.execute();
|
||||
lnav_data.ld_top_source.update_user_msg();
|
||||
top_source->update_user_msg();
|
||||
for (auto& sc : lnav_data.ld_status) {
|
||||
sc.do_update();
|
||||
}
|
||||
@ -2150,6 +2205,26 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
// XXX
|
||||
lnav_data.ld_log_source.set_preview_sql_filter(nullptr);
|
||||
lnav_data.ld_log_source.set_sql_filter("", nullptr);
|
||||
lnav_data.ld_log_source.set_sql_marker("", nullptr);
|
||||
lnav_config_listener::unload_all();
|
||||
|
||||
{
|
||||
sqlite3_stmt* stmt_iter = nullptr;
|
||||
|
||||
do {
|
||||
stmt_iter = sqlite3_next_stmt(lnav_data.ld_db.in(), stmt_iter);
|
||||
if (stmt_iter != nullptr) {
|
||||
const auto* stmt_sql = sqlite3_sql(stmt_iter);
|
||||
|
||||
log_warning("unfinalized SQL statement: %s", stmt_sql);
|
||||
ensure(false);
|
||||
}
|
||||
} while (stmt_iter != nullptr);
|
||||
}
|
||||
|
||||
for (auto& drop_stmt : tables_to_drop) {
|
||||
sqlite3_exec(lnav_data.ld_db.in(),
|
||||
drop_stmt.c_str(),
|
||||
|
@ -71,7 +71,6 @@
|
||||
#include "sql_util.hh"
|
||||
#include "statusview_curses.hh"
|
||||
#include "textfile_sub_source.hh"
|
||||
#include "top_status_source.hh"
|
||||
#include "view_helpers.hh"
|
||||
|
||||
class spectrogram_source;
|
||||
@ -184,7 +183,6 @@ struct lnav_data_t {
|
||||
ln_mode_t ld_last_config_mode{ln_mode_t::FILTER};
|
||||
|
||||
statusview_curses ld_status[LNS__MAX];
|
||||
top_status_source ld_top_source;
|
||||
bottom_status_source ld_bottom_source;
|
||||
filter_status_source ld_filter_status_source;
|
||||
filter_help_status_source ld_filter_help_status_source;
|
||||
@ -259,6 +257,8 @@ struct lnav_data_t {
|
||||
bool ld_initial_build{false};
|
||||
bool ld_show_help_view{false};
|
||||
|
||||
lnav::func::scoped_cb ld_status_refresher;
|
||||
|
||||
ghc::filesystem::file_time_type ld_last_dot_lnav_time;
|
||||
};
|
||||
|
||||
|
@ -85,10 +85,7 @@ do_observer_update(const std::shared_ptr<logfile>& lf)
|
||||
if (isendwin()) {
|
||||
return;
|
||||
}
|
||||
lnav_data.ld_top_source.update_time();
|
||||
for (auto& sc : lnav_data.ld_status) {
|
||||
sc.do_update();
|
||||
}
|
||||
lnav_data.ld_status_refresher();
|
||||
if (lf && lnav_data.ld_mode == ln_mode_t::FILES
|
||||
&& !lnav_data.ld_initial_build)
|
||||
{
|
||||
@ -437,15 +434,7 @@ rescan_files(bool req)
|
||||
if (!done && !(lnav_data.ld_flags & LNF_HEADLESS)) {
|
||||
lnav_data.ld_files_view.set_needs_update();
|
||||
lnav_data.ld_files_view.do_update();
|
||||
lnav_data.ld_top_source.update_time();
|
||||
lnav_data.ld_status[LNS_TOP].do_update();
|
||||
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
||||
lnav_data.ld_rl_view->do_update();
|
||||
if (handle_winch()) {
|
||||
layout_views();
|
||||
lnav_data.ld_view_stack.do_update();
|
||||
}
|
||||
refresh();
|
||||
lnav_data.ld_status_refresher();
|
||||
}
|
||||
} while (!done && lnav_data.ld_looping);
|
||||
return true;
|
||||
|
@ -96,6 +96,9 @@ static auto scc = injector::bind<sysclip::config>::to_instance(
|
||||
static auto lsc = injector::bind<logfile_sub_source_ns::config>::to_instance(
|
||||
+[]() { return &lnav_config.lc_log_source; });
|
||||
|
||||
static auto tssc = injector::bind<top_status_source_cfg>::to_instance(
|
||||
+[]() { return &lnav_config.lc_top_status_cfg; });
|
||||
|
||||
bool
|
||||
check_experimental(const char* feature_name)
|
||||
{
|
||||
@ -961,7 +964,8 @@ static const struct json_path_container ui_handlers = {
|
||||
.with_description("The format for the clock displayed in "
|
||||
"the top-left corner using strftime(3) conversions")
|
||||
.with_example("%a %b %d %H:%M:%S %Z")
|
||||
.for_field(&_lnav_config::lc_ui_clock_format),
|
||||
.for_field(&_lnav_config::lc_top_status_cfg,
|
||||
&top_status_source_cfg::tssc_clock_format),
|
||||
yajlpp::property_handler("dim-text")
|
||||
.with_synopsis("bool")
|
||||
.with_description("Reduce the brightness of text (useful for xterms). "
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "styling.hh"
|
||||
#include "sysclip.cfg.hh"
|
||||
#include "tailer/tailer.looper.cfg.hh"
|
||||
#include "top_status_source.cfg.hh"
|
||||
|
||||
/**
|
||||
* Check if an experimental feature should be enabled by
|
||||
@ -85,7 +86,7 @@ struct key_map {
|
||||
};
|
||||
|
||||
struct _lnav_config {
|
||||
std::string lc_ui_clock_format;
|
||||
top_status_source_cfg lc_top_status_cfg;
|
||||
bool lc_ui_dim_text;
|
||||
bool lc_ui_default_colors{true};
|
||||
std::string lc_ui_keymap;
|
||||
|
@ -52,6 +52,16 @@ public:
|
||||
|
||||
virtual void reload_config(error_reporter& reporter) {}
|
||||
|
||||
virtual void unload_config() {}
|
||||
|
||||
static void unload_all() {
|
||||
auto* lcl = LISTENER_LIST;
|
||||
while (lcl != nullptr) {
|
||||
lcl->unload_config();
|
||||
lcl = lcl->lcl_next;
|
||||
}
|
||||
}
|
||||
|
||||
static lnav_config_listener* LISTENER_LIST;
|
||||
|
||||
lnav_config_listener* lcl_next;
|
||||
|
@ -52,8 +52,7 @@ struct compiled_watch_expr {
|
||||
struct expressions : public lnav_config_listener {
|
||||
void reload_config(error_reporter& reporter) override
|
||||
{
|
||||
auto& lnav_db = injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>();
|
||||
auto& lnav_db = injector::get<auto_sqlite3&>();
|
||||
|
||||
if (lnav_db.in() == nullptr) {
|
||||
log_warning("db not initialized yet!");
|
||||
@ -99,6 +98,10 @@ struct expressions : public lnav_config_listener {
|
||||
}
|
||||
}
|
||||
|
||||
void unload_config() override {
|
||||
this->e_watch_exprs.clear();
|
||||
}
|
||||
|
||||
std::map<std::string, compiled_watch_expr> e_watch_exprs;
|
||||
};
|
||||
|
||||
@ -114,9 +117,7 @@ eval_with(logfile& lf, logfile::iterator ll)
|
||||
return;
|
||||
}
|
||||
|
||||
static auto& lnav_db
|
||||
= injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>();
|
||||
static auto& lnav_db = injector::get<auto_sqlite3&>();
|
||||
|
||||
char timestamp_buffer[64] = "";
|
||||
shared_buffer_ref raw_sbr;
|
||||
|
@ -1334,12 +1334,17 @@ logfile_sub_source::set_sql_marker(std::string stmt_str, sqlite3_stmt* stmt)
|
||||
}
|
||||
}
|
||||
|
||||
this->lss_marker_stmt_text = std::move(stmt_str);
|
||||
this->lss_marker_stmt = stmt;
|
||||
|
||||
if (this->tss_view == nullptr) {
|
||||
return Ok();
|
||||
}
|
||||
|
||||
auto& vis_bm = this->tss_view->get_bookmarks();
|
||||
auto& expr_marks_bv = vis_bm[&textview_curses::BM_USER_EXPR];
|
||||
|
||||
expr_marks_bv.clear();
|
||||
this->lss_marker_stmt_text = std::move(stmt_str);
|
||||
this->lss_marker_stmt = stmt;
|
||||
if (this->lss_index_delegate) {
|
||||
this->lss_index_delegate->index_start(*this);
|
||||
}
|
||||
|
@ -175,9 +175,7 @@ replace_home_dir(std::string path)
|
||||
Result<void, lnav::console::user_message>
|
||||
export_to(FILE* file)
|
||||
{
|
||||
static auto& lnav_db
|
||||
= injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>();
|
||||
static auto& lnav_db = injector::get<auto_sqlite3&>();
|
||||
|
||||
static const char* BOOKMARK_QUERY = R"(
|
||||
SELECT log_time_msecs, log_format, log_mark, log_comment, log_tags, log_line_hash
|
||||
|
@ -45,9 +45,7 @@ sql_cmd_dump(exec_context& ec,
|
||||
std::string cmdline,
|
||||
std::vector<std::string>& args)
|
||||
{
|
||||
static auto& lnav_db
|
||||
= injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>();
|
||||
static auto& lnav_db = injector::get<auto_sqlite3&>();
|
||||
static auto& lnav_flags = injector::get<unsigned long&, lnav_flags_tag>();
|
||||
|
||||
std::string retval;
|
||||
@ -90,9 +88,7 @@ sql_cmd_read(exec_context& ec,
|
||||
std::string cmdline,
|
||||
std::vector<std::string>& args)
|
||||
{
|
||||
static auto& lnav_db
|
||||
= injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>();
|
||||
static auto& lnav_db = injector::get<auto_sqlite3&>();
|
||||
static auto& lnav_flags = injector::get<unsigned long&, lnav_flags_tag>();
|
||||
|
||||
std::string retval;
|
||||
|
@ -43,6 +43,8 @@
|
||||
/* XXX figure out how to do this with the template */
|
||||
void sqlite_close_wrapper(void* mem);
|
||||
|
||||
using auto_sqlite3 = auto_mem<sqlite3, sqlite_close_wrapper>;
|
||||
|
||||
namespace sqlitepp {
|
||||
|
||||
inline auto_mem<char>
|
||||
|
@ -455,9 +455,7 @@ textfile_sub_source::rescan_files(
|
||||
textfile_sub_source::scan_callback& callback,
|
||||
nonstd::optional<ui_clock::time_point> deadline)
|
||||
{
|
||||
static auto& lnav_db
|
||||
= injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>();
|
||||
static auto& lnav_db = injector::get<auto_sqlite3&>();
|
||||
|
||||
file_iterator iter;
|
||||
bool retval = false;
|
||||
|
@ -29,22 +29,31 @@
|
||||
|
||||
#include "top_status_source.hh"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "base/injector.hh"
|
||||
#include "bound_tags.hh"
|
||||
#include "config.h"
|
||||
#include "lnav.hh"
|
||||
#include "lnav_config.hh"
|
||||
#include "logfile_sub_source.hh"
|
||||
#include "md2attr_line.hh"
|
||||
#include "md4cpp.hh"
|
||||
#include "shlex.hh"
|
||||
#include "shlex.resolver.hh"
|
||||
#include "sql_util.hh"
|
||||
#include "sqlitepp.client.hh"
|
||||
#include "top_status_source.cfg.hh"
|
||||
|
||||
top_status_source::top_status_source()
|
||||
static const char* MSG_QUERY = R"(
|
||||
SELECT message FROM lnav_user_notifications
|
||||
WHERE message IS NOT NULL AND
|
||||
(expiration IS NULL OR expiration > datetime('now')) AND
|
||||
(views IS NULL OR
|
||||
json_contains(views, (SELECT name FROM lnav_top_view)))
|
||||
ORDER BY priority DESC
|
||||
LIMIT 1
|
||||
)";
|
||||
|
||||
top_status_source::top_status_source(auto_sqlite3& db,
|
||||
const top_status_source_cfg& cfg)
|
||||
: tss_config(cfg),
|
||||
tss_user_msgs_stmt(prepare_stmt(db.in(), MSG_QUERY).unwrap())
|
||||
{
|
||||
this->tss_fields[TSF_TIME].set_width(28);
|
||||
this->tss_fields[TSF_TIME].set_role(role_t::VCR_STATUS_INFO);
|
||||
@ -62,7 +71,7 @@ top_status_source::update_time(const timeval& current_time)
|
||||
buffer[0] = ' ';
|
||||
strftime(&buffer[1],
|
||||
sizeof(buffer) - 1,
|
||||
lnav_config.lc_ui_clock_format.c_str(),
|
||||
this->tss_config.tssc_clock_format.c_str(),
|
||||
localtime(¤t_time.tv_sec));
|
||||
sf.set_value(buffer);
|
||||
}
|
||||
@ -76,40 +85,14 @@ top_status_source::update_time()
|
||||
this->update_time(tv);
|
||||
}
|
||||
|
||||
static const char* MSG_QUERY = R"(
|
||||
SELECT message FROM lnav_user_notifications
|
||||
WHERE message IS NOT NULL AND
|
||||
(expiration IS NULL OR expiration > datetime('now')) AND
|
||||
(views IS NULL OR
|
||||
json_contains(views, (SELECT name FROM lnav_top_view)))
|
||||
ORDER BY priority DESC
|
||||
LIMIT 1
|
||||
)";
|
||||
|
||||
struct user_msg_stmt {
|
||||
user_msg_stmt()
|
||||
: ums_stmt(
|
||||
prepare_stmt(injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>()
|
||||
.in(),
|
||||
MSG_QUERY)
|
||||
.unwrap())
|
||||
{
|
||||
}
|
||||
|
||||
prepared_stmt ums_stmt;
|
||||
};
|
||||
|
||||
void
|
||||
top_status_source::update_user_msg()
|
||||
{
|
||||
static thread_local user_msg_stmt um_stmt;
|
||||
|
||||
auto& al = this->tss_fields[TSF_USER_MSG].get_value();
|
||||
al.clear();
|
||||
|
||||
um_stmt.ums_stmt.reset();
|
||||
auto fetch_res = um_stmt.ums_stmt.fetch_row<std::string>();
|
||||
this->tss_user_msgs_stmt.reset();
|
||||
auto fetch_res = this->tss_user_msgs_stmt.fetch_row<std::string>();
|
||||
fetch_res.match(
|
||||
[&al](const std::string& value) {
|
||||
shlex lexer(value);
|
||||
|
37
src/top_status_source.cfg.hh
Normal file
37
src/top_status_source.cfg.hh
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2022, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lnav_top_status_source_cfg_hh
|
||||
#define lnav_top_status_source_cfg_hh
|
||||
|
||||
struct top_status_source_cfg {
|
||||
std::string tssc_clock_format;
|
||||
};
|
||||
|
||||
#endif
|
@ -32,19 +32,30 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "base/injector.hh"
|
||||
#include "bound_tags.hh"
|
||||
#include "listview_curses.hh"
|
||||
#include "sql_util.hh"
|
||||
#include "sqlitepp.client.hh"
|
||||
#include "statusview_curses.hh"
|
||||
#include "top_status_source.cfg.hh"
|
||||
|
||||
class top_status_source : public status_data_source {
|
||||
public:
|
||||
typedef enum {
|
||||
enum field_t {
|
||||
TSF_TIME,
|
||||
TSF_USER_MSG,
|
||||
|
||||
TSF__MAX
|
||||
} field_t;
|
||||
};
|
||||
|
||||
top_status_source();
|
||||
explicit top_status_source(auto_sqlite3& db,
|
||||
const top_status_source_cfg& cfg);
|
||||
|
||||
using injectable
|
||||
= top_status_source(auto_sqlite3& db, const top_status_source_cfg& cfg);
|
||||
|
||||
size_t statusview_fields() override { return TSF__MAX; }
|
||||
|
||||
@ -60,7 +71,9 @@ public:
|
||||
void update_user_msg();
|
||||
|
||||
private:
|
||||
const top_status_source_cfg& tss_config;
|
||||
status_field tss_fields[TSF__MAX];
|
||||
prepared_stmt tss_user_msgs_stmt;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -294,6 +294,8 @@ EXPECTED_FILES = \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_09bd16e044302f6b121092534708594bdad11b5a.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_1c6eee38f66356fcd9a9f0faedaea6dbcc901060.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_1c6eee38f66356fcd9a9f0faedaea6dbcc901060.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_218ecb88b4753010c4264b3ac351260b4811612f.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_218ecb88b4753010c4264b3ac351260b4811612f.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_290a3c49e53c2229a7400c107338fa0bb38375e2.err \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_290a3c49e53c2229a7400c107338fa0bb38375e2.out \
|
||||
$(srcdir)/%reldir%/test_logfile.sh_3fc6bfd8a6160817211f3e14fde957af75b9dbe7.err \
|
||||
|
@ -0,0 +1,2 @@
|
||||
[1m[4mbasename(filepath) [0m[1m[4m descriptor [0m[1m[4m mimetype [0m[1m[4m content [0m
|
||||
[1mlogfile_syslog.1.gz[0m[1m [0m[1mnet.zlib.gzip.header[0m[1m [0m[1mapplication/json[0m[1m [0m[1m{"name":"logfile_syslog.1","mtime":"2007-11-03T16:23:00.000","comment":""} [0m
|
@ -697,5 +697,5 @@ run_cap_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_ansi.1
|
||||
|
||||
run_cap_test ${lnav_test} -n \
|
||||
-c ';SELECT * FROM lnav_file_metadata' \
|
||||
-c ';SELECT basename(filepath),descriptor,mimetype,content FROM lnav_file_metadata' \
|
||||
logfile_syslog.1.gz
|
||||
|
@ -72,11 +72,6 @@ rebuild_indexes_repeatedly()
|
||||
readline_context::command_map_t lnav_commands;
|
||||
|
||||
namespace injector {
|
||||
template<>
|
||||
void
|
||||
force_linking(sqlite_db_tag anno)
|
||||
{
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
|
@ -51,7 +51,15 @@ main(int argc, char* argv[])
|
||||
{
|
||||
int retval = EXIT_SUCCESS;
|
||||
|
||||
top_status_source tss;
|
||||
auto_sqlite3 db;
|
||||
|
||||
if (sqlite3_open(":memory:", db.out()) != SQLITE_OK) {
|
||||
fprintf(stderr, "error: unable to create sqlite memory database\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
top_status_source_cfg cfg;
|
||||
top_status_source tss(db, cfg);
|
||||
|
||||
setenv("HOME", "/", 1);
|
||||
|
||||
@ -72,7 +80,7 @@ main(int argc, char* argv[])
|
||||
tss.update_time();
|
||||
assert(val.get_string() != sf.get_value().get_string());
|
||||
|
||||
lnav_config.lc_ui_clock_format = "abc";
|
||||
cfg.tssc_clock_format = "abc";
|
||||
tss.update_time();
|
||||
val = sf.get_value();
|
||||
assert(val.get_string() == " abc");
|
||||
|
Loading…
Reference in New Issue
Block a user