Getting psql to redisplay command after \e

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Getting psql to redisplay command after \e
Дата
Msg-id 13192.1572318028@sss.pgh.pa.us
обсуждение исходный текст
Ответы Re: Getting psql to redisplay command after \e
Re: Getting psql to redisplay command after \e
Список pgsql-hackers
The attached patch teaches psql to redisplay any not-yet-executed
query text after editing with \e.  The fact that you don't get to
see what you're about to execute has been complained of before,
most recently at bug #16034 [1].  In that thread I complained that
we needed some probably-not-very-portable readline functionality
to make this work.  However, after experimenting with trying to
shove text back into readline's buffer, I realized that there's
not really any need to do that: we just need to print the waiting
text and then collect another line.  (As a bonus, it works the
same even if you turned off readline with -n.)

It also seems like to make this not confusing, we need to regurgitate
a prompt before the query text.  As an example, if I do

regression=# \e

and then put this into the edited file:

select 1,
2,
3

what I see after exiting the editor is now

regression=# select 1,
2,
3
regression-#

Without the initial prompt it looks (to me anyway) like output
from the command, rather than something I've sort of automagically
typed.

In the cited bug, Pavlo argued that we should also print any
completed commands that get sent to the backend immediately
after \e.  It'd be possible to do that by extending this patch
(basically, dump about-to-be-executed commands if need_redisplay
is still true), but on the whole I think that that would be overly
chatty, so I didn't do it.

This could stand some review and testing (e.g. does it interact
badly with any other psql features), so I'll add it to the
upcoming CF.

            regards, tom lane

[1] https://www.postgresql.org/message-id/flat/16034-a7ebf0622970a1dd%40postgresql.org

diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 7789fc6..c8f9cb7 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1831,9 +1831,10 @@ testdb=>
         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.
         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 +1894,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 +1971,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>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index b981ae8..7f57da8 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -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++;
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index b3a8407..f7b1b94 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -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;

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Thomas Munro
Дата:
Сообщение: Re: Preserve versions of initdb-created collations in pg_upgrade
Следующее
От: Dilip Kumar
Дата:
Сообщение: Re: Typos and inconsistencies in code