/** \file highlight.c Functions for syntax highlighting */ #include #include #include #include #include #include #include #include #include #include "config.h" #include "fallback.h" #include "util.h" #include "wutil.h" #include "highlight.h" #include "tokenizer.h" #include "proc.h" #include "parser.h" #include "parse_util.h" #include "builtin.h" #include "function.h" #include "env.h" #include "expand.h" #include "sanity.h" #include "common.h" #include "complete.h" #include "output.h" static void highlight_universal_internal( wchar_t * buff, int *color, int pos, array_list_t *error ); /** The environment variables used to specify the color of different tokens. */ static wchar_t *highlight_var[] = { L"fish_color_normal", L"fish_color_command", L"fish_color_redirection", L"fish_color_end", L"fish_color_error", L"fish_color_param", L"fish_color_comment", L"fish_color_match", L"fish_color_search_match", L"fish_color_operator", L"fish_color_escape", L"fish_color_quote" } ; #define VAR_COUNT ( sizeof(highlight_var)/sizeof(wchar_t *) ) int highlight_get_color( int highlight ) { if( highlight < 0 ) return FISH_COLOR_NORMAL; if( highlight >= VAR_COUNT ) return FISH_COLOR_NORMAL; wchar_t *val = env_get( highlight_var[highlight]); if( val == 0 ) val = env_get( highlight_var[HIGHLIGHT_NORMAL]); if( val == 0 ) { return FISH_COLOR_NORMAL; } return output_color_code( val ); } /** Highligt operators (such as $, ~, %, as well as escaped characters. */ static void highlight_param( const wchar_t * buff, int *color, int pos, array_list_t *error ) { int mode = 0; int in_pos, len = wcslen( buff ); int bracket_count=0; wchar_t c; for( in_pos=0; in_pos= 0 ) last_val = color[i]; else color[i] = last_val; } highlight_universal_internal( buff, color, pos, error ); /* Spaces should not be highlighted at all, since it makes cursor look funky in some terminals */ for( i=0; buff[i]; i++ ) { if( iswspace(buff[i]) ) { color[i]=0; } } } /** Perform quote and parenthesis highlighting on the specified string. */ static void highlight_universal_internal( wchar_t * buff, int *color, int pos, array_list_t *error ) { if( (pos >= 0) && (pos < wcslen(buff)) ) { /* Highlight matching quotes */ if( (buff[pos] == L'\'') || (buff[pos] == L'\"') ) { array_list_t l; al_init( &l ); int level=0; wchar_t prev_q=0; wchar_t *str=buff; int match_found=0; while(*str) { switch( *str ) { case L'\\': str++; break; case L'\"': case L'\'': if( level == 0 ) { level++; al_push( &l, (void *)(str-buff) ); prev_q = *str; } else { if( prev_q == *str ) { int pos1, pos2; level--; pos1 = (int)al_pop( &l ); pos2 = str-buff; if( pos1==pos || pos2==pos ) { color[pos1]|=HIGHLIGHT_MATCH<<8; color[pos2]|=HIGHLIGHT_MATCH<<8; match_found = 1; } prev_q = *str==L'\"'?L'\'':L'\"'; } else { level++; al_push( &l, (void *)(str-buff) ); prev_q = *str; } } break; } if( (*str == L'\0')) break; str++; } al_destroy( &l ); if( !match_found ) color[pos] = HIGHLIGHT_ERROR<<8; } /* Highlight matching parenthesis */ if( wcschr( L"()[]{}", buff[pos] ) ) { int step = wcschr(L"({[", buff[pos])?1:-1; wchar_t dec_char = *(wcschr( L"()[]{}", buff[pos] ) + step); wchar_t inc_char = buff[pos]; int level = 0; wchar_t *str = &buff[pos]; int match_found=0; while( (str >= buff) && *str) { if( *str == inc_char ) level++; if( *str == dec_char ) level--; if( level == 0 ) { int pos2 = str-buff; color[pos]|=HIGHLIGHT_MATCH<<8; color[pos2]|=HIGHLIGHT_MATCH<<8; match_found=1; break; } str+= step; } if( !match_found ) color[pos] = HIGHLIGHT_ERROR<<8; } } } void highlight_universal( wchar_t * buff, int *color, int pos, array_list_t *error ) { int i; for( i=0; buff[i] != 0; i++ ) color[i] = 0; highlight_universal_internal( buff, color, pos, error ); }