\h tab-completion

Started by Stephen Frostalmost 9 years ago12 messages
#1Stephen Frost
sfrost@snowman.net

All,

I'm not really inclined to do it myself right now, but it'd be awful
nice if we had better table completion for \h.

Right now, '\h alter<tab>' returns nothing, and '\h alter' returns a
*bunch* of stuff.

Yet, we happily support '\h alter view' and friends, returning just the
info relevant for that particular command.

This would be a good starter project for someone new to work on, imv,
tho it could also go on the to-do list.

Thanks!

Stephen

#2Beena Emerson
memissemerson@gmail.com
In reply to: Stephen Frost (#1)
1 attachment(s)
Re: \h tab-completion

On Wed, Jan 25, 2017 at 9:03 AM, Stephen Frost <sfrost@snowman.net> wrote:

All,

I'm not really inclined to do it myself right now, but it'd be awful
nice if we had better table completion for \h.

Right now, '\h alter<tab>' returns nothing, and '\h alter' returns a
*bunch* of stuff.

Yet, we happily support '\h alter view' and friends, returning just the
info relevant for that particular command.

This would be a good starter project for someone new to work on, imv,
tho it could also go on the to-do list.

Thanks!

I think the following change in tab-complete.c would do the trick.

-       else if (Matches1("ALTER"))
+       else if (TailMatches1("ALTER"))

postgres=# \h ALTER
AGGREGATE DOMAIN FUNCTION
MATERIALIZED VIEW RULE SYSTEM TYPE
COLLATION EVENT TRIGGER GROUP OPERATOR
SCHEMA TABLE USER
CONVERSION EXTENSION INDEX POLICY
SEQUENCE TABLESPACE USER MAPPING FOR
DATABASE FOREIGN DATA WRAPPER LANGUAGE
PUBLICATION SERVER TEXT SEARCH VIEW
DEFAULT PRIVILEGES FOREIGN TABLE LARGE OBJECT ROLE
SUBSCRIPTION TRIGGER

--
Thank you,

Beena Emerson

Have a Great Day!

Attachments:

tab-complete-hALTER.patchapplication/octet-stream; name=tab-complete-hALTER.patchDownload
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index d6fffcf..8b3bfff 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1403,7 +1403,7 @@ psql_completion(const char *text, int start, int end)
 								   "UNION SELECT 'ALL IN TABLESPACE'");
 
 	/* ALTER something */
-	else if (Matches1("ALTER"))
+	else if (TailMatches1("ALTER"))
 	{
 		static const char *const list_ALTER[] =
 		{"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
#3Michael Paquier
michael.paquier@gmail.com
In reply to: Beena Emerson (#2)
Re: \h tab-completion

On Wed, Jan 25, 2017 at 3:03 PM, Beena Emerson <memissemerson@gmail.com> wrote:

I think the following change in tab-complete.c would do the trick.

-       else if (Matches1("ALTER"))
+       else if (TailMatches1("ALTER"))

Nope. This change breaks a bunch of subcommands, take for example
ALTER TABLE foo ALTER, which would be completed to all the potential
objects of ALTER commands with your patch, but in this case for
example we just need to look at the column names, CONSTRAINT and
COLUMN. CREATE is not part of any subcommands so that's easy to see it
work with \h. What I think you should do is making the code path of
\\h smarter with some exceptions by using TailMatchesCS2() for ALTER.
There is as well the case of DROP commands that should be treated by
the way.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Beena Emerson
memissemerson@gmail.com
In reply to: Michael Paquier (#3)
Re: \h tab-completion

On Wed, Jan 25, 2017 at 11:43 AM, Michael Paquier <michael.paquier@gmail.com

wrote:

On Wed, Jan 25, 2017 at 3:03 PM, Beena Emerson <memissemerson@gmail.com>
wrote:

I think the following change in tab-complete.c would do the trick.

-       else if (Matches1("ALTER"))
+       else if (TailMatches1("ALTER"))

Nope. This change breaks a bunch of subcommands, take for example
ALTER TABLE foo ALTER, which would be completed to all the potential
objects of ALTER commands with your patch, but in this case for
example we just need to look at the column names, CONSTRAINT and
COLUMN. CREATE is not part of any subcommands so that's easy to see it
work with \h. What I think you should do is making the code path of
\\h smarter with some exceptions by using TailMatchesCS2() for ALTER.
There is as well the case of DROP commands that should be treated by
the way.

I feared the same.
I will check this.

--
Thank you,

Beena Emerson

Have a Great Day!

#5Andreas Karlsson
andreas@proxel.se
In reply to: Michael Paquier (#3)
1 attachment(s)
Re: \h tab-completion

On 01/25/2017 07:13 AM, Michael Paquier wrote:

What I think you should do is making the code path of
\\h smarter with some exceptions by using TailMatchesCS2() for ALTER.
There is as well the case of DROP commands that should be treated by
the way.

Yes, I think that is correct approach. I have attached a patch where I
add completion for \h ALTER and \h DROP.

Andreas

Attachments:

help-completion-v1.patchtext/x-patch; name=help-completion-v1.patchDownload
commit 045c92b10eb8777d29fc920c55561d645c0b8f30
Author: Andreas Karlsson <andreas@proxel.se>
Date:   Fri Feb 3 13:05:48 2017 +0100

    Add compleition for \help DROP|ALTER

diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index d6fffcf42f..653630dac2 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1262,6 +1262,17 @@ psql_completion(const char *text, int start, int end)
 	(previous_words_count >= 2 && \
 	 word_matches_cs(p1, prev_wd) && \
 	 word_matches_cs(p2, prev2_wd))
+#define TailMatchesCS3(p3, p2, p1) \
+	(previous_words_count >= 3 && \
+	 word_matches_cs(p1, prev_wd) && \
+	 word_matches_cs(p2, prev2_wd) && \
+	 word_matches_cs(p3, prev3_wd))
+#define TailMatchesCS4(p4, p3, p2, p1) \
+	(previous_words_count >= 4 && \
+	 word_matches_cs(p1, prev_wd) && \
+	 word_matches_cs(p2, prev2_wd) && \
+	 word_matches_cs(p3, prev3_wd) && \
+	 word_matches_cs(p4, prev4_wd))
 
 	/*
 	 * Macros for matching N words beginning at the start of the line,
@@ -3256,8 +3267,51 @@ psql_completion(const char *text, int start, int end)
 
 	else if (TailMatchesCS1("\\encoding"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
-	else if (TailMatchesCS1("\\h") || TailMatchesCS1("\\help"))
+	else if (TailMatchesCS1("\\h|\\help"))
 		COMPLETE_WITH_LIST(sql_commands);
+	else if (TailMatchesCS2("\\h|\\help", MatchAny))
+	{
+		if (TailMatches1("DROP"))
+			matches = completion_matches(text, drop_command_generator);
+		else if (TailMatches1("ALTER"))
+		{
+			static const char *const list_ALTER[] =
+			{"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
+				"EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
+				"GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR",
+				"POLICY", "PUBLICATION", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE",
+				"SUBSCRIPTION", "SYSTEM", "TABLE", "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
+			"USER", "USER MAPPING FOR", "VIEW", NULL};
+
+			COMPLETE_WITH_LIST(list_ALTER);
+		}
+	}
+	else if (TailMatchesCS3("\\h|\\help", MatchAny, MatchAny))
+	{
+		if (TailMatches2("DROP", "ACCESS"))
+			COMPLETE_WITH_CONST("METHOD");
+		else if (TailMatches2("ALTER", "DEFAULT"))
+			COMPLETE_WITH_CONST("PRIVILEGES");
+		else if (TailMatches2("ALTER|DROP", "EVENT"))
+			COMPLETE_WITH_CONST("TRIGGER");
+		else if (TailMatches2("ALTER|DROP", "FOREIGN"))
+			COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
+		else if (TailMatches2("ALTER", "LARGE"))
+			COMPLETE_WITH_CONST("OBJECT");
+		else if (TailMatches2("ALTER|DROP", "MATERIALIZED"))
+			COMPLETE_WITH_CONST("VIEW");
+		else if (TailMatches2("ALTER|DROP", "TEXT"))
+			COMPLETE_WITH_CONST("SEARCH");
+		else if (TailMatches2("ALTER|DROP", "USER"))
+			COMPLETE_WITH_CONST("MAPPING FOR");
+	}
+	else if (TailMatchesCS4("\\h|\\help", MatchAny, MatchAny, MatchAny))
+	{
+		if (TailMatches3("ALTER|DROP", "FOREIGN", "DATA"))
+			COMPLETE_WITH_CONST("WRAPPER");
+		else if (TailMatches3("ALTER|DROP", "USER", "MAPPING"))
+			COMPLETE_WITH_CONST("FOR");
+	}
 	else if (TailMatchesCS1("\\l*") && !TailMatchesCS1("\\lo*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_databases);
 	else if (TailMatchesCS1("\\password"))
#6Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Andreas Karlsson (#5)
Re: \h tab-completion

On 2/3/17 07:12, Andreas Karlsson wrote:

On 01/25/2017 07:13 AM, Michael Paquier wrote:

What I think you should do is making the code path of
\\h smarter with some exceptions by using TailMatchesCS2() for ALTER.
There is as well the case of DROP commands that should be treated by
the way.

Yes, I think that is correct approach. I have attached a patch where I
add completion for \h ALTER and \h DROP.

Instead of creating another copy of list_ALTER, let's use the
words_after_create list and write a version of
create_command_generator/drop_command_generator.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Kyotaro HORIGUCHI
horiguchi.kyotaro@lab.ntt.co.jp
In reply to: Peter Eisentraut (#6)
Re: \h tab-completion

Hello,

At Wed, 1 Mar 2017 08:47:15 -0500, Peter Eisentraut <peter.eisentraut@2ndquadrant.com> wrote in <ceaf1188-5d7d-a8e1-19aa-8184b5923072@2ndquadrant.com>

On 2/3/17 07:12, Andreas Karlsson wrote:

On 01/25/2017 07:13 AM, Michael Paquier wrote:

What I think you should do is making the code path of
\\h smarter with some exceptions by using TailMatchesCS2() for ALTER.
There is as well the case of DROP commands that should be treated by
the way.

Yes, I think that is correct approach. I have attached a patch where I
add completion for \h ALTER and \h DROP.

Instead of creating another copy of list_ALTER, let's use the
words_after_create list and write a version of
create_command_generator/drop_command_generator.

I'd like to separate the completion code into context-detector
and completion-engine. The former returns a "perse context value"
and the latter shows the suggestions from the values. Help engine
can use the same context-detector with the completion code. But
the correspondence between the two routines seems hardly
maintained:( (and such separation(refactoring) will be stuck on
the way)

Even this is a bit different topic from this patch aims, another
random thought on the help is that \h command should offer the
restriction words instead of all documents of possiblly-matching
(or head-matching) commands. For example, the current \h command
shows the following for create command.

=# \h create<cr>
Command: CREATE ACCESS METHOD
Description: define a new access method
Syntax:
CREATE ACCESS METHOD name
TYPE access_method_type
HANDLER handler_function

Command: CREATE AGGREGATE
...

This seems pointless to me and should offer the list of the next
words and short summary. gdb does the following for the case the
following.

| (gdb) help enable
| Enable some breakpoints.
| Give breakpoint numbers (separated by spaces) as arguments.
| With no subcommand, breakpoints are enabled until you command otherwise.
| This is used to cancel the effect of the "disable" command.
| With a subcommand you can enable temporarily.
|
| List of enable subcommands:
|
| enable breakpoints -- Enable some breakpoints
| enable count -- Enable breakpoints for COUNT hits
| enable delete -- Enable breakpoints and delete when hit

| =# \h create<cr>
| Define an object
|
| List of create subcommands:
|
| CREATE ACCESS METHOD - Define a new access method
| CREATE AGGREGATE - Define a new aggregate function
| ...

One bothersome problem is distinction between "CREATE TABLE" and
("CREATE TABLE AS" and "CREATE TABLESPACE"), but this might be
resolved by a small craft in documentation.

| - Documentation for "CREATE TABLE"
| Define a table
|
| You might want to see the following commands.
| CREATE TABLE AS - Define a new table from the result of a query
| CREATE TABLESPACE - Define a new tablespace.
|
| Syntax:
| CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] %s ( [

regards,

--
Kyotaro Horiguchi
NTT Open Source Software Center

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8David Steele
david@pgmasters.net
In reply to: Peter Eisentraut (#6)
Re: \h tab-completion

Hi Andreas,

On 3/1/17 8:47 AM, Peter Eisentraut wrote:

On 2/3/17 07:12, Andreas Karlsson wrote:

On 01/25/2017 07:13 AM, Michael Paquier wrote:

What I think you should do is making the code path of
\\h smarter with some exceptions by using TailMatchesCS2() for ALTER.
There is as well the case of DROP commands that should be treated by
the way.

Yes, I think that is correct approach. I have attached a patch where I
add completion for \h ALTER and \h DROP.

Instead of creating another copy of list_ALTER, let's use the
words_after_create list and write a version of
create_command_generator/drop_command_generator.

Do you know when you will have a new patch available for review that
incorporates Peter's request?

Thanks,
--
-David
david@pgmasters.net

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Andreas Karlsson
andreas@proxel.se
In reply to: David Steele (#8)
Re: \h tab-completion

On 03/13/2017 03:56 PM, David Steele wrote:

Do you know when you will have a new patch available for review that
incorporates Peter's request?

I believe I will find the time to finish it some time in a couple of days.

Andreas

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Andreas Karlsson
andreas@proxel.se
In reply to: Peter Eisentraut (#6)
1 attachment(s)
Re: \h tab-completion

On 03/01/2017 02:47 PM, Peter Eisentraut wrote:

Instead of creating another copy of list_ALTER, let's use the
words_after_create list and write a version of
create_command_generator/drop_command_generator.

Good idea. Here is a patch with that.

Andreas

Attachments:

help-completion-v2.patchtext/x-diff; name=help-completion-v2.patchDownload
commit 7d691929f5814da87bb8a532e7dcfa2bd1dc9f15
Author: Andreas Karlsson <andreas@proxel.se>
Date:   Fri Feb 3 13:05:48 2017 +0100

    Add compleition for \help DROP|ALTER

diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index e8458e939e..3df7636c5b 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -982,10 +982,11 @@ typedef struct
 
 #define THING_NO_CREATE		(1 << 0)	/* should not show up after CREATE */
 #define THING_NO_DROP		(1 << 1)	/* should not show up after DROP */
-#define THING_NO_SHOW		(THING_NO_CREATE | THING_NO_DROP)
+#define THING_NO_ALTER		(1 << 2)	/* should not show up after ALTER */
+#define THING_NO_SHOW		(THING_NO_CREATE | THING_NO_DROP | THING_NO_ALTER)
 
 static const pgsql_thing_t words_after_create[] = {
-	{"ACCESS METHOD", NULL, NULL},
+	{"ACCESS METHOD", NULL, NULL, THING_NO_ALTER},
 	{"AGGREGATE", NULL, &Query_for_list_of_aggregates},
 	{"CAST", NULL, NULL},		/* Casts have complex structures for names, so
 								 * skip it */
@@ -999,6 +1000,7 @@ static const pgsql_thing_t words_after_create[] = {
 	{"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
 	{"DATABASE", Query_for_list_of_databases},
 	{"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
+	{"DEFAULT PRIVILEGES", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
 	{"DOMAIN", NULL, &Query_for_list_of_domains},
 	{"EVENT TRIGGER", NULL, NULL},
 	{"EXTENSION", Query_for_list_of_extensions},
@@ -1006,12 +1008,13 @@ static const pgsql_thing_t words_after_create[] = {
 	{"FOREIGN TABLE", NULL, NULL},
 	{"FUNCTION", NULL, &Query_for_list_of_functions},
 	{"GROUP", Query_for_list_of_roles},
-	{"LANGUAGE", Query_for_list_of_languages},
 	{"INDEX", NULL, &Query_for_list_of_indexes},
+	{"LANGUAGE", Query_for_list_of_languages, NULL, THING_NO_ALTER},
+	{"LARGE OBJECT", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
 	{"MATERIALIZED VIEW", NULL, &Query_for_list_of_matviews},
 	{"OPERATOR", NULL, NULL},	/* Querying for this is probably not such a
 								 * good idea. */
-	{"OWNED", NULL, NULL, THING_NO_CREATE},		/* for DROP OWNED BY ... */
+	{"OWNED", NULL, NULL, THING_NO_CREATE | THING_NO_ALTER},		/* for DROP OWNED BY ... */
 	{"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
 	{"POLICY", NULL, NULL},
 	{"PUBLICATION", Query_for_list_of_publications},
@@ -1021,15 +1024,16 @@ static const pgsql_thing_t words_after_create[] = {
 	{"SEQUENCE", NULL, &Query_for_list_of_sequences},
 	{"SERVER", Query_for_list_of_servers},
 	{"SUBSCRIPTION", Query_for_list_of_subscriptions},
+	{"SYSTEM", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
 	{"TABLE", NULL, &Query_for_list_of_tables},
 	{"TABLESPACE", Query_for_list_of_tablespaces},
-	{"TEMP", NULL, NULL, THING_NO_DROP},		/* for CREATE TEMP TABLE ... */
+	{"TEMP", NULL, NULL, THING_NO_DROP | THING_NO_ALTER},		/* for CREATE TEMP TABLE ... */
 	{"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
 	{"TEXT SEARCH", NULL, NULL},
 	{"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s' AND NOT tgisinternal"},
 	{"TYPE", NULL, &Query_for_list_of_datatypes},
-	{"UNIQUE", NULL, NULL, THING_NO_DROP},		/* for CREATE UNIQUE INDEX ... */
-	{"UNLOGGED", NULL, NULL, THING_NO_DROP},	/* for CREATE UNLOGGED TABLE
+	{"UNIQUE", NULL, NULL, THING_NO_DROP | THING_NO_ALTER},		/* for CREATE UNIQUE INDEX ... */
+	{"UNLOGGED", NULL, NULL, THING_NO_DROP | THING_NO_ALTER},	/* for CREATE UNLOGGED TABLE
 												 * ... */
 	{"USER", Query_for_list_of_roles},
 	{"USER MAPPING FOR", NULL, NULL},
@@ -1042,6 +1046,7 @@ static const pgsql_thing_t words_after_create[] = {
 static char **psql_completion(const char *text, int start, int end);
 static char *create_command_generator(const char *text, int state);
 static char *drop_command_generator(const char *text, int state);
+static char *alter_command_generator(const char *text, int state);
 static char *complete_from_query(const char *text, int state);
 static char *complete_from_schema_query(const char *text, int state);
 static char *_complete_from_query(int is_schema_query,
@@ -1316,6 +1321,17 @@ psql_completion(const char *text, int start, int end)
 	(previous_words_count >= 2 && \
 	 word_matches_cs(p1, prev_wd) && \
 	 word_matches_cs(p2, prev2_wd))
+#define TailMatchesCS3(p3, p2, p1) \
+	(previous_words_count >= 3 && \
+	 word_matches_cs(p1, prev_wd) && \
+	 word_matches_cs(p2, prev2_wd) && \
+	 word_matches_cs(p3, prev3_wd))
+#define TailMatchesCS4(p4, p3, p2, p1) \
+	(previous_words_count >= 4 && \
+	 word_matches_cs(p1, prev_wd) && \
+	 word_matches_cs(p2, prev2_wd) && \
+	 word_matches_cs(p3, prev3_wd) && \
+	 word_matches_cs(p4, prev4_wd))
 
 	/*
 	 * Macros for matching N words beginning at the start of the line,
@@ -1459,17 +1475,7 @@ psql_completion(const char *text, int start, int end)
 
 	/* ALTER something */
 	else if (Matches1("ALTER"))
-	{
-		static const char *const list_ALTER[] =
-		{"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
-			"EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
-			"GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR",
-			"POLICY", "PUBLICATION", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE",
-			"SUBSCRIPTION", "SYSTEM", "TABLE", "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
-		"USER", "USER MAPPING FOR", "VIEW", NULL};
-
-		COMPLETE_WITH_LIST(list_ALTER);
-	}
+		matches = completion_matches(text, alter_command_generator);
 	/* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx */
 	else if (TailMatches4("ALL", "IN", "TABLESPACE", MatchAny))
 		COMPLETE_WITH_LIST2("SET TABLESPACE", "OWNED BY");
@@ -3353,8 +3359,41 @@ psql_completion(const char *text, int start, int end)
 
 	else if (TailMatchesCS1("\\encoding"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
-	else if (TailMatchesCS1("\\h") || TailMatchesCS1("\\help"))
+	else if (TailMatchesCS1("\\h|\\help"))
 		COMPLETE_WITH_LIST(sql_commands);
+	else if (TailMatchesCS2("\\h|\\help", MatchAny))
+	{
+		if (TailMatches1("DROP"))
+			matches = completion_matches(text, drop_command_generator);
+		else if (TailMatches1("ALTER"))
+			matches = completion_matches(text, alter_command_generator);
+	}
+	else if (TailMatchesCS3("\\h|\\help", MatchAny, MatchAny))
+	{
+		if (TailMatches2("DROP", "ACCESS"))
+			COMPLETE_WITH_CONST("METHOD");
+		else if (TailMatches2("ALTER", "DEFAULT"))
+			COMPLETE_WITH_CONST("PRIVILEGES");
+		else if (TailMatches2("ALTER|DROP", "EVENT"))
+			COMPLETE_WITH_CONST("TRIGGER");
+		else if (TailMatches2("ALTER|DROP", "FOREIGN"))
+			COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
+		else if (TailMatches2("ALTER", "LARGE"))
+			COMPLETE_WITH_CONST("OBJECT");
+		else if (TailMatches2("ALTER|DROP", "MATERIALIZED"))
+			COMPLETE_WITH_CONST("VIEW");
+		else if (TailMatches2("ALTER|DROP", "TEXT"))
+			COMPLETE_WITH_CONST("SEARCH");
+		else if (TailMatches2("ALTER|DROP", "USER"))
+			COMPLETE_WITH_CONST("MAPPING FOR");
+	}
+	else if (TailMatchesCS4("\\h|\\help", MatchAny, MatchAny, MatchAny))
+	{
+		if (TailMatches3("ALTER|DROP", "FOREIGN", "DATA"))
+			COMPLETE_WITH_CONST("WRAPPER");
+		else if (TailMatches3("ALTER|DROP", "USER", "MAPPING"))
+			COMPLETE_WITH_CONST("FOR");
+	}
 	else if (TailMatchesCS1("\\l*") && !TailMatchesCS1("\\lo*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_databases);
 	else if (TailMatchesCS1("\\password"))
@@ -3536,6 +3575,15 @@ drop_command_generator(const char *text, int state)
 	return create_or_drop_command_generator(text, state, THING_NO_DROP);
 }
 
+/*
+ * This function gives you a list of things you can put after an ALTER command.
+ */
+static char *
+alter_command_generator(const char *text, int state)
+{
+	return create_or_drop_command_generator(text, state, THING_NO_ALTER);
+}
+
 /* The following two functions are wrappers for _complete_from_query */
 
 static char *
#11Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Andreas Karlsson (#10)
Re: \h tab-completion

On 3/15/17 22:46, Andreas Karlsson wrote:

On 03/01/2017 02:47 PM, Peter Eisentraut wrote:

Instead of creating another copy of list_ALTER, let's use the
words_after_create list and write a version of
create_command_generator/drop_command_generator.

Good idea. Here is a patch with that.

Committed with some tweaking.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Andreas Karlsson
andreas@proxel.se
In reply to: Peter Eisentraut (#11)
Re: \h tab-completion

On 03/17/2017 12:01 AM, Peter Eisentraut wrote:

Committed with some tweaking.

Thanks!

Andreas

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers