/** \file output.c Generic output functions */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_TERMIOS_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #include #include #include #if HAVE_NCURSES_H #include #else #include #endif #if HAVE_TERMIO_H #include #endif #if HAVE_TERM_H #include #elif HAVE_NCURSES_TERM_H #include #endif #include #include #include #include #include #include "fallback.h" #include "util.h" #include "wutil.h" #include "expand.h" #include "common.h" #include "output.h" #include "halloc_util.h" #include "highlight.h" /** Number of color names in the col array */ #define COLORS (sizeof(col)/sizeof(wchar_t *)) static int writeb_internal( char c ); /** Names of different colors. */ static const wchar_t *col[]= { L"black", L"red", L"green", L"brown", L"yellow", L"blue", L"magenta", L"purple", L"cyan", L"white" L"normal" } ; /** Mapping from color name (the 'col' array) to color index as used in ANSI color terminals, and also the fish_color_* constants defined in highlight.h. Non-ANSI terminals will display the wrong colors, since they use a different mapping. */ static const int col_idx[]= { 0, 1, 2, 3, 3, 4, 5, 5, 6, 7, FISH_COLOR_NORMAL, }; /** The function used for output */ static int (*out)(char c) = &writeb_internal; /** Name of terminal */ static wchar_t *current_term = 0; void output_set_writer( int (*writer)(char) ) { CHECK( writer, ); out = writer; } int (*output_get_writer())(char) { return out; } void set_color( int c, int c2 ) { ASSERT_IS_MAIN_THREAD(); static int last_color = FISH_COLOR_NORMAL; static int last_color2 = FISH_COLOR_NORMAL; static int was_bold=0; static int was_underline=0; int bg_set=0, last_bg_set=0; char *fg = 0, *bg=0; int is_bold = 0; int is_underline = 0; /* Test if we have at least basic support for setting fonts, colors and related bits - otherwise just give up... */ if( !exit_attribute_mode ) { return; } is_bold |= (c&FISH_COLOR_BOLD)!=0; is_bold |= (c2&FISH_COLOR_BOLD)!=0; is_underline |= (c&FISH_COLOR_UNDERLINE)!=0; is_underline |= (c2&FISH_COLOR_UNDERLINE)!=0; c = c&(~(FISH_COLOR_BOLD|FISH_COLOR_UNDERLINE)); c2 = c2&(~(FISH_COLOR_BOLD|FISH_COLOR_UNDERLINE)); if( (set_a_foreground != 0) && (strlen( set_a_foreground) != 0 ) ) { fg = set_a_foreground; bg = set_a_background; } else if( (set_foreground != 0) && (strlen( set_foreground) != 0 ) ) { fg = set_foreground; bg = set_background; } if( (c == FISH_COLOR_RESET) || (c2 == FISH_COLOR_RESET)) { c = c2 = FISH_COLOR_NORMAL; was_bold=0; was_underline=0; if( fg ) { /* If we exit attibute mode, we must first set a color, or previously coloured text might lose it's color. Terminals are weird... */ writembs( tparm( fg, 0 ) ); } writembs( exit_attribute_mode ); return; } if( was_bold && !is_bold ) { /* Only way to exit bold mode is a reset of all attributes. */ writembs( exit_attribute_mode ); last_color = FISH_COLOR_NORMAL; last_color2 = FISH_COLOR_NORMAL; was_bold=0; was_underline=0; } if( last_color2 != FISH_COLOR_NORMAL && last_color2 != FISH_COLOR_RESET && last_color2 != FISH_COLOR_IGNORE ) { /* Background was set */ last_bg_set=1; } if( c2 != FISH_COLOR_NORMAL && c2 != FISH_COLOR_IGNORE ) { /* Background is set */ bg_set=1; c = (c2==FISH_COLOR_WHITE)?FISH_COLOR_BLACK:FISH_COLOR_WHITE; } if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0)) { if(bg_set && !last_bg_set) { /* Background color changed and is set, so we enter bold mode to make reading easier. This means bold mode is _always_ on when the background color is set. */ writembs( enter_bold_mode ); } if(!bg_set && last_bg_set) { /* Background color changed and is no longer set, so we exit bold mode */ writembs( exit_attribute_mode ); was_bold=0; was_underline=0; /* We don't know if exit_attribute_mode resets colors, so we set it to something known. */ if( fg ) { writembs( tparm( fg, 0 ) ); last_color=0; } } } if( last_color != c ) { if( c==FISH_COLOR_NORMAL ) { if( fg ) { writembs( tparm( fg, 0 ) ); } writembs( exit_attribute_mode ); last_color2 = FISH_COLOR_NORMAL; was_bold=0; was_underline=0; } else if( ( c >= 0 ) && ( c < FISH_COLOR_NORMAL ) ) { if( fg ) { writembs( tparm( fg, c ) ); } } } last_color = c; if( last_color2 != c2 ) { if( c2 == FISH_COLOR_NORMAL ) { if( bg ) { writembs( tparm( bg, 0 ) ); } writembs( exit_attribute_mode ); if( ( last_color != FISH_COLOR_NORMAL ) && fg ) { if( fg ) { writembs( tparm( fg, last_color ) ); } } was_bold=0; was_underline=0; last_color2 = c2; } else if ( ( c2 >= 0 ) && ( c2 < FISH_COLOR_NORMAL ) ) { if( bg ) { writembs( tparm( bg, c2 ) ); } last_color2 = c2; } } /* Lastly, we set bold mode and underline mode correctly */ if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0) && !bg_set ) { if( is_bold && !was_bold ) { if( enter_bold_mode ) { writembs( tparm( enter_bold_mode ) ); } } was_bold = is_bold; } if( was_underline && !is_underline ) { writembs( exit_underline_mode ); } if( !was_underline && is_underline ) { writembs( enter_underline_mode ); } was_underline = is_underline; } /** Default output method, simply calls write() on stdout */ static int writeb_internal( char c ) { write_loop( 1, &c, 1 ); return 0; } int writeb( tputs_arg_t b ) { out( b ); return 0; } int writembs_internal( char *str ) { CHECK( str, 1 ); return tputs(str,1,&writeb)==ERR?1:0; } int writech( wint_t ch ) { mbstate_t state; size_t i; char buff[MB_LEN_MAX+1]; size_t bytes; if( ( ch >= ENCODE_DIRECT_BASE) && ( ch < ENCODE_DIRECT_BASE+256) ) { buff[0] = ch - ENCODE_DIRECT_BASE; bytes=1; } else { memset( &state, 0, sizeof(state) ); bytes= wcrtomb( buff, ch, &state ); switch( bytes ) { case (size_t)(-1): { return 1; } } } for( i=0; imax_width ) { break; } written+=w; writech( *(str++) ); } written += wcwidth( ellipsis_char ); writech( ellipsis_char ); while( written < max_width ) { written++; writestr( L" " ); } } int write_escaped_str( const wchar_t *str, int max_len ) { wchar_t *out; int i; int len; int written=0; CHECK( str, 0 ); out = escape( str, 1 ); len = my_wcswidth( out ); if( max_len && (max_len < len)) { for( i=0; (written+wcwidth(out[i]))<=(max_len-1); i++ ) { writech( out[i] ); written += wcwidth( out[i] ); } writech( ellipsis_char ); written += wcwidth( ellipsis_char ); for( i=written; i"); }