mirror of
https://github.com/tstack/lnav.git
synced 2024-09-11 21:07:39 +03:00
[prql] add more online help
This commit is contained in:
parent
8d70397005
commit
6d2d414e97
@ -258,7 +258,7 @@ copyright = u'2023, Tim Stack'
|
|||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.12'
|
version = '0.12'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.12.0'
|
release = '0.12.1'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -95,7 +95,7 @@ release: osx-package musl-package release-NEWS.md
|
|||||||
|
|
||||||
push:
|
push:
|
||||||
env LANG=UTF-8 package_cloud push tstack/lnav/ubuntu/lucid outbox/lnav*.deb
|
env LANG=UTF-8 package_cloud push tstack/lnav/ubuntu/lucid outbox/lnav*.deb
|
||||||
env LANG=UTF-8 package_cloud push tstack/lnav/el/5 outbox/lnav-0.12.0-1.x86_64.rpm
|
env LANG=UTF-8 package_cloud push tstack/lnav/el/5 outbox/lnav-0.12.1-1.x86_64.rpm
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
cd vagrant-static && vagrant destroy -f
|
cd vagrant-static && vagrant destroy -f
|
||||||
|
@ -45,6 +45,7 @@ enum class help_context_t {
|
|||||||
HC_SQL_FUNCTION,
|
HC_SQL_FUNCTION,
|
||||||
HC_SQL_TABLE_VALUED_FUNCTION,
|
HC_SQL_TABLE_VALUED_FUNCTION,
|
||||||
HC_PRQL_TRANSFORM,
|
HC_PRQL_TRANSFORM,
|
||||||
|
HC_PRQL_FUNCTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class help_function_type_t {
|
enum class help_function_type_t {
|
||||||
@ -97,6 +98,7 @@ struct help_text {
|
|||||||
std::vector<const char*> ht_opposites;
|
std::vector<const char*> ht_opposites;
|
||||||
help_function_type_t ht_function_type{help_function_type_t::HFT_REGULAR};
|
help_function_type_t ht_function_type{help_function_type_t::HFT_REGULAR};
|
||||||
std::vector<const char*> ht_prql_path;
|
std::vector<const char*> ht_prql_path;
|
||||||
|
const char* ht_default_value{nullptr};
|
||||||
void* ht_impl{nullptr};
|
void* ht_impl{nullptr};
|
||||||
|
|
||||||
help_text() = default;
|
help_text() = default;
|
||||||
@ -159,6 +161,12 @@ struct help_text {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
help_text& prql_function() noexcept
|
||||||
|
{
|
||||||
|
this->ht_context = help_context_t::HC_PRQL_FUNCTION;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
help_text& with_summary(const char* summary) noexcept
|
help_text& with_summary(const char* summary) noexcept
|
||||||
{
|
{
|
||||||
this->ht_summary = summary;
|
this->ht_summary = summary;
|
||||||
@ -191,6 +199,12 @@ struct help_text {
|
|||||||
|
|
||||||
help_text& with_example(const help_example& example) noexcept;
|
help_text& with_example(const help_example& example) noexcept;
|
||||||
|
|
||||||
|
help_text& with_default_value(const char* defval)
|
||||||
|
{
|
||||||
|
this->ht_default_value = defval;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
help_text& optional() noexcept
|
help_text& optional() noexcept
|
||||||
{
|
{
|
||||||
this->ht_nargs = help_nargs_t::HN_OPTIONAL;
|
this->ht_nargs = help_nargs_t::HN_OPTIONAL;
|
||||||
|
@ -357,12 +357,55 @@ format_help_text_for_term(const help_text& ht,
|
|||||||
for (const auto& param : ht.ht_parameters) {
|
for (const auto& param : ht.ht_parameters) {
|
||||||
out.append(" ");
|
out.append(" ");
|
||||||
if (param.ht_nargs == help_nargs_t::HN_OPTIONAL) {
|
if (param.ht_nargs == help_nargs_t::HN_OPTIONAL) {
|
||||||
out.append("[");
|
out.append(lnav::roles::symbol(param.ht_name));
|
||||||
|
out.append(":");
|
||||||
|
if (param.ht_default_value) {
|
||||||
|
out.append(param.ht_default_value);
|
||||||
|
} else {
|
||||||
|
out.append("null");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (param.ht_group_start) {
|
||||||
|
out.append(param.ht_group_start);
|
||||||
|
}
|
||||||
|
out.append(lnav::roles::variable(param.ht_name));
|
||||||
}
|
}
|
||||||
out.append(lnav::roles::variable(param.ht_name));
|
if (param.ht_nargs == help_nargs_t::HN_ONE_OR_MORE) {
|
||||||
if (param.ht_nargs == help_nargs_t::HN_OPTIONAL) {
|
out.append("1"_variable);
|
||||||
|
out.append(" [");
|
||||||
|
out.append("..."_variable);
|
||||||
|
out.append(" ");
|
||||||
|
out.append(lnav::roles::variable(param.ht_name));
|
||||||
|
out.append("N"_variable);
|
||||||
out.append("]");
|
out.append("]");
|
||||||
}
|
}
|
||||||
|
if (param.ht_group_end) {
|
||||||
|
out.append(param.ht_group_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.with_attr(string_attr{
|
||||||
|
line_range{(int) line_start, (int) out.get_string().length()},
|
||||||
|
VC_ROLE.value(role_t::VCR_H3),
|
||||||
|
});
|
||||||
|
if (htc != help_text_content::synopsis) {
|
||||||
|
alb.append("\n")
|
||||||
|
.append(lnav::roles::table_border(
|
||||||
|
repeat("\u2550", tws.tws_width)))
|
||||||
|
.append("\n")
|
||||||
|
.indent(body_indent)
|
||||||
|
.append(attr_line_t::from_ansi_str(ht.ht_summary),
|
||||||
|
&tws.with_indent(body_indent + 2))
|
||||||
|
.append("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case help_context_t::HC_PRQL_FUNCTION: {
|
||||||
|
auto line_start = out.al_string.length();
|
||||||
|
|
||||||
|
out.append(lnav::roles::symbol(ht.ht_name));
|
||||||
|
for (const auto& param : ht.ht_parameters) {
|
||||||
|
out.append(" ");
|
||||||
|
out.append(lnav::roles::variable(param.ht_name));
|
||||||
if (param.ht_nargs == help_nargs_t::HN_ONE_OR_MORE) {
|
if (param.ht_nargs == help_nargs_t::HN_ONE_OR_MORE) {
|
||||||
out.append("1"_variable);
|
out.append("1"_variable);
|
||||||
out.append(" [");
|
out.append(" [");
|
||||||
@ -417,6 +460,21 @@ format_help_text_for_term(const help_text& ht,
|
|||||||
.append(attr_line_t::from_ansi_str(param.ht_summary),
|
.append(attr_line_t::from_ansi_str(param.ht_summary),
|
||||||
&(tws.with_indent(2 + max_param_name_width + 3)))
|
&(tws.with_indent(2 + max_param_name_width + 3)))
|
||||||
.append("\n");
|
.append("\n");
|
||||||
|
if (!param.ht_enum_values.empty()) {
|
||||||
|
alb.indent(body_indent + max_param_name_width)
|
||||||
|
.append(" ")
|
||||||
|
.append("Values"_h5)
|
||||||
|
.append(": ");
|
||||||
|
auto initial = true;
|
||||||
|
for (const auto* ename : param.ht_enum_values) {
|
||||||
|
if (!initial) {
|
||||||
|
alb.append("|");
|
||||||
|
}
|
||||||
|
alb.append(lnav::roles::symbol(ename));
|
||||||
|
initial = false;
|
||||||
|
}
|
||||||
|
alb.append("\n");
|
||||||
|
}
|
||||||
if (!param.ht_parameters.empty()) {
|
if (!param.ht_parameters.empty()) {
|
||||||
for (const auto& sub_param : param.ht_parameters) {
|
for (const auto& sub_param : param.ht_parameters) {
|
||||||
alb.indent(body_indent + max_param_name_width + 3)
|
alb.indent(body_indent + max_param_name_width + 3)
|
||||||
@ -536,6 +594,7 @@ format_example_text_for_term(const help_text& ht,
|
|||||||
case help_context_t::HC_SQL_FUNCTION:
|
case help_context_t::HC_SQL_FUNCTION:
|
||||||
case help_context_t::HC_SQL_TABLE_VALUED_FUNCTION:
|
case help_context_t::HC_SQL_TABLE_VALUED_FUNCTION:
|
||||||
case help_context_t::HC_PRQL_TRANSFORM:
|
case help_context_t::HC_PRQL_TRANSFORM:
|
||||||
|
case help_context_t::HC_PRQL_FUNCTION:
|
||||||
readline_sqlite_highlighter(ex_line, 0);
|
readline_sqlite_highlighter(ex_line, 0);
|
||||||
prompt = ";";
|
prompt = ";";
|
||||||
break;
|
break;
|
||||||
@ -627,6 +686,7 @@ format_help_text_for_rst(const help_text& ht,
|
|||||||
prefix = "";
|
prefix = "";
|
||||||
break;
|
break;
|
||||||
case help_context_t::HC_PRQL_TRANSFORM:
|
case help_context_t::HC_PRQL_TRANSFORM:
|
||||||
|
case help_context_t::HC_PRQL_FUNCTION:
|
||||||
is_sql = true;
|
is_sql = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -140,7 +140,7 @@ const char *PRQL_HELP =
|
|||||||
|
|
||||||
const char *PRQL_EXAMPLE =
|
const char *PRQL_EXAMPLE =
|
||||||
ANSI_UNDERLINE("Examples") "\n"
|
ANSI_UNDERLINE("Examples") "\n"
|
||||||
" from %s | count_by { log_level }\n"
|
" from %s | stats.count_by { log_level }\n"
|
||||||
" from %s | filter log_line == lnav.view.top_line\n"
|
" from %s | filter log_line == lnav.view.top_line\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -577,7 +577,9 @@ rl_search_internal(readline_curses* rc, ln_mode_t mode, bool complete = false)
|
|||||||
riter != curr_stage_prql.get_attrs().rend();
|
riter != curr_stage_prql.get_attrs().rend();
|
||||||
++riter)
|
++riter)
|
||||||
{
|
{
|
||||||
if (riter->sa_type != &lnav::sql::PRQL_PIPE_ATTR) {
|
if (riter->sa_type != &lnav::sql::PRQL_STAGE_ATTR
|
||||||
|
|| riter->sa_range.lr_start == 0)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
curr_stage_prql.insert(riter->sa_range.lr_start,
|
curr_stage_prql.insert(riter->sa_range.lr_start,
|
||||||
@ -600,7 +602,9 @@ rl_search_internal(readline_curses* rc, ln_mode_t mode, bool complete = false)
|
|||||||
riter != prev_stage_prql.get_attrs().rend();
|
riter != prev_stage_prql.get_attrs().rend();
|
||||||
++riter)
|
++riter)
|
||||||
{
|
{
|
||||||
if (riter->sa_type != &lnav::sql::PRQL_PIPE_ATTR) {
|
if (riter->sa_type != &lnav::sql::PRQL_STAGE_ATTR
|
||||||
|
|| riter->sa_range.lr_start == 0)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
prev_stage_prql.insert(riter->sa_range.lr_start,
|
prev_stage_prql.insert(riter->sa_range.lr_start,
|
||||||
|
@ -589,6 +589,7 @@ static readline_context::command_t sql_commands[] = {
|
|||||||
.with_parameter(
|
.with_parameter(
|
||||||
help_text{"side", "Specifies which rows to include"}
|
help_text{"side", "Specifies which rows to include"}
|
||||||
.with_enum_values({"inner", "left", "right", "full"})
|
.with_enum_values({"inner", "left", "right", "full"})
|
||||||
|
.with_default_value("inner")
|
||||||
.optional())
|
.optional())
|
||||||
.with_parameter(
|
.with_parameter(
|
||||||
{"table", "The other table to join with the current rows"})
|
{"table", "The other table to join with the current rows"})
|
||||||
@ -622,6 +623,25 @@ static readline_context::command_t sql_commands[] = {
|
|||||||
"prql-source",
|
"prql-source",
|
||||||
{"prql-source"},
|
{"prql-source"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"stats.count_by",
|
||||||
|
prql_cmd_sort,
|
||||||
|
help_text(
|
||||||
|
"stats.count_by",
|
||||||
|
"Partition rows and count the number of rows in each partition")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{"column", "The columns to group by"}
|
||||||
|
.one_or_more()
|
||||||
|
.with_grouping("{", "}"))
|
||||||
|
.with_example({
|
||||||
|
"To count rows for a particular value of column 'a'",
|
||||||
|
"from [{a=1}, {a=1}, {a=2}] | stats.count_by a",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
nullptr,
|
||||||
|
"prql-source",
|
||||||
|
{"prql-source"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"sort",
|
"sort",
|
||||||
prql_cmd_sort,
|
prql_cmd_sort,
|
||||||
|
@ -1045,13 +1045,136 @@ register_sqlite_funcs(sqlite3* db, sqlite_registration_func_t* reg_funcs)
|
|||||||
.with_tags({"json"})
|
.with_tags({"json"})
|
||||||
.with_example(
|
.with_example(
|
||||||
{"To iterate over an array",
|
{"To iterate over an array",
|
||||||
R"(SELECT key,value,type,atom,fullkey,path FROM json_tree('[null,1,"two",{"three":4.5}]'))"})
|
R"(SELECT key,value,type,atom,fullkey,path FROM json_tree('[null,1,"two",{"three":4.5}]'))"}),
|
||||||
|
|
||||||
|
help_text("text.contains", "Returns true if col contains sub")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(
|
||||||
|
help_text{"sub", "The substring to look for in col"})
|
||||||
|
.with_parameter(help_text{"col", "The string to examine"})
|
||||||
|
.with_example({
|
||||||
|
"To check if 'Hello' contains 'lo'",
|
||||||
|
"from [{s='Hello'}] | select { s=text.contains 'lo' s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
})
|
||||||
|
.with_example({
|
||||||
|
"To check if 'Goodbye' contains 'lo'",
|
||||||
|
"from [{s='Goodbye'}] | select { s=text.contains 'lo' s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.ends_with", "Returns true if col ends with suffix")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(
|
||||||
|
help_text{"suffix", "The string to look for at the end of col"})
|
||||||
|
.with_parameter(help_text{"col", "The string to examine"})
|
||||||
|
.with_example({
|
||||||
|
"To check if 'Hello' ends with 'lo'",
|
||||||
|
"from [{s='Hello'}] | select { s=text.ends_with 'lo' s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
})
|
||||||
|
.with_example({
|
||||||
|
"To check if 'Goodbye' ends with 'lo'",
|
||||||
|
"from [{s='Goodbye'}] | select { s=text.ends_with 'lo' s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.extract", "Extract a slice of a string")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{
|
||||||
|
"idx",
|
||||||
|
"The starting index where the first character is index 1"})
|
||||||
|
.with_parameter(help_text{"len", "The length of the slice"})
|
||||||
|
.with_parameter(help_text{"str", "The string to extract from"})
|
||||||
|
.with_example({
|
||||||
|
"To extract a substring from s",
|
||||||
|
"from [{s='Hello, World!'}] | select { s=text.extract 1 5 s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.length", "Returns the number of characters in col")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{"col", "The string to examine"})
|
||||||
|
.with_example({
|
||||||
|
"To count the number of characters in s",
|
||||||
|
"from [{s='Hello, World!'}] | select { s=text.length s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.lower", "Converts col to lowercase")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{"col", "The string to convert"})
|
||||||
|
.with_example({
|
||||||
|
"To convert s to lowercase",
|
||||||
|
"from [{s='HELLO'}] | select { s=text.lower s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.ltrim", "Remove whitespace from the left side of col")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{"col", "The string to trim"})
|
||||||
|
.with_example({
|
||||||
|
"To trim the left side of s",
|
||||||
|
"from [{s=' HELLO '}] | select { s=text.ltrim s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.replace",
|
||||||
|
"Replace all occurrences of before with after in col")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{"before", "The string to find"})
|
||||||
|
.with_parameter(help_text{"after", "The replacement"})
|
||||||
|
.with_parameter(help_text{"col", "The string to trim"})
|
||||||
|
.with_example({
|
||||||
|
"To erase foo in s",
|
||||||
|
"from [{s='foobar'}] | select { s=text.replace 'foo' '' s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.rtrim", "Remove whitespace from the right side of col")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{"col", "The string to trim"})
|
||||||
|
.with_example({
|
||||||
|
"To trim the right side of s",
|
||||||
|
"from [{s=' HELLO '}] | select { s=text.rtrim s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.starts_with", "Returns true if col starts with suffix")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{
|
||||||
|
"suffix", "The string to look for at the start of col"})
|
||||||
|
.with_parameter(help_text{"col", "The string to examine"})
|
||||||
|
.with_example({
|
||||||
|
"To check if 'Hello' starts with 'lo'",
|
||||||
|
"from [{s='Hello'}] | select { s=text.starts_with 'He' s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
})
|
||||||
|
.with_example({
|
||||||
|
"To check if 'Goodbye' starts with 'lo'",
|
||||||
|
"from [{s='Goodbye'}] | select { s=text.starts_with 'He' s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.trim", "Remove whitespace from the both sides of col")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{"col", "The string to trim"})
|
||||||
|
.with_example({
|
||||||
|
"To trim s",
|
||||||
|
"from [{s=' HELLO '}] | select { s=text.trim s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
|
help_text("text.upper", "Converts col to uppercase")
|
||||||
|
.prql_function()
|
||||||
|
.with_parameter(help_text{"col", "The string to convert"})
|
||||||
|
.with_example({
|
||||||
|
"To convert s to uppercase",
|
||||||
|
"from [{s='hello'}] | select { s=text.upper s }",
|
||||||
|
help_example::language::prql,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!help_registration_done) {
|
if (!help_registration_done) {
|
||||||
for (auto& ht : builtin_funcs) {
|
for (auto& ht : builtin_funcs) {
|
||||||
sqlite_function_help.insert(std::make_pair(ht.ht_name, &ht));
|
switch (ht.ht_context) {
|
||||||
|
case help_context_t::HC_PRQL_FUNCTION:
|
||||||
|
lnav::sql::prql_functions.emplace(ht.ht_name, &ht);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sqlite_function_help.emplace(ht.ht_name, &ht);
|
||||||
|
break;
|
||||||
|
}
|
||||||
ht.index_tags();
|
ht.index_tags();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -952,7 +952,8 @@ execute_example(const help_text& ht)
|
|||||||
case help_context_t::HC_SQL_INFIX:
|
case help_context_t::HC_SQL_INFIX:
|
||||||
case help_context_t::HC_SQL_FUNCTION:
|
case help_context_t::HC_SQL_FUNCTION:
|
||||||
case help_context_t::HC_SQL_TABLE_VALUED_FUNCTION:
|
case help_context_t::HC_SQL_TABLE_VALUED_FUNCTION:
|
||||||
case help_context_t::HC_PRQL_TRANSFORM: {
|
case help_context_t::HC_PRQL_TRANSFORM:
|
||||||
|
case help_context_t::HC_PRQL_FUNCTION: {
|
||||||
exec_context ec;
|
exec_context ec;
|
||||||
|
|
||||||
ec.ec_label_source_stack.push_back(&dls);
|
ec.ec_label_source_stack.push_back(&dls);
|
||||||
@ -1010,6 +1011,12 @@ execute_examples()
|
|||||||
for (auto help_pair : sqlite_function_help) {
|
for (auto help_pair : sqlite_function_help) {
|
||||||
execute_example(*help_pair.second);
|
execute_example(*help_pair.second);
|
||||||
}
|
}
|
||||||
|
for (auto help_pair : lnav::sql::prql_functions) {
|
||||||
|
if (help_pair.second->ht_context != help_context_t::HC_PRQL_FUNCTION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
execute_example(*help_pair.second);
|
||||||
|
}
|
||||||
for (auto cmd_pair : *sql_cmd_map) {
|
for (auto cmd_pair : *sql_cmd_map) {
|
||||||
if (cmd_pair.second->c_help.ht_context
|
if (cmd_pair.second->c_help.ht_context
|
||||||
!= help_context_t::HC_PRQL_TRANSFORM)
|
!= help_context_t::HC_PRQL_TRANSFORM)
|
||||||
|
Loading…
Reference in New Issue
Block a user