[master] 38506b339 Use "help -j" to get list for command completion.

Poul-Henning Kamp phk at FreeBSD.org
Wed Aug 4 09:11:06 UTC 2021


commit 38506b339af043d64bef12b7c27fbfc7df62e657
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Wed Aug 4 09:07:43 2021 +0000

    Use "help -j" to get list for command completion.
    
    Do it on demand, so start/stop changes to available commands is properly reflected.

diff --git a/bin/varnishadm/varnishadm.c b/bin/varnishadm/varnishadm.c
index ebc1aa2cc..d95cc8845 100644
--- a/bin/varnishadm/varnishadm.c
+++ b/bin/varnishadm/varnishadm.c
@@ -61,10 +61,13 @@
 
 #include "vdef.h"
 
+#include "vqueue.h"
+
 #include "vapi/vsig.h"
 #include "vapi/vsm.h"
 #include "vas.h"
 #include "vcli.h"
+#include "vjsn.h"
 #include "vtcp.h"
 
 #define RL_EXIT(status) \
@@ -76,6 +79,7 @@
 
 static double timeout = 5;
 static int p_arg = 0;
+static int line_sock;
 
 static void
 cli_write(int sock, const char *s)
@@ -212,13 +216,12 @@ do_args(int sock, int argc, char * const *argv)
 /* Callback for readline, doesn't take a private pointer, so we need
  * to have a global variable.
  */
-static int _line_sock;
 static void v_matchproto_()
 send_line(char *l)
 {
 	if (l) {
-		cli_write(_line_sock, l);
-		cli_write(_line_sock, "\n");
+		cli_write(line_sock, l);
+		cli_write(line_sock, "\n");
 		if (*l)
 			add_history(l);
 		rl_callback_handler_install("varnish> ", send_line);
@@ -227,27 +230,49 @@ send_line(char *l)
 	}
 }
 
-static char *commands[256];
 static char *
 command_generator (const char *text, int state)
 {
-	static int list_index, len;
-	const char *name;
+	static struct vjsn *jsn_cmds;
+	static const struct vjsn_val *jv;
+	struct vjsn_val *jv2;
+	unsigned u;
+	char *answer = NULL;
+	const char *err;
 
-	/* If this is a new word to complete, initialize now.  This
-	   includes saving the length of TEXT for efficiency, and
-	   initializing the index variable to 0. */
 	if (!state) {
-		list_index = 0;
-		len = strlen(text);
+		cli_write(line_sock, "help -j\n");
+		u = VCLI_ReadResult(line_sock, NULL, &answer, timeout);
+		if (u) {
+			free(answer);
+			return (NULL);
+		}
+		jsn_cmds = vjsn_parse(answer, &err);
+		if (err != NULL)
+			return (NULL);
+		free(answer);
+		AN(jsn_cmds);
+		AN(jsn_cmds->value);
+		assert (jsn_cmds->value->type == VJSN_ARRAY);
+		jv = VTAILQ_FIRST(&jsn_cmds->value->children);
+		assert (jv->type == VJSN_NUMBER);
+		jv = VTAILQ_NEXT(jv, list);
+		assert (jv->type == VJSN_ARRAY);
+		jv = VTAILQ_NEXT(jv, list);
+		assert (jv->type == VJSN_NUMBER);
+		jv = VTAILQ_NEXT(jv, list);
 	}
-
-	while ((name = commands[list_index]) != NULL) {
-		list_index++;
-		if (strncmp (name, text, len) == 0)
-			return (strdup(name));
+	while (jv != NULL) {
+		assert (jv->type == VJSN_OBJECT);
+		jv2 = VTAILQ_FIRST(&jv->children);
+		AN(jv2);
+		jv = VTAILQ_NEXT(jv, list);
+		assert (jv2->type == VJSN_STRING);
+		assert (!strcmp(jv2->name, "request"));
+		if (!strncmp(text, jv2->value, strlen(text)))
+			return (strdup(jv2->value));
 	}
-	/* If no names matched, then return NULL. */
+	vjsn_delete(&jsn_cmds);
 	return (NULL);
 }
 
@@ -272,9 +297,7 @@ interactive(int sock)
 {
 	struct pollfd fds[2];
 	int i;
-	char *answer = NULL;
-	unsigned u, status;
-	_line_sock = sock;
+	line_sock = sock;
 	rl_already_prompted = 1;
 	rl_callback_handler_install("varnish> ", send_line);
 	rl_attempted_completion_function = varnishadm_completion;
@@ -284,34 +307,6 @@ interactive(int sock)
 	fds[1].fd = 0;
 	fds[1].events = POLLIN;
 
-	/* Grab the commands, for completion */
-	cli_write(sock, "help\n");
-	u = VCLI_ReadResult(fds[0].fd, &status, &answer, timeout);
-	if (!u) {
-		char *t, c[128];
-		if (status == CLIS_COMMS) {
-			RL_EXIT(0);
-		}
-		t = answer;
-
-		i = 0;
-		while (*t) {
-			if (sscanf(t, "%127s", c) == 1) {
-				commands[i++] = strdup(c);
-				while (*t != '\n' && *t != '\0')
-					t++;
-				if (*t == '\n')
-					t++;
-			} else {
-				/* what? */
-				fprintf(stderr, "Unknown command '%s' parsing "
-					"help output. Tab completion may be "
-					"broken\n", t);
-				break;
-			}
-		}
-	}
-	free(answer);
 	cli_write(sock, "banner\n");
 	while (1) {
 		i = poll(fds, 2, -1);


More information about the varnish-commit mailing list