diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index 73fbfcd4..e1607aaf 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -453,7 +453,7 @@ buffer_line_y_difference(Application_Links *app, Buffer_ID buffer_id, i64 line_a, i64 line_b){ Models *models = (Models*)app->cmd_context; Editing_File *file = imp_get_file(models, buffer_id); - f32 result = {}; + f32 result = 0.0f; if (api_check_buffer(file)){ Face *face = font_set_face_from_id(&models->font_set, face_id); if (face != 0){ @@ -544,7 +544,7 @@ buffer_relative_character_from_pos(Application_Links *app, Buffer_ID buffer_id, { Models *models = (Models*)app->cmd_context; Editing_File *file = imp_get_file(models, buffer_id); - i64 result = {}; + i64 result = 0; if (api_check_buffer(file)){ Face *face = font_set_face_from_id(&models->font_set, face_id); if (face != 0){ @@ -580,7 +580,7 @@ api(custom) function f32 view_line_y_difference(Application_Links *app, View_ID view_id, i64 line_a, i64 line_b){ Models *models = (Models*)app->cmd_context; View *view = imp_get_view(models, view_id); - f32 result = {}; + f32 result = 0.0f; if (api_check_view(view)){ result = view_line_y_difference(app->tctx, models, view, line_a, line_b); } @@ -635,7 +635,7 @@ api(custom) function i64 view_relative_character_from_pos(Application_Links *app, View_ID view_id, i64 base_line, i64 pos){ Models *models = (Models*)app->cmd_context; View *view = imp_get_view(models, view_id); - i64 result = {}; + i64 result = 0; if (api_check_view(view)){ result = view_relative_character_from_pos(app->tctx, models, view, base_line, pos); } @@ -646,7 +646,7 @@ api(custom) function i64 view_pos_from_relative_character(Application_Links *app, View_ID view_id, i64 base_line, i64 character){ Models *models = (Models*)app->cmd_context; View *view = imp_get_view(models, view_id); - i64 result = {}; + i64 result = 0; if (api_check_view(view)){ result = view_pos_from_relative_character(app->tctx, models, view, base_line, character); } @@ -730,7 +730,7 @@ api(custom) function Dirty_State buffer_get_dirty_state(Application_Links *app, Buffer_ID buffer_id){ Models *models = (Models*)app->cmd_context; Editing_File *file = imp_get_file(models, buffer_id); - Dirty_State result = {}; + Dirty_State result = 0; if (api_check_buffer(file)){ result = file->state.dirty; } @@ -2814,7 +2814,7 @@ api(custom) function Text_Layout_ID text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, Buffer_Point buffer_point){ Models *models = (Models*)app->cmd_context; Editing_File *file = imp_get_file(models, buffer_id); - Text_Layout_ID result = {}; + Text_Layout_ID result = 0; if (api_check_buffer(file)){ Thread_Context *tctx = app->tctx; Scratch_Block scratch(tctx); @@ -2962,7 +2962,7 @@ text_layout_character_on_screen(Application_Links *app, Text_Layout_ID layout_id y += line.height; } - // TODO(allen): optimization: This is some fairly heavy computation. We really + // TODO(allen): optimization: This is some fairly heavy computation. We really // need to accelerate the (pos -> item) lookup within a single // Buffer_Layout_Item_List. b32 is_first_item = true; diff --git a/4ed_buffer.cpp b/4ed_buffer.cpp index 842d7220..1e526935 100644 --- a/4ed_buffer.cpp +++ b/4ed_buffer.cpp @@ -658,7 +658,7 @@ buffer_get_pos_range_from_line_number(Gap_Buffer *buffer, i64 line_number){ internal i64 buffer_get_first_pos_from_line_number(Gap_Buffer *buffer, i64 line_number){ - i64 result = {}; + i64 result = 0; if (line_number < 1){ result = 0; } @@ -673,7 +673,7 @@ buffer_get_first_pos_from_line_number(Gap_Buffer *buffer, i64 line_number){ internal i64 buffer_get_last_pos_from_line_number(Gap_Buffer *buffer, i64 line_number){ - i64 result = {}; + i64 result = 0; if (line_number < 1){ result = 0; } diff --git a/4ed_string_matching.cpp b/4ed_string_matching.cpp index 4fd28843..2907d24b 100644 --- a/4ed_string_matching.cpp +++ b/4ed_string_matching.cpp @@ -125,7 +125,7 @@ find_all_matches_forward(Arena *arena, i32 maximum_output_count, jump_back_0: if (n + 1 == needle.size){ - String_Match_Flag flags = {}; + String_Match_Flag flags = 0; if (!(last_insensitive >= 0 && j <= (u64)last_insensitive && (u64)last_insensitive < j + needle.size)){ @@ -245,7 +245,7 @@ find_all_matches_backward(Arena *arena, i32 maximum_output_count, jump_back_0: if (n + 1 == needle.size){ - String_Match_Flag flags = {}; + String_Match_Flag flags = 0; if (!(last_insensitive < size && j >= last_insensitive && last_insensitive > j - (i64)needle.size)){ diff --git a/bin/4ed_build.cpp b/bin/4ed_build.cpp index 41ad2d55..3bce85f6 100644 --- a/bin/4ed_build.cpp +++ b/bin/4ed_build.cpp @@ -43,6 +43,7 @@ char *platform_names[] = { enum{ Compiler_CL, Compiler_GCC, + Compiler_Clang, // Compiler_COUNT, Compiler_None = Compiler_COUNT, @@ -51,6 +52,7 @@ enum{ char *compiler_names[] = { "cl", "gcc", + "clang", }; #if OS_WINDOWS @@ -67,6 +69,11 @@ char *compiler_names[] = { # define This_Compiler Compiler_CL #elif COMPILER_GCC # define This_Compiler Compiler_GCC +<<<<<<< HEAD +======= +#elif COMPILER_CLANG +# define This_Compiler Compiler_Clang +>>>>>>> yuval_macos_platform_layer #else # error This compilers is not enumerated. #endif @@ -90,7 +97,7 @@ char *includes[] = { "custom", FOREIGN "/freetype2", 0, }; char *windows_platform_layer[] = { "platform_win32/win32_4ed.cpp", 0 }; char *linux_platform_layer[] = { "platform_linux/linux_4ed.cpp", 0 }; -char *mac_platform_layer[] = { "platform_mac/mac_4ed.m", "platform_mac/mac_4ed.cpp", 0 }; +char *mac_platform_layer[] = { "platform_mac/mac_4ed.mm", 0 }; char **platform_layers[Platform_COUNT] = { windows_platform_layer, @@ -100,12 +107,13 @@ char **platform_layers[Platform_COUNT] = { char *windows_cl_platform_inc[] = { "platform_all", 0 }; char *linux_gcc_platform_inc[] = { "platform_all", "platform_unix", 0 }; -char *mac_gcc_platform_inc[] = { "platform_all", "platform_unix", 0 }; + +char *mac_clang_platform_inc[] = { "platform_all", "platform_unix", 0 }; char **platform_includes[Platform_COUNT][Compiler_COUNT] = { - {windows_cl_platform_inc, 0 }, - {0 , linux_gcc_platform_inc}, - {0 , mac_gcc_platform_inc }, + {windows_cl_platform_inc, 0 , 0}, + {0 , linux_gcc_platform_inc, 0}, + {0 , 0 , mac_clang_platform_inc}, }; char *default_custom_target = "../code/custom/4coder_default_bindings.cpp"; @@ -298,6 +306,7 @@ build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, cha #define GCC_LIBS_X64 GCC_LIBS_COMMON #define GCC_LIBS_X86 GCC_LIBS_COMMON +<<<<<<< HEAD #elif OS_MAC # define GCC_OPTS \ @@ -317,6 +326,9 @@ FOREIGN "/x64/libfreetype-mac.a" #define GCC_LIBS_X86 GCC_LIBS_COMMON \ FOREIGN "/x86/libfreetype-mac.a" +#else +# error gcc options not set for this platform +======= #else # error gcc options not set for this platform #endif @@ -391,6 +403,120 @@ build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, cha fm_popdir(temp); } +#elif COMPILER_CLANG + +#if OS_MAC + +# define CLANG_OPTS \ +"-Wno-write-strings -Wno-deprecated-declarations " \ +"-Wno-comment -Wno-switch -Wno-null-dereference " \ +"-Wno-tautological-compare -Wno-unused-result " \ +"-Wno-missing-declarations -Wno-nullability-completeness " \ +"-std=c++11 " + +#define CLANG_LIBS_COMMON \ +"-framework Cocoa -framework QuartzCore " \ +"-framework CoreServices " \ +"-framework OpenGL -framework IOKit -framework Metal -framework MetalKit " + +#define CLANG_LIBS_X64 CLANG_LIBS_COMMON \ +FOREIGN "/x64/libfreetype-mac.a" + +#define CLANG_LIBS_X86 CLANG_LIBS_COMMON \ +FOREIGN "/x86/libfreetype-mac.a" + +#else +# error clang options not set for this platform +>>>>>>> yuval_macos_platform_layer +#endif + +internal void +build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ + Build_Line line; + fm_init_build_line(&line); + + switch (arch){ + case Arch_X64: + fm_add_to_line(line, "-m64"); + fm_add_to_line(line, "-DFTECH_64_BIT"); break; + + case Arch_X86: + fm_add_to_line(line, "-m32"); + fm_add_to_line(line, "-DFTECH_32_BIT"); break; + + default: InvalidPath; + } + + if (flags & OPTS){ + <<<<<<< HEAD + fm_add_to_line(line, GCC_OPTS); + ======= + fm_add_to_line(line, CLANG_OPTS); + >>>>>>> yuval_macos_platform_layer + } + + fm_add_to_line(line, "-I%s", code_path); + if (inc_folders != 0){ + for (u32 i = 0; inc_folders[i] != 0; ++i){ + char *str = fm_str(arena, code_path, "/", inc_folders[i]); + fm_add_to_line(line, "-I%s", str); + } + } + + if (flags & DEBUG_INFO){ + fm_add_to_line(line, "-g -O0"); + } + + if (flags & OPTIMIZATION){ + fm_add_to_line(line, "-O3"); + } + + if (flags & SHARED_CODE){ + fm_add_to_line(line, "-shared"); + } + + if (defines != 0){ + for (u32 i = 0; defines[i]; ++i){ + char *define_flag = fm_str(arena, "-D", defines[i]); + fm_add_to_line(line, "%s", define_flag); + } + } + + fm_add_to_line(line, "-I\"%s\"", code_path); + for (u32 i = 0; code_files[i] != 0; ++i){ + fm_add_to_line(line, "\"%s/%s\"", code_path, code_files[i]); + } + + if (flags & LIBS){ + if (arch == Arch_X64){ + <<<<<<< HEAD + fm_add_to_line(line, GCC_LIBS_X64); + } + else if (arch == Arch_X86) + { + fm_add_to_line(line, GCC_LIBS_X86); + ======= + fm_add_to_line(line, CLANG_LIBS_X64); + } + else if (arch == Arch_X86) + { + fm_add_to_line(line, CLANG_LIBS_X86); + >>>>>>> yuval_macos_platform_layer + } + } + + fm_finish_build_line(&line); + + Temp_Dir temp = fm_pushdir(out_path); + <<<<<<< HEAD + systemf("g++ %s -o %s", line.build_options, out_file); + ======= + // systemf("clang++ %s -E -o %s", line.build_options, "4ed.i"); + systemf("clang++ %s -o %s", line.build_options, out_file); + >>>>>>> yuval_macos_platform_layer + fm_popdir(temp); +} + #else # error build function not defined for this compiler #endif @@ -427,7 +553,11 @@ buildsuper(Arena *arena, char *cdir, char *file, u32 arch){ BEGIN_TIME_SECTION(); Temp_Dir temp = fm_pushdir(fm_str(arena, BUILD_DIR)); - char *build_script = fm_str(arena, "custom/bin/buildsuper_", arch_names[arch], BAT); + char *build_script_postfix = ""; + if (This_OS == Platform_Mac){ + build_script_postfix = "-mac"; + } + char *build_script = fm_str(arena, "custom/bin/buildsuper_", arch_names[arch], build_script_postfix, BAT); char *build_command = fm_str(arena, "\"", cdir, "/", build_script, "\" \"", file, "\""); if (This_OS == Platform_Windows){ @@ -584,10 +714,10 @@ int main(int argc, char **argv){ Assert(n < sizeof(cdir)); END_TIME_SECTION("current directory"); - u32 flags = DEBUG_INFO | SUPER; + u32 flags = SUPER; u32 arch = Arch_X64; #if defined(DEV_BUILD) || defined(DEV_BUILD_X86) - flags |= INTERNAL; + flags |= DEBUG_INFO | INTERNAL; #endif #if defined(OPT_BUILD) || defined(OPT_BUILD_X86) flags |= OPTIMIZATION; diff --git a/bin/build-mac.sh b/bin/build-mac.sh new file mode 100755 index 00000000..83062702 --- /dev/null +++ b/bin/build-mac.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# If any command errors, stop the script +set -e + +# Set up directories (mirrors build.bat) +# NOTE(yuval): Replaced readlink with realpath which works for both macOS and Linux +ME="$(realpath "$0")" +LOCATION="$(dirname "$ME")" +SRC_ROOT="$(dirname "$LOCATION")" +PROJECT_ROOT="$(dirname "$SRC_ROOT")" +if [ ! -d "$PROJECT_ROOT/build" ]; then +mkdir "$PROJECT_ROOT/build" +fi +BUILD_ROOT="$PROJECT_ROOT/build" +BIN_ROOT="$SRC_ROOT/bin" +CUSTOM_ROOT="$SRC_ROOT/custom" +CUSTOM_BIN="$CUSTOM_ROOT/bin" + +# Get the build mode +BUILD_MODE="$1" +if [ -z "$BUILD_MODE" ]; then + BUILD_MODE="-DDEV_BUILD" +fi + +# Get the OS specific flags +chmod +rx "$BIN_ROOT/detect_os.sh" +os=$("$BIN_ROOT/detect_os.sh") + +if [[ "$os" == "linux" ]]; then +WARNINGS="-Wno-write-strings -Wno-comment" +elif [[ "$os" == "mac" ]]; then +WARNINGS="-Wno-write-strings -Wno-comment -Wno-null-dereference -Wno-logical-op-parentheses -Wno-switch" +fi + +FLAGS="-D_GNU_SOURCE -fPIC -fpermissive $BUILD_MODE" +INCLUDES="-I$SRC_ROOT -I$CUSTOM_ROOT" + +# Execute +clang++ $WARNINGS $FLAGS $INCLUDES "$BIN_ROOT/4ed_build.cpp" -g -o "$BUILD_ROOT/build" +pushd "$SRC_ROOT" +"$BUILD_ROOT/build" +popd diff --git a/bin/build_x86-mac.sh b/bin/build_x86-mac.sh new file mode 100644 index 00000000..3642eddf --- /dev/null +++ b/bin/build_x86-mac.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +./build.sh -DDEV_BUILD_X86 + + diff --git a/custom/4coder_base_types.cpp b/custom/4coder_base_types.cpp index 677029a2..4df57089 100644 --- a/custom/4coder_base_types.cpp +++ b/custom/4coder_base_types.cpp @@ -1727,7 +1727,7 @@ Ii32_size(i32 pos, i32 size){ function Range_i64 Ii64_size(i64 pos, i64 size){ return(Ii64(pos, pos + size)); -} +} function Range_u64 Iu64_size(u64 pos, u64 size){ return(Iu64(pos, pos + size)); @@ -6967,10 +6967,10 @@ global_const u8 integer_symbol_reverse[128] = { global_const u8 base64[64] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '$', }; @@ -6987,7 +6987,7 @@ global_const u8 base64_reverse[128] = { function u64 digit_count_from_integer(u64 x, u32 radix){ - u64 result = {}; + u64 result = 0; if (radix >= 2 && radix <= 16){ if (x == 0){ result = 1; diff --git a/custom/4coder_base_types.h b/custom/4coder_base_types.h index 5d309777..715ccbf9 100644 --- a/custom/4coder_base_types.h +++ b/custom/4coder_base_types.h @@ -31,14 +31,34 @@ # error architecture not supported yet # endif +#elif defined(__clang__) + +# define COMPILER_CLANG 1 + +# if defined(__APPLE__) && defined(__MACH__) +# define OS_MAC 1 +# else +# error This compiler/platform combo is not supported yet +# endif + +# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) +# define ARCH_X64 1 +# elif defined(i386) || defined(__i386) || defined(__i386__) +# define ARCH_X86 1 +# elif defined(__aarch64__) +# define ARCH_ARM64 1 +# elif defined(__arm__) +# define ARCH_ARM32 1 +# else +# error architecture not supported yet +# endif + #elif defined(__GNUC__) || defined(__GNUG__) # define COMPILER_GCC 1 # if defined(__gnu_linux__) # define OS_LINUX 1 -# elif defined(__APPLE__) && defined(__MACH__) -# define OS_MAC 1 # else # error This compiler/platform combo is not supported yet # endif @@ -92,6 +112,9 @@ #if !defined(COMPILER_GCC) #define COMPILER_GCC 0 #endif +#if !defined(COMPILER_CLANG) +#define COMPILER_CLANG 0 +#endif #if !defined(OS_WINDOWS) #define OS_WINDOWS 0 #endif @@ -121,12 +144,11 @@ #endif #endif -#if OS_WINDOWS -# if ARCH_32BIT -# define CALL_CONVENTION __stdcall -# else -# define CALL_CONVENTION -# endif +// NOTE(yuval): Changed this so that CALL_CONVENTION will be defined for all platforms +#if ARCH_32BIT +# define CALL_CONVENTION __stdcall +#else +# define CALL_CONVENTION #endif #if defined(JUST_GUESS_INTS) @@ -834,7 +856,7 @@ enum{ struct String_Const_char{ char *str; - u64 size; + u64 size; }; struct String_Const_u8{ union{ @@ -922,25 +944,25 @@ struct Node_String_Const_u32{ struct List_String_Const_char{ Node_String_Const_char *first; Node_String_Const_char *last; - u64 total_size; + u64 total_size; i32 node_count; }; struct List_String_Const_u8{ Node_String_Const_u8 *first; Node_String_Const_u8 *last; - u64 total_size; + u64 total_size; i32 node_count; }; struct List_String_Const_u16{ Node_String_Const_u16 *first; Node_String_Const_u16 *last; - u64 total_size; + u64 total_size; i32 node_count; }; struct List_String_Const_u32{ Node_String_Const_u32 *first; Node_String_Const_u32 *last; - u64 total_size; + u64 total_size; i32 node_count; }; @@ -951,7 +973,7 @@ struct Node_String_Const_Any{ struct List_String_Const_Any{ Node_String_Const_Any *first; Node_String_Const_Any *last; - u64 total_size; + u64 total_size; i32 node_count; }; @@ -960,40 +982,40 @@ struct String_char{ String_Const_char string; struct{ char *str; - u64 size; + u64 size; }; }; - u64 cap; + u64 cap; }; struct String_u8{ union{ String_Const_u8 string; struct{ u8 *str; - u64 size; + u64 size; }; }; - u64 cap; + u64 cap; }; struct String_u16{ union{ String_Const_u16 string; struct{ u16 *str; - u64 size; + u64 size; }; }; - u64 cap; + u64 cap; }; struct String_u32{ union{ String_Const_u32 string; struct{ u32 *str; - u64 size; + u64 size; }; }; - u64 cap; + u64 cap; }; struct String_Any{ @@ -1001,8 +1023,8 @@ struct String_Any{ union{ struct{ void *str; - u64 size; - u64 cap; + u64 size; + u64 cap; }; String_char s_char; String_u8 s_u8; @@ -1089,7 +1111,7 @@ struct Base_Allocator{ struct Cursor{ u8 *base; - u64 pos; + u64 pos; u64 cap; }; struct Temp_Memory_Cursor{ @@ -1229,7 +1251,7 @@ struct Heap_Node{ struct{ Heap_Basic_Node order; Heap_Basic_Node alloc; - u64 size; + u64 size; }; u8 force_size__[64]; }; @@ -1240,8 +1262,8 @@ struct Heap{ Arena *arena; Heap_Basic_Node in_order; Heap_Basic_Node free_nodes; - u64 used_space; - u64 total_space; + u64 used_space; + u64 total_space; }; #endif diff --git a/custom/4coder_code_index.cpp b/custom/4coder_code_index.cpp index ff9c6731..6d4e413a 100644 --- a/custom/4coder_code_index.cpp +++ b/custom/4coder_code_index.cpp @@ -1,1183 +1,2360 @@ -/* -4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. -*/ - -// TOP - -global Code_Index global_code_index = {}; - -function void -code_index_init(void){ - global_code_index.mutex = system_mutex_make(); - global_code_index.node_arena = make_arena_system(KB(4)); - global_code_index.buffer_to_index_file = make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); -} - -function Code_Index_File_Storage* -code_index__alloc_storage(void){ - Code_Index_File_Storage *result = global_code_index.free_storage; - if (result == 0){ - result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); - } - else{ - sll_stack_pop(global_code_index.free_storage); - } - zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); - global_code_index.storage_count += 1; - return(result); -} - -function void -code_index__free_storage(Code_Index_File_Storage *storage){ - zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); - global_code_index.storage_count -= 1; - sll_stack_push(global_code_index.free_storage, storage); -} - -function void -code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ - sll_queue_push(list->first, list->last, nest); - list->count += 1; -} - -function Code_Index_Nest_Ptr_Array -code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ - Code_Index_Nest_Ptr_Array array = {}; - array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); - array.count = list->count; - i32 counter = 0; - for (Code_Index_Nest *node = list->first; - node != 0; - node = node->next){ - array.ptrs[counter] = node; - counter += 1; - } - return(array); -} - -function Code_Index_Note_Ptr_Array -code_index_note_ptr_array_from_list(Arena *arena, Code_Index_Note_List *list){ - Code_Index_Note_Ptr_Array array = {}; - array.ptrs = push_array_zero(arena, Code_Index_Note*, list->count); - array.count = list->count; - i32 counter = 0; - for (Code_Index_Note *node = list->first; - node != 0; - node = node->next){ - array.ptrs[counter] = node; - counter += 1; - } - return(array); -} - -function void -code_index_lock(void){ - system_mutex_acquire(global_code_index.mutex); -} - -function void -code_index_unlock(void){ - system_mutex_release(global_code_index.mutex); -} - -function void -code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ - Code_Index_File_Storage *storage = 0; - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - storage = (Code_Index_File_Storage*)IntAsPtr(val); - linalloc_clear(&storage->arena); - } - else{ - storage = code_index__alloc_storage(); - table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); - } - storage->arena = arena; - storage->file = index; -} - -function void -code_index_erase_file(Buffer_ID buffer){ - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); - linalloc_clear(&storage->arena); - table_erase(&global_code_index.buffer_to_index_file, lookup); - code_index__free_storage(storage); - } -} - -function Code_Index_File* -code_index_get_file(Buffer_ID buffer){ - Code_Index_File *result = 0; - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); - result = storage->file; - } - return(result); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_Nest_Ptr_Array *array, i64 pos){ - Code_Index_Nest *result = 0; - i32 count = array->count; - Code_Index_Nest **nest_ptrs = array->ptrs; - for (i32 i = 0; i < count; i += 1){ - Code_Index_Nest *nest = nest_ptrs[i]; - if (nest->open.max <= pos && pos <= nest->close.min){ - Code_Index_Nest *sub_nest = - code_index_get_nest(&nest->nest_array, pos); - if (sub_nest != 0){ - result = sub_nest; - } - else{ - result = nest; - } - break; - } - } - return(result); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_Nest *nest, i64 pos){ - return(code_index_get_nest(&nest->nest_array, pos)); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_File *file, i64 pos){ - return(code_index_get_nest(&file->nest_array, pos)); -} - -function void -index_shift(i64 *ptr, Range_i64 old_range, u64 new_size){ - i64 i = *ptr; - if (old_range.min <= i && i < old_range.max){ - *ptr = old_range.first; - } - else if (old_range.max <= i){ - *ptr = i + new_size - (old_range.max - old_range.min); - } -} - -function void -code_index_shift(Code_Index_Nest_Ptr_Array *array, - Range_i64 old_range, u64 new_size){ - i32 count = array->count; - Code_Index_Nest **nest_ptr = array->ptrs; - for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ - Code_Index_Nest *nest = *nest_ptr; - index_shift(&nest->open.min, old_range, new_size); - index_shift(&nest->open.max, old_range, new_size); - if (nest->is_closed){ - index_shift(&nest->close.min, old_range, new_size); - index_shift(&nest->close.max, old_range, new_size); - } - code_index_shift(&nest->nest_array, old_range, new_size); - } -} - -function void -code_index_shift(Code_Index_File *file, Range_i64 old_range, u64 new_size){ - code_index_shift(&file->nest_array, old_range, new_size); -} - -//////////////////////////////// - -function void -generic_parse_inc(Generic_Parse_State *state){ - if (!token_it_inc_all(&state->it)){ - state->finished = true; - } -} - -function void -generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - for (;token != 0 && !state->finished;){ - if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ - break; - } - if (token->kind == TokenBaseKind_Comment){ - state->handle_comment(state->app, state->arena, index, token, state->contents); - } - else if (token->kind == TokenBaseKind_Whitespace){ - Range_i64 range = Ii64(token); - u8 *ptr = state->contents.str + range.one_past_last - 1; - for (i64 i = range.one_past_last - 1; - i >= range.first; - i -= 1, ptr -= 1){ - if (*ptr == '\n'){ - state->prev_line_start = ptr + 1; - break; - } - } - } - else{ - break; - } - generic_parse_inc(state); - token = token_it_read(&state->it); - } -} - -function void -generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ - state->app = app; - state->arena = arena; - state->contents = contents; - state->it = token_iterator(0, tokens); - state->handle_comment = handle_comment; - state->prev_line_start = contents.str; -} - -//////////////////////////////// - -#if 0 -// NOTE(allen): grammar syntax -(X) = X -X Y = X and then Y -X? = zero or one X -$X = check for X but don't consume -[X] = zero or more Xs -X | Y = either X or Y -* = anything that does not match previous options in a X | Y | ... chain -* - X = anything that does not match X or previous options in a Y | Z | ... chain - = a token of type X -"X" = literally the string "X" -X{Y} = X with flag Y - -// NOTE(allen): grammar of code index parse -file: [preprocessor | scope | parens | function | type | * - ] -preprocessor: [scope | parens | stmnt]{pp-body} -scope: [preprocessor | scope | parens | * - ] -paren: [preprocessor | scope | parens | * - ] -stmnt-close-pattern: | | | | | -stmnt: [type | * - stmnt-close-pattern] stmnt-close-pattern -type: struct | union | enum | typedef -struct: "struct" $(";" | "{") -union: "union" $(";" | "{") -enum: "enum" $(";" | "{") -typedef: "typedef" [* - ( (";" | "("))] $(";" | "(") -function: >"(" ["(" ")" | * - ("(" | ")")] ")" ("{" | ";") - -#endif - -//////////////////////////////// - -function Code_Index_Note* -index_new_note(Code_Index_File *index, Generic_Parse_State *state, Range_i64 range, Code_Index_Note_Kind kind, Code_Index_Nest *parent){ - Code_Index_Note *result = push_array(state->arena, Code_Index_Note, 1); - sll_queue_push(index->note_list.first, index->note_list.last, result); - index->note_list.count += 1; - result->note_kind = kind; - result->pos = range; - result->text = push_string_copy(state->arena, string_substring(state->contents, range)); - result->file = index; - result->parent = parent; - return(result); -} - -function void -cpp_parse_type_structure(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - if (state->finished){ - return; - } - Token *token = token_it_read(&state->it); - if (token != 0 && token->kind == TokenBaseKind_Identifier){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - Token *peek = token_it_read(&state->it); - if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || - peek->kind == TokenBaseKind_ScopeOpen){ - index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); - } - } -} - -function void -cpp_parse_type_def(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - for (;;){ - b32 did_advance = false; - Token *token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - if (token->kind == TokenBaseKind_Identifier){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - did_advance = true; - Token *peek = token_it_read(&state->it); - if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || - peek->kind == TokenBaseKind_ParentheticalOpen){ - index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); - break; - } - } - else if (token->kind == TokenBaseKind_StatementClose || - token->kind == TokenBaseKind_ScopeOpen || - token->kind == TokenBaseKind_ScopeClose || - token->kind == TokenBaseKind_ScopeOpen || - token->kind == TokenBaseKind_ScopeClose){ - break; - } - else if (token->kind == TokenBaseKind_Keyword){ - String_Const_u8 lexeme = string_substring(state->contents, Ii64(token)); - if (string_match(lexeme, string_u8_litexpr("struct")) || - string_match(lexeme, string_u8_litexpr("union")) || - string_match(lexeme, string_u8_litexpr("enum"))){ - break; - } - } - if (!did_advance){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - } - } -} - -function void -cpp_parse_function(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ - Token *token = token_it_read(&state->it); - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - if (state->finished){ - return; - } - Token *peek = token_it_read(&state->it); - Token *reset_point = peek; - if (peek != 0 && peek->sub_kind == TokenCppKind_ParenOp){ - b32 at_paren_close = false; - i32 paren_nest_level = 0; - for (; peek != 0;){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - peek = token_it_read(&state->it); - if (peek == 0 || state->finished){ - break; - } - - if (peek->kind == TokenBaseKind_ParentheticalOpen){ - paren_nest_level += 1; - } - else if (peek->kind == TokenBaseKind_ParentheticalClose){ - if (paren_nest_level > 0){ - paren_nest_level -= 1; - } - else{ - at_paren_close = true; - break; - } - } - } - - if (at_paren_close){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - peek = token_it_read(&state->it); - if (peek != 0 && - peek->kind == TokenBaseKind_ScopeOpen || - peek->kind == TokenBaseKind_StatementClose){ - index_new_note(index, state, Ii64(token), CodeIndexNote_Function, parent); - } - } - } - state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); -} - -function Code_Index_Nest* -generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Statement; - result->open = Ii64(token->pos); - result->close = Ii64(max_i64); - result->file = index; - - state->in_statement = true; - - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - } - - if (token->kind == TokenBaseKind_ScopeOpen || - token->kind == TokenBaseKind_ScopeClose || - token->kind == TokenBaseKind_ParentheticalOpen){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - - if (token->kind == TokenBaseKind_StatementClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - generic_parse_inc(state); - } - - state->in_statement = false; - - return(result); -} - -function Code_Index_Nest* -generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Preprocessor; - result->open = Ii64(token->pos); - result->close = Ii64(max_i64); - result->file = index; - - state->in_preprocessor = true; - - b32 potential_macro = false; - if (state->do_cpp_parse){ - if (token->sub_kind == TokenCppKind_PPDefine){ - potential_macro = true; - } - } - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - - if (state->do_cpp_parse && potential_macro){ - if (token->sub_kind == TokenCppKind_Identifier){ - index_new_note(index, state, Ii64(token), CodeIndexNote_Macro, result); - } - potential_macro = false; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - generic_parse_inc(state); - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->in_preprocessor = false; - - return(result); -} - -function Code_Index_Nest* -generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Scope; - result->open = Ii64(token); - result->close = Ii64(max_i64); - result->file = index; - - state->scope_counter += 1; - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - continue; - } - } - - if (token->kind == TokenBaseKind_ScopeClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalClose){ - generic_parse_inc(state); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - - // NOTE(allen): after a parenthetical group we consider ourselves immediately - // transitioning into a statement - nest = generic_parse_statement(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - - continue; - } - - { - Code_Index_Nest *nest = generic_parse_statement(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - } - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->scope_counter -= 1; - - return(result); -} - -function Code_Index_Nest* -generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Paren; - result->open = Ii64(token); - result->close = Ii64(max_i64); - result->file = index; - - i64 manifested_characters_on_line = 0; - { - u8 *ptr = state->prev_line_start; - u8 *end_ptr = state->contents.str + token->pos; - // NOTE(allen): Initial whitespace - for (;ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - break; - } - } - // NOTE(allen): Manifested characters - manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; - } - - state->paren_counter += 1; - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - continue; - } - } - - if (token->kind == TokenBaseKind_ParentheticalClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - if (token->kind == TokenBaseKind_ScopeClose){ - break; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - generic_parse_inc(state); - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->paren_counter -= 1; - - return(result); -} - -function b32 -generic_parse_full_input_breaks(Code_Index_File *index, Generic_Parse_State *state, i32 limit){ - b32 result = false; - - i64 first_index = token_it_index(&state->it); - i64 one_past_last_index = first_index + limit; - for (;;){ - generic_parse_skip_soft_tokens(index, state); - Token *token = token_it_read(&state->it); - - if (token == 0 || state->finished){ - result = true; - break; - } - - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else if (state->do_cpp_parse){ - if (token->sub_kind == TokenCppKind_Struct || - token->sub_kind == TokenCppKind_Union || - token->sub_kind == TokenCppKind_Enum){ - cpp_parse_type_structure(index, state, 0); - } - else if (token->sub_kind == TokenCppKind_Typedef){ - cpp_parse_type_def(index, state, 0); - } - else if (token->sub_kind == TokenCppKind_Identifier){ - cpp_parse_function(index, state, 0); - } - else{ - generic_parse_inc(state); - } - } - else{ - generic_parse_inc(state); - } - - i64 index = token_it_index(&state->it); - if (index >= one_past_last_index){ - token = token_it_read(&state->it); - if (token == 0){ - result = true; - } - break; - } - } - - if (result){ - index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); - index->note_array = code_index_note_ptr_array_from_list(state->arena, &index->note_list); - } - - return(result); -} - -//////////////////////////////// - -function void -default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, Token *token, String_Const_u8 contents){ - -} - -function void -generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ - generic_parse_init(app, arena, contents, tokens, default_comment_index, state); -} - -//////////////////////////////// - -function Token_Pair -layout_token_pair(Token_Array *tokens, i64 pos){ - Token_Pair result = {}; - Token_Iterator_Array it = token_iterator_pos(0, tokens, pos); - Token *b = token_it_read(&it); - if (b != 0){ - if (b->kind == TokenBaseKind_Whitespace){ - token_it_inc_non_whitespace(&it); - b = token_it_read(&it); - } - } - token_it_dec_non_whitespace(&it); - Token *a = token_it_read(&it); - if (a != 0){ - result.a = *a; - } - if (b != 0){ - result.b = *b; - } - return(result); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance, b32 *unresolved_dependence){ - f32 result = 0.f; - if (nest != 0){ - switch (nest->kind){ - case CodeIndexNest_Scope: - case CodeIndexNest_Preprocessor: - { - result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); - if (nest->open.min < pos && nest->open.max <= pos && - (!nest->is_closed || pos < nest->close.min)){ - result += 4.f*space_advance; - } - }break; - - case CodeIndexNest_Statement: - { - result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); - if (nest->open.min < pos && nest->open.max <= pos && - (!nest->is_closed || pos < nest->close.min)){ - result += 4.f*space_advance; - } - }break; - - case CodeIndexNest_Paren: - { - Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1, unresolved_dependence); - result = box.x1; - }break; - } - } - return(result); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance){ - b32 ignore; - return(layout_index_x_shift(app, reflex, nest, pos, space_advance, &ignore)); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance, b32 *unresolved_dependence){ - f32 indent = 0; - Code_Index_Nest *nest = code_index_get_nest(file, pos); - if (nest != 0){ - indent = layout_index_x_shift(app, reflex, nest, pos, space_advance, unresolved_dependence); - } - return(indent); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance){ - b32 ignore; - return(layout_index_x_shift(app, reflex, file, pos, space_advance, &ignore)); -} - -function void -layout_index__emit_chunk(LefRig_TopBot_Layout_Vars *pos_vars, Face_ID face, Arena *arena, u8 *text_str, i64 range_first, u8 *ptr, u8 *end, Layout_Item_List *list){ - for (;ptr < end;){ - Character_Consume_Result consume = utf8_consume(ptr, (u64)(end - ptr)); - if (consume.codepoint != '\r'){ - i64 index = layout_index_from_ptr(ptr, text_str, range_first); - if (consume.codepoint != max_u32){ - lr_tb_write(pos_vars, face, arena, list, index, consume.codepoint); - } - else{ - lr_tb_write_byte(pos_vars, face, arena, list, index, *ptr); - } - } - ptr += consume.inc; - } -} - -function i32 -layout_token_score_wrap_token(Token_Pair *pair, Token_Cpp_Kind kind){ - i32 result = 0; - if (pair->a.sub_kind != kind && pair->b.sub_kind == kind){ - result -= 1; - } - else if (pair->a.sub_kind == kind && pair->b.sub_kind != kind){ - result += 1; - } - return(result); -} - -function Layout_Item_List -layout_index__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file, Layout_Wrap_Kind kind){ - Scratch_Block scratch(app); - - Managed_Scope scope = buffer_get_managed_scope(app, buffer); - Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); - - Layout_Item_List list = get_empty_item_list(range); - String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); - - Face_Advance_Map advance_map = get_face_advance_map(app, face); - Face_Metrics metrics = get_face_metrics(app, face); - LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); - - f32 wrap_align_x = width - metrics.normal_advance; - - Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); - - if (text.size == 0){ - lr_tb_write_blank(&pos_vars, face, arena, &list, range.start); - } - else{ - b32 first_of_the_line = true; - Newline_Layout_Vars newline_vars = get_newline_layout_vars(); - - u8 *ptr = text.str; - u8 *end_ptr = ptr + text.size; - u8 *word_ptr = ptr; - - u8 *pending_wrap_ptr = ptr; - f32 pending_wrap_x = 0.f; - i32 pending_wrap_paren_nest_count = 0; - i32 pending_wrap_token_score = 0; - f32 pending_wrap_accumulated_w = 0.f; - - start: - if (ptr == end_ptr){ - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto finish; - } - - if (!character_is_whitespace(*ptr)){ - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto consuming_non_whitespace; - } - - { - for (;ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - pending_wrap_ptr = ptr; - word_ptr = ptr; - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto consuming_non_whitespace; - } - if (*ptr == '\n'){ - pending_wrap_ptr = ptr; - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto consuming_normal_whitespace; - } - } - - if (ptr == end_ptr){ - pending_wrap_ptr = ptr; - i64 index = layout_index_from_ptr(ptr - 1, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto finish; - } - } - - consuming_non_whitespace: - { - for (;ptr <= end_ptr; ptr += 1){ - if (ptr == end_ptr || character_is_whitespace(*ptr)){ - break; - } - } - - // NOTE(allen): measure this word - newline_layout_consume_default(&newline_vars); - String_Const_u8 word = SCu8(word_ptr, ptr); - u8 *word_end = ptr; - { - f32 word_advance = 0.f; - ptr = word.str; - for (;ptr < word_end;){ - Character_Consume_Result consume = utf8_consume(ptr, (u64)(word_end - ptr)); - if (consume.codepoint != max_u32){ - word_advance += lr_tb_advance(&pos_vars, face, consume.codepoint); - } - else{ - word_advance += lr_tb_advance_byte(&pos_vars); - } - ptr += consume.inc; - } - pending_wrap_accumulated_w += word_advance; - } - - if (!first_of_the_line && (kind == Layout_Wrapped) && lr_tb_crosses_width(&pos_vars, pending_wrap_accumulated_w)){ - i64 index = layout_index_from_ptr(pending_wrap_ptr, text.str, range.first); - lr_tb_align_rightward(&pos_vars, wrap_align_x); - lr_tb_write_ghost(&pos_vars, face, arena, &list, index, '\\'); - - lr_tb_next_line(&pos_vars); -#if 0 - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); -#endif - - ptr = pending_wrap_ptr; - pending_wrap_accumulated_w = 0.f; - first_of_the_line = true; - goto start; - } - } - - consuming_normal_whitespace: - for (; ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - u8 *new_wrap_ptr = ptr; - - i64 index = layout_index_from_ptr(new_wrap_ptr, text.str, range.first); - Code_Index_Nest *new_wrap_nest = code_index_get_nest(file, index); - b32 invalid_wrap_x = false; - f32 new_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance, &invalid_wrap_x); - if (invalid_wrap_x){ - new_wrap_x = max_f32; - } - - i32 new_wrap_paren_nest_count = 0; - for (Code_Index_Nest *nest = new_wrap_nest; - nest != 0; - nest = nest->parent){ - if (nest->kind == CodeIndexNest_Paren){ - new_wrap_paren_nest_count += 1; - } - } - - Token_Pair new_wrap_token_pair = layout_token_pair(tokens_ptr, index); - - // TODO(allen): pull out the token scoring part and make it replacable for other - // language's token based wrap scoring needs. - i32 token_score = 0; - if (new_wrap_token_pair.a.kind == TokenBaseKind_Keyword){ - if (new_wrap_token_pair.b.kind == TokenBaseKind_ParentheticalOpen || - new_wrap_token_pair.b.kind == TokenBaseKind_Keyword){ - token_score -= 2; - } - } - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Eq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_PlusEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_MinusEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_StarEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_DivEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_ModEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_LeftLeftEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_RightRightEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Comma); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_AndAnd); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_OrOr); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Ternary); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Colon); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Semicolon); - - i32 new_wrap_token_score = token_score; - - b32 new_wrap_ptr_is_better = false; - if (first_of_the_line){ - new_wrap_ptr_is_better = true; - } - else{ - if (new_wrap_token_score > pending_wrap_token_score){ - new_wrap_ptr_is_better = true; - } - else if (new_wrap_token_score == pending_wrap_token_score){ - f32 new_score = new_wrap_paren_nest_count*10.f + new_wrap_x; - f32 old_score = pending_wrap_paren_nest_count*10.f + pending_wrap_x + metrics.normal_advance*4.f + pending_wrap_accumulated_w*0.5f; - - if (new_score < old_score){ - new_wrap_ptr_is_better = true; - } - } - } - - if (new_wrap_ptr_is_better){ - layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, new_wrap_ptr, &list); - first_of_the_line = false; - - pending_wrap_ptr = new_wrap_ptr; - pending_wrap_paren_nest_count = new_wrap_paren_nest_count; - pending_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance); - pending_wrap_paren_nest_count = new_wrap_paren_nest_count; - pending_wrap_token_score = new_wrap_token_score; - pending_wrap_accumulated_w = 0.f; - } - - word_ptr = ptr; - goto consuming_non_whitespace; - } - - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - switch (*ptr){ - default: - { - newline_layout_consume_default(&newline_vars); - pending_wrap_accumulated_w += lr_tb_advance(&pos_vars, face, *ptr); - }break; - - case '\r': - { - newline_layout_consume_CR(&newline_vars, index); - }break; - - case '\n': - { - layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); - pending_wrap_ptr = ptr + 1; - pending_wrap_accumulated_w = 0.f; - - u64 newline_index = newline_layout_consume_LF(&newline_vars, index); - lr_tb_write_blank(&pos_vars, face, arena, &list, newline_index); - lr_tb_next_line(&pos_vars); - first_of_the_line = true; - ptr += 1; - goto start; - }break; - } - } - - finish: - if (newline_layout_consume_finish(&newline_vars)){ - layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - lr_tb_write_blank(&pos_vars, face, arena, &list, index); - } - } - - layout_item_list_finish(&list, -pos_vars.line_to_text_shift); - - return(list); -} - -function Layout_Item_List -layout_virt_indent_index(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ - Layout_Item_List result = {}; - - if (global_config.enable_virtual_whitespace){ - code_index_lock(); - Code_Index_File *file = code_index_get_file(buffer); - if (file != 0){ - result = layout_index__inner(app, arena, buffer, range, face, width, file, kind); - } - code_index_unlock(); - if (file == 0){ - result = layout_virt_indent_literal(app, arena, buffer, range, face, width, kind); - } - } - else{ - result = layout_basic(app, arena, buffer, range, face, width, kind); - } - - return(result); -} - -function Layout_Item_List -layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ - return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Unwrapped)); -} - -function Layout_Item_List -layout_virt_indent_index_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ - return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Wrapped)); -} - -function Layout_Item_List -layout_virt_indent_index_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ - Managed_Scope scope = buffer_get_managed_scope(app, buffer); - b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); - b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); - return(layout_virt_indent_index(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); -} - -CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) -CUSTOM_DOC("Toggles the current buffer's virtual whitespace status.") -{ - global_config.enable_virtual_whitespace = !global_config.enable_virtual_whitespace; - - for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); - buffer != 0; - buffer = get_buffer_next(app, buffer, Access_Always)){ - buffer_clear_layout_cache(app, buffer); - } -} - -// BOTTOM - +/* +4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. +*/ + +// TOP + +global Code_Index global_code_index = {}; + +function void +code_index_init(void){ + global_code_index.mutex = system_mutex_make(); + global_code_index.node_arena = make_arena_system(KB(4)); + global_code_index.buffer_to_index_file = make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); +} + +function Code_Index_File_Storage* +code_index__alloc_storage(void){ + Code_Index_File_Storage *result = global_code_index.free_storage; + if (result == 0){ + result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); + } + else{ + sll_stack_pop(global_code_index.free_storage); + } + zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); + global_code_index.storage_count += 1; + return(result); +} + +function void +code_index__free_storage(Code_Index_File_Storage *storage){ + zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); + global_code_index.storage_count -= 1; + sll_stack_push(global_code_index.free_storage, storage); +} + +function void +code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ + sll_queue_push(list->first, list->last, nest); + list->count += 1; +} + +function Code_Index_Nest_Ptr_Array +code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ + Code_Index_Nest_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Nest *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function Code_Index_Note_Ptr_Array +code_index_note_ptr_array_from_list(Arena *arena, Code_Index_Note_List *list){ + Code_Index_Note_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Note*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Note *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function void +code_index_lock(void){ + system_mutex_acquire(global_code_index.mutex); +} + +function void +code_index_unlock(void){ + system_mutex_release(global_code_index.mutex); +} + +function void +code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ + Code_Index_File_Storage *storage = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + } + else{ + storage = code_index__alloc_storage(); + table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); + } + storage->arena = arena; + storage->file = index; +} + +function void +code_index_erase_file(Buffer_ID buffer){ + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + table_erase(&global_code_index.buffer_to_index_file, lookup); + code_index__free_storage(storage); + } +} + +function Code_Index_File* +code_index_get_file(Buffer_ID buffer){ + Code_Index_File *result = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + result = storage->file; + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest_Ptr_Array *array, i64 pos){ + Code_Index_Nest *result = 0; + i32 count = array->count; + Code_Index_Nest **nest_ptrs = array->ptrs; + for (i32 i = 0; i < count; i += 1){ + Code_Index_Nest *nest = nest_ptrs[i]; + if (nest->open.max <= pos && pos <= nest->close.min){ + Code_Index_Nest *sub_nest = + code_index_get_nest(&nest->nest_array, pos); + if (sub_nest != 0){ + result = sub_nest; + } + else{ + result = nest; + } + break; + } + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest *nest, i64 pos){ + return(code_index_get_nest(&nest->nest_array, pos)); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_File *file, i64 pos){ + return(code_index_get_nest(&file->nest_array, pos)); +} + +function void +index_shift(i64 *ptr, Range_i64 old_range, u64 new_size){ + i64 i = *ptr; + if (old_range.min <= i && i < old_range.max){ + *ptr = old_range.first; + } + else if (old_range.max <= i){ + *ptr = i + new_size - (old_range.max - old_range.min); + } +} + +function void +code_index_shift(Code_Index_Nest_Ptr_Array *array, + Range_i64 old_range, u64 new_size){ + i32 count = array->count; + Code_Index_Nest **nest_ptr = array->ptrs; + for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ + Code_Index_Nest *nest = *nest_ptr; + index_shift(&nest->open.min, old_range, new_size); + index_shift(&nest->open.max, old_range, new_size); + if (nest->is_closed){ + index_shift(&nest->close.min, old_range, new_size); + index_shift(&nest->close.max, old_range, new_size); + } + code_index_shift(&nest->nest_array, old_range, new_size); + } +} + +function void +code_index_shift(Code_Index_File *file, Range_i64 old_range, u64 new_size){ + code_index_shift(&file->nest_array, old_range, new_size); +} + +//////////////////////////////// + +function void +generic_parse_inc(Generic_Parse_State *state){ + if (!token_it_inc_all(&state->it)){ + state->finished = true; + } +} + +function void +generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + for (;token != 0 && !state->finished;){ + if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ + break; + } + if (token->kind == TokenBaseKind_Comment){ + state->handle_comment(state->app, state->arena, index, token, state->contents); + } + else if (token->kind == TokenBaseKind_Whitespace){ + Range_i64 range = Ii64(token); + u8 *ptr = state->contents.str + range.one_past_last - 1; + for (i64 i = range.one_past_last - 1; + i >= range.first; + i -= 1, ptr -= 1){ + if (*ptr == '\n'){ + state->prev_line_start = ptr + 1; + break; + } + } + } + else{ + break; + } + generic_parse_inc(state); + token = token_it_read(&state->it); + } +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ + state->app = app; + state->arena = arena; + state->contents = contents; + state->it = token_iterator(0, tokens); + state->handle_comment = handle_comment; + state->prev_line_start = contents.str; +} + +//////////////////////////////// + +#if 0 +// NOTE(allen): grammar syntax +(X) = X +X Y = X and then Y +X? = zero or one X +$X = check for X but don't consume +[X] = zero or more Xs +X | Y = either X or Y +* = anything that does not match previous options in a X | Y | ... chain +* - X = anything that does not match X or previous options in a Y | Z | ... chain + = a token of type X +"X" = literally the string "X" +X{Y} = X with flag Y + +// NOTE(allen): grammar of code index parse +file: [preprocessor | scope | parens | function | type | * - ] +preprocessor: [scope | parens | stmnt]{pp-body} +scope: [preprocessor | scope | parens | * - ] +paren: [preprocessor | scope | parens | * - ] +stmnt-close-pattern: | | | | | +stmnt: [type | * - stmnt-close-pattern] stmnt-close-pattern +type: struct | union | enum | typedef +struct: "struct" $(";" | "{") +union: "union" $(";" | "{") +enum: "enum" $(";" | "{") +typedef: "typedef" [* - ( (";" | "("))] $(";" | "(") +function: >"(" ["(" ")" | * - ("(" | ")")] ")" ("{" | ";") + +#endif + +//////////////////////////////// + +function Code_Index_Note* +index_new_note(Code_Index_File *index, Generic_Parse_State *state, Range_i64 range, Code_Index_Note_Kind kind, Code_Index_Nest *parent){ + Code_Index_Note *result = push_array(state->arena, Code_Index_Note, 1); + sll_queue_push(index->note_list.first, index->note_list.last, result); + index->note_list.count += 1; + result->note_kind = kind; + result->pos = range; + result->text = push_string_copy(state->arena, string_substring(state->contents, range)); + result->file = index; + result->parent = parent; + return(result); +} + +function void +cpp_parse_type_structure(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + if (state->finished){ + return; + } + Token *token = token_it_read(&state->it); + if (token != 0 && token->kind == TokenBaseKind_Identifier){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + Token *peek = token_it_read(&state->it); + if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || + peek->kind == TokenBaseKind_ScopeOpen){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); + } + } +} + +function void +cpp_parse_type_def(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + for (;;){ + b32 did_advance = false; + Token *token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + if (token->kind == TokenBaseKind_Identifier){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + did_advance = true; + Token *peek = token_it_read(&state->it); + if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || + peek->kind == TokenBaseKind_ParentheticalOpen){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); + break; + } + } + else if (token->kind == TokenBaseKind_StatementClose || + token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose){ + break; + } + else if (token->kind == TokenBaseKind_Keyword){ + String_Const_u8 lexeme = string_substring(state->contents, Ii64(token)); + if (string_match(lexeme, string_u8_litexpr("struct")) || + string_match(lexeme, string_u8_litexpr("union")) || + string_match(lexeme, string_u8_litexpr("enum"))){ + break; + } + } + if (!did_advance){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + } + } +} + +function void +cpp_parse_function(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + Token *token = token_it_read(&state->it); + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + if (state->finished){ + return; + } + Token *peek = token_it_read(&state->it); + Token *reset_point = peek; + if (peek != 0 && peek->sub_kind == TokenCppKind_ParenOp){ + b32 at_paren_close = false; + i32 paren_nest_level = 0; + for (; peek != 0;){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + peek = token_it_read(&state->it); + if (peek == 0 || state->finished){ + break; + } + + if (peek->kind == TokenBaseKind_ParentheticalOpen){ + paren_nest_level += 1; + } + else if (peek->kind == TokenBaseKind_ParentheticalClose){ + if (paren_nest_level > 0){ + paren_nest_level -= 1; + } + else{ + at_paren_close = true; + break; + } + } + } + + if (at_paren_close){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + peek = token_it_read(&state->it); + if (peek != 0 && + peek->kind == TokenBaseKind_ScopeOpen || + peek->kind == TokenBaseKind_StatementClose){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Function, parent); + } + } + } + state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); +} + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Statement; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_statement = true; + + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + + if (token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ParentheticalOpen){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (token->kind == TokenBaseKind_StatementClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + generic_parse_inc(state); + } + + state->in_statement = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Preprocessor; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_preprocessor = true; + + b32 potential_macro = false; + if (state->do_cpp_parse){ + if (token->sub_kind == TokenCppKind_PPDefine){ + potential_macro = true; + } + } + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (state->do_cpp_parse && potential_macro){ + if (token->sub_kind == TokenCppKind_Identifier){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Macro, result); + } + potential_macro = false; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->in_preprocessor = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Scope; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + state->scope_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ScopeClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + generic_parse_inc(state); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + + // NOTE(allen): after a parenthetical group we consider ourselves immediately + // transitioning into a statement + nest = generic_parse_statement(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + + continue; + } + + { + Code_Index_Nest *nest = generic_parse_statement(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + } + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->scope_counter -= 1; + + return(result); +} + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Paren; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + i64 manifested_characters_on_line = 0; + { + u8 *ptr = state->prev_line_start; + u8 *end_ptr = state->contents.str + token->pos; + // NOTE(allen): Initial whitespace + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + break; + } + } + // NOTE(allen): Manifested characters + manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; + } + + state->paren_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeClose){ + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->paren_counter -= 1; + + return(result); +} + +function b32 +generic_parse_full_input_breaks(Code_Index_File *index, Generic_Parse_State *state, i32 limit){ + b32 result = false; + + i64 first_index = token_it_index(&state->it); + i64 one_past_last_index = first_index + limit; + for (;;){ + generic_parse_skip_soft_tokens(index, state); + Token *token = token_it_read(&state->it); + + if (token == 0 || state->finished){ + result = true; + break; + } + + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (state->do_cpp_parse){ + if (token->sub_kind == TokenCppKind_Struct || + token->sub_kind == TokenCppKind_Union || + token->sub_kind == TokenCppKind_Enum){ + cpp_parse_type_structure(index, state, 0); + } + else if (token->sub_kind == TokenCppKind_Typedef){ + cpp_parse_type_def(index, state, 0); + } + else if (token->sub_kind == TokenCppKind_Identifier){ + cpp_parse_function(index, state, 0); + } + else{ + generic_parse_inc(state); + } + } + else{ + generic_parse_inc(state); + } + + i64 index = token_it_index(&state->it); + if (index >= one_past_last_index){ + token = token_it_read(&state->it); + if (token == 0){ + result = true; + } + break; + } + } + + if (result){ + index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); + index->note_array = code_index_note_ptr_array_from_list(state->arena, &index->note_list); + } + + return(result); +} + +//////////////////////////////// + +function void +default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, Token *token, String_Const_u8 contents){ + +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ + generic_parse_init(app, arena, contents, tokens, default_comment_index, state); +} + +//////////////////////////////// + +function Token_Pair +layout_token_pair(Token_Array *tokens, i64 pos){ + Token_Pair result = {}; + Token_Iterator_Array it = token_iterator_pos(0, tokens, pos); + Token *b = token_it_read(&it); + if (b != 0){ + if (b->kind == TokenBaseKind_Whitespace){ + token_it_inc_non_whitespace(&it); + b = token_it_read(&it); + } + } + token_it_dec_non_whitespace(&it); + Token *a = token_it_read(&it); + if (a != 0){ + result.a = *a; + } + if (b != 0){ + result.b = *b; + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 result = 0.f; + if (nest != 0){ + switch (nest->kind){ + case CodeIndexNest_Scope: + case CodeIndexNest_Preprocessor: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Statement: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Paren: + { + Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1, unresolved_dependence); + result = box.x1; + }break; + } + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, nest, pos, space_advance, &ignore)); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 indent = 0; + Code_Index_Nest *nest = code_index_get_nest(file, pos); + if (nest != 0){ + indent = layout_index_x_shift(app, reflex, nest, pos, space_advance, unresolved_dependence); + } + return(indent); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, file, pos, space_advance, &ignore)); +} + +function void +layout_index__emit_chunk(LefRig_TopBot_Layout_Vars *pos_vars, Face_ID face, Arena *arena, u8 *text_str, i64 range_first, u8 *ptr, u8 *end, Layout_Item_List *list){ + for (;ptr < end;){ + Character_Consume_Result consume = utf8_consume(ptr, (u64)(end - ptr)); + if (consume.codepoint != '\r'){ + i64 index = layout_index_from_ptr(ptr, text_str, range_first); + if (consume.codepoint != max_u32){ + lr_tb_write(pos_vars, face, arena, list, index, consume.codepoint); + } + else{ + lr_tb_write_byte(pos_vars, face, arena, list, index, *ptr); + } + } + ptr += consume.inc; + } +} + +function i32 +layout_token_score_wrap_token(Token_Pair *pair, Token_Cpp_Kind kind){ + i32 result = 0; + if (pair->a.sub_kind != kind && pair->b.sub_kind == kind){ + result -= 1; + } + else if (pair->a.sub_kind == kind && pair->b.sub_kind != kind){ + result += 1; + } + return(result); +} + +function Layout_Item_List +layout_index__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file, Layout_Wrap_Kind kind){ + Scratch_Block scratch(app); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); + + Layout_Item_List list = get_empty_item_list(range); + String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); + + Face_Advance_Map advance_map = get_face_advance_map(app, face); + Face_Metrics metrics = get_face_metrics(app, face); + LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); + + f32 wrap_align_x = width - metrics.normal_advance; + + Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); + + if (text.size == 0){ + lr_tb_write_blank(&pos_vars, face, arena, &list, range.start); + } + else{ + b32 first_of_the_line = true; + Newline_Layout_Vars newline_vars = get_newline_layout_vars(); + + u8 *ptr = text.str; + u8 *end_ptr = ptr + text.size; + u8 *word_ptr = ptr; + + u8 *pending_wrap_ptr = ptr; + f32 pending_wrap_x = 0.f; + i32 pending_wrap_paren_nest_count = 0; + i32 pending_wrap_token_score = 0; + f32 pending_wrap_accumulated_w = 0.f; + + start: + if (ptr == end_ptr){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + + if (!character_is_whitespace(*ptr)){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + + { + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + pending_wrap_ptr = ptr; + word_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + if (*ptr == '\n'){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_normal_whitespace; + } + } + + if (ptr == end_ptr){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr - 1, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + } + + consuming_non_whitespace: + { + for (;ptr <= end_ptr; ptr += 1){ + if (ptr == end_ptr || character_is_whitespace(*ptr)){ + break; + } + } + + // NOTE(allen): measure this word + newline_layout_consume_default(&newline_vars); + String_Const_u8 word = SCu8(word_ptr, ptr); + u8 *word_end = ptr; + { + f32 word_advance = 0.f; + ptr = word.str; + for (;ptr < word_end;){ + Character_Consume_Result consume = utf8_consume(ptr, (u64)(word_end - ptr)); + if (consume.codepoint != max_u32){ + word_advance += lr_tb_advance(&pos_vars, face, consume.codepoint); + } + else{ + word_advance += lr_tb_advance_byte(&pos_vars); + } + ptr += consume.inc; + } + pending_wrap_accumulated_w += word_advance; + } + + if (!first_of_the_line && (kind == Layout_Wrapped) && lr_tb_crosses_width(&pos_vars, pending_wrap_accumulated_w)){ + i64 index = layout_index_from_ptr(pending_wrap_ptr, text.str, range.first); + lr_tb_align_rightward(&pos_vars, wrap_align_x); + lr_tb_write_ghost(&pos_vars, face, arena, &list, index, '\\'); + + lr_tb_next_line(&pos_vars); +#if 0 + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); +#endif + + ptr = pending_wrap_ptr; + pending_wrap_accumulated_w = 0.f; + first_of_the_line = true; + goto start; + } + } + + consuming_normal_whitespace: + for (; ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + u8 *new_wrap_ptr = ptr; + + i64 index = layout_index_from_ptr(new_wrap_ptr, text.str, range.first); + Code_Index_Nest *new_wrap_nest = code_index_get_nest(file, index); + b32 invalid_wrap_x = false; + f32 new_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance, &invalid_wrap_x); + if (invalid_wrap_x){ + new_wrap_x = max_f32; + } + + i32 new_wrap_paren_nest_count = 0; + for (Code_Index_Nest *nest = new_wrap_nest; + nest != 0; + nest = nest->parent){ + if (nest->kind == CodeIndexNest_Paren){ + new_wrap_paren_nest_count += 1; + } + } + + Token_Pair new_wrap_token_pair = layout_token_pair(tokens_ptr, index); + + // TODO(allen): pull out the token scoring part and make it replacable for other + // language's token based wrap scoring needs. + i32 token_score = 0; + if (new_wrap_token_pair.a.kind == TokenBaseKind_Keyword){ + if (new_wrap_token_pair.b.kind == TokenBaseKind_ParentheticalOpen || + new_wrap_token_pair.b.kind == TokenBaseKind_Keyword){ + token_score -= 2; + } + } + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Eq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_PlusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_MinusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_StarEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_DivEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_ModEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_LeftLeftEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_RightRightEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Comma); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_AndAnd); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_OrOr); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Ternary); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Colon); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Semicolon); + + i32 new_wrap_token_score = token_score; + + b32 new_wrap_ptr_is_better = false; + if (first_of_the_line){ + new_wrap_ptr_is_better = true; + } + else{ + if (new_wrap_token_score > pending_wrap_token_score){ + new_wrap_ptr_is_better = true; + } + else if (new_wrap_token_score == pending_wrap_token_score){ + f32 new_score = new_wrap_paren_nest_count*10.f + new_wrap_x; + f32 old_score = pending_wrap_paren_nest_count*10.f + pending_wrap_x + metrics.normal_advance*4.f + pending_wrap_accumulated_w*0.5f; + + if (new_score < old_score){ + new_wrap_ptr_is_better = true; + } + } + } + + if (new_wrap_ptr_is_better){ + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, new_wrap_ptr, &list); + first_of_the_line = false; + + pending_wrap_ptr = new_wrap_ptr; + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance); + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_token_score = new_wrap_token_score; + pending_wrap_accumulated_w = 0.f; + } + + word_ptr = ptr; + goto consuming_non_whitespace; + } + + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + switch (*ptr){ + default: + { + newline_layout_consume_default(&newline_vars); + pending_wrap_accumulated_w += lr_tb_advance(&pos_vars, face, *ptr); + }break; + + case '\r': + { + newline_layout_consume_CR(&newline_vars, index); + }break; + + case '\n': + { + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + pending_wrap_ptr = ptr + 1; + pending_wrap_accumulated_w = 0.f; + + u64 newline_index = newline_layout_consume_LF(&newline_vars, index); + lr_tb_write_blank(&pos_vars, face, arena, &list, newline_index); + lr_tb_next_line(&pos_vars); + first_of_the_line = true; + ptr += 1; + goto start; + }break; + } + } + + finish: + if (newline_layout_consume_finish(&newline_vars)){ + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + lr_tb_write_blank(&pos_vars, face, arena, &list, index); + } + } + + layout_item_list_finish(&list, -pos_vars.line_to_text_shift); + + return(list); +} + +function Layout_Item_List +layout_virt_indent_index(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ + Layout_Item_List result = {}; + + if (global_config.enable_virtual_whitespace){ + code_index_lock(); + Code_Index_File *file = code_index_get_file(buffer); + if (file != 0){ + result = layout_index__inner(app, arena, buffer, range, face, width, file, kind); + } + code_index_unlock(); + if (file == 0){ + result = layout_virt_indent_literal(app, arena, buffer, range, face, width, kind); + } + } + else{ + result = layout_basic(app, arena, buffer, range, face, width, kind); + } + + return(result); +} + +function Layout_Item_List +layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Unwrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Wrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); + return(layout_virt_indent_index(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); +} + +CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) +CUSTOM_DOC("Toggles the current buffer's virtual whitespace status.") +{ + global_config.enable_virtual_whitespace = !global_config.enable_virtual_whitespace; + + for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); + buffer != 0; + buffer = get_buffer_next(app, buffer, Access_Always)){ + buffer_clear_layout_cache(app, buffer); + } +} + +// BOTTOM + +#if 0 +======= +/* +4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. +*/ + +// TOP + +global Code_Index global_code_index = {}; + +function void +code_index_init(void){ + global_code_index.mutex = system_mutex_make(); + global_code_index.node_arena = make_arena_system(KB(4)); + global_code_index.buffer_to_index_file = make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); +} + +function Code_Index_File_Storage* +code_index__alloc_storage(void){ + Code_Index_File_Storage *result = global_code_index.free_storage; + if (result == 0){ + result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); + } + else{ + sll_stack_pop(global_code_index.free_storage); + } + zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); + global_code_index.storage_count += 1; + return(result); +} + +function void +code_index__free_storage(Code_Index_File_Storage *storage){ + zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); + global_code_index.storage_count -= 1; + sll_stack_push(global_code_index.free_storage, storage); +} + +function void +code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ + sll_queue_push(list->first, list->last, nest); + list->count += 1; +} + +function Code_Index_Nest_Ptr_Array +code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ + Code_Index_Nest_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Nest *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function Code_Index_Note_Ptr_Array +code_index_note_ptr_array_from_list(Arena *arena, Code_Index_Note_List *list){ + Code_Index_Note_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Note*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Note *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function void +code_index_lock(void){ + system_mutex_acquire(global_code_index.mutex); +} + +function void +code_index_unlock(void){ + system_mutex_release(global_code_index.mutex); +} + +function void +code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ + Code_Index_File_Storage *storage = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + } + else{ + storage = code_index__alloc_storage(); + table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); + } + storage->arena = arena; + storage->file = index; +} + +function void +code_index_erase_file(Buffer_ID buffer){ + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + table_erase(&global_code_index.buffer_to_index_file, lookup); + code_index__free_storage(storage); + } +} + +function Code_Index_File* +code_index_get_file(Buffer_ID buffer){ + Code_Index_File *result = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + result = storage->file; + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest_Ptr_Array *array, i64 pos){ + Code_Index_Nest *result = 0; + i32 count = array->count; + Code_Index_Nest **nest_ptrs = array->ptrs; + for (i32 i = 0; i < count; i += 1){ + Code_Index_Nest *nest = nest_ptrs[i]; + if (nest->open.max <= pos && pos <= nest->close.min){ + Code_Index_Nest *sub_nest = + code_index_get_nest(&nest->nest_array, pos); + if (sub_nest != 0){ + result = sub_nest; + } + else{ + result = nest; + } + break; + } + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest *nest, i64 pos){ + return(code_index_get_nest(&nest->nest_array, pos)); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_File *file, i64 pos){ + return(code_index_get_nest(&file->nest_array, pos)); +} + +function void +index_shift(i64 *ptr, Range_i64 old_range, u64 new_size){ + i64 i = *ptr; + if (old_range.min <= i && i < old_range.max){ + *ptr = old_range.first; + } + else if (old_range.max <= i){ + *ptr = i + new_size - (old_range.max - old_range.min); + } +} + +function void +code_index_shift(Code_Index_Nest_Ptr_Array *array, + Range_i64 old_range, u64 new_size){ + i32 count = array->count; + Code_Index_Nest **nest_ptr = array->ptrs; + for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ + Code_Index_Nest *nest = *nest_ptr; + index_shift(&nest->open.min, old_range, new_size); + index_shift(&nest->open.max, old_range, new_size); + if (nest->is_closed){ + index_shift(&nest->close.min, old_range, new_size); + index_shift(&nest->close.max, old_range, new_size); + } + code_index_shift(&nest->nest_array, old_range, new_size); + } +} + +function void +code_index_shift(Code_Index_File *file, Range_i64 old_range, u64 new_size){ + code_index_shift(&file->nest_array, old_range, new_size); +} + +//////////////////////////////// + +function void +generic_parse_inc(Generic_Parse_State *state){ + if (!token_it_inc_all(&state->it)){ + state->finished = true; + } +} + +function void +generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + for (;token != 0 && !state->finished;){ + if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ + break; + } + if (token->kind == TokenBaseKind_Comment){ + state->handle_comment(state->app, state->arena, index, token, state->contents); + } + else if (token->kind == TokenBaseKind_Whitespace){ + Range_i64 range = Ii64(token); + u8 *ptr = state->contents.str + range.one_past_last - 1; + for (i64 i = range.one_past_last - 1; + i >= range.first; + i -= 1, ptr -= 1){ + if (*ptr == '\n'){ + state->prev_line_start = ptr + 1; + break; + } + } + } + else{ + break; + } + generic_parse_inc(state); + token = token_it_read(&state->it); + } +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ + state->app = app; + state->arena = arena; + state->contents = contents; + state->it = token_iterator(0, tokens); + state->handle_comment = handle_comment; + state->prev_line_start = contents.str; +} + +//////////////////////////////// + +#if 0 +// NOTE(allen): grammar syntax +(X) = X +X Y = X and then Y +X? = zero or one X +$X = check for X but dont consume // NOTE(yuval): Removed apostrophe as it was causing a warning when compiling with gcc +[X] = zero or more Xs +X | Y = either X or Y +* = anything that does not match previous options in a X | Y | ... chain +* - X = anything that does not match X or previous options in a Y | Z | ... chain + = a token of type X +"X" = literally the string "X" +X{Y} = X with flag Y + +// NOTE(allen): grammar of code index parse +file: [preprocessor | scope | parens | function | type | * - ] +preprocessor: [scope | parens | stmnt]{pp-body} +scope: [preprocessor | scope | parens | * - ] +paren: [preprocessor | scope | parens | * - ] +stmnt-close-pattern: | | | | | +stmnt: [type | * - stmnt-close-pattern] stmnt-close-pattern +type: struct | union | enum | typedef +struct: "struct" $(";" | "{") +union: "union" $(";" | "{") +enum: "enum" $(";" | "{") +typedef: "typedef" [* - ( (";" | "("))] $(";" | "(") +function: >"(" [* - ("(" | ")" | "{" | "}" | ";")] ")" ("{" | ";") + +#endif + +//////////////////////////////// + +function Code_Index_Note* +index_new_note(Code_Index_File *index, Generic_Parse_State *state, Range_i64 range, Code_Index_Note_Kind kind, Code_Index_Nest *parent){ + Code_Index_Note *result = push_array(state->arena, Code_Index_Note, 1); + sll_queue_push(index->note_list.first, index->note_list.last, result); + index->note_list.count += 1; + result->note_kind = kind; + result->pos = range; + result->text = push_string_copy(state->arena, string_substring(state->contents, range)); + result->file = index; + result->parent = parent; + return(result); +} + +function void +cpp_parse_type_structure(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + if (state->finished){ + return; + } + Token *token = token_it_read(&state->it); + if (token != 0 && token->kind == TokenBaseKind_Identifier){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + Token *peek = token_it_read(&state->it); + if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || + peek->kind == TokenBaseKind_ScopeOpen){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); + } + } +} + +function void +cpp_parse_type_def(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + for (;;){ + b32 did_advance = false; + Token *token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + if (token->kind == TokenBaseKind_Identifier){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + did_advance = true; + Token *peek = token_it_read(&state->it); + if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || + peek->kind == TokenBaseKind_ParentheticalOpen){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); + break; + } + } + else if (token->kind == TokenBaseKind_StatementClose || + token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose){ + break; + } + else if (token->kind == TokenBaseKind_Keyword){ + String_Const_u8 lexeme = string_substring(state->contents, Ii64(token)); + if (string_match(lexeme, string_u8_litexpr("struct")) || + string_match(lexeme, string_u8_litexpr("union")) || + string_match(lexeme, string_u8_litexpr("enum"))){ + break; + } + } + if (!did_advance){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + } + } +} + +function void +cpp_parse_function(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + Token *token = token_it_read(&state->it); + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + if (state->finished){ + return; + } + Token *peek = token_it_read(&state->it); + Token *reset_point = peek; + if (peek != 0 && peek->sub_kind == TokenCppKind_ParenOp){ + b32 at_paren_close = false; + for (; peek != 0;){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + peek = token_it_read(&state->it); + if (peek == 0 || state->finished){ + break; + } + + if (peek->kind == TokenBaseKind_ParentheticalOpen || + peek->kind == TokenBaseKind_ScopeOpen || + peek->kind == TokenBaseKind_ScopeClose || + peek->kind == TokenBaseKind_StatementClose){ + break; + } + if (peek->kind == TokenBaseKind_ParentheticalClose){ + at_paren_close = true; + break; + } + } + + if (at_paren_close){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + peek = token_it_read(&state->it); + if (peek != 0 && + peek->kind == TokenBaseKind_ScopeOpen || + peek->kind == TokenBaseKind_StatementClose){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Function, parent); + } + } + } + state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); +} + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Statement; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_statement = true; + + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + + if (token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ParentheticalOpen){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (token->kind == TokenBaseKind_StatementClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + generic_parse_inc(state); + } + + state->in_statement = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Preprocessor; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_preprocessor = true; + + b32 potential_macro = false; + if (state->do_cpp_parse){ + if (token->sub_kind == TokenCppKind_PPDefine){ + potential_macro = true; + } + } + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (state->do_cpp_parse && potential_macro){ + if (token->sub_kind == TokenCppKind_Identifier){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Macro, result); + } + potential_macro = false; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->in_preprocessor = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Scope; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + state->scope_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ScopeClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + generic_parse_inc(state); + continue; + } + + { + Code_Index_Nest *nest = generic_parse_statement(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + } + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->scope_counter -= 1; + + return(result); +} + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Paren; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + i64 manifested_characters_on_line = 0; + { + u8 *ptr = state->prev_line_start; + u8 *end_ptr = state->contents.str + token->pos; + // NOTE(allen): Initial whitespace + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + break; + } + } + // NOTE(allen): Manifested characters + manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; + } + + state->paren_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeClose){ + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->paren_counter -= 1; + + return(result); +} + +function b32 +generic_parse_full_input_breaks(Code_Index_File *index, Generic_Parse_State *state, i32 limit){ + b32 result = false; + + i64 first_index = token_it_index(&state->it); + i64 one_past_last_index = first_index + limit; + for (;;){ + generic_parse_skip_soft_tokens(index, state); + Token *token = token_it_read(&state->it); + + if (token == 0 || state->finished){ + result = true; + break; + } + + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (state->do_cpp_parse){ + if (token->sub_kind == TokenCppKind_Struct || + token->sub_kind == TokenCppKind_Union || + token->sub_kind == TokenCppKind_Enum){ + cpp_parse_type_structure(index, state, 0); + } + else if (token->sub_kind == TokenCppKind_Typedef){ + cpp_parse_type_def(index, state, 0); + } + else if (token->sub_kind == TokenCppKind_Identifier){ + cpp_parse_function(index, state, 0); + } + else{ + generic_parse_inc(state); + } + } + else{ + generic_parse_inc(state); + } + + i64 index = token_it_index(&state->it); + if (index >= one_past_last_index){ + token = token_it_read(&state->it); + if (token == 0){ + result = true; + } + break; + } + } + + if (result){ + index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); + index->note_array = code_index_note_ptr_array_from_list(state->arena, &index->note_list); + } + + return(result); +} + +//////////////////////////////// + +function void +default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, Token *token, String_Const_u8 contents){ + +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ + generic_parse_init(app, arena, contents, tokens, default_comment_index, state); +} + +//////////////////////////////// + +function Token_Pair +layout_token_pair(Token_Array *tokens, i64 pos){ + Token_Pair result = {}; + Token_Iterator_Array it = token_iterator_pos(0, tokens, pos); + Token *b = token_it_read(&it); + if (b != 0){ + if (b->kind == TokenBaseKind_Whitespace){ + token_it_inc_non_whitespace(&it); + b = token_it_read(&it); + } + } + token_it_dec_non_whitespace(&it); + Token *a = token_it_read(&it); + if (a != 0){ + result.a = *a; + } + if (b != 0){ + result.b = *b; + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 result = 0.f; + if (nest != 0){ + switch (nest->kind){ + case CodeIndexNest_Scope: + case CodeIndexNest_Preprocessor: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Statement: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Paren: + { + Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1, unresolved_dependence); + result = box.x1; + }break; + } + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, nest, pos, space_advance, &ignore)); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 indent = 0; + Code_Index_Nest *nest = code_index_get_nest(file, pos); + if (nest != 0){ + indent = layout_index_x_shift(app, reflex, nest, pos, space_advance, unresolved_dependence); + } + return(indent); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, file, pos, space_advance, &ignore)); +} + +function void +layout_index__emit_chunk(LefRig_TopBot_Layout_Vars *pos_vars, Face_ID face, Arena *arena, u8 *text_str, i64 range_first, u8 *ptr, u8 *end, Layout_Item_List *list){ + for (;ptr < end;){ + Character_Consume_Result consume = utf8_consume(ptr, (u64)(end - ptr)); + if (consume.codepoint != '\r'){ + i64 index = layout_index_from_ptr(ptr, text_str, range_first); + if (consume.codepoint != max_u32){ + lr_tb_write(pos_vars, face, arena, list, index, consume.codepoint); + } + else{ + lr_tb_write_byte(pos_vars, face, arena, list, index, *ptr); + } + } + ptr += consume.inc; + } +} + +function i32 +layout_token_score_wrap_token(Token_Pair *pair, Token_Cpp_Kind kind){ + i32 result = 0; + if (pair->a.sub_kind != kind && pair->b.sub_kind == kind){ + result -= 1; + } + else if (pair->a.sub_kind == kind && pair->b.sub_kind != kind){ + result += 1; + } + return(result); +} + +function Layout_Item_List +layout_index__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file, Layout_Wrap_Kind kind){ + Scratch_Block scratch(app); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); + + Layout_Item_List list = get_empty_item_list(range); + String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); + + Face_Advance_Map advance_map = get_face_advance_map(app, face); + Face_Metrics metrics = get_face_metrics(app, face); + LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); + + f32 wrap_align_x = width - metrics.normal_advance; + + Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); + + if (text.size == 0){ + lr_tb_write_blank(&pos_vars, face, arena, &list, range.start); + } + else{ + b32 first_of_the_line = true; + Newline_Layout_Vars newline_vars = get_newline_layout_vars(); + + u8 *ptr = text.str; + u8 *end_ptr = ptr + text.size; + u8 *word_ptr = ptr; + + u8 *pending_wrap_ptr = ptr; + f32 pending_wrap_x = 0.f; + i32 pending_wrap_paren_nest_count = 0; + i32 pending_wrap_token_score = 0; + f32 pending_wrap_accumulated_w = 0.f; + + start: + if (ptr == end_ptr){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + + if (!character_is_whitespace(*ptr)){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + + { + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + pending_wrap_ptr = ptr; + word_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + if (*ptr == '\n'){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_normal_whitespace; + } + } + + if (ptr == end_ptr){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr - 1, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + } + + consuming_non_whitespace: + { + for (;ptr <= end_ptr; ptr += 1){ + if (ptr == end_ptr || character_is_whitespace(*ptr)){ + break; + } + } + + // NOTE(allen): measure this word + newline_layout_consume_default(&newline_vars); + String_Const_u8 word = SCu8(word_ptr, ptr); + u8 *word_end = ptr; + { + f32 word_advance = 0.f; + ptr = word.str; + for (;ptr < word_end;){ + Character_Consume_Result consume = utf8_consume(ptr, (u64)(word_end - ptr)); + if (consume.codepoint != max_u32){ + word_advance += lr_tb_advance(&pos_vars, face, consume.codepoint); + } + else{ + word_advance += lr_tb_advance_byte(&pos_vars); + } + ptr += consume.inc; + } + pending_wrap_accumulated_w += word_advance; + } + + if (!first_of_the_line && (kind == Layout_Wrapped) && lr_tb_crosses_width(&pos_vars, pending_wrap_accumulated_w)){ + i64 index = layout_index_from_ptr(pending_wrap_ptr, text.str, range.first); + lr_tb_align_rightward(&pos_vars, wrap_align_x); + lr_tb_write_ghost(&pos_vars, face, arena, &list, index, '\\'); + + lr_tb_next_line(&pos_vars); +#if 0 + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); +#endif + + ptr = pending_wrap_ptr; + pending_wrap_accumulated_w = 0.f; + first_of_the_line = true; + goto start; + } + } + + consuming_normal_whitespace: + for (; ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + u8 *new_wrap_ptr = ptr; + + i64 index = layout_index_from_ptr(new_wrap_ptr, text.str, range.first); + Code_Index_Nest *new_wrap_nest = code_index_get_nest(file, index); + b32 invalid_wrap_x = false; + f32 new_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance, &invalid_wrap_x); + if (invalid_wrap_x){ + new_wrap_x = max_f32; + } + + i32 new_wrap_paren_nest_count = 0; + for (Code_Index_Nest *nest = new_wrap_nest; + nest != 0; + nest = nest->parent){ + if (nest->kind == CodeIndexNest_Paren){ + new_wrap_paren_nest_count += 1; + } + } + + Token_Pair new_wrap_token_pair = layout_token_pair(tokens_ptr, index); + + // TODO(allen): pull out the token scoring part and make it replacable for other + // language's token based wrap scoring needs. + i32 token_score = 0; + if (new_wrap_token_pair.a.kind == TokenBaseKind_Keyword){ + if (new_wrap_token_pair.b.kind == TokenBaseKind_ParentheticalOpen || + new_wrap_token_pair.b.kind == TokenBaseKind_Keyword){ + token_score -= 2; + } + } + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Eq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_PlusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_MinusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_StarEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_DivEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_ModEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_LeftLeftEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_RightRightEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Comma); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_AndAnd); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_OrOr); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Ternary); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Colon); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Semicolon); + + i32 new_wrap_token_score = token_score; + + b32 new_wrap_ptr_is_better = false; + if (first_of_the_line){ + new_wrap_ptr_is_better = true; + } + else{ + if (new_wrap_token_score > pending_wrap_token_score){ + new_wrap_ptr_is_better = true; + } + else if (new_wrap_token_score == pending_wrap_token_score){ + f32 new_score = new_wrap_paren_nest_count*10.f + new_wrap_x; + f32 old_score = pending_wrap_paren_nest_count*10.f + pending_wrap_x + metrics.normal_advance*4.f + pending_wrap_accumulated_w*0.5f; + + if (new_score < old_score){ + new_wrap_ptr_is_better = true; + } + } + } + + if (new_wrap_ptr_is_better){ + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, new_wrap_ptr, &list); + first_of_the_line = false; + + pending_wrap_ptr = new_wrap_ptr; + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance); + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_token_score = new_wrap_token_score; + pending_wrap_accumulated_w = 0.f; + } + + word_ptr = ptr; + goto consuming_non_whitespace; + } + + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + switch (*ptr){ + default: + { + newline_layout_consume_default(&newline_vars); + pending_wrap_accumulated_w += lr_tb_advance(&pos_vars, face, *ptr); + }break; + + case '\r': + { + newline_layout_consume_CR(&newline_vars, index); + }break; + + case '\n': + { + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + pending_wrap_ptr = ptr + 1; + pending_wrap_accumulated_w = 0.f; + + u64 newline_index = newline_layout_consume_LF(&newline_vars, index); + lr_tb_write_blank(&pos_vars, face, arena, &list, newline_index); + lr_tb_next_line(&pos_vars); + first_of_the_line = true; + ptr += 1; + goto start; + }break; + } + } + + finish: + if (newline_layout_consume_finish(&newline_vars)){ + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + lr_tb_write_blank(&pos_vars, face, arena, &list, index); + } + } + + layout_item_list_finish(&list, -pos_vars.line_to_text_shift); + + return(list); +} + +function Layout_Item_List +layout_virt_indent_index(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ + Layout_Item_List result = {}; + + if (global_config.enable_virtual_whitespace){ + code_index_lock(); + Code_Index_File *file = code_index_get_file(buffer); + if (file != 0){ + result = layout_index__inner(app, arena, buffer, range, face, width, file, kind); + } + code_index_unlock(); + if (file == 0){ + result = layout_virt_indent_literal(app, arena, buffer, range, face, width, kind); + } + } + else{ + result = layout_basic(app, arena, buffer, range, face, width, kind); + } + + return(result); +} + +function Layout_Item_List +layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Unwrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Wrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); + return(layout_virt_indent_index(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); +} + +CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) +CUSTOM_DOC("Toggles the current buffer's virtual whitespace status.") +{ + global_config.enable_virtual_whitespace = !global_config.enable_virtual_whitespace; + + for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); + buffer != 0; + buffer = get_buffer_next(app, buffer, Access_Always)){ + buffer_clear_layout_cache(app, buffer); + } +} + +// BOTTOM + +>>>>>>> yuval_macos_platform_layer +#endif diff --git a/custom/4coder_command_map.cpp b/custom/4coder_command_map.cpp index d2114d07..0d0ae016 100644 --- a/custom/4coder_command_map.cpp +++ b/custom/4coder_command_map.cpp @@ -425,21 +425,21 @@ function Command_Trigger_List map_get_triggers_recursive(Arena *arena, Mapping *mapping, Command_Map *map, Command_Binding binding){ Command_Trigger_List result = {}; if (mapping != 0){ - for (i32 safety_counter = 0; - map != 0 && safety_counter < 40; - safety_counter += 1){ - Command_Trigger_List list = map_get_triggers_non_recursive(mapping, map, binding); - - for (Command_Trigger *node = list.first, *next = 0; - node != 0; - node = next){ - next = node->next; - Command_Trigger *nnode = push_array_write(arena, Command_Trigger, 1, node); - sll_queue_push(result.first, result.last, nnode); + for (i32 safety_counter = 0; + map != 0 && safety_counter < 40; + safety_counter += 1){ + Command_Trigger_List list = map_get_triggers_non_recursive(mapping, map, binding); + + for (Command_Trigger *node = list.first, *next = 0; + node != 0; + node = next){ + next = node->next; + Command_Trigger *nnode = push_array_write(arena, Command_Trigger, 1, node); + sll_queue_push(result.first, result.last, nnode); + } + + map = mapping_get_map(mapping, map->parent); } - - map = mapping_get_map(mapping, map->parent); - } } return(result); } @@ -721,7 +721,7 @@ map_set_binding_l(Mapping *mapping, Command_Map *map, Custom_Command_Function *c va_start(args, code2); Command_Binding binding = {}; binding.custom = custom; - map_set_binding_lv(mapping, map, binding, code1, code2, args); + map_set_binding_lv(mapping, map, binding, code1, code2, args); va_end(args); } #endif @@ -755,7 +755,7 @@ map_set_binding_l(m, map, BindFWrap_(F), InputEventKind_MouseMove, 0, __VA_ARGS_ #define BindCore(F, K, ...) \ map_set_binding_l(m, map, BindFWrap_(F), InputEventKind_Core, (K), __VA_ARGS__, 0) -#elif COMPILER_GCC +#elif COMPILER_GCC | COMPILER_CLANG #define Bind(F, K, ...) \ map_set_binding_l(m, map, BindFWrap_(F), InputEventKind_KeyStroke, (K), ##__VA_ARGS__, 0) diff --git a/custom/4coder_draw.cpp b/custom/4coder_draw.cpp index 2f719f74..60ee2b6d 100644 --- a/custom/4coder_draw.cpp +++ b/custom/4coder_draw.cpp @@ -40,7 +40,7 @@ draw_string(Application_Links *app, Face_ID font_id, String_Const_u8 string, Vec function Vec2_f32 draw_string(Application_Links *app, Face_ID font_id, String_Const_u8 string, Vec2_f32 p, FColor color){ ARGB_Color argb = fcolor_resolve(color); - draw_string(app, font_id, string, p, argb); + return(draw_string(app, font_id, string, p, argb)); } function void @@ -356,7 +356,7 @@ draw_line_number_margin(Application_Links *app, View_ID view_id, Buffer_ID buffe Vec2_f32 p = V2f32(margin.x0, line_y.min); Temp_Memory_Block temp(scratch); Fancy_String *string = push_fancy_stringf(scratch, 0, line_color, - "%*lld", + "%*lld", line_count_digit_count, line_number); draw_fancy_string(app, face_id, fcolor_zero(), string, p); @@ -719,6 +719,7 @@ draw_original_4coder_style_cursor_mark_highlight(Application_Links *app, View_ID b32 has_highlight_range = draw_highlight_range(app, view_id, buffer, text_layout_id, roundness); if (!has_highlight_range){ i32 cursor_sub_id = default_cursor_sub_id(); + i64 cursor_pos = view_get_cursor_pos(app, view_id); i64 mark_pos = view_get_mark_pos(app, view_id); if (is_active_view){ diff --git a/custom/4coder_fancy.cpp b/custom/4coder_fancy.cpp index 9b840962..4364db02 100644 --- a/custom/4coder_fancy.cpp +++ b/custom/4coder_fancy.cpp @@ -347,11 +347,11 @@ function Fancy_String* push_fancy_string_fixed(Arena *arena, Fancy_Line *line, FColor fore, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fore, 0.f, 0.f, "%-*.*s", max, string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fore, 0.f, 0.f, "%-*.*s...", max - 3, string_expand(value))); } } @@ -360,12 +360,12 @@ push_fancy_string_fixed(Arena *arena, Fancy_Line *line, f32 pre_margin, f32 post_margin, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), pre_margin, post_margin, "%-*.*s", max, string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), pre_margin, post_margin, "%-*.*s...", max - 3, string_expand(value))); } @@ -374,11 +374,11 @@ function Fancy_String* push_fancy_string_fixed(Arena *arena, Fancy_Line *line, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), 0.f, 0.f, "%-*.*s", max, string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), 0.f, 0.f, "%-*.*s...", max - 3, string_expand(value))); } } @@ -452,11 +452,11 @@ function Fancy_String* push_fancy_string_trunc(Arena *arena, Fancy_Line *line, FColor fore, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fore, 0.f, 0.f, "%.*s", string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fore, 0.f, 0.f, "%.*s...", max - 3, value.str)); } } @@ -465,12 +465,12 @@ push_fancy_string_trunc(Arena *arena, Fancy_Line *line, f32 pre_margin, f32 post_margin, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), pre_margin, post_margin, "%.*s", string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), pre_margin, post_margin, "%.*s...", max - 3, value.str)); } @@ -479,11 +479,11 @@ function Fancy_String* push_fancy_string_trunc(Arena *arena, Fancy_Line *line, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), 0.f, 0.f, "%.*s", string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), 0.f, 0.f, "%.*s...", max - 3, value.str)); } } @@ -620,7 +620,7 @@ draw_fancy_string__inner(Application_Links *app, Face_ID face, FColor fore, Fanc use_fore = string->fore; } if (use_face != 0){ - ARGB_Color use_argb = fcolor_resolve(use_fore); + ARGB_Color use_argb = fcolor_resolve(use_fore); Face_Metrics metrics = get_face_metrics(app, use_face); f32 down_shift = (base_line - metrics.ascent); down_shift = clamp_bot(0.f, down_shift); @@ -668,7 +668,7 @@ get_fancy_string_height(Application_Links *app, Face_ID face, function f32 get_fancy_string_text_height(Application_Links *app, Face_ID face, - Fancy_String *string){ + Fancy_String *string){ Fancy_String *next = string->next; string->next = 0; f32 result = get_fancy_string_text_height__inner(app, face, string); @@ -700,10 +700,10 @@ function f32 get_fancy_line_width(Application_Links *app, Face_ID face, Fancy_Line *line){ f32 result = 0.f; if (line != 0){ - if (line->face != 0){ - face = line->face; - } - result = get_fancy_string_width__inner(app, face, line->first); + if (line->face != 0){ + face = line->face; + } + result = get_fancy_string_width__inner(app, face, line->first); } return(result); } @@ -749,12 +749,12 @@ draw_fancy_line(Application_Links *app, Face_ID face, FColor fore, Fancy_Line *line, Vec2_f32 p, u32 flags, Vec2_f32 delta){ Vec2_f32 result = {}; if (line != 0){ - if (line->face != 0){ - face = line->face; - } - if (fcolor_is_valid(line->fore)){ - fore = line->fore; - } + if (line->face != 0){ + face = line->face; + } + if (fcolor_is_valid(line->fore)){ + fore = line->fore; + } result = draw_fancy_string__inner(app, face, fore, line->first, p, flags, delta); } return(result); diff --git a/custom/4coder_file_moving.h b/custom/4coder_file_moving.h index b9beb7fe..3b8f0172 100644 --- a/custom/4coder_file_moving.h +++ b/custom/4coder_file_moving.h @@ -115,7 +115,7 @@ internal void fm__swap_ptr(char **A, char **B); fm__swap_ptr(&line.build_options, &line.build_options_prev); \ }while(0) -#elif COMPILER_GCC +#elif COMPILER_GCC | COMPILER_CLANG #define fm_add_to_line(line, str, ...) do{ \ snprintf(line.build_options, line.build_max, "%s " str, \ @@ -259,9 +259,9 @@ extern "C"{ #define OPEN_ALWAYS 4 #define TRUNCATE_EXISTING 5 -#define FILE_ATTRIBUTE_READONLY 0x00000001 -#define FILE_ATTRIBUTE_NORMAL 0x00000080 -#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define FILE_ATTRIBUTE_READONLY 0x00000001 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 global u64 perf_frequency; @@ -370,9 +370,9 @@ fm_copy_file(char *file, char *newname){ internal void fm_copy_all(char *source, char *folder){ - fprintf(stdout, "copy %s to %s\n", source, folder); - fflush(stdout); - systemf("xcopy /s /e /y /q %s %s > nul", source, folder); + fprintf(stdout, "copy %s to %s\n", source, folder); + fflush(stdout); + systemf("xcopy /s /e /y /q %s %s > nul", source, folder); } internal void diff --git a/custom/4coder_malloc_allocator.cpp b/custom/4coder_malloc_allocator.cpp index a16b7419..8a142f86 100644 --- a/custom/4coder_malloc_allocator.cpp +++ b/custom/4coder_malloc_allocator.cpp @@ -5,7 +5,10 @@ // TOP #include -#include + +#if !OS_MAC +# include +#endif internal void* base_reserve__malloc(void *user_data, u64 size, u64 *size_out, String_Const_u8 location){ diff --git a/custom/4coder_types.h b/custom/4coder_types.h index cf2549f7..b6feca08 100644 --- a/custom/4coder_types.h +++ b/custom/4coder_types.h @@ -54,7 +54,7 @@ struct Color_Array{ api(custom) struct Color_Table{ - Color_Array *arrays; + Color_Array *arrays; u32 count; }; @@ -742,7 +742,7 @@ struct View_Context{ u64 delta_rule_memory_size; b32 hides_buffer; struct Mapping *mapping; - i64 map_id; + i64 map_id; }; api(custom) @@ -778,4 +778,3 @@ struct Process_State{ }; #endif - diff --git a/custom/bin/buildsuper_x64-mac.sh b/custom/bin/buildsuper_x64-mac.sh new file mode 100755 index 00000000..ff3699a8 --- /dev/null +++ b/custom/bin/buildsuper_x64-mac.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# If any command errors, stop the script +set -e + +# Store the real CWD +ME="$(realpath "$0")" +LOCATION="$(dirname "$ME")" +CODE_HOME="$(dirname "$LOCATION")" + +# Find the most reasonable candidate build file +SOURCE="$1" +if [ -z "$SOURCE" ]; then + SOURCE="$(readlink -f "$CODE_HOME/4coder_default_bindings.cpp")" +fi + +# NOTE(yuval): Removed -Wno-writable-strings as it is the same as -Wno-write-strings +opts="-Wno-write-strings -Wno-null-dereference -Wno-comment -Wno-switch -Wno-missing-declarations -Wno-logical-op-parentheses -g" +arch=-m64 + +preproc_file=4coder_command_metadata.i +meta_macros="-DMETA_PASS" +clang++ -I"$CODE_HOME" $meta_macros $arch $opts $debug -std=gnu++0x "$SOURCE" -E -o $preproc_file +clang++ -I"$CODE_HOME" $opts $debug -std=gnu++0x "$CODE_HOME/4coder_metadata_generator.cpp" -o "$CODE_HOME/metadata_generator" +"$CODE_HOME/metadata_generator" -R "$CODE_HOME" "$PWD/$preproc_file" + +clang++ -I"$CODE_HOME" $arch $opts $debug -std=c++11 "$SOURCE" -shared -o custom_4coder.so -fPIC + +rm "$CODE_HOME/metadata_generator" +rm $preproc_file diff --git a/custom/bin/buildsuper_x86-mac.sh b/custom/bin/buildsuper_x86-mac.sh new file mode 100755 index 00000000..e3dde9b0 --- /dev/null +++ b/custom/bin/buildsuper_x86-mac.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Store the real CWD +REAL_PWD="$PWD" + +# Find the code home folder +TARGET_FILE="$0" +cd `dirname $TARGET_FILE` +TARGET_FILE=`basename $TARGET_FILE` +while [ -L "$TARGET_FILE" ] +do + TARGET_FILE=`readlink $TARGET_FILE` + cd `dirname $TARGET_FILE` + TARGET_FILE=`basename $TARGET_FILE` +done +PHYS_DIR=`pwd -P` +SCRIPT_FILE=$PHYS_DIR/$TARGET_FILE +code_home=$(dirname "$SCRIPT_FILE") + +# Find the most reasonable candidate build file +SOURCE="$1" +if [ -z "$SOURCE" ]; then + SOURCE="$code_home/4coder_default_bindings.cpp" +fi + +TARGET_FILE="$SOURCE" +cd `dirname $TARGET_FILE` +TARGET_FILE=`basename $TARGET_FILE` +while [ -L "$TARGET_FILE" ] +do + TARGET_FILE=`readlink $TARGET_FILE` + cd `dirname $TARGET_FILE` + TARGET_FILE=`basename $TARGET_FILE` +done +PHYS_DIR=`pwd -P` +SOURCE=$PHYS_DIR/$TARGET_FILE + +# NOTE(yuval): Removed -Wno-writable-strings as it is the same as -Wno-write-strings +opts="-Wno-write-strings -Wno-null-dereference -Wno-comment -Wno-switch -g" +arch=-m32 + +cd "$REAL_PWD" +preproc_file=4coder_command_metadata.i +meta_macros="-DMETA_PASS" +g++ -I"$code_home" $meta_macros $arch $opts $debug -std=gnu++0x "$SOURCE" -E -o $preproc_file +g++ -I"$code_home" $opts $debug -std=gnu++0x "$code_home/4coder_metadata_generator.cpp" -o metadata_generator +./metadata_generator -R "$code_home" "$PWD/$preproc_file" + +g++ -I"$code_home" $arch $opts $debug -std=gnu++0x "$SOURCE" -shared -o custom_4coder.so -fPIC + +rm metadata_generator +rm $preproc_file + diff --git a/custom/generated/4coder_event_codes.h b/custom/generated/4coder_event_codes.h index 8358d6a2..633caf07 100644 --- a/custom/generated/4coder_event_codes.h +++ b/custom/generated/4coder_event_codes.h @@ -1,212 +1,212 @@ enum{ -KeyCode_A = 1, -KeyCode_B = 2, -KeyCode_C = 3, -KeyCode_D = 4, -KeyCode_E = 5, -KeyCode_F = 6, -KeyCode_G = 7, -KeyCode_H = 8, -KeyCode_I = 9, -KeyCode_J = 10, -KeyCode_K = 11, -KeyCode_L = 12, -KeyCode_M = 13, -KeyCode_N = 14, -KeyCode_O = 15, -KeyCode_P = 16, -KeyCode_Q = 17, -KeyCode_R = 18, -KeyCode_S = 19, -KeyCode_T = 20, -KeyCode_U = 21, -KeyCode_V = 22, -KeyCode_W = 23, -KeyCode_X = 24, -KeyCode_Y = 25, -KeyCode_Z = 26, -KeyCode_0 = 27, -KeyCode_1 = 28, -KeyCode_2 = 29, -KeyCode_3 = 30, -KeyCode_4 = 31, -KeyCode_5 = 32, -KeyCode_6 = 33, -KeyCode_7 = 34, -KeyCode_8 = 35, -KeyCode_9 = 36, -KeyCode_Space = 37, -KeyCode_Tick = 38, -KeyCode_Minus = 39, -KeyCode_Equal = 40, -KeyCode_LeftBracket = 41, -KeyCode_RightBracket = 42, -KeyCode_Semicolon = 43, -KeyCode_Quote = 44, -KeyCode_Comma = 45, -KeyCode_Period = 46, -KeyCode_ForwardSlash = 47, -KeyCode_BackwardSlash = 48, -KeyCode_Tab = 49, -KeyCode_Escape = 50, -KeyCode_Pause = 51, -KeyCode_Up = 52, -KeyCode_Down = 53, -KeyCode_Left = 54, -KeyCode_Right = 55, -KeyCode_Backspace = 56, -KeyCode_Return = 57, -KeyCode_Delete = 58, -KeyCode_Insert = 59, -KeyCode_Home = 60, -KeyCode_End = 61, -KeyCode_PageUp = 62, -KeyCode_PageDown = 63, -KeyCode_CapsLock = 64, -KeyCode_NumLock = 65, -KeyCode_ScrollLock = 66, -KeyCode_Menu = 67, -KeyCode_Shift = 68, -KeyCode_Control = 69, -KeyCode_Alt = 70, -KeyCode_Command = 71, -KeyCode_F1 = 72, -KeyCode_F2 = 73, -KeyCode_F3 = 74, -KeyCode_F4 = 75, -KeyCode_F5 = 76, -KeyCode_F6 = 77, -KeyCode_F7 = 78, -KeyCode_F8 = 79, -KeyCode_F9 = 80, -KeyCode_F10 = 81, -KeyCode_F11 = 82, -KeyCode_F12 = 83, -KeyCode_F13 = 84, -KeyCode_F14 = 85, -KeyCode_F15 = 86, -KeyCode_F16 = 87, -KeyCode_COUNT = 88, + KeyCode_A = 1, + KeyCode_B = 2, + KeyCode_C = 3, + KeyCode_D = 4, + KeyCode_E = 5, + KeyCode_F = 6, + KeyCode_G = 7, + KeyCode_H = 8, + KeyCode_I = 9, + KeyCode_J = 10, + KeyCode_K = 11, + KeyCode_L = 12, + KeyCode_M = 13, + KeyCode_N = 14, + KeyCode_O = 15, + KeyCode_P = 16, + KeyCode_Q = 17, + KeyCode_R = 18, + KeyCode_S = 19, + KeyCode_T = 20, + KeyCode_U = 21, + KeyCode_V = 22, + KeyCode_W = 23, + KeyCode_X = 24, + KeyCode_Y = 25, + KeyCode_Z = 26, + KeyCode_0 = 27, + KeyCode_1 = 28, + KeyCode_2 = 29, + KeyCode_3 = 30, + KeyCode_4 = 31, + KeyCode_5 = 32, + KeyCode_6 = 33, + KeyCode_7 = 34, + KeyCode_8 = 35, + KeyCode_9 = 36, + KeyCode_Space = 37, + KeyCode_Tick = 38, + KeyCode_Minus = 39, + KeyCode_Equal = 40, + KeyCode_LeftBracket = 41, + KeyCode_RightBracket = 42, + KeyCode_Semicolon = 43, + KeyCode_Quote = 44, + KeyCode_Comma = 45, + KeyCode_Period = 46, + KeyCode_ForwardSlash = 47, + KeyCode_BackwardSlash = 48, + KeyCode_Tab = 49, + KeyCode_Escape = 50, + KeyCode_Pause = 51, + KeyCode_Up = 52, + KeyCode_Down = 53, + KeyCode_Left = 54, + KeyCode_Right = 55, + KeyCode_Backspace = 56, + KeyCode_Return = 57, + KeyCode_Delete = 58, + KeyCode_Insert = 59, + KeyCode_Home = 60, + KeyCode_End = 61, + KeyCode_PageUp = 62, + KeyCode_PageDown = 63, + KeyCode_CapsLock = 64, + KeyCode_NumLock = 65, + KeyCode_ScrollLock = 66, + KeyCode_Menu = 67, + KeyCode_Shift = 68, + KeyCode_Control = 69, + KeyCode_Alt = 70, + KeyCode_Command = 71, + KeyCode_F1 = 72, + KeyCode_F2 = 73, + KeyCode_F3 = 74, + KeyCode_F4 = 75, + KeyCode_F5 = 76, + KeyCode_F6 = 77, + KeyCode_F7 = 78, + KeyCode_F8 = 79, + KeyCode_F9 = 80, + KeyCode_F10 = 81, + KeyCode_F11 = 82, + KeyCode_F12 = 83, + KeyCode_F13 = 84, + KeyCode_F14 = 85, + KeyCode_F15 = 86, + KeyCode_F16 = 87, + KeyCode_COUNT = 88, }; global char* key_code_name[KeyCode_COUNT] = { -"None", -"A", -"B", -"C", -"D", -"E", -"F", -"G", -"H", -"I", -"J", -"K", -"L", -"M", -"N", -"O", -"P", -"Q", -"R", -"S", -"T", -"U", -"V", -"W", -"X", -"Y", -"Z", -"0", -"1", -"2", -"3", -"4", -"5", -"6", -"7", -"8", -"9", -"Space", -"Tick", -"Minus", -"Equal", -"LeftBracket", -"RightBracket", -"Semicolon", -"Quote", -"Comma", -"Period", -"ForwardSlash", -"BackwardSlash", -"Tab", -"Escape", -"Pause", -"Up", -"Down", -"Left", -"Right", -"Backspace", -"Return", -"Delete", -"Insert", -"Home", -"End", -"PageUp", -"PageDown", -"CapsLock", -"NumLock", -"ScrollLock", -"Menu", -"Shift", -"Control", -"Alt", -"Command", -"F1", -"F2", -"F3", -"F4", -"F5", -"F6", -"F7", -"F8", -"F9", -"F10", -"F11", -"F12", -"F13", -"F14", -"F15", -"F16", + "None", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "Space", + "Tick", + "Minus", + "Equal", + "LeftBracket", + "RightBracket", + "Semicolon", + "Quote", + "Comma", + "Period", + "ForwardSlash", + "BackwardSlash", + "Tab", + "Escape", + "Pause", + "Up", + "Down", + "Left", + "Right", + "Backspace", + "Return", + "Delete", + "Insert", + "Home", + "End", + "PageUp", + "PageDown", + "CapsLock", + "NumLock", + "ScrollLock", + "Menu", + "Shift", + "Control", + "Alt", + "Command", + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "F10", + "F11", + "F12", + "F13", + "F14", + "F15", + "F16", }; enum{ -MouseCode_Left = 1, -MouseCode_Middle = 2, -MouseCode_Right = 3, -MouseCode_COUNT = 4, + MouseCode_Left = 1, + MouseCode_Middle = 2, + MouseCode_Right = 3, + MouseCode_COUNT = 4, }; global char* mouse_code_name[MouseCode_COUNT] = { -"None", -"Left", -"Middle", -"Right", + "None", + "Left", + "Middle", + "Right", }; enum{ -CoreCode_Startup = 1, -CoreCode_Animate = 2, -CoreCode_ClickActivateView = 3, -CoreCode_ClickDeactivateView = 4, -CoreCode_TryExit = 5, -CoreCode_FileExternallyModified = 6, -CoreCode_NewClipboardContents = 7, -CoreCode_COUNT = 8, + CoreCode_Startup = 1, + CoreCode_Animate = 2, + CoreCode_ClickActivateView = 3, + CoreCode_ClickDeactivateView = 4, + CoreCode_TryExit = 5, + CoreCode_FileExternallyModified = 6, + CoreCode_NewClipboardContents = 7, + CoreCode_COUNT = 8, }; global char* core_code_name[CoreCode_COUNT] = { -"None", -"Startup", -"Animate", -"ClickActivateView", -"ClickDeactivateView", -"TryExit", -"FileExternallyModified", -"NewClipboardContents", + "None", + "Startup", + "Animate", + "ClickActivateView", + "ClickDeactivateView", + "TryExit", + "FileExternallyModified", + "NewClipboardContents", }; diff --git a/custom/generated/lexer_cpp.cpp b/custom/generated/lexer_cpp.cpp index a1a3ffae..213d6ac5 100644 --- a/custom/generated/lexer_cpp.cpp +++ b/custom/generated/lexer_cpp.cpp @@ -43,447 +43,453 @@ lexeme_table_lookup(u64 *hash_array, String_Const_u8 *key_array, } #endif -u64 cpp_main_keys_hash_array[121] = { -0x0000000000000000,0x03cf3a59df2800d7,0x31804e296403b305,0x3b709b613539c371, -0x3b709aad95fb97b3,0x0000000000000000,0x14996033a5460d1b,0x3180604229f03e4d, -0x0000000000000000,0x0000000000000000,0x14996033a7e5b03b,0x0000000000000000, -0x03cf3a58ab580caf,0x0000000000000000,0x0000000000000000,0x1901b5d07bbd53e1, -0x3180496d6573ea51,0x0000000000000000,0x0000000000000000,0x0000000000000000, -0x0000000000000000,0x0000000000000000,0x3b709aaa9c896d6b,0xf11624614cefdacf, -0x3b709b7949044f87,0x0000000000000000,0x3b709aaa14b4549f,0xf114e97ba34018a3, -0x3180604229f29813,0x0000000000000000,0x1904509dbde2a353,0x03cf3a596f0f2511, -0x14996033a5507959,0x0000000000000000,0x5f3f9fc0d0a0c93f,0x03cf3a58b58c753b, -0x0000000000000000,0x0000000000000000,0xf10f7eff9095fb23,0x3b709aaa68405a55, -0x3b709b61a18cc255,0x3b709aaa7edd8723,0x0000000000000000,0xc8abc849dbd6ac9f, -0x0000000000000000,0x7e5f4ab862627b7b,0x0000000000000000,0x0000000000000000, -0xf114b8e386ce372d,0x14996033a5580e25,0x0000000000000000,0x14996033a7d21aed, -0x3b709b61a19e76af,0x0000000000000000,0x14996033ab0ae5d3,0x14996033a5509f41, -0x0000000000000000,0x0000000000000000,0x0000000000000000,0x03cf3a58b646fa01, -0xf10e5cfb2d0856c9,0x8d730a2abbb45b53,0x0000000000000000,0x3b709b4626a5db05, -0x0000000000000000,0x03cf3a59de20fa7b,0x0000000000000000,0x14996033a6b2b45f, -0xf10f17d125465a91,0x03cf3a59dfc04c9f,0x5f3f9fc0d0a0ba41,0x0000000000000000, -0x5f3f9fc0d0a6ec81,0x0000000000000000,0x3b709aaa4a86002b,0x0000000000000000, -0x0000000000000000,0x5f3f9fc0d0a00819,0x0000000000000000,0x0000000000000000, -0xc8abc849dbd6adb5,0x0000000000000000,0x0000000000000000,0x0000000000000000, -0x5f3f9fc0d0a0d087,0x0000000000000000,0x0000000000000000,0x31806cea0e7fbb29, -0x0000000000000000,0x0000000000000000,0x31806c8004d41f17,0x3b709b468ffbb151, -0x03cf3a59df3fc9f3,0x1744d2f34117d803,0x0000000000000000,0x0000000000000000, -0x0000000000000000,0x0000000000000000,0x03cf3a596ff8a353,0x0000000000000000, -0x0000000000000000,0x1a21e4856eaac353,0x3b709aaa7cdf92c5,0x0000000000000000, -0x14996033a553c5cb,0x03cf3a58b52cfddd,0x0000000000000000,0x31804dc503d40aab, -0x0a1c76541b3d4ccf,0x9721eca88effbb53,0xf10ea2bb4912c001,0x14996033a54db691, -0x0000000000000000,0xf1165cbc0c8e31e1,0xf10e41346ef0ed11,0x0000000000000000, -0x0000000000000000,0x0000000000000000,0x3b709aaa4b875f33,0xf10f7c240be83eed, -0x0000000000000000, +u64 cpp_main_keys_hash_array[124] = { +0x26092f2f0215ece3,0x0000000000000000,0x5ce5a2eda58b1f23,0xb2d6c5c6769fa3a3, +0xb9ddf454bfe26d23,0x0000000000000000,0xcd0f6cfa687dd553,0x0000000000000000, +0x0000000000000000,0x5ce5a2e0c5100279,0x5ce5a2ede7babb3d,0x0000000000000000, +0x0000000000000000,0x6f6d951cb7cb582d,0x0e10b5f7624a6565,0xf889fe35be4428e3, +0x6f6d951cb404483f,0x26092f2f02f1c5ef,0x0000000000000000,0xe2b3ddb2fb5b2e6b, +0x0000000000000000,0x6f6d951cb4ea937d,0x0000000000000000,0x0000000000000000, +0x0000000000000000,0x0e10b1af23a24eb5,0x5ce5a2f3706ea43f,0x0000000000000000, +0xb2d6ca88b991d451,0xe2b3ddb2fb5a20a9,0x0000000000000000,0x26092f2f02d33cab, +0x0000000000000000,0x0000000000000000,0x5ce5a2e66f839a73,0x0000000000000000, +0x5ce5a2eda5890521,0x0000000000000000,0x6f6d951cb4228ddb,0x6f6d951cba73c8ab, +0xb9ddf454bfe26e41,0xd50b424c05eec7e9,0x8557f78510d2bb43,0x0000000000000000, +0x0000000000000000,0x26092f2f020b132d,0x0000000000000000,0x0000000000000000, +0xe2b3ddb2fb5bc1c9,0x0000000000000000,0x8ef935ae0949ace3,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x0000000000000000,0x26092f2f02d2781b, +0x26092f2f02e7a15d,0xb2d6c74182f6a66d,0x0000000000000000,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x0000000000000000,0x26092f2f02e78453, +0xe2b3ddb2fb5bd5b5,0xb2d6c74182f6a7e9,0x0000000000000000,0x0000000000000000, +0xb2d6c6c7361150b5,0x5ce5a2e0b306cde5,0x0000000000000000,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x5ce5a2e7e5c24db3,0x26092f2f0216583b, +0x0e101bb85ac205ad,0x6f6d951cacb1aa35,0x0000000000000000,0x0000000000000000, +0x0000000000000000,0x5ce5a2e197faf9d9,0xe2b3ddb2fb5baba1,0x6f6d951cba402e7b, +0x26092f2f02e1d2eb,0x0000000000000000,0x73a9345f7aa71363,0x0000000000000000, +0x0e10b66610117f15,0x0000000000000000,0xe95e136b18f58763,0x0e10078c941fcafb, +0x0000000000000000,0x0000000000000000,0x5ce5a2f37530abf3,0xb2d6c68c37b0f1f7, +0x5ce5a2e7e4364fe9,0x5ce5a2f37536698d,0x0000000000000000,0x0000000000000000, +0x5ce5a2e049adcf39,0x0000000000000000,0x0000000000000000,0x0e100efea5987c03, +0x6f6d951c847de2fb,0x0e106caf9da9bbbd,0x0e109bd9232f3723,0x0000000000000000, +0x6f6d951c86ec6929,0x0000000000000000,0x0000000000000000,0x0e114d6868e6156b, +0x6f6d951c8f3e1899,0x0e105b1fdc2b41ad,0xb2d6c5dc5a9a53e5,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x26092f2f0212aa4b,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x5ce5a2f37ca36a8b,0xcd1ba7f6b56d6ce3, }; -u8 cpp_main_keys_key_array_1[] = {0x63,0x6c,0x61,0x73,0x73,}; -u8 cpp_main_keys_key_array_2[] = {0x74,0x79,0x70,0x65,0x64,0x65,0x66,}; -u8 cpp_main_keys_key_array_3[] = {0x64,0x6f,0x75,0x62,0x6c,0x65,}; -u8 cpp_main_keys_key_array_4[] = {0x74,0x79,0x70,0x65,0x69,0x64,}; -u8 cpp_main_keys_key_array_6[] = {0x6c,0x6f,0x6e,0x67,}; -u8 cpp_main_keys_key_array_7[] = {0x61,0x6c,0x69,0x67,0x6e,0x6f,0x66,}; -u8 cpp_main_keys_key_array_10[] = {0x74,0x68,0x69,0x73,}; -u8 cpp_main_keys_key_array_12[] = {0x73,0x68,0x6f,0x72,0x74,}; -u8 cpp_main_keys_key_array_15[] = {0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,}; -u8 cpp_main_keys_key_array_16[] = {0x70,0x72,0x69,0x76,0x61,0x74,0x65,}; -u8 cpp_main_keys_key_array_22[] = {0x70,0x75,0x62,0x6c,0x69,0x63,}; -u8 cpp_main_keys_key_array_23[] = {0x6e,0x6f,0x65,0x78,0x63,0x65,0x70,0x74,}; -u8 cpp_main_keys_key_array_24[] = {0x66,0x72,0x69,0x65,0x6e,0x64,}; +u8 cpp_main_keys_key_array_0[] = {0x74,0x72,0x75,0x65,}; +u8 cpp_main_keys_key_array_2[] = {0x73,0x69,0x67,0x6e,0x65,0x64,}; +u8 cpp_main_keys_key_array_3[] = {0x76,0x69,0x72,0x74,0x75,0x61,0x6c,}; +u8 cpp_main_keys_key_array_4[] = {0x64,0x6f,}; +u8 cpp_main_keys_key_array_6[] = {0x70,0x72,0x6f,0x74,0x65,0x63,0x74,0x65,0x64,}; +u8 cpp_main_keys_key_array_9[] = {0x64,0x6f,0x75,0x62,0x6c,0x65,}; +u8 cpp_main_keys_key_array_10[] = {0x70,0x75,0x62,0x6c,0x69,0x63,}; +u8 cpp_main_keys_key_array_13[] = {0x63,0x6c,0x61,0x73,0x73,}; +u8 cpp_main_keys_key_array_14[] = {0x74,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,}; +u8 cpp_main_keys_key_array_15[] = {0x73,0x74,0x61,0x74,0x69,0x63,0x5f,0x63,0x61,0x73,0x74,}; +u8 cpp_main_keys_key_array_16[] = {0x63,0x61,0x74,0x63,0x68,}; +u8 cpp_main_keys_key_array_17[] = {0x67,0x6f,0x74,0x6f,}; +u8 cpp_main_keys_key_array_19[] = {0x61,0x73,0x6d,}; +u8 cpp_main_keys_key_array_21[] = {0x62,0x72,0x65,0x61,0x6b,}; +u8 cpp_main_keys_key_array_25[] = {0x76,0x6f,0x6c,0x61,0x74,0x69,0x6c,0x65,}; u8 cpp_main_keys_key_array_26[] = {0x73,0x77,0x69,0x74,0x63,0x68,}; -u8 cpp_main_keys_key_array_27[] = {0x65,0x78,0x70,0x6c,0x69,0x63,0x69,0x74,}; -u8 cpp_main_keys_key_array_28[] = {0x61,0x6c,0x69,0x67,0x6e,0x61,0x73,}; -u8 cpp_main_keys_key_array_30[] = {0x73,0x74,0x61,0x74,0x69,0x63,0x5f,0x63,0x61,0x73,0x74,}; -u8 cpp_main_keys_key_array_31[] = {0x66,0x61,0x6c,0x73,0x65,}; -u8 cpp_main_keys_key_array_32[] = {0x63,0x68,0x61,0x72,}; -u8 cpp_main_keys_key_array_34[] = {0x6e,0x65,0x77,}; -u8 cpp_main_keys_key_array_35[] = {0x75,0x73,0x69,0x6e,0x67,}; -u8 cpp_main_keys_key_array_38[] = {0x75,0x6e,0x73,0x69,0x67,0x6e,0x65,0x64,}; -u8 cpp_main_keys_key_array_39[] = {0x72,0x65,0x74,0x75,0x72,0x6e,}; -u8 cpp_main_keys_key_array_40[] = {0x65,0x78,0x74,0x65,0x72,0x6e,}; -u8 cpp_main_keys_key_array_41[] = {0x73,0x69,0x67,0x6e,0x65,0x64,}; -u8 cpp_main_keys_key_array_43[] = {0x64,0x6f,}; -u8 cpp_main_keys_key_array_45[] = {0x74,0x68,0x72,0x65,0x61,0x64,0x5f,0x6c,0x6f,0x63,0x61,0x6c,}; -u8 cpp_main_keys_key_array_48[] = {0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,}; -u8 cpp_main_keys_key_array_49[] = {0x65,0x6e,0x75,0x6d,}; -u8 cpp_main_keys_key_array_51[] = {0x74,0x72,0x75,0x65,}; -u8 cpp_main_keys_key_array_52[] = {0x65,0x78,0x70,0x6f,0x72,0x74,}; -u8 cpp_main_keys_key_array_54[] = {0x76,0x6f,0x69,0x64,}; -u8 cpp_main_keys_key_array_55[] = {0x63,0x61,0x73,0x65,}; -u8 cpp_main_keys_key_array_59[] = {0x77,0x68,0x69,0x6c,0x65,}; -u8 cpp_main_keys_key_array_60[] = {0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,}; -u8 cpp_main_keys_key_array_61[] = {0x63,0x6f,0x6e,0x73,0x74,0x5f,0x63,0x61,0x73,0x74,}; -u8 cpp_main_keys_key_array_63[] = {0x69,0x6e,0x6c,0x69,0x6e,0x65,}; -u8 cpp_main_keys_key_array_65[] = {0x62,0x72,0x65,0x61,0x6b,}; -u8 cpp_main_keys_key_array_67[] = {0x67,0x6f,0x74,0x6f,}; -u8 cpp_main_keys_key_array_68[] = {0x74,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,}; -u8 cpp_main_keys_key_array_69[] = {0x63,0x61,0x74,0x63,0x68,}; -u8 cpp_main_keys_key_array_70[] = {0x66,0x6f,0x72,}; -u8 cpp_main_keys_key_array_72[] = {0x74,0x72,0x79,}; -u8 cpp_main_keys_key_array_74[] = {0x73,0x74,0x61,0x74,0x69,0x63,}; -u8 cpp_main_keys_key_array_77[] = {0x61,0x73,0x6d,}; -u8 cpp_main_keys_key_array_80[] = {0x69,0x66,}; -u8 cpp_main_keys_key_array_84[] = {0x69,0x6e,0x74,}; -u8 cpp_main_keys_key_array_87[] = {0x6e,0x75,0x6c,0x6c,0x70,0x74,0x72,}; -u8 cpp_main_keys_key_array_90[] = {0x64,0x65,0x66,0x61,0x75,0x6c,0x74,}; -u8 cpp_main_keys_key_array_91[] = {0x64,0x65,0x6c,0x65,0x74,0x65,}; -u8 cpp_main_keys_key_array_92[] = {0x63,0x6f,0x6e,0x73,0x74,}; -u8 cpp_main_keys_key_array_93[] = {0x70,0x72,0x6f,0x74,0x65,0x63,0x74,0x65,0x64,}; -u8 cpp_main_keys_key_array_98[] = {0x66,0x6c,0x6f,0x61,0x74,}; -u8 cpp_main_keys_key_array_101[] = {0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x5f,0x63,0x61,0x73,0x74,}; -u8 cpp_main_keys_key_array_102[] = {0x73,0x69,0x7a,0x65,0x6f,0x66,}; -u8 cpp_main_keys_key_array_104[] = {0x62,0x6f,0x6f,0x6c,}; -u8 cpp_main_keys_key_array_105[] = {0x75,0x6e,0x69,0x6f,0x6e,}; -u8 cpp_main_keys_key_array_107[] = {0x76,0x69,0x72,0x74,0x75,0x61,0x6c,}; -u8 cpp_main_keys_key_array_108[] = {0x73,0x74,0x61,0x74,0x69,0x63,0x5f,0x61,0x73,0x73,0x65,0x72,0x74,}; -u8 cpp_main_keys_key_array_109[] = {0x72,0x65,0x69,0x6e,0x74,0x65,0x72,0x70,0x72,0x65,0x74,0x5f,0x63,0x61,0x73,0x74,}; -u8 cpp_main_keys_key_array_110[] = {0x76,0x6f,0x6c,0x61,0x74,0x69,0x6c,0x65,}; -u8 cpp_main_keys_key_array_111[] = {0x65,0x6c,0x73,0x65,}; -u8 cpp_main_keys_key_array_113[] = {0x64,0x65,0x63,0x6c,0x74,0x79,0x70,0x65,}; -u8 cpp_main_keys_key_array_114[] = {0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,}; -u8 cpp_main_keys_key_array_118[] = {0x73,0x74,0x72,0x75,0x63,0x74,}; -u8 cpp_main_keys_key_array_119[] = {0x74,0x79,0x70,0x65,0x6e,0x61,0x6d,0x65,}; -String_Const_u8 cpp_main_keys_key_array[121] = { +u8 cpp_main_keys_key_array_28[] = {0x74,0x79,0x70,0x65,0x64,0x65,0x66,}; +u8 cpp_main_keys_key_array_29[] = {0x74,0x72,0x79,}; +u8 cpp_main_keys_key_array_31[] = {0x65,0x6c,0x73,0x65,}; +u8 cpp_main_keys_key_array_34[] = {0x72,0x65,0x74,0x75,0x72,0x6e,}; +u8 cpp_main_keys_key_array_36[] = {0x73,0x69,0x7a,0x65,0x6f,0x66,}; +u8 cpp_main_keys_key_array_38[] = {0x63,0x6f,0x6e,0x73,0x74,}; +u8 cpp_main_keys_key_array_39[] = {0x66,0x61,0x6c,0x73,0x65,}; +u8 cpp_main_keys_key_array_40[] = {0x69,0x66,}; +u8 cpp_main_keys_key_array_41[] = {0x73,0x74,0x61,0x74,0x69,0x63,0x5f,0x61,0x73,0x73,0x65,0x72,0x74,}; +u8 cpp_main_keys_key_array_42[] = {0x74,0x68,0x72,0x65,0x61,0x64,0x5f,0x6c,0x6f,0x63,0x61,0x6c,}; +u8 cpp_main_keys_key_array_45[] = {0x74,0x68,0x69,0x73,}; +u8 cpp_main_keys_key_array_48[] = {0x69,0x6e,0x74,}; +u8 cpp_main_keys_key_array_50[] = {0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x5f,0x63,0x61,0x73,0x74,}; +u8 cpp_main_keys_key_array_55[] = {0x65,0x6e,0x75,0x6d,}; +u8 cpp_main_keys_key_array_56[] = {0x63,0x68,0x61,0x72,}; +u8 cpp_main_keys_key_array_57[] = {0x61,0x6c,0x69,0x67,0x6e,0x61,0x73,}; +u8 cpp_main_keys_key_array_63[] = {0x63,0x61,0x73,0x65,}; +u8 cpp_main_keys_key_array_64[] = {0x66,0x6f,0x72,}; +u8 cpp_main_keys_key_array_65[] = {0x61,0x6c,0x69,0x67,0x6e,0x6f,0x66,}; +u8 cpp_main_keys_key_array_68[] = {0x64,0x65,0x66,0x61,0x75,0x6c,0x74,}; +u8 cpp_main_keys_key_array_69[] = {0x64,0x65,0x6c,0x65,0x74,0x65,}; +u8 cpp_main_keys_key_array_74[] = {0x65,0x78,0x74,0x65,0x72,0x6e,}; +u8 cpp_main_keys_key_array_75[] = {0x6c,0x6f,0x6e,0x67,}; +u8 cpp_main_keys_key_array_76[] = {0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,}; +u8 cpp_main_keys_key_array_77[] = {0x77,0x68,0x69,0x6c,0x65,}; +u8 cpp_main_keys_key_array_81[] = {0x69,0x6e,0x6c,0x69,0x6e,0x65,}; +u8 cpp_main_keys_key_array_82[] = {0x6e,0x65,0x77,}; +u8 cpp_main_keys_key_array_83[] = {0x66,0x6c,0x6f,0x61,0x74,}; +u8 cpp_main_keys_key_array_84[] = {0x62,0x6f,0x6f,0x6c,}; +u8 cpp_main_keys_key_array_86[] = {0x63,0x6f,0x6e,0x73,0x74,0x5f,0x63,0x61,0x73,0x74,}; +u8 cpp_main_keys_key_array_88[] = {0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,}; +u8 cpp_main_keys_key_array_90[] = {0x72,0x65,0x69,0x6e,0x74,0x65,0x72,0x70,0x72,0x65,0x74,0x5f,0x63,0x61,0x73,0x74,}; +u8 cpp_main_keys_key_array_91[] = {0x65,0x78,0x70,0x6c,0x69,0x63,0x69,0x74,}; +u8 cpp_main_keys_key_array_94[] = {0x73,0x74,0x72,0x75,0x63,0x74,}; +u8 cpp_main_keys_key_array_95[] = {0x6e,0x75,0x6c,0x6c,0x70,0x74,0x72,}; +u8 cpp_main_keys_key_array_96[] = {0x65,0x78,0x70,0x6f,0x72,0x74,}; +u8 cpp_main_keys_key_array_97[] = {0x73,0x74,0x61,0x74,0x69,0x63,}; +u8 cpp_main_keys_key_array_100[] = {0x66,0x72,0x69,0x65,0x6e,0x64,}; +u8 cpp_main_keys_key_array_103[] = {0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,}; +u8 cpp_main_keys_key_array_104[] = {0x75,0x73,0x69,0x6e,0x67,}; +u8 cpp_main_keys_key_array_105[] = {0x64,0x65,0x63,0x6c,0x74,0x79,0x70,0x65,}; +u8 cpp_main_keys_key_array_106[] = {0x75,0x6e,0x73,0x69,0x67,0x6e,0x65,0x64,}; +u8 cpp_main_keys_key_array_108[] = {0x73,0x68,0x6f,0x72,0x74,}; +u8 cpp_main_keys_key_array_111[] = {0x74,0x79,0x70,0x65,0x6e,0x61,0x6d,0x65,}; +u8 cpp_main_keys_key_array_112[] = {0x75,0x6e,0x69,0x6f,0x6e,}; +u8 cpp_main_keys_key_array_113[] = {0x6e,0x6f,0x65,0x78,0x63,0x65,0x70,0x74,}; +u8 cpp_main_keys_key_array_114[] = {0x70,0x72,0x69,0x76,0x61,0x74,0x65,}; +u8 cpp_main_keys_key_array_118[] = {0x76,0x6f,0x69,0x64,}; +u8 cpp_main_keys_key_array_122[] = {0x74,0x79,0x70,0x65,0x69,0x64,}; +u8 cpp_main_keys_key_array_123[] = {0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,}; +String_Const_u8 cpp_main_keys_key_array[124] = { +{cpp_main_keys_key_array_0, 4}, {0, 0}, -{cpp_main_keys_key_array_1, 5}, -{cpp_main_keys_key_array_2, 7}, -{cpp_main_keys_key_array_3, 6}, -{cpp_main_keys_key_array_4, 6}, +{cpp_main_keys_key_array_2, 6}, +{cpp_main_keys_key_array_3, 7}, +{cpp_main_keys_key_array_4, 2}, {0, 0}, -{cpp_main_keys_key_array_6, 4}, -{cpp_main_keys_key_array_7, 7}, +{cpp_main_keys_key_array_6, 9}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_10, 4}, -{0, 0}, -{cpp_main_keys_key_array_12, 5}, +{cpp_main_keys_key_array_9, 6}, +{cpp_main_keys_key_array_10, 6}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_15, 9}, -{cpp_main_keys_key_array_16, 7}, +{cpp_main_keys_key_array_13, 5}, +{cpp_main_keys_key_array_14, 8}, +{cpp_main_keys_key_array_15, 11}, +{cpp_main_keys_key_array_16, 5}, +{cpp_main_keys_key_array_17, 4}, +{0, 0}, +{cpp_main_keys_key_array_19, 3}, +{0, 0}, +{cpp_main_keys_key_array_21, 5}, {0, 0}, {0, 0}, {0, 0}, -{0, 0}, -{0, 0}, -{cpp_main_keys_key_array_22, 6}, -{cpp_main_keys_key_array_23, 8}, -{cpp_main_keys_key_array_24, 6}, -{0, 0}, +{cpp_main_keys_key_array_25, 8}, {cpp_main_keys_key_array_26, 6}, -{cpp_main_keys_key_array_27, 8}, +{0, 0}, {cpp_main_keys_key_array_28, 7}, +{cpp_main_keys_key_array_29, 3}, {0, 0}, -{cpp_main_keys_key_array_30, 11}, -{cpp_main_keys_key_array_31, 5}, -{cpp_main_keys_key_array_32, 4}, -{0, 0}, -{cpp_main_keys_key_array_34, 3}, -{cpp_main_keys_key_array_35, 5}, +{cpp_main_keys_key_array_31, 4}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_38, 8}, -{cpp_main_keys_key_array_39, 6}, -{cpp_main_keys_key_array_40, 6}, -{cpp_main_keys_key_array_41, 6}, +{cpp_main_keys_key_array_34, 6}, {0, 0}, -{cpp_main_keys_key_array_43, 2}, +{cpp_main_keys_key_array_36, 6}, {0, 0}, -{cpp_main_keys_key_array_45, 12}, +{cpp_main_keys_key_array_38, 5}, +{cpp_main_keys_key_array_39, 5}, +{cpp_main_keys_key_array_40, 2}, +{cpp_main_keys_key_array_41, 13}, +{cpp_main_keys_key_array_42, 12}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_45, 4}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_48, 3}, +{0, 0}, +{cpp_main_keys_key_array_50, 12}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_48, 8}, -{cpp_main_keys_key_array_49, 4}, {0, 0}, -{cpp_main_keys_key_array_51, 4}, -{cpp_main_keys_key_array_52, 6}, {0, 0}, -{cpp_main_keys_key_array_54, 4}, {cpp_main_keys_key_array_55, 4}, +{cpp_main_keys_key_array_56, 4}, +{cpp_main_keys_key_array_57, 7}, {0, 0}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_59, 5}, -{cpp_main_keys_key_array_60, 8}, -{cpp_main_keys_key_array_61, 10}, {0, 0}, -{cpp_main_keys_key_array_63, 6}, {0, 0}, -{cpp_main_keys_key_array_65, 5}, +{cpp_main_keys_key_array_63, 4}, +{cpp_main_keys_key_array_64, 3}, +{cpp_main_keys_key_array_65, 7}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_68, 7}, +{cpp_main_keys_key_array_69, 6}, +{0, 0}, {0, 0}, -{cpp_main_keys_key_array_67, 4}, -{cpp_main_keys_key_array_68, 8}, -{cpp_main_keys_key_array_69, 5}, -{cpp_main_keys_key_array_70, 3}, {0, 0}, -{cpp_main_keys_key_array_72, 3}, {0, 0}, {cpp_main_keys_key_array_74, 6}, -{0, 0}, -{0, 0}, -{cpp_main_keys_key_array_77, 3}, -{0, 0}, -{0, 0}, -{cpp_main_keys_key_array_80, 2}, +{cpp_main_keys_key_array_75, 4}, +{cpp_main_keys_key_array_76, 8}, +{cpp_main_keys_key_array_77, 5}, {0, 0}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_84, 3}, +{cpp_main_keys_key_array_81, 6}, +{cpp_main_keys_key_array_82, 3}, +{cpp_main_keys_key_array_83, 5}, +{cpp_main_keys_key_array_84, 4}, +{0, 0}, +{cpp_main_keys_key_array_86, 10}, +{0, 0}, +{cpp_main_keys_key_array_88, 8}, +{0, 0}, +{cpp_main_keys_key_array_90, 16}, +{cpp_main_keys_key_array_91, 8}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_87, 7}, +{cpp_main_keys_key_array_94, 6}, +{cpp_main_keys_key_array_95, 7}, +{cpp_main_keys_key_array_96, 6}, +{cpp_main_keys_key_array_97, 6}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_90, 7}, -{cpp_main_keys_key_array_91, 6}, -{cpp_main_keys_key_array_92, 5}, -{cpp_main_keys_key_array_93, 9}, +{cpp_main_keys_key_array_100, 6}, {0, 0}, {0, 0}, +{cpp_main_keys_key_array_103, 8}, +{cpp_main_keys_key_array_104, 5}, +{cpp_main_keys_key_array_105, 8}, +{cpp_main_keys_key_array_106, 8}, +{0, 0}, +{cpp_main_keys_key_array_108, 5}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_98, 5}, -{0, 0}, -{0, 0}, -{cpp_main_keys_key_array_101, 12}, -{cpp_main_keys_key_array_102, 6}, -{0, 0}, -{cpp_main_keys_key_array_104, 4}, -{cpp_main_keys_key_array_105, 5}, -{0, 0}, -{cpp_main_keys_key_array_107, 7}, -{cpp_main_keys_key_array_108, 13}, -{cpp_main_keys_key_array_109, 16}, -{cpp_main_keys_key_array_110, 8}, -{cpp_main_keys_key_array_111, 4}, -{0, 0}, +{cpp_main_keys_key_array_111, 8}, +{cpp_main_keys_key_array_112, 5}, {cpp_main_keys_key_array_113, 8}, -{cpp_main_keys_key_array_114, 8}, +{cpp_main_keys_key_array_114, 7}, {0, 0}, {0, 0}, {0, 0}, -{cpp_main_keys_key_array_118, 6}, -{cpp_main_keys_key_array_119, 8}, +{cpp_main_keys_key_array_118, 4}, {0, 0}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_122, 6}, +{cpp_main_keys_key_array_123, 9}, }; -Lexeme_Table_Value cpp_main_keys_value_array[121] = { +Lexeme_Table_Value cpp_main_keys_value_array[124] = { +{8, TokenCppKind_LiteralTrue}, +{0, 0}, +{4, TokenCppKind_Signed}, +{4, TokenCppKind_Virtual}, +{4, TokenCppKind_Do}, +{0, 0}, +{4, TokenCppKind_Protected}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Double}, +{4, TokenCppKind_Public}, +{0, 0}, {0, 0}, {4, TokenCppKind_Class}, -{4, TokenCppKind_Typedef}, -{4, TokenCppKind_Double}, -{4, TokenCppKind_TypeID}, +{4, TokenCppKind_Template}, +{4, TokenCppKind_StaticCast}, +{4, TokenCppKind_Catch}, +{4, TokenCppKind_Goto}, {0, 0}, -{4, TokenCppKind_Long}, -{4, TokenCppKind_AlignOf}, +{4, TokenCppKind_Asm}, +{0, 0}, +{4, TokenCppKind_Break}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Volatile}, +{4, TokenCppKind_Switch}, +{0, 0}, +{4, TokenCppKind_Typedef}, +{4, TokenCppKind_Try}, +{0, 0}, +{4, TokenCppKind_Else}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Return}, +{0, 0}, +{4, TokenCppKind_SizeOf}, +{0, 0}, +{4, TokenCppKind_Const}, +{8, TokenCppKind_LiteralFalse}, +{4, TokenCppKind_If}, +{4, TokenCppKind_StaticAssert}, +{4, TokenCppKind_ThreadLocal}, {0, 0}, {0, 0}, {4, TokenCppKind_This}, {0, 0}, -{4, TokenCppKind_Short}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Namespace}, -{4, TokenCppKind_Private}, -{0, 0}, -{0, 0}, -{0, 0}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Public}, -{4, TokenCppKind_NoExcept}, -{4, TokenCppKind_Friend}, -{0, 0}, -{4, TokenCppKind_Switch}, -{4, TokenCppKind_Explicit}, -{4, TokenCppKind_AlignAs}, -{0, 0}, -{4, TokenCppKind_StaticCast}, -{8, TokenCppKind_LiteralFalse}, -{4, TokenCppKind_Char}, -{0, 0}, -{4, TokenCppKind_New}, -{4, TokenCppKind_Using}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Unsigned}, -{4, TokenCppKind_Return}, -{4, TokenCppKind_Extern}, -{4, TokenCppKind_Signed}, -{0, 0}, -{4, TokenCppKind_Do}, -{0, 0}, -{4, TokenCppKind_ThreadLocal}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Continue}, -{4, TokenCppKind_Enum}, -{0, 0}, -{8, TokenCppKind_LiteralTrue}, -{4, TokenCppKind_Export}, -{0, 0}, -{4, TokenCppKind_Void}, -{4, TokenCppKind_Case}, -{0, 0}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_While}, -{4, TokenCppKind_Operator}, -{4, TokenCppKind_ConstCast}, -{0, 0}, -{4, TokenCppKind_Inline}, -{0, 0}, -{4, TokenCppKind_Break}, -{0, 0}, -{4, TokenCppKind_Goto}, -{4, TokenCppKind_Template}, -{4, TokenCppKind_Catch}, -{4, TokenCppKind_For}, -{0, 0}, -{4, TokenCppKind_Try}, -{0, 0}, -{4, TokenCppKind_Static}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Asm}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_If}, -{0, 0}, -{0, 0}, {0, 0}, {4, TokenCppKind_Int}, {0, 0}, +{4, TokenCppKind_DynamicCast}, {0, 0}, -{4, TokenCppKind_NullPtr}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Enum}, +{4, TokenCppKind_Char}, +{4, TokenCppKind_AlignAs}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Case}, +{4, TokenCppKind_For}, +{4, TokenCppKind_AlignOf}, {0, 0}, {0, 0}, {4, TokenCppKind_Default}, {4, TokenCppKind_Delete}, -{4, TokenCppKind_Const}, -{4, TokenCppKind_Protected}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, -{4, TokenCppKind_Float}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_DynamicCast}, -{4, TokenCppKind_SizeOf}, -{0, 0}, -{4, TokenCppKind_Bool}, -{4, TokenCppKind_Union}, -{0, 0}, -{4, TokenCppKind_Virtual}, -{4, TokenCppKind_StaticAssert}, -{4, TokenCppKind_ReinterpretCast}, -{4, TokenCppKind_Volatile}, -{4, TokenCppKind_Else}, -{0, 0}, -{4, TokenCppKind_DeclType}, +{4, TokenCppKind_Extern}, +{4, TokenCppKind_Long}, {4, TokenCppKind_Register}, +{4, TokenCppKind_While}, {0, 0}, {0, 0}, {0, 0}, +{4, TokenCppKind_Inline}, +{4, TokenCppKind_New}, +{4, TokenCppKind_Float}, +{4, TokenCppKind_Bool}, +{0, 0}, +{4, TokenCppKind_ConstCast}, +{0, 0}, +{4, TokenCppKind_Operator}, +{0, 0}, +{4, TokenCppKind_ReinterpretCast}, +{4, TokenCppKind_Explicit}, +{0, 0}, +{0, 0}, {4, TokenCppKind_Struct}, +{4, TokenCppKind_NullPtr}, +{4, TokenCppKind_Export}, +{4, TokenCppKind_Static}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Friend}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Continue}, +{4, TokenCppKind_Using}, +{4, TokenCppKind_DeclType}, +{4, TokenCppKind_Unsigned}, +{0, 0}, +{4, TokenCppKind_Short}, +{0, 0}, +{0, 0}, {4, TokenCppKind_Typename}, +{4, TokenCppKind_Union}, +{4, TokenCppKind_NoExcept}, +{4, TokenCppKind_Private}, {0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Void}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_TypeID}, +{4, TokenCppKind_Namespace}, }; -i32 cpp_main_keys_slot_count = 121; -u64 cpp_main_keys_seed = 0x57fd2e8360fc723f; +i32 cpp_main_keys_slot_count = 124; +u64 cpp_main_keys_seed = 0x8546da5e0b8a4494; u64 cpp_pp_directives_hash_array[25] = { -0x0000000000000000,0x0000000000000000,0xfcbe0e69ab5f0ab5,0x0000000000000000, -0xdfa7f6eb98ca462d,0xdfa7f6ebae1c243d,0x26e6293f7c60a9d7,0x0000000000000000, -0xfcbe0e6b92eff62d,0x0000000000000000,0xdfa7f6604dbd1a65,0xfcbe0e69ab4edf49, -0x0000000000000000,0xdfa7f6ee4efdc3a3,0xfcbe0e6b014df297,0x26e6293f7c60632d, -0x0000000000000000,0xfcbe0e6b09dcce2d,0x0000000000000000,0x0000000000000000, -0x26e6293f722aa025,0xa6ba73c3a74f4285,0xb0a57847c3818ea9,0x0000000000000000, -0xb0a595ffc01d0bd5, +0xa9c93e3b092cb44d,0x0000000000000000,0x0dd88216be8f0f45,0x0000000000000000, +0x0dd88216bc8af78d,0x92a889595c683c55,0xdab9e300145b906f,0x92a889577e972a4b, +0x0000000000000000,0x0dd88216bb8053ff,0x0000000000000000,0x0dd88216bd573601, +0x0000000000000000,0xdab9e300142a071d,0x0000000000000000,0xa9c93ef34054fce1, +0x0dd88216a4783a45,0xdab9e300145b9a25,0x92a889595b4a2105,0x0000000000000000, +0x86d1d427e10cd86d,0x0000000000000000,0x92a889590753d01d,0x0000000000000000, +0x0000000000000000, }; -u8 cpp_pp_directives_key_array_2[] = {0x65,0x6e,0x64,0x69,0x66,}; -u8 cpp_pp_directives_key_array_4[] = {0x69,0x66,0x6e,0x64,0x65,0x66,}; -u8 cpp_pp_directives_key_array_5[] = {0x69,0x6d,0x70,0x6f,0x72,0x74,}; +u8 cpp_pp_directives_key_array_0[] = {0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,}; +u8 cpp_pp_directives_key_array_2[] = {0x69,0x66,0x64,0x65,0x66,}; +u8 cpp_pp_directives_key_array_4[] = {0x65,0x6e,0x64,0x69,0x66,}; +u8 cpp_pp_directives_key_array_5[] = {0x69,0x66,0x6e,0x64,0x65,0x66,}; u8 cpp_pp_directives_key_array_6[] = {0x65,0x6c,0x73,0x65,}; -u8 cpp_pp_directives_key_array_8[] = {0x69,0x66,0x64,0x65,0x66,}; -u8 cpp_pp_directives_key_array_10[] = {0x64,0x65,0x66,0x69,0x6e,0x65,}; +u8 cpp_pp_directives_key_array_7[] = {0x70,0x72,0x61,0x67,0x6d,0x61,}; +u8 cpp_pp_directives_key_array_9[] = {0x75,0x73,0x69,0x6e,0x67,}; u8 cpp_pp_directives_key_array_11[] = {0x65,0x72,0x72,0x6f,0x72,}; -u8 cpp_pp_directives_key_array_13[] = {0x70,0x72,0x61,0x67,0x6d,0x61,}; -u8 cpp_pp_directives_key_array_14[] = {0x75,0x73,0x69,0x6e,0x67,}; -u8 cpp_pp_directives_key_array_15[] = {0x65,0x6c,0x69,0x66,}; -u8 cpp_pp_directives_key_array_17[] = {0x75,0x6e,0x64,0x65,0x66,}; -u8 cpp_pp_directives_key_array_20[] = {0x6c,0x69,0x6e,0x65,}; -u8 cpp_pp_directives_key_array_21[] = {0x69,0x66,}; -u8 cpp_pp_directives_key_array_22[] = {0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,}; -u8 cpp_pp_directives_key_array_24[] = {0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,}; +u8 cpp_pp_directives_key_array_13[] = {0x6c,0x69,0x6e,0x65,}; +u8 cpp_pp_directives_key_array_15[] = {0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,}; +u8 cpp_pp_directives_key_array_16[] = {0x75,0x6e,0x64,0x65,0x66,}; +u8 cpp_pp_directives_key_array_17[] = {0x65,0x6c,0x69,0x66,}; +u8 cpp_pp_directives_key_array_18[] = {0x69,0x6d,0x70,0x6f,0x72,0x74,}; +u8 cpp_pp_directives_key_array_20[] = {0x69,0x66,}; +u8 cpp_pp_directives_key_array_22[] = {0x64,0x65,0x66,0x69,0x6e,0x65,}; String_Const_u8 cpp_pp_directives_key_array[25] = { -{0, 0}, +{cpp_pp_directives_key_array_0, 7}, {0, 0}, {cpp_pp_directives_key_array_2, 5}, {0, 0}, -{cpp_pp_directives_key_array_4, 6}, +{cpp_pp_directives_key_array_4, 5}, {cpp_pp_directives_key_array_5, 6}, {cpp_pp_directives_key_array_6, 4}, +{cpp_pp_directives_key_array_7, 6}, {0, 0}, -{cpp_pp_directives_key_array_8, 5}, +{cpp_pp_directives_key_array_9, 5}, {0, 0}, -{cpp_pp_directives_key_array_10, 6}, {cpp_pp_directives_key_array_11, 5}, {0, 0}, -{cpp_pp_directives_key_array_13, 6}, -{cpp_pp_directives_key_array_14, 5}, -{cpp_pp_directives_key_array_15, 4}, +{cpp_pp_directives_key_array_13, 4}, {0, 0}, -{cpp_pp_directives_key_array_17, 5}, +{cpp_pp_directives_key_array_15, 7}, +{cpp_pp_directives_key_array_16, 5}, +{cpp_pp_directives_key_array_17, 4}, +{cpp_pp_directives_key_array_18, 6}, +{0, 0}, +{cpp_pp_directives_key_array_20, 2}, +{0, 0}, +{cpp_pp_directives_key_array_22, 6}, {0, 0}, {0, 0}, -{cpp_pp_directives_key_array_20, 4}, -{cpp_pp_directives_key_array_21, 2}, -{cpp_pp_directives_key_array_22, 7}, -{0, 0}, -{cpp_pp_directives_key_array_24, 7}, }; Lexeme_Table_Value cpp_pp_directives_value_array[25] = { -{0, 0}, -{0, 0}, -{5, TokenCppKind_PPEndIf}, -{0, 0}, -{5, TokenCppKind_PPIfNDef}, -{5, TokenCppKind_PPImport}, -{5, TokenCppKind_PPElse}, +{5, TokenCppKind_PPVersion}, {0, 0}, {5, TokenCppKind_PPIfDef}, {0, 0}, -{5, TokenCppKind_PPDefine}, +{5, TokenCppKind_PPEndIf}, +{5, TokenCppKind_PPIfNDef}, +{5, TokenCppKind_PPElse}, +{5, TokenCppKind_PPPragma}, +{0, 0}, +{5, TokenCppKind_PPUsing}, +{0, 0}, {5, TokenCppKind_PPError}, {0, 0}, -{5, TokenCppKind_PPPragma}, -{5, TokenCppKind_PPUsing}, -{5, TokenCppKind_PPElIf}, -{0, 0}, -{5, TokenCppKind_PPUndef}, -{0, 0}, -{0, 0}, {5, TokenCppKind_PPLine}, -{5, TokenCppKind_PPIf}, -{5, TokenCppKind_PPInclude}, {0, 0}, -{5, TokenCppKind_PPVersion}, +{5, TokenCppKind_PPInclude}, +{5, TokenCppKind_PPUndef}, +{5, TokenCppKind_PPElIf}, +{5, TokenCppKind_PPImport}, +{0, 0}, +{5, TokenCppKind_PPIf}, +{0, 0}, +{5, TokenCppKind_PPDefine}, +{0, 0}, +{0, 0}, }; i32 cpp_pp_directives_slot_count = 25; -u64 cpp_pp_directives_seed = 0xe34ca5b52cfeb288; +u64 cpp_pp_directives_seed = 0x6e8a1011f7d8dd90; u64 cpp_pp_keys_hash_array[2] = { -0x0000000000000000,0xbef27711d7aba2b5, +0x56dd32803fcaa4ab,0x0000000000000000, }; -u8 cpp_pp_keys_key_array_1[] = {0x64,0x65,0x66,0x69,0x6e,0x65,0x64,}; +u8 cpp_pp_keys_key_array_0[] = {0x64,0x65,0x66,0x69,0x6e,0x65,0x64,}; String_Const_u8 cpp_pp_keys_key_array[2] = { +{cpp_pp_keys_key_array_0, 7}, {0, 0}, -{cpp_pp_keys_key_array_1, 7}, }; Lexeme_Table_Value cpp_pp_keys_value_array[2] = { -{0, 0}, {4, TokenCppKind_PPDefined}, +{0, 0}, }; i32 cpp_pp_keys_slot_count = 2; -u64 cpp_pp_keys_seed = 0x5c61314da2466695; +u64 cpp_pp_keys_seed = 0xbb7907ea1860ef2c; struct Lex_State_Cpp{ u32 flags_ZF0; u32 flags_KF0; diff --git a/custom/generated/system_api.h b/custom/generated/system_api.h index ce9536da..f67a518f 100644 --- a/custom/generated/system_api.h +++ b/custom/generated/system_api.h @@ -93,53 +93,53 @@ typedef b32 system_set_fullscreen_type(b32 full_screen); typedef b32 system_is_fullscreen_type(void); typedef Input_Modifier_Set system_get_keyboard_modifiers_type(Arena* arena); struct API_VTable_system{ -system_get_path_type *get_path; -system_get_canonical_type *get_canonical; -system_get_file_list_type *get_file_list; -system_quick_file_attributes_type *quick_file_attributes; -system_load_handle_type *load_handle; -system_load_attributes_type *load_attributes; -system_load_file_type *load_file; -system_load_close_type *load_close; -system_save_file_type *save_file; -system_load_library_type *load_library; -system_release_library_type *release_library; -system_get_proc_type *get_proc; -system_now_time_type *now_time; -system_wake_up_timer_create_type *wake_up_timer_create; -system_wake_up_timer_release_type *wake_up_timer_release; -system_wake_up_timer_set_type *wake_up_timer_set; -system_signal_step_type *signal_step; -system_sleep_type *sleep; -system_post_clipboard_type *post_clipboard; -system_cli_call_type *cli_call; -system_cli_begin_update_type *cli_begin_update; -system_cli_update_step_type *cli_update_step; -system_cli_end_update_type *cli_end_update; -system_open_color_picker_type *open_color_picker; -system_get_screen_scale_factor_type *get_screen_scale_factor; -system_thread_launch_type *thread_launch; -system_thread_join_type *thread_join; -system_thread_free_type *thread_free; -system_thread_get_id_type *thread_get_id; -system_acquire_global_frame_mutex_type *acquire_global_frame_mutex; -system_release_global_frame_mutex_type *release_global_frame_mutex; -system_mutex_make_type *mutex_make; -system_mutex_acquire_type *mutex_acquire; -system_mutex_release_type *mutex_release; -system_mutex_free_type *mutex_free; -system_condition_variable_make_type *condition_variable_make; -system_condition_variable_wait_type *condition_variable_wait; -system_condition_variable_signal_type *condition_variable_signal; -system_condition_variable_free_type *condition_variable_free; -system_memory_allocate_type *memory_allocate; -system_memory_set_protection_type *memory_set_protection; -system_memory_free_type *memory_free; -system_memory_annotation_type *memory_annotation; -system_show_mouse_cursor_type *show_mouse_cursor; -system_set_fullscreen_type *set_fullscreen; -system_is_fullscreen_type *is_fullscreen; -system_get_keyboard_modifiers_type *get_keyboard_modifiers; + system_get_path_type *get_path; + system_get_canonical_type *get_canonical; + system_get_file_list_type *get_file_list; + system_quick_file_attributes_type *quick_file_attributes; + system_load_handle_type *load_handle; + system_load_attributes_type *load_attributes; + system_load_file_type *load_file; + system_load_close_type *load_close; + system_save_file_type *save_file; + system_load_library_type *load_library; + system_release_library_type *release_library; + system_get_proc_type *get_proc; + system_now_time_type *now_time; + system_wake_up_timer_create_type *wake_up_timer_create; + system_wake_up_timer_release_type *wake_up_timer_release; + system_wake_up_timer_set_type *wake_up_timer_set; + system_signal_step_type *signal_step; + system_sleep_type *sleep; + system_post_clipboard_type *post_clipboard; + system_cli_call_type *cli_call; + system_cli_begin_update_type *cli_begin_update; + system_cli_update_step_type *cli_update_step; + system_cli_end_update_type *cli_end_update; + system_open_color_picker_type *open_color_picker; + system_get_screen_scale_factor_type *get_screen_scale_factor; + system_thread_launch_type *thread_launch; + system_thread_join_type *thread_join; + system_thread_free_type *thread_free; + system_thread_get_id_type *thread_get_id; + system_acquire_global_frame_mutex_type *acquire_global_frame_mutex; + system_release_global_frame_mutex_type *release_global_frame_mutex; + system_mutex_make_type *mutex_make; + system_mutex_acquire_type *mutex_acquire; + system_mutex_release_type *mutex_release; + system_mutex_free_type *mutex_free; + system_condition_variable_make_type *condition_variable_make; + system_condition_variable_wait_type *condition_variable_wait; + system_condition_variable_signal_type *condition_variable_signal; + system_condition_variable_free_type *condition_variable_free; + system_memory_allocate_type *memory_allocate; + system_memory_set_protection_type *memory_set_protection; + system_memory_free_type *memory_free; + system_memory_annotation_type *memory_annotation; + system_show_mouse_cursor_type *show_mouse_cursor; + system_set_fullscreen_type *set_fullscreen; + system_is_fullscreen_type *is_fullscreen; + system_get_keyboard_modifiers_type *get_keyboard_modifiers; }; #if defined(STATIC_LINK_API) internal String_Const_u8 system_get_path(Arena* arena, System_Path_Code path_code); diff --git a/custom/metadata_generator.dSYM/Contents/Info.plist b/custom/metadata_generator.dSYM/Contents/Info.plist new file mode 100644 index 00000000..a05ad97b --- /dev/null +++ b/custom/metadata_generator.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.metadata_generator + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/custom/metadata_generator.dSYM/Contents/Resources/DWARF/metadata_generator b/custom/metadata_generator.dSYM/Contents/Resources/DWARF/metadata_generator new file mode 100644 index 00000000..815fd871 Binary files /dev/null and b/custom/metadata_generator.dSYM/Contents/Resources/DWARF/metadata_generator differ diff --git a/metal/4ed_metal_render.mm b/metal/4ed_metal_render.mm new file mode 100644 index 00000000..6f029cc7 --- /dev/null +++ b/metal/4ed_metal_render.mm @@ -0,0 +1,535 @@ +/* 4coder Metal render implementation */ + +#undef clamp +#undef function +#import +#import + +#include "AAPLShaderTypes.h" +#define function static + +//////////////////////////////// + +typedef id Metal_Texture; + +struct Metal_Buffer{ + Node node; + + id buffer; + u32 size; + u64 last_reuse_time; +}; + +//////////////////////////////// + +@interface Metal_Renderer : NSObject +@property (nonatomic) Render_Target *target; + +- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)mtkView target:(Render_Target*)target; + +- (u32)get_texture_of_dim:(Vec3_i32)dim kind:(Texture_Kind)kind; +- (b32)fill_texture:(u32)texture kind:(Texture_Kind)kind pos:(Vec3_i32)p dim:(Vec3_i32)dim data:(void*)data; +- (void)bind_texture:(u32)handle encoder:(id)render_encoder; + +- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size; +- (void)add_reusable_buffer:(Metal_Buffer*)buffer; +@end + +//////////////////////////////// + +global_const u32 metal__max_textures = 256; + +//////////////////////////////// + +global_const char *metal__shaders_source = R"( +#include +#include + +using namespace metal; + +//////////////////////////////// + +typedef struct{ +float2 xy [[attribute(0)]]; +float3 uvw [[attribute(1)]]; +uint32_t color [[attribute(2)]]; +float half_thickness [[attribute(3)]]; +} Vertex; + +// NOTE(yuval): Vertex shader outputs and fragment shader inputs +typedef struct{ +// NOTE(yuval): Vertex shader output +float4 position [[position]]; + +// NOTE(yuval): Fragment shader inputs +float4 color; +float3 uvw; +float2 xy; +float2 adjusted_half_dim; +float half_thickness; +} Rasterizer_Data; + +//////////////////////////////// + +vertex Rasterizer_Data +vertex_shader(Vertex in [[stage_in]], +constant float4x4 &proj [[buffer(1)]]){ +Rasterizer_Data out; + +// NOTE(yuval): Calculate position in NDC +out.position = proj * float4(in.xy, 0.0, 1.0); + +// NOTE(yuval): Convert color to float4 format +out.color.b = ((float((in.color ) & 0xFFu)) / 255.0); +out.color.g = ((float((in.color >> 8u) & 0xFFu)) / 255.0); +out.color.r = ((float((in.color >> 16u) & 0xFFu)) / 255.0); +out.color.a = ((float((in.color >> 24u) & 0xFFu)) / 255.0); + +// NOTE(yuval): Pass uvw coordinates to the fragment shader +out.uvw = in.uvw; + +// NOTE(yuval): Calculate adjusted half dim +float2 center = in.uvw.xy; +float2 half_dim = abs(in.xy - center); +out.adjusted_half_dim = (half_dim - in.uvw.zz + float2(0.5, 0.5)); + +// NOTE(yuval): Pass half_thickness to the fragment shader +out.half_thickness = in.half_thickness; + +// NOTE(yuval): Pass xy to the fragment shader +out.xy = in.xy; + +return(out); +} + +//////////////////////////////// + +float +rectangle_sd(float2 p, float2 b){ +float2 d = (abs(p) - b); +float result = (length(max(d, float2(0.0, 0.0))) + min(max(d.x, d.y), 0.0)); + +return(result); +} + +fragment float4 +fragment_shader(Rasterizer_Data in [[stage_in]], +texture2d_array in_texture [[texture(0)]]){ +float has_thickness = step(0.49, in.half_thickness); +float does_not_have_thickness = (1.0 - has_thickness); + +constexpr sampler texture_sampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear); +half sample_value = in_texture.sample(texture_sampler, in.uvw.xy, in.uvw.z).r; +sample_value *= does_not_have_thickness; + +float2 center = in.uvw.xy; +float roundness = in.uvw.z; +float sd = rectangle_sd(in.xy - center, in.adjusted_half_dim); +sd = sd - roundness; +sd = (abs(sd + in.half_thickness) - in.half_thickness); +float shape_value = (1.0 - smoothstep(-1.0, 0.0, sd)); +shape_value *= has_thickness; + +float4 out_color = float4(in.color.xyz, in.color.a * (sample_value + shape_value)); +return(out_color); +} +)"; + +//////////////////////////////// + +function Metal_Buffer* +metal__make_buffer(u32 size, id device){ + Metal_Buffer *result = (Metal_Buffer*)malloc(sizeof(Metal_Buffer)); + + // NOTE(yuval): Create the vertex buffer + MTLResourceOptions options = MTLCPUCacheModeWriteCombined|MTLResourceStorageModeManaged; + result->buffer = [device newBufferWithLength:size options:options]; + result->size = size; + + // NOTE(yuval): Set the last_reuse_time to the current time + result->last_reuse_time = system_now_time(); + + return result; +} + +//////////////////////////////// + +@implementation Metal_Renderer{ + id device; + id pipeline_state; + id command_queue; + id capture_scope; + + Node buffer_cache; + u64 last_buffer_cache_purge_time; + + Metal_Texture *textures; + u32 next_texture_handle_index; +} + +- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)mtk_view target:(Render_Target*)target{ + self = [super init]; + if (self == nil){ + return(nil); + } + + _target = target; + + NSError *error = nil; + + device = mtk_view.device; + + // NOTE(yuval): Compile the shaders + id vertex_function = nil; + id fragment_function = nil; + { + NSString *shaders_source_str = [NSString stringWithUTF8String:metal__shaders_source]; + + MTLCompileOptions *options = [[MTLCompileOptions alloc] init]; + options.fastMathEnabled = YES; + + id shader_library = [device newLibraryWithSource:shaders_source_str + options:options error:&error]; + vertex_function = [shader_library newFunctionWithName:@"vertex_shader"]; + fragment_function = [shader_library newFunctionWithName:@"fragment_shader"]; + + [options release]; + } + + Assert(error == nil); + Assert((vertex_function != nil) && (fragment_function != nil)); + + // NOTE(yuval): Configure the pipeline descriptor + { + MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor]; + vertexDescriptor.attributes[0].offset = OffsetOfMember(Render_Vertex, xy); + vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position + vertexDescriptor.attributes[0].bufferIndex = 0; + vertexDescriptor.attributes[1].offset = OffsetOfMember(Render_Vertex, uvw); + vertexDescriptor.attributes[1].format = MTLVertexFormatFloat3; // texCoords + vertexDescriptor.attributes[1].bufferIndex = 0; + vertexDescriptor.attributes[2].offset = OffsetOfMember(Render_Vertex, color); + vertexDescriptor.attributes[2].format = MTLVertexFormatUInt; // color + vertexDescriptor.attributes[2].bufferIndex = 0; + vertexDescriptor.attributes[3].offset = OffsetOfMember(Render_Vertex, half_thickness); + vertexDescriptor.attributes[3].format = MTLVertexFormatFloat; // position + vertexDescriptor.attributes[3].bufferIndex = 0; + vertexDescriptor.layouts[0].stepRate = 1; + vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; + vertexDescriptor.layouts[0].stride = sizeof(Render_Vertex); + + MTLRenderPipelineDescriptor *pipeline_state_descriptor = [[MTLRenderPipelineDescriptor alloc] init]; + pipeline_state_descriptor.label = @"4coder Metal Renderer Pipeline"; + pipeline_state_descriptor.vertexFunction = vertex_function; + pipeline_state_descriptor.fragmentFunction = fragment_function; + pipeline_state_descriptor.vertexDescriptor = vertexDescriptor; + pipeline_state_descriptor.colorAttachments[0].pixelFormat = mtk_view.colorPixelFormat; + pipeline_state_descriptor.colorAttachments[0].blendingEnabled = YES; + pipeline_state_descriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + pipeline_state_descriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + pipeline_state_descriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + pipeline_state_descriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + pipeline_state_descriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; + pipeline_state_descriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + + pipeline_state = [device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor + error:&error]; + } + + Assert(error == nil); + + // NOTE(yuval): Create the command queue + command_queue = [device newCommandQueue]; + + // NOTE(yuval): Initialize buffer caching + dll_init_sentinel(&buffer_cache); + last_buffer_cache_purge_time = system_now_time(); + + // NOTE(yuval): Initialize the textures array + textures = (Metal_Texture*)system_memory_allocate(metal__max_textures * sizeof(Metal_Texture), file_name_line_number_lit_u8); + next_texture_handle_index = 0; + + // NOTE(yuval): Create the fallback texture + _target->fallback_texture_id = [self get_texture_of_dim:V3i32(2, 2, 1) + kind:TextureKind_Mono]; + u8 white_block[] = {0xFF, 0xFF, 0xFF, 0xFF}; + [self fill_texture:_target->fallback_texture_id + kind:TextureKind_Mono + pos:V3i32(0, 0, 0) + dim:V3i32(2, 2, 1) + data:white_block]; + + // NOTE(yuval): Create a capture scope for gpu frame capture + capture_scope = [[MTLCaptureManager sharedCaptureManager] + newCaptureScopeWithDevice:device]; + capture_scope.label = @"4coder Metal Capture Scope"; + + return(self); +} + +- (void)mtkView:(nonnull MTKView*)view drawableSizeWillChange:(CGSize)size{ + // NOTE(yuval): Nothing to do here because we use the render target's dimentions for rendering +} + +- (void)drawInMTKView:(nonnull MTKView*)view{ +#if FRED_INTERNAL + [capture_scope beginScope]; +#endif + + // HACK(yuval): This is the best way I found to force valid width and height without drawing on the next draw cycle (1 frame delay). + + CGSize drawable_size = [view drawableSize]; + i32 width = (i32)Min(_target->width, drawable_size.width); + i32 height = (i32)Min(_target->height, drawable_size.height); + + Font_Set *font_set = (Font_Set*)_target->font_set; + + // NOTE(yuval): Create the command buffer + id command_buffer = [command_queue commandBuffer]; + command_buffer.label = @"4coder Metal Render Command"; + + // NOTE(yuval): Obtain the render pass descriptor from the renderer's view + MTLRenderPassDescriptor *render_pass_descriptor = view.currentRenderPassDescriptor; + if (render_pass_descriptor != nil){ + render_pass_descriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0f, 0.0f, 0.0f, 1.0f); + + // NOTE(yuval): Create the render command encoder + id render_encoder = + [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor]; + render_encoder.label = @"4coder Render Encoder"; + + // NOTE(yuval): Set the region of the drawable to draw into + [render_encoder setViewport:(MTLViewport){0.0, 0.0, (double)width, (double)height, 0.0, 1.0}]; + + // NOTE(yuval): Set the render pipeline to use for drawing + [render_encoder setRenderPipelineState:pipeline_state]; + + // NOTE(yuval): Calculate the projection matrix + float left = 0, right = (float)width; + float bottom = (float)height, top = 0; + float near_depth = -1.0f, far_depth = 1.0f; + float proj[16] = { + 2.0f / (right - left), 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f / (top - bottom), 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f / (far_depth - near_depth), 0.0f, + -((right + left) / (right - left)), -((top + bottom) / (top - bottom)), + -(near_depth / (far_depth - near_depth)), 1.0f + }; + + // NOTE(yuval): Calculate required vertex buffer size + i32 all_vertex_count = 0; + for (Render_Group *group = _target->group_first; + group; + group = group->next){ + all_vertex_count += group->vertex_list.vertex_count; + } + + u32 vertex_buffer_size = (all_vertex_count * sizeof(Render_Vertex)); + + // NOTE(yuval): Find & Get a vertex buffer matching the required size + Metal_Buffer *buffer = [self get_reusable_buffer_with_size:vertex_buffer_size]; + + // NOTE(yuval): Pass the vertex buffer to the vertex shader + [render_encoder setVertexBuffer:buffer->buffer + offset:0 + atIndex:0]; + + // NOTE(yuval): Pass the projection matrix to the vertex shader + [render_encoder setVertexBytes:&proj + length:sizeof(proj) + atIndex:1]; + + u32 buffer_offset = 0; + for (Render_Group *group = _target->group_first; + group; + group = group->next){ + // NOTE(yuval): Set scissor rect + { + Rect_i32 box = Ri32(group->clip_box); + + NSUInteger x0 = (NSUInteger)Min(Max(0, box.x0), width - 1); + NSUInteger x1 = (NSUInteger)Min(Max(0, box.x1), width); + NSUInteger y0 = (NSUInteger)Min(Max(0, box.y0), height - 1); + NSUInteger y1 = (NSUInteger)Min(Max(0, box.y1), height); + + MTLScissorRect scissor_rect; + scissor_rect.x = x0; + scissor_rect.y = y0; + scissor_rect.width = (x1 - x0); + scissor_rect.height = (y1 - y0); + + [render_encoder setScissorRect:scissor_rect]; + } + + i32 vertex_count = group->vertex_list.vertex_count; + if (vertex_count > 0){ + // NOTE(yuval): Bind a texture + { + Face* face = font_set_face_from_id(font_set, group->face_id); + if (face != 0){ + // NOTE(yuval): Bind face texture + [self bind_texture:face->texture + encoder:render_encoder]; + } else{ + // NOTE(yuval): Bind fallback texture + [self bind_texture:_target->fallback_texture_id + encoder:render_encoder]; + } + } + + // NOTE(yuval): Copy the vertex data to the vertex buffer + { + + u8 *group_buffer_contents = (u8*)[buffer->buffer contents] + buffer_offset; + u8 *cursor = group_buffer_contents; + for (Render_Vertex_Array_Node *node = group->vertex_list.first; + node; + node = node->next){ + i32 size = node->vertex_count * sizeof(*node->vertices); + memcpy(cursor, node->vertices, size); + cursor += size; + } + + NSUInteger data_size = (NSUInteger)(cursor - group_buffer_contents); + NSRange modify_range = NSMakeRange(buffer_offset, data_size); + [buffer->buffer didModifyRange:modify_range]; + } + + // NOTE(yuval): Set the vertex buffer offset to the beginning of the group's vertices + [render_encoder setVertexBufferOffset:buffer_offset atIndex:0]; + + // NOTE(yuval): Draw the vertices + [render_encoder drawPrimitives:MTLPrimitiveTypeTriangle + vertexStart:0 + vertexCount:vertex_count]; + + buffer_offset += (vertex_count * sizeof(Render_Vertex)); + } + } + + [render_encoder endEncoding]; + + // NOTE(yuval): Schedule a present once the framebuffer is complete using the current drawable + [command_buffer presentDrawable:view.currentDrawable]; + + [command_buffer addCompletedHandler:^(id){ + dispatch_async(dispatch_get_main_queue(), ^{ + [self add_reusable_buffer:buffer]; + }); + }]; + } + + // NOTE(yuval): Finalize rendering here and push the command buffer to the GPU + [command_buffer commit]; + +#if FRED_INTERNAL + [capture_scope endScope]; +#endif +} + +- (u32)get_texture_of_dim:(Vec3_i32)dim kind:(Texture_Kind)kind{ + u32 handle = next_texture_handle_index; + + // NOTE(yuval): Create a texture descriptor + MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init]; + texture_descriptor.textureType = MTLTextureType2DArray; + texture_descriptor.pixelFormat = MTLPixelFormatR8Unorm; + texture_descriptor.width = dim.x; + texture_descriptor.height = dim.y; + texture_descriptor.depth = dim.z; + + // NOTE(yuval): Create the texture from the device using the descriptor and add it to the textures array + Metal_Texture texture = [device newTextureWithDescriptor:texture_descriptor]; + textures[handle] = texture; + + next_texture_handle_index += 1; + + return handle; +} + +- (b32)fill_texture:(u32)handle kind:(Texture_Kind)kind pos:(Vec3_i32)p dim:(Vec3_i32)dim data:(void*)data{ + b32 result = false; + + if (data){ + Metal_Texture texture = textures[handle]; + + if (texture != 0){ + MTLRegion replace_region = { + {(NSUInteger)p.x, (NSUInteger)p.y, (NSUInteger)p.z}, + {(NSUInteger)dim.x, (NSUInteger)dim.y, (NSUInteger)dim.z} + }; + + // NOTE(yuval): Fill the texture with data + [texture replaceRegion:replace_region + mipmapLevel:0 + withBytes:data + bytesPerRow:dim.x]; + + result = true; + } + } + + return result; +} + +- (void)bind_texture:(u32)handle encoder:(id)render_encoder{ + Metal_Texture texture = textures[handle]; + if (texture != 0){ + [render_encoder setFragmentTexture:texture + atIndex:0]; + } +} + +- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size{ + // NOTE(yuval): This routine is a modified version of Dear ImGui's MetalContext::dequeueReusableBufferOfLength in imgui_impl_metal.mm + + u64 now = system_now_time(); + + // NOTE(yuval): Purge old buffers that haven't been useful for a while + if ((now - last_buffer_cache_purge_time) > 1000000){ + Node prev_buffer_cache = buffer_cache; + dll_init_sentinel(&buffer_cache); + + for (Node *node = prev_buffer_cache.next; + node != &buffer_cache; + node = node->next){ + Metal_Buffer *candidate = CastFromMember(Metal_Buffer, node, node); + if (candidate->last_reuse_time > last_buffer_cache_purge_time){ + dll_insert(&buffer_cache, node); + } + } + + last_buffer_cache_purge_time = now; + } + + // NOTE(yuval): See if we have a buffer we can reuse + Metal_Buffer *best_candidate = 0; + for (Node *node = buffer_cache.next; + node != &buffer_cache; + node = node->next){ + Metal_Buffer *candidate = CastFromMember(Metal_Buffer, node, node); + if ((candidate->size >= size) && ((!best_candidate) || (best_candidate->last_reuse_time > candidate->last_reuse_time))){ + best_candidate = candidate; + } + } + + Metal_Buffer *result; + if (best_candidate){ + // NOTE(yuval): A best candidate has been found! Remove it from the buffer list and set its last reuse time. + dll_remove(&best_candidate->node); + best_candidate->last_reuse_time = now; + result = best_candidate; + } else{ + // NOTE(yuval): No luck; make a new buffer. + result = metal__make_buffer(size, device); + } + + return result; +} + +- (void)add_reusable_buffer:(Metal_Buffer*)buffer{ + // NOTE(yuval): This routine is a modified version of Dear ImGui's MetalContext::enqueueReusableBuffer in imgui_impl_metal.mm + + dll_insert(&buffer_cache, &buffer->node); +} +@end diff --git a/metal/AAPLShaderTypes.h b/metal/AAPLShaderTypes.h new file mode 100644 index 00000000..a464b446 --- /dev/null +++ b/metal/AAPLShaderTypes.h @@ -0,0 +1,25 @@ +/* +See LICENSE folder for this sample’s licensing information. + +Abstract: +Header containing types and enum constants shared between Metal shaders and C/ObjC source +*/ + +#ifndef AAPLShaderTypes_h +#define AAPLShaderTypes_h + +#undef clamp +#include +#define clamp(a,x,b) clamp_((a),(x),(b)) + +// This structure defines the layout of vertices sent to the vertex +// shader. This header is shared between the .metal shader and C code, to guarantee that +// the layout of the vertex array in the C code matches the layout that the .metal +// vertex shader expects. +typedef struct +{ + vector_float2 position; + vector_float4 color; +} AAPLVertex; + +#endif /* AAPLShaderTypes_h */ diff --git a/metal/AAPLShaders.metal b/metal/AAPLShaders.metal new file mode 100644 index 00000000..60c3736b --- /dev/null +++ b/metal/AAPLShaders.metal @@ -0,0 +1,64 @@ +/* +See LICENSE folder for this sample’s licensing information. + +Abstract: +Metal shaders used for this sample +*/ + +#include +#include + +using namespace metal; + +// Include header shared between this Metal shader code and C code executing Metal API commands. +#import "AAPLShaderTypes.h" + +// Vertex shader outputs and fragment shader inputs +typedef struct +{ + // The [[position]] attribute of this member indicates that this value + // is the clip space position of the vertex when this structure is + // returned from the vertex function. + float4 position [[position]]; + + // Since this member does not have a special attribute, the rasterizer + // interpolates its value with the values of the other triangle vertices + // and then passes the interpolated value to the fragment shader for each + // fragment in the triangle. + float4 color; + +} RasterizerData; + +vertex RasterizerData +vertexShader(uint vertexID [[vertex_id]], + constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]], + constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]]) +{ + RasterizerData out; + + // Index into the array of positions to get the current vertex. + // The positions are specified in pixel dimensions (i.e. a value of 100 + // is 100 pixels from the origin). + float2 pixelSpacePosition = vertices[vertexID].position.xy; + + // Get the viewport size and cast to float. + vector_float2 viewportSize = vector_float2(*viewportSizePointer); + + + // To convert from positions in pixel space to positions in clip-space, + // divide the pixel coordinates by half the size of the viewport. + out.position = vector_float4(0.0, 0.0, 0.0, 1.0); + out.position.xy = pixelSpacePosition / (viewportSize / 2.0); + + // Pass the input color directly to the rasterizer. + out.color = vertices[vertexID].color; + + return out; +} + +fragment float4 fragmentShader(RasterizerData in [[stage_in]]) +{ + // Return the interpolated color. + return in.color; +} + diff --git a/opengl/4ed_opengl_defines.h b/opengl/4ed_opengl_defines.h index be20f65e..c64640cf 100644 --- a/opengl/4ed_opengl_defines.h +++ b/opengl/4ed_opengl_defines.h @@ -12,8 +12,6 @@ #if !defined(FRED_OPENGL_DEFINES_H) #define FRED_OPENGL_DEFINES_H -#include - #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_MULTISAMPLE 0x809D @@ -224,9 +222,6 @@ typedef void GL_Debug_Function(GLenum src, void *user_data); typedef GL_Debug_Function *GLDEBUGPROC; -#define GL_FUNC(N,R,P) typedef R (CALL_CONVENTION N##_Function)P; N##_Function *N = 0; -#include "4ed_opengl_funcs.h" - #endif // BOTTOM diff --git a/opengl/4ed_opengl_render.cpp b/opengl/4ed_opengl_render.cpp index 48f3ef6f..9daddb2d 100644 --- a/opengl/4ed_opengl_render.cpp +++ b/opengl/4ed_opengl_render.cpp @@ -9,8 +9,6 @@ // TOP -#include "4ed_opengl_defines.h" - internal void gl__bind_texture(Render_Target *t, i32 texid){ if (t->bound_texture != texid){ @@ -225,11 +223,16 @@ gl_render(Render_Target *t){ #if !SHIP_MODE glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, 0, false); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, 0, false); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, 0, true); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, 0, true); - glDebugMessageCallback(gl__error_callback, 0); + if (glDebugMessageControl){ + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, 0, false); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, 0, false); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, 0, true); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, 0, true); + } + + if (glDebugMessageCallback){ + glDebugMessageCallback(gl__error_callback, 0); + } #endif //////////////////////////////// @@ -256,7 +259,7 @@ gl_render(Render_Target *t){ //////////////////////////////// - { + { t->fallback_texture_id = gl__get_texture(V3i32(2, 2, 1), TextureKind_Mono); u8 white_block[] = { 0xFF, 0xFF, 0xFF, 0xFF, }; gl__fill_texture(TextureKind_Mono, 0, V3i32(0, 0, 0), V3i32(2, 2, 1), white_block); @@ -282,6 +285,7 @@ gl_render(Render_Target *t){ t->free_texture_first = 0; t->free_texture_last = 0; + u64 begin_draw = system_now_time(); for (Render_Group *group = t->group_first; group != 0; group = group->next){ diff --git a/platform_mac/mac_4ed.mm b/platform_mac/mac_4ed.mm new file mode 100644 index 00000000..e4ca5ec1 --- /dev/null +++ b/platform_mac/mac_4ed.mm @@ -0,0 +1,1361 @@ +/* Mac Objective-C layer for 4coder */ + +#define FPS 60 +#define frame_useconds (1000000 / FPS) + +#include "4coder_base_types.h" +#include "4coder_version.h" +#include "4coder_events.h" + +#include "4coder_table.h" + +// NOTE(allen): This is a very unfortunate hack, but hopefully there will never be a need to use the Marker +// type in the platform layer. If that changes then instead change the name of Marker and make a transition +// macro that is only included in custom code. +#define Marker Marker__SAVE_THIS_IDENTIFIER +#include "4coder_types.h" +#undef Marker + +#include "4coder_default_colors.h" + +#include "4coder_system_types.h" +#define STATIC_LINK_API +#include "generated/system_api.h" + +#include "4ed_font_interface.h" +#define STATIC_LINK_API +#include "generated/graphics_api.h" +#define STATIC_LINK_API +#include "generated/font_api.h" + +#include "4ed_font_set.h" +#include "4ed_render_target.h" +#include "4ed_search_list.h" +#include "4ed.h" + +#include "generated/system_api.cpp" +#include "generated/graphics_api.cpp" +#include "generated/font_api.cpp" + +#include "4coder_base_types.cpp" +#include "4coder_stringf.cpp" +#include "4coder_events.cpp" +#include "4coder_hash_functions.cpp" +#include "4coder_table.cpp" +#include "4coder_log.cpp" + +#include "4ed_search_list.cpp" + +#include "mac_objective_c_to_cpp_links.h" + +#undef function +#undef internal +#undef global +#undef external +#import + +#include // NOTE(yuval): Used for proc_pidpath +#include // NOTE(yuval): Used for virtual key codes +#include // NOTE(yuval): Used for mach_absolute_time, mach_timebase_info, mach_timebase_info_data_t + +#include // NOTE(yuval): Used for opendir, readdir +#include // NOTE(yuval): Used for dlopen, dlclose, dlsym +#include // NOTE(yuval): Used for errno +#include // NOTE(yuval): Used for open +#include // NOTE(yuval): Used for threads, mutexes, cvs +#include // NOTE(yuval): Used for getcwd, read, write, getpid +#include // NOTE(yuval): Used for mmap, munmap, mprotect +#include // NOTE(yuval): Used for stat +#include // NOTE(yuval): Used for struct stat, pid_t + +#include // NOTE(yuval): Used for free + +#define function static +#define internal static +#define global static +#define external extern "C" + +struct Control_Keys{ + b8 l_ctrl; + b8 r_ctrl; + b8 l_alt; + b8 r_alt; + b8 l_shift; + b8 r_shift; + b8 l_command; + b8 r_command; +}; + +struct Mac_Input_Chunk_Transient{ + Input_List event_list; + b8 mouse_l_press; + b8 mouse_l_release; + b8 mouse_r_press; + b8 mouse_r_release; + b8 out_of_window; + i8 mouse_wheel; + b8 trying_to_kill; +}; + +struct Mac_Input_Chunk_Persistent{ + Vec2_i32 mouse; + Control_Keys controls; + Input_Modifier_Set_Fixed modifiers; + b8 mouse_l; + b8 mouse_r; +}; + +struct Mac_Input_Chunk{ + Mac_Input_Chunk_Transient trans; + Mac_Input_Chunk_Persistent pers; +}; + +//////////////////////////////// + +#define SLASH '/' +#define DLL "so" + +#include "4coder_hash_functions.cpp" +#include "4coder_system_allocator.cpp" +#include "4coder_malloc_allocator.cpp" +#include "4coder_codepoint_map.cpp" + +#include "4ed_mem.cpp" +#include "4ed_font_set.cpp" + +//////////////////////////////// + +@interface FCoder_App_Delegate : NSObject +@end + +@interface FCoder_Window_Delegate : NSObject +- (void)process_focus_event; +@end + +@interface FCoder_View : NSView +- (void)request_display; +- (void)check_clipboard; +- (void)process_keyboard_event:(NSEvent*)event down:(b8)down; +- (void)process_mouse_move_event:(NSEvent*)event; +@end + +//////////////////////////////// + +typedef i32 Mac_Object_Kind; +enum{ + MacObjectKind_ERROR = 0, + MacObjectKind_Timer = 1, + MacObjectKind_Thread = 2, + MacObjectKind_Mutex = 3, + MacObjectKind_CV = 4, +}; + +struct Mac_Object{ + Node node; + Mac_Object_Kind kind; + + union{ + NSTimer* timer; + + struct{ + pthread_t thread; + Thread_Function *proc; + void *ptr; + } thread; + + pthread_mutex_t mutex; + pthread_cond_t cv; + }; +}; + +struct Mac_Vars { + i32 width, height; + + Thread_Context *tctx; + + Arena *frame_arena; + Input_Event *active_key_stroke; + Input_Event *active_text_input; + Mac_Input_Chunk input_chunk; + b8 lctrl_lalt_is_altgr; + + b8 full_screen; + b8 do_toggle; + b32 send_exit_signal; + + i32 cursor_show; + i32 prev_cursor_show; + NSCursor *cursor_ibeam; + NSCursor *cursor_arrow; + NSCursor *cursor_leftright; + NSCursor *cursor_updown; + + String_Const_u8 binary_path; + + Arena *clipboard_arena; + String_Const_u8 clipboard_contents; + u32 clipboard_change_count; + b32 next_clipboard_is_self; + + Arena clip_post_arena; + String_Const_u8 clip_post; + + NSWindow *window; + FCoder_View *view; + f32 screen_scale_factor; + + mach_timebase_info_data_t timebase_info; + b32 first; + void *base_ptr; + + u64 timer_start; + b32 step_requested; + i32 running_cli; + + Node free_mac_objects; + Node timer_objects; + + pthread_mutex_t thread_launch_mutex; + pthread_cond_t thread_launch_cv; + b32 waiting_for_launch; + + System_Mutex global_frame_mutex; + + Log_Function *log_string; +}; + +//////////////////////////////// + +#include "mac_4ed_renderer.h" + +//////////////////////////////// + +global Mac_Vars mac_vars; +global Mac_Renderer *renderer; +global Render_Target target; +global App_Functions app; + +//////////////////////////////// + +function Mac_Object* +mac_alloc_object(Mac_Object_Kind kind){ + Mac_Object *result = 0; + + if (mac_vars.free_mac_objects.next != &mac_vars.free_mac_objects){ + result = CastFromMember(Mac_Object, node, mac_vars.free_mac_objects.next); + } + + if (!result){ + i32 count = 512; + Mac_Object *objects = (Mac_Object*)system_memory_allocate(count * sizeof(Mac_Object), file_name_line_number_lit_u8); + + // NOTE(yuval): Link the first node of the dll to the sentinel + objects[0].node.prev = &mac_vars.free_mac_objects; + mac_vars.free_mac_objects.next = &objects[0].node; + + // NOTE(yuval): Link all dll nodes to each other + for (i32 chain_index = 1; chain_index < count; chain_index += 1){ + objects[chain_index - 1].node.next = &objects[chain_index].node; + objects[chain_index].node.prev = &objects[chain_index - 1].node; + } + + // NOTE(yuval): Link the last node of the dll to the sentinel + objects[count - 1].node.next = &mac_vars.free_mac_objects; + mac_vars.free_mac_objects.prev = &objects[count - 1].node; + + result = CastFromMember(Mac_Object, node, mac_vars.free_mac_objects.next); + } + + Assert(result); + dll_remove(&result->node); + block_zero_struct(result); + result->kind = kind; + + return(result); +} + +function void +mac_free_object(Mac_Object *object){ + if (object->node.next != 0){ + dll_remove(&object->node); + } + + dll_insert(&mac_vars.free_mac_objects, &object->node); +} + +function inline Plat_Handle +mac_to_plat_handle(Mac_Object *object){ + Plat_Handle result = *(Plat_Handle*)(&object); + return(result); +} + +function inline Mac_Object* +mac_to_object(Plat_Handle handle){ + Mac_Object *result = *(Mac_Object**)(&handle); + return(result); +} + +//////////////////////////////// + +function void +mac_error_box(char *msg, b32 shutdown = true){ + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + + NSString *title_string = @"Error"; + NSString *message_string = [NSString stringWithUTF8String:msg]; + [alert setMessageText:title_string]; + [alert setInformativeText:message_string]; + + [alert runModal]; + + if (shutdown){ + exit(1); + } +} + +//////////////////////////////// + +#if defined(FRED_INTERNAL) +function inline void +mac_profile(char *name, u64 begin, u64 end){ + printf("%s Time: %fs\n", name, ((end - begin) / 1000000.0f)); +} + +#define MacProfileScope(name) for (u64 glue(_i_, __LINE__) = 0, glue(_begin_, __LINE__) = system_now_time();\ +glue(_i_, __LINE__) == 0;\ +glue(_i_, __LINE__) = 1, mac_profile(name, glue(_begin_, __LINE__), system_now_time())) +#else +# define mac_profile(...) +# define MacProfileScope(...) +#endif + +//////////////////////////////// + +#import "mac_4ed_renderer.mm" + +#include "4ed_font_provider_freetype.h" +#include "4ed_font_provider_freetype.cpp" + +#import "mac_4ed_functions.mm" + +//////////////////////////////// + +global_const u8 kVK_Menu = 0x6E; + +global Key_Code keycode_lookup_table[255] = {}; + +function void +mac_keycode_init(void){ + keycode_lookup_table[kVK_ANSI_A] = KeyCode_A; + keycode_lookup_table[kVK_ANSI_B] = KeyCode_B; + keycode_lookup_table[kVK_ANSI_C] = KeyCode_C; + keycode_lookup_table[kVK_ANSI_D] = KeyCode_D; + keycode_lookup_table[kVK_ANSI_E] = KeyCode_E; + keycode_lookup_table[kVK_ANSI_F] = KeyCode_F; + keycode_lookup_table[kVK_ANSI_G] = KeyCode_G; + keycode_lookup_table[kVK_ANSI_H] = KeyCode_H; + keycode_lookup_table[kVK_ANSI_I] = KeyCode_I; + keycode_lookup_table[kVK_ANSI_J] = KeyCode_J; + keycode_lookup_table[kVK_ANSI_K] = KeyCode_K; + keycode_lookup_table[kVK_ANSI_L] = KeyCode_L; + keycode_lookup_table[kVK_ANSI_M] = KeyCode_M; + keycode_lookup_table[kVK_ANSI_N] = KeyCode_N; + keycode_lookup_table[kVK_ANSI_O] = KeyCode_O; + keycode_lookup_table[kVK_ANSI_P] = KeyCode_P; + keycode_lookup_table[kVK_ANSI_Q] = KeyCode_Q; + keycode_lookup_table[kVK_ANSI_R] = KeyCode_R; + keycode_lookup_table[kVK_ANSI_S] = KeyCode_S; + keycode_lookup_table[kVK_ANSI_T] = KeyCode_T; + keycode_lookup_table[kVK_ANSI_U] = KeyCode_U; + keycode_lookup_table[kVK_ANSI_V] = KeyCode_V; + keycode_lookup_table[kVK_ANSI_W] = KeyCode_W; + keycode_lookup_table[kVK_ANSI_X] = KeyCode_X; + keycode_lookup_table[kVK_ANSI_Y] = KeyCode_Y; + keycode_lookup_table[kVK_ANSI_Z] = KeyCode_Z; + + keycode_lookup_table[kVK_ANSI_0] = KeyCode_0; + keycode_lookup_table[kVK_ANSI_1] = KeyCode_1; + keycode_lookup_table[kVK_ANSI_2] = KeyCode_2; + keycode_lookup_table[kVK_ANSI_3] = KeyCode_3; + keycode_lookup_table[kVK_ANSI_4] = KeyCode_4; + keycode_lookup_table[kVK_ANSI_5] = KeyCode_5; + keycode_lookup_table[kVK_ANSI_6] = KeyCode_6; + keycode_lookup_table[kVK_ANSI_7] = KeyCode_7; + keycode_lookup_table[kVK_ANSI_8] = KeyCode_8; + keycode_lookup_table[kVK_ANSI_9] = KeyCode_9; + + keycode_lookup_table[kVK_Space] = KeyCode_Space; + keycode_lookup_table[kVK_ANSI_Grave] = KeyCode_Tick; + keycode_lookup_table[kVK_ANSI_Minus] = KeyCode_Minus; + keycode_lookup_table[kVK_ANSI_Equal] = KeyCode_Equal; + keycode_lookup_table[kVK_ANSI_LeftBracket] = KeyCode_LeftBracket; + keycode_lookup_table[kVK_ANSI_RightBracket] = KeyCode_RightBracket; + keycode_lookup_table[kVK_ANSI_Semicolon] = KeyCode_Semicolon; + keycode_lookup_table[kVK_ANSI_Quote] = KeyCode_Quote; + keycode_lookup_table[kVK_ANSI_Comma] = KeyCode_Comma; + keycode_lookup_table[kVK_ANSI_Period] = KeyCode_Period; + keycode_lookup_table[kVK_ANSI_Slash] = KeyCode_ForwardSlash; + keycode_lookup_table[kVK_ANSI_Backslash] = KeyCode_BackwardSlash; + + keycode_lookup_table[kVK_Tab] = KeyCode_Tab; + // NOTE(yuval): No Pause key on macOS! + keycode_lookup_table[kVK_Escape] = KeyCode_Escape; + + keycode_lookup_table[kVK_UpArrow] = KeyCode_Up; + keycode_lookup_table[kVK_DownArrow] = KeyCode_Down; + keycode_lookup_table[kVK_LeftArrow] = KeyCode_Left; + keycode_lookup_table[kVK_RightArrow] = KeyCode_Right; + + keycode_lookup_table[kVK_Delete] = KeyCode_Backspace; + keycode_lookup_table[kVK_Return] = KeyCode_Return; + + keycode_lookup_table[kVK_ForwardDelete] = KeyCode_Delete; + //keycode_lookup_table[] = KeyCode_Insert; // TODO(yuval): Figure how to get keyDown events for the insert key + keycode_lookup_table[kVK_Home] = KeyCode_Home; + keycode_lookup_table[kVK_End] = KeyCode_End; + keycode_lookup_table[kVK_PageUp] = KeyCode_PageUp; + keycode_lookup_table[kVK_PageDown] = KeyCode_PageDown; + + keycode_lookup_table[kVK_CapsLock] = KeyCode_CapsLock; + keycode_lookup_table[kVK_ANSI_KeypadClear] = KeyCode_NumLock; + // NOTE(yuval): No Scroll Lock key on macOS! + keycode_lookup_table[kVK_Menu] = KeyCode_Menu; + + keycode_lookup_table[kVK_Shift] = KeyCode_Shift; + keycode_lookup_table[kVK_RightShift] = KeyCode_Shift; + + keycode_lookup_table[kVK_Control] = KeyCode_Control; + keycode_lookup_table[kVK_RightControl] = KeyCode_Control; + + keycode_lookup_table[kVK_Option] = KeyCode_Alt; + keycode_lookup_table[kVK_RightOption] = KeyCode_Alt; + + keycode_lookup_table[kVK_Command] = KeyCode_Command; + keycode_lookup_table[kVK_RightCommand] = KeyCode_Command; // NOTE(yuval): Right Command + + keycode_lookup_table[kVK_F1] = KeyCode_F1; + keycode_lookup_table[kVK_F2] = KeyCode_F2; + keycode_lookup_table[kVK_F3] = KeyCode_F3; + keycode_lookup_table[kVK_F4] = KeyCode_F4; + keycode_lookup_table[kVK_F5] = KeyCode_F5; + keycode_lookup_table[kVK_F6] = KeyCode_F6; + keycode_lookup_table[kVK_F7] = KeyCode_F7; + keycode_lookup_table[kVK_F8] = KeyCode_F8; + keycode_lookup_table[kVK_F9] = KeyCode_F9; + + keycode_lookup_table[kVK_F10] = KeyCode_F10; + keycode_lookup_table[kVK_F11] = KeyCode_F11; + keycode_lookup_table[kVK_F12] = KeyCode_F12; + keycode_lookup_table[kVK_F13] = KeyCode_F13; + keycode_lookup_table[kVK_F14] = KeyCode_F14; + keycode_lookup_table[kVK_F15] = KeyCode_F15; + keycode_lookup_table[kVK_F16] = KeyCode_F16; +} + +//////////////////////////////// + +function b32 +mac_file_can_be_made(u8* filename){ + b32 result = access((char*)filename, W_OK) == 0; + return(result); +} + +//////////////////////////////// + +function void +mac_resize(float width, float height){ + if ((width > 0.0f) && (height > 0.0f)){ +#if 1 + NSSize coord_size = NSMakeSize(width, height); + NSSize backing_size = [mac_vars.view convertSizeToBacking:coord_size]; + + mac_vars.width = (i32)backing_size.width; + mac_vars.height = (i32)backing_size.height; + + target.width = (i32)backing_size.width; + target.height = (i32)backing_size.height; +#else + mac_vars.width = (i32)width; + mac_vars.height = (i32)height; + + target.width = (i32)width; + target.height = (i32)height; +#endif + } + + system_signal_step(0); +} + +function inline void +mac_resize(NSWindow *window){ + NSRect bounds = [[window contentView] bounds]; + mac_resize(bounds.size.width, bounds.size.height); +} + +//////////////////////////////// + +function u32 +mac_get_clipboard_change_count(void){ + NSPasteboard *board = [NSPasteboard generalPasteboard]; + u32 result = board.changeCount; + + return(result); +} + +function b32 +mac_read_clipboard_contents(Arena *scratch){ + b32 result = false; + + Temp_Memory temp = begin_temp(scratch); + { + NSPasteboard *board = [NSPasteboard generalPasteboard]; + NSString *utf8_type = @"public.utf8-plain-text"; + NSArray *types_array = [NSArray arrayWithObjects:utf8_type, nil]; + NSString *has_string = [board availableTypeFromArray:types_array]; + if (has_string != nil){ + NSData *data = [board dataForType:utf8_type]; + if (data != nil){ + u32 copy_length = data.length; + if (copy_length > 0){ + Arena *clip_arena = mac_vars.clipboard_arena; + linalloc_clear(clip_arena); + + mac_vars.clipboard_contents = string_const_u8_push(clip_arena, copy_length); + [data getBytes:mac_vars.clipboard_contents.str + length:mac_vars.clipboard_contents.size]; + + result = true; + } + } + } + } + end_temp(temp); + + return(result); +} + +function void +mac_post_clipboard(Arena *scratch, char *text, i32 len){ + NSPasteboard *board = [NSPasteboard generalPasteboard]; + + NSString *utf8_type = @"public.utf8-plain-text"; + NSArray *types_array = [NSArray arrayWithObjects:utf8_type, nil]; + [board declareTypes:types_array + owner:nil]; + + NSString *paste_string = [[NSString alloc] initWithBytes:text + length:len + encoding:NSUTF8StringEncoding]; + [board setString:paste_string + forType:utf8_type]; + [paste_string release]; + + mac_vars.next_clipboard_is_self = true; +} + +//////////////////////////////// + +function void +mac_toggle_fullscreen(void){ + [mac_vars.window toggleFullScreen:nil]; +} + +//////////////////////////////// + +@implementation FCoder_App_Delegate +- (void)applicationDidFinishLaunching:(id)sender{ +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender{ + return(YES); +} + +- (void)applicationWillTerminate:(NSNotification*)notification{ +} +@end + +@implementation FCoder_Window_Delegate +- (BOOL)windowShouldClose:(id)sender{ + mac_vars.input_chunk.trans.trying_to_kill = true; + system_signal_step(0); + + return(NO); +} + +- (void)windowDidResize:(NSNotification*)notification{ + mac_resize(mac_vars.window); +} + +- (void)windowDidMiniaturize:(NSNotification*)notification{ +} + +- (void)windowDidDeminiaturize:(NSNotification*)notification{ +} + +- (void)windowDidBecomeKey:(NSNotification *)notification{ + // NOTE(yuval): The window is the focused window + [self process_focus_event]; +} + +- (void)windowDidResignKey:(NSNotification *)notification{ + // NOTE(yuval): The window has lost focus + [self process_focus_event]; +} + +- (void)process_focus_event{ + mac_vars.input_chunk.pers.mouse_l = false; + mac_vars.input_chunk.pers.mouse_r = false; + block_zero_struct(&mac_vars.input_chunk.pers.controls); + block_zero_struct(&mac_vars.input_chunk.pers.modifiers); + mac_vars.active_key_stroke = 0; + mac_vars.active_text_input = 0; + + system_signal_step(0); +} +@end + +@implementation FCoder_View +- (id)init{ + self = [super init]; + return(self); +} + +- (void)dealloc{ + [super dealloc]; +} + +- (void)viewDidChangeBackingProperties{ + // TODO(yuval): If the screen scale factor changed, modify the current face to use the new screen scale factor. + mac_resize(mac_vars.window); +} + +- (BOOL)wantsUpdateLayer +{ + return YES; +} + +- (void)updateLayer{ + u64 prev_timer_start; + + MacProfileScope("Draw Rect"){ + mac_vars.step_requested = false; + + MacProfileScope("Acquire Frame Mutex"){ + // NOTE(yuval): Read comment in win32_4ed.cpp's main loop + system_mutex_acquire(mac_vars.global_frame_mutex); + } + + Application_Step_Input input = {}; + + // NOTE(yuval): Prepare the Frame Input + MacProfileScope("Prepare Input"){ + Mac_Input_Chunk input_chunk = mac_vars.input_chunk; + + input.first_step = mac_vars.first; + input.dt = frame_useconds / 1000000.0f; + input.events = input_chunk.trans.event_list; + + input.mouse.out_of_window = input_chunk.trans.out_of_window; + + input.mouse.l = input_chunk.pers.mouse_l; + input.mouse.press_l = input_chunk.trans.mouse_l_press; + input.mouse.release_l = input_chunk.trans.mouse_l_release; + + input.mouse.r = input_chunk.pers.mouse_r; + input.mouse.press_r = input_chunk.trans.mouse_r_press; + input.mouse.release_r = input_chunk.trans.mouse_r_release; + + input.mouse.wheel = input_chunk.trans.mouse_wheel; + input.mouse.p = input_chunk.pers.mouse; + + input.trying_to_kill = input_chunk.trans.trying_to_kill; + + block_zero_struct(&mac_vars.input_chunk.trans); + mac_vars.active_key_stroke = 0; + mac_vars.active_text_input = 0; + + // NOTE(yuval): See comment in win32_4ed.cpp's main loop + if (mac_vars.send_exit_signal){ + input.trying_to_kill = true; + mac_vars.send_exit_signal = false; + } + } + + // NOTE(yuval): Frame clipboard input + MacProfileScope("Frame Clipboard Input"){ + block_zero_struct(&mac_vars.clipboard_contents); + input.clipboard_changed = false; + + if (mac_vars.clipboard_change_count != 0){ + u32 change_count = mac_get_clipboard_change_count(); + if (change_count != mac_vars.clipboard_change_count){ + if (mac_vars.next_clipboard_is_self){ + mac_vars.next_clipboard_is_self = false; + } else{ + for (i32 r = 0; r < 4; ++r){ + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + + if (mac_read_clipboard_contents(scratch)){ + input.clipboard_changed = true; + break; + } + } + } + + mac_vars.clipboard_change_count = change_count; + } + } + + input.clipboard = mac_vars.clipboard_contents; + } + + mac_vars.clip_post.size = 0; + + // NOTE(yuval): Application Core Update + Application_Step_Result result = {}; + MacProfileScope("Step"){ + if (app.step != 0){ + result = app.step(mac_vars.tctx, &target, mac_vars.base_ptr, &input); + } + } + + // NOTE(yuval): Quit the app if requested by the application core + MacProfileScope("Perform Kill"){ + if (result.perform_kill){ + [NSApp terminate:nil]; + } + } + + // NOTE(yuval): Post new clipboard content + MacProfileScope("Post Clipboard"){ + if (mac_vars.clip_post.size > 0){ + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + mac_post_clipboard(scratch, (char*)mac_vars.clip_post.str, (i32)mac_vars.clip_post.size); + } + } + + // NOTE(yuval): Switch to a new title + MacProfileScope("Switch Title"){ + if (result.has_new_title){ + NSString *str = [NSString stringWithUTF8String:result.title_string]; + [mac_vars.window setTitle:str]; + } + } + + // NOTE(yuval): Switch to new cursor + MacProfileScope("Switch Cursor"){ + // NOTE(yuval): Switch cursor type + switch (result.mouse_cursor_type){ + case APP_MOUSE_CURSOR_ARROW: + { + [mac_vars.cursor_arrow set]; + } break; + + case APP_MOUSE_CURSOR_IBEAM: + { + [mac_vars.cursor_ibeam set]; + } break; + + case APP_MOUSE_CURSOR_LEFTRIGHT: + { + [mac_vars.cursor_leftright set]; + } break; + + case APP_MOUSE_CURSOR_UPDOWN: + { + [mac_vars.cursor_updown set]; + } break; + } + + // NOTE(yuval): Show or hide cursor + if (mac_vars.cursor_show != mac_vars.prev_cursor_show){ + switch (mac_vars.cursor_show){ + case MouseCursorShow_Never: + { + [NSCursor hide]; + } break; + + case MouseCursorShow_Always: + { + [NSCursor unhide]; + } break; + } + + mac_vars.prev_cursor_show = mac_vars.cursor_show; + } + } + + // NOTE(yuval): Update lctrl_lalt_is_altgr status + mac_vars.lctrl_lalt_is_altgr = (b8)result.lctrl_lalt_is_altgr; + + // NOTE(yuval): Render + MacProfileScope("Render"){ + renderer->render(renderer, &target); + } + + // NOTE(yuval): Toggle full screen + MacProfileScope("Toggle Full Screen"){ + if (mac_vars.do_toggle){ + mac_toggle_fullscreen(); + mac_vars.do_toggle = false; + } + } + + // NOTE(yuval): Schedule another step if needed + MacProfileScope("Schedule Step"){ + if (result.animating || (mac_vars.running_cli > 0)){ + system_signal_step(0); + } + } + + // NOTE(yuval): Sleep a bit to cool off + MacProfileScope("Cool Down"){ + system_mutex_release(mac_vars.global_frame_mutex); + { + u64 timer_end = system_now_time(); + u64 end_target = (mac_vars.timer_start + frame_useconds); + + if (timer_end < end_target){ + if ((end_target - timer_end) > 1000){ + // NOTE(yuval): Sleep until the end target minus a millisecond (to allow the scheduler to wake the process in time) + system_sleep(end_target - timer_end - 1000); + } + + // NOTE(yuval): Iterate through the rest of the time that's left using a regular for loop to make sure that we hit the end target + u64 now = system_now_time(); + while (now < end_target){ + now = system_now_time(); + } + } + + prev_timer_start = mac_vars.timer_start; + mac_vars.timer_start = system_now_time(); + } + system_mutex_acquire(mac_vars.global_frame_mutex); + } + + MacProfileScope("Cleanup"){ + mac_vars.first = false; + + linalloc_clear(mac_vars.frame_arena); + + // NOTE(yuval): Release the global frame mutex until the next drawRect call + system_mutex_release(mac_vars.global_frame_mutex); + } + } + + mac_profile("Frame", prev_timer_start, mac_vars.timer_start); +#if FRED_INTERNAL + printf("\n"); +#endif +} + +- (BOOL)acceptsFirstResponder{ + return(YES); +} + +- (BOOL)becomeFirstResponder{ + return(YES); +} + +- (BOOL)resignFirstResponder{ + return(YES); +} + +- (void)keyDown:(NSEvent*)event{ + // NOTE(yuval): Process keyboard event + [self process_keyboard_event:event down:true]; + + // NOTE(yuval): Process TextInsert event + { + NSString *characters = [event characters]; + if ([characters length] > 0){ + // NOTE(yuval): Get the first utf-16 character + u32 c = [characters characterAtIndex:0]; + if (c == '\r'){ + c = '\n'; + } + + // NOTE(yuval): Check for a valid text input + if ((c > 127) || ((' ' <= c) && (c <= '~')) || (c == '\t') || (c == '\n') || (c == '\r')){ + String_Const_u16 str_16 = SCu16((u16*)&c, 1); + String_Const_u8 str_8 = string_u8_from_string_u16(mac_vars.frame_arena, str_16).string; + + Input_Event *event = push_input_event(mac_vars.frame_arena, &mac_vars.input_chunk.trans.event_list); + event->kind = InputEventKind_TextInsert; + event->text.string = str_8; + event->text.next_text = 0; + event->text.blocked = false; + if (mac_vars.active_text_input){ + mac_vars.active_text_input->text.next_text = event; + } else if (mac_vars.active_key_stroke){ + mac_vars.active_key_stroke->key.first_dependent_text = event; + } + + mac_vars.active_text_input = event; + + system_signal_step(0); + } + } + } +} + +- (void)keyUp:(NSEvent*)event{ + [self process_keyboard_event:event down:false]; +} + +- (void)flagsChanged:(NSEvent *)event{ + NSEventModifierFlags flags = [event modifierFlags]; + b8 ctrl_pressed = ((flags & NSEventModifierFlagControl) != 0); + b8 alt_pressed = ((flags & NSEventModifierFlagOption) != 0); + b8 shift_pressed = ((flags & NSEventModifierFlagShift) != 0); + b8 command_pressed = ((flags & NSEventModifierFlagCommand) != 0); + + Control_Keys *controls = &mac_vars.input_chunk.pers.controls; + u16 event_key_code = [event keyCode]; + if (event_key_code == kVK_Control){ + controls->l_ctrl = ctrl_pressed; + [self process_keyboard_event:event down:ctrl_pressed]; + } else if (event_key_code == kVK_RightControl){ + controls->r_ctrl = ctrl_pressed; + [self process_keyboard_event:event down:ctrl_pressed]; + } else if (event_key_code == kVK_Option){ + controls->l_alt = alt_pressed; + [self process_keyboard_event:event down:alt_pressed]; + } else if (event_key_code == kVK_RightOption){ + controls->r_alt = alt_pressed; + [self process_keyboard_event:event down:alt_pressed]; + } else if (event_key_code == kVK_Shift){ + controls->l_shift = shift_pressed; + [self process_keyboard_event:event down:shift_pressed]; + } else if (event_key_code == kVK_RightShift){ + controls->r_shift = shift_pressed; + [self process_keyboard_event:event down:shift_pressed]; + } else if (event_key_code == kVK_Command){ + controls->l_command = command_pressed; + [self process_keyboard_event:event down:command_pressed]; + } else if (event_key_code == kVK_RightCommand){ + controls->r_command = command_pressed; + [self process_keyboard_event:event down:command_pressed]; + } +} + +- (void)mouseMoved:(NSEvent*)event{ + [self process_mouse_move_event:event]; +} + +- (void)mouseDragged:(NSEvent*)event{ + [self process_mouse_move_event:event]; +} + +- (void)scrollWheel:(NSEvent *)event{ + float dx = event.scrollingDeltaX; + float dy = event.scrollingDeltaY; + + i8 scroll_speed = 100; + if (dy > 0){ + scroll_speed *= -1; + } + mac_vars.input_chunk.trans.mouse_wheel = scroll_speed; + + system_signal_step(0); +} + +- (void)mouseDown:(NSEvent*)event{ + mac_vars.input_chunk.trans.mouse_l_press = true; + mac_vars.input_chunk.pers.mouse_l = true; + + system_signal_step(0); +} + +- (void)mouseUp:(NSEvent*)event{ + mac_vars.input_chunk.trans.mouse_l_release = true; + mac_vars.input_chunk.pers.mouse_l = false; + + system_signal_step(0); +} + +- (void)rightMouseDown:(NSEvent*)event{ + [super rightMouseDown:event]; + + mac_vars.input_chunk.trans.mouse_r_press = true; + mac_vars.input_chunk.pers.mouse_r = true; + + system_signal_step(0); +} + +- (void)rightMouseUp:(NSEvent*)event{ + mac_vars.input_chunk.trans.mouse_r_release = true; + mac_vars.input_chunk.pers.mouse_r = false; + + system_signal_step(0); +} + +- (void)request_display{ + CGRect cg_rect = CGRectMake(0, 0, mac_vars.width, mac_vars.height); + NSRect rect = NSRectFromCGRect(cg_rect); + [self setNeedsDisplayInRect:rect]; +} + +- (void)check_clipboard{ + u32 change_count = mac_get_clipboard_change_count(); + if (change_count != mac_vars.clipboard_change_count){ + system_signal_step(0); + } +} + +- (void)process_keyboard_event:(NSEvent*)event down:(b8)down{ + b8 release = !down; + + Input_Modifier_Set_Fixed *mods = &mac_vars.input_chunk.pers.modifiers; + + // NOTE(yuval): Set control modifiers + { + Control_Keys *controls = &mac_vars.input_chunk.pers.controls; + + b8 ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); + b8 alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); + if (mac_vars.lctrl_lalt_is_altgr && controls->l_alt && controls->l_ctrl){ + ctrl = false; + alt = false; + } + + b8 shift = (controls->r_shift || controls->l_shift); + b8 command = (controls->r_command || controls->l_command); + + set_modifier(mods, KeyCode_Control, ctrl); + set_modifier(mods, KeyCode_Alt, alt); + set_modifier(mods, KeyCode_Shift, shift); + set_modifier(mods, KeyCode_Command, command); + } + + // NOTE(yuval): Process KeyStroke / KeyRelease event + { + u16 event_key_code = [event keyCode]; + Key_Code key = keycode_lookup_table[(u8)event_key_code]; + if (down){ + if (key != 0){ + add_modifier(mods, key); + + Input_Event *event = push_input_event(mac_vars.frame_arena, &mac_vars.input_chunk.trans.event_list); + event->kind = InputEventKind_KeyStroke; + event->key.code = key; + event->key.modifiers = copy_modifier_set(mac_vars.frame_arena, mods); + + mac_vars.active_key_stroke = event; + + system_signal_step(0); + } + } else{ + mac_vars.active_key_stroke = 0; + mac_vars.active_text_input = 0; + + if (key != 0){ + Input_Event *event = push_input_event(mac_vars.frame_arena, &mac_vars.input_chunk.trans.event_list); + event->kind = InputEventKind_KeyRelease; + event->key.code = key; + event->key.modifiers = copy_modifier_set(mac_vars.frame_arena, mods); + + remove_modifier(mods, key); + } + + system_signal_step(0); + } + } +} + +- (void)process_mouse_move_event:(NSEvent*)event{ + NSPoint location = [event locationInWindow]; + NSPoint backing_location = [self convertPointToBacking:location]; + + Vec2_i32 new_m = V2i32(backing_location.x, mac_vars.height - backing_location.y); + if (new_m != mac_vars.input_chunk.pers.mouse){ + mac_vars.input_chunk.pers.mouse = new_m; + + Rect_i32 screen = Ri32(0, 0, target.width, target.height); + mac_vars.input_chunk.trans.out_of_window = !rect_contains_point(screen, new_m); + + } + + system_signal_step(0); +} +@end + +//////////////////////////////// + +int +main(int arg_count, char **args){ + @autoreleasepool{ + // NOTE(yuval): Create NSApplication & Delegate + [NSApplication sharedApplication]; + Assert(NSApp != nil); + + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + FCoder_App_Delegate *app_delegate = [[FCoder_App_Delegate alloc] init]; + [NSApp setDelegate:app_delegate]; + + pthread_mutex_init(&memory_tracker_mutex, 0); + + // NOTE(yuval): Context setup + Thread_Context _tctx = {}; + thread_ctx_init(&_tctx, ThreadKind_Main, + get_base_allocator_system(), + get_base_allocator_system()); + + block_zero_struct(&mac_vars); + mac_vars.tctx = &_tctx; + + API_VTable_system system_vtable = {}; + system_api_fill_vtable(&system_vtable); + + API_VTable_graphics graphics_vtable = {}; + graphics_api_fill_vtable(&graphics_vtable); + + API_VTable_font font_vtable = {}; + font_api_fill_vtable(&font_vtable); + + // NOTE(yuval): Memory + mac_vars.frame_arena = reserve_arena(mac_vars.tctx); + target.arena = make_arena_system(KB(256)); + + dll_init_sentinel(&mac_vars.free_mac_objects); + dll_init_sentinel(&mac_vars.timer_objects); + + pthread_mutex_init(&mac_vars.thread_launch_mutex, 0); + pthread_cond_init(&mac_vars.thread_launch_cv, 0); + + // NOTE(yuval): Screen scale factor calculation + { + NSScreen* screen = [NSScreen mainScreen]; + NSDictionary* desc = [screen deviceDescription]; + NSSize size = [[desc valueForKey:NSDeviceResolution] sizeValue]; + f32 max_dpi = Max(size.width, size.height); + mac_vars.screen_scale_factor = (max_dpi / 72.0f); + } + + // NOTE(yuval): Load core + System_Library core_library = {}; + { + App_Get_Functions *get_funcs = 0; + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + Path_Search_List search_list = {}; + search_list_add_system_path(scratch, &search_list, SystemPath_Binary); + + String_Const_u8 core_path = get_full_path(scratch, &search_list, SCu8("4ed_app.so")); + if (system_load_library(scratch, core_path, &core_library)){ + get_funcs = (App_Get_Functions*)system_get_proc(core_library, "app_get_functions"); + if (get_funcs != 0){ + app = get_funcs(); + } + else{ + char msg[] = "Failed to get application code from '4ed_app.so'."; + mac_error_box(msg); + } + } + else{ + char msg[] = "Could not load '4ed_app.so'. This file should be in the same directory as the main '4ed' executable."; + mac_error_box(msg); + } + } + + // NOTE(yuval): Send api vtables to core + app.load_vtables(&system_vtable, &font_vtable, &graphics_vtable); + mac_vars.log_string = app.get_logger(); + + // NOTE(yuval): Init & command line parameters + Plat_Settings plat_settings = {}; + mac_vars.base_ptr = 0; + { + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + String_Const_u8 curdir = system_get_path(scratch, SystemPath_CurrentDirectory); + curdir = string_mod_replace_character(curdir, '\\', '/'); + char **files = 0; + i32 *file_count = 0; + mac_vars.base_ptr = app.read_command_line(mac_vars.tctx, curdir, &plat_settings, &files, &file_count, arg_count, args); + { + i32 end = *file_count; + i32 i = 0, j = 0; + for (; i < end; ++i){ + if (mac_file_can_be_made((u8*)files[i])){ + files[j] = files[i]; + ++j; + } + } + *file_count = j; + } + } + + // NOTE(yuval): Load custom layer + System_Library custom_library = {}; + Custom_API custom = {}; + { + char custom_not_found_msg[] = "Did not find a library for the custom layer."; + char custom_fail_version_msg[] = "Failed to load custom code due to missing version information or a version mismatch. Try rebuilding with buildsuper."; + char custom_fail_init_apis[] = "Failed to load custom code due to missing 'init_apis' symbol. Try rebuilding with buildsuper"; + + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + String_Const_u8 default_file_name = string_u8_litexpr("custom_4coder.so"); + Path_Search_List search_list = {}; + search_list_add_system_path(scratch, &search_list, SystemPath_CurrentDirectory); + search_list_add_system_path(scratch, &search_list, SystemPath_Binary); + String_Const_u8 custom_file_names[2] = {}; + i32 custom_file_count = 1; + if (plat_settings.custom_dll != 0){ + custom_file_names[0] = SCu8(plat_settings.custom_dll); + if (!plat_settings.custom_dll_is_strict){ + custom_file_names[1] = default_file_name; + custom_file_count += 1; + } + } + else{ + custom_file_names[0] = default_file_name; + } + String_Const_u8 custom_file_name = {}; + for (i32 i = 0; i < custom_file_count; i += 1){ + custom_file_name = get_full_path(scratch, &search_list, custom_file_names[i]); + if (custom_file_name.size > 0){ + break; + } + } + b32 has_library = false; + if (custom_file_name.size > 0){ + if (system_load_library(scratch, custom_file_name, &custom_library)){ + has_library = true; + } + } + + if (!has_library){ + mac_error_box(custom_not_found_msg); + } + custom.get_version = (_Get_Version_Type*)system_get_proc(custom_library, "get_version"); + if (custom.get_version == 0 || custom.get_version(MAJOR, MINOR, PATCH) == 0){ + mac_error_box(custom_fail_version_msg); + } + custom.init_apis = (_Init_APIs_Type*)system_get_proc(custom_library, "init_apis"); + if (custom.init_apis == 0){ + mac_error_box(custom_fail_init_apis); + } + } + + // + // Window and Renderer Initialization + // + + // NOTE(yuval): Create Window & Window Delegate + i32 w; + i32 h; + if (plat_settings.set_window_size){ + w = plat_settings.window_w; + h = plat_settings.window_h; + } else{ + w = 800; + h = 600; + } + + NSRect screen_rect = [[NSScreen mainScreen] frame]; + NSRect initial_frame = NSMakeRect((f32)(screen_rect.size.width - w) * 0.5f, (f32)(screen_rect.size.height - h) * 0.5f, w, h); + + u32 style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; + + mac_vars.window = [[NSWindow alloc] initWithContentRect:initial_frame + styleMask:style_mask + backing:NSBackingStoreBuffered + defer:NO]; + + FCoder_Window_Delegate *window_delegate = [[FCoder_Window_Delegate alloc] init]; + [mac_vars.window setDelegate:window_delegate]; + + [mac_vars.window setMinSize:NSMakeSize(100, 100)]; + [mac_vars.window setBackgroundColor:NSColor.blackColor]; + [mac_vars.window setTitle:@"GRAPHICS"]; + [mac_vars.window setAcceptsMouseMovedEvents:YES]; + + NSView* content_view = [mac_vars.window contentView]; + + // NOTE(yuval): Create the 4coder view + mac_vars.view = [[FCoder_View alloc] init]; + [mac_vars.view setFrame:[content_view bounds]]; + [mac_vars.view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + mac_vars.view.wantsLayer = true; + + // NOTE(yuval): Display window and view + [content_view addSubview:mac_vars.view]; + [mac_vars.window makeKeyAndOrderFront:nil]; + + // NOTE(yuval): Initialize the renderer + renderer = mac_init_renderer(MacRenderer_Metal, mac_vars.window, &target); + + mac_resize(w, h); + + // + // NOTE(yuval): Misc System Initializations + // + + // NOTE(yuval): Initialize clipboard + { + mac_vars.clipboard_arena = reserve_arena(mac_vars.tctx); + mac_vars.clipboard_change_count = mac_get_clipboard_change_count(); + mac_vars.next_clipboard_is_self = false; + + // NOTE(yuval): Read the current clipboard + { + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + mac_read_clipboard_contents(scratch); + } + + // NOTE(yuval): Start the clipboard polling timer + [NSTimer scheduledTimerWithTimeInterval: 0.5 + target:mac_vars.view + selector:@selector(check_clipboard) + userInfo:nil repeats:YES]; + } + + // NOTE(yuval): Initialize the virtul keycodes table + mac_keycode_init(); + + // NOTE(yuval): Initialize cursors + { + mac_vars.cursor_show = MouseCursorShow_Always; + mac_vars.prev_cursor_show = MouseCursorShow_Always; + + mac_vars.cursor_arrow = [NSCursor arrowCursor]; + mac_vars.cursor_ibeam = [NSCursor IBeamCursor]; + mac_vars.cursor_leftright = [NSCursor resizeLeftRightCursor]; + mac_vars.cursor_updown = [NSCursor resizeUpDownCursor]; + } + + // NOTE(yuval): Get the timebase info + mach_timebase_info(&mac_vars.timebase_info); + + // + // App init + // + + { + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + String_Const_u8 curdir = system_get_path(scratch, SystemPath_CurrentDirectory); + curdir = string_mod_replace_character(curdir, '\\', '/'); + app.init(mac_vars.tctx, &target, mac_vars.base_ptr, mac_vars.clipboard_contents, curdir, custom); + } + + // + // Start Main Loop + // + + mac_vars.first = true; + mac_vars.step_requested = false; + mac_vars.running_cli = 0; + + if (plat_settings.fullscreen_window){ + mac_toggle_fullscreen(); + } + + mac_vars.global_frame_mutex = system_mutex_make(); + + mac_vars.timer_start = system_now_time(); + + // NOTE(yuval): Start the app's run loop + [NSApp run]; + } +} \ No newline at end of file diff --git a/platform_mac/mac_4ed_functions.mm b/platform_mac/mac_4ed_functions.mm new file mode 100644 index 00000000..85a6c0f4 --- /dev/null +++ b/platform_mac/mac_4ed_functions.mm @@ -0,0 +1,927 @@ +/* macOS System/Graphics/Font API Implementations */ + +/********************/ +/* System API */ +/********************/ + +//////////////////////////////// + +function +system_get_path_sig(){ + String_Const_u8 result = {}; + + switch (path_code){ + case SystemPath_CurrentDirectory: + { + char *working_dir = getcwd(NULL, 0); + u64 working_dir_length = cstring_length(working_dir); + + // TODO(yuval): Maybe use push_string_copy instead + u8 *out = push_array(arena, u8, working_dir_length); + block_copy(out, working_dir, working_dir_length); + + free(working_dir); + + result = SCu8(out, working_dir_length); + } break; + + case SystemPath_Binary: + { + local_persist b32 has_stashed_4ed_path = false; + if (!has_stashed_4ed_path){ + local_const i32 binary_path_capacity = KB(32); + u8 *memory = (u8*)system_memory_allocate(binary_path_capacity, file_name_line_number_lit_u8); + + pid_t pid = getpid(); + i32 size = proc_pidpath(pid, memory, binary_path_capacity); + Assert(size <= binary_path_capacity - 1); + + mac_vars.binary_path = SCu8(memory, size); + mac_vars.binary_path = string_remove_last_folder(mac_vars.binary_path); + mac_vars.binary_path.str[mac_vars.binary_path.size] = 0; + + has_stashed_4ed_path = true; + } + + result = push_string_copy(arena, mac_vars.binary_path); + } break; + } + + return(result); +} + +function +system_get_canonical_sig(){ + NSString *path_ns_str = + [[NSString alloc] initWithBytes:name.data length:name.size encoding:NSUTF8StringEncoding]; + + NSString *standardized_path_ns_str = [path_ns_str stringByStandardizingPath]; + String_Const_u8 standardized_path = SCu8((u8*)[standardized_path_ns_str UTF8String],[standardized_path_ns_str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); + + String_Const_u8 result = push_string_copy(arena, standardized_path); + + [path_ns_str release]; + + return(result); +} + +//////////////////////////////// + +function File_Attributes +mac_get_file_attributes(struct stat file_stat) { + File_Attributes result; + result.size = file_stat.st_size; + result.last_write_time = file_stat.st_mtimespec.tv_sec; + + result.flags = 0; + if (S_ISDIR(file_stat.st_mode)) { + result.flags |= FileAttribute_IsDirectory; + } + + return(result); +} + +function inline File_Attributes +mac_file_attributes_from_path(char *path) { + File_Attributes result = {}; + + struct stat file_stat; + if (stat(path, &file_stat) == 0){ + result = mac_get_file_attributes(file_stat); + } + + return(result); +} + +function inline File_Attributes +mac_file_attributes_from_fd(i32 fd) { + File_Attributes result = {}; + + struct stat file_stat; + if (fstat(fd, &file_stat) == 0){ + result = mac_get_file_attributes(file_stat); + } + + return(result); +} + +function +system_get_file_list_sig(){ + File_List result = {}; + + u8 *c_directory = push_array(arena, u8, directory.size + 1); + block_copy(c_directory, directory.str, directory.size); + c_directory[directory.size] = 0; + + DIR *dir = opendir((char*)c_directory); + if (dir){ + File_Info* first = 0; + File_Info* last = 0; + i32 count = 0; + + for (struct dirent *entry = readdir(dir); + entry; + entry = readdir(dir)){ + char *c_file_name = entry->d_name; + String_Const_u8 file_name = SCu8(c_file_name); + + if (string_match(file_name, string_u8_litexpr(".")) || string_match(file_name, string_u8_litexpr(".."))){ + continue; + } + + File_Info *info = push_array(arena, File_Info, 1); + sll_queue_push(first, last, info); + count += 1; + + info->file_name = push_string_copy(arena, file_name); + + // NOTE(yuval): Get file attributes + { + Temp_Memory temp = begin_temp(arena); + + b32 append_slash = false; + u64 file_path_size = directory.size + file_name.size; + if (string_get_character(directory, directory.size - 1) != '/'){ + append_slash = true; + file_path_size += 1; + } + + char *file_path = push_array(arena, char, file_path_size + 1); + char *file_path_at = file_path; + + block_copy(file_path_at, directory.str, directory.size); + file_path_at += directory.size; + + if (append_slash){ + *file_path_at = '/'; + file_path_at += 1; + } + + block_copy(file_path_at, file_name.str, file_name.size); + file_path_at += file_name.size; + + *file_path_at = 0; + + info->attributes = mac_file_attributes_from_path(file_path); + + end_temp(temp); + } + } + + closedir(dir); + + result.infos = push_array(arena, File_Info*, count); + result.count = count; + + i32 index = 0; + for (File_Info *node = first; + node != 0; + node = node->next){ + result.infos[index] = node; + index += 1; + } + } + + return(result); +} + +function +system_quick_file_attributes_sig(){ + Temp_Memory temp = begin_temp(scratch); + + char *c_file_name = push_array(scratch, char, file_name.size + 1); + block_copy(c_file_name, file_name.str, file_name.size); + c_file_name[file_name.size] = 0; + + File_Attributes result = mac_file_attributes_from_path(c_file_name); + + end_temp(temp); + + return(result); +} + +function inline Plat_Handle +mac_to_plat_handle(i32 fd){ + Plat_Handle result = *(Plat_Handle*)(&fd); + return(result); +} + +function inline i32 +mac_to_fd(Plat_Handle handle){ + i32 result = *(i32*)(&handle); + return(result); +} + +function +system_load_handle_sig(){ + b32 result = false; + + i32 fd = open(file_name, O_RDONLY); + if ((fd != -1) && (fd != 0)) { + *out = mac_to_plat_handle(fd); + result = true; + } + + return(result); +} + +function +system_load_attributes_sig(){ + i32 fd = mac_to_fd(handle); + File_Attributes result = mac_file_attributes_from_fd(fd); + + return(result); +} + +function +system_load_file_sig(){ + i32 fd = mac_to_fd(handle); + + do{ + ssize_t bytes_read = read(fd, buffer, size); + if (bytes_read == -1){ + if (errno != EINTR){ + // NOTE(yuval): An error occured while reading from the file descriptor + break; + } + } else{ + size -= bytes_read; + buffer += bytes_read; + } + } while (size > 0); + + b32 result = (size == 0); + return(result); +} + +function +system_load_close_sig(){ + b32 result = true; + + i32 fd = mac_to_fd(handle); + if (close(fd) == -1){ + // NOTE(yuval): An error occured while close the file descriptor + result = false; + } + + return(result); +} + +function +system_save_file_sig(){ + File_Attributes result = {}; + + i32 fd = open(file_name, O_WRONLY | O_TRUNC | O_CREAT, 00640); + if (fd != -1) { + do{ + ssize_t bytes_written = write(fd, data.str, data.size); + if (bytes_written == -1){ + if (errno != EINTR){ + // NOTE(yuval): An error occured while writing to the file descriptor + break; + } + } else{ + data.size -= bytes_written; + data.str += bytes_written; + } + } while (data.size > 0); + + if (data.size == 0) { + result = mac_file_attributes_from_fd(fd); + } + + close(fd); + } + + return(result); +} + +//////////////////////////////// + +function inline System_Library +mac_to_system_library(void *dl_handle){ + System_Library result = *(System_Library*)(&dl_handle); + return(result); +} + +function inline void* +mac_to_dl_handle(System_Library system_lib){ + void *result = *(void**)(&system_lib); + return(result); +} + +function +system_load_library_sig(){ + b32 result = false; + + void *lib = 0; + + // NOTE(yuval): Open library handle + { + Temp_Memory temp = begin_temp(scratch); + + char *c_file_name = push_array(scratch, char, file_name.size + 1); + block_copy(c_file_name, file_name.str, file_name.size); + c_file_name[file_name.size] = 0; + + lib = dlopen(c_file_name, RTLD_LAZY | RTLD_GLOBAL); + + end_temp(temp); + } + + if (lib){ + *out = mac_to_system_library(lib); + result = true; + } + + return(result); +} + +function +system_release_library_sig(){ + void *lib = mac_to_dl_handle(handle); + i32 rc = dlclose(lib); + + b32 result = (rc == 0); + return(result); +} + +function +system_get_proc_sig(){ + void *lib = mac_to_dl_handle(handle); + Void_Func *result = (Void_Func*)dlsym(lib, proc_name); + + return(result); +} + +//////////////////////////////// + +function +system_now_time_sig(){ + u64 now = mach_absolute_time(); + + // NOTE(yuval): Now time nanoseconds conversion + f64 now_nano = (f64)((f64)now * + ((f64)mac_vars.timebase_info.numer / + (f64)mac_vars.timebase_info.denom)); + + // NOTE(yuval): Conversion to useconds + u64 result = (u64)(now_nano * 1.0E-3); + return(result); +} + +function +system_wake_up_timer_create_sig(){ + Mac_Object *object = mac_alloc_object(MacObjectKind_Timer); + dll_insert(&mac_vars.timer_objects, &object->node); + + object->timer = nil; + + Plat_Handle result = mac_to_plat_handle(object); + return(result); +} + +function +system_wake_up_timer_release_sig(){ + Mac_Object *object = mac_to_object(handle); + if (object->kind == MacObjectKind_Timer){ + if ((object->timer != nil) && [object->timer isValid]) { + [object->timer invalidate]; + mac_free_object(object); + } + } +} + +function +system_wake_up_timer_set_sig(){ + Mac_Object *object = mac_to_object(handle); + if (object->kind == MacObjectKind_Timer){ + f64 time_seconds = ((f64)time_milliseconds / 1000.0); + object->timer = [NSTimer scheduledTimerWithTimeInterval:time_seconds + target:mac_vars.view + selector:@selector(request_display) + userInfo:nil repeats:NO]; + } +} + +function +system_signal_step_sig(){ + if (!mac_vars.step_requested){ + [NSTimer scheduledTimerWithTimeInterval:0.0 + target:mac_vars.view + selector:@selector(request_display) + userInfo:nil repeats:NO]; + + mac_vars.step_requested = true; + } +} + +function +system_sleep_sig(){ + u64 nanoseconds = (microseconds * Thousand(1)); + u64 abs_sleep_time = (u64)((f64)nanoseconds * + ((f64)mac_vars.timebase_info.denom / + (f64)mac_vars.timebase_info.numer)); + + u64 now = mach_absolute_time(); + mach_wait_until(now + abs_sleep_time); +} + +//////////////////////////////// + +function +system_post_clipboard_sig(){ + Arena *arena = &mac_vars.clip_post_arena; + if (arena->base_allocator == 0){ + *arena = make_arena_system(); + } else{ + linalloc_clear(arena); + } + + mac_vars.clip_post.str = push_array(arena, u8, str.size + 1); + if (mac_vars.clip_post.str != 0){ + block_copy(mac_vars.clip_post.str, str.str, str.size); + mac_vars.clip_post.str[str.size] = 0; + mac_vars.clip_post.size = str.size; + } else{ + // NOTE(yuval): Failed to allocate buffer for clipboard post + } +} + +//////////////////////////////// + +function +system_cli_call_sig(){ + b32 result = false; + + int pipe_fds[2]; + if (pipe(pipe_fds) == -1){ + perror("system_cli_call: pipe"); + return(false); + } + + pid_t child_pid = fork(); + if (child_pid == -1){ + perror("system_cli_call: fork"); + return(false); + } + + enum { PIPE_FD_READ, PIPE_FD_WRITE }; + + if (child_pid == 0){ + // NOTE(yuval): Child Process + close(pipe_fds[PIPE_FD_READ]); + dup2(pipe_fds[PIPE_FD_WRITE], STDOUT_FILENO); + dup2(pipe_fds[PIPE_FD_WRITE], STDERR_FILENO); + + if (chdir(path) == -1){ + perror("system_cli_call: chdir"); + exit(1); + } + + char* argv[] = {"sh", "-c", script, 0}; + + if (execv("/bin/sh", argv) == -1){ + perror("system_cli_call: execv"); + } + + exit(1); + } else{ + // NOTE(yuval): Parent Process + close(pipe_fds[PIPE_FD_WRITE]); + + *(pid_t*)&cli_out->proc = child_pid; + *(int*)&cli_out->out_read = pipe_fds[PIPE_FD_READ]; + *(int*)&cli_out->out_write = pipe_fds[PIPE_FD_WRITE]; + + mac_vars.running_cli += 1; + } + + return(true); +} + +function +system_cli_begin_update_sig(){ + // NOTE(yuval): Nothing to do here. +} + +function +system_cli_update_step_sig(){ + int pipe_read_fd = *(int*)&cli->out_read; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(pipe_read_fd, &fds); + + struct timeval tv = {}; + + size_t space_left = max; + char* ptr = dest; + + while (space_left > 0 && (select(pipe_read_fd + 1, &fds, NULL, NULL, &tv) == 1)){ + ssize_t num = read(pipe_read_fd, ptr, space_left); + if (num == -1){ + perror("system_cli_update_step: read"); + } else if (num == 0){ + // NOTE(inso): EOF + break; + } else{ + ptr += num; + space_left -= num; + } + } + + *amount = (ptr - dest); + + b32 result = ((ptr - dest) > 0); + return(result); +} + +function +system_cli_end_update_sig(){ + b32 close_me = false; + + pid_t pid = *(pid_t*)&cli->proc; + + int status; + if (pid && (waitpid(pid, &status, WNOHANG) > 0)){ + cli->exit = WEXITSTATUS(status); + + close(*(int*)&cli->out_read); + close(*(int*)&cli->out_write); + + mac_vars.running_cli -= 1; + + close_me = true; + } + + return(close_me); +} + +//////////////////////////////// + +function +system_open_color_picker_sig(){ + NotImplemented; +} + +function +system_get_screen_scale_factor_sig(){ + f32 result = mac_vars.screen_scale_factor; + return(result); +} + +//////////////////////////////// + +function void* +mac_thread_wrapper(void *ptr){ + Mac_Object *object = (Mac_Object*)ptr; + Thread_Function *proc = object->thread.proc; + void *object_ptr = object->thread.ptr; + + pthread_mutex_lock(&mac_vars.thread_launch_mutex); + { + mac_vars.waiting_for_launch = false; + pthread_cond_signal(&mac_vars.thread_launch_cv); + } + pthread_mutex_unlock(&mac_vars.thread_launch_mutex); + + proc(object_ptr); + + return(0); +} + +function +system_thread_launch_sig(){ + Mac_Object *object = mac_alloc_object(MacObjectKind_Thread); + object->thread.proc = proc; + object->thread.ptr = ptr; + + pthread_mutex_lock(&mac_vars.thread_launch_mutex); + { + mac_vars.waiting_for_launch = true; + pthread_create(&object->thread.thread, 0, mac_thread_wrapper, object); + + while (mac_vars.waiting_for_launch){ + pthread_cond_wait(&mac_vars.thread_launch_cv, &mac_vars.thread_launch_mutex); + } + } + pthread_mutex_unlock(&mac_vars.thread_launch_mutex); + + System_Thread result = mac_to_plat_handle(object); + return(result); +} + +function +system_thread_join_sig(){ + Mac_Object *object = mac_to_object(thread); + if (object->kind == MacObjectKind_Thread){ + pthread_join(object->thread.thread, 0); + } +} + +function +system_thread_free_sig(){ + Mac_Object* object = mac_to_object(thread); + if (object->kind == MacObjectKind_Thread){ + mac_free_object(object); + } +} + +function +system_thread_get_id_sig(){ + pthread_t id = pthread_self(); + i32 result = *(i32*)(&id); + return(result); +} + +function +system_mutex_make_sig(){ + Mac_Object *object = mac_alloc_object(MacObjectKind_Mutex); + pthread_mutex_init(&object->mutex, 0); + + System_Mutex result = mac_to_plat_handle(object); + return(result); +} + +function +system_mutex_acquire_sig(){ + Mac_Object *object = mac_to_object(mutex); + if (object->kind == MacObjectKind_Mutex){ + pthread_mutex_lock(&object->mutex); + } +} + +function +system_mutex_release_sig(){ + Mac_Object *object = mac_to_object(mutex); + if (object->kind == MacObjectKind_Mutex){ + pthread_mutex_unlock(&object->mutex); + } +} + +function +system_mutex_free_sig(){ + Mac_Object *object = mac_to_object(mutex); + if (object->kind == MacObjectKind_Mutex){ + pthread_mutex_destroy(&object->mutex); + mac_free_object(object); + } +} + +function +system_acquire_global_frame_mutex_sig(){ + if (tctx->kind == ThreadKind_AsyncTasks){ + system_mutex_acquire(mac_vars.global_frame_mutex); + } +} + +function +system_release_global_frame_mutex_sig(){ + if (tctx->kind == ThreadKind_AsyncTasks){ + system_mutex_release(mac_vars.global_frame_mutex); + } +} + +function +system_condition_variable_make_sig(){ + Mac_Object *object = mac_alloc_object(MacObjectKind_CV); + pthread_cond_init(&object->cv, 0); + + System_Condition_Variable result = mac_to_plat_handle(object); + return(result); +} + +function +system_condition_variable_wait_sig(){ + Mac_Object *object_cv = mac_to_object(cv); + Mac_Object *object_mutex = mac_to_object(mutex); + if ((object_cv->kind == MacObjectKind_CV) && (object_mutex->kind == MacObjectKind_Mutex)){ + pthread_cond_wait(&object_cv->cv, &object_mutex->mutex); + } +} + +function +system_condition_variable_signal_sig(){ + Mac_Object *object = mac_to_object(cv); + if (object->kind == MacObjectKind_CV){ + pthread_cond_signal(&object->cv); + } +} + +function +system_condition_variable_free_sig(){ + Mac_Object *object = mac_to_object(cv); + if (object->kind == MacObjectKind_CV){ + pthread_cond_destroy(&object->cv); + mac_free_object(object); + } +} + +//////////////////////////////// + +struct Memory_Annotation_Tracker_Node{ + Memory_Annotation_Tracker_Node *next; + Memory_Annotation_Tracker_Node *prev; + String_Const_u8 location; + u64 size; +}; + +struct Memory_Annotation_Tracker{ + Memory_Annotation_Tracker_Node *first; + Memory_Annotation_Tracker_Node *last; + i32 count; +}; + +global Memory_Annotation_Tracker memory_tracker = {}; +global pthread_mutex_t memory_tracker_mutex; + +global_const u64 ALLOCATION_SIZE_ADJUSTMENT = 64; + +function void* +mac_memory_allocate_extended(void *base, u64 size, String_Const_u8 location){ + u64 adjusted_size = size + ALLOCATION_SIZE_ADJUSTMENT; + void *memory = mmap(base, adjusted_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + Memory_Annotation_Tracker_Node *node = (Memory_Annotation_Tracker_Node*)memory; + + pthread_mutex_lock(&memory_tracker_mutex); + { + zdll_push_back(memory_tracker.first, memory_tracker.last, node); + memory_tracker.count += 1; + } + pthread_mutex_unlock(&memory_tracker_mutex); + + node->location = location; + node->size = size; + + void* result = (node + 1); + return(result); +} + +function void +mac_memory_free_extended(void *ptr){ + Memory_Annotation_Tracker_Node *node = (Memory_Annotation_Tracker_Node*)ptr; + node -= 1; + + pthread_mutex_lock(&memory_tracker_mutex); + { + zdll_remove(memory_tracker.first, memory_tracker.last, node); + memory_tracker.count -= 1; + } + pthread_mutex_unlock(&memory_tracker_mutex); + + munmap(node, node->size + ALLOCATION_SIZE_ADJUSTMENT); +} + +function +system_memory_allocate_sig(){ + void* result = mac_memory_allocate_extended(0, size, location); + return(result); +} + +function +system_memory_set_protection_sig(){ + b32 result = true; + + int protect = 0; + switch (flags & 0x7){ + case 0: + { + protect = PROT_NONE; + } break; + + case MemProtect_Read: + { + protect = PROT_READ; + } break; + + case MemProtect_Write: + case MemProtect_Read | MemProtect_Write: + { + protect = PROT_READ | PROT_WRITE; + } break; + + case MemProtect_Execute: + { + protect = PROT_EXEC; + } break; + + case MemProtect_Execute | MemProtect_Read: + { + protect = PROT_READ | PROT_EXEC; + } break; + + // NOTE(inso): some W^X protection things might be unhappy about this one + case MemProtect_Execute | MemProtect_Write: + case MemProtect_Execute | MemProtect_Write | MemProtect_Read: + { + protect = PROT_READ | PROT_WRITE | PROT_EXEC; + } break; + } + + Memory_Annotation_Tracker_Node *node = (Memory_Annotation_Tracker_Node*)ptr; + node -= 1; + + if(mprotect(node, size, protect) == -1){ + result = false; + } + + return(result); +} + +function +system_memory_free_sig(){ + mac_memory_free_extended(ptr); +} + +function +system_memory_annotation_sig(){ + Memory_Annotation result = {}; + + pthread_mutex_lock(&memory_tracker_mutex); + { + for (Memory_Annotation_Tracker_Node *node = memory_tracker.first; + node != 0; + node = node->next){ + // TODO(yuval): Fix the API so that annotations would not mess with the system memory. + // Memory_Annotation_Node *r_node = push_array(arena, Memory_Annotation_Node, 1); + Memory_Annotation_Node *r_node = (Memory_Annotation_Node*)malloc(sizeof(Memory_Annotation_Node)); + sll_queue_push(result.first, result.last, r_node); + result.count += 1; + + r_node->location = node->location; + r_node->address = node + 1; + r_node->size = node->size; + } + + } + pthread_mutex_unlock(&memory_tracker_mutex); + + return(result); +} + +//////////////////////////////// + +function +system_show_mouse_cursor_sig(){ + mac_vars.cursor_show = show; +} + +function +system_set_fullscreen_sig(){ + // NOTE(yuval): Read comment in system_set_fullscreen_sig in win32_4ed.cpp + mac_vars.do_toggle = (mac_vars.full_screen != full_screen); + + b32 success = true; + return(success); +} + +function +system_is_fullscreen_sig(){ + // NOTE(yuval): Read comment in system_is_fullscreen_sig in win32_4ed.cpp + b32 result = (mac_vars.full_screen != mac_vars.do_toggle); + return(result); +} + +function +system_get_keyboard_modifiers_sig(){ + Input_Modifier_Set result = copy_modifier_set(arena, &mac_vars.input_chunk.pers.modifiers); + return(result); +} + +//////////////////////////////// + +/**********************/ +/* Graphics API */ +/**********************/ + +//////////////////////////////// + +function +graphics_get_texture_sig(){ + u32 result = renderer->get_texture(renderer, dim, texture_kind); + return(result); +} + +function +graphics_fill_texture_sig(){ + b32 result = renderer->fill_texture(renderer, texture_kind, texture, p, dim, data); + return(result); +} + +//////////////////////////////// + +/******************/ +/* Font API */ +/******************/ + +//////////////////////////////// + +function +font_make_face_sig(){ + Face* result = ft__font_make_face(arena, description, scale_factor); + return(result); +} + +//////////////////////////////// \ No newline at end of file diff --git a/platform_mac/mac_4ed_metal.mm b/platform_mac/mac_4ed_metal.mm new file mode 100644 index 00000000..3b03423b --- /dev/null +++ b/platform_mac/mac_4ed_metal.mm @@ -0,0 +1,83 @@ +/* Mac Metal layer for 4coder */ + +#import "metal/4ed_metal_render.mm" + +//////////////////////////////// + +struct Mac_Metal{ + Mac_Renderer base; + + Metal_Renderer *renderer; + MTKView *view; +}; + +//////////////////////////////// + +function +mac_render_sig(mac_metal__render){ +#if defined(FRED_INTERNAL) + printf("Redering using Metal!\n"); +#endif + + Mac_Metal *metal = (Mac_Metal*)renderer; + [metal->view draw]; +} + +function +mac_get_texture_sig(mac_metal__get_texture){ + Mac_Metal *metal = (Mac_Metal*)renderer; + u32 result = [metal->renderer get_texture_of_dim:dim + kind:texture_kind]; + + return(result); +} + +function +mac_fill_texture_sig(mac_metal__fill_texture){ + Mac_Metal *metal = (Mac_Metal*)renderer; + b32 result = [metal->renderer fill_texture:texture + kind:texture_kind + pos:p + dim:dim + data:data]; + + return(result); +} + +function Mac_Metal* +mac_metal__init(NSWindow *window, Render_Target *target){ + // NOTE(yuval): Create the Mac Metal rendere + Mac_Metal *metal = (Mac_Metal*)system_memory_allocate(sizeof(Mac_Metal), + file_name_line_number_lit_u8); + metal->base.render = mac_metal__render; + metal->base.get_texture = mac_metal__get_texture; + metal->base.fill_texture = mac_metal__fill_texture; + + // NOTE(yuval): Create the Metal view + NSView *content_view = [window contentView]; + + metal->view = [[MTKView alloc] initWithFrame:[content_view bounds]]; + [metal->view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [metal->view setPaused:YES]; + [metal->view setEnableSetNeedsDisplay:NO]; + + metal->view.device = MTLCreateSystemDefaultDevice(); + + // NOTE(yuval): Add the Metal view as a subview of the window + [content_view addSubview:metal->view]; + + // NOTE(yuval): Create the Metal renderer and set it as the Metal view's delegate + metal->renderer = [[Metal_Renderer alloc] initWithMetalKitView:metal->view target:target]; + metal->view.delegate = metal->renderer; + + return(metal); +} + +//////////////////////////////// + +// TODO(yuval): This function should be exported to a DLL +function +mac_load_renderer_sig(mac_load_metal_renderer){ + Mac_Renderer *renderer = (Mac_Renderer*)mac_metal__init(window, target); + return(renderer); +} diff --git a/platform_mac/mac_4ed.cpp b/platform_mac/mac_4ed_old.cpp similarity index 99% rename from platform_mac/mac_4ed.cpp rename to platform_mac/mac_4ed_old.cpp index 77b111ec..81e7ffc3 100644 --- a/platform_mac/mac_4ed.cpp +++ b/platform_mac/mac_4ed_old.cpp @@ -782,7 +782,7 @@ osx_init(){ osxvars.input.first_step = true; // - // HACK(allen): + // HACK(allen): // Previously zipped stuff is here, it should be zipped in the new pattern now. // diff --git a/platform_mac/mac_4ed.m b/platform_mac/mac_4ed_old.m similarity index 99% rename from platform_mac/mac_4ed.m rename to platform_mac/mac_4ed_old.m index ebadc1ca..fad0565e 100644 --- a/platform_mac/mac_4ed.m +++ b/platform_mac/mac_4ed_old.m @@ -814,9 +814,9 @@ osx_list_loadable_fonts(void){ NSString *font_n = fonts[i]; char *font_n_c = (char*)[font_n UTF8String]; NSFont *font = [font_manager - fontWithFamily:font_n - traits:NSUnboldFontMask|NSUnitalicFontMask - weight:5 + fontWithFamily:font_n + traits:NSUnboldFontMask|NSUnitalicFontMask + weight:5 size:12]; NSString *path = get_font_path(font); char *path_c = 0; diff --git a/platform_mac/mac_4ed_opengl.mm b/platform_mac/mac_4ed_opengl.mm new file mode 100644 index 00000000..dcfe3715 --- /dev/null +++ b/platform_mac/mac_4ed_opengl.mm @@ -0,0 +1,183 @@ +/* Mac OpenGL layer for 4coder */ + +#include "mac_4ed_renderer.h" + +//////////////////////////////// +#include +#include + +#include "opengl/4ed_opengl_defines.h" + +#define GL_FUNC(N,R,P) typedef R (CALL_CONVENTION N##_Function)P; N##_Function *N = 0; +#include "mac_4ed_opengl_funcs.h" + +//////////////////////////////// + +#include "opengl/4ed_opengl_render.cpp" + +//////////////////////////////// + +@interface OpenGL_View : NSOpenGLView +- (void)init_gl; +- (void)render:(Render_Target*)target; +@end + +//////////////////////////////// + +struct Mac_OpenGL{ + Mac_Renderer base; + + OpenGL_View *view; +}; + +//////////////////////////////// + +@implementation OpenGL_View{ + b32 gl_is_initialized; +} + +- (id)init{ + self = [super init]; + if (self == nil){ + return nil; + } + + gl_is_initialized = false; + [self init_gl]; + + return self; +} + +- (void)dealloc{ + [super dealloc]; +} + +- (void)prepareOpenGL{ + [super prepareOpenGL]; + + [[self openGLContext] makeCurrentContext]; + + // NOTE(yuval): Setup vsync + GLint swap_int = 1; + [[self openGLContext] setValues:&swap_int forParameter:NSOpenGLCPSwapInterval]; +} + +- (void)awakeFromNib{ + [self init_gl]; +} + +- (void)reshape{ + [super reshape]; + + [[self openGLContext] makeCurrentContext]; + [[self openGLContext] update]; +} + +- (void)init_gl{ + if (gl_is_initialized){ + return; + } + + // NOTE(yuval): Setup OpenGL + NSOpenGLPixelFormatAttribute opengl_attrs[] = { + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFAAccelerated, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorSize, 32, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 24, + 0 + }; + + NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:opengl_attrs]; + if (pixel_format == nil){ + fprintf(stderr, "Error creating OpenGLPixelFormat\n"); + exit(1); + } + + NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:nil]; + + [self setPixelFormat:pixel_format]; + [self setOpenGLContext:context]; + + [context makeCurrentContext]; + + [pixel_format release]; + + gl_is_initialized = true; +} + +- (void)render:(Render_Target*)target{ + Assert(gl_is_initialized); + + CGLLockContext([[self openGLContext] CGLContextObj]); + [[self openGLContext] makeCurrentContext]; + + gl_render(target); + + [[self openGLContext] flushBuffer]; + CGLUnlockContext([[self openGLContext] CGLContextObj]); +} +@end + +//////////////////////////////// + +function +mac_render_sig(mac_gl__render){ +#if defined(FRED_INTERNAL) + printf("Redering using OpenGL!\n"); +#endif + + Mac_OpenGL *gl = (Mac_OpenGL*)renderer; + [gl->view render:target]; +} + +function +mac_get_texture_sig(mac_gl__get_texture){ + u32 result = gl__get_texture(dim, texture_kind); + return(result); +} + +function +mac_fill_texture_sig(mac_gl__fill_texture){ + b32 result = gl__fill_texture(texture_kind, texture, p, dim, data); + return(result); +} + +function Mac_OpenGL* +mac_gl__init(NSWindow *window, Render_Target *target){ + // NOTE(yuval): Create the Mac OpenGL Renderer + Mac_OpenGL *gl = (Mac_OpenGL*)system_memory_allocate(sizeof(Mac_OpenGL), + file_name_line_number_lit_u8); + gl->base.render = mac_gl__render; + gl->base.get_texture = mac_gl__get_texture; + gl->base.fill_texture = mac_gl__fill_texture; + + // NOTE(yuval): Create the OpenGL view + NSView *content_view = [window contentView]; + + gl->view = [[OpenGL_View alloc] init]; + [gl->view setFrame:[content_view bounds]]; + [gl->view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [gl->view setWantsBestResolutionOpenGLSurface:YES]; + + // NOTE(yuval): Add the OpenGL view as a subview of the window + [content_view addSubview:gl->view]; + + // NOTE(yuval): Load gl functions + void *gl_image = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY); + +#define GL_FUNC(f,R,P) ((f) = (f##_Function*)dlsym(gl_image, #f)); +#include "mac_4ed_opengl_funcs.h" + + return(gl); +} + +//////////////////////////////// + +// TODO(yuval): This function should be exported to a DLL +function +mac_load_renderer_sig(mac_load_opengl_renderer){ + Mac_Renderer *renderer = (Mac_Renderer*)mac_gl__init(window, target); + return(renderer); +} diff --git a/platform_mac/mac_4ed_opengl_funcs.h b/platform_mac/mac_4ed_opengl_funcs.h new file mode 100644 index 00000000..649847f9 --- /dev/null +++ b/platform_mac/mac_4ed_opengl_funcs.h @@ -0,0 +1,17 @@ +/* Mac OpenGL functions for 4coder */ + +// TOP +/* Usage: +#define GL_FUNC(N,R,P) ~~~~ +#include "4ed_opengl_funcs.h" +*/ + +GL_FUNC(glDebugMessageControl, void, (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled)) +GL_FUNC(glDebugMessageCallback, void, (GLDEBUGPROC callback, const void *userParam)) + +GL_FUNC(glGenVertexArrays, void, (GLsizei n, GLuint *arrays)) +GL_FUNC(glBindVertexArray, void, (GLuint array)) + +GL_FUNC(glVertexAttribIPointer, void, (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)) + +#undef GL_FUNC diff --git a/platform_mac/mac_4ed_renderer.h b/platform_mac/mac_4ed_renderer.h new file mode 100644 index 00000000..ecc11ff2 --- /dev/null +++ b/platform_mac/mac_4ed_renderer.h @@ -0,0 +1,44 @@ +/* Mac Renderer Abstraction */ + +#if !defined(FRED_MAC_RENDERER_H) +#define FRED_MAC_RENDERER_H + +//////////////////////////////// + +// TODO(yuval): This should be refactored into a platform independent renderer + +struct Mac_Renderer; + +#define mac_render_sig(name) void name(Mac_Renderer *renderer, Render_Target *target) +typedef mac_render_sig(mac_render_type); + +#define mac_get_texture_sig(name) u32 name(Mac_Renderer *renderer, Vec3_i32 dim, Texture_Kind texture_kind) +typedef mac_get_texture_sig(mac_get_texture_type); + +#define mac_fill_texture_sig(name) b32 name(Mac_Renderer *renderer, Texture_Kind texture_kind, u32 texture, Vec3_i32 p, Vec3_i32 dim, void* data) +typedef mac_fill_texture_sig(mac_fill_texture_type); + +typedef i32 Mac_Renderer_Kind; +enum{ + MacRenderer_OpenGL, + MacRenderer_Metal, + // + MacRenderer_COUNT +}; + +struct Mac_Renderer{ + mac_render_type *render; + + mac_get_texture_type *get_texture; + mac_fill_texture_type *fill_texture; +}; + +//////////////////////////////// + +// NOTE(yuval): This is the actual platform dependent function that each renderer implementation implements and should be exported into a DLL +#define mac_load_renderer_sig(name) Mac_Renderer* name(NSWindow *window, Render_Target *target) +typedef mac_load_renderer_sig(mac_load_renderer_type); + +//////////////////////////////// + +#endif \ No newline at end of file diff --git a/platform_mac/mac_4ed_renderer.mm b/platform_mac/mac_4ed_renderer.mm new file mode 100644 index 00000000..7ad171b6 --- /dev/null +++ b/platform_mac/mac_4ed_renderer.mm @@ -0,0 +1,26 @@ +/* Mac Renderer Abstraction Implementation */ + +// TODO(yuval): This should NOT be included here once the renderer is exported to a DLL +#import "mac_4ed_opengl.mm" +#import "mac_4ed_metal.mm" + +// TODO(yuval): Replace this array with an array of the paths to the renderer dlls +global mac_load_renderer_type *mac_renderer_load_functions[MacRenderer_COUNT] = { + mac_load_opengl_renderer, + mac_load_metal_renderer +}; + +function Mac_Renderer* +mac_init_renderer(Mac_Renderer_Kind kind, NSWindow *window, Render_Target *target){ + // TODO(yuval): Import renderer load function from a DLL instead of using an array of the load functions. This would allow us to switch the renderer backend and implemented new backends with ease. + + mac_load_renderer_type *load_renderer = mac_renderer_load_functions[kind]; + Mac_Renderer *result = load_renderer(window, target); + + if (!result){ + mac_error_box("Unable to initialize the renderer!"); + } + + return result; +} + diff --git a/platform_mac/mac_objective_c_to_cpp_links.h b/platform_mac/mac_objective_c_to_cpp_links.h new file mode 100644 index 00000000..ab043fc1 --- /dev/null +++ b/platform_mac/mac_objective_c_to_cpp_links.h @@ -0,0 +1,24 @@ +/* Types and functions for communication between C++ and Objective-C layers. */ + +#if !defined(MAC_OBJECTIVE_C_TO_CPP_LINKS_H) +#define MAC_OBJECTIVE_C_TO_CPP_LINKS_H + +// In C++ layer +external String_Const_u8 +mac_SCu8(u8* str, u64 size); + +external String_Const_u8 +mac_push_string_copy(Arena *arena, String_Const_u8 src); + +external void +mac_init(); + +// In Objective-C layer +external String_Const_u8 +mac_standardize_path(Arena* arena, String_Const_u8 path); + +external i32 +mac_get_binary_path(void* buffer, u32 size); + +#endif + diff --git a/platform_mac/osx_objective_c_to_cpp_links.h b/platform_mac/osx_objective_c_to_cpp_links_old.h similarity index 100% rename from platform_mac/osx_objective_c_to_cpp_links.h rename to platform_mac/osx_objective_c_to_cpp_links_old.h diff --git a/platform_unix/unix_4ed_functions.cpp b/platform_unix/unix_4ed_functions.cpp index 75e121fb..d6fe65b7 100644 --- a/platform_unix/unix_4ed_functions.cpp +++ b/platform_unix/unix_4ed_functions.cpp @@ -64,7 +64,7 @@ Sys_Memory_Allocate_Sig(system_memory_allocate){ return(result); } -internal +internal Sys_Memory_Set_Protection_Sig(system_memory_set_protection){ bool32 result = true; diff --git a/platform_win32/win32_4ed.cpp b/platform_win32/win32_4ed.cpp index 737167ff..c83fe429 100644 --- a/platform_win32/win32_4ed.cpp +++ b/platform_win32/win32_4ed.cpp @@ -335,7 +335,7 @@ system_set_fullscreen_sig(){ internal system_is_fullscreen_sig(){ - // NOTE(allen): Report the fullscreen status as it would be set at the beginning of the + // NOTE(allen): Report the fullscreen status as it would be set at the beginning of the // next frame. That is, take into account all fullscreen toggle requests that have come in // already this frame. Read: "full_screen XOR do_toggle" b32 result = (win32vars.full_screen != win32vars.do_toggle); @@ -605,6 +605,9 @@ os_popup_error(char *title, char *message){ #include "4ed_font_provider_freetype.cpp" #include +#include "opengl/4ed_opengl_defines.h" +#define GL_FUNC(N,R,P) typedef R (CALL_CONVENTION N##_Function)P; N##_Function *N = 0; +#include "opengl/4ed_opengl_funcs.h" #include "opengl/4ed_opengl_render.cpp" internal diff --git a/platform_win32/win32_4ed_functions.cpp b/platform_win32/win32_4ed_functions.cpp index 8e139ea1..5e7533b3 100644 --- a/platform_win32/win32_4ed_functions.cpp +++ b/platform_win32/win32_4ed_functions.cpp @@ -444,7 +444,7 @@ color_picker_hook(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam){ // Would it have killed you to update rgbResult continuously, or at least // provide a GetCurrentColor() call??? // - // Anyway, since the color picker doesn't tell us when the color is + // Anyway, since the color picker doesn't tell us when the color is // changed, what we do is watch for messages that repaint the color // swatch, which is dialog id 0x2c5, and then we sample it to see what // color it is. No, I'm not fucking kidding, that's what we do. @@ -533,7 +533,7 @@ internal system_open_color_picker_sig(){ // TODO(allen): review // NOTE(casey): Because this is going to be used by a semi-permanent thread, we need to - // copy it to system memory where it can live as long as it wants, no matter what we do + // copy it to system memory where it can live as long as it wants, no matter what we do // over here on the 4coder threads. Color_Picker *perm = (Color_Picker*)system_memory_allocate(sizeof(Color_Picker), string_u8_litexpr(file_name_line_number)); *perm = *picker;