Prevent multi-line prompts from repeating during window resize

Fixes https://github.com/fish-shell/fish-shell/issues/321
This commit is contained in:
ridiculousfish 2012-10-15 19:25:56 -07:00
parent 211b9ea8b9
commit 618b42980d

View file

@ -162,69 +162,70 @@ static bool allow_soft_wrap(void)
to detect common escape sequences that may be embeded in a prompt,
such as color codes.
*/
static size_t calc_prompt_width( const wchar_t *prompt )
static size_t calc_prompt_width_and_lines( const wchar_t *prompt, size_t *out_prompt_lines )
{
size_t res = 0;
size_t j, k;
*out_prompt_lines = 1;
for( j=0; prompt[j]; j++ )
{
if( prompt[j] == L'\x1b' )
{
/*
This is the start of an escape code. Try to guess it's width.
*/
This is the start of an escape code. Try to guess it's width.
*/
size_t p;
int len=0;
bool found = false;
/*
Detect these terminfo color escapes with parameter
value 0..7, all of which don't move the cursor
*/
Detect these terminfo color escapes with parameter
value 0..7, all of which don't move the cursor
*/
char * const esc[] =
{
set_a_foreground,
set_a_background,
set_foreground,
set_background,
}
{
set_a_foreground,
set_a_background,
set_foreground,
set_background,
}
;
/*
Detect these semi-common terminfo escapes without any
parameter values, all of which don't move the cursor
*/
Detect these semi-common terminfo escapes without any
parameter values, all of which don't move the cursor
*/
char * const esc2[] =
{
enter_bold_mode,
exit_attribute_mode,
enter_underline_mode,
exit_underline_mode,
enter_standout_mode,
exit_standout_mode,
flash_screen,
enter_subscript_mode,
exit_subscript_mode,
enter_superscript_mode,
exit_superscript_mode,
enter_blink_mode,
enter_italics_mode,
exit_italics_mode,
enter_reverse_mode,
enter_shadow_mode,
exit_shadow_mode,
enter_standout_mode,
exit_standout_mode,
enter_secure_mode
}
{
enter_bold_mode,
exit_attribute_mode,
enter_underline_mode,
exit_underline_mode,
enter_standout_mode,
exit_standout_mode,
flash_screen,
enter_subscript_mode,
exit_subscript_mode,
enter_superscript_mode,
exit_superscript_mode,
enter_blink_mode,
enter_italics_mode,
exit_italics_mode,
enter_reverse_mode,
enter_shadow_mode,
exit_shadow_mode,
enter_standout_mode,
exit_standout_mode,
enter_secure_mode
}
;
for( p=0; p < sizeof esc / sizeof *esc && !found; p++ )
{
if( !esc[p] )
continue;
for( k=0; k<8; k++ )
{
len = try_sequence( tparm(esc[p],k), &prompt[j] );
@ -245,27 +246,27 @@ static size_t calc_prompt_width( const wchar_t *prompt )
found = true;
}
}
for( p=0; p < (sizeof(esc2)/sizeof(char *)) && !found; p++ )
{
if( !esc2[p] )
continue;
/*
Test both padded and unpadded version, just to
be safe. Most versions of tparm don't actually
seem to do anything these days.
*/
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[p]), &prompt[j] ),
try_sequence( esc2[p], &prompt[j] ));
try_sequence( esc2[p], &prompt[j] ));
if( len )
{
j += (len-1);
found = true;
}
}
if( !found )
{
if( prompt[j+1] == L'k' )
@ -280,13 +281,13 @@ static size_t calc_prompt_width( const wchar_t *prompt )
if( end )
{
/*
You'd thing this should be
'(end-prompt)+2', in order to move j
past the end of the string, but there is
a 'j++' at the end of each lap, so j
should always point to the last menged
character, e.g. +1.
*/
You'd thing this should be
'(end-prompt)+2', in order to move j
past the end of the string, but there is
a 'j++' at the end of each lap, so j
should always point to the last menged
character, e.g. +1.
*/
j = (end-prompt)+1;
}
else
@ -296,7 +297,7 @@ static size_t calc_prompt_width( const wchar_t *prompt )
}
}
}
}
else if( prompt[j] == L'\t' )
{
@ -305,18 +306,38 @@ static size_t calc_prompt_width( const wchar_t *prompt )
else if( prompt[j] == L'\n' )
{
res = 0;
*out_prompt_lines += 1;
}
else
{
/*
Ordinary decent character. Just add width.
*/
Ordinary decent character. Just add width.
*/
res += fish_wcwidth( prompt[j] );
}
}
return res;
}
static size_t calc_prompt_width(const wchar_t *prompt)
{
size_t ignored;
return calc_prompt_width_and_lines(prompt, &ignored);
}
static size_t calc_prompt_lines(const wchar_t *prompt)
{
// Hack for the common case where there's no newline at all
// I don't know if a newline can appear in an escape sequence,
// so if we detect a newline we have to defer to calc_prompt_width_and_lines
size_t result = 1;
if (wcschr(prompt, L'\n') != NULL)
{
calc_prompt_width_and_lines(prompt, &result);
}
return result;
}
/**
Test if there is space between the time fields of struct stat to
use for sub second information. If so, we assume this space
@ -987,19 +1008,26 @@ void s_reset( screen_t *s, bool reset_cursor )
/* If we are resetting the cursor, we're going to make a new line and leave junk behind. If we are not resetting the cursor, we need to remember how many lines we had output to, so we can clear the remaining lines in the next call to s_update. This prevents leaving junk underneath the cursor when resizing a window wider such that it reduces our desired line count. */
if (! reset_cursor)
s->actual_lines_before_reset = s->actual.line_count();
int prev_line = s->actual.cursor.y;
/* If the prompt is multi-line, we need to move up to the prompt's initial line. We do this by lying to ourselves and claiming that we're really below what we consider "line 0" (which is the last line of the prompt). This will cause is to move up to try to get back to line 0, but really we're getting back to the initial line of the prompt. */
const size_t prompt_line_count = calc_prompt_lines(s->actual_prompt.c_str());
assert(prompt_line_count >= 1);
prev_line += (prompt_line_count - 1);
s->actual.resize(0);
s->actual.cursor.x = s->actual.cursor.y = 0;
s->actual_prompt = L"";
s->actual.cursor.x = 0;
s->actual.cursor.y = 0;
s->actual_prompt.clear();
s->need_clear=true;
if( !reset_cursor )
{
/*
This should prevent reseting the cursor position during the
next repaint.
*/
This should prevent reseting the cursor position during the
next repaint.
*/
write_loop( 1, "\r", 1 );
s->actual.cursor.y = prev_line;
}