|
@@ -25,6 +25,7 @@ typedef struct ctx_s {
|
|
|
|
|
|
bool_t cmd_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata);
|
|
|
bool_t completion_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata);
|
|
|
+bool_t help_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata);
|
|
|
static bool_t stdin_cb(faux_eloop_t *eloop, faux_eloop_type_e type,
|
|
|
void *associated_data, void *user_data);
|
|
|
|
|
@@ -67,8 +68,10 @@ int klish_interactive_shell(ktp_session_t *ktp, struct options *opts)
|
|
|
|
|
|
// Don't stop interactive loop on each answer
|
|
|
ktp_session_set_stop_on_answer(ktp, BOOL_FALSE);
|
|
|
+
|
|
|
ktp_session_set_cb(ktp, KTP_SESSION_CB_CMD_ACK, cmd_ack_cb, &ctx);
|
|
|
ktp_session_set_cb(ktp, KTP_SESSION_CB_COMPLETION_ACK, completion_ack_cb, &ctx);
|
|
|
+ ktp_session_set_cb(ktp, KTP_SESSION_CB_HELP_ACK, help_ack_cb, &ctx);
|
|
|
eloop = ktp_session_eloop(ktp);
|
|
|
faux_eloop_add_fd(eloop, STDIN_FILENO, POLLIN, stdin_cb, &ctx);
|
|
|
faux_eloop_loop(eloop);
|
|
@@ -295,3 +298,87 @@ bool_t completion_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata)
|
|
|
|
|
|
return BOOL_TRUE;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+bool_t help_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata)
|
|
|
+{
|
|
|
+ ctx_t *ctx = (ctx_t *)udata;
|
|
|
+ faux_list_node_t *iter = NULL;
|
|
|
+ uint32_t param_len = 0;
|
|
|
+ char *param_data = NULL;
|
|
|
+ uint16_t param_type = 0;
|
|
|
+ char *prefix = NULL;
|
|
|
+ faux_list_t *completions = NULL;
|
|
|
+ size_t completions_num = 0;
|
|
|
+ size_t max_compl_len = 0;
|
|
|
+
|
|
|
+ tinyrl_set_busy(ctx->tinyrl, BOOL_FALSE);
|
|
|
+
|
|
|
+ prefix = faux_msg_get_str_param_by_type(msg, KTP_PARAM_PREFIX);
|
|
|
+
|
|
|
+ completions = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
|
|
|
+ NULL, NULL, (void (*)(void *))faux_str_free);
|
|
|
+
|
|
|
+ iter = faux_msg_init_param_iter(msg);
|
|
|
+ while (faux_msg_get_param_each(&iter, ¶m_type, (void **)¶m_data, ¶m_len)) {
|
|
|
+ char *compl = NULL;
|
|
|
+ if (KTP_PARAM_LINE != param_type)
|
|
|
+ continue;
|
|
|
+ compl = faux_str_dupn(param_data, param_len);
|
|
|
+ faux_list_add(completions, compl);
|
|
|
+ if (param_len > max_compl_len)
|
|
|
+ max_compl_len = param_len;
|
|
|
+ }
|
|
|
+
|
|
|
+ completions_num = faux_list_len(completions);
|
|
|
+
|
|
|
+ // Single possible completion
|
|
|
+ if (1 == completions_num) {
|
|
|
+ char *compl = (char *)faux_list_data(faux_list_head(completions));
|
|
|
+ tinyrl_line_insert(ctx->tinyrl, compl, strlen(compl));
|
|
|
+ tinyrl_redisplay(ctx->tinyrl);
|
|
|
+
|
|
|
+ // Multi possible completions
|
|
|
+ } else if (completions_num > 1) {
|
|
|
+ faux_list_node_t *eq_iter = NULL;
|
|
|
+ size_t eq_part = 0;
|
|
|
+ char *str = NULL;
|
|
|
+ char *compl = NULL;
|
|
|
+
|
|
|
+ // Try to find equal part for all possible completions
|
|
|
+ eq_iter = faux_list_head(completions);
|
|
|
+ str = (char *)faux_list_data(eq_iter);
|
|
|
+ eq_part = strlen(str);
|
|
|
+ eq_iter = faux_list_next_node(eq_iter);
|
|
|
+
|
|
|
+ while ((compl = (char *)faux_list_each(&eq_iter)) && (eq_part > 0)) {
|
|
|
+ size_t cur_eq = 0;
|
|
|
+ cur_eq = tinyrl_equal_part(ctx->tinyrl, str, compl);
|
|
|
+ if (cur_eq < eq_part)
|
|
|
+ eq_part = cur_eq;
|
|
|
+ }
|
|
|
+
|
|
|
+ // The equal part was found
|
|
|
+ if (eq_part > 0) {
|
|
|
+ tinyrl_line_insert(ctx->tinyrl, str, eq_part);
|
|
|
+ tinyrl_redisplay(ctx->tinyrl);
|
|
|
+
|
|
|
+ // There is no equal part for all completions
|
|
|
+ } else {
|
|
|
+ tinyrl_multi_crlf(ctx->tinyrl);
|
|
|
+ tinyrl_reset_line_state(ctx->tinyrl);
|
|
|
+ display_completions(ctx->tinyrl, completions,
|
|
|
+ prefix, max_compl_len);
|
|
|
+ tinyrl_redisplay(ctx->tinyrl);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ faux_list_free(completions);
|
|
|
+ faux_str_free(prefix);
|
|
|
+
|
|
|
+ // Happy compiler
|
|
|
+ ktp = ktp;
|
|
|
+ msg = msg;
|
|
|
+
|
|
|
+ return BOOL_TRUE;
|
|
|
+}
|