Autodetect common escape codes in fish_prompt output

darcs-hash:20051213101859-ac50b-0ff01bb168d894d401d3d93cc11740789bac0d62.gz
This commit is contained in:
axel 2005-12-13 20:18:59 +10:00
parent 9c32709fe1
commit 8bf0a14bd5
4 changed files with 129 additions and 20 deletions

View File

@ -915,17 +915,11 @@ The default \c fish prompt is
<p>
<pre>
function fish_prompt -d "Write out the prompt"
printf '\%s\@\%s\%s\\n\%s\%s\\n> ' (whoami) (hostname|cut -d . -f 1) (set_color \$fish_color_cwd) (prompt_pwd) (set_color normal)
printf '\%s\@\%s\%s\%s\%s> ' (whoami) (hostname|cut -d . -f 1) (set_color \$fish_color_cwd) (prompt_pwd) (set_color normal)
end
</pre>
</p>
If you are using \c set_color or other commands that output escape
codes to change the font settings of the terminal, you must always and
every such sequence with a newline. This is needed since fish needs to
know that exact length of the prompt in order to tetect when the
cursor reaches the end of the line. Any newlines in the output of the
\c fish_prompt command are ignored.
\subsection title Programmable title

View File

@ -29,7 +29,7 @@ end
# long it is.
function fish_prompt -d "Write out the prompt"
printf '%s@%s \n%s\n%s\n%s\n> ' (whoami) (hostname|cut -d . -f 1) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
printf '%s@%s %s%s%s> \n' (whoami) (hostname|cut -d . -f 1) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
end
#

View File

@ -128,7 +128,7 @@ void set_color( int c, int c2 )
{
c = c2 = FISH_COLOR_NORMAL;
if( fg )
writembs( tparm( set_a_foreground, 0 ) );
writembs( tparm( fg, 0 ) );
writembs( exit_attribute_mode );
return;
}

137
reader.c
View File

@ -620,6 +620,129 @@ void reader_write_title()
set_color( FISH_COLOR_RESET, FISH_COLOR_RESET );
}
/**
Tests if the specified narrow character sequence is present at the
specified position of the specified wide character string. All of
\c seq must match, but str may be longer than seq.
*/
static int try_sequence( char *seq, wchar_t *str )
{
int i;
for( i=0;; i++ )
{
if( !seq[i] )
return i;
if( seq[i] != str[i] )
return 0;
}
return 0;
}
/**
Calculate the width of the specified prompt. Does some clever magic
to detect common escape sequences that may be embeded in a prompt,
such as color codes.
*/
static int calc_prompt_width( array_list_t *arr )
{
int res = 0;
int i, j, k;
for( i=0; i<al_get_count( arr ); i++ )
{
wchar_t *next = (wchar_t *)al_get( arr, i );
for( j=0; next[j]; j++ )
{
if( next[j] == L'\e' )
{
/*
This is the start of an escape code. Try to guess it's width.
*/
int l;
int len=0;
int found = 0;
/*
Test these color escapes with parameter value 0..7
*/
char * esc[] =
{
set_a_foreground,
set_a_background,
set_foreground,
set_background,
}
;
/*
Test these regular escapes without any parameter values
*/
char *esc2[] =
{
enter_bold_mode,
exit_attribute_mode,
enter_underline_mode,
exit_underline_mode,
enter_standout_mode,
exit_standout_mode,
flash_screen
}
;
for( l=0; l < (sizeof(esc)/sizeof(char *)) && !found; l++ )
{
if( !esc[l] )
continue;
for( k=0; k<8; k++ )
{
len = try_sequence( tparm(esc[l],k), &next[j] );
if( len )
{
j += (len-1);
found = 1;
break;
}
}
}
for( l=0; l < (sizeof(esc2)/sizeof(char *)) && !found; l++ )
{
if( !esc2[l] )
continue;
/*
Test both padded and unpadded version, just to
be safe. Most versions of tparm don't actually
seem to do anything these days.
*/
len = maxi( try_sequence( tparm(esc2[l]), &next[j] ),
try_sequence( esc2[l], &next[j] ));
if( len )
{
j += (len-1);
found = 1;
}
}
}
else
{
/*
Ordinary decent character. Just add width.
*/
res += wcwidth( next[j] );
}
}
}
return res;
}
/**
Write the prompt to screen. If data->exec_prompt is set, the prompt
command is first evaluated, and the title will be reexecuted as
@ -649,14 +772,8 @@ static void write_prompt()
al_init( &prompt_list );
}
}
data->prompt_width=0;
for( i=0; i<al_get_count( &prompt_list ); i++ )
{
wchar_t *next = (wchar_t *)al_get( &prompt_list, i );
if( *next == L'\e' )
continue;
data->prompt_width += my_wcswidth( next );
}
data->prompt_width=calc_prompt_width( &prompt_list );
data->exec_prompt = 0;
reader_write_title();
@ -2509,9 +2626,7 @@ wchar_t *reader_readline()
if( last_char != R_YANK && last_char != R_YANK_POP )
yank=0;
switch (c)
switch( c )
{
/* go to beginning of line*/