[prql] add more online help

circleci-project-setup v0.12.1-beta1
Tim Stack 2 months ago
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));
}
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…
Cancel
Save