Fix bug where case insensitive file completions would get directory components removed

darcs-hash:20070324190738-ac50b-2f94de910083eae1fe563284b9953071df706072.gz
This commit is contained in:
axel 2007-03-25 05:07:38 +10:00
parent f6b3fcb4f5
commit 3f4b47b4af
3 changed files with 310 additions and 228 deletions

View file

@ -1593,13 +1593,14 @@ static void complete_param_expand( wchar_t *str,
/** /**
Complete the specified string as an environment variable Complete the specified string as an environment variable
*/ */
static int complete_variable( const wchar_t *var, static int complete_variable( const wchar_t *whole_var,
array_list_t *comp ) int start_offset,
array_list_t *comp_list )
{ {
int i; int i;
const wchar_t *var = &whole_var[start_offset];
int varlen = wcslen( var ); int varlen = wcslen( var );
int res = 0; int res = 0;
array_list_t names; array_list_t names;
al_init( &names ); al_init( &names );
env_get_names( &names, 0 ); env_get_names( &names, 0 );
@ -1608,11 +1609,19 @@ static int complete_variable( const wchar_t *var,
{ {
wchar_t *name = (wchar_t *)al_get( &names, i ); wchar_t *name = (wchar_t *)al_get( &names, i );
int namelen = wcslen( name ); int namelen = wcslen( name );
int match=0, match_no_case=0;
if( varlen > namelen ) if( varlen > namelen )
continue; continue;
if( wcsncmp( var, name, varlen) == 0 ) match = ( wcsncmp( var, name, varlen) == 0 );
if( !match )
{
match_no_case = ( wcsncasecmp( var, name, varlen) == 0 );
}
if( match || match_no_case )
{ {
wchar_t *value_unescaped, *value; wchar_t *value_unescaped, *value;
@ -1620,20 +1629,37 @@ static int complete_variable( const wchar_t *var,
if( value_unescaped ) if( value_unescaped )
{ {
string_buffer_t desc; string_buffer_t desc;
string_buffer_t comp;
int flags = 0;
int offset = 0;
sb_init( &comp );
if( match )
{
sb_append( &comp, &name[varlen] );
offset = varlen;
}
else
{
sb_append_substring( &comp, whole_var, start_offset );
sb_append( &comp, name );
flags = COMPLETE_NO_CASE;
}
value = expand_escape_variable( value_unescaped ); value = expand_escape_variable( value_unescaped );
sb_init( &desc ); sb_init( &desc );
sb_printf( &desc, COMPLETE_VAR_DESC_VAL, value ); sb_printf( &desc, COMPLETE_VAR_DESC_VAL, value );
completion_allocate( comp, completion_allocate( comp_list,
&name[varlen], (wchar_t *)comp.buff,
(wchar_t *)desc.buff, (wchar_t *)desc.buff,
0 ); flags );
res =1; res =1;
free( value ); free( value );
sb_destroy( &desc ); sb_destroy( &desc );
sb_destroy( &comp );
} }
} }
@ -1660,7 +1686,7 @@ static int try_complete_variable( const wchar_t *cmd,
if( cmd[i] == L'$' ) if( cmd[i] == L'$' )
{ {
/* wprintf( L"Var prefix \'%ls\'\n", &cmd[i+1] );*/ /* wprintf( L"Var prefix \'%ls\'\n", &cmd[i+1] );*/
return complete_variable( &cmd[i+1], comp ); return complete_variable( cmd, i+1, comp );
} }
if( !isalnum(cmd[i]) && cmd[i]!=L'_' ) if( !isalnum(cmd[i]) && cmd[i]!=L'_' )
{ {
@ -1790,7 +1816,7 @@ static int try_complete_user( const wchar_t *cmd,
void complete( const wchar_t *cmd, void complete( const wchar_t *cmd,
array_list_t *comp ) array_list_t *comp )
{ {
wchar_t *begin, *end, *prev_begin, *prev_end; wchar_t *tok_begin, *tok_end, *cmdsubst_begin, *cmdsubst_end, *prev_begin, *prev_end;
wchar_t *buff; wchar_t *buff;
tokenizer tok; tokenizer tok;
wchar_t *current_token=0, *current_command=0, *prev_token=0; wchar_t *current_token=0, *current_command=0, *prev_token=0;
@ -1802,7 +1828,7 @@ void complete( const wchar_t *cmd,
int use_function = 1; int use_function = 1;
int use_builtin = 1; int use_builtin = 1;
int had_ddash = 0; int had_ddash = 0;
CHECK( cmd, ); CHECK( cmd, );
CHECK( comp, ); CHECK( comp, );
@ -1812,35 +1838,30 @@ void complete( const wchar_t *cmd,
cursor_pos = wcslen(cmd ); cursor_pos = wcslen(cmd );
parse_util_cmdsubst_extent( cmd, cursor_pos, &cmdsubst_begin, &cmdsubst_end );
parse_util_token_extent( cmd, cursor_pos, &tok_begin, &tok_end, &prev_begin, &prev_end );
if( !cmdsubst_begin )
done=1;
/** /**
If we are completing a variable name or a tilde expansion user If we are completing a variable name or a tilde expansion user
name, we do that and return. No need for any other competions. name, we do that and return. No need for any other competions.
*/ */
if( try_complete_variable( cmd, comp ) || try_complete_user( cmd, comp ))
{
done=1;
}
/*
Set on_command to true if cursor is over a command, and set the
name of the current command, and various other parsing to find
out what we should complete, and how it should be completed.
*/
if( !done ) if( !done )
{ {
parse_util_cmdsubst_extent( cmd, cursor_pos, &begin, &end ); if( try_complete_variable( tok_begin, comp ) || try_complete_user( tok_begin, comp ))
{
if( !begin )
done=1; done=1;
}
} }
if( !done ) if( !done )
{ {
pos = cursor_pos-(begin-cmd); pos = cursor_pos-(cmdsubst_begin-cmd);
buff = wcsndup( begin, end-begin ); buff = wcsndup( cmdsubst_begin, cmdsubst_end-cmdsubst_begin );
if( !buff ) if( !buff )
done=1; done=1;
@ -1948,9 +1969,7 @@ void complete( const wchar_t *cmd,
Get the string to complete Get the string to complete
*/ */
parse_util_token_extent( cmd, cursor_pos, &begin, &end, &prev_begin, &prev_end ); current_token = wcsndup( tok_begin, cursor_pos-(tok_begin-cmd) );
current_token = wcsndup( begin, cursor_pos-(begin-cmd) );
prev_token = prev_begin ? wcsndup( prev_begin, prev_end - prev_begin ): wcsdup(L""); prev_token = prev_begin ? wcsndup( prev_begin, prev_end - prev_begin ): wcsdup(L"");

387
reader.c
View file

@ -961,73 +961,73 @@ static void completion_insert( const wchar_t *val, int flags )
else else
{ {
get_param( data->buff, get_param( data->buff,
data->buff_pos, data->buff_pos,
&quote, &quote,
0, 0, 0 ); 0, 0, 0 );
if( quote == L'\0' ) if( quote == L'\0' )
{
replaced = escape( val, 1 );
}
else
{
int unescapable=0;
const wchar_t *pin;
wchar_t *pout;
replaced = pout =
malloc( sizeof(wchar_t)*(wcslen(val) + 1) );
for( pin=val; *pin; pin++ )
{ {
switch( *pin ) replaced = escape( val, 1 );
{
case L'\n':
case L'\t':
case L'\b':
case L'\r':
unescapable=1;
break;
default:
*pout++ = *pin;
break;
}
}
if( unescapable )
{
free( replaced );
wchar_t *tmp = escape( val, 1 );
replaced = wcsdupcat( L" ", tmp );
free( tmp);
replaced[0]=quote;
} }
else else
*pout = 0;
}
if( insert_str( replaced ) )
{
/*
Print trailing space since this is the only completion
*/
if( add_space )
{ {
int unescapable=0;
if( (quote) && const wchar_t *pin;
(data->buff[data->buff_pos] != quote ) ) wchar_t *pout;
replaced = pout =
malloc( sizeof(wchar_t)*(wcslen(val) + 1) );
for( pin=val; *pin; pin++ )
{ {
/* switch( *pin )
This is a quoted parameter, first print a quote {
*/ case L'\n':
insert_char( quote ); case L'\t':
case L'\b':
case L'\r':
unescapable=1;
break;
default:
*pout++ = *pin;
break;
}
} }
insert_char( L' ' ); if( unescapable )
{
free( replaced );
wchar_t *tmp = escape( val, 1 );
replaced = wcsdupcat( L" ", tmp );
free( tmp);
replaced[0]=quote;
}
else
*pout = 0;
} }
}
free(replaced); if( insert_str( replaced ) )
{
/*
Print trailing space since this is the only completion
*/
if( add_space )
{
if( (quote) &&
(data->buff[data->buff_pos] != quote ) )
{
/*
This is a quoted parameter, first print a quote
*/
insert_char( quote );
}
insert_char( L' ' );
}
}
free(replaced);
} }
@ -1231,22 +1231,42 @@ static int handle_completions( array_list_t *comp )
int done = 0; int done = 0;
int count = 0; int count = 0;
int flags=0; int flags=0;
wchar_t *begin, *end;
wchar_t *tok;
if( al_get_count( comp ) == 0 ) parse_util_token_extent( data->buff, data->buff_pos, &begin, 0, 0, 0 );
{ end = data->buff+data->buff_pos;
reader_flash();
return 0;
}
if( al_get_count( comp ) == 1 )
{
completion_t *c = (completion_t *)al_get( comp, 0 );
completion_insert( c->completion,
c->flags );
return 1;
}
context = halloc( 0, 0 ); context = halloc( 0, 0 );
tok = halloc_wcsndup( context, begin, end-begin );
switch( al_get_count( comp ) )
{
case 0:
{
reader_flash();
done = 1;
break;
}
case 1:
{
completion_t *c = (completion_t *)al_get( comp, 0 );
if( !(c->flags & COMPLETE_NO_CASE) || expand_is_clean( tok ) )
{
completion_insert( c->completion,
c->flags );
}
done = 1;
len = 1;
}
}
if( !done )
{
for( i=0; i<al_get_count( comp ); i++ ) for( i=0; i<al_get_count( comp ); i++ )
{ {
@ -1280,122 +1300,119 @@ static int handle_completions( array_list_t *comp )
completion_insert(base, flags); completion_insert(base, flags);
done = 1; done = 1;
} }
}
if( base == 0 ) if( !done && base == 0 )
{
if( begin )
{ {
wchar_t *begin, *end;
parse_util_token_extent( data->buff, data->buff_pos, &begin, 0, 0, 0 ); if( expand_is_clean( tok ) )
if( begin )
{ {
end = data->buff+data->buff_pos; int offset = wcslen( tok );
wchar_t *tok = halloc_wcsndup( context, begin, end-begin );
count = 0;
if( expand_is_clean( tok ) )
for( i=0; i<al_get_count( comp ); i++ )
{ {
int offset = wcslen( tok ); completion_t *c = (completion_t *)al_get( comp, i );
int new_len;
count = 0;
for( i=0; i<al_get_count( comp ); i++ )
{
completion_t *c = (completion_t *)al_get( comp, i );
int new_len;
if( !(c->flags & COMPLETE_NO_CASE) ) if( !(c->flags & COMPLETE_NO_CASE) )
continue; continue;
count++; count++;
if( base ) 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 ) new_len = offset + comp_ilen( base+offset, c->completion+offset );
flags = flags | COMPLETE_NO_SPACE; len = new_len < len ? new_len: len;
base[len]=L'\0';
completion_insert( base, flags );
done = 1;
} }
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 ); free( base );
if( !done ) if( !done )
{
/*
There is no common prefix in the completions, and show_list
is true, so we print the list
*/
int len;
wchar_t * prefix;
wchar_t * prefix_start;
get_param( data->buff,
data->buff_pos,
0,
&prefix_start,
0,
0 );
len = &data->buff[data->buff_pos]-prefix_start+1;
if( len <= PREFIX_MAX_LEN )
{ {
/* prefix = malloc( sizeof(wchar_t)*(len+1) );
There is no common prefix in the completions, and show_list wcslcpy( prefix, prefix_start, len );
is true, so we print the list prefix[len]=L'\0';
*/ }
int len; else
wchar_t * prefix; {
wchar_t * prefix_start; wchar_t tmp[2]=
get_param( data->buff, {
data->buff_pos, ellipsis_char,
0, 0
&prefix_start, }
0, ;
0 );
len = &data->buff[data->buff_pos]-prefix_start+1; prefix = wcsdupcat( tmp,
prefix_start + (len - PREFIX_MAX_LEN) );
if( len <= PREFIX_MAX_LEN ) prefix[PREFIX_MAX_LEN] = 0;
{
prefix = malloc( sizeof(wchar_t)*(len+1) );
wcslcpy( prefix, prefix_start, len );
prefix[len]=L'\0';
}
else
{
wchar_t tmp[2]=
{
ellipsis_char,
0
}
;
prefix = wcsdupcat( tmp,
prefix_start + (len - PREFIX_MAX_LEN) );
prefix[PREFIX_MAX_LEN] = 0;
}
{
int is_quoted;
wchar_t quote;
get_param( data->buff, data->buff_pos, &quote, 0, 0, 0 );
is_quoted = (quote != L'\0');
write(1, "\n", 1 );
run_pager( prefix, is_quoted, comp );
}
free( prefix );
s_reset( &data->screen );
repaint();
} }
{
int is_quoted;
wchar_t quote;
get_param( data->buff, data->buff_pos, &quote, 0, 0, 0 );
is_quoted = (quote != L'\0');
write(1, "\n", 1 );
run_pager( prefix, is_quoted, comp );
}
free( prefix );
s_reset( &data->screen );
repaint();
}
halloc_free( context ); halloc_free( context );
return len; return len;
@ -2354,11 +2371,11 @@ wchar_t *reader_readline()
break; break;
} }
/* /*
if( (last_char == R_COMPLETE) && (c != R_COMPLETE) && (!comp_empty) ) if( (last_char == R_COMPLETE) && (c != R_COMPLETE) && (!comp_empty) )
{ {
halloc_destroy( comp ); halloc_destroy( comp );
comp = 0; comp = 0;
} }
*/ */
if( last_char != R_YANK && last_char != R_YANK_POP ) if( last_char != R_YANK && last_char != R_YANK_POP )
yank=0; yank=0;
@ -2881,8 +2898,8 @@ wchar_t *reader_readline()
writestr( L"\n" ); writestr( L"\n" );
/* /*
if( comp ) if( comp )
halloc_free( comp ); halloc_free( comp );
*/ */
if( !reader_exit_forced() ) if( !reader_exit_forced() )
{ {
@ -2960,21 +2977,21 @@ static int read_ni( int fd )
if( str ) if( str )
{ {
string_buffer_t sb; string_buffer_t sb;
sb_init( &sb ); sb_init( &sb );
if( !parser_test( str, 0, &sb, L"fish" ) ) if( !parser_test( str, 0, &sb, L"fish" ) )
{ {
eval( str, 0, TOP ); eval( str, 0, TOP );
} }
else else
{ {
fwprintf( stderr, L"%ls", sb.buff ); fwprintf( stderr, L"%ls", sb.buff );
res = 1; res = 1;
} }
sb_destroy( &sb ); sb_destroy( &sb );
free( str ); free( str );
} }
else else
{ {

View file

@ -802,10 +802,10 @@ static int test_flags( wchar_t *filename,
} }
int wildcard_expand( const wchar_t *wc, static int wildcard_expand_internal( const wchar_t *wc,
const wchar_t *base_dir, const wchar_t *base_dir,
int flags, int flags,
array_list_t *out ) array_list_t *out )
{ {
/* Points to the end of the current wildcard segment */ /* Points to the end of the current wildcard segment */
@ -854,7 +854,7 @@ int wildcard_expand( const wchar_t *wc,
{ {
wchar_t * foo = wcsdup( wc ); wchar_t * foo = wcsdup( wc );
foo[len-1]=0; foo[len-1]=0;
int res = wildcard_expand( foo, base_dir, flags, out ); int res = wildcard_expand_internal( foo, base_dir, flags, out );
free( foo ); free( foo );
return res; return res;
} }
@ -1125,10 +1125,10 @@ int wildcard_expand( const wchar_t *wc,
} }
} }
new_res = wildcard_expand( new_wc, new_res = wildcard_expand_internal( new_wc,
new_dir, new_dir,
flags, flags,
out ); out );
if( new_res == -1 ) if( new_res == -1 )
{ {
@ -1144,10 +1144,12 @@ int wildcard_expand( const wchar_t *wc,
*/ */
if( partial_match ) if( partial_match )
{ {
new_res = wildcard_expand( wcschr( wc, ANY_STRING_RECURSIVE ),
new_dir, new_res = wildcard_expand_internal( wcschr( wc, ANY_STRING_RECURSIVE ),
flags | WILDCARD_RECURSIVE, new_dir,
out ); flags | WILDCARD_RECURSIVE,
out );
if( new_res == -1 ) if( new_res == -1 )
{ {
res = -1; res = -1;
@ -1175,3 +1177,47 @@ int wildcard_expand( const wchar_t *wc,
return res; return res;
} }
int wildcard_expand( const wchar_t *wc,
const wchar_t *base_dir,
int flags,
array_list_t *out )
{
int c = al_get_count( out );
int res = wildcard_expand_internal( wc, base_dir, flags, out );
int i;
if( flags & ACCEPT_INCOMPLETE )
{
wchar_t *wc_base;
wchar_t *wc_base_ptr = wcsrchr( wc, L'/' );
if( wc_base_ptr )
{
string_buffer_t sb;
sb_init( &sb );
wc_base = wcsndup( wc, (wc_base_ptr-wc)+1 );
for( i=c; i<al_get_count( out ); i++ )
{
completion_t *c = al_get( out, i );
if( c->flags & COMPLETE_NO_CASE )
{
sb_clear( &sb );
sb_printf( &sb, L"%ls%ls", wc_base, c->completion );
c->completion = halloc_wcsdup( out, (wchar_t *)sb.buff );
}
}
sb_destroy( &sb );
free( wc_base );
}
}
return res;
}