Skip to content

Commit 020258f

Browse files
committed
Treat case of tab-completion keywords a bit more carefully.
When completing keywords that are offered alongside names obtained from a query, preserve the user's choice of keyword case. This would have been messy to do before 02b8048, but now it's fairly simple. A complication is that we want keywords to be shown in upper case in any tab-completion menus that include both keywords and non-keywords, so we can't switch their case until enough has been typed that only keyword(s) remain to be chosen. Also, adjust some places where 02b8048 thoughtlessly held over a previous choice to display keywords in lower case. (I think I got confused as to whether those words were keywords or variable names, but they're the former.) Dagfinn Ilmari Mannsåker and Tom Lane Discussion: https://postgr.es/m/8735l41ynm.fsf@wibble.ilmari.org
1 parent a5a9d77 commit 020258f

File tree

2 files changed

+62
-29
lines changed

2 files changed

+62
-29
lines changed

src/bin/psql/t/010_tab_completion.pl

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
# set up a few database objects
4242
$node->safe_psql('postgres',
43-
"CREATE TABLE tab1 (f1 int primary key, f2 text);\n"
43+
"CREATE TABLE tab1 (c1 int primary key, c2 text);\n"
4444
. "CREATE TABLE mytab123 (f1 int, f2 text);\n"
4545
. "CREATE TABLE mytab246 (f1 int, f2 text);\n"
4646
. "CREATE TABLE \"mixedName\" (f1 int, f2 text);\n"
@@ -317,14 +317,30 @@ sub clear_line
317317

318318
clear_line();
319319

320-
# check completion of a keyword offered in addition to object names
321-
# (that code path currently doesn't preserve case of what's typed)
322-
check_completion(
323-
"comment on constraint foo on dom\t",
324-
qr|DOMAIN|,
325-
"offer keyword in addition to query result");
326-
327-
clear_query();
320+
# check completion of a keyword offered in addition to object names;
321+
# such a keyword should obey COMP_KEYWORD_CASE once only keyword
322+
# completions are possible
323+
foreach (
324+
[ 'lower', 'CO', 'column' ],
325+
[ 'upper', 'co', 'COLUMN' ],
326+
[ 'preserve-lower', 'co', 'column' ],
327+
[ 'preserve-upper', 'CO', 'COLUMN' ],)
328+
{
329+
my ($case, $in, $out) = @$_;
330+
331+
check_completion(
332+
"\\set COMP_KEYWORD_CASE $case\n",
333+
qr/postgres=#/,
334+
"set completion case to '$case'");
335+
check_completion("alter table tab1 rename c\t\t",
336+
qr|COLUMN|,
337+
"offer keyword COLUMN for input c<TAB>, COMP_KEYWORD_CASE = $case");
338+
clear_query();
339+
check_completion("alter table tab1 rename $in\t\t\t",
340+
qr|$out|,
341+
"offer keyword $out for input $in<TAB>, COMP_KEYWORD_CASE = $case");
342+
clear_query();
343+
}
328344

329345
# send psql an explicit \q to shut it down, else pty won't close properly
330346
$timer->start(5);

src/bin/psql/tab-complete.c

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,9 +1320,11 @@ initialize_readline(void)
13201320
rl_basic_word_break_characters = WORD_BREAKS;
13211321

13221322
/*
1323-
* We should include '"' in rl_completer_quote_characters too, but that
1324-
* will require some upgrades to how we handle quoted identifiers, so
1325-
* that's for another day.
1323+
* Ideally we'd include '"' in rl_completer_quote_characters too, which
1324+
* should allow us to complete quoted identifiers that include spaces.
1325+
* However, the library support for rl_completer_quote_characters is
1326+
* presently too inconsistent to want to mess with that. (Note in
1327+
* particular that libedit has this variable but completely ignores it.)
13261328
*/
13271329
rl_completer_quote_characters = "'";
13281330

@@ -2059,7 +2061,7 @@ psql_completion(const char *text, int start, int end)
20592061
COMPLETE_WITH("SET", "RESET");
20602062
else if (Matches("ALTER", "SYSTEM", "SET|RESET"))
20612063
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_alter_system_set_vars,
2062-
"all");
2064+
"ALL");
20632065
else if (Matches("ALTER", "SYSTEM", "SET", MatchAny))
20642066
COMPLETE_WITH("TO");
20652067
/* ALTER VIEW <name> */
@@ -4039,16 +4041,18 @@ psql_completion(const char *text, int start, int end)
40394041
/* Complete with a variable name */
40404042
else if (TailMatches("SET|RESET") && !TailMatches("UPDATE", MatchAny, "SET"))
40414043
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_set_vars,
4042-
"constraints",
4043-
"transaction",
4044-
"session",
4045-
"role",
4046-
"tablespace",
4047-
"all");
4044+
"CONSTRAINTS",
4045+
"TRANSACTION",
4046+
"SESSION",
4047+
"ROLE",
4048+
"TABLESPACE",
4049+
"ALL");
40484050
else if (Matches("SHOW"))
40494051
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_show_vars,
4050-
"session authorization",
4051-
"all");
4052+
"SESSION AUTHORIZATION",
4053+
"ALL");
4054+
else if (Matches("SHOW", "SESSION"))
4055+
COMPLETE_WITH("AUTHORIZATION");
40524056
/* Complete "SET TRANSACTION" */
40534057
else if (Matches("SET", "TRANSACTION"))
40544058
COMPLETE_WITH("SNAPSHOT", "ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE");
@@ -4742,7 +4746,8 @@ _complete_from_query(const char *simple_query,
47424746
{
47434747
static int list_index,
47444748
num_schema_only,
4745-
num_other;
4749+
num_query_other,
4750+
num_keywords;
47464751
static PGresult *result = NULL;
47474752
static bool non_empty_object;
47484753
static bool schemaquoted;
@@ -4765,7 +4770,8 @@ _complete_from_query(const char *simple_query,
47654770
/* Reset static state, ensuring no memory leaks */
47664771
list_index = 0;
47674772
num_schema_only = 0;
4768-
num_other = 0;
4773+
num_query_other = 0;
4774+
num_keywords = 0;
47694775
PQclear(result);
47704776
result = NULL;
47714777

@@ -4986,7 +4992,10 @@ _complete_from_query(const char *simple_query,
49864992

49874993
/* In verbatim mode, we return all the items as-is */
49884994
if (verbatim)
4995+
{
4996+
num_query_other++;
49894997
return pg_strdup(item);
4998+
}
49904999

49915000
/*
49925001
* In normal mode, a name requiring quoting will be returned only
@@ -5007,7 +5016,7 @@ _complete_from_query(const char *simple_query,
50075016
if (item == NULL && nsp != NULL)
50085017
num_schema_only++;
50095018
else
5010-
num_other++;
5019+
num_query_other++;
50115020

50125021
return requote_identifier(nsp, item, schemaquoted, objectquoted);
50135022
}
@@ -5031,8 +5040,12 @@ _complete_from_query(const char *simple_query,
50315040
list_index++;
50325041
if (pg_strncasecmp(text, item, strlen(text)) == 0)
50335042
{
5034-
num_other++;
5035-
return pg_strdup(item);
5043+
num_keywords++;
5044+
/* Match keyword case if we are returning only keywords */
5045+
if (num_schema_only == 0 && num_query_other == 0)
5046+
return pg_strdup_keyword_case(item, text);
5047+
else
5048+
return pg_strdup(item);
50365049
}
50375050
}
50385051
}
@@ -5049,8 +5062,12 @@ _complete_from_query(const char *simple_query,
50495062
list_index++;
50505063
if (pg_strncasecmp(text, item, strlen(text)) == 0)
50515064
{
5052-
num_other++;
5053-
return pg_strdup(item);
5065+
num_keywords++;
5066+
/* Match keyword case if we are returning only keywords */
5067+
if (num_schema_only == 0 && num_query_other == 0)
5068+
return pg_strdup_keyword_case(item, text);
5069+
else
5070+
return pg_strdup(item);
50545071
}
50555072
}
50565073
}
@@ -5062,7 +5079,7 @@ _complete_from_query(const char *simple_query,
50625079
* completion subject text, which is not what we want.
50635080
*/
50645081
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
5065-
if (num_schema_only > 0 && num_other == 0)
5082+
if (num_schema_only > 0 && num_query_other == 0 && num_keywords == 0)
50665083
rl_completion_append_character = '\0';
50675084
#endif
50685085

0 commit comments

Comments
 (0)