It seems like if [email protected] 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?= <[email protected]>
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?= <[email protected]>
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?= <[email protected]>
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