mirror of https://github.com/tstack/lnav.git
[config-ui] support for searching
This commit is contained in:
parent
8b38bb0970
commit
56866d8a33
|
@ -32,6 +32,7 @@
|
|||
#ifndef curl_looper_hh
|
||||
#define curl_looper_hh
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -234,7 +235,7 @@ private:
|
|||
|
||||
bool cl_started;
|
||||
pthread_t cl_thread;
|
||||
volatile bool cl_looping;
|
||||
std::atomic<bool> cl_looping;
|
||||
auto_mem<CURLM> cl_curl_multi;
|
||||
pthread_mutex_t cl_mutex;
|
||||
pthread_cond_t cl_cond;
|
||||
|
|
|
@ -103,6 +103,19 @@ bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
|
|||
lv.reload_data();
|
||||
return true;
|
||||
}
|
||||
case 'n': {
|
||||
execute_command(lnav_data.ld_exec_context, "next-mark search");
|
||||
return true;
|
||||
}
|
||||
case 'N': {
|
||||
execute_command(lnav_data.ld_exec_context, "prev-mark search");
|
||||
return true;
|
||||
}
|
||||
case '/': {
|
||||
execute_command(lnav_data.ld_exec_context,
|
||||
"prompt search-files");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -219,6 +219,19 @@ bool filter_sub_source::list_input_handle_key(listview_curses &lv, int ch)
|
|||
tss->text_filters_changed();
|
||||
return true;
|
||||
}
|
||||
case 'n': {
|
||||
execute_command(lnav_data.ld_exec_context, "next-mark search");
|
||||
return true;
|
||||
}
|
||||
case 'N': {
|
||||
execute_command(lnav_data.ld_exec_context, "prev-mark search");
|
||||
return true;
|
||||
}
|
||||
case '/': {
|
||||
execute_command(lnav_data.ld_exec_context,
|
||||
"prompt search-filters");
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
log_debug("unhandled %x", ch);
|
||||
break;
|
||||
|
|
|
@ -347,8 +347,14 @@ public:
|
|||
if (this->lv_selectable) {
|
||||
if (this->lv_selection < top) {
|
||||
this->lv_selection = top;
|
||||
} else if (this->lv_selection > this->get_bottom()) {
|
||||
this->lv_selection = this->get_bottom();
|
||||
} else {
|
||||
auto bot = this->get_bottom();
|
||||
|
||||
if (bot != -1_vl) {
|
||||
if (this->lv_selection > bot) {
|
||||
this->lv_selection = bot;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this->invoke_scroll();
|
||||
|
@ -367,6 +373,8 @@ public:
|
|||
|
||||
if (avail > 0) {
|
||||
retval += vis_line_t(avail - 1);
|
||||
} else {
|
||||
retval = -1_vl;
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
|
65
src/lnav.cc
65
src/lnav.cc
|
@ -715,7 +715,7 @@ vis_line_t next_cluster(
|
|||
bookmark_type_t *bt,
|
||||
const vis_line_t top)
|
||||
{
|
||||
textview_curses *tc = *(lnav_data.ld_view_stack.top());
|
||||
textview_curses *tc = get_textview_for_mode(lnav_data.ld_mode);
|
||||
vis_bookmarks &bm = tc->get_bookmarks();
|
||||
bookmark_vector<vis_line_t> &bv = bm[bt];
|
||||
bool top_is_marked = binary_search(bv.begin(), bv.end(), top);
|
||||
|
@ -760,19 +760,26 @@ bool moveto_cluster(vis_line_t(bookmark_vector<vis_line_t>::*f) (vis_line_t) con
|
|||
bookmark_type_t *bt,
|
||||
vis_line_t top)
|
||||
{
|
||||
textview_curses *tc = *(lnav_data.ld_view_stack.top());
|
||||
textview_curses *tc = get_textview_for_mode(lnav_data.ld_mode);
|
||||
vis_line_t new_top;
|
||||
|
||||
new_top = next_cluster(f, bt, top);
|
||||
if (new_top == -1) {
|
||||
new_top = next_cluster(f, bt, tc->get_top());
|
||||
new_top = next_cluster(f, bt,
|
||||
tc->is_selectable() ?
|
||||
tc->get_selection() :
|
||||
tc->get_top());
|
||||
}
|
||||
if (new_top != -1) {
|
||||
tc->get_sub_source()->get_location_history() | [new_top] (auto lh) {
|
||||
lh->loc_history_append(new_top);
|
||||
};
|
||||
|
||||
tc->set_top(new_top);
|
||||
if (tc->is_selectable()) {
|
||||
tc->set_selection(new_top);
|
||||
} else {
|
||||
tc->set_top(new_top);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -784,9 +791,14 @@ bool moveto_cluster(vis_line_t(bookmark_vector<vis_line_t>::*f) (vis_line_t) con
|
|||
void previous_cluster(bookmark_type_t *bt, textview_curses *tc)
|
||||
{
|
||||
key_repeat_history &krh = lnav_data.ld_key_repeat_history;
|
||||
vis_line_t height, new_top, initial_top = tc->get_top();
|
||||
vis_line_t height, new_top, initial_top;
|
||||
unsigned long width;
|
||||
|
||||
if (tc->is_selectable()) {
|
||||
initial_top = tc->get_selection();
|
||||
} else {
|
||||
initial_top = tc->get_top();
|
||||
}
|
||||
new_top = next_cluster(&bookmark_vector<vis_line_t>::prev,
|
||||
bt,
|
||||
initial_top);
|
||||
|
@ -804,7 +816,11 @@ void previous_cluster(bookmark_type_t *bt, textview_curses *tc)
|
|||
lh->loc_history_append(new_top);
|
||||
};
|
||||
|
||||
tc->set_top(new_top);
|
||||
if (tc->is_selectable()) {
|
||||
tc->set_selection(new_top);
|
||||
} else {
|
||||
tc->set_top(new_top);
|
||||
}
|
||||
}
|
||||
else {
|
||||
alerter::singleton().chime();
|
||||
|
@ -813,7 +829,8 @@ void previous_cluster(bookmark_type_t *bt, textview_curses *tc)
|
|||
|
||||
vis_line_t search_forward_from(textview_curses *tc)
|
||||
{
|
||||
vis_line_t height, retval = tc->get_top();
|
||||
vis_line_t height, retval =
|
||||
tc->is_selectable() ? tc->get_selection() : tc->get_top();
|
||||
key_repeat_history &krh = lnav_data.ld_key_repeat_history;
|
||||
unsigned long width;
|
||||
|
||||
|
@ -1315,6 +1332,8 @@ static bool handle_key(int ch) {
|
|||
|
||||
case LNM_COMMAND:
|
||||
case LNM_SEARCH:
|
||||
case LNM_SEARCH_FILTERS:
|
||||
case LNM_SEARCH_FILES:
|
||||
case LNM_CAPTURE:
|
||||
case LNM_SQL:
|
||||
case LNM_EXEC:
|
||||
|
@ -1479,6 +1498,8 @@ static void looper()
|
|||
readline_context command_context("cmd", &lnav_commands);
|
||||
|
||||
readline_context search_context("search", nullptr, false);
|
||||
readline_context search_filters_context("search-filters", nullptr, false);
|
||||
readline_context search_files_context("search-files", nullptr, false);
|
||||
readline_context index_context("capture");
|
||||
readline_context sql_context("sql", nullptr, false);
|
||||
readline_context exec_context("exec");
|
||||
|
@ -1491,6 +1512,12 @@ static void looper()
|
|||
search_context
|
||||
.set_append_character(0)
|
||||
.set_highlighter(readline_regex_highlighter);
|
||||
search_filters_context
|
||||
.set_append_character(0)
|
||||
.set_highlighter(readline_regex_highlighter);
|
||||
search_files_context
|
||||
.set_append_character(0)
|
||||
.set_highlighter(readline_regex_highlighter);
|
||||
sql_context
|
||||
.set_highlighter(readline_sqlite_highlighter)
|
||||
.set_quote_chars("\"")
|
||||
|
@ -1505,6 +1532,8 @@ static void looper()
|
|||
|
||||
rlc.add_context(LNM_COMMAND, command_context);
|
||||
rlc.add_context(LNM_SEARCH, search_context);
|
||||
rlc.add_context(LNM_SEARCH_FILTERS, search_filters_context);
|
||||
rlc.add_context(LNM_SEARCH_FILES, search_files_context);
|
||||
rlc.add_context(LNM_CAPTURE, index_context);
|
||||
rlc.add_context(LNM_SQL, sql_context);
|
||||
rlc.add_context(LNM_EXEC, exec_context);
|
||||
|
@ -1797,6 +1826,8 @@ static void looper()
|
|||
for (auto &tc : lnav_data.ld_views) {
|
||||
tc.update_poll_set(pollfds);
|
||||
}
|
||||
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;
|
||||
|
@ -1850,6 +1881,8 @@ static void looper()
|
|||
|
||||
rlc.check_poll_set(pollfds);
|
||||
lnav_data.ld_filter_source.fss_editor.check_poll_set(pollfds);
|
||||
lnav_data.ld_filter_view.check_poll_set(pollfds);
|
||||
lnav_data.ld_files_view.check_poll_set(pollfds);
|
||||
}
|
||||
|
||||
if (timer.time_to_update(overlay_counter)) {
|
||||
|
@ -2006,6 +2039,8 @@ void wait_for_children()
|
|||
for (auto &tc : lnav_data.ld_views) {
|
||||
tc.update_poll_set(pollfds);
|
||||
}
|
||||
lnav_data.ld_filter_view.update_poll_set(pollfds);
|
||||
lnav_data.ld_files_view.update_poll_set(pollfds);
|
||||
|
||||
if (pollfds.empty()) {
|
||||
return;
|
||||
|
@ -2030,9 +2065,25 @@ void wait_for_children()
|
|||
lnav_data.ld_bottom_source.update_hits(tc);
|
||||
};
|
||||
}
|
||||
lnav_data.ld_filter_view.check_poll_set(pollfds);
|
||||
lnav_data.ld_files_view.check_poll_set(pollfds);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
textview_curses *get_textview_for_mode(ln_mode_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case LNM_SEARCH_FILTERS:
|
||||
case LNM_FILTER:
|
||||
return &lnav_data.ld_filter_view;
|
||||
case LNM_SEARCH_FILES:
|
||||
case LNM_FILES:
|
||||
return &lnav_data.ld_files_view;
|
||||
default:
|
||||
return *lnav_data.ld_view_stack.top();
|
||||
}
|
||||
}
|
||||
|
||||
static void print_errors(vector<string> error_list)
|
||||
{
|
||||
for (auto &iter : error_list) {
|
||||
|
|
|
@ -78,6 +78,8 @@ typedef enum {
|
|||
LNM_FILES,
|
||||
LNM_COMMAND,
|
||||
LNM_SEARCH,
|
||||
LNM_SEARCH_FILTERS,
|
||||
LNM_SEARCH_FILES,
|
||||
LNM_CAPTURE,
|
||||
LNM_SQL,
|
||||
LNM_EXEC,
|
||||
|
@ -380,5 +382,6 @@ bool moveto_cluster(vis_line_t(bookmark_vector<vis_line_t>::*f) (vis_line_t) con
|
|||
vis_line_t top);
|
||||
void previous_cluster(bookmark_type_t *bt, textview_curses *tc);
|
||||
vis_line_t search_forward_from(textview_curses *tc);
|
||||
textview_curses *get_textview_for_mode(ln_mode_t mode);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -430,7 +430,7 @@ static Result<string, string> com_goto_mark(exec_context &ec, string cmdline, ve
|
|||
args.emplace_back("mark-type");
|
||||
}
|
||||
else {
|
||||
textview_curses *tc = *lnav_data.ld_view_stack.top();
|
||||
textview_curses *tc = get_textview_for_mode(lnav_data.ld_mode);
|
||||
string type_name = "user";
|
||||
|
||||
if (args.size() > 1) {
|
||||
|
@ -4119,6 +4119,43 @@ static void search_prompt(vector<string> &args)
|
|||
ANSI_BOLD("CTRL+]") " to abort)");
|
||||
}
|
||||
|
||||
static void search_filters_prompt(vector<string> &args)
|
||||
{
|
||||
lnav_data.ld_mode = LNM_SEARCH_FILTERS;
|
||||
add_view_text_possibilities(lnav_data.ld_rl_view,
|
||||
LNM_SEARCH_FILTERS,
|
||||
"*",
|
||||
&lnav_data.ld_filter_view);
|
||||
lnav_data.ld_rl_view->focus(LNM_SEARCH_FILTERS,
|
||||
cget(args, 2).value_or("/"),
|
||||
cget(args, 3).value_or(""));
|
||||
lnav_data.ld_bottom_source.set_prompt(
|
||||
"Search for: "
|
||||
"(Press " ANSI_BOLD("CTRL+J") " to jump to a previous hit and "
|
||||
ANSI_BOLD("CTRL+]") " to abort)");
|
||||
}
|
||||
|
||||
static void search_files_prompt(vector<string> &args)
|
||||
{
|
||||
static pcrecpp::RE re_escape(R"(([.\^$*+?()\[\]{}\\|]))");
|
||||
|
||||
lnav_data.ld_mode = LNM_SEARCH_FILES;
|
||||
for (const auto& lf : lnav_data.ld_active_files.fc_files) {
|
||||
auto path = lf->get_unique_path();
|
||||
re_escape.GlobalReplace(R"(\\\1)", &path);
|
||||
lnav_data.ld_rl_view->add_possibility(LNM_SEARCH_FILES,
|
||||
"*",
|
||||
path);
|
||||
}
|
||||
lnav_data.ld_rl_view->focus(LNM_SEARCH_FILES,
|
||||
cget(args, 2).value_or("/"),
|
||||
cget(args, 3).value_or(""));
|
||||
lnav_data.ld_bottom_source.set_prompt(
|
||||
"Search for: "
|
||||
"(Press " ANSI_BOLD("CTRL+J") " to jump to a previous hit and "
|
||||
ANSI_BOLD("CTRL+]") " to abort)");
|
||||
}
|
||||
|
||||
static void sql_prompt(vector<string> &args)
|
||||
{
|
||||
textview_curses *tc = *lnav_data.ld_view_stack.top();
|
||||
|
@ -4170,6 +4207,8 @@ static Result<string, string> com_prompt(exec_context &ec, string cmdline, vecto
|
|||
{"command", command_prompt},
|
||||
{"script", script_prompt},
|
||||
{"search", search_prompt},
|
||||
{"search-filters", search_filters_prompt},
|
||||
{"search-files", search_files_prompt},
|
||||
{"sql", sql_prompt},
|
||||
{"user", user_prompt},
|
||||
};
|
||||
|
|
|
@ -142,7 +142,7 @@ void rl_set_help()
|
|||
|
||||
void rl_change(void *dummy, readline_curses *rc)
|
||||
{
|
||||
textview_curses *tc = *lnav_data.ld_view_stack.top();
|
||||
textview_curses *tc = get_textview_for_mode(lnav_data.ld_mode);
|
||||
|
||||
tc->get_highlights().erase({highlight_source_t::PREVIEW, "preview"});
|
||||
tc->get_highlights().erase({highlight_source_t::PREVIEW, "bodypreview"});
|
||||
|
@ -271,7 +271,7 @@ void rl_change(void *dummy, readline_curses *rc)
|
|||
|
||||
static void rl_search_internal(void *dummy, readline_curses *rc, ln_mode_t mode, bool complete = false)
|
||||
{
|
||||
textview_curses *tc = *lnav_data.ld_view_stack.top();
|
||||
textview_curses *tc = get_textview_for_mode(mode);
|
||||
string term_val;
|
||||
string name;
|
||||
|
||||
|
@ -281,6 +281,8 @@ static void rl_search_internal(void *dummy, readline_curses *rc, ln_mode_t mode,
|
|||
|
||||
switch (mode) {
|
||||
case LNM_SEARCH:
|
||||
case LNM_SEARCH_FILTERS:
|
||||
case LNM_SEARCH_FILES:
|
||||
name = "$search";
|
||||
break;
|
||||
|
||||
|
@ -440,7 +442,7 @@ static void rl_search_internal(void *dummy, readline_curses *rc, ln_mode_t mode,
|
|||
|
||||
void rl_search(void *dummy, readline_curses *rc)
|
||||
{
|
||||
textview_curses *tc = *lnav_data.ld_view_stack.top();
|
||||
textview_curses *tc = get_textview_for_mode(lnav_data.ld_mode);
|
||||
|
||||
rl_search_internal(dummy, rc, lnav_data.ld_mode);
|
||||
tc->set_follow_search_for(0, {});
|
||||
|
@ -448,7 +450,7 @@ void rl_search(void *dummy, readline_curses *rc)
|
|||
|
||||
void rl_abort(void *dummy, readline_curses *rc)
|
||||
{
|
||||
textview_curses *tc = *lnav_data.ld_view_stack.top();
|
||||
textview_curses *tc = get_textview_for_mode(lnav_data.ld_mode);
|
||||
|
||||
lnav_data.ld_bottom_source.set_prompt("");
|
||||
lnav_data.ld_example_source.clear();
|
||||
|
@ -480,7 +482,7 @@ void rl_abort(void *dummy, readline_curses *rc)
|
|||
|
||||
static void rl_callback_int(void *dummy, readline_curses *rc, bool is_alt)
|
||||
{
|
||||
textview_curses *tc = *lnav_data.ld_view_stack.top();
|
||||
textview_curses *tc = get_textview_for_mode(lnav_data.ld_mode);
|
||||
exec_context &ec = lnav_data.ld_exec_context;
|
||||
string alt_msg;
|
||||
|
||||
|
@ -492,7 +494,20 @@ static void rl_callback_int(void *dummy, readline_curses *rc, bool is_alt)
|
|||
tc->get_highlights().erase({highlight_source_t::PREVIEW, "preview"});
|
||||
tc->get_highlights().erase({highlight_source_t::PREVIEW, "bodypreview"});
|
||||
|
||||
auto old_mode = std::exchange(lnav_data.ld_mode, LNM_PAGING);
|
||||
auto new_mode = LNM_PAGING;
|
||||
|
||||
switch (lnav_data.ld_mode) {
|
||||
case LNM_SEARCH_FILTERS:
|
||||
new_mode = LNM_FILTER;
|
||||
break;
|
||||
case LNM_SEARCH_FILES:
|
||||
new_mode = LNM_FILES;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto old_mode = std::exchange(lnav_data.ld_mode, new_mode);
|
||||
switch (old_mode) {
|
||||
case LNM_PAGING:
|
||||
case LNM_FILTER:
|
||||
|
@ -514,6 +529,8 @@ static void rl_callback_int(void *dummy, readline_curses *rc, bool is_alt)
|
|||
break;
|
||||
|
||||
case LNM_SEARCH:
|
||||
case LNM_SEARCH_FILTERS:
|
||||
case LNM_SEARCH_FILES:
|
||||
case LNM_CAPTURE:
|
||||
rl_search_internal(dummy, rc, old_mode, true);
|
||||
if (!rc->get_value().empty()) {
|
||||
|
|
|
@ -256,7 +256,9 @@ void layout_views()
|
|||
|
||||
bool doc_open = doc_height > 0;
|
||||
bool filters_open = (lnav_data.ld_mode == LNM_FILTER ||
|
||||
lnav_data.ld_mode == LNM_FILES) &&
|
||||
lnav_data.ld_mode == LNM_FILES ||
|
||||
lnav_data.ld_mode == LNM_SEARCH_FILTERS ||
|
||||
lnav_data.ld_mode == LNM_SEARCH_FILES) &&
|
||||
!preview_status_open &&
|
||||
!doc_open;
|
||||
int filter_height = filters_open ? 3 : 0;
|
||||
|
|
Loading…
Reference in New Issue