Make psql redisplay the query buffer after \e.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 22 Nov 2019 22:07:54 +0000 (17:07 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 22 Nov 2019 22:07:54 +0000 (17:07 -0500)
Up to now, whatever you'd edited was put back into the query buffer
but not redisplayed, which is less than user-friendly.  But we can
improve that just by printing the text along with a prompt, if we
enforce that the editing result ends with a newline (which it
typically would anyway).  You then continue typing more lines if
you want, or you can type ";" or do \g or \r or another \e.

This is intentionally divorced from readline's processing,
for simplicity and so that it works the same with or without
readline enabled.  We discussed possibly integrating things
more closely with readline; but that seems difficult, uncertainly
portable across different readline and libedit versions, and
of limited real benefit anyway.  Let's try the simple way and
see if it's good enough.

Patch by me, thanks to Fabien Coelho and Laurenz Albe for review

Discussion: https://postgr.es/m/13192.1572318028@sss.pgh.pa.us

doc/src/sgml/ref/psql-ref.sgml
src/bin/psql/command.c
src/bin/psql/mainloop.c

index a55ca6a2666fda5a7667ff51db21c06f62f89d5a..48b081fd58a27aad4c6926edad8126db7939085f 100644 (file)
@@ -1831,9 +1831,13 @@ testdb=&gt;
         the normal rules of <application>psql</application>, treating the
         whole buffer as a single line.  Any complete queries are immediately
         executed; that is, if the query buffer contains or ends with a
-        semicolon, everything up to that point is executed.  Whatever remains
-        will wait in the query buffer; type semicolon or <literal>\g</literal> to
-        send it, or <literal>\r</literal> to cancel it by clearing the query buffer.
+        semicolon, everything up to that point is executed and removed from
+        the query buffer.  Whatever remains in the query buffer is
+        redisplayed.  Type semicolon or <literal>\g</literal> to send it,
+        or <literal>\r</literal> to cancel it by clearing the query buffer.
+        </para>
+
+        <para>
         Treating the buffer as a single line primarily affects meta-commands:
         whatever is in the buffer after a meta-command will be taken as
         argument(s) to the meta-command, even if it spans multiple lines.
@@ -1893,7 +1897,8 @@ Tue Oct 26 21:40:57 CEST 1999
          in the form of a <command>CREATE OR REPLACE FUNCTION</command> or
          <command>CREATE OR REPLACE PROCEDURE</command> command.
          Editing is done in the same way as for <literal>\edit</literal>.
-         After the editor exits, the updated command waits in the query buffer;
+         After the editor exits, the updated command is executed immediately
+         if you added a semicolon to it.  Otherwise it is redisplayed;
          type semicolon or <literal>\g</literal> to send it, or <literal>\r</literal>
          to cancel.
         </para>
@@ -1969,7 +1974,8 @@ Tue Oct 26 21:40:57 CEST 1999
          This command fetches and edits the definition of the named view,
          in the form of a <command>CREATE OR REPLACE VIEW</command> command.
          Editing is done in the same way as for <literal>\edit</literal>.
-         After the editor exits, the updated command waits in the query buffer;
+         After the editor exits, the updated command is executed immediately
+         if you added a semicolon to it.  Otherwise it is redisplayed;
          type semicolon or <literal>\g</literal> to send it, or <literal>\r</literal>
          to cancel.
         </para>
index b981ae81ffa84ec39d4cfc3a5598d1b3a07c0ef3..7f57da8cc50287800f521675dbfd892d18cd9816 100644 (file)
@@ -3508,7 +3508,8 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
        {
            unsigned int ql = query_buf->len;
 
-           if (ql == 0 || query_buf->data[ql - 1] != '\n')
+           /* force newline-termination of what we send to editor */
+           if (ql > 0 && query_buf->data[ql - 1] != '\n')
            {
                appendPQExpBufferChar(query_buf, '\n');
                ql++;
index b3a840756af97a5fdca8f02752587c6959fa2bde..f7b1b94599dc939777f6d816645ffb11b5f21b38 100644 (file)
@@ -47,6 +47,7 @@ MainLoop(FILE *source)
    volatile int successResult = EXIT_SUCCESS;
    volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
    volatile promptStatus_t prompt_status = PROMPT_READY;
+   volatile bool need_redisplay = false;
    volatile int count_eof = 0;
    volatile bool die_on_error = false;
    FILE       *prev_cmd_source;
@@ -118,6 +119,7 @@ MainLoop(FILE *source)
            count_eof = 0;
            slashCmdStatus = PSQL_CMD_UNKNOWN;
            prompt_status = PROMPT_READY;
+           need_redisplay = false;
            pset.stmt_lineno = 1;
            cancel_pressed = false;
 
@@ -152,6 +154,18 @@ MainLoop(FILE *source)
            /* May need to reset prompt, eg after \r command */
            if (query_buf->len == 0)
                prompt_status = PROMPT_READY;
+           /* If query buffer came from \e, redisplay it with a prompt */
+           if (need_redisplay)
+           {
+               if (query_buf->len > 0)
+               {
+                   fputs(get_prompt(PROMPT_READY, cond_stack), stdout);
+                   fputs(query_buf->data, stdout);
+                   fflush(stdout);
+               }
+               need_redisplay = false;
+           }
+           /* Now we can fetch a line */
            line = gets_interactive(get_prompt(prompt_status, cond_stack),
                                    query_buf);
        }
@@ -518,6 +532,10 @@ MainLoop(FILE *source)
                {
                    /* should not see this in inactive branch */
                    Assert(conditional_active(cond_stack));
+                   /* ensure what came back from editing ends in a newline */
+                   if (query_buf->len > 0 &&
+                       query_buf->data[query_buf->len - 1] != '\n')
+                       appendPQExpBufferChar(query_buf, '\n');
                    /* rescan query_buf as new input */
                    psql_scan_finish(scan_state);
                    free(line);
@@ -529,6 +547,8 @@ MainLoop(FILE *source)
                                    pset.encoding, standard_strings());
                    line_saved_in_history = false;
                    prompt_status = PROMPT_READY;
+                   /* we'll want to redisplay after parsing what we have */
+                   need_redisplay = true;
                }
                else if (slashCmdStatus == PSQL_CMD_TERMINATE)
                    break;