On Thu, Jan 25, 2018 at 03:46:30PM -0500, Bruce Momjian wrote:
> On Mon, Jan 15, 2018 at 11:10:44AM -0500, Robert Haas wrote:
> > prompt_status does seem to be available in psql's MainLoop(), so I
> > think that could be done, but the problem is that I don't know exactly
> > what message would be useful to print when we're in a "in quotes"
> > state.  If I had a good message text for that state, I might just
> > choose to use it always rather than multiplying the number of
> > messages.
> > 
> > More broadly, I think what is needed here is less C-fu than
> > English-fu.  If we come up with something good, we can make it print
> > that thing.
> 
> I just read this thread and have some ideas.  First, the reason 'help'
> was added so easily is because it pointed users at getting more
> information, and it required to be the first command in the query
> buffer.
> 
> I realize we are now considering allowing 'help', 'quit', and 'exit' to
> appear alone on a line with whitespace before it, and remove the
> requirement that it be the first thing in the query buffer.
> 
> I think there are a few things to consider.
> 
> First, allowing whitespace to be before the keyword --- do we really
> think that typing <space>exit will more likely be typed by a user trying
> to exit than part of an SQL query?  I think requiring no space around
> the keyword would reduce the number of false hints.
> 
> Second, I am thinking we can check prompt_status and report "Use \q" if
> we are not in a quoted string, and suggest "Use Control-D then \q" (or
> "Use Control-C then \q" on Windows) and be done with it.  By printing
> the Control-D only when we are in a quoted strong, we minimize the
> number of times that we are wrong due to stty changes.

I used Robert's patch and modified it to match the ideas I had above.
Specifically no white space can be before 'help', 'exit' or 'quit' and
prompt_status is used to adjust the suggestion.  Here is the visible
behavior:

        test=> exit
        (exits)
        
        test=> SELECT
        test-> exit
-->     Use \q to quit.
        test-> \q

        test=> SELECT '
        test'> exit
-->     Use control-D to quit.
        test'> \q

        test=> SELECT "
        test"> exit
-->     Use control-D to quit.
        test"> \q
        
        test=> SELECT /*
        test*> exit
-->     Use control-D to quit.
        test*> \q

        test=> SELECT 'asbs' AS
        test-> exit
-->     Use \q to quit.
        test-> \q

        test=> SELECT 'asbs' AS
        test->     exit
        test-> ;
         exit
        ------
         asbs
        (1 row)

One open issue is the existing help display is inaccurate on Windows:

        Use \\? for help or press control-C to clear the input buffer.

Oh, it clears the input buffer alright, _and_ exits psql.  This patch
also removes the control-C mention on Windows.

-- 
  Bruce Momjian  <br...@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

+ As you are, so once was I.  As I am, so you will be. +
+                      Ancient Roman grave inscription +
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
new file mode 100644
index a8778a5..a3ef150
*** a/src/bin/psql/mainloop.c
--- b/src/bin/psql/mainloop.c
*************** MainLoop(FILE *source)
*** 216,236 ****
  			continue;
  		}
  
! 		/* A request for help? Be friendly and give them some guidance */
! 		if (pset.cur_cmd_interactive && query_buf->len == 0 &&
! 			pg_strncasecmp(line, "help", 4) == 0 &&
! 			(line[4] == '\0' || line[4] == ';' || isspace((unsigned char) line[4])))
  		{
! 			free(line);
! 			puts(_("You are using psql, the command-line interface to PostgreSQL."));
! 			printf(_("Type:  \\copyright for distribution terms\n"
! 					 "       \\h for help with SQL commands\n"
! 					 "       \\? for help with psql commands\n"
! 					 "       \\g or terminate with semicolon to execute query\n"
! 					 "       \\q to quit\n"));
  
! 			fflush(stdout);
! 			continue;
  		}
  
  		/* echo back if flag is set, unless interactive */
--- 216,323 ----
  			continue;
  		}
  
! 		/* Recognize "help", "quit", "exit" only in interactive mode */
! 		if (pset.cur_cmd_interactive)
  		{
! 			char	   *first_word = line;
! 			char	   *rest_of_line = NULL;
! 			bool		found_help = false;
! 			bool		found_exit_or_quit = false;
  
! 			/* Search for the words we recognize;  must be first word */
! 			if (pg_strncasecmp(first_word, "help", 4) == 0)
! 			{
! 				rest_of_line = first_word + 4;
! 				found_help = true;
! 			}
! 			else if (pg_strncasecmp(first_word, "exit", 4) == 0 ||
! 					 pg_strncasecmp(first_word, "quit", 4) == 0)
! 			{
! 				rest_of_line = first_word + 4;
! 				found_exit_or_quit = true;
! 			}
! 
! 			/*
! 			 * If we found a command word, check whether the rest of the line
! 			 * contains only whitespace plus maybe one semicolon.  If not,
! 			 * ignore the command word after all.
! 			 */
! 			if (rest_of_line != NULL)
! 			{
! 				/*
! 				 * Ignore unless rest of line is whitespace, plus maybe one
! 				 * semicolon
! 				 */
! 				while (isspace((unsigned char) *rest_of_line))
! 					++rest_of_line;
! 				if (*rest_of_line == ';')
! 					++rest_of_line;
! 				while (isspace((unsigned char) *rest_of_line))
! 					++rest_of_line;
! 				if (*rest_of_line != '\0')
! 				{
! 					found_help = false;
! 					found_exit_or_quit = false;
! 				}
! 			}
! 
! 			/*
! 			 * "help" is only a command when the query buffer is empty, but we
! 			 * emit a one-line message even when it isn't to help confused
! 			 * users.  The text is still added to the query buffer in that
! 			 * case.
! 			 */
! 			if (found_help)
! 			{
! 				if (query_buf->len != 0)
! #ifndef WIN32
! 					puts(_("Use \\? for help or press control-C to clear the input buffer."));
! #else
! 					puts(_("Use \\? for help."));
! #endif
! 				else
! 				{
! 					puts(_("You are using psql, the command-line interface to PostgreSQL."));
! 					printf(_("Type:  \\copyright for distribution terms\n"
! 							 "       \\h for help with SQL commands\n"
! 							 "       \\? for help with psql commands\n"
! 							 "       \\g or terminate with semicolon to execute query\n"
! 							 "       \\q to quit\n"));
! 					free(line);
! 					fflush(stdout);
! 					continue;
! 				}
! 			}
! 			/*
! 			 * "quit" and "exit" are only commands when the query buffer is
! 			 * empty, but we emit a one-line message even when it isn't to
! 			 * help confused users.  The text is still added to the query
! 			 * buffer in that case.
! 			 */
! 			if (found_exit_or_quit)
! 			{
! 				if (query_buf->len != 0)
! 				{
! 					if (prompt_status == PROMPT_READY ||
! 						prompt_status == PROMPT_CONTINUE ||
! 						prompt_status == PROMPT_PAREN)
! 						puts(_("Use \\q to quit."));
! 					else
! #ifndef WIN32
! 						puts(_("Use control-D to quit."));
! #else
! 						puts(_("Use control-C to quit."));
! #endif
! 				}
! 				else
! 				{
! 					/* exit app */
! 					free(line);
! 					fflush(stdout);
! 					successResult = EXIT_SUCCESS;
! 					break;
! 				}
! 			}
  		}
  
  		/* echo back if flag is set, unless interactive */

Reply via email to