mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 05:28:49 +00:00
Add autoindentation support
darcs-hash:20061007005625-ac50b-11873654797eb1e98fd17893022bdf995be3e2aa.gz
This commit is contained in:
parent
184d58cd36
commit
560e53fd5f
8 changed files with 167 additions and 47 deletions
|
@ -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;
|
||||
}
|
||||
|
|
76
parser.c
76
parser.c
|
@ -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;
|
||||
|
|
14
parser.h
14
parser.h
|
@ -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,
|
||||
|
|
25
reader.c
25
reader.c
|
@ -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 );
|
||||
}
|
||||
|
|
34
screen.c
34
screen.c
|
@ -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( ¤t->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 )
|
||||
|
|
1
screen.h
1
screen.h
|
@ -90,6 +90,7 @@ void s_write( screen_t *s,
|
|||
wchar_t *prompt,
|
||||
wchar_t *commandline,
|
||||
int *colors,
|
||||
int *indent,
|
||||
int cursor_pos );
|
||||
|
||||
/**
|
||||
|
|
37
tokenizer.c
37
tokenizer.c
|
@ -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 ))
|
||||
|
|
23
tokenizer.h
23
tokenizer.h
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue