On Wed, 17 Sep 2025 12:53:10 -0700 Masahiko Sawada <[email protected]> wrote:
> On Fri, Jul 18, 2025 at 12:49 AM Yugo Nagata <[email protected]> wrote: > > > > On Thu, 17 Jul 2025 10:57:36 +0900 > > Yugo Nagata <[email protected]> wrote: > > > > > On Tue, 17 Jun 2025 00:08:32 +0900 > > > Yugo Nagata <[email protected]> wrote: > > > > > > > On Thu, 5 Jun 2025 16:52:00 +0900 > > > > Yugo Nagata <[email protected]> wrote: > > > > > > > > > On Thu, 5 Jun 2025 10:08:35 +0900 > > > > > Yugo Nagata <[email protected]> wrote: > > > > > > > > > > > Hi, > > > > > > > > > > > > Currently, tab completion for COPY only suggests filenames after TO > > > > > > or > > > > > > FROM, even though STDIN, STDOUT, and PROGRAM are also valid syntax > > > > > > options. > > > > > > > > > > > > I'd like to propose improving the tab completion behavior as > > > > > > described in > > > > > > the subject, so that these keywords are suggested appropriately, > > > > > > and filenames > > > > > > are offered as potential command names after the PROGRAM keyword. > > > > > > > > > > > > I've attached this proposal as a patch series with the following > > > > > > three parts: > > > > > > > > > > I'm sorry but the previous patches were accidentally broken and > > > > > didn't work. > > > > > I've attached fixed patches. > > > > > > > > > > > > > > > > > 0001: Refactor match_previous_words() to remove direct use of > > > > > > rl_completion_matches() > > > > > > > > > > > > This is a preparatory cleanup. Most completions in > > > > > > match_previous_words() already use > > > > > > COMPLETE_WITH* macros, which wrap rl_completion_matches(). However, > > > > > > some direct calls > > > > > > still remain. > > > > > > > > > > > > This patch replaces the remaining direct calls with > > > > > > COMPLETE_WITH_FILES or > > > > > > COMPLETE_WITH_GENERATOR, improving consistency and readability. > > > > > > > > > > > > 0002: Add tab completion support for COPY ... TO/FROM STDIN, > > > > > > STDOUT, and PROGRAM > > > > > > > > > > > > This is the main patch. It extends tab completion to suggest STDIN, > > > > > > STDOUT, and PROGRAM > > > > > > after TO or FROM. After PROGRAM, filenames are suggested as > > > > > > possible command names. > > > > > > > > > > > > To support this, a new macro COMPLETE_WITH_FILES_PLUS is > > > > > > introduced. This allows > > > > > > combining literal keywords with filename suggestions in the > > > > > > completion list. > > > > > > > > > > > > 0003: Improve tab completion for COPY option lists > > > > > > > > > > > > Currently, only the first option in a parenthesized list is > > > > > > suggested during completion, > > > > > > and nothing is suggested after a comma. > > > > > > > > > > > > This patch enables suggestions after each comma, improving > > > > > > usability when specifying > > > > > > multiple options. > > > > > > > > > > > > Although not directly related to the main proposal, I believe this > > > > > > is a helpful enhancement > > > > > > to COPY tab completion and included it here for completeness. > > > > > > > > > > > > I’d appreciate your review and feedback on this series. > > > > The previous patch was broken failed to complie since I missed following > > the required format of if-conditions in match_previous_words(). > > I've attached update patches. > > > > I agree with the basic direction of the patches. Here are some > comments on the first two patches: Thank you for reviewing it. I've attached an updated patch. > > v5-0001-Refactor-match_previous_words-to-remove-direct-us.patch: > > --- > +#define COMPLETE_WITH_GENERATOR(function) \ > + matches = rl_completion_matches(text, function) > > I think it would be clearer if we use 'generator' or 'genfunc' instead > of 'function' as a macro argument. I fixed it to use 'generator'. > > v5-0002-Add-tab-completion-support-for-COPY-.-TO-FROM-STD.patch: > > --- > + /* Complete COPY|\copy <sth> FROM|TO PROGRAM command */ > + else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", "PROGRAM")) > + COMPLETE_WITH_FILES("", HeadMatches("COPY")); /* > COPY requires quoted filename */ > > Why does it complete the query with files names even after 'PROGRAM'? Users can specify the command by giving a filename with an absolute or relative path, so I think it makes sense to allow filename completion after PROGRAM. > --- > +static char * > +_complete_from_files(const char *text, int state) > { > > I think the comments of complete_from_files() should be moved to this > new function. For instance, the comments starts with: > > * This function wraps rl_filename_completion_function() to strip quotes from > * the input before searching for matches and to quote any matches for which > * the consuming command will require it. > > But complete_from_files() function no longer calls > rl_filename_completion_function(). I moved the comments to the top of _complete_from_files() and added a new comment for complete_from_files() to describe that it is a wrapper of the former. > --- > - /* Complete COPY <sth> FROM <sth> */ > - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny)) > + /* Complete COPY <sth> FROM [PROGRAM] <sth> */ > + else if (Matches("COPY|\\copy", MatchAny, "FROM", > MatchAnyExcept("PROGRAM")) || > + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny)) > > I see this kind of conversion many places in the patch; convert one > condition with MatchAny into two conditions with > MatchAnyExcept("PROGRAM") and '"PROGRAM", MatchAny'. How about > simplifying it using MatchAnyN. For example, > > else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, MatchAnyN)) We could simplify this by using MatchAnyN, but doing so would cause "WITH (" or "WHERE" to be suggested after "WITH (...)", even though that is not allowed by the syntax. This could be misleading for users, so I wonder whether it is worth adding a bit of complexity to prevent possible confusion. Regards, Yugo Nagata -- Yugo Nagata <[email protected]>
>From 8f99014ee3ca852c61406e9799a8752690dd1454 Mon Sep 17 00:00:00 2001 From: Yugo Nagata <[email protected]> Date: Thu, 5 Jun 2025 09:39:09 +0900 Subject: [PATCH v6 3/3] Improve tab completion for COPY option lists Previously, only the first option in a parenthesized list was suggested during tab completion. Subsequent options after a comma were not completed. This commit enhances the behavior to suggest valid options after each comma. --- src/bin/psql/tab-complete.in.c | 53 +++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index a8041401b8b..0cc2c6e516b 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -3361,30 +3361,35 @@ match_previous_words(int pattern_id, Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny)) COMPLETE_WITH("WITH (", "WHERE"); - /* Complete COPY <sth> FROM [PROGRAM] filename WITH ( */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(") || - Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(")) - COMPLETE_WITH(Copy_from_options); - - /* Complete COPY <sth> TO [PROGRAM] filename WITH ( */ - else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAnyExcept("PROGRAM"), "WITH", "(") || - Matches("COPY|\\copy", MatchAny, "TO", "PROGRAM", MatchAny, "WITH", "(")) - COMPLETE_WITH(Copy_to_options); - - /* Complete COPY <sth> FROM|TO [PROGRAM] <sth> WITH (FORMAT */ - else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAnyExcept("PROGRAM"), "WITH", "(", "FORMAT") || - Matches("COPY|\\copy", MatchAny, "FROM|TO", "PROGRAM", MatchAny, "WITH", "(", "FORMAT")) - COMPLETE_WITH("binary", "csv", "text"); - - /* Complete COPY <sth> FROM [PROGRAM] filename WITH (ON_ERROR */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(", "ON_ERROR") || - Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(", "ON_ERROR")) - COMPLETE_WITH("stop", "ignore"); - - /* Complete COPY <sth> FROM [PROGRAM] filename WITH (LOG_VERBOSITY */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(", "LOG_VERBOSITY") || - Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(", "LOG_VERBOSITY")) - COMPLETE_WITH("silent", "default", "verbose"); + /* Complete COPY <sth> FROM|TO [PROGRAM] filename WITH ( */ + else if (HeadMatches("COPY|\\copy", MatchAny, "FROM|TO", MatchAnyExcept("PROGRAM"), "WITH", "(") || + HeadMatches("COPY|\\copy", MatchAny, "FROM|TO", "PROGRAM", MatchAny, "WITH", "(")) + { + if (!HeadMatches("COPY|\\copy", MatchAny, "FROM|TO", MatchAnyExcept("PROGRAM"), "WITH", "(*)") && + !HeadMatches("COPY|\\copy", MatchAny, "FROM|TO", "PROGRAM", MatchAny, "WITH", "(*)")) + { + /* We're in an unfinished parenthesized option list. */ + if (ends_with(prev_wd, '(') || ends_with(prev_wd, ',')) + { + if (HeadMatches("COPY|\\copy", MatchAny, "FROM")) + COMPLETE_WITH(Copy_from_options); + else + COMPLETE_WITH(Copy_to_options); + } + + /* Complete COPY <sth> FROM|TO filename WITH (FORMAT */ + else if (TailMatches("FORMAT")) + COMPLETE_WITH("binary", "csv", "text"); + + /* Complete COPY <sth> FROM filename WITH (ON_ERROR */ + else if (TailMatches("ON_ERROR")) + COMPLETE_WITH("stop", "ignore"); + + /* Complete COPY <sth> FROM filename WITH (LOG_VERBOSITY */ + else if (TailMatches("LOG_VERBOSITY")) + COMPLETE_WITH("silent", "default", "verbose"); + } + } /* Complete COPY <sth> FROM [PROGRAM] <sth> WITH (<options>) */ else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", MatchAny) || -- 2.43.0
>From df49bba655d94b850fc8b2a1e946e8efcd874d37 Mon Sep 17 00:00:00 2001 From: Yugo Nagata <[email protected]> Date: Thu, 5 Jun 2025 09:39:24 +0900 Subject: [PATCH v6 2/3] Add tab completion support for COPY ... TO/FROM STDIN, STDOUT, and PROGRAM Previously, tab completion for COPY only suggested filenames after TO or FROM, even though STDIN, STDOUT, and PROGRAM are also valid options. This commit extends the completion to include these keywords. After PROGRAM, filename suggestions are shown as potential command names. To support this, a new macro COMPLETE_WITH_FILES_PLUS is introduced, allowing both literal keywords and filenames to be included in the completion results. --- src/bin/psql/tab-complete.in.c | 125 ++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 24 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 6176741d20b..a8041401b8b 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -443,13 +443,23 @@ do { \ matches = rl_completion_matches(text, complete_from_schema_query); \ } while (0) -#define COMPLETE_WITH_FILES(escape, force_quote) \ +#define COMPLETE_WITH_FILES_LIST(escape, force_quote, list) \ do { \ completion_charp = escape; \ + completion_charpp = list; \ completion_force_quote = force_quote; \ matches = rl_completion_matches(text, complete_from_files); \ } while (0) +#define COMPLETE_WITH_FILES(escape, force_quote) \ + COMPLETE_WITH_FILES_LIST(escape, force_quote, NULL) + +#define COMPLETE_WITH_FILES_PLUS(escape, force_quote, ...) \ +do { \ + static const char *const list[] = { __VA_ARGS__, NULL }; \ + COMPLETE_WITH_FILES_LIST(escape, force_quote, list); \ +} while (0) + #define COMPLETE_WITH_GENERATOR(generator) \ matches = rl_completion_matches(text, generator) @@ -1484,6 +1494,7 @@ static void append_variable_names(char ***varnames, int *nvars, static char **complete_from_variables(const char *text, const char *prefix, const char *suffix, bool need_value); static char *complete_from_files(const char *text, int state); +static char *_complete_from_files(const char *text, int state); static char *pg_strdup_keyword_case(const char *s, const char *ref); static char *escape_string(const char *text); @@ -3324,42 +3335,60 @@ match_previous_words(int pattern_id, /* Complete COPY <sth> */ else if (Matches("COPY|\\copy", MatchAny)) COMPLETE_WITH("FROM", "TO"); - /* Complete COPY <sth> FROM|TO with filename */ - else if (Matches("COPY", MatchAny, "FROM|TO")) - COMPLETE_WITH_FILES("", true); /* COPY requires quoted filename */ - else if (Matches("\\copy", MatchAny, "FROM|TO")) - COMPLETE_WITH_FILES("", false); - - /* Complete COPY <sth> TO <sth> */ - else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAny)) + /* Complete COPY|\copy <sth> FROM|TO with filename or STDIN/STDOUT/PROGRAM */ + else if (Matches("COPY|\\copy", MatchAny, "FROM|TO")) + { + /* COPY requires quoted filename */ + bool force_quote = HeadMatches("COPY"); + + if (TailMatches("FROM")) + COMPLETE_WITH_FILES_PLUS("", force_quote, "STDIN", "PROGRAM"); + else + COMPLETE_WITH_FILES_PLUS("", force_quote, "STDOUT", "PROGRAM"); + } + + /* Complete COPY|\copy <sth> FROM|TO PROGRAM command */ + else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", "PROGRAM")) + COMPLETE_WITH_FILES("", HeadMatches("COPY")); /* COPY requires quoted filename */ + + /* Complete COPY <sth> TO [PROGRAM] <sth> */ + else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAnyExcept("PROGRAM")) || + Matches("COPY|\\copy", MatchAny, "TO", "PROGRAM", MatchAny)) COMPLETE_WITH("WITH ("); - /* Complete COPY <sth> FROM <sth> */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny)) + /* Complete COPY <sth> FROM [PROGRAM] <sth> */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM")) || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny)) COMPLETE_WITH("WITH (", "WHERE"); - /* Complete COPY <sth> FROM filename WITH ( */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", "(")) + /* Complete COPY <sth> FROM [PROGRAM] filename WITH ( */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(") || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(")) COMPLETE_WITH(Copy_from_options); - /* Complete COPY <sth> TO filename WITH ( */ - else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAny, "WITH", "(")) + /* Complete COPY <sth> TO [PROGRAM] filename WITH ( */ + else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAnyExcept("PROGRAM"), "WITH", "(") || + Matches("COPY|\\copy", MatchAny, "TO", "PROGRAM", MatchAny, "WITH", "(")) COMPLETE_WITH(Copy_to_options); - /* Complete COPY <sth> FROM|TO filename WITH (FORMAT */ - else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "(", "FORMAT")) + /* Complete COPY <sth> FROM|TO [PROGRAM] <sth> WITH (FORMAT */ + else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAnyExcept("PROGRAM"), "WITH", "(", "FORMAT") || + Matches("COPY|\\copy", MatchAny, "FROM|TO", "PROGRAM", MatchAny, "WITH", "(", "FORMAT")) COMPLETE_WITH("binary", "csv", "text"); - /* Complete COPY <sth> FROM filename WITH (ON_ERROR */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", "(", "ON_ERROR")) + /* Complete COPY <sth> FROM [PROGRAM] filename WITH (ON_ERROR */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(", "ON_ERROR") || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(", "ON_ERROR")) COMPLETE_WITH("stop", "ignore"); - /* Complete COPY <sth> FROM filename WITH (LOG_VERBOSITY */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", "(", "LOG_VERBOSITY")) + /* Complete COPY <sth> FROM [PROGRAM] filename WITH (LOG_VERBOSITY */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(", "LOG_VERBOSITY") || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(", "LOG_VERBOSITY")) COMPLETE_WITH("silent", "default", "verbose"); - /* Complete COPY <sth> FROM <sth> WITH (<options>) */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", MatchAny)) + /* Complete COPY <sth> FROM [PROGRAM] <sth> WITH (<options>) */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", MatchAny) || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", MatchAny)) COMPLETE_WITH("WHERE"); /* CREATE ACCESS METHOD */ @@ -6241,6 +6270,54 @@ complete_from_variables(const char *text, const char *prefix, const char *suffix } +/* + * This function wraps _complete_from_files() so that both literal keywords + * and filenames can be included in the completion results. + * + * If completion_charpp is set to a null-terminated array of literal keywords, + * those keywords are added to the completion results alongside filenames, + * as long as they case-insensitively match the current input. + */ +static char * +complete_from_files(const char *text, int state) +{ + char *result; + static int list_index; + static bool files_done; + const char *item; + + /* Initialization */ + if (state == 0) + { + list_index = 0; + files_done = false; + } + + /* Return a filename that matches */ + if (!files_done && (result = _complete_from_files(text, state))) + return result; + else if (!completion_charpp) + return NULL; + else + files_done = true; + + /* + * If there are no more matching files, check for hard-wired keywords. + * These will only be returned if they match the input-so-far, + * ignoring case. + */ + while ((item = completion_charpp[list_index++])) + { + if (pg_strncasecmp(text, item, strlen(text)) == 0) + { + completion_force_quote = false; + return pg_strdup_keyword_case(item, text); + } + } + + return NULL; +} + /* * This function wraps rl_filename_completion_function() to strip quotes from * the input before searching for matches and to quote any matches for which @@ -6255,7 +6332,7 @@ complete_from_variables(const char *text, const char *prefix, const char *suffix * quotes around the result. (The SQL COPY command requires that.) */ static char * -complete_from_files(const char *text, int state) +_complete_from_files(const char *text, int state) { #ifdef USE_FILENAME_QUOTING_FUNCTIONS -- 2.43.0
>From 5ce0f42dd9865db8f484e733fb0e6794017f3188 Mon Sep 17 00:00:00 2001 From: Yugo Nagata <[email protected]> Date: Thu, 5 Jun 2025 09:38:45 +0900 Subject: [PATCH v6 1/3] Refactor match_previous_words() to remove direct use of rl_completion_matches() Most tab completions in match_previous_words() use COMPLETE_WITH* macros, which wrap rl_completion_matches(). However, some direct calls to rl_completion_matches() still remained. This commit replaces the remaining direct calls with the new macro, COMPLETE_WITH_FILES or COMPLETE_WITH_GENERATOR, for improved consistency and readability. --- src/bin/psql/tab-complete.in.c | 38 ++++++++++++++++------------------ 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 6b20a4404b2..6176741d20b 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -443,6 +443,16 @@ do { \ matches = rl_completion_matches(text, complete_from_schema_query); \ } while (0) +#define COMPLETE_WITH_FILES(escape, force_quote) \ +do { \ + completion_charp = escape; \ + completion_force_quote = force_quote; \ + matches = rl_completion_matches(text, complete_from_files); \ +} while (0) + +#define COMPLETE_WITH_GENERATOR(generator) \ + matches = rl_completion_matches(text, generator) + /* * Assembly instructions for schema queries * @@ -2182,7 +2192,7 @@ match_previous_words(int pattern_id, /* for INDEX and TABLE/SEQUENCE, respectively */ "UNIQUE", "UNLOGGED"); else - matches = rl_completion_matches(text, create_command_generator); + COMPLETE_WITH_GENERATOR(create_command_generator); } /* complete with something you can create or replace */ else if (TailMatches("CREATE", "OR", "REPLACE")) @@ -2192,7 +2202,7 @@ match_previous_words(int pattern_id, /* DROP, but not DROP embedded in other commands */ /* complete with something you can drop */ else if (Matches("DROP")) - matches = rl_completion_matches(text, drop_command_generator); + COMPLETE_WITH_GENERATOR(drop_command_generator); /* ALTER */ @@ -2203,7 +2213,7 @@ match_previous_words(int pattern_id, /* ALTER something */ else if (Matches("ALTER")) - matches = rl_completion_matches(text, alter_command_generator); + COMPLETE_WITH_GENERATOR(alter_command_generator); /* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx */ else if (TailMatches("ALL", "IN", "TABLESPACE", MatchAny)) COMPLETE_WITH("SET TABLESPACE", "OWNED BY"); @@ -3316,17 +3326,9 @@ match_previous_words(int pattern_id, COMPLETE_WITH("FROM", "TO"); /* Complete COPY <sth> FROM|TO with filename */ else if (Matches("COPY", MatchAny, "FROM|TO")) - { - completion_charp = ""; - completion_force_quote = true; /* COPY requires quoted filename */ - matches = rl_completion_matches(text, complete_from_files); - } + COMPLETE_WITH_FILES("", true); /* COPY requires quoted filename */ else if (Matches("\\copy", MatchAny, "FROM|TO")) - { - completion_charp = ""; - completion_force_quote = false; - matches = rl_completion_matches(text, complete_from_files); - } + COMPLETE_WITH_FILES("", false); /* Complete COPY <sth> TO <sth> */ else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAny)) @@ -5427,9 +5429,9 @@ match_previous_words(int pattern_id, else if (TailMatchesCS("\\h|\\help", MatchAny)) { if (TailMatches("DROP")) - matches = rl_completion_matches(text, drop_command_generator); + COMPLETE_WITH_GENERATOR(drop_command_generator); else if (TailMatches("ALTER")) - matches = rl_completion_matches(text, alter_command_generator); + COMPLETE_WITH_GENERATOR(alter_command_generator); /* * CREATE is recognized by tail match elsewhere, so doesn't need to be @@ -5529,11 +5531,7 @@ match_previous_words(int pattern_id, else if (TailMatchesCS("\\cd|\\e|\\edit|\\g|\\gx|\\i|\\include|" "\\ir|\\include_relative|\\o|\\out|" "\\s|\\w|\\write|\\lo_import")) - { - completion_charp = "\\"; - completion_force_quote = false; - matches = rl_completion_matches(text, complete_from_files); - } + COMPLETE_WITH_FILES("\\", false); /* gen_tabcomplete.pl ends special processing here */ /* END GEN_TABCOMPLETE */ -- 2.43.0
