Support in newshell for <cmd>?*[j] and j*[j] <command>
This commit is contained in:
parent
f5664319be
commit
8cfa9e31e3
10 changed files with 437 additions and 87 deletions
|
|
@ -89,10 +89,10 @@ err:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool do_autocmplt_cmdidentifier(RzCmd *cmd, const char *name, void *user) {
|
||||
static bool do_autocmplt_cmdidentifier(RzCmd *cmd, const RzCmdDesc *desc, void *user) {
|
||||
struct autocmplt_cmdidentifier_t *u = (struct autocmplt_cmdidentifier_t *)user;
|
||||
if (!strncmp(name, u->s, u->len)) {
|
||||
rz_line_ns_completion_result_add(u->res, name);
|
||||
if (!strncmp(desc->name, u->s, u->len)) {
|
||||
rz_line_ns_completion_result_add(u->res, desc->name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -103,7 +103,7 @@ static void autocmplt_cmdidentifier(RzCore *core, RzLineNSCompletionResult *res,
|
|||
.s = s,
|
||||
.len = len,
|
||||
};
|
||||
rz_cmd_foreach_cmdname(core->rcmd, do_autocmplt_cmdidentifier, &u);
|
||||
rz_cmd_foreach_cmdname(core->rcmd, NULL, do_autocmplt_cmdidentifier, &u);
|
||||
}
|
||||
|
||||
static void autocmplt_cmd_arg_file(RzLineNSCompletionResult *res, const char *s, size_t len) {
|
||||
|
|
|
|||
154
librz/core/cmd.c
154
librz/core/cmd.c
|
|
@ -4618,7 +4618,8 @@ DEFINE_HANDLE_TS_FCN_AND_SYMBOL(arged_command) {
|
|||
if (!help_pra) {
|
||||
goto err;
|
||||
}
|
||||
char *help_msg = rz_cmd_get_help(state->core->rcmd, help_pra, true);
|
||||
bool use_color = state->core->print->flags & RZ_PRINT_FLAGS_COLOR;
|
||||
char *help_msg = rz_cmd_get_help(state->core->rcmd, help_pra, use_color);
|
||||
if (!help_msg) {
|
||||
goto help_pra_err;
|
||||
}
|
||||
|
|
@ -4760,55 +4761,116 @@ DEFINE_HANDLE_TS_FCN_AND_SYMBOL(redirect_command) {
|
|||
return res;
|
||||
}
|
||||
|
||||
typedef struct _search_help {
|
||||
bool color;
|
||||
RzStrBuf *sb;
|
||||
PJ *pj;
|
||||
} RzHelpSearch;
|
||||
|
||||
static bool help_search_cmd_desc_entry(RzCmd *cmd, const RzCmdDesc *cd, void *user) {
|
||||
rz_return_val_if_fail(cd, false);
|
||||
RzHelpSearch *hs = (RzHelpSearch *)user;
|
||||
if (hs->pj) {
|
||||
rz_cmd_get_help_json(cmd, cd, hs->pj);
|
||||
} else {
|
||||
rz_cmd_get_help_strbuf(cmd, cd, hs->color, hs->sb);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_cmd_help_search_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
||||
RzCmdStatus status = RZ_CMD_STATUS_OK;
|
||||
RzCmdDesc *begin = NULL;
|
||||
|
||||
if (argc == 2) {
|
||||
begin = rz_cmd_get_desc(core->rcmd, argv[1]);
|
||||
if (!begin) {
|
||||
status = RZ_CMD_STATUS_NONEXISTINGCMD;
|
||||
goto exit_status;
|
||||
}
|
||||
}
|
||||
|
||||
RzHelpSearch hs = {
|
||||
.color = core->print->flags & RZ_PRINT_FLAGS_COLOR,
|
||||
.pj = NULL,
|
||||
.sb = NULL,
|
||||
};
|
||||
|
||||
if (mode & RZ_OUTPUT_MODE_JSON) {
|
||||
hs.pj = pj_new();
|
||||
if (!hs.pj) {
|
||||
status = RZ_CMD_STATUS_ERROR;
|
||||
goto exit_status;
|
||||
}
|
||||
pj_o(hs.pj);
|
||||
} else {
|
||||
hs.sb = rz_strbuf_new(NULL);
|
||||
if (!hs.sb) {
|
||||
status = RZ_CMD_STATUS_ERROR;
|
||||
goto exit_status;
|
||||
}
|
||||
}
|
||||
|
||||
rz_cmd_foreach_cmdname(core->rcmd, begin, help_search_cmd_desc_entry, &hs);
|
||||
|
||||
if (mode & RZ_OUTPUT_MODE_JSON) {
|
||||
pj_end(hs.pj);
|
||||
rz_cons_printf("%s\n", pj_string(hs.pj));
|
||||
pj_free(hs.pj);
|
||||
} else {
|
||||
char *help = rz_strbuf_drain(hs.sb);
|
||||
rz_cons_printf("%s", help);
|
||||
free(help);
|
||||
}
|
||||
exit_status:
|
||||
return status;
|
||||
}
|
||||
|
||||
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(help_command) {
|
||||
size_t node_str_len = strlen(node_string);
|
||||
if (node_str_len >= 2 && !strcmp(node_string + node_str_len - 2, "?*")) {
|
||||
// TODO: get recursive help from RzCmdDesc
|
||||
int detail = 0;
|
||||
if (node_str_len > 3 && node_string[node_str_len - 3] == '?') {
|
||||
detail++;
|
||||
if (node_str_len > 4 && node_string[node_str_len - 4] == '?') {
|
||||
detail++;
|
||||
}
|
||||
}
|
||||
node_string[node_str_len - 2 - detail] = '\0';
|
||||
recursive_help(state->core, detail, node_string);
|
||||
return RZ_CMD_STATUS_OK;
|
||||
} else {
|
||||
TSNode command = ts_node_child_by_field_name(node, "command", strlen("command"));
|
||||
char *command_str = ts_node_sub_string(command, state->input);
|
||||
TSNode args = ts_node_child_by_field_name(node, "args", strlen("args"));
|
||||
RzCmdParsedArgs *pr_args = NULL;
|
||||
RzCmdStatus res = RZ_CMD_STATUS_INVALID;
|
||||
if (!ts_node_is_null(args)) {
|
||||
RzCmdDesc *cd = rz_cmd_get_desc(state->core->rcmd, command_str);
|
||||
bool do_unwrap = cd && cd->type != RZ_CMD_DESC_TYPE_OLDINPUT;
|
||||
pr_args = ts_node_handle_arg_prargs(state, node, args, 1, do_unwrap);
|
||||
if (!pr_args) {
|
||||
goto err_else;
|
||||
}
|
||||
rz_cmd_parsed_args_setcmd(pr_args, command_str);
|
||||
} else {
|
||||
pr_args = rz_cmd_parsed_args_newcmd(command_str);
|
||||
if (!pr_args) {
|
||||
goto err_else;
|
||||
}
|
||||
}
|
||||
|
||||
// let's try first with the new auto-generated help, if
|
||||
// something fails fallback to old behaviour
|
||||
char *help_msg = rz_cmd_get_help(state->core->rcmd, pr_args, state->core->print->flags & RZ_PRINT_FLAGS_COLOR);
|
||||
if (help_msg) {
|
||||
rz_cons_printf("%s", help_msg);
|
||||
free(help_msg);
|
||||
res = RZ_CMD_STATUS_OK;
|
||||
}
|
||||
err_else:
|
||||
rz_cmd_parsed_args_free(pr_args);
|
||||
free(command_str);
|
||||
return res;
|
||||
node_string[node_str_len - 2] = 0;
|
||||
const char *argv[2] = { NULL, node_string };
|
||||
return rz_cmd_help_search_handler(state->core, 2, argv, RZ_OUTPUT_MODE_STANDARD);
|
||||
} else if (node_str_len >= 3 && !strcmp(node_string + node_str_len - 3, "?*j")) {
|
||||
node_string[node_str_len - 3] = 0;
|
||||
const char *argv[2] = { NULL, node_string };
|
||||
return rz_cmd_help_search_handler(state->core, 2, argv, RZ_OUTPUT_MODE_JSON);
|
||||
}
|
||||
return RZ_CMD_STATUS_OK;
|
||||
|
||||
TSNode command = ts_node_child_by_field_name(node, "command", strlen("command"));
|
||||
char *command_str = ts_node_sub_string(command, state->input);
|
||||
TSNode args = ts_node_child_by_field_name(node, "args", strlen("args"));
|
||||
RzCmdParsedArgs *pr_args = NULL;
|
||||
RzCmdStatus res = RZ_CMD_STATUS_INVALID;
|
||||
if (!ts_node_is_null(args)) {
|
||||
RzCmdDesc *cd = rz_cmd_get_desc(state->core->rcmd, command_str);
|
||||
bool do_unwrap = cd && cd->type != RZ_CMD_DESC_TYPE_OLDINPUT;
|
||||
pr_args = ts_node_handle_arg_prargs(state, node, args, 1, do_unwrap);
|
||||
if (!pr_args) {
|
||||
goto err_else;
|
||||
}
|
||||
rz_cmd_parsed_args_setcmd(pr_args, command_str);
|
||||
} else {
|
||||
pr_args = rz_cmd_parsed_args_newcmd(command_str);
|
||||
if (!pr_args) {
|
||||
goto err_else;
|
||||
}
|
||||
}
|
||||
|
||||
// let's try first with the new auto-generated help, if
|
||||
// something fails fallback to old behaviour
|
||||
bool use_color = state->core->print->flags & RZ_PRINT_FLAGS_COLOR;
|
||||
char *help_msg = rz_cmd_get_help(state->core->rcmd, pr_args, use_color);
|
||||
if (help_msg) {
|
||||
rz_cons_printf("%s", help_msg);
|
||||
free(help_msg);
|
||||
res = RZ_CMD_STATUS_OK;
|
||||
}
|
||||
err_else:
|
||||
rz_cmd_parsed_args_free(pr_args);
|
||||
free(command_str);
|
||||
return res;
|
||||
}
|
||||
|
||||
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_seek_command) {
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ static size_t strbuf_append_calc(RzStrBuf *sb, const char *s) {
|
|||
return strlen(s);
|
||||
}
|
||||
|
||||
static void fill_modes_children_chars(RzStrBuf *sb, RzCmdDesc *cd) {
|
||||
static void fill_modes_children_chars(RzStrBuf *sb, const RzCmdDesc *cd) {
|
||||
// RZ_CMD_DESC_TYPE_ARGV_MODES does not have actual children for
|
||||
// the output modes, so we consider it separately
|
||||
size_t i;
|
||||
|
|
@ -653,7 +653,7 @@ static void fill_modes_children_chars(RzStrBuf *sb, RzCmdDesc *cd) {
|
|||
}
|
||||
}
|
||||
|
||||
static size_t fill_children_chars(RzStrBuf *sb, RzCmdDesc *cd) {
|
||||
static size_t fill_children_chars(RzStrBuf *sb, const RzCmdDesc *cd) {
|
||||
if (cd->help->options) {
|
||||
return strbuf_append_calc(sb, cd->help->options);
|
||||
}
|
||||
|
|
@ -663,7 +663,7 @@ static size_t fill_children_chars(RzStrBuf *sb, RzCmdDesc *cd) {
|
|||
|
||||
void **it;
|
||||
bool has_other_commands = false;
|
||||
RzCmdDesc *exec_cd = rz_cmd_desc_get_exec(cd);
|
||||
const RzCmdDesc *exec_cd = rz_cmd_desc_get_exec((RzCmdDesc *)cd);
|
||||
if (exec_cd) {
|
||||
switch (exec_cd->type) {
|
||||
case RZ_CMD_DESC_TYPE_ARGV_MODES:
|
||||
|
|
@ -706,7 +706,7 @@ static size_t fill_children_chars(RzStrBuf *sb, RzCmdDesc *cd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
static bool show_children_shortcut(RzCmdDesc *cd) {
|
||||
static bool show_children_shortcut(const RzCmdDesc *cd) {
|
||||
return cd->n_children || cd->help->options || cd->type == RZ_CMD_DESC_TYPE_OLDINPUT || cd->type == RZ_CMD_DESC_TYPE_ARGV_MODES;
|
||||
}
|
||||
|
||||
|
|
@ -739,7 +739,7 @@ static void fill_wrapped_comment(RzCmd *cmd, RzStrBuf *sb, const char *comment,
|
|||
}
|
||||
}
|
||||
|
||||
static size_t fill_args(RzStrBuf *sb, RzCmdDesc *cd) {
|
||||
static size_t fill_args(RzStrBuf *sb, const RzCmdDesc *cd) {
|
||||
const RzCmdDescArg *arg;
|
||||
size_t n_optionals = 0;
|
||||
size_t len = 0;
|
||||
|
|
@ -836,11 +836,11 @@ static void fill_usage_strbuf(RzCmd *cmd, RzStrBuf *sb, RzCmdDesc *cd, bool use_
|
|||
rz_strbuf_append(sb, "\n");
|
||||
}
|
||||
|
||||
static size_t calc_padding_len(RzCmdDesc *cd, const char *name) {
|
||||
static size_t calc_padding_len(const RzCmdDesc *cd, const char *name, bool show_children) {
|
||||
size_t name_len = strlen(name);
|
||||
size_t args_len = 0;
|
||||
size_t children_length = 0;
|
||||
if (show_children_shortcut(cd)) {
|
||||
if (show_children && show_children_shortcut(cd)) {
|
||||
RzStrBuf sb;
|
||||
rz_strbuf_init(&sb);
|
||||
fill_children_chars(&sb, cd);
|
||||
|
|
@ -859,14 +859,14 @@ static size_t calc_padding_len(RzCmdDesc *cd, const char *name) {
|
|||
return name_len + args_len + children_length;
|
||||
}
|
||||
|
||||
static void update_minmax_len(RzCmdDesc *cd, size_t *max_len, size_t *min_len) {
|
||||
size_t val = calc_padding_len(cd, cd->name);
|
||||
static void update_minmax_len(RzCmdDesc *cd, size_t *max_len, size_t *min_len, bool show_children) {
|
||||
size_t val = calc_padding_len(cd, cd->name, show_children);
|
||||
*max_len = val > *max_len ? val : *max_len;
|
||||
*min_len = val < *min_len ? val : *min_len;
|
||||
}
|
||||
|
||||
static void do_print_child_help(RzCmd *cmd, RzStrBuf *sb, RzCmdDesc *cd, const char *name, const char *summary, bool show_children, size_t max_len, bool use_color) {
|
||||
size_t str_len = calc_padding_len(cd, name);
|
||||
static void do_print_child_help(RzCmd *cmd, RzStrBuf *sb, const RzCmdDesc *cd, const char *name, const char *summary, bool show_children, size_t max_len, bool use_color) {
|
||||
size_t str_len = calc_padding_len(cd, name, show_children);
|
||||
int padding = str_len < max_len ? max_len - str_len : 0;
|
||||
const char *pal_args_color = "",
|
||||
*pal_opt_color = "",
|
||||
|
|
@ -918,7 +918,7 @@ static char *group_get_help(RzCmd *cmd, RzCmdDesc *cd, bool use_color) {
|
|||
|
||||
rz_cmd_desc_children_foreach(cd, it_cd) {
|
||||
RzCmdDesc *child = *(RzCmdDesc **)it_cd;
|
||||
update_minmax_len(child, &max_len, &min_len);
|
||||
update_minmax_len(child, &max_len, &min_len, true);
|
||||
}
|
||||
if (max_len - min_len > MAX_RIGHT_ALIGHNMENT) {
|
||||
max_len = min_len + MAX_RIGHT_ALIGHNMENT;
|
||||
|
|
@ -936,7 +936,7 @@ static char *argv_modes_get_help(RzCmd *cmd, RzCmdDesc *cd, bool use_color) {
|
|||
fill_usage_strbuf(cmd, sb, cd, use_color);
|
||||
|
||||
size_t max_len = 0, min_len = SIZE_MAX;
|
||||
update_minmax_len(cd, &max_len, &min_len);
|
||||
update_minmax_len(cd, &max_len, &min_len, true);
|
||||
max_len++; // consider the suffix letter
|
||||
if (max_len - min_len > MAX_RIGHT_ALIGHNMENT) {
|
||||
max_len = min_len + MAX_RIGHT_ALIGHNMENT;
|
||||
|
|
@ -1022,17 +1022,18 @@ static char *argv_get_help(RzCmd *cmd, RzCmdDesc *cd, size_t detail, bool use_co
|
|||
|
||||
switch (detail) {
|
||||
case 1:
|
||||
return rz_strbuf_drain(sb);
|
||||
break;
|
||||
case 2:
|
||||
if (cd->help->description) {
|
||||
rz_strbuf_appendf(sb, "\n%s\n", cd->help->description);
|
||||
}
|
||||
fill_details(cmd, cd, sb, use_color);
|
||||
return rz_strbuf_drain(sb);
|
||||
break;
|
||||
default:
|
||||
rz_strbuf_free(sb);
|
||||
return NULL;
|
||||
}
|
||||
return rz_strbuf_drain(sb);
|
||||
}
|
||||
|
||||
static char *fake_get_help(RzCmd *cmd, RzCmdDesc *cd, bool use_color) {
|
||||
|
|
@ -1089,6 +1090,142 @@ static char *get_help(RzCmd *cmd, RzCmdDesc *cd, RzCmdParsedArgs *args, bool use
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void fill_args_json(const RzCmdDesc *cd, PJ *j) {
|
||||
const RzCmdDescArg *arg;
|
||||
bool has_array = false;
|
||||
pj_ka(j, "args");
|
||||
const char *argtype = NULL;
|
||||
for (arg = cd->help->args; arg && arg->name; arg++) {
|
||||
if (has_array) {
|
||||
rz_warn_if_reached();
|
||||
break;
|
||||
}
|
||||
pj_o(j);
|
||||
#define CASE_TYPE(x, y) \
|
||||
case (x): \
|
||||
argtype = (y); \
|
||||
break
|
||||
switch (arg->type) {
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_FAKE, "fake");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_NUM, "number");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_RZNUM, "expression");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_STRING, "string");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_ENV, "environment_variable");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_ZIGN, "zignature");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_ZIGN_SPACE, "zignature_space");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_CHOICES, "choice");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_FCN, "function");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_FILE, "filename");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_OPTION, "option");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_CMD, "command");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_MACRO, "macro");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_EVAL_KEY, "evaluable");
|
||||
CASE_TYPE(RZ_CMD_ARG_TYPE_EVAL_FULL, "evaluable_full");
|
||||
#undef CASE_TYPE
|
||||
default:
|
||||
argtype = "unknown";
|
||||
break;
|
||||
}
|
||||
pj_ks(j, "type", argtype);
|
||||
pj_ks(j, "name", arg->name);
|
||||
if (arg->type == RZ_CMD_ARG_TYPE_FAKE) {
|
||||
pj_end(j);
|
||||
continue;
|
||||
}
|
||||
if (arg->no_space) {
|
||||
pj_kb(j, "nospace", true);
|
||||
}
|
||||
if (!arg->optional) {
|
||||
pj_kb(j, "required", true);
|
||||
}
|
||||
if (arg->flags & RZ_CMD_ARG_FLAG_LAST) {
|
||||
pj_kb(j, "is_last", true);
|
||||
}
|
||||
if (arg->flags & RZ_CMD_ARG_FLAG_ARRAY) {
|
||||
pj_kb(j, "is_array", true);
|
||||
}
|
||||
if (arg->flags & RZ_CMD_ARG_FLAG_OPTION) {
|
||||
pj_kb(j, "is_option", true);
|
||||
}
|
||||
if (arg->default_value) {
|
||||
pj_ks(j, "default", arg->default_value);
|
||||
}
|
||||
if (arg->type == RZ_CMD_ARG_TYPE_CHOICES) {
|
||||
pj_ka(j, "choices");
|
||||
const char **choice = arg->choices;
|
||||
for (; *choice; choice++) {
|
||||
pj_s(j, *choice);
|
||||
}
|
||||
pj_end(j);
|
||||
}
|
||||
pj_end(j);
|
||||
}
|
||||
pj_end(j);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Generates a JSON output of the given help message description
|
||||
*
|
||||
* \param cmd reference to RzCmd
|
||||
* \param cd reference to RzCmdDesc
|
||||
* \param j reference to PJ
|
||||
*
|
||||
* \return returns false if an invalid argument was given, otherwise true.
|
||||
*/
|
||||
RZ_API bool rz_cmd_get_help_json(RzCmd *cmd, const RzCmdDesc *cd, PJ *j) {
|
||||
rz_return_val_if_fail(cmd && cd && j, false);
|
||||
pj_ko(j, cd->name);
|
||||
pj_ks(j, "cmd", cd->name);
|
||||
const char *type;
|
||||
switch (cd->type) {
|
||||
#define CASE_CDTYPE(x, y) \
|
||||
case (x): \
|
||||
type = (y); \
|
||||
break
|
||||
CASE_CDTYPE(RZ_CMD_DESC_TYPE_OLDINPUT, "oldinput");
|
||||
CASE_CDTYPE(RZ_CMD_DESC_TYPE_ARGV, "argv");
|
||||
CASE_CDTYPE(RZ_CMD_DESC_TYPE_GROUP, "group");
|
||||
CASE_CDTYPE(RZ_CMD_DESC_TYPE_INNER, "inner");
|
||||
CASE_CDTYPE(RZ_CMD_DESC_TYPE_FAKE, "fake");
|
||||
CASE_CDTYPE(RZ_CMD_DESC_TYPE_ARGV_MODES, "argv_modes");
|
||||
#undef CASE_CDTYPE
|
||||
default:
|
||||
type = "unknown";
|
||||
break;
|
||||
}
|
||||
pj_ks(j, "type", type);
|
||||
if (cd->help->args_str) {
|
||||
pj_ks(j, "args_str", cd->help->args_str);
|
||||
} else {
|
||||
RzStrBuf *sb = rz_strbuf_new(NULL);
|
||||
fill_args(sb, cd);
|
||||
char *args = rz_strbuf_drain(sb);
|
||||
pj_ks(j, "args_str", args);
|
||||
free(args);
|
||||
}
|
||||
fill_args_json(cd, j);
|
||||
pj_ks(j, "description", cd->help->description ? cd->help->description : "");
|
||||
pj_ks(j, "summary", cd->help->summary ? cd->help->summary : "");
|
||||
pj_end(j);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Generates a text output of the given help message description (summary format)
|
||||
*
|
||||
* \param cmd reference to RzCmd
|
||||
* \param cd reference to RzCmdDesc
|
||||
* \param use_color output strings with color codes.
|
||||
* \param sb reference to RzStrBuf
|
||||
*
|
||||
* \return returns false if an invalid argument was given, otherwise true.
|
||||
*/
|
||||
RZ_API bool rz_cmd_get_help_strbuf(RzCmd *cmd, const RzCmdDesc *cd, bool use_color, RzStrBuf *sb) {
|
||||
rz_return_val_if_fail(cmd && cd && sb, false);
|
||||
do_print_child_help(cmd, sb, cd, cd->name, cd->help->summary, false, MAX_RIGHT_ALIGHNMENT, use_color);
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_API char *rz_cmd_get_help(RzCmd *cmd, RzCmdParsedArgs *args, bool use_color) {
|
||||
char *cmdid = strdup(rz_cmd_parsed_args_cmd(args));
|
||||
char *cmdid_p = cmdid + strlen(cmdid) - 1;
|
||||
|
|
@ -1822,7 +1959,7 @@ RZ_API RzCmdDesc *rz_cmd_desc_parent(RzCmdDesc *cd) {
|
|||
return cd->parent;
|
||||
}
|
||||
|
||||
RZ_API bool rz_cmd_desc_has_handler(RzCmdDesc *cd) {
|
||||
RZ_API bool rz_cmd_desc_has_handler(const RzCmdDesc *cd) {
|
||||
rz_return_val_if_fail(cd, false);
|
||||
switch (cd->type) {
|
||||
case RZ_CMD_DESC_TYPE_ARGV:
|
||||
|
|
@ -1879,6 +2016,17 @@ RZ_API const RzCmdDescArg *rz_cmd_desc_get_arg(RzCmd *cmd, const RzCmdDesc *cd,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static RzCmdDescHelp *mode_cmd_desc_help(RzCmdDescHelp *dst, const RzCmdDescHelp *src, const char *suffix) {
|
||||
dst->summary = rz_str_newf("%s%s", src->summary, suffix);
|
||||
dst->description = src->description;
|
||||
dst->args_str = src->args_str;
|
||||
dst->usage = src->usage;
|
||||
dst->options = src->options;
|
||||
dst->details = src->details;
|
||||
dst->args = src->args;
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void cmd_foreach_cmdname(RzCmd *cmd, RzCmdDesc *cd, RzCmdForeachNameCb cb, void *user) {
|
||||
if (!cd) {
|
||||
return;
|
||||
|
|
@ -1890,15 +2038,25 @@ static void cmd_foreach_cmdname(RzCmd *cmd, RzCmdDesc *cd, RzCmdForeachNameCb cb
|
|||
switch (cd->type) {
|
||||
case RZ_CMD_DESC_TYPE_ARGV:
|
||||
if (rz_cmd_desc_has_handler(cd)) {
|
||||
cb(cmd, cd->name, user);
|
||||
cb(cmd, cd, user);
|
||||
}
|
||||
break;
|
||||
case RZ_CMD_DESC_TYPE_ARGV_MODES:
|
||||
for (i = 0; i < RZ_ARRAY_SIZE(argv_modes); i++) {
|
||||
if (cd->d.argv_modes_data.modes & argv_modes[i].mode) {
|
||||
char *name = rz_str_newf("%s%s", cd->name, argv_modes[i].suffix);
|
||||
cb(cmd, name, user);
|
||||
free(name);
|
||||
RzCmdDescHelp mode_help;
|
||||
const RzCmdDescHelp *copy = cd->help;
|
||||
cd->help = mode_cmd_desc_help(&mode_help, copy, argv_modes[i].summary_suffix);
|
||||
|
||||
char *name = cd->name;
|
||||
cd->name = rz_str_newf("%s%s", name, argv_modes[i].suffix);
|
||||
|
||||
cb(cmd, cd, user);
|
||||
|
||||
free(cd->name);
|
||||
free((char *)mode_help.summary);
|
||||
cd->name = name;
|
||||
cd->help = copy;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -1906,7 +2064,7 @@ static void cmd_foreach_cmdname(RzCmd *cmd, RzCmdDesc *cd, RzCmdForeachNameCb cb
|
|||
break;
|
||||
case RZ_CMD_DESC_TYPE_OLDINPUT:
|
||||
if (rz_cmd_desc_has_handler(cd)) {
|
||||
cb(cmd, cd->name, user);
|
||||
cb(cmd, cd, user);
|
||||
}
|
||||
// fallthrough
|
||||
case RZ_CMD_DESC_TYPE_INNER:
|
||||
|
|
@ -1926,11 +2084,12 @@ static void cmd_foreach_cmdname(RzCmd *cmd, RzCmdDesc *cd, RzCmdForeachNameCb cb
|
|||
* commands (e.g. ?, h?, etc.) are ignored.
|
||||
*
|
||||
* \param cmd Reference to RzCmd
|
||||
* \param begin Reference to RzCmdDesc from where to begin the for loop; if NULL the root will be used.
|
||||
* \param cb Callback function that is called for each command name.
|
||||
* \param user Additional user data that is passed to the callback \p cb.
|
||||
*/
|
||||
RZ_API void rz_cmd_foreach_cmdname(RzCmd *cmd, RzCmdForeachNameCb cb, void *user) {
|
||||
RzCmdDesc *cd = rz_cmd_get_root(cmd);
|
||||
RZ_API void rz_cmd_foreach_cmdname(RzCmd *cmd, RzCmdDesc *begin, RzCmdForeachNameCb cb, void *user) {
|
||||
RzCmdDesc *cd = begin ? begin : rz_cmd_get_root(cmd);
|
||||
cmd_foreach_cmdname(cmd, cd, cb, user);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ static const RzCmdDescArg remote_open_args[2];
|
|||
static const RzCmdDescArg remote_rap_args[3];
|
||||
static const RzCmdDescArg remote_tcp_args[3];
|
||||
static const RzCmdDescArg remote_rap_bg_args[2];
|
||||
static const RzCmdDescArg cmd_help_search_args[2];
|
||||
static const RzCmdDescArg push_escaped_args[2];
|
||||
static const RzCmdDescArg eval_getset_args[2];
|
||||
static const RzCmdDescArg eval_list_args[2];
|
||||
|
|
@ -598,6 +599,20 @@ static const RzCmdDescHelp remote_rap_bg_help = {
|
|||
.args = remote_rap_bg_args,
|
||||
};
|
||||
|
||||
static const RzCmdDescArg cmd_help_search_args[] = {
|
||||
{
|
||||
.name = "search_cmd",
|
||||
.type = RZ_CMD_ARG_TYPE_STRING,
|
||||
.optional = true,
|
||||
|
||||
},
|
||||
{ 0 },
|
||||
};
|
||||
static const RzCmdDescHelp cmd_help_search_help = {
|
||||
.summary = "Search help",
|
||||
.args = cmd_help_search_args,
|
||||
};
|
||||
|
||||
static const RzCmdDescHelp cmd_help_help = {
|
||||
.summary = "Help or evaluate math expression",
|
||||
.options = "[??]",
|
||||
|
|
@ -2362,6 +2377,9 @@ RZ_IPI void newshell_cmddescs_init(RzCore *core) {
|
|||
RzCmdDesc *remote_rap_bg_cd = rz_cmd_desc_argv_new(core->rcmd, equal__cd, "=&:", rz_remote_rap_bg_handler, &remote_rap_bg_help);
|
||||
rz_warn_if_fail(remote_rap_bg_cd);
|
||||
|
||||
RzCmdDesc *cmd_help_search_cd = rz_cmd_desc_argv_modes_new(core->rcmd, root_cd, "?*", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_help_search_handler, &cmd_help_search_help);
|
||||
rz_warn_if_fail(cmd_help_search_cd);
|
||||
|
||||
RzCmdDesc *cmd_help_cd = rz_cmd_desc_oldinput_new(core->rcmd, root_cd, "?", rz_cmd_help, &cmd_help_help);
|
||||
rz_warn_if_fail(cmd_help_cd);
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ RZ_IPI int rz_equal_h_handler_old(void *data, const char *input);
|
|||
RZ_IPI int rz_equal_H_handler_old(void *data, const char *input);
|
||||
RZ_IPI RzCmdStatus rz_remote_tcp_handler(RzCore *core, int argc, const char **argv);
|
||||
RZ_IPI RzCmdStatus rz_remote_rap_bg_handler(RzCore *core, int argc, const char **argv);
|
||||
RZ_IPI RzCmdStatus rz_cmd_help_search_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);
|
||||
RZ_IPI int rz_cmd_help(void *data, const char *input);
|
||||
RZ_IPI RzCmdStatus rz_push_escaped_handler(RzCore *core, int argc, const char **argv);
|
||||
RZ_IPI int rz_cmd_ox(void *data, const char *input);
|
||||
|
|
|
|||
|
|
@ -347,6 +347,16 @@
|
|||
args:
|
||||
- name: port
|
||||
type: RZ_CMD_ARG_TYPE_NUM
|
||||
- name: "?*"
|
||||
cname: cmd_help_search
|
||||
summary: Search help
|
||||
args:
|
||||
- name: search_cmd
|
||||
type: RZ_CMD_ARG_TYPE_STRING
|
||||
optional: true
|
||||
modes:
|
||||
- RZ_OUTPUT_MODE_STANDARD
|
||||
- RZ_OUTPUT_MODE_JSON
|
||||
- name: "?"
|
||||
cname: cmd_help
|
||||
options: "[??]"
|
||||
|
|
|
|||
|
|
@ -431,7 +431,7 @@ typedef struct rz_core_plugin_t {
|
|||
RzCmdCb fini;
|
||||
} RzCorePlugin;
|
||||
|
||||
typedef bool (*RzCmdForeachNameCb)(RzCmd *cmd, const char *name, void *user);
|
||||
typedef bool (*RzCmdForeachNameCb)(RzCmd *cmd, const RzCmdDesc *desc, void *user);
|
||||
|
||||
#ifdef RZ_API
|
||||
RZ_API int rz_core_plugin_init(RzCmd *cmd);
|
||||
|
|
@ -449,6 +449,8 @@ RZ_API RzCmdStatus rz_cmd_call_parsed_args(RzCmd *cmd, RzCmdParsedArgs *args);
|
|||
RZ_API RzCmdDesc *rz_cmd_get_root(RzCmd *cmd);
|
||||
RZ_API RzCmdDesc *rz_cmd_get_desc(RzCmd *cmd, const char *cmd_identifier);
|
||||
RZ_API char *rz_cmd_get_help(RzCmd *cmd, RzCmdParsedArgs *args, bool use_color);
|
||||
RZ_API bool rz_cmd_get_help_json(RzCmd *cmd, const RzCmdDesc *cd, PJ *j);
|
||||
RZ_API bool rz_cmd_get_help_strbuf(RzCmd *cmd, const RzCmdDesc *cd, bool use_color, RzStrBuf *sb);
|
||||
|
||||
static inline RzCmdStatus rz_cmd_int2status(int v) {
|
||||
if (v == -2) {
|
||||
|
|
@ -485,9 +487,9 @@ RZ_API RzCmdDesc *rz_cmd_desc_oldinput_new(RzCmd *cmd, RzCmdDesc *parent, const
|
|||
RZ_API RzCmdDesc *rz_cmd_desc_fake_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, const RzCmdDescHelp *help);
|
||||
RZ_API RzCmdDesc *rz_cmd_desc_parent(RzCmdDesc *cd);
|
||||
RZ_API RzCmdDesc *rz_cmd_desc_get_exec(RzCmdDesc *cd);
|
||||
RZ_API bool rz_cmd_desc_has_handler(RzCmdDesc *cd);
|
||||
RZ_API bool rz_cmd_desc_has_handler(const RzCmdDesc *cd);
|
||||
RZ_API bool rz_cmd_desc_remove(RzCmd *cmd, RzCmdDesc *cd);
|
||||
RZ_API void rz_cmd_foreach_cmdname(RzCmd *cmd, RzCmdForeachNameCb cb, void *user);
|
||||
RZ_API void rz_cmd_foreach_cmdname(RzCmd *cmd, RzCmdDesc *begin, RzCmdForeachNameCb cb, void *user);
|
||||
RZ_API const RzCmdDescArg *rz_cmd_desc_get_arg(RzCmd *cmd, const RzCmdDesc *cd, size_t i);
|
||||
|
||||
#define rz_cmd_desc_children_foreach(root, it_cd) rz_pvector_foreach (&root->children, it_cd)
|
||||
|
|
|
|||
|
|
@ -104,8 +104,12 @@ static bool is_concat_eq_sep(const int32_t ch) {
|
|||
return is_concat(ch) && ch != '=';
|
||||
}
|
||||
|
||||
static bool is_recursive_help(int id_len, const int32_t before_last_ch, const int32_t last_ch) {
|
||||
return id_len >= 2 && before_last_ch == '?' && last_ch == '*';
|
||||
static bool is_recursive_help(const int32_t before_last_ch, const int32_t last_ch) {
|
||||
return before_last_ch == '?' && last_ch == '*';
|
||||
}
|
||||
|
||||
static bool is_recursive_help_json(const int32_t trd_last_ch, const int32_t snd_last_ch, const int32_t last_ch) {
|
||||
return trd_last_ch == '?' && snd_last_ch == '*' && last_ch == 'j';
|
||||
}
|
||||
|
||||
static bool scan_number(TSLexer *lexer, const bool *valid_symbols) {
|
||||
|
|
@ -178,7 +182,9 @@ bool tree_sitter_rzcmd_external_scanner_scan(void *payload, TSLexer *lexer, cons
|
|||
return false;
|
||||
}
|
||||
// ?? is not considered an help command, just a regular one
|
||||
if ((res[i_res - 1] == '?' && strcmp (res, "??")) || (i_res >= 2 && is_recursive_help (i_res, res[i_res - 2], res[i_res - 1]))) {
|
||||
if ((res[i_res - 1] == '?' && strcmp (res, "??") != 0) ||
|
||||
(i_res > 2 && is_recursive_help (res[i_res - 2], res[i_res - 1])) ||
|
||||
(i_res > 3 && is_recursive_help_json (res[i_res - 3], res[i_res - 2], res[i_res - 1]))) {
|
||||
if (i_res == 1) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,4 +242,54 @@ EOF
|
|||
EXPECT=<<EOF
|
||||
0x116e
|
||||
EOF
|
||||
RUN
|
||||
RUN
|
||||
|
||||
NAME=recursive help
|
||||
FILE=-
|
||||
CMDS=<<EOF
|
||||
?* zi
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
| zi [<commens>] # Show zignatures matching information
|
||||
| zij [<commens>] # Show zignatures matching information (JSON mode)
|
||||
| zi* [<commens>] # Show zignatures matching information (rizin mode)
|
||||
| ziq [<commens>] # Show zignatures matching information (quiet mode)
|
||||
| zii <from> <to> # Show zignatures matching information in range
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=recursive help (json)
|
||||
FILE=-
|
||||
CMDS=<<EOF
|
||||
?*j zi
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
{"zi":{"cmd":"zi","type":"argv_modes","args_str":" [<commens>]","args":[{"type":"string","name":"commens"}],"description":"","summary":"Show zignatures matching information"},"zij":{"cmd":"zij","type":"argv_modes","args_str":" [<commens>]","args":[{"type":"string","name":"commens"}],"description":"","summary":"Show zignatures matching information (JSON mode)"},"zi*":{"cmd":"zi*","type":"argv_modes","args_str":" [<commens>]","args":[{"type":"string","name":"commens"}],"description":"","summary":"Show zignatures matching information (rizin mode)"},"ziq":{"cmd":"ziq","type":"argv_modes","args_str":" [<commens>]","args":[{"type":"string","name":"commens"}],"description":"","summary":"Show zignatures matching information (quiet mode)"},"zii":{"cmd":"zii","type":"argv","args_str":" <from> <to>","args":[{"type":"number","name":"from","required":true},{"type":"number","name":"to","required":true}],"description":"","summary":"Show zignatures matching information in range"}}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
||||
NAME=old recursive help
|
||||
FILE=-
|
||||
CMDS=<<EOF
|
||||
zi?*
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
| zi [<commens>] # Show zignatures matching information
|
||||
| zij [<commens>] # Show zignatures matching information (JSON mode)
|
||||
| zi* [<commens>] # Show zignatures matching information (rizin mode)
|
||||
| ziq [<commens>] # Show zignatures matching information (quiet mode)
|
||||
| zii <from> <to> # Show zignatures matching information in range
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=old recursive help (json)
|
||||
FILE=-
|
||||
CMDS=<<EOF
|
||||
zi?*j
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
{"zi":{"cmd":"zi","type":"argv_modes","args_str":" [<commens>]","args":[{"type":"string","name":"commens"}],"description":"","summary":"Show zignatures matching information"},"zij":{"cmd":"zij","type":"argv_modes","args_str":" [<commens>]","args":[{"type":"string","name":"commens"}],"description":"","summary":"Show zignatures matching information (JSON mode)"},"zi*":{"cmd":"zi*","type":"argv_modes","args_str":" [<commens>]","args":[{"type":"string","name":"commens"}],"description":"","summary":"Show zignatures matching information (rizin mode)"},"ziq":{"cmd":"ziq","type":"argv_modes","args_str":" [<commens>]","args":[{"type":"string","name":"commens"}],"description":"","summary":"Show zignatures matching information (quiet mode)"},"zii":{"cmd":"zii","type":"argv","args_str":" <from> <to>","args":[{"type":"number","name":"from","required":true},{"type":"number","name":"to","required":true}],"description":"","summary":"Show zignatures matching information in range"}}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -543,10 +543,10 @@ bool test_cmd_argv_modes(void) {
|
|||
pa = rz_cmd_parsed_args_newcmd("z?");
|
||||
h = rz_cmd_get_help(cmd, pa, false);
|
||||
exp_h = "Usage: z[jqJ] # z summary\n"
|
||||
"| z # z summary\n"
|
||||
"| zj # z summary (JSON mode)\n"
|
||||
"| zq # z summary (quiet mode)\n"
|
||||
"| zJ # z summary (verbose JSON mode)\n";
|
||||
"| z # z summary\n"
|
||||
"| zj # z summary (JSON mode)\n"
|
||||
"| zq # z summary (quiet mode)\n"
|
||||
"| zJ # z summary (verbose JSON mode)\n";
|
||||
mu_assert_streq(h, exp_h, "zj, zJ and zq are considered in the sub help");
|
||||
free(h);
|
||||
rz_cmd_parsed_args_free(pa);
|
||||
|
|
@ -599,8 +599,8 @@ bool test_cmd_group_argv_modes(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
static bool foreach_cmdname_cb(RzCmd *cmd, const char *name, void *user) {
|
||||
rz_list_append((RzList *)user, strdup(name));
|
||||
static bool foreach_cmdname_cb(RzCmd *cmd, const RzCmdDesc *desc, void *user) {
|
||||
rz_list_append((RzList *)user, strdup(desc->name));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -619,7 +619,7 @@ bool test_foreach_cmdname(void) {
|
|||
rz_cmd_desc_argv_new(cmd, v_inner_cd, "v2", zd_handler, &fake_help);
|
||||
|
||||
RzList *res = rz_list_newf(free);
|
||||
rz_cmd_foreach_cmdname(cmd, foreach_cmdname_cb, res);
|
||||
rz_cmd_foreach_cmdname(cmd, NULL, foreach_cmdname_cb, res);
|
||||
|
||||
const char *exp_regular[] = { "z", "zj", "zq", "zd", "zsq", "pi", "v", "v1", "v2" };
|
||||
mu_assert_eq(rz_list_length(res), RZ_ARRAY_SIZE(exp_regular), "count regular commands that can be executed");
|
||||
|
|
@ -645,6 +645,47 @@ bool test_foreach_cmdname(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
bool test_foreach_cmdname_begin(void) {
|
||||
RzCmd *cmd = rz_cmd_new(false);
|
||||
RzCmdDesc *root = rz_cmd_get_root(cmd);
|
||||
RzCmdDesc *z_cd = rz_cmd_desc_group_modes_new(cmd, root, "z", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET, z_modes_handler, &fake_help, &fake_help);
|
||||
rz_cmd_desc_argv_new(cmd, z_cd, "zd", zd_handler, &fake_help);
|
||||
rz_cmd_desc_argv_modes_new(cmd, z_cd, "zs", RZ_OUTPUT_MODE_QUIET, z_modes_handler, &fake_help);
|
||||
rz_cmd_desc_fake_new(cmd, root, "x", &fake_help);
|
||||
RzCmdDesc *p_cd = rz_cmd_desc_group_new(cmd, root, "p", NULL, NULL, &fake_help);
|
||||
rz_cmd_desc_argv_new(cmd, p_cd, "pi", zd_handler, &fake_help);
|
||||
RzCmdDesc *v_cd = rz_cmd_desc_oldinput_new(cmd, root, "v", a_oldinput_cb, &fake_help);
|
||||
RzCmdDesc *v_inner_cd = rz_cmd_desc_inner_new(cmd, v_cd, "v", &fake_help);
|
||||
rz_cmd_desc_argv_new(cmd, v_inner_cd, "v1", zd_handler, &fake_help);
|
||||
rz_cmd_desc_argv_new(cmd, v_inner_cd, "v2", zd_handler, &fake_help);
|
||||
|
||||
RzList *res = rz_list_newf(free);
|
||||
rz_cmd_foreach_cmdname(cmd, v_cd, foreach_cmdname_cb, res);
|
||||
|
||||
const char *exp_regular[] = { "v", "v1", "v2" };
|
||||
mu_assert_eq(rz_list_length(res), RZ_ARRAY_SIZE(exp_regular), "count regular commands that can be executed");
|
||||
|
||||
RzList *exp_regular_l = rz_list_new_from_array((const void **)exp_regular, RZ_ARRAY_SIZE(exp_regular));
|
||||
rz_list_sort(exp_regular_l, (RzListComparator)strcmp);
|
||||
rz_list_sort(res, (RzListComparator)strcmp);
|
||||
|
||||
RzListIter *it;
|
||||
char *s;
|
||||
size_t i = 0;
|
||||
rz_list_foreach (exp_regular_l, it, s) {
|
||||
RzStrBuf sb;
|
||||
rz_strbuf_initf(&sb, "check command `%s`", s);
|
||||
mu_assert_streq(rz_list_get_n(res, i++), s, rz_strbuf_get(&sb));
|
||||
rz_strbuf_fini(&sb);
|
||||
}
|
||||
|
||||
rz_list_free(res);
|
||||
rz_list_free(exp_regular_l);
|
||||
|
||||
rz_cmd_free(cmd);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_arg_escaping(void) {
|
||||
mu_assert_streq_free(rz_cmd_escape_arg("hello", RZ_CMD_ESCAPE_ONE_ARG), "hello", "regular string remains the same");
|
||||
mu_assert_streq_free(rz_cmd_escape_arg("hello world", RZ_CMD_ESCAPE_ONE_ARG), "hello\\ world", "spaces are escaped");
|
||||
|
|
@ -829,6 +870,7 @@ int all_tests() {
|
|||
mu_run_test(test_cmd_argv_modes);
|
||||
mu_run_test(test_cmd_group_argv_modes);
|
||||
mu_run_test(test_foreach_cmdname);
|
||||
mu_run_test(test_foreach_cmdname_begin);
|
||||
mu_run_test(test_arg_escaping);
|
||||
mu_run_test(test_double_quoted_arg_escaping);
|
||||
mu_run_test(test_single_quoted_arg_escaping);
|
||||
|
|
|
|||
Loading…
Reference in a new issue