2017-11-21 18:25:19 +00:00
/*
4 coder_scope_commands . cpp - A set of commands and helpers relevant for scope level navigation and editing .
*/
// TOP
2019-02-26 23:08:42 +00:00
static b32 parse_statement_down ( Application_Links * app , Statement_Parser * parser , Cpp_Token * token_out ) ;
2018-05-09 07:10:07 +00:00
////////////////////////////////
2017-11-21 18:25:19 +00:00
2018-09-30 12:14:47 +00:00
static Find_Scope_Token_Type
2019-02-26 23:08:42 +00:00
find_scope_get_token_type ( u32 flags , Cpp_Token_Type token_type ) {
2018-09-30 12:14:47 +00:00
Find_Scope_Token_Type type = FindScopeTokenType_None ;
if ( flags & FindScope_Brace ) {
switch ( token_type ) {
case CPP_TOKEN_BRACE_OPEN :
{
type = FindScopeTokenType_Open ;
} break ;
case CPP_TOKEN_BRACE_CLOSE :
{
type = FindScopeTokenType_Close ;
} break ;
}
}
if ( flags & FindScope_Paren ) {
switch ( token_type ) {
case CPP_TOKEN_PARENTHESE_OPEN :
{
type = FindScopeTokenType_Open ;
} break ;
case CPP_TOKEN_PARENTHESE_CLOSE :
{
type = FindScopeTokenType_Close ;
} break ;
}
}
return ( type ) ;
}
2019-02-26 23:08:42 +00:00
static b32
2019-06-20 23:43:27 +00:00
find_scope_top ( Application_Links * app , Buffer_ID buffer , i64 start_pos , u32 flags , i64 * end_pos_out ) {
2019-02-02 00:23:48 +00:00
Cpp_Get_Token_Result get_result = { } ;
2019-02-26 23:08:42 +00:00
b32 success = false ;
i32 position = 0 ;
2019-06-19 02:31:59 +00:00
if ( get_token_from_pos ( app , buffer , start_pos , & get_result ) ) {
2019-02-26 23:08:42 +00:00
i32 token_index = get_result . token_index ;
2019-06-19 02:31:59 +00:00
if ( HasFlag ( flags , FindScope_Parent ) ) {
2019-02-02 00:23:48 +00:00
- - token_index ;
2019-02-21 06:58:34 +00:00
if ( get_result . in_whitespace_after_token ) {
2019-02-02 00:23:48 +00:00
+ + token_index ;
}
}
if ( token_index > = 0 ) {
2019-04-04 08:25:16 +00:00
Token_Range token_range = buffer_get_token_range ( app , buffer ) ;
2019-02-02 00:23:48 +00:00
if ( token_range . first ! = 0 ) {
Token_Iterator token_it = make_token_iterator ( token_range , token_index ) ;
2019-02-26 23:08:42 +00:00
i32 nest_level = 0 ;
2019-02-02 00:23:48 +00:00
for ( Cpp_Token * token = token_iterator_current ( & token_it ) ;
token ! = 0 ;
token = token_iterator_goto_prev ( & token_it ) ) {
Find_Scope_Token_Type type = find_scope_get_token_type ( flags , token - > type ) ;
switch ( type ) {
case FindScopeTokenType_Open :
{
if ( nest_level = = 0 ) {
success = true ;
position = token - > start ;
if ( flags & FindScope_EndOfToken ) {
position + = token - > size ;
}
goto finished ;
}
else {
- - nest_level ;
}
} break ;
case FindScopeTokenType_Close :
{
+ + nest_level ;
} break ;
}
}
}
}
}
finished : ;
* end_pos_out = position ;
return ( success ) ;
}
2019-02-26 23:08:42 +00:00
static b32
2019-06-20 23:43:27 +00:00
find_scope_bottom ( Application_Links * app , Buffer_ID buffer , i64 start_pos , u32 flags , i64 * end_pos_out ) {
2019-02-02 00:23:48 +00:00
Cpp_Get_Token_Result get_result = { } ;
2019-02-26 23:08:42 +00:00
b32 success = false ;
i32 position = 0 ;
2019-06-19 02:31:59 +00:00
if ( get_token_from_pos ( app , buffer , start_pos , & get_result ) ) {
2019-02-26 23:08:42 +00:00
i32 token_index = get_result . token_index + 1 ;
2019-06-19 02:31:59 +00:00
if ( HasFlag ( flags , FindScope_Parent ) ) {
2019-02-02 00:23:48 +00:00
- - token_index ;
2019-02-21 06:58:34 +00:00
if ( get_result . in_whitespace_after_token ) {
2019-02-02 00:23:48 +00:00
+ + token_index ;
}
}
if ( token_index > = 0 ) {
2019-04-04 08:25:16 +00:00
Token_Range token_range = buffer_get_token_range ( app , buffer ) ;
2019-02-02 00:23:48 +00:00
if ( token_range . first ! = 0 ) {
Token_Iterator token_it = make_token_iterator ( token_range , token_index ) ;
2019-02-26 23:08:42 +00:00
i32 nest_level = 0 ;
2019-02-02 00:23:48 +00:00
for ( Cpp_Token * token = token_iterator_current ( & token_it ) ;
token ! = 0 ;
token = token_iterator_goto_next ( & token_it ) ) {
Find_Scope_Token_Type type = find_scope_get_token_type ( flags , token - > type ) ;
switch ( type ) {
case FindScopeTokenType_Open :
{
+ + nest_level ;
} break ;
case FindScopeTokenType_Close :
{
if ( nest_level = = 0 ) {
success = true ;
position = token - > start ;
if ( flags & FindScope_EndOfToken ) {
position + = token - > size ;
}
goto finished ;
}
else {
- - nest_level ;
}
} break ;
}
}
}
}
}
finished : ;
* end_pos_out = position ;
return ( success ) ;
}
2019-02-26 23:08:42 +00:00
static b32
2019-06-20 23:43:27 +00:00
find_next_scope ( Application_Links * app , Buffer_ID buffer , i64 start_pos , u32 flags , i64 * end_pos_out ) {
2019-02-02 00:23:48 +00:00
Cpp_Get_Token_Result get_result = { } ;
2019-02-26 23:08:42 +00:00
b32 success = 0 ;
2019-06-20 23:43:27 +00:00
i64 position = 0 ;
2019-06-19 02:31:59 +00:00
if ( get_token_from_pos ( app , buffer , start_pos , & get_result ) ) {
2019-04-04 08:25:16 +00:00
i32 token_index = get_result . token_index + 1 ;
2019-02-02 00:23:48 +00:00
if ( token_index > = 0 ) {
2019-04-04 08:25:16 +00:00
Token_Range token_range = buffer_get_token_range ( app , buffer ) ;
2019-02-02 00:23:48 +00:00
if ( token_range . first ! = 0 ) {
Token_Iterator token_it = make_token_iterator ( token_range , token_index ) ;
2019-06-19 02:31:59 +00:00
if ( HasFlag ( flags , FindScope_NextSibling ) ) {
2019-02-26 23:08:42 +00:00
i32 nest_level = 1 ;
2019-02-02 00:23:48 +00:00
for ( Cpp_Token * token = token_iterator_current ( & token_it ) ;
token ! = 0 ;
token = token_iterator_goto_next ( & token_it ) ) {
Find_Scope_Token_Type type = find_scope_get_token_type ( flags , token - > type ) ;
switch ( type ) {
case FindScopeTokenType_Open :
{
if ( nest_level = = 0 ) {
success = 1 ;
position = token - > start ;
if ( flags & FindScope_EndOfToken ) {
position + = token - > size ;
}
goto finished ;
}
else {
+ + nest_level ;
}
} break ;
case FindScopeTokenType_Close :
{
- - nest_level ;
if ( nest_level = = - 1 ) {
position = start_pos ;
goto finished ;
}
} break ;
}
}
}
else {
for ( Cpp_Token * token = token_iterator_current ( & token_it ) ;
token ! = 0 ;
token = token_iterator_goto_next ( & token_it ) ) {
Find_Scope_Token_Type type = find_scope_get_token_type ( flags , token - > type ) ;
if ( type = = FindScopeTokenType_Open ) {
success = 1 ;
position = token - > start ;
if ( flags & FindScope_EndOfToken ) {
position + = token - > size ;
}
goto finished ;
}
}
}
}
}
}
finished : ;
* end_pos_out = position ;
return ( success ) ;
}
2017-11-21 18:25:19 +00:00
2019-02-26 23:08:42 +00:00
static b32
2019-06-20 23:43:27 +00:00
find_prev_scope ( Application_Links * app , Buffer_ID buffer , i64 start_pos , u32 flags , i64 * end_pos_out ) {
2019-02-02 00:23:48 +00:00
Cpp_Get_Token_Result get_result = { } ;
2019-02-26 23:08:42 +00:00
b32 success = false ;
2019-06-20 23:43:27 +00:00
i64 position = 0 ;
2019-06-19 02:31:59 +00:00
if ( get_token_from_pos ( app , buffer , start_pos , & get_result ) ) {
i32 token_index = get_result . token_index - 1 ;
2019-02-02 00:23:48 +00:00
if ( token_index > = 0 ) {
2019-04-04 08:25:16 +00:00
Token_Range token_range = buffer_get_token_range ( app , buffer ) ;
2019-02-02 00:23:48 +00:00
if ( token_range . first ! = 0 ) {
Token_Iterator token_it = make_token_iterator ( token_range , token_index ) ;
if ( flags & FindScope_NextSibling ) {
2019-02-26 23:08:42 +00:00
i32 nest_level = - 1 ;
2019-02-02 00:23:48 +00:00
for ( Cpp_Token * token = token_iterator_current ( & token_it ) ;
token ! = 0 ;
token = token_iterator_goto_prev ( & token_it ) ) {
Find_Scope_Token_Type type = find_scope_get_token_type ( flags , token - > type ) ;
switch ( type ) {
case FindScopeTokenType_Open :
{
if ( nest_level = = - 1 ) {
position = start_pos ;
goto finished ;
}
else if ( nest_level = = 0 ) {
success = true ;
position = token - > start ;
if ( flags & FindScope_EndOfToken ) {
position + = token - > size ;
}
goto finished ;
}
else {
- - nest_level ;
}
} break ;
case FindScopeTokenType_Close :
{
+ + nest_level ;
} break ;
}
}
}
else {
for ( Cpp_Token * token = token_iterator_current ( & token_it ) ;
token ! = 0 ;
token = token_iterator_goto_prev ( & token_it ) ) {
Find_Scope_Token_Type type = find_scope_get_token_type ( flags , token - > type ) ;
if ( type = = FindScopeTokenType_Open ) {
success = true ;
position = token - > start ;
if ( flags & FindScope_EndOfToken ) {
position + = token - > size ;
}
goto finished ;
}
}
}
}
}
}
finished : ;
* end_pos_out = position ;
return ( success ) ;
}
2017-11-21 18:25:19 +00:00
2019-02-26 23:08:42 +00:00
static b32
2019-06-20 23:43:27 +00:00
find_scope_range ( Application_Links * app , Buffer_ID buffer , i64 start_pos , Range_i64 * range_out , u32 flags ) {
2019-04-04 08:25:16 +00:00
b32 result = false ;
2019-06-20 23:43:27 +00:00
Range_i64 range = { } ;
2019-04-04 08:25:16 +00:00
if ( find_scope_top ( app , buffer , start_pos , FindScope_Parent | flags , & range . start ) ) {
if ( find_scope_bottom ( app , buffer , start_pos , FindScope_Parent | FindScope_EndOfToken | flags , & range . end ) ) {
2018-09-25 08:41:49 +00:00
* range_out = range ;
2019-04-04 08:25:16 +00:00
result = true ;
2018-09-25 08:41:49 +00:00
}
}
2019-04-04 08:25:16 +00:00
return ( result ) ;
2018-09-25 08:41:49 +00:00
}
2017-11-21 18:25:19 +00:00
static void
2019-09-02 18:59:36 +00:00
view_set_to_region ( Application_Links * app , View_ID view , i64 major_pos , i64 minor_pos ) {
2019-06-20 23:43:27 +00:00
Range_i64 range = Ii64 ( major_pos , minor_pos ) ;
2019-02-26 23:08:42 +00:00
b32 bottom_major = false ;
2017-11-21 18:25:19 +00:00
if ( major_pos = = range . max ) {
bottom_major = true ;
}
2019-09-02 18:59:36 +00:00
Buffer_Cursor top = view_compute_cursor ( app , view , seek_pos ( range . min ) ) ;
2019-06-20 04:45:58 +00:00
if ( top . line > 0 ) {
2019-09-02 18:59:36 +00:00
Buffer_Cursor bottom = view_compute_cursor ( app , view , seek_pos ( range . max ) ) ;
2019-06-20 04:45:58 +00:00
if ( bottom . line > 0 ) {
2019-06-19 02:31:59 +00:00
Rect_f32 region = view_get_buffer_region ( app , view ) ;
2019-09-02 18:59:36 +00:00
f32 view_height = rect_height ( region ) ;
f32 skirt_height = view_height * .1f ;
Interval_f32 acceptable_y = If32 ( skirt_height , view_height * .9f ) ;
2019-02-27 05:49:35 +00:00
2019-09-02 18:59:36 +00:00
f32 target_height = view_line_y_difference ( app , view , bottom . line , top . line ) ;
2017-11-21 18:25:19 +00:00
2019-09-02 18:59:36 +00:00
if ( target_height > view_height ) {
i64 major_line = bottom . line ;
if ( range . min = = major_pos ) {
major_line = top . line ;
}
2017-11-21 18:25:19 +00:00
2019-09-02 18:59:36 +00:00
Buffer_Scroll scroll = view_get_buffer_scroll ( app , view ) ;
scroll . target . line_number = major_line ;
scroll . target . pixel_shift . y = - skirt_height ;
view_set_buffer_scroll ( app , view , scroll ) ;
}
else {
Buffer_Scroll scroll = view_get_buffer_scroll ( app , view ) ;
Vec2_f32 top_p = view_relative_xy_of_pos ( app , view , scroll . position . line_number , range . min ) ;
top_p - = scroll . position . pixel_shift ;
if ( top_p . y < acceptable_y . min ) {
scroll . target . line_number = top . line ;
scroll . target . pixel_shift . y = - skirt_height ;
view_set_buffer_scroll ( app , view , scroll ) ;
2017-11-21 18:25:19 +00:00
}
else {
2019-09-02 18:59:36 +00:00
Vec2_f32 bot_p = view_relative_xy_of_pos ( app , view , scroll . position . line_number , range . max ) ;
bot_p - = scroll . position . pixel_shift ;
if ( bot_p . y > acceptable_y . max ) {
scroll . target . line_number = bottom . line ;
scroll . target . pixel_shift . y = skirt_height - view_height ;
view_set_buffer_scroll ( app , view , scroll ) ;
2017-11-21 18:25:19 +00:00
}
}
}
}
}
}
2018-10-06 01:42:56 +00:00
CUSTOM_COMMAND_SIG ( select_surrounding_scope )
2017-11-21 18:25:19 +00:00
CUSTOM_DOC ( " Finds the scope enclosed by '{' '}' surrounding the cursor and puts the cursor and mark on the '{' and '}'. " )
{
2019-06-19 02:31:59 +00:00
View_ID view = get_active_view ( app , AccessProtected ) ;
Buffer_ID buffer = view_get_buffer ( app , view , AccessProtected ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
Range_i64 range = { } ;
2019-04-06 21:13:49 +00:00
if ( find_scope_range ( app , buffer , pos , & range , FindScope_Brace ) ) {
view_set_cursor ( app , view , seek_pos ( range . first ) , true ) ;
view_set_mark ( app , view , seek_pos ( range . end ) ) ;
2019-09-02 18:59:36 +00:00
view_set_to_region ( app , view , range . first , range . end ) ;
2019-04-06 21:13:49 +00:00
no_mark_snap_to_cursor ( app , view ) ;
2017-11-21 18:25:19 +00:00
}
}
2018-10-06 01:42:56 +00:00
CUSTOM_COMMAND_SIG ( select_next_scope_absolute )
2017-11-21 18:25:19 +00:00
CUSTOM_DOC ( " Finds the first scope started by '{' after the cursor and puts the cursor and mark on the '{' and '}'. " )
{
2019-06-19 02:31:59 +00:00
View_ID view = get_active_view ( app , AccessProtected ) ;
Buffer_ID buffer = view_get_buffer ( app , view , AccessProtected ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
i64 start_pos = pos ;
i64 top = 0 ;
i64 bottom = 0 ;
2019-04-04 08:25:16 +00:00
if ( find_next_scope ( app , buffer , start_pos , FindScope_Brace , & top ) ) {
if ( find_scope_bottom ( app , buffer , top , FindScope_EndOfToken | FindScope_Brace , & bottom ) ) {
2019-04-06 21:13:49 +00:00
view_set_cursor ( app , view , seek_pos ( top ) , true ) ;
view_set_mark ( app , view , seek_pos ( bottom ) ) ;
2019-09-02 18:59:36 +00:00
view_set_to_region ( app , view , top , bottom ) ;
2019-04-06 21:13:49 +00:00
no_mark_snap_to_cursor ( app , view ) ;
2017-11-21 18:25:19 +00:00
}
}
}
2018-10-06 01:42:56 +00:00
CUSTOM_COMMAND_SIG ( select_prev_scope_absolute )
2017-11-21 18:25:19 +00:00
CUSTOM_DOC ( " Finds the first scope started by '{' before the cursor and puts the cursor and mark on the '{' and '}'. " )
{
2019-06-19 02:31:59 +00:00
View_ID view = get_active_view ( app , AccessProtected ) ;
Buffer_ID buffer = view_get_buffer ( app , view , AccessProtected ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
i64 start_pos = pos ;
i64 top = 0 ;
i64 bottom = 0 ;
2019-04-04 08:25:16 +00:00
if ( find_prev_scope ( app , buffer , start_pos , FindScope_Brace , & top ) ) {
if ( find_scope_bottom ( app , buffer , top , FindScope_EndOfToken | FindScope_Brace , & bottom ) ) {
2019-04-06 21:13:49 +00:00
view_set_cursor ( app , view , seek_pos ( top ) , true ) ;
view_set_mark ( app , view , seek_pos ( bottom ) ) ;
2019-09-02 18:59:36 +00:00
view_set_to_region ( app , view , top , bottom ) ;
2019-04-06 21:13:49 +00:00
no_mark_snap_to_cursor ( app , view ) ;
2017-11-21 18:25:19 +00:00
}
}
}
2017-11-29 23:00:14 +00:00
static void
2019-06-01 23:58:28 +00:00
place_begin_and_end_on_own_lines ( Application_Links * app , char * begin , char * end ) {
2019-06-19 02:31:59 +00:00
View_ID view = get_active_view ( app , AccessOpen ) ;
Buffer_ID buffer = view_get_buffer ( app , view , AccessOpen ) ;
2017-11-21 18:25:19 +00:00
2019-06-20 23:43:27 +00:00
Range_i64 range = get_view_range ( app , view ) ;
Range_i64 lines = get_line_range_from_pos_range ( app , buffer , range ) ;
range = get_pos_range_from_line_range ( app , buffer , lines ) ;
2017-11-21 18:25:19 +00:00
2019-06-02 03:07:57 +00:00
Scratch_Block scratch ( app ) ;
2017-11-21 18:25:19 +00:00
2019-06-05 23:04:35 +00:00
b32 min_line_blank = line_is_valid_and_blank ( app , buffer , lines . min ) ;
b32 max_line_blank = line_is_valid_and_blank ( app , buffer , lines . max ) ;
2017-11-29 23:00:14 +00:00
2019-06-01 23:58:28 +00:00
if ( ( lines . min < lines . max ) | | ( ! min_line_blank ) ) {
String_Const_u8 begin_str = { } ;
String_Const_u8 end_str = { } ;
2017-11-21 18:25:19 +00:00
2019-06-20 23:43:27 +00:00
i64 min_adjustment = 0 ;
i64 max_adjustment = 0 ;
2017-11-21 18:25:19 +00:00
2019-06-01 23:58:28 +00:00
if ( min_line_blank ) {
2019-06-18 22:56:09 +00:00
begin_str = push_u8_stringf ( scratch , " \n %s " , begin ) ;
2019-06-01 23:58:28 +00:00
min_adjustment + = 1 ;
2017-11-21 18:25:19 +00:00
}
2019-06-01 23:58:28 +00:00
else {
2019-06-18 22:56:09 +00:00
begin_str = push_u8_stringf ( scratch , " %s \n " , begin ) ;
2019-06-01 23:58:28 +00:00
}
if ( max_line_blank ) {
2019-06-18 22:56:09 +00:00
end_str = push_u8_stringf ( scratch , " %s \n " , end ) ;
2019-06-01 23:58:28 +00:00
}
else {
2019-06-18 22:56:09 +00:00
end_str = push_u8_stringf ( scratch , " \n %s " , end ) ;
2019-06-01 23:58:28 +00:00
max_adjustment + = 1 ;
2017-11-21 18:25:19 +00:00
}
2019-06-01 23:58:28 +00:00
max_adjustment + = begin_str . size ;
2019-06-20 23:43:27 +00:00
Range_i64 new_pos = Ii64 ( range . min + min_adjustment , range . max + max_adjustment ) ;
2017-11-21 18:25:19 +00:00
2019-06-14 20:28:20 +00:00
History_Group group = history_group_begin ( app , buffer ) ;
2019-06-20 23:43:27 +00:00
buffer_replace_range ( app , buffer , Ii64 ( range . min ) , begin_str ) ;
buffer_replace_range ( app , buffer , Ii64 ( range . max + begin_str . size ) , end_str ) ;
2019-06-14 20:28:20 +00:00
history_group_end ( group ) ;
2017-11-21 18:25:19 +00:00
2019-06-20 23:43:27 +00:00
set_view_range ( app , view , new_pos ) ;
2017-11-21 18:25:19 +00:00
}
else {
2019-06-18 22:56:09 +00:00
String_Const_u8 str = push_u8_stringf ( scratch , " %s \n \n %s " , begin , end ) ;
2019-06-01 23:58:28 +00:00
buffer_replace_range ( app , buffer , range , str ) ;
2019-06-20 23:43:27 +00:00
i64 center_pos = range . min + cstring_length ( begin ) + 1 ;
2019-04-06 21:13:49 +00:00
view_set_cursor ( app , view , seek_pos ( center_pos ) , true ) ;
view_set_mark ( app , view , seek_pos ( center_pos ) ) ;
2017-11-21 18:25:19 +00:00
}
2017-11-29 23:00:14 +00:00
}
CUSTOM_COMMAND_SIG ( place_in_scope )
CUSTOM_DOC ( " Wraps the code contained in the range between cursor and mark with a new curly brace scope. " )
{
2019-06-01 23:58:28 +00:00
place_begin_and_end_on_own_lines ( app , " { " , " } " ) ;
2017-11-21 18:25:19 +00:00
}
CUSTOM_COMMAND_SIG ( delete_current_scope )
CUSTOM_DOC ( " Deletes the braces surrounding the currently selected scope. Leaves the contents within the scope. " )
{
2019-06-19 02:31:59 +00:00
View_ID view = get_active_view ( app , AccessOpen ) ;
Buffer_ID buffer = view_get_buffer ( app , view , AccessOpen ) ;
2017-11-21 18:25:19 +00:00
2019-06-20 23:43:27 +00:00
Range_i64 range = get_view_range ( app , view ) ;
2019-06-19 02:31:59 +00:00
if ( buffer_get_char ( app , buffer , range . min ) = = ' { ' & &
buffer_get_char ( app , buffer , range . max - 1 ) = = ' } ' ) {
2019-02-26 23:08:42 +00:00
i32 top_len = 1 ;
2019-06-19 02:31:59 +00:00
i32 bot_len = 1 ;
if ( buffer_get_char ( app , buffer , range . min - 1 ) = = ' \n ' ) {
2017-11-21 18:25:19 +00:00
top_len = 2 ;
}
2019-06-19 02:31:59 +00:00
if ( buffer_get_char ( app , buffer , range . max + 1 ) = = ' \n ' ) {
bot_len = 2 ;
2017-11-21 18:25:19 +00:00
}
2019-09-02 18:59:36 +00:00
Batch_Edit batch_first = { } ;
Batch_Edit batch_last = { } ;
2017-11-21 18:25:19 +00:00
2019-09-02 18:59:36 +00:00
batch_first . edit . text = SCu8 ( ) ;
batch_first . edit . range = Ii64 ( range . min + 1 - top_len , range . min + 1 ) ;
batch_first . next = & batch_last ;
batch_last . edit . text = SCu8 ( ) ;
batch_last . edit . range = Ii64 ( ( i32 ) ( range . max - 1 ) , ( i32 ) ( range . max - 1 + bot_len ) ) ;
2017-11-21 18:25:19 +00:00
2019-09-02 18:59:36 +00:00
buffer_batch_edit ( app , buffer , & batch_first ) ;
2017-11-21 18:25:19 +00:00
}
}
static Cpp_Token *
parser_next_token ( Statement_Parser * parser ) {
2019-02-02 00:23:48 +00:00
return ( token_iterator_goto_next ( & parser - > token_iterator ) ) ;
2017-11-21 18:25:19 +00:00
}
2019-02-26 23:08:42 +00:00
static b32
2017-11-21 18:25:19 +00:00
parse_for_down ( Application_Links * app , Statement_Parser * parser , Cpp_Token * token_out ) {
2019-02-26 23:08:42 +00:00
b32 success = false ;
2017-11-21 18:25:19 +00:00
Cpp_Token * token = parser_next_token ( parser ) ;
2019-02-26 23:08:42 +00:00
i32 paren_level = 0 ;
2019-06-01 23:58:28 +00:00
for ( ; token ! = 0 ; ) {
2017-11-21 18:25:19 +00:00
if ( ! ( token - > flags & CPP_TFLAG_PP_BODY ) ) {
switch ( token - > type ) {
case CPP_TOKEN_PARENTHESE_OPEN :
{
+ + paren_level ;
} break ;
case CPP_TOKEN_PARENTHESE_CLOSE :
{
- - paren_level ;
if ( paren_level = = 0 ) {
success = parse_statement_down ( app , parser , token_out ) ;
goto finished ;
}
else if ( paren_level < 0 ) {
success = false ;
goto finished ;
}
} break ;
}
}
token = parser_next_token ( parser ) ;
}
finished : ;
return ( success ) ;
}
2019-02-26 23:08:42 +00:00
static b32
2017-11-21 18:25:19 +00:00
parse_if_down ( Application_Links * app , Statement_Parser * parser , Cpp_Token * token_out ) {
2019-02-26 23:08:42 +00:00
b32 success = false ;
2017-11-21 18:25:19 +00:00
Cpp_Token * token = parser_next_token ( parser ) ;
if ( token ! = 0 ) {
success = parse_statement_down ( app , parser , token_out ) ;
if ( success ) {
token = parser_next_token ( parser ) ;
2019-06-01 23:58:28 +00:00
if ( token ! = 0 & & token - > type = = CPP_TOKEN_ELSE ) {
success = parse_statement_down ( app , parser , token_out ) ;
2017-11-21 18:25:19 +00:00
}
}
}
return ( success ) ;
}
2019-02-26 23:08:42 +00:00
static b32
2017-11-21 18:25:19 +00:00
parse_block_down ( Application_Links * app , Statement_Parser * parser , Cpp_Token * token_out ) {
2019-02-26 23:08:42 +00:00
b32 success = false ;
2017-11-21 18:25:19 +00:00
Cpp_Token * token = parser_next_token ( parser ) ;
2019-02-26 23:08:42 +00:00
i32 nest_level = 0 ;
2017-11-21 18:25:19 +00:00
while ( token ! = 0 ) {
switch ( token - > type ) {
case CPP_TOKEN_BRACE_OPEN :
{
+ + nest_level ;
} break ;
case CPP_TOKEN_BRACE_CLOSE :
{
if ( nest_level = = 0 ) {
* token_out = * token ;
success = true ;
goto finished ;
}
- - nest_level ;
} break ;
}
token = parser_next_token ( parser ) ;
}
finished : ;
return ( success ) ;
}
2019-02-26 23:08:42 +00:00
static b32
2017-11-21 18:25:19 +00:00
parse_statement_down ( Application_Links * app , Statement_Parser * parser , Cpp_Token * token_out ) {
2019-02-26 23:08:42 +00:00
b32 success = false ;
2017-11-21 18:25:19 +00:00
Cpp_Token * token = parser_next_token ( parser ) ;
if ( token ! = 0 ) {
2019-02-26 23:08:42 +00:00
b32 not_getting_block = false ;
2017-11-21 18:25:19 +00:00
do {
switch ( token - > type ) {
case CPP_TOKEN_BRACE_CLOSE :
{
goto finished ;
} break ;
2019-02-05 01:06:48 +00:00
case CPP_TOKEN_FOR :
2017-11-21 18:25:19 +00:00
{
2019-02-05 01:06:48 +00:00
success = parse_for_down ( app , parser , token_out ) ;
goto finished ;
} break ;
case CPP_TOKEN_IF :
{
success = parse_if_down ( app , parser , token_out ) ;
goto finished ;
} break ;
case CPP_TOKEN_ELSE :
{
success = false ;
goto finished ;
2017-11-21 18:25:19 +00:00
} break ;
case CPP_TOKEN_BRACE_OPEN :
{
if ( ! not_getting_block ) {
success = parse_block_down ( app , parser , token_out ) ;
goto finished ;
}
} break ;
case CPP_TOKEN_SEMICOLON :
{
success = true ;
* token_out = * token ;
goto finished ;
} break ;
case CPP_TOKEN_EQ :
{
not_getting_block = true ;
} break ;
}
token = parser_next_token ( parser ) ;
} while ( token ! = 0 ) ;
}
finished : ;
return ( success ) ;
}
2019-02-02 00:23:48 +00:00
static Statement_Parser
2019-04-04 08:25:16 +00:00
make_statement_parser ( Application_Links * app , Buffer_ID buffer , i32 token_index ) {
2019-02-02 00:23:48 +00:00
Statement_Parser parser = { } ;
2019-04-04 08:25:16 +00:00
Token_Range token_range = buffer_get_token_range ( app , buffer ) ;
2019-02-02 00:23:48 +00:00
if ( token_range . first ! = 0 ) {
parser . token_iterator = make_token_iterator ( token_range , token_index ) ;
parser . buffer = buffer ;
}
return ( parser ) ;
}
2019-02-26 23:08:42 +00:00
static b32
2019-06-20 23:43:27 +00:00
find_whole_statement_down ( Application_Links * app , Buffer_ID buffer , i64 pos , i64 * start_out , i64 * end_out ) {
2019-02-26 23:08:42 +00:00
b32 result = false ;
2019-06-20 23:43:27 +00:00
i64 start = pos ;
i64 end = start ;
2017-11-21 18:25:19 +00:00
2018-11-20 08:18:54 +00:00
Cpp_Get_Token_Result get_result = { } ;
2019-06-19 02:31:59 +00:00
if ( get_token_from_pos ( app , buffer , pos , & get_result ) ) {
2019-02-02 00:23:48 +00:00
Statement_Parser parser = make_statement_parser ( app , buffer , get_result . token_index ) ;
if ( parser . buffer ! = 0 ) {
2019-02-21 06:58:34 +00:00
if ( get_result . in_whitespace_after_token ) {
2019-02-02 00:23:48 +00:00
parser_next_token ( & parser ) ;
}
2017-11-21 18:25:19 +00:00
2018-11-20 08:18:54 +00:00
Cpp_Token end_token = { } ;
2017-11-21 18:25:19 +00:00
if ( parse_statement_down ( app , & parser , & end_token ) ) {
end = end_token . start + end_token . size ;
result = true ;
}
}
}
* start_out = start ;
* end_out = end ;
return ( result ) ;
}
CUSTOM_COMMAND_SIG ( scope_absorb_down )
CUSTOM_DOC ( " If a scope is currently selected, and a statement or block statement is present below the current scope, the statement is moved into the scope. " )
{
2019-06-19 02:31:59 +00:00
View_ID view = get_active_view ( app , AccessOpen ) ;
Buffer_ID buffer = view_get_buffer ( app , view , AccessOpen ) ;
2019-04-06 21:13:49 +00:00
2019-06-20 23:43:27 +00:00
Range_i64 range = get_view_range ( app , view ) ;
2019-06-19 02:31:59 +00:00
if ( buffer_get_char ( app , buffer , range . min ) = = ' { ' & &
buffer_get_char ( app , buffer , range . max - 1 ) = = ' } ' ) {
2019-06-01 23:58:28 +00:00
Scratch_Block scratch ( app ) ;
2019-06-19 02:31:59 +00:00
if ( find_whole_statement_down ( app , buffer , range . max , & range . start , & range . end ) ) {
2019-06-02 03:07:57 +00:00
String_Const_u8 base_string = push_buffer_range ( app , scratch , buffer , range ) ;
2019-06-01 23:58:28 +00:00
String_Const_u8 string = string_skip_chop_whitespace ( base_string ) ;
2017-11-21 18:25:19 +00:00
2019-02-26 23:08:42 +00:00
i32 newline_count = 0 ;
2019-06-01 23:58:28 +00:00
for ( u8 * ptr = base_string . str ; ptr < string . str ; + + ptr ) {
2017-11-21 18:25:19 +00:00
if ( * ptr = = ' \n ' ) {
+ + newline_count ;
}
}
2019-02-26 23:08:42 +00:00
b32 extra_newline = false ;
2017-11-21 18:25:19 +00:00
if ( newline_count > = 2 ) {
extra_newline = true ;
}
2019-06-01 23:58:28 +00:00
String_Const_u8 edit_str = { } ;
2017-11-21 18:25:19 +00:00
if ( extra_newline ) {
2019-06-18 22:56:09 +00:00
edit_str = push_u8_stringf ( scratch , " \n %.*s \n " , string_expand ( string ) ) ;
2017-11-21 18:25:19 +00:00
}
else {
2019-06-18 22:56:09 +00:00
edit_str = push_u8_stringf ( scratch , " %.*s \n " , string_expand ( string ) ) ;
2017-11-21 18:25:19 +00:00
}
2019-09-02 18:59:36 +00:00
Batch_Edit batch_first = { } ;
Batch_Edit batch_last = { } ;
batch_first . edit . text = edit_str ;
batch_first . edit . range = Ii64 ( range . min - 1 , range . min - 1 ) ;
batch_first . next = & batch_last ;
batch_last . edit . text = SCu8 ( ) ;
batch_last . edit . range = range ;
buffer_batch_edit ( app , buffer , & batch_first ) ;
2017-11-21 18:25:19 +00:00
}
}
2018-10-06 01:42:56 +00:00
2019-04-06 21:13:49 +00:00
no_mark_snap_to_cursor ( app , view ) ;
2017-11-21 18:25:19 +00:00
}
// BOTTOM