diff options
author | axel <axel@liljencrantz.se> | 2006-02-14 10:08:23 +1000 |
---|---|---|
committer | axel <axel@liljencrantz.se> | 2006-02-14 10:08:23 +1000 |
commit | 0dab94a54c26a4d78191e8e60de630c93581136a (patch) | |
tree | a02db5b52c5e2b099176f9f00fd29267f2de2f2e /fish_pager.c | |
parent | 3097f71abd83a138a4f5295cf8f9634b8e7dfadf (diff) |
Group multiple switches with common description together when printing completions
darcs-hash:20060214000823-ac50b-2bde1ac964baf12a515d763a076434757ac9fd21.gz
Diffstat (limited to 'fish_pager.c')
-rw-r--r-- | fish_pager.c | 540 |
1 files changed, 241 insertions, 299 deletions
diff --git a/fish_pager.c b/fish_pager.c index 427bfe06..42a8b304 100644 --- a/fish_pager.c +++ b/fish_pager.c @@ -42,6 +42,7 @@ #include "output.h" #include "input_common.h" #include "env_universal.h" +#include "halloc.h" #include "halloc_util.h" enum @@ -92,8 +93,18 @@ static wchar_t *hightlight_var[] = static string_buffer_t out_buff; static FILE *out_file; +typedef struct +{ + array_list_t *comp; + wchar_t *desc; + int comp_width; + int desc_width; + int pref_width; + int min_width; +} + comp_t; -int get_color( int highlight ) +static int get_color( int highlight ) { if( highlight < 0 ) return FISH_COLOR_NORMAL; @@ -103,9 +114,6 @@ int get_color( int highlight ) wchar_t *val = env_universal_get( hightlight_var[highlight]); if( val == 0 ) - return FISH_COLOR_NORMAL; - - if( val == 0 ) { return FISH_COLOR_NORMAL; } @@ -113,7 +121,20 @@ int get_color( int highlight ) return output_color_code( val ); } -int try_sequence( char *seq ) +static void recalc_width( array_list_t *l, const wchar_t *prefix ) +{ + int i; + for( i=0; i<al_get_count( l ); i++ ) + { + comp_t *c = (comp_t *)al_get( l, i ); + + c->min_width = mini( c->desc_width, maxi(0,termsize.ws_col/3 - 2)) + + mini( c->desc_width, maxi(0,termsize.ws_col/5 - 4)) +4; + } + +} + +static int try_sequence( char *seq ) { int j, k; wint_t c=0; @@ -195,6 +216,80 @@ static wint_t readch() return input_common_readch(0); } +static int print_max( const wchar_t *str, int max, int has_more ) +{ + int i; + int written = 0; + for( i=0; str[i]; i++ ) + { + if( written + wcwidth(str[i]) > max ) + break; + if( ( written + wcwidth(str[i]) == max) && (has_more || str[i+1]) ) + { + writech( ellipsis_char ); + written += wcwidth(ellipsis_char ); + break; + } + + writech( str[i] ); + written+= wcwidth( str[i] ); + } + return written; +} + +static void completion_print_item( const wchar_t *prefix, comp_t *c, int width ) +{ + int comp_width, desc_width; + int i; + int written=0; + + if( c->pref_width <= width ) + { + /* + The entry fits, we give it as much space as it wants + */ + comp_width = c->comp_width; + desc_width = c->desc_width; + } + else + { + /* + The completion and description won't fit on the + allocated space. Give a maximum of 2/3 of the + space to the completion, and whatever is left to + the description. + */ + int desc_all = c->desc_width?c->desc_width+4:0; + + comp_width = maxi( mini( c->comp_width, + 2*(width-4)/3 ), + width - desc_all ); + + desc_width = width-comp_width-4; + } + + for( i=0; i<al_get_count( c->comp ); i++ ) + { + if( i != 0 ) + written += print_max( L" ", comp_width - written, 1 ); + set_color( get_color(HIGHLIGHT_PAGER_PREFIX),FISH_COLOR_NORMAL ); + written += print_max( prefix, comp_width - written, 1 ); + set_color( get_color(HIGHLIGHT_PAGER_COMPLETION),FISH_COLOR_IGNORE ); + written += print_max( (wchar_t *)al_get( c->comp, i ), comp_width - written, i!=(al_get_count(c->comp)-1) ); + } + + while( written < (width-desc_width-2)) + { + written++; + writech( L' '); + } + + written += print_max( L"(", 1, 0 ); + set_color( get_color( HIGHLIGHT_PAGER_DESCRIPTION ), + FISH_COLOR_IGNORE ); + written += print_max( c->desc, desc_width, 0 ); + written += print_max( L")", 1, 0 ); +} /** Print the specified part of the completion list, using the @@ -220,288 +315,24 @@ static void completion_print( int cols, int rows = (al_get_count( l )-1)/cols+1; int i, j; - int prefix_width= my_wcswidth(prefix); for( i = row_start; i<row_stop; i++ ) { for( j = 0; j < cols; j++ ) { - wchar_t *el, *el_end; + comp_t *el; if( al_get_count( l ) <= j*rows + i ) continue; - el = (wchar_t *)al_get( l, j*rows + i ); - el_end= wcschr( el, COMPLETE_SEP ); - - set_color( get_color(HIGHLIGHT_PAGER_PREFIX),FISH_COLOR_NORMAL ); - - writestr( prefix ); - - set_color( get_color(HIGHLIGHT_PAGER_COMPLETION),FISH_COLOR_IGNORE ); - - if( el_end == 0 ) - { - /* We do not have a description for this completion */ - int written = 0; - int max_written = width[j] - prefix_width - (j==cols-1?0:2); - - if( is_quoted ) - { - for( i=0; i<max_written; i++ ) - { - if( !el[i] ) - break; - writech( el[i] ); - written+= wcwidth( el[i] ); - } - } - else - { - written = write_escaped_str( el, max_written ); - } - - set_color( get_color( HIGHLIGHT_PAGER_DESCRIPTION ), - FISH_COLOR_IGNORE ); - - writespace( width[j]- - written- - prefix_width ); - } - else - { - int whole_desc_width = my_wcswidth(el_end+1); - int whole_comp_width; - - /* - Temporarily drop the description so that wcswidth et - al only calculate the width of the completion. - */ - *el_end = L'\0'; - - /* - Calculate preferred completion width - */ - if( is_quoted ) - { - whole_comp_width = my_wcswidth(el); - } - else - { - wchar_t *tmp = escape( el, 1 ); - whole_comp_width = my_wcswidth( tmp ); - free(tmp); - } - - /* - Calculate how wide this entry 'wants' to be - */ - int pref_width = whole_desc_width + 4 + prefix_width + 2 - - (j==cols-1?2:0) + whole_comp_width; - - int comp_width, desc_width; - - if( pref_width <= width[j] ) - { - /* - The entry fits, we give it as much space as it wants - */ - comp_width = whole_comp_width; - desc_width = whole_desc_width; - } - else - { - /* - The completion and description won't fit on the - allocated space. Give a maximum of 2/3 of the - space to the completion, and whatever is left to - the description. - */ - int sum = width[j] - prefix_width - 4 - 2 + (j==cols-1?2:0); - - comp_width = maxi( mini( whole_comp_width, - 2*sum/3 ), - sum - whole_desc_width ); - desc_width = sum-comp_width; - } - - /* First we must print the completion. */ - if( is_quoted ) - { - writestr_ellipsis( el, comp_width); - } - else - { - write_escaped_str( el, comp_width ); - } - - /* Put the description back */ - *el_end = COMPLETE_SEP; - - /* And print it */ - set_color( get_color(HIGHLIGHT_PAGER_DESCRIPTION), - FISH_COLOR_IGNORE ); - writespace( maxi( 2, - width[j] - - comp_width - - desc_width - - 4 - - prefix_width - + (j==cols-1?2:0) ) ); - /* Print description */ - writestr(L"("); - writestr_ellipsis( el_end+1, desc_width); - writestr(L")"); - - if( j != cols-1) - writestr( L" " ); - - } - } - writech( L'\n' ); - } -} - -/** - Calculates how long the specified string would be when printed on the command line. - - \param str The string to be printed. - \param is_quoted Whether the string would be printed quoted or unquoted - \param pref_width the preferred width for this item - \param min_width the minimum width for this item -*/ -static void printed_length( wchar_t *str, - int is_quoted, - int *pref_width, - int *min_width ) -{ - if( is_quoted ) - { - wchar_t *sep = wcschr(str,COMPLETE_SEP); - if( sep ) - { - *sep=0; - int cw = my_wcswidth( str ); - int dw = my_wcswidth(sep+1); - - if( termsize.ws_col > 80 ) - dw = mini( dw, termsize.ws_col/3 ); - - - *pref_width = cw+dw+4; - - if( dw > termsize.ws_col/3 ) - { - dw = termsize.ws_col/3; - } - - *min_width=cw+dw+4; - - *sep= COMPLETE_SEP; - return; - } - else - { - *pref_width=*min_width= my_wcswidth( str ); - return; - } - - } - else - { - int comp_len=0, desc_len=0; - int has_description = 0; - while( *str != 0 ) - { - if( ( *str >= ENCODE_DIRECT_BASE) && - ( *str < ENCODE_DIRECT_BASE+256) ) - { - if( has_description ) - desc_len+=4; - else - comp_len+=4; - - } - else - { - - switch( *str ) - { - case L'\n': - case L'\b': - case L'\r': - case L'\e': - case L'\t': - case L'\\': - case L'&': - case L'$': - case L' ': - case L'#': - case L'^': - case L'<': - case L'>': - case L'(': - case L')': - case L'[': - case L']': - case L'{': - case L'}': - case L'?': - case L'*': - case L'|': - case L';': - case L':': - case L'\'': - case L'"': - case L'%': - case L'~': - - if( has_description ) - desc_len++; - else - comp_len+=2; - break; - - case COMPLETE_SEP: - has_description = 1; - break; - - default: - if( has_description ) - desc_len+= wcwidth(*str); - else - comp_len+= wcwidth(*str); - break; - } - } + el = (comp_t *)al_get( l, j*rows + i ); - str++; - } - if( has_description ) - { - /* - Mangle long descriptions to make formating look nicer - */ - debug( 3, L"Desc, width = %d %d\n", comp_len, desc_len ); -// if( termsize.ws_col > 80 ) -// desc_len = mini( desc_len, termsize.ws_col/3 ); - - *pref_width = comp_len+ desc_len+4;; - - comp_len = mini( comp_len, maxi(0,termsize.ws_col/3 - 2)); - desc_len = mini( desc_len, maxi(0,termsize.ws_col/5 - 4)); + completion_print_item( prefix, el, width[j] ); - *min_width = comp_len+ desc_len+4; - return; + if( j != cols-1) + writestr( L" " ); } - else - { - debug( 3, L"No desc, width = %d\n", comp_len ); - - *pref_width=*min_width= comp_len; - return; - } - + writech( L'\n' ); } } @@ -552,8 +383,6 @@ static int completion_try_print( int cols, int pref_tot_width=0; int min_tot_width = 0; - int prefix_width = my_wcswidth( prefix ); - int res=0; /* Skip completions on tiny terminals @@ -561,25 +390,24 @@ static int completion_try_print( int cols, if( termsize.ws_col < 16 ) return 1; - + memset( pref_width, 0, sizeof(pref_width) ); memset( min_width, 0, sizeof(min_width) ); - + /* Calculate how wide the list would be */ for( j = 0; j < cols; j++ ) { for( i = 0; i<rows; i++ ) { int pref,min; - wchar_t *el; + comp_t *c; if( al_get_count( l ) <= j*rows + i ) continue; - el = (wchar_t *)al_get( l, j*rows + i ); - printed_length( el, is_quoted, &pref, &min ); - - pref += prefix_width; - min += prefix_width; + c = (comp_t *)al_get( l, j*rows + i ); + pref = c->pref_width; + min = c->min_width; + if( j != cols-1 ) { pref += 2; @@ -808,7 +636,9 @@ static int completion_try_print( int cols, } /** - Substitute any series of tabs, newlines, etc. with a single space character in completion description + Substitute any series of whitespace with a single space character + inside completion descriptions. Remove all whitespace from + beginning/end of completion descriptions. */ static void mangle_descriptions( array_list_t *l ) { @@ -847,6 +677,117 @@ static void mangle_descriptions( array_list_t *l ) } /** + Merge multiple completions with the same description to the same line +*/ +static void join_completions( array_list_t *l ) +{ + int i, in, out; + hash_table_t desc_table; + + hash_init( &desc_table, &hash_wcs_func, &hash_wcs_cmp ); + + for( i=0; i<al_get_count(l); i++ ) + { + wchar_t *item = (wchar_t *)al_get( l, i ); + wchar_t *desc = wcschr( item, COMPLETE_SEP ); + long prev_idx; + + if( !desc ) + continue; + desc++; + prev_idx = ((long)hash_get( &desc_table, desc) )-1; + if( prev_idx == -1 ) + { + hash_put( &desc_table, desc, (void *)(i+1)); + } + else + { + string_buffer_t foo; + wchar_t *old = (wchar_t *)al_get( l, prev_idx ); + wchar_t *old_end = wcschr( old, COMPLETE_SEP ); + + if( old_end ) + { + *old_end = 0; + + sb_init( &foo ); + sb_append( &foo, old ); + sb_append_char( &foo, COMPLETE_ITEM_SEP ); + sb_append( &foo, item ); + al_set( l, prev_idx, foo.buff ); + free( (void *)al_get( l, i ) ); + al_set( l, i, 0 ); + } + +// debug( 1, L"WOOT WOOT %ls är släkt med %ls", item, al_get( l, prev_idx ) ); + + } + + } + hash_destroy( &desc_table ); + + out=0; + for( in=0; in < al_get_count(l); in++ ) + { + if( al_get( l, in ) ) + { + al_set( l, out++, al_get( l, in ) ); + } + } + al_truncate( l, out ); + +} + +/** + Replace compåletion strings with a comp_t structure +*/ +static void mangle_completions( array_list_t *l, const wchar_t *prefix ) +{ + int i; + + for( i=0; i<al_get_count( l ); i++ ) + { + wchar_t *next = (wchar_t *)al_get( l, i ); + wchar_t *start, *end; + comp_t *comp = halloc( global_context, sizeof( comp_t ) ); + comp->comp = al_halloc( global_context ); + + for( start=end=next; *end; end++ ) + { + wchar_t c = *end; + + if( c == COMPLETE_ITEM_SEP || c==COMPLETE_SEP ) + { + *end = 0; + wchar_t * str = escape( start, 1 ); + comp->comp_width += my_wcswidth( str ); + halloc_register( global_context, str ); + al_push( comp->comp, str ); + start = end+1; + } + + if( c == COMPLETE_SEP ) + { + comp->desc = halloc_wcsdup( global_context, start ); + break; + } + } + + comp->comp_width += my_wcswidth(prefix)*al_get_count(comp->comp) + (al_get_count(comp->comp)-1); + comp->desc_width = comp->desc?my_wcswidth( comp->desc ):0; + + comp->pref_width = comp->comp_width + comp->desc_width + (comp->desc_width?4:0); + + free( next ); + al_set( l, i, comp ); + } + + recalc_width( l, prefix ); +} + + + +/** Respond to a winch signal by checking the terminal size */ static void handle_winch( int sig ) @@ -942,45 +883,48 @@ void destroy() del_curterm( cur_term ); sb_destroy( &out_buff ); fclose( out_file ); - } int main( int argc, char **argv ) { int i; int is_quoted=0; - array_list_t comp; + array_list_t *comp; wchar_t *prefix; - init(); + if( argc < 3 ) { debug( 0, L"Insufficient arguments" ); } else { + comp = al_halloc( global_context ); prefix = str2wcs( argv[2] ); is_quoted = strcmp( "1", argv[1] )==0; - + is_quoted = 0; + debug( 3, L"prefix is '%ls'", prefix ); - - al_init( &comp ); - + for( i=3; i<argc; i++ ) { wchar_t *wcs = str2wcs( argv[i] ); if( wcs ) { - al_push( &comp, wcs ); + al_push( comp, wcs ); } } - mangle_descriptions( &comp ); - + mangle_descriptions( comp ); + if( wcscmp( prefix, L"-" ) == 0 ) + join_completions( comp ); + mangle_completions( comp, prefix ); + + for( i = 6; i>0; i-- ) { - switch( completion_try_print( i, prefix, is_quoted, &comp ) ) + switch( completion_try_print( i, prefix, is_quoted, comp ) ) { case 0: break; @@ -994,8 +938,6 @@ int main( int argc, char **argv ) } - al_foreach( &comp, (void(*)(const void *))&free ); - al_destroy( &comp ); free(prefix ); fwprintf( out_file, L"%ls", (wchar_t *)out_buff.buff ); |