├── .github └── workflows │ └── main.yml ├── 4coder_qol.cpp ├── 4coder_qol_bindings.cpp ├── 4coder_qol_block.cpp ├── 4coder_qol_bview.cpp ├── 4coder_qol_bview.h ├── 4coder_qol_colors.cpp ├── 4coder_qol_commands.cpp ├── 4coder_qol_cpp_lexer_gen.cpp ├── 4coder_qol_draw.cpp ├── 4coder_qol_helper.h ├── 4coder_qol_hooks.cpp ├── 4coder_qol_isearch.cpp ├── 4coder_qol_jumps.cpp ├── 4coder_qol_lister.cpp ├── 4coder_qol_lister.h ├── 4coder_qol_snippets.cpp ├── 4coder_qol_token.cpp ├── 4coder_qol_token.h ├── README.md ├── apply.bat ├── apply.sh ├── build.bat ├── build.sh ├── build_lexer.bat ├── config.4coder ├── custom ├── 4coder_app_links_allocator.cpp ├── 4coder_async_tasks.cpp ├── 4coder_async_tasks.h ├── 4coder_audio.cpp ├── 4coder_audio.h ├── 4coder_auto_indent.cpp ├── 4coder_auto_indent.h ├── 4coder_base_commands.cpp ├── 4coder_base_types.cpp ├── 4coder_base_types.h ├── 4coder_buffer_seek_constructors.cpp ├── 4coder_build_commands.cpp ├── 4coder_build_commands.h ├── 4coder_cli_command.cpp ├── 4coder_clipboard.cpp ├── 4coder_clipboard.h ├── 4coder_code_index.cpp ├── 4coder_code_index.h ├── 4coder_code_index_listers.cpp ├── 4coder_codepoint_map.cpp ├── 4coder_combined_write_commands.cpp ├── 4coder_combined_write_commands.h ├── 4coder_command_map.cpp ├── 4coder_command_map.h ├── 4coder_config.cpp ├── 4coder_config.h ├── 4coder_config_grammar.txt ├── 4coder_custom.cpp ├── 4coder_default_bindings.cpp ├── 4coder_default_colors.cpp ├── 4coder_default_colors.h ├── 4coder_default_framework.cpp ├── 4coder_default_framework.h ├── 4coder_default_framework_variables.cpp ├── 4coder_default_hooks.cpp ├── 4coder_default_include.cpp ├── 4coder_default_include.h ├── 4coder_default_map.cpp ├── 4coder_delta_rule.cpp ├── 4coder_delta_rule.h ├── 4coder_doc_commands.cpp ├── 4coder_doc_content_types.cpp ├── 4coder_doc_content_types.h ├── 4coder_docs.cpp ├── 4coder_draw.cpp ├── 4coder_draw.h ├── 4coder_dynamic_bindings.cpp ├── 4coder_eol.cpp ├── 4coder_events.cpp ├── 4coder_events.h ├── 4coder_examples.cpp ├── 4coder_fancy.cpp ├── 4coder_file.cpp ├── 4coder_file.h ├── 4coder_file_moving.h ├── 4coder_font_helper.cpp ├── 4coder_function_list.cpp ├── 4coder_function_list.h ├── 4coder_hash_functions.cpp ├── 4coder_helper.cpp ├── 4coder_helper.h ├── 4coder_insertion.cpp ├── 4coder_insertion.h ├── 4coder_jump_lister.cpp ├── 4coder_jump_lister.h ├── 4coder_jump_sticky.cpp ├── 4coder_jump_sticky.h ├── 4coder_jumping.cpp ├── 4coder_jumping.h ├── 4coder_keyboard_macro.cpp ├── 4coder_layout.cpp ├── 4coder_layout_rule.cpp ├── 4coder_layout_rule.h ├── 4coder_lister_base.cpp ├── 4coder_lister_base.h ├── 4coder_lists.cpp ├── 4coder_log.cpp ├── 4coder_log_parser.cpp ├── 4coder_log_parser.h ├── 4coder_mac_map.cpp ├── 4coder_malloc_allocator.cpp ├── 4coder_metadata_generator.cpp ├── 4coder_miblo_numbers.cpp ├── 4coder_prj_v1.cpp ├── 4coder_prj_v1.h ├── 4coder_profile.cpp ├── 4coder_profile.h ├── 4coder_profile_inspect.cpp ├── 4coder_profile_inspect.h ├── 4coder_profile_static_disable.cpp ├── 4coder_profile_static_enable.cpp ├── 4coder_project_commands.cpp ├── 4coder_project_commands.h ├── 4coder_scope_commands.cpp ├── 4coder_scope_commands.h ├── 4coder_search.cpp ├── 4coder_search.h ├── 4coder_search_list.cpp ├── 4coder_search_list.h ├── 4coder_string_match.cpp ├── 4coder_string_match.h ├── 4coder_stringf.cpp ├── 4coder_system_allocator.cpp ├── 4coder_system_helpers.cpp ├── 4coder_system_types.h ├── 4coder_table.cpp ├── 4coder_table.h ├── 4coder_token.cpp ├── 4coder_token.h ├── 4coder_tutorial.cpp ├── 4coder_tutorial.h ├── 4coder_types.h ├── 4coder_variables.cpp ├── 4coder_variables.h ├── 4coder_version.h ├── bin │ ├── build_metadata.bat │ ├── build_metadata.sh │ ├── build_one_time.bat │ ├── build_one_time.sh │ ├── buildsuper_x64-linux.sh │ ├── buildsuper_x64-mac.sh │ ├── buildsuper_x64-win.bat │ ├── buildsuper_x86-linux.sh │ ├── buildsuper_x86-win.bat │ ├── detect_os.sh │ ├── setup_cl_generic.bat │ ├── setup_cl_x64.bat │ └── setup_cl_x86.bat ├── generated │ ├── 4coder_event_codes.h │ ├── custom_api.cpp │ ├── custom_api.h │ ├── custom_api_constructor.cpp │ ├── custom_api_master_list.h │ ├── lexer_cpp.cpp │ ├── lexer_cpp.h │ ├── system_api.cpp │ ├── system_api.h │ ├── system_api_constructor.cpp │ └── system_api_master_list.h ├── languages │ ├── 4coder_cpp_lexer_gen.cpp │ └── 4coder_cpp_lexer_test.cpp ├── lexer_generator │ ├── 4coder_lex_gen_hand_written.cpp │ ├── 4coder_lex_gen_hand_written.h │ ├── 4coder_lex_gen_main.cpp │ ├── pcg_basic.c │ └── pcg_basic.h ├── project_.4coder └── stb_sprintf.h ├── plugins ├── 4coder_multi_cursor.cpp └── 4coder_tabs.cpp ├── project.4coder ├── run_test.bat └── theme-qol.4coder /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Download 2 | 3 | on: push 4 | 5 | jobs: 6 | build_4coder_qol: 7 | name: Build 4coder_qol 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | include: 12 | - suffix: x64-win 13 | os: windows-latest 14 | build_cmd: custom\bin\buildsuper_x64-win.bat 15 | - suffix: x64-linux 16 | os: ubuntu-latest 17 | build_cmd: ./custom/bin/buildsuper_x64-linux.sh 18 | - suffix: x64-mac 19 | os: macos-13 20 | build_cmd: ./custom/bin/buildsuper_x64-mac.sh 21 | # - suffix: arm64-mac 22 | # os: macos-latest 23 | # build_cmd: ./custom/bin/buildsuper_arm64-mac.sh 24 | runs-on: ${{ matrix.os }} 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: ilammy/msvc-dev-cmd@v1.4.1 # this is a no-op on Linux and macOS 28 | - name: Build 4coder_qol-${{ matrix.suffix }} 29 | run: ${{ matrix.build_cmd }} 4coder_qol.cpp release 30 | - name: Generate 4coder_qol Artifacts 31 | uses: actions/upload-artifact@v4.6.0 32 | with: 33 | name: 4coder_qol-${{ matrix.suffix }} 34 | path: | 35 | custom_4coder.* 36 | theme-*.4coder 37 | 38 | create_gh_release: 39 | if: startsWith(github.ref, 'refs/tags/') 40 | needs: build_4coder_qol 41 | name: Upload 42 | runs-on: ubuntu-latest 43 | steps: 44 | - name: Download 4coder_qol Artifacts 45 | uses: actions/download-artifact@v4 46 | with: 47 | path: artifacts_dir 48 | pattern: 4coder_qol-* 49 | - run: | 50 | cd artifacts_dir 51 | for f in ./* ; do zip -r "$f.zip" $f ; done; 52 | - name: Upload Artifacts to Release 53 | uses: softprops/action-gh-release@v2 54 | with: 55 | files: artifacts_dir/4coder_qol-*.zip 56 | -------------------------------------------------------------------------------- /4coder_qol.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "4coder_default_include.h" 3 | 4 | //#define SNIPPET_EXPANSION "path/to/snippet.inc" 5 | 6 | #define AUTO_CENTER_AFTER_JUMPS false 7 | 8 | #include "4coder_qol_token.h" 9 | #include "4coder_qol_lister.h" 10 | #include "4coder_qol_bview.h" 11 | #define run_lister qol_run_lister 12 | 13 | CUSTOM_ID(colors, defcolor_type); 14 | CUSTOM_ID(colors, defcolor_function); 15 | CUSTOM_ID(colors, defcolor_macro); 16 | CUSTOM_ID(colors, defcolor_enum); 17 | CUSTOM_ID(colors, defcolor_global); 18 | CUSTOM_ID(colors, defcolor_control); 19 | CUSTOM_ID(colors, defcolor_primitive); 20 | CUSTOM_ID(colors, defcolor_struct); 21 | CUSTOM_ID(colors, defcolor_non_text); 22 | CUSTOM_ID(colors, defcolor_operator); 23 | 24 | #include "4coder_default_include.cpp" 25 | 26 | #include "4coder_qol_jumps.cpp" 27 | 28 | #include "plugins/4coder_multi_cursor.cpp" 29 | #include "plugins/4coder_tabs.cpp" 30 | 31 | global b32 qol_opened_brace = false; 32 | global u8 qol_target_char; 33 | global Buffer_Cursor qol_col_cursor = {-1}; 34 | 35 | global Vec2_f32 qol_cur_cursor_pos; 36 | global Vec2_f32 qol_nxt_cursor_pos; 37 | 38 | global Color_Table qol_cur_colors; 39 | global Color_Table qol_nxt_colors; 40 | 41 | global Face_ID qol_small_face; 42 | 43 | global Buffer_ID qol_temp_buffer; 44 | 45 | global View_ID qol_try_exit_view; 46 | 47 | global u8 g_qol_bot_buffer[1024]; 48 | global String_u8 g_qol_bot_string = Su8(g_qol_bot_buffer, 0, sizeof(g_qol_bot_buffer)); 49 | 50 | global Character_Predicate character_predicate_word = {}; 51 | global Character_Predicate character_predicate_non_word = {}; 52 | 53 | #include "4coder_qol_helper.h" 54 | #include "4coder_qol_block.cpp" 55 | 56 | #include "4coder_qol_colors.cpp" 57 | #include "4coder_qol_token.cpp" 58 | 59 | function void qol_setup_essential_mapping(Mapping *mapping, i64 global_id, i64 file_id, i64 code_id); 60 | function void qol_setup_default_mapping(Mapping *mapping, i64 global_id, i64 file_id, i64 code_id); 61 | 62 | #include "4coder_qol_commands.cpp" 63 | #include "4coder_qol_isearch.cpp" 64 | #include "4coder_qol_draw.cpp" 65 | #include "4coder_qol_lister.cpp" 66 | #include "4coder_qol_bview.cpp" 67 | #include "4coder_qol_snippets.cpp" 68 | 69 | #include "4coder_qol_bindings.cpp" 70 | #include "4coder_qol_hooks.cpp" 71 | 72 | #if !defined(META_PASS) 73 | #include "generated/managed_id_metadata.cpp" 74 | #endif 75 | 76 | void custom_layer_init(Application_Links *app){ 77 | Thread_Context *tctx = get_thread_context(app); 78 | 79 | default_framework_init(app); 80 | 81 | MC_init(app); 82 | 83 | MC_register(exit_4coder, MC_Command_Global); 84 | MC_register(default_try_exit, MC_Command_Global); 85 | MC_register(mouse_wheel_change_face_size, MC_Command_Global); 86 | MC_register(swap_panels, MC_Command_Global); 87 | MC_register(save, MC_Command_Global); 88 | MC_register(save_all_dirty_buffers, MC_Command_Global); 89 | MC_register(qol_column_toggle, MC_Command_Global); 90 | MC_register(center_view, MC_Command_Global); 91 | MC_register(left_adjust_view, MC_Command_Global); 92 | 93 | MC_register(copy, MC_Command_CursorCopy); 94 | MC_register(cut, MC_Command_CursorCopy); 95 | MC_register(paste_and_indent, MC_Command_CursorPaste); 96 | 97 | // Set up custom layer hooks 98 | { 99 | set_custom_hook(app, HookID_BufferViewerUpdate, default_view_adjust); 100 | 101 | set_custom_hook(app, HookID_ViewEventHandler, qol_view_input_handler); 102 | set_custom_hook(app, HookID_Tick, qol_tick); 103 | set_custom_hook(app, HookID_RenderCaller, qol_render_caller); 104 | set_custom_hook(app, HookID_WholeScreenRenderCaller, qol_whole_screen_render_caller); 105 | 106 | set_custom_hook(app, HookID_DeltaRule, fixed_time_cubic_delta); 107 | set_custom_hook_memory_size(app, HookID_DeltaRule, 108 | delta_ctx_size(fixed_time_cubic_delta_memory_size)); 109 | 110 | set_custom_hook(app, HookID_BufferNameResolver, default_buffer_name_resolution); 111 | 112 | set_custom_hook(app, HookID_BeginBuffer, default_begin_buffer); 113 | set_custom_hook(app, HookID_EndBuffer, end_buffer_close_jump_list); 114 | set_custom_hook(app, HookID_NewFile, default_new_file); 115 | set_custom_hook(app, HookID_SaveFile, qol_file_save); 116 | set_custom_hook(app, HookID_BufferEditRange, MC_buffer_edit_range); 117 | set_custom_hook(app, HookID_BufferRegion, qol_buffer_region); 118 | set_custom_hook(app, HookID_ViewChangeBuffer, default_view_change_buffer); 119 | 120 | set_custom_hook(app, HookID_Layout, layout_unwrapped); 121 | } 122 | 123 | mapping_init(tctx, &framework_mapping); 124 | String_ID global_map_id = vars_save_string_lit("keys_global"); 125 | String_ID file_map_id = vars_save_string_lit("keys_file"); 126 | String_ID code_map_id = vars_save_string_lit("keys_code"); 127 | qol_setup_essential_mapping(&framework_mapping, global_map_id, file_map_id, code_map_id); 128 | } 129 | -------------------------------------------------------------------------------- /4coder_qol_block.cpp: -------------------------------------------------------------------------------- 1 | 2 | typedef void QOL_Range_Func(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 range); 3 | 4 | function Rect_f32 5 | qol_get_rel_block_rect(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 range, i64 line){ 6 | Vec2_f32 p0 = view_relative_xy_of_pos(app, view, line, range.min); 7 | Vec2_f32 p1 = view_relative_xy_of_pos(app, view, line, range.max); 8 | return Rf32(Min(p0.x, p1.x), Min(p0.y, p1.y), Max(p0.x, p1.x), Max(p0.y, p1.y)); 9 | } 10 | 11 | function Rect_f32 12 | qol_get_abs_block_rect(Application_Links *app, View_ID view, Buffer_ID buffer, Text_Layout_ID text_layout_id, Range_i64 range){ 13 | Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); 14 | 15 | i64 rel_pos = range.min; 16 | if (!range_contains(visible_range, rel_pos)){ rel_pos = range.max; } 17 | if (!range_contains(visible_range, rel_pos)){ rel_pos = scan(app, boundary_alpha_numeric, buffer, Scan_Forward, visible_range.min); } 18 | if (!range_contains(visible_range, rel_pos)){ return Rect_f32{}; } // This is nearly impossible to hit... nearly 19 | 20 | i64 line = get_line_number_from_pos(app, buffer, rel_pos); 21 | Vec2_f32 rel_p = view_relative_xy_of_pos(app, view, line, rel_pos); 22 | Rect_f32 rel_rect = text_layout_character_on_screen(app, text_layout_id, rel_pos); 23 | Vec2_f32 offset0 = rel_p - rel_rect.p0; 24 | Vec2_f32 offset1 = rel_p - rel_rect.p1; 25 | Rect_f32 min_rect, max_rect; 26 | 27 | if (range_contains(visible_range, range.min)){ 28 | min_rect = text_layout_character_on_screen(app, text_layout_id, range.min); 29 | } 30 | else{ 31 | Vec2_f32 min_p = view_relative_xy_of_pos(app, view, line, range.min); 32 | min_rect = Rf32(min_p - offset0, min_p - offset1); 33 | } 34 | 35 | if (range_contains(visible_range, range.max)){ 36 | max_rect = text_layout_character_on_screen(app, text_layout_id, range.max); 37 | } 38 | else{ 39 | Vec2_f32 max_p = view_relative_xy_of_pos(app, view, line, range.max); 40 | max_rect = Rf32(max_p - offset0, max_p - offset1); 41 | } 42 | 43 | return rect_union(min_rect, max_rect); 44 | } 45 | 46 | struct Block_Iter{ 47 | Application_Links *app; 48 | View_ID view; 49 | Buffer_ID buffer; 50 | i64 line; 51 | i64 line_min; 52 | i64 line_max; 53 | Rect_f32 rect; 54 | Range_i64 range; 55 | }; 56 | 57 | function bool 58 | qol_block_iter_next(Block_Iter *iter){ 59 | Application_Links *app = iter->app; 60 | View_ID view = iter->view; 61 | Buffer_ID buffer = iter->buffer; 62 | f32 line_advance = rect_height(iter->rect)/f32(Max(1.f, iter->line_max - iter->line_min)); 63 | for (; iter->line >= iter->line_min; iter->line -= 1){ 64 | if (line_is_valid_and_blank(app, buffer, iter->line)){ continue; } 65 | f32 y = line_advance*(iter->line - iter->line_min); 66 | Vec2_f32 min_point = V2f32(iter->rect.x0, y); 67 | Vec2_f32 max_point = V2f32(iter->rect.x1, y); 68 | i64 min_pos = view_pos_at_relative_xy(app, view, iter->line_min, min_point); 69 | i64 max_pos = view_pos_at_relative_xy(app, view, iter->line_min, max_point); 70 | 71 | Vec2_f32 min_p = view_relative_xy_of_pos(app, view, iter->line_min, min_pos); 72 | Vec2_f32 max_p = view_relative_xy_of_pos(app, view, iter->line_min, max_pos); 73 | bool contains_min = rect_contains_point(iter->rect, min_p); 74 | bool contains_max = rect_contains_point(iter->rect, max_p); 75 | if (!contains_min || !contains_max){ continue; } 76 | 77 | iter->range = Ii64(min_pos, max_pos+1); 78 | iter->line -= 1; 79 | return true; 80 | } 81 | return false; 82 | } 83 | 84 | function Block_Iter 85 | qol_block_iter_init(Application_Links *app, View_ID view, Range_i64 range){ 86 | Block_Iter result; 87 | result.app = app; 88 | result.view = view; 89 | result.buffer = view_get_buffer(app, view, Access_ReadVisible); 90 | result.line_min = get_line_number_from_pos(app, result.buffer, range.min); 91 | result.line_max = get_line_number_from_pos(app, result.buffer, range.max); 92 | result.line = result.line_max; 93 | result.rect = qol_get_rel_block_rect(app, view, result.buffer, range, result.line_min); 94 | result.rect.x1 += 0.01f; 95 | result.rect.y1 += 0.01f; 96 | return result; 97 | } 98 | 99 | function void 100 | qol_block_apply(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 block, QOL_Range_Func *func){ 101 | for (Block_Iter iter = qol_block_iter_init(app, view, block); qol_block_iter_next(&iter);){ 102 | func(app, view, buffer, iter.range); 103 | } 104 | } 105 | 106 | function void 107 | qol_range_delete(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 range){ 108 | buffer_replace_range(app, buffer, range, string_u8_empty); 109 | } 110 | 111 | function void 112 | qol_range_fade(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 range){ 113 | buffer_post_fade(app, buffer, 0.667f, range, fcolor_resolve(fcolor_id(defcolor_pop2))); 114 | } 115 | 116 | function void 117 | qol_block_delete(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 range){ 118 | History_Group group = history_group_begin(app, buffer); 119 | qol_block_apply(app, view, buffer, range, qol_range_delete); 120 | history_group_end(group); 121 | } -------------------------------------------------------------------------------- /4coder_qol_bview.cpp: -------------------------------------------------------------------------------- 1 | 2 | CUSTOM_COMMAND_SIG(qol_bview_close) 3 | CUSTOM_DOC("[QOL] Closes bottom view") 4 | { 5 | g_qol_nxt_bot_height = 0.f; 6 | } 7 | 8 | CUSTOM_COMMAND_SIG(qol_bview_open) 9 | CUSTOM_DOC("[QOL] Opens bottom view") 10 | { 11 | Scratch_Block scratch(app); 12 | g_qol_nxt_bot_height = 0.35f*rect_height(global_get_screen_rectangle(app)); 13 | qol_bot_text_set(push_buffer_unique_name(app, scratch, g_qol_b_buffer)); 14 | } 15 | 16 | CUSTOM_COMMAND_SIG(qol_bview_toggle) 17 | CUSTOM_DOC("[QOL] Toggles bottom view open/close") 18 | { 19 | g_qol_nxt_bot_height > 0.5f ? qol_bview_close(app) : qol_bview_open(app); 20 | } 21 | 22 | function void qol_bview_set_buffer(Application_Links *app, Buffer_ID buffer){ 23 | g_qol_b_buffer = buffer; 24 | view_set_buffer(app, g_qol_b_view, buffer, SetBuffer_KeepOriginalGUI); 25 | } 26 | 27 | CUSTOM_COMMAND_SIG(qol_bview_active_to_bottom) 28 | CUSTOM_DOC("[QOL] Sets opens active buffer in bottom view") 29 | { 30 | View_ID view = get_active_view(app, Access_ReadVisible); 31 | qol_bview_set_buffer(app, view_get_buffer(app, view, Access_ReadVisible)); 32 | qol_bview_open(app); 33 | } 34 | 35 | CUSTOM_COMMAND_SIG(qol_bview_bottom_to_active) 36 | CUSTOM_DOC("[QOL] Opens bottom view buffer in active view") 37 | { 38 | View_ID view = get_active_view(app, Access_ReadVisible); 39 | view_set_buffer(app, view, g_qol_b_buffer, 0); 40 | qol_bview_close(app); 41 | } 42 | 43 | CUSTOM_COMMAND_SIG(qol_bview_scroll_up) 44 | CUSTOM_DOC("[QOL] Scrolls bottom view up") 45 | { 46 | Buffer_Scroll scroll = view_get_buffer_scroll(app, g_qol_b_view); 47 | scroll.target = view_move_buffer_point(app, g_qol_b_view, scroll.target, V2f32(0.f, -g_qol_nxt_bot_height)); 48 | move_vertical_pixels(app, g_qol_b_view, -g_qol_nxt_bot_height); 49 | view_set_buffer_scroll(app, g_qol_b_view, scroll, SetBufferScroll_SnapCursorIntoView); 50 | } 51 | 52 | CUSTOM_COMMAND_SIG(qol_bview_scroll_down) 53 | CUSTOM_DOC("[QOL] Scolls bottom view down") 54 | { 55 | Buffer_Scroll scroll = view_get_buffer_scroll(app, g_qol_b_view); 56 | scroll.target = view_move_buffer_point(app, g_qol_b_view, scroll.target, V2f32(0.f, g_qol_nxt_bot_height)); 57 | move_vertical_pixels(app, g_qol_b_view, g_qol_nxt_bot_height); 58 | view_set_buffer_scroll(app, g_qol_b_view, scroll, SetBufferScroll_SnapCursorIntoView); 59 | } 60 | 61 | function void 62 | qol_bview_render(Application_Links *app, Frame_Info frame_info, View_ID view){ 63 | Rect_f32 region = view_get_screen_rect(app, view); 64 | Face_ID face_id = get_face_id(app, 0); 65 | Face_Metrics metrics = get_face_metrics(app, face_id); 66 | f32 text_field_height = qol_bot_text_height(app, metrics); 67 | region = rect_split_top_bottom_neg(region, text_field_height).min; 68 | 69 | qol_lister_render(app, frame_info, view); 70 | 71 | if (g_qol_lister == 0 && g_qol_b_buffer && g_qol_nxt_bot_height > 0.5f){ 72 | Rect_f32 rect = rect_split_left_right(region, 4.f).max; 73 | Rect_f32 prev_clip = draw_set_clip(app, rect); 74 | Face_ID face = get_face_id(app, g_qol_b_buffer); 75 | 76 | Buffer_Scroll scroll = view_get_buffer_scroll(app, view); 77 | Buffer_Point_Delta_Result delta = delta_apply(app, view, frame_info.animation_dt, scroll); 78 | if (!block_match_struct(&scroll.position, &delta.point)){ 79 | block_copy_struct(&scroll.position, &delta.point); 80 | view_set_buffer_scroll(app, view, scroll, SetBufferScroll_NoCursorChange); 81 | } 82 | if (delta.still_animating){ 83 | animate_in_n_milliseconds(app, 0); 84 | } 85 | 86 | Text_Layout_ID text_layout_id = text_layout_create(app, g_qol_b_buffer, rect, scroll.position); 87 | qol_render_buffer(app, view, face, g_qol_b_buffer, text_layout_id, rect); 88 | text_layout_free(app, text_layout_id); 89 | draw_set_clip(app, prev_clip); 90 | } 91 | 92 | if (g_qol_lister == 0 && g_qol_cur_bot_height > 0.5f){ 93 | Rect_f32 dividor_rect = rect_split_top_bottom_neg(region, 2.f).max; 94 | draw_rectangle_fcolor(app, dividor_rect, 0.f, get_item_margin_color(UIHighlight_Active)); 95 | } 96 | } 97 | 98 | function void 99 | qol_tick_bview(Application_Links *app, Frame_Info frame_info){ 100 | Face_ID face_id = get_face_id(app, 0); 101 | Face_Metrics metrics = get_face_metrics(app, face_id); 102 | f32 block_height = lister_get_block_height(metrics.line_height); 103 | 104 | if (g_qol_lister){ 105 | Vec2_i32 grid = qol_lister_grid_dim(app, g_qol_lister); 106 | g_qol_nxt_bot_height = grid.y*block_height; 107 | view_set_active(app, g_qol_lister_view); 108 | } 109 | 110 | f32 text_field_height = qol_bot_text_height(app, metrics); 111 | f32 max_height = 0.5f*rect_height(global_get_screen_rectangle(app)); 112 | f32 nxt_height = Min(text_field_height + g_qol_nxt_bot_height, max_height); 113 | 114 | qol_interp(g_qol_cur_bot_height, nxt_height, frame_info.animation_dt, 1e-14f); 115 | if (abs_f32(g_qol_cur_bot_height - nxt_height) >= 1.f){ 116 | animate_in_n_milliseconds(app, 0); 117 | } 118 | else{ 119 | g_qol_cur_bot_height = nxt_height; 120 | } 121 | view_set_split_pixel_size(app, g_qol_b_view, (i32)g_qol_cur_bot_height); 122 | } 123 | 124 | function void 125 | qol_bview_spin(Application_Links *app){ 126 | View_ID view = get_this_ctx_view(app, Access_Always); 127 | View_Context ctx = view_current_context(app, view); 128 | ctx.render_caller = qol_bview_render; 129 | ctx.hides_buffer = true; 130 | View_Context_Block ctx_block(app, view, &ctx); 131 | change_active_panel_backwards(app); 132 | 133 | for (;;){ 134 | User_Input in = get_next_input(app, EventPropertyGroup_Any, 0); 135 | if (in.abort){ break; } 136 | leave_current_input_unhandled(app); 137 | } 138 | } 139 | 140 | function void 141 | qol_bview_init(Application_Links *app){ 142 | Panel_ID root = panel_get_root(app); 143 | Panel_ID split = panel_split(app, root, Dimension_Y); 144 | if (split){ 145 | panel_set_split(app, split, PanelSplitKind_FixedPixels_Max, 1.f); 146 | g_qol_b_view = panel_get_view(app, panel_get_child(app, split, Side_Max), Access_Always); 147 | view_enqueue_command_function(app, g_qol_b_view, qol_bview_spin); 148 | view_set_setting(app, g_qol_b_view, ViewSetting_ShowFileBar, false); 149 | view_set_passive(app, g_qol_b_view, true); 150 | view_set_camera_bounds(app, g_qol_b_view, V2f32(max_f32, max_f32), V2f32(1,1)); 151 | qol_bview_set_buffer(app, buffer_identifier_to_id_create_out_buffer(app, standard_build_build_buffer_identifier)); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /4coder_qol_bview.h: -------------------------------------------------------------------------------- 1 | 2 | global View_ID g_qol_b_view; 3 | global Buffer_ID g_qol_b_buffer; 4 | global f32 g_qol_cur_bot_height; 5 | global f32 g_qol_nxt_bot_height; 6 | 7 | function void qol_bview_set_buffer(Application_Links *app, Buffer_ID buffer); 8 | -------------------------------------------------------------------------------- /4coder_qol_colors.cpp: -------------------------------------------------------------------------------- 1 | 2 | function bool 3 | qol_is_theme_file(String_Const_u8 name){ 4 | String_Const_u8 target_prefix = string_u8_litexpr("theme-"); 5 | String_Const_u8 target_suffix = string_u8_litexpr(".4coder"); 6 | String_Const_u8 actual_prefix = string_prefix(name, target_prefix.size); 7 | String_Const_u8 actual_suffix = string_postfix(name, target_suffix.size); 8 | return string_match(actual_prefix, target_prefix) && string_match(actual_suffix, target_suffix); 9 | } 10 | 11 | function Color_Table 12 | qol_color_table_init(Application_Links *app){ 13 | Color_Table table = make_color_table(app, &global_permanent_arena); 14 | for (i64 i = 0; i < table.count; i += 1){ 15 | table.arrays[i].vals = push_array(&global_permanent_arena, ARGB_Color, 15); 16 | table.arrays[i].count = 15; 17 | } 18 | return table; 19 | } 20 | 21 | function void 22 | qol_color_table_copy(Color_Table dst, Color_Table src){ 23 | for (i64 i = 0; i < src.count; i += 1){ 24 | Color_Array *dst_array = &dst.arrays[i]; 25 | Color_Array *src_array = &src.arrays[i]; 26 | dst_array->count = src_array->count; 27 | block_copy(dst_array->vals, src_array->vals, src_array->count*sizeof(ARGB_Color)); 28 | } 29 | } 30 | 31 | function void 32 | qol_tick_colors(Application_Links *app, Frame_Info frame_info){ 33 | b32 needs_tick = false; 34 | 35 | if (active_color_table.arrays != qol_cur_colors.arrays){ 36 | qol_color_table_copy(qol_nxt_colors, active_color_table); 37 | active_color_table = qol_cur_colors; 38 | needs_tick = true; 39 | } 40 | 41 | for (i64 i = 0; i < qol_cur_colors.count; i += 1){ 42 | Color_Array cur_array = qol_cur_colors.arrays[i]; 43 | Color_Array nxt_array = qol_nxt_colors.arrays[i]; 44 | for (i64 j = 0; j < cur_array.count; j += 1){ 45 | Vec4_f32 cur = unpack_color(cur_array.vals[j]); 46 | Vec4_f32 nxt = unpack_color(nxt_array.vals[j]); 47 | Vec4_f32 dif = nxt - cur; 48 | qol_interp(cur, nxt, frame_info.animation_dt, 1e-4f); 49 | if (near_zero(dif, 0.05f)){ 50 | cur = nxt; 51 | } 52 | else{ 53 | needs_tick = true; 54 | } 55 | cur_array.vals[j] = pack_color(cur); 56 | } 57 | } 58 | 59 | if (needs_tick){ 60 | animate_in_n_milliseconds(app, 0); 61 | } 62 | } -------------------------------------------------------------------------------- /4coder_qol_helper.h: -------------------------------------------------------------------------------- 1 | 2 | #define qol_interp(cur, nxt, dt, rate) (cur += (((nxt) - (cur))*(1.f - pow_f32(rate, dt)))) 3 | 4 | function void 5 | printf_message(Application_Links *app, char *format, ...){ 6 | Scratch_Block scratch(app); 7 | va_list args; 8 | va_start(args, format); 9 | String_Const_u8 result = push_stringfv(scratch, format, args); 10 | print_message(app, result); 11 | va_end(args); 12 | } 13 | 14 | function Range_i64 15 | get_line_range_from_pos(Application_Links *app, Buffer_ID buffer, i64 pos){ 16 | i64 line = get_line_number_from_pos(app, buffer, pos); 17 | return get_line_pos_range(app, buffer, line); 18 | } 19 | 20 | function void 21 | qol_bot_text_set(String_Const_u8 string){ 22 | block_copy(g_qol_bot_buffer, string.str, string.size); 23 | g_qol_bot_string.size = string.size; 24 | } 25 | 26 | function void 27 | qol_bot_text_append(String_Const_u8 string){ 28 | string_append(&g_qol_bot_string, string); 29 | } 30 | 31 | function f32 32 | qol_bot_line_count(Application_Links *app){ 33 | f32 line = def_get_config_f32(app, vars_save_string_lit("bot_line_count")); 34 | return clamp(1.f, line, 5.f); 35 | } 36 | 37 | function f32 38 | qol_bot_text_height(Application_Links *app, Face_Metrics metrics){ 39 | f32 height_char = metrics.ascent - metrics.descent; 40 | f32 height_initial = qol_bot_line_count(app)*height_char; 41 | f32 height_baseline = 0.5f*height_initial; 42 | f32 height_required = height_baseline + 0.5f*height_char; 43 | return 2.f + Max(height_initial, height_required) + 2.f; 44 | } 45 | 46 | function f32 47 | qol_bot_text_y_offset(Application_Links *app, Face_Metrics metrics){ 48 | f32 height_char = metrics.ascent - metrics.descent; 49 | f32 height_initial = qol_bot_line_count(app)*height_char; 50 | f32 height_baseline = 0.5f*height_initial; 51 | return 2.f + height_baseline + 0.5f*height_char; 52 | } 53 | 54 | function Rect_f32 rect_vsplit(Rect_f32 r, f32 t, b32 c){ return !c ? rect_split_left_right(r, t).min : rect_split_left_right_neg(r, t).max; } 55 | function Rect_f32 rect_hsplit(Rect_f32 r, f32 t, b32 c){ return !c ? rect_split_top_bottom(r, t).min : rect_split_top_bottom_neg(r, t).max; } 56 | -------------------------------------------------------------------------------- /4coder_qol_hooks.cpp: -------------------------------------------------------------------------------- 1 | 2 | CUSTOM_COMMAND_SIG(qol_startup) 3 | CUSTOM_DOC("QOL command for responding to a startup event") 4 | { 5 | ProfileScope(app, "qol startup"); 6 | User_Input input = get_current_input(app); 7 | if (match_core_code(&input, CoreCode_Startup)){ 8 | String_Const_u8_Array file_names = input.event.core.file_names; 9 | load_themes_default_folder(app); 10 | default_4coder_initialize(app, file_names); 11 | default_4coder_side_by_side_panels(app, file_names); 12 | 13 | /// NOTE(BYP): Not ideal, but I'd rather simplify others testing 4coder_qol 14 | String_ID global_map_id = vars_save_string_lit("keys_global"); 15 | String_ID file_map_id = vars_save_string_lit("keys_file"); 16 | String_ID code_map_id = vars_save_string_lit("keys_code"); 17 | qol_setup_default_mapping(&framework_mapping, global_map_id, file_map_id, code_map_id); 18 | TAB_setup_default_mapping(&framework_mapping, global_map_id, file_map_id, code_map_id); 19 | 20 | b32 auto_load = def_get_config_b32(vars_save_string_lit("automatically_load_project")); 21 | if (auto_load){ 22 | load_project(app); 23 | } 24 | 25 | qol_temp_buffer = create_buffer(app, string_u8_litexpr("*qol_temp*"), 26 | BufferCreate_Background | BufferCreate_AlwaysNew | BufferCreate_NeverAttachToFile); 27 | buffer_set_setting(app, qol_temp_buffer, BufferSetting_Unimportant, true); 28 | buffer_set_setting(app, qol_temp_buffer, BufferSetting_Unkillable, true); 29 | buffer_set_setting(app, qol_temp_buffer, BufferSetting_ReadOnly, false); 30 | qol_snippet_init(app); 31 | 32 | TAB_startup_inner(app); 33 | qol_bview_init(app); 34 | } 35 | 36 | { 37 | def_audio_init(); 38 | } 39 | 40 | { 41 | def_enable_virtual_whitespace = def_get_config_b32(vars_save_string_lit("enable_virtual_whitespace")); 42 | clear_all_layouts(app); 43 | } 44 | 45 | Face_Description desc = get_global_face_description(app); 46 | desc.parameters.pt_size -= 4; 47 | qol_small_face = try_create_new_face(app, &desc); 48 | 49 | String_Const_u8 non_word_chars = string_u8_litexpr(" \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-_"); 50 | character_predicate_non_word = character_predicate_from_chars(non_word_chars); 51 | character_predicate_word = character_predicate_not(&character_predicate_non_word); 52 | 53 | Scratch_Block scratch(app); 54 | set_active_color(get_color_table_by_name(def_get_config_string(scratch, vars_save_string_lit("default_theme_name")))); 55 | qol_cur_colors = qol_color_table_init(app); 56 | qol_nxt_colors = qol_color_table_init(app); 57 | qol_color_table_copy(qol_cur_colors, active_color_table); 58 | qol_color_table_copy(qol_nxt_colors, active_color_table); 59 | } 60 | 61 | function void 62 | qol_tick(Application_Links *app, Frame_Info frame_info){ 63 | default_tick(app, frame_info); 64 | 65 | f32 dt = frame_info.animation_dt; 66 | 67 | qol_interp(qol_cur_cursor_pos, qol_nxt_cursor_pos, dt, 1e-14f); 68 | if (!near_zero(qol_cur_cursor_pos - qol_nxt_cursor_pos, 0.5f)){ 69 | animate_in_n_milliseconds(app, 0); 70 | } 71 | 72 | if (qol_try_exit_view != 0){ 73 | view_set_active(app, qol_try_exit_view); 74 | } 75 | 76 | qol_tick_colors(app, frame_info); 77 | 78 | qol_tick_bview(app, frame_info); 79 | 80 | MC_tick_inner(app, frame_info); 81 | TAB_tick_inner(app, frame_info); 82 | } 83 | 84 | BUFFER_HOOK_SIG(qol_file_save){ 85 | default_file_save(app, buffer_id); 86 | 87 | Scratch_Block scratch(app); 88 | String_Const_u8 path = push_buffer_file_name(app, scratch, buffer_id); 89 | String_Const_u8 name = string_front_of_path(path); 90 | 91 | if (qol_is_theme_file(name)){ 92 | Color_Table color_table = make_color_table(app, &global_theme_arena); 93 | Config *config = theme_parse__buffer(app, scratch, buffer_id, &global_theme_arena, &color_table); 94 | String_Const_u8 error_text = config_stringize_errors(app, scratch, config); 95 | comp_error(app, error_text); 96 | 97 | if (error_text.size > 0){ 98 | print_message(app, error_text); 99 | } 100 | else{ 101 | qol_color_table_copy(qol_nxt_colors, color_table); 102 | } 103 | } 104 | 105 | if (string_match(name, string_u8_litexpr("config.4coder"))){ 106 | View_ID view = get_active_view(app, Access_Always); 107 | view_enqueue_command_function(app, view, qol_reload_config); 108 | } 109 | 110 | if (string_match(name, string_u8_litexpr("project.4coder"))){ 111 | View_ID view = get_active_view(app, Access_Always); 112 | view_enqueue_command_function(app, view, qol_reload_project); 113 | } 114 | 115 | if (string_match(name, string_u8_litexpr("bindings.4coder"))){ 116 | View_ID view = get_active_view(app, Access_Always); 117 | view_enqueue_command_function(app, view, qol_reload_bindings); 118 | } 119 | 120 | return 0; 121 | } 122 | 123 | CUSTOM_COMMAND_SIG(qol_view_input_handler) 124 | CUSTOM_DOC("QOL Input consumption loop for views") 125 | { 126 | Scratch_Block scratch(app); 127 | default_input_handler_init(app, scratch); 128 | 129 | View_ID view = get_this_ctx_view(app, Access_Always); 130 | Managed_Scope scope = view_get_managed_scope(app, view); 131 | 132 | for (;;){ 133 | // NOTE(allen): Get input 134 | User_Input input = get_next_input(app, EventPropertyGroup_Any, 0); 135 | if (input.abort){ 136 | break; 137 | } 138 | 139 | ProfileScopeNamed(app, "before view input", view_input_profile); 140 | 141 | // NOTE(allen): Mouse Suppression 142 | Event_Property event_properties = get_event_properties(&input.event); 143 | if (suppressing_mouse && (event_properties & EventPropertyGroup_AnyMouseEvent) != 0){ 144 | continue; 145 | } 146 | 147 | // NOTE(allen): Get binding 148 | if (implicit_map_function == 0){ 149 | implicit_map_function = default_implicit_map; 150 | } 151 | Implicit_Map_Result map_result = implicit_map_function(app, 0, 0, &input.event); 152 | if (map_result.command == 0){ 153 | leave_current_input_unhandled(app); 154 | continue; 155 | } 156 | 157 | // NOTE(allen): Run the command and pre/post command stuff 158 | qol_pre_command(app, scope); 159 | ProfileCloseNow(view_input_profile); 160 | map_result.command(app); 161 | ProfileScope(app, "after view input"); 162 | qol_post_command(app, scope); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /4coder_qol_jumps.cpp: -------------------------------------------------------------------------------- 1 | 2 | CUSTOM_ID(attachment, qol_view_jumps); 3 | 4 | struct QOL_Point{ 5 | Buffer_ID buffer; 6 | i64 pos; 7 | }; 8 | 9 | struct QOL_View_Jumps{ 10 | b32 check; 11 | QOL_Point point; 12 | i64 bot, pos, top; 13 | Point_Stack_Slot ring[128]; 14 | }; 15 | 16 | function QOL_View_Jumps* qol_jumps(Application_Links *app, View_ID view){ 17 | Managed_Scope scope = view_get_managed_scope(app, view); 18 | return scope_attachment(app, scope, qol_view_jumps, QOL_View_Jumps); 19 | } 20 | 21 | function QOL_Point qol_current_point(Application_Links *app){ 22 | QOL_Point point = {}; 23 | View_ID view = get_active_view(app, Access_ReadVisible); 24 | point.buffer = view_get_buffer(app, view, Access_ReadVisible); 25 | point.pos = view_get_cursor_pos(app, view); 26 | return point; 27 | } 28 | 29 | function QOL_Point qol_point_from_slot(Application_Links *app, Point_Stack_Slot slot){ 30 | Marker *marker = (Marker*)managed_object_get_pointer(app, slot.object); 31 | return marker == 0 ? QOL_Point{-1,-1} : QOL_Point{slot.buffer, marker->pos}; 32 | } 33 | 34 | function Point_Stack_Slot qol_alloc_slot_from_point(Application_Links *app, QOL_Point point){ 35 | Point_Stack_Slot slot = {}; 36 | Managed_Object object = alloc_buffer_markers_on_buffer(app, point.buffer, 1, 0); 37 | Marker *marker = (Marker*)managed_object_get_pointer(app, object); 38 | marker->pos = point.pos; 39 | marker->lean_right = false; 40 | slot.buffer = point.buffer; 41 | slot.object = object; 42 | return slot; 43 | } 44 | 45 | function void qol_free_slot(Application_Links *app, Point_Stack_Slot slot){ 46 | managed_object_free(app, slot.object); 47 | } 48 | 49 | function b32 qol_is_jump(Application_Links *app, QOL_Point a, QOL_Point b){ 50 | if (!buffer_exists(app, a.buffer)){ return false; } 51 | return a.buffer != b.buffer || 1 < range_size(get_line_range_from_pos_range(app, a.buffer, Ii64(a.pos, b.pos))); 52 | } 53 | 54 | function void qol_pre_command_inner(Application_Links *app, Managed_Scope scope){ 55 | QOL_View_Jumps *jumps = scope_attachment(app, scope, qol_view_jumps, QOL_View_Jumps); 56 | jumps->check = true; 57 | jumps->point = qol_current_point(app); 58 | } 59 | 60 | function void qol_post_command_inner(Application_Links *app, Managed_Scope scope){ 61 | QOL_View_Jumps *jumps = scope_attachment(app, scope, qol_view_jumps, QOL_View_Jumps); 62 | QOL_Point point = qol_current_point(app); 63 | if (jumps != 0 && jumps->check && qol_is_jump(app, jumps->point, point)){ 64 | i64 cap = ArrayCount(jumps->ring); 65 | if (jumps->pos - jumps->bot == cap-1){ 66 | qol_free_slot(app, jumps->ring[jumps->bot++ % cap]); 67 | } 68 | if (2*cap <= jumps->pos){ 69 | jumps->top -= cap; 70 | jumps->bot -= cap; 71 | } 72 | jumps->ring[jumps->pos++ % cap] = qol_alloc_slot_from_point(app, jumps->point); 73 | jumps->top = jumps->pos; 74 | } 75 | } 76 | 77 | function void qol_pre_command(Application_Links *app, Managed_Scope scope){ 78 | qol_pre_command_inner(app, scope); 79 | default_pre_command(app, scope); 80 | } 81 | 82 | function void qol_post_command(Application_Links *app, Managed_Scope scope){ 83 | default_post_command(app, scope); 84 | qol_post_command_inner(app, scope); 85 | } 86 | 87 | function void qol_jump_to_point(Application_Links *app, View_ID view, QOL_Point point){ 88 | if (point.buffer != view_get_buffer(app, view, Access_Always)){ 89 | view_set_buffer(app, view, point.buffer, 0); 90 | view_set_cursor(app, view, seek_pos(point.pos)); 91 | center_view(app); 92 | } 93 | else{ 94 | Range_i64 range = Ii64(view_get_cursor_pos(app, view), point.pos); 95 | Range_i64 lines = get_line_range_from_pos_range(app, point.buffer, range); 96 | f32 y_diff = view_line_y_difference(app, view, lines.max, lines.min); 97 | view_set_cursor(app, view, seek_pos(point.pos)); 98 | if (rect_height(view_get_buffer_region(app, view)) < y_diff){ 99 | center_view(app); 100 | } 101 | } 102 | } 103 | 104 | CUSTOM_COMMAND_SIG(qol_jump_down) 105 | CUSTOM_DOC("[QOL] Jump down the view's jump stack") 106 | { 107 | View_ID view = get_active_view(app, Access_ReadVisible); 108 | QOL_View_Jumps *jumps = qol_jumps(app, view); 109 | jumps->check = false; 110 | 111 | if (jumps->pos == jumps->bot){ return; } 112 | QOL_Point point = qol_point_from_slot(app, ArraySafe(jumps->ring, --jumps->pos)); 113 | if (!buffer_exists(app, point.buffer)){ return; } 114 | 115 | if (jumps->pos+1 == jumps->top){ 116 | ArraySafe(jumps->ring, jumps->top++) = qol_alloc_slot_from_point(app, qol_current_point(app)); 117 | } 118 | qol_jump_to_point(app, view, point); 119 | } 120 | 121 | CUSTOM_COMMAND_SIG(qol_jump_up) 122 | CUSTOM_DOC("[QOL] Jump back up the view's jump stack") 123 | { 124 | View_ID view = get_active_view(app, Access_ReadVisible); 125 | QOL_View_Jumps *jumps = qol_jumps(app, view); 126 | jumps->check = false; 127 | 128 | if (jumps->top <= jumps->pos+1){ return; } 129 | QOL_Point point = qol_point_from_slot(app, ArraySafe(jumps->ring, ++jumps->pos)); 130 | if (!buffer_exists(app, point.buffer)){ return; } 131 | qol_jump_to_point(app, view, point); 132 | } 133 | -------------------------------------------------------------------------------- /4coder_qol_lister.h: -------------------------------------------------------------------------------- 1 | 2 | function Lister_Result qol_run_lister(Application_Links *app, Lister *lister); 3 | function void qol_lister__backspace_text_field__default(Application_Links *app); 4 | function void qol_lister__backspace_text_field__file_path(Application_Links *app); -------------------------------------------------------------------------------- /4coder_qol_snippets.cpp: -------------------------------------------------------------------------------- 1 | 2 | global Buffer_ID qol_snippet_buffer; 3 | 4 | function void 5 | qol_snippet_init(Application_Links *app){ 6 | qol_snippet_buffer = create_buffer(app, string_u8_litexpr("*qol_snippet*"), 7 | BufferCreate_Background | BufferCreate_AlwaysNew | BufferCreate_NeverAttachToFile); 8 | buffer_set_setting(app, qol_snippet_buffer, BufferSetting_Unimportant, true); 9 | buffer_set_setting(app, qol_snippet_buffer, BufferSetting_Unkillable, true); 10 | buffer_set_setting(app, qol_snippet_buffer, BufferSetting_ReadOnly, false); 11 | } 12 | 13 | CUSTOM_COMMAND_SIG(qol_snippet_begin) 14 | CUSTOM_DOC("[QOL] Opens *qol_snippet* empty buffer") 15 | { 16 | View_ID view = open_view(app, get_next_view_after_active(app, Access_Always), ViewSplit_Bottom); 17 | view_set_split_proportion(app, view, 0.2f); 18 | view_set_active(app, view); 19 | view_set_buffer(app, view, qol_snippet_buffer, 0); 20 | buffer_replace_range(app, qol_snippet_buffer, buffer_range(app, qol_snippet_buffer), string_u8_empty); 21 | } 22 | 23 | CUSTOM_COMMAND_SIG(qol_snippet_end) 24 | CUSTOM_DOC("[QOL] ") 25 | { 26 | Scratch_Block scratch(app); 27 | View_ID view = get_first_view_with_buffer(app, qol_snippet_buffer); 28 | if (view == 0){ return; } 29 | 30 | Buffer_ID buffer = qol_snippet_buffer; 31 | Range_i64 range = buffer_range(app, qol_snippet_buffer); 32 | String_Const_u8 str = push_buffer_range(app, scratch, buffer, range); 33 | String_Const_u8 name = string_u8_empty; 34 | String_Const_u8 text = string_u8_empty; 35 | i64 cursor = view_get_cursor_pos(app, view); 36 | i64 mark = view_get_mark_pos(app, view); 37 | 38 | // Snippet Name 39 | { 40 | Query_Bar_Group group(app); 41 | u8 string_space[256]; 42 | Query_Bar bar = {}; 43 | bar.prompt = string_u8_litexpr("Snippet Name: "); 44 | bar.string = SCu8(string_space, (u64)0); 45 | bar.string_capacity = sizeof(string_space); 46 | if (!query_user_string(app, &bar)){ return; } 47 | name = bar.string; 48 | } 49 | 50 | // Snippet Text 51 | { 52 | Character_Predicate pred_esc = character_predicate_from_chars(string_u8_litexpr("\"\\\n\t")); 53 | String_Const_u8 quote = string_u8_litexpr("\\\""); 54 | String_Const_u8 tab = string_u8_litexpr("\\t"); 55 | String_Const_u8 newline = string_u8_litexpr("\\n"); 56 | String_Const_u8 backslash = string_u8_litexpr("\\\\"); 57 | 58 | String8List list = {}; 59 | for (i64 pos = 0;;){ 60 | String_Match match = buffer_seek_character_class(app, buffer, &pred_esc, Scan_Forward, pos-1); 61 | if (match.buffer == 0){ 62 | string_list_push(scratch, &list, string_substring(str, Ii64(pos, range.end))); 63 | break; 64 | } 65 | 66 | String_Const_u8 esc_str = string_u8_empty; 67 | switch (buffer_get_char(app, buffer, match.range.min)){ 68 | case '"':{ esc_str = quote; } break; 69 | case '\t':{ esc_str = tab; } break; 70 | case '\n':{ esc_str = newline; } break; 71 | case '\\':{ esc_str = backslash; } break; 72 | } 73 | string_list_push(scratch, &list, string_substring(str, Ii64(pos, match.range.min))); 74 | string_list_push(scratch, &list, esc_str); 75 | pos = match.range.max; 76 | if (!range_contains(range, pos)){ break; } 77 | } 78 | text = string_list_flatten(scratch, list); 79 | } 80 | 81 | String_Const_u8 snippet = push_stringf(scratch, "\t{\"%S\", \"%S\", %lld, %lld},\n", name, text, cursor, mark); 82 | String_Const_u8 full_path = push_stringf(scratch, "%Ssnippets.4coder", system_get_path(scratch, SystemPath_Binary)); 83 | Buffer_ID buffer_snippets = 0; 84 | if (!open_file(app, &buffer_snippets, full_path, 0, 0)){ return; } 85 | 86 | b32 did_write = 0; 87 | Range_i64 snippet_range = buffer_range(app, buffer_snippets); 88 | String_Const_u8 str_snippets = push_buffer_range(app, scratch, buffer_snippets, snippet_range); 89 | 90 | Config *parsed = def_config_from_text(app, scratch, full_path, str_snippets); 91 | if (parsed != 0){ 92 | for (Config_Assignment *node = parsed->first; node != 0; node = node->next){ 93 | if (string_match(node->l->identifier, SCu8("snippets")) && node->r->type == ConfigRValueType_Compound){ 94 | i64 pos = node->r->range.end-1; 95 | buffer_replace_range(app, buffer_snippets, Ii64(pos), snippet); 96 | buffer_save(app, buffer_snippets, full_path, 0); 97 | did_write = true; 98 | break; 99 | } 100 | } 101 | } 102 | 103 | if (!did_write){ 104 | String_Const_u8 string = push_stringf(scratch, "snippets = {\n%S};", snippet); 105 | Range_i64 replace = (parsed != 0 ? Ii64(0,0) : snippet_range); 106 | buffer_replace_range(app, buffer_snippets, replace, string); 107 | buffer_save(app, buffer_snippets, full_path, 0); 108 | } 109 | view_enqueue_command_function(app, view, close_panel); 110 | } 111 | -------------------------------------------------------------------------------- /4coder_qol_token.h: -------------------------------------------------------------------------------- 1 | 2 | enum{ 3 | qol_TokenKind_Primitive = TokenBaseKind_COUNT, 4 | qol_TokenKind_Control, 5 | qol_TokenKind_Struct, 6 | }; 7 | -------------------------------------------------------------------------------- /apply.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | copy .\custom_4coder.* ..\custom_4coder.* 3 | copy .\custom_4coder.* ..\qol\custom_4coder.* -------------------------------------------------------------------------------- /apply.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp ./custom_4coder.* ../ 4 | cp ./custom_4coder.* ../4coder_qol/ 5 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set qol_dir=%cd% 3 | IF NOT exist ..\test_build ( 4 | mkdir ..\test_build 5 | xcopy /E ..\themes\ ..\test_build\themes\ 6 | xcopy /E ..\fonts\ ..\test_build\fonts\ 7 | copy ..\4ed.exe ..\test_build\4ed.exe 8 | copy ..\4ed_app.dll ..\test_build\4ed_app.dll 9 | copy ..\config.4coder ..\test_build\config.4coder 10 | ) 11 | pushd ..\test_build 12 | call %qol_dir%\custom\bin\buildsuper_x64-win.bat %qol_dir%\4coder_qol.cpp %1 13 | call %qol_dir%\apply.bat 14 | popd 15 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | qol_dir=$(pwd) 4 | 5 | if [ ! -d ../test_build ]; then 6 | mkdir ../test_build 7 | cp -r ../themes/ ../test_build/themes/ 8 | cp -r ../fonts/ ../test_build/fonts/ 9 | cp ../4ed ../test_build/4ed 10 | cp ../4ed_app.so ../test_build/4ed_app.so 11 | cp ../config.4coder ../test_build/config.4coder 12 | fi 13 | 14 | 15 | cd ../test_build 16 | ${qol_dir}/custom/bin/buildsuper_x64-linux.sh ${qol_dir}/4coder_qol.cpp $1 17 | ${qol_dir}/apply.sh 18 | -------------------------------------------------------------------------------- /build_lexer.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call custom\bin\build_one_time.bat .\4coder_qol_cpp_lexer_gen.cpp ..\ %1 3 | del ..\4coder_qol_cpp_lexer_gen.obj 4 | ..\one_time.exe 5 | del ..\one_time.* -------------------------------------------------------------------------------- /config.4coder: -------------------------------------------------------------------------------- 1 | // Command Mapping 2 | // "" - Leave the bindings unaltered - use this when writing your own customization! 3 | // "choose" - Ask 4coder to choose based on platform. 4 | // "default" - Use the default keybindings 4coder has always had. 5 | // "mac-default" - Use keybindings similar to those found in other Mac applications. 6 | mapping = ""; 7 | 8 | // MODE 9 | // "4coder" - The default 4coder mode that has been around since the beginning of time (2015) 10 | // "notepad-like" - Single "thin" cursor and highlight ranges like in notepad, sublime, notepad++, etc 11 | mode = "4coder"; 12 | bind_by_physical_key = false; 13 | 14 | // UI 15 | use_file_bars = true; 16 | hide_file_bar_in_ui = false; 17 | use_error_highlight = true; 18 | use_jump_highlight = true; 19 | use_scope_highlight = true; 20 | use_paren_helper = true; 21 | use_comment_keyword = true; 22 | use_comment_annotations = true; // highlight @iden in comments 23 | use_code_peek = true; 24 | lister_whole_word_backspace_when_modified = true; 25 | show_line_number_margins = true; 26 | enable_output_wrapping = false; 27 | highlight_line_at_cursor = true; 28 | 29 | filebar_on_top = false; 30 | show_hex_colors = true; 31 | file_explorer_cli = "explorer"; // non-Windows set to "open" 32 | bot_line_count = 1.5f; 33 | 34 | // "" - Rectangle 35 | // "|" - Thin-line 36 | // "_" - Underscore 37 | // "L" - Corner 38 | cursor_style = ""; 39 | mark_style = "L"; 40 | 41 | scroll_margin_x = 1.f; 42 | scroll_margin_y = 2.f; 43 | 44 | enable_undo_fade_out = true; 45 | 46 | // cursor_roundess is a value [0,50] setting the radius of 47 | // the cursor and mark's roundness as a percentage of their width 48 | // (At 50 the left and right corners will be so round they form a semi-circle, 49 | // hence 50 is the max) 50 | cursor_roundness = 45; 51 | 52 | // mark_thickness is a pixel count value setting the 53 | // thickness of the mark wire box in original mode 54 | mark_thickness = 2; 55 | 56 | // lister_roundess is a value [0,50] setting the radius of 57 | // the lister items' roundness as a percentage of their height 58 | lister_roundness = 20; 59 | 60 | // Code Wrapping 61 | treat_as_code = ".cpp.c.hpp.h.cc.cs.java.rs.glsl.m.mm.4coder"; 62 | enable_virtual_whitespace = true; 63 | virtual_whitespace_regular_indent = 2; 64 | enable_code_wrapping = false; 65 | 66 | // This only applies to code files in code-wrapping mode. 67 | // Plain text and code files without virtual-whitespace will not be effected. 68 | automatically_indent_text_on_save = true; 69 | 70 | // When set to true, all unsaved changes will be saved on a build. 71 | automatically_save_changes_on_build = true; 72 | 73 | // Load project on startup 74 | automatically_load_project = true; 75 | 76 | // Indentation 77 | indent_with_tabs = false; 78 | indent_width = 4; 79 | default_tab_width = 4; 80 | 81 | // Theme 82 | default_theme_name = "theme-qol"; 83 | 84 | // Font 85 | default_font_name = "liberation-mono.ttf"; 86 | default_font_size = 16; 87 | default_font_hinting = true; 88 | 89 | // aa modes: 90 | // 8bit - mono-chrome 0-255 opacity channel per pixel 91 | // 1bit - mono-chrome 0/1 opacity channel per pixel 92 | default_font_aa_mode = "8bit"; 93 | 94 | // User 95 | user_name = "QOL"; 96 | 97 | // Keyboard AltGr setting 98 | lalt_lctrl_is_altgr = false; 99 | 100 | // Project setup configuration 101 | default_compiler_bat = "cl"; 102 | default_flags_bat = "-FC -GR- -EHa- -nologo -Zi"; 103 | default_compiler_sh = "g++"; 104 | default_flags_sh = "-g"; 105 | -------------------------------------------------------------------------------- /custom/4coder_app_links_allocator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder app links base allocator 3 | */ 4 | 5 | // TOP 6 | 7 | Scratch_Block::Scratch_Block(Application_Links *app){ 8 | Thread_Context *t = this->tctx = get_thread_context(app); 9 | this->arena = tctx_reserve(t); 10 | this->temp = begin_temp(this->arena); 11 | } 12 | 13 | Scratch_Block::Scratch_Block(Application_Links *app, Arena *a1){ 14 | Thread_Context *t = this->tctx = get_thread_context(app); 15 | this->arena = tctx_reserve(t, a1); 16 | this->temp = begin_temp(this->arena); 17 | } 18 | 19 | Scratch_Block::Scratch_Block(Application_Links *app, Arena *a1, Arena *a2){ 20 | Thread_Context *t = this->tctx = get_thread_context(app); 21 | this->arena = tctx_reserve(t, a1, a2); 22 | this->temp = begin_temp(this->arena); 23 | } 24 | 25 | Scratch_Block::Scratch_Block(Application_Links *app, Arena *a1, Arena *a2, Arena *a3){ 26 | Thread_Context *t = this->tctx = get_thread_context(app); 27 | this->arena = tctx_reserve(t, a1, a2, a3); 28 | this->temp = begin_temp(this->arena); 29 | } 30 | 31 | // BOTTOM 32 | -------------------------------------------------------------------------------- /custom/4coder_async_tasks.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder_async_tasks.cpp - Types for the custom layer asynchronous task system. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_ASYNC_TASKS_H) 8 | #define FCODER_ASYNC_TASKS_H 9 | 10 | typedef void Async_Task_Function_Type(struct Async_Context *actx, String_Const_u8 data); 11 | typedef u64 Async_Task; 12 | 13 | struct Async_Thread{ 14 | struct Async_System *async_system; 15 | System_Thread thread; 16 | struct Async_Node *node; 17 | Async_Task task; 18 | b32 cancel_signal; 19 | }; 20 | 21 | struct Async_Node{ 22 | union{ 23 | Async_Node *next; 24 | Node node; 25 | }; 26 | Async_Task task; 27 | Async_Thread *thread; 28 | Async_Task_Function_Type *func; 29 | String_Const_u8 data; 30 | }; 31 | 32 | struct Async_System{ 33 | void *cmd_context; 34 | 35 | Heap node_heap; 36 | Arena node_arena; 37 | System_Mutex mutex; 38 | System_Condition_Variable cv; 39 | System_Condition_Variable join_cv; 40 | Async_Task task_id_counter; 41 | Async_Node *free_nodes; 42 | Node task_sent; 43 | i32 task_count; 44 | 45 | Async_Thread thread; 46 | }; 47 | 48 | struct Async_Context{ 49 | Application_Links *app; 50 | Async_Thread *thread; 51 | }; 52 | 53 | #endif 54 | 55 | // BOTTOM 56 | -------------------------------------------------------------------------------- /custom/4coder_audio.h: -------------------------------------------------------------------------------- 1 | /* date = November 23rd 2020 1:18 pm */ 2 | 3 | #ifndef FCODER_AUDIO_H 4 | #define FCODER_AUDIO_H 5 | 6 | //////////////////////////////// 7 | // NOTE(allen): Default Mixer Types 8 | 9 | struct Audio_Control{ 10 | volatile f32 channel_volume[2]; 11 | volatile u32 generation; 12 | volatile u32 last_played_sample_index; 13 | volatile b32 loop; 14 | }; 15 | 16 | struct Audio_Clip{ 17 | i16 *samples; 18 | Audio_Control *control; 19 | f32 channel_volume[2]; 20 | 21 | u32 sample_count; 22 | u32 at_sample_index; 23 | }; 24 | 25 | struct Audio_System{ 26 | volatile u32 quit; 27 | volatile u32 ticket; 28 | volatile u32 serving; 29 | volatile u32 generation; 30 | 31 | Audio_Clip playing_clips[64]; 32 | 33 | // NOTE(casey): Requests to play sounds are written to a pending array to avoid long locking 34 | volatile u32 pending_clip_count; 35 | Audio_Clip pending_clips[64]; 36 | }; 37 | 38 | //////////////////////////////// 39 | // NOTE(allen): Default Mixer 40 | 41 | function void def_audio_init(void); 42 | function void def_audio_play_clip(Audio_Clip clip, Audio_Control *control); 43 | function b32 def_audio_is_playing(Audio_Control *control); 44 | function void def_audio_stop(Audio_Control *control); 45 | 46 | function void def_audio_mix_sources(void *ctx, f32 *mix_buffer, u32 sample_count); 47 | function void def_audio_mix_destination(i16 *dst, f32 *src, u32 sample_count); 48 | 49 | //////////////////////////////// 50 | // NOTE(allen): Loading Clip 51 | 52 | function Audio_Clip audio_clip_from_wav_data(String_Const_u8 data); 53 | function Audio_Clip audio_clip_from_wav_FILE(Arena *arena, FILE *file); 54 | function Audio_Clip audio_clip_from_wav_file_name(Arena *arena, char *file_name); 55 | 56 | #endif //4CODER_AUDIO_H 57 | -------------------------------------------------------------------------------- /custom/4coder_auto_indent.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_auto_indent.h - Auto-indentation types. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_AUTO_INDENT_H) 8 | #define FCODER_AUTO_INDENT_H 9 | 10 | typedef u32 Indent_Flag; 11 | enum{ 12 | Indent_ClearLine = 0x1, 13 | Indent_UseTab = 0x2, 14 | Indent_FullTokens = 0x4, 15 | }; 16 | 17 | struct Nest{ 18 | Nest *next; 19 | Token_Base_Kind kind; 20 | i64 indent; 21 | }; 22 | 23 | struct Nest_Alloc{ 24 | Nest *free_nest; 25 | }; 26 | 27 | struct Indent_Line_Cache{ 28 | i64 where_token_starts; 29 | i64 line_number_for_cached_indent; 30 | i64 start_pos; 31 | i64 one_past_last_pos; 32 | Indent_Info indent_info; 33 | }; 34 | 35 | #endif 36 | 37 | // BOTTOM 38 | -------------------------------------------------------------------------------- /custom/4coder_buffer_seek_constructors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Buffer seek descriptor constructors. 3 | */ 4 | 5 | // TOP 6 | 7 | static Buffer_Seek 8 | seek_pos(i64 pos){ 9 | Buffer_Seek result; 10 | result.type = buffer_seek_pos; 11 | result.pos = pos; 12 | return(result); 13 | } 14 | 15 | static Buffer_Seek 16 | seek_line_col(i64 line, i64 col){ 17 | Buffer_Seek result; 18 | result.type = buffer_seek_line_col; 19 | result.line = line; 20 | result.col = col; 21 | return(result); 22 | } 23 | 24 | // BOTTOM 25 | -------------------------------------------------------------------------------- /custom/4coder_build_commands.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_build_commands.h - Commands for building types. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_BUILD_COMMANDS_H) 8 | #define FCODER_BUILD_COMMANDS_H 9 | 10 | function void comp_error(Application_Links *app, String_Const_u8 error_text); 11 | 12 | #endif 13 | 14 | // BOTTOM -------------------------------------------------------------------------------- /custom/4coder_cli_command.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_system_command.cpp - Commands for executing arbitrary system command line instructions. 3 | */ 4 | 5 | // TOP 6 | 7 | CUSTOM_COMMAND_SIG(execute_previous_cli) 8 | CUSTOM_DOC("If the command execute_any_cli has already been used, this will execute a CLI reusing the most recent buffer name and command.") 9 | { 10 | String_Const_u8 out_buffer = SCu8(out_buffer_space); 11 | String_Const_u8 cmd = SCu8(command_space); 12 | String_Const_u8 hot_directory = SCu8(hot_directory_space); 13 | 14 | if (out_buffer.size > 0 && cmd.size > 0 && hot_directory.size > 0){ 15 | View_ID view = get_active_view(app, Access_Always); 16 | Buffer_Identifier id = buffer_identifier(out_buffer); 17 | exec_system_command(app, view, id, hot_directory, cmd, CLI_OverlapWithConflict|CLI_CursorAtEnd|CLI_SendEndSignal); 18 | lock_jump_buffer(app, out_buffer); 19 | } 20 | } 21 | 22 | CUSTOM_COMMAND_SIG(execute_any_cli) 23 | CUSTOM_DOC("Queries for an output buffer name and system command, runs the system command as a CLI and prints the output to the specified buffer."){ 24 | Scratch_Block scratch(app); 25 | Query_Bar_Group group(app); 26 | 27 | Query_Bar bar_out = {}; 28 | bar_out.prompt = string_u8_litexpr("Output Buffer: "); 29 | bar_out.string = SCu8(out_buffer_space, (u64)0); 30 | bar_out.string_capacity = sizeof(out_buffer_space); 31 | if (!query_user_string(app, &bar_out)) return; 32 | bar_out.string.size = clamp_top(bar_out.string.size, sizeof(out_buffer_space) - 1); 33 | out_buffer_space[bar_out.string.size] = 0; 34 | 35 | Query_Bar bar_cmd = {}; 36 | bar_cmd.prompt = string_u8_litexpr("Command: "); 37 | bar_cmd.string = SCu8(command_space, (u64)0); 38 | bar_cmd.string_capacity = sizeof(command_space); 39 | if (!query_user_string(app, &bar_cmd)) return; 40 | bar_cmd.string.size = clamp_top(bar_cmd.string.size, sizeof(command_space) - 1); 41 | command_space[bar_cmd.string.size] = 0; 42 | 43 | String_Const_u8 hot = push_hot_directory(app, scratch); 44 | { 45 | u64 size = clamp_top(hot.size, sizeof(hot_directory_space)); 46 | block_copy(hot_directory_space, hot.str, size); 47 | hot_directory_space[hot.size] = 0; 48 | } 49 | 50 | execute_previous_cli(app); 51 | } 52 | 53 | // BOTTOM 54 | -------------------------------------------------------------------------------- /custom/4coder_clipboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_clipboard.cpp - Copy paste commands and clipboard related setup. 3 | */ 4 | 5 | // TOP 6 | 7 | #ifndef FCODER_CLIPBOARD_H 8 | #define FCODER_CLIPBOARD_H 9 | 10 | struct Clipboard{ 11 | Arena arena; 12 | Heap heap; 13 | String_Const_u8 *clips; 14 | u32 clip_index; 15 | u32 clip_capacity; 16 | }; 17 | 18 | #endif //4CODER_CLIPBOARD_H 19 | 20 | // BOTTOM 21 | -------------------------------------------------------------------------------- /custom/4coder_code_index.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_code_index.h - Generic code indexing system for layout, definition jumps, etc. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_CODE_INDEX_H) 8 | #define FCODER_CODE_INDEX_H 9 | 10 | struct Code_Index_Nest_List{ 11 | struct Code_Index_Nest *first; 12 | struct Code_Index_Nest *last; 13 | i32 count; 14 | }; 15 | 16 | struct Code_Index_Nest_Ptr_Array{ 17 | struct Code_Index_Nest **ptrs; 18 | i32 count; 19 | }; 20 | 21 | typedef i32 Code_Index_Nest_Kind; 22 | enum{ 23 | CodeIndexNest_Scope, 24 | CodeIndexNest_Paren, 25 | CodeIndexNest_Preprocessor, 26 | CodeIndexNest_Statement, 27 | }; 28 | 29 | struct Code_Index_Nest{ 30 | Code_Index_Nest *next; 31 | 32 | Code_Index_Nest_Kind kind; 33 | b32 is_closed; 34 | Range_i64 open; 35 | Range_i64 close; 36 | 37 | struct Code_Index_File *file; 38 | Code_Index_Nest *parent; 39 | 40 | Code_Index_Nest_List nest_list; 41 | Code_Index_Nest_Ptr_Array nest_array; 42 | }; 43 | 44 | typedef i64 Code_Index_Note_Kind; 45 | enum{ 46 | CodeIndexNote_Type, 47 | CodeIndexNote_Function, 48 | CodeIndexNote_Macro, 49 | CodeIndexNote_Enum, 50 | CodeIndexNote_Global, 51 | CodeIndexNote_4coderCommand, 52 | }; 53 | 54 | struct Code_Index_Note{ 55 | Code_Index_Note *next; 56 | Code_Index_Note_Kind note_kind; 57 | Range_i64 pos; 58 | String_Const_u8 text; 59 | struct Code_Index_File *file; 60 | Code_Index_Nest *parent; 61 | 62 | Code_Index_Note *prev_in_hash; 63 | Code_Index_Note *next_in_hash; 64 | }; 65 | 66 | struct Code_Index_Note_List{ 67 | Code_Index_Note *first; 68 | Code_Index_Note *last; 69 | i32 count; 70 | }; 71 | 72 | struct Code_Index_Note_Ptr_Array{ 73 | Code_Index_Note **ptrs; 74 | i32 count; 75 | }; 76 | 77 | struct Code_Index_File{ 78 | Code_Index_Nest_List nest_list; 79 | Code_Index_Nest_Ptr_Array nest_array; 80 | Code_Index_Note_List note_list; 81 | Code_Index_Note_Ptr_Array note_array; 82 | Buffer_ID buffer; 83 | }; 84 | 85 | struct Code_Index_File_Storage{ 86 | Code_Index_File_Storage *next; 87 | Code_Index_File_Storage *prev; 88 | Arena arena; 89 | Code_Index_File *file; 90 | }; 91 | 92 | struct Code_Index{ 93 | System_Mutex mutex; 94 | Arena node_arena; 95 | Table_u64_u64 buffer_to_index_file; 96 | Code_Index_File_Storage *free_storage; 97 | Code_Index_File_Storage *storage_first; 98 | Code_Index_File_Storage *storage_last; 99 | i32 storage_count; 100 | 101 | Code_Index_Note_List name_hash[4099]; 102 | }; 103 | 104 | //////////////////////////////// 105 | 106 | struct Generic_Parse_State{ 107 | Application_Links *app; 108 | Arena *arena; 109 | String_Const_u8 contents; 110 | Token_Iterator_Array it; 111 | u8 *prev_line_start; 112 | b32 finished; 113 | 114 | i32 scope_counter; 115 | i32 paren_counter; 116 | b32 in_preprocessor; 117 | b32 in_statement; 118 | 119 | b32 do_cpp_parse; 120 | }; 121 | 122 | #endif 123 | 124 | // BOTTOM 125 | -------------------------------------------------------------------------------- /custom/4coder_code_index_listers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_code_index_listers.cpp - Listers for exploring the contents of the code index. 3 | */ 4 | 5 | // TOP 6 | 7 | struct Tiny_Jump{ 8 | Buffer_ID buffer; 9 | i64 pos; 10 | }; 11 | 12 | function void 13 | lister_fill_index(Application_Links *app, Lister *lister){ 14 | code_index_lock(); 15 | for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); 16 | buffer != 0; 17 | buffer = get_buffer_next(app, buffer, Access_Always)){ 18 | Code_Index_File *file = code_index_get_file(buffer); 19 | if (file != 0){ 20 | for (i32 i = 0; i < file->note_array.count; i += 1){ 21 | Code_Index_Note *note = file->note_array.ptrs[i]; 22 | Tiny_Jump *jump = push_array(lister->arena, Tiny_Jump, 1); 23 | jump->buffer = buffer; 24 | jump->pos = note->pos.first; 25 | 26 | String_Const_u8 sort = (note->note_kind == CodeIndexNote_Type ? string_u8_litexpr("type") : 27 | note->note_kind == CodeIndexNote_Function ? string_u8_litexpr("function") : 28 | note->note_kind == CodeIndexNote_Macro ? string_u8_litexpr("macro") : 29 | note->note_kind == CodeIndexNote_Enum ? string_u8_litexpr("enum") : 30 | note->note_kind == CodeIndexNote_Global ? string_u8_litexpr("global") : string_u8_empty); 31 | lister_add_item(lister, note->text, sort, jump, 0); 32 | } 33 | } 34 | } 35 | code_index_unlock(); 36 | } 37 | 38 | CUSTOM_UI_COMMAND_SIG(jump_to_definition) 39 | CUSTOM_DOC("List all definitions in the code index and jump to one chosen by the user.") 40 | { 41 | Scratch_Block scratch(app); 42 | Lister_Block lister(app, scratch); 43 | lister_set_query(lister, string_u8_litexpr("Definition:")); 44 | lister_set_default_handlers(lister); 45 | 46 | lister_fill_index(app, lister); 47 | 48 | Lister_Result l_result = run_lister(app, lister); 49 | Tiny_Jump result = {}; 50 | if (!l_result.canceled && l_result.user_data != 0){ 51 | block_copy_struct(&result, (Tiny_Jump*)l_result.user_data); 52 | } 53 | 54 | if (result.buffer != 0){ 55 | View_ID view = get_this_ctx_view(app, Access_Always); 56 | point_stack_push_view_cursor(app, view); 57 | jump_to_location(app, view, result.buffer, result.pos); 58 | } 59 | } 60 | 61 | CUSTOM_UI_COMMAND_SIG(jump_to_definition_at_cursor) 62 | CUSTOM_DOC("Jump to the first definition in the code index matching an identifier at the cursor") 63 | { 64 | View_ID view = get_active_view(app, Access_Visible); 65 | 66 | if (view != 0){ 67 | Scratch_Block scratch(app); 68 | String_Const_u8 query = push_token_or_word_under_active_cursor(app, scratch); 69 | 70 | code_index_lock(); 71 | for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); 72 | buffer != 0; 73 | buffer = get_buffer_next(app, buffer, Access_Always)){ 74 | Code_Index_File *file = code_index_get_file(buffer); 75 | if (file != 0){ 76 | for (i32 i = 0; i < file->note_array.count; i += 1){ 77 | Code_Index_Note *note = file->note_array.ptrs[i]; 78 | if (string_match(note->text, query)){ 79 | point_stack_push_view_cursor(app, view); 80 | jump_to_location(app, view, buffer, note->pos.first); 81 | goto done; 82 | } 83 | } 84 | } 85 | } 86 | done:; 87 | code_index_unlock(); 88 | } 89 | } 90 | 91 | // BOTTOM 92 | -------------------------------------------------------------------------------- /custom/4coder_codepoint_map.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_codepoint_map.cpp - Codepoint map to index 3 | */ 4 | 5 | // TOP 6 | 7 | function b32 8 | codepoint_index_map_read(Codepoint_Index_Map *map, u32 codepoint, u16 *index_out){ 9 | b32 success = true; 10 | if (codepoint == 0 && map->has_zero_index){ 11 | *index_out = map->zero_index; 12 | } 13 | else if (table_read(&map->table, codepoint, index_out)){ 14 | // NOTE(allen): do nothing 15 | } 16 | else{ 17 | success = false; 18 | } 19 | return(success); 20 | } 21 | 22 | function u16 23 | codepoint_index_map_count(Codepoint_Index_Map *map){ 24 | return(map->max_index + 1); 25 | } 26 | 27 | function f32 28 | font_get_glyph_advance(Face_Advance_Map *map, Face_Metrics *metrics, u32 codepoint, f32 tab_multiplier){ 29 | f32 result = 0.f; 30 | if (codepoint == '\t'){ 31 | result = metrics->space_advance*tab_multiplier; 32 | } 33 | else{ 34 | if (character_is_whitespace(codepoint)){ 35 | codepoint = ' '; 36 | } 37 | u16 index = 0; 38 | if (codepoint_index_map_read(&map->codepoint_to_index, codepoint, &index)){ 39 | if (index < map->index_count){ 40 | result = map->advance[index]; 41 | } 42 | } 43 | } 44 | return(result); 45 | } 46 | 47 | function f32 48 | font_get_max_glyph_advance_range(Face_Advance_Map *map, Face_Metrics *metrics, 49 | u32 codepoint_first, u32 codepoint_last, 50 | f32 tab_multiplier){ 51 | f32 result = font_get_glyph_advance(map, metrics, codepoint_first, tab_multiplier); 52 | for (u32 i = codepoint_first + 1; i <= codepoint_last; i += 1){ 53 | f32 a = font_get_glyph_advance(map, metrics, i, tab_multiplier); 54 | result = Max(a, result); 55 | } 56 | return(result); 57 | } 58 | 59 | function f32 60 | font_get_average_glyph_advance_range(Face_Advance_Map *map, Face_Metrics *metrics, 61 | u32 codepoint_first, u32 codepoint_last, 62 | f32 tab_multiplier){ 63 | f32 result = 0.f; 64 | for (u32 i = codepoint_first; i <= codepoint_last; i += 1){ 65 | result += font_get_glyph_advance(map, metrics, i, tab_multiplier); 66 | } 67 | result /= (f32)(codepoint_last - codepoint_first + 1); 68 | return(result); 69 | } 70 | 71 | // BOTTOM 72 | -------------------------------------------------------------------------------- /custom/4coder_combined_write_commands.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_combined_write_commands.cpp - Commands for writing text specialized for particular contexts. 3 | */ 4 | 5 | // TOP 6 | 7 | struct Snippet{ 8 | char *name; 9 | char *text; 10 | i32 cursor_offset; 11 | i32 mark_offset; 12 | }; 13 | 14 | struct Snippet_Array{ 15 | Snippet *snippets; 16 | i32 count; 17 | }; 18 | 19 | // BOTTOM 20 | -------------------------------------------------------------------------------- /custom/4coder_command_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_command_map.h - Command management types 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_CODEPOINT_MAP_H) 8 | #define FCODER_CODEPOINT_MAP_H 9 | 10 | typedef i64 Command_Map_ID; 11 | 12 | struct Command_Trigger{ 13 | Command_Trigger *next; 14 | Input_Event_Kind kind; 15 | u32 sub_code; 16 | Input_Modifier_Set mods; 17 | }; 18 | 19 | struct Command_Trigger_List{ 20 | Command_Trigger *first; 21 | Command_Trigger *last; 22 | }; 23 | 24 | struct Command_Binding{ 25 | union{ 26 | Custom_Command_Function *custom; 27 | char *name; 28 | }; 29 | 30 | Command_Binding(); 31 | Command_Binding(Custom_Command_Function *c); 32 | Command_Binding(char *n); 33 | 34 | operator Custom_Command_Function*(); 35 | operator char*(); 36 | }; 37 | 38 | struct Command_Modified_Binding{ 39 | Command_Modified_Binding *next; 40 | SNode order_node; 41 | Input_Modifier_Set mods; 42 | Command_Binding binding; 43 | }; 44 | 45 | struct Command_Binding_List{ 46 | Command_Binding_List *next; 47 | SNode *first; 48 | SNode *last; 49 | i32 count; 50 | }; 51 | 52 | struct Command_Map{ 53 | Command_Map *next; 54 | Command_Map *prev; 55 | Command_Map_ID id; 56 | Command_Map_ID parent; 57 | Command_Binding text_input_command; 58 | Arena node_arena; 59 | Table_u64_u64 event_code_to_binding_list; 60 | Table_u64_u64 cmd_to_binding_trigger; 61 | Command_Modified_Binding *binding_first; 62 | Command_Modified_Binding *binding_last; 63 | Command_Binding_List *list_first; 64 | Command_Binding_List *list_last; 65 | 66 | struct Binding_Unit *real_beginning; 67 | }; 68 | 69 | struct Mapping{ 70 | Arena node_arena; 71 | Heap heap; 72 | Base_Allocator heap_wrapper; 73 | Table_u64_u64 id_to_map; 74 | Command_Map_ID id_counter; 75 | Command_Map *first_map; 76 | Command_Map *last_map; 77 | Command_Map *free_maps; 78 | Command_Modified_Binding *free_bindings; 79 | Command_Binding_List *free_lists; 80 | }; 81 | 82 | typedef i32 Binding_Match_Rule; 83 | enum{ 84 | BindingMatchRule_Strict, 85 | BindingMatchRule_Loose, 86 | }; 87 | 88 | struct Map_Event_Breakdown{ 89 | Input_Modifier_Set *mod_set; 90 | u64 key; 91 | Key_Code skip_self_mod; 92 | }; 93 | 94 | #endif 95 | 96 | // BOTTOM 97 | -------------------------------------------------------------------------------- /custom/4coder_config_grammar.txt: -------------------------------------------------------------------------------- 1 | sconfig := [version] {assignment} 2 | 3 | version := "version" "(" INTEGER ")" ";" 4 | assignment := lvalue "=" rvalue ";" 5 | lvalue := IDENTIFIER [ "[" INTEGER "]" ] 6 | rvalue := lvalue | BOOLEAN | INTEGER | FLOAT | STRING | CHARACTER | "{" compound_body 7 | compound_body := compound_element {"," compound_element} [","] "}" 8 | compound_element := ["." (IDENTIFIER | INTEGER) "="] rvalue 9 | -------------------------------------------------------------------------------- /custom/4coder_custom.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_custom.cpp 3 | */ 4 | 5 | // TOP 6 | 7 | extern "C" b32 8 | get_version(i32 maj, i32 min, i32 patch){ 9 | return(maj == MAJOR && min == MINOR && patch == PATCH); 10 | } 11 | 12 | extern "C" Custom_Layer_Init_Type* 13 | init_apis(API_VTable_custom *custom_vtable, API_VTable_system *system_vtable){ 14 | custom_api_read_vtable(custom_vtable); 15 | system_api_read_vtable(system_vtable); 16 | return(custom_layer_init); 17 | } 18 | 19 | // BOTTOM 20 | -------------------------------------------------------------------------------- /custom/4coder_default_bindings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_default_bidings.cpp - Supplies the default bindings used for default 4coder behavior. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_DEFAULT_BINDINGS_CPP) 8 | #define FCODER_DEFAULT_BINDINGS_CPP 9 | 10 | #include "4coder_default_include.cpp" 11 | 12 | // NOTE(allen): Users can declare their own managed IDs here. 13 | 14 | #if !defined(META_PASS) 15 | #include "generated/managed_id_metadata.cpp" 16 | #endif 17 | 18 | void 19 | custom_layer_init(Application_Links *app){ 20 | Thread_Context *tctx = get_thread_context(app); 21 | 22 | // NOTE(allen): setup for default framework 23 | default_framework_init(app); 24 | 25 | // NOTE(allen): default hooks and command maps 26 | set_all_default_hooks(app); 27 | mapping_init(tctx, &framework_mapping); 28 | String_ID global_map_id = vars_save_string_lit("keys_global"); 29 | String_ID file_map_id = vars_save_string_lit("keys_file"); 30 | String_ID code_map_id = vars_save_string_lit("keys_code"); 31 | #if OS_MAC 32 | setup_mac_mapping(&framework_mapping, global_map_id, file_map_id, code_map_id); 33 | #else 34 | setup_default_mapping(&framework_mapping, global_map_id, file_map_id, code_map_id); 35 | #endif 36 | setup_essential_mapping(&framework_mapping, global_map_id, file_map_id, code_map_id); 37 | } 38 | 39 | #endif //FCODER_DEFAULT_BINDINGS 40 | 41 | // BOTTOM 42 | -------------------------------------------------------------------------------- /custom/4coder_default_colors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Default color slots 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_DEFAULT_COLORS_H) 8 | #define FCODER_DEFAULT_COLORS_H 9 | 10 | CUSTOM_ID(colors, defcolor_bar); 11 | CUSTOM_ID(colors, defcolor_base); 12 | CUSTOM_ID(colors, defcolor_pop1); 13 | CUSTOM_ID(colors, defcolor_pop2); 14 | CUSTOM_ID(colors, defcolor_back); 15 | CUSTOM_ID(colors, defcolor_margin); 16 | CUSTOM_ID(colors, defcolor_margin_hover); 17 | CUSTOM_ID(colors, defcolor_margin_active); 18 | CUSTOM_ID(colors, defcolor_list_item); 19 | CUSTOM_ID(colors, defcolor_list_item_hover); 20 | CUSTOM_ID(colors, defcolor_list_item_active); 21 | CUSTOM_ID(colors, defcolor_cursor); 22 | CUSTOM_ID(colors, defcolor_at_cursor); 23 | CUSTOM_ID(colors, defcolor_highlight_cursor_line); 24 | CUSTOM_ID(colors, defcolor_highlight); 25 | CUSTOM_ID(colors, defcolor_at_highlight); 26 | CUSTOM_ID(colors, defcolor_mark); 27 | CUSTOM_ID(colors, defcolor_text_default); 28 | CUSTOM_ID(colors, defcolor_comment); 29 | CUSTOM_ID(colors, defcolor_comment_pop); 30 | CUSTOM_ID(colors, defcolor_keyword); 31 | CUSTOM_ID(colors, defcolor_str_constant); 32 | CUSTOM_ID(colors, defcolor_char_constant); 33 | CUSTOM_ID(colors, defcolor_int_constant); 34 | CUSTOM_ID(colors, defcolor_float_constant); 35 | CUSTOM_ID(colors, defcolor_bool_constant); 36 | CUSTOM_ID(colors, defcolor_preproc); 37 | CUSTOM_ID(colors, defcolor_include); 38 | CUSTOM_ID(colors, defcolor_special_character); 39 | CUSTOM_ID(colors, defcolor_ghost_character); 40 | CUSTOM_ID(colors, defcolor_highlight_junk); 41 | CUSTOM_ID(colors, defcolor_highlight_white); 42 | CUSTOM_ID(colors, defcolor_paste); 43 | CUSTOM_ID(colors, defcolor_undo); 44 | CUSTOM_ID(colors, defcolor_back_cycle); 45 | CUSTOM_ID(colors, defcolor_text_cycle); 46 | CUSTOM_ID(colors, defcolor_line_numbers_back); 47 | CUSTOM_ID(colors, defcolor_line_numbers_text); 48 | 49 | struct Color_Table_Node{ 50 | Color_Table_Node *next; 51 | String_Const_u8 name; 52 | Color_Table table; 53 | }; 54 | 55 | struct Color_Table_List{ 56 | Color_Table_Node *first; 57 | Color_Table_Node *last; 58 | i32 count; 59 | }; 60 | 61 | global Color_Table active_color_table = {}; 62 | global Color_Table default_color_table = {}; 63 | 64 | global Arena global_theme_arena = {}; 65 | global Color_Table_List global_theme_list = {}; 66 | 67 | #endif 68 | 69 | // BOTTOM 70 | -------------------------------------------------------------------------------- /custom/4coder_default_framework.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_default_framework.cpp - Sets up the basics of the framework that is used for default 4coder behaviour. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_DEFAULT_FRAMEWORK_H) 8 | #define FCODER_DEFAULT_FRAMEWORK_H 9 | 10 | //////////////////////////////// 11 | 12 | typedef i64 Rewrite_Type; 13 | enum{ 14 | Rewrite_None, 15 | Rewrite_NoChange, 16 | Rewrite_Paste, 17 | Rewrite_WordComplete 18 | }; 19 | 20 | //////////////////////////////// 21 | 22 | struct ID_Line_Column_Jump_Location{ 23 | Buffer_ID buffer_id; 24 | i32 line; 25 | i32 column; 26 | }; 27 | typedef ID_Line_Column_Jump_Location ID_Based_Jump_Location; 28 | 29 | struct ID_Pos_Jump_Location{ 30 | Buffer_ID buffer_id; 31 | i64 pos; 32 | }; 33 | 34 | struct Name_Line_Column_Location{ 35 | String_Const_u8 file; 36 | i32 line; 37 | i32 column; 38 | }; 39 | 40 | struct Parsed_Jump{ 41 | b32 success; 42 | Name_Line_Column_Location location; 43 | i32 colon_position; 44 | b32 is_sub_jump; 45 | b32 sub_jump_indented; 46 | b32 sub_jump_note; 47 | b32 is_ms_style; 48 | b32 has_rust_arrow; 49 | }; 50 | 51 | struct ID_Pos_Jump_Location_Array{ 52 | struct ID_Pos_Jump_Location *jumps; 53 | i32 count; 54 | }; 55 | 56 | //////////////////////////////// 57 | 58 | #define POINT_STACK_DEPTH 100 59 | 60 | struct Point_Stack_Slot{ 61 | Buffer_ID buffer; 62 | Managed_Object object; 63 | }; 64 | 65 | struct Point_Stack{ 66 | Point_Stack_Slot markers[POINT_STACK_DEPTH + 1]; 67 | i32 top; 68 | i32 bot; 69 | }; 70 | 71 | //////////////////////////////// 72 | 73 | typedef i32 Fallback_Dispatch_Result_Code; 74 | enum{ 75 | FallbackDispatch_Unhandled, 76 | FallbackDispatch_DidCall, 77 | FallbackDispatch_DelayedUICall, 78 | }; 79 | 80 | struct Fallback_Dispatch_Result{ 81 | Fallback_Dispatch_Result_Code code; 82 | Custom_Command_Function *func; 83 | }; 84 | 85 | //////////////////////////////// 86 | 87 | typedef void View_Render_Hook(Application_Links *app, View_ID view, Frame_Info frame_info, Rect_f32 inner); 88 | 89 | //////////////////////////////// 90 | 91 | function b32 92 | do_buffer_kill_user_check(Application_Links *app, Buffer_ID buffer, View_ID view); 93 | 94 | function b32 95 | do_4coder_close_user_check(Application_Links *app, View_ID view); 96 | 97 | //////////////////////////////// 98 | 99 | struct Buffer_Modified_Node{ 100 | Buffer_Modified_Node *next; 101 | Buffer_Modified_Node *prev; 102 | Buffer_ID buffer; 103 | }; 104 | 105 | struct Buffer_Modified_Set{ 106 | Arena arena; 107 | Buffer_Modified_Node *free; 108 | Buffer_Modified_Node *first; 109 | Buffer_Modified_Node *last; 110 | Table_u64_u64 id_to_node; 111 | }; 112 | 113 | //////////////////////////////// 114 | 115 | struct Fade_Range{ 116 | Fade_Range *next; 117 | Buffer_ID buffer_id; 118 | f32 t; 119 | f32 full_t; 120 | ARGB_Color color; 121 | b32 negate_fade_direction; 122 | Range_i64 range; 123 | 124 | void (*finish_call)(Application_Links *app, struct Fade_Range *range); 125 | void *opaque[4]; 126 | }; 127 | 128 | struct Fade_Range_List{ 129 | Fade_Range *first; 130 | Fade_Range *last; 131 | i32 count; 132 | }; 133 | 134 | #endif 135 | 136 | //////////////////////////////// 137 | 138 | struct Implicit_Map_Result{ 139 | String_ID map; 140 | Custom_Command_Function *command; 141 | }; 142 | 143 | typedef Implicit_Map_Result Implicit_Map_Function(Application_Links *app, 144 | String_ID buffer_language, 145 | String_ID global_mode, 146 | Input_Event *event); 147 | 148 | global Implicit_Map_Function *implicit_map_function = 0; 149 | 150 | // BOTTOM 151 | -------------------------------------------------------------------------------- /custom/4coder_default_framework_variables.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_default_framework_variables.cpp - Declares the global variables used by the framework for 3 | the default 4coder behavior. 4 | */ 5 | 6 | // TOP 7 | 8 | CUSTOM_ID(attachment, view_rewrite_loc); 9 | CUSTOM_ID(attachment, view_next_rewrite_loc); 10 | CUSTOM_ID(attachment, view_paste_index_loc); 11 | CUSTOM_ID(attachment, view_is_passive_loc); 12 | CUSTOM_ID(attachment, view_snap_mark_to_cursor); 13 | CUSTOM_ID(attachment, view_ui_data); 14 | CUSTOM_ID(attachment, view_highlight_range); 15 | CUSTOM_ID(attachment, view_highlight_buffer); 16 | CUSTOM_ID(attachment, view_render_hook); 17 | CUSTOM_ID(attachment, view_word_complete_menu); 18 | CUSTOM_ID(attachment, view_lister_loc); 19 | CUSTOM_ID(attachment, view_previous_buffer); 20 | 21 | CUSTOM_ID(attachment, buffer_map_id); 22 | CUSTOM_ID(attachment, buffer_eol_setting); 23 | CUSTOM_ID(attachment, buffer_lex_task); 24 | CUSTOM_ID(attachment, buffer_wrap_lines); 25 | 26 | CUSTOM_ID(attachment, sticky_jump_marker_handle); 27 | CUSTOM_ID(attachment, attachment_tokens); 28 | 29 | //////////////////////////////// 30 | 31 | #if 0 32 | CUSTOM_ID(command_map, mapid_global); 33 | CUSTOM_ID(command_map, mapid_file); 34 | CUSTOM_ID(command_map, mapid_code); 35 | #endif 36 | 37 | //////////////////////////////// 38 | 39 | global b32 allow_immediate_close_without_checking_for_changes = false; 40 | 41 | global char *default_extensions[] = { 42 | "cpp", 43 | "hpp", 44 | "c", 45 | "h", 46 | "cc", 47 | "cs", 48 | "java", 49 | "rs", 50 | "glsl", 51 | "m", 52 | }; 53 | 54 | #if !defined(AUTO_CENTER_AFTER_JUMPS) 55 | #define AUTO_CENTER_AFTER_JUMPS true 56 | #endif 57 | global b32 auto_center_after_jumps = AUTO_CENTER_AFTER_JUMPS; 58 | global u8 locked_buffer_space[256]; 59 | global String_Const_u8 locked_buffer = {}; 60 | 61 | 62 | global u8 out_buffer_space[1024]; 63 | global u8 command_space[1024]; 64 | global char hot_directory_space[1024]; 65 | 66 | global b32 suppressing_mouse = false; 67 | 68 | global b32 show_fps_hud = false; 69 | 70 | // TODO(allen): REMOVE THIS! 71 | global Heap global_heap; 72 | 73 | enum{ 74 | FCoderMode_Original = 0, 75 | FCoderMode_NotepadLike = 1, 76 | }; 77 | global i32 fcoder_mode = FCoderMode_Original; 78 | 79 | global ID_Pos_Jump_Location prev_location = {}; 80 | 81 | global Arena global_permanent_arena = {}; 82 | 83 | global Arena global_config_arena = {}; 84 | 85 | global char previous_isearch_query[256] = {}; 86 | 87 | global Mapping framework_mapping = {}; 88 | 89 | global Buffer_Modified_Set global_buffer_modified_set = {}; 90 | 91 | global b32 def_enable_virtual_whitespace = false; 92 | 93 | //////////////////////////////// 94 | 95 | global b32 global_keyboard_macro_is_recording = false; 96 | global Range_i64 global_keyboard_macro_range = {}; 97 | 98 | //////////////////////////////// 99 | 100 | global Fade_Range_List buffer_fade_ranges = {}; 101 | global Arena fade_range_arena = {}; 102 | global Fade_Range *free_fade_ranges = 0; 103 | 104 | //////////////////////////////// 105 | 106 | global Point_Stack point_stack = {}; 107 | 108 | //////////////////////////////// 109 | 110 | global Clipboard clipboard0 = {}; 111 | 112 | // BOTTOM 113 | -------------------------------------------------------------------------------- /custom/4coder_default_include.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_default_include.cpp - Default set of commands and setup used in 4coder. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_DEFAULT_INCLUDE_CPP) 8 | #define FCODER_DEFAULT_INCLUDE_CPP 9 | 10 | #if !defined(FCODER_DEFAULT_INCLUDE_H) 11 | #include "4coder_default_include.h" 12 | #endif 13 | 14 | #include "4coder_base_types.cpp" 15 | #include "4coder_stringf.cpp" 16 | #include "4coder_app_links_allocator.cpp" 17 | #include "4coder_system_allocator.cpp" 18 | 19 | #include "4coder_file.cpp" 20 | 21 | #define DYNAMIC_LINK_API 22 | #include "generated/custom_api.cpp" 23 | #define DYNAMIC_LINK_API 24 | #include "generated/system_api.cpp" 25 | #include "4coder_system_helpers.cpp" 26 | #include "4coder_layout.cpp" 27 | #include "4coder_profile.cpp" 28 | #include "4coder_profile_static_enable.cpp" 29 | #include "4coder_events.cpp" 30 | #include "4coder_custom.cpp" 31 | #include "4coder_log.cpp" 32 | #include "4coder_hash_functions.cpp" 33 | #include "4coder_table.cpp" 34 | #include "4coder_codepoint_map.cpp" 35 | #include "4coder_async_tasks.cpp" 36 | #include "4coder_string_match.cpp" 37 | #include "4coder_buffer_seek_constructors.cpp" 38 | #include "4coder_token.cpp" 39 | #include "4coder_command_map.cpp" 40 | 41 | #include "generated/lexer_cpp.cpp" 42 | 43 | #include "4coder_default_map.cpp" 44 | #include "4coder_mac_map.cpp" 45 | 46 | #include "4coder_default_framework_variables.cpp" 47 | #include "4coder_default_colors.cpp" 48 | #include "4coder_helper.cpp" 49 | #include "4coder_delta_rule.cpp" 50 | #include "4coder_layout_rule.cpp" 51 | #include "4coder_code_index.cpp" 52 | #include "4coder_fancy.cpp" 53 | #include "4coder_draw.cpp" 54 | #include "4coder_font_helper.cpp" 55 | #include "4coder_config.cpp" 56 | #include "4coder_dynamic_bindings.cpp" 57 | #include "4coder_default_framework.cpp" 58 | #include "4coder_clipboard.cpp" 59 | #include "4coder_lister_base.cpp" 60 | #include "4coder_base_commands.cpp" 61 | #include "4coder_insertion.cpp" 62 | #include "4coder_eol.cpp" 63 | #include "4coder_lists.cpp" 64 | #include "4coder_auto_indent.cpp" 65 | #include "4coder_search.cpp" 66 | #include "4coder_jumping.cpp" 67 | #include "4coder_jump_sticky.cpp" 68 | #include "4coder_jump_lister.cpp" 69 | #include "4coder_code_index_listers.cpp" 70 | #include "4coder_log_parser.cpp" 71 | #include "4coder_keyboard_macro.cpp" 72 | #include "4coder_cli_command.cpp" 73 | #include "4coder_build_commands.cpp" 74 | #include "4coder_project_commands.cpp" 75 | #include "4coder_prj_v1.cpp" 76 | #include "4coder_function_list.cpp" 77 | #include "4coder_scope_commands.cpp" 78 | #include "4coder_combined_write_commands.cpp" 79 | #include "4coder_miblo_numbers.cpp" 80 | #include "4coder_profile_inspect.cpp" 81 | #include "4coder_tutorial.cpp" 82 | #include "4coder_doc_content_types.cpp" 83 | #include "4coder_doc_commands.cpp" 84 | #include "4coder_docs.cpp" 85 | #include "4coder_variables.cpp" 86 | #include "4coder_audio.cpp" 87 | #include "4coder_search_list.cpp" 88 | 89 | #include "4coder_examples.cpp" 90 | 91 | #include "4coder_default_hooks.cpp" 92 | 93 | #endif 94 | 95 | // BOTTOM 96 | -------------------------------------------------------------------------------- /custom/4coder_default_include.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_default_include.h - Default set of commands and setup used in 4coder. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_DEFAULT_INCLUDE_H) 8 | #define FCODER_DEFAULT_INCLUDE_H 9 | 10 | #if !defined(FCODER_TRANSITION_TO) 11 | #define FCODER_TRANSITION_TO 0 12 | #endif 13 | 14 | #include 15 | #include 16 | 17 | #include "4coder_base_types.h" 18 | #include "4coder_version.h" 19 | #include "4coder_table.h" 20 | #include "4coder_events.h" 21 | #include "4coder_types.h" 22 | #include "4coder_doc_content_types.h" 23 | #include "4coder_default_colors.h" 24 | #define DYNAMIC_LINK_API 25 | #include "generated/custom_api.h" 26 | #include "4coder_system_types.h" 27 | #define DYNAMIC_LINK_API 28 | #include "generated/system_api.h" 29 | #if !defined(META_PASS) 30 | #include "generated/command_metadata.h" 31 | #endif 32 | 33 | #include "4coder_token.h" 34 | #include "generated/lexer_cpp.h" 35 | 36 | #include "4coder_variables.h" 37 | #include "4coder_audio.h" 38 | #include "4coder_profile.h" 39 | #include "4coder_async_tasks.h" 40 | #include "4coder_string_match.h" 41 | #include "4coder_helper.h" 42 | #include "4coder_delta_rule.h" 43 | #include "4coder_layout_rule.h" 44 | #include "4coder_code_index.h" 45 | #include "4coder_draw.h" 46 | #include "4coder_insertion.h" 47 | #include "4coder_command_map.h" 48 | #include "4coder_lister_base.h" 49 | #include "4coder_clipboard.h" 50 | #include "4coder_default_framework.h" 51 | #include "4coder_config.h" 52 | #include "4coder_auto_indent.h" 53 | #include "4coder_search.h" 54 | #include "4coder_build_commands.h" 55 | #include "4coder_jumping.h" 56 | #include "4coder_jump_sticky.h" 57 | #include "4coder_jump_lister.h" 58 | #include "4coder_project_commands.h" 59 | #include "4coder_prj_v1.h" 60 | #include "4coder_function_list.h" 61 | #include "4coder_scope_commands.h" 62 | #include "4coder_combined_write_commands.h" 63 | #include "4coder_log_parser.h" 64 | #include "4coder_profile_inspect.h" 65 | #include "4coder_tutorial.h" 66 | #include "4coder_search_list.h" 67 | 68 | #endif 69 | 70 | // BOTTOM 71 | -------------------------------------------------------------------------------- /custom/4coder_delta_rule.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_delta_rule.h - Types for built in delta rules and delta rule helpers. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_DELTA_RULE_H) 8 | #define FCODER_DELTA_RULE_H 9 | 10 | union Delta_Context_Header{ 11 | Buffer_Point point; 12 | Vec2_f32 p; 13 | }; 14 | struct Buffer_Point_Delta_Result{ 15 | Buffer_Point point; 16 | b32 still_animating; 17 | }; 18 | struct Vec2_f32_Delta_Result{ 19 | Vec2_f32 p; 20 | b32 still_animating; 21 | }; 22 | 23 | struct Smooth_Step{ 24 | f32 p; 25 | f32 v; 26 | }; 27 | 28 | #endif 29 | 30 | // BOTTOM 31 | -------------------------------------------------------------------------------- /custom/4coder_doc_commands.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 14.12.2019 5 | * 6 | * Documentation of the custom layer's primary api. 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | function Doc_Cluster* 13 | doc_commands(Arena *arena){ 14 | Doc_Cluster *cluster = new_doc_cluster(arena, "Commands", "commands"); 15 | for (i32 i = 0; i < ArrayCount(fcoder_metacmd_table); i += 1){ 16 | String_Const_u8 cmd_name = SCu8(fcoder_metacmd_table[i].name, 17 | fcoder_metacmd_table[i].name_len); 18 | String_Const_u8 title = push_u8_stringf(arena, "Command %S", cmd_name); 19 | Doc_Page *page = new_doc_page(arena, cluster, (char*)title.str, (char*)cmd_name.str); 20 | Doc_Block *block = new_doc_block(arena, page, "brief"); 21 | doc_text(arena, block, fcoder_metacmd_table[i].description); 22 | } 23 | return(cluster); 24 | } 25 | 26 | function Doc_Cluster* 27 | doc_default_bindings(Arena *arena, i32 map_count, Mapping *mapping_array, char **page_titles, char **page_names, 28 | i64 global_id, i64 file_id, i64 code_id){ 29 | Doc_Cluster *cluster = new_doc_cluster(arena, "Bindings", "bindings"); 30 | 31 | for (i32 i = 0; i < map_count; i += 1){ 32 | Mapping *mapping = &mapping_array[i]; 33 | Doc_Page *page = new_doc_page(arena, cluster, page_titles[i], page_names[i]); 34 | for (Command_Map *map = mapping->first_map; 35 | map != 0; 36 | map = map->next){ 37 | char *map_name = ""; 38 | if (map->id == global_id){ 39 | map_name = "Global"; 40 | } 41 | else if (map->id == file_id){ 42 | map_name = "File"; 43 | } 44 | else if (map->id == code_id){ 45 | map_name = "Code"; 46 | } 47 | 48 | Doc_Block *block = new_doc_block(arena, page, map_name); 49 | Doc_Paragraph *par = new_doc_par_table(arena, block); 50 | 51 | struct Bind_Node{ 52 | Bind_Node *next; 53 | Input_Event_Kind kind; 54 | u32 sub_code; 55 | Input_Modifier_Set mods; 56 | Command_Binding binding; 57 | u32 j; 58 | }; 59 | 60 | Bind_Node *first = 0; 61 | Bind_Node *last = 0; 62 | i32 node_count = 0; 63 | 64 | if (map->text_input_command.name != 0){ 65 | Bind_Node *node = push_array_zero(arena, Bind_Node, 1); 66 | sll_queue_push(first, last, node); 67 | node_count += 1; 68 | node->binding = map->text_input_command; 69 | node->j = max_u32; 70 | } 71 | 72 | u32 counts[] = { 73 | KeyCode_COUNT, 74 | KeyCode_COUNT, 75 | MouseCode_COUNT, 76 | MouseCode_COUNT, 77 | 1, 78 | 1, 79 | CoreCode_COUNT, 80 | }; 81 | 82 | u32 event_codes[] = { 83 | InputEventKind_KeyStroke, 84 | InputEventKind_KeyRelease, 85 | InputEventKind_MouseButton, 86 | InputEventKind_MouseButtonRelease, 87 | InputEventKind_MouseWheel, 88 | InputEventKind_MouseMove, 89 | InputEventKind_Core, 90 | }; 91 | 92 | char *mouse_wheel_name[] = {"MoveWheel"}; 93 | char *mouse_move_name[] = {"MoveMove"}; 94 | 95 | char **event_names[] = { 96 | key_code_name, 97 | key_code_name, 98 | mouse_code_name, 99 | mouse_code_name, 100 | mouse_wheel_name, 101 | mouse_move_name, 102 | core_code_name, 103 | }; 104 | 105 | b32 is_release[] = { 106 | false, 107 | true, 108 | false, 109 | true, 110 | false, 111 | false, 112 | false, 113 | }; 114 | 115 | for (u32 j = 0; j < ArrayCount(counts); j += 1){ 116 | for (u32 code = 0; code < counts[j]; code += 1){ 117 | u64 key = mapping__key(event_codes[j], code); 118 | Table_Lookup lookup = table_lookup(&map->event_code_to_binding_list, key); 119 | if (lookup.found_match){ 120 | u64 val = 0; 121 | table_read(&map->event_code_to_binding_list, lookup, &val); 122 | Command_Binding_List *list = (Command_Binding_List*)IntAsPtr(val); 123 | for (SNode *snode = list->first; 124 | snode != 0; 125 | snode = snode->next){ 126 | Command_Modified_Binding *mod_binding = CastFromMember(Command_Modified_Binding, order_node, snode); 127 | 128 | Bind_Node *node = push_array_zero(arena, Bind_Node, 1); 129 | sll_queue_push(first, last, node); 130 | node_count += 1; 131 | node->kind = event_codes[j]; 132 | node->sub_code = code; 133 | node->mods = mod_binding->mods; 134 | node->binding = mod_binding->binding; 135 | node->j = j; 136 | } 137 | } 138 | } 139 | } 140 | 141 | Vec2_i32 table_dims = V2i32(2, node_count); 142 | Doc_Content_List *vals = push_array_zero(arena, Doc_Content_List, table_dims.x*table_dims.y); 143 | Bind_Node *bnode = first; 144 | for (i32 y = 0; y < table_dims.y; y += 1, bnode = bnode->next){ 145 | Doc_Content_List *line = &vals[y*table_dims.x]; 146 | doc_text(arena, &line[0], "["); 147 | if (bnode->j != max_u32){ 148 | doc_text(arena, &line[0], event_names[bnode->j][bnode->sub_code]); 149 | if (is_release[bnode->j]){ 150 | doc_text(arena, &line[0], "Release"); 151 | } 152 | 153 | Input_Modifier_Set *mods = &bnode->mods; 154 | for (i32 k = 0; k < mods->count; k += 1){ 155 | doc_text(arena, &line[0], key_code_name[mods->mods[k]]); 156 | } 157 | } 158 | else{ 159 | doc_text(arena, &line[0], "TextInput"); 160 | } 161 | doc_text(arena, &line[0], "]"); 162 | 163 | Doc_Content *content = doc_text(arena, &line[1], bnode->binding.name); 164 | content->page_link = SCu8(bnode->binding.name); 165 | } 166 | 167 | par->table.dim = table_dims; 168 | par->table.vals = vals; 169 | } 170 | } 171 | 172 | return(cluster); 173 | } 174 | 175 | // BOTTOM 176 | -------------------------------------------------------------------------------- /custom/4coder_doc_content_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_doc_content_types.h - Documentation content types 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FRED_DOC_CONTENT_TYPES_H) 8 | #define FRED_DOC_CONTENT_TYPES_H 9 | 10 | typedef i32 Doc_Month; 11 | enum{ 12 | None, 13 | January, 14 | February, 15 | March, 16 | April, 17 | May, 18 | June, 19 | July, 20 | August, 21 | September, 22 | October, 23 | November, 24 | December, 25 | }; 26 | char *doc_month_names[] = { 27 | "None", 28 | "January", 29 | "February", 30 | "March", 31 | "April", 32 | "May", 33 | "June", 34 | "July", 35 | "August", 36 | "September", 37 | "October", 38 | "November", 39 | "December", 40 | }; 41 | char *doc_day_names[] = { 42 | "0", 43 | "1st", 44 | "2nd", 45 | "3rd", 46 | "4th", 47 | "5th", 48 | "6th", 49 | "7th", 50 | "8th", 51 | "9th", 52 | "10th", 53 | "11th", 54 | "12th", 55 | "13th", 56 | "14th", 57 | "15th", 58 | "16th", 59 | "17th", 60 | "18th", 61 | "19th", 62 | "20th", 63 | "21st", 64 | "22nd", 65 | "23rd", 66 | "24th", 67 | "25th", 68 | "26th", 69 | "27th", 70 | "28th", 71 | "29th", 72 | "30th", 73 | "31st", 74 | }; 75 | 76 | struct Doc_Date{ 77 | i32 day; 78 | Doc_Month month; 79 | i32 year; 80 | }; 81 | 82 | typedef i32 Doc_Content_Emphasis; 83 | enum{ 84 | DocContentEmphasis_Normal, 85 | DocContentEmphasis_SmallHeader, 86 | DocContentEmphasis_Heavy, 87 | DocContentEmphasis_Stylish, 88 | DocContentEmphasis_Code, 89 | }; 90 | struct Doc_Content{ 91 | Doc_Content *next; 92 | String_Const_u8 text; 93 | String_Const_u8 page_link; 94 | String_Const_u8 block_link; 95 | Doc_Content_Emphasis emphasis; 96 | }; 97 | struct Doc_Content_List{ 98 | Doc_Content *first; 99 | Doc_Content *last; 100 | u64 total_size; 101 | i32 node_count; 102 | }; 103 | 104 | typedef i32 Doc_Code_Language; 105 | enum{ 106 | DocCodeLanguage_None, 107 | DocCodeLanguage_Cpp, 108 | DocCodeLanguage_Bat, 109 | }; 110 | char *doc_language_name[] = { 111 | "none", 112 | "C++", 113 | "Batch", 114 | }; 115 | struct Doc_Code_Sample{ 116 | Doc_Code_Sample *next; 117 | String_Const_u8 contents; 118 | Doc_Code_Language language; 119 | }; 120 | struct Doc_Code_Sample_List{ 121 | Doc_Code_Sample *first; 122 | Doc_Code_Sample *last; 123 | i32 count; 124 | }; 125 | 126 | typedef i32 Doc_Paragraph_Kind; 127 | enum{ 128 | DocParagraphKind_Text, 129 | DocParagraphKind_Code, 130 | DocParagraphKind_Table, 131 | }; 132 | struct Doc_Paragraph{ 133 | Doc_Paragraph *next; 134 | Doc_Paragraph_Kind kind; 135 | union{ 136 | Doc_Content_List text; 137 | Doc_Code_Sample_List code; 138 | struct{ 139 | Vec2_i32 dim; 140 | Doc_Content_List *vals; 141 | } table; 142 | }; 143 | }; 144 | 145 | struct Doc_Block{ 146 | Doc_Block *next; 147 | 148 | struct Doc_Page *owner; 149 | 150 | String_Const_u8 name; 151 | 152 | Doc_Paragraph *first_par; 153 | Doc_Paragraph *last_par; 154 | i32 par_count; 155 | }; 156 | 157 | struct Doc_Block_Ptr{ 158 | Doc_Block_Ptr *next; 159 | Doc_Block *block; 160 | }; 161 | 162 | struct Doc_Block_List{ 163 | Doc_Block_Ptr *first; 164 | Doc_Block_Ptr *last; 165 | i32 count; 166 | }; 167 | 168 | struct Doc_Page{ 169 | Doc_Page *next; 170 | 171 | struct Doc_Cluster *owner; 172 | 173 | String_Const_u8 title; 174 | String_Const_u8 name; 175 | 176 | Doc_Block *first_block; 177 | Doc_Block *last_block; 178 | i32 block_count; 179 | 180 | Doc_Block_List quick_jumps; 181 | }; 182 | 183 | struct Doc_Log{ 184 | Doc_Log *next; 185 | String_Const_u8 content; 186 | }; 187 | 188 | struct Doc_Cluster{ 189 | String_Const_u8 title; 190 | String_Const_u8 name; 191 | Doc_Date gen_date; 192 | 193 | Doc_Page *first_page; 194 | Doc_Page *last_page; 195 | i32 page_count; 196 | 197 | Doc_Log *first_log; 198 | Doc_Log *last_log; 199 | }; 200 | 201 | #endif 202 | 203 | // BOTTOM 204 | -------------------------------------------------------------------------------- /custom/4coder_draw.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_draw.h - Layout and rendering types of standard UI pieces (including buffers) 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_DRAW_H) 8 | #define FCODER_DRAW_H 9 | 10 | struct Comment_Highlight_Pair{ 11 | String_Const_u8 needle; 12 | ARGB_Color color; 13 | }; 14 | 15 | typedef i32 Range_Highlight_Kind; 16 | enum{ 17 | RangeHighlightKind_LineHighlight, 18 | RangeHighlightKind_CharacterHighlight, 19 | }; 20 | 21 | #endif 22 | 23 | // BOTTOM 24 | -------------------------------------------------------------------------------- /custom/4coder_dynamic_bindings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_dynamic_bindings.cpp - Dynamic Bindings 3 | */ 4 | 5 | // TOP 6 | 7 | function Key_Code 8 | dynamic_binding_key_code_from_string(String_Const_u8 key_string){ 9 | Key_Code result = 0; 10 | for (i32 i = 1; i < KeyCode_COUNT; i += 1){ 11 | String_Const_u8 str = SCu8(key_code_name[i]); 12 | if (string_match(str, key_string)){ 13 | result = i; 14 | break; 15 | } 16 | } 17 | return result; 18 | } 19 | 20 | function b32 21 | dynamic_binding_load_from_path(Application_Links *app, Arena *arena, Mapping *mapping, String_Const_u8 full_path){ 22 | b32 result = false; 23 | 24 | String8 message = push_stringf(arena, "loading bindings: %S\n", full_path); 25 | print_message(app, message); 26 | 27 | FILE *file = 0; 28 | if (full_path.size > 0){ 29 | file = fopen((char*)full_path.str, "rb"); 30 | } 31 | 32 | if (file != 0){ 33 | String_Const_u8 filename = string_front_of_path(full_path); 34 | String_Const_u8 data = dump_file_handle(arena, file); 35 | Config *parsed = def_config_from_text(app, arena, filename, data); 36 | comp_error(app, config_stringize_errors(app, arena, parsed)); 37 | fclose(file); 38 | 39 | if (parsed != 0){ 40 | result = true; 41 | 42 | Thread_Context* tctx = get_thread_context(app); 43 | mapping_release(tctx, mapping); 44 | mapping_init(tctx, mapping); 45 | MappingScope(); 46 | SelectMapping(mapping); 47 | 48 | for (Config_Assignment *assignment = parsed->first; 49 | assignment != 0; 50 | assignment = assignment->next){ 51 | Config_LValue *l = assignment->l; 52 | if (l != 0 && l->index == 0){ 53 | Config_Get_Result rvalue = config_evaluate_rvalue(parsed, assignment, assignment->r); 54 | if (rvalue.type == ConfigRValueType_Compound){ 55 | String_Const_u8 map_name = l->identifier; 56 | String_ID map_name_id = vars_save_string(map_name); 57 | 58 | SelectMap(map_name_id); 59 | 60 | 61 | Config_Compound *compound = rvalue.compound; 62 | 63 | Config_Get_Result_List list = typed_compound_array_reference_list(arena, parsed, compound); 64 | for (Config_Get_Result_Node *node = list.first; node != 0; node = node->next){ 65 | Config_Compound *src = node->result.compound; 66 | String_Const_u8 cmd_string = {0}; 67 | String_Const_u8 key_string = {0}; 68 | String_Const_u8 mod_string[9] = {0}; 69 | 70 | if (!config_compound_string_member(parsed, src, "cmd", 0, &cmd_string)){ 71 | def_config_push_error(arena, parsed, node->result.pos, "Command string is required in binding"); 72 | goto finish_map; 73 | } 74 | 75 | if (!config_compound_string_member(parsed, src, "key", 1, &key_string)){ 76 | def_config_push_error(arena, parsed, node->result.pos, "Key string is required in binding"); 77 | goto finish_map; 78 | } 79 | 80 | for (i32 mod_idx = 0; mod_idx < ArrayCount(mod_string); mod_idx += 1){ 81 | String_Const_u8 str = push_stringf(arena, "mod_%i", mod_idx); 82 | if (config_compound_string_member(parsed, src, str, 2 + mod_idx, &mod_string[mod_idx])){ 83 | // NOTE(rjf): No-Op 84 | } 85 | } 86 | 87 | // NOTE(rjf): Map read in successfully. 88 | { 89 | // NOTE(rjf): Find command. 90 | Command_Metadata *command = get_command_metadata_from_name(cmd_string); 91 | 92 | // NOTE(rjf): Find keycode. 93 | Key_Code keycode = dynamic_binding_key_code_from_string(key_string); 94 | 95 | // NOTE(rjf): Find mods. 96 | i32 mod_count = 0; 97 | Key_Code mods[ArrayCount(mod_string)] = {0}; 98 | for (i32 i = 0; i < ArrayCount(mod_string); i += 1){ 99 | if (mod_string[i].str){ 100 | mods[mod_count] = dynamic_binding_key_code_from_string(mod_string[i]); 101 | mod_count += 1; 102 | } 103 | } 104 | 105 | if (keycode != 0 && command != 0){ 106 | Input_Modifier_Set mods_set = { mods, mod_count, }; 107 | map_set_binding(mapping, map, command->proc, InputEventKind_KeyStroke, keycode, &mods_set); 108 | } 109 | else{ 110 | def_config_push_error(arena, parsed, node->result.pos, 111 | (keycode != 0) ? (char*)"Invalid command" : 112 | (command != 0) ? (char*)"Invalid key": 113 | (char*)"Invalid command and key"); 114 | } 115 | } 116 | 117 | finish_map:; 118 | } 119 | 120 | 121 | if (parsed->errors.first != 0){ 122 | String_Const_u8 error_text = config_stringize_errors(app, arena, parsed); 123 | print_message(app, error_text); 124 | } 125 | } 126 | } 127 | } 128 | } 129 | } 130 | 131 | return(result); 132 | } 133 | 134 | function b32 135 | dynamic_binding_load_from_file(Application_Links *app, Mapping *mapping, String_Const_u8 filename){ 136 | Scratch_Block scratch(app); 137 | 138 | String_Const_u8 filename_copied = push_string_copy(scratch, filename); 139 | String8List search_list = {}; 140 | def_search_normal_load_list(scratch, &search_list); 141 | String_Const_u8 full_path = def_search_get_full_path(scratch, &search_list, filename_copied); 142 | return dynamic_binding_load_from_path(app, scratch, mapping, full_path); 143 | } 144 | 145 | // BOTTOM 146 | -------------------------------------------------------------------------------- /custom/4coder_eol.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder_eol.cpp - Commands and routines for controling the end-of-line encoding 3 | * of files. 4 | */ 5 | 6 | // TOP 7 | 8 | function void 9 | rewrite_lines_to_crlf(Application_Links *app, Buffer_ID buffer){ 10 | ProfileScope(app, "rewrite lines to crlf"); 11 | Scratch_Block scratch(app); 12 | i64 size = buffer_get_size(app, buffer); 13 | 14 | Batch_Edit *first = 0; 15 | Batch_Edit *last = 0; 16 | 17 | ProfileBlockNamed(app, "build batch edit", profile_batch); 18 | i64 pos = -1; 19 | Character_Predicate pred_cr = character_predicate_from_character('\r'); 20 | Character_Predicate pred_lf = character_predicate_from_character('\n'); 21 | Character_Predicate pred = character_predicate_or(&pred_cr, &pred_lf); 22 | for (;;){ 23 | String_Match match = buffer_seek_character_class(app, buffer, &pred, 24 | Scan_Forward, pos); 25 | if (match.range.min == match.range.max){ 26 | break; 27 | } 28 | pos = match.range.min; 29 | 30 | u8 c1 = buffer_get_char(app, buffer, pos); 31 | u8 c2 = buffer_get_char(app, buffer, pos + 1); 32 | if (c1 == '\r'){ 33 | if (pos + 1 == size || c2 != '\n'){ 34 | Batch_Edit *edit = push_array(scratch, Batch_Edit, 1); 35 | sll_queue_push(first, last, edit); 36 | edit->edit.text = string_u8_litexpr(""); 37 | edit->edit.range = match.range; 38 | } 39 | else{ 40 | pos += 1; 41 | } 42 | } 43 | else{ 44 | Batch_Edit *edit = push_array(scratch, Batch_Edit, 1); 45 | sll_queue_push(first, last, edit); 46 | edit->edit.text = string_u8_litexpr("\r"); 47 | edit->edit.range = Ii64(pos); 48 | } 49 | } 50 | ProfileCloseNow(profile_batch); 51 | 52 | buffer_batch_edit(app, buffer, first); 53 | } 54 | 55 | function void 56 | rewrite_lines_to_lf(Application_Links *app, Buffer_ID buffer){ 57 | ProfileScope(app, "rewrite lines to lf"); 58 | Scratch_Block scratch(app); 59 | 60 | Batch_Edit *first = 0; 61 | Batch_Edit *last = 0; 62 | 63 | ProfileBlockNamed(app, "build batch edit", profile_batch); 64 | i64 pos = -1; 65 | Character_Predicate pred = character_predicate_from_character('\r'); 66 | for (;;){ 67 | String_Match match = buffer_seek_character_class(app, buffer, &pred, 68 | Scan_Forward, pos); 69 | if (match.range.min == match.range.max){ 70 | break; 71 | } 72 | pos = match.range.min; 73 | 74 | Batch_Edit *edit = push_array(scratch, Batch_Edit, 1); 75 | sll_queue_push(first, last, edit); 76 | edit->edit.text = string_u8_litexpr(""); 77 | edit->edit.range = match.range; 78 | } 79 | ProfileCloseNow(profile_batch); 80 | 81 | buffer_batch_edit(app, buffer, first); 82 | } 83 | 84 | //////////////////////////////// 85 | 86 | CUSTOM_COMMAND_SIG(set_eol_mode_to_crlf) 87 | CUSTOM_DOC("Puts the buffer in crlf line ending mode.") 88 | { 89 | View_ID view = get_active_view(app, Access_ReadWriteVisible); 90 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); 91 | Managed_Scope scope = buffer_get_managed_scope(app, buffer); 92 | Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, 93 | Line_Ending_Kind); 94 | if (eol_setting != 0){ 95 | *eol_setting = LineEndingKind_CRLF; 96 | } 97 | } 98 | 99 | CUSTOM_COMMAND_SIG(set_eol_mode_to_lf) 100 | CUSTOM_DOC("Puts the buffer in lf line ending mode.") 101 | { 102 | View_ID view = get_active_view(app, Access_ReadWriteVisible); 103 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); 104 | Managed_Scope scope = buffer_get_managed_scope(app, buffer); 105 | Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, 106 | Line_Ending_Kind); 107 | if (eol_setting != 0){ 108 | *eol_setting = LineEndingKind_LF; 109 | } 110 | } 111 | 112 | CUSTOM_COMMAND_SIG(set_eol_mode_to_binary) 113 | CUSTOM_DOC("Puts the buffer in bin line ending mode.") 114 | { 115 | View_ID view = get_active_view(app, Access_ReadWriteVisible); 116 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); 117 | Managed_Scope scope = buffer_get_managed_scope(app, buffer); 118 | Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, 119 | Line_Ending_Kind); 120 | if (eol_setting != 0){ 121 | *eol_setting = LineEndingKind_Binary; 122 | } 123 | } 124 | 125 | CUSTOM_COMMAND_SIG(set_eol_mode_from_contents) 126 | CUSTOM_DOC("Sets the buffer's line ending mode to match the contents of the buffer.") 127 | { 128 | View_ID view = get_active_view(app, Access_ReadWriteVisible); 129 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); 130 | Line_Ending_Kind setting = guess_line_ending_kind_from_buffer(app, buffer); 131 | Managed_Scope scope = buffer_get_managed_scope(app, buffer); 132 | Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, 133 | Line_Ending_Kind); 134 | if (eol_setting != 0){ 135 | *eol_setting = setting; 136 | } 137 | } 138 | 139 | // BOTTOM 140 | -------------------------------------------------------------------------------- /custom/4coder_events.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder event types 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_EVENTS_H) 8 | #define FCODER_EVENTS_H 9 | 10 | typedef void Custom_Command_Function(struct Application_Links *app); 11 | 12 | typedef u32 Key_Code; 13 | typedef u32 Mouse_Code; 14 | typedef u32 Core_Code; 15 | #include "generated/4coder_event_codes.h" 16 | 17 | typedef u32 Input_Event_Kind; 18 | enum{ 19 | InputEventKind_None, 20 | InputEventKind_TextInsert, 21 | InputEventKind_KeyStroke, 22 | InputEventKind_KeyRelease, 23 | InputEventKind_MouseButton, 24 | InputEventKind_MouseButtonRelease, 25 | InputEventKind_MouseWheel, 26 | InputEventKind_MouseMove, 27 | InputEventKind_Core, 28 | InputEventKind_CustomFunction, 29 | 30 | InputEventKind_COUNT, 31 | }; 32 | 33 | typedef u32 Key_Flags; 34 | enum{ 35 | KeyFlag_IsDeadKey = (1 << 0), 36 | }; 37 | 38 | global_const i32 Input_MaxModifierCount = 8; 39 | 40 | struct Input_Modifier_Set{ 41 | Key_Code *mods; 42 | i32 count; 43 | }; 44 | 45 | struct Input_Modifier_Set_Fixed{ 46 | Key_Code mods[Input_MaxModifierCount]; 47 | i32 count; 48 | }; 49 | 50 | struct Input_Event{ 51 | Input_Event_Kind kind; 52 | b32 virtual_event; 53 | union{ 54 | struct{ 55 | String_Const_u8 string; 56 | 57 | // used internally 58 | Input_Event *next_text; 59 | b32 blocked; 60 | } text; 61 | struct{ 62 | Key_Code code; 63 | Key_Flags flags; 64 | Input_Modifier_Set modifiers; 65 | 66 | // used internally 67 | Input_Event *first_dependent_text; 68 | } key; 69 | struct{ 70 | Mouse_Code code; 71 | Vec2_i32 p; 72 | Input_Modifier_Set modifiers; 73 | } mouse; 74 | struct{ 75 | f32 value; 76 | Vec2_i32 p; 77 | Input_Modifier_Set modifiers; 78 | } mouse_wheel; 79 | struct{ 80 | Vec2_i32 p; 81 | Input_Modifier_Set modifiers; 82 | } mouse_move; 83 | struct{ 84 | Core_Code code; 85 | union{ 86 | String_Const_u8 string; 87 | i32 id; 88 | struct{ 89 | String_Const_u8_Array flag_strings; 90 | String_Const_u8_Array file_names; 91 | }; 92 | }; 93 | } core; 94 | Custom_Command_Function *custom_func; 95 | }; 96 | }; 97 | 98 | struct Input_Event_Node{ 99 | Input_Event_Node *next; 100 | Input_Event event; 101 | }; 102 | 103 | struct Input_List{ 104 | Input_Event_Node *first; 105 | Input_Event_Node *last; 106 | i32 count; 107 | }; 108 | 109 | typedef u32 Event_Property; 110 | enum{ 111 | EventProperty_AnyKey = 0x0001, 112 | EventProperty_Escape = 0x0002, 113 | EventProperty_AnyKeyRelease = 0x0004, 114 | EventProperty_MouseButton = 0x0008, 115 | EventProperty_MouseRelease = 0x0010, 116 | EventProperty_MouseWheel = 0x0020, 117 | EventProperty_MouseMove = 0x0040, 118 | EventProperty_Animate = 0x0080, 119 | EventProperty_ViewActivation = 0x0100, 120 | EventProperty_TextInsert = 0x0200, 121 | EventProperty_AnyFile = 0x0400, 122 | EventProperty_Startup = 0x0800, 123 | EventProperty_Exit = 0x1000, 124 | EventProperty_Clipboard = 0x2000, 125 | EventProperty_CustomFunction = 0x4000, 126 | }; 127 | enum{ 128 | EventPropertyGroup_AnyKeyboardEvent = 129 | EventProperty_AnyKey| 130 | EventProperty_Escape| 131 | EventProperty_AnyKeyRelease| 132 | EventProperty_TextInsert, 133 | EventPropertyGroup_AnyMouseEvent = 134 | EventProperty_MouseButton| 135 | EventProperty_MouseRelease| 136 | EventProperty_MouseWheel| 137 | EventProperty_MouseMove, 138 | EventPropertyGroup_AnyUserInput = 139 | EventPropertyGroup_AnyKeyboardEvent| 140 | EventPropertyGroup_AnyMouseEvent, 141 | EventPropertyGroup_AnyCore = 142 | EventProperty_Animate| 143 | EventProperty_ViewActivation| 144 | EventProperty_AnyFile| 145 | EventProperty_Startup| 146 | EventProperty_Exit| 147 | EventProperty_Clipboard| 148 | EventProperty_Animate, 149 | EventPropertyGroup_Any = 150 | EventPropertyGroup_AnyUserInput| 151 | EventPropertyGroup_AnyCore| 152 | EventProperty_CustomFunction, 153 | }; 154 | 155 | #endif 156 | 157 | // BOTTOM 158 | -------------------------------------------------------------------------------- /custom/4coder_file.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 03.10.2019 5 | * 6 | * Basic helpers for C std file handling. 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | #include 13 | 14 | function String_Const_u8 15 | data_from_file(Arena *arena, FILE *file){ 16 | String_Const_u8 result = {}; 17 | if (file != 0){ 18 | fseek(file, 0, SEEK_END); 19 | result.size = ftell(file); 20 | fseek(file, 0, SEEK_SET); 21 | result.str = push_array(arena, u8, result.size + 1); 22 | fread(result.str, 1, (size_t)result.size, file); 23 | result.str[result.size] = 0; 24 | } 25 | return(result); 26 | } 27 | 28 | // BOTTOM 29 | -------------------------------------------------------------------------------- /custom/4coder_font_helper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_font_helper.cpp - Procedures for font setting operations 3 | */ 4 | 5 | // TOP 6 | 7 | internal Face_Description 8 | get_buffer_face_description(Application_Links *app, Buffer_ID buffer){ 9 | Face_ID current_id = get_face_id(app, buffer); 10 | Face_Description description = {}; 11 | if (current_id != 0){ 12 | description = get_face_description(app, current_id); 13 | } 14 | return(description); 15 | } 16 | 17 | internal Face_Description 18 | get_global_face_description(Application_Links *app){ 19 | return(get_buffer_face_description(app, 0)); 20 | } 21 | 22 | internal b32 23 | font_load_location_match(Font_Load_Location *a, Font_Load_Location *b){ 24 | return(string_match(a->file_name, b->file_name)); 25 | } 26 | 27 | internal b32 28 | face_load_parameters_match(Face_Load_Parameters *a, Face_Load_Parameters *b){ 29 | return(block_compare(a, b, sizeof(*a)) == 0); 30 | } 31 | 32 | internal b32 33 | face_description_match(Face_Description *a, Face_Description *b){ 34 | b32 result = false; 35 | if (font_load_location_match(&a->font, &b->font) && 36 | face_load_parameters_match(&a->parameters, &b->parameters)){ 37 | result = true; 38 | } 39 | return(result); 40 | } 41 | 42 | internal Face_ID 43 | face_id_from_font_load_target(Application_Links *app, Font_Load_Location *font){ 44 | Face_ID largest_id = get_largest_face_id(app); 45 | Face_ID result = 0; 46 | for (Face_ID id = 1; id <= largest_id; ++id){ 47 | Face_Description compare = get_face_description(app, id); 48 | if (font_load_location_match(&compare.font, font)){ 49 | result = id; 50 | break; 51 | } 52 | } 53 | return(result); 54 | } 55 | 56 | internal Face_ID 57 | face_id_from_face_load_parameters(Application_Links *app, Face_Load_Parameters *parameters){ 58 | Face_ID largest_id = get_largest_face_id(app); 59 | Face_ID result = 0; 60 | for (Face_ID id = 1; id <= largest_id; ++id){ 61 | Face_Description compare = get_face_description(app, id); 62 | if (face_load_parameters_match(&compare.parameters, parameters)){ 63 | result = id; 64 | break; 65 | } 66 | } 67 | return(result); 68 | } 69 | 70 | internal Face_ID 71 | face_id_from_description(Application_Links *app, Face_Description *description){ 72 | Face_ID largest_id = get_largest_face_id(app); 73 | Face_ID result = 0; 74 | for (Face_ID id = 1; id <= largest_id; ++id){ 75 | Face_Description compare = get_face_description(app, id); 76 | if (face_description_match(&compare, description)){ 77 | result = id; 78 | break; 79 | } 80 | } 81 | return(result); 82 | } 83 | 84 | internal b32 85 | modify_global_face_by_description(Application_Links *app, Face_Description description){ 86 | Face_ID face_id = get_face_id(app, 0); 87 | return(try_modify_face(app, face_id, &description)); 88 | } 89 | 90 | internal void 91 | set_buffer_face_by_description(Application_Links *app, Buffer_ID buffer, Face_Description *description){ 92 | Face_ID id = face_id_from_description(app, description); 93 | if (id == 0){ 94 | id = try_create_new_face(app, description); 95 | } 96 | if (id != 0){ 97 | buffer_set_face(app, buffer, id); 98 | } 99 | } 100 | 101 | internal void 102 | set_buffer_face_by_font_load_location(Application_Links *app, Buffer_ID buffer, Font_Load_Location *font){ 103 | Face_Description description = get_buffer_face_description(app, buffer); 104 | description.font = *font; 105 | set_buffer_face_by_description(app, buffer, &description); 106 | } 107 | 108 | internal void 109 | set_buffer_face_by_face_load_parameters(Application_Links *app, Buffer_ID buffer, Face_Load_Parameters *parameters){ 110 | Face_Description description = get_buffer_face_description(app, buffer); 111 | description.parameters = *parameters; 112 | set_buffer_face_by_description(app, buffer, &description); 113 | } 114 | 115 | // BOTTOM 116 | -------------------------------------------------------------------------------- /custom/4coder_function_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_function_list.cpp - Command for listing all functions in a C/C++ file in a jump list. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_FUNCTION_LIST_H) 8 | #define FCODER_FUNCTION_LIST_H 9 | 10 | struct Function_Positions{ 11 | i64 sig_start_index; 12 | i64 sig_end_index; 13 | i64 open_paren_pos; 14 | }; 15 | 16 | struct Get_Positions_Results{ 17 | i64 positions_count; 18 | i64 next_token_index; 19 | b32 still_looping; 20 | }; 21 | 22 | #endif 23 | 24 | // BOTTOM 25 | -------------------------------------------------------------------------------- /custom/4coder_hash_functions.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 26.08.2018 5 | * 6 | * Generic hash functions 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | #if !defined(FCODER_HASH_FUNCTIONS_CPP) 13 | #define FCODER_HASH_FUNCTIONS_CPP 14 | 15 | static u64 16 | table_hash_u8(u8 *v, u64 size){ 17 | u64 hash = 0; 18 | for (u8 *p = v, *e = v + size; p < e; p += 1){ 19 | u8 k = *p; 20 | k *= 81; 21 | k = ((u8)(k << 4)) | ((u8)(k >> 4)); 22 | hash ^= k; 23 | hash *= 11; 24 | hash += 237; 25 | } 26 | return(hash); 27 | } 28 | static u64 29 | table_hash_u16(u16 *v, u64 size){ 30 | u64 hash = 0; 31 | for (u16 *p = v, *e = v + size; p < e; p += 1){ 32 | u16 k = *p; 33 | k *= 11601; 34 | k = ((u16)(k << 8)) | ((u16)(k >> 8)); 35 | hash ^= k; 36 | hash *= 11; 37 | hash += 12525; 38 | } 39 | return(hash); 40 | } 41 | static u64 42 | table_hash_u32(u32 *v, u64 size){ 43 | u64 hash = 0; 44 | for (u32 *p = v, *e = v + size; p < e; p += 1){ 45 | u32 k = *p; 46 | k *= 3432918353U; 47 | k = ((u32)(k << 16)) | ((u32)(k >> 16)); 48 | hash ^= k; 49 | hash *= 11; 50 | hash += 2041000173U; 51 | } 52 | return(hash); 53 | } 54 | static u64 55 | table_hash_u64(u64 *v, u64 size){ 56 | u64 hash = 0; 57 | for (u64 *p = v, *e = v + size; p < e; p += 1){ 58 | u64 k = *p; 59 | k *= 14744272059406101841ULL; 60 | k = ((u64)(k << 32)) | ((u64)(k >> 32)); 61 | hash ^= k; 62 | hash *= 11; 63 | hash += 8766028991911375085ULL; 64 | } 65 | return(hash); 66 | } 67 | static u64 68 | table_hash(void *v, i32 it_size, u64 size){ 69 | u64 hash = 0; 70 | switch (it_size){ 71 | case 1: 72 | { 73 | hash = table_hash_u8((u8*)v, size); 74 | }break; 75 | case 2: 76 | { 77 | hash = table_hash_u16((u16*)v, size); 78 | }break; 79 | case 4: 80 | { 81 | hash = table_hash_u32((u32*)v, size); 82 | }break; 83 | case 8: 84 | { 85 | hash = table_hash_u64((u64*)v, size); 86 | }break; 87 | default: 88 | { 89 | hash = table_hash_u8((u8*)v, it_size*size); 90 | }break; 91 | } 92 | return(hash); 93 | } 94 | 95 | #endif 96 | 97 | // BOTTOM 98 | -------------------------------------------------------------------------------- /custom/4coder_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Miscellaneous helpers for common operations. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_HELPER_H) 8 | #define FCODER_HELPER_H 9 | 10 | struct File_Name_Data{ 11 | String_Const_u8 file_name; 12 | String_Const_u8 data; 13 | }; 14 | 15 | struct View_Context_Block{ 16 | Application_Links *app; 17 | View_ID view; 18 | 19 | View_Context_Block(Application_Links *app, View_ID view, View_Context *ctx); 20 | ~View_Context_Block(); 21 | }; 22 | 23 | //////////////////////////////// 24 | 25 | typedef i32 Position_Within_Line; 26 | enum{ 27 | PositionWithinLine_Start, 28 | PositionWithinLine_SkipLeadingWhitespace, 29 | PositionWithinLine_End, 30 | }; 31 | 32 | typedef u32 Buffer_Seek_String_Flags; 33 | enum{ 34 | BufferSeekString_Backward = 1, 35 | BufferSeekString_CaseInsensitive = 2, 36 | }; 37 | 38 | //////////////////////////////// 39 | 40 | typedef b8 Character_Predicate_Function(u8 c); 41 | 42 | global Character_Predicate character_predicate_alpha = { { 43 | 0, 0, 0, 0, 0, 0, 0, 0, 44 | 254, 255, 255, 7, 254, 255, 255, 7, 45 | 0, 0, 0, 0, 0, 0, 0, 0, 46 | 0, 0, 0, 0, 0, 0, 0, 0, 47 | } }; 48 | 49 | global Character_Predicate character_predicate_alpha_numeric = { { 50 | 0, 0, 0, 0, 0, 0, 255, 3, 51 | 254, 255, 255, 7, 254, 255, 255, 7, 52 | 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 54 | } }; 55 | 56 | global Character_Predicate character_predicate_alpha_numeric_underscore = { { 57 | 0, 0, 0, 0, 0, 0, 255, 3, 58 | 254, 255, 255, 135, 254, 255, 255, 7, 59 | 0, 0, 0, 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, 0, 0, 0, 61 | } }; 62 | 63 | global Character_Predicate character_predicate_uppercase = { { 64 | 0, 0, 0, 0, 0, 0, 0, 0, 65 | 254, 255, 255, 7, 0, 0, 0, 0, 66 | 0, 0, 0, 0, 0, 0, 0, 0, 67 | 0, 0, 0, 0, 0, 0, 0, 0, 68 | } }; 69 | 70 | global Character_Predicate character_predicate_lowercase = { { 71 | 0, 0, 0, 0, 0, 0, 0, 0, 72 | 0, 0, 0, 0, 254, 255, 255, 7, 73 | 0, 0, 0, 0, 0, 0, 0, 0, 74 | 0, 0, 0, 0, 0, 0, 0, 0, 75 | } }; 76 | 77 | global Character_Predicate character_predicate_base10 = { { 78 | 0, 0, 0, 0, 0, 0, 255, 3, 79 | 0, 0, 0, 0, 0, 0, 0, 0, 80 | 0, 0, 0, 0, 0, 0, 0, 0, 81 | 0, 0, 0, 0, 0, 0, 0, 0, 82 | } }; 83 | 84 | global Character_Predicate character_predicate_base16 = { { 85 | 0, 0, 0, 0, 0, 0, 255, 3, 86 | 126, 0, 0, 0, 126, 0, 0, 0, 87 | 0, 0, 0, 0, 0, 0, 0, 0, 88 | 0, 0, 0, 0, 0, 0, 0, 0, 89 | } }; 90 | 91 | global Character_Predicate character_predicate_whitespace = { { 92 | 0, 62, 0, 0, 1, 0, 0, 0, 93 | 0, 0, 0, 0, 0, 0, 0, 0, 94 | 0, 0, 0, 0, 0, 0, 0, 0, 95 | 0, 0, 0, 0, 0, 0, 0, 0, 96 | } }; 97 | 98 | global Character_Predicate character_predicate_non_whitespace = { { 99 | 255, 193, 255, 255, 254, 255, 255, 255, 100 | 255, 255, 255, 255, 255, 255, 255, 255, 101 | 255, 255, 255, 255, 255, 255, 255, 255, 102 | 255, 255, 255, 255, 255, 255, 255, 255, 103 | } }; 104 | 105 | global Character_Predicate character_predicate_utf8_byte = { { 106 | 0, 0, 0, 0, 0, 0, 0, 0, 107 | 0, 0, 0, 0, 0, 0, 0, 0, 108 | 255, 255, 255, 255, 255, 255, 255, 255, 109 | 255, 255, 255, 255, 255, 255, 255, 255, 110 | } }; 111 | 112 | global Character_Predicate character_predicate_alpha_numeric_utf8 = { { 113 | 0, 0, 0, 0, 0, 0, 255, 3, 114 | 254, 255, 255, 7, 254, 255, 255, 7, 115 | 255, 255, 255, 255, 255, 255, 255, 255, 116 | 255, 255, 255, 255, 255, 255, 255, 255, 117 | } }; 118 | 119 | global Character_Predicate character_predicate_alpha_numeric_underscore_utf8 = { { 120 | 0, 0, 0, 0, 0, 0, 255, 3, 121 | 254, 255, 255, 135, 254, 255, 255, 7, 122 | 255, 255, 255, 255, 255, 255, 255, 255, 123 | 255, 255, 255, 255, 255, 255, 255, 255, 124 | } }; 125 | 126 | typedef i64 Boundary_Function(Application_Links *app, Buffer_ID buffer, Side side, Scan_Direction direction, i64 pos); 127 | 128 | struct Boundary_Function_Node{ 129 | Boundary_Function_Node *next; 130 | Boundary_Function *func; 131 | }; 132 | struct Boundary_Function_List{ 133 | Boundary_Function_Node *first; 134 | Boundary_Function_Node *last; 135 | i32 count; 136 | }; 137 | 138 | typedef Range_i64 Enclose_Function(Application_Links *app, Buffer_ID buffer, Range_i64 range); 139 | 140 | struct Indent_Info{ 141 | i64 first_char_pos; 142 | i32 indent_pos; 143 | b32 is_blank; 144 | b32 all_space; 145 | }; 146 | 147 | //////////////////////////////// 148 | 149 | struct Sort_Pair_i32{ 150 | i32 index; 151 | i32 key; 152 | }; 153 | 154 | //////////////////////////////// 155 | 156 | struct History_Group{ 157 | Application_Links *app; 158 | Buffer_ID buffer; 159 | History_Record_Index first; 160 | }; 161 | 162 | //////////////////////////////// 163 | 164 | typedef i32 View_Split_Kind; 165 | enum{ 166 | ViewSplitKind_Ratio, 167 | ViewSplitKind_FixedPixels, 168 | }; 169 | 170 | //////////////////////////////// 171 | 172 | typedef i32 Nest_Delimiter_Kind; 173 | enum{ 174 | NestDelim_None = 0, 175 | NestDelim_Open = 1, 176 | NestDelim_Close = 2, 177 | }; 178 | 179 | typedef u32 Find_Nest_Flag; 180 | enum{ 181 | FindNest_Scope = 1, 182 | FindNest_Paren = 2, 183 | FindNest_EndOfToken = 4, 184 | FindNest_Balanced = 8, 185 | }; 186 | 187 | #endif 188 | 189 | // BOTTOM 190 | -------------------------------------------------------------------------------- /custom/4coder_insertion.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial inserts helpers 3 | */ 4 | 5 | // TOP 6 | 7 | function Buffer_Insertion 8 | begin_buffer_insertion_at(Application_Links *app, Buffer_ID buffer_id, i64 at){ 9 | Buffer_Insertion result = {}; 10 | result.app = app; 11 | result.buffer = buffer_id; 12 | result.at = at; 13 | return(result); 14 | } 15 | 16 | function Buffer_Insertion 17 | begin_buffer_insertion_at_buffered(Application_Links *app, Buffer_ID buffer_id, i64 at, Cursor *cursor){ 18 | Buffer_Insertion result = begin_buffer_insertion_at(app, buffer_id, at); 19 | result.buffering = true; 20 | result.cursor = cursor; 21 | result.temp = begin_temp(cursor); 22 | return(result); 23 | } 24 | 25 | function Buffer_Insertion 26 | begin_buffer_insertion_at_buffered(Application_Links *app, Buffer_ID buffer_id, i64 at, Arena *buffer_memory, u64 buffer_memory_size){ 27 | Cursor *cursor = push_array(buffer_memory, Cursor, 1); 28 | *cursor = make_cursor(push_array(buffer_memory, u8, buffer_memory_size), buffer_memory_size); 29 | return(begin_buffer_insertion_at_buffered(app, buffer_id, at, cursor)); 30 | } 31 | 32 | function Buffer_Insertion 33 | begin_buffer_insertion(Application_Links *app){ 34 | View_ID view = get_active_view(app, Access_Always); 35 | Buffer_ID buffer = view_get_buffer(app, view, Access_Always); 36 | i64 cursor_pos = view_get_cursor_pos(app, view); 37 | Buffer_Insertion result = begin_buffer_insertion_at(app, buffer, cursor_pos); 38 | return(result); 39 | } 40 | 41 | function void 42 | insert_string__no_buffering(Buffer_Insertion *insertion, String_Const_u8 string){ 43 | buffer_replace_range(insertion->app, insertion->buffer, Ii64(insertion->at), string); 44 | insertion->at += string.size; 45 | } 46 | 47 | function void 48 | insert__flush(Buffer_Insertion *insertion){ 49 | Cursor *cursor = insertion->cursor; 50 | u64 pos = insertion->temp.temp_memory_cursor.pos; 51 | String_Const_u8 string = SCu8(cursor->base + pos, cursor->pos - pos); 52 | insert_string__no_buffering(insertion, string); 53 | end_temp(insertion->temp); 54 | } 55 | 56 | function char* 57 | insert__reserve(Buffer_Insertion *insertion, u64 size){ 58 | char *space = push_array(insertion->cursor, char, size); 59 | if (space == 0){ 60 | insert__flush(insertion); 61 | space = push_array(insertion->cursor, char, size); 62 | } 63 | return(space); 64 | } 65 | 66 | function void 67 | end_buffer_insertion(Buffer_Insertion *insertion){ 68 | if (insertion->buffering){ 69 | insert__flush(insertion); 70 | } 71 | } 72 | 73 | function void 74 | insert_string(Buffer_Insertion *insertion, String_Const_u8 string){ 75 | if (!insertion->buffering){ 76 | insert_string__no_buffering(insertion, string); 77 | } 78 | else{ 79 | char *space = insert__reserve(insertion, string.size); 80 | if (space != 0){ 81 | block_copy(space, string.str, string.size); 82 | } 83 | else{ 84 | insert_string__no_buffering(insertion, string); 85 | } 86 | } 87 | } 88 | 89 | function u64 90 | insertf(Buffer_Insertion *insertion, char *format, ...){ 91 | Scratch_Block scratch(insertion->app); 92 | va_list args; 93 | va_start(args, format); 94 | String_Const_u8 string = push_u8_stringfv(scratch, format, args); 95 | va_end(args); 96 | insert_string(insertion, string); 97 | return(string.size); 98 | } 99 | 100 | function void 101 | insertc(Buffer_Insertion *insertion, char C){ 102 | insert_string(insertion, SCu8(&C, 1)); 103 | } 104 | 105 | function b32 106 | insert_line_from_buffer(Buffer_Insertion *insertion, Buffer_ID buffer_id, i32 line, i32 truncate_at){ 107 | b32 success = is_valid_line(insertion->app, buffer_id, line); 108 | if (success){ 109 | Scratch_Block scratch(insertion->app); 110 | insert_string(insertion, push_buffer_line(insertion->app, scratch, buffer_id, line)); 111 | } 112 | return(success); 113 | } 114 | 115 | function b32 116 | insert_line_from_buffer(Buffer_Insertion *insertion, Buffer_ID buffer_id, i32 line){ 117 | return(insert_line_from_buffer(insertion, buffer_id, line, 0)); 118 | } 119 | 120 | // BOTTOM 121 | -------------------------------------------------------------------------------- /custom/4coder_insertion.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial inserts helpers 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FRED_INSERTION_H) 8 | #define FRED_INSERTION_H 9 | 10 | struct Buffer_Insertion{ 11 | Application_Links *app; 12 | Buffer_ID buffer; 13 | i64 at; 14 | b32 buffering; 15 | Cursor *cursor; 16 | Temp_Memory temp; 17 | }; 18 | 19 | #endif 20 | 21 | // BOTTOM 22 | -------------------------------------------------------------------------------- /custom/4coder_jump_lister.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_jump_lister.cpp - Lister for jump buffers. 3 | */ 4 | 5 | // TOP 6 | 7 | function Jump_Lister_Result 8 | get_jump_index_from_user(Application_Links *app, Marker_List *list, 9 | String_Const_u8 query){ 10 | Jump_Lister_Result result = {}; 11 | if (list != 0){ 12 | Scratch_Block scratch(app); 13 | Lister_Block lister(app, scratch); 14 | lister_set_query(lister, query); 15 | lister_set_default_handlers(lister); 16 | 17 | Buffer_ID list_buffer = list->buffer_id; 18 | 19 | i32 option_count = list->jump_count; 20 | Managed_Object stored_jumps = list->jump_array; 21 | for (i32 i = 0; i < option_count; i += 1){ 22 | Sticky_Jump_Stored stored = {}; 23 | managed_object_load_data(app, stored_jumps, i, 1, &stored); 24 | String_Const_u8 line = push_buffer_line(app, scratch, list_buffer, 25 | stored.list_line); 26 | lister_add_item(lister, line, SCu8(), IntAsPtr(i), 0); 27 | } 28 | 29 | Lister_Result l_result = run_lister(app, lister); 30 | if (!l_result.canceled){ 31 | result.success = true; 32 | result.index = (i32)PtrAsInt(l_result.user_data); 33 | } 34 | } 35 | 36 | return(result); 37 | } 38 | 39 | function Jump_Lister_Result 40 | get_jump_index_from_user(Application_Links *app, Marker_List *list, char *query){ 41 | return(get_jump_index_from_user(app, list, SCu8(query))); 42 | } 43 | 44 | function void 45 | jump_to_jump_lister_result(Application_Links *app, View_ID view, 46 | Marker_List *list, Jump_Lister_Result *jump){ 47 | if (jump->success){ 48 | ID_Pos_Jump_Location location = {}; 49 | if (get_jump_from_list(app, list, jump->index, &location)){ 50 | Buffer_ID jump_dst_buffer = {}; 51 | if (get_jump_buffer(app, &jump_dst_buffer, &location)){ 52 | view_set_active(app, view); 53 | jump_to_location(app, view, jump_dst_buffer, location); 54 | } 55 | } 56 | } 57 | } 58 | 59 | CUSTOM_COMMAND_SIG(view_jump_list_with_lister) 60 | CUSTOM_DOC("When executed on a buffer with jumps, creates a persistent lister for all the jumps") 61 | { 62 | Heap *heap = &global_heap; 63 | View_ID view = get_active_view(app, Access_Always); 64 | Buffer_ID buffer = view_get_buffer(app, view, Access_Always); 65 | Marker_List *list = get_or_make_list_for_buffer(app, heap, buffer); 66 | if (list != 0){ 67 | Jump_Lister_Result jump = get_jump_index_from_user(app, list, "Jump:"); 68 | jump_to_jump_lister_result(app, view, list, &jump); 69 | } 70 | } 71 | 72 | // BOTTOM 73 | -------------------------------------------------------------------------------- /custom/4coder_jump_lister.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_jump_lister.h - Lister for jump buffers. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_JUMP_LISTER_H) 8 | #define FCODER_JUMP_LISTER_H 9 | 10 | typedef i32 Jump_Lister_Activation_Rule; 11 | enum{ 12 | JumpListerActivation_OpenInUIView = 0, 13 | JumpListerActivation_OpenInTargetViewKeepUI = 1, 14 | JumpListerActivation_OpenInTargetViewCloseUI = 2, 15 | JumpListerActivation_OpenInNextViewKeepUI = 3, 16 | JumpListerActivation_OpenInNextViewCloseUI = 4, 17 | }; 18 | 19 | struct Jump_Lister_Parameters{ 20 | Buffer_ID list_buffer_id; 21 | Jump_Lister_Activation_Rule activation_rule; 22 | View_ID target_view_id; 23 | }; 24 | 25 | struct Jump_Lister_Result{ 26 | b32 success; 27 | i32 index; 28 | }; 29 | 30 | #endif 31 | 32 | // BOTTOM -------------------------------------------------------------------------------- /custom/4coder_jump_sticky.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_jump_sticky.h - Types for persistant jump positions. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_JUMP_STICKY_H) 8 | #define FCODER_JUMP_STICKY_H 9 | 10 | struct Sticky_Jump{ 11 | i64 list_line; 12 | i64 list_colon_index; 13 | b32 is_sub_error; 14 | Buffer_ID jump_buffer_id; 15 | i64 jump_pos; 16 | }; 17 | 18 | struct Sticky_Jump_Stored{ 19 | i64 list_line; 20 | i64 list_colon_index; 21 | b32 is_sub_error; 22 | Buffer_ID jump_buffer_id; 23 | i32 index_into_marker_array; 24 | }; 25 | 26 | struct Sticky_Jump_Node{ 27 | Sticky_Jump_Node *next; 28 | Sticky_Jump jump; 29 | }; 30 | 31 | struct Sticky_Jump_Array{ 32 | Sticky_Jump *jumps; 33 | i32 count; 34 | }; 35 | 36 | struct Sticky_Jump_Node_Header{ 37 | Managed_Object memory; 38 | Managed_Object markers; 39 | i32 first_index; 40 | i32 count; 41 | }; 42 | 43 | enum Jump_Location_Flag{ 44 | JumpFlag_IsSubJump = 0x1, 45 | }; 46 | 47 | struct Marker_List{ 48 | Managed_Object jump_array; 49 | i32 jump_count; 50 | i32 previous_size; 51 | Buffer_ID buffer_id; 52 | }; 53 | 54 | struct Marker_List_Node{ 55 | Marker_List_Node *next; 56 | Marker_List_Node *prev; 57 | Marker_List list; 58 | Buffer_ID buffer_id; 59 | }; 60 | 61 | struct Locked_Jump_State{ 62 | View_ID view; 63 | Marker_List *list; 64 | i32 list_index; 65 | }; 66 | 67 | #endif 68 | 69 | // BOTTOM 70 | -------------------------------------------------------------------------------- /custom/4coder_jumping.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_jumping.h - Typesused when writing code to jump to locations and seek through jump lists. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_JUMPING_H) 8 | #define FCODER_JUMPING_H 9 | 10 | typedef u32 Jump_Flag; 11 | enum{ 12 | JumpFlag_SkipSubs = 1, 13 | }; 14 | 15 | #endif 16 | 17 | // BOTTOM -------------------------------------------------------------------------------- /custom/4coder_keyboard_macro.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_keyboard_macro.cpp - Keyboard macro recording and replaying commands. 3 | */ 4 | 5 | // TOP 6 | 7 | function Buffer_ID 8 | get_keyboard_log_buffer(Application_Links *app){ 9 | return(get_buffer_by_name(app, string_u8_litexpr("*keyboard*"), Access_Always)); 10 | } 11 | 12 | function void 13 | keyboard_macro_play_single_line(Application_Links *app, String_Const_u8 macro_line){ 14 | Scratch_Block scratch(app); 15 | Input_Event event = parse_keyboard_event(scratch, macro_line); 16 | if (event.kind != InputEventKind_None){ 17 | enqueue_virtual_event(app, &event); 18 | } 19 | } 20 | 21 | function void 22 | keyboard_macro_play(Application_Links *app, String_Const_u8 macro){ 23 | Scratch_Block scratch(app); 24 | List_String_Const_u8 lines = string_split(scratch, macro, (u8*)"\n", 1); 25 | for (Node_String_Const_u8 *node = lines.first; 26 | node != 0; 27 | node = node->next){ 28 | String_Const_u8 line = string_skip_chop_whitespace(node->string); 29 | keyboard_macro_play_single_line(app, line); 30 | } 31 | } 32 | 33 | function b32 34 | get_current_input_is_virtual(Application_Links *app){ 35 | User_Input input = get_current_input(app); 36 | return(input.event.virtual_event); 37 | } 38 | 39 | //////////////////////////////// 40 | 41 | CUSTOM_COMMAND_SIG(keyboard_macro_start_recording) 42 | CUSTOM_DOC("Start macro recording, do nothing if macro recording is already started") 43 | { 44 | if (global_keyboard_macro_is_recording || 45 | get_current_input_is_virtual(app)){ 46 | return; 47 | } 48 | 49 | Buffer_ID buffer = get_keyboard_log_buffer(app); 50 | global_keyboard_macro_is_recording = true; 51 | global_keyboard_macro_range.first = buffer_get_size(app, buffer); 52 | } 53 | 54 | CUSTOM_COMMAND_SIG(keyboard_macro_finish_recording) 55 | CUSTOM_DOC("Stop macro recording, do nothing if macro recording is not already started") 56 | { 57 | if (!global_keyboard_macro_is_recording || 58 | get_current_input_is_virtual(app)){ 59 | return; 60 | } 61 | 62 | Buffer_ID buffer = get_keyboard_log_buffer(app); 63 | global_keyboard_macro_is_recording = false; 64 | i64 end = buffer_get_size(app, buffer); 65 | Buffer_Cursor cursor = buffer_compute_cursor(app, buffer, seek_pos(end)); 66 | Buffer_Cursor back_cursor = buffer_compute_cursor(app, buffer, seek_line_col(cursor.line - 1, 1)); 67 | global_keyboard_macro_range.one_past_last = back_cursor.pos; 68 | 69 | #if 0 70 | Scratch_Block scratch(app); 71 | String_Const_u8 macro = push_buffer_range(app, scratch, buffer, global_keyboard_macro_range); 72 | print_message(app, string_u8_litexpr("recorded:\n")); 73 | print_message(app, macro); 74 | #endif 75 | } 76 | 77 | CUSTOM_COMMAND_SIG(keyboard_macro_replay) 78 | CUSTOM_DOC("Replay the most recently recorded keyboard macro") 79 | { 80 | if (global_keyboard_macro_is_recording || 81 | get_current_input_is_virtual(app)){ 82 | return; 83 | } 84 | 85 | Buffer_ID buffer = get_keyboard_log_buffer(app); 86 | Scratch_Block scratch(app); 87 | String_Const_u8 macro = push_buffer_range(app, scratch, buffer, global_keyboard_macro_range); 88 | keyboard_macro_play(app, macro); 89 | } 90 | 91 | // BOTTOM 92 | -------------------------------------------------------------------------------- /custom/4coder_layout_rule.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_layout_rule.h - Built in layout rule types. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_LAYOUT_RULE_H) 8 | #define FCODER_LAYOUT_RULE_H 9 | 10 | struct Newline_Layout_Vars{ 11 | i64 newline_character_index; 12 | b32 consuming_newline_characters; 13 | b32 prev_did_emit_newline; 14 | }; 15 | 16 | struct LefRig_TopBot_Layout_Vars{ 17 | Face_Advance_Map *advance_map; 18 | Face_Metrics *metrics; 19 | f32 tab_width; 20 | f32 line_to_text_shift; 21 | 22 | Vec2_f32 blank_dim; 23 | 24 | Vec2_f32 p; 25 | f32 line_y; 26 | f32 text_y; 27 | f32 width; 28 | }; 29 | 30 | struct Layout_Reflex{ 31 | Layout_Item_List *list; 32 | Buffer_ID buffer; 33 | f32 width; 34 | Face_ID face; 35 | }; 36 | 37 | typedef i32 Layout_Wrap_Kind; 38 | enum{ 39 | Layout_Unwrapped, 40 | Layout_Wrapped, 41 | }; 42 | 43 | typedef i32 Layout_Virtual_Indent; 44 | enum{ 45 | LayoutVirtualIndent_Off, 46 | LayoutVirtualIndent_On, 47 | }; 48 | 49 | #endif 50 | 51 | // BOTTOM 52 | -------------------------------------------------------------------------------- /custom/4coder_lister_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Lister base 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_LISTER_BASE_H) 8 | #define FCODER_LISTER_BASE_H 9 | 10 | typedef i32 Lister_Activation_Code; 11 | enum{ 12 | ListerActivation_Finished = 0, 13 | ListerActivation_Continue = 1, 14 | ListerActivation_ContinueAndRefresh = 2, 15 | }; 16 | 17 | typedef void Lister_Regenerate_List_Function_Type(Application_Links *app, struct Lister *lister); 18 | 19 | struct Lister_Node{ 20 | Lister_Node *next; 21 | Lister_Node *prev; 22 | String_Const_u8 string; 23 | union{ 24 | String_Const_u8 status; 25 | i32 index; 26 | }; 27 | void *user_data; 28 | i32 raw_index; 29 | }; 30 | 31 | struct Lister_Node_List{ 32 | Lister_Node *first; 33 | Lister_Node *last; 34 | i32 count; 35 | }; 36 | 37 | struct Lister_Node_Ptr_Array{ 38 | Lister_Node **node_ptrs; 39 | i32 count; 40 | }; 41 | 42 | typedef Lister_Activation_Code Lister_Write_Character_Function(Application_Links *app); 43 | typedef Lister_Activation_Code Lister_Key_Stroke_Function(Application_Links *app); 44 | typedef void Lister_Navigate_Function(Application_Links *app, 45 | View_ID view, struct Lister *lister, 46 | i32 index_delta); 47 | 48 | struct Lister_Handlers{ 49 | Lister_Regenerate_List_Function_Type *refresh; 50 | Lister_Write_Character_Function *write_character; 51 | Custom_Command_Function *backspace; 52 | Lister_Navigate_Function *navigate; 53 | Lister_Key_Stroke_Function *key_stroke; 54 | }; 55 | 56 | struct Lister_Result{ 57 | b32 canceled; 58 | b32 activated_by_click; 59 | String_Const_u8 text_field; 60 | void *user_data; 61 | }; 62 | 63 | struct Lister{ 64 | Arena *arena; 65 | Temp_Memory restore_all_point; 66 | 67 | Lister_Handlers handlers; 68 | 69 | Mapping *mapping; 70 | Command_Map *map; 71 | 72 | u8 query_space[256]; 73 | u8 text_field_space[256]; 74 | u8 key_string_space[256]; 75 | String_u8 query; 76 | String_u8 text_field; 77 | String_u8 key_string; 78 | 79 | Lister_Node_List options; 80 | Temp_Memory filter_restore_point; 81 | Lister_Node_Ptr_Array filtered; 82 | 83 | b32 set_vertical_focus_to_item; 84 | Lister_Node *highlighted_node; 85 | void *hot_user_data; 86 | i32 item_index; 87 | i32 raw_item_index; 88 | 89 | Basic_Scroll scroll; 90 | i32 visible_count; 91 | 92 | Lister_Result out; 93 | }; 94 | 95 | struct Lister_Prev_Current{ 96 | Lister *prev; 97 | Lister *current; 98 | }; 99 | 100 | struct Lister_Block{ 101 | Application_Links *app; 102 | Lister_Prev_Current lister; 103 | Lister_Block(Application_Links *app, Arena *arena); 104 | ~Lister_Block(); 105 | operator Lister *(); 106 | }; 107 | 108 | struct Lister_Prealloced_String{ 109 | String_Const_u8 string; 110 | }; 111 | 112 | struct Lister_Filtered{ 113 | Lister_Node_Ptr_Array exact_matches; 114 | Lister_Node_Ptr_Array before_extension_matches; 115 | Lister_Node_Ptr_Array substring_matches; 116 | }; 117 | 118 | //////////////////////////////// 119 | 120 | struct Lister_Choice{ 121 | Lister_Choice *next; 122 | String_Const_u8 string; 123 | String_Const_u8 status; 124 | Key_Code key_code; 125 | union{ 126 | u64 user_data; 127 | void *user_data_ptr; 128 | }; 129 | }; 130 | 131 | struct Lister_Choice_List{ 132 | Lister_Choice *first; 133 | Lister_Choice *last; 134 | }; 135 | 136 | #endif 137 | 138 | // BOTTOM 139 | -------------------------------------------------------------------------------- /custom/4coder_log.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 14.08.2019 5 | * 6 | * Logging helpers. 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | #if !defined(FCODER_LOG_CPP) 13 | #define FCODER_LOG_CPP 14 | 15 | internal String_Const_u8 16 | log_event(Arena *arena, String_Const_u8 event_name, String_Const_u8 src_name, i32 line_number, i32 buffer, i32 view, i32 thread_id){ 17 | List_String_Const_u8 list = {}; 18 | string_list_pushf(arena, &list, "%S:%d: %S", src_name, line_number, event_name); 19 | if (thread_id != 0){ 20 | string_list_pushf(arena, &list, " [thread=%d]", thread_id); 21 | } 22 | if (buffer != 0){ 23 | string_list_pushf(arena, &list, " [buffer=%d]", buffer); 24 | } 25 | if (view != 0){ 26 | string_list_pushf(arena, &list, " [view=%d]", view); 27 | } 28 | string_list_push(arena, &list, string_u8_litexpr("\n")); 29 | return(string_list_flatten(arena, list)); 30 | } 31 | 32 | #define LogEventStr(log_call, arena, B, V, T, E) \ 33 | Stmnt(Temp_Memory temp_LOG = begin_temp(arena); \ 34 | String_Const_u8 M = log_event(arena, E, \ 35 | string_u8_litexpr(__FILE__), \ 36 | __LINE__, (B), (V), (T)); \ 37 | log_call; \ 38 | end_temp(temp_LOG); ) 39 | 40 | #define LogEventLit(log_call, arena, B, V, T, Elit) \ 41 | LogEventStr(log_call, arena, (B), (V), (T), string_u8_litexpr(Elit)) 42 | 43 | #define LogEventF(log_call, arena, B, V, T, Ef, ...) \ 44 | Stmnt(Temp_Memory temp_LOG_F = begin_temp(arena); \ 45 | String_Const_u8 E = push_u8_stringf(arena, Ef, __VA_ARGS__); \ 46 | LogEventStr(log_call, arena, B, V, T, E); \ 47 | end_temp(temp_LOG_F); ) 48 | 49 | #endif 50 | 51 | // BOTTOM 52 | -------------------------------------------------------------------------------- /custom/4coder_log_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 14.08.2019 5 | * 6 | * Log parser. 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | #if !defined(FCODER_LOG_PARSER_H) 13 | #define FCODER_LOG_PARSER_H 14 | 15 | typedef i64 Log_Tag_Kind; 16 | enum{ 17 | LogTagKind_Null, 18 | LogTagKind_Integer, 19 | LogTagKind_String, 20 | }; 21 | 22 | typedef i32 Log_String_Source; 23 | enum{ 24 | LogParse_ExternalString, 25 | LogParse_PreAllocatedString, 26 | }; 27 | 28 | struct Log_Tag_Value{ 29 | Log_Tag_Kind kind; 30 | union{ 31 | u64 value; 32 | i64 value_s; 33 | }; 34 | }; 35 | 36 | struct Log_Sort_Key{ 37 | Log_Tag_Value value; 38 | i32 number; 39 | }; 40 | 41 | struct Log_Tag_Name_Value{ 42 | u64 name; 43 | Log_Tag_Value value; 44 | }; 45 | 46 | struct Log_Tag{ 47 | Log_Tag *next; 48 | u64 name; 49 | Log_Tag_Value value; 50 | }; 51 | 52 | struct Log_Event{ 53 | Log_Event *next; 54 | u64 src_file_name; 55 | u64 event_name; 56 | u64 line_number; 57 | 58 | Log_Tag *first_tag; 59 | Log_Tag *last_tag; 60 | i32 tag_count; 61 | 62 | i32 event_number; 63 | 64 | Table_u64_u64 tag_name_to_tag_ptr_table; 65 | }; 66 | 67 | struct Log_Event_Ptr_Node{ 68 | Log_Event_Ptr_Node *next; 69 | Log_Event *event; 70 | }; 71 | 72 | struct Log_Event_List{ 73 | Log_Event_Ptr_Node *first; 74 | Log_Event_Ptr_Node *last; 75 | i32 count; 76 | }; 77 | 78 | struct Log_Event_Ptr_Array{ 79 | Log_Event **events; 80 | i32 count; 81 | }; 82 | 83 | struct Log_Tag_Value_Array{ 84 | Log_Tag_Value *vals; 85 | i32 count; 86 | }; 87 | 88 | struct Log_Parse{ 89 | Arena *arena; 90 | 91 | Log_Event *first_event; 92 | Log_Event *last_event; 93 | i32 event_count; 94 | 95 | u64 string_id_counter; 96 | Table_Data_u64 string_to_id_table; 97 | Table_u64_Data id_to_string_table; 98 | 99 | Table_Data_u64 tag_value_to_event_list_table; 100 | Table_u64_u64 tag_name_to_event_list_table; 101 | }; 102 | 103 | //////////////////////////////// 104 | 105 | struct Log_Graph_Thread_Bucket{ 106 | Log_Graph_Thread_Bucket *next; 107 | Range_i32 range; 108 | b32 had_a_tag; 109 | u64 thread_id_value; 110 | }; 111 | 112 | struct Log_Graph_Box{ 113 | Log_Graph_Box *next; 114 | Rect_f32 rect; 115 | Log_Event *event; 116 | }; 117 | 118 | typedef i32 Log_Filter_Kind; 119 | enum{ 120 | LogFilter_ERROR, 121 | LogFilter_TagValue, 122 | LogFilter_Tag, 123 | }; 124 | 125 | struct Log_Filter{ 126 | Log_Filter *next; 127 | Log_Filter *prev; 128 | Log_Filter_Kind kind; 129 | u64 tag_name_code; 130 | Log_Tag_Value tag_value; 131 | }; 132 | 133 | struct Log_Filter_Set{ 134 | Log_Filter filters_memory[20]; 135 | Log_Filter *free_filters; 136 | Log_Filter *first; 137 | Log_Filter *last; 138 | i32 count; 139 | i32 alter_counter; 140 | }; 141 | 142 | typedef i32 Log_Graph_List_Tab; 143 | enum{ 144 | LogTab_ERROR, 145 | LogTab_Filters, 146 | LogTab_Previews, 147 | LogTab_COUNT, 148 | }; 149 | 150 | struct Log_Graph{ 151 | b32 holding_temp; 152 | Temp_Memory temp; 153 | Rect_f32 layout_region; 154 | Face_ID face_id; 155 | i32 filter_alter_counter; 156 | i32 preview_alter_counter; 157 | Log_Graph_List_Tab tab; 158 | Rect_f32 details_region; 159 | Log_Event_List filtered_list; 160 | Log_Event_Ptr_Array event_array; 161 | Log_Graph_Thread_Bucket *first_bucket; 162 | Log_Graph_Thread_Bucket *last_bucket; 163 | i32 bucket_count; 164 | Log_Graph_Box *first_box; 165 | Log_Graph_Box *last_box; 166 | i32 box_count; 167 | f32 y_scroll; 168 | f32 max_y_scroll; 169 | Log_Event *selected_event; 170 | b32 has_unused_click; 171 | Vec2_f32 unused_click; 172 | }; 173 | 174 | #endif 175 | 176 | // BOTTOM 177 | -------------------------------------------------------------------------------- /custom/4coder_malloc_allocator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder malloc base allocator 3 | */ 4 | 5 | // TOP 6 | 7 | #include 8 | 9 | #if !OS_MAC 10 | # include 11 | #endif 12 | 13 | internal void* 14 | base_reserve__malloc(void *user_data, u64 size, u64 *size_out, String_Const_u8 location){ 15 | *size_out = size; 16 | return(malloc((size_t)size)); 17 | } 18 | 19 | internal void 20 | base_free__malloc(void *user_data, void *ptr){ 21 | free(ptr); 22 | } 23 | 24 | internal Base_Allocator 25 | make_malloc_base_allocator(void){ 26 | return(make_base_allocator(base_reserve__malloc, 0, 0, 27 | base_free__malloc, 0, 0)); 28 | } 29 | 30 | global Base_Allocator malloc_base_allocator = {}; 31 | 32 | internal Base_Allocator* 33 | get_allocator_malloc(void){ 34 | if (malloc_base_allocator.reserve == 0){ 35 | malloc_base_allocator = make_malloc_base_allocator(); 36 | } 37 | return(&malloc_base_allocator); 38 | } 39 | 40 | internal Arena 41 | make_arena_malloc(u64 chunk_size, u64 align){ 42 | Base_Allocator *allocator = get_allocator_malloc(); 43 | return(make_arena(allocator, chunk_size, align)); 44 | } 45 | 46 | internal Arena 47 | make_arena_malloc(u64 chunk_size){ 48 | return(make_arena_malloc(chunk_size, 8)); 49 | } 50 | 51 | internal Arena 52 | make_arena_malloc(void){ 53 | return(make_arena_malloc(KB(16), 8)); 54 | } 55 | 56 | // BOTTOM 57 | -------------------------------------------------------------------------------- /custom/4coder_prj_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_prj_v1.h - type header paired with 4coder_prj_v1.cpp 3 | */ 4 | 5 | // TOP 6 | 7 | #ifndef FCODER_PRJ_V1_H 8 | #define FCODER_PRJ_V1_H 9 | 10 | /////////////////////////////// 11 | // NOTE(allen): Project v0-v1 Structure 12 | 13 | struct Prj_V1_File_Load_Path{ 14 | String8 path; 15 | b32 recursive; 16 | b32 relative; 17 | }; 18 | 19 | struct Prj_V1_File_Load_Path_Array{ 20 | Prj_V1_File_Load_Path *paths; 21 | i32 count; 22 | }; 23 | 24 | struct Prj_V1_Command{ 25 | String8 name; 26 | String8 cmd; 27 | String8 out; 28 | b32 footer_panel; 29 | b32 save_dirty_files; 30 | b32 cursor_at_end; 31 | }; 32 | 33 | struct Prj_V1_Command_Array{ 34 | Prj_V1_Command *commands; 35 | i32 count; 36 | }; 37 | 38 | struct Prj_V1{ 39 | b32 loaded; 40 | 41 | String8 dir; 42 | String8 name; 43 | 44 | Prj_Pattern_List pattern_list; 45 | Prj_Pattern_List blacklist_pattern_list; 46 | Prj_V1_File_Load_Path_Array load_path_array; 47 | Prj_V1_Command_Array command_array; 48 | 49 | i32 fkey_commands[16]; 50 | }; 51 | 52 | enum Prj_V1_OS_Match_Level{ 53 | PrjV1OSMatchLevel_NoMatch = 0, 54 | PrjV1OSMatchLevel_PassiveMatch = 1, 55 | PrjV1OSMatchLevel_ActiveMatch = 2, 56 | }; 57 | 58 | 59 | //////////////////////////////// 60 | // NOTE(allen): Project v0-v1 -> v2 Function 61 | 62 | function Variable_Handle prj_v1_to_v2(Application_Links *app, String8 dir, Config *parsed); 63 | 64 | 65 | #endif //4CODER_PRJ_V1_H 66 | 67 | // BOTTOM 68 | -------------------------------------------------------------------------------- /custom/4coder_profile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder_profile.cpp - Built in self profiling report. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_PROFILE_H) 8 | #define FCODER_PROFILE_H 9 | 10 | struct Profile_Global_List{ 11 | System_Mutex mutex; 12 | Arena node_arena; 13 | Arena_Node *first_arena; 14 | Arena_Node *last_arena; 15 | Profile_Thread *first_thread; 16 | Profile_Thread *last_thread; 17 | i32 thread_count; 18 | Profile_Enable_Flag disable_bits; 19 | }; 20 | 21 | struct Profile_Block{ 22 | Thread_Context *tctx; 23 | Profile_Global_List *list; 24 | b32 is_closed; 25 | Profile_ID id; 26 | 27 | Profile_Block(Thread_Context *tctx, Profile_Global_List *list, 28 | String_Const_u8 name, String_Const_u8 location); 29 | Profile_Block(Application_Links *app, String_Const_u8 name, String_Const_u8 location); 30 | ~Profile_Block(); 31 | void close_now(); 32 | }; 33 | 34 | struct Profile_Scope_Block{ 35 | Thread_Context *tctx; 36 | Profile_Global_List *list; 37 | b32 is_closed; 38 | Profile_ID id; 39 | 40 | Profile_Scope_Block(Thread_Context *tctx, Profile_Global_List *list, 41 | String_Const_u8 name, String_Const_u8 location); 42 | Profile_Scope_Block(Application_Links *app, String_Const_u8 name, String_Const_u8 location); 43 | ~Profile_Scope_Block(); 44 | void close_now(); 45 | }; 46 | 47 | #endif 48 | 49 | // BOTTOM 50 | -------------------------------------------------------------------------------- /custom/4coder_profile_inspect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder_profile_inspect.h - Built in self profiling UI. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_PROFILE_INSPECT_H) 8 | #define FCODER_PROFILE_INSPECT_H 9 | 10 | struct Profile_Node_Ptr{ 11 | Profile_Node_Ptr *next; 12 | struct Profile_Node *ptr; 13 | }; 14 | 15 | struct Profile_Slot{ 16 | Profile_Slot *next; 17 | String_Const_u8 location; 18 | String_Const_u8 name; 19 | 20 | u64 total_time; 21 | b32 corrupted_time; 22 | 23 | i32 hit_count; 24 | Profile_Node_Ptr *first_hit; 25 | Profile_Node_Ptr *last_hit; 26 | }; 27 | 28 | struct Profile_Node{ 29 | Profile_Node *next; 30 | Profile_Node *parent; 31 | Profile_Slot *slot; 32 | struct Profile_Inspection_Thread *thread; 33 | Range_u64 time; 34 | Profile_ID id; 35 | u64 unique_counter; 36 | 37 | Profile_Node *first_child; 38 | Profile_Node *last_child; 39 | i32 child_count; 40 | 41 | b32 closed; 42 | }; 43 | 44 | struct Profile_Inspection_Thread{ 45 | i32 thread_id; 46 | String_Const_u8 name; 47 | Profile_Node root; 48 | u64 active_time; 49 | }; 50 | 51 | struct Profile_Error{ 52 | Profile_Error *next; 53 | String_Const_u8 message; 54 | String_Const_u8 location; 55 | }; 56 | 57 | typedef i32 Profile_Inspection_Tab; 58 | enum{ 59 | ProfileInspectTab_None, 60 | ProfileInspectTab_Threads, 61 | ProfileInspectTab_Blocks, 62 | ProfileInspectTab_Errors, 63 | ProfileInspectTab_Memory, 64 | ProfileInspectTab_Selection, 65 | }; 66 | 67 | struct Profile_Inspection{ 68 | Profile_Slot *first_slot; 69 | Profile_Slot *last_slot; 70 | Profile_Error *first_error; 71 | Profile_Error *last_error; 72 | Profile_Inspection_Thread *threads; 73 | i32 slot_count; 74 | i32 thread_count; 75 | i32 error_count; 76 | 77 | Profile_Inspection_Tab tab_id; 78 | Profile_Inspection_Thread *selected_thread; 79 | Profile_Slot *selected_slot; 80 | Profile_Node *selected_node; 81 | 82 | Profile_Inspection_Tab tab_id_hovered; 83 | String_Const_u8 full_name_hovered; 84 | u64 unique_counter_hovered; 85 | String_Const_u8 location_jump_hovered; 86 | Profile_Inspection_Thread *hover_thread; 87 | Profile_Slot *hover_slot; 88 | Profile_Node *hover_node; 89 | }; 90 | 91 | global Profile_Inspection global_profile_inspection = {}; 92 | 93 | struct Memory_Bucket{ 94 | Memory_Bucket *next; 95 | Memory_Annotation annotation; 96 | String_Const_u8 location; 97 | u64 total_memory; 98 | }; 99 | 100 | #endif 101 | 102 | // TOP 103 | -------------------------------------------------------------------------------- /custom/4coder_profile_static_disable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder_profile_static_disable.cpp - Statically removes all profile posting code 3 | * that follows until the next 4coder_profile_static_enable.cpp 4 | */ 5 | 6 | // TOP 7 | 8 | #if defined(ProfileBlock) 9 | #undef ProfileBlock 10 | #undef ProfileScope 11 | #undef ProfileBlockNamed 12 | #undef ProfileScopeNamed 13 | 14 | #undef ProfileTLBlock 15 | #undef ProfileTLScope 16 | #undef ProfileTLBlockNamed 17 | #undef ProfileTLScopeNamed 18 | 19 | #undef ProfileCloseNow 20 | #endif 21 | 22 | #define ProfileBlock(T,N) 23 | #define ProfileScope(T,N) 24 | #define ProfileBlockNamed(T,N,M) 25 | #define ProfileScopeNamed(T,N,M) 26 | 27 | #define ProfileTLBlock(T,L,N) 28 | #define ProfileTLScope(T,L,N) 29 | #define ProfileTLBlockNamed(T,L,N,M) 30 | #define ProfileTLScopeNamed(T,L,N,M) 31 | 32 | #define ProfileCloseNow(O) 33 | 34 | // BOTTOM 35 | -------------------------------------------------------------------------------- /custom/4coder_profile_static_enable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder_profile_static_enable.cpp - Macro interface for self profiler. 3 | */ 4 | 5 | // TOP 6 | 7 | #if defined(ProfileBlock) 8 | #undef ProfileBlock 9 | #undef ProfileScope 10 | #undef ProfileBlockNamed 11 | #undef ProfileScopeNamed 12 | 13 | #undef ProfileTLBlock 14 | #undef ProfileTLScope 15 | #undef ProfileTLBlockNamed 16 | #undef ProfileTLScopeNamed 17 | 18 | #undef ProfileCloseNow 19 | #endif 20 | 21 | #define ProfileBlock(T,N) \ 22 | Profile_Block glue(profile_block_, __LINE__) \ 23 | ((T), string_u8_litexpr(N), string_u8_litexpr(file_name_line_number)) 24 | 25 | #define ProfileScope(T,N) \ 26 | Profile_Scope_Block glue(profile_block_, __LINE__) \ 27 | ((T), string_u8_litexpr(N), string_u8_litexpr(file_name_line_number)) 28 | 29 | #define ProfileBlockNamed(T,N,M) \ 30 | Profile_Block M \ 31 | ((T), string_u8_litexpr(N), string_u8_litexpr(file_name_line_number)) 32 | 33 | #define ProfileScopeNamed(T,N,M) \ 34 | Profile_Scope_Block M \ 35 | ((T), string_u8_litexpr(N), string_u8_litexpr(file_name_line_number)) 36 | 37 | 38 | 39 | #define ProfileTLBlock(T,L,N) \ 40 | Profile_Block glue(profile_block_, __LINE__) \ 41 | ((T), (L), string_u8_litexpr(N), string_u8_litexpr(file_name_line_number)) 42 | 43 | #define ProfileTLScope(T,L,N) \ 44 | Profile_Scope_Block glue(profile_block_, __LINE__) \ 45 | ((T), (L), string_u8_litexpr(N), string_u8_litexpr(file_name_line_number)) 46 | 47 | #define ProfileTLBlockNamed(T,L,N,M) \ 48 | Profile_Block M \ 49 | ((T), (L), string_u8_litexpr(N), string_u8_litexpr(file_name_line_number)) 50 | 51 | #define ProfileTLScopeNamed(T,L,N,M) \ 52 | Profile_Scope_Block M \ 53 | ((T), (L), string_u8_litexpr(N), string_u8_litexpr(file_name_line_number)) 54 | 55 | 56 | 57 | #define ProfileCloseNow(B) ((B).close_now()) 58 | 59 | // BOTTOM 60 | -------------------------------------------------------------------------------- /custom/4coder_project_commands.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_project_commands.h - type header paired with 4coder_project_commands.cpp 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_PROJECT_COMMANDS_H) 8 | #define FCODER_PROJECT_COMMANDS_H 9 | 10 | //////////////////////////////// 11 | // NOTE(allen): Match Pattern Types 12 | 13 | struct Prj_Pattern{ 14 | String8List absolutes; 15 | }; 16 | 17 | struct Prj_Pattern_Node{ 18 | Prj_Pattern_Node *next; 19 | Prj_Pattern pattern; 20 | }; 21 | 22 | struct Prj_Pattern_List{ 23 | Prj_Pattern_Node *first; 24 | Prj_Pattern_Node *last; 25 | i32 count; 26 | }; 27 | 28 | typedef u32 Prj_Open_File_Flags; 29 | enum{ 30 | PrjOpenFileFlag_Recursive = 1, 31 | }; 32 | 33 | /////////////////////////////// 34 | // NOTE(allen): Project Files 35 | 36 | struct Prj_Setup_Status{ 37 | b32 bat_exists; 38 | b32 sh_exists; 39 | b32 project_exists; 40 | b32 everything_exists; 41 | }; 42 | 43 | struct Prj_Key_Strings{ 44 | b32 success; 45 | String8 script_file; 46 | String8 code_file; 47 | String8 output_dir; 48 | String8 binary_file; 49 | }; 50 | 51 | typedef u32 Prj_Setup_Script_Flags; 52 | enum{ 53 | PrjSetupScriptFlag_Project = 0x1, 54 | PrjSetupScriptFlag_Bat = 0x2, 55 | PrjSetupScriptFlag_Sh = 0x4, 56 | }; 57 | 58 | //////////////////////////////// 59 | // NOTE(allen): File Pattern Operators 60 | 61 | function Prj_Pattern_List prj_pattern_list_from_extension_array(Arena *arena, String8Array list); 62 | function Prj_Pattern_List prj_pattern_list_from_var(Arena *arena, Variable_Handle var); 63 | function Prj_Pattern_List prj_get_standard_blacklist(Arena *arena); 64 | 65 | function b32 prj_match_in_pattern_list(String8 string, Prj_Pattern_List list); 66 | 67 | function void prj_close_files_with_ext(Application_Links *app, String8Array extension_array); 68 | function void prj_open_files_pattern_filter(Application_Links *app, String8 dir, Prj_Pattern_List whitelist, Prj_Pattern_List blacklist, Prj_Open_File_Flags flags); 69 | function void prj_open_all_files_with_ext_in_hot(Application_Links *app, String8Array array, Prj_Open_File_Flags flags); 70 | 71 | //////////////////////////////// 72 | // NOTE(allen): Project Files 73 | 74 | function void prj_stringize_project(Application_Links *app, Arena *arena, Variable_Handle project, String8List *out); 75 | 76 | function Prj_Setup_Status prj_file_is_setup(Application_Links *app, String8 script_path, String8 script_file); 77 | function b32 prj_generate_bat(Arena *scratch, String8 opts, String8 compiler, String8 script_path, String8 script_file, String8 code_file, String8 output_dir, String8 binary_file); 78 | function b32 prj_generate_sh(Arena *scratch, String8 opts, String8 compiler, String8 script_path, String8 script_file, String8 code_file, String8 output_dir, String8 binary_file); 79 | function b32 prj_generate_project(Arena *scratch, String8 script_path, String8 script_file, String8 output_dir, String8 binary_file); 80 | 81 | function void prj_setup_scripts(Application_Links *app, Prj_Setup_Script_Flags flags); 82 | 83 | //////////////////////////////// 84 | // NOTE(allen): Project Operations 85 | 86 | function void prj_exec_command(Application_Links *app, Variable_Handle cmd_var); 87 | function Variable_Handle prj_command_from_name(Application_Links *app, String8 cmd_name); 88 | function void prj_exec_command_name(Application_Links *app, String8 cmd_name); 89 | function void prj_exec_command_fkey_index(Application_Links *app, i32 fkey_index); 90 | 91 | function String8 prj_full_file_path_from_project(Arena *arena, Variable_Handle project); 92 | function String8 prj_path_from_project(Arena *arena, Variable_Handle project); 93 | function Variable_Handle prj_cmd_from_user(Application_Links *app, Variable_Handle prj_var, String8 query); 94 | 95 | #endif 96 | 97 | // BOTTOM 98 | -------------------------------------------------------------------------------- /custom/4coder_scope_commands.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_scope_commands.cpp - A set of commands and helpers relevant for scope level navigation and editing. 3 | */ 4 | 5 | // TOP 6 | 7 | function void 8 | select_next_scope_after_pos(Application_Links *app, View_ID view, Buffer_ID buffer, 9 | i64 pos){ 10 | Find_Nest_Flag flags = FindNest_Scope; 11 | Range_i64 range = {}; 12 | if (find_nest_side(app, buffer, pos + 1, flags, Scan_Forward, NestDelim_Open, 13 | &range) && 14 | find_nest_side(app, buffer, range.end, 15 | flags|FindNest_Balanced|FindNest_EndOfToken, Scan_Forward, 16 | NestDelim_Close, &range.end)){ 17 | select_scope(app, view, range); 18 | } 19 | } 20 | 21 | function b32 22 | range_is_scope_selection(Application_Links *app, Buffer_ID buffer, Range_i64 range){ 23 | return (buffer_get_char(app, buffer, range.min) == '{' && 24 | buffer_get_char(app, buffer, range.max - 1) == '}'); 25 | } 26 | 27 | CUSTOM_COMMAND_SIG(select_surrounding_scope) 28 | CUSTOM_DOC("Finds the scope enclosed by '{' '}' surrounding the cursor and puts the cursor and mark on the '{' and '}'.") 29 | { 30 | View_ID view = get_active_view(app, Access_ReadVisible); 31 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible); 32 | i64 pos = view_get_cursor_pos(app, view); 33 | Range_i64 range = {}; 34 | if (find_surrounding_nest(app, buffer, pos, FindNest_Scope, &range)){ 35 | select_scope(app, view, range); 36 | } 37 | } 38 | 39 | CUSTOM_COMMAND_SIG(select_surrounding_scope_maximal) 40 | CUSTOM_DOC("Selects the top-most scope that surrounds the cursor.") 41 | { 42 | View_ID view = get_active_view(app, Access_ReadVisible); 43 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible); 44 | i64 pos = view_get_cursor_pos(app, view); 45 | Range_i64 range = {}; 46 | if (find_surrounding_nest(app, buffer, pos, FindNest_Scope, &range)){ 47 | for (;;){ 48 | pos = range.min; 49 | if (!find_surrounding_nest(app, buffer, pos, FindNest_Scope, &range)){ 50 | break; 51 | } 52 | } 53 | select_scope(app, view, range); 54 | } 55 | } 56 | 57 | CUSTOM_COMMAND_SIG(select_next_scope_absolute) 58 | CUSTOM_DOC("Finds the first scope started by '{' after the cursor and puts the cursor and mark on the '{' and '}'.") 59 | { 60 | View_ID view = get_active_view(app, Access_ReadVisible); 61 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible); 62 | i64 pos = view_get_cursor_pos(app, view); 63 | select_next_scope_after_pos(app, view, buffer, pos); 64 | } 65 | 66 | CUSTOM_COMMAND_SIG(select_next_scope_after_current) 67 | CUSTOM_DOC("If a scope is selected, find first scope that starts after the selected scope. Otherwise find the first scope that starts after the cursor.") 68 | { 69 | View_ID view = get_active_view(app, Access_ReadVisible); 70 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible); 71 | i64 cursor_pos = view_get_cursor_pos(app, view); 72 | i64 mark_pos = view_get_mark_pos(app, view); 73 | Range_i64 range = Ii64(cursor_pos, mark_pos); 74 | if (range_is_scope_selection(app, buffer, range)){ 75 | select_next_scope_after_pos(app, view, buffer, range.max); 76 | } 77 | else{ 78 | select_next_scope_after_pos(app, view, buffer, cursor_pos); 79 | } 80 | } 81 | 82 | CUSTOM_COMMAND_SIG(select_prev_scope_absolute) 83 | CUSTOM_DOC("Finds the first scope started by '{' before the cursor and puts the cursor and mark on the '{' and '}'.") 84 | { 85 | View_ID view = get_active_view(app, Access_ReadVisible); 86 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible); 87 | i64 pos = view_get_cursor_pos(app, view); 88 | Find_Nest_Flag flags = FindNest_Scope; 89 | Range_i64 range = {}; 90 | if (find_nest_side(app, buffer, pos - 1, 91 | flags, Scan_Backward, NestDelim_Open, &range) && 92 | find_nest_side(app, buffer, range.end, 93 | flags|FindNest_Balanced|FindNest_EndOfToken, Scan_Forward, 94 | NestDelim_Close, &range.end)){ 95 | select_scope(app, view, range); 96 | } 97 | } 98 | 99 | CUSTOM_COMMAND_SIG(select_prev_top_most_scope) 100 | CUSTOM_DOC("Finds the first scope that starts before the cursor, then finds the top most scope that contains that scope.") 101 | { 102 | select_prev_scope_absolute(app); 103 | select_surrounding_scope_maximal(app); 104 | } 105 | 106 | CUSTOM_COMMAND_SIG(place_in_scope) 107 | CUSTOM_DOC("Wraps the code contained in the range between cursor and mark with a new curly brace scope.") 108 | { 109 | place_begin_and_end_on_own_lines(app, "{", "}"); 110 | } 111 | 112 | CUSTOM_COMMAND_SIG(delete_current_scope) 113 | CUSTOM_DOC("Deletes the braces surrounding the currently selected scope. Leaves the contents within the scope.") 114 | { 115 | View_ID view = get_active_view(app, Access_ReadWriteVisible); 116 | Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); 117 | 118 | Range_i64 range = get_view_range(app, view); 119 | if (range_is_scope_selection(app, buffer, range)){ 120 | i32 top_len = 1; 121 | i32 bot_len = 1; 122 | if (buffer_get_char(app, buffer, range.min - 1) == '\n'){ 123 | top_len = 2; 124 | } 125 | if (buffer_get_char(app, buffer, range.max + 1) == '\n'){ 126 | bot_len = 2; 127 | } 128 | 129 | Batch_Edit batch_first = {}; 130 | Batch_Edit batch_last = {}; 131 | 132 | batch_first.edit.text = SCu8(); 133 | batch_first.edit.range = Ii64(range.min + 1 - top_len, range.min + 1); 134 | batch_first.next = &batch_last; 135 | batch_last.edit.text = SCu8(); 136 | batch_last.edit.range = Ii64((i32)(range.max - 1), (i32)(range.max - 1 + bot_len)); 137 | 138 | buffer_batch_edit(app, buffer, &batch_first); 139 | } 140 | } 141 | 142 | // BOTTOM 143 | -------------------------------------------------------------------------------- /custom/4coder_scope_commands.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_scope_commands.cpp - A set of commands and helpers relevant for scope level navigation and editing. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_SCOPE_COMMANDS_H) 8 | #define FCODER_SCOPE_COMMANDS_H 9 | 10 | #endif 11 | 12 | // BOTTOM 13 | -------------------------------------------------------------------------------- /custom/4coder_search.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_search.h - Types that are used in the search accross all buffers procedures. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_SEARCH_H) 8 | #define FCODER_SEARCH_H 9 | 10 | typedef u32 List_All_Locations_Flag; 11 | enum{ 12 | ListAllLocationsFlag_CaseSensitive = 1, 13 | ListAllLocationsFlag_MatchSubstring = 2, 14 | }; 15 | 16 | struct Word_Complete_Iterator{ 17 | Application_Links *app; 18 | Arena *arena; 19 | 20 | b32 initialized; 21 | Range_i64 range; 22 | 23 | Temp_Memory arena_restore; 24 | Buffer_ID first_buffer; 25 | Buffer_ID current_buffer; 26 | b32 scan_all_buffers; 27 | String_Const_u8 needle; 28 | 29 | List_String_Const_u8 list; 30 | Node_String_Const_u8 *node; 31 | Table_Data_u64 already_used_table; 32 | }; 33 | 34 | struct Word_Complete_Menu{ 35 | Render_Caller_Function *prev_render_caller; 36 | Word_Complete_Iterator *it; 37 | String_Const_u8 options[8]; 38 | i32 count; 39 | }; 40 | 41 | #endif 42 | 43 | // BOTOTM 44 | -------------------------------------------------------------------------------- /custom/4coder_search_list.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 01.10.2019 5 | * 6 | * Search list helper. 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | //////////////////////////////// 13 | // NOTE(allen): Search List Builders 14 | 15 | function void 16 | def_search_list_add_path(Arena *arena, List_String_Const_u8 *list, String_Const_u8 path){ 17 | String_Const_u8 path_copy = push_string_copy(arena, path); 18 | string_list_push(arena, list, path_copy); 19 | } 20 | 21 | function void 22 | def_search_list_add_system_path(Arena *arena, List_String_Const_u8 *list, System_Path_Code path){ 23 | String_Const_u8 path_string = system_get_path(arena, path); 24 | string_list_push(arena, list, path_string); 25 | } 26 | 27 | //////////////////////////////// 28 | // NOTE(allen): Search List Functions 29 | 30 | function String_Const_u8 31 | def_search_get_full_path(Arena *arena, List_String_Const_u8 *list, String_Const_u8 relative){ 32 | String_Const_u8 result = {}; 33 | Temp_Memory temp = begin_temp(arena); 34 | 35 | for (Node_String_Const_u8 *node = list->first; 36 | node != 0; 37 | node = node->next){ 38 | String_Const_u8 path = node->string; 39 | b32 has_slash = character_is_slash(string_get_character(path, path.size - 1)); 40 | String_Const_u8 full_name = (has_slash ? 41 | push_u8_stringf(arena, "%S%S", path, relative) : 42 | push_u8_stringf(arena, "%S/%S", path, relative)); 43 | 44 | File_Attributes attribs = system_quick_file_attributes(arena, full_name); 45 | if (attribs.last_write_time > 0){ 46 | result = full_name; 47 | break; 48 | } 49 | 50 | end_temp(temp); 51 | } 52 | 53 | return(result); 54 | } 55 | 56 | function FILE* 57 | def_search_fopen(Arena *arena, List_String_Const_u8 *list, char *file_name, char *opt){ 58 | Temp_Memory_Block block(arena); 59 | String_Const_u8 full_path = def_search_get_full_path(arena, list, SCu8(file_name)); 60 | FILE *file = 0; 61 | if (full_path.size > 0){ 62 | file = fopen((char*)full_path.str, opt); 63 | } 64 | return(file); 65 | } 66 | 67 | // BOTTOM 68 | -------------------------------------------------------------------------------- /custom/4coder_search_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 01.10.2019 5 | * 6 | * Search list helper. 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | #if !defined(FRED_SEARCH_LIST_H) 13 | #define FRED_SEARCH_LIST_H 14 | 15 | //////////////////////////////// 16 | // NOTE(allen): Search List Builders 17 | 18 | function void def_search_add_path(Arena *arena, List_String_Const_u8 *list, String_Const_u8 path); 19 | function void def_search_list_add_system_path(Arena *arena, List_String_Const_u8 *list, System_Path_Code path); 20 | 21 | //////////////////////////////// 22 | // NOTE(allen): Search List Functions 23 | 24 | function String_Const_u8 def_search_get_full_path(Arena *arena, List_String_Const_u8 *list, String_Const_u8 file_name); 25 | function FILE *def_search_fopen(Arena *arena, List_String_Const_u8 *list, char *file_name, char *opt); 26 | 27 | #endif 28 | 29 | // BOTTOM 30 | -------------------------------------------------------------------------------- /custom/4coder_string_match.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 17.06.2019 5 | * 6 | * Routines for operating on the String_Match and String_Match_List types. 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | internal void 13 | string_match_list_push(Arena *arena, String_Match_List *list, 14 | Buffer_ID buffer, i32 string_id, String_Match_Flag flags, Range_i64 range){ 15 | String_Match *match = push_array(arena, String_Match, 1); 16 | sll_queue_push(list->first, list->last, match); 17 | list->count += 1; 18 | match->buffer = buffer; 19 | match->string_id = string_id; 20 | match->flags = flags; 21 | match->range = range; 22 | } 23 | 24 | internal void 25 | string_match_list_push(Arena *arena, String_Match_List *list, 26 | Buffer_ID buffer, i32 string_id, String_Match_Flag flags, i64 start, i64 length){ 27 | string_match_list_push(arena, list, buffer, string_id, flags, 28 | Ii64(start, start + length)); 29 | } 30 | 31 | internal String_Match_List 32 | string_match_list_join(String_Match_List *a, String_Match_List *b){ 33 | String_Match_List list = *a; 34 | block_zero_struct(a); 35 | if (list.last != 0){ 36 | list.last->next = b->first; 37 | if (b->last != 0){ 38 | list.last = b->last; 39 | } 40 | } 41 | else{ 42 | list.first = b->first; 43 | list.last = b->last; 44 | } 45 | list.count += b->count; 46 | block_zero_struct(b); 47 | return(list); 48 | } 49 | 50 | internal void 51 | string_match_list_filter_flags(String_Match_List *list, String_Match_Flag must_have_flags, String_Match_Flag must_not_have_flags){ 52 | String_Match_List new_list = {}; 53 | if ((must_have_flags & must_not_have_flags) == 0){ 54 | for (String_Match *node = list->first, *next = 0; 55 | node != 0; 56 | node = next){ 57 | next = node->next; 58 | if ((node->flags & must_have_flags) == must_have_flags && (node->flags & must_not_have_flags) == 0){ 59 | sll_queue_push(new_list.first, new_list.last, node); 60 | new_list.count += 1; 61 | } 62 | } 63 | } 64 | *list = new_list; 65 | } 66 | 67 | internal void 68 | string_match_list_filter_remove_buffer(String_Match_List *list, Buffer_ID buffer){ 69 | String_Match_List new_list = {}; 70 | for (String_Match *node = list->first, *next = 0; 71 | node != 0; 72 | node = next){ 73 | next = node->next; 74 | if (node->buffer != buffer){ 75 | sll_queue_push(new_list.first, new_list.last, node); 76 | new_list.count += 1; 77 | } 78 | } 79 | *list = new_list; 80 | } 81 | 82 | internal void 83 | string_match_list_filter_remove_buffer_predicate(Application_Links *app, String_Match_List *list, Buffer_Predicate *predicate){ 84 | String_Match_List new_list = {}; 85 | for (String_Match *node = list->first, *next = 0; 86 | node != 0; 87 | node = next){ 88 | next = node->next; 89 | if (!predicate(app, node->buffer)){ 90 | sll_queue_push(new_list.first, new_list.last, node); 91 | new_list.count += 1; 92 | } 93 | } 94 | *list = new_list; 95 | } 96 | 97 | internal String_Match_List 98 | string_match_list_merge_nearest(String_Match_List *a, String_Match_List *b, Range_i64 range){ 99 | String_Match_List list = {}; 100 | String_Match *node_a = a->first; 101 | String_Match *node_b = b->first; 102 | for (String_Match *next_a = node_a, *next_b = node_b; 103 | node_a != 0 && node_b != 0; 104 | node_a = next_a, node_b = next_b){ 105 | i64 dist_a = range_distance(node_a->range, range); 106 | i64 dist_b = range_distance(node_b->range, range); 107 | if (dist_a <= dist_b){ 108 | next_a = next_a->next; 109 | sll_queue_push(list.first, list.last, node_a); 110 | list.count += 1; 111 | } 112 | else{ 113 | next_b = next_b->next; 114 | sll_queue_push(list.first, list.last, node_b); 115 | list.count += 1; 116 | } 117 | } 118 | Assert(node_a == 0 || node_b == 0); 119 | // TODO(allen): this is dumb O(n) work that could be O(1) 120 | String_Match *node = 0; 121 | if (node_a != 0){ 122 | node = node_a; 123 | } 124 | else if (node_b != 0){ 125 | node = node_b; 126 | } 127 | for (String_Match *next = 0; 128 | node != 0; 129 | node = next){ 130 | next = node->next; 131 | sll_queue_push(list.first, list.last, node); 132 | list.count += 1; 133 | } 134 | block_zero_struct(a); 135 | block_zero_struct(b); 136 | return(list); 137 | } 138 | 139 | internal String_Match_List 140 | string_match_list_merge_front_to_back(String_Match_List *a, String_Match_List *b){ 141 | return(string_match_list_merge_nearest(a, b, Ii64((i64)0))); 142 | } 143 | 144 | // BOTTOM 145 | -------------------------------------------------------------------------------- /custom/4coder_string_match.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mr. 4th Dimention - Allen Webster 3 | * 4 | * 30.07.2019 5 | * 6 | * Types for operating on the String_Match and String_Match_List types. 7 | * 8 | */ 9 | 10 | // TOP 11 | 12 | #if !defined(FCODER_STRING_MATCH_H) 13 | #define FCODER_STRING_MATCH_H 14 | 15 | typedef b32 Buffer_Predicate(Application_Links *app, Buffer_ID buffer); 16 | 17 | #endif 18 | 19 | // BOTTOM -------------------------------------------------------------------------------- /custom/4coder_system_allocator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder malloc base allocator 3 | */ 4 | 5 | // TOP 6 | 7 | internal void* 8 | base_reserve__system(void *user_data, u64 size, u64 *size_out, String_Const_u8 location){ 9 | u64 extra_size = 128; 10 | u64 increased_size = size + extra_size; 11 | size = round_up_u64(increased_size, KB(4)); 12 | *size_out = size - extra_size; 13 | void *ptr = system_memory_allocate(size, location); 14 | *(u64*)ptr = size; 15 | ptr = (u8*)ptr + extra_size; 16 | return(ptr); 17 | } 18 | 19 | internal void 20 | base_free__system(void *user_data, void *ptr){ 21 | u64 extra_size = 128; 22 | ptr = (u8*)ptr - extra_size; 23 | u64 size = *(u64*)ptr; 24 | system_memory_free(ptr, size); 25 | } 26 | 27 | internal Base_Allocator 28 | make_base_allocator_system(void){ 29 | return(make_base_allocator(base_reserve__system, 0, 0, base_free__system, 0, 0)); 30 | } 31 | 32 | global Base_Allocator base_allocator_system = {}; 33 | 34 | internal Base_Allocator* 35 | get_base_allocator_system(void){ 36 | if (base_allocator_system.reserve == 0){ 37 | base_allocator_system = make_base_allocator_system(); 38 | } 39 | return(&base_allocator_system); 40 | } 41 | 42 | internal Arena 43 | make_arena_system(u64 chunk_size, u64 align){ 44 | return(make_arena(get_base_allocator_system(), chunk_size, align)); 45 | } 46 | 47 | internal Arena 48 | make_arena_system(u64 chunk_size){ 49 | return(make_arena_system(chunk_size, 8)); 50 | } 51 | 52 | internal Arena 53 | make_arena_system(void){ 54 | return(make_arena_system(KB(16), 8)); 55 | } 56 | 57 | // BOTTOM 58 | -------------------------------------------------------------------------------- /custom/4coder_system_helpers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder_system_types.h - Implementation of universal (cross platform) helpers 3 | */ 4 | 5 | // TOP 6 | 7 | Mutex_Lock::Mutex_Lock(System_Mutex m){ 8 | system_mutex_acquire(m); 9 | this->mutex = m; 10 | } 11 | 12 | Mutex_Lock::~Mutex_Lock(){ 13 | system_mutex_release(this->mutex); 14 | } 15 | 16 | Mutex_Lock::operator System_Mutex(){ 17 | return(this->mutex); 18 | } 19 | 20 | // BOTTOM 21 | -------------------------------------------------------------------------------- /custom/4coder_system_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder_system_types.h - Types relating to the system api. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_SYSTEM_TYPES_H) 8 | #define FCODER_SYSTEM_TYPES_H 9 | 10 | typedef i32 Key_Mode; 11 | enum{ 12 | KeyMode_LanguageArranged, 13 | KeyMode_Physical, 14 | }; 15 | 16 | struct Plat_Handle{ 17 | u32 d[4]; 18 | }; 19 | typedef Plat_Handle System_Library; 20 | typedef Plat_Handle System_Thread; 21 | typedef Plat_Handle System_Mutex; 22 | typedef Plat_Handle System_Condition_Variable; 23 | typedef void Thread_Function(void *ptr); 24 | struct CLI_Handles{ 25 | Plat_Handle proc; 26 | Plat_Handle out_read; 27 | Plat_Handle out_write; 28 | Plat_Handle in_read; 29 | Plat_Handle in_write; 30 | u32 scratch_space[4]; 31 | i32 exit; 32 | }; 33 | 34 | typedef i32 System_Path_Code; 35 | enum{ 36 | SystemPath_CurrentDirectory, 37 | SystemPath_Binary, 38 | SystemPath_UserDirectory, 39 | }; 40 | 41 | struct Memory_Annotation_Node{ 42 | Memory_Annotation_Node *next; 43 | String_Const_u8 location; 44 | void *address; 45 | u64 size; 46 | }; 47 | 48 | struct Memory_Annotation{ 49 | Memory_Annotation_Node *first; 50 | Memory_Annotation_Node *last; 51 | i32 count; 52 | }; 53 | 54 | struct Mutex_Lock{ 55 | Mutex_Lock(System_Mutex mutex); 56 | ~Mutex_Lock(); 57 | operator System_Mutex(); 58 | System_Mutex mutex; 59 | }; 60 | 61 | #endif 62 | 63 | // BOTTOM 64 | -------------------------------------------------------------------------------- /custom/4coder_table.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder tables 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_TABLES_H) 8 | #define FCODER_TABLES_H 9 | 10 | struct Table_Lookup{ 11 | u64 hash; 12 | u32 index; 13 | b8 found_match; 14 | b8 found_empty_slot; 15 | b8 found_erased_slot; 16 | }; 17 | 18 | struct Table_u64_u64{ 19 | Base_Allocator *allocator; 20 | void *memory; 21 | u64 *keys; 22 | u64 *vals; 23 | u32 slot_count; 24 | u32 used_count; 25 | u32 dirty_count; 26 | }; 27 | 28 | struct Table_u32_u16{ 29 | Base_Allocator *allocator; 30 | void *memory; 31 | u32 *keys; 32 | u16 *vals; 33 | u32 slot_count; 34 | u32 used_count; 35 | u32 dirty_count; 36 | }; 37 | 38 | struct Table_Data_u64{ 39 | Base_Allocator *allocator; 40 | void *memory; 41 | u64 *hashes; 42 | String_Const_u8 *keys; 43 | u64 *vals; 44 | u32 slot_count; 45 | u32 used_count; 46 | u32 dirty_count; 47 | }; 48 | 49 | struct Table_u64_Data{ 50 | Base_Allocator *allocator; 51 | void *memory; 52 | u64 *keys; 53 | String_Const_u8 *vals; 54 | u32 slot_count; 55 | u32 used_count; 56 | u32 dirty_count; 57 | }; 58 | 59 | struct Table_Data_Data{ 60 | Base_Allocator *allocator; 61 | void *memory; 62 | u64 *hashes; 63 | String_Const_u8 *keys; 64 | String_Const_u8 *vals; 65 | u32 slot_count; 66 | u32 used_count; 67 | u32 dirty_count; 68 | }; 69 | 70 | #endif 71 | 72 | // BOTTOM 73 | -------------------------------------------------------------------------------- /custom/4coder_token.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 4coder token types 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_TOKEN_H) 8 | #define FCODER_TOKEN_H 9 | 10 | typedef i16 Token_Base_Kind; 11 | enum{ 12 | TokenBaseKind_EOF = 0, 13 | TokenBaseKind_Whitespace = 1, 14 | TokenBaseKind_LexError = 2, 15 | TokenBaseKind_Comment = 3, 16 | TokenBaseKind_Keyword = 4, 17 | TokenBaseKind_Preprocessor = 5, 18 | TokenBaseKind_Identifier = 6, 19 | TokenBaseKind_Operator = 7, 20 | TokenBaseKind_LiteralInteger = 8, 21 | TokenBaseKind_LiteralFloat = 9, 22 | TokenBaseKind_LiteralString = 10, 23 | TokenBaseKind_ScopeOpen = 11, 24 | TokenBaseKind_ScopeClose = 12, 25 | TokenBaseKind_ParentheticalOpen = 13, 26 | TokenBaseKind_ParentheticalClose = 14, 27 | TokenBaseKind_StatementClose = 15, 28 | 29 | TokenBaseKind_COUNT = 16, 30 | }; 31 | 32 | char *token_base_kind_names[] ={ 33 | "EOF", 34 | "Whitespace", 35 | "LexError", 36 | "Comment", 37 | "Keyword", 38 | "Preprocessor", 39 | "Identifier", 40 | "Operator", 41 | "LiteralInteger", 42 | "LiteralFloat", 43 | "LiteralString", 44 | "ScopeOpen", 45 | "ScopeClose", 46 | "ParentheticalOpen", 47 | "ParentheticalClose", 48 | "StatementClose", 49 | }; 50 | 51 | typedef u16 Token_Base_Flag; 52 | enum{ 53 | TokenBaseFlag_PreprocessorBody = 1, 54 | }; 55 | 56 | struct Token{ 57 | i64 pos; 58 | i64 size; 59 | Token_Base_Kind kind; 60 | Token_Base_Flag flags; 61 | i16 sub_kind; 62 | u16 sub_flags; 63 | }; 64 | 65 | struct Token_Pair{ 66 | Token a; 67 | Token b; 68 | }; 69 | 70 | struct Token_Array{ 71 | Token *tokens; 72 | i64 count; 73 | i64 max; 74 | }; 75 | 76 | struct Token_Block{ 77 | Token_Block *next; 78 | Token_Block *prev; 79 | Token *tokens; 80 | i64 count; 81 | i64 max; 82 | }; 83 | 84 | struct Token_List{ 85 | Token_Block *first; 86 | Token_Block *last; 87 | i64 node_count; 88 | i64 total_count; 89 | }; 90 | 91 | struct Token_Relex{ 92 | b32 successful_resync; 93 | i64 first_resync_index; 94 | }; 95 | 96 | struct Token_Iterator_Array{ 97 | u64 user_id; 98 | Token *ptr; 99 | Token *tokens; 100 | i64 count; 101 | }; 102 | 103 | struct Token_Iterator_List{ 104 | u64 user_id; 105 | i64 index; 106 | Token *ptr; 107 | Token_Block *block; 108 | Token_Block *first; 109 | Token_Block *last; 110 | i64 node_count; 111 | i64 total_count; 112 | }; 113 | 114 | typedef i32 Token_Iterator_Kind; 115 | enum{ 116 | TokenIterator_Array, 117 | TokenIterator_List, 118 | }; 119 | 120 | struct Token_Iterator{ 121 | Token_Iterator_Kind kind; 122 | union{ 123 | Token_Iterator_Array array; 124 | Token_Iterator_List list; 125 | }; 126 | }; 127 | 128 | #endif 129 | 130 | // BOTTOM 131 | -------------------------------------------------------------------------------- /custom/4coder_tutorial.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_tutorial.h - Guided graphical tutorial system. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_TUTORIAL_H) 8 | #define FCODER_TUTORIAL_H 9 | 10 | typedef i32 Tutorial_Action; 11 | enum{ 12 | TutorialAction_None, 13 | TutorialAction_Minimize, 14 | TutorialAction_Maximize, 15 | TutorialAction_Prev, 16 | TutorialAction_Next, 17 | TutorialAction_Index, 18 | TutorialAction_Exit, 19 | TutorialAction_Restart, 20 | }; 21 | 22 | struct Tutorial_Slide{ 23 | Fancy_Block long_details; 24 | Fancy_Line short_details; 25 | }; 26 | 27 | typedef Tutorial_Slide Tutorial_Slide_Function(Application_Links *app, Arena *arena); 28 | 29 | struct Tutorial_Desc{ 30 | Tutorial_Slide_Function *func; 31 | String_Const_u8 title; 32 | }; 33 | 34 | struct Tutorial_State{ 35 | b32 in_tutorial; 36 | View_ID view; 37 | Face_ID face; 38 | b32 is_active; 39 | Tutorial_Action hover_action; 40 | Tutorial_Action depressed_action; 41 | 42 | Tutorial_Desc *slides; 43 | i32 slide_count; 44 | i32 slide_index; 45 | i32 hover_index; 46 | }; 47 | 48 | #endif 49 | 50 | // BOTTOM 51 | -------------------------------------------------------------------------------- /custom/4coder_variables.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_variables.h - Variables system 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_VARIABLES_H) 8 | #define FCODER_VARIABLES_H 9 | 10 | //////////////////////////////// 11 | // NOTE(allen): Types 12 | 13 | typedef u64 String_ID; 14 | 15 | struct Variable{ 16 | Variable *parent; 17 | Variable *next; 18 | String_ID key; 19 | String_ID string; 20 | Variable *first; 21 | Variable *last; 22 | }; 23 | 24 | struct Variable_Handle{ 25 | Variable *ptr; 26 | }; 27 | 28 | //////////////////////////////// 29 | // NOTE(allen): Functions 30 | 31 | // TODO(allen): fix names fuck you for picking these allen: 32 | // read_string 33 | // read_keyu 34 | // save_string 35 | 36 | function String_ID vars_save_string(String_Const_u8 string); 37 | #define vars_save_string_lit(S) vars_save_string(string_u8_litexpr(S)) 38 | function String8 vars_read_string(Arena *arena, String_ID id); 39 | 40 | function Variable_Handle vars_get_root(void); 41 | function Variable_Handle vars_get_nil(void); 42 | function b32 vars_is_nil(Variable_Handle var); 43 | function b32 vars_is_nil(Variable *var); 44 | function b32 vars_match(Variable_Handle a, Variable_Handle b); 45 | 46 | function Variable_Handle vars_first_child(Variable_Handle var); 47 | function Variable_Handle vars_next_sibling(Variable_Handle var); 48 | function Variable_Handle vars_parent(Variable_Handle var); 49 | 50 | #define Vars_Children(it, par) Variable_Handle it = vars_first_child(par); !vars_is_nil(it); it = vars_next_sibling(it) 51 | 52 | function Variable_Handle vars_read_key(Variable_Handle var, String_ID key); 53 | function String_ID vars_key_id_from_var(Variable_Handle var); 54 | function String8 vars_key_from_var(Arena *arena, Variable_Handle var); 55 | 56 | function String_ID vars_string_id_from_var(Variable_Handle var); 57 | function String8 vars_string_from_var(Arena *arena, Variable_Handle var); 58 | function b32 vars_b32_from_var(Variable_Handle var); 59 | function f32 vars_f32_from_var(Application_Links *app, Variable_Handle var); 60 | function u64 vars_u64_from_var(Application_Links *app, Variable_Handle var); 61 | 62 | function void vars_set_string(Variable_Handle var, String_ID string); 63 | function void vars_erase(Variable_Handle var, String_ID key); 64 | function Variable_Handle vars_new_variable(Variable_Handle var, String_ID key); 65 | function Variable_Handle vars_new_variable(Variable_Handle var, String_ID key, String_ID string); 66 | function void vars_clear_keys(Variable_Handle var); 67 | 68 | function void vars_print_indented(Application_Links *app, Variable_Handle var, i32 indent); 69 | function void vars_print(Application_Links *app, Variable_Handle var); 70 | 71 | #endif //4CODER_VARIABLES_H 72 | 73 | // BOTTOM 74 | -------------------------------------------------------------------------------- /custom/4coder_version.h: -------------------------------------------------------------------------------- 1 | #define MAJOR 4 2 | #define MINOR 1 3 | #define PATCH 8 4 | 5 | // string 6 | #define VN__(a,b,c) #a "." #b "." #c 7 | #define VN_(a,b,c) VN__(a,b,c) 8 | #define VERSION_NUMBER VN_(MAJOR,MINOR,PATCH) 9 | #define VERSION_STRING "beta " VERSION_NUMBER 10 | 11 | #define ST__(s) #s 12 | #define ST_(s) ST__(s) 13 | #define MAJOR_STR ST_(MAJOR) 14 | #define MINOR_STR ST_(MINOR) 15 | #define PATCH_STR ST_(PATCH) 16 | 17 | #if defined(FRED_SUPER) 18 | #define VERSION_TYPE " super!" 19 | #else 20 | #define VERSION_TYPE 21 | #endif 22 | 23 | // string 24 | #define VN__(a,b,c) #a "." #b "." #c 25 | #define VN_(a,b,c) VN__(a,b,c) 26 | #define VERSION_NUMBER VN_(MAJOR,MINOR,PATCH) 27 | #define VERSION_STRING "beta " VERSION_NUMBER 28 | 29 | #define VERSION VERSION_STRING VERSION_TYPE 30 | 31 | #define WINDOW_NAME "4coder: " VERSION 32 | 33 | // long string 34 | #define L_VN__(a,b,c) L#a L"." L#b L"." L#c 35 | #define L_VN_(a,b,c) L_VN__(a,b,c) 36 | #define L_VERSION_NUMBER L_VN_(MAJOR,MINOR,PATCH) 37 | #define L_VERSION_STRING L"beta " L_VERSION_NUMBER 38 | 39 | #if defined(FRED_SUPER) 40 | #define L_VERSION_TYPE L" super!" 41 | #else 42 | #define L_VERSION_TYPE 43 | #endif 44 | 45 | #define L_VERSION L_VERSION_STRING L_VERSION_TYPE 46 | 47 | #define L_WINDOW_NAME L"4coder: " L_VERSION -------------------------------------------------------------------------------- /custom/bin/build_metadata.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set code_home=%~dp0 4 | if %code_home:~-1%==\ (set code_home=%code_home:~0,-1%) 5 | 6 | set src=%1 7 | if "%src%" == "" set src=4coder_default_bindings.cpp 8 | 9 | set opts=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4390 /WX 10 | set opts=%opts% /GR- /EHa- /nologo /FC 11 | 12 | pushd ..\build 13 | set preproc_file=4coder_command_metadata.i 14 | set meta_macros=/DMETA_PASS 15 | cl /I"%code_home%" %opts% %debug% %code_home%\%src% /P /Fi%preproc_file% %meta_macros% 16 | cl %opts% ..\code\4coder_metadata_generator.cpp /Zi /Femetadata_generator 17 | metadata_generator -R "%code_home%" "%cd%\\%preproc_file%" 18 | 19 | popd 20 | -------------------------------------------------------------------------------- /custom/bin/build_metadata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Store the real CWD 4 | REAL_PWD="$PWD" 5 | 6 | # Find the code home folder 7 | TARGET_FILE="$0" 8 | cd `dirname $TARGET_FILE` 9 | TARGET_FILE=`basename $TARGET_FILE` 10 | while [ -L "$TARGET_FILE" ] 11 | do 12 | TARGET_FILE=`readlink $TARGET_FILE` 13 | cd `dirname $TARGET_FILE` 14 | TARGET_FILE=`basename $TARGET_FILE` 15 | done 16 | PHYS_DIR=`pwd -P` 17 | SCRIPT_FILE=$PHYS_DIR/$TARGET_FILE 18 | code_home=$(dirname "$SCRIPT_FILE") 19 | 20 | # Find the most reasonable candidate build file 21 | SOURCE="$1" 22 | if [ -z "$SOURCE" ]; then 23 | SOURCE="$code_home/4coder_default_bindings.cpp" 24 | fi 25 | 26 | TARGET_FILE="$SOURCE" 27 | cd `dirname $TARGET_FILE` 28 | TARGET_FILE=`basename $TARGET_FILE` 29 | while [ -L "$TARGET_FILE" ] 30 | do 31 | TARGET_FILE=`readlink $TARGET_FILE` 32 | cd `dirname $TARGET_FILE` 33 | TARGET_FILE=`basename $TARGET_FILE` 34 | done 35 | PHYS_DIR=`pwd -P` 36 | SOURCE=$PHYS_DIR/$TARGET_FILE 37 | 38 | opts="-Wno-write-strings -Wno-null-dereference -Wno-comment -Wno-switch -Wno-writable-strings -g" 39 | 40 | cd ../build > /dev/null 41 | preproc_file=4coder_command_metadata.i 42 | meta_macros="-DMETA_PASS" 43 | g++ -I"$code_home" $meta_macros $opts -std=gnu++0x "$SOURCE" -E -o $preproc_file 44 | g++ -I"$code_home" $opts -std=gnu++0x ../code/4coder_metadata_generator.cpp -o metadata_generator 45 | ./metadata_generator -R "$code_home" "$PWD/$preproc_file" 46 | cd $code_home > /dev/null 47 | -------------------------------------------------------------------------------- /custom/bin/build_one_time.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM usage: