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.
|
||||
version = '0.12'
|
||||
# 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
|
||||
# for a list of supported languages.
|
||||
|
@ -95,7 +95,7 @@ release: osx-package musl-package release-NEWS.md
|
||||
|
||||
push:
|
||||
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:
|
||||
cd vagrant-static && vagrant destroy -f
|
||||
|
@ -45,6 +45,7 @@ enum class help_context_t {
|
||||
HC_SQL_FUNCTION,
|
||||
HC_SQL_TABLE_VALUED_FUNCTION,
|
||||
HC_PRQL_TRANSFORM,
|
||||
HC_PRQL_FUNCTION,
|
||||
};
|
||||
|
||||
enum class help_function_type_t {
|
||||
@ -97,6 +98,7 @@ struct help_text {
|
||||
std::vector<const char*> ht_opposites;
|
||||
help_function_type_t ht_function_type{help_function_type_t::HFT_REGULAR};
|
||||
std::vector<const char*> ht_prql_path;
|
||||
const char* ht_default_value{nullptr};
|
||||
void* ht_impl{nullptr};
|
||||
|
||||
help_text() = default;
|
||||
@ -159,6 +161,12 @@ struct help_text {
|
||||
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
|
||||
{
|
||||
this->ht_summary = summary;
|
||||
@ -191,6 +199,12 @@ struct help_text {
|
||||
|
||||
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
|
||||
{
|
||||
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) {
|
||||
out.append(" ");
|
||||
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));
|
||||
if (param.ht_nargs == help_nargs_t::HN_OPTIONAL) {
|
||||
}
|
||||
if (param.ht_nargs == help_nargs_t::HN_ONE_OR_MORE) {
|
||||
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("]");
|
||||
}
|
||||
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) {
|
||||
out.append("1"_variable);
|
||||
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),
|
||||
&(tws.with_indent(2 + max_param_name_width + 3)))
|
||||
.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()) {
|
||||
for (const auto& sub_param : param.ht_parameters) {
|
||||
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_TABLE_VALUED_FUNCTION:
|
||||
case help_context_t::HC_PRQL_TRANSFORM:
|
||||
case help_context_t::HC_PRQL_FUNCTION:
|
||||
readline_sqlite_highlighter(ex_line, 0);
|
||||
prompt = ";";
|
||||
break;
|
||||
@ -627,6 +686,7 @@ format_help_text_for_rst(const help_text& ht,
|
||||
prefix = "";
|
||||
break;
|
||||
case help_context_t::HC_PRQL_TRANSFORM:
|
||||
case help_context_t::HC_PRQL_FUNCTION:
|
||||
is_sql = true;
|
||||
break;
|
||||
default:
|
||||
|
@ -140,7 +140,7 @@ const char *PRQL_HELP =
|
||||
|
||||
const char *PRQL_EXAMPLE =
|
||||
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"
|
||||
;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
prev_stage_prql.insert(riter->sa_range.lr_start,
|
||||
|
@ -589,6 +589,7 @@ static readline_context::command_t sql_commands[] = {
|
||||
.with_parameter(
|
||||
help_text{"side", "Specifies which rows to include"}
|
||||
.with_enum_values({"inner", "left", "right", "full"})
|
||||
.with_default_value("inner")
|
||||
.optional())
|
||||
.with_parameter(
|
||||
{"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"},
|
||||
},
|
||||
{
|
||||
"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",
|
||||
prql_cmd_sort,
|
||||
|
@ -1045,13 +1045,136 @@ register_sqlite_funcs(sqlite3* db, sqlite_registration_func_t* reg_funcs)
|
||||
.with_tags({"json"})
|
||||
.with_example(
|
||||
{"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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -952,7 +952,8 @@ execute_example(const help_text& ht)
|
||||
case help_context_t::HC_SQL_INFIX:
|
||||
case help_context_t::HC_SQL_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;
|
||||
|
||||
ec.ec_label_source_stack.push_back(&dls);
|
||||
@ -1010,6 +1011,12 @@ execute_examples()
|
||||
for (auto help_pair : sqlite_function_help) {
|
||||
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) {
|
||||
if (cmd_pair.second->c_help.ht_context
|
||||
!= help_context_t::HC_PRQL_TRANSFORM)
|
||||
|
Loading…
Reference in New Issue
Block a user