From e3ba6cda83b64246c2b4d3df01f62444f4b37c9d Mon Sep 17 00:00:00 2001
From: Bogdan Pilch <bogdan.pilch@opensynergy.com>
Date: Sun, 7 Sep 2014 18:59:12 +0200
Subject: [PATCH] Implemented support for turning off/on tab completion (in
 readline).

---
 src/bin/psql/command.c      | 20 ++++++++++++++++++++
 src/bin/psql/help.c         |  1 +
 src/bin/psql/input.c        |  9 +++++++++
 src/bin/psql/input.h        |  1 +
 src/bin/psql/mainloop.c     |  3 +++
 src/bin/psql/settings.h     |  1 +
 src/bin/psql/startup.c      |  7 ++++++-
 src/bin/psql/tab-complete.c |  9 +++++++++
 src/bin/psql/tab-complete.h |  1 +
 9 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 741a72d..e14b15b 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -1343,6 +1343,26 @@ exec_command(const char *cmd,
 		free(value);
 	}
 
+	/* \tab -- toggle tab completion */
+	else if (strcmp(cmd, "tab") == 0)
+	{
+		char	   *opt = psql_scan_slash_option(scan_state,
+												 OT_NORMAL, NULL, false);
+
+		if (opt)
+			pset.tab_completion = ParseVariableBool(opt);
+		else
+			pset.tab_completion = !pset.tab_completion;
+		if (!pset.quiet)
+		{
+			if (pset.tab_completion)
+				puts(_("Tab completion is on."));
+			else
+				puts(_("Tab completion is off."));
+		}
+		free(opt);
+	}
+
 	/* \timing -- toggle timing of queries */
 	else if (strcmp(cmd, "timing") == 0)
 	{
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 3aa3c16..afc90b8 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -87,6 +87,7 @@ usage(void)
 
 	printf(_("\nInput and output options:\n"));
 	printf(_("  -a, --echo-all           echo all input from script\n"));
+	printf(_("  -C, --tab-completion-off turn off tab completion\n"));
 	printf(_("  -e, --echo-queries       echo commands sent to server\n"));
 	printf(_("  -E, --echo-hidden        display queries that internal commands generate\n"));
 	printf(_("  -L, --log-file=FILENAME  send session log to file\n"));
diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index aa32a3f..96f73c6 100644
--- a/src/bin/psql/input.c
+++ b/src/bin/psql/input.c
@@ -263,6 +263,15 @@ decode_history(void)
 
 
 /*
+ * Just a wrapper function for readline setup
+ */
+void
+set_input_completion(void)
+{
+	set_readline_completion();
+}
+
+/*
  * Put any startup stuff related to input in here. It's good to maintain
  * abstraction this way.
  *
diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h
index 1d10a22..ad1eede 100644
--- a/src/bin/psql/input.h
+++ b/src/bin/psql/input.h
@@ -41,6 +41,7 @@
 char	   *gets_interactive(const char *prompt);
 char	   *gets_fromFile(FILE *source);
 
+void		set_input_completion(void);
 void		initializeInput(int flags);
 bool		saveHistory(char *fname, int max_lines, bool appendFlag, bool encodeFlag);
 
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index c3aff20..92546e0 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -123,6 +123,9 @@ MainLoop(FILE *source)
 
 		fflush(stdout);
 
+		/* Modify readline settings if necessary */
+		set_input_completion();
+
 		/*
 		 * get another line
 		 */
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 0a60e68..7e5e98c 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -89,6 +89,7 @@ typedef struct _psqlSettings
 	uint64		lineno;			/* also for error reporting */
 
 	bool		timing;			/* enable timing of all queries */
+	bool		tab_completion;		/* enable/disable tab completion in interactive mode */
 
 	FILE	   *logfile;		/* session log file handle */
 
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 45653a1..df9d720 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -121,6 +121,7 @@ main(int argc, char *argv[])
 	pset.copyStream = NULL;
 	pset.cur_cmd_source = stdin;
 	pset.cur_cmd_interactive = false;
+	pset.tab_completion = true;
 
 	/* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
 	pset.popt.topt.format = PRINT_ALIGNED;
@@ -372,6 +373,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
 		{"record-separator-zero", no_argument, NULL, '0'},
 		{"single-step", no_argument, NULL, 's'},
 		{"single-line", no_argument, NULL, 'S'},
+		{"tab-completion-off", no_argument, NULL, 'C'},
 		{"tuples-only", no_argument, NULL, 't'},
 		{"table-attr", required_argument, NULL, 'T'},
 		{"username", required_argument, NULL, 'U'},
@@ -391,7 +393,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
 
 	memset(options, 0, sizeof *options);
 
-	while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
+	while ((c = getopt_long(argc, argv, "aAc:Cd:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
 							long_options, &optindex)) != -1)
 	{
 		switch (c)
@@ -412,6 +414,9 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
 				else
 					options->action = ACT_SINGLE_QUERY;
 				break;
+			case 'C':
+				pset.tab_completion = false;
+				break;
 			case 'd':
 				options->dbname = pg_strdup(optarg);
 				break;
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 96de778..9ed2d0f 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -830,6 +830,15 @@ initialize_readline(void)
 	 */
 }
 
+/*
+ * Set the readline to inhibit or allow command completion
+ * based on global pset.tab_completion
+ */
+void
+set_readline_completion(void)
+{
+	rl_inhibit_completion = ( pset.tab_completion ? 0 : 1 );
+}
 
 /*
  * The completion function.
diff --git a/src/bin/psql/tab-complete.h b/src/bin/psql/tab-complete.h
index 5022ca2..e6226b9 100644
--- a/src/bin/psql/tab-complete.h
+++ b/src/bin/psql/tab-complete.h
@@ -11,5 +11,6 @@
 #include "postgres_fe.h"
 
 void		initialize_readline(void);
+void		set_readline_completion(void);
 
 #endif
-- 
1.9.1

