Fix the kill-line, backward-kill-line and kill-whole-line commands to work correctly with multiline editing

darcs-hash:20061012132732-ac50b-03fe641cf32ace645c88174528e849ab0d1ecb4b.gz
This commit is contained in:
axel 2006-10-12 23:27:32 +10:00
parent 97f7c2093b
commit b70b966f90
3 changed files with 192 additions and 29 deletions

58
kill.c
View file

@ -105,6 +105,64 @@ void kill_add( wchar_t *str )
} }
} }
/**
Remove the specified node from the circular list
*/
static void kill_remove_node( ll_node_t *n )
{
if( n->prev == n )
{
kill_last=kill_current = 0;
}
else
{
ll_node_t *nxt = n->prev;
while( nxt->prev != n )
{
nxt=nxt->prev;
}
nxt->prev = n->prev;
if( kill_last == n )
{
kill_last = n->prev;
}
kill_current=kill_last;
free( n->data );
free( n );
}
}
/**
Remove first match for specified string from circular list
*/
static void kill_remove( wchar_t *s )
{
ll_node_t *n, *next;
if( !kill_last )
{
return;
}
for( n=kill_last;
n!=kill_last || next == 0 ;
n=n->prev )
{
if( wcscmp( (wchar_t *)n->data, s ) == 0 )
{
kill_remove_node( n );
}
next = n;
}
}
void kill_replace( wchar_t *old, wchar_t *new )
{
kill_remove( old );
kill_add( new );
}
wchar_t *kill_yank_rotate() wchar_t *kill_yank_rotate()
{ {

6
kill.h
View file

@ -9,6 +9,12 @@
#include <wchar.h> #include <wchar.h>
/**
Replace the specified string in the killring
*/
void kill_replace( wchar_t *old, wchar_t *new );
/** /**
Add a string to the top of the killring Add a string to the top of the killring
*/ */

157
reader.c
View file

@ -127,6 +127,9 @@ commence.
*/ */
#define READAHEAD_MAX 256 #define READAHEAD_MAX 256
#define KILL_APPEND 0
#define KILL_PREPEND 1
/** /**
A struct describing the state of the interactive reader. These A struct describing the state of the interactive reader. These
states can be stacked, in case reader_readline is called from states can be stacked, in case reader_readline is called from
@ -241,6 +244,8 @@ typedef struct reader_data
*/ */
int prev_end_loop; int prev_end_loop;
string_buffer_t kill_item;
/** /**
Pointer to previous reader_data Pointer to previous reader_data
*/ */
@ -366,6 +371,35 @@ int reader_exit_forced()
return exit_forced; return exit_forced;
} }
static void reader_kill( wchar_t *begin, int length, int mode, int new )
{
if( new )
{
sb_clear( &data->kill_item );
sb_append_substring( &data->kill_item, begin, length );
kill_add( (wchar_t *)data->kill_item.buff );
}
else
{
wchar_t *old = wcsdup( (wchar_t *)data->kill_item.buff);
if( mode == KILL_APPEND )
{
sb_append_substring( &data->kill_item, begin, length );
}
else
{
sb_clear( &data->kill_item );
sb_append_substring( &data->kill_item, begin, length );
sb_append( &data->kill_item, old );
}
kill_replace( old, (wchar_t *)data->kill_item.buff );
free( old );
}
}
/** /**
string_buffer used as temporary storage for the reader_readline function string_buffer used as temporary storage for the reader_readline function
@ -725,6 +759,10 @@ static int insert_str(wchar_t *str)
int len = wcslen( str ); int len = wcslen( str );
int old_len = data->buff_len; int old_len = data->buff_len;
assert( data->buff_pos >= 0 );
assert( data->buff_pos <= data->buff_len );
assert( len >= 0 );
data->buff_len += len; data->buff_len += len;
check_size(); check_size();
@ -1150,9 +1188,7 @@ static int handle_completions( array_list_t *comp )
get_param( data->buff, data->buff_pos, &quote, 0, 0, 0 ); get_param( data->buff, data->buff_pos, &quote, 0, 0, 0 );
is_quoted = (quote != L'\0'); is_quoted = (quote != L'\0');
writech(L'\n'); write(1, "\n", 1 );
run_pager( prefix, is_quoted, comp ); run_pager( prefix, is_quoted, comp );
@ -1718,6 +1754,7 @@ void reader_push( wchar_t *name )
reader_data_t *n = calloc( 1, sizeof( reader_data_t ) ); reader_data_t *n = calloc( 1, sizeof( reader_data_t ) );
n->name = wcsdup( name ); n->name = wcsdup( name );
n->next = data; n->next = data;
sb_init( &n->kill_item );
data=n; data=n;
@ -1761,6 +1798,7 @@ void reader_pop()
free( n->color ); free( n->color );
free( n->indent ); free( n->indent );
free( n->search_buff ); free( n->search_buff );
sb_destroy( &n->kill_item );
s_destroy( &n->screen ); s_destroy( &n->screen );
sb_destroy( &n->prompt_buff ); sb_destroy( &n->prompt_buff );
@ -2135,51 +2173,112 @@ wchar_t *reader_readline()
break; break;
} }
/* kill*/ /* kill */
case R_KILL_LINE: case R_KILL_LINE:
{ {
kill_add( &data->buff[data->buff_pos] ); wchar_t *begin = &data->buff[data->buff_pos];
data->buff_len = data->buff_pos; wchar_t *end = begin;
data->buff[data->buff_len]=L'\0'; int len;
while( *end && *end != L'\n' )
repaint(); end++;
if( end==begin && *end )
end++;
len = end-begin;
if( len )
{
reader_kill( begin, len, KILL_APPEND, last_char!=R_KILL_LINE );
memmove( begin, end, sizeof( wchar_t )*(wcslen( end )+1) );
data->buff_len -= len;
reader_super_highlight_me_plenty( data->color, data->buff_pos, 0 );
repaint();
}
break; break;
} }
case R_BACKWARD_KILL_LINE: case R_BACKWARD_KILL_LINE:
{ {
wchar_t *str = wcsndup( data->buff, data->buff_pos ); if( data->buff_pos > 0 )
if( !str ) {
DIE_MEM(); wchar_t *end = &data->buff[data->buff_pos];
wchar_t *begin = end;
int len;
while( begin > data->buff && *begin != L'\n' )
begin--;
if( *begin == L'\n' )
begin++;
len = maxi( end-begin, 1 );
begin = end - len;
reader_kill( begin, len, KILL_PREPEND, last_char!=R_BACKWARD_KILL_LINE );
memmove( begin, end, sizeof( wchar_t )*(wcslen( end )+1) );
data->buff_pos -= len;
data->buff_len -= len;
kill_add( str ); reader_super_highlight_me_plenty( data->color, data->buff_pos, 0 );
free( str ); repaint();
data->buff_len = wcslen(data->buff +data->buff_pos); }
memmove( data->buff, data->buff +data->buff_pos, sizeof(wchar_t)*data->buff_len );
data->buff[data->buff_len]=L'\0';
data->buff_pos=0;
reader_super_highlight_me_plenty( data->color, data->buff_pos, 0 );
repaint();
break; break;
} }
case R_KILL_WHOLE_LINE: case R_KILL_WHOLE_LINE:
{ {
kill_add( data->buff ); wchar_t *end = &data->buff[data->buff_pos];
data->buff_len = data->buff_pos = 0; wchar_t *begin = end;
data->buff[data->buff_len]=L'\0'; int len;
reader_super_highlight_me_plenty( data->color, data->buff_pos, 0 ); //debug( 0, L"WOOOOOT" );
while( begin > data->buff && *begin != L'\n' )
begin--;
if( *begin == L'\n' )
begin++;
len = maxi( end-begin, 0 );
begin = end - len;
repaint(); while( *end && *end != L'\n' )
end++;
if( begin == end && *end )
end++;
len = end-begin;
if( len )
{
reader_kill( begin, len, KILL_APPEND, last_char!=R_KILL_WHOLE_LINE );
memmove( begin, end, sizeof( wchar_t )*(wcslen( end )+1) );
data->buff_pos = begin - data->buff;
data->buff_len -= len;
reader_super_highlight_me_plenty( data->color, data->buff_pos, 0 );
repaint();
}
break; break;
} }
/* yank*/ /* yank*/
case R_YANK: case R_YANK:
{ yank_str = kill_yank(); {
yank_str = kill_yank();
insert_str( yank_str ); insert_str( yank_str );
yank = wcslen( yank_str ); yank = wcslen( yank_str );
break; break;