mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-04-01 01:15:14 +08:00
Update history loading/saving to handle multiline editing
darcs-hash:20061008135046-ac50b-e830fe313e23f632b9c645227f41c49c8ce600f4.gz
This commit is contained in:
parent
6400b60bdd
commit
179f575593
197
history.c
197
history.c
@ -104,6 +104,11 @@ static int is_loaded=0;
|
||||
|
||||
static ll_node_t *unused = 0;
|
||||
|
||||
/**
|
||||
Create a new ll_node_t struct. The struct is allocated using
|
||||
halloc, and will be automatically free'd on shutdown, but not
|
||||
before.
|
||||
*/
|
||||
static ll_node_t *history_create_node()
|
||||
{
|
||||
ll_node_t *res;
|
||||
@ -119,12 +124,182 @@ static ll_node_t *history_create_node()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Return a ll_node_t struct to the pool of unused such structs, so
|
||||
that it can later be reused by a call to history_create_node().
|
||||
*/
|
||||
static void history_free_node( ll_node_t *n )
|
||||
{
|
||||
n->next = unused;
|
||||
unused = n;
|
||||
}
|
||||
|
||||
/**
|
||||
Add backslashes to all newlines, so that the returning string is
|
||||
suitable for writing to the history file. The memory for the return
|
||||
value will be reused by subsequent calls to this function.
|
||||
*/
|
||||
static wchar_t *history_escape_newlines( wchar_t *in )
|
||||
{
|
||||
static string_buffer_t *out = 0;
|
||||
if( !out )
|
||||
{
|
||||
out = sb_halloc( global_context );
|
||||
if( !out )
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_clear( out );
|
||||
}
|
||||
for( ; *in; in++ )
|
||||
{
|
||||
if( *in == L'\\' )
|
||||
{
|
||||
sb_append_char( out, *in );
|
||||
if( *(in+1) )
|
||||
{
|
||||
in++;
|
||||
sb_append_char( out, *in );
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
This is a weird special case. When we are trying to
|
||||
save a string that ends with a backslash, we need to
|
||||
handle it specially, otherwise this command would be
|
||||
combined with the one following it. We hack around
|
||||
this by adding an additional newline.
|
||||
*/
|
||||
sb_append_char( out, L'\n' );
|
||||
}
|
||||
|
||||
}
|
||||
else if( *in == L'\n' )
|
||||
{
|
||||
sb_append_char( out, L'\\' );
|
||||
sb_append_char( out, *in );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_append_char( out, *in );
|
||||
}
|
||||
|
||||
}
|
||||
return (wchar_t *)out->buff;
|
||||
}
|
||||
|
||||
/**
|
||||
Remove backslashes from all newlines. This makes a string from the
|
||||
history file better formated for on screen display. The memory for
|
||||
the return value will be reused by subsequent calls to this
|
||||
function.
|
||||
*/
|
||||
static wchar_t *history_unescape_newlines( wchar_t *in )
|
||||
{
|
||||
static string_buffer_t *out = 0;
|
||||
if( !out )
|
||||
{
|
||||
out = sb_halloc( global_context );
|
||||
if( !out )
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_clear( out );
|
||||
}
|
||||
for( ; *in; in++ )
|
||||
{
|
||||
if( *in == L'\\' )
|
||||
{
|
||||
if( *(in+1)!= L'\n')
|
||||
{
|
||||
sb_append_char( out, *in );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_append_char( out, *in );
|
||||
}
|
||||
|
||||
}
|
||||
return (wchar_t *)out->buff;
|
||||
}
|
||||
|
||||
/**
|
||||
Read a complete histor entry from the specified FILE.
|
||||
*/
|
||||
static wchar_t *history_load_entry( FILE *in )
|
||||
{
|
||||
int was_backslash = 0;
|
||||
static string_buffer_t *out = 0;
|
||||
int first_char = 1;
|
||||
int ignore = 0;
|
||||
|
||||
if( !out )
|
||||
{
|
||||
out = sb_halloc( global_context );
|
||||
if( !out )
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_clear( out );
|
||||
}
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
wint_t c;
|
||||
|
||||
c = getwc( in );
|
||||
|
||||
|
||||
if( errno == EILSEQ )
|
||||
{
|
||||
getc( in );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( c == WEOF )
|
||||
break;
|
||||
|
||||
|
||||
if( c == L'\n' )
|
||||
{
|
||||
if( ignore )
|
||||
{
|
||||
ignore = 0;
|
||||
continue;
|
||||
}
|
||||
if( !was_backslash )
|
||||
break;
|
||||
}
|
||||
|
||||
if( first_char )
|
||||
{
|
||||
if( c == L'#' )
|
||||
ignore = 1;
|
||||
}
|
||||
|
||||
first_char = 0;
|
||||
|
||||
if( !ignore )
|
||||
sb_append_char( out, c );
|
||||
|
||||
was_backslash = ( (c == L'\\') && !was_backslash);
|
||||
|
||||
}
|
||||
|
||||
return (wchar_t *)out->buff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Load history from file
|
||||
*/
|
||||
@ -132,7 +307,6 @@ static int history_load()
|
||||
{
|
||||
wchar_t *fn;
|
||||
wchar_t *buff=0;
|
||||
int buff_len=0;
|
||||
FILE *in_stream;
|
||||
hash_table_t used;
|
||||
int res = 0;
|
||||
@ -158,18 +332,7 @@ static int history_load()
|
||||
{
|
||||
while( !feof( in_stream ) )
|
||||
{
|
||||
int buff_read = fgetws2( &buff, &buff_len, in_stream );
|
||||
if( buff_read == -1 )
|
||||
{
|
||||
debug( 1, L"The following non-fatal error occurred while reading command history from \'%ls\':", mode_name );
|
||||
wperror( L"fgetws2" );
|
||||
fclose( in_stream );
|
||||
free( fn );
|
||||
free( buff );
|
||||
signal_unblock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
buff = history_unescape_newlines(history_load_entry( in_stream ));
|
||||
/*
|
||||
We do not call history_add here, since that would make
|
||||
history_load() take quadratic time, and may be
|
||||
@ -206,7 +369,7 @@ static int history_load()
|
||||
{
|
||||
if( errno != ENOENT )
|
||||
{
|
||||
debug( 1, L"The following non-fatal error occurred while reading command history from \'%ls\':", mode_name );
|
||||
debug( 1, _(L"The following non-fatal error occurred while reading command history from \'%ls\':"), mode_name );
|
||||
wperror( L"fopen" );
|
||||
res = -1;
|
||||
|
||||
@ -217,7 +380,6 @@ static int history_load()
|
||||
|
||||
hash_destroy( &used );
|
||||
|
||||
free( buff );
|
||||
free( fn );
|
||||
last_loaded = history_last;
|
||||
signal_unblock();
|
||||
@ -309,10 +471,13 @@ void history_set_mode( wchar_t *name )
|
||||
*/
|
||||
static void history_save_node( ll_node_t *n, FILE *out )
|
||||
{
|
||||
wchar_t *escaped;
|
||||
if( n==0 )
|
||||
return;
|
||||
history_save_node( n->prev, out );
|
||||
fwprintf(out, L"%ls\n", (wchar_t *)(n->data) );
|
||||
|
||||
escaped = history_escape_newlines( (wchar_t *)(n->data) );
|
||||
fwprintf(out, L"#\n%ls\n", escaped );
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user