Browse Source

ktpd: Function to generate help

Serj Kalichev 1 year ago
parent
commit
e24c3ca2c8
1 changed files with 70 additions and 57 deletions
  1. 70 57
      klish/ktp/ktpd_session.c

+ 70 - 57
klish/ktp/ktpd_session.c

@@ -399,8 +399,11 @@ static bool_t ktpd_session_process_completion(ktpd_session_t *ktpd, faux_msg_t *
 			res = ksession_exec_locally(ktpd->session, completion,
 				pargv, &rc, &out);
 			kparg_free(parg);
-			if (!res || (rc < 0) || !out)
+			if (!res || (rc < 0) || !out) {
+				if (out)
+					faux_str_free(out);
 				continue;
+			}
 
 			// Get all completions one by one
 			str = out;
@@ -481,6 +484,18 @@ static void help_free(void *ptr)
 }
 
 
+// Now help generation is simple. The 'prefix' (first help field) is generated
+// by PTYPE's help function. It can be something like 'ip', 'filter' i.e.
+// subcommand or '3..89', '<STRING>' i.e. description of type. The second
+// field is description of current parameter. For example 'Interface IP
+// address'. So the full help can be:
+// AAA.BBB.CCC.DDD Interface IP address
+// [ first field ] [ second field     ]
+//
+// Not all possible parameters can conform currently partly-typed line but it's
+// not clear how to filter them. Completions can be solution but completions are
+// not mandatory so parameter with non completed completion list can be filtered
+// out.
 static bool_t ktpd_session_process_help(ktpd_session_t *ktpd, faux_msg_t *msg)
 {
 	char *line = NULL;
@@ -489,7 +504,6 @@ static bool_t ktpd_session_process_help(ktpd_session_t *ktpd, faux_msg_t *msg)
 	ktp_cmd_e cmd = KTP_HELP_ACK;
 	uint32_t status = KTP_STATUS_NONE;
 	const char *prefix = NULL;
-	size_t prefix_len = 0;
 
 	assert(ktpd);
 	assert(msg);
@@ -518,84 +532,83 @@ static bool_t ktpd_session_process_help(ktpd_session_t *ktpd, faux_msg_t *msg)
 
 	// Last unfinished word. Common prefix for all entries
 	prefix = kpargv_last_arg(pargv);
-	if (!faux_str_is_empty(prefix)) {
-		prefix_len = strlen(prefix);
-//		faux_msg_add_param(ack, KTP_PARAM_PREFIX, prefix, prefix_len);
-	}
-/*
+
 	// Fill msg with possible completions
 	if (!kpargv_completions_is_empty(pargv)) {
 		const kentry_t *candidate = NULL;
 		kpargv_completions_node_t *citer = kpargv_completions_iter(pargv);
 		faux_list_node_t *help_iter = NULL;
 		faux_list_t *help_list = NULL;
-		char *compl_str = NULL;
+		help_t *help_struct = NULL;
 
 		help_list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
 			help_compare, help_kcompare, help_free);
 		while ((candidate = kpargv_completions_each(&citer))) {
-			const kentry_t *completion = NULL;
-			kparg_t *parg = NULL;
-			int rc = -1;
-			char *out = NULL;
-			bool_t res = BOOL_FALSE;
-			char *l = NULL; // One line of completion
-			const char *str = NULL;
-
-			// Get completion entry from candidate entry
-			completion = kentry_nested_by_purpose(candidate,
-				KENTRY_PURPOSE_COMPLETION);
-			// If candidate entry doesn't contain completion then try
-			// to get completion from entry's PTYPE
-			if (!completion) {
-				const kentry_t *ptype = NULL;
-				ptype = kentry_nested_by_purpose(candidate,
-					KENTRY_PURPOSE_PTYPE);
-				if (!ptype)
-					continue;
-				completion = kentry_nested_by_purpose(ptype,
-					KENTRY_PURPOSE_COMPLETION);
-			}
-			if (!completion)
-				continue;
-			parg = kparg_new(candidate, prefix);
-			kpargv_set_candidate_parg(pargv, parg);
-			res = ksession_exec_locally(ktpd->session, completion,
-				pargv, &rc, &out);
-			kparg_free(parg);
-			if (!res || (rc < 0) || !out)
+			const kentry_t *help = NULL;
+			const kentry_t *ptype = NULL;
+			char *prefix_str = NULL;
+			char *line_str = NULL;
+
+			// Get help from PTYPE for 'prefix'
+			ptype = kentry_nested_by_purpose(candidate,
+				KENTRY_PURPOSE_PTYPE);
+			if (!ptype) // Can't get help for ENTRY w/o PTYPE
 				continue;
+			help = kentry_nested_by_purpose(ptype,
+				KENTRY_PURPOSE_HELP);
+			if (help) {
+				kparg_t *parg = NULL;
+				int rc = -1;
+				parg = kparg_new(candidate, prefix);
+				kpargv_set_candidate_parg(pargv, parg);
+				ksession_exec_locally(ktpd->session,
+					help, pargv, &rc, &prefix_str);
+				kparg_free(parg);
+			}
+			if (!prefix_str) {
+				// If help is not defined use name of PTYPE.
+				// It can be informative enough.
+				prefix_str = faux_str_dup(kentry_name(ptype));
+			}
 
-			// Get all completions one by one
-			str = out;
-			while ((l = faux_str_getline(str, &str))) {
-				// Compare prefix
-				if ((prefix_len > 0) &&
-					(faux_str_cmpn(prefix, l, prefix_len) != 0)) {
-					faux_str_free(l);
-					continue;
-				}
-				compl_str = l + prefix_len;
-				faux_list_add(completions, faux_str_dup(compl_str));
-				faux_str_free(l);
+			// Get completion entry from candidate entry for 'line'
+			help = kentry_nested_by_purpose(candidate,
+				KENTRY_PURPOSE_HELP);
+			if (help) {
+				kparg_t *parg = NULL;
+				int rc = -1;
+				parg = kparg_new(candidate, prefix);
+				kpargv_set_candidate_parg(pargv, parg);
+				ksession_exec_locally(ktpd->session,
+					help, pargv, &rc, &line_str);
+				kparg_free(parg);
 			}
-			faux_str_free(out);
+			if (!line_str) {
+				// If help is not defined use name of ENTRY.
+				// It can be informative enough.
+				line_str = faux_str_dup(kentry_name(candidate));
+			}
+
+			help_struct = help_new(prefix_str, line_str);
+			faux_list_add(help_list, help_struct);
 		}
 
-		// Put completion list to message
-		citer = faux_list_head(completions);
-		while ((compl_str = faux_list_each(&citer))) {
+		// Put help list to message
+		help_iter = faux_list_head(help_list);
+		while ((help_struct = (help_t *)faux_list_each(&help_iter))) {
+			faux_msg_add_param(ack, KTP_PARAM_PREFIX,
+				help_struct->prefix, strlen(help_struct->prefix));
 			faux_msg_add_param(ack, KTP_PARAM_LINE,
-				compl_str, strlen(compl_str));
+				help_struct->line, strlen(help_struct->line));
 		}
-		faux_list_free(completions);
+		faux_list_free(help_list);
 	}
 
 	faux_msg_send_async(ack, ktpd->async);
 	faux_msg_free(ack);
 
 	kpargv_free(pargv);
-*/
+
 	return BOOL_TRUE;
 }