Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d7d77f3

Browse files
committed
psql: Add completion for \help DROP|ALTER
While \help CREATE would complete usefully, \help DROP or \help ALTER did not complete anything. Expand the list of things after CREATE and DROP to cover ALTER as well, and use that for the ALTER completion. Also make minor tweaks to that list. Also add support for completing \help on multiword commands like CREATE TEXT SEARCH ... Author: Andreas Karlsson <andreas@proxel.se>
1 parent 1914c5e commit d7d77f3

File tree

1 file changed

+74
-19
lines changed

1 file changed

+74
-19
lines changed

src/bin/psql/tab-complete.c

+74-19
Original file line numberDiff line numberDiff line change
@@ -982,10 +982,11 @@ typedef struct
982982

983983
#define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
984984
#define THING_NO_DROP (1 << 1) /* should not show up after DROP */
985-
#define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
985+
#define THING_NO_ALTER (1 << 2) /* should not show up after ALTER */
986+
#define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP | THING_NO_ALTER)
986987

987988
static const pgsql_thing_t words_after_create[] = {
988-
{"ACCESS METHOD", NULL, NULL},
989+
{"ACCESS METHOD", NULL, NULL, THING_NO_ALTER},
989990
{"AGGREGATE", NULL, &Query_for_list_of_aggregates},
990991
{"CAST", NULL, NULL}, /* Casts have complex structures for names, so
991992
* skip it */
@@ -999,19 +1000,21 @@ static const pgsql_thing_t words_after_create[] = {
9991000
{"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
10001001
{"DATABASE", Query_for_list_of_databases},
10011002
{"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
1003+
{"DEFAULT PRIVILEGES", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
10021004
{"DOMAIN", NULL, &Query_for_list_of_domains},
10031005
{"EVENT TRIGGER", NULL, NULL},
10041006
{"EXTENSION", Query_for_list_of_extensions},
10051007
{"FOREIGN DATA WRAPPER", NULL, NULL},
10061008
{"FOREIGN TABLE", NULL, NULL},
10071009
{"FUNCTION", NULL, &Query_for_list_of_functions},
10081010
{"GROUP", Query_for_list_of_roles},
1009-
{"LANGUAGE", Query_for_list_of_languages},
10101011
{"INDEX", NULL, &Query_for_list_of_indexes},
1012+
{"LANGUAGE", Query_for_list_of_languages},
1013+
{"LARGE OBJECT", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
10111014
{"MATERIALIZED VIEW", NULL, &Query_for_list_of_matviews},
10121015
{"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
10131016
* good idea. */
1014-
{"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */
1017+
{"OWNED", NULL, NULL, THING_NO_CREATE | THING_NO_ALTER}, /* for DROP OWNED BY ... */
10151018
{"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
10161019
{"POLICY", NULL, NULL},
10171020
{"PUBLICATION", Query_for_list_of_publications},
@@ -1021,15 +1024,18 @@ static const pgsql_thing_t words_after_create[] = {
10211024
{"SEQUENCE", NULL, &Query_for_list_of_sequences},
10221025
{"SERVER", Query_for_list_of_servers},
10231026
{"SUBSCRIPTION", Query_for_list_of_subscriptions},
1027+
{"SYSTEM", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
10241028
{"TABLE", NULL, &Query_for_list_of_tables},
10251029
{"TABLESPACE", Query_for_list_of_tablespaces},
1026-
{"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
1030+
{"TEMP", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE TEMP TABLE ... */
10271031
{"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
1032+
{"TEMPORARY", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE TEMPORARY TABLE ... */
10281033
{"TEXT SEARCH", NULL, NULL},
1034+
{"TRANSFORM", NULL, NULL},
10291035
{"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"},
10301036
{"TYPE", NULL, &Query_for_list_of_datatypes},
1031-
{"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
1032-
{"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE
1037+
{"UNIQUE", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE UNIQUE INDEX ... */
1038+
{"UNLOGGED", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE UNLOGGED TABLE
10331039
* ... */
10341040
{"USER", Query_for_list_of_roles},
10351041
{"USER MAPPING FOR", NULL, NULL},
@@ -1042,6 +1048,7 @@ static const pgsql_thing_t words_after_create[] = {
10421048
static char **psql_completion(const char *text, int start, int end);
10431049
static char *create_command_generator(const char *text, int state);
10441050
static char *drop_command_generator(const char *text, int state);
1051+
static char *alter_command_generator(const char *text, int state);
10451052
static char *complete_from_query(const char *text, int state);
10461053
static char *complete_from_schema_query(const char *text, int state);
10471054
static char *_complete_from_query(int is_schema_query,
@@ -1316,6 +1323,17 @@ psql_completion(const char *text, int start, int end)
13161323
(previous_words_count >= 2 && \
13171324
word_matches_cs(p1, prev_wd) && \
13181325
word_matches_cs(p2, prev2_wd))
1326+
#define TailMatchesCS3(p3, p2, p1) \
1327+
(previous_words_count >= 3 && \
1328+
word_matches_cs(p1, prev_wd) && \
1329+
word_matches_cs(p2, prev2_wd) && \
1330+
word_matches_cs(p3, prev3_wd))
1331+
#define TailMatchesCS4(p4, p3, p2, p1) \
1332+
(previous_words_count >= 4 && \
1333+
word_matches_cs(p1, prev_wd) && \
1334+
word_matches_cs(p2, prev2_wd) && \
1335+
word_matches_cs(p3, prev3_wd) && \
1336+
word_matches_cs(p4, prev4_wd))
13191337

13201338
/*
13211339
* Macros for matching N words beginning at the start of the line,
@@ -1459,17 +1477,7 @@ psql_completion(const char *text, int start, int end)
14591477

14601478
/* ALTER something */
14611479
else if (Matches1("ALTER"))
1462-
{
1463-
static const char *const list_ALTER[] =
1464-
{"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
1465-
"EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
1466-
"GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR",
1467-
"POLICY", "PUBLICATION", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE",
1468-
"SUBSCRIPTION", "SYSTEM", "TABLE", "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
1469-
"USER", "USER MAPPING FOR", "VIEW", NULL};
1470-
1471-
COMPLETE_WITH_LIST(list_ALTER);
1472-
}
1480+
matches = completion_matches(text, alter_command_generator);
14731481
/* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx */
14741482
else if (TailMatches4("ALL", "IN", "TABLESPACE", MatchAny))
14751483
COMPLETE_WITH_LIST2("SET TABLESPACE", "OWNED BY");
@@ -2622,6 +2630,7 @@ psql_completion(const char *text, int start, int end)
26222630
else if (Matches3("DROP", "OWNED", "BY"))
26232631
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
26242632

2633+
/* DROP TEXT SEARCH */
26252634
else if (Matches3("DROP", "TEXT", "SEARCH"))
26262635
COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
26272636

@@ -3353,8 +3362,45 @@ psql_completion(const char *text, int start, int end)
33533362

33543363
else if (TailMatchesCS1("\\encoding"))
33553364
COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
3356-
else if (TailMatchesCS1("\\h") || TailMatchesCS1("\\help"))
3365+
else if (TailMatchesCS1("\\h|\\help"))
33573366
COMPLETE_WITH_LIST(sql_commands);
3367+
else if (TailMatchesCS2("\\h|\\help", MatchAny))
3368+
{
3369+
if (TailMatches1("DROP"))
3370+
matches = completion_matches(text, drop_command_generator);
3371+
else if (TailMatches1("ALTER"))
3372+
matches = completion_matches(text, alter_command_generator);
3373+
/* CREATE is recognized by tail match elsewhere, so doesn't need to be
3374+
* repeated here */
3375+
}
3376+
else if (TailMatchesCS3("\\h|\\help", MatchAny, MatchAny))
3377+
{
3378+
if (TailMatches2("CREATE|DROP", "ACCESS"))
3379+
COMPLETE_WITH_CONST("METHOD");
3380+
else if (TailMatches2("ALTER", "DEFAULT"))
3381+
COMPLETE_WITH_CONST("PRIVILEGES");
3382+
else if (TailMatches2("CREATE|ALTER|DROP", "EVENT"))
3383+
COMPLETE_WITH_CONST("TRIGGER");
3384+
else if (TailMatches2("CREATE|ALTER|DROP", "FOREIGN"))
3385+
COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
3386+
else if (TailMatches2("ALTER", "LARGE"))
3387+
COMPLETE_WITH_CONST("OBJECT");
3388+
else if (TailMatches2("CREATE|ALTER|DROP", "MATERIALIZED"))
3389+
COMPLETE_WITH_CONST("VIEW");
3390+
else if (TailMatches2("CREATE|ALTER|DROP", "TEXT"))
3391+
COMPLETE_WITH_CONST("SEARCH");
3392+
else if (TailMatches2("CREATE|ALTER|DROP", "USER"))
3393+
COMPLETE_WITH_CONST("MAPPING FOR");
3394+
}
3395+
else if (TailMatchesCS4("\\h|\\help", MatchAny, MatchAny, MatchAny))
3396+
{
3397+
if (TailMatches3("CREATE|ALTER|DROP", "FOREIGN", "DATA"))
3398+
COMPLETE_WITH_CONST("WRAPPER");
3399+
else if (TailMatches3("CREATE|ALTER|DROP", "TEXT", "SEARCH"))
3400+
COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
3401+
else if (TailMatches3("CREATE|ALTER|DROP", "USER", "MAPPING"))
3402+
COMPLETE_WITH_CONST("FOR");
3403+
}
33583404
else if (TailMatchesCS1("\\l*") && !TailMatchesCS1("\\lo*"))
33593405
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
33603406
else if (TailMatchesCS1("\\password"))
@@ -3536,6 +3582,15 @@ drop_command_generator(const char *text, int state)
35363582
return create_or_drop_command_generator(text, state, THING_NO_DROP);
35373583
}
35383584

3585+
/*
3586+
* This function gives you a list of things you can put after an ALTER command.
3587+
*/
3588+
static char *
3589+
alter_command_generator(const char *text, int state)
3590+
{
3591+
return create_or_drop_command_generator(text, state, THING_NO_ALTER);
3592+
}
3593+
35393594
/* The following two functions are wrappers for _complete_from_query */
35403595

35413596
static char *

0 commit comments

Comments
 (0)