Report similar names for builtins that user is searching for

This commit is contained in:
Robert Bendun 2023-03-05 01:10:43 +01:00
parent 92e5c3169c
commit 719e8d4f26
4 changed files with 88 additions and 19 deletions

View File

@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Builtin documentation for builtin functions display from repl and command line. - Builtin documentation for builtin functions display from repl and command line (`musique doc <builtin>`)
- Man documentation for commandline interface builtin (`musique man`)
- Suggestions which command line parameters user may wanted to use - Suggestions which command line parameters user may wanted to use
### Changed ### Changed

View File

@ -15,6 +15,8 @@
#include <utility> #include <utility>
#include <variant> #include <variant>
// TODO: Command line parameters full documentation in other then man pages format. Maybe HTML generation?
#ifdef _WIN32 #ifdef _WIN32
extern "C" { extern "C" {
#include <io.h> #include <io.h>
@ -53,6 +55,11 @@ static Requires_Argument show_docs = [](std::string_view builtin) {
} }
std::cerr << pretty::begin_error << "musique: error:" << pretty::end; std::cerr << pretty::begin_error << "musique: error:" << pretty::end;
std::cerr << " cannot find documentation for given builtin" << std::endl; std::cerr << " cannot find documentation for given builtin" << std::endl;
std::cerr << "Similar ones are:" << std::endl;
for (auto similar : similar_names_to_builtin(builtin)) {
std::cerr << " " << similar << '\n';
}
std::exit(1); std::exit(1);
}; };
@ -347,11 +354,12 @@ void cmd::print_close_matches(std::string_view arg)
std::cout << "\nInvoke 'musique help' to read more about available commands\n"; std::cout << "\nInvoke 'musique help' to read more about available commands\n";
} }
void cmd::usage() static inline void iterate_over_documentation(
std::ostream& out,
std::string_view Documentation_For_Handler_Entry::* handler,
std::string_view prefix,
std::ostream&(*first)(std::ostream&, std::string_view name))
{ {
std::cerr << "usage: " << pretty::begin_bold << "musique" << pretty::end << " [subcommand]...\n";
std::cerr << " where available subcommands are:\n";
decltype(std::optional(all_parameters.begin())) previous = std::nullopt; decltype(std::optional(all_parameters.begin())) previous = std::nullopt;
for (auto it = all_parameters.begin();; ++it) { for (auto it = all_parameters.begin();; ++it) {
@ -361,14 +369,12 @@ void cmd::usage()
if (it == all_parameters.end() || (previous && it->handler_ptr() != (*previous)->handler_ptr())) { if (it == all_parameters.end() || (previous && it->handler_ptr() != (*previous)->handler_ptr())) {
auto &e = **previous; auto &e = **previous;
switch (e.arguments()) { switch (e.arguments()) {
break; case 0: std::cerr << '\n'; break; case 0: out << '\n';
break; case 1: std::cerr << " ARG\n"; break; case 1: out << " ARG\n";
break; default: unreachable(); break; default: unreachable();
} }
std::cerr << " " out << prefix << find_documentation_for_handler(e.handler_ptr()).*handler << "\n\n";
<< find_documentation_for_handler(e.handler_ptr()).short_documentation
<< "\n\n";
} }
if (it == all_parameters.end()) { if (it == all_parameters.end()) {
@ -376,12 +382,24 @@ void cmd::usage()
} }
if (previous && (**previous).handler_ptr() == it->handler_ptr()) { if (previous && (**previous).handler_ptr() == it->handler_ptr()) {
std::cerr << ", " << it->name; out << ", " << it->name;
} else { } else {
std::cerr << " " << pretty::begin_bold << it->name << pretty::end; first(out, it->name);
} }
previous = it; previous = it;
} }
}
void cmd::usage()
{
std::cerr << "usage: " << pretty::begin_bold << "musique" << pretty::end << " [subcommand]...\n";
std::cerr << " where available subcommands are:\n";
iterate_over_documentation(std::cerr, &Documentation_For_Handler_Entry::short_documentation, " ",
[](std::ostream& out, std::string_view name) -> std::ostream&
{
return out << " " << pretty::begin_bold << name << pretty::end;
});
std::exit(2); std::exit(2);
} }
@ -411,11 +429,28 @@ SUBCOMMANDS
Musique is an interpreted, interactive, musical domain specific programming language Musique is an interpreted, interactive, musical domain specific programming language
that allows for algorythmic music composition, live-coding and orchestra performing. that allows for algorythmic music composition, live-coding and orchestra performing.
.SH SUBCOMMANDS .SH SUBCOMMANDS
TODO All subcommands can be expressed in three styles: -i arg -j -k
.SH ENVIROMENT .I or
TODO: NO_COLORS env --i=arg --j --k
.I or
i arg j k
)troff";
iterate_over_documentation(std::cout, &Documentation_For_Handler_Entry::long_documentation, {},
[](std::ostream& out, std::string_view name) -> std::ostream&
{
return out << ".TP\n" << name;
});
std::cout << R"troff(.SH ENVIROMENT
.TP
NO_COLOR
This enviroment variable overrides standard Musique color behaviour.
When it's defined, it disables colors and ensures they are not enabled.
.SH FILES .SH FILES
TODO: History file .TP
History file
History file for interactive mode is kept in XDG_DATA_HOME (or similar on other operating systems).
.SH EXAMPLES .SH EXAMPLES
.TP .TP
musique \-c "play (c5 + up 12)" musique \-c "play (c5 + up 12)"
@ -425,7 +460,6 @@ musique run examples/ode-to-joy.mq
Play Ode to Joy written as Musique source code in examples/ode-to-joy.mq Play Ode to Joy written as Musique source code in examples/ode-to-joy.mq
)troff"; )troff";
std::exit(0); std::exit(0);
} }

View File

@ -3,7 +3,12 @@
#include <optional> #include <optional>
#include <string_view> #include <string_view>
#include <vector>
std::optional<std::string_view> find_documentation_for_builtin(std::string_view builtin_name); std::optional<std::string_view> find_documentation_for_builtin(std::string_view builtin_name);
/// Returns top 4 similar names to required
std::vector<std::string_view> similar_names_to_builtin(std::string_view builtin_name);
#endif #endif

View File

@ -70,6 +70,28 @@ std::optional<std::string_view> find_documentation_for_builtin(std::string_view
} }
return std::nullopt; return std::nullopt;
} }
std::vector<std::string_view> similar_names_to_builtin(std::string_view builtin_name)
{
auto minimum_distance = std::numeric_limits<int>::max();
std::array<std::pair<std::string_view, std::string_view>, 4> closest;
std::partial_sort_copy(
names_to_documentation.begin(), names_to_documentation.end(),
closest.begin(), closest.end(),
[&minimum_distance, builtin_name](auto const& lhs, auto const& rhs) {
auto const lhs_score = edit_distance(builtin_name, lhs.first);
auto const rhs_score = edit_distance(builtin_name, rhs.first);
minimum_distance = std::min({ minimum_distance, lhs_score, rhs_score });
return lhs_score < rhs_score;
}
);
std::vector<std::string_view> result;
result.resize(4);
std::transform(closest.begin(), closest.end(), result.begin(), [](auto const& p) { return p.first; });
return result;
}
""" """
def warning(*args, prefix: str | None = None): def warning(*args, prefix: str | None = None):
@ -238,8 +260,15 @@ def generate_cpp_documentation(builtins: typing.Iterable[Builtin], output_path:
return f"{builtin.implementation}_doc" return f"{builtin.implementation}_doc"
with open(output_path, "w") as out: with open(output_path, "w") as out:
print("#include <array>", file=out) includes = [
print("#include <musique/interpreter/builtin_function_documentation.hh>\n", file=out) "algorithm",
"array",
"edit_distance.hh",
"musique/interpreter/builtin_function_documentation.hh",
"vector",
]
for include in includes:
print(f"#include <{include}>", file=out)
# 1. Generate strings with documentation # 1. Generate strings with documentation
for builtin in builtins: for builtin in builtins: