From e9bd84014dd38629899af4d609785525c5c2abc5 Mon Sep 17 00:00:00 2001
From: alterego655 <824662526@qq.com>
Date: Mon, 29 Sep 2025 14:25:57 +0800
Subject: [PATCH v1] Add tab completion support for WAIT FOR command

Implement  tab completion for the WAIT FOR LSN command in psql.
---
 src/bin/psql/tab-complete.in.c | 43 +++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 6176741d20b..2f710484d92 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -1260,7 +1260,7 @@ static const char *const sql_commands[] = {
 	"REASSIGN", "REFRESH MATERIALIZED VIEW", "REINDEX", "RELEASE",
 	"RESET", "REVOKE", "ROLLBACK",
 	"SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
-	"TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
+	"TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WAIT FOR", "WITH",
 	NULL
 };
 
@@ -5273,6 +5273,47 @@ match_previous_words(int pattern_id,
 	else if (HeadMatches("VACUUM"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_vacuumables);
 
+/*
+ * WAIT FOR LSN '<lsn>' [ [WITH] ( <option> [, ...] ) ]
+ */
+	else if (Matches("WAIT"))
+		COMPLETE_WITH("FOR");
+	else if (Matches("WAIT", "FOR"))
+		COMPLETE_WITH("LSN");
+	else if (Matches("WAIT", "FOR", "LSN"))
+		/* No completion for LSN value - user must provide manually */
+		;
+	else if (Matches("WAIT", "FOR", "LSN", MatchAny))
+		COMPLETE_WITH("WITH", "(");
+	else if (Matches("WAIT", "FOR", "LSN", MatchAny, "WITH"))
+		COMPLETE_WITH("(");
+	else if (Matches("WAIT", "FOR", "LSN", MatchAny, "WITH", "(") ||
+			 Matches("WAIT", "FOR", "LSN", MatchAny, "("))
+		COMPLETE_WITH("timeout", "no_throw");
+	else if (HeadMatches("WAIT", "FOR", "LSN", MatchAny, "WITH", "(*") &&
+			 !HeadMatches("WAIT", "FOR", "LSN", MatchAny, "WITH", "(*)"))
+	{
+		/*
+		 * This fires if we're in an unfinished parenthesized option list.
+		 * get_previous_words treats a completed parenthesized option list as
+		 * one word, so the above test is correct.
+		 */
+		if (ends_with(prev_wd, '(') || ends_with(prev_wd, ','))
+		{
+			COMPLETE_WITH("timeout", "no_throw");
+		}
+		/* timeout takes a string value, no_throw takes no value */
+	}
+	else if (HeadMatches("WAIT", "FOR", "LSN", MatchAny, "(*") &&
+			 !HeadMatches("WAIT", "FOR", "LSN", MatchAny, "(*)"))
+	{
+		/* Handle optional WITH syntax: WAIT FOR LSN '<lsn>' ( ... ) */
+		if (ends_with(prev_wd, '(') || ends_with(prev_wd, ','))
+		{
+			COMPLETE_WITH("timeout", "no_throw");
+		}
+	}
+
 /* WITH [RECURSIVE] */
 
 	/*
-- 
2.51.0

