From 2aea1d5a84ec696f0a013a42a2c50ca1476a7ceb Mon Sep 17 00:00:00 2001 From: axel Date: Thu, 1 Mar 2007 07:43:27 +1000 Subject: [PATCH] Initial checkin of code for using case insensitive completion as a fallback for regular completion. Some types of completions don't yet support the feature. darcs-hash:20070228214327-ac50b-9b5c69a1c3e0c11b560f8c61be0441d2ee9d6404.gz --- builtin_complete.c | 28 ++++--- complete.c | 59 ++++++++++---- complete.h | 5 +- reader.c | 196 ++++++++++++++++++++++++++++++++++++++++----- wildcard.c | 20 ++++- 5 files changed, 255 insertions(+), 53 deletions(-) diff --git a/builtin_complete.c b/builtin_complete.c index 8ea38a3aa..64b91de25 100644 --- a/builtin_complete.c +++ b/builtin_complete.c @@ -50,7 +50,8 @@ static void builtin_complete_add2( const wchar_t *cmd, int result_mode, const wchar_t *condition, const wchar_t *comp, - const wchar_t *desc ) + const wchar_t *desc, + int flags ) { int i; const wchar_t *s; @@ -65,7 +66,8 @@ static void builtin_complete_add2( const wchar_t *cmd, result_mode, condition, comp, - desc ); + desc, + flags ); } for( i=0; icomp = comp?halloc_wcsdup(opt, comp):L""; opt->condition = condition?halloc_wcsdup(opt, condition):L""; opt->long_opt = long_opt?halloc_wcsdup(opt, long_opt):L"" ; - + opt->flags = flags; + if( desc && wcslen( desc ) ) { opt->desc = halloc_wcsdup( opt, desc ); @@ -1022,9 +1026,9 @@ static void complete_cmd_desc( const wchar_t *cmd, array_list_t *comp ) { completion_t *c = (completion_t *)al_get( comp, i ); const wchar_t *el = c->completion; - + wchar_t *new_desc; - + new_desc = (wchar_t *)hash_get( &lookup, el ); @@ -1205,7 +1209,8 @@ static void complete_cmd( const wchar_t *cmd, static void complete_from_args( const wchar_t *str, const wchar_t *args, const wchar_t *desc, - array_list_t *comp_out ) + array_list_t *comp_out, + int flags ) { array_list_t possible_comp; @@ -1216,7 +1221,7 @@ static void complete_from_args( const wchar_t *str, eval_args( args, &possible_comp ); proc_pop_interactive(); - complete_strings( comp_out, str, desc, 0, &possible_comp, COMPLETE_AUTO_SPACE ); + complete_strings( comp_out, str, desc, 0, &possible_comp, flags ); al_foreach( &possible_comp, &free ); al_destroy( &possible_comp ); @@ -1384,7 +1389,7 @@ static int complete_param( const wchar_t *cmd_orig, { use_common &= ((o->result_mode & NO_COMMON )==0); use_files &= ((o->result_mode & NO_FILES )==0); - complete_from_args( arg, o->comp, C_(o->desc), comp_out ); + complete_from_args( arg, o->comp, C_(o->desc), comp_out, o->flags ); } } @@ -1407,7 +1412,7 @@ static int complete_param( const wchar_t *cmd_orig, old_style_match = 1; use_common &= ((o->result_mode & NO_COMMON )==0); use_files &= ((o->result_mode & NO_FILES )==0); - complete_from_args( str, o->comp, C_(o->desc), comp_out ); + complete_from_args( str, o->comp, C_(o->desc), comp_out, o->flags ); } } } @@ -1433,7 +1438,7 @@ static int complete_param( const wchar_t *cmd_orig, { use_common &= ((o->result_mode & NO_COMMON )==0); use_files &= ((o->result_mode & NO_FILES )==0); - complete_from_args( str, o->comp, C_(o->desc), comp_out ); + complete_from_args( str, o->comp, C_(o->desc), comp_out, o->flags ); } } @@ -1458,7 +1463,7 @@ static int complete_param( const wchar_t *cmd_orig, if( (o->short_opt == L'\0' ) && (o->long_opt[0]==L'\0')) { use_files &= ((o->result_mode & NO_FILES )==0); - complete_from_args( str, o->comp, C_(o->desc), comp_out ); + complete_from_args( str, o->comp, C_(o->desc), comp_out, o->flags ); } if( wcslen(str) > 0 && use_switches ) @@ -1483,19 +1488,38 @@ static int complete_param( const wchar_t *cmd_orig, */ if( o->long_opt[0] != L'\0' ) { + int match=0, match_no_case=0; + string_buffer_t *whole_opt = sb_halloc( context ); sb_append2( whole_opt, o->old_mode?L"-":L"--", o->long_opt, (void *)0 ); - if( wcsncmp( str, (wchar_t *)whole_opt->buff, wcslen(str) )==0) + match = wcsncmp( str, (wchar_t *)whole_opt->buff, wcslen(str) )==0; + + if( !match ) + { + match_no_case = wcsncasecmp( str, (wchar_t *)whole_opt->buff, wcslen(str) )==0; + } + + if( match || match_no_case ) { int has_arg=0; /* Does this switch have any known arguments */ int req_arg=0; /* Does this switch _require_ an argument */ + int offset = 0; + int flags = 0; + + + if( match ) + offset = wcslen( str ); + else + flags = COMPLETE_NO_CASE; + has_arg = !!wcslen( o->comp ); req_arg = (o->result_mode & NO_COMMON ); if( !o->old_mode && ( has_arg && !req_arg ) ) { + /* Optional arguments to a switch can only be handled using the '=', so we @@ -1507,23 +1531,24 @@ static int complete_param( const wchar_t *cmd_orig, */ string_buffer_t completion; sb_init( &completion ); + sb_printf( &completion, L"%ls=", - ((wchar_t *)whole_opt->buff)+wcslen(str) ); - + ((wchar_t *)whole_opt->buff)+offset ); + completion_allocate( comp_out, (wchar_t *)completion.buff, C_(o->desc), - 0 ); + flags ); + sb_destroy( &completion ); } completion_allocate( comp_out, - ((wchar_t *)whole_opt->buff) + wcslen(str), + ((wchar_t *)whole_opt->buff) + offset, C_(o->desc), - 0 ); - + flags ); } } } diff --git a/complete.h b/complete.h index 56e668846..dbb3259cf 100644 --- a/complete.h +++ b/complete.h @@ -75,8 +75,8 @@ /** This compeltion is case insensitive */ - #define COMPLETE_NO_CASE 2 + /** This compeltion is the whole argument, not just the remainder. This flag must never be set on completions returned from the complete() @@ -169,7 +169,8 @@ void complete_add( const wchar_t *cmd, int result_mode, const wchar_t *condition, const wchar_t *comp, - const wchar_t *desc ); + const wchar_t *desc, + int flags ); /** Sets whether the completion list for this command is complete. If true, any options not matching one of the provided options will be diff --git a/reader.c b/reader.c index c7fb7709f..8d8fda9f9 100644 --- a/reader.c +++ b/reader.c @@ -751,6 +751,19 @@ static int comp_len( const wchar_t *a, const wchar_t *b ) return i; } +/** + Calculate the case insensitive length of the common prefix substring of two strings. +*/ +static int comp_ilen( const wchar_t *a, const wchar_t *b ) +{ + int i; + for( i=0; + a[i] != '\0' && b[i] != '\0' && towlower(a[i])==towlower(b[i]); + i++ ) + ; + return i; +} + /** Find the outermost quoting style of current token. Returns 0 if token is not quoted. @@ -887,12 +900,47 @@ static void get_param( wchar_t *cmd, just the common prefix of several completions. If the former, end by printing a space (and an end quote if the parameter is quoted). */ -static void completion_insert( const wchar_t *val, int is_complete ) +static void completion_insert( const wchar_t *val, int flags ) { wchar_t *replaced; wchar_t quote; + int add_space = !(flags & COMPLETE_NO_SPACE); + int do_replace = (flags&COMPLETE_NO_CASE); + if( do_replace ) + { + + int tok_start, tok_len; + wchar_t *begin, *end; + string_buffer_t sb; + + parse_util_token_extent( data->buff, data->buff_pos, &begin, 0, 0, 0 ); + end = data->buff+data->buff_pos; + + tok_start = begin - data->buff; + tok_len = end-begin; + + sb_init( &sb ); + sb_append_substring( &sb, data->buff, begin - data->buff ); + sb_append( &sb, val ); + if( add_space ) + { + sb_append( &sb, L" " ); + } + + sb_append( &sb, end ); + + reader_set_buffer( (wchar_t *)sb.buff, (begin-data->buff)+wcslen(val)+!!add_space ); + sb_destroy( &sb ); + + reader_super_highlight_me_plenty( data->buff_pos, 0 ); + repaint(); + + } + else + { + get_param( data->buff, data->buff_pos, "e, @@ -944,7 +992,7 @@ static void completion_insert( const wchar_t *val, int is_complete ) /* Print trailing space since this is the only completion */ - if( is_complete ) + if( add_space ) { if( (quote) && @@ -960,6 +1008,9 @@ static void completion_insert( const wchar_t *val, int is_complete ) } free(replaced); + + } + } /** @@ -1009,6 +1060,7 @@ static void run_pager( wchar_t *prefix, int is_quoted, array_list_t *comp ) for( i=0; icompletion ) { - foo = escape( el->completion, 1 ); - } + if( el->flags & COMPLETE_NO_CASE ) + { + if( base_len == -1 ) + { + wchar_t *begin; + + parse_util_token_extent( data->buff, data->buff_pos, &begin, 0, 0, 0 ); + base_len = data->buff_pos - (begin-data->buff); + + } + + + foo = escape( el->completion + base_len, 1 ); + } + else + { + foo = escape( el->completion, 1 ); + } + } + if( el && el->description ) { baz = escape( el->description, 1 ); @@ -1135,40 +1205,119 @@ static void reader_flash() static int handle_completions( array_list_t *comp ) { int i; + void *context = 0; + wchar_t *base = 0; + int len = 0; + int done = 0; + int count = 0; + int flags=0; if( al_get_count( comp ) == 0 ) { reader_flash(); return 0; } - else if( al_get_count( comp ) == 1 ) + + if( al_get_count( comp ) == 1 ) { completion_t *c = (completion_t *)al_get( comp, 0 ); completion_insert( c->completion, - !(c->flags & COMPLETE_NO_SPACE) ); + c->flags ); return 1; } - else - { - completion_t *c = (completion_t *)al_get( comp, 0 ); - wchar_t *base = wcsdup( c->completion ); - int len = wcslen( base ); + + context = halloc( 0, 0 ); - for( i=1; icompletion ); - len = new_len < len ? new_len: len; + int new_len; + + if( c->flags & COMPLETE_NO_CASE ) + continue; + + count++; + + if( base ) + { + new_len = comp_len( base, c->completion ); + len = new_len < len ? new_len: len; + } + else + { + base = wcsdup( c->completion ); + len = wcslen( base ); + flags = c->flags; + } } + if( len > 0 ) { + if( count > 1 ) + flags = flags | COMPLETE_NO_SPACE; + base[len]=L'\0'; - wchar_t *woot = wcschr( base, COMPLETE_SEP ); - if( woot != 0 ) - *woot = L'\0'; - completion_insert(base, 0); + completion_insert(base, flags); + done = 1; } - else + + if( base == 0 ) + { + wchar_t *begin, *end; + + parse_util_token_extent( data->buff, data->buff_pos, &begin, 0, 0, 0 ); + + if( begin ) + { + end = data->buff+data->buff_pos; + wchar_t *tok = halloc_wcsndup( context, begin, end-begin ); + + if( expand_is_clean( tok ) ) + { + int offset = wcslen( tok ); + + count = 0; + + for( i=0; iflags & COMPLETE_NO_CASE) ) + continue; + + count++; + + if( base ) + { + new_len = offset + comp_ilen( base+offset, c->completion+offset ); + len = new_len < len ? new_len: len; + } + else + { + base = wcsdup( c->completion ); + len = wcslen( base ); + flags = c->flags; + + } + } + + if( len > offset ) + { + if( count > 1 ) + flags = flags | COMPLETE_NO_SPACE; + + base[len]=L'\0'; + completion_insert( base, flags ); + done = 1; + } + } + } + } + + free( base ); + + if( !done ) { /* There is no common prefix in the completions, and show_list @@ -1225,9 +1374,12 @@ static int handle_completions( array_list_t *comp ) } - free( base ); - return len; - } + + halloc_free( context ); + + return len; + + } diff --git a/wildcard.c b/wildcard.c index 85185b11a..fcee957cb 100644 --- a/wildcard.c +++ b/wildcard.c @@ -287,7 +287,13 @@ static int wildcard_complete_internal( const wchar_t *orig, */ out_completion = wcsdup( str ); } - + + if( flags & COMPLETE_NO_CASE ) + { + free( out_completion ); + out_completion = wcsdup( orig ); + } + if( out_completion ) { completion_allocate( out, @@ -295,7 +301,7 @@ static int wildcard_complete_internal( const wchar_t *orig, out_desc, flags ); } - + free ( out_completion ); return 1; @@ -329,6 +335,10 @@ static int wildcard_complete_internal( const wchar_t *orig, { return wildcard_complete_internal( orig, str+1, wc+1, 0, desc, desc_func, out, flags ); } + else if( towlower(*wc) == towlower(*str) ) + { + return wildcard_complete_internal( orig, str+1, wc+1, 0, desc, desc_func, out, flags | COMPLETE_NO_CASE ); + } return 0; } @@ -339,7 +349,11 @@ int wildcard_complete( const wchar_t *str, array_list_t *out, int flags ) { - return wildcard_complete_internal( str, str, wc, 1, desc, desc_func, out, flags ); + int res; + + res = wildcard_complete_internal( str, str, wc, 1, desc, desc_func, out, flags ); + + return res; }