Skip to content

Commit

Permalink
[textinput] up arrow for history
Browse files Browse the repository at this point in the history
  • Loading branch information
tstack committed Feb 17, 2025
1 parent d00c7cd commit 908f180
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 65 deletions.
4 changes: 2 additions & 2 deletions src/base/intern_string.hh
Original file line number Diff line number Diff line change
Expand Up @@ -982,10 +982,10 @@ operator==(const string_fragment& left, const intern_string_t& right)
&& (memcmp(left.data(), right.get(), left.length()) == 0);
}

inline string_fragment
constexpr string_fragment
operator"" _frag(const char* str, std::size_t len)
{
return string_fragment::from_byte_range(str, 0, len);
return string_fragment{str, 0, (int) len};
}

namespace std {
Expand Down
51 changes: 49 additions & 2 deletions src/cmd.parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include "cmd.parser.hh"

#include "data_scanner.hh"
#include "shlex.hh"

namespace lnav::command {
Expand All @@ -42,7 +43,40 @@ parsed::arg_at(int x) const
for (const auto& arg : this->p_args) {
for (const auto& se : arg.second.a_values) {
if (se.se_origin.sf_begin <= x && x <= se.se_origin.sf_end) {
return std::make_pair(arg.second.a_help, se);
switch (arg.second.a_help->ht_format) {
case help_parameter_format_t::HPF_TEXT:
case help_parameter_format_t::HPF_REGEX: {
data_scanner ds(se.se_value);

while (true) {
auto tok_res = ds.tokenize2();

if (!tok_res) {
break;
}
auto tok = tok_res.value();

log_debug("cap b:%d x:%d e:%d",
tok.tr_capture.c_begin,
x,
tok.tr_capture.c_end);
if (tok.tr_capture.c_begin <= x
&& x <= tok.tr_capture.c_end)
{
return std::make_pair(
arg.second.a_help,
shlex::split_element_t{
tok.to_string_fragment(),
tok.to_string(),
});
}
}
return std::make_pair(arg.second.a_help,
shlex::split_element_t{});
}
default:
return std::make_pair(arg.second.a_help, se);
}
}
}
}
Expand Down Expand Up @@ -114,12 +148,25 @@ parse_for(mode_t mode,
}

do {
const auto& se = split_args[split_index];
switch (param.ht_format) {
case help_parameter_format_t::HPF_TEXT:
case help_parameter_format_t::HPF_REGEX: {
const auto& last_se = split_args.back();
auto sf = string_fragment{
se.se_origin.sf_string,
se.se_origin.sf_begin,
last_se.se_origin.sf_end,
};
arg.a_values.emplace_back(
shlex::split_element_t{sf, sf.to_string()});
split_index = split_args.size() - 1;
break;
}
case help_parameter_format_t::HPF_STRING:
case help_parameter_format_t::HPF_FILENAME:
case help_parameter_format_t::HPF_LOADED_FILE:
case help_parameter_format_t::HPF_FORMAT_FIELD: {
const auto& se = split_args[split_index];
if (!param.ht_enum_values.empty()) {
auto enum_iter = std::find(param.ht_enum_values.begin(),
param.ht_enum_values.end(),
Expand Down
8 changes: 8 additions & 0 deletions src/itertools.similar.hh
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ operator|(const T& in, const lnav::itertools::details::similar_to<F>& st)
}

std::priority_queue<score_pair, std::vector<score_pair>, score_cmp> pq;
auto exact_match = false;

for (const auto& elem : in) {
int score = 0;
Expand All @@ -117,6 +118,9 @@ operator|(const T& in, const lnav::itertools::details::similar_to<F>& st)
if (score <= 0) {
continue;
}
if (st.st_pattern == estr) {
exact_match = true;
}
pq.push(std::make_pair(score, elem));

if (pq.size() > st.st_count) {
Expand All @@ -130,6 +134,10 @@ operator|(const T& in, const lnav::itertools::details::similar_to<F>& st)
}
std::reverse(retval.begin(), retval.end());

if (retval.size() == 1 && exact_match) {
retval.pop_back();
}

return retval;
}

Expand Down
69 changes: 55 additions & 14 deletions src/lnav.prompt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "itertools.similar.hh"
#include "lnav.hh"
#include "log_format_ext.hh"
#include "readline_highlighters.hh"
#include "readline_possibilities.hh"
#include "scn/scan.h"
#include "shlex.hh"
Expand Down Expand Up @@ -165,10 +166,10 @@ prompt&
prompt::get()
{
static prompt retval = {
textinput::history::for_context(string_fragment::from_const("sql")),
textinput::history::for_context(string_fragment::from_const("cmd")),
textinput::history::for_context(string_fragment::from_const("search")),
textinput::history::for_context(string_fragment::from_const("script")),
textinput::history::for_context("sql"_frag),
textinput::history::for_context("cmd"_frag),
textinput::history::for_context("search"_frag),
textinput::history::for_context("script"_frag),
};

return retval;
Expand Down Expand Up @@ -245,14 +246,30 @@ prompt::refresh_sql_completions(textview_curses& tc)
void
prompt::rl_history(textinput_curses& tc)
{
auto& hist = this->get_history_for(tc.tc_prefix.al_string.front());
auto sigil = tc.tc_prefix.al_string.front();
auto& hist = this->get_history_for(sigil);
std::vector<attr_line_t> poss;
hist.query_entries(tc.get_content(), [&poss](const auto& e) {
poss.emplace_back(
attr_line_t()
.append(e.e_content)
.with_attr_for_all(SUBST_TEXT.value(e.e_content)));
});
auto cb = [&poss, sigil](const auto& e) {
auto al = attr_line_t()
.append(e.e_content)
.with_attr_for_all(SUBST_TEXT.value(e.e_content));
switch (sigil) {
case ':':
readline_command_highlighter(al, std::nullopt);
break;
case ';':
readline_sqlite_highlighter(al, std::nullopt);
break;
case '/':
readline_regex_highlighter(al, std::nullopt);
break;
}
poss.emplace_back(al.move());
};
hist.query_entries(tc.get_content(), cb);
if (poss.empty()) {
hist.query_entries(""_frag, cb);
}
tc.open_popup_for_history(poss);
}

Expand All @@ -278,6 +295,7 @@ sql_item_visitor::operator()(const prompt::sql_keyword_t&) const
static constexpr auto retval = prompt::sql_item_meta{
" ",
"",
" ",
role_t::VCR_KEYWORD,
};

Expand All @@ -291,6 +309,7 @@ sql_item_visitor::operator()(const prompt::sql_collation_t&) const
static constexpr auto retval = prompt::sql_item_meta{
" ",
"",
" ",
role_t::VCR_IDENTIFIER,
};

Expand All @@ -304,6 +323,7 @@ sql_item_visitor::operator()(const prompt::sql_db_t&) const
static constexpr auto retval = prompt::sql_item_meta{
"\u26c1",
"",
".",
role_t::VCR_IDENTIFIER,
};

Expand All @@ -317,6 +337,7 @@ sql_item_visitor::operator()(const prompt::sql_table_t&) const
static constexpr auto retval = prompt::sql_item_meta{
"\U0001f143",
"",
" ",
role_t::VCR_IDENTIFIER,
};

Expand All @@ -330,6 +351,7 @@ sql_item_visitor::operator()(const prompt::sql_table_valued_function_t&) const
static constexpr auto retval = prompt::sql_item_meta{
"\U0001D453",
"()",
"(",
role_t::VCR_FUNCTION,
};

Expand All @@ -343,6 +365,7 @@ sql_item_visitor::operator()(const prompt::sql_function_t&) const
static constexpr auto retval = prompt::sql_item_meta{
"\U0001D453",
"()",
"(",
role_t::VCR_FUNCTION,
};

Expand All @@ -356,6 +379,7 @@ sql_item_visitor::operator()(const prompt::sql_column_t&) const
static constexpr auto retval = prompt::sql_item_meta{
"\U0001F132",
"",
"",
role_t::VCR_IDENTIFIER,
};

Expand All @@ -369,6 +393,7 @@ sql_item_visitor::operator()(const prompt::sql_number_t&) const
static constexpr auto retval = prompt::sql_item_meta{
"\U0001F13D",
"",
" ",
role_t::VCR_NUMBER,
};

Expand All @@ -382,6 +407,7 @@ sql_item_visitor::operator()(const prompt::sql_string_t&) const
static constexpr auto retval = prompt::sql_item_meta{
"\U0001f142",
"",
" ",
role_t::VCR_STRING,
};

Expand All @@ -395,6 +421,7 @@ sql_item_visitor::operator()(const prompt::sql_var_t&) const
static constexpr auto retval = prompt::sql_item_meta{
"\U0001f145",
"",
" ",
role_t::VCR_VARIABLE,
};

Expand All @@ -416,16 +443,30 @@ prompt::get_sql_completion_text(const std::pair<std::string, sql_item_t>& p)
.append(" ")
.append(p.first, VC_ROLE.value(item_meta.sim_role))
.append(item_meta.sim_display_suffix)
.with_attr_for_all(SUBST_TEXT.value(p.first));
.with_attr_for_all(
SUBST_TEXT.value(p.first + item_meta.sim_replace_suffix));
}

std::vector<attr_line_t>
prompt::get_cmd_parameter_completion(const help_text* ht,
prompt::get_cmd_parameter_completion(textview_curses& tc,
const help_text* ht,
const std::string& str)
{
log_debug("cmd comp %s", str.c_str());
if (ht->ht_enum_values.empty()) {
switch (ht->ht_format) {
case help_parameter_format_t::HPF_REGEX: {
std::vector<attr_line_t> retval;
auto poss_str = view_text_possibilities(tc)
| lnav::itertools::similar_to(str, 10);

for (const auto& str : poss_str) {
retval.emplace_back(
attr_line_t().append(str).with_attr_for_all(
SUBST_TEXT.value(lnav::pcre2pp::quote(str))));
}
return retval;
}
case help_parameter_format_t::HPF_FILENAME: {
auto str_as_path = std::filesystem::path{str};
auto parent = str_as_path.parent_path();
Expand Down Expand Up @@ -499,7 +540,7 @@ prompt::get_cmd_parameter_completion(const help_text* ht,
return ht->ht_enum_values | lnav::itertools::similar_to(str, 10)
| lnav::itertools::map([](const auto& x) {
return attr_line_t(x).with_attr_for_all(
lnav::prompt::SUBST_TEXT.value(std::string(x) + " "));
SUBST_TEXT.value(std::string(x) + " "));
});
}

Expand Down
3 changes: 2 additions & 1 deletion src/lnav.prompt.hh
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct prompt {
struct sql_item_meta {
const char* sim_type_hint;
const char* sim_display_suffix;
const char* sim_replace_suffix;
role_t sim_role;
};

Expand Down Expand Up @@ -108,7 +109,7 @@ struct prompt {
const std::pair<std::string, sql_item_t>& p);

std::vector<attr_line_t> get_cmd_parameter_completion(
const help_text* ht, const std::string& str);
textview_curses& tc, const help_text* ht, const std::string& str);

void rl_history(textinput_curses& tc);
void rl_completion(textinput_curses& tc);
Expand Down
44 changes: 22 additions & 22 deletions src/log_vtab_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,28 +57,28 @@ thread_local _log_vtab_data log_vtab_data;

const std::unordered_set<string_fragment, frag_hasher>
log_vtab_impl::RESERVED_COLUMNS = {
string_fragment::from_const("log_line"),
string_fragment::from_const("log_time"),
string_fragment::from_const("log_level"),
string_fragment::from_const("log_part"),
string_fragment::from_const("log_actual_time"),
string_fragment::from_const("log_idle_msecs"),
string_fragment::from_const("log_mark"),
string_fragment::from_const("log_comment"),
string_fragment::from_const("log_tags"),
string_fragment::from_const("log_annotations"),
string_fragment::from_const("log_filters"),
string_fragment::from_const("log_opid"),
string_fragment::from_const("log_user_opid"),
string_fragment::from_const("log_format"),
string_fragment::from_const("log_format_regex"),
string_fragment::from_const("log_time_msecs"),
string_fragment::from_const("log_path"),
string_fragment::from_const("log_unique_path"),
string_fragment::from_const("log_text"),
string_fragment::from_const("log_body"),
string_fragment::from_const("log_raw_text"),
string_fragment::from_const("log_line_hash"),
"log_line"_frag,
"log_time"_frag,
"log_level"_frag,
"log_part"_frag,
"log_actual_time"_frag,
"log_idle_msecs"_frag,
"log_mark"_frag,
"log_comment"_frag,
"log_tags"_frag,
"log_annotations"_frag,
"log_filters"_frag,
"log_opid"_frag,
"log_user_opid"_frag,
"log_format"_frag,
"log_format_regex"_frag,
"log_time_msecs"_frag,
"log_path"_frag,
"log_unique_path"_frag,
"log_text"_frag,
"log_body"_frag,
"log_raw_text"_frag,
"log_line_hash"_frag,
};

static const char* const LOG_COLUMNS = R"( (
Expand Down
Loading

0 comments on commit 908f180

Please sign in to comment.