On Tue, Jun 7, 2022 at 3:23 PM Tom Lane <t...@sss.pgh.pa.us> wrote:
> The code needs a comment about why it's emitting a newline, though.
> In particular, it had better explain why that should be conditional
> on !pagerpipe, because that makes no sense to me.

Yeah.  OK, here's my take:

+               /*
+                * If the terminal driver echoed "^C",
libedit/libreadline might be
+                * confused about the cursor position.  Therefore,
inject a newline
+                * before the next prompt is displayed.  We only do
this when not using
+                * a pager, because pagers are expected to restore the
screen to a sane
+                * state on exit.
+                */

AFAIK pagers conventionally use something like termcap ti/te[1] to
restore the screen, or equivalents in tinfo etc (likely via curses).
If we were to inject an extra newline we'd just have a blank line for
nothing.  I suppose there could be a hypothetical pager that doesn't
follow that convention, and in fact both less and pspg have a -X
option to preserve last output, but in any case I expect that pagers
disable echoing, so I don't think the ^C will make it to the screen,
and furthermore ^C isn't used for exit anyway.  Rather than speculate
about the precise details, I just said "... sane state on exit".
Pavel, do you agree?

Here's how it looks after I enter and then exit Pavel's streaming pager:

$ PSQL_WATCH_PAGER='pspg --stream' ~/install/bin/psql postgres
psql (15beta1)
Type "help" for help.

postgres=# select;
--
(1 row)

postgres=# \watch 1
postgres=#

FWIW it's the same with PSQL_WATCH_PAGER='less'.

[1] 
https://www.gnu.org/software/termutils/manual/termcap-1.3/html_node/termcap_39.html
From a9389a8755379d4df2c52eb760d355aa5cf0ff96 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.mu...@gmail.com>
Date: Tue, 7 Jun 2022 14:18:51 +1200
Subject: [PATCH v2] Fix \watch's interaction with libedit/libreadline.

When you hit ^C, the terminal driver in Unix-like systems echos "^C" as
well as sending an interrupt signal (depending on stty settings).  The
line editing library (libedit/libreadline) is then confused about the
current cursor location, and might corrupt the display.  Fix, by moving
to a new line before the next prompt is displayed.

Author: Pavel Stehule <pavel.steh...@gmail.com>
Reported-by: Tom Lane <t...@sss.pgh.pa.us>
Discussion: https://postgr.es/m/3278793.1626198638%40sss.pgh.pa.us
---
 src/bin/psql/command.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index b51d28780b..7f366c80e9 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -5169,6 +5169,18 @@ do_watch(PQExpBuffer query_buf, double sleep)
 		pclose(pagerpipe);
 		restore_sigpipe_trap();
 	}
+	else
+	{
+		/*
+		 * If the terminal driver echoed "^C", libedit/libreadline might be
+		 * confused about the cursor position.  Therefore, inject a newline
+		 * before the next prompt is displayed.  We only do this when not using
+		 * a pager, because pagers are expected to restore the screen to a sane
+		 * state on exit.
+		 */
+		fprintf(stdout, "\n");
+		fflush(stdout);
+	}
 
 #ifdef HAVE_POSIX_DECL_SIGWAIT
 	/* Disable the interval timer. */
-- 
2.35.1

Reply via email to