2017-01-29 00:03:23 +00:00
|
|
|
/*
|
|
|
|
4coder_function_list.cpp - Command for listing all functions in a C/C++ file in a jump list.
|
|
|
|
*/
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
// TOP
|
|
|
|
|
|
|
|
// NOTE(allen|a4.0.14): This turned out to be a nasty little routine. There might
|
|
|
|
// be a better way to do it with just tokens that I didn't see the first time
|
|
|
|
// through. Once I build a real parser this should become almost just as easy as
|
|
|
|
// iterating tokens is now.
|
|
|
|
//
|
2019-09-28 23:29:54 +00:00
|
|
|
// NOTE(allen|b4.1.0): This routine assumes C++ sub_kinds in the tokens of the buffer.
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-02-01 22:50:33 +00:00
|
|
|
static Get_Positions_Results
|
2019-09-28 23:29:54 +00:00
|
|
|
get_function_positions(Application_Links *app, Buffer_ID buffer, i64 first_token_index, Function_Positions *positions_array, i64 positions_max){
|
2019-02-01 22:50:33 +00:00
|
|
|
Get_Positions_Results result = {};
|
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
Token_Array array = get_token_array_from_buffer(app, buffer);
|
|
|
|
if (array.tokens != 0){
|
|
|
|
Token_Iterator_Array it = token_iterator_index(buffer, &array, first_token_index);
|
2019-02-01 22:50:33 +00:00
|
|
|
|
2019-02-26 23:08:42 +00:00
|
|
|
i32 nest_level = 0;
|
|
|
|
i32 paren_nest_level = 0;
|
2019-02-01 22:50:33 +00:00
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
Token_Iterator_Array first_paren_it = {};
|
|
|
|
i64 first_paren_index = 0;
|
|
|
|
i64 first_paren_position = 0;
|
|
|
|
i64 last_paren_index = 0;
|
2019-02-01 22:50:33 +00:00
|
|
|
|
|
|
|
// Look for the next token at global scope that might need to be printed.
|
|
|
|
mode1:
|
|
|
|
Assert(nest_level == 0);
|
|
|
|
Assert(paren_nest_level == 0);
|
|
|
|
first_paren_index = 0;
|
|
|
|
first_paren_position = 0;
|
|
|
|
last_paren_index = 0;
|
2019-09-28 23:29:54 +00:00
|
|
|
for (;;){
|
|
|
|
Token *token = token_it_read(&it);
|
|
|
|
if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){
|
|
|
|
switch (token->sub_kind){
|
|
|
|
case TokenCppKind_BraceOp:
|
2019-02-01 22:50:33 +00:00
|
|
|
{
|
|
|
|
++nest_level;
|
|
|
|
}break;
|
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
case TokenCppKind_BraceCl:
|
2019-02-01 22:50:33 +00:00
|
|
|
{
|
|
|
|
if (nest_level > 0){
|
|
|
|
--nest_level;
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
case TokenCppKind_ParenOp:
|
2019-02-01 22:50:33 +00:00
|
|
|
{
|
|
|
|
if (nest_level == 0){
|
2019-09-28 23:29:54 +00:00
|
|
|
first_paren_it = it;
|
|
|
|
first_paren_index = token_it_index(&it);
|
|
|
|
first_paren_position = token->pos;
|
2019-02-01 22:50:33 +00:00
|
|
|
goto paren_mode1;
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
}
|
|
|
|
}
|
2019-09-28 23:29:54 +00:00
|
|
|
if (!token_it_inc(&it)){
|
|
|
|
goto end;
|
|
|
|
}
|
2019-02-01 22:50:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Look for a closing parenthese to mark the end of a function signature.
|
|
|
|
paren_mode1:
|
|
|
|
paren_nest_level = 0;
|
2019-09-28 23:29:54 +00:00
|
|
|
for (;;){
|
|
|
|
Token *token = token_it_read(&it);
|
|
|
|
if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){
|
|
|
|
switch (token->sub_kind){
|
|
|
|
case TokenCppKind_ParenOp:
|
2019-02-01 22:50:33 +00:00
|
|
|
{
|
|
|
|
++paren_nest_level;
|
|
|
|
}break;
|
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
case TokenCppKind_ParenCl:
|
2019-02-01 22:50:33 +00:00
|
|
|
{
|
|
|
|
--paren_nest_level;
|
|
|
|
if (paren_nest_level == 0){
|
2019-09-28 23:29:54 +00:00
|
|
|
last_paren_index = token_it_index(&it);
|
2019-02-01 22:50:33 +00:00
|
|
|
goto paren_mode2;
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
}
|
|
|
|
}
|
2019-09-28 23:29:54 +00:00
|
|
|
if (!token_it_inc(&it)){
|
|
|
|
goto end;
|
|
|
|
}
|
2019-02-01 22:50:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Look backwards from an open parenthese to find the start of a function signature.
|
|
|
|
paren_mode2:
|
|
|
|
{
|
2019-09-28 23:29:54 +00:00
|
|
|
Token_Iterator_Array restore_point = it;
|
|
|
|
it = first_paren_it;
|
|
|
|
i64 signature_start_index = 0;
|
|
|
|
for (;;){
|
|
|
|
Token *token = token_it_read(&it);
|
|
|
|
if (HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) ||
|
|
|
|
token->sub_kind == TokenCppKind_BraceCl ||
|
|
|
|
token->sub_kind == TokenCppKind_Semicolon ||
|
|
|
|
token->sub_kind == TokenCppKind_ParenCl){
|
|
|
|
if (!token_it_inc(&it)){
|
2019-02-05 20:39:12 +00:00
|
|
|
signature_start_index = first_paren_index;
|
|
|
|
}
|
2019-09-28 23:29:54 +00:00
|
|
|
else{
|
|
|
|
signature_start_index = token_it_index(&it);
|
|
|
|
}
|
2019-02-01 22:50:33 +00:00
|
|
|
goto paren_mode2_done;
|
|
|
|
}
|
2019-09-28 23:29:54 +00:00
|
|
|
if (!token_it_dec(&it)){
|
|
|
|
break;
|
|
|
|
}
|
2019-02-01 22:50:33 +00:00
|
|
|
}
|
|
|
|
|
2019-02-05 20:39:12 +00:00
|
|
|
// When this loop ends by going all the way back to the beginning set the
|
|
|
|
// signature start to 0 and fall through to the printing phase.
|
2019-02-01 22:50:33 +00:00
|
|
|
signature_start_index = 0;
|
|
|
|
|
|
|
|
paren_mode2_done:;
|
|
|
|
{
|
2019-09-28 23:29:54 +00:00
|
|
|
Function_Positions positions = {};
|
2019-02-01 22:50:33 +00:00
|
|
|
positions.sig_start_index = signature_start_index;
|
|
|
|
positions.sig_end_index = last_paren_index;
|
|
|
|
positions.open_paren_pos = first_paren_position;
|
|
|
|
positions_array[result.positions_count++] = positions;
|
|
|
|
}
|
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
it = restore_point;
|
2019-02-01 22:50:33 +00:00
|
|
|
if (result.positions_count >= positions_max){
|
2019-09-28 23:29:54 +00:00
|
|
|
result.next_token_index = token_it_index(&it);
|
2019-02-01 22:50:33 +00:00
|
|
|
result.still_looping = true;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto mode1;
|
|
|
|
}
|
|
|
|
end:;
|
|
|
|
}
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2019-02-02 00:23:48 +00:00
|
|
|
static void
|
2019-09-28 23:29:54 +00:00
|
|
|
print_positions_buffered(Application_Links *app, Buffer_Insertion *out, Buffer_ID buffer, Function_Positions *positions_array, i64 positions_count){
|
|
|
|
Scratch_Block scratch(app);
|
2019-02-02 00:23:48 +00:00
|
|
|
|
2019-06-02 03:07:57 +00:00
|
|
|
String_Const_u8 buffer_name = push_buffer_unique_name(app, scratch, buffer);
|
2019-02-02 00:23:48 +00:00
|
|
|
|
2019-02-26 23:08:42 +00:00
|
|
|
for (i32 i = 0; i < positions_count; ++i){
|
2019-02-02 00:23:48 +00:00
|
|
|
Function_Positions *positions = &positions_array[i];
|
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
i64 start_index = positions->sig_start_index;
|
|
|
|
i64 end_index = positions->sig_end_index;
|
2019-06-20 23:43:27 +00:00
|
|
|
i64 open_paren_pos = positions->open_paren_pos;
|
|
|
|
i64 line_number = get_line_number_from_pos(app, buffer, open_paren_pos);
|
2019-02-02 00:23:48 +00:00
|
|
|
|
2019-02-05 20:39:12 +00:00
|
|
|
Assert(end_index > start_index);
|
2019-02-02 00:23:48 +00:00
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
Token_Array array = get_token_array_from_buffer(app, buffer);
|
|
|
|
if (array.tokens != 0){
|
2019-06-20 23:43:27 +00:00
|
|
|
insertf(out, "%.*s:%lld: ", string_expand(buffer_name), line_number);
|
2019-02-02 00:23:48 +00:00
|
|
|
|
2019-09-04 05:31:35 +00:00
|
|
|
Token prev_token = {};
|
2019-09-28 23:29:54 +00:00
|
|
|
Token_Iterator_Array it = token_iterator_index(buffer, &array, start_index);
|
|
|
|
for (;;){
|
|
|
|
Token *token = token_it_read(&it);
|
|
|
|
if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) &&
|
|
|
|
token->kind != TokenBaseKind_Comment){
|
|
|
|
if ((prev_token.sub_kind == TokenCppKind_Identifier ||
|
|
|
|
prev_token.sub_kind == TokenCppKind_Star ||
|
|
|
|
prev_token.sub_kind == TokenCppKind_Comma ||
|
|
|
|
prev_token.kind == TokenBaseKind_Keyword) &&
|
|
|
|
!(token->sub_kind == TokenCppKind_ParenOp ||
|
|
|
|
token->sub_kind == TokenCppKind_ParenCl ||
|
|
|
|
token->sub_kind == TokenCppKind_Comma)){
|
2019-06-01 23:58:28 +00:00
|
|
|
insertc(out, ' ');
|
2019-02-02 00:23:48 +00:00
|
|
|
}
|
2019-06-01 23:58:28 +00:00
|
|
|
|
|
|
|
Temp_Memory token_temp = begin_temp(scratch);
|
2019-10-15 22:30:06 +00:00
|
|
|
String_Const_u8 lexeme = push_token_lexeme(app, scratch, buffer, token);
|
2019-06-01 23:58:28 +00:00
|
|
|
insert_string(out, lexeme);
|
|
|
|
end_temp(token_temp);
|
2019-02-02 00:23:48 +00:00
|
|
|
|
|
|
|
prev_token = *token;
|
|
|
|
}
|
2019-09-28 23:29:54 +00:00
|
|
|
if (!token_it_inc(&it)){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i64 index = token_it_index(&it);
|
|
|
|
if (index > end_index){
|
|
|
|
break;
|
|
|
|
}
|
2019-02-02 00:23:48 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
insertc(out, '\n');
|
2019-02-02 00:23:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-29 16:32:06 +00:00
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
list_all_functions(Application_Links *app, Buffer_ID optional_target_buffer){
|
|
|
|
// TODO(allen): Use create or switch to buffer and clear here?
|
|
|
|
String_Const_u8 decls_name = string_u8_litexpr("*decls*");
|
2019-10-18 02:54:02 +00:00
|
|
|
Buffer_ID decls_buffer = get_buffer_by_name(app, decls_name, Access_Always);
|
2019-04-04 08:25:16 +00:00
|
|
|
if (!buffer_exists(app, decls_buffer)){
|
2019-06-19 02:31:59 +00:00
|
|
|
decls_buffer = create_buffer(app, decls_name, BufferCreate_AlwaysNew);
|
2019-04-04 08:25:16 +00:00
|
|
|
buffer_set_setting(app, decls_buffer, BufferSetting_Unimportant, true);
|
|
|
|
buffer_set_setting(app, decls_buffer, BufferSetting_ReadOnly, true);
|
2019-09-28 23:29:54 +00:00
|
|
|
//buffer_set_setting(app, decls_buffer, BufferSetting_WrapLine, false);
|
2017-03-29 16:32:06 +00:00
|
|
|
}
|
|
|
|
else{
|
2019-06-20 23:43:27 +00:00
|
|
|
clear_buffer(app, decls_buffer);
|
2019-04-04 08:25:16 +00:00
|
|
|
buffer_send_end_signal(app, decls_buffer);
|
2017-03-29 16:32:06 +00:00
|
|
|
}
|
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
Scratch_Block scratch(app);
|
2017-03-29 16:32:06 +00:00
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
// TODO(allen): rewrite get_function_positions to allocate on arena
|
|
|
|
i32 positions_max = KB(4)/sizeof(Function_Positions);
|
2019-06-01 23:58:28 +00:00
|
|
|
Function_Positions *positions_array = push_array(scratch, Function_Positions, positions_max);
|
2017-03-29 16:32:06 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
Cursor insertion_cursor = make_cursor(push_array(scratch, u8, KB(256)), KB(256));
|
|
|
|
Buffer_Insertion out = begin_buffer_insertion_at_buffered(app, decls_buffer, 0, &insertion_cursor);
|
2018-12-10 01:31:30 +00:00
|
|
|
|
2019-10-18 02:54:02 +00:00
|
|
|
for (Buffer_ID buffer_it = get_buffer_next(app, 0, Access_Always);
|
2019-04-04 08:25:16 +00:00
|
|
|
buffer_it != 0;
|
2019-10-18 02:54:02 +00:00
|
|
|
buffer_it = get_buffer_next(app, buffer_it, Access_Always)){
|
2019-04-04 08:25:16 +00:00
|
|
|
Buffer_ID buffer = buffer_it;
|
2018-09-15 23:48:02 +00:00
|
|
|
if (optional_target_buffer != 0){
|
2019-04-04 08:25:16 +00:00
|
|
|
buffer = optional_target_buffer;
|
2018-09-15 23:48:02 +00:00
|
|
|
}
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
Token_Array array = get_token_array_from_buffer(app, buffer);
|
|
|
|
if (array.tokens != 0){
|
|
|
|
i64 token_index = 0;
|
2019-04-04 08:25:16 +00:00
|
|
|
b32 still_looping = false;
|
|
|
|
do{
|
|
|
|
Get_Positions_Results get_positions_results = get_function_positions(app, buffer, token_index, positions_array, positions_max);
|
|
|
|
|
2019-09-28 23:29:54 +00:00
|
|
|
i64 positions_count = get_positions_results.positions_count;
|
2019-04-04 08:25:16 +00:00
|
|
|
token_index = get_positions_results.next_token_index;
|
|
|
|
still_looping = get_positions_results.still_looping;
|
|
|
|
|
2019-07-27 02:31:01 +00:00
|
|
|
print_positions_buffered(app, &out, buffer, positions_array, positions_count);
|
2019-04-04 08:25:16 +00:00
|
|
|
}while(still_looping);
|
2018-09-15 23:48:02 +00:00
|
|
|
|
2019-04-04 08:25:16 +00:00
|
|
|
if (optional_target_buffer != 0){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-09-15 23:48:02 +00:00
|
|
|
}
|
2017-03-29 16:32:06 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
end_buffer_insertion(&out);
|
2018-12-10 01:31:30 +00:00
|
|
|
|
2019-10-18 02:54:02 +00:00
|
|
|
View_ID view = get_active_view(app, Access_Always);
|
2019-04-07 17:36:24 +00:00
|
|
|
view_set_buffer(app, view, decls_buffer, 0);
|
2017-03-29 16:32:06 +00:00
|
|
|
|
2019-08-16 02:54:06 +00:00
|
|
|
lock_jump_buffer(app, decls_name);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(list_all_functions_current_buffer)
|
|
|
|
CUSTOM_DOC("Creates a jump list of lines of the current buffer that appear to define or declare functions.")
|
|
|
|
{
|
2019-10-18 02:54:02 +00:00
|
|
|
View_ID view = get_active_view(app, Access_ReadVisible);
|
|
|
|
Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible);
|
2019-06-19 02:31:59 +00:00
|
|
|
if (buffer != 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
list_all_functions(app, buffer);
|
2018-09-15 23:48:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_functions_current_buffer_lister)
|
|
|
|
CUSTOM_DOC("Creates a lister of locations that look like function definitions and declarations in the buffer.")
|
|
|
|
{
|
2019-12-23 17:15:18 +00:00
|
|
|
Heap *heap = &global_heap;
|
2019-10-18 02:54:02 +00:00
|
|
|
View_ID view = get_active_view(app, Access_ReadVisible);
|
|
|
|
Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible);
|
2019-06-19 02:31:59 +00:00
|
|
|
if (buffer != 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
list_all_functions(app, buffer);
|
2019-10-18 02:54:02 +00:00
|
|
|
view = get_active_view(app, Access_Always);
|
2019-10-25 23:33:50 +00:00
|
|
|
buffer = view_get_buffer(app, view, Access_Always);
|
2019-12-23 17:15:18 +00:00
|
|
|
Marker_List *list = get_or_make_list_for_buffer(app, heap, buffer);
|
2019-10-25 23:33:50 +00:00
|
|
|
if (list != 0){
|
|
|
|
Jump_Lister_Result jump = get_jump_index_from_user(app, list,
|
|
|
|
"Function:");
|
|
|
|
jump_to_jump_lister_result(app, view, list, &jump);
|
|
|
|
}
|
2018-09-15 23:48:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_functions_all_buffers)
|
|
|
|
CUSTOM_DOC("Creates a jump list of lines from all buffers that appear to define or declare functions.")
|
|
|
|
{
|
2019-06-01 23:58:28 +00:00
|
|
|
list_all_functions(app, 0);
|
2018-09-15 23:48:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_functions_all_buffers_lister)
|
|
|
|
CUSTOM_DOC("Creates a lister of locations that look like function definitions and declarations all buffers.")
|
|
|
|
{
|
2019-12-23 17:15:18 +00:00
|
|
|
Heap *heap = &global_heap;
|
2019-06-01 23:58:28 +00:00
|
|
|
list_all_functions(app, 0);
|
2019-10-18 02:54:02 +00:00
|
|
|
View_ID view = get_active_view(app, Access_Always);
|
|
|
|
Buffer_ID buffer = view_get_buffer(app, view, Access_Always);
|
2019-12-23 17:15:18 +00:00
|
|
|
Marker_List *list = get_or_make_list_for_buffer(app, heap, buffer);
|
2019-10-25 23:33:50 +00:00
|
|
|
if (list != 0){
|
2019-12-23 17:15:18 +00:00
|
|
|
Jump_Lister_Result jump = get_jump_index_from_user(app, list, "Function:");
|
2019-10-25 23:33:50 +00:00
|
|
|
jump_to_jump_lister_result(app, view, list, &jump);
|
|
|
|
}
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// BOTTOM
|
|
|
|
|