It seems like if gnu.bash....@googlegroups.com eat the first occurrence of this email (not in the mailman archives)... second attempt:
=== Rationale: Let's say you want to complete http URL (which contain ':'). The completion probably contains this kind of statement: _comp() { COMPREPLY=( $(compgen -W "http://foo http://bar"; -- "$cur") ) } After the completion function is evaluated, readline will consider the value of $COMP_WORDBREAKS to split the word to complete... If the current argument is 'http://', then: - if $COMP_WORDBREAKS contains ':' , only '//' will be used by the completion process. - otherwise (and if ' ' (space) is part of $COMP_WORDBREAKS), the whole 'http://' string will be used. The problem is that this evaluation happens after the completion function has returned (and won't work before $COMP_WORDBREAKS has really been modified to match our needs): The FAQ says: E13) Why does filename completion misbehave if a colon appears in the filename? and the workaround proposed, ie: _comp() { export COMP_WORDBREAKS="${COMP_WORDBREAKS//:/}" COMPREPLY=( $(compgen -W "http://foo http://bar"; -- "$cur") ) } ... has mainly two drawbacks: 1) the completion has to alter the user environment $ comp http://<TAB> $ echo $COMP_WORDBREAKS "'><=;|&( ### ':' has disappeared, other completion functions ### may suffer from this 2) the first time we try a completion, _comp() has not yet been executed so our modified $COMP_WORDBREAKS isn't yet part of the context. $ comp http://<TAB> completes (the first time) to $ comp http:http:// but after that, $COMP_WORDBREAKS is modified so the next calls will succeed. === the proposed patch is in 3 parts (also attached): https://gitorious.org/drzraf/bash/commit/0994f18671dc9c080b01af9c6005a19c7edac17c Adds a char *word_breaks to the COMPSPEC struct https://gitorious.org/drzraf/bash/commit/123ba1c50078c0857c489809132cc39ab59d7636 Support of a -B <COMP_WORDBREAKS> flag to the complete builtin https://gitorious.org/drzraf/bash/commit/be1ff9edf02d7a28b1a4d18d8e996ef4ba56c490 registers readline 'rl_completion_word_break_hook' and makes the bash hook returning the value of the complete -B <flag> if it was specified during the call to the 'complete' builtin. === If the rationale of this patch is accepted, I would be happy to discuss the possibility to implement it at the 'compopt' level (what I was so far unable to do) in order to change dynamically word bounds *during* the completion process. Raph
>From 0994f18671dc9c080b01af9c6005a19c7edac17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Fri, 27 May 2011 14:55:02 +0200 Subject: [PATCH 1/3] added char *word_breaks to the COMPSPEC struct. It will allow registration of a $COMP_WORDBREAKS equivalent on a per-completion basis. --- pcomplete.h | 1 + pcomplib.c | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/pcomplete.h b/pcomplete.h index 6c1a664..31ef3cb 100644 --- a/pcomplete.h +++ b/pcomplete.h @@ -37,6 +37,7 @@ typedef struct compspec { char *command; char *lcommand; char *filterpat; + char *word_breaks; } COMPSPEC; /* Values for COMPSPEC actions. These are things the shell knows how to diff --git a/pcomplib.c b/pcomplib.c index fe337e4..5d812c7 100644 --- a/pcomplib.c +++ b/pcomplib.c @@ -64,6 +64,7 @@ compspec_create () ret->command = (char *)NULL; ret->lcommand = (char *)NULL; ret->filterpat = (char *)NULL; + ret->word_breaks = (char *)NULL; return ret; } @@ -83,6 +84,7 @@ compspec_dispose (cs) FREE (cs->command); FREE (cs->lcommand); FREE (cs->filterpat); + FREE (cs->word_breaks); free (cs); } @@ -108,6 +110,7 @@ compspec_copy (cs) new->command = STRDUP (cs->command); new->lcommand = STRDUP (cs->lcommand); new->filterpat = STRDUP (cs->filterpat); + new->word_breaks = STRDUP (cs->word_breaks); return new; } -- 1.7.3.4
>From 123ba1c50078c0857c489809132cc39ab59d7636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Fri, 27 May 2011 14:58:01 +0200 Subject: [PATCH 2/3] added support of the -B <COMP_WORDBREAKS> flag to the 'complete' builtin. It will allow registration of a $COMP_WORDBREAKS equivalent on a per-completion basis. --- builtins/complete.def | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/builtins/complete.def b/builtins/complete.def index b9f0a13..248cd05 100644 --- a/builtins/complete.def +++ b/builtins/complete.def @@ -94,7 +94,7 @@ static void print_compopts __P((const char *, COMPSPEC *, int)); static void print_all_completions __P((void)); static int print_cmd_completions __P((WORD_LIST *)); -static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg; +static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg, *Barg; static const struct _compacts { const char * const actname; @@ -193,7 +193,7 @@ build_actions (list, flagp, actp, optp) opt_given = 0; reset_internal_getopt (); - while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:DE")) != -1) + while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:B:G:W:P:S:X:F:C:DE")) != -1) { opt_given = 1; switch (opt) @@ -278,6 +278,9 @@ build_actions (list, flagp, actp, optp) } acts |= compacts[ind].actflag; break; + case 'B': + Barg = list_optarg; + break; case 'C': Carg = list_optarg; break; @@ -355,7 +358,7 @@ complete_builtin (list) opt_given = oflags.pflag = oflags.rflag = oflags.Dflag = oflags.Eflag = 0; acts = copts = (unsigned long)0L; - Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL; + Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = Barg = (char *)NULL; cs = (COMPSPEC *)NULL; /* Build the actions from the arguments. Also sets the [A-Z]arg variables @@ -423,6 +426,7 @@ complete_builtin (list) cs->funcname = STRDUP (Farg); cs->command = STRDUP (Carg); cs->filterpat = STRDUP (Xarg); + cs->word_breaks = STRDUP (Barg); for (rval = EXECUTION_SUCCESS, l = wl ? wl : list ; l; l = l->next) { -- 1.7.3.4
>From be1ff9edf02d7a28b1a4d18d8e996ef4ba56c490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+fl...@gmail.com> Date: Fri, 27 May 2011 15:00:19 +0200 Subject: [PATCH 3/3] Registered readline "rl_completion_word_break_hook" in bash under "word_break_completion_hook". If the -B flag of the 'complete' builtin has been used, its value is returned and is used by readline to split the word to complete. It allows registration of a $COMP_WORDBREAKS equivalent on a per-completion basis. Eg: It is now possible, without messing-up with $COMP_WORDBREAKS, to use the following in a completion script: _comp() { [...] COMPREPLY=( $(compgen -W "http://foo http://bar"; -- "$cur") ) return 0 } then register a completion using: $ complete -F _comp -B "${COMP_WORDBREAKS//:/}" comp --- bashline.c | 20 ++++++++++++++++++++ 1 files changed, 20 insertions(+), 0 deletions(-) diff --git a/bashline.c b/bashline.c index 59278e5..692b912 100644 --- a/bashline.c +++ b/bashline.c @@ -132,6 +132,7 @@ static void display_shell_completion_footer __P((void)); static char *variable_completion_function __P((const char *, int)); static char *hostname_completion_function __P((const char *, int)); static char *command_subst_completion_function __P((const char *, int)); +static char *word_break_completion_hook __P((void)); static void build_history_completion_array __P((void)); static char *history_completion_generator __P((const char *, int)); @@ -516,6 +517,12 @@ initialize_readline () /* Tell the filename completer we want a chance to ignore some names. */ rl_ignore_some_completions_function = filename_completion_ignore; + /* returns the break characters readline will use to split words. + Instead of using COMP_WORDBREAKS, this function uses the value specified + with the -B flag of the 'complete' builtin (or return 0 otherwise). + So there is no need to alter $COMP_WORDBREAKS in the user shell environment */ + rl_completion_word_break_hook = word_break_completion_hook; + /* Bind C-xC-e to invoke emacs and run result as commands. */ rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap); #if defined (VI_MODE) @@ -576,6 +583,7 @@ bashline_reset () rl_completion_entry_function = NULL; rl_directory_rewrite_hook = bash_directory_completion_hook; rl_ignore_some_completions_function = filename_completion_ignore; + rl_completion_word_break_hook = word_break_completion_hook; } /* Contains the line to push into readline. */ @@ -2848,6 +2856,18 @@ bash_directory_completion_hook (dirname) return (return_value); } +char *word_break_completion_hook(void) { + COMPSPEC *cs; + int start = 0; + int s = find_cmd_start (start); + char *n = find_cmd_name (s); + + cs = progcomp_search (n); + if(cs && cs->word_breaks) + return cs->word_breaks; + return 0; +} + static char **history_completion_array = (char **)NULL; static int harry_size; static int harry_len; -- 1.7.3.4