Make automatic history reloading actually work the way it should

darcs-hash:20061022012102-ac50b-e57a0dd2c918a2a8abd0210b9f8a2163ce664b74.gz
This commit is contained in:
axel 2006-10-22 11:21:02 +10:00
parent da81328d75
commit b83a7cb659

117
history.c
View file

@ -58,6 +58,15 @@ typedef struct
*/ */
array_list_t item; array_list_t item;
/**
A hash table containing all the items created by the current
session as keys. This can be used as a lookup when loading the
history list to ignore the on-file version of an entry from
this session.
*/
hash_table_t session_item;
/** /**
The current history position The current history position
*/ */
@ -129,6 +138,25 @@ static hash_table_t *mode_table=0;
*/ */
static history_mode_t *current_mode=0; static history_mode_t *current_mode=0;
/**
Hash function for item_t struct
*/
static int hash_item_func( void *v )
{
item_t *i = (item_t *)v;
return i->timestamp ^ hash_wcs_func( i->data );
}
/**
Comparison function for item_t struct
*/
static int hash_item_cmp( void *v1, void *v2 )
{
item_t *i1 = (item_t *)v1;
item_t *i2 = (item_t *)v2;
return (i1->timestamp == i2->timestamp) && (wcscmp( i1->data, i2->data )==0);
}
/** /**
Add backslashes to all newlines, so that the returning string is Add backslashes to all newlines, so that the returning string is
suitable for writing to the history file. The memory for the return suitable for writing to the history file. The memory for the return
@ -397,6 +425,9 @@ static history_mode_t *history_create_mode( const wchar_t *name )
halloc_register_function( new_mode, (void (*)(void *))&al_destroy, &new_mode->item ); halloc_register_function( new_mode, (void (*)(void *))&al_destroy, &new_mode->item );
halloc_register_function( new_mode, (void (*)(void *))&al_destroy, &new_mode->used ); halloc_register_function( new_mode, (void (*)(void *))&al_destroy, &new_mode->used );
hash_init( &new_mode->session_item, &hash_item_func, &hash_item_cmp );
halloc_register_function( new_mode, (void (*)(void *))&hash_destroy, &new_mode->session_item );
new_mode->save_timestamp=time(0); new_mode->save_timestamp=time(0);
new_mode->item_context = halloc( 0,0 ); new_mode->item_context = halloc( 0,0 );
@ -447,12 +478,14 @@ static void history_populate_from_mmap( history_mode_t *m )
char *end = begin + m->mmap_length; char *end = begin + m->mmap_length;
char *pos; char *pos;
array_list_t tmp; array_list_t old_item;
array_list_t session_item_list;
int ignore_newline = 0; int ignore_newline = 0;
int do_push = 1; int do_push = 1;
al_init( &tmp ); al_init( &old_item );
al_push_all( &tmp, &m->item ); al_init( &session_item_list );
al_push_all( &old_item, &m->item );
al_truncate( &m->item, 0 ); al_truncate( &m->item, 0 );
for( pos = begin; pos <end; pos++ ) for( pos = begin; pos <end; pos++ )
@ -460,9 +493,23 @@ static void history_populate_from_mmap( history_mode_t *m )
if( do_push ) if( do_push )
{ {
item_t *i;
item_t *i_orig;
ignore_newline = *pos == '#'; ignore_newline = *pos == '#';
i = item_get( m, pos );
assert( i!=pos );
if( (i_orig=hash_get( &current_mode->session_item, i ) ) )
{
al_push( &session_item_list, i_orig );
}
else
{
al_push( &m->item, pos ); al_push( &m->item, pos );
// debug( 0, L"Push item at offset %d", pos-begin ); }
do_push = 0; do_push = 0;
} }
@ -489,11 +536,13 @@ static void history_populate_from_mmap( history_mode_t *m )
} }
} }
al_push_all( &m->item, &session_item_list );
m->pos += al_get_count( &m->item ); m->pos += al_get_count( &m->item );
al_push_all( &m->item, &tmp ); al_push_all( &m->item, &old_item );
al_destroy( &tmp );
// debug( 0, L"History has %d items", al_get_count( &m->item ));
al_destroy( &session_item_list );
al_destroy( &old_item );
} }
/** /**
@ -510,6 +559,8 @@ static void history_load( history_mode_t *m )
if( !m ) if( !m )
return; return;
m->has_loaded=1;
signal_block(); signal_block();
context = halloc( 0, 0 ); context = halloc( 0, 0 );
@ -536,31 +587,10 @@ static void history_load( history_mode_t *m )
} }
} }
m->has_loaded=1;
halloc_free( context ); halloc_free( context );
signal_unblock(); signal_unblock();
} }
/**
Hash function for item_t struct
*/
static int hash_item_func( void *v )
{
item_t *i = (item_t *)v;
return i->timestamp ^ hash_wcs_func( i->data );
}
/**
Comparison function for item_t struct
*/
static int hash_item_cmp( void *v1, void *v2 )
{
item_t *i1 = (item_t *)v1;
item_t *i2 = (item_t *)v2;
return (i1->timestamp == i2->timestamp) && (wcscmp( i1->data, i2->data )==0);
}
/** /**
Save the specified mode to file Save the specified mode to file
*/ */
@ -657,19 +687,24 @@ static void history_save_mode( void *n, history_mode_t *m )
} }
halloc_free( on_disk); halloc_free( on_disk);
/* /*
Reset the history. The item_t entries created in this session
are not lost or dropped, they are stored in the session_item
hash table. On reload, they will be automatically inserted at
the end of the history list.
*/
if( m->mmap_start && (m->mmap_start != MAP_FAILED ) ) if( m->mmap_start && (m->mmap_start != MAP_FAILED ) )
munmap( m->mmap_start, m->mmap_length ); munmap( m->mmap_start, m->mmap_length );
halloc_free( m->item_context );
m->item_context = halloc( 0, 0 );
al_truncate( &m->item, 0 ); al_truncate( &m->item, 0 );
al_truncate( &m->used, 0 ); al_truncate( &m->used, 0 );
m->pos = 0; m->pos = 0;
m->has_loaded = 0; m->has_loaded = 0;
m->mmap_start=0; m->mmap_start=0;
m->mmap_length=0; m->mmap_length=0;
*/
m->save_timestamp=time(0); m->save_timestamp=time(0);
m->new_count = 0; m->new_count = 0;
@ -689,6 +724,8 @@ void history_add( const wchar_t *str )
i->timestamp = time(0); i->timestamp = time(0);
al_push( &current_mode->item, i ); al_push( &current_mode->item, i );
hash_put( &current_mode->session_item, i, i );
al_truncate( &current_mode->used, 0 ); al_truncate( &current_mode->used, 0 );
current_mode->pos = al_get_count( &current_mode->item ); current_mode->pos = al_get_count( &current_mode->item );
@ -744,7 +781,7 @@ const wchar_t *history_prev_match( const wchar_t *needle )
there is a chance that the return value of any there is a chance that the return value of any
previous call to item_get will become previous call to item_get will become
invalid. The history_is_used function uses the invalid. The history_is_used function uses the
istem_get() function. Therefore, we must create item_get() function. Therefore, we must create
a copy of the haystack string, and if the string a copy of the haystack string, and if the string
is unused, we must call item_get anew. is unused, we must call item_get anew.
*/ */
@ -825,6 +862,9 @@ void history_reset()
if( current_mode ) if( current_mode )
{ {
current_mode->pos = al_get_count( &current_mode->item ); current_mode->pos = al_get_count( &current_mode->item );
/*
Clear list of search matches
*/
al_truncate( &current_mode->used, 0 ); al_truncate( &current_mode->used, 0 );
} }
} }
@ -833,6 +873,11 @@ const wchar_t *history_next_match( const wchar_t *needle)
{ {
if( current_mode ) if( current_mode )
{ {
/*
The index of previous search matches are saved in the 'used'
list. We just need to pop the top item and set the new
position. Easy!
*/
if( al_get_count( &current_mode->used ) ) if( al_get_count( &current_mode->used ) )
{ {
al_pop( &current_mode->used ); al_pop( &current_mode->used );
@ -844,6 +889,10 @@ const wchar_t *history_next_match( const wchar_t *needle)
} }
} }
/*
The used-list is empty. Set position to 'past end of list'
and return the search string.
*/
current_mode->pos = al_get_count( &current_mode->item ); current_mode->pos = al_get_count( &current_mode->item );
} }
@ -888,6 +937,8 @@ void history_destroy()
void history_sanity_check() void history_sanity_check()
{ {
/*
No sanity checking implemented yet...
*/
} }