From e15c4ab5fb0de2cab393ed4be2136e1832746412 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Tue, 12 Aug 2014 11:57:39 +0900 Subject: [PATCH] Add tab-completion for \unset and valid setting values of psql variables. This commit also changes tab-completion for \set so that it displays all the special variables like COMP_KEYWORD_CASE. Previously it displayed only variables having the set values. Which was not user-friendly for those who want to set the unset variables. This commit also changes tab-completion for :variable so that only the variables having the set values are displayed. Previously even unset variables were displayed. Pavel Stehule, modified by me. --- doc/src/sgml/ref/psql-ref.sgml | 9 ++- src/bin/psql/tab-complete.c | 139 ++++++++++++++++++++++++++++----- 2 files changed, 127 insertions(+), 21 deletions(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 133390ab63..74d46183e5 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -2827,7 +2827,9 @@ bar they are sent to the server. The switch for this is . If set to errors then only failed queries are displayed on standard error output. The switch - for this is . + for this is . If unset, or if set to + none (or any other value than those above) then + no queries are displayed. @@ -2892,8 +2894,9 @@ bar list. If set to a value of ignoredups, lines matching the previous history line are not entered. A value of ignoreboth combines the two options. If - unset, or if set to any other value than those above, all lines - read in interactive mode are saved on the history list. + unset, or if set to none (or any other value + than those above), all lines read in interactive mode are + saved on the history list. diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 24e60b7609..b4f185620f 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -813,8 +813,11 @@ static char *_complete_from_query(int is_schema_query, const char *text, int state); static char *complete_from_list(const char *text, int state); static char *complete_from_const(const char *text, int state); +static void append_variable_names(char ***varnames, int *nvars, + int *maxvars, const char *varname, + const char *prefix, const char *suffix); static char **complete_from_variables(const char *text, - const char *prefix, const char *suffix); + const char *prefix, const char *suffix, bool need_value); static char *complete_from_files(const char *text, int state); static char *pg_strdup_keyword_case(const char *s, const char *ref); @@ -925,11 +928,11 @@ psql_completion(const char *text, int start, int end) else if (text[0] == ':' && text[1] != ':') { if (text[1] == '\'') - matches = complete_from_variables(text, ":'", "'"); + matches = complete_from_variables(text, ":'", "'", true); else if (text[1] == '"') - matches = complete_from_variables(text, ":\"", "\""); + matches = complete_from_variables(text, ":\"", "\"", true); else - matches = complete_from_variables(text, ":", ""); + matches = complete_from_variables(text, ":", "", true); } /* If no previous word, suggest one of the basic sql commands */ @@ -3604,9 +3607,71 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST_CS(my_list); } } + else if (strcmp(prev_wd, "\\unset") == 0) + { + matches = complete_from_variables(text, "", "", true); + } else if (strcmp(prev_wd, "\\set") == 0) { - matches = complete_from_variables(text, "", ""); + matches = complete_from_variables(text, "", "", false); + } + else if (strcmp(prev2_wd, "\\set") == 0) + { + static const char *const boolean_value_list[] = + {"on", "off", NULL}; + + if (strcmp(prev_wd, "AUTOCOMMIT") == 0) + COMPLETE_WITH_LIST_CS(boolean_value_list); + else if (strcmp(prev_wd, "COMP_KEYWORD_CASE") == 0) + { + static const char *const my_list[] = + {"lower", "upper", "preserve-lower", "preserve-upper", NULL}; + + COMPLETE_WITH_LIST_CS(my_list); + } + else if (strcmp(prev_wd, "ECHO") == 0) + { + static const char *const my_list[] = + {"errors", "queries", "all", "none", NULL}; + + COMPLETE_WITH_LIST_CS(my_list); + } + else if (strcmp(prev_wd, "ECHO_HIDDEN") == 0) + { + static const char *const my_list[] = + {"noexec", "off", "on", NULL}; + + COMPLETE_WITH_LIST_CS(my_list); + } + else if (strcmp(prev_wd, "HISTCONTROL") == 0) + { + static const char *const my_list[] = + {"ignorespace", "ignoredups", "ignoreboth", "none", NULL}; + + COMPLETE_WITH_LIST_CS(my_list); + } + else if (strcmp(prev_wd, "ON_ERROR_ROLLBACK") == 0) + { + static const char *const my_list[] = + {"on", "off", "interactive", NULL}; + + COMPLETE_WITH_LIST_CS(my_list); + } + else if (strcmp(prev_wd, "ON_ERROR_STOP") == 0) + COMPLETE_WITH_LIST_CS(boolean_value_list); + else if (strcmp(prev_wd, "QUIET") == 0) + COMPLETE_WITH_LIST_CS(boolean_value_list); + else if (strcmp(prev_wd, "SINGLELINE") == 0) + COMPLETE_WITH_LIST_CS(boolean_value_list); + else if (strcmp(prev_wd, "SINGLESTEP") == 0) + COMPLETE_WITH_LIST_CS(boolean_value_list); + else if (strcmp(prev_wd, "VERBOSITY") == 0) + { + static const char *const my_list[] = + {"default", "verbose", "terse", NULL}; + + COMPLETE_WITH_LIST_CS(my_list); + } } else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); @@ -4052,13 +4117,40 @@ complete_from_const(const char *text, int state) } +/* + * This function appends the variable name with prefix and suffix to + * the variable names array. + */ +static void +append_variable_names(char ***varnames, int *nvars, + int *maxvars, const char *varname, + const char *prefix, const char *suffix) +{ + if (*nvars >= *maxvars) + { + *maxvars *= 2; + *varnames = (char **) realloc(*varnames, + ((*maxvars) + 1) * sizeof(char *)); + if (!(*varnames)) + { + psql_error("out of memory\n"); + exit(EXIT_FAILURE); + } + } + + (*varnames)[(*nvars)++] = psprintf("%s%s%s", prefix, varname, suffix); +} + + /* * This function supports completion with the name of a psql variable. * The variable names can be prefixed and suffixed with additional text - * to support quoting usages. + * to support quoting usages. If need_value is true, only the variables + * that have the set values are picked up. */ static char ** -complete_from_variables(const char *text, const char *prefix, const char *suffix) +complete_from_variables(const char *text, const char *prefix, const char *suffix, + bool need_value) { char **matches; char **varnames; @@ -4067,23 +4159,34 @@ complete_from_variables(const char *text, const char *prefix, const char *suffix int i; struct _variable *ptr; + static const char *const known_varnames[] = { + "AUTOCOMMIT", "COMP_KEYWORD_CASE", "DBNAME", "ECHO", "ECHO_HIDDEN", + "ENCODING", "FETCH_COUNT", "HISTCONTROL", "HISTFILE", "HISTSIZE", + "HOST", "IGNOREEOF", "LASTOID", "ON_ERROR_ROLLBACK", "ON_ERROR_STOP", + "PORT", "PROMPT1", "PROMPT2", "PROMPT3", "QUIET", "SINGLELINE", + "SINGLESTEP", "USER", "VERBOSITY", NULL + }; + varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *)); + if (!need_value) + { + for (i = 0; known_varnames[i] && nvars < maxvars; i++) + append_variable_names(&varnames, &nvars, &maxvars, + known_varnames[i], prefix, suffix); + } + for (ptr = pset.vars->next; ptr; ptr = ptr->next) { - if (nvars >= maxvars) + if (need_value && !(ptr->value)) + continue; + for (i = 0; known_varnames[i]; i++) /* remove duplicate entry */ { - maxvars *= 2; - varnames = (char **) realloc(varnames, - (maxvars + 1) * sizeof(char *)); - if (!varnames) - { - psql_error("out of memory\n"); - exit(EXIT_FAILURE); - } + if (strcmp(ptr->name, known_varnames[i]) == 0) + continue; } - - varnames[nvars++] = psprintf("%s%s%s", prefix, ptr->name, suffix); + append_variable_names(&varnames, &nvars, &maxvars, ptr->name, + prefix, suffix); } varnames[nvars] = NULL;