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

Reply via email to