Add autoindentation support

darcs-hash:20061007005625-ac50b-11873654797eb1e98fd17893022bdf995be3e2aa.gz
This commit is contained in:
axel 2006-10-07 10:56:25 +10:00
parent 184d58cd36
commit 560e53fd5f
8 changed files with 167 additions and 47 deletions

View file

@ -489,14 +489,14 @@ static int builtin_complete( wchar_t **argv )
{
if( condition && wcslen( condition ) )
{
if( parser_test( condition, 0, 0 ) )
if( parser_test( condition, 0, 0, 0 ) )
{
sb_printf( sb_err,
L"%ls: Condition '%ls' contained a syntax error\n",
argv[0],
condition );
parser_test( condition, sb_err, argv[0] );
parser_test( condition, 0, sb_err, argv[0] );
res = 1;
}

View file

@ -2839,7 +2839,7 @@ static int parser_test_argument( const wchar_t *arg, string_buffer_t *out, const
// debug( 1, L"%ls -> %ls %ls", arg_cpy, subst, tmp.buff );
err |= parser_test( subst, out, prefix );
err |= parser_test( subst, 0, out, prefix );
free( subst );
free( arg_cpy );
@ -2981,6 +2981,7 @@ int parser_test_args(const wchar_t * buff,
}
int parser_test( const wchar_t * buff,
int *block_level,
string_buffer_t *out,
const wchar_t *prefix )
{
@ -2992,6 +2993,8 @@ int parser_test( const wchar_t * buff,
int had_cmd=0;
int count = 0;
int err=0;
int unfinished = 0;
tokenizer *previous_tokenizer=current_tokenizer;
int previous_pos=current_tokenizer_pos;
static int block_pos[BLOCK_MAX_COUNT];
@ -3033,6 +3036,17 @@ int parser_test( const wchar_t * buff,
wchar_t *cmd=0;
CHECK( buff, 1 );
if( block_level )
{
int i;
int len = wcslen(buff);
for( i=0; i<len; i++ )
{
block_level[i] = -1;
}
}
context = halloc( 0, 0 );
current_tokenizer = &tok;
@ -3108,6 +3122,17 @@ int parser_test( const wchar_t * buff,
tok_set_pos( &tok, mark );
}
/*
Store the block level. This needs to be done
_after_ checking for end commands, but _before_
shecking for block opening commands.
*/
if( block_level )
{
block_level[tok_get_pos( &tok )] = count;
}
/*
Handle block commands
*/
@ -3572,18 +3597,25 @@ int parser_test( const wchar_t * buff,
case TOK_ERROR:
default:
err = 1;
if( out )
if( tok_get_error( &tok ) == TOK_UNTERMINATED_QUOTE )
{
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
TOK_ERR_MSG,
tok_last(&tok) );
print_errors( out, prefix );
//debug( 2, tok_last( &tok) );
unfinished = 1;
}
else
{
err = 1;
if( out )
{
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
TOK_ERR_MSG,
tok_last(&tok) );
print_errors( out, prefix );
}
}
break;
}
@ -3667,9 +3699,29 @@ int parser_test( const wchar_t * buff,
halloc_free( context );
res = 0;
if( block_level )
{
int last_level = 0;
int i;
int len = wcslen(buff);
for( i=0; i<len; i++ )
{
if( block_level[i] >= 0 )
last_level = block_level[i];
block_level[i] = last_level;
}
}
if( count!= 0 )
unfinished = 1;
if( err )
res |= PARSER_TEST_ERROR;
if( count!= 0 )
if( unfinished )
res |= PARSER_TEST_INCOMPLETE;
return res;

View file

@ -305,11 +305,17 @@ const wchar_t *parser_get_block_desc( int block );
/**
Test if the specified string can be parsed, or if more bytes need
to be read first. The result has the first bit set if the string
contains errors, and the second bit is set if the string contains
an unclosed block.
to be read first. The result will have the PARSER_TEST_ERROR bit
set if there is a syntax error in the code, and the
PARSER_TEST_INCOMPLETE bit set if the code contains unclosed
blocks.
\param buff the text buffer to test
\param block_level if non-null, the block nesting level will be filled out into this array
\param out if non-null, any errors in the command will be filled out into this buffer
\param prefix the prefix string to prepend to each error message written to the \c out buffer
*/
int parser_test( const wchar_t * buff, string_buffer_t *out, const wchar_t *prefix );
int parser_test( const wchar_t * buff, int *block_level, string_buffer_t *out, const wchar_t *prefix );
/**
Test if the specified string can be parsed as an argument list,

View file

@ -204,7 +204,7 @@ typedef struct reader_data
/**
New color buffer, used for syntax highlighting.
*/
int *new_color;
int *indent;
/**
Should the prompt command be reexecuted on the next repaint
@ -419,13 +419,13 @@ static int check_size()
data->color = realloc( data->color,
sizeof(int)*data->buff_sz);
data->new_color = realloc( data->new_color,
sizeof(int)*data->buff_sz);
data->indent = realloc( data->indent,
sizeof(int)*data->buff_sz);
if( data->buff==0 ||
data->search_buff==0 ||
data->color==0 ||
data->new_color == 0 )
data->indent == 0 )
{
DIE_MEM();
}
@ -627,10 +627,10 @@ void reader_exit( int do_exit, int forced )
void repaint()
{
calc_prompt();
parser_test( data->buff, data->indent, 0, 0 );
// assert( wcslen( (wchar_t *)data->prompt_buff.buff));
s_write( &data->screen, (wchar_t *)data->prompt_buff.buff, data->buff, data->color, data->buff_pos );
s_write( &data->screen, (wchar_t *)data->prompt_buff.buff, data->buff, data->color, data->indent, data->buff_pos );
}
@ -1679,7 +1679,7 @@ void reader_run_command( const wchar_t *cmd )
static int shell_test( wchar_t *b )
{
int res = parser_test( b, 0, 0 );
int res = parser_test( b, 0, 0, 0 );
if( res & PARSER_TEST_ERROR )
{
@ -1687,10 +1687,11 @@ static int shell_test( wchar_t *b )
sb_init( &sb );
int tmp[1];
int tmp2[1];
s_write( &data->screen, L"", L"", tmp, 0 );
s_write( &data->screen, L"", L"", tmp, tmp2, 0 );
parser_test( b, &sb, L"fish" );
parser_test( b, 0, &sb, L"fish" );
fwprintf( stderr, L"%ls", sb.buff );
sb_destroy( &sb );
}
@ -1753,7 +1754,7 @@ void reader_pop()
free( n->prompt );
free( n->buff );
free( n->color );
free( n->new_color );
free( n->indent );
free( n->search_buff );
s_destroy( &n->screen );
@ -2550,7 +2551,7 @@ static int read_ni( int fd )
string_buffer_t sb;
sb_init( &sb );
if( !parser_test( str, &sb, L"fish" ) )
if( !parser_test( str, 0, &sb, L"fish" ) )
{
eval( str, 0, TOP );
}

View file

@ -337,8 +337,9 @@ static line_t *s_create_line()
than the screen width.
*/
static void s_desired_append_char( screen_t *s,
wchar_t b,
wchar_t b,
int c,
int indent,
int prompt_width )
{
int line_no = s->desired_cursor[1];
@ -352,9 +353,9 @@ static void s_desired_append_char( screen_t *s,
al_push( &s->desired, current );
s->desired_cursor[1]++;
s->desired_cursor[0]=0;
for( i=0; i < prompt_width; i++ )
for( i=0; i < prompt_width+indent*4; i++ )
{
s_desired_append_char( s, L' ', 0, prompt_width );
s_desired_append_char( s, L' ', 0, indent, prompt_width );
}
break;
}
@ -400,9 +401,9 @@ static void s_desired_append_char( screen_t *s,
s->desired_cursor[0]=0;
for( i=0; i < (prompt_width-ew); i++ )
{
s_desired_append_char( s, L' ', 0, prompt_width );
s_desired_append_char( s, L' ', 0, indent, prompt_width );
}
s_desired_append_char( s, ellipsis_char, HIGHLIGHT_COMMENT, prompt_width );
s_desired_append_char( s, ellipsis_char, HIGHLIGHT_COMMENT, indent, prompt_width );
}
al_set_long( &current->text, s->desired_cursor[0], b );
@ -687,6 +688,7 @@ void s_write( screen_t *s,
wchar_t *prompt,
wchar_t *b,
int *c,
int *indent,
int cursor )
{
int i;
@ -719,26 +721,42 @@ void s_write( screen_t *s,
for( i=0; i<prompt_width; i++ )
{
s_desired_append_char( s, L' ', 0, prompt_width );
s_desired_append_char( s, L' ', 0, 0, prompt_width );
}
for( i=0; b[i]; i++ )
{
int col = c[i];
int ind = indent[i];
if( i == cursor )
{
col = 0;
}
s_desired_append_char( s, b[i], col, prompt_width );
if( b[i] == L'\n' && b[i+1] )
ind = indent[i+1];
if( i == cursor )
{
cursor_arr[0] = s->desired_cursor[0] - wcwidth(b[i]);
cursor_arr[0] = s->desired_cursor[0];
cursor_arr[1] = s->desired_cursor[1];
}
s_desired_append_char( s, b[i], col, ind, prompt_width );
if( i== cursor && s->desired_cursor[1] != cursor_arr[1] && b[i] != L'\n' )
{
/**
Ugh. We are placed exactly at the wrapping point of a
wrapped line, move cursor to the line below so the
cursor won't be on the ellipsis which looks
unintuitive.
*/
cursor_arr[0] = s->desired_cursor[0] - wcwidth(b[i]);
cursor_arr[1] = s->desired_cursor[1];
}
}
if( i == cursor )

View file

@ -90,6 +90,7 @@ void s_write( screen_t *s,
wchar_t *prompt,
wchar_t *commandline,
int *colors,
int *indent,
int cursor_pos );
/**

View file

@ -30,6 +30,11 @@ segments.
*/
#define EOL_ERROR _( L"Unexpected end of token" )
/**
Error string for unexpected end of string
*/
#define QUOTE_ERROR _( L"Unterminated quote" )
/**
Error string for mismatched parenthesis
*/
@ -101,19 +106,26 @@ static int check_size( tokenizer *tok, size_t len )
/**
Set the latest tokens string to be the specified error message
*/
static void tok_error( tokenizer *tok, const wchar_t *err )
static void tok_error( tokenizer *tok, int error_type, const wchar_t *error_message )
{
tok->last_type = TOK_ERROR;
if( !check_size( tok, wcslen( err)+1 ))
tok->error = error_type;
if( !check_size( tok, wcslen( error_message)+1 ))
{
if( tok->last != 0 )
*tok->last=0;
return;
}
wcscpy( tok->last, err );
wcscpy( tok->last, error_message );
}
int tok_get_error( tokenizer *tok )
{
return tok->error;
}
void tok_init( tokenizer *tok, const wchar_t *b, int flags )
{
@ -239,7 +251,7 @@ static void read_string( tokenizer *tok )
tok->buff++;
if( *tok->buff == L'\0' )
{
tok_error( tok, EOL_ERROR );
tok_error( tok, TOK_UNTERMINATED_ESCAPE, EOL_ERROR );
return;
}
else if( *tok->buff == L'\n' && mode == 0)
@ -298,7 +310,7 @@ static void read_string( tokenizer *tok )
if( (!tok->accept_unfinished) )
{
tok_error( tok, EOL_ERROR );
tok_error( tok, TOK_UNTERMINATED_QUOTE, QUOTE_ERROR );
return;
}
do_loop = 0;
@ -331,7 +343,16 @@ static void read_string( tokenizer *tok )
tok->buff=(wchar_t *)end;
}
else
{
tok->buff += wcslen( tok->buff );
if( (!tok->accept_unfinished) )
{
tok_error( tok, TOK_UNTERMINATED_QUOTE, QUOTE_ERROR );
return;
}
do_loop = 0;
}
break;
}
@ -380,7 +401,7 @@ static void read_string( tokenizer *tok )
if( (!tok->accept_unfinished) && (mode!=0) )
{
tok_error( tok, PARAN_ERROR );
tok_error( tok, TOK_UNTERMINATED_SUBSHELL, PARAN_ERROR );
return;
}
@ -441,7 +462,7 @@ static void read_redirect( tokenizer *tok, int fd )
{
if( fd == 0 )
{
tok_error( tok, PIPE_ERROR );
tok_error( tok, TOK_OTHER, PIPE_ERROR );
return;
}
check_size( tok, FD_STR_MAX_LEN );
@ -458,7 +479,7 @@ static void read_redirect( tokenizer *tok, int fd )
}
else
{
tok_error( tok, REDIRECT_ERROR);
tok_error( tok, TOK_OTHER, REDIRECT_ERROR);
}
if( !check_size( tok, 2 ))

View file

@ -29,7 +29,20 @@ enum token_type
TOK_BACKGROUND,/**< send job to bg token */
TOK_COMMENT/**< comment token */
}
;
;
/**
Tokenizer error types
*/
enum tokenizer_error
{
TOK_UNTERMINATED_QUOTE,
TOK_UNTERMINATED_SUBSHELL,
TOK_UNTERMINATED_ESCAPE,
TOK_OTHER
}
;
/**
Flag telling the tokenizer to accept incomplete parameters,
@ -73,6 +86,8 @@ typedef struct
int free_orig;
/** Type of last quote, can be either ' or ".*/
wchar_t last_quote;
/** Last error */
int error;
}
tokenizer;
@ -151,4 +166,10 @@ void tok_set_pos( tokenizer *tok, int pos );
*/
const wchar_t *tok_get_desc( int type );
/**
Get tokenizer error type. Should only be called if tok_last_tope returns TOK_ERROR.
*/
int tok_get_error( tokenizer *tok );
#endif