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 ) ;
static f32 scope_center_threshold = 0.75f ;
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-04-04 08:25:16 +00:00
find_scope_top ( Application_Links * app , Buffer_ID buffer , i32 start_pos , u32 flags , i32 * 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-02-02 00:23:48 +00:00
if ( buffer_get_token_index ( app , buffer , start_pos , & get_result ) ) {
2019-02-26 23:08:42 +00:00
i32 token_index = get_result . token_index ;
2019-02-02 00:23:48 +00:00
if ( flags & FindScope_Parent ) {
- - 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-04-04 08:25:16 +00:00
find_scope_bottom ( Application_Links * app , Buffer_ID buffer , i32 start_pos , u32 flags , i32 * 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-02-02 00:23:48 +00:00
if ( buffer_get_token_index ( app , buffer , start_pos , & get_result ) ) {
2019-02-26 23:08:42 +00:00
i32 token_index = get_result . token_index + 1 ;
2019-02-02 00:23:48 +00:00
if ( flags & FindScope_Parent ) {
- - 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-04-04 08:25:16 +00:00
find_next_scope ( Application_Links * app , Buffer_ID buffer , i32 start_pos , u32 flags , i32 * 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 ;
i32 position = 0 ;
2019-02-02 00:23:48 +00:00
if ( buffer_get_token_index ( 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 ) ;
if ( ( flags & FindScope_NextSibling ) ! = 0 ) {
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-04-04 08:25:16 +00:00
find_prev_scope ( Application_Links * app , Buffer_ID buffer , i32 start_pos , u32 flags , i32 * 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-02-02 00:23:48 +00:00
if ( buffer_get_token_index ( app , buffer , start_pos , & get_result ) ) {
2019-02-26 23:08:42 +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 ) ;
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-04-04 08:25:16 +00:00
find_scope_range ( Application_Links * app , Buffer_ID buffer , i32 start_pos , Range * range_out , u32 flags ) {
b32 result = false ;
2018-11-20 08:18:54 +00:00
Range 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-04-06 21:13:49 +00:00
view_set_to_region ( Application_Links * app , View_ID view , i32 major_pos , i32 minor_pos , f32 normalized_threshold ) {
2017-11-21 18:25:19 +00:00
Range range = make_range ( 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 ;
}
2018-11-20 08:18:54 +00:00
Full_Cursor top = { } ;
Full_Cursor bottom = { } ;
2017-11-21 18:25:19 +00:00
if ( view_compute_cursor ( app , view , seek_pos ( range . min ) , & top ) ) {
if ( view_compute_cursor ( app , view , seek_pos ( range . max ) , & bottom ) ) {
2019-02-26 23:08:42 +00:00
f32 top_y = top . wrapped_y ;
f32 bottom_y = bottom . wrapped_y ;
2017-11-21 18:25:19 +00:00
2019-02-27 05:49:35 +00:00
Rect_i32 region = { } ;
2019-04-06 21:13:49 +00:00
view_get_buffer_region ( app , view , & region ) ;
2019-02-27 05:49:35 +00:00
2019-04-06 21:13:49 +00:00
GUI_Scroll_Vars scroll = { } ;
view_get_scroll_vars ( app , view , & scroll ) ;
2019-02-27 05:49:35 +00:00
f32 half_view_height = .5f * ( f32 ) ( rect_height ( region ) ) ;
2019-02-26 23:08:42 +00:00
f32 threshold = normalized_threshold * half_view_height ;
f32 current_center_y = ( ( f32 ) scroll . target_y ) + half_view_height ;
2017-11-21 18:25:19 +00:00
if ( top_y < current_center_y - threshold | | bottom_y > current_center_y + threshold ) {
2019-02-26 23:08:42 +00:00
f32 center_target_y = .5f * ( top_y + bottom_y ) ;
2017-11-21 18:25:19 +00:00
if ( bottom_major ) {
if ( center_target_y < bottom_y - half_view_height * .9f ) {
center_target_y = bottom_y - half_view_height * .9f ;
}
}
else {
if ( center_target_y > top_y + half_view_height * .9f ) {
center_target_y = top_y + half_view_height * .9f ;
}
}
2019-02-26 23:08:42 +00:00
f32 target_y = center_target_y - half_view_height ;
2017-11-21 18:25:19 +00:00
if ( target_y < 0 ) {
target_y = 0 ;
}
2019-02-26 23:08:42 +00:00
scroll . target_y = ( i32 ) ( target_y ) ;
2017-11-21 18:25:19 +00:00
view_set_scroll ( app , view , scroll ) ;
}
}
}
}
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-04-06 21:13:49 +00:00
View_ID view = 0 ;
get_active_view ( app , AccessProtected , & view ) ;
2019-04-04 08:25:16 +00:00
Buffer_ID buffer = 0 ;
2019-04-06 21:13:49 +00:00
view_get_buffer ( app , view , AccessProtected , & buffer ) ;
i32 pos = 0 ;
view_get_cursor_pos ( app , view , & pos ) ;
2018-11-20 08:18:54 +00:00
Range 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 ) ) ;
view_set_to_region ( app , view , range . first , range . end , scope_center_threshold ) ;
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-04-06 21:13:49 +00:00
View_ID view = 0 ;
get_active_view ( app , AccessProtected , & view ) ;
2019-04-04 08:25:16 +00:00
Buffer_ID buffer = 0 ;
2019-04-06 21:13:49 +00:00
view_get_buffer ( app , view , AccessProtected , & buffer ) ;
i32 pos = 0 ;
view_get_cursor_pos ( app , view , & pos ) ;
i32 start_pos = pos ;
2019-02-26 23:08:42 +00:00
i32 top = 0 ;
i32 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 ) ) ;
view_set_to_region ( app , view , top , bottom , scope_center_threshold ) ;
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-04-06 21:13:49 +00:00
View_ID view = 0 ;
get_active_view ( app , AccessProtected , & view ) ;
2019-04-04 08:25:16 +00:00
Buffer_ID buffer = 0 ;
2019-04-06 21:13:49 +00:00
view_get_buffer ( app , view , AccessProtected , & buffer ) ;
i32 pos = 0 ;
view_get_cursor_pos ( app , view , & pos ) ;
i32 start_pos = pos ;
i32 top = 0 ;
i32 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 ) ) ;
view_set_to_region ( app , view , top , bottom , scope_center_threshold ) ;
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-04-06 21:13:49 +00:00
View_ID view = 0 ;
get_active_view ( app , AccessOpen , & view ) ;
2019-04-04 08:25:16 +00:00
Buffer_ID buffer = 0 ;
2019-04-06 21:13:49 +00:00
view_get_buffer ( app , view , AccessOpen , & buffer ) ;
2017-11-21 18:25:19 +00:00
2018-11-20 08:18:54 +00:00
Range lines = { } ;
2019-04-06 21:13:49 +00:00
Range range = get_view_range ( app , view ) ;
2019-06-02 03:07:57 +00:00
lines . min = get_line_number_from_pos ( app , buffer , range . min ) ;
lines . max = get_line_number_from_pos ( app , buffer , range . max ) ;
range . min = get_line_start_pos ( app , buffer , lines . min ) ;
range . max = get_line_end_pos ( app , buffer , lines . max ) ;
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-01 23:58:28 +00:00
umem min_adjustment = 0 ;
umem max_adjustment = 0 ;
2017-11-21 18:25:19 +00:00
2019-06-01 23:58:28 +00:00
if ( min_line_blank ) {
begin_str = string_u8_pushf ( scratch , " \n %s " , begin ) ;
min_adjustment + = 1 ;
2017-11-21 18:25:19 +00:00
}
2019-06-01 23:58:28 +00:00
else {
begin_str = string_u8_pushf ( scratch , " %s \n " , begin ) ;
}
if ( max_line_blank ) {
end_str = string_u8_pushf ( scratch , " %s \n " , end ) ;
}
else {
end_str = string_u8_pushf ( scratch , " \n %s " , end ) ;
max_adjustment + = 1 ;
2017-11-21 18:25:19 +00:00
}
2019-06-01 23:58:28 +00:00
max_adjustment + = begin_str . size ;
Range new_pos = make_range ( range . min + ( i32 ) min_adjustment , range . max + ( i32 ) max_adjustment ) ;
2017-11-21 18:25:19 +00:00
2019-06-14 20:28:20 +00:00
i32 cursor_pos = 0 ;
2019-06-01 23:58:28 +00:00
i32 mark_pos = 0 ;
view_get_cursor_pos ( app , view , & cursor_pos ) ;
2017-11-21 18:25:19 +00:00
2019-06-01 23:58:28 +00:00
if ( cursor_pos = = range . min ) {
cursor_pos = new_pos . min ;
mark_pos = new_pos . max ;
}
else {
cursor_pos = new_pos . max ;
mark_pos = new_pos . min ;
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-01 23:58:28 +00:00
buffer_replace_range ( app , buffer , make_range ( range . min ) , begin_str ) ;
buffer_replace_range ( app , buffer , make_range ( range . max + ( i32 ) 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-04-06 21:13:49 +00:00
view_set_cursor ( app , view , seek_pos ( cursor_pos ) , true ) ;
view_set_mark ( app , view , seek_pos ( mark_pos ) ) ;
2017-11-21 18:25:19 +00:00
}
else {
2019-06-01 23:58:28 +00:00
String_Const_u8 str = string_u8_pushf ( scratch , " %s \n \n %s " , begin , end ) ;
buffer_replace_range ( app , buffer , range , str ) ;
i32 center_pos = range . min + ( i32 ) 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-04-06 21:13:49 +00:00
View_ID view = 0 ;
get_active_view ( app , AccessOpen , & view ) ;
2019-04-04 08:25:16 +00:00
Buffer_ID buffer = 0 ;
2019-04-06 21:13:49 +00:00
view_get_buffer ( app , view , AccessOpen , & buffer ) ;
2017-11-21 18:25:19 +00:00
2019-04-06 21:13:49 +00:00
i32 view_cursor_pos = 0 ;
view_get_cursor_pos ( app , view , & view_cursor_pos ) ;
i32 view_mark_pos = 0 ;
view_get_mark_pos ( app , view , & view_mark_pos ) ;
i32 top = view_cursor_pos ;
i32 bottom = view_mark_pos ;
2017-11-21 18:25:19 +00:00
if ( top > bottom ) {
2019-02-26 23:08:42 +00:00
i32 x = top ;
2017-11-21 18:25:19 +00:00
top = bottom ;
bottom = x ;
}
2019-04-04 08:25:16 +00:00
if ( buffer_get_char ( app , buffer , top ) = = ' { ' & & buffer_get_char ( app , buffer , bottom - 1 ) = = ' } ' ) {
2019-02-26 23:08:42 +00:00
i32 top_len = 1 ;
i32 bottom_len = 1 ;
2019-04-04 08:25:16 +00:00
if ( buffer_get_char ( app , buffer , top - 1 ) = = ' \n ' ) {
2017-11-21 18:25:19 +00:00
top_len = 2 ;
}
2019-04-04 08:25:16 +00:00
if ( buffer_get_char ( app , buffer , bottom + 1 ) = = ' \n ' ) {
2017-11-21 18:25:19 +00:00
bottom_len = 2 ;
}
Buffer_Edit edits [ 2 ] ;
edits [ 0 ] . str_start = 0 ;
edits [ 0 ] . len = 0 ;
2019-04-01 02:41:39 +00:00
edits [ 0 ] . start = top + 1 - top_len ;
edits [ 0 ] . end = top + 1 ;
2017-11-21 18:25:19 +00:00
edits [ 1 ] . str_start = 0 ;
edits [ 1 ] . len = 0 ;
2019-04-01 02:41:39 +00:00
edits [ 1 ] . start = bottom - 1 ;
edits [ 1 ] . end = bottom - 1 + bottom_len ;
2017-11-21 18:25:19 +00:00
2019-04-05 23:30:24 +00:00
buffer_batch_edit ( app , buffer , 0 , edits , 2 ) ;
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-04-04 08:25:16 +00:00
find_whole_statement_down ( Application_Links * app , Buffer_ID buffer , i32 pos , i32 * start_out , i32 * end_out ) {
2019-02-26 23:08:42 +00:00
b32 result = false ;
i32 start = pos ;
i32 end = start ;
2017-11-21 18:25:19 +00:00
2018-11-20 08:18:54 +00:00
Cpp_Get_Token_Result get_result = { } ;
2017-11-21 18:25:19 +00:00
if ( buffer_get_token_index ( 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-04-06 21:13:49 +00:00
View_ID view = 0 ;
get_active_view ( app , AccessOpen , & view ) ;
2019-04-04 08:25:16 +00:00
Buffer_ID buffer = 0 ;
2019-04-06 21:13:49 +00:00
view_get_buffer ( app , view , AccessOpen , & buffer ) ;
i32 view_cursor_pos = 0 ;
view_get_cursor_pos ( app , view , & view_cursor_pos ) ;
i32 view_mark_pos = 0 ;
view_get_mark_pos ( app , view , & view_mark_pos ) ;
2017-11-21 18:25:19 +00:00
2019-04-06 21:13:49 +00:00
i32 top = view_cursor_pos ;
i32 bottom = view_mark_pos ;
2017-11-21 18:25:19 +00:00
if ( top > bottom ) {
2019-02-26 23:08:42 +00:00
i32 x = top ;
2017-11-21 18:25:19 +00:00
top = bottom ;
bottom = x ;
}
2019-04-04 08:25:16 +00:00
if ( buffer_get_char ( app , buffer , top ) = = ' { ' & & buffer_get_char ( app , buffer , bottom - 1 ) = = ' } ' ) {
2019-06-01 23:58:28 +00:00
Scratch_Block scratch ( app ) ;
2018-11-20 08:18:54 +00:00
Range range = { } ;
2019-04-04 08:25:16 +00:00
if ( find_whole_statement_down ( app , buffer , bottom , & 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-01 23:58:28 +00:00
edit_str = string_u8_pushf ( scratch , " \n %.*s \n " , string_expand ( string ) ) ;
2017-11-21 18:25:19 +00:00
}
else {
2019-06-01 23:58:28 +00:00
edit_str = string_u8_pushf ( scratch , " %.*s \n " , string_expand ( string ) ) ;
2017-11-21 18:25:19 +00:00
}
Buffer_Edit edits [ 2 ] ;
edits [ 0 ] . str_start = 0 ;
2019-06-01 23:58:28 +00:00
edits [ 0 ] . len = ( i32 ) edit_str . size ;
edits [ 0 ] . start = bottom - 1 ;
edits [ 0 ] . end = bottom - 1 ;
2017-11-21 18:25:19 +00:00
edits [ 1 ] . str_start = 0 ;
edits [ 1 ] . len = 0 ;
edits [ 1 ] . start = range . start ;
edits [ 1 ] . end = range . end ;
2019-06-01 23:58:28 +00:00
buffer_batch_edit ( app , buffer , ( char * ) edit_str . str , edits , 2 ) ;
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