Add canse insensitive tilde completion

darcs-hash:20080113193221-75c98-169804fe128001f73eaee6fab28bfb99dca7c93e.gz
This commit is contained in:
liljencrantz 2008-01-14 05:32:21 +10:00
parent c2b28063e1
commit f5540ff958
3 changed files with 153 additions and 62 deletions

View file

@ -58,7 +58,7 @@ These functions are used for storing and retrieving tab-completion data, as well
/** /**
Description for ~USER completion Description for ~USER completion
*/ */
#define COMPLETE_USER_DESC _( L"Home for %s" ) #define COMPLETE_USER_DESC _( L"Home for %ls" )
/** /**
Description for short variables. The value is concatenated to this description Description for short variables. The value is concatenated to this description
@ -1613,8 +1613,8 @@ 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 *whole_var, static int complete_variable( const wchar_t *whole_var,
int start_offset, int start_offset,
array_list_t *comp_list ) array_list_t *comp_list )
{ {
int i; int i;
const wchar_t *var = &whole_var[start_offset]; const wchar_t *var = &whole_var[start_offset];
@ -1796,26 +1796,42 @@ static int try_complete_user( const wchar_t *cmd,
{ {
if( wcsncmp( user_name, pw_name, name_len )==0 ) if( wcsncmp( user_name, pw_name, name_len )==0 )
{ {
string_buffer_t desc; string_buffer_t desc;
string_buffer_t name;
sb_init( &name );
sb_printf( &name,
L"%ls/",
&pw_name[name_len] );
sb_init( &desc ); sb_init( &desc );
sb_printf( &desc, sb_printf( &desc,
COMPLETE_USER_DESC, COMPLETE_USER_DESC,
pw->pw_gecos ); pw_name );
completion_allocate( comp, completion_allocate( comp,
(wchar_t *)name.buff, &pw_name[name_len],
(wchar_t *)desc.buff, (wchar_t *)desc.buff,
0 ); COMPLETE_NO_SPACE );
res=1; res=1;
sb_destroy( &desc );
}
else if( wcsncasecmp( user_name, pw_name, name_len )==0 )
{
string_buffer_t name;
string_buffer_t desc;
sb_init( &name );
sb_init( &desc );
sb_printf( &name,
L"~%ls",
pw_name );
sb_printf( &desc,
COMPLETE_USER_DESC,
pw_name );
completion_allocate( comp,
(wchar_t *)name.buff,
(wchar_t *)desc.buff,
COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE );
res=1;
sb_destroy( &desc ); sb_destroy( &desc );
sb_destroy( &name ); sb_destroy( &name );

View file

@ -94,6 +94,13 @@
*/ */
#define COMPLETE_AUTO_SPACE 8 #define COMPLETE_AUTO_SPACE 8
/**
This completion should be inserted as-is, without escaping.
*/
#define COMPLETE_DONT_ESCAPE 16
typedef struct typedef struct
{ {

164
reader.c
View file

@ -998,7 +998,10 @@ static void completion_insert( const wchar_t *val, int flags )
wchar_t quote; wchar_t quote;
int add_space = !(flags & COMPLETE_NO_SPACE); int add_space = !(flags & COMPLETE_NO_SPACE);
int do_replace = (flags&COMPLETE_NO_CASE); int do_replace = (flags & COMPLETE_NO_CASE);
int do_escape = !(flags & COMPLETE_DONT_ESCAPE);
// debug( 0, L"Insert completion %ls with flags %d", val, flags);
if( do_replace ) if( do_replace )
{ {
@ -1017,11 +1020,18 @@ static void completion_insert( const wchar_t *val, int flags )
sb_init( &sb ); sb_init( &sb );
sb_append_substring( &sb, data->buff, begin - data->buff ); sb_append_substring( &sb, data->buff, begin - data->buff );
escaped = escape( val, ESCAPE_ALL | ESCAPE_NO_QUOTED ); if( do_escape )
{
sb_append( &sb, escaped ); escaped = escape( val, ESCAPE_ALL | ESCAPE_NO_QUOTED );
free( escaped ); sb_append( &sb, escaped );
free( escaped );
}
else
{
sb_append( &sb, val );
}
if( add_space ) if( add_space )
{ {
sb_append( &sb, L" " ); sb_append( &sb, L" " );
@ -1039,52 +1049,60 @@ static void completion_insert( const wchar_t *val, int flags )
else else
{ {
get_param( data->buff, if( do_escape )
{
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, ESCAPE_ALL | ESCAPE_NO_QUOTED ); replaced = escape( val, ESCAPE_ALL | ESCAPE_NO_QUOTED );
}
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 )
{
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, ESCAPE_ALL | ESCAPE_NO_QUOTED );
replaced = wcsdupcat( L" ", tmp );
free( tmp);
replaced[0]=quote;
}
else
*pout = 0;
}
} }
else else
{ {
int unescapable=0; replaced = wcsdup(val);
const wchar_t *pin;
wchar_t *pout;
replaced = pout =
malloc( sizeof(wchar_t)*(wcslen(val) + 1) );
for( pin=val; *pin; pin++ )
{
switch( *pin )
{
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, ESCAPE_ALL | ESCAPE_NO_QUOTED );
replaced = wcsdupcat( L" ", tmp );
free( tmp);
replaced[0]=quote;
}
else
*pout = 0;
} }
if( insert_str( replaced ) ) if( insert_str( replaced ) )
{ {
/* /*
@ -1292,6 +1310,27 @@ static void reader_flash()
} }
#define UNCLEAN L"$*?({})"
int reader_can_replace( const wchar_t *in )
{
const wchar_t * str = in;
CHECK( in, 1 );
/*
Test characters that have a special meaning in any character position
*/
while( *str )
{
if( wcschr( UNCLEAN, *str ) )
return 0;
str++;
}
return 1;
}
/** /**
Handle the list of completions. This means the following: Handle the list of completions. This means the following:
@ -1327,24 +1366,39 @@ static int handle_completions( array_list_t *comp )
context = halloc( 0, 0 ); context = halloc( 0, 0 );
tok = halloc_wcsndup( context, begin, end-begin ); tok = halloc_wcsndup( context, begin, end-begin );
/*
Check trivial cases
*/
switch( al_get_count( comp ) ) switch( al_get_count( comp ) )
{ {
/*
No suitable completions found, flash screen and retur
*/
case 0: case 0:
{ {
reader_flash(); reader_flash();
done = 1; done = 1;
break; break;
} }
/*
Exactly one suitable completion found - insert it
*/
case 1: case 1:
{ {
completion_t *c = (completion_t *)al_get( comp, 0 ); completion_t *c = (completion_t *)al_get( comp, 0 );
if( !(c->flags & COMPLETE_NO_CASE) || expand_is_clean( tok ) ) /*
If this is a replacement completion, check
that we know how to replace it, e.g. that
the token doesn't contain evil operators
like {}
*/
if( !(c->flags & COMPLETE_NO_CASE) || reader_can_replace( tok ) )
{ {
completion_insert( c->completion, completion_insert( c->completion,
c->flags ); c->flags );
} }
done = 1; done = 1;
len = 1; len = 1;
@ -1355,12 +1409,17 @@ static int handle_completions( array_list_t *comp )
if( !done ) if( !done )
{ {
/*
Try to find something to insert whith the correct case
*/
for( i=0; i<al_get_count( comp ); i++ ) for( i=0; i<al_get_count( comp ); i++ )
{ {
completion_t *c = (completion_t *)al_get( comp, i ); completion_t *c = (completion_t *)al_get( comp, i );
int new_len; int new_len;
/*
Ignore case insensitive completions for now
*/
if( c->flags & COMPLETE_NO_CASE ) if( c->flags & COMPLETE_NO_CASE )
continue; continue;
@ -1379,6 +1438,9 @@ static int handle_completions( array_list_t *comp )
} }
} }
/*
If we found something to insert, do it.
*/
if( len > 0 ) if( len > 0 )
{ {
if( count > 1 ) if( count > 1 )
@ -1390,14 +1452,18 @@ static int handle_completions( array_list_t *comp )
} }
} }
if( !done && base == 0 ) if( !done && base == 0 )
{ {
/*
Try to find something to insert ignoring case
*/
if( begin ) if( begin )
{ {
if( expand_is_clean( tok ) ) if( reader_can_replace( tok ) )
{ {
int offset = wcslen( tok ); int offset = wcslen( tok );
@ -2602,9 +2668,11 @@ wchar_t *reader_readline()
comp = al_halloc( 0 ); comp = al_halloc( 0 );
data->complete_func( buffcpy, comp ); data->complete_func( buffcpy, comp );
sort_completion_list( comp ); sort_completion_list( comp );
remove_duplicates( comp ); remove_duplicates( comp );
free( buffcpy ); free( buffcpy );
comp_empty = handle_completions( comp ); comp_empty = handle_completions( comp );