diff --git a/.gitignore b/.gitignore index 47f4eb31..0872785b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ vc120.pdb 4ed_data.ctm .DS_Store +*.dSYM \ No newline at end of file diff --git a/4ed.cpp b/4ed.cpp index 8059d581..78818d9c 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1,842 +1,839 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.12.2014 - * - * Application layer for project codename "4ed" - * - */ - -// TOP - -internal void -init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, i32 argc, char **argv){ - char *arg = 0; - Command_Line_Mode mode = CLMode_App; - Command_Line_Action action = CLAct_Nothing; - b32 strict = false; - - settings->init_files_max = ArrayCount(settings->init_files); - for (i32 i = 1; i <= argc; ++i){ - if (i == argc){ - arg = ""; - } - else{ - arg = argv[i]; - } - - if (arg[0] == '-' && arg[1] == '-'){ - char *long_arg_name = arg+2; - if (string_match(SCu8(long_arg_name), string_u8_litexpr("custom"))){ - mode = CLMode_Custom; - continue; - } - } - - switch (mode){ - case CLMode_App: - { - switch (action){ - case CLAct_Nothing: - { - if (arg[0] == '-'){ - action = CLAct_Ignore; - switch (arg[1]){ - case 'd': action = CLAct_CustomDLL; strict = false; break; - case 'D': action = CLAct_CustomDLL; strict = true; break; - - case 'i': action = CLAct_InitialFilePosition; break; - - case 'w': action = CLAct_WindowSize; break; - case 'W': action = CLAct_WindowMaximize; break; - case 'p': action = CLAct_WindowPosition; break; - case 'F': action = CLAct_WindowFullscreen; break; - - case 'f': action = CLAct_FontSize; break; - case 'h': action = CLAct_FontUseHinting; --i; break; - } - } - else if (arg[0] != 0){ - if (settings->init_files_count < settings->init_files_max){ - i32 index = settings->init_files_count++; - settings->init_files[index] = arg; - } - } - }break; - - case CLAct_CustomDLL: - { - plat_settings->custom_dll_is_strict = (b8)strict; - if (i < argc){ - plat_settings->custom_dll = argv[i]; - } - action = CLAct_Nothing; - }break; - - case CLAct_InitialFilePosition: - { - if (i < argc){ - settings->initial_line = (i32)string_to_integer(SCu8(argv[i]), 10); - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowSize: - { - if (i + 1 < argc){ - plat_settings->set_window_size = true; - - i32 w = (i32)string_to_integer(SCu8(argv[i]), 10); - i32 h = (i32)string_to_integer(SCu8(argv[i + 1]), 10); - if (w > 0){ - plat_settings->window_w = w; - } - if (h > 0){ - plat_settings->window_h = h; - } - - ++i; - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowMaximize: - { - --i; - plat_settings->maximize_window = true; - action = CLAct_Nothing; - }break; - - case CLAct_WindowPosition: - { - if (i + 1 < argc){ - plat_settings->set_window_pos = true; - - i32 x = (i32)string_to_integer(SCu8(argv[i]), 10); - i32 y = (i32)string_to_integer(SCu8(argv[i + 1]), 10); - if (x > 0){ - plat_settings->window_x = x; - } - if (y > 0){ - plat_settings->window_y = y; - } - - ++i; - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowFullscreen: - { - --i; - plat_settings->fullscreen_window = true; - action = CLAct_Nothing; - }break; - - case CLAct_FontSize: - { - if (i < argc){ - settings->font_size = (i32)string_to_integer(SCu8(argv[i]), 10); - } - action = CLAct_Nothing; - }break; - - case CLAct_FontUseHinting: - { - plat_settings->use_hinting = true; - settings->use_hinting = plat_settings->use_hinting; - action = CLAct_Nothing; - }break; - } - }break; - - case CLMode_Custom: - { - settings->custom_flags = argv + i; - settings->custom_flags_count = argc - i; - i = argc; - mode = CLMode_App; - }break; - } - } -} - -//////////////////////////////// - -internal Models* -models_init(void){ - Arena arena = make_arena_system(); - Models *models = push_array_zero(&arena, Models, 1); - models->arena_ = arena; - models->arena = &models->arena_; - heap_init(&models->heap, get_base_allocator_system()); - return(models); -} - -internal void -app_load_vtables(API_VTable_system *vtable_system, API_VTable_font *vtable_font, API_VTable_graphics *vtable_graphics){ - system_api_read_vtable(vtable_system); - font_api_read_vtable(vtable_font); - graphics_api_read_vtable(vtable_graphics); -} - -internal Log_Function* -app_get_logger(void){ - log_init(); - return(log_string); -} - -App_Read_Command_Line_Sig(app_read_command_line){ - Models *models = models_init(); - App_Settings *settings = &models->settings; - block_zero_struct(settings); - if (argc > 1){ - init_command_line_settings(&models->settings, plat_settings, argc, argv); - } - *files = models->settings.init_files; - *file_count = &models->settings.init_files_count; - return(models); -} - -App_Init_Sig(app_init){ - Models *models = (Models*)base_ptr; - models->keep_playing = true; - - models->config_api = api; - models->virtual_event_arena = reserve_arena(tctx); - - profile_init(&models->profile_list); - - managed_ids_init(tctx->allocator, &models->managed_id_set); - - API_VTable_custom custom_vtable = {}; - custom_api_fill_vtable(&custom_vtable); - API_VTable_system system_vtable = {}; - system_api_fill_vtable(&system_vtable); - Custom_Layer_Init_Type *custom_init = api.init_apis(&custom_vtable, &system_vtable); - Assert(custom_init != 0); - - // NOTE(allen): coroutines - coroutine_system_init(&models->coroutines); - - // NOTE(allen): font set - font_set_init(&models->font_set); - - // NOTE(allen): live set - Arena *arena = models->arena; - { - models->view_set.count = 0; - models->view_set.max = MAX_VIEWS; - models->view_set.views = push_array(arena, View, models->view_set.max); - - //dll_init_sentinel - models->view_set.free_sentinel.next = &models->view_set.free_sentinel; - models->view_set.free_sentinel.prev = &models->view_set.free_sentinel; - - i32 max = models->view_set.max; - View *view = models->view_set.views; - for (i32 i = 0; i < max; ++i, ++view){ - //dll_insert(&models->view_set.free_sentinel, view); - view->next = models->view_set.free_sentinel.next; - view->prev = &models->view_set.free_sentinel; - models->view_set.free_sentinel.next = view; - view->next->prev = view; - } - } - - lifetime_allocator_init(tctx->allocator, &models->lifetime_allocator); - dynamic_workspace_init(&models->lifetime_allocator, DynamicWorkspace_Global, 0, &models->dynamic_workspace); - - // NOTE(allen): file setup - working_set_init(models, &models->working_set); - Mutex_Lock file_order_lock(models->working_set.mutex); - - // NOTE(allen): - global_history_init(&models->global_history); - text_layout_init(tctx, &models->text_layouts); - - // NOTE(allen): clipboard setup - models->working_set.clipboard_max_size = ArrayCount(models->working_set.clipboards); - models->working_set.clipboard_size = 0; - models->working_set.clipboard_current = 0; - models->working_set.clipboard_rolling = 0; - - // TODO(allen): do(better clipboard allocation) - if (clipboard.str != 0){ - String_Const_u8 *dest = working_set_next_clipboard_string(&models->heap, &models->working_set, clipboard.size); - block_copy(dest->str, clipboard.str, clipboard.size); - } - - // NOTE(allen): style setup - { - Scratch_Block scratch(tctx); - Face_Description description = {}; - description.font.file_name = get_file_path_in_fonts_folder(scratch, string_u8_litexpr("liberation-mono.ttf")); - description.parameters.pt_size = 12; - Face *new_face = font_set_new_face(&models->font_set, &description); - models->global_face_id = new_face->id; - } - - // NOTE(allen): title space - models->has_new_title = true; - models->title_capacity = KB(4); - models->title_space = push_array(arena, char, models->title_capacity); - block_copy(models->title_space, WINDOW_NAME, sizeof(WINDOW_NAME)); - - // NOTE(allen): miscellaneous init - hot_directory_init(arena, &models->hot_directory, current_directory); - child_process_container_init(tctx->allocator, &models->child_processes); - models->period_wakeup_timer = system_wake_up_timer_create(); - - // NOTE(allen): custom layer init - Application_Links app = {}; - app.tctx = tctx; - app.cmd_context = models; - custom_init(&app); - - // NOTE(allen): init baked in buffers - File_Init init_files[] = { - { string_u8_litinit("*messages*"), &models->message_buffer , true , }, - { string_u8_litinit("*scratch*") , &models->scratch_buffer , false, }, - { string_u8_litinit("*log*") , &models->log_buffer , true , }, - { string_u8_litinit("*keyboard*"), &models->keyboard_buffer, true , }, - }; - - Heap *heap = &models->heap; - for (i32 i = 0; i < ArrayCount(init_files); ++i){ - Editing_File *file = working_set_allocate_file(&models->working_set, &models->lifetime_allocator); - buffer_bind_name(tctx, models, arena, &models->working_set, file, init_files[i].name); - - if (init_files[i].ptr != 0){ - *init_files[i].ptr = file; - } - - File_Attributes attributes = {}; - file_create_from_string(tctx, models, file, SCu8(), attributes); - if (init_files[i].read_only){ - file->settings.read_only = true; - history_free(tctx, &file->state.history); - } - - file->settings.never_kill = true; - file_set_unimportant(file, true); - } - - // NOTE(allen): setup first panel - { - Panel *panel = layout_initialize(arena, &models->layout); - View *new_view = live_set_alloc_view(&models->lifetime_allocator, &models->view_set, panel); - view_init(tctx, models, new_view, models->scratch_buffer, models->view_event_handler); - } -} - -App_Step_Sig(app_step){ - Models *models = (Models*)base_ptr; - - Mutex_Lock file_order_lock(models->working_set.mutex); - Scratch_Block scratch(tctx, Scratch_Share); - - models->next_animate_delay = max_u32; - models->animate_next_frame = false; - - // NOTE(allen): per-frame update of models state - begin_frame(target, &models->font_set); - models->target = target; - models->input = input; - - // NOTE(allen): OS clipboard event handling - String_Const_u8 clipboard = input->clipboard; - if (clipboard.str != 0){ - String_Const_u8 *dest = working_set_next_clipboard_string(&models->heap, &models->working_set, clipboard.size); - dest->size = eol_convert_in((char*)dest->str, (char*)clipboard.str, (i32)clipboard.size); - if (input->clipboard_changed){ - co_send_core_event(tctx, models, CoreCode_NewClipboardContents, *dest); - } - } - - // NOTE(allen): reorganizing panels on screen - Vec2_i32 prev_dim = layout_get_root_size(&models->layout); - Vec2_i32 current_dim = V2i32(target->width, target->height); - layout_set_root_size(&models->layout, current_dim); - - // NOTE(allen): update child processes - f32 dt = input->dt; - if (dt > 0){ - Temp_Memory_Block temp(scratch); - - Child_Process_Container *child_processes = &models->child_processes; - Child_Process **processes_to_free = push_array(scratch, Child_Process*, child_processes->active_child_process_count); - i32 processes_to_free_count = 0; - - u32 max = KB(128); - char *dest = push_array(scratch, char, max); - - for (Node *node = child_processes->child_process_active_list.next; - node != &child_processes->child_process_active_list; - node = node->next){ - Child_Process *child_process = CastFromMember(Child_Process, node, node); - - Editing_File *file = child_process->out_file; - CLI_Handles *cli = &child_process->cli; - - // TODO(allen): do(call a 'child process updated hook' let that hook populate the buffer if it so chooses) - - b32 edited_file = false; - u32 amount = 0; - system_cli_begin_update(cli); - if (system_cli_update_step(cli, dest, max, &amount)){ - if (file != 0 && amount > 0){ - amount = eol_in_place_convert_in(dest, amount); - output_file_append(tctx, models, file, SCu8(dest, amount)); - edited_file = true; - } - } - - if (system_cli_end_update(cli)){ - if (file != 0){ - String_Const_u8 str = push_u8_stringf(scratch, "exited with code %d", cli->exit); - output_file_append(tctx, models, file, str); - edited_file = true; - } - processes_to_free[processes_to_free_count++] = child_process; - child_process_set_return_code(models, child_processes, child_process->id, cli->exit); - } - - if (child_process->cursor_at_end && file != 0){ - file_cursor_to_end(tctx, models, file); - } - } - - for (i32 i = 0; i < processes_to_free_count; ++i){ - child_process_free(child_processes, processes_to_free[i]->id); - } - } - - // NOTE(allen): simulated events - Input_List input_list = input->events; - Input_Modifier_Set modifiers = system_get_keyboard_modifiers(scratch); - if (input->mouse.press_l){ - Input_Event event = {}; - event.kind = InputEventKind_MouseButton; - event.mouse.code = MouseCode_Left; - event.mouse.p = input->mouse.p; - event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); - push_input_event(scratch, &input_list, &event); - } - else if (input->mouse.release_l){ - Input_Event event = {}; - event.kind = InputEventKind_MouseButtonRelease; - event.mouse.code = MouseCode_Left; - event.mouse.p = input->mouse.p; - event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); - push_input_event(scratch, &input_list, &event); - } - if (input->mouse.press_r){ - Input_Event event = {}; - event.kind = InputEventKind_MouseButton; - event.mouse.code = MouseCode_Right; - event.mouse.p = input->mouse.p; - event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); - push_input_event(scratch, &input_list, &event); - } - else if (input->mouse.release_r){ - Input_Event event = {}; - event.kind = InputEventKind_MouseButtonRelease; - event.mouse.code = MouseCode_Right; - event.mouse.p = input->mouse.p; - event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); - push_input_event(scratch, &input_list, &event); - } - if (input->mouse.wheel != 0){ - Input_Event event = {}; - event.kind = InputEventKind_MouseWheel; - event.mouse_wheel.value = (f32)(input->mouse.wheel); - event.mouse_wheel.p = input->mouse.p; - event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); - push_input_event(scratch, &input_list, &event); - } - if (input->mouse.p != models->prev_p){ - b32 was_in_window = rect_contains_point(Ri32(0, 0, prev_dim.x, prev_dim.y), models->prev_p); - b32 is_in_window = rect_contains_point(Ri32(0, 0, current_dim.x, current_dim.y), input->mouse.p); - if (is_in_window || was_in_window){ - Input_Event event = {}; - event.kind = InputEventKind_MouseMove; - event.mouse_move.p = input->mouse.p; - event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); - push_input_event(scratch, &input_list, &event); - } - } - if (models->animated_last_frame){ - Input_Event event = {}; - event.kind = InputEventKind_Core; - event.core.code = CoreCode_Animate; - push_input_event(scratch, &input_list, &event); - } - - // NOTE(allen): expose layout - Layout *layout = &models->layout; - - // NOTE(allen): mouse hover status - Panel *mouse_panel = 0; - Panel *divider_panel = 0; - b32 mouse_in_margin = false; - Vec2_i32 mouse = input->mouse.p; - { - for (Panel *panel = layout_get_first_open_panel(layout); - panel != 0; - panel = layout_get_next_open_panel(layout, panel)){ - if (rect_contains_point(panel->rect_full, mouse)){ - mouse_panel = panel; - if (!rect_contains_point(panel->rect_inner, mouse)){ - mouse_in_margin = true; - for (divider_panel = mouse_panel->parent; - divider_panel != 0; - divider_panel = divider_panel->parent){ - if (rect_contains_point(divider_panel->rect_inner, mouse)){ - break; - } - } - } - } - if (mouse_panel != 0){ - break; - } - } - } - - // NOTE(allen): First frame initialization - if (input->first_step){ - Temp_Memory_Block temp(scratch); - - String_Const_u8_Array file_names = {}; - file_names.count = models->settings.init_files_count; - file_names.vals = push_array(scratch, String_Const_u8, file_names.count); - for (i32 i = 0; i < file_names.count; i += 1){ - file_names.vals[i] = SCu8(models->settings.init_files[i]); - } - - String_Const_u8_Array flags = {}; - flags.count = models->settings.custom_flags_count; - flags.vals = push_array(scratch, String_Const_u8, flags.count); - for (i32 i = 0; i < flags.count; i += 1){ - flags.vals[i] = SCu8(models->settings.custom_flags[i]); - } - - Input_Event event = {}; - event.kind = InputEventKind_Core; - event.core.code = CoreCode_Startup; - event.core.flag_strings = flags; - event.core.file_names = file_names; - co_send_event(tctx, models, &event); - } - - // NOTE(allen): consume event stream - Input_Event_Node *input_node = input_list.first; - Input_Event_Node *input_node_next = 0; - for (;; input_node = input_node_next){ - // NOTE(allen): first handle any events coming from the view command - // function queue - Model_View_Command_Function cmd_func = models_pop_view_command_function(models); - if (cmd_func.custom_func != 0){ - View *view = imp_get_view(models, cmd_func.view_id); - if (view != 0){ - input_node_next = input_node; - Input_Event cmd_func_event = {}; - cmd_func_event.kind = InputEventKind_CustomFunction; - cmd_func_event.custom_func = cmd_func.custom_func; - co_send_event(tctx, models, view, &cmd_func_event); - continue; - } - } - - Temp_Memory_Block temp(scratch); - Input_Event *simulated_input = 0; - Input_Event virtual_event = models_pop_virtual_event(scratch, models); - if (virtual_event.kind != InputEventKind_None){ - virtual_event.virtual_event = true; - simulated_input = &virtual_event; - } - else{ - if (input_node == 0){ - break; - } - input_node_next = input_node->next; - simulated_input = &input_node->event; - - if (simulated_input->kind == InputEventKind_TextInsert && simulated_input->text.blocked){ - continue; - } - - // NOTE(allen): record to keyboard history - if (simulated_input->kind == InputEventKind_KeyStroke || - simulated_input->kind == InputEventKind_KeyRelease || - simulated_input->kind == InputEventKind_TextInsert){ - Temp_Memory_Block temp_key_line(scratch); - String_Const_u8 key_line = stringize_keyboard_event(scratch, simulated_input); - output_file_append(tctx, models, models->keyboard_buffer, key_line); - } - } - - b32 event_was_handled = false; - Input_Event *event = simulated_input; - - Panel *active_panel = layout_get_active_panel(layout); - View *view = active_panel->view; - Assert(view != 0); - - switch (models->state){ - case APP_STATE_EDIT: - { - typedef i32 Event_Consume_Rule; - enum{ - EventConsume_None, - EventConsume_BeginResize, - EventConsume_ClickChangeView, - EventConsume_CustomCommand, - }; - - Event_Consume_Rule consume_rule = EventConsume_CustomCommand; - if (match_mouse_code(event, MouseCode_Left) && (divider_panel != 0)){ - consume_rule = EventConsume_BeginResize; - } - else if (match_mouse_code(event, MouseCode_Left) && - mouse_panel != 0 && mouse_panel != active_panel){ - consume_rule = EventConsume_ClickChangeView; - } - - switch (consume_rule){ - case EventConsume_BeginResize: - { - models->state = APP_STATE_RESIZING; - models->resizing_intermediate_panel = divider_panel; - event_was_handled = true; - }break; - - case EventConsume_ClickChangeView: - { - // NOTE(allen): run deactivate command - co_send_core_event(tctx, models, view, CoreCode_ClickDeactivateView); - - layout->active_panel = mouse_panel; - models->animate_next_frame = true; - active_panel = mouse_panel; - view = active_panel->view; - - // NOTE(allen): run activate command - co_send_core_event(tctx, models, view, CoreCode_ClickActivateView); - - event_was_handled = true; - }break; - - case EventConsume_CustomCommand: - { - event_was_handled = co_send_event(tctx, models, view, event); - }break; - } - }break; - - case APP_STATE_RESIZING: - { - Event_Property event_flags = get_event_properties(event); - if (HasFlag(event_flags, EventProperty_AnyKey) || - match_mouse_code_release(event, MouseCode_Left)){ - models->state = APP_STATE_EDIT; - } - else if (event->kind == InputEventKind_MouseMove){ - if (input->mouse.l){ - Panel *split = models->resizing_intermediate_panel; - Range_i32 limits = layout_get_limiting_range_on_split(layout, split); - i32 mouse_position = (split->vertical_split)?(mouse.x):(mouse.y); - mouse_position = clamp(limits.min, mouse_position, limits.max); - layout_set_split_absolute_position(layout, split, mouse_position); - } - else{ - models->state = APP_STATE_EDIT; - } - } - }break; - } - - if (event_was_handled && event->kind == InputEventKind_KeyStroke){ - for (Input_Event *dependent_text = event->key.first_dependent_text; - dependent_text != 0; - dependent_text = dependent_text->text.next_text){ - Assert(dependent_text->kind == InputEventKind_TextInsert); - dependent_text->text.blocked = true; - } - } - } - - linalloc_clear(models->virtual_event_arena); - models->free_virtual_event = 0; - models->first_virtual_event = 0; - models->last_virtual_event = 0; - - // NOTE(allen): send panel size update - if (models->layout.panel_state_dirty){ - models->layout.panel_state_dirty = false; - if (models->buffer_viewer_update != 0){ - Application_Links app = {}; - app.tctx = tctx; - app.cmd_context = models; - models->buffer_viewer_update(&app); - } - } - - // NOTE(allen): dt - f32 literal_dt = 0.f; - u64 now_usecond_stamp = system_now_time(); - if (!input->first_step){ - u64 elapsed_useconds = now_usecond_stamp - models->last_render_usecond_stamp; - literal_dt = (f32)((f64)(elapsed_useconds)/1000000.f); - } - models->last_render_usecond_stamp = now_usecond_stamp; - f32 animation_dt = 0.f; - if (models->animated_last_frame){ - animation_dt = literal_dt; - } - - // NOTE(allen): on the first frame there should be no scrolling - if (input->first_step){ - for (Panel *panel = layout_get_first_open_panel(layout); - panel != 0; - panel = layout_get_next_open_panel(layout, panel)){ - View *view = panel->view; - File_Edit_Positions edit_pos = view_get_edit_pos(view); - edit_pos.scroll.position = view_normalize_buffer_point(tctx, models, view, edit_pos.scroll.target); - block_zero_struct(&edit_pos.scroll.target); - view_set_edit_pos(view, edit_pos); - } - } - - // NOTE(allen): hook for files reloaded - { - Working_Set *working_set = &models->working_set; - Assert(working_set->has_external_mod_sentinel.next != 0); - if (working_set->has_external_mod_sentinel.next != &working_set->has_external_mod_sentinel){ - for (Node *node = working_set->has_external_mod_sentinel.next, *next = 0; - node != &working_set->has_external_mod_sentinel; - node = next){ - next = node->next; - Editing_File *file = CastFromMember(Editing_File, external_mod_node, node); - dll_remove(node); - block_zero_struct(node); - co_send_core_event(tctx, models, CoreCode_FileExternallyModified, file->id); - } - } - } - - // NOTE(allen): if the exit signal has been sent, run the exit hook. - if (input->trying_to_kill){ - models->keep_playing = false; - } - if (!models->keep_playing){ - if (co_send_core_event(tctx, models, CoreCode_TryExit)){ - models->keep_playing = true; - } - } - - // NOTE(allen): rendering - { - Frame_Info frame = {}; - frame.index = models->frame_counter; - frame.literal_dt = literal_dt; - frame.animation_dt = animation_dt; - - Application_Links app = {}; - app.tctx = tctx; - app.cmd_context = models; - - if (models->tick != 0){ - models->tick(&app, frame); - } - - begin_render_section(target, models->frame_counter, literal_dt, animation_dt); - models->in_render_mode = true; - - Live_Views *live_views = &models->view_set; - for (Node *node = layout->open_panels.next; - node != &layout->open_panels; - node = node->next){ - Panel *panel = CastFromMember(Panel, node, node); - View *view = panel->view; - View_Context_Node *ctx = view->ctx; - if (ctx != 0){ - Render_Caller_Function *render_caller = ctx->ctx.render_caller; - if (render_caller != 0){ - render_caller(&app, frame, view_get_id(live_views, view)); - } - } - } - - models->in_render_mode = false; - end_render_section(target); - } - - // NOTE(allen): flush the log - log_flush(tctx, models); - - // NOTE(allen): set the app_result - Application_Step_Result app_result = {}; - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; - app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; - - // NOTE(allen): get new window title - if (models->has_new_title){ - models->has_new_title = false; - app_result.has_new_title = true; - app_result.title_string = models->title_space; - } - - // NOTE(allen): get cursor type - if (mouse_panel != 0 && !mouse_in_margin){ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; - } - else if (divider_panel != 0){ - if (divider_panel->vertical_split){ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_LEFTRIGHT; - } - else{ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_UPDOWN; - } - } - else{ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; - } - - models->prev_mouse_panel = mouse_panel; - app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; - app_result.perform_kill = !models->keep_playing; - app_result.animating = models->animate_next_frame; - if (models->animate_next_frame){ - // NOTE(allen): Silence the timer, because we're going to do another frame right away anyways. - system_wake_up_timer_set(models->period_wakeup_timer, max_u32); - } - else{ - // NOTE(allen): Set the timer's wakeup period, possibly to max_u32 thus effectively silencing it. - system_wake_up_timer_set(models->period_wakeup_timer, models->next_animate_delay); - } - - // NOTE(allen): Update Frame to Frame States - models->prev_p = input->mouse.p; - models->animated_last_frame = app_result.animating; - models->frame_counter += 1; - - // end-of-app_step - return(app_result); -} - -extern "C" App_Get_Functions_Sig(app_get_functions){ - App_Functions result = {}; - - result.load_vtables = app_load_vtables; - result.get_logger = app_get_logger; - result.read_command_line = app_read_command_line; - result.init = app_init; - result.step = app_step; - - return(result); -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.12.2014 + * + * Application layer for project codename "4ed" + * + */ + +// TOP + +internal void +init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, i32 argc, char **argv){ + char *arg = 0; + Command_Line_Mode mode = CLMode_App; + Command_Line_Action action = CLAct_Nothing; + b32 strict = false; + + settings->init_files_max = ArrayCount(settings->init_files); + for (i32 i = 1; i <= argc; ++i){ + if (i == argc){ + arg = ""; + } + else{ + arg = argv[i]; + } + + if (arg[0] == '-' && arg[1] == '-'){ + char *long_arg_name = arg+2; + if (string_match(SCu8(long_arg_name), string_u8_litexpr("custom"))){ + mode = CLMode_Custom; + continue; + } + } + + switch (mode){ + case CLMode_App: + { + switch (action){ + case CLAct_Nothing: + { + if (arg[0] == '-'){ + action = CLAct_Ignore; + switch (arg[1]){ + case 'd': action = CLAct_CustomDLL; strict = false; break; + case 'D': action = CLAct_CustomDLL; strict = true; break; + + case 'i': action = CLAct_InitialFilePosition; break; + + case 'w': action = CLAct_WindowSize; break; + case 'W': action = CLAct_WindowMaximize; break; + case 'p': action = CLAct_WindowPosition; break; + case 'F': action = CLAct_WindowFullscreen; break; + + case 'f': action = CLAct_FontSize; break; + case 'h': action = CLAct_FontUseHinting; --i; break; + } + } + else if (arg[0] != 0){ + if (settings->init_files_count < settings->init_files_max){ + i32 index = settings->init_files_count++; + settings->init_files[index] = arg; + } + } + }break; + + case CLAct_CustomDLL: + { + plat_settings->custom_dll_is_strict = (b8)strict; + if (i < argc){ + plat_settings->custom_dll = argv[i]; + } + action = CLAct_Nothing; + }break; + + case CLAct_InitialFilePosition: + { + if (i < argc){ + settings->initial_line = (i32)string_to_integer(SCu8(argv[i]), 10); + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowSize: + { + if (i + 1 < argc){ + plat_settings->set_window_size = true; + + i32 w = (i32)string_to_integer(SCu8(argv[i]), 10); + i32 h = (i32)string_to_integer(SCu8(argv[i + 1]), 10); + if (w > 0){ + plat_settings->window_w = w; + } + if (h > 0){ + plat_settings->window_h = h; + } + + ++i; + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowMaximize: + { + --i; + plat_settings->maximize_window = true; + action = CLAct_Nothing; + }break; + + case CLAct_WindowPosition: + { + if (i + 1 < argc){ + plat_settings->set_window_pos = true; + + i32 x = (i32)string_to_integer(SCu8(argv[i]), 10); + i32 y = (i32)string_to_integer(SCu8(argv[i + 1]), 10); + if (x > 0){ + plat_settings->window_x = x; + } + if (y > 0){ + plat_settings->window_y = y; + } + + ++i; + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowFullscreen: + { + --i; + plat_settings->fullscreen_window = true; + action = CLAct_Nothing; + }break; + + case CLAct_FontSize: + { + if (i < argc){ + settings->font_size = (i32)string_to_integer(SCu8(argv[i]), 10); + } + action = CLAct_Nothing; + }break; + + case CLAct_FontUseHinting: + { + plat_settings->use_hinting = true; + settings->use_hinting = plat_settings->use_hinting; + action = CLAct_Nothing; + }break; + } + }break; + + case CLMode_Custom: + { + settings->custom_flags = argv + i; + settings->custom_flags_count = argc - i; + i = argc; + mode = CLMode_App; + }break; + } + } +} + +//////////////////////////////// + +internal Models* +models_init(void){ + Arena arena = make_arena_system(); + Models *models = push_array_zero(&arena, Models, 1); + models->arena_ = arena; + models->arena = &models->arena_; + heap_init(&models->heap, get_base_allocator_system()); + return(models); +} + +internal void +app_load_vtables(API_VTable_system *vtable_system, API_VTable_font *vtable_font, API_VTable_graphics *vtable_graphics){ + system_api_read_vtable(vtable_system); + font_api_read_vtable(vtable_font); + graphics_api_read_vtable(vtable_graphics); +} + +internal Log_Function* +app_get_logger(void){ + log_init(); + return(log_string); +} + +App_Read_Command_Line_Sig(app_read_command_line){ + Models *models = models_init(); + App_Settings *settings = &models->settings; + block_zero_struct(settings); + if (argc > 1){ + init_command_line_settings(&models->settings, plat_settings, argc, argv); + } + *files = models->settings.init_files; + *file_count = &models->settings.init_files_count; + return(models); +} + +App_Init_Sig(app_init){ + Models *models = (Models*)base_ptr; + models->keep_playing = true; + models->hard_exit = false; + + models->config_api = api; + models->virtual_event_arena = reserve_arena(tctx); + + profile_init(&models->profile_list); + + managed_ids_init(tctx->allocator, &models->managed_id_set); + + API_VTable_custom custom_vtable = {}; + custom_api_fill_vtable(&custom_vtable); + API_VTable_system system_vtable = {}; + system_api_fill_vtable(&system_vtable); + Custom_Layer_Init_Type *custom_init = api.init_apis(&custom_vtable, &system_vtable); + Assert(custom_init != 0); + + // NOTE(allen): coroutines + coroutine_system_init(&models->coroutines); + + // NOTE(allen): font set + font_set_init(&models->font_set); + + // NOTE(allen): live set + Arena *arena = models->arena; + { + models->view_set.count = 0; + models->view_set.max = MAX_VIEWS; + models->view_set.views = push_array(arena, View, models->view_set.max); + + //dll_init_sentinel + models->view_set.free_sentinel.next = &models->view_set.free_sentinel; + models->view_set.free_sentinel.prev = &models->view_set.free_sentinel; + + i32 max = models->view_set.max; + View *view = models->view_set.views; + for (i32 i = 0; i < max; ++i, ++view){ + //dll_insert(&models->view_set.free_sentinel, view); + view->next = models->view_set.free_sentinel.next; + view->prev = &models->view_set.free_sentinel; + models->view_set.free_sentinel.next = view; + view->next->prev = view; + } + } + + lifetime_allocator_init(tctx->allocator, &models->lifetime_allocator); + dynamic_workspace_init(&models->lifetime_allocator, DynamicWorkspace_Global, 0, &models->dynamic_workspace); + + // NOTE(allen): file setup + working_set_init(models, &models->working_set); + Mutex_Lock file_order_lock(models->working_set.mutex); + + // NOTE(allen): + global_history_init(&models->global_history); + text_layout_init(tctx, &models->text_layouts); + + // NOTE(allen): clipboard setup + models->working_set.clipboard_max_size = ArrayCount(models->working_set.clipboards); + models->working_set.clipboard_size = 0; + models->working_set.clipboard_current = 0; + models->working_set.clipboard_rolling = 0; + + // TODO(allen): do(better clipboard allocation) + if (clipboard.str != 0){ + String_Const_u8 *dest = working_set_next_clipboard_string(&models->heap, &models->working_set, clipboard.size); + block_copy(dest->str, clipboard.str, clipboard.size); + } + + // NOTE(allen): style setup + { + Scratch_Block scratch(tctx); + Face_Description description = {}; + description.font.file_name = get_file_path_in_fonts_folder(scratch, string_u8_litexpr("liberation-mono.ttf")); + description.parameters.pt_size = 12; + Face *new_face = font_set_new_face(&models->font_set, &description); + models->global_face_id = new_face->id; + } + + // NOTE(allen): title space + models->has_new_title = true; + models->title_capacity = KB(4); + models->title_space = push_array(arena, char, models->title_capacity); + block_copy(models->title_space, WINDOW_NAME, sizeof(WINDOW_NAME)); + + // NOTE(allen): miscellaneous init + hot_directory_init(arena, &models->hot_directory, current_directory); + child_process_container_init(tctx->allocator, &models->child_processes); + models->period_wakeup_timer = system_wake_up_timer_create(); + + // NOTE(allen): custom layer init + Application_Links app = {}; + app.tctx = tctx; + app.cmd_context = models; + custom_init(&app); + + // NOTE(allen): init baked in buffers + File_Init init_files[] = { + { string_u8_litinit("*messages*"), &models->message_buffer , true , }, + { string_u8_litinit("*scratch*") , &models->scratch_buffer , false, }, + { string_u8_litinit("*log*") , &models->log_buffer , true , }, + { string_u8_litinit("*keyboard*"), &models->keyboard_buffer, true , }, + }; + + Heap *heap = &models->heap; + for (i32 i = 0; i < ArrayCount(init_files); ++i){ + Editing_File *file = working_set_allocate_file(&models->working_set, &models->lifetime_allocator); + buffer_bind_name(tctx, models, arena, &models->working_set, file, init_files[i].name); + + if (init_files[i].ptr != 0){ + *init_files[i].ptr = file; + } + + File_Attributes attributes = {}; + file_create_from_string(tctx, models, file, SCu8(), attributes); + if (init_files[i].read_only){ + file->settings.read_only = true; + history_free(tctx, &file->state.history); + } + + file->settings.never_kill = true; + file_set_unimportant(file, true); + } + + // NOTE(allen): setup first panel + { + Panel *panel = layout_initialize(arena, &models->layout); + View *new_view = live_set_alloc_view(&models->lifetime_allocator, &models->view_set, panel); + view_init(tctx, models, new_view, models->scratch_buffer, models->view_event_handler); + } +} + +App_Step_Sig(app_step){ + Models *models = (Models*)base_ptr; + + Mutex_Lock file_order_lock(models->working_set.mutex); + Scratch_Block scratch(tctx, Scratch_Share); + + models->next_animate_delay = max_u32; + models->animate_next_frame = false; + + // NOTE(allen): per-frame update of models state + begin_frame(target, &models->font_set); + models->target = target; + models->input = input; + + // NOTE(allen): OS clipboard event handling + String_Const_u8 clipboard = input->clipboard; + if (clipboard.str != 0){ + String_Const_u8 *dest = working_set_next_clipboard_string(&models->heap, &models->working_set, clipboard.size); + dest->size = eol_convert_in((char*)dest->str, (char*)clipboard.str, (i32)clipboard.size); + if (input->clipboard_changed){ + co_send_core_event(tctx, models, CoreCode_NewClipboardContents, *dest); + } + } + + // NOTE(allen): reorganizing panels on screen + Vec2_i32 prev_dim = layout_get_root_size(&models->layout); + Vec2_i32 current_dim = V2i32(target->width, target->height); + layout_set_root_size(&models->layout, current_dim); + + // NOTE(allen): update child processes + f32 dt = input->dt; + if (dt > 0){ + Temp_Memory_Block temp(scratch); + + Child_Process_Container *child_processes = &models->child_processes; + Child_Process **processes_to_free = push_array(scratch, Child_Process*, child_processes->active_child_process_count); + i32 processes_to_free_count = 0; + + u32 max = KB(128); + char *dest = push_array(scratch, char, max); + + for (Node *node = child_processes->child_process_active_list.next; + node != &child_processes->child_process_active_list; + node = node->next){ + Child_Process *child_process = CastFromMember(Child_Process, node, node); + + Editing_File *file = child_process->out_file; + CLI_Handles *cli = &child_process->cli; + + // TODO(allen): do(call a 'child process updated hook' let that hook populate the buffer if it so chooses) + + b32 edited_file = false; + u32 amount = 0; + system_cli_begin_update(cli); + if (system_cli_update_step(cli, dest, max, &amount)){ + if (file != 0 && amount > 0){ + amount = eol_in_place_convert_in(dest, amount); + output_file_append(tctx, models, file, SCu8(dest, amount)); + edited_file = true; + } + } + + if (system_cli_end_update(cli)){ + if (file != 0){ + String_Const_u8 str = push_u8_stringf(scratch, "exited with code %d", cli->exit); + output_file_append(tctx, models, file, str); + edited_file = true; + } + processes_to_free[processes_to_free_count++] = child_process; + child_process_set_return_code(models, child_processes, child_process->id, cli->exit); + } + + if (child_process->cursor_at_end && file != 0){ + file_cursor_to_end(tctx, models, file); + } + } + + for (i32 i = 0; i < processes_to_free_count; ++i){ + child_process_free(child_processes, processes_to_free[i]->id); + } + } + + // NOTE(allen): simulated events + Input_List input_list = input->events; + Input_Modifier_Set modifiers = system_get_keyboard_modifiers(scratch); + if (input->mouse.press_l){ + Input_Event event = {}; + event.kind = InputEventKind_MouseButton; + event.mouse.code = MouseCode_Left; + event.mouse.p = input->mouse.p; + event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); + push_input_event(scratch, &input_list, &event); + } + else if (input->mouse.release_l){ + Input_Event event = {}; + event.kind = InputEventKind_MouseButtonRelease; + event.mouse.code = MouseCode_Left; + event.mouse.p = input->mouse.p; + event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); + push_input_event(scratch, &input_list, &event); + } + if (input->mouse.press_r){ + Input_Event event = {}; + event.kind = InputEventKind_MouseButton; + event.mouse.code = MouseCode_Right; + event.mouse.p = input->mouse.p; + event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); + push_input_event(scratch, &input_list, &event); + } + else if (input->mouse.release_r){ + Input_Event event = {}; + event.kind = InputEventKind_MouseButtonRelease; + event.mouse.code = MouseCode_Right; + event.mouse.p = input->mouse.p; + event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); + push_input_event(scratch, &input_list, &event); + } + if (input->mouse.wheel != 0){ + Input_Event event = {}; + event.kind = InputEventKind_MouseWheel; + event.mouse_wheel.value = (f32)(input->mouse.wheel); + event.mouse_wheel.p = input->mouse.p; + event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); + push_input_event(scratch, &input_list, &event); + } + if (input->mouse.p != models->prev_p){ + b32 was_in_window = rect_contains_point(Ri32(0, 0, prev_dim.x, prev_dim.y), models->prev_p); + b32 is_in_window = rect_contains_point(Ri32(0, 0, current_dim.x, current_dim.y), input->mouse.p); + if (is_in_window || was_in_window){ + Input_Event event = {}; + event.kind = InputEventKind_MouseMove; + event.mouse_move.p = input->mouse.p; + event.mouse.modifiers = copy_modifier_set(scratch, &modifiers); + push_input_event(scratch, &input_list, &event); + } + } + if (models->animated_last_frame){ + Input_Event event = {}; + event.kind = InputEventKind_Core; + event.core.code = CoreCode_Animate; + push_input_event(scratch, &input_list, &event); + } + + // NOTE(allen): expose layout + Layout *layout = &models->layout; + + // NOTE(allen): mouse hover status + Panel *mouse_panel = 0; + Panel *divider_panel = 0; + b32 mouse_in_margin = false; + Vec2_i32 mouse = input->mouse.p; + { + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ + if (rect_contains_point(panel->rect_full, mouse)){ + mouse_panel = panel; + if (!rect_contains_point(panel->rect_inner, mouse)){ + mouse_in_margin = true; + for (divider_panel = mouse_panel->parent; + divider_panel != 0; + divider_panel = divider_panel->parent){ + if (rect_contains_point(divider_panel->rect_inner, mouse)){ + break; + } + } + } + } + if (mouse_panel != 0){ + break; + } + } + } + + // NOTE(allen): First frame initialization + if (input->first_step){ + Temp_Memory_Block temp(scratch); + + String_Const_u8_Array file_names = {}; + file_names.count = models->settings.init_files_count; + file_names.vals = push_array(scratch, String_Const_u8, file_names.count); + for (i32 i = 0; i < file_names.count; i += 1){ + file_names.vals[i] = SCu8(models->settings.init_files[i]); + } + + String_Const_u8_Array flags = {}; + flags.count = models->settings.custom_flags_count; + flags.vals = push_array(scratch, String_Const_u8, flags.count); + for (i32 i = 0; i < flags.count; i += 1){ + flags.vals[i] = SCu8(models->settings.custom_flags[i]); + } + + Input_Event event = {}; + event.kind = InputEventKind_Core; + event.core.code = CoreCode_Startup; + event.core.flag_strings = flags; + event.core.file_names = file_names; + co_send_event(tctx, models, &event); + } + + // NOTE(allen): consume event stream + Input_Event_Node *input_node = input_list.first; + Input_Event_Node *input_node_next = 0; + for (;; input_node = input_node_next){ + // NOTE(allen): first handle any events coming from the view command + // function queue + Model_View_Command_Function cmd_func = models_pop_view_command_function(models); + if (cmd_func.custom_func != 0){ + View *view = imp_get_view(models, cmd_func.view_id); + if (view != 0){ + input_node_next = input_node; + Input_Event cmd_func_event = {}; + cmd_func_event.kind = InputEventKind_CustomFunction; + cmd_func_event.custom_func = cmd_func.custom_func; + co_send_event(tctx, models, view, &cmd_func_event); + continue; + } + } + + Temp_Memory_Block temp(scratch); + Input_Event *simulated_input = 0; + Input_Event virtual_event = models_pop_virtual_event(scratch, models); + if (virtual_event.kind != InputEventKind_None){ + virtual_event.virtual_event = true; + simulated_input = &virtual_event; + } + else{ + if (input_node == 0){ + break; + } + input_node_next = input_node->next; + simulated_input = &input_node->event; + + if (simulated_input->kind == InputEventKind_TextInsert && simulated_input->text.blocked){ + continue; + } + + // NOTE(allen): record to keyboard history + if (simulated_input->kind == InputEventKind_KeyStroke || + simulated_input->kind == InputEventKind_KeyRelease || + simulated_input->kind == InputEventKind_TextInsert){ + Temp_Memory_Block temp_key_line(scratch); + String_Const_u8 key_line = stringize_keyboard_event(scratch, simulated_input); + output_file_append(tctx, models, models->keyboard_buffer, key_line); + } + } + + b32 event_was_handled = false; + Input_Event *event = simulated_input; + + Panel *active_panel = layout_get_active_panel(layout); + View *view = active_panel->view; + Assert(view != 0); + + switch (models->state){ + case APP_STATE_EDIT: + { + typedef i32 Event_Consume_Rule; + enum{ + EventConsume_None, + EventConsume_BeginResize, + EventConsume_ClickChangeView, + EventConsume_CustomCommand, + }; + + Event_Consume_Rule consume_rule = EventConsume_CustomCommand; + if (match_mouse_code(event, MouseCode_Left) && (divider_panel != 0)){ + consume_rule = EventConsume_BeginResize; + } + else if (match_mouse_code(event, MouseCode_Left) && + mouse_panel != 0 && mouse_panel != active_panel){ + consume_rule = EventConsume_ClickChangeView; + } + + switch (consume_rule){ + case EventConsume_BeginResize: + { + models->state = APP_STATE_RESIZING; + models->resizing_intermediate_panel = divider_panel; + event_was_handled = true; + }break; + + case EventConsume_ClickChangeView: + { + // NOTE(allen): run deactivate command + co_send_core_event(tctx, models, view, CoreCode_ClickDeactivateView); + + layout->active_panel = mouse_panel; + models->animate_next_frame = true; + active_panel = mouse_panel; + view = active_panel->view; + + // NOTE(allen): run activate command + co_send_core_event(tctx, models, view, CoreCode_ClickActivateView); + + event_was_handled = true; + }break; + + case EventConsume_CustomCommand: + { + event_was_handled = co_send_event(tctx, models, view, event); + }break; + } + }break; + + case APP_STATE_RESIZING: + { + Event_Property event_flags = get_event_properties(event); + if (HasFlag(event_flags, EventProperty_AnyKey) || + match_mouse_code_release(event, MouseCode_Left)){ + models->state = APP_STATE_EDIT; + } + else if (event->kind == InputEventKind_MouseMove){ + if (input->mouse.l){ + Panel *split = models->resizing_intermediate_panel; + Range_i32 limits = layout_get_limiting_range_on_split(layout, split); + i32 mouse_position = (split->vertical_split)?(mouse.x):(mouse.y); + mouse_position = clamp(limits.min, mouse_position, limits.max); + layout_set_split_absolute_position(layout, split, mouse_position); + } + else{ + models->state = APP_STATE_EDIT; + } + } + }break; + } + + if (event_was_handled && event->kind == InputEventKind_KeyStroke){ + for (Input_Event *dependent_text = event->key.first_dependent_text; + dependent_text != 0; + dependent_text = dependent_text->text.next_text){ + Assert(dependent_text->kind == InputEventKind_TextInsert); + dependent_text->text.blocked = true; + } + } + } + + linalloc_clear(models->virtual_event_arena); + models->free_virtual_event = 0; + models->first_virtual_event = 0; + models->last_virtual_event = 0; + + // NOTE(allen): send panel size update + if (models->layout.panel_state_dirty){ + models->layout.panel_state_dirty = false; + if (models->buffer_viewer_update != 0){ + Application_Links app = {}; + app.tctx = tctx; + app.cmd_context = models; + models->buffer_viewer_update(&app); + } + } + + // NOTE(allen): dt + f32 literal_dt = 0.f; + u64 now_usecond_stamp = system_now_time(); + if (!input->first_step){ + u64 elapsed_useconds = now_usecond_stamp - models->last_render_usecond_stamp; + literal_dt = (f32)((f64)(elapsed_useconds)/1000000.f); + } + models->last_render_usecond_stamp = now_usecond_stamp; + f32 animation_dt = 0.f; + if (models->animated_last_frame){ + animation_dt = literal_dt; + } + + // NOTE(allen): on the first frame there should be no scrolling + if (input->first_step){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ + View *view = panel->view; + File_Edit_Positions edit_pos = view_get_edit_pos(view); + edit_pos.scroll.position = view_normalize_buffer_point(tctx, models, view, edit_pos.scroll.target); + block_zero_struct(&edit_pos.scroll.target); + view_set_edit_pos(view, edit_pos); + } + } + + // NOTE(allen): hook for files reloaded + { + Working_Set *working_set = &models->working_set; + Assert(working_set->has_external_mod_sentinel.next != 0); + if (working_set->has_external_mod_sentinel.next != &working_set->has_external_mod_sentinel){ + for (Node *node = working_set->has_external_mod_sentinel.next, *next = 0; + node != &working_set->has_external_mod_sentinel; + node = next){ + next = node->next; + Editing_File *file = CastFromMember(Editing_File, external_mod_node, node); + dll_remove(node); + block_zero_struct(node); + co_send_core_event(tctx, models, CoreCode_FileExternallyModified, file->id); + } + } + } + + // NOTE(allen): if the exit signal has been sent, run the exit hook. + if (!models->keep_playing || input->trying_to_kill){ + co_send_core_event(tctx, models, CoreCode_TryExit); + models->keep_playing = true; + } + + // NOTE(allen): rendering + { + Frame_Info frame = {}; + frame.index = models->frame_counter; + frame.literal_dt = literal_dt; + frame.animation_dt = animation_dt; + + Application_Links app = {}; + app.tctx = tctx; + app.cmd_context = models; + + if (models->tick != 0){ + models->tick(&app, frame); + } + + begin_render_section(target, models->frame_counter, literal_dt, animation_dt); + models->in_render_mode = true; + + Live_Views *live_views = &models->view_set; + for (Node *node = layout->open_panels.next; + node != &layout->open_panels; + node = node->next){ + Panel *panel = CastFromMember(Panel, node, node); + View *view = panel->view; + View_Context_Node *ctx = view->ctx; + if (ctx != 0){ + Render_Caller_Function *render_caller = ctx->ctx.render_caller; + if (render_caller != 0){ + render_caller(&app, frame, view_get_id(live_views, view)); + } + } + } + + models->in_render_mode = false; + end_render_section(target); + } + + // NOTE(allen): flush the log + log_flush(tctx, models); + + // NOTE(allen): set the app_result + Application_Step_Result app_result = {}; + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; + app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; + + // NOTE(allen): get new window title + if (models->has_new_title){ + models->has_new_title = false; + app_result.has_new_title = true; + app_result.title_string = models->title_space; + } + + // NOTE(allen): get cursor type + if (mouse_panel != 0 && !mouse_in_margin){ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + } + else if (divider_panel != 0){ + if (divider_panel->vertical_split){ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_LEFTRIGHT; + } + else{ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_UPDOWN; + } + } + else{ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + } + + models->prev_mouse_panel = mouse_panel; + app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; + app_result.perform_kill = models->hard_exit; + app_result.animating = models->animate_next_frame; + if (models->animate_next_frame){ + // NOTE(allen): Silence the timer, because we're going to do another frame right away anyways. + system_wake_up_timer_set(models->period_wakeup_timer, max_u32); + } + else{ + // NOTE(allen): Set the timer's wakeup period, possibly to max_u32 thus effectively silencing it. + system_wake_up_timer_set(models->period_wakeup_timer, models->next_animate_delay); + } + + // NOTE(allen): Update Frame to Frame States + models->prev_p = input->mouse.p; + models->animated_last_frame = app_result.animating; + models->frame_counter += 1; + + // end-of-app_step + return(app_result); +} + +extern "C" App_Get_Functions_Sig(app_get_functions){ + App_Functions result = {}; + + result.load_vtables = app_load_vtables; + result.get_logger = app_get_logger; + result.read_command_line = app_read_command_line; + result.init = app_init; + result.step = app_step; + + return(result); +} + +// BOTTOM + diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index 933262b4..9b668788 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -453,7 +453,7 @@ buffer_line_y_difference(Application_Links *app, Buffer_ID buffer_id, i64 line_a, i64 line_b){ Models *models = (Models*)app->cmd_context; Editing_File *file = imp_get_file(models, buffer_id); - f32 result = {}; + f32 result = 0.0f; if (api_check_buffer(file)){ Face *face = font_set_face_from_id(&models->font_set, face_id); if (face != 0){ @@ -521,13 +521,30 @@ buffer_relative_box_of_pos(Application_Links *app, Buffer_ID buffer_id, f32 widt return(result); } +api(custom) function Rect_f32 +buffer_padded_box_of_pos(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos){ + Models *models = (Models*)app->cmd_context; + Editing_File *file = imp_get_file(models, buffer_id); + Rect_f32 result = {}; + if (api_check_buffer(file)){ + Face *face = font_set_face_from_id(&models->font_set, face_id); + if (face != 0){ + Layout_Function *layout_func = file_get_layout_func(file); + result = file_padded_box_of_pos(app->tctx, models, file, + layout_func, width, face, + base_line, pos); + } + } + return(result); +} + api(custom) function i64 buffer_relative_character_from_pos(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos) { Models *models = (Models*)app->cmd_context; Editing_File *file = imp_get_file(models, buffer_id); - i64 result = {}; + i64 result = 0; if (api_check_buffer(file)){ Face *face = font_set_face_from_id(&models->font_set, face_id); if (face != 0){ @@ -563,7 +580,7 @@ api(custom) function f32 view_line_y_difference(Application_Links *app, View_ID view_id, i64 line_a, i64 line_b){ Models *models = (Models*)app->cmd_context; View *view = imp_get_view(models, view_id); - f32 result = {}; + f32 result = 0.0f; if (api_check_view(view)){ result = view_line_y_difference(app->tctx, models, view, line_a, line_b); } @@ -603,11 +620,22 @@ view_relative_box_of_pos(Application_Links *app, View_ID view_id, i64 base_line, return(result); } +api(custom) function Rect_f32 +view_padded_box_of_pos(Application_Links *app, View_ID view_id, i64 base_line, i64 pos){ + Models *models = (Models*)app->cmd_context; + View *view = imp_get_view(models, view_id); + Rect_f32 result = {}; + if (api_check_view(view)){ + result = view_padded_box_of_pos(app->tctx, models, view, base_line, pos); + } + return(result); +} + api(custom) function i64 view_relative_character_from_pos(Application_Links *app, View_ID view_id, i64 base_line, i64 pos){ Models *models = (Models*)app->cmd_context; View *view = imp_get_view(models, view_id); - i64 result = {}; + i64 result = 0; if (api_check_view(view)){ result = view_relative_character_from_pos(app->tctx, models, view, base_line, pos); } @@ -618,7 +646,7 @@ api(custom) function i64 view_pos_from_relative_character(Application_Links *app, View_ID view_id, i64 base_line, i64 character){ Models *models = (Models*)app->cmd_context; View *view = imp_get_view(models, view_id); - i64 result = {}; + i64 result = 0; if (api_check_view(view)){ result = view_pos_from_relative_character(app->tctx, models, view, base_line, character); } @@ -702,7 +730,7 @@ api(custom) function Dirty_State buffer_get_dirty_state(Application_Links *app, Buffer_ID buffer_id){ Models *models = (Models*)app->cmd_context; Editing_File *file = imp_get_file(models, buffer_id); - Dirty_State result = {}; + Dirty_State result = 0; if (api_check_buffer(file)){ result = file->state.dirty; } @@ -771,6 +799,11 @@ buffer_get_setting(Application_Links *app, Buffer_ID buffer_id, Buffer_Setting_I *value_out = file->settings.unimportant; }break; + case BufferSetting_Unkillable: + { + *value_out = (file->settings.never_kill || file->settings.unkillable); + }break; + case BufferSetting_ReadOnly: { *value_out = file->settings.read_only; @@ -809,14 +842,14 @@ buffer_set_setting(Application_Links *app, Buffer_ID buffer_id, Buffer_Setting_I } }break; + case BufferSetting_Unkillable: + { + file->settings.unkillable = (value != 0); + }break; + case BufferSetting_ReadOnly: { - if (value){ - file->settings.read_only = true; - } - else{ - file->settings.read_only = false; - } + file->settings.read_only = (value != 0); }break; case BufferSetting_RecordsHistory: @@ -915,7 +948,7 @@ buffer_kill(Application_Links *app, Buffer_ID buffer_id, Buffer_Kill_Flag flags) Editing_File *file = imp_get_file(models, buffer_id); Buffer_Kill_Result result = BufferKillResult_DoesNotExist; if (api_check_buffer(file)){ - if (!file->settings.never_kill){ + if (!file->settings.never_kill && !file->settings.unkillable){ b32 needs_to_save = file_needs_save(file); if (!needs_to_save || (flags & BufferKill_AlwaysKill) != 0){ Thread_Context *tctx = app->tctx; @@ -1080,7 +1113,7 @@ get_view_prev__inner(Layout *layout, View *view){ } } else{ - Panel *panel = layout_get_first_open_panel(layout); + Panel *panel = layout_get_last_open_panel(layout); view = panel->view; } return(view); @@ -1678,23 +1711,6 @@ view_set_buffer(Application_Links *app, View_ID view_id, Buffer_ID buffer_id, Se return(result); } -// TODO(allen): remove this! -api(custom) function b32 -view_post_fade(Application_Links *app, View_ID view_id, f32 seconds, Range_i64 range, - ARGB_Color color){ - Models *models = (Models*)app->cmd_context; - View *view = imp_get_view(models, view_id); - b32 result = false; - if (api_check_view(view)){ - i64 size = range_size(range); - if (size > 0){ - view_post_paste_effect(view, seconds, (i32)range.start, (i32)size, color); - result = true; - } - } - return(result); -} - api(custom) function b32 view_push_context(Application_Links *app, View_ID view_id, View_Context *ctx){ Models *models = (Models*)app->cmd_context; @@ -1991,7 +2007,7 @@ managed_scope_get_attachment(Application_Links *app, Managed_Scope scope, Manage } else{ #define M \ - "ERROR: scope attachment already exists with a size smaller than the requested size; no attachment pointer can be returned." +"ERROR: scope attachment already exists with a size smaller than the requested size; no attachment pointer can be returned." print_message(app, string_u8_litexpr(M)); #undef M } @@ -2390,7 +2406,7 @@ set_global_face(Application_Links *app, Face_ID id) b32 result = false; Face *face = font_set_face_from_id(&models->font_set, id); if (face != 0){ - models->global_face_id = face->id; + models->global_face_id = face->id; result = true; } return(result); @@ -2733,6 +2749,13 @@ send_exit_signal(Application_Links *app) models->keep_playing = false; } +api(custom) function void +hard_exit(Application_Links *app) +{ + Models *models = (Models*)app->cmd_context; + models->hard_exit = true; +} + api(custom) function void set_window_title(Application_Links *app, String_Const_u8 title) { @@ -2796,7 +2819,7 @@ api(custom) function Text_Layout_ID text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, Buffer_Point buffer_point){ Models *models = (Models*)app->cmd_context; Editing_File *file = imp_get_file(models, buffer_id); - Text_Layout_ID result = {}; + Text_Layout_ID result = 0; if (api_check_buffer(file)){ Thread_Context *tctx = app->tctx; Scratch_Block scratch(tctx); @@ -2826,10 +2849,10 @@ text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, B Range_i64 visible_line_number_range = Ii64(buffer_point.line_number, line_number); Range_i64 visible_range = Ii64(buffer_get_first_pos_from_line_number(buffer, visible_line_number_range.min), - buffer_get_last_pos_from_line_number(buffer, visible_line_number_range.max)); + buffer_get_last_pos_from_line_number(buffer, visible_line_number_range.max)); i64 item_count = range_size_inclusive(visible_range); - ARGB_Color *colors_array = push_array_zero(arena, ARGB_Color, item_count); + ARGB_Color *colors_array = push_array_zero(arena, ARGB_Color, item_count); result = text_layout_new(&models->text_layouts, arena, buffer_id, buffer_point, visible_range, visible_line_number_range, rect, colors_array, layout_func); @@ -2944,7 +2967,7 @@ text_layout_character_on_screen(Application_Links *app, Text_Layout_ID layout_id y += line.height; } - // TODO(allen): optimization: This is some fairly heavy computation. We really + // TODO(allen): optimization: This is some fairly heavy computation. We really // need to accelerate the (pos -> item) lookup within a single // Buffer_Layout_Item_List. b32 is_first_item = true; @@ -2987,13 +3010,35 @@ paint_text_color(Application_Links *app, Text_Layout_ID layout_id, Range_i64 ran range.max = clamp_top(range.max, layout->visible_range.max); range.min -= layout->visible_range.min; range.max -= layout->visible_range.min; - ARGB_Color *color_ptr = layout->item_colors + range.min; + ARGB_Color *color_ptr = layout->item_colors + range.min; for (i64 i = range.min; i < range.max; i += 1, color_ptr += 1){ *color_ptr = color; } } } +api(custom) function void +paint_text_color_blend(Application_Links *app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color, f32 blend){ + Models *models = (Models*)app->cmd_context; + Rect_f32 result = {}; + Text_Layout *layout = text_layout_get(&models->text_layouts, layout_id); + if (layout != 0){ + range.min = clamp_bot(layout->visible_range.min, range.min); + range.max = clamp_top(range.max, layout->visible_range.max); + range.min -= layout->visible_range.min; + range.max -= layout->visible_range.min; + Vec4_f32 color_v4f32 = unpack_color(color); + Vec4_f32 color_pm_v4f32 = color_v4f32*blend; + f32 neg_blend = 1.f - blend; + ARGB_Color *color_ptr = layout->item_colors + range.min; + for (i64 i = range.min; i < range.max; i += 1, color_ptr += 1){ + Vec4_f32 color_ptr_v4f32 = unpack_color(*color_ptr); + Vec4_f32 blended_v4f32 = color_ptr_v4f32*neg_blend + color_pm_v4f32; + *color_ptr = pack_color(blended_v4f32); + } + } +} + api(custom) function b32 text_layout_free(Application_Links *app, Text_Layout_ID text_layout_id){ Models *models = (Models*)app->cmd_context; diff --git a/4ed_app_models.h b/4ed_app_models.h index 4c7a4bf3..670b0c26 100644 --- a/4ed_app_models.h +++ b/4ed_app_models.h @@ -105,7 +105,8 @@ struct Models{ Hot_Directory hot_directory; - b32 keep_playing; + b8 keep_playing; + b8 hard_exit; b32 has_new_title; char *title_space; diff --git a/4ed_buffer.cpp b/4ed_buffer.cpp index c625e6f0..1e526935 100644 --- a/4ed_buffer.cpp +++ b/4ed_buffer.cpp @@ -646,53 +646,6 @@ buffer_remeasure_starts(Thread_Context *tctx, Gap_Buffer *buffer, Batch_Edit *ba } } -#if 0 -internal void -buffer_remeasure_starts(Arena *scratch, Gap_Buffer *buffer, - Range_i64 old_line_indexes, i64 line_shift, i64 text_shift){ - Temp_Memory temp = begin_temp(scratch); - buffer_starts__ensure_max_size(buffer, buffer->line_start_count + line_shift); - - i64 new_line_indexes_opl = old_line_indexes.one_past_last + line_shift; - i64 old_line_start_count = buffer->line_start_count; - i64 *line_start_ptr = buffer->line_starts + old_line_indexes.one_past_last; - for (i64 i = old_line_indexes.one_past_last; - i < old_line_start_count; - i += 1, line_start_ptr += 1){ - *line_start_ptr += text_shift; - } - block_copy_dynamic_array(buffer->line_starts + new_line_indexes_opl, - buffer->line_starts + old_line_indexes.one_past_last, - buffer->line_start_count - old_line_indexes.one_past_last); - - i64 first_pos = buffer->line_starts[old_line_indexes.first]; - i64 write_counter = old_line_indexes.first + 1; - i64 pos = first_pos; - List_String_Const_u8 list = buffer_get_chunks(scratch, buffer); - buffer_chunks_clamp(&list, Ii64(first_pos, buffer_size(buffer))); - for (Node_String_Const_u8 *node = list.first; - node != 0; - node = node->next){ - u8 *byte = node->string.str; - u8 *byte_opl = byte + node->string.size; - for (;byte < byte_opl; byte += 1){ - pos += 1; - if (*byte == '\n'){ - buffer->line_starts[write_counter] = pos; - write_counter += 1; - if (write_counter == new_line_indexes_opl){ - goto double_break; - } - } - } - } - double_break:; - - buffer->line_start_count += line_shift; - end_temp(temp); -} -#endif - internal Range_i64 buffer_get_pos_range_from_line_number(Gap_Buffer *buffer, i64 line_number){ Range_i64 result = {}; @@ -705,7 +658,7 @@ buffer_get_pos_range_from_line_number(Gap_Buffer *buffer, i64 line_number){ internal i64 buffer_get_first_pos_from_line_number(Gap_Buffer *buffer, i64 line_number){ - i64 result = {}; + i64 result = 0; if (line_number < 1){ result = 0; } @@ -720,7 +673,7 @@ buffer_get_first_pos_from_line_number(Gap_Buffer *buffer, i64 line_number){ internal i64 buffer_get_last_pos_from_line_number(Gap_Buffer *buffer, i64 line_number){ - i64 result = {}; + i64 result = 0; if (line_number < 1){ result = 0; } diff --git a/4ed_edit.cpp b/4ed_edit.cpp index 73d4ca81..d05097e3 100644 --- a/4ed_edit.cpp +++ b/4ed_edit.cpp @@ -90,8 +90,7 @@ edit_fix_markers__compute_scroll_y(i32 line_height, i32 old_y_val, f32 new_y_val } function void -edit_fix_markers(Thread_Context *tctx, Models *models, Editing_File *file, - Batch_Edit *batch){ +edit_fix_markers(Thread_Context *tctx, Models *models, Editing_File *file, Batch_Edit *batch){ Layout *layout = &models->layout; Lifetime_Object *file_lifetime_object = file->lifetime_object; @@ -135,7 +134,10 @@ edit_fix_markers(Thread_Context *tctx, Models *models, Editing_File *file, File_Edit_Positions edit_pos = view_get_edit_pos(view); write_cursor_with_index(cursors, &cursor_count, (i32)edit_pos.cursor_pos); write_cursor_with_index(cursors, &cursor_count, (i32)view->mark); - // TODO(allen): write a cursor for the current scroll line + Buffer_Cursor pos_cursor = file_compute_cursor(file, seek_line_col(edit_pos.scroll.position.line_number, 1)); + Buffer_Cursor targ_cursor = file_compute_cursor(file, seek_line_col(edit_pos.scroll.target.line_number, 1)); + write_cursor_with_index(cursors, &cursor_count, pos_cursor.pos); + write_cursor_with_index(cursors, &cursor_count, targ_cursor.pos); } } @@ -156,6 +158,8 @@ edit_fix_markers(Thread_Context *tctx, Models *models, Editing_File *file, } } + buffer_remeasure_starts(tctx, &file->state.buffer, batch); + if (cursor_count > 0 || r_cursor_count > 0){ buffer_sort_cursors( cursors, cursor_count); buffer_sort_cursors(r_cursors, r_cursor_count); @@ -178,8 +182,15 @@ edit_fix_markers(Thread_Context *tctx, Models *models, Editing_File *file, i64 cursor_pos = cursors[cursor_count++].pos; view->mark = cursors[cursor_count++].pos; File_Edit_Positions edit_pos = view_get_edit_pos(view); + + i64 scroll_pos = cursors[cursor_count++].pos; + i64 scroll_targ = cursors[cursor_count++].pos; + Buffer_Cursor pos_cursor = file_compute_cursor(file, seek_pos(scroll_pos)); + Buffer_Cursor targ_cursor = file_compute_cursor(file, seek_pos(scroll_targ)); + edit_pos.scroll.position.line_number = pos_cursor.line; + edit_pos.scroll.target.line_number = targ_cursor.line; + view_set_cursor_and_scroll(tctx, models, view, cursor_pos, edit_pos.scroll); - // TODO(allen): read a cursor for the current scroll line } } @@ -254,7 +265,6 @@ edit_single(Thread_Context *tctx, Models *models, Editing_File *file, batch.edit.text = string; batch.edit.range = range; - buffer_remeasure_starts(tctx, &file->state.buffer, &batch); edit_fix_markers(tctx, models, file, &batch); post_edit_call_hook(tctx, models, file, Ii64_size(range.first, string.size), range_size(range)); @@ -489,7 +499,6 @@ edit_batch(Thread_Context *tctx, Models *models, Editing_File *file, file_clear_layout_cache(file); - buffer_remeasure_starts(tctx, buffer, batch); edit_fix_markers(tctx, models, file, batch); post_edit_call_hook(tctx, models, file, new_range, range_size(old_range)); @@ -501,7 +510,7 @@ edit_batch(Thread_Context *tctx, Models *models, Editing_File *file, //////////////////////////////// - function Editing_File* +function Editing_File* create_file(Thread_Context *tctx, Models *models, String_Const_u8 file_name, Buffer_Create_Flag flags){ Editing_File *result = 0; diff --git a/4ed_file.cpp b/4ed_file.cpp index a201fe9b..c3c18d64 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -440,6 +440,21 @@ file_relative_xy_of_pos(Thread_Context *tctx, Models *models, Editing_File *file return(rect_center(rect)); } +function Rect_f32 +file_padded_box_of_pos(Thread_Context *tctx, Models *models, Editing_File *file, + Layout_Function *layout_func, f32 width, Face *face, + i64 base_line, i64 pos){ + i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1; + Layout_Item_List line = file_get_line_layout(tctx, models, file, layout_func, width, face, line_number); + Rect_f32 result = layout_padded_box_of_pos(line, pos); + + f32 y_difference = file_line_y_difference(tctx, models, file, layout_func, width, face, line_number, base_line); + result.y0 += y_difference; + result.y1 += y_difference; + + return(result); +} + internal Buffer_Point file_normalize_buffer_point(Thread_Context *tctx, Models *models, Editing_File *file, Layout_Function *layout_func, f32 width, Face *face, diff --git a/4ed_file.h b/4ed_file.h index 1eb82013..e292bbb2 100644 --- a/4ed_file.h +++ b/4ed_file.h @@ -24,15 +24,6 @@ struct File_Edit_Positions{ i64 cursor_pos; }; -// TODO(allen): do(replace Text_Effect with IM rendering over time) -struct Text_Effect{ - i64 start; - i64 end; - u32 color; - f32 seconds_down; - f32 seconds_max; -}; - struct Editing_File_Settings{ Layout_Function *layout_func; Face_ID face_id; @@ -40,6 +31,7 @@ struct Editing_File_Settings{ b8 is_initialized; b8 unimportant; b8 read_only; + b8 unkillable; b8 never_kill; }; @@ -62,8 +54,6 @@ struct Editing_File_State{ History history; i32 current_record_index; - Text_Effect paste_effect; - Dirty_State dirty; File_Save_State save_state; diff --git a/4ed_history.cpp b/4ed_history.cpp index d18e84b1..d292fdea 100644 --- a/4ed_history.cpp +++ b/4ed_history.cpp @@ -314,6 +314,7 @@ history__optimize_group(Arena *scratch, History *history, Record *record){ String_Const_u8 merged_forward = {}; String_Const_u8 merged_backward = {}; + i64 merged_first = 0; if (left->single.first + (i64)left->single.forward_text.size == right->single.first){ do_merge = true; merged_forward = push_u8_stringf(scratch, "%.*s%.*s", @@ -322,6 +323,7 @@ history__optimize_group(Arena *scratch, History *history, Record *record){ merged_backward = push_u8_stringf(scratch, "%.*s%.*s", string_expand(left->single.backward_text), string_expand(right->single.backward_text)); + merged_first = left->single.first; } else if (right->single.first + (i64)right->single.backward_text.size == left->single.first){ do_merge = true; @@ -331,6 +333,7 @@ history__optimize_group(Arena *scratch, History *history, Record *record){ merged_backward = push_u8_stringf(scratch, "%.*s%.*s", string_expand(right->single.backward_text), string_expand(left->single.backward_text)); + merged_first = right->single.first; } else{ break; @@ -340,6 +343,7 @@ history__optimize_group(Arena *scratch, History *history, Record *record){ end_temp(left->restore_point); left->edit_number = right->edit_number; + left->single.first = merged_first; left->single.forward_text = push_string_copy(history->arena, merged_forward); left->single.backward_text = push_string_copy(history->arena, merged_backward); diff --git a/4ed_layout.cpp b/4ed_layout.cpp index e64c12da..3b81bdbd 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -123,6 +123,16 @@ layout_get_first_open_panel(Layout *layout){ return(panel); } +internal Panel* +layout_get_last_open_panel(Layout *layout){ + Panel *panel = CastFromMember(Panel, node, layout->open_panels.prev); + if (panel != 0 && &panel->node == &layout->open_panels){ + panel = 0; + } + AssertImplies(panel != 0, panel->kind == PanelKind_Final); + return(panel); +} + internal Panel* layout_get_next_open_panel(Layout *layout, Panel *panel){ panel = CastFromMember(Panel, node, panel->node.next); @@ -289,7 +299,7 @@ layout_initialize(Arena *arena, Layout *layout){ Panel *panel = panels; layout->free_panels.next = &panel->node; panel->node.prev = &layout->free_panels; - for (i32 i = 1; i < MAX_VIEWS; i += 1, panel += 1){ + for (i32 i = 1; i < panel_alloc_count; i += 1, panel += 1){ panel[1].node.prev = &panel[0].node; panel[0].node.next = &panel[1].node; } diff --git a/4ed_string_matching.cpp b/4ed_string_matching.cpp index 4fd28843..2907d24b 100644 --- a/4ed_string_matching.cpp +++ b/4ed_string_matching.cpp @@ -125,7 +125,7 @@ find_all_matches_forward(Arena *arena, i32 maximum_output_count, jump_back_0: if (n + 1 == needle.size){ - String_Match_Flag flags = {}; + String_Match_Flag flags = 0; if (!(last_insensitive >= 0 && j <= (u64)last_insensitive && (u64)last_insensitive < j + needle.size)){ @@ -245,7 +245,7 @@ find_all_matches_backward(Arena *arena, i32 maximum_output_count, jump_back_0: if (n + 1 == needle.size){ - String_Match_Flag flags = {}; + String_Match_Flag flags = 0; if (!(last_insensitive < size && j >= last_insensitive && last_insensitive > j - (i64)needle.size)){ diff --git a/4ed_view.cpp b/4ed_view.cpp index dd7a25a2..3a25ea21 100644 --- a/4ed_view.cpp +++ b/4ed_view.cpp @@ -234,6 +234,17 @@ view_relative_xy_of_pos(Thread_Context *tctx, Models *models, View *view, return(rect_center(rect)); } +function Rect_f32 +view_padded_box_of_pos(Thread_Context *tctx, Models *models, View *view, + i64 base_line, i64 pos){ + Editing_File *file = view->file; + Face *face = file_get_face(models, file); + f32 width = view_width(tctx, models, view); + Layout_Function *layout_func = file_get_layout_func(file); + return(file_padded_box_of_pos(tctx, models, file, + layout_func, width, face, base_line, pos)); +} + internal Buffer_Point view_normalize_buffer_point(Thread_Context *tctx, Models *models, View *view, Buffer_Point point){ @@ -430,16 +441,6 @@ view_set_cursor_and_scroll(Thread_Context *tctx, Models *models, View *view, i64 view_set_edit_pos(view, edit_pos); } -internal void -view_post_paste_effect(View *view, f32 seconds, i64 start, i64 size, ARGB_Color color){ - Editing_File *file = view->file; - file->state.paste_effect.start = start; - file->state.paste_effect.end = start + size; - file->state.paste_effect.color = color; - file->state.paste_effect.seconds_down = seconds; - file->state.paste_effect.seconds_max = seconds; -} - //////////////////////////////// internal void @@ -518,7 +519,7 @@ co_handle_request(Models *models, Coroutine *co, Co_Out *out){ Face_Description *description = out->face_description; Face *face = font_set_new_face(&models->font_set, description); Co_In in = {}; - in.face_id = face->id; + in.face_id = (face != 0)?face->id:0; result = coroutine_run(&models->coroutines, co, &in, out); }break; diff --git a/4ed_working_set.cpp b/4ed_working_set.cpp index e51c6c40..7077007e 100644 --- a/4ed_working_set.cpp +++ b/4ed_working_set.cpp @@ -21,7 +21,8 @@ file_change_notification_check(Arena *scratch, Working_Set *working_set, Editing if (file->canon.name_size > 0 && !file->settings.unimportant){ String_Const_u8 name = SCu8(file->canon.name_space, file->canon.name_size); File_Attributes attributes = system_quick_file_attributes(scratch, name); - if (attributes.last_write_time > file->attributes.last_write_time){ + if ((attributes.last_write_time > file->attributes.last_write_time) || + (attributes.last_write_time == 0 && file->attributes.last_write_time > 0)){ if (file->state.save_state == FileSaveState_SavedWaitingForNotification){ file->state.save_state = FileSaveState_Normal; file->attributes = attributes; diff --git a/bin/4ed_build.cpp b/bin/4ed_build.cpp index 4362da1a..f76e9880 100644 --- a/bin/4ed_build.cpp +++ b/bin/4ed_build.cpp @@ -1,613 +1,718 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * ??.??.???? - * - * 4coder development build rule. - * - */ - -// TOP - -//#define FM_PRINT_COMMANDS - -#include "4coder_base_types.h" -#include "4coder_version.h" - -#include "4coder_base_types.cpp" -#include "4coder_malloc_allocator.cpp" - -#define FTECH_FILE_MOVING_IMPLEMENTATION -#include "4coder_file_moving.h" - - -// -// OS and compiler index -// - -enum{ - Platform_Windows, - Platform_Linux, - Platform_Mac, - // - Platform_COUNT, - Platform_None = Platform_COUNT, -}; - -char *platform_names[] = { - "win", - "linux", - "mac", -}; - -enum{ - Compiler_CL, - Compiler_GCC, - // - Compiler_COUNT, - Compiler_None = Compiler_COUNT, -}; - -char *compiler_names[] = { - "cl", - "gcc", -}; - -#if OS_WINDOWS -# define This_OS Platform_Windows -#elif OS_LINUX -# define This_OS Platform_Linux -#elif OS_MAC -# define This_OS Platform_Mac -#else -# error This platform is not enumerated. -#endif - -#if COMPILER_CL -# define This_Compiler Compiler_CL -#elif COMPILER_GCC -# define This_Compiler Compiler_GCC -#else -# error This compilers is not enumerated. -#endif - -// -// Universal directories -// - -#define BUILD_DIR "../build" -#define PACK_DIR "../distributions" -#define SITE_DIR "../site" - -#define FOREIGN "../4coder-non-source/foreign" -#define FOREIGN_WIN "..\\4coder-non-source\\foreign" - -char *includes[] = { "custom", FOREIGN "/freetype2", 0, }; - -// -// Platform layer file tables -// - -char *windows_platform_layer[] = { "platform_win32/win32_4ed.cpp", 0 }; -char *linux_platform_layer[] = { "platform_linux/linux_4ed.cpp", 0 }; -char *mac_platform_layer[] = { "platform_mac/mac_4ed.m", "platform_mac/mac_4ed.cpp", 0 }; - -char **platform_layers[Platform_COUNT] = { - windows_platform_layer, - linux_platform_layer , - mac_platform_layer , -}; - -char *windows_cl_platform_inc[] = { "platform_all", 0 }; -char *linux_gcc_platform_inc[] = { "platform_all", "platform_unix", 0 }; -char *mac_gcc_platform_inc[] = { "platform_all", "platform_unix", 0 }; - -char **platform_includes[Platform_COUNT][Compiler_COUNT] = { - {windows_cl_platform_inc, 0 }, - {0 , linux_gcc_platform_inc}, - {0 , mac_gcc_platform_inc }, -}; - -char *default_custom_target = "../code/custom/4coder_default_bindings.cpp"; - -// NOTE(allen): Architectures - -enum{ - Arch_X64, - Arch_X86, - - // - Arch_COUNT, - Arch_None = Arch_COUNT, -}; - -char *arch_names[] = { - "x64", - "x86", -}; - -// NOTE(allen): Build flags - -enum{ - OPTS = 0x1, - LIBS = 0x2, - ICON = 0x4, - SHARED_CODE = 0x8, - DEBUG_INFO = 0x10, - OPTIMIZATION = 0x20, - SUPER = 0x40, - INTERNAL = 0x80, - SHIP = 0x100, -}; - -internal char** -get_defines_from_flags(Arena *arena, u32 flags){ - char **result = 0; - if (HasFlag(flags, SHIP)){ - result = fm_list(arena, fm_list_one_item(arena, "SHIP_MODE"), result); - } - if (HasFlag(flags, INTERNAL)){ - result = fm_list(arena, fm_list_one_item(arena, "FRED_INTERNAL"), result); - } - if (HasFlag(flags, SUPER)){ - result = fm_list(arena, fm_list_one_item(arena, "FRED_SUPER"), result); - } - return(result); -} - -// -// build implementation: cl -// - -#if COMPILER_CL - -#define CL_OPTS \ -"-W4 -wd4310 -wd4100 -wd4201 -wd4505 -wd4996 " \ -"-wd4127 -wd4510 -wd4512 -wd4610 -wd4390 " \ -"-wd4611 -wd4189 -WX -GR- -EHa- -nologo -FC" - -#define CL_LIBS_X64 \ -"user32.lib winmm.lib gdi32.lib opengl32.lib comdlg32.lib " \ -FOREIGN_WIN "\\x64\\freetype.lib" - -#define CL_LIBS_X86 \ -"user32.lib winmm.lib gdi32.lib opengl32.lib comdlg32.lib " \ -FOREIGN_WIN "\\x86\\freetype.lib" - -#define CL_ICON "..\\4coder-non-source\\res\\icon.res" - -internal void -build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ - Temp_Dir temp = fm_pushdir(out_path); - - Build_Line line; - fm_init_build_line(&line); - - if (arch == Arch_X86){ - fm_add_to_line(line, "%s\\custom\\bin\\setup_cl_x86.bat &", code_path); - } - - fm_add_to_line(line, "cl"); - - if (flags & OPTS){ - fm_add_to_line(line, CL_OPTS); - } - - switch (arch){ - case Arch_X64: fm_add_to_line(line, "-DFTECH_64_BIT"); break; - case Arch_X86: fm_add_to_line(line, "-DFTECH_32_BIT"); break; - default: InvalidPath; - } - - fm_add_to_line(line, "-I%s", code_path); - if (inc_folders != 0){ - for (u32 i = 0; inc_folders[i] != 0; ++i){ - char *str = fm_str(arena, code_path, "/", inc_folders[i]); - fm_add_to_line(line, "-I%s", str); - } - } - - if (flags & LIBS){ - switch (arch){ - case Arch_X64: fm_add_to_line(line, CL_LIBS_X64); break; - case Arch_X86: fm_add_to_line(line, CL_LIBS_X86); break; - default: InvalidPath; - } - } - - if (flags & ICON){ - fm_add_to_line(line, CL_ICON); - } - - if (flags & DEBUG_INFO){ - fm_add_to_line(line, "-Zi"); - fm_add_to_line(line, "-DDO_CRAZY_EXPENSIVE_ASSERTS"); - } - - if (flags & OPTIMIZATION){ - fm_add_to_line(line, "-O2"); - } - - if (flags & SHARED_CODE){ - fm_add_to_line(line, "-LD"); - } - - if (defines != 0){ - for (u32 i = 0; defines[i] != 0; ++i){ - char *define_flag = fm_str(arena, "-D", defines[i]); - fm_add_to_line(line, "%s", define_flag); - } - } - - for (u32 i = 0; code_files[i]; ++i){ - fm_add_to_line(line, "\"%s\\%s\"", code_path, code_files[i]); - } - - fm_add_to_line(line, "-Fe%s", out_file); - - fm_add_to_line(line, "-link -INCREMENTAL:NO -RELEASE -PDBALTPATH:%%_PDB%%"); - switch (arch){ - case Arch_X64: fm_add_to_line(line, "-MACHINE:X64"); break; - case Arch_X86: fm_add_to_line(line, "-MACHINE:X86"); break; - default: InvalidPath; - } - - if (flags & DEBUG_INFO){ - fm_add_to_line(line, "-DEBUG"); - } - - if (flags & SHARED_CODE){ - Assert(exports != 0); - fm_add_to_line(line, "-OPT:REF"); - for (u32 i = 0; exports[i] != 0; ++i){ - char *str = fm_str(arena, "-EXPORT:", exports[i]); - fm_add_to_line(line, "%s", str); - } - } - else{ - fm_add_to_line(line, "-NODEFAULTLIB:library"); - } - - fm_finish_build_line(&line); - - //printf("%s\n", line.build_options); - systemf("%s", line.build_options); - fm_popdir(temp); - - fflush(stdout); -} - -// -// build implementation: gcc -// - -#elif COMPILER_GCC - -#if OS_LINUX - -# define GCC_OPTS \ -"-Wno-write-strings " \ -"-D_GNU_SOURCE -fPIC " \ -"-fno-threadsafe-statics -pthread " \ -"-Wno-unused-result" - -#define GCC_LIBS_COMMON \ -"-lX11 -lpthread -lm -lrt " \ -"-lGL -ldl -lXfixes -lfreetype -lfontconfig" - -#define GCC_LIBS_X64 GCC_LIBS_COMMON -#define GCC_LIBS_X86 GCC_LIBS_COMMON - -#elif OS_MAC - -# define GCC_OPTS \ -"-Wno-write-strings -Wno-deprecated-declarations " \ -"-Wno-comment -Wno-switch -Wno-null-dereference " \ -"-Wno-tautological-compare " \ -"-Wno-unused-result " - -#define GCC_LIBS_COMMON \ -"-framework Cocoa -framework QuartzCore " \ -"-framework CoreServices " \ -"-framework OpenGL -framework IOKit " - -#define GCC_LIBS_X64 GCC_LIBS_COMMON \ -FOREIGN "/x64/libfreetype-mac.a" - -#define GCC_LIBS_X86 GCC_LIBS_COMMON \ -FOREIGN "/x86/libfreetype-mac.a" - -#else -# error gcc options not set for this platform -#endif - -internal void -build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ - Build_Line line; - fm_init_build_line(&line); - - switch (arch){ - case Arch_X64: - fm_add_to_line(line, "-m64"); - fm_add_to_line(line, "-DFTECH_64_BIT"); break; - - case Arch_X86: - fm_add_to_line(line, "-m32"); - fm_add_to_line(line, "-DFTECH_32_BIT"); break; - - default: InvalidPath; - } - - if (flags & OPTS){ - fm_add_to_line(line, GCC_OPTS); - } - - fm_add_to_line(line, "-I%s", code_path); - if (inc_folders != 0){ - for (u32 i = 0; inc_folders[i] != 0; ++i){ - char *str = fm_str(arena, code_path, "/", inc_folders[i]); - fm_add_to_line(line, "-I%s", str); - } - } - - if (flags & DEBUG_INFO){ - fm_add_to_line(line, "-g -O0"); - } - - if (flags & OPTIMIZATION){ - fm_add_to_line(line, "-O3"); - } - - if (flags & SHARED_CODE){ - fm_add_to_line(line, "-shared"); - } - - if (defines != 0){ - for (u32 i = 0; defines[i]; ++i){ - char *define_flag = fm_str(arena, "-D", defines[i]); - fm_add_to_line(line, "%s", define_flag); - } - } - - fm_add_to_line(line, "-I\"%s\"", code_path); - for (u32 i = 0; code_files[i] != 0; ++i){ - fm_add_to_line(line, "\"%s/%s\"", code_path, code_files[i]); - } - - if (flags & LIBS){ - if (arch == Arch_X64){ - fm_add_to_line(line, GCC_LIBS_X64); - } - else if (arch == Arch_X86) - { - fm_add_to_line(line, GCC_LIBS_X86); - } - } - - fm_finish_build_line(&line); - - Temp_Dir temp = fm_pushdir(out_path); - systemf("g++ %s -o %s", line.build_options, out_file); - fm_popdir(temp); -} - -#else -# error build function not defined for this compiler -#endif - -internal void -build(Arena *arena, u32 flags, u32 arch, char *code_path, char *code_file, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ - char **code_files = fm_list_one_item(arena, code_file); - build(arena, flags, arch, code_path, code_files, out_path, out_file, defines, exports, inc_folders); -} - -internal void -build_and_run(Arena *arena, char *cdir, char *filename, char *name, u32 flags){ - char *dir = fm_str(arena, BUILD_DIR); - - { - char *file = fm_str(arena, filename); - BEGIN_TIME_SECTION(); - build(arena, flags, Arch_X64, cdir, file, dir, name, get_defines_from_flags(arena, flags), 0, includes); - END_TIME_SECTION(fm_str(arena, "build ", name)); - } - - if (prev_error == 0){ - char *cmd = fm_str(arena, dir, "/", name); - BEGIN_TIME_SECTION(); - fm_execute_in_dir(cdir, cmd, 0); - END_TIME_SECTION(fm_str(arena, "run ", name)); - } -} - -internal void -buildsuper(Arena *arena, char *cdir, char *file, u32 arch){ - printf("BUILDSUPER: cdir: %s; file: %s; arch: %u\n", cdir, file, arch); - - BEGIN_TIME_SECTION(); - Temp_Dir temp = fm_pushdir(fm_str(arena, BUILD_DIR)); - - char *build_script = fm_str(arena, "custom/bin/buildsuper_", arch_names[arch], BAT); - - char *build_command = fm_str(arena, "\"", cdir, "/", build_script, "\" \"", file, "\""); - if (This_OS == Platform_Windows){ - build_command = fm_str(arena, "call ", build_command); - } - systemf("%s", build_command); - - fm_popdir(temp); - END_TIME_SECTION("build custom"); - fflush(stdout); -} - -internal void -build_main(Arena *arena, char *cdir, b32 update_local_theme, u32 flags, u32 arch){ - char *dir = fm_str(arena, BUILD_DIR); - - { - char *file = fm_str(arena, "4ed_app_target.cpp"); - char **exports = fm_list_one_item(arena, "app_get_functions"); - - char **build_includes = includes; - - BEGIN_TIME_SECTION(); - build(arena, OPTS | SHARED_CODE | flags, arch, cdir, file, dir, "4ed_app" DLL, get_defines_from_flags(arena, flags), exports, build_includes); - END_TIME_SECTION("build 4ed_app"); - } - - { - BEGIN_TIME_SECTION(); - char **inc = (char**)fm_list(arena, includes, platform_includes[This_OS][This_Compiler]); - build(arena, OPTS | LIBS | ICON | flags, arch, cdir, platform_layers[This_OS], dir, "4ed", get_defines_from_flags(arena, flags), 0, inc); - END_TIME_SECTION("build 4ed"); - } - - if (update_local_theme){ - BEGIN_TIME_SECTION(); - char *themes_folder = fm_str(arena, "../build/themes"); - char *source_themes_folder = fm_str(arena, "ship_files/themes"); - fm_clear_folder(themes_folder); - fm_make_folder_if_missing(arena, themes_folder); - fm_copy_all(source_themes_folder, themes_folder); - END_TIME_SECTION("move files"); - } - - fflush(stdout); -} - -internal void -standard_build(Arena *arena, char *cdir, u32 flags, u32 arch){ - buildsuper(arena, cdir, fm_str(arena, default_custom_target), arch); - build_main(arena, cdir, true, flags, arch); -} - -internal char* -get_4coder_dist_name(Arena *arena, u32 platform, char *tier, u32 arch){ - char *name = fm_str(arena, "4coder-" MAJOR_STR "-" MINOR_STR "-" PATCH_STR "-", tier); - if (platform != Platform_None){ - name = fm_str(arena, name, "-", platform_names[platform]); - } - if (arch != Arch_None){ - name = fm_str(arena, name, "-", arch_names[arch]); - } - return(name); -} - -enum{ - Tier_Demo, - Tier_Super, - Tier_COUNT, -}; - -internal void -package(Arena *arena, char *cdir){ - // NOTE(allen): meta - char *build_dir = fm_str(arena, BUILD_DIR); - char *pack_dir = fm_str(arena, PACK_DIR); - char *dist_files[3]; - dist_files[0] = fm_str(arena, "../4coder-non-source/dist_files"); - dist_files[1] = fm_str(arena, "ship_files"); - dist_files[2] = fm_str(arena, "ship_files_super"); - - printf("build dir: %s\n", build_dir); - printf("pack dir: %s\n", pack_dir); - printf("dist files: %s, %s, %s\n", dist_files[0], dist_files[1], dist_files[2]); - fflush(stdout); - - char *tier_names[] = { "demo", "super", }; - u32 base_flags = SHIP | DEBUG_INFO | OPTIMIZATION; - u32 tier_flags[] = { 0, SUPER, }; - - fm_make_folder_if_missing(arena, pack_dir); - - for (u32 i = 0; i < Tier_COUNT; i += 1){ - char *tier_name = tier_names[i]; - u32 flags = base_flags | tier_flags[i]; - - Temp_Memory temp = begin_temp(arena); - char *current_dist_tier = fm_str(arena, ".." SLASH "current_dist_", tier_name); - - for (u32 arch = 0; arch < Arch_COUNT; ++arch){ - char *arch_name = arch_names[arch]; - char *parent_dir = fm_str(arena, current_dist_tier, "_", arch_name); - char *dir = fm_str(arena, parent_dir, SLASH "4coder"); - char *zip_dir = fm_str(arena, pack_dir, SLASH, tier_name, "_", arch_name); - - printf("\nbuild: %s_%s\n", tier_name, arch_name); - printf("parent_dir: %s\n", parent_dir); - printf("dir: %s\n", dir); - printf("zip_dir: %s\n", zip_dir); - fflush(stdout); - - buildsuper(arena, cdir, fm_str(arena, default_custom_target), arch); - build_main(arena, cdir, false, flags, arch); - - fm_make_folder_if_missing(arena, parent_dir); - fm_clear_folder(parent_dir); - fm_make_folder_if_missing(arena, dir); - fm_copy_file(fm_str(arena, build_dir, "/4ed" EXE), fm_str(arena, dir, "/4ed" EXE)); - fm_copy_file(fm_str(arena, build_dir, "/4ed_app" DLL), fm_str(arena, dir, "/4ed_app" DLL)); - fm_copy_file(fm_str(arena, build_dir, "/custom_4coder" DLL), fm_str(arena, dir, "/custom_4coder" DLL)); - - i32 dist_file_count = ArrayCount(dist_files); - if (i == Tier_Demo){ - dist_file_count -= 1; - } - - for (i32 j = 0; j < dist_file_count; j += 1){ - fm_copy_all(dist_files[j], dir); - } - - if (i == Tier_Super){ - char *custom_src_dir = fm_str(arena, cdir, SLASH, "custom"); - char *custom_dst_dir = fm_str(arena, dir, SLASH, "custom"); - fm_make_folder_if_missing(arena, custom_dst_dir); - fm_copy_all(custom_src_dir, custom_dst_dir); - } - - char *dist_name = get_4coder_dist_name(arena, This_OS, tier_name, arch); - char *zip_name = fm_str(arena, zip_dir, SLASH, dist_name, ".zip"); - fm_make_folder_if_missing(arena, zip_dir); - fm_zip(parent_dir, "4coder", zip_name); - } - - end_temp(temp); - } -} - -int main(int argc, char **argv){ - Arena arena = fm_init_system(); - - char cdir[256]; - BEGIN_TIME_SECTION(); - i32 n = fm_get_current_directory(cdir, sizeof(cdir)); - Assert(n < sizeof(cdir)); - END_TIME_SECTION("current directory"); - - u32 flags = SUPER; - u32 arch = Arch_X64; - #if defined(DEV_BUILD) || defined(DEV_BUILD_X86) - flags |= DEBUG_INFO | INTERNAL; - #endif -#if defined(OPT_BUILD) || defined(OPT_BUILD_X86) - flags |= OPTIMIZATION; - #endif -#if defined(DEV_BUILD_X86) || defined(OPT_BUILD_X86) - arch = Arch_X86; -#endif - -#if defined(DEV_BUILD) || defined(OPT_BUILD) || defined(DEV_BUILD_X86) -standard_build(&arena, cdir, flags, arch); - -#elif defined(PACKAGE) - package(&arena, cdir); - -#else -# error No build type specified. -#endif - - return(error_state); -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * ??.??.???? + * + * 4coder development build rule. + * + */ + +// TOP + +//#define FM_PRINT_COMMANDS + +#include "4coder_base_types.h" +#include "4coder_version.h" + +#include "4coder_base_types.cpp" +#include "4coder_malloc_allocator.cpp" + +#define FTECH_FILE_MOVING_IMPLEMENTATION +#include "4coder_file_moving.h" + + +// +// OS and compiler index +// + +enum{ + Platform_Windows, + Platform_Linux, + Platform_Mac, + // + Platform_COUNT, + Platform_None = Platform_COUNT, +}; + +char *platform_names[] = { + "win", + "linux", + "mac", +}; + +enum{ + Compiler_CL, + Compiler_GCC, + Compiler_Clang, + // + Compiler_COUNT, + Compiler_None = Compiler_COUNT, +}; + +char *compiler_names[] = { + "cl", + "gcc", + "clang", +}; + +#if OS_WINDOWS +# define This_OS Platform_Windows +#elif OS_LINUX +# define This_OS Platform_Linux +#elif OS_MAC +# define This_OS Platform_Mac +#else +# error This platform is not enumerated. +#endif + +#if COMPILER_CL +# define This_Compiler Compiler_CL +#elif COMPILER_GCC +# define This_Compiler Compiler_GCC +#elif COMPILER_CLANG +# define This_Compiler Compiler_Clang +#else +# error This compilers is not enumerated. +#endif + +// +// Universal directories +// + +#define BUILD_DIR "../build" +#define PACK_DIR "../distributions" +#define SITE_DIR "../site" + +#define FOREIGN "../4coder-non-source/foreign" +#define FOREIGN_WIN "..\\4coder-non-source\\foreign" + +char *includes[] = { "custom", FOREIGN "/freetype2", 0, }; + +// +// Platform layer file tables +// + +char *windows_platform_layer[] = { "platform_win32/win32_4ed.cpp", 0 }; +char *linux_platform_layer[] = { "platform_linux/linux_4ed.cpp", 0 }; +char *mac_platform_layer[] = { "platform_mac/mac_4ed.mm", 0 }; + +char **platform_layers[Platform_COUNT] = { + windows_platform_layer, + linux_platform_layer , + mac_platform_layer , +}; + +char *windows_cl_platform_inc[] = { "platform_all", 0 }; +char *linux_gcc_platform_inc[] = { "platform_all", "platform_unix", 0 }; + +char *mac_clang_platform_inc[] = { "platform_all", "platform_unix", 0 }; + +char **platform_includes[Platform_COUNT][Compiler_COUNT] = { + {windows_cl_platform_inc, 0 , 0}, + {0 , linux_gcc_platform_inc, 0}, + {0 , 0 , mac_clang_platform_inc}, +}; + +char *default_custom_target = "../code/custom/4coder_default_bindings.cpp"; + +// NOTE(allen): Architectures + +enum{ + Arch_X64, + Arch_X86, + + // + Arch_COUNT, + Arch_None = Arch_COUNT, +}; + +char *arch_names[] = { + "x64", + "x86", +}; + +// NOTE(allen): Build flags + +enum{ + OPTS = 0x1, + LIBS = 0x2, + ICON = 0x4, + SHARED_CODE = 0x8, + DEBUG_INFO = 0x10, + OPTIMIZATION = 0x20, + SUPER = 0x40, + INTERNAL = 0x80, + SHIP = 0x100, +}; + +internal char** +get_defines_from_flags(Arena *arena, u32 flags){ + char **result = 0; + if (HasFlag(flags, SHIP)){ + result = fm_list(arena, fm_list_one_item(arena, "SHIP_MODE"), result); + } + if (HasFlag(flags, INTERNAL)){ + result = fm_list(arena, fm_list_one_item(arena, "FRED_INTERNAL"), result); + } + if (HasFlag(flags, SUPER)){ + result = fm_list(arena, fm_list_one_item(arena, "FRED_SUPER"), result); + } + return(result); +} + +// +// build implementation: cl +// + +#if COMPILER_CL + +#define CL_OPTS \ +"-W4 -wd4310 -wd4100 -wd4201 -wd4505 -wd4996 " \ +"-wd4127 -wd4510 -wd4512 -wd4610 -wd4390 " \ +"-wd4611 -wd4189 -WX -GR- -EHa- -nologo -FC" + +#define CL_LIBS_X64 \ +"user32.lib winmm.lib gdi32.lib opengl32.lib comdlg32.lib " \ +FOREIGN_WIN "\\x64\\freetype.lib" + +#define CL_LIBS_X86 \ +"user32.lib winmm.lib gdi32.lib opengl32.lib comdlg32.lib " \ +FOREIGN_WIN "\\x86\\freetype.lib" + +#define CL_ICON "..\\4coder-non-source\\res\\icon.res" + +internal void +build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ + Temp_Dir temp = fm_pushdir(out_path); + + Build_Line line; + fm_init_build_line(&line); + + if (arch == Arch_X86){ + fm_add_to_line(line, "%s\\custom\\bin\\setup_cl_x86.bat &", code_path); + } + + fm_add_to_line(line, "cl"); + + if (flags & OPTS){ + fm_add_to_line(line, CL_OPTS); + } + + switch (arch){ + case Arch_X64: fm_add_to_line(line, "-DFTECH_64_BIT"); break; + case Arch_X86: fm_add_to_line(line, "-DFTECH_32_BIT"); break; + default: InvalidPath; + } + + fm_add_to_line(line, "-I%s", code_path); + if (inc_folders != 0){ + for (u32 i = 0; inc_folders[i] != 0; ++i){ + char *str = fm_str(arena, code_path, "/", inc_folders[i]); + fm_add_to_line(line, "-I%s", str); + } + } + + if (flags & LIBS){ + switch (arch){ + case Arch_X64: fm_add_to_line(line, CL_LIBS_X64); break; + case Arch_X86: fm_add_to_line(line, CL_LIBS_X86); break; + default: InvalidPath; + } + } + + if (flags & ICON){ + fm_add_to_line(line, CL_ICON); + } + + if (flags & DEBUG_INFO){ + fm_add_to_line(line, "-Zi"); + fm_add_to_line(line, "-DDO_CRAZY_EXPENSIVE_ASSERTS"); + } + + if (flags & OPTIMIZATION){ + fm_add_to_line(line, "-O2"); + } + + if (flags & SHARED_CODE){ + fm_add_to_line(line, "-LD"); + } + + if (defines != 0){ + for (u32 i = 0; defines[i] != 0; ++i){ + char *define_flag = fm_str(arena, "-D", defines[i]); + fm_add_to_line(line, "%s", define_flag); + } + } + + for (u32 i = 0; code_files[i]; ++i){ + fm_add_to_line(line, "\"%s\\%s\"", code_path, code_files[i]); + } + + fm_add_to_line(line, "-Fe%s", out_file); + + fm_add_to_line(line, "-link -INCREMENTAL:NO -RELEASE -PDBALTPATH:%%_PDB%%"); + switch (arch){ + case Arch_X64: fm_add_to_line(line, "-MACHINE:X64"); break; + case Arch_X86: fm_add_to_line(line, "-MACHINE:X86"); break; + default: InvalidPath; + } + + if (flags & DEBUG_INFO){ + fm_add_to_line(line, "-DEBUG"); + } + + if (flags & SHARED_CODE){ + Assert(exports != 0); + fm_add_to_line(line, "-OPT:REF"); + for (u32 i = 0; exports[i] != 0; ++i){ + char *str = fm_str(arena, "-EXPORT:", exports[i]); + fm_add_to_line(line, "%s", str); + } + } + else{ + fm_add_to_line(line, "-NODEFAULTLIB:library"); + } + + fm_finish_build_line(&line); + + //printf("%s\n", line.build_options); + systemf("%s", line.build_options); + fm_popdir(temp); + + fflush(stdout); +} + +// +// build implementation: gcc +// + +#elif COMPILER_GCC + +#if OS_LINUX + +# define GCC_OPTS \ +"-Wno-write-strings " \ +"-D_GNU_SOURCE -fPIC " \ +"-fno-threadsafe-statics -pthread " \ +"-Wno-unused-result" + +#define GCC_LIBS_COMMON \ +"-lX11 -lpthread -lm -lrt " \ +"-lGL -ldl -lXfixes -lfreetype -lfontconfig" + +#define GCC_LIBS_X64 GCC_LIBS_COMMON +#define GCC_LIBS_X86 GCC_LIBS_COMMON + +#else +# error gcc options not set for this platform +#endif + +internal void +build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ + Build_Line line; + fm_init_build_line(&line); + + switch (arch){ + case Arch_X64: + fm_add_to_line(line, "-m64"); + fm_add_to_line(line, "-DFTECH_64_BIT"); break; + + case Arch_X86: + fm_add_to_line(line, "-m32"); + fm_add_to_line(line, "-DFTECH_32_BIT"); break; + + default: InvalidPath; + } + + if (flags & OPTS){ + fm_add_to_line(line, GCC_OPTS); + } + + fm_add_to_line(line, "-I%s", code_path); + if (inc_folders != 0){ + for (u32 i = 0; inc_folders[i] != 0; ++i){ + char *str = fm_str(arena, code_path, "/", inc_folders[i]); + fm_add_to_line(line, "-I%s", str); + } + } + + if (flags & DEBUG_INFO){ + fm_add_to_line(line, "-g -O0"); + } + + if (flags & OPTIMIZATION){ + fm_add_to_line(line, "-O3"); + } + + if (flags & SHARED_CODE){ + fm_add_to_line(line, "-shared"); + } + + if (defines != 0){ + for (u32 i = 0; defines[i]; ++i){ + char *define_flag = fm_str(arena, "-D", defines[i]); + fm_add_to_line(line, "%s", define_flag); + } + } + + fm_add_to_line(line, "-I\"%s\"", code_path); + for (u32 i = 0; code_files[i] != 0; ++i){ + fm_add_to_line(line, "\"%s/%s\"", code_path, code_files[i]); + } + + if (flags & LIBS){ + if (arch == Arch_X64){ + fm_add_to_line(line, GCC_LIBS_X64); + } + else if (arch == Arch_X86) + { + fm_add_to_line(line, GCC_LIBS_X86); + } + } + + fm_finish_build_line(&line); + + Temp_Dir temp = fm_pushdir(out_path); + systemf("g++ %s -o %s", line.build_options, out_file); + fm_popdir(temp); +} + +#elif COMPILER_CLANG + +#if OS_MAC + +# define CLANG_OPTS \ +"-Wno-write-strings -Wno-deprecated-declarations " \ +"-Wno-comment -Wno-switch -Wno-null-dereference " \ +"-Wno-tautological-compare -Wno-unused-result " \ +"-Wno-missing-declarations -Wno-nullability-completeness " \ +"-std=c++11 " + +#define CLANG_LIBS_COMMON \ +"-framework Cocoa -framework QuartzCore " \ +"-framework CoreServices " \ +"-framework OpenGL -framework IOKit -framework Metal -framework MetalKit " + +#define CLANG_LIBS_X64 CLANG_LIBS_COMMON \ +FOREIGN "/x64/libfreetype-mac.a" + +#define CLANG_LIBS_X86 CLANG_LIBS_COMMON \ +FOREIGN "/x86/libfreetype-mac.a" + +#else +# error clang options not set for this platform +#endif + +internal void +build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ + Build_Line line; + fm_init_build_line(&line); + + switch (arch){ + case Arch_X64: + fm_add_to_line(line, "-m64"); + fm_add_to_line(line, "-DFTECH_64_BIT"); break; + + case Arch_X86: + fm_add_to_line(line, "-m32"); + fm_add_to_line(line, "-DFTECH_32_BIT"); break; + + default: InvalidPath; + } + + if (flags & OPTS){ + fm_add_to_line(line, CLANG_OPTS); + } + + fm_add_to_line(line, "-I%s", code_path); + if (inc_folders != 0){ + for (u32 i = 0; inc_folders[i] != 0; ++i){ + char *str = fm_str(arena, code_path, "/", inc_folders[i]); + fm_add_to_line(line, "-I%s", str); + } + } + + if (flags & DEBUG_INFO){ + fm_add_to_line(line, "-g -O0"); + } + + if (flags & OPTIMIZATION){ + fm_add_to_line(line, "-O3"); + } + + if (flags & SHARED_CODE){ + fm_add_to_line(line, "-shared"); + } + + if (defines != 0){ + for (u32 i = 0; defines[i]; ++i){ + char *define_flag = fm_str(arena, "-D", defines[i]); + fm_add_to_line(line, "%s", define_flag); + } + } + + fm_add_to_line(line, "-I\"%s\"", code_path); + for (u32 i = 0; code_files[i] != 0; ++i){ + fm_add_to_line(line, "\"%s/%s\"", code_path, code_files[i]); + } + + if (flags & LIBS){ + if (arch == Arch_X64){ + fm_add_to_line(line, CLANG_LIBS_X64); + } + else if (arch == Arch_X86) + { + fm_add_to_line(line, CLANG_LIBS_X86); + } + } + + fm_finish_build_line(&line); + + Temp_Dir temp = fm_pushdir(out_path); + + // systemf("clang++ %s -E -o %s", line.build_options, "4ed.i"); + systemf("clang++ %s -o %s", line.build_options, out_file); + fm_popdir(temp); +} + +#else +# error build function not defined for this compiler +#endif + +internal void +build(Arena *arena, u32 flags, u32 arch, char *code_path, char *code_file, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ + char **code_files = fm_list_one_item(arena, code_file); + build(arena, flags, arch, code_path, code_files, out_path, out_file, defines, exports, inc_folders); +} + +internal void +build_and_run(Arena *arena, char *cdir, char *filename, char *name, u32 flags){ + char *dir = fm_str(arena, BUILD_DIR); + + { + char *file = fm_str(arena, filename); + BEGIN_TIME_SECTION(); + build(arena, flags, Arch_X64, cdir, file, dir, name, get_defines_from_flags(arena, flags), 0, includes); + END_TIME_SECTION(fm_str(arena, "build ", name)); + } + + if (prev_error == 0){ + char *cmd = fm_str(arena, dir, "/", name); + BEGIN_TIME_SECTION(); + fm_execute_in_dir(cdir, cmd, 0); + END_TIME_SECTION(fm_str(arena, "run ", name)); + } +} + +internal void +buildsuper(Arena *arena, char *cdir, char *file, u32 arch){ + printf("BUILDSUPER: cdir: %s; file: %s; arch: %u\n", cdir, file, arch); + + BEGIN_TIME_SECTION(); + Temp_Dir temp = fm_pushdir(fm_str(arena, BUILD_DIR)); + + char *build_script_postfix = ""; + if (This_OS == Platform_Mac){ + build_script_postfix = "-mac"; + } + char *build_script = fm_str(arena, "custom/bin/buildsuper_", arch_names[arch], build_script_postfix, BAT); + + char *build_command = fm_str(arena, "\"", cdir, "/", build_script, "\" \"", file, "\""); + if (This_OS == Platform_Windows){ + build_command = fm_str(arena, "call ", build_command); + } + systemf("%s", build_command); + + fm_popdir(temp); + END_TIME_SECTION("build custom"); + fflush(stdout); +} + +internal void +build_main(Arena *arena, char *cdir, b32 update_local_theme, u32 flags, u32 arch){ + char *dir = fm_str(arena, BUILD_DIR); + + { + char *file = fm_str(arena, "4ed_app_target.cpp"); + char **exports = fm_list_one_item(arena, "app_get_functions"); + + char **build_includes = includes; + + BEGIN_TIME_SECTION(); + build(arena, OPTS | SHARED_CODE | flags, arch, cdir, file, dir, "4ed_app" DLL, get_defines_from_flags(arena, flags), exports, build_includes); + END_TIME_SECTION("build 4ed_app"); + } + + { + BEGIN_TIME_SECTION(); + char **inc = (char**)fm_list(arena, includes, platform_includes[This_OS][This_Compiler]); + build(arena, OPTS | LIBS | ICON | flags, arch, cdir, platform_layers[This_OS], dir, "4ed", get_defines_from_flags(arena, flags), 0, inc); + END_TIME_SECTION("build 4ed"); + } + + if (update_local_theme){ + BEGIN_TIME_SECTION(); + char *themes_folder = fm_str(arena, "../build/themes"); + char *source_themes_folder = fm_str(arena, "ship_files/themes"); + fm_clear_folder(themes_folder); + fm_make_folder_if_missing(arena, themes_folder); + fm_copy_all(source_themes_folder, themes_folder); + END_TIME_SECTION("move files"); + } + + fflush(stdout); +} + +internal void +standard_build(Arena *arena, char *cdir, u32 flags, u32 arch){ + buildsuper(arena, cdir, fm_str(arena, default_custom_target), arch); + build_main(arena, cdir, true, flags, arch); +} + +internal char* +get_4coder_dist_name(Arena *arena, u32 platform, char *tier, u32 arch){ + char *name = fm_str(arena, "4coder-" MAJOR_STR "-" MINOR_STR "-" PATCH_STR "-", tier); + if (platform != Platform_None){ + name = fm_str(arena, name, "-", platform_names[platform]); + } + if (arch != Arch_None){ + name = fm_str(arena, name, "-", arch_names[arch]); + } + return(name); +} + +enum{ + Tier_Demo, + Tier_Super, + Tier_COUNT, +}; + +function void +package_for_arch(Arena *arena, u32 arch, char *cdir, char *build_dir, char *pack_dir, i32 tier, char *tier_name, char *current_dist_tier, u32 flags, char** dist_files, i32 dist_file_count){ + char *arch_name = arch_names[arch]; + char *parent_dir = fm_str(arena, current_dist_tier, "_", arch_name); + char *dir = fm_str(arena, parent_dir, SLASH "4coder"); + char *zip_dir = fm_str(arena, pack_dir, SLASH, tier_name, "_", arch_name); + + printf("\nbuild: %s_%s\n", tier_name, arch_name); + printf("parent_dir: %s\n", parent_dir); + printf("dir: %s\n", dir); + printf("zip_dir: %s\n", zip_dir); + fflush(stdout); + + buildsuper(arena, cdir, fm_str(arena, default_custom_target), arch); + build_main(arena, cdir, false, flags, arch); + + fm_clear_folder(parent_dir); + fm_make_folder_if_missing(arena, parent_dir); + + fm_make_folder_if_missing(arena, dir); + fm_copy_file(fm_str(arena, build_dir, "/4ed" EXE), fm_str(arena, dir, "/4ed" EXE)); + fm_copy_file(fm_str(arena, build_dir, "/4ed_app" DLL), fm_str(arena, dir, "/4ed_app" DLL)); + fm_copy_file(fm_str(arena, build_dir, "/custom_4coder" DLL), fm_str(arena, dir, "/custom_4coder" DLL)); + + if (tier == Tier_Demo){ + dist_file_count -= 1; + } + + for (i32 j = 0; j < dist_file_count; j += 1){ + fm_copy_all(dist_files[j], dir); + } + + if (tier == Tier_Super){ + char *custom_src_dir = fm_str(arena, cdir, SLASH, "custom"); + char *custom_dst_dir = fm_str(arena, dir, SLASH, "custom"); + // HACK(yuval): make_folder_if_missing seems to cause a second custom folder to be created inside the custom folder on macOS. + //if (This_OS != Platform_Mac){ + fm_make_folder_if_missing(arena, custom_dst_dir); + //} + fm_copy_all(custom_src_dir, custom_dst_dir); + } + + char *dist_name = get_4coder_dist_name(arena, This_OS, tier_name, arch); + char *zip_name = fm_str(arena, zip_dir, SLASH, dist_name, ".zip"); + fm_make_folder_if_missing(arena, zip_dir); + fm_zip(parent_dir, "4coder", zip_name); +} + +internal void +package(Arena *arena, char *cdir){ + // NOTE(allen): meta + char *build_dir = fm_str(arena, BUILD_DIR); + char *pack_dir = fm_str(arena, PACK_DIR); + char *dist_files[3]; + dist_files[0] = fm_str(arena, "../4coder-non-source/dist_files"); + dist_files[1] = fm_str(arena, "ship_files"); + dist_files[2] = fm_str(arena, "ship_files_super"); + + printf("build dir: %s\n", build_dir); + printf("pack dir: %s\n", pack_dir); + printf("dist files: %s, %s, %s\n", dist_files[0], dist_files[1], dist_files[2]); + fflush(stdout); + + char *tier_names[] = { "demo", "super", }; + u32 base_flags = SHIP | DEBUG_INFO | OPTIMIZATION; + u32 tier_flags[] = { 0, SUPER, }; + + fm_make_folder_if_missing(arena, pack_dir); + + for (u32 i = 0; i < Tier_COUNT; i += 1){ + char *tier_name = tier_names[i]; + u32 flags = base_flags | tier_flags[i]; + + Temp_Memory temp = begin_temp(arena); + char *current_dist_tier = fm_str(arena, ".." SLASH "current_dist_", tier_name); + + u32 arch_count = Arch_COUNT; + u32 arch_array[2] = { + Arch_X64, + Arch_X86, + }; + if (This_OS == Platform_Mac){ + arch_count = 1; + } + for (u32 arch_ind = 0; arch_ind < arch_count; arch_ind += 1){ + u32 arch = arch_array[arch_ind]; + package_for_arch(arena, arch, cdir, build_dir, pack_dir, i, tier_name, current_dist_tier, flags, dist_files, ArrayCount(dist_files)); + } + + end_temp(temp); + } +} + +int main(int argc, char **argv){ + Arena arena = fm_init_system(); + + char cdir[256]; + BEGIN_TIME_SECTION(); + i32 n = fm_get_current_directory(cdir, sizeof(cdir)); + Assert(n < sizeof(cdir)); + END_TIME_SECTION("current directory"); + + u32 flags = SUPER; + u32 arch = Arch_X64; +#if defined(DEV_BUILD) || defined(DEV_BUILD_X86) + flags |= DEBUG_INFO | INTERNAL; +#endif +#if defined(OPT_BUILD) || defined(OPT_BUILD_X86) + flags |= OPTIMIZATION; +#endif +#if defined(DEV_BUILD_X86) || defined(OPT_BUILD_X86) + arch = Arch_X86; +#endif + +#if defined(DEV_BUILD) || defined(OPT_BUILD) || defined(DEV_BUILD_X86) || defined(OPT_BUILD_X86) + standard_build(&arena, cdir, flags, arch); + +#elif defined(PACKAGE) + package(&arena, cdir); + +#else +# error No build type specified. +#endif + + return(error_state); +} + +// BOTTOM + diff --git a/bin/build-mac.sh b/bin/build-mac.sh new file mode 100755 index 00000000..83062702 --- /dev/null +++ b/bin/build-mac.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# If any command errors, stop the script +set -e + +# Set up directories (mirrors build.bat) +# NOTE(yuval): Replaced readlink with realpath which works for both macOS and Linux +ME="$(realpath "$0")" +LOCATION="$(dirname "$ME")" +SRC_ROOT="$(dirname "$LOCATION")" +PROJECT_ROOT="$(dirname "$SRC_ROOT")" +if [ ! -d "$PROJECT_ROOT/build" ]; then +mkdir "$PROJECT_ROOT/build" +fi +BUILD_ROOT="$PROJECT_ROOT/build" +BIN_ROOT="$SRC_ROOT/bin" +CUSTOM_ROOT="$SRC_ROOT/custom" +CUSTOM_BIN="$CUSTOM_ROOT/bin" + +# Get the build mode +BUILD_MODE="$1" +if [ -z "$BUILD_MODE" ]; then + BUILD_MODE="-DDEV_BUILD" +fi + +# Get the OS specific flags +chmod +rx "$BIN_ROOT/detect_os.sh" +os=$("$BIN_ROOT/detect_os.sh") + +if [[ "$os" == "linux" ]]; then +WARNINGS="-Wno-write-strings -Wno-comment" +elif [[ "$os" == "mac" ]]; then +WARNINGS="-Wno-write-strings -Wno-comment -Wno-null-dereference -Wno-logical-op-parentheses -Wno-switch" +fi + +FLAGS="-D_GNU_SOURCE -fPIC -fpermissive $BUILD_MODE" +INCLUDES="-I$SRC_ROOT -I$CUSTOM_ROOT" + +# Execute +clang++ $WARNINGS $FLAGS $INCLUDES "$BIN_ROOT/4ed_build.cpp" -g -o "$BUILD_ROOT/build" +pushd "$SRC_ROOT" +"$BUILD_ROOT/build" +popd diff --git a/bin/build_optimized.bat b/bin/build_optimized.bat index 6e8741f6..4069b540 100644 --- a/bin/build_optimized.bat +++ b/bin/build_optimized.bat @@ -1,3 +1,3 @@ @echo off -call build.bat /DOPT_BUILD \ No newline at end of file +call bin\build.bat /DOPT_BUILD diff --git a/bin/build_x86-mac.sh b/bin/build_x86-mac.sh new file mode 100644 index 00000000..3642eddf --- /dev/null +++ b/bin/build_x86-mac.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +./build.sh -DDEV_BUILD_X86 + + diff --git a/bin/itchio_push_all.sh b/bin/itchio_push_all.sh index cc37cd27..bb606ddf 100644 --- a/bin/itchio_push_all.sh +++ b/bin/itchio_push_all.sh @@ -1,7 +1,5 @@ #!/bin/sh -#todo rewrite this as a build.cpp script - if [ "$#" -lt "3" ] then echo need 3 parameters diff --git a/bin/itchio_push_mac.sh b/bin/itchio_push_mac.sh new file mode 100755 index 00000000..cf5a7d5b --- /dev/null +++ b/bin/itchio_push_mac.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +if [ "$#" -lt "3" ] +then +echo need 3 parameters +exit +else + +fake=$1 +maj=$2 +min=$3 + +vr=$fake.$maj.$min +fv=$fake-$maj-$min + +flags="--fix-permissions --userversion=$vr" +dir=../distributions + +butler push $flags $dir/demo_x64/4coder-$fv-demo-mac-x64.zip 4coder/4coder:mac-x64-demo +butler push $flags $dir/super_x64/4coder-$fv-super-mac-x64.zip 4coder/4coder:mac-x64 + +fi diff --git a/bin/package-mac.sh b/bin/package-mac.sh new file mode 100755 index 00000000..92eb8a24 --- /dev/null +++ b/bin/package-mac.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +chmod 777 bin/build-mac.sh +bin/build-mac.sh "-DPACKAGE" diff --git a/custom/4coder_auto_indent.cpp b/custom/4coder_auto_indent.cpp index d05d98f8..f6460cd0 100644 --- a/custom/4coder_auto_indent.cpp +++ b/custom/4coder_auto_indent.cpp @@ -15,7 +15,7 @@ make_batch_from_indentations(Application_Links *app, Arena *arena, Buffer_ID buf line_number <= lines.max; ++line_number){ i64 line_start_pos = get_line_start_pos(app, buffer, line_number); - Indent_Info indent_info = get_indent_info_line_start(app, buffer, line_start_pos, tab_width); + Indent_Info indent_info = get_indent_info_line_number_and_start(app, buffer, line_number, line_start_pos, tab_width); i64 correct_indentation = shifted_indentations[line_number]; if (indent_info.is_blank && HasFlag(flags, Indent_ClearLine)){ @@ -63,6 +63,7 @@ set_line_indents(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i internal Token* find_anchor_token(Application_Links *app, Buffer_ID buffer, Token_Array *tokens, i64 invalid_line){ + ProfileScope(app, "find anchor token"); Token *result = 0; if (tokens != 0 && tokens->tokens != 0){ @@ -146,8 +147,20 @@ indent__unfinished_statement(Token *token, Nest *current_nest){ return(result); } +function void +line_indent_cache_update(Application_Links *app, Buffer_ID buffer, i32 tab_width, Indent_Line_Cache *line_cache){ + if (line_cache->line_number_for_cached_indent != line_cache->where_token_starts){ + ProfileScope(app, "get indent info"); + line_cache->line_number_for_cached_indent = line_cache->where_token_starts; + line_cache->start_pos = get_line_start_pos(app, buffer, line_cache->where_token_starts); + Range_i64 range = Ii64(line_cache->start_pos, line_cache->one_past_last_pos); + line_cache->indent_info = get_indent_info_range(app, buffer, range, tab_width); + } +} + internal i64* get_indentation_array(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 lines, Indent_Flag flags, i32 tab_width, i32 indent_width){ + ProfileScope(app, "get indentation array"); i64 count = lines.max - lines.min + 1; i64 *indentations = push_array(arena, i64, count); i64 *shifted_indentations = indentations - lines.first; @@ -174,11 +187,17 @@ get_indentation_array(Application_Links *app, Arena *arena, Buffer_ID buffer, Ra i64 actual_indent = 0; b32 in_unfinished_statement = false; + Indent_Line_Cache line_cache = {}; + for (;;){ Token *token = token_it_read(&token_it); - i64 line_where_token_starts = get_line_number_from_pos(app, buffer, token->pos); - i64 line_start_pos = get_line_start_pos(app, buffer, line_where_token_starts); - Indent_Info line_indent_info = get_indent_info_line_start(app, buffer, line_start_pos, tab_width); + + if (line_cache.where_token_starts == 0 || + token->pos >= line_cache.one_past_last_pos){ + ProfileScope(app, "get line number"); + line_cache.where_token_starts = get_line_number_from_pos(app, buffer, token->pos); + line_cache.one_past_last_pos = get_line_end_pos(app, buffer, line_cache.where_token_starts); + } i64 current_indent = 0; if (nest != 0){ @@ -229,7 +248,8 @@ get_indentation_array(Application_Links *app, Arena *arena, Buffer_ID buffer, Ra Nest *new_nest = indent__new_nest(arena, &nest_alloc); sll_stack_push(nest, new_nest); nest->kind = TokenBaseKind_ParentheticalOpen; - nest->indent = (token->pos - line_indent_info.first_char_pos) + 1; + line_indent_cache_update(app, buffer, tab_width, &line_cache); + nest->indent = (token->pos - line_cache.indent_info.first_char_pos) + 1; following_indent = nest->indent; shift_by_actual_indent = true; }break; @@ -245,7 +265,7 @@ get_indentation_array(Application_Links *app, Arena *arena, Buffer_ID buffer, Ra if (nest != 0){ following_indent = nest->indent; } - ignore_unfinished_statement = true; + //ignore_unfinished_statement = true; }break; } } @@ -255,30 +275,42 @@ get_indentation_array(Application_Links *app, Arena *arena, Buffer_ID buffer, Ra } #define EMIT(N) \ - Stmnt(if (lines.first <= line_it){shifted_indentations[line_it]=N;} \ - if (line_it == lines.end){goto finished;} \ - actual_indent = N; ) +Stmnt(if (lines.first <= line_it){shifted_indentations[line_it]=N;} \ +if (line_it == lines.end){goto finished;} \ +actual_indent = N; ) i64 line_it = line_last_indented; - for (;line_it < line_where_token_starts;){ - line_it += 1; - if (line_it == line_where_token_starts){ - EMIT(this_indent); - } - else{ - EMIT(last_indent); + if (lines.first <= line_cache.where_token_starts){ + for (;line_it < line_cache.where_token_starts;){ + line_it += 1; + if (line_it == line_cache.where_token_starts){ + EMIT(this_indent); + } + else{ + EMIT(last_indent); + } } } + else{ + actual_indent = this_indent; + line_it = line_cache.where_token_starts; + } - i64 line_where_token_starts_shift = this_indent - line_indent_info.indent_pos; i64 line_where_token_ends = get_line_number_from_pos(app, buffer, token->pos + token->size); - for (;line_it < line_where_token_ends;){ - line_it += 1; - i64 line_it_start_pos = get_line_start_pos(app, buffer, line_it); - Indent_Info line_it_indent_info = get_indent_info_line_start(app, buffer, line_it_start_pos, tab_width); - i64 new_indent = line_it_indent_info.indent_pos + line_where_token_starts_shift; - new_indent = clamp_bot(0, new_indent); - EMIT(new_indent); + if (lines.first <= line_where_token_ends){ + line_indent_cache_update(app, buffer, tab_width, &line_cache); + i64 line_where_token_starts_shift = this_indent - line_cache.indent_info.indent_pos; + for (;line_it < line_where_token_ends;){ + line_it += 1; + i64 line_it_start_pos = get_line_start_pos(app, buffer, line_it); + Indent_Info line_it_indent_info = get_indent_info_line_number_and_start(app, buffer, line_it, line_it_start_pos, tab_width); + i64 new_indent = line_it_indent_info.indent_pos + line_where_token_starts_shift; + new_indent = clamp_bot(0, new_indent); + EMIT(new_indent); + } + } + else{ + line_it = line_where_token_ends; } #undef EMIT @@ -395,6 +427,7 @@ CUSTOM_DOC("Auto-indents the range between the cursor and the mark.") CUSTOM_COMMAND_SIG(write_text_and_auto_indent) CUSTOM_DOC("Inserts text and auto-indents the line on which the cursor sits if any of the text contains 'layout punctuation' such as ;:{}()[]# and new lines.") { + ProfileScope(app, "write and auto indent"); User_Input in = get_current_input(app); String_Const_u8 insert = to_writable(&in); if (insert.str != 0 && insert.size > 0){ diff --git a/custom/4coder_auto_indent.h b/custom/4coder_auto_indent.h index 214cc8b8..79e2fa05 100644 --- a/custom/4coder_auto_indent.h +++ b/custom/4coder_auto_indent.h @@ -24,6 +24,14 @@ struct Nest_Alloc{ Nest *free_nest; }; +struct Indent_Line_Cache{ + i64 where_token_starts; + i64 line_number_for_cached_indent; + i64 start_pos; + i64 one_past_last_pos; + Indent_Info indent_info; +}; + #endif // BOTTOM diff --git a/custom/4coder_base_commands.cpp b/custom/4coder_base_commands.cpp index 0cb42ebc..6b204cb2 100644 --- a/custom/4coder_base_commands.cpp +++ b/custom/4coder_base_commands.cpp @@ -65,7 +65,7 @@ CUSTOM_DOC("Inserts whatever text was used to trigger this command.") } CUSTOM_COMMAND_SIG(write_space) -CUSTOM_DOC("Inserts an underscore.") +CUSTOM_DOC("Inserts a space.") { write_text(app, string_u8_litexpr(" ")); } @@ -112,6 +112,17 @@ CUSTOM_DOC("Deletes the character to the left of the cursor.") } } +CUSTOM_COMMAND_SIG(test_double_backspace) +CUSTOM_DOC("Made for testing purposes (I should have deleted this if you are reading it let me know)") +{ + View_ID view = get_active_view(app, Access_ReadWriteVisible); + Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); + History_Group group = history_group_begin(app, buffer); + backspace_char(app); + backspace_char(app); + history_group_end(group); +} + CUSTOM_COMMAND_SIG(set_mark) CUSTOM_DOC("Sets the mark to the current position of the cursor.") { @@ -281,9 +292,15 @@ move_vertical_pixels(Application_Links *app, View_ID view, f32 pixels){ ProfileScope(app, "move vertical pixels"); i64 pos = view_get_cursor_pos(app, view); Buffer_Cursor cursor = view_compute_cursor(app, view, seek_pos(pos)); - Vec2_f32 p = view_relative_xy_of_pos(app, view, cursor.line, pos); + Rect_f32 r = view_padded_box_of_pos(app, view, cursor.line, pos); + Vec2_f32 p = {}; p.x = view_get_preferred_x(app, view); - p.y += pixels; + if (pixels > 0.f){ + p.y = r.y1 + pixels; + } + else{ + p.y = r.y0 + pixels; + } i64 new_pos = view_pos_at_relative_xy(app, view, cursor.line, p); view_set_cursor(app, view, seek_pos(new_pos)); no_mark_snap_to_cursor_if_shift(app, view); @@ -299,20 +316,12 @@ internal void move_vertical_lines(Application_Links *app, View_ID view, i64 lines){ if (lines > 0){ for (i64 i = 0; i < lines; i += 1){ - i64 pos = view_get_cursor_pos(app, view); - Buffer_Cursor cursor = view_compute_cursor(app, view, seek_pos(pos)); - Rect_f32 box = view_relative_box_of_pos(app, view, cursor.line, cursor.pos); - f32 half_height = rect_height(box)*0.5f; - move_vertical_pixels(app, half_height + 2.f); + move_vertical_pixels(app, 1.f); } } else{ for (i64 i = 0; i > lines; i -= 1){ - i64 pos = view_get_cursor_pos(app, view); - Buffer_Cursor cursor = view_compute_cursor(app, view, seek_pos(pos)); - Rect_f32 box = view_relative_box_of_pos(app, view, cursor.line, cursor.pos); - f32 half_height = rect_height(box)*0.5f; - move_vertical_pixels(app, -half_height - 2.f); + move_vertical_pixels(app, -1.f); } } } @@ -1079,10 +1088,8 @@ query_replace_base(Application_Links *app, View_ID view, Buffer_ID buffer_id, i6 i64 new_pos = 0; seek_string_forward(app, buffer_id, pos - 1, 0, r, &new_pos); - i64 buffer_size = buffer_get_size(app, buffer_id); - User_Input in = {}; - for (;new_pos < buffer_size;){ + for (;;){ Range_i64 match = Ii64(new_pos, new_pos + r.size); isearch__update_highlight(app, view, match); @@ -1091,9 +1098,11 @@ query_replace_base(Application_Links *app, View_ID view, Buffer_ID buffer_id, i6 break; } - if (match_key_code(&in, KeyCode_Y) || - match_key_code(&in, KeyCode_Return) || - match_key_code(&in, KeyCode_Tab)){ + i64 size = buffer_get_size(app, buffer_id); + if (match.max <= size && + (match_key_code(&in, KeyCode_Y) || + match_key_code(&in, KeyCode_Return) || + match_key_code(&in, KeyCode_Tab))){ buffer_replace_range(app, buffer_id, match, w); pos = match.start + w.size; } @@ -1313,23 +1322,20 @@ CUSTOM_DOC("Queries the user for a new name and renames the file of the current bar.prompt = push_u8_stringf(scratch, "Rename '%.*s' to: ", string_expand(front)); bar.string = SCu8(name_space, (u64)0); bar.string_capacity = sizeof(name_space); - if (query_user_string(app, &bar)){ - if (bar.string.size != 0){ - // TODO(allen): There should be a way to say, "detach a buffer's file" and "attach this file to a buffer" - List_String_Const_u8 new_file_name_list = {}; - string_list_push(scratch, &new_file_name_list, file_name); - string_list_push(scratch, &new_file_name_list, bar.string); - String_Const_u8 new_file_name = string_list_flatten(scratch, new_file_name_list, StringFill_NullTerminate); - if (buffer_save(app, buffer, new_file_name, BufferSave_IgnoreDirtyFlag)){ - Buffer_ID new_buffer = create_buffer(app, new_file_name, BufferCreate_NeverNew|BufferCreate_JustChangedFile); - if (new_buffer != 0 && new_buffer != buffer){ - delete_file_base(app, file_name, buffer); - view_set_buffer(app, view, new_buffer, 0); - } + if (query_user_string(app, &bar) && bar.string.size != 0){ + // TODO(allen): There should be a way to say, "detach a buffer's file" and "attach this file to a buffer" + List_String_Const_u8 new_file_name_list = {}; + string_list_push(scratch, &new_file_name_list, string_remove_front_of_path(file_name)); + string_list_push(scratch, &new_file_name_list, bar.string); + String_Const_u8 new_file_name = string_list_flatten(scratch, new_file_name_list, StringFill_NullTerminate); + if (buffer_save(app, buffer, new_file_name, BufferSave_IgnoreDirtyFlag)){ + Buffer_ID new_buffer = create_buffer(app, new_file_name, BufferCreate_NeverNew|BufferCreate_JustChangedFile); + if (new_buffer != 0 && new_buffer != buffer){ + delete_file_base(app, file_name, buffer); + view_set_buffer(app, view, new_buffer, 0); } } } - } } diff --git a/custom/4coder_base_types.cpp b/custom/4coder_base_types.cpp index 9f7b3483..6585e4e7 100644 --- a/custom/4coder_base_types.cpp +++ b/custom/4coder_base_types.cpp @@ -1727,7 +1727,7 @@ Ii32_size(i32 pos, i32 size){ function Range_i64 Ii64_size(i64 pos, i64 size){ return(Ii64(pos, pos + size)); -} +} function Range_u64 Iu64_size(u64 pos, u64 size){ return(Iu64(pos, pos + size)); @@ -2978,7 +2978,7 @@ make_base_allocator(Base_Allocator_Reserve_Signature *func_reserve, } function Data base_allocate__inner(Base_Allocator *allocator, u64 size, String_Const_u8 location){ - u64 full_size = 0; + u64 full_size = 0; void *memory = allocator->reserve(allocator->user_data, size, &full_size, location); allocator->commit(allocator->user_data, memory, full_size); return(make_data(memory, (u64)full_size)); @@ -4321,6 +4321,18 @@ string_remove_last_folder(String_Const_u32 str){ return(str); } +function b32 +string_looks_like_drive_letter(String_Const_u8 string){ + b32 result = false; + if (string.size == 3 && + character_is_alpha(string.str[0]) && + string.str[1] == ':' && + character_is_slash(string.str[2])){ + result = true; + } + return(result); +} + function String_Const_char string_remove_front_of_path(String_Const_char str){ i64 slash_pos = string_find_last_slash(str); @@ -4399,6 +4411,26 @@ string_front_of_path(String_Const_u32 str){ return(str); } +function String_Const_u8 +string_remove_front_folder_of_path(String_Const_u8 str){ + i64 slash_pos = string_find_last_slash(string_chop(str, 1)); + if (slash_pos < 0){ + str.size = 0; + } + else{ + str.size = slash_pos + 1; + } + return(str); +} +function String_Const_u8 +string_front_folder_of_path(String_Const_u8 str){ + i64 slash_pos = string_find_last_slash(string_chop(str, 1)); + if (slash_pos >= 0){ + str = string_skip(str, slash_pos + 1); + } + return(str); +} + function String_Const_char string_file_extension(String_Const_char string){ return(string_skip(string, string_find_last(string, '.') + 1)); @@ -4728,9 +4760,10 @@ string_find_first(String_Const_char str, String_Const_char needle, String_Match_ i = str.size; if (str.size >= needle.size){ i = 0; + char c = character_to_upper(needle.str[0]); u64 one_past_last = str.size - needle.size + 1; for (;i < one_past_last; i += 1){ - if (str.str[i] == needle.str[0]){ + if (character_to_upper(str.str[i]) == c){ String_Const_char source_part = string_prefix(string_skip(str, i), needle.size); if (string_match(source_part, needle, rule)){ break; @@ -4751,9 +4784,10 @@ string_find_first(String_Const_u8 str, String_Const_u8 needle, String_Match_Rule i = str.size; if (str.size >= needle.size){ i = 0; + u8 c = character_to_upper(needle.str[0]); u64 one_past_last = str.size - needle.size + 1; for (;i < one_past_last; i += 1){ - if (str.str[i] == needle.str[0]){ + if (character_to_upper(str.str[i]) == c){ String_Const_u8 source_part = string_prefix(string_skip(str, i), needle.size); if (string_match(source_part, needle, rule)){ break; @@ -4774,9 +4808,10 @@ string_find_first(String_Const_u16 str, String_Const_u16 needle, String_Match_Ru i = str.size; if (str.size >= needle.size){ i = 0; + u16 c = character_to_upper(needle.str[0]); u64 one_past_last = str.size - needle.size + 1; for (;i < one_past_last; i += 1){ - if (str.str[i] == needle.str[0]){ + if (character_to_upper(str.str[i]) == c){ String_Const_u16 source_part = string_prefix(string_skip(str, i), needle.size); if (string_match(source_part, needle, rule)){ break; @@ -4797,9 +4832,10 @@ string_find_first(String_Const_u32 str, String_Const_u32 needle, String_Match_Ru i = str.size; if (str.size >= needle.size){ i = 0; + u32 c = character_to_upper(needle.str[0]); u64 one_past_last = str.size - needle.size + 1; for (;i < one_past_last; i += 1){ - if (str.str[i] == needle.str[0]){ + if (character_to_upper(str.str[i]) == c){ String_Const_u32 source_part = string_prefix(string_skip(str, i), needle.size); if (string_match(source_part, needle, rule)){ break; @@ -5281,7 +5317,7 @@ push_string_copy(Arena *arena, u64 size, String_Const_Any src){ return(string); } - function String_Const_u8_Array +function String_Const_u8_Array push_string_array_copy(Arena *arena, String_Const_u8_Array src){ String_Const_u8_Array result = {}; result.vals = push_array(arena, String_Const_u8, src.count); @@ -6943,10 +6979,10 @@ global_const u8 integer_symbol_reverse[128] = { global_const u8 base64[64] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '$', }; @@ -6963,7 +6999,7 @@ global_const u8 base64_reverse[128] = { function u64 digit_count_from_integer(u64 x, u32 radix){ - u64 result = {}; + u64 result = 0; if (radix >= 2 && radix <= 16){ if (x == 0){ result = 1; diff --git a/custom/4coder_base_types.h b/custom/4coder_base_types.h index 3ca3f926..31f29195 100644 --- a/custom/4coder_base_types.h +++ b/custom/4coder_base_types.h @@ -31,14 +31,34 @@ # error architecture not supported yet # endif +#elif defined(__clang__) + +# define COMPILER_CLANG 1 + +# if defined(__APPLE__) && defined(__MACH__) +# define OS_MAC 1 +# else +# error This compiler/platform combo is not supported yet +# endif + +# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) +# define ARCH_X64 1 +# elif defined(i386) || defined(__i386) || defined(__i386__) +# define ARCH_X86 1 +# elif defined(__aarch64__) +# define ARCH_ARM64 1 +# elif defined(__arm__) +# define ARCH_ARM32 1 +# else +# error architecture not supported yet +# endif + #elif defined(__GNUC__) || defined(__GNUG__) # define COMPILER_GCC 1 # if defined(__gnu_linux__) # define OS_LINUX 1 -# elif defined(__APPLE__) && defined(__MACH__) -# define OS_MAC 1 # else # error This compiler/platform combo is not supported yet # endif @@ -92,6 +112,9 @@ #if !defined(COMPILER_GCC) #define COMPILER_GCC 0 #endif +#if !defined(COMPILER_CLANG) +#define COMPILER_CLANG 0 +#endif #if !defined(OS_WINDOWS) #define OS_WINDOWS 0 #endif @@ -121,12 +144,11 @@ #endif #endif -#if OS_WINDOWS -# if ARCH_32BIT -# define CALL_CONVENTION __stdcall -# else -# define CALL_CONVENTION -# endif +// NOTE(yuval): Changed this so that CALL_CONVENTION will be defined for all platforms +#if ARCH_32BIT +# define CALL_CONVENTION __stdcall +#else +# define CALL_CONVENTION #endif #if defined(JUST_GUESS_INTS) @@ -268,8 +290,6 @@ enum{ #define Max(a,b) (((a)>(b))?(a):(b)) #define Min(a,b) (((a)<(b))?(a):(b)) -#define max(a,b) (((a)>(b))?(a):(b)) -#define min(a,b) (((a)<(b))?(a):(b)) #define clamp_top(a,b) Min(a,b) #define clamp_bot(a,b) Max(a,b) #define clamp_(a,x,b) ((a>x)?a:((bprev == 0); \ +for(T *p_ = f; p_ != 0; p_ = p_->next){ Assert(p_->prev == 0 || p_->prev->next == p_); Assert(p_->next == 0 || p_->next->prev == p_); } } ) + //////////////////////////////// union Vec2_i8{ @@ -836,7 +859,7 @@ enum{ struct String_Const_char{ char *str; - u64 size; + u64 size; }; struct String_Const_u8{ union{ @@ -924,25 +947,25 @@ struct Node_String_Const_u32{ struct List_String_Const_char{ Node_String_Const_char *first; Node_String_Const_char *last; - u64 total_size; + u64 total_size; i32 node_count; }; struct List_String_Const_u8{ Node_String_Const_u8 *first; Node_String_Const_u8 *last; - u64 total_size; + u64 total_size; i32 node_count; }; struct List_String_Const_u16{ Node_String_Const_u16 *first; Node_String_Const_u16 *last; - u64 total_size; + u64 total_size; i32 node_count; }; struct List_String_Const_u32{ Node_String_Const_u32 *first; Node_String_Const_u32 *last; - u64 total_size; + u64 total_size; i32 node_count; }; @@ -953,7 +976,7 @@ struct Node_String_Const_Any{ struct List_String_Const_Any{ Node_String_Const_Any *first; Node_String_Const_Any *last; - u64 total_size; + u64 total_size; i32 node_count; }; @@ -962,40 +985,40 @@ struct String_char{ String_Const_char string; struct{ char *str; - u64 size; + u64 size; }; }; - u64 cap; + u64 cap; }; struct String_u8{ union{ String_Const_u8 string; struct{ u8 *str; - u64 size; + u64 size; }; }; - u64 cap; + u64 cap; }; struct String_u16{ union{ String_Const_u16 string; struct{ u16 *str; - u64 size; + u64 size; }; }; - u64 cap; + u64 cap; }; struct String_u32{ union{ String_Const_u32 string; struct{ u32 *str; - u64 size; + u64 size; }; }; - u64 cap; + u64 cap; }; struct String_Any{ @@ -1003,8 +1026,8 @@ struct String_Any{ union{ struct{ void *str; - u64 size; - u64 cap; + u64 size; + u64 cap; }; String_char s_char; String_u8 s_u8; @@ -1091,7 +1114,7 @@ struct Base_Allocator{ struct Cursor{ u8 *base; - u64 pos; + u64 pos; u64 cap; }; struct Temp_Memory_Cursor{ @@ -1231,7 +1254,7 @@ struct Heap_Node{ struct{ Heap_Basic_Node order; Heap_Basic_Node alloc; - u64 size; + u64 size; }; u8 force_size__[64]; }; @@ -1242,8 +1265,8 @@ struct Heap{ Arena *arena; Heap_Basic_Node in_order; Heap_Basic_Node free_nodes; - u64 used_space; - u64 total_space; + u64 used_space; + u64 total_space; }; #endif diff --git a/custom/4coder_build_commands.cpp b/custom/4coder_build_commands.cpp index cc7e6dc1..52d924e9 100644 --- a/custom/4coder_build_commands.cpp +++ b/custom/4coder_build_commands.cpp @@ -63,7 +63,7 @@ standard_build_exec_command(Application_Links *app, View_ID view, String_Const_u standard_build_exec_flags); } -static b32 +function b32 standard_search_and_build_from_dir(Application_Links *app, View_ID view, String_Const_u8 start_dir){ Scratch_Block scratch(app); @@ -82,15 +82,9 @@ standard_search_and_build_from_dir(Application_Links *app, View_ID view, String_ if (result){ // NOTE(allen): Build String_Const_u8 path = string_remove_last_folder(full_file_path); -#if OS_WINDOWS - String_Const_u8 command = push_u8_stringf(scratch, "%.*s/%.*s", + String_Const_u8 command = push_u8_stringf(scratch, "\"%.*s/%.*s\"", string_expand(path), string_expand(cmd_string)); -#elif OS_LINUX || OS_MAC - String_Const_u8 command = cmd_string; -#else -#error OS needs standard search and build rules -#endif if (global_config.automatically_save_changes_on_build){ save_all_dirty_buffers(app); } @@ -153,7 +147,7 @@ get_or_open_build_panel(Application_Links *app){ return(view); } - function void +function void set_fancy_compilation_buffer_font(Application_Links *app){ Buffer_ID buffer = get_comp_buffer(app); Font_Load_Location font = {}; diff --git a/custom/4coder_cli_command.cpp b/custom/4coder_cli_command.cpp index 446c4b86..038e0ed9 100644 --- a/custom/4coder_cli_command.cpp +++ b/custom/4coder_cli_command.cpp @@ -29,12 +29,16 @@ CUSTOM_DOC("Queries for an output buffer name and system command, runs the syste bar_out.string = SCu8(out_buffer_space, (u64)0); bar_out.string_capacity = sizeof(out_buffer_space); if (!query_user_string(app, &bar_out)) return; + bar_out.string.size = clamp_top(bar_out.string.size, sizeof(out_buffer_space) - 1); + out_buffer_space[bar_out.string.size] = 0; Query_Bar bar_cmd = {}; bar_cmd.prompt = string_u8_litexpr("Command: "); bar_cmd.string = SCu8(command_space, (u64)0); bar_cmd.string_capacity = sizeof(command_space); if (!query_user_string(app, &bar_cmd)) return; + bar_cmd.string.size = clamp_top(bar_cmd.string.size, sizeof(command_space) - 1); + command_space[bar_cmd.string.size] = 0; String_Const_u8 hot = push_hot_directory(app, scratch); { diff --git a/custom/4coder_clipboard.cpp b/custom/4coder_clipboard.cpp index fdb44353..8b562253 100644 --- a/custom/4coder_clipboard.cpp +++ b/custom/4coder_clipboard.cpp @@ -4,7 +4,7 @@ // TOP - function b32 +function b32 clipboard_post_buffer_range(Application_Links *app, i32 clipboard_index, Buffer_ID buffer, Range_i64 range){ b32 success = false; Scratch_Block scratch(app); @@ -46,24 +46,25 @@ CUSTOM_DOC("At the cursor, insert the text at the top of the clipboard.") Managed_Scope scope = view_get_managed_scope(app, view); Rewrite_Type *next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); - *next_rewrite = Rewrite_Paste; - i32 *paste_index = scope_attachment(app, scope, view_paste_index_loc, i32); - *paste_index = 0; - - Scratch_Block scratch(app); - - String_Const_u8 string = push_clipboard_index(app, scratch, 0, *paste_index); - if (string.size > 0){ - Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); + if (next_rewrite != 0){ + *next_rewrite = Rewrite_Paste; + i32 *paste_index = scope_attachment(app, scope, view_paste_index_loc, i32); + *paste_index = 0; - i64 pos = view_get_cursor_pos(app, view); - buffer_replace_range(app, buffer, Ii64(pos), string); - view_set_mark(app, view, seek_pos(pos)); - view_set_cursor_and_preferred_x(app, view, seek_pos(pos + (i32)string.size)); + Scratch_Block scratch(app); - // TODO(allen): Send this to all views. - ARGB_Color argb = fcolor_resolve(fcolor_id(defcolor_paste)); - view_post_fade(app, view, 0.667f, Ii64_size(pos, string.size), argb); + String_Const_u8 string = push_clipboard_index(app, scratch, 0, *paste_index); + if (string.size > 0){ + Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); + + i64 pos = view_get_cursor_pos(app, view); + buffer_replace_range(app, buffer, Ii64(pos), string); + view_set_mark(app, view, seek_pos(pos)); + view_set_cursor_and_preferred_x(app, view, seek_pos(pos + (i32)string.size)); + + ARGB_Color argb = fcolor_resolve(fcolor_id(defcolor_paste)); + buffer_post_fade(app, buffer, 0.667f, Ii64_size(pos, string.size), argb); + } } } } @@ -80,29 +81,31 @@ CUSTOM_DOC("If the previous command was paste or paste_next, replaces the paste no_mark_snap_to_cursor(app, scope); Rewrite_Type *rewrite = scope_attachment(app, scope, view_rewrite_loc, Rewrite_Type); - if (*rewrite == Rewrite_Paste){ - Rewrite_Type *next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); - *next_rewrite = Rewrite_Paste; - - i32 *paste_index_ptr = scope_attachment(app, scope, view_paste_index_loc, i32); - i32 paste_index = (*paste_index_ptr) + 1; - *paste_index_ptr = paste_index; - - String_Const_u8 string = push_clipboard_index(app, scratch, 0, paste_index); - - Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); - - Range_i64 range = get_view_range(app, view); - i64 pos = range.min; - - buffer_replace_range(app, buffer, range, string); - view_set_cursor_and_preferred_x(app, view, seek_pos(pos + string.size)); - - ARGB_Color argb = fcolor_resolve(fcolor_id(defcolor_paste)); - view_post_fade(app, view, 0.667f, Ii64_size(pos, string.size), argb); - } - else{ - paste(app); + if (rewrite != 0){ + if (*rewrite == Rewrite_Paste){ + Rewrite_Type *next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); + *next_rewrite = Rewrite_Paste; + + i32 *paste_index_ptr = scope_attachment(app, scope, view_paste_index_loc, i32); + i32 paste_index = (*paste_index_ptr) + 1; + *paste_index_ptr = paste_index; + + String_Const_u8 string = push_clipboard_index(app, scratch, 0, paste_index); + + Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); + + Range_i64 range = get_view_range(app, view); + i64 pos = range.min; + + buffer_replace_range(app, buffer, range, string); + view_set_cursor_and_preferred_x(app, view, seek_pos(pos + string.size)); + + ARGB_Color argb = fcolor_resolve(fcolor_id(defcolor_paste)); + buffer_post_fade(app, buffer, 0.667f, Ii64_size(pos, string.size), argb); + } + else{ + paste(app); + } } } } @@ -132,30 +135,30 @@ CUSTOM_COMMAND_SIG(multi_paste){ Managed_Scope scope = view_get_managed_scope(app, view); Rewrite_Type *rewrite = scope_attachment(app, scope, view_rewrite_loc, Rewrite_Type); - if (*rewrite == Rewrite_Paste){ - Rewrite_Type *next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); - *next_rewrite = Rewrite_Paste; - i32 *paste_index_ptr = scope_attachment(app, scope, view_paste_index_loc, i32); - i32 paste_index = (*paste_index_ptr) + 1; - *paste_index_ptr = paste_index; - - String_Const_u8 string = push_clipboard_index(app, scratch, 0, paste_index); - - String_Const_u8 insert_string = push_u8_stringf(scratch, "\n%.*s", string_expand(string)); - - Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); - Range_i64 range = get_view_range(app, view); - buffer_replace_range(app, buffer, Ii64(range.max), insert_string); - view_set_mark(app, view, seek_pos(range.max + 1)); - view_set_cursor_and_preferred_x(app, view, seek_pos(range.max + insert_string.size)); - - ARGB_Color argb = fcolor_resolve(fcolor_id(defcolor_paste)); - view_post_fade(app, view, 0.667f, - Ii64(range.max + 1, range.max + insert_string.size), - argb); - } - else{ - paste(app); + if (rewrite != 0){ + if (*rewrite == Rewrite_Paste){ + Rewrite_Type *next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); + *next_rewrite = Rewrite_Paste; + i32 *paste_index_ptr = scope_attachment(app, scope, view_paste_index_loc, i32); + i32 paste_index = (*paste_index_ptr) + 1; + *paste_index_ptr = paste_index; + + String_Const_u8 string = push_clipboard_index(app, scratch, 0, paste_index); + + String_Const_u8 insert_string = push_u8_stringf(scratch, "\n%.*s", string_expand(string)); + + Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible); + Range_i64 range = get_view_range(app, view); + buffer_replace_range(app, buffer, Ii64(range.max), insert_string); + view_set_mark(app, view, seek_pos(range.max + 1)); + view_set_cursor_and_preferred_x(app, view, seek_pos(range.max + insert_string.size)); + + ARGB_Color argb = fcolor_resolve(fcolor_id(defcolor_paste)); + view_post_fade(app, buffer, 0.667f, Ii64(range.max + 1, range.max + insert_string.size), argb); + } + else{ + paste(app); + } } } } @@ -207,9 +210,8 @@ multi_paste_range(Application_Links *app, View_ID view, Range_i64 range, i32 pas view_set_mark(app, view, seek_pos(finish_range.min)); view_set_cursor_and_preferred_x(app, view, seek_pos(finish_range.max)); - // TODO(allen): Send this to all views. ARGB_Color argb = fcolor_resolve(fcolor_id(defcolor_paste)); - view_post_fade(app, view, 0.667f, finish_range, argb); + buffer_post_fade(app, buffer, 0.667f, finish_range, argb); } } return(finish_range); diff --git a/custom/4coder_code_index.cpp b/custom/4coder_code_index.cpp index 2e7d0fcc..6d4e413a 100644 --- a/custom/4coder_code_index.cpp +++ b/custom/4coder_code_index.cpp @@ -1,1173 +1,2360 @@ -/* -4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. -*/ - -// TOP - -global Code_Index global_code_index = {}; - -function void -code_index_init(void){ - global_code_index.mutex = system_mutex_make(); - global_code_index.node_arena = make_arena_system(KB(4)); - global_code_index.buffer_to_index_file = make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); -} - -function Code_Index_File_Storage* -code_index__alloc_storage(void){ - Code_Index_File_Storage *result = global_code_index.free_storage; - if (result == 0){ - result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); - } - else{ - sll_stack_pop(global_code_index.free_storage); - } - zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); - global_code_index.storage_count += 1; - return(result); -} - -function void -code_index__free_storage(Code_Index_File_Storage *storage){ - zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); - global_code_index.storage_count -= 1; - sll_stack_push(global_code_index.free_storage, storage); -} - -function void -code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ - sll_queue_push(list->first, list->last, nest); - list->count += 1; -} - -function Code_Index_Nest_Ptr_Array -code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ - Code_Index_Nest_Ptr_Array array = {}; - array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); - array.count = list->count; - i32 counter = 0; - for (Code_Index_Nest *node = list->first; - node != 0; - node = node->next){ - array.ptrs[counter] = node; - counter += 1; - } - return(array); -} - -function Code_Index_Note_Ptr_Array -code_index_note_ptr_array_from_list(Arena *arena, Code_Index_Note_List *list){ - Code_Index_Note_Ptr_Array array = {}; - array.ptrs = push_array_zero(arena, Code_Index_Note*, list->count); - array.count = list->count; - i32 counter = 0; - for (Code_Index_Note *node = list->first; - node != 0; - node = node->next){ - array.ptrs[counter] = node; - counter += 1; - } - return(array); -} - -function void -code_index_lock(void){ - system_mutex_acquire(global_code_index.mutex); -} - -function void -code_index_unlock(void){ - system_mutex_release(global_code_index.mutex); -} - -function void -code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ - Code_Index_File_Storage *storage = 0; - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - storage = (Code_Index_File_Storage*)IntAsPtr(val); - linalloc_clear(&storage->arena); - } - else{ - storage = code_index__alloc_storage(); - table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); - } - storage->arena = arena; - storage->file = index; -} - -function void -code_index_erase_file(Buffer_ID buffer){ - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); - linalloc_clear(&storage->arena); - table_erase(&global_code_index.buffer_to_index_file, lookup); - code_index__free_storage(storage); - } -} - -function Code_Index_File* -code_index_get_file(Buffer_ID buffer){ - Code_Index_File *result = 0; - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); - result = storage->file; - } - return(result); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_Nest_Ptr_Array *array, i64 pos){ - Code_Index_Nest *result = 0; - i32 count = array->count; - Code_Index_Nest **nest_ptrs = array->ptrs; - for (i32 i = 0; i < count; i += 1){ - Code_Index_Nest *nest = nest_ptrs[i]; - if (nest->open.max <= pos && pos <= nest->close.min){ - Code_Index_Nest *sub_nest = - code_index_get_nest(&nest->nest_array, pos); - if (sub_nest != 0){ - result = sub_nest; - } - else{ - result = nest; - } - break; - } - } - return(result); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_Nest *nest, i64 pos){ - return(code_index_get_nest(&nest->nest_array, pos)); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_File *file, i64 pos){ - return(code_index_get_nest(&file->nest_array, pos)); -} - -function void -index_shift(i64 *ptr, Range_i64 old_range, u64 new_size){ - i64 i = *ptr; - if (old_range.min <= i && i < old_range.max){ - *ptr = old_range.first; - } - else if (old_range.max <= i){ - *ptr = i + new_size - (old_range.max - old_range.min); - } -} - -function void -code_index_shift(Code_Index_Nest_Ptr_Array *array, - Range_i64 old_range, u64 new_size){ - i32 count = array->count; - Code_Index_Nest **nest_ptr = array->ptrs; - for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ - Code_Index_Nest *nest = *nest_ptr; - index_shift(&nest->open.min, old_range, new_size); - index_shift(&nest->open.max, old_range, new_size); - if (nest->is_closed){ - index_shift(&nest->close.min, old_range, new_size); - index_shift(&nest->close.max, old_range, new_size); - } - code_index_shift(&nest->nest_array, old_range, new_size); - } -} - -function void -code_index_shift(Code_Index_File *file, Range_i64 old_range, u64 new_size){ - code_index_shift(&file->nest_array, old_range, new_size); -} - -//////////////////////////////// - -function void -generic_parse_inc(Generic_Parse_State *state){ - if (!token_it_inc_all(&state->it)){ - state->finished = true; - } -} - -function void -generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - for (;token != 0 && !state->finished;){ - if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ - break; - } - if (token->kind == TokenBaseKind_Comment){ - state->handle_comment(state->app, state->arena, index, token, state->contents); - } - else if (token->kind == TokenBaseKind_Whitespace){ - Range_i64 range = Ii64(token); - u8 *ptr = state->contents.str + range.one_past_last - 1; - for (i64 i = range.one_past_last - 1; - i >= range.first; - i -= 1, ptr -= 1){ - if (*ptr == '\n'){ - state->prev_line_start = ptr + 1; - break; - } - } - } - else{ - break; - } - generic_parse_inc(state); - token = token_it_read(&state->it); - } -} - -function void -generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ - state->app = app; - state->arena = arena; - state->contents = contents; - state->it = token_iterator(0, tokens); - state->handle_comment = handle_comment; - state->prev_line_start = contents.str; -} - -//////////////////////////////// - -#if 0 -// NOTE(allen): grammar syntax -(X) = X -X Y = X and then Y -X? = zero or one X -$X = check for X but don't consume -[X] = zero or more Xs -X | Y = either X or Y -* = anything that does not match previous options in a X | Y | ... chain -* - X = anything that does not match X or previous options in a Y | Z | ... chain - = a token of type X -"X" = literally the string "X" -X{Y} = X with flag Y - -// NOTE(allen): grammar of code index parse -file: [preprocessor | scope | parens | function | type | * - ] -preprocessor: [scope | parens | stmnt]{pp-body} -scope: [preprocessor | scope | parens | * - ] -paren: [preprocessor | scope | parens | * - ] -stmnt-close-pattern: | | | | | -stmnt: [type | * - stmnt-close-pattern] stmnt-close-pattern -type: struct | union | enum | typedef -struct: "struct" $(";" | "{") -union: "union" $(";" | "{") -enum: "enum" $(";" | "{") -typedef: "typedef" [* - ( (";" | "("))] $(";" | "(") -function: >"(" [* - ("(" | ")" | "{" | "}" | ";")] ")" ("{" | ";") - -#endif - -//////////////////////////////// - -function Code_Index_Note* -index_new_note(Code_Index_File *index, Generic_Parse_State *state, Range_i64 range, Code_Index_Note_Kind kind, Code_Index_Nest *parent){ - Code_Index_Note *result = push_array(state->arena, Code_Index_Note, 1); - sll_queue_push(index->note_list.first, index->note_list.last, result); - index->note_list.count += 1; - result->note_kind = kind; - result->pos = range; - result->text = push_string_copy(state->arena, string_substring(state->contents, range)); - result->file = index; - result->parent = parent; - return(result); -} - -function void -cpp_parse_type_structure(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - if (state->finished){ - return; - } - Token *token = token_it_read(&state->it); - if (token != 0 && token->kind == TokenBaseKind_Identifier){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - Token *peek = token_it_read(&state->it); - if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || - peek->kind == TokenBaseKind_ScopeOpen){ - index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); - } - } -} - -function void -cpp_parse_type_def(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - for (;;){ - b32 did_advance = false; - Token *token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - if (token->kind == TokenBaseKind_Identifier){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - did_advance = true; - Token *peek = token_it_read(&state->it); - if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || - peek->kind == TokenBaseKind_ParentheticalOpen){ - index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); - break; - } - } - else if (token->kind == TokenBaseKind_StatementClose || - token->kind == TokenBaseKind_ScopeOpen || - token->kind == TokenBaseKind_ScopeClose || - token->kind == TokenBaseKind_ScopeOpen || - token->kind == TokenBaseKind_ScopeClose){ - break; - } - else if (token->kind == TokenBaseKind_Keyword){ - String_Const_u8 lexeme = string_substring(state->contents, Ii64(token)); - if (string_match(lexeme, string_u8_litexpr("struct")) || - string_match(lexeme, string_u8_litexpr("union")) || - string_match(lexeme, string_u8_litexpr("enum"))){ - break; - } - } - if (!did_advance){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - } - } -} - -function void -cpp_parse_function(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ - Token *token = token_it_read(&state->it); - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - if (state->finished){ - return; - } - Token *peek = token_it_read(&state->it); - Token *reset_point = peek; - if (peek != 0 && peek->sub_kind == TokenCppKind_ParenOp){ - b32 at_paren_close = false; - for (; peek != 0;){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - peek = token_it_read(&state->it); - if (peek == 0 || state->finished){ - break; - } - - if (peek->kind == TokenBaseKind_ParentheticalOpen || - peek->kind == TokenBaseKind_ScopeOpen || - peek->kind == TokenBaseKind_ScopeClose || - peek->kind == TokenBaseKind_StatementClose){ - break; - } - if (peek->kind == TokenBaseKind_ParentheticalClose){ - at_paren_close = true; - break; - } - } - - if (at_paren_close){ - generic_parse_inc(state); - generic_parse_skip_soft_tokens(index, state); - peek = token_it_read(&state->it); - if (peek != 0 && - peek->kind == TokenBaseKind_ScopeOpen || - peek->kind == TokenBaseKind_StatementClose){ - index_new_note(index, state, Ii64(token), CodeIndexNote_Function, parent); - } - } - } - state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); -} - -function Code_Index_Nest* -generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Statement; - result->open = Ii64(token->pos); - result->close = Ii64(max_i64); - result->file = index; - - state->in_statement = true; - - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - } - - if (token->kind == TokenBaseKind_ScopeOpen || - token->kind == TokenBaseKind_ScopeClose || - token->kind == TokenBaseKind_ParentheticalOpen){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - - if (token->kind == TokenBaseKind_StatementClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - generic_parse_inc(state); - } - - state->in_statement = false; - - return(result); -} - -function Code_Index_Nest* -generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Preprocessor; - result->open = Ii64(token->pos); - result->close = Ii64(max_i64); - result->file = index; - - state->in_preprocessor = true; - - b32 potential_macro = false; - if (state->do_cpp_parse){ - if (token->sub_kind == TokenCppKind_PPDefine){ - potential_macro = true; - } - } - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - - if (state->do_cpp_parse && potential_macro){ - if (token->sub_kind == TokenCppKind_Identifier){ - index_new_note(index, state, Ii64(token), CodeIndexNote_Macro, result); - } - potential_macro = false; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - generic_parse_inc(state); - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->in_preprocessor = false; - - return(result); -} - -function Code_Index_Nest* -generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Scope; - result->open = Ii64(token); - result->close = Ii64(max_i64); - result->file = index; - - state->scope_counter += 1; - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - continue; - } - } - - if (token->kind == TokenBaseKind_ScopeClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalClose){ - generic_parse_inc(state); - continue; - } - - { - Code_Index_Nest *nest = generic_parse_statement(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - } - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->scope_counter -= 1; - - return(result); -} - -function Code_Index_Nest* -generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Paren; - result->open = Ii64(token); - result->close = Ii64(max_i64); - result->file = index; - - i64 manifested_characters_on_line = 0; - { - u8 *ptr = state->prev_line_start; - u8 *end_ptr = state->contents.str + token->pos; - // NOTE(allen): Initial whitespace - for (;ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - break; - } - } - // NOTE(allen): Manifested characters - manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; - } - - state->paren_counter += 1; - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - continue; - } - } - - if (token->kind == TokenBaseKind_ParentheticalClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - if (token->kind == TokenBaseKind_ScopeClose){ - break; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - generic_parse_inc(state); - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->paren_counter -= 1; - - return(result); -} - -function b32 -generic_parse_full_input_breaks(Code_Index_File *index, Generic_Parse_State *state, i32 limit){ - b32 result = false; - - i64 first_index = token_it_index(&state->it); - i64 one_past_last_index = first_index + limit; - for (;;){ - generic_parse_skip_soft_tokens(index, state); - Token *token = token_it_read(&state->it); - - if (token == 0 || state->finished){ - result = true; - break; - } - - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else if (state->do_cpp_parse){ - if (token->sub_kind == TokenCppKind_Struct || - token->sub_kind == TokenCppKind_Union || - token->sub_kind == TokenCppKind_Enum){ - cpp_parse_type_structure(index, state, 0); - } - else if (token->sub_kind == TokenCppKind_Typedef){ - cpp_parse_type_def(index, state, 0); - } - else if (token->sub_kind == TokenCppKind_Identifier){ - cpp_parse_function(index, state, 0); - } - else{ - generic_parse_inc(state); - } - } - else{ - generic_parse_inc(state); - } - - i64 index = token_it_index(&state->it); - if (index >= one_past_last_index){ - token = token_it_read(&state->it); - if (token == 0){ - result = true; - } - break; - } - } - - if (result){ - index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); - index->note_array = code_index_note_ptr_array_from_list(state->arena, &index->note_list); - } - - return(result); -} - -//////////////////////////////// - -function void -default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, Token *token, String_Const_u8 contents){ - -} - -function void -generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ - generic_parse_init(app, arena, contents, tokens, default_comment_index, state); -} - -//////////////////////////////// - -function Token_Pair -layout_token_pair(Token_Array *tokens, i64 pos){ - Token_Pair result = {}; - Token_Iterator_Array it = token_iterator_pos(0, tokens, pos); - Token *b = token_it_read(&it); - if (b != 0){ - if (b->kind == TokenBaseKind_Whitespace){ - token_it_inc_non_whitespace(&it); - b = token_it_read(&it); - } - } - token_it_dec_non_whitespace(&it); - Token *a = token_it_read(&it); - if (a != 0){ - result.a = *a; - } - if (b != 0){ - result.b = *b; - } - return(result); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance, b32 *unresolved_dependence){ - f32 result = 0.f; - if (nest != 0){ - switch (nest->kind){ - case CodeIndexNest_Scope: - case CodeIndexNest_Preprocessor: - { - result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); - if (nest->open.min < pos && nest->open.max <= pos && - (!nest->is_closed || pos < nest->close.min)){ - result += 4.f*space_advance; - } - }break; - - case CodeIndexNest_Statement: - { - result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); - if (nest->open.min < pos && nest->open.max <= pos && - (!nest->is_closed || pos < nest->close.min)){ - result += 4.f*space_advance; - } - }break; - - case CodeIndexNest_Paren: - { - Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1, unresolved_dependence); - result = box.x1; - }break; - } - } - return(result); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance){ - b32 ignore; - return(layout_index_x_shift(app, reflex, nest, pos, space_advance, &ignore)); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance, b32 *unresolved_dependence){ - f32 indent = 0; - Code_Index_Nest *nest = code_index_get_nest(file, pos); - if (nest != 0){ - indent = layout_index_x_shift(app, reflex, nest, pos, space_advance, unresolved_dependence); - } - return(indent); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance){ - b32 ignore; - return(layout_index_x_shift(app, reflex, file, pos, space_advance, &ignore)); -} - -function void -layout_index__emit_chunk(LefRig_TopBot_Layout_Vars *pos_vars, Face_ID face, Arena *arena, u8 *text_str, i64 range_first, u8 *ptr, u8 *end, Layout_Item_List *list){ - for (;ptr < end;){ - Character_Consume_Result consume = utf8_consume(ptr, (u64)(end - ptr)); - if (consume.codepoint != '\r'){ - i64 index = layout_index_from_ptr(ptr, text_str, range_first); - if (consume.codepoint != max_u32){ - lr_tb_write(pos_vars, face, arena, list, index, consume.codepoint); - } - else{ - lr_tb_write_byte(pos_vars, face, arena, list, index, *ptr); - } - } - ptr += consume.inc; - } -} - -function i32 -layout_token_score_wrap_token(Token_Pair *pair, Token_Cpp_Kind kind){ - i32 result = 0; - if (pair->a.sub_kind != kind && pair->b.sub_kind == kind){ - result -= 1; - } - else if (pair->a.sub_kind == kind && pair->b.sub_kind != kind){ - result += 1; - } - return(result); -} - -function Layout_Item_List -layout_index__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file, Layout_Wrap_Kind kind){ - Scratch_Block scratch(app); - - Managed_Scope scope = buffer_get_managed_scope(app, buffer); - Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); - - Layout_Item_List list = get_empty_item_list(range); - String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); - - Face_Advance_Map advance_map = get_face_advance_map(app, face); - Face_Metrics metrics = get_face_metrics(app, face); - LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); - - f32 wrap_align_x = width - metrics.normal_advance; - - Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); - - if (text.size == 0){ - lr_tb_write_blank(&pos_vars, face, arena, &list, range.start); - } - else{ - b32 first_of_the_line = true; - Newline_Layout_Vars newline_vars = get_newline_layout_vars(); - - u8 *ptr = text.str; - u8 *end_ptr = ptr + text.size; - u8 *word_ptr = ptr; - - u8 *pending_wrap_ptr = ptr; - f32 pending_wrap_x = 0.f; - i32 pending_wrap_paren_nest_count = 0; - i32 pending_wrap_token_score = 0; - f32 pending_wrap_accumulated_w = 0.f; - - start: - if (ptr == end_ptr){ - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto finish; - } - - if (!character_is_whitespace(*ptr)){ - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto consuming_non_whitespace; - } - - { - for (;ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - pending_wrap_ptr = ptr; - word_ptr = ptr; - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto consuming_non_whitespace; - } - if (*ptr == '\n'){ - pending_wrap_ptr = ptr; - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto consuming_normal_whitespace; - } - } - - if (ptr == end_ptr){ - pending_wrap_ptr = ptr; - i64 index = layout_index_from_ptr(ptr - 1, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - goto finish; - } - } - - consuming_non_whitespace: - { - for (;ptr <= end_ptr; ptr += 1){ - if (ptr == end_ptr || character_is_whitespace(*ptr)){ - break; - } - } - - // NOTE(allen): measure this word - newline_layout_consume_default(&newline_vars); - String_Const_u8 word = SCu8(word_ptr, ptr); - u8 *word_end = ptr; - { - f32 word_advance = 0.f; - ptr = word.str; - for (;ptr < word_end;){ - Character_Consume_Result consume = utf8_consume(ptr, (u64)(word_end - ptr)); - if (consume.codepoint != max_u32){ - word_advance += lr_tb_advance(&pos_vars, face, consume.codepoint); - } - else{ - word_advance += lr_tb_advance_byte(&pos_vars); - } - ptr += consume.inc; - } - pending_wrap_accumulated_w += word_advance; - } - - if (!first_of_the_line && (kind == Layout_Wrapped) && lr_tb_crosses_width(&pos_vars, pending_wrap_accumulated_w)){ - i64 index = layout_index_from_ptr(pending_wrap_ptr, text.str, range.first); - lr_tb_align_rightward(&pos_vars, wrap_align_x); - lr_tb_write_ghost(&pos_vars, face, arena, &list, index, '\\'); - - lr_tb_next_line(&pos_vars); -#if 0 - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); -#endif - - ptr = pending_wrap_ptr; - pending_wrap_accumulated_w = 0.f; - first_of_the_line = true; - goto start; - } - } - - consuming_normal_whitespace: - for (; ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - u8 *new_wrap_ptr = ptr; - - i64 index = layout_index_from_ptr(new_wrap_ptr, text.str, range.first); - Code_Index_Nest *new_wrap_nest = code_index_get_nest(file, index); - b32 invalid_wrap_x = false; - f32 new_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance, &invalid_wrap_x); - if (invalid_wrap_x){ - new_wrap_x = max_f32; - } - - i32 new_wrap_paren_nest_count = 0; - for (Code_Index_Nest *nest = new_wrap_nest; - nest != 0; - nest = nest->parent){ - if (nest->kind == CodeIndexNest_Paren){ - new_wrap_paren_nest_count += 1; - } - } - - Token_Pair new_wrap_token_pair = layout_token_pair(tokens_ptr, index); - - // TODO(allen): pull out the token scoring part and make it replacable for other - // language's token based wrap scoring needs. - i32 token_score = 0; - if (new_wrap_token_pair.a.kind == TokenBaseKind_Keyword){ - if (new_wrap_token_pair.b.kind == TokenBaseKind_ParentheticalOpen || - new_wrap_token_pair.b.kind == TokenBaseKind_Keyword){ - token_score -= 2; - } - } - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Eq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_PlusEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_MinusEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_StarEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_DivEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_ModEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_LeftLeftEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_RightRightEq); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Comma); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_AndAnd); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_OrOr); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Ternary); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Colon); - token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Semicolon); - - i32 new_wrap_token_score = token_score; - - b32 new_wrap_ptr_is_better = false; - if (first_of_the_line){ - new_wrap_ptr_is_better = true; - } - else{ - if (new_wrap_token_score > pending_wrap_token_score){ - new_wrap_ptr_is_better = true; - } - else if (new_wrap_token_score == pending_wrap_token_score){ - f32 new_score = new_wrap_paren_nest_count*10.f + new_wrap_x; - f32 old_score = pending_wrap_paren_nest_count*10.f + pending_wrap_x + metrics.normal_advance*4.f + pending_wrap_accumulated_w*0.5f; - - if (new_score < old_score){ - new_wrap_ptr_is_better = true; - } - } - } - - if (new_wrap_ptr_is_better){ - layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, new_wrap_ptr, &list); - first_of_the_line = false; - - pending_wrap_ptr = new_wrap_ptr; - pending_wrap_paren_nest_count = new_wrap_paren_nest_count; - pending_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance); - pending_wrap_paren_nest_count = new_wrap_paren_nest_count; - pending_wrap_token_score = new_wrap_token_score; - pending_wrap_accumulated_w = 0.f; - } - - word_ptr = ptr; - goto consuming_non_whitespace; - } - - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - switch (*ptr){ - default: - { - newline_layout_consume_default(&newline_vars); - pending_wrap_accumulated_w += lr_tb_advance(&pos_vars, face, *ptr); - }break; - - case '\r': - { - newline_layout_consume_CR(&newline_vars, index); - }break; - - case '\n': - { - layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); - pending_wrap_ptr = ptr + 1; - pending_wrap_accumulated_w = 0.f; - - u64 newline_index = newline_layout_consume_LF(&newline_vars, index); - lr_tb_write_blank(&pos_vars, face, arena, &list, newline_index); - lr_tb_next_line(&pos_vars); - first_of_the_line = true; - ptr += 1; - goto start; - }break; - } - } - - finish: - if (newline_layout_consume_finish(&newline_vars)){ - layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - lr_tb_write_blank(&pos_vars, face, arena, &list, index); - } - } - - layout_item_list_finish(&list, -pos_vars.line_to_text_shift); - - return(list); -} - -function Layout_Item_List -layout_virt_indent_index(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ - Layout_Item_List result = {}; - - if (global_config.enable_virtual_whitespace){ - code_index_lock(); - Code_Index_File *file = code_index_get_file(buffer); - if (file != 0){ - result = layout_index__inner(app, arena, buffer, range, face, width, file, kind); - } - code_index_unlock(); - if (file == 0){ - result = layout_virt_indent_literal(app, arena, buffer, range, face, width, kind); - } - } - else{ - result = layout_basic(app, arena, buffer, range, face, width, kind); - } - - return(result); -} - -function Layout_Item_List -layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ - return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Unwrapped)); -} - -function Layout_Item_List -layout_virt_indent_index_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ - return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Wrapped)); -} - -function Layout_Item_List -layout_virt_indent_index_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ - Managed_Scope scope = buffer_get_managed_scope(app, buffer); - b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); - b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); - return(layout_virt_indent_index(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); -} - -CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) -CUSTOM_DOC("Toggles the current buffer's virtual whitespace status.") -{ - global_config.enable_virtual_whitespace = !global_config.enable_virtual_whitespace; - - for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); - buffer != 0; - buffer = get_buffer_next(app, buffer, Access_Always)){ - buffer_clear_layout_cache(app, buffer); - } -} - -// BOTTOM - +/* +4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. +*/ + +// TOP + +global Code_Index global_code_index = {}; + +function void +code_index_init(void){ + global_code_index.mutex = system_mutex_make(); + global_code_index.node_arena = make_arena_system(KB(4)); + global_code_index.buffer_to_index_file = make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); +} + +function Code_Index_File_Storage* +code_index__alloc_storage(void){ + Code_Index_File_Storage *result = global_code_index.free_storage; + if (result == 0){ + result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); + } + else{ + sll_stack_pop(global_code_index.free_storage); + } + zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); + global_code_index.storage_count += 1; + return(result); +} + +function void +code_index__free_storage(Code_Index_File_Storage *storage){ + zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); + global_code_index.storage_count -= 1; + sll_stack_push(global_code_index.free_storage, storage); +} + +function void +code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ + sll_queue_push(list->first, list->last, nest); + list->count += 1; +} + +function Code_Index_Nest_Ptr_Array +code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ + Code_Index_Nest_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Nest *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function Code_Index_Note_Ptr_Array +code_index_note_ptr_array_from_list(Arena *arena, Code_Index_Note_List *list){ + Code_Index_Note_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Note*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Note *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function void +code_index_lock(void){ + system_mutex_acquire(global_code_index.mutex); +} + +function void +code_index_unlock(void){ + system_mutex_release(global_code_index.mutex); +} + +function void +code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ + Code_Index_File_Storage *storage = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + } + else{ + storage = code_index__alloc_storage(); + table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); + } + storage->arena = arena; + storage->file = index; +} + +function void +code_index_erase_file(Buffer_ID buffer){ + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + table_erase(&global_code_index.buffer_to_index_file, lookup); + code_index__free_storage(storage); + } +} + +function Code_Index_File* +code_index_get_file(Buffer_ID buffer){ + Code_Index_File *result = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + result = storage->file; + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest_Ptr_Array *array, i64 pos){ + Code_Index_Nest *result = 0; + i32 count = array->count; + Code_Index_Nest **nest_ptrs = array->ptrs; + for (i32 i = 0; i < count; i += 1){ + Code_Index_Nest *nest = nest_ptrs[i]; + if (nest->open.max <= pos && pos <= nest->close.min){ + Code_Index_Nest *sub_nest = + code_index_get_nest(&nest->nest_array, pos); + if (sub_nest != 0){ + result = sub_nest; + } + else{ + result = nest; + } + break; + } + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest *nest, i64 pos){ + return(code_index_get_nest(&nest->nest_array, pos)); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_File *file, i64 pos){ + return(code_index_get_nest(&file->nest_array, pos)); +} + +function void +index_shift(i64 *ptr, Range_i64 old_range, u64 new_size){ + i64 i = *ptr; + if (old_range.min <= i && i < old_range.max){ + *ptr = old_range.first; + } + else if (old_range.max <= i){ + *ptr = i + new_size - (old_range.max - old_range.min); + } +} + +function void +code_index_shift(Code_Index_Nest_Ptr_Array *array, + Range_i64 old_range, u64 new_size){ + i32 count = array->count; + Code_Index_Nest **nest_ptr = array->ptrs; + for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ + Code_Index_Nest *nest = *nest_ptr; + index_shift(&nest->open.min, old_range, new_size); + index_shift(&nest->open.max, old_range, new_size); + if (nest->is_closed){ + index_shift(&nest->close.min, old_range, new_size); + index_shift(&nest->close.max, old_range, new_size); + } + code_index_shift(&nest->nest_array, old_range, new_size); + } +} + +function void +code_index_shift(Code_Index_File *file, Range_i64 old_range, u64 new_size){ + code_index_shift(&file->nest_array, old_range, new_size); +} + +//////////////////////////////// + +function void +generic_parse_inc(Generic_Parse_State *state){ + if (!token_it_inc_all(&state->it)){ + state->finished = true; + } +} + +function void +generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + for (;token != 0 && !state->finished;){ + if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ + break; + } + if (token->kind == TokenBaseKind_Comment){ + state->handle_comment(state->app, state->arena, index, token, state->contents); + } + else if (token->kind == TokenBaseKind_Whitespace){ + Range_i64 range = Ii64(token); + u8 *ptr = state->contents.str + range.one_past_last - 1; + for (i64 i = range.one_past_last - 1; + i >= range.first; + i -= 1, ptr -= 1){ + if (*ptr == '\n'){ + state->prev_line_start = ptr + 1; + break; + } + } + } + else{ + break; + } + generic_parse_inc(state); + token = token_it_read(&state->it); + } +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ + state->app = app; + state->arena = arena; + state->contents = contents; + state->it = token_iterator(0, tokens); + state->handle_comment = handle_comment; + state->prev_line_start = contents.str; +} + +//////////////////////////////// + +#if 0 +// NOTE(allen): grammar syntax +(X) = X +X Y = X and then Y +X? = zero or one X +$X = check for X but don't consume +[X] = zero or more Xs +X | Y = either X or Y +* = anything that does not match previous options in a X | Y | ... chain +* - X = anything that does not match X or previous options in a Y | Z | ... chain + = a token of type X +"X" = literally the string "X" +X{Y} = X with flag Y + +// NOTE(allen): grammar of code index parse +file: [preprocessor | scope | parens | function | type | * - ] +preprocessor: [scope | parens | stmnt]{pp-body} +scope: [preprocessor | scope | parens | * - ] +paren: [preprocessor | scope | parens | * - ] +stmnt-close-pattern: | | | | | +stmnt: [type | * - stmnt-close-pattern] stmnt-close-pattern +type: struct | union | enum | typedef +struct: "struct" $(";" | "{") +union: "union" $(";" | "{") +enum: "enum" $(";" | "{") +typedef: "typedef" [* - ( (";" | "("))] $(";" | "(") +function: >"(" ["(" ")" | * - ("(" | ")")] ")" ("{" | ";") + +#endif + +//////////////////////////////// + +function Code_Index_Note* +index_new_note(Code_Index_File *index, Generic_Parse_State *state, Range_i64 range, Code_Index_Note_Kind kind, Code_Index_Nest *parent){ + Code_Index_Note *result = push_array(state->arena, Code_Index_Note, 1); + sll_queue_push(index->note_list.first, index->note_list.last, result); + index->note_list.count += 1; + result->note_kind = kind; + result->pos = range; + result->text = push_string_copy(state->arena, string_substring(state->contents, range)); + result->file = index; + result->parent = parent; + return(result); +} + +function void +cpp_parse_type_structure(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + if (state->finished){ + return; + } + Token *token = token_it_read(&state->it); + if (token != 0 && token->kind == TokenBaseKind_Identifier){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + Token *peek = token_it_read(&state->it); + if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || + peek->kind == TokenBaseKind_ScopeOpen){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); + } + } +} + +function void +cpp_parse_type_def(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + for (;;){ + b32 did_advance = false; + Token *token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + if (token->kind == TokenBaseKind_Identifier){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + did_advance = true; + Token *peek = token_it_read(&state->it); + if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || + peek->kind == TokenBaseKind_ParentheticalOpen){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); + break; + } + } + else if (token->kind == TokenBaseKind_StatementClose || + token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose){ + break; + } + else if (token->kind == TokenBaseKind_Keyword){ + String_Const_u8 lexeme = string_substring(state->contents, Ii64(token)); + if (string_match(lexeme, string_u8_litexpr("struct")) || + string_match(lexeme, string_u8_litexpr("union")) || + string_match(lexeme, string_u8_litexpr("enum"))){ + break; + } + } + if (!did_advance){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + } + } +} + +function void +cpp_parse_function(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + Token *token = token_it_read(&state->it); + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + if (state->finished){ + return; + } + Token *peek = token_it_read(&state->it); + Token *reset_point = peek; + if (peek != 0 && peek->sub_kind == TokenCppKind_ParenOp){ + b32 at_paren_close = false; + i32 paren_nest_level = 0; + for (; peek != 0;){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + peek = token_it_read(&state->it); + if (peek == 0 || state->finished){ + break; + } + + if (peek->kind == TokenBaseKind_ParentheticalOpen){ + paren_nest_level += 1; + } + else if (peek->kind == TokenBaseKind_ParentheticalClose){ + if (paren_nest_level > 0){ + paren_nest_level -= 1; + } + else{ + at_paren_close = true; + break; + } + } + } + + if (at_paren_close){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + peek = token_it_read(&state->it); + if (peek != 0 && + peek->kind == TokenBaseKind_ScopeOpen || + peek->kind == TokenBaseKind_StatementClose){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Function, parent); + } + } + } + state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); +} + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Statement; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_statement = true; + + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + + if (token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ParentheticalOpen){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (token->kind == TokenBaseKind_StatementClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + generic_parse_inc(state); + } + + state->in_statement = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Preprocessor; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_preprocessor = true; + + b32 potential_macro = false; + if (state->do_cpp_parse){ + if (token->sub_kind == TokenCppKind_PPDefine){ + potential_macro = true; + } + } + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (state->do_cpp_parse && potential_macro){ + if (token->sub_kind == TokenCppKind_Identifier){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Macro, result); + } + potential_macro = false; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->in_preprocessor = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Scope; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + state->scope_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ScopeClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + generic_parse_inc(state); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + + // NOTE(allen): after a parenthetical group we consider ourselves immediately + // transitioning into a statement + nest = generic_parse_statement(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + + continue; + } + + { + Code_Index_Nest *nest = generic_parse_statement(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + } + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->scope_counter -= 1; + + return(result); +} + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Paren; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + i64 manifested_characters_on_line = 0; + { + u8 *ptr = state->prev_line_start; + u8 *end_ptr = state->contents.str + token->pos; + // NOTE(allen): Initial whitespace + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + break; + } + } + // NOTE(allen): Manifested characters + manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; + } + + state->paren_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeClose){ + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->paren_counter -= 1; + + return(result); +} + +function b32 +generic_parse_full_input_breaks(Code_Index_File *index, Generic_Parse_State *state, i32 limit){ + b32 result = false; + + i64 first_index = token_it_index(&state->it); + i64 one_past_last_index = first_index + limit; + for (;;){ + generic_parse_skip_soft_tokens(index, state); + Token *token = token_it_read(&state->it); + + if (token == 0 || state->finished){ + result = true; + break; + } + + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (state->do_cpp_parse){ + if (token->sub_kind == TokenCppKind_Struct || + token->sub_kind == TokenCppKind_Union || + token->sub_kind == TokenCppKind_Enum){ + cpp_parse_type_structure(index, state, 0); + } + else if (token->sub_kind == TokenCppKind_Typedef){ + cpp_parse_type_def(index, state, 0); + } + else if (token->sub_kind == TokenCppKind_Identifier){ + cpp_parse_function(index, state, 0); + } + else{ + generic_parse_inc(state); + } + } + else{ + generic_parse_inc(state); + } + + i64 index = token_it_index(&state->it); + if (index >= one_past_last_index){ + token = token_it_read(&state->it); + if (token == 0){ + result = true; + } + break; + } + } + + if (result){ + index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); + index->note_array = code_index_note_ptr_array_from_list(state->arena, &index->note_list); + } + + return(result); +} + +//////////////////////////////// + +function void +default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, Token *token, String_Const_u8 contents){ + +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ + generic_parse_init(app, arena, contents, tokens, default_comment_index, state); +} + +//////////////////////////////// + +function Token_Pair +layout_token_pair(Token_Array *tokens, i64 pos){ + Token_Pair result = {}; + Token_Iterator_Array it = token_iterator_pos(0, tokens, pos); + Token *b = token_it_read(&it); + if (b != 0){ + if (b->kind == TokenBaseKind_Whitespace){ + token_it_inc_non_whitespace(&it); + b = token_it_read(&it); + } + } + token_it_dec_non_whitespace(&it); + Token *a = token_it_read(&it); + if (a != 0){ + result.a = *a; + } + if (b != 0){ + result.b = *b; + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 result = 0.f; + if (nest != 0){ + switch (nest->kind){ + case CodeIndexNest_Scope: + case CodeIndexNest_Preprocessor: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Statement: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Paren: + { + Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1, unresolved_dependence); + result = box.x1; + }break; + } + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, nest, pos, space_advance, &ignore)); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 indent = 0; + Code_Index_Nest *nest = code_index_get_nest(file, pos); + if (nest != 0){ + indent = layout_index_x_shift(app, reflex, nest, pos, space_advance, unresolved_dependence); + } + return(indent); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, file, pos, space_advance, &ignore)); +} + +function void +layout_index__emit_chunk(LefRig_TopBot_Layout_Vars *pos_vars, Face_ID face, Arena *arena, u8 *text_str, i64 range_first, u8 *ptr, u8 *end, Layout_Item_List *list){ + for (;ptr < end;){ + Character_Consume_Result consume = utf8_consume(ptr, (u64)(end - ptr)); + if (consume.codepoint != '\r'){ + i64 index = layout_index_from_ptr(ptr, text_str, range_first); + if (consume.codepoint != max_u32){ + lr_tb_write(pos_vars, face, arena, list, index, consume.codepoint); + } + else{ + lr_tb_write_byte(pos_vars, face, arena, list, index, *ptr); + } + } + ptr += consume.inc; + } +} + +function i32 +layout_token_score_wrap_token(Token_Pair *pair, Token_Cpp_Kind kind){ + i32 result = 0; + if (pair->a.sub_kind != kind && pair->b.sub_kind == kind){ + result -= 1; + } + else if (pair->a.sub_kind == kind && pair->b.sub_kind != kind){ + result += 1; + } + return(result); +} + +function Layout_Item_List +layout_index__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file, Layout_Wrap_Kind kind){ + Scratch_Block scratch(app); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); + + Layout_Item_List list = get_empty_item_list(range); + String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); + + Face_Advance_Map advance_map = get_face_advance_map(app, face); + Face_Metrics metrics = get_face_metrics(app, face); + LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); + + f32 wrap_align_x = width - metrics.normal_advance; + + Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); + + if (text.size == 0){ + lr_tb_write_blank(&pos_vars, face, arena, &list, range.start); + } + else{ + b32 first_of_the_line = true; + Newline_Layout_Vars newline_vars = get_newline_layout_vars(); + + u8 *ptr = text.str; + u8 *end_ptr = ptr + text.size; + u8 *word_ptr = ptr; + + u8 *pending_wrap_ptr = ptr; + f32 pending_wrap_x = 0.f; + i32 pending_wrap_paren_nest_count = 0; + i32 pending_wrap_token_score = 0; + f32 pending_wrap_accumulated_w = 0.f; + + start: + if (ptr == end_ptr){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + + if (!character_is_whitespace(*ptr)){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + + { + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + pending_wrap_ptr = ptr; + word_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + if (*ptr == '\n'){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_normal_whitespace; + } + } + + if (ptr == end_ptr){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr - 1, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + } + + consuming_non_whitespace: + { + for (;ptr <= end_ptr; ptr += 1){ + if (ptr == end_ptr || character_is_whitespace(*ptr)){ + break; + } + } + + // NOTE(allen): measure this word + newline_layout_consume_default(&newline_vars); + String_Const_u8 word = SCu8(word_ptr, ptr); + u8 *word_end = ptr; + { + f32 word_advance = 0.f; + ptr = word.str; + for (;ptr < word_end;){ + Character_Consume_Result consume = utf8_consume(ptr, (u64)(word_end - ptr)); + if (consume.codepoint != max_u32){ + word_advance += lr_tb_advance(&pos_vars, face, consume.codepoint); + } + else{ + word_advance += lr_tb_advance_byte(&pos_vars); + } + ptr += consume.inc; + } + pending_wrap_accumulated_w += word_advance; + } + + if (!first_of_the_line && (kind == Layout_Wrapped) && lr_tb_crosses_width(&pos_vars, pending_wrap_accumulated_w)){ + i64 index = layout_index_from_ptr(pending_wrap_ptr, text.str, range.first); + lr_tb_align_rightward(&pos_vars, wrap_align_x); + lr_tb_write_ghost(&pos_vars, face, arena, &list, index, '\\'); + + lr_tb_next_line(&pos_vars); +#if 0 + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); +#endif + + ptr = pending_wrap_ptr; + pending_wrap_accumulated_w = 0.f; + first_of_the_line = true; + goto start; + } + } + + consuming_normal_whitespace: + for (; ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + u8 *new_wrap_ptr = ptr; + + i64 index = layout_index_from_ptr(new_wrap_ptr, text.str, range.first); + Code_Index_Nest *new_wrap_nest = code_index_get_nest(file, index); + b32 invalid_wrap_x = false; + f32 new_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance, &invalid_wrap_x); + if (invalid_wrap_x){ + new_wrap_x = max_f32; + } + + i32 new_wrap_paren_nest_count = 0; + for (Code_Index_Nest *nest = new_wrap_nest; + nest != 0; + nest = nest->parent){ + if (nest->kind == CodeIndexNest_Paren){ + new_wrap_paren_nest_count += 1; + } + } + + Token_Pair new_wrap_token_pair = layout_token_pair(tokens_ptr, index); + + // TODO(allen): pull out the token scoring part and make it replacable for other + // language's token based wrap scoring needs. + i32 token_score = 0; + if (new_wrap_token_pair.a.kind == TokenBaseKind_Keyword){ + if (new_wrap_token_pair.b.kind == TokenBaseKind_ParentheticalOpen || + new_wrap_token_pair.b.kind == TokenBaseKind_Keyword){ + token_score -= 2; + } + } + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Eq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_PlusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_MinusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_StarEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_DivEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_ModEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_LeftLeftEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_RightRightEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Comma); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_AndAnd); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_OrOr); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Ternary); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Colon); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Semicolon); + + i32 new_wrap_token_score = token_score; + + b32 new_wrap_ptr_is_better = false; + if (first_of_the_line){ + new_wrap_ptr_is_better = true; + } + else{ + if (new_wrap_token_score > pending_wrap_token_score){ + new_wrap_ptr_is_better = true; + } + else if (new_wrap_token_score == pending_wrap_token_score){ + f32 new_score = new_wrap_paren_nest_count*10.f + new_wrap_x; + f32 old_score = pending_wrap_paren_nest_count*10.f + pending_wrap_x + metrics.normal_advance*4.f + pending_wrap_accumulated_w*0.5f; + + if (new_score < old_score){ + new_wrap_ptr_is_better = true; + } + } + } + + if (new_wrap_ptr_is_better){ + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, new_wrap_ptr, &list); + first_of_the_line = false; + + pending_wrap_ptr = new_wrap_ptr; + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance); + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_token_score = new_wrap_token_score; + pending_wrap_accumulated_w = 0.f; + } + + word_ptr = ptr; + goto consuming_non_whitespace; + } + + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + switch (*ptr){ + default: + { + newline_layout_consume_default(&newline_vars); + pending_wrap_accumulated_w += lr_tb_advance(&pos_vars, face, *ptr); + }break; + + case '\r': + { + newline_layout_consume_CR(&newline_vars, index); + }break; + + case '\n': + { + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + pending_wrap_ptr = ptr + 1; + pending_wrap_accumulated_w = 0.f; + + u64 newline_index = newline_layout_consume_LF(&newline_vars, index); + lr_tb_write_blank(&pos_vars, face, arena, &list, newline_index); + lr_tb_next_line(&pos_vars); + first_of_the_line = true; + ptr += 1; + goto start; + }break; + } + } + + finish: + if (newline_layout_consume_finish(&newline_vars)){ + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + lr_tb_write_blank(&pos_vars, face, arena, &list, index); + } + } + + layout_item_list_finish(&list, -pos_vars.line_to_text_shift); + + return(list); +} + +function Layout_Item_List +layout_virt_indent_index(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ + Layout_Item_List result = {}; + + if (global_config.enable_virtual_whitespace){ + code_index_lock(); + Code_Index_File *file = code_index_get_file(buffer); + if (file != 0){ + result = layout_index__inner(app, arena, buffer, range, face, width, file, kind); + } + code_index_unlock(); + if (file == 0){ + result = layout_virt_indent_literal(app, arena, buffer, range, face, width, kind); + } + } + else{ + result = layout_basic(app, arena, buffer, range, face, width, kind); + } + + return(result); +} + +function Layout_Item_List +layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Unwrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Wrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); + return(layout_virt_indent_index(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); +} + +CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) +CUSTOM_DOC("Toggles the current buffer's virtual whitespace status.") +{ + global_config.enable_virtual_whitespace = !global_config.enable_virtual_whitespace; + + for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); + buffer != 0; + buffer = get_buffer_next(app, buffer, Access_Always)){ + buffer_clear_layout_cache(app, buffer); + } +} + +// BOTTOM + +#if 0 +======= +/* +4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. +*/ + +// TOP + +global Code_Index global_code_index = {}; + +function void +code_index_init(void){ + global_code_index.mutex = system_mutex_make(); + global_code_index.node_arena = make_arena_system(KB(4)); + global_code_index.buffer_to_index_file = make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); +} + +function Code_Index_File_Storage* +code_index__alloc_storage(void){ + Code_Index_File_Storage *result = global_code_index.free_storage; + if (result == 0){ + result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); + } + else{ + sll_stack_pop(global_code_index.free_storage); + } + zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); + global_code_index.storage_count += 1; + return(result); +} + +function void +code_index__free_storage(Code_Index_File_Storage *storage){ + zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); + global_code_index.storage_count -= 1; + sll_stack_push(global_code_index.free_storage, storage); +} + +function void +code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ + sll_queue_push(list->first, list->last, nest); + list->count += 1; +} + +function Code_Index_Nest_Ptr_Array +code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ + Code_Index_Nest_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Nest *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function Code_Index_Note_Ptr_Array +code_index_note_ptr_array_from_list(Arena *arena, Code_Index_Note_List *list){ + Code_Index_Note_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Note*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Note *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function void +code_index_lock(void){ + system_mutex_acquire(global_code_index.mutex); +} + +function void +code_index_unlock(void){ + system_mutex_release(global_code_index.mutex); +} + +function void +code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ + Code_Index_File_Storage *storage = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + } + else{ + storage = code_index__alloc_storage(); + table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); + } + storage->arena = arena; + storage->file = index; +} + +function void +code_index_erase_file(Buffer_ID buffer){ + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + table_erase(&global_code_index.buffer_to_index_file, lookup); + code_index__free_storage(storage); + } +} + +function Code_Index_File* +code_index_get_file(Buffer_ID buffer){ + Code_Index_File *result = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + result = storage->file; + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest_Ptr_Array *array, i64 pos){ + Code_Index_Nest *result = 0; + i32 count = array->count; + Code_Index_Nest **nest_ptrs = array->ptrs; + for (i32 i = 0; i < count; i += 1){ + Code_Index_Nest *nest = nest_ptrs[i]; + if (nest->open.max <= pos && pos <= nest->close.min){ + Code_Index_Nest *sub_nest = + code_index_get_nest(&nest->nest_array, pos); + if (sub_nest != 0){ + result = sub_nest; + } + else{ + result = nest; + } + break; + } + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest *nest, i64 pos){ + return(code_index_get_nest(&nest->nest_array, pos)); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_File *file, i64 pos){ + return(code_index_get_nest(&file->nest_array, pos)); +} + +function void +index_shift(i64 *ptr, Range_i64 old_range, u64 new_size){ + i64 i = *ptr; + if (old_range.min <= i && i < old_range.max){ + *ptr = old_range.first; + } + else if (old_range.max <= i){ + *ptr = i + new_size - (old_range.max - old_range.min); + } +} + +function void +code_index_shift(Code_Index_Nest_Ptr_Array *array, + Range_i64 old_range, u64 new_size){ + i32 count = array->count; + Code_Index_Nest **nest_ptr = array->ptrs; + for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ + Code_Index_Nest *nest = *nest_ptr; + index_shift(&nest->open.min, old_range, new_size); + index_shift(&nest->open.max, old_range, new_size); + if (nest->is_closed){ + index_shift(&nest->close.min, old_range, new_size); + index_shift(&nest->close.max, old_range, new_size); + } + code_index_shift(&nest->nest_array, old_range, new_size); + } +} + +function void +code_index_shift(Code_Index_File *file, Range_i64 old_range, u64 new_size){ + code_index_shift(&file->nest_array, old_range, new_size); +} + +//////////////////////////////// + +function void +generic_parse_inc(Generic_Parse_State *state){ + if (!token_it_inc_all(&state->it)){ + state->finished = true; + } +} + +function void +generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + for (;token != 0 && !state->finished;){ + if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ + break; + } + if (token->kind == TokenBaseKind_Comment){ + state->handle_comment(state->app, state->arena, index, token, state->contents); + } + else if (token->kind == TokenBaseKind_Whitespace){ + Range_i64 range = Ii64(token); + u8 *ptr = state->contents.str + range.one_past_last - 1; + for (i64 i = range.one_past_last - 1; + i >= range.first; + i -= 1, ptr -= 1){ + if (*ptr == '\n'){ + state->prev_line_start = ptr + 1; + break; + } + } + } + else{ + break; + } + generic_parse_inc(state); + token = token_it_read(&state->it); + } +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ + state->app = app; + state->arena = arena; + state->contents = contents; + state->it = token_iterator(0, tokens); + state->handle_comment = handle_comment; + state->prev_line_start = contents.str; +} + +//////////////////////////////// + +#if 0 +// NOTE(allen): grammar syntax +(X) = X +X Y = X and then Y +X? = zero or one X +$X = check for X but dont consume // NOTE(yuval): Removed apostrophe as it was causing a warning when compiling with gcc +[X] = zero or more Xs +X | Y = either X or Y +* = anything that does not match previous options in a X | Y | ... chain +* - X = anything that does not match X or previous options in a Y | Z | ... chain + = a token of type X +"X" = literally the string "X" +X{Y} = X with flag Y + +// NOTE(allen): grammar of code index parse +file: [preprocessor | scope | parens | function | type | * - ] +preprocessor: [scope | parens | stmnt]{pp-body} +scope: [preprocessor | scope | parens | * - ] +paren: [preprocessor | scope | parens | * - ] +stmnt-close-pattern: | | | | | +stmnt: [type | * - stmnt-close-pattern] stmnt-close-pattern +type: struct | union | enum | typedef +struct: "struct" $(";" | "{") +union: "union" $(";" | "{") +enum: "enum" $(";" | "{") +typedef: "typedef" [* - ( (";" | "("))] $(";" | "(") +function: >"(" [* - ("(" | ")" | "{" | "}" | ";")] ")" ("{" | ";") + +#endif + +//////////////////////////////// + +function Code_Index_Note* +index_new_note(Code_Index_File *index, Generic_Parse_State *state, Range_i64 range, Code_Index_Note_Kind kind, Code_Index_Nest *parent){ + Code_Index_Note *result = push_array(state->arena, Code_Index_Note, 1); + sll_queue_push(index->note_list.first, index->note_list.last, result); + index->note_list.count += 1; + result->note_kind = kind; + result->pos = range; + result->text = push_string_copy(state->arena, string_substring(state->contents, range)); + result->file = index; + result->parent = parent; + return(result); +} + +function void +cpp_parse_type_structure(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + if (state->finished){ + return; + } + Token *token = token_it_read(&state->it); + if (token != 0 && token->kind == TokenBaseKind_Identifier){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + Token *peek = token_it_read(&state->it); + if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || + peek->kind == TokenBaseKind_ScopeOpen){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); + } + } +} + +function void +cpp_parse_type_def(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + for (;;){ + b32 did_advance = false; + Token *token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + if (token->kind == TokenBaseKind_Identifier){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + did_advance = true; + Token *peek = token_it_read(&state->it); + if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || + peek->kind == TokenBaseKind_ParentheticalOpen){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); + break; + } + } + else if (token->kind == TokenBaseKind_StatementClose || + token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose){ + break; + } + else if (token->kind == TokenBaseKind_Keyword){ + String_Const_u8 lexeme = string_substring(state->contents, Ii64(token)); + if (string_match(lexeme, string_u8_litexpr("struct")) || + string_match(lexeme, string_u8_litexpr("union")) || + string_match(lexeme, string_u8_litexpr("enum"))){ + break; + } + } + if (!did_advance){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + } + } +} + +function void +cpp_parse_function(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ + Token *token = token_it_read(&state->it); + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + if (state->finished){ + return; + } + Token *peek = token_it_read(&state->it); + Token *reset_point = peek; + if (peek != 0 && peek->sub_kind == TokenCppKind_ParenOp){ + b32 at_paren_close = false; + for (; peek != 0;){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + peek = token_it_read(&state->it); + if (peek == 0 || state->finished){ + break; + } + + if (peek->kind == TokenBaseKind_ParentheticalOpen || + peek->kind == TokenBaseKind_ScopeOpen || + peek->kind == TokenBaseKind_ScopeClose || + peek->kind == TokenBaseKind_StatementClose){ + break; + } + if (peek->kind == TokenBaseKind_ParentheticalClose){ + at_paren_close = true; + break; + } + } + + if (at_paren_close){ + generic_parse_inc(state); + generic_parse_skip_soft_tokens(index, state); + peek = token_it_read(&state->it); + if (peek != 0 && + peek->kind == TokenBaseKind_ScopeOpen || + peek->kind == TokenBaseKind_StatementClose){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Function, parent); + } + } + } + state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); +} + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Statement; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_statement = true; + + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + + if (token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ParentheticalOpen){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (token->kind == TokenBaseKind_StatementClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + generic_parse_inc(state); + } + + state->in_statement = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Preprocessor; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_preprocessor = true; + + b32 potential_macro = false; + if (state->do_cpp_parse){ + if (token->sub_kind == TokenCppKind_PPDefine){ + potential_macro = true; + } + } + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (state->do_cpp_parse && potential_macro){ + if (token->sub_kind == TokenCppKind_Identifier){ + index_new_note(index, state, Ii64(token), CodeIndexNote_Macro, result); + } + potential_macro = false; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->in_preprocessor = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Scope; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + state->scope_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ScopeClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + generic_parse_inc(state); + continue; + } + + { + Code_Index_Nest *nest = generic_parse_statement(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + } + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->scope_counter -= 1; + + return(result); +} + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Paren; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + i64 manifested_characters_on_line = 0; + { + u8 *ptr = state->prev_line_start; + u8 *end_ptr = state->contents.str + token->pos; + // NOTE(allen): Initial whitespace + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + break; + } + } + // NOTE(allen): Manifested characters + manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; + } + + state->paren_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeClose){ + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->paren_counter -= 1; + + return(result); +} + +function b32 +generic_parse_full_input_breaks(Code_Index_File *index, Generic_Parse_State *state, i32 limit){ + b32 result = false; + + i64 first_index = token_it_index(&state->it); + i64 one_past_last_index = first_index + limit; + for (;;){ + generic_parse_skip_soft_tokens(index, state); + Token *token = token_it_read(&state->it); + + if (token == 0 || state->finished){ + result = true; + break; + } + + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (state->do_cpp_parse){ + if (token->sub_kind == TokenCppKind_Struct || + token->sub_kind == TokenCppKind_Union || + token->sub_kind == TokenCppKind_Enum){ + cpp_parse_type_structure(index, state, 0); + } + else if (token->sub_kind == TokenCppKind_Typedef){ + cpp_parse_type_def(index, state, 0); + } + else if (token->sub_kind == TokenCppKind_Identifier){ + cpp_parse_function(index, state, 0); + } + else{ + generic_parse_inc(state); + } + } + else{ + generic_parse_inc(state); + } + + i64 index = token_it_index(&state->it); + if (index >= one_past_last_index){ + token = token_it_read(&state->it); + if (token == 0){ + result = true; + } + break; + } + } + + if (result){ + index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); + index->note_array = code_index_note_ptr_array_from_list(state->arena, &index->note_list); + } + + return(result); +} + +//////////////////////////////// + +function void +default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, Token *token, String_Const_u8 contents){ + +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ + generic_parse_init(app, arena, contents, tokens, default_comment_index, state); +} + +//////////////////////////////// + +function Token_Pair +layout_token_pair(Token_Array *tokens, i64 pos){ + Token_Pair result = {}; + Token_Iterator_Array it = token_iterator_pos(0, tokens, pos); + Token *b = token_it_read(&it); + if (b != 0){ + if (b->kind == TokenBaseKind_Whitespace){ + token_it_inc_non_whitespace(&it); + b = token_it_read(&it); + } + } + token_it_dec_non_whitespace(&it); + Token *a = token_it_read(&it); + if (a != 0){ + result.a = *a; + } + if (b != 0){ + result.b = *b; + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 result = 0.f; + if (nest != 0){ + switch (nest->kind){ + case CodeIndexNest_Scope: + case CodeIndexNest_Preprocessor: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Statement: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Paren: + { + Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1, unresolved_dependence); + result = box.x1; + }break; + } + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, nest, pos, space_advance, &ignore)); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 indent = 0; + Code_Index_Nest *nest = code_index_get_nest(file, pos); + if (nest != 0){ + indent = layout_index_x_shift(app, reflex, nest, pos, space_advance, unresolved_dependence); + } + return(indent); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, file, pos, space_advance, &ignore)); +} + +function void +layout_index__emit_chunk(LefRig_TopBot_Layout_Vars *pos_vars, Face_ID face, Arena *arena, u8 *text_str, i64 range_first, u8 *ptr, u8 *end, Layout_Item_List *list){ + for (;ptr < end;){ + Character_Consume_Result consume = utf8_consume(ptr, (u64)(end - ptr)); + if (consume.codepoint != '\r'){ + i64 index = layout_index_from_ptr(ptr, text_str, range_first); + if (consume.codepoint != max_u32){ + lr_tb_write(pos_vars, face, arena, list, index, consume.codepoint); + } + else{ + lr_tb_write_byte(pos_vars, face, arena, list, index, *ptr); + } + } + ptr += consume.inc; + } +} + +function i32 +layout_token_score_wrap_token(Token_Pair *pair, Token_Cpp_Kind kind){ + i32 result = 0; + if (pair->a.sub_kind != kind && pair->b.sub_kind == kind){ + result -= 1; + } + else if (pair->a.sub_kind == kind && pair->b.sub_kind != kind){ + result += 1; + } + return(result); +} + +function Layout_Item_List +layout_index__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file, Layout_Wrap_Kind kind){ + Scratch_Block scratch(app); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); + + Layout_Item_List list = get_empty_item_list(range); + String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); + + Face_Advance_Map advance_map = get_face_advance_map(app, face); + Face_Metrics metrics = get_face_metrics(app, face); + LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); + + f32 wrap_align_x = width - metrics.normal_advance; + + Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); + + if (text.size == 0){ + lr_tb_write_blank(&pos_vars, face, arena, &list, range.start); + } + else{ + b32 first_of_the_line = true; + Newline_Layout_Vars newline_vars = get_newline_layout_vars(); + + u8 *ptr = text.str; + u8 *end_ptr = ptr + text.size; + u8 *word_ptr = ptr; + + u8 *pending_wrap_ptr = ptr; + f32 pending_wrap_x = 0.f; + i32 pending_wrap_paren_nest_count = 0; + i32 pending_wrap_token_score = 0; + f32 pending_wrap_accumulated_w = 0.f; + + start: + if (ptr == end_ptr){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + + if (!character_is_whitespace(*ptr)){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + + { + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + pending_wrap_ptr = ptr; + word_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + if (*ptr == '\n'){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_normal_whitespace; + } + } + + if (ptr == end_ptr){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr - 1, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + } + + consuming_non_whitespace: + { + for (;ptr <= end_ptr; ptr += 1){ + if (ptr == end_ptr || character_is_whitespace(*ptr)){ + break; + } + } + + // NOTE(allen): measure this word + newline_layout_consume_default(&newline_vars); + String_Const_u8 word = SCu8(word_ptr, ptr); + u8 *word_end = ptr; + { + f32 word_advance = 0.f; + ptr = word.str; + for (;ptr < word_end;){ + Character_Consume_Result consume = utf8_consume(ptr, (u64)(word_end - ptr)); + if (consume.codepoint != max_u32){ + word_advance += lr_tb_advance(&pos_vars, face, consume.codepoint); + } + else{ + word_advance += lr_tb_advance_byte(&pos_vars); + } + ptr += consume.inc; + } + pending_wrap_accumulated_w += word_advance; + } + + if (!first_of_the_line && (kind == Layout_Wrapped) && lr_tb_crosses_width(&pos_vars, pending_wrap_accumulated_w)){ + i64 index = layout_index_from_ptr(pending_wrap_ptr, text.str, range.first); + lr_tb_align_rightward(&pos_vars, wrap_align_x); + lr_tb_write_ghost(&pos_vars, face, arena, &list, index, '\\'); + + lr_tb_next_line(&pos_vars); +#if 0 + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); +#endif + + ptr = pending_wrap_ptr; + pending_wrap_accumulated_w = 0.f; + first_of_the_line = true; + goto start; + } + } + + consuming_normal_whitespace: + for (; ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + u8 *new_wrap_ptr = ptr; + + i64 index = layout_index_from_ptr(new_wrap_ptr, text.str, range.first); + Code_Index_Nest *new_wrap_nest = code_index_get_nest(file, index); + b32 invalid_wrap_x = false; + f32 new_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance, &invalid_wrap_x); + if (invalid_wrap_x){ + new_wrap_x = max_f32; + } + + i32 new_wrap_paren_nest_count = 0; + for (Code_Index_Nest *nest = new_wrap_nest; + nest != 0; + nest = nest->parent){ + if (nest->kind == CodeIndexNest_Paren){ + new_wrap_paren_nest_count += 1; + } + } + + Token_Pair new_wrap_token_pair = layout_token_pair(tokens_ptr, index); + + // TODO(allen): pull out the token scoring part and make it replacable for other + // language's token based wrap scoring needs. + i32 token_score = 0; + if (new_wrap_token_pair.a.kind == TokenBaseKind_Keyword){ + if (new_wrap_token_pair.b.kind == TokenBaseKind_ParentheticalOpen || + new_wrap_token_pair.b.kind == TokenBaseKind_Keyword){ + token_score -= 2; + } + } + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Eq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_PlusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_MinusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_StarEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_DivEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_ModEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_LeftLeftEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_RightRightEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Comma); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_AndAnd); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_OrOr); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Ternary); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Colon); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Semicolon); + + i32 new_wrap_token_score = token_score; + + b32 new_wrap_ptr_is_better = false; + if (first_of_the_line){ + new_wrap_ptr_is_better = true; + } + else{ + if (new_wrap_token_score > pending_wrap_token_score){ + new_wrap_ptr_is_better = true; + } + else if (new_wrap_token_score == pending_wrap_token_score){ + f32 new_score = new_wrap_paren_nest_count*10.f + new_wrap_x; + f32 old_score = pending_wrap_paren_nest_count*10.f + pending_wrap_x + metrics.normal_advance*4.f + pending_wrap_accumulated_w*0.5f; + + if (new_score < old_score){ + new_wrap_ptr_is_better = true; + } + } + } + + if (new_wrap_ptr_is_better){ + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, new_wrap_ptr, &list); + first_of_the_line = false; + + pending_wrap_ptr = new_wrap_ptr; + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance); + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_token_score = new_wrap_token_score; + pending_wrap_accumulated_w = 0.f; + } + + word_ptr = ptr; + goto consuming_non_whitespace; + } + + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + switch (*ptr){ + default: + { + newline_layout_consume_default(&newline_vars); + pending_wrap_accumulated_w += lr_tb_advance(&pos_vars, face, *ptr); + }break; + + case '\r': + { + newline_layout_consume_CR(&newline_vars, index); + }break; + + case '\n': + { + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + pending_wrap_ptr = ptr + 1; + pending_wrap_accumulated_w = 0.f; + + u64 newline_index = newline_layout_consume_LF(&newline_vars, index); + lr_tb_write_blank(&pos_vars, face, arena, &list, newline_index); + lr_tb_next_line(&pos_vars); + first_of_the_line = true; + ptr += 1; + goto start; + }break; + } + } + + finish: + if (newline_layout_consume_finish(&newline_vars)){ + layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + lr_tb_write_blank(&pos_vars, face, arena, &list, index); + } + } + + layout_item_list_finish(&list, -pos_vars.line_to_text_shift); + + return(list); +} + +function Layout_Item_List +layout_virt_indent_index(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ + Layout_Item_List result = {}; + + if (global_config.enable_virtual_whitespace){ + code_index_lock(); + Code_Index_File *file = code_index_get_file(buffer); + if (file != 0){ + result = layout_index__inner(app, arena, buffer, range, face, width, file, kind); + } + code_index_unlock(); + if (file == 0){ + result = layout_virt_indent_literal(app, arena, buffer, range, face, width, kind); + } + } + else{ + result = layout_basic(app, arena, buffer, range, face, width, kind); + } + + return(result); +} + +function Layout_Item_List +layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Unwrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Wrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); + return(layout_virt_indent_index(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); +} + +CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) +CUSTOM_DOC("Toggles the current buffer's virtual whitespace status.") +{ + global_config.enable_virtual_whitespace = !global_config.enable_virtual_whitespace; + + for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); + buffer != 0; + buffer = get_buffer_next(app, buffer, Access_Always)){ + buffer_clear_layout_cache(app, buffer); + } +} + +// BOTTOM + +>>>>>>> yuval_macos_platform_layer +#endif diff --git a/custom/4coder_command_map.cpp b/custom/4coder_command_map.cpp index d2114d07..0d0ae016 100644 --- a/custom/4coder_command_map.cpp +++ b/custom/4coder_command_map.cpp @@ -425,21 +425,21 @@ function Command_Trigger_List map_get_triggers_recursive(Arena *arena, Mapping *mapping, Command_Map *map, Command_Binding binding){ Command_Trigger_List result = {}; if (mapping != 0){ - for (i32 safety_counter = 0; - map != 0 && safety_counter < 40; - safety_counter += 1){ - Command_Trigger_List list = map_get_triggers_non_recursive(mapping, map, binding); - - for (Command_Trigger *node = list.first, *next = 0; - node != 0; - node = next){ - next = node->next; - Command_Trigger *nnode = push_array_write(arena, Command_Trigger, 1, node); - sll_queue_push(result.first, result.last, nnode); + for (i32 safety_counter = 0; + map != 0 && safety_counter < 40; + safety_counter += 1){ + Command_Trigger_List list = map_get_triggers_non_recursive(mapping, map, binding); + + for (Command_Trigger *node = list.first, *next = 0; + node != 0; + node = next){ + next = node->next; + Command_Trigger *nnode = push_array_write(arena, Command_Trigger, 1, node); + sll_queue_push(result.first, result.last, nnode); + } + + map = mapping_get_map(mapping, map->parent); } - - map = mapping_get_map(mapping, map->parent); - } } return(result); } @@ -721,7 +721,7 @@ map_set_binding_l(Mapping *mapping, Command_Map *map, Custom_Command_Function *c va_start(args, code2); Command_Binding binding = {}; binding.custom = custom; - map_set_binding_lv(mapping, map, binding, code1, code2, args); + map_set_binding_lv(mapping, map, binding, code1, code2, args); va_end(args); } #endif @@ -755,7 +755,7 @@ map_set_binding_l(m, map, BindFWrap_(F), InputEventKind_MouseMove, 0, __VA_ARGS_ #define BindCore(F, K, ...) \ map_set_binding_l(m, map, BindFWrap_(F), InputEventKind_Core, (K), __VA_ARGS__, 0) -#elif COMPILER_GCC +#elif COMPILER_GCC | COMPILER_CLANG #define Bind(F, K, ...) \ map_set_binding_l(m, map, BindFWrap_(F), InputEventKind_KeyStroke, (K), ##__VA_ARGS__, 0) diff --git a/custom/4coder_config.cpp b/custom/4coder_config.cpp index bb283b16..753b09d6 100644 --- a/custom/4coder_config.cpp +++ b/custom/4coder_config.cpp @@ -1,1617 +1,1671 @@ -/* -4coder_config.cpp - Parsing *.4coder files. -*/ - -// TOP - -function String_Const_u8_Array -parse_extension_line_to_extension_list(Application_Links *app, - Arena *arena, String_Const_u8 str){ - ProfileScope(app, "parse extension line to extension list"); - i32 count = 0; - for (u64 i = 0; i < str.size; i += 1){ - if (str.str[i] == '.'){ - count += 1; - } - } - - String_Const_u8_Array array = {}; - array.count = count; - array.strings = push_array(arena, String_Const_u8, count); - - push_align(arena, 1); - str = string_skip(str, string_find_first(str, '.') + 1); - for (i32 i = 0; i < count; i += 1){ - u64 next_period = string_find_first(str, '.'); - String_Const_u8 extension = string_prefix(str, next_period); - str = string_skip(str, next_period + 1); - array.strings[i] = push_string_copy(arena, extension); - } - push_align(arena, 8); - - return(array); -} - -//////////////////////////////// - -function Error_Location -get_error_location(Application_Links *app, u8 *base, u8 *pos){ - ProfileScope(app, "get error location"); - Error_Location location = {}; - location.line_number = 1; - location.column_number = 1; - for (u8 *ptr = base; - ptr < pos; - ptr += 1){ - if (*ptr == '\n'){ - location.line_number += 1; - location.column_number = 1; - } - else{ - location.column_number += 1; - } - } - return(location); -} - -function String_Const_u8 -config_stringize_errors(Application_Links *app, Arena *arena, Config *parsed){ - ProfileScope(app, "stringize errors"); - String_Const_u8 result = {}; - if (parsed->errors.first != 0){ - List_String_Const_u8 list = {}; - for (Config_Error *error = parsed->errors.first; - error != 0; - error = error->next){ - Error_Location location = get_error_location(app, parsed->data.str, error->pos); - string_list_pushf(arena, &list, "%.*s:%d:%d: %.*s\n", - string_expand(error->file_name), location.line_number, location.column_number, string_expand(error->text)); - } - result = string_list_flatten(arena, list); - } - return(result); -} - -//////////////////////////////// - -function void -config_parser__advance_to_next(Config_Parser *ctx){ - Token *t = ctx->token; - Token *e = ctx->end; - for (t += 1; - t < e && (t->kind == TokenBaseKind_Comment || - t->kind == TokenBaseKind_Whitespace); - t += 1); - ctx->token = t; -} - -function Config_Parser -make_config_parser(Arena *arena, String_Const_u8 file_name, String_Const_u8 data, Token_Array array){ - Config_Parser ctx = {}; - ctx.start = array.tokens; - ctx.token = ctx.start - 1; - ctx.end = ctx.start + array.count; - ctx.file_name = file_name; - ctx.data = data; - ctx.arena = arena; - config_parser__advance_to_next(&ctx); - return(ctx); -} - -function b32 -config_parser__recognize_base_token(Config_Parser *ctx, Token_Base_Kind kind){ - b32 result = false; - if (ctx->start <= ctx->token && ctx->token < ctx->end){ - result = (ctx->token->kind == kind); - } - else if (kind == TokenBaseKind_EOF){ - result = true; - } - return(result); -} - -function b32 -config_parser__recognize_token(Config_Parser *ctx, Token_Cpp_Kind kind){ - b32 result = false; - if (ctx->start <= ctx->token && ctx->token < ctx->end){ - result = (ctx->token->sub_kind == kind); - } - else if (kind == TokenCppKind_EOF){ - result = true; - } - return(result); -} - -function b32 -config_parser__recognize_boolean(Config_Parser *ctx){ - b32 result = false; - Token *token = ctx->token; - if (ctx->start <= ctx->token && ctx->token < ctx->end){ - result = (token->sub_kind == TokenCppKind_LiteralTrue || - token->sub_kind == TokenCppKind_LiteralFalse); - } - return(result); -} - -function String_Const_u8 -config_parser__get_lexeme(Config_Parser *ctx){ - String_Const_u8 lexeme = {}; - Token *token = ctx->token; - if (ctx->start <= token && token < ctx->end){ - lexeme = SCu8(ctx->data.str + token->pos, token->size); - } - return(lexeme); -} - -function Config_Integer -config_parser__get_int(Config_Parser *ctx){ - Config_Integer config_integer = {}; - String_Const_u8 str = config_parser__get_lexeme(ctx); - if (string_match(string_prefix(str, 2), string_u8_litexpr("0x"))){ - config_integer.is_signed = false; - config_integer.uinteger = (u32)(string_to_integer(string_skip(str, 2), 16)); - } - else{ - b32 is_negative = (string_get_character(str, 0) == '-'); - if (is_negative){ - str = string_skip(str, 1); - } - config_integer.is_signed = true; - config_integer.integer = (i32)(string_to_integer(str, 10)); - if (is_negative){ - config_integer.integer *= -1; - } - } - return(config_integer); -} - -function b32 -config_parser__get_boolean(Config_Parser *ctx){ - String_Const_u8 str = config_parser__get_lexeme(ctx); - return(string_match(str, string_u8_litexpr("true"))); -} - -function b32 -config_parser__recognize_text(Config_Parser *ctx, String_Const_u8 text){ - String_Const_u8 lexeme = config_parser__get_lexeme(ctx); - return(lexeme.str != 0 && string_match(lexeme, text)); -} - -function b32 -config_parser__match_token(Config_Parser *ctx, Token_Cpp_Kind kind){ - b32 result = config_parser__recognize_token(ctx, kind); - if (result){ - config_parser__advance_to_next(ctx); - } - return(result); -} - -function b32 -config_parser__match_text(Config_Parser *ctx, String_Const_u8 text){ - b32 result = config_parser__recognize_text(ctx, text); - if (result){ - config_parser__advance_to_next(ctx); - } - return(result); -} - -#define config_parser__match_text_lit(c,s) config_parser__match_text((c), string_u8_litexpr(s)) - -function Config *config_parser__config (Config_Parser *ctx); -function i32 *config_parser__version (Config_Parser *ctx); -function Config_Assignment *config_parser__assignment(Config_Parser *ctx); -function Config_LValue *config_parser__lvalue (Config_Parser *ctx); -function Config_RValue *config_parser__rvalue (Config_Parser *ctx); -function Config_Compound *config_parser__compound (Config_Parser *ctx); -function Config_Compound_Element *config_parser__element (Config_Parser *ctx); - -function Config* -config_parse(Application_Links *app, Arena *arena, String_Const_u8 file_name, - String_Const_u8 data, Token_Array array){ - ProfileScope(app, "config parse"); - Temp_Memory restore_point = begin_temp(arena); - Config_Parser ctx = make_config_parser(arena, file_name, data, array); - Config *config = config_parser__config(&ctx); - if (config == 0){ - end_temp(restore_point); - } - return(config); -} - -// TODO(allen): Move to string library -function Config_Error* -config_error_push(Arena *arena, Config_Error_List *list, String_Const_u8 file_name, - u8 *pos, char *error_text){ - Config_Error *error = push_array(arena, Config_Error, 1); - zdll_push_back(list->first, list->last, error); - list->count += 1; - error->file_name = file_name; - error->pos = pos; - error->text = push_string_copy(arena, SCu8(error_text)); - return(error); -} - -function u8* -config_parser__get_pos(Config_Parser *ctx){ - return(ctx->data.str + ctx->token->pos); -} - -function void -config_parser__log_error_pos(Config_Parser *ctx, u8 *pos, char *error_text){ - config_error_push(ctx->arena, &ctx->errors, ctx->file_name, pos, error_text); -} - -function void -config_parser__log_error(Config_Parser *ctx, char *error_text){ - config_parser__log_error_pos(ctx, config_parser__get_pos(ctx), error_text); -} - -function Config* -config_parser__config(Config_Parser *ctx){ - i32 *version = config_parser__version(ctx); - - Config_Assignment *first = 0; - Config_Assignment *last = 0; - i32 count = 0; - for (;!config_parser__recognize_token(ctx, TokenCppKind_EOF);){ - Config_Assignment *assignment = config_parser__assignment(ctx); - if (assignment != 0){ - zdll_push_back(first, last, assignment); - count += 1; - } - } - - Config *config = push_array(ctx->arena, Config, 1); - block_zero_struct(config); - config->version = version; - config->first = first; - config->last = last; - config->count = count; - config->errors = ctx->errors; - config->file_name = ctx->file_name; - config->data = ctx->data; - return(config); -} - -function void -config_parser__recover_parse(Config_Parser *ctx){ - for (;;){ - if (config_parser__match_token(ctx, TokenCppKind_Semicolon)){ - break; - } - if (config_parser__recognize_token(ctx, TokenCppKind_EOF)){ - break; - } - config_parser__advance_to_next(ctx); - } -} - -function i32* -config_parser__version(Config_Parser *ctx){ - require(config_parser__match_text_lit(ctx, "version")); - - if (!config_parser__match_token(ctx, TokenCppKind_ParenOp)){ - config_parser__log_error(ctx, "expected token '(' for version specifier: 'version(#)'"); - config_parser__recover_parse(ctx); - return(0); - } - - if (!config_parser__recognize_base_token(ctx, TokenBaseKind_LiteralInteger)){ - config_parser__log_error(ctx, "expected an integer constant for version specifier: 'version(#)'"); - config_parser__recover_parse(ctx); - return(0); - } - - Config_Integer value = config_parser__get_int(ctx); - config_parser__advance_to_next(ctx); - - if (!config_parser__match_token(ctx, TokenCppKind_ParenCl)){ - config_parser__log_error(ctx, "expected token ')' for version specifier: 'version(#)'"); - config_parser__recover_parse(ctx); - return(0); - } - - if (!config_parser__match_token(ctx, TokenCppKind_Semicolon)){ - config_parser__log_error(ctx, "expected token ';' for version specifier: 'version(#)'"); - config_parser__recover_parse(ctx); - return(0); - } - - i32 *ptr = push_array(ctx->arena, i32, 1); - *ptr = value.integer; - return(ptr); -} - -function Config_Assignment* -config_parser__assignment(Config_Parser *ctx){ - u8 *pos = config_parser__get_pos(ctx); - - Config_LValue *l = config_parser__lvalue(ctx); - if (l == 0){ - config_parser__log_error(ctx, "expected an l-value; l-value formats: 'identifier', 'identifier[#]'"); - config_parser__recover_parse(ctx); - return(0); - } - - if (!config_parser__match_token(ctx, TokenCppKind_Eq)){ - config_parser__log_error(ctx, "expected token '=' for assignment: 'l-value = r-value;'"); - config_parser__recover_parse(ctx); - return(0); - } - - Config_RValue *r = config_parser__rvalue(ctx); - if (r == 0){ - config_parser__log_error(ctx, "expected an r-value; r-value formats:\n" - "\tconstants (true, false, integers, hexadecimal integers, strings, characters)\n" - "\tany l-value that is set in the file\n" - "\tcompound: '{ compound-element, compound-element, compound-element ...}'\n" - "\ta compound-element is an r-value, and can have a layout specifier\n" - "\tcompound-element with layout specifier: .name = r-value, .integer = r-value"); - config_parser__recover_parse(ctx); - return(0); - } - - if (!config_parser__match_token(ctx, TokenCppKind_Semicolon)){ - config_parser__log_error(ctx, "expected token ';' for assignment: 'l-value = r-value;'"); - config_parser__recover_parse(ctx); - return(0); - } - - Config_Assignment *assignment = push_array_zero(ctx->arena, Config_Assignment, 1); - assignment->pos = pos; - assignment->l = l; - assignment->r = r; - return(assignment); -} - -function Config_LValue* -config_parser__lvalue(Config_Parser *ctx){ - require(config_parser__recognize_token(ctx, TokenCppKind_Identifier)); - String_Const_u8 identifier = config_parser__get_lexeme(ctx); - config_parser__advance_to_next(ctx); - - i32 index = 0; - if (config_parser__match_token(ctx, TokenCppKind_BrackOp)){ - require(config_parser__recognize_base_token(ctx, TokenBaseKind_LiteralInteger)); - Config_Integer value = config_parser__get_int(ctx); - index = value.integer; - config_parser__advance_to_next(ctx); - require(config_parser__match_token(ctx, TokenCppKind_BrackCl)); - } - - Config_LValue *lvalue = push_array_zero(ctx->arena, Config_LValue, 1); - lvalue->identifier = identifier; - lvalue->index = index; - return(lvalue); -} - -function Config_RValue* -config_parser__rvalue(Config_Parser *ctx){ - Config_RValue *rvalue = 0; - if (config_parser__recognize_token(ctx, TokenCppKind_Identifier)){ - Config_LValue *l = config_parser__lvalue(ctx); - require(l != 0); - rvalue = push_array_zero(ctx->arena, Config_RValue, 1); - rvalue->type = ConfigRValueType_LValue; - rvalue->lvalue = l; - } - else if (config_parser__recognize_token(ctx, TokenCppKind_BraceOp)){ - config_parser__advance_to_next(ctx); - Config_Compound *compound = config_parser__compound(ctx); - require(compound != 0); - rvalue = push_array_zero(ctx->arena, Config_RValue, 1); - rvalue->type = ConfigRValueType_Compound; - rvalue->compound = compound; - } - else if (config_parser__recognize_boolean(ctx)){ - b32 b = config_parser__get_boolean(ctx); - config_parser__advance_to_next(ctx); - rvalue = push_array_zero(ctx->arena, Config_RValue, 1); - rvalue->type = ConfigRValueType_Boolean; - rvalue->boolean = b; - } - else if (config_parser__recognize_base_token(ctx, TokenBaseKind_LiteralInteger)){ - Config_Integer value = config_parser__get_int(ctx); - config_parser__advance_to_next(ctx); - rvalue = push_array_zero(ctx->arena, Config_RValue, 1); - rvalue->type = ConfigRValueType_Integer; - if (value.is_signed){ - rvalue->integer = value.integer; - } - else{ - rvalue->uinteger = value.uinteger; - } - } - else if (config_parser__recognize_token(ctx, TokenCppKind_LiteralString)){ - String_Const_u8 s = config_parser__get_lexeme(ctx); - config_parser__advance_to_next(ctx); - s = string_chop(string_skip(s, 1), 1); - String_Const_u8 interpreted = string_interpret_escapes(ctx->arena, s); - rvalue = push_array_zero(ctx->arena, Config_RValue, 1); - rvalue->type = ConfigRValueType_String; - rvalue->string = interpreted; - } - else if (config_parser__recognize_token(ctx, TokenCppKind_LiteralCharacter)){ - String_Const_u8 s = config_parser__get_lexeme(ctx); - config_parser__advance_to_next(ctx); - s = string_chop(string_skip(s, 1), 1); - String_Const_u8 interpreted = string_interpret_escapes(ctx->arena, s); - rvalue = push_array_zero(ctx->arena, Config_RValue, 1); - rvalue->type = ConfigRValueType_Character; - rvalue->character = string_get_character(interpreted, 0); - } - return(rvalue); -} - -function void -config_parser__compound__check(Config_Parser *ctx, Config_Compound *compound){ - b32 implicit_index_allowed = true; - for (Config_Compound_Element *node = compound->first; - node != 0; - node = node->next){ - if (node->l.type != ConfigLayoutType_Unset){ - implicit_index_allowed = false; - } - else if (!implicit_index_allowed){ - config_parser__log_error_pos(ctx, node->l.pos, - "encountered unlabeled member after one or more labeled members"); - } - } -} - -function Config_Compound* -config_parser__compound(Config_Parser *ctx){ - Config_Compound_Element *first = 0; - Config_Compound_Element *last = 0; - i32 count = 0; - - Config_Compound_Element *element = config_parser__element(ctx); - require(element != 0); - zdll_push_back(first, last, element); - count += 1; - - for (;config_parser__match_token(ctx, TokenCppKind_Comma);){ - if (config_parser__recognize_token(ctx, TokenCppKind_BraceCl)){ - break; - } - element = config_parser__element(ctx); - require(element != 0); - zdll_push_back(first, last, element); - count += 1; - } - - require(config_parser__match_token(ctx, TokenCppKind_BraceCl)); - - Config_Compound *compound = push_array(ctx->arena, Config_Compound, 1); - block_zero_struct(compound); - compound->first = first; - compound->last = last; - compound->count = count; - config_parser__compound__check(ctx, compound); - return(compound); -} - -function Config_Compound_Element* -config_parser__element(Config_Parser *ctx){ - Config_Layout layout = {}; - layout.pos = config_parser__get_pos(ctx); - if (config_parser__match_token(ctx, TokenCppKind_Dot)){ - if (config_parser__recognize_token(ctx, TokenCppKind_Identifier)){ - layout.type = ConfigLayoutType_Identifier; - layout.identifier = config_parser__get_lexeme(ctx); - config_parser__advance_to_next(ctx); - } - else if (config_parser__recognize_base_token(ctx, TokenBaseKind_LiteralInteger)){ - layout.type = ConfigLayoutType_Integer; - Config_Integer value = config_parser__get_int(ctx); - layout.integer = value.integer; - config_parser__advance_to_next(ctx); - } - else{ - return(0); - } - require(config_parser__match_token(ctx, TokenCppKind_Eq)); - } - Config_RValue *rvalue = config_parser__rvalue(ctx); - require(rvalue != 0); - Config_Compound_Element *element = push_array(ctx->arena, Config_Compound_Element, 1); - block_zero_struct(element); - element->l = layout; - element->r = rvalue; - return(element); -} - -//////////////////////////////// - -function Config_Error* -config_add_error(Arena *arena, Config *config, u8 *pos, char *error_text){ - return(config_error_push(arena, &config->errors, config->file_name, pos, - error_text)); -} - -//////////////////////////////// - -function Config_Assignment* -config_lookup_assignment(Config *config, String_Const_u8 var_name, i32 subscript){ - Config_Assignment *assignment = 0; - for (assignment = config->first; - assignment != 0; - assignment = assignment->next){ - Config_LValue *l = assignment->l; - if (l != 0 && string_match(l->identifier, var_name) && l->index == subscript){ - break; - } - } - return(assignment); -} - -function Config_Get_Result -config_var(Config *config, String_Const_u8 var_name, i32 subscript); - -function Config_Get_Result -config_evaluate_rvalue(Config *config, Config_Assignment *assignment, Config_RValue *r){ - Config_Get_Result result = {}; - if (r != 0 && !assignment->visited){ - if (r->type == ConfigRValueType_LValue){ - assignment->visited = true; - Config_LValue *l = r->lvalue; - result = config_var(config, l->identifier, l->index); - assignment->visited = false; - } - else{ - result.success = true; - result.pos = assignment->pos; - result.type = r->type; - switch (r->type){ - case ConfigRValueType_Boolean: - { - result.boolean = r->boolean; - }break; - - case ConfigRValueType_Integer: - { - result.integer = r->integer; - }break; - - case ConfigRValueType_String: - { - result.string = r->string; - }break; - - case ConfigRValueType_Character: - { - result.character = r->character; - }break; - - case ConfigRValueType_Compound: - { - result.compound = r->compound; - }break; - } - } - } - return(result); -} - -function Config_Get_Result -config_var(Config *config, String_Const_u8 var_name, i32 subscript){ - Config_Get_Result result = {}; - Config_Assignment *assignment = config_lookup_assignment(config, var_name, subscript); - if (assignment != 0){ - result = config_evaluate_rvalue(config, assignment, assignment->r); - } - return(result); -} - -function Config_Get_Result -config_compound_member(Config *config, Config_Compound *compound, String_Const_u8 var_name, i32 index){ - Config_Get_Result result = {}; - i32 implicit_index = 0; - b32 implicit_index_is_valid = true; - for (Config_Compound_Element *element = compound->first; - element != 0; - element = element->next, implicit_index += 1){ - b32 element_matches_query = false; - switch (element->l.type){ - case ConfigLayoutType_Unset: - { - if (implicit_index_is_valid && index == implicit_index){ - element_matches_query = true; - } - }break; - - case ConfigLayoutType_Identifier: - { - implicit_index_is_valid = false; - if (string_match(element->l.identifier, var_name)){ - element_matches_query = true; - } - }break; - - case ConfigLayoutType_Integer: - { - implicit_index_is_valid = false; - if (element->l.integer == index){ - element_matches_query = true; - } - }break; - } - if (element_matches_query){ - Config_Assignment dummy_assignment = {}; - dummy_assignment.pos = element->l.pos; - result = config_evaluate_rvalue(config, &dummy_assignment, element->r); - break; - } - } - return(result); -} - -function Config_Iteration_Step_Result -typed_array_iteration_step(Config *parsed, Config_Compound *compound, Config_RValue_Type type, i32 index); - -function i32 -typed_array_get_count(Config *parsed, Config_Compound *compound, Config_RValue_Type type); - -function Config_Get_Result_List -typed_array_reference_list(Arena *arena, Config *parsed, Config_Compound *compound, Config_RValue_Type type); - -#define config_fixed_string_var(c,v,s,o,a) config_placed_string_var((c),(v),(s),(o),(a),sizeof(a)) - -//////////////////////////////// - -function b32 -config_has_var(Config *config, String_Const_u8 var_name, i32 subscript){ - Config_Get_Result result = config_var(config, var_name, subscript); - return(result.success && result.type == ConfigRValueType_NoType); -} - -function b32 -config_has_var(Config *config, char *var_name, i32 subscript){ - return(config_has_var(config, SCu8(var_name), subscript)); -} - -function b32 -config_bool_var(Config *config, String_Const_u8 var_name, i32 subscript, b32* var_out){ - Config_Get_Result result = config_var(config, var_name, subscript); - b32 success = (result.success && result.type == ConfigRValueType_Boolean); - if (success){ - *var_out = result.boolean; - } - return(success); -} -function b32 -config_bool_var(Config *config, String_Const_u8 var_name, i32 subscript, b8 *var_out){ - b32 temp = false; - b32 success = config_bool_var(config, var_name, subscript, &temp); - if (success){ - *var_out = (temp != false); - } - return(success); -} -function b32 -config_bool_var(Config *config, char *var_name, i32 subscript, b32* var_out){ - return(config_bool_var(config, SCu8(var_name), subscript, var_out)); -} -function b32 -config_bool_var(Config *config, char* var_name, i32 subscript, b8 *var_out){ - b32 temp = false; - b32 success = config_bool_var(config, SCu8(var_name), subscript, &temp); - if (success){ - *var_out = (temp != false); - } - return(success); -} - -function b32 -config_int_var(Config *config, String_Const_u8 var_name, i32 subscript, i32* var_out){ - Config_Get_Result result = config_var(config, var_name, subscript); - b32 success = result.success && result.type == ConfigRValueType_Integer; - if (success){ - *var_out = result.integer; - } - return(success); -} - -function b32 -config_int_var(Config *config, char *var_name, i32 subscript, i32* var_out){ - return(config_int_var(config, SCu8(var_name), subscript, var_out)); -} - -function b32 -config_uint_var(Config *config, String_Const_u8 var_name, i32 subscript, u32* var_out){ - Config_Get_Result result = config_var(config, var_name, subscript); - b32 success = result.success && result.type == ConfigRValueType_Integer; - if (success){ - *var_out = result.uinteger; - } - return(success); -} - -function b32 -config_uint_var(Config *config, char *var_name, i32 subscript, u32* var_out){ - return(config_uint_var(config, SCu8(var_name), subscript, var_out)); -} - -function b32 -config_string_var(Config *config, String_Const_u8 var_name, i32 subscript, String_Const_u8* var_out){ - Config_Get_Result result = config_var(config, var_name, subscript); - b32 success = result.success && result.type == ConfigRValueType_String; - if (success){ - *var_out = result.string; - } - return(success); -} - -function b32 -config_string_var(Config *config, char *var_name, i32 subscript, String_Const_u8* var_out){ - return(config_string_var(config, SCu8(var_name), subscript, var_out)); -} - -function b32 -config_placed_string_var(Config *config, String_Const_u8 var_name, i32 subscript, String_Const_u8* var_out, u8 *space, u64 space_size){ - Config_Get_Result result = config_var(config, var_name, subscript); - b32 success = (result.success && result.type == ConfigRValueType_String); - if (success){ - u64 size = result.string.size; - size = clamp_top(size, space_size); - block_copy(space, result.string.str, size); - *var_out = SCu8(space, size); - } - return(success); -} - -function b32 -config_placed_string_var(Config *config, char *var_name, i32 subscript, String_Const_u8* var_out, u8 *space, u64 space_size){ - return(config_placed_string_var(config, SCu8(var_name), subscript, var_out, space, space_size)); -} - -function b32 -config_char_var(Config *config, String_Const_u8 var_name, i32 subscript, char* var_out){ - Config_Get_Result result = config_var(config, var_name, subscript); - b32 success = result.success && result.type == ConfigRValueType_Character; - if (success){ - *var_out = result.character; - } - return(success); -} - -function b32 -config_char_var(Config *config, char *var_name, i32 subscript, char* var_out){ - return(config_char_var(config, SCu8(var_name), subscript, var_out)); -} - -function b32 -config_compound_var(Config *config, String_Const_u8 var_name, i32 subscript, Config_Compound** var_out){ - Config_Get_Result result = config_var(config, var_name, subscript); - b32 success = (result.success && result.type == ConfigRValueType_Compound); - if (success){ - *var_out = result.compound; - } - return(success); -} - -function b32 -config_compound_var(Config *config, char *var_name, i32 subscript, Config_Compound** var_out){ - return(config_compound_var(config, SCu8(var_name), subscript, var_out)); -} - -function b32 -config_compound_has_member(Config *config, Config_Compound *compound, - String_Const_u8 var_name, i32 index){ - Config_Get_Result result = config_compound_member(config, compound, var_name, index); - b32 success = result.success && result.type == ConfigRValueType_NoType; - return(success); -} - -function b32 -config_compound_has_member(Config *config, Config_Compound *compound, - char *var_name, i32 index){ - return(config_compound_has_member(config, compound, SCu8(var_name), index)); -} - -function b32 -config_compound_bool_member(Config *config, Config_Compound *compound, - String_Const_u8 var_name, i32 index, b32* var_out){ - Config_Get_Result result = config_compound_member(config, compound, var_name, index); - b32 success = result.success && result.type == ConfigRValueType_Boolean; - if (success){ - *var_out = result.boolean; - } - return(success); -} - -function b32 -config_compound_bool_member(Config *config, Config_Compound *compound, - char *var_name, i32 index, b32* var_out){ - return(config_compound_bool_member(config, compound, SCu8(var_name), index, var_out)); -} - -function b32 -config_compound_int_member(Config *config, Config_Compound *compound, - String_Const_u8 var_name, i32 index, i32* var_out){ - Config_Get_Result result = config_compound_member(config, compound, var_name, index); - b32 success = result.success && result.type == ConfigRValueType_Integer; - if (success){ - *var_out = result.integer; - } - return(success); -} - -function b32 -config_compound_int_member(Config *config, Config_Compound *compound, - char *var_name, i32 index, i32* var_out){ - return(config_compound_int_member(config, compound, SCu8(var_name), index, var_out)); -} - -function b32 -config_compound_uint_member(Config *config, Config_Compound *compound, - String_Const_u8 var_name, i32 index, u32* var_out){ - Config_Get_Result result = config_compound_member(config, compound, var_name, index); - b32 success = result.success && result.type == ConfigRValueType_Integer; - if (success){ - *var_out = result.uinteger; - } - return(success); -} - -function b32 -config_compound_uint_member(Config *config, Config_Compound *compound, - char *var_name, i32 index, u32* var_out){ - return(config_compound_uint_member(config, compound, SCu8(var_name), index, var_out)); -} - -function b32 -config_compound_string_member(Config *config, Config_Compound *compound, - String_Const_u8 var_name, i32 index, String_Const_u8* var_out){ - Config_Get_Result result = config_compound_member(config, compound, var_name, index); - b32 success = (result.success && result.type == ConfigRValueType_String); - if (success){ - *var_out = result.string; - } - return(success); -} - -function b32 -config_compound_string_member(Config *config, Config_Compound *compound, - char *var_name, i32 index, String_Const_u8* var_out){ - return(config_compound_string_member(config, compound, SCu8(var_name), index, var_out)); -} - -function b32 -config_compound_placed_string_member(Config *config, Config_Compound *compound, - String_Const_u8 var_name, i32 index, String_Const_u8* var_out, u8 *space, u64 space_size){ - Config_Get_Result result = config_compound_member(config, compound, var_name, index); - b32 success = (result.success && result.type == ConfigRValueType_String); - if (success){ - u64 size = result.string.size; - size = clamp_top(size, space_size); - block_copy(space, result.string.str, size); - *var_out = SCu8(space, size); - } - return(success); -} - -function b32 -config_compound_placed_string_member(Config *config, Config_Compound *compound, - char *var_name, i32 index, String_Const_u8* var_out, u8 *space, u64 space_size){ - return(config_compound_placed_string_member(config, compound, SCu8(var_name), index, var_out, space, space_size)); -} - -function b32 -config_compound_char_member(Config *config, Config_Compound *compound, - String_Const_u8 var_name, i32 index, char* var_out){ - Config_Get_Result result = config_compound_member(config, compound, var_name, index); - b32 success = result.success && result.type == ConfigRValueType_Character; - if (success){ - *var_out = result.character; - } - return(success); -} - -function b32 -config_compound_char_member(Config *config, Config_Compound *compound, - char *var_name, i32 index, char* var_out){ - return(config_compound_char_member(config, compound, SCu8(var_name), index, var_out)); -} - -function b32 -config_compound_compound_member(Config *config, Config_Compound *compound, - String_Const_u8 var_name, i32 index, Config_Compound** var_out){ - Config_Get_Result result = config_compound_member(config, compound, var_name, index); - b32 success = result.success && result.type == ConfigRValueType_Compound; - if (success){ - *var_out = result.compound; - } - return(success); -} - -function b32 -config_compound_compound_member(Config *config, Config_Compound *compound, - char *var_name, i32 index, Config_Compound** var_out){ - return(config_compound_compound_member(config, compound, SCu8(var_name), index, var_out)); -} - -function Iteration_Step_Result -typed_has_array_iteration_step(Config *config, Config_Compound *compound, i32 index){ - Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_NoType, index); - return(result.step); -} - -function Iteration_Step_Result -typed_bool_array_iteration_step(Config *config, Config_Compound *compound, i32 index, b32* var_out){ - Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Boolean, index); - b32 success = (result.step == Iteration_Good); - if (success){ - *var_out = result.get.boolean; - } - return(result.step); -} - -function Iteration_Step_Result -typed_int_array_iteration_step(Config *config, Config_Compound *compound, i32 index, i32* var_out){ - Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Integer, index); - b32 success = (result.step == Iteration_Good); - if (success){ - *var_out = result.get.integer; - } - return(result.step); -} - -function Iteration_Step_Result -typed_uint_array_iteration_step(Config *config, Config_Compound *compound, i32 index, u32* var_out){ - Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Integer, index); - b32 success = (result.step == Iteration_Good); - if (success){ - *var_out = result.get.uinteger; - } - return(result.step); -} - -function Iteration_Step_Result -typed_string_array_iteration_step(Config *config, Config_Compound *compound, i32 index, String_Const_u8* var_out){ - Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_String, index); - b32 success = (result.step == Iteration_Good); - if (success){ - *var_out = result.get.string; - } - return(result.step); -} - -function Iteration_Step_Result -typed_placed_string_array_iteration_step(Config *config, Config_Compound *compound, i32 index, String_Const_u8* var_out, u8 *space, u64 space_size){ - Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_String, index); - b32 success = (result.step == Iteration_Good); - if (success){ - u64 size = result.get.string.size; - size = clamp_top(size, space_size); - block_copy(space, result.get.string.str, size); - *var_out = SCu8(space, size); - } - return(result.step); -} - -function Iteration_Step_Result -typed_char_array_iteration_step(Config *config, Config_Compound *compound, i32 index, char* var_out){ - Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Character, index); - b32 success = (result.step == Iteration_Good); - if (success){ - *var_out = result.get.character; - } - return(result.step); -} - -function Iteration_Step_Result -typed_compound_array_iteration_step(Config *config, Config_Compound *compound, i32 index, Config_Compound** var_out){ - Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Compound, index); - b32 success = (result.step == Iteration_Good); - if (success){ - *var_out = result.get.compound; - } - return(result.step); -} - -function i32 -typed_bool_array_get_count(Config *config, Config_Compound *compound){ - i32 count = typed_array_get_count(config, compound, ConfigRValueType_Boolean); - return(count); -} - -function i32 -typed_int_array_get_count(Config *config, Config_Compound *compound){ - i32 count = typed_array_get_count(config, compound, ConfigRValueType_Integer); - return(count); -} - -function i32 -typed_float_array_get_count(Config *config, Config_Compound *compound){ - i32 count = typed_array_get_count(config, compound, ConfigRValueType_Float); - return(count); -} - -function i32 -typed_string_array_get_count(Config *config, Config_Compound *compound){ - i32 count = typed_array_get_count(config, compound, ConfigRValueType_String); - return(count); -} - -function i32 -typed_character_array_get_count(Config *config, Config_Compound *compound){ - i32 count = typed_array_get_count(config, compound, ConfigRValueType_Character); - return(count); -} - -function i32 -typed_compound_array_get_count(Config *config, Config_Compound *compound){ - i32 count = typed_array_get_count(config, compound, ConfigRValueType_Compound); - return(count); -} - -function i32 -typed_no_type_array_get_count(Config *config, Config_Compound *compound){ - i32 count = typed_array_get_count(config, compound, ConfigRValueType_NoType); - return(count); -} - -function Config_Get_Result_List -typed_bool_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ - Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Boolean); - return(list); -} - -function Config_Get_Result_List -typed_int_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ - Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Integer); - return(list); -} - -function Config_Get_Result_List -typed_float_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ - Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Float); - return(list); -} - -function Config_Get_Result_List -typed_string_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ - Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_String); - return(list); -} - -function Config_Get_Result_List -typed_character_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ - Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Character); - return(list); -} - -function Config_Get_Result_List -typed_compound_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ - Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Compound); - return(list); -} - -function Config_Get_Result_List -typed_no_type_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ - Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_NoType); - return(list); -} - -//////////////////////////////// - -function Config_Iteration_Step_Result -typed_array_iteration_step(Config *parsed, Config_Compound *compound, Config_RValue_Type type, i32 index){ - Config_Iteration_Step_Result result = {}; - result.step = Iteration_Quit; - Config_Get_Result get_result = config_compound_member(parsed, compound, string_u8_litexpr("~"), index); - if (get_result.success){ - if (get_result.type == type || type == ConfigRValueType_NoType){ - result.step = Iteration_Good; - result.get = get_result; - } - else{ - result.step = Iteration_Skip; - } - } - return(result); -} - -function i32 -typed_array_get_count(Config *parsed, Config_Compound *compound, Config_RValue_Type type){ - i32 count = 0; - for (i32 i = 0;; ++i){ - Config_Iteration_Step_Result result = typed_array_iteration_step(parsed, compound, type, i); - if (result.step == Iteration_Skip){ - continue; - } - else if (result.step == Iteration_Quit){ - break; - } - count += 1; - } - return(count); -} - -function Config_Get_Result_List -typed_array_reference_list(Arena *arena, Config *parsed, Config_Compound *compound, Config_RValue_Type type){ - Config_Get_Result_List list = {}; - for (i32 i = 0;; ++i){ - Config_Iteration_Step_Result result = typed_array_iteration_step(parsed, compound, type, i); - if (result.step == Iteration_Skip){ - continue; - } - else if (result.step == Iteration_Quit){ - break; - } - Config_Get_Result_Node *node = push_array(arena, Config_Get_Result_Node, 1); - node->result = result.get; - zdll_push_back(list.first, list.last, node); - list.count += 1; - } - return(list); -} - -//////////////////////////////// - -function void -change_mode(Application_Links *app, String_Const_u8 mode){ - fcoder_mode = FCoderMode_Original; - if (string_match(mode, string_u8_litexpr("4coder"))){ - fcoder_mode = FCoderMode_Original; - } - else if (string_match(mode, string_u8_litexpr("notepad-like"))){ - begin_notepad_mode(app); - } - else{ - print_message(app, string_u8_litexpr("Unknown mode.\n")); - } -} - -//////////////////////////////// - -function Token_Array -token_array_from_text(Application_Links *app, Arena *arena, String_Const_u8 data){ - ProfileScope(app, "token array from text"); - Token_List list = lex_full_input_cpp(arena, data); - return(token_array_from_list(arena, &list)); -} - -function Config* -config_from_text(Application_Links *app, Arena *arena, String_Const_u8 file_name, - String_Const_u8 data){ - Config *parsed = 0; - Temp_Memory restore_point = begin_temp(arena); - Token_Array array = token_array_from_text(app, arena, data); - if (array.tokens != 0){ - parsed = config_parse(app, arena, file_name, data, array); - if (parsed == 0){ - end_temp(restore_point); - } - } - return(parsed); -} - -//////////////////////////////// - -function void -config_init_default(Config_Data *config){ - config->user_name = SCu8(config->user_name_space, (u64)0); - - block_zero_struct(&config->code_exts); - - config->mode = SCu8(config->mode_space, (u64)0); - - config->use_scroll_bars = false; - config->use_file_bars = true; - config->hide_file_bar_in_ui = true; - config->use_error_highlight = true; - config->use_jump_highlight = true; - config->use_scope_highlight = true; - config->use_paren_helper = true; - config->use_comment_keyword = true; - config->lister_whole_word_backspace_when_modified = false; - config->show_line_number_margins = false; - - config->enable_virtual_whitespace = true; - config->enable_code_wrapping = true; - config->automatically_adjust_wrapping = true; - config->automatically_indent_text_on_save = true; - config->automatically_save_changes_on_build = true; - config->automatically_load_project = false; - - config->indent_with_tabs = false; - config->indent_width = 4; - - config->default_wrap_width = 672; - config->default_min_base_width = 550; - - config->default_theme_name = SCu8(config->default_theme_name_space, sizeof("4coder") - 1); - block_copy(config->default_theme_name.str, "4coder", config->default_theme_name.size); - config->highlight_line_at_cursor = true; - - config->default_font_name = SCu8(config->default_font_name_space, (u64)0); - config->default_font_size = 16; - config->default_font_hinting = false; - - config->default_compiler_bat = SCu8(config->default_compiler_bat_space, 2); - block_copy(config->default_compiler_bat.str, "cl", 2); - - config->default_flags_bat = SCu8(config->default_flags_bat_space, (u64)0); - - config->default_compiler_sh = SCu8(config->default_compiler_sh_space, 3); - block_copy(config->default_compiler_sh.str, "g++", 3); - - config->default_flags_sh = SCu8(config->default_flags_sh_space, (u64)0); - - config->lalt_lctrl_is_altgr = false; -} - -function Config* -config_parse__data(Application_Links *app, Arena *arena, String_Const_u8 file_name, - String_Const_u8 data, Config_Data *config){ - config_init_default(config); - - b32 success = false; - - Config *parsed = config_from_text(app, arena, file_name, data); - if (parsed != 0){ - success = true; - - config_fixed_string_var(parsed, "user_name", 0, - &config->user_name, config->user_name_space); - - String_Const_u8 str = {}; - if (config_string_var(parsed, "treat_as_code", 0, &str)){ - config->code_exts = - parse_extension_line_to_extension_list(app, arena, str); - } - - config_fixed_string_var(parsed, "mode", 0, - &config->mode, config->mode_space); - - config_bool_var(parsed, "use_scroll_bars", 0, &config->use_scroll_bars); - config_bool_var(parsed, "use_file_bars", 0, &config->use_file_bars); - config_bool_var(parsed, "hide_file_bar_in_ui", 0, &config->hide_file_bar_in_ui); - config_bool_var(parsed, "use_error_highlight", 0, &config->use_error_highlight); - config_bool_var(parsed, "use_jump_highlight", 0, &config->use_jump_highlight); - config_bool_var(parsed, "use_scope_highlight", 0, &config->use_scope_highlight); - config_bool_var(parsed, "use_paren_helper", 0, &config->use_paren_helper); - config_bool_var(parsed, "use_comment_keyword", 0, &config->use_comment_keyword); - config_bool_var(parsed, "lister_whole_word_backspace_when_modified", 0, &config->lister_whole_word_backspace_when_modified); - config_bool_var(parsed, "show_line_number_margins", 0, &config->show_line_number_margins); - - - config_bool_var(parsed, "enable_virtual_whitespace", 0, &config->enable_virtual_whitespace); - config_bool_var(parsed, "enable_code_wrapping", 0, &config->enable_code_wrapping); - config_bool_var(parsed, "automatically_adjust_wrapping", 0, &config->automatically_adjust_wrapping); - config_bool_var(parsed, "automatically_indent_text_on_save", 0, &config->automatically_indent_text_on_save); - config_bool_var(parsed, "automatically_save_changes_on_build", 0, &config->automatically_save_changes_on_build); - config_bool_var(parsed, "automatically_load_project", 0, &config->automatically_load_project); - - config_bool_var(parsed, "indent_with_tabs", 0, &config->indent_with_tabs); - config_int_var(parsed, "indent_width", 0, &config->indent_width); - - config_int_var(parsed, "default_wrap_width", 0, &config->default_wrap_width); - config_int_var(parsed, "default_min_base_width", 0, &config->default_min_base_width); - - config_fixed_string_var(parsed, "default_theme_name", 0, - &config->default_theme_name, config->default_theme_name_space); - config_bool_var(parsed, "highlight_line_at_cursor", 0, &config->highlight_line_at_cursor); - - config_fixed_string_var(parsed, "default_font_name", 0, - &config->default_font_name, config->default_font_name_space); - config_int_var(parsed, "default_font_size", 0, &config->default_font_size); - config_bool_var(parsed, "default_font_hinting", 0, &config->default_font_hinting); - - config_fixed_string_var(parsed, "default_compiler_bat", 0, - &config->default_compiler_bat, config->default_compiler_bat_space); - config_fixed_string_var(parsed, "default_flags_bat", 0, - &config->default_flags_bat, config->default_flags_bat_space); - config_fixed_string_var(parsed, "default_compiler_sh", 0, - &config->default_compiler_sh, config->default_compiler_sh_space); - config_fixed_string_var(parsed, "default_flags_sh", 0, - &config->default_flags_sh, config->default_flags_sh_space); - - config_bool_var(parsed, "lalt_lctrl_is_altgr", 0, &config->lalt_lctrl_is_altgr); - } - - if (!success){ - config_init_default(config); - } - - return(parsed); -} - -function Config* -config_parse__file_handle(Application_Links *app, Arena *arena, - String_Const_u8 file_name, FILE *file, Config_Data *config){ - Config *parsed = 0; - Data data = dump_file_handle(arena, file); - if (data.data != 0){ - parsed = config_parse__data(app, arena, file_name, SCu8(data), config); - } - else{ - config_init_default(config); - } - return(parsed); -} - -function Config* -config_parse__file_name(Application_Links *app, Arena *arena, char *file_name, Config_Data *config){ - Config *parsed = 0; - b32 success = false; - FILE *file = open_file_try_current_path_then_binary_path(app, file_name); - if (file != 0){ - Data data = dump_file_handle(arena, file); - fclose(file); - if (data.data != 0){ - parsed = config_parse__data(app, arena, SCu8(file_name), SCu8(data), - config); - success = true; - } - } - if (!success){ - config_init_default(config); - } - return(parsed); -} - -function Config* -theme_parse__data(Application_Links *app, Arena *arena, String_Const_u8 file_name, String_Const_u8 data, Arena *color_arena, Color_Table *color_table){ - Config *parsed = config_from_text(app, arena, file_name, data); - if (parsed != 0){ - for (Config_Assignment *node = parsed->first; - node != 0; - node = node->next){ - Scratch_Block scratch(app); - Config_LValue *l = node->l; - String_Const_u8 l_name = push_string_copy(scratch, l->identifier); - Managed_ID id = managed_id_get(app, string_u8_litexpr("colors"), l_name); - if (id != 0){ - u32 color = 0; - if (config_uint_var(parsed, l_name, 0, &color)){ - color_table->arrays[id%color_table->count] = make_colors(color_arena, color); - } - else{ - Config_Compound *compound = 0; - if (config_compound_var(parsed, l_name, 0, &compound)){ - local_persist u32 color_array[256]; - i32 counter = 0; - for (i32 i = 0;; i += 1){ - Config_Iteration_Step_Result result = typed_array_iteration_step(parsed, compound, ConfigRValueType_Integer, i); - if (result.step == Iteration_Skip){ - continue; - } - else if (result.step == Iteration_Quit){ - break; - } - - color_array[counter] = result.get.uinteger; - counter += 1; - if (counter == 256){ - break; - } - } - - color_table->arrays[id%color_table->count] = make_colors(color_arena, color_array, counter); - } - } - } - - } - } - return(parsed); -} - -function Config* -theme_parse__file_handle(Application_Links *app, Arena *arena, String_Const_u8 file_name, FILE *file, Arena *color_arena, Color_Table *color_table){ - Data data = dump_file_handle(arena, file); - Config *parsed = 0; - if (data.data != 0){ - parsed = theme_parse__data(app, arena, file_name, SCu8(data), color_arena, color_table); - } - return(parsed); -} - -function Config* -theme_parse__file_name(Application_Links *app, Arena *arena, char *file_name, Arena *color_arena, Color_Table *color_table){ - Config *parsed = 0; - FILE *file = open_file_try_current_path_then_binary_path(app, file_name); - if (file != 0){ - Data data = dump_file_handle(arena, file); - fclose(file); - parsed = theme_parse__data(app, arena, SCu8(file_name), SCu8(data), color_arena, color_table); - } - if (parsed == 0){ - Scratch_Block scratch(app); - String_Const_u8 str = push_u8_stringf(arena, "Did not find %s, theme not loaded", file_name); - print_message(app, str); - } - return(parsed); -} - -//////////////////////////////// - -function void -config_feedback_bool(Arena *arena, List_String_Const_u8 *list, char *name, b32 val){ - string_list_pushf(arena, list, "%s = %s;\n", name, (char*)(val?"true":"false")); -} - -function void -config_feedback_string(Arena *arena, List_String_Const_u8 *list, char *name, String_Const_u8 val){ - val.size = clamp_bot(0, val.size); - string_list_pushf(arena, list, "%s = \"%.*s\";\n", name, string_expand(val)); -} - -function void -config_feedback_string(Arena *arena, List_String_Const_u8 *list, char *name, char *val){ - string_list_pushf(arena, list, "%s = \"%s\";\n", name, val); -} - -function void -config_feedback_extension_list(Arena *arena, List_String_Const_u8 *list, char *name, String_Const_u8_Array *extensions){ - string_list_pushf(arena, list, "%s = \"", name); - for (i32 i = 0; i < extensions->count; ++i){ - String_Const_u8 ext = extensions->strings[i]; - string_list_pushf(arena, list, ".%.*s", string_expand(ext)); - } - string_list_push_u8_lit(arena, list, "\";\n"); -} - -function void -config_feedback_int(Arena *arena, List_String_Const_u8 *list, char *name, i32 val){ - string_list_pushf(arena, list, "%s = %d;\n", name, val); -} - -//////////////////////////////// - -function void -load_config_and_apply(Application_Links *app, Arena *out_arena, Config_Data *config, - i32 override_font_size, b32 override_hinting){ - Scratch_Block scratch(app); - - linalloc_clear(out_arena); - Config *parsed = config_parse__file_name(app, out_arena, "config.4coder", config); - - if (parsed != 0){ - // Top - print_message(app, string_u8_litexpr("Loaded config file:\n")); - - // Errors - String_Const_u8 error_text = config_stringize_errors(app, scratch, parsed); - if (error_text.str != 0){ - print_message(app, error_text); - } - } - else{ - print_message(app, string_u8_litexpr("Using default config:\n")); - Face_Description description = get_face_description(app, 0); - if (description.font.file_name.str != 0){ - u64 size = Min(description.font.file_name.size, sizeof(config->default_font_name_space)); - block_copy(config->default_font_name_space, description.font.file_name.str, size); - config->default_font_name.size = size; - } - } - - if (config->default_font_name.size == 0){ -#define M "liberation-mono.ttf" - block_copy(config->default_font_name_space, M, sizeof(M) - 1); - config->default_font_name.size = sizeof(M) - 1; -#undef M - } - - { - // Values - Temp_Memory temp2 = begin_temp(scratch); - List_String_Const_u8 list = {}; - - config_feedback_string(scratch, &list, "user_name", config->user_name); - config_feedback_extension_list(scratch, &list, "treat_as_code", &config->code_exts); - - config_feedback_string(scratch, &list, "mode", config->mode); - - config_feedback_bool(scratch, &list, "use_scroll_bars", config->use_scroll_bars); - config_feedback_bool(scratch, &list, "use_file_bars", config->use_file_bars); - config_feedback_bool(scratch, &list, "hide_file_bar_in_ui", config->hide_file_bar_in_ui); - config_feedback_bool(scratch, &list, "use_error_highlight", config->use_error_highlight); - config_feedback_bool(scratch, &list, "use_jump_highlight", config->use_jump_highlight); - config_feedback_bool(scratch, &list, "use_scope_highlight", config->use_scope_highlight); - config_feedback_bool(scratch, &list, "use_paren_helper", config->use_paren_helper); - config_feedback_bool(scratch, &list, "use_comment_keyword", config->use_comment_keyword); - config_feedback_bool(scratch, &list, "lister_whole_word_backspace_when_modified", config->lister_whole_word_backspace_when_modified); - config_feedback_bool(scratch, &list, "show_line_number_margins", config->show_line_number_margins); - - config_feedback_bool(scratch, &list, "enable_virtual_whitespace", config->enable_virtual_whitespace); - config_feedback_bool(scratch, &list, "enable_code_wrapping", config->enable_code_wrapping); - config_feedback_bool(scratch, &list, "automatically_indent_text_on_save", config->automatically_indent_text_on_save); - config_feedback_bool(scratch, &list, "automatically_save_changes_on_build", config->automatically_save_changes_on_build); - config_feedback_bool(scratch, &list, "automatically_adjust_wrapping", config->automatically_adjust_wrapping); - config_feedback_bool(scratch, &list, "automatically_load_project", config->automatically_load_project); - - config_feedback_bool(scratch, &list, "indent_with_tabs", config->indent_with_tabs); - config_feedback_int(scratch, &list, "indent_width", config->indent_width); - - config_feedback_int(scratch, &list, "default_wrap_width", config->default_wrap_width); - config_feedback_int(scratch, &list, "default_min_base_width", config->default_min_base_width); - - config_feedback_string(scratch, &list, "default_theme_name", config->default_theme_name); - config_feedback_bool(scratch, &list, "highlight_line_at_cursor", config->highlight_line_at_cursor); - - config_feedback_string(scratch, &list, "default_font_name", config->default_font_name); - config_feedback_int(scratch, &list, "default_font_size", config->default_font_size); - config_feedback_bool(scratch, &list, "default_font_hinting", config->default_font_hinting); - - config_feedback_string(scratch, &list, "default_compiler_bat", config->default_compiler_bat); - config_feedback_string(scratch, &list, "default_flags_bat", config->default_flags_bat); - config_feedback_string(scratch, &list, "default_compiler_sh", config->default_compiler_sh); - config_feedback_string(scratch, &list, "default_flags_sh", config->default_flags_sh); - - config_feedback_bool(scratch, &list, "lalt_lctrl_is_altgr", config->lalt_lctrl_is_altgr); - - string_list_push_u8_lit(scratch, &list, "\n"); - String_Const_u8 message = string_list_flatten(scratch, list); - print_message(app, message); - end_temp(temp2); - } - - // Apply config - change_mode(app, config->mode); - global_set_setting(app, GlobalSetting_LAltLCtrlIsAltGr, config->lalt_lctrl_is_altgr); - - // TODO(allen): -#if 0 - change_theme(app, config->default_theme_name.str, config->default_theme_name.size); - #endif - - Face_Description description = {}; - if (override_font_size != 0){ - description.parameters.pt_size = override_font_size; - } - else{ - description.parameters.pt_size = config->default_font_size; - } - description.parameters.hinting = config->default_font_hinting || override_hinting; - - description.font.file_name = config->default_font_name; - if (!modify_global_face_by_description(app, description)){ - description.font.file_name = get_file_path_in_fonts_folder(scratch, config->default_font_name); - modify_global_face_by_description(app, description); - } -} - -function void -load_theme_file_into_live_set(Application_Links *app, char *file_name){ - Arena *arena = &global_theme_arena; - Color_Table color_table = make_color_table(app, arena); - Scratch_Block scratch(app); - Config *config = theme_parse__file_name(app, scratch, file_name, arena, &color_table); - String_Const_u8 error_text = config_stringize_errors(app, scratch, config); - print_message(app, error_text); - - String_Const_u8 name = SCu8(file_name); - name = string_front_of_path(name); - if (string_match(string_postfix(name, 7), string_u8_litexpr(".4coder"))){ - name = string_chop(name, 7); - } - save_theme(color_table, name); -} - -function void -load_folder_of_themes_into_live_set(Application_Links *app, String_Const_u8 path){ - Scratch_Block scratch(app, Scratch_Share); - - File_List list = system_get_file_list(scratch, path); - for (File_Info **ptr = list.infos, **end = list.infos + list.count; - ptr < end; - ptr += 1){ - File_Info *info = *ptr; - if (!HasFlag(info->attributes.flags, FileAttribute_IsDirectory)){ - String_Const_u8 name = info->file_name; - Temp_Memory_Block temp(scratch); - String_Const_u8 full_name = push_u8_stringf(scratch, "%.*s/%.*s", - string_expand(path), - string_expand(name)); - load_theme_file_into_live_set(app, (char*)full_name.str); - } - } -} - -// BOTTOM - +/* +4coder_config.cpp - Parsing *.4coder files. +*/ + +// TOP + +function String_Const_u8_Array +parse_extension_line_to_extension_list(Application_Links *app, + Arena *arena, String_Const_u8 str){ + ProfileScope(app, "parse extension line to extension list"); + i32 count = 0; + for (u64 i = 0; i < str.size; i += 1){ + if (str.str[i] == '.'){ + count += 1; + } + } + + String_Const_u8_Array array = {}; + array.count = count; + array.strings = push_array(arena, String_Const_u8, count); + + push_align(arena, 1); + str = string_skip(str, string_find_first(str, '.') + 1); + for (i32 i = 0; i < count; i += 1){ + u64 next_period = string_find_first(str, '.'); + String_Const_u8 extension = string_prefix(str, next_period); + str = string_skip(str, next_period + 1); + array.strings[i] = push_string_copy(arena, extension); + } + push_align(arena, 8); + + return(array); +} + +//////////////////////////////// + +function void +setup_built_in_mapping(Application_Links *app, String_Const_u8 name, Mapping *mapping, i64 global_id, i64 file_id, i64 code_id){ + Thread_Context *tctx = get_thread_context(app); + if (string_match(name, string_u8_litexpr("default"))){ + mapping_release(tctx, mapping); + mapping_init(tctx, mapping); + setup_default_mapping(mapping, global_id, file_id, code_id); + } + else if (string_match(name, string_u8_litexpr("mac-default"))){ + mapping_release(tctx, mapping); + mapping_init(tctx, mapping); + setup_mac_mapping(mapping, global_id, file_id, code_id); + } + else if (string_match(name, string_u8_litexpr("choose"))){ + mapping_release(tctx, mapping); + mapping_init(tctx, mapping); +#if OS_MAC + setup_mac_mapping(mapping, global_id, file_id, code_id); +#else + setup_default_mapping(mapping, global_id, file_id, code_id); +#endif + } +} + +//////////////////////////////// + +function Error_Location +get_error_location(Application_Links *app, u8 *base, u8 *pos){ + ProfileScope(app, "get error location"); + Error_Location location = {}; + location.line_number = 1; + location.column_number = 1; + for (u8 *ptr = base; + ptr < pos; + ptr += 1){ + if (*ptr == '\n'){ + location.line_number += 1; + location.column_number = 1; + } + else{ + location.column_number += 1; + } + } + return(location); +} + +function String_Const_u8 +config_stringize_errors(Application_Links *app, Arena *arena, Config *parsed){ + ProfileScope(app, "stringize errors"); + String_Const_u8 result = {}; + if (parsed->errors.first != 0){ + List_String_Const_u8 list = {}; + for (Config_Error *error = parsed->errors.first; + error != 0; + error = error->next){ + Error_Location location = get_error_location(app, parsed->data.str, error->pos); + string_list_pushf(arena, &list, "%.*s:%d:%d: %.*s\n", + string_expand(error->file_name), location.line_number, location.column_number, string_expand(error->text)); + } + result = string_list_flatten(arena, list); + } + return(result); +} + +//////////////////////////////// + +function void +config_parser__advance_to_next(Config_Parser *ctx){ + Token *t = ctx->token; + Token *e = ctx->end; + for (t += 1; + t < e && (t->kind == TokenBaseKind_Comment || + t->kind == TokenBaseKind_Whitespace); + t += 1); + ctx->token = t; +} + +function Config_Parser +make_config_parser(Arena *arena, String_Const_u8 file_name, String_Const_u8 data, Token_Array array){ + Config_Parser ctx = {}; + ctx.start = array.tokens; + ctx.token = ctx.start - 1; + ctx.end = ctx.start + array.count; + ctx.file_name = file_name; + ctx.data = data; + ctx.arena = arena; + config_parser__advance_to_next(&ctx); + return(ctx); +} + +function b32 +config_parser__recognize_base_token(Config_Parser *ctx, Token_Base_Kind kind){ + b32 result = false; + if (ctx->start <= ctx->token && ctx->token < ctx->end){ + result = (ctx->token->kind == kind); + } + else if (kind == TokenBaseKind_EOF){ + result = true; + } + return(result); +} + +function b32 +config_parser__recognize_token(Config_Parser *ctx, Token_Cpp_Kind kind){ + b32 result = false; + if (ctx->start <= ctx->token && ctx->token < ctx->end){ + result = (ctx->token->sub_kind == kind); + } + else if (kind == TokenCppKind_EOF){ + result = true; + } + return(result); +} + +function b32 +config_parser__recognize_boolean(Config_Parser *ctx){ + b32 result = false; + Token *token = ctx->token; + if (ctx->start <= ctx->token && ctx->token < ctx->end){ + result = (token->sub_kind == TokenCppKind_LiteralTrue || + token->sub_kind == TokenCppKind_LiteralFalse); + } + return(result); +} + +function String_Const_u8 +config_parser__get_lexeme(Config_Parser *ctx){ + String_Const_u8 lexeme = {}; + Token *token = ctx->token; + if (ctx->start <= token && token < ctx->end){ + lexeme = SCu8(ctx->data.str + token->pos, token->size); + } + return(lexeme); +} + +function Config_Integer +config_parser__get_int(Config_Parser *ctx){ + Config_Integer config_integer = {}; + String_Const_u8 str = config_parser__get_lexeme(ctx); + if (string_match(string_prefix(str, 2), string_u8_litexpr("0x"))){ + config_integer.is_signed = false; + config_integer.uinteger = (u32)(string_to_integer(string_skip(str, 2), 16)); + } + else{ + b32 is_negative = (string_get_character(str, 0) == '-'); + if (is_negative){ + str = string_skip(str, 1); + } + config_integer.is_signed = true; + config_integer.integer = (i32)(string_to_integer(str, 10)); + if (is_negative){ + config_integer.integer *= -1; + } + } + return(config_integer); +} + +function b32 +config_parser__get_boolean(Config_Parser *ctx){ + String_Const_u8 str = config_parser__get_lexeme(ctx); + return(string_match(str, string_u8_litexpr("true"))); +} + +function b32 +config_parser__recognize_text(Config_Parser *ctx, String_Const_u8 text){ + String_Const_u8 lexeme = config_parser__get_lexeme(ctx); + return(lexeme.str != 0 && string_match(lexeme, text)); +} + +function b32 +config_parser__match_token(Config_Parser *ctx, Token_Cpp_Kind kind){ + b32 result = config_parser__recognize_token(ctx, kind); + if (result){ + config_parser__advance_to_next(ctx); + } + return(result); +} + +function b32 +config_parser__match_text(Config_Parser *ctx, String_Const_u8 text){ + b32 result = config_parser__recognize_text(ctx, text); + if (result){ + config_parser__advance_to_next(ctx); + } + return(result); +} + +#define config_parser__match_text_lit(c,s) config_parser__match_text((c), string_u8_litexpr(s)) + +function Config *config_parser__config (Config_Parser *ctx); +function i32 *config_parser__version (Config_Parser *ctx); +function Config_Assignment *config_parser__assignment(Config_Parser *ctx); +function Config_LValue *config_parser__lvalue (Config_Parser *ctx); +function Config_RValue *config_parser__rvalue (Config_Parser *ctx); +function Config_Compound *config_parser__compound (Config_Parser *ctx); +function Config_Compound_Element *config_parser__element (Config_Parser *ctx); + +function Config* +config_parse(Application_Links *app, Arena *arena, String_Const_u8 file_name, + String_Const_u8 data, Token_Array array){ + ProfileScope(app, "config parse"); + Temp_Memory restore_point = begin_temp(arena); + Config_Parser ctx = make_config_parser(arena, file_name, data, array); + Config *config = config_parser__config(&ctx); + if (config == 0){ + end_temp(restore_point); + } + return(config); +} + +// TODO(allen): Move to string library +function Config_Error* +config_error_push(Arena *arena, Config_Error_List *list, String_Const_u8 file_name, + u8 *pos, char *error_text){ + Config_Error *error = push_array(arena, Config_Error, 1); + zdll_push_back(list->first, list->last, error); + list->count += 1; + error->file_name = file_name; + error->pos = pos; + error->text = push_string_copy(arena, SCu8(error_text)); + return(error); +} + +function u8* +config_parser__get_pos(Config_Parser *ctx){ + return(ctx->data.str + ctx->token->pos); +} + +function void +config_parser__log_error_pos(Config_Parser *ctx, u8 *pos, char *error_text){ + config_error_push(ctx->arena, &ctx->errors, ctx->file_name, pos, error_text); +} + +function void +config_parser__log_error(Config_Parser *ctx, char *error_text){ + config_parser__log_error_pos(ctx, config_parser__get_pos(ctx), error_text); +} + +function Config* +config_parser__config(Config_Parser *ctx){ + i32 *version = config_parser__version(ctx); + + Config_Assignment *first = 0; + Config_Assignment *last = 0; + i32 count = 0; + for (;!config_parser__recognize_token(ctx, TokenCppKind_EOF);){ + Config_Assignment *assignment = config_parser__assignment(ctx); + if (assignment != 0){ + zdll_push_back(first, last, assignment); + count += 1; + } + } + + Config *config = push_array(ctx->arena, Config, 1); + block_zero_struct(config); + config->version = version; + config->first = first; + config->last = last; + config->count = count; + config->errors = ctx->errors; + config->file_name = ctx->file_name; + config->data = ctx->data; + return(config); +} + +function void +config_parser__recover_parse(Config_Parser *ctx){ + for (;;){ + if (config_parser__match_token(ctx, TokenCppKind_Semicolon)){ + break; + } + if (config_parser__recognize_token(ctx, TokenCppKind_EOF)){ + break; + } + config_parser__advance_to_next(ctx); + } +} + +function i32* +config_parser__version(Config_Parser *ctx){ + require(config_parser__match_text_lit(ctx, "version")); + + if (!config_parser__match_token(ctx, TokenCppKind_ParenOp)){ + config_parser__log_error(ctx, "expected token '(' for version specifier: 'version(#)'"); + config_parser__recover_parse(ctx); + return(0); + } + + if (!config_parser__recognize_base_token(ctx, TokenBaseKind_LiteralInteger)){ + config_parser__log_error(ctx, "expected an integer constant for version specifier: 'version(#)'"); + config_parser__recover_parse(ctx); + return(0); + } + + Config_Integer value = config_parser__get_int(ctx); + config_parser__advance_to_next(ctx); + + if (!config_parser__match_token(ctx, TokenCppKind_ParenCl)){ + config_parser__log_error(ctx, "expected token ')' for version specifier: 'version(#)'"); + config_parser__recover_parse(ctx); + return(0); + } + + if (!config_parser__match_token(ctx, TokenCppKind_Semicolon)){ + config_parser__log_error(ctx, "expected token ';' for version specifier: 'version(#)'"); + config_parser__recover_parse(ctx); + return(0); + } + + i32 *ptr = push_array(ctx->arena, i32, 1); + *ptr = value.integer; + return(ptr); +} + +function Config_Assignment* +config_parser__assignment(Config_Parser *ctx){ + u8 *pos = config_parser__get_pos(ctx); + + Config_LValue *l = config_parser__lvalue(ctx); + if (l == 0){ + config_parser__log_error(ctx, "expected an l-value; l-value formats: 'identifier', 'identifier[#]'"); + config_parser__recover_parse(ctx); + return(0); + } + + if (!config_parser__match_token(ctx, TokenCppKind_Eq)){ + config_parser__log_error(ctx, "expected token '=' for assignment: 'l-value = r-value;'"); + config_parser__recover_parse(ctx); + return(0); + } + + Config_RValue *r = config_parser__rvalue(ctx); + if (r == 0){ + config_parser__log_error(ctx, "expected an r-value; r-value formats:\n" + "\tconstants (true, false, integers, hexadecimal integers, strings, characters)\n" + "\tany l-value that is set in the file\n" + "\tcompound: '{ compound-element, compound-element, compound-element ...}'\n" + "\ta compound-element is an r-value, and can have a layout specifier\n" + "\tcompound-element with layout specifier: .name = r-value, .integer = r-value"); + config_parser__recover_parse(ctx); + return(0); + } + + if (!config_parser__match_token(ctx, TokenCppKind_Semicolon)){ + config_parser__log_error(ctx, "expected token ';' for assignment: 'l-value = r-value;'"); + config_parser__recover_parse(ctx); + return(0); + } + + Config_Assignment *assignment = push_array_zero(ctx->arena, Config_Assignment, 1); + assignment->pos = pos; + assignment->l = l; + assignment->r = r; + return(assignment); +} + +function Config_LValue* +config_parser__lvalue(Config_Parser *ctx){ + require(config_parser__recognize_token(ctx, TokenCppKind_Identifier)); + String_Const_u8 identifier = config_parser__get_lexeme(ctx); + config_parser__advance_to_next(ctx); + + i32 index = 0; + if (config_parser__match_token(ctx, TokenCppKind_BrackOp)){ + require(config_parser__recognize_base_token(ctx, TokenBaseKind_LiteralInteger)); + Config_Integer value = config_parser__get_int(ctx); + index = value.integer; + config_parser__advance_to_next(ctx); + require(config_parser__match_token(ctx, TokenCppKind_BrackCl)); + } + + Config_LValue *lvalue = push_array_zero(ctx->arena, Config_LValue, 1); + lvalue->identifier = identifier; + lvalue->index = index; + return(lvalue); +} + +function Config_RValue* +config_parser__rvalue(Config_Parser *ctx){ + Config_RValue *rvalue = 0; + if (config_parser__recognize_token(ctx, TokenCppKind_Identifier)){ + Config_LValue *l = config_parser__lvalue(ctx); + require(l != 0); + rvalue = push_array_zero(ctx->arena, Config_RValue, 1); + rvalue->type = ConfigRValueType_LValue; + rvalue->lvalue = l; + } + else if (config_parser__recognize_token(ctx, TokenCppKind_BraceOp)){ + config_parser__advance_to_next(ctx); + Config_Compound *compound = config_parser__compound(ctx); + require(compound != 0); + rvalue = push_array_zero(ctx->arena, Config_RValue, 1); + rvalue->type = ConfigRValueType_Compound; + rvalue->compound = compound; + } + else if (config_parser__recognize_boolean(ctx)){ + b32 b = config_parser__get_boolean(ctx); + config_parser__advance_to_next(ctx); + rvalue = push_array_zero(ctx->arena, Config_RValue, 1); + rvalue->type = ConfigRValueType_Boolean; + rvalue->boolean = b; + } + else if (config_parser__recognize_base_token(ctx, TokenBaseKind_LiteralInteger)){ + Config_Integer value = config_parser__get_int(ctx); + config_parser__advance_to_next(ctx); + rvalue = push_array_zero(ctx->arena, Config_RValue, 1); + rvalue->type = ConfigRValueType_Integer; + if (value.is_signed){ + rvalue->integer = value.integer; + } + else{ + rvalue->uinteger = value.uinteger; + } + } + else if (config_parser__recognize_token(ctx, TokenCppKind_LiteralString)){ + String_Const_u8 s = config_parser__get_lexeme(ctx); + config_parser__advance_to_next(ctx); + s = string_chop(string_skip(s, 1), 1); + String_Const_u8 interpreted = string_interpret_escapes(ctx->arena, s); + rvalue = push_array_zero(ctx->arena, Config_RValue, 1); + rvalue->type = ConfigRValueType_String; + rvalue->string = interpreted; + } + else if (config_parser__recognize_token(ctx, TokenCppKind_LiteralCharacter)){ + String_Const_u8 s = config_parser__get_lexeme(ctx); + config_parser__advance_to_next(ctx); + s = string_chop(string_skip(s, 1), 1); + String_Const_u8 interpreted = string_interpret_escapes(ctx->arena, s); + rvalue = push_array_zero(ctx->arena, Config_RValue, 1); + rvalue->type = ConfigRValueType_Character; + rvalue->character = string_get_character(interpreted, 0); + } + return(rvalue); +} + +function void +config_parser__compound__check(Config_Parser *ctx, Config_Compound *compound){ + b32 implicit_index_allowed = true; + for (Config_Compound_Element *node = compound->first; + node != 0; + node = node->next){ + if (node->l.type != ConfigLayoutType_Unset){ + implicit_index_allowed = false; + } + else if (!implicit_index_allowed){ + config_parser__log_error_pos(ctx, node->l.pos, + "encountered unlabeled member after one or more labeled members"); + } + } +} + +function Config_Compound* +config_parser__compound(Config_Parser *ctx){ + Config_Compound_Element *first = 0; + Config_Compound_Element *last = 0; + i32 count = 0; + + Config_Compound_Element *element = config_parser__element(ctx); + require(element != 0); + zdll_push_back(first, last, element); + count += 1; + + for (;config_parser__match_token(ctx, TokenCppKind_Comma);){ + if (config_parser__recognize_token(ctx, TokenCppKind_BraceCl)){ + break; + } + element = config_parser__element(ctx); + require(element != 0); + zdll_push_back(first, last, element); + count += 1; + } + + require(config_parser__match_token(ctx, TokenCppKind_BraceCl)); + + Config_Compound *compound = push_array(ctx->arena, Config_Compound, 1); + block_zero_struct(compound); + compound->first = first; + compound->last = last; + compound->count = count; + config_parser__compound__check(ctx, compound); + return(compound); +} + +function Config_Compound_Element* +config_parser__element(Config_Parser *ctx){ + Config_Layout layout = {}; + layout.pos = config_parser__get_pos(ctx); + if (config_parser__match_token(ctx, TokenCppKind_Dot)){ + if (config_parser__recognize_token(ctx, TokenCppKind_Identifier)){ + layout.type = ConfigLayoutType_Identifier; + layout.identifier = config_parser__get_lexeme(ctx); + config_parser__advance_to_next(ctx); + } + else if (config_parser__recognize_base_token(ctx, TokenBaseKind_LiteralInteger)){ + layout.type = ConfigLayoutType_Integer; + Config_Integer value = config_parser__get_int(ctx); + layout.integer = value.integer; + config_parser__advance_to_next(ctx); + } + else{ + return(0); + } + require(config_parser__match_token(ctx, TokenCppKind_Eq)); + } + Config_RValue *rvalue = config_parser__rvalue(ctx); + require(rvalue != 0); + Config_Compound_Element *element = push_array(ctx->arena, Config_Compound_Element, 1); + block_zero_struct(element); + element->l = layout; + element->r = rvalue; + return(element); +} + +//////////////////////////////// + +function Config_Error* +config_add_error(Arena *arena, Config *config, u8 *pos, char *error_text){ + return(config_error_push(arena, &config->errors, config->file_name, pos, + error_text)); +} + +//////////////////////////////// + +function Config_Assignment* +config_lookup_assignment(Config *config, String_Const_u8 var_name, i32 subscript){ + Config_Assignment *assignment = 0; + for (assignment = config->first; + assignment != 0; + assignment = assignment->next){ + Config_LValue *l = assignment->l; + if (l != 0 && string_match(l->identifier, var_name) && l->index == subscript){ + break; + } + } + return(assignment); +} + +function Config_Get_Result +config_var(Config *config, String_Const_u8 var_name, i32 subscript); + +function Config_Get_Result +config_evaluate_rvalue(Config *config, Config_Assignment *assignment, Config_RValue *r){ + Config_Get_Result result = {}; + if (r != 0 && !assignment->visited){ + if (r->type == ConfigRValueType_LValue){ + assignment->visited = true; + Config_LValue *l = r->lvalue; + result = config_var(config, l->identifier, l->index); + assignment->visited = false; + } + else{ + result.success = true; + result.pos = assignment->pos; + result.type = r->type; + switch (r->type){ + case ConfigRValueType_Boolean: + { + result.boolean = r->boolean; + }break; + + case ConfigRValueType_Integer: + { + result.integer = r->integer; + }break; + + case ConfigRValueType_String: + { + result.string = r->string; + }break; + + case ConfigRValueType_Character: + { + result.character = r->character; + }break; + + case ConfigRValueType_Compound: + { + result.compound = r->compound; + }break; + } + } + } + return(result); +} + +function Config_Get_Result +config_var(Config *config, String_Const_u8 var_name, i32 subscript){ + Config_Get_Result result = {}; + Config_Assignment *assignment = config_lookup_assignment(config, var_name, subscript); + if (assignment != 0){ + result = config_evaluate_rvalue(config, assignment, assignment->r); + } + return(result); +} + +function Config_Get_Result +config_compound_member(Config *config, Config_Compound *compound, String_Const_u8 var_name, i32 index){ + Config_Get_Result result = {}; + i32 implicit_index = 0; + b32 implicit_index_is_valid = true; + for (Config_Compound_Element *element = compound->first; + element != 0; + element = element->next, implicit_index += 1){ + b32 element_matches_query = false; + switch (element->l.type){ + case ConfigLayoutType_Unset: + { + if (implicit_index_is_valid && index == implicit_index){ + element_matches_query = true; + } + }break; + + case ConfigLayoutType_Identifier: + { + implicit_index_is_valid = false; + if (string_match(element->l.identifier, var_name)){ + element_matches_query = true; + } + }break; + + case ConfigLayoutType_Integer: + { + implicit_index_is_valid = false; + if (element->l.integer == index){ + element_matches_query = true; + } + }break; + } + if (element_matches_query){ + Config_Assignment dummy_assignment = {}; + dummy_assignment.pos = element->l.pos; + result = config_evaluate_rvalue(config, &dummy_assignment, element->r); + break; + } + } + return(result); +} + +function Config_Iteration_Step_Result +typed_array_iteration_step(Config *parsed, Config_Compound *compound, Config_RValue_Type type, i32 index); + +function i32 +typed_array_get_count(Config *parsed, Config_Compound *compound, Config_RValue_Type type); + +function Config_Get_Result_List +typed_array_reference_list(Arena *arena, Config *parsed, Config_Compound *compound, Config_RValue_Type type); + +#define config_fixed_string_var(c,v,s,o,a) config_placed_string_var((c),(v),(s),(o),(a),sizeof(a)) + +//////////////////////////////// + +function b32 +config_has_var(Config *config, String_Const_u8 var_name, i32 subscript){ + Config_Get_Result result = config_var(config, var_name, subscript); + return(result.success && result.type == ConfigRValueType_NoType); +} + +function b32 +config_has_var(Config *config, char *var_name, i32 subscript){ + return(config_has_var(config, SCu8(var_name), subscript)); +} + +function b32 +config_bool_var(Config *config, String_Const_u8 var_name, i32 subscript, b32* var_out){ + Config_Get_Result result = config_var(config, var_name, subscript); + b32 success = (result.success && result.type == ConfigRValueType_Boolean); + if (success){ + *var_out = result.boolean; + } + return(success); +} +function b32 +config_bool_var(Config *config, String_Const_u8 var_name, i32 subscript, b8 *var_out){ + b32 temp = false; + b32 success = config_bool_var(config, var_name, subscript, &temp); + if (success){ + *var_out = (temp != false); + } + return(success); +} +function b32 +config_bool_var(Config *config, char *var_name, i32 subscript, b32* var_out){ + return(config_bool_var(config, SCu8(var_name), subscript, var_out)); +} +function b32 +config_bool_var(Config *config, char* var_name, i32 subscript, b8 *var_out){ + b32 temp = false; + b32 success = config_bool_var(config, SCu8(var_name), subscript, &temp); + if (success){ + *var_out = (temp != false); + } + return(success); +} + +function b32 +config_int_var(Config *config, String_Const_u8 var_name, i32 subscript, i32* var_out){ + Config_Get_Result result = config_var(config, var_name, subscript); + b32 success = result.success && result.type == ConfigRValueType_Integer; + if (success){ + *var_out = result.integer; + } + return(success); +} + +function b32 +config_int_var(Config *config, char *var_name, i32 subscript, i32* var_out){ + return(config_int_var(config, SCu8(var_name), subscript, var_out)); +} + +function b32 +config_uint_var(Config *config, String_Const_u8 var_name, i32 subscript, u32* var_out){ + Config_Get_Result result = config_var(config, var_name, subscript); + b32 success = result.success && result.type == ConfigRValueType_Integer; + if (success){ + *var_out = result.uinteger; + } + return(success); +} + +function b32 +config_uint_var(Config *config, char *var_name, i32 subscript, u32* var_out){ + return(config_uint_var(config, SCu8(var_name), subscript, var_out)); +} + +function b32 +config_string_var(Config *config, String_Const_u8 var_name, i32 subscript, String_Const_u8* var_out){ + Config_Get_Result result = config_var(config, var_name, subscript); + b32 success = result.success && result.type == ConfigRValueType_String; + if (success){ + *var_out = result.string; + } + return(success); +} + +function b32 +config_string_var(Config *config, char *var_name, i32 subscript, String_Const_u8* var_out){ + return(config_string_var(config, SCu8(var_name), subscript, var_out)); +} + +function b32 +config_placed_string_var(Config *config, String_Const_u8 var_name, i32 subscript, String_Const_u8* var_out, u8 *space, u64 space_size){ + Config_Get_Result result = config_var(config, var_name, subscript); + b32 success = (result.success && result.type == ConfigRValueType_String); + if (success){ + u64 size = result.string.size; + size = clamp_top(size, space_size); + block_copy(space, result.string.str, size); + *var_out = SCu8(space, size); + } + return(success); +} + +function b32 +config_placed_string_var(Config *config, char *var_name, i32 subscript, String_Const_u8* var_out, u8 *space, u64 space_size){ + return(config_placed_string_var(config, SCu8(var_name), subscript, var_out, space, space_size)); +} + +function b32 +config_char_var(Config *config, String_Const_u8 var_name, i32 subscript, char* var_out){ + Config_Get_Result result = config_var(config, var_name, subscript); + b32 success = result.success && result.type == ConfigRValueType_Character; + if (success){ + *var_out = result.character; + } + return(success); +} + +function b32 +config_char_var(Config *config, char *var_name, i32 subscript, char* var_out){ + return(config_char_var(config, SCu8(var_name), subscript, var_out)); +} + +function b32 +config_compound_var(Config *config, String_Const_u8 var_name, i32 subscript, Config_Compound** var_out){ + Config_Get_Result result = config_var(config, var_name, subscript); + b32 success = (result.success && result.type == ConfigRValueType_Compound); + if (success){ + *var_out = result.compound; + } + return(success); +} + +function b32 +config_compound_var(Config *config, char *var_name, i32 subscript, Config_Compound** var_out){ + return(config_compound_var(config, SCu8(var_name), subscript, var_out)); +} + +function b32 +config_compound_has_member(Config *config, Config_Compound *compound, + String_Const_u8 var_name, i32 index){ + Config_Get_Result result = config_compound_member(config, compound, var_name, index); + b32 success = result.success && result.type == ConfigRValueType_NoType; + return(success); +} + +function b32 +config_compound_has_member(Config *config, Config_Compound *compound, + char *var_name, i32 index){ + return(config_compound_has_member(config, compound, SCu8(var_name), index)); +} + +function b32 +config_compound_bool_member(Config *config, Config_Compound *compound, + String_Const_u8 var_name, i32 index, b32* var_out){ + Config_Get_Result result = config_compound_member(config, compound, var_name, index); + b32 success = result.success && result.type == ConfigRValueType_Boolean; + if (success){ + *var_out = result.boolean; + } + return(success); +} + +function b32 +config_compound_bool_member(Config *config, Config_Compound *compound, + char *var_name, i32 index, b32* var_out){ + return(config_compound_bool_member(config, compound, SCu8(var_name), index, var_out)); +} + +function b32 +config_compound_int_member(Config *config, Config_Compound *compound, + String_Const_u8 var_name, i32 index, i32* var_out){ + Config_Get_Result result = config_compound_member(config, compound, var_name, index); + b32 success = result.success && result.type == ConfigRValueType_Integer; + if (success){ + *var_out = result.integer; + } + return(success); +} + +function b32 +config_compound_int_member(Config *config, Config_Compound *compound, + char *var_name, i32 index, i32* var_out){ + return(config_compound_int_member(config, compound, SCu8(var_name), index, var_out)); +} + +function b32 +config_compound_uint_member(Config *config, Config_Compound *compound, + String_Const_u8 var_name, i32 index, u32* var_out){ + Config_Get_Result result = config_compound_member(config, compound, var_name, index); + b32 success = result.success && result.type == ConfigRValueType_Integer; + if (success){ + *var_out = result.uinteger; + } + return(success); +} + +function b32 +config_compound_uint_member(Config *config, Config_Compound *compound, + char *var_name, i32 index, u32* var_out){ + return(config_compound_uint_member(config, compound, SCu8(var_name), index, var_out)); +} + +function b32 +config_compound_string_member(Config *config, Config_Compound *compound, + String_Const_u8 var_name, i32 index, String_Const_u8* var_out){ + Config_Get_Result result = config_compound_member(config, compound, var_name, index); + b32 success = (result.success && result.type == ConfigRValueType_String); + if (success){ + *var_out = result.string; + } + return(success); +} + +function b32 +config_compound_string_member(Config *config, Config_Compound *compound, + char *var_name, i32 index, String_Const_u8* var_out){ + return(config_compound_string_member(config, compound, SCu8(var_name), index, var_out)); +} + +function b32 +config_compound_placed_string_member(Config *config, Config_Compound *compound, + String_Const_u8 var_name, i32 index, String_Const_u8* var_out, u8 *space, u64 space_size){ + Config_Get_Result result = config_compound_member(config, compound, var_name, index); + b32 success = (result.success && result.type == ConfigRValueType_String); + if (success){ + u64 size = result.string.size; + size = clamp_top(size, space_size); + block_copy(space, result.string.str, size); + *var_out = SCu8(space, size); + } + return(success); +} + +function b32 +config_compound_placed_string_member(Config *config, Config_Compound *compound, + char *var_name, i32 index, String_Const_u8* var_out, u8 *space, u64 space_size){ + return(config_compound_placed_string_member(config, compound, SCu8(var_name), index, var_out, space, space_size)); +} + +function b32 +config_compound_char_member(Config *config, Config_Compound *compound, + String_Const_u8 var_name, i32 index, char* var_out){ + Config_Get_Result result = config_compound_member(config, compound, var_name, index); + b32 success = result.success && result.type == ConfigRValueType_Character; + if (success){ + *var_out = result.character; + } + return(success); +} + +function b32 +config_compound_char_member(Config *config, Config_Compound *compound, + char *var_name, i32 index, char* var_out){ + return(config_compound_char_member(config, compound, SCu8(var_name), index, var_out)); +} + +function b32 +config_compound_compound_member(Config *config, Config_Compound *compound, + String_Const_u8 var_name, i32 index, Config_Compound** var_out){ + Config_Get_Result result = config_compound_member(config, compound, var_name, index); + b32 success = result.success && result.type == ConfigRValueType_Compound; + if (success){ + *var_out = result.compound; + } + return(success); +} + +function b32 +config_compound_compound_member(Config *config, Config_Compound *compound, + char *var_name, i32 index, Config_Compound** var_out){ + return(config_compound_compound_member(config, compound, SCu8(var_name), index, var_out)); +} + +function Iteration_Step_Result +typed_has_array_iteration_step(Config *config, Config_Compound *compound, i32 index){ + Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_NoType, index); + return(result.step); +} + +function Iteration_Step_Result +typed_bool_array_iteration_step(Config *config, Config_Compound *compound, i32 index, b32* var_out){ + Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Boolean, index); + b32 success = (result.step == Iteration_Good); + if (success){ + *var_out = result.get.boolean; + } + return(result.step); +} + +function Iteration_Step_Result +typed_int_array_iteration_step(Config *config, Config_Compound *compound, i32 index, i32* var_out){ + Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Integer, index); + b32 success = (result.step == Iteration_Good); + if (success){ + *var_out = result.get.integer; + } + return(result.step); +} + +function Iteration_Step_Result +typed_uint_array_iteration_step(Config *config, Config_Compound *compound, i32 index, u32* var_out){ + Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Integer, index); + b32 success = (result.step == Iteration_Good); + if (success){ + *var_out = result.get.uinteger; + } + return(result.step); +} + +function Iteration_Step_Result +typed_string_array_iteration_step(Config *config, Config_Compound *compound, i32 index, String_Const_u8* var_out){ + Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_String, index); + b32 success = (result.step == Iteration_Good); + if (success){ + *var_out = result.get.string; + } + return(result.step); +} + +function Iteration_Step_Result +typed_placed_string_array_iteration_step(Config *config, Config_Compound *compound, i32 index, String_Const_u8* var_out, u8 *space, u64 space_size){ + Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_String, index); + b32 success = (result.step == Iteration_Good); + if (success){ + u64 size = result.get.string.size; + size = clamp_top(size, space_size); + block_copy(space, result.get.string.str, size); + *var_out = SCu8(space, size); + } + return(result.step); +} + +function Iteration_Step_Result +typed_char_array_iteration_step(Config *config, Config_Compound *compound, i32 index, char* var_out){ + Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Character, index); + b32 success = (result.step == Iteration_Good); + if (success){ + *var_out = result.get.character; + } + return(result.step); +} + +function Iteration_Step_Result +typed_compound_array_iteration_step(Config *config, Config_Compound *compound, i32 index, Config_Compound** var_out){ + Config_Iteration_Step_Result result = typed_array_iteration_step(config, compound, ConfigRValueType_Compound, index); + b32 success = (result.step == Iteration_Good); + if (success){ + *var_out = result.get.compound; + } + return(result.step); +} + +function i32 +typed_bool_array_get_count(Config *config, Config_Compound *compound){ + i32 count = typed_array_get_count(config, compound, ConfigRValueType_Boolean); + return(count); +} + +function i32 +typed_int_array_get_count(Config *config, Config_Compound *compound){ + i32 count = typed_array_get_count(config, compound, ConfigRValueType_Integer); + return(count); +} + +function i32 +typed_float_array_get_count(Config *config, Config_Compound *compound){ + i32 count = typed_array_get_count(config, compound, ConfigRValueType_Float); + return(count); +} + +function i32 +typed_string_array_get_count(Config *config, Config_Compound *compound){ + i32 count = typed_array_get_count(config, compound, ConfigRValueType_String); + return(count); +} + +function i32 +typed_character_array_get_count(Config *config, Config_Compound *compound){ + i32 count = typed_array_get_count(config, compound, ConfigRValueType_Character); + return(count); +} + +function i32 +typed_compound_array_get_count(Config *config, Config_Compound *compound){ + i32 count = typed_array_get_count(config, compound, ConfigRValueType_Compound); + return(count); +} + +function i32 +typed_no_type_array_get_count(Config *config, Config_Compound *compound){ + i32 count = typed_array_get_count(config, compound, ConfigRValueType_NoType); + return(count); +} + +function Config_Get_Result_List +typed_bool_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ + Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Boolean); + return(list); +} + +function Config_Get_Result_List +typed_int_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ + Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Integer); + return(list); +} + +function Config_Get_Result_List +typed_float_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ + Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Float); + return(list); +} + +function Config_Get_Result_List +typed_string_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ + Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_String); + return(list); +} + +function Config_Get_Result_List +typed_character_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ + Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Character); + return(list); +} + +function Config_Get_Result_List +typed_compound_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ + Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_Compound); + return(list); +} + +function Config_Get_Result_List +typed_no_type_array_reference_list(Arena *arena, Config *config, Config_Compound *compound){ + Config_Get_Result_List list = typed_array_reference_list(arena, config, compound, ConfigRValueType_NoType); + return(list); +} + +//////////////////////////////// + +function Config_Iteration_Step_Result +typed_array_iteration_step(Config *parsed, Config_Compound *compound, Config_RValue_Type type, i32 index){ + Config_Iteration_Step_Result result = {}; + result.step = Iteration_Quit; + Config_Get_Result get_result = config_compound_member(parsed, compound, string_u8_litexpr("~"), index); + if (get_result.success){ + if (get_result.type == type || type == ConfigRValueType_NoType){ + result.step = Iteration_Good; + result.get = get_result; + } + else{ + result.step = Iteration_Skip; + } + } + return(result); +} + +function i32 +typed_array_get_count(Config *parsed, Config_Compound *compound, Config_RValue_Type type){ + i32 count = 0; + for (i32 i = 0;; ++i){ + Config_Iteration_Step_Result result = typed_array_iteration_step(parsed, compound, type, i); + if (result.step == Iteration_Skip){ + continue; + } + else if (result.step == Iteration_Quit){ + break; + } + count += 1; + } + return(count); +} + +function Config_Get_Result_List +typed_array_reference_list(Arena *arena, Config *parsed, Config_Compound *compound, Config_RValue_Type type){ + Config_Get_Result_List list = {}; + for (i32 i = 0;; ++i){ + Config_Iteration_Step_Result result = typed_array_iteration_step(parsed, compound, type, i); + if (result.step == Iteration_Skip){ + continue; + } + else if (result.step == Iteration_Quit){ + break; + } + Config_Get_Result_Node *node = push_array(arena, Config_Get_Result_Node, 1); + node->result = result.get; + zdll_push_back(list.first, list.last, node); + list.count += 1; + } + return(list); +} + +//////////////////////////////// + +function void +change_mode(Application_Links *app, String_Const_u8 mode){ + fcoder_mode = FCoderMode_Original; + if (string_match(mode, string_u8_litexpr("4coder"))){ + fcoder_mode = FCoderMode_Original; + } + else if (string_match(mode, string_u8_litexpr("notepad-like"))){ + begin_notepad_mode(app); + } + else{ + print_message(app, string_u8_litexpr("Unknown mode.\n")); + } +} + +//////////////////////////////// + +function Token_Array +token_array_from_text(Application_Links *app, Arena *arena, String_Const_u8 data){ + ProfileScope(app, "token array from text"); + Token_List list = lex_full_input_cpp(arena, data); + return(token_array_from_list(arena, &list)); +} + +function Config* +config_from_text(Application_Links *app, Arena *arena, String_Const_u8 file_name, + String_Const_u8 data){ + Config *parsed = 0; + Temp_Memory restore_point = begin_temp(arena); + Token_Array array = token_array_from_text(app, arena, data); + if (array.tokens != 0){ + parsed = config_parse(app, arena, file_name, data, array); + if (parsed == 0){ + end_temp(restore_point); + } + } + return(parsed); +} + +//////////////////////////////// + +function void +config_init_default(Config_Data *config){ + config->user_name = SCu8(config->user_name_space, (u64)0); + + block_zero_struct(&config->code_exts); + + config->mapping = SCu8(config->mapping_space, (u64)0); + config->mode = SCu8(config->mode_space, (u64)0); + + config->use_scroll_bars = false; + config->use_file_bars = true; + config->hide_file_bar_in_ui = true; + config->use_error_highlight = true; + config->use_jump_highlight = true; + config->use_scope_highlight = true; + config->use_paren_helper = true; + config->use_comment_keyword = true; + config->lister_whole_word_backspace_when_modified = false; + config->show_line_number_margins = false; + + config->enable_virtual_whitespace = true; + config->enable_code_wrapping = true; + config->automatically_indent_text_on_save = true; + config->automatically_save_changes_on_build = true; + config->automatically_load_project = false; + + config->indent_with_tabs = false; + config->indent_width = 4; + + config->default_theme_name = SCu8(config->default_theme_name_space, sizeof("4coder") - 1); + block_copy(config->default_theme_name.str, "4coder", config->default_theme_name.size); + config->highlight_line_at_cursor = true; + + config->default_font_name = SCu8(config->default_font_name_space, (u64)0); + config->default_font_size = 16; + config->default_font_hinting = false; + + config->default_compiler_bat = SCu8(config->default_compiler_bat_space, 2); + block_copy(config->default_compiler_bat.str, "cl", 2); + + config->default_flags_bat = SCu8(config->default_flags_bat_space, (u64)0); + + config->default_compiler_sh = SCu8(config->default_compiler_sh_space, 3); + block_copy(config->default_compiler_sh.str, "g++", 3); + + config->default_flags_sh = SCu8(config->default_flags_sh_space, (u64)0); + + config->lalt_lctrl_is_altgr = false; +} + +function Config* +config_parse__data(Application_Links *app, Arena *arena, String_Const_u8 file_name, + String_Const_u8 data, Config_Data *config){ + config_init_default(config); + + b32 success = false; + + Config *parsed = config_from_text(app, arena, file_name, data); + if (parsed != 0){ + success = true; + + config_fixed_string_var(parsed, "user_name", 0, + &config->user_name, config->user_name_space); + + String_Const_u8 str = {}; + if (config_string_var(parsed, "treat_as_code", 0, &str)){ + config->code_exts = + parse_extension_line_to_extension_list(app, arena, str); + } + + config_fixed_string_var(parsed, "mapping", 0, &config->mapping, config->mapping_space); + config_fixed_string_var(parsed, "mode", 0, &config->mode, config->mode_space); + + config_bool_var(parsed, "use_scroll_bars", 0, &config->use_scroll_bars); + config_bool_var(parsed, "use_file_bars", 0, &config->use_file_bars); + config_bool_var(parsed, "hide_file_bar_in_ui", 0, &config->hide_file_bar_in_ui); + config_bool_var(parsed, "use_error_highlight", 0, &config->use_error_highlight); + config_bool_var(parsed, "use_jump_highlight", 0, &config->use_jump_highlight); + config_bool_var(parsed, "use_scope_highlight", 0, &config->use_scope_highlight); + config_bool_var(parsed, "use_paren_helper", 0, &config->use_paren_helper); + config_bool_var(parsed, "use_comment_keyword", 0, &config->use_comment_keyword); + config_bool_var(parsed, "lister_whole_word_backspace_when_modified", 0, &config->lister_whole_word_backspace_when_modified); + config_bool_var(parsed, "show_line_number_margins", 0, &config->show_line_number_margins); + + + config_bool_var(parsed, "enable_virtual_whitespace", 0, &config->enable_virtual_whitespace); + config_bool_var(parsed, "enable_code_wrapping", 0, &config->enable_code_wrapping); + config_bool_var(parsed, "automatically_indent_text_on_save", 0, &config->automatically_indent_text_on_save); + config_bool_var(parsed, "automatically_save_changes_on_build", 0, &config->automatically_save_changes_on_build); + config_bool_var(parsed, "automatically_load_project", 0, &config->automatically_load_project); + + config_bool_var(parsed, "indent_with_tabs", 0, &config->indent_with_tabs); + config_int_var(parsed, "indent_width", 0, &config->indent_width); + + config_fixed_string_var(parsed, "default_theme_name", 0, + &config->default_theme_name, config->default_theme_name_space); + config_bool_var(parsed, "highlight_line_at_cursor", 0, &config->highlight_line_at_cursor); + + config_fixed_string_var(parsed, "default_font_name", 0, + &config->default_font_name, config->default_font_name_space); + config_int_var(parsed, "default_font_size", 0, &config->default_font_size); + config_bool_var(parsed, "default_font_hinting", 0, &config->default_font_hinting); + + config_fixed_string_var(parsed, "default_compiler_bat", 0, + &config->default_compiler_bat, config->default_compiler_bat_space); + config_fixed_string_var(parsed, "default_flags_bat", 0, + &config->default_flags_bat, config->default_flags_bat_space); + config_fixed_string_var(parsed, "default_compiler_sh", 0, + &config->default_compiler_sh, config->default_compiler_sh_space); + config_fixed_string_var(parsed, "default_flags_sh", 0, + &config->default_flags_sh, config->default_flags_sh_space); + + config_bool_var(parsed, "lalt_lctrl_is_altgr", 0, &config->lalt_lctrl_is_altgr); + } + + if (!success){ + config_init_default(config); + } + + return(parsed); +} + +function Config* +config_parse__file_handle(Application_Links *app, Arena *arena, + String_Const_u8 file_name, FILE *file, Config_Data *config){ + Config *parsed = 0; + Data data = dump_file_handle(arena, file); + if (data.data != 0){ + parsed = config_parse__data(app, arena, file_name, SCu8(data), config); + } + else{ + config_init_default(config); + } + return(parsed); +} + +function Config* +config_parse__file_name(Application_Links *app, Arena *arena, char *file_name, Config_Data *config){ + Config *parsed = 0; + b32 success = false; + FILE *file = open_file_try_current_path_then_binary_path(app, file_name); + if (file != 0){ + Data data = dump_file_handle(arena, file); + fclose(file); + if (data.data != 0){ + parsed = config_parse__data(app, arena, SCu8(file_name), SCu8(data), + config); + success = true; + } + } + if (!success){ + config_init_default(config); + } + return(parsed); +} + +function Config* +theme_parse__data(Application_Links *app, Arena *arena, String_Const_u8 file_name, String_Const_u8 data, Arena *color_arena, Color_Table *color_table){ + Config *parsed = config_from_text(app, arena, file_name, data); + if (parsed != 0){ + for (Config_Assignment *node = parsed->first; + node != 0; + node = node->next){ + Scratch_Block scratch(app); + Config_LValue *l = node->l; + String_Const_u8 l_name = push_string_copy(scratch, l->identifier); + Managed_ID id = managed_id_get(app, string_u8_litexpr("colors"), l_name); + if (id != 0){ + u32 color = 0; + if (config_uint_var(parsed, l_name, 0, &color)){ + color_table->arrays[id%color_table->count] = make_colors(color_arena, color); + } + else{ + Config_Compound *compound = 0; + if (config_compound_var(parsed, l_name, 0, &compound)){ + local_persist u32 color_array[256]; + i32 counter = 0; + for (i32 i = 0;; i += 1){ + Config_Iteration_Step_Result result = typed_array_iteration_step(parsed, compound, ConfigRValueType_Integer, i); + if (result.step == Iteration_Skip){ + continue; + } + else if (result.step == Iteration_Quit){ + break; + } + + color_array[counter] = result.get.uinteger; + counter += 1; + if (counter == 256){ + break; + } + } + + color_table->arrays[id%color_table->count] = make_colors(color_arena, color_array, counter); + } + } + } + + } + } + return(parsed); +} + +function Config* +theme_parse__buffer(Application_Links *app, Arena *arena, Buffer_ID buffer, Arena *color_arena, Color_Table *color_table){ + String_Const_u8 contents = push_whole_buffer(app, arena, buffer); + Config *parsed = 0; + if (contents.str != 0){ + String_Const_u8 file_name = push_buffer_file_name(app, arena, buffer); + parsed = theme_parse__data(app, arena, file_name, contents, color_arena, color_table); + } + return(parsed); +} + +function Config* +theme_parse__file_handle(Application_Links *app, Arena *arena, String_Const_u8 file_name, FILE *file, Arena *color_arena, Color_Table *color_table){ + Data data = dump_file_handle(arena, file); + Config *parsed = 0; + if (data.data != 0){ + parsed = theme_parse__data(app, arena, file_name, SCu8(data), color_arena, color_table); + } + return(parsed); +} + +function Config* +theme_parse__file_name(Application_Links *app, Arena *arena, char *file_name, Arena *color_arena, Color_Table *color_table){ + Config *parsed = 0; + FILE *file = open_file_try_current_path_then_binary_path(app, file_name); + if (file != 0){ + Data data = dump_file_handle(arena, file); + fclose(file); + parsed = theme_parse__data(app, arena, SCu8(file_name), SCu8(data), color_arena, color_table); + } + if (parsed == 0){ + Scratch_Block scratch(app); + String_Const_u8 str = push_u8_stringf(arena, "Did not find %s, theme not loaded", file_name); + print_message(app, str); + } + return(parsed); +} + +//////////////////////////////// + +function void +config_feedback_bool(Arena *arena, List_String_Const_u8 *list, char *name, b32 val){ + string_list_pushf(arena, list, "%s = %s;\n", name, (char*)(val?"true":"false")); +} + +function void +config_feedback_string(Arena *arena, List_String_Const_u8 *list, char *name, String_Const_u8 val){ + val.size = clamp_bot(0, val.size); + string_list_pushf(arena, list, "%s = \"%.*s\";\n", name, string_expand(val)); +} + +function void +config_feedback_string(Arena *arena, List_String_Const_u8 *list, char *name, char *val){ + string_list_pushf(arena, list, "%s = \"%s\";\n", name, val); +} + +function void +config_feedback_extension_list(Arena *arena, List_String_Const_u8 *list, char *name, String_Const_u8_Array *extensions){ + string_list_pushf(arena, list, "%s = \"", name); + for (i32 i = 0; i < extensions->count; ++i){ + String_Const_u8 ext = extensions->strings[i]; + string_list_pushf(arena, list, ".%.*s", string_expand(ext)); + } + string_list_push_u8_lit(arena, list, "\";\n"); +} + +function void +config_feedback_int(Arena *arena, List_String_Const_u8 *list, char *name, i32 val){ + string_list_pushf(arena, list, "%s = %d;\n", name, val); +} + +//////////////////////////////// + +function void +load_config_and_apply(Application_Links *app, Arena *out_arena, Config_Data *config, + i32 override_font_size, b32 override_hinting){ + Scratch_Block scratch(app); + + linalloc_clear(out_arena); + Config *parsed = config_parse__file_name(app, out_arena, "config.4coder", config); + + if (parsed != 0){ + // Top + print_message(app, string_u8_litexpr("Loaded config file:\n")); + + // Errors + String_Const_u8 error_text = config_stringize_errors(app, scratch, parsed); + if (error_text.str != 0){ + print_message(app, error_text); + } + } + else{ + print_message(app, string_u8_litexpr("Using default config:\n")); + Face_Description description = get_face_description(app, 0); + if (description.font.file_name.str != 0){ + u64 size = Min(description.font.file_name.size, sizeof(config->default_font_name_space)); + block_copy(config->default_font_name_space, description.font.file_name.str, size); + config->default_font_name.size = size; + } + } + + if (config->default_font_name.size == 0){ +#define M "liberation-mono.ttf" + block_copy(config->default_font_name_space, M, sizeof(M) - 1); + config->default_font_name.size = sizeof(M) - 1; +#undef M + } + + { + // Values + Temp_Memory temp2 = begin_temp(scratch); + List_String_Const_u8 list = {}; + + config_feedback_string(scratch, &list, "user_name", config->user_name); + config_feedback_extension_list(scratch, &list, "treat_as_code", &config->code_exts); + + config_feedback_string(scratch, &list, "mapping", config->mapping); + config_feedback_string(scratch, &list, "mode", config->mode); + + config_feedback_bool(scratch, &list, "use_scroll_bars", config->use_scroll_bars); + config_feedback_bool(scratch, &list, "use_file_bars", config->use_file_bars); + config_feedback_bool(scratch, &list, "hide_file_bar_in_ui", config->hide_file_bar_in_ui); + config_feedback_bool(scratch, &list, "use_error_highlight", config->use_error_highlight); + config_feedback_bool(scratch, &list, "use_jump_highlight", config->use_jump_highlight); + config_feedback_bool(scratch, &list, "use_scope_highlight", config->use_scope_highlight); + config_feedback_bool(scratch, &list, "use_paren_helper", config->use_paren_helper); + config_feedback_bool(scratch, &list, "use_comment_keyword", config->use_comment_keyword); + config_feedback_bool(scratch, &list, "lister_whole_word_backspace_when_modified", config->lister_whole_word_backspace_when_modified); + config_feedback_bool(scratch, &list, "show_line_number_margins", config->show_line_number_margins); + + config_feedback_bool(scratch, &list, "enable_virtual_whitespace", config->enable_virtual_whitespace); + config_feedback_bool(scratch, &list, "enable_code_wrapping", config->enable_code_wrapping); + config_feedback_bool(scratch, &list, "automatically_indent_text_on_save", config->automatically_indent_text_on_save); + config_feedback_bool(scratch, &list, "automatically_save_changes_on_build", config->automatically_save_changes_on_build); + config_feedback_bool(scratch, &list, "automatically_load_project", config->automatically_load_project); + + config_feedback_bool(scratch, &list, "indent_with_tabs", config->indent_with_tabs); + config_feedback_int(scratch, &list, "indent_width", config->indent_width); + + config_feedback_string(scratch, &list, "default_theme_name", config->default_theme_name); + config_feedback_bool(scratch, &list, "highlight_line_at_cursor", config->highlight_line_at_cursor); + + config_feedback_string(scratch, &list, "default_font_name", config->default_font_name); + config_feedback_int(scratch, &list, "default_font_size", config->default_font_size); + config_feedback_bool(scratch, &list, "default_font_hinting", config->default_font_hinting); + + config_feedback_string(scratch, &list, "default_compiler_bat", config->default_compiler_bat); + config_feedback_string(scratch, &list, "default_flags_bat", config->default_flags_bat); + config_feedback_string(scratch, &list, "default_compiler_sh", config->default_compiler_sh); + config_feedback_string(scratch, &list, "default_flags_sh", config->default_flags_sh); + + config_feedback_bool(scratch, &list, "lalt_lctrl_is_altgr", config->lalt_lctrl_is_altgr); + + string_list_push_u8_lit(scratch, &list, "\n"); + String_Const_u8 message = string_list_flatten(scratch, list); + print_message(app, message); + end_temp(temp2); + } + + // Apply config + setup_built_in_mapping(app, config->mapping, &framework_mapping, mapid_global, mapid_file, mapid_code); + change_mode(app, config->mode); + global_set_setting(app, GlobalSetting_LAltLCtrlIsAltGr, config->lalt_lctrl_is_altgr); + + Color_Table *colors = get_color_table_by_name(config->default_theme_name); + set_active_color(colors); + + Face_Description description = {}; + if (override_font_size != 0){ + description.parameters.pt_size = override_font_size; + } + else{ + description.parameters.pt_size = config->default_font_size; + } + description.parameters.hinting = config->default_font_hinting || override_hinting; + + description.font.file_name = config->default_font_name; + if (!modify_global_face_by_description(app, description)){ + description.font.file_name = get_file_path_in_fonts_folder(scratch, config->default_font_name); + modify_global_face_by_description(app, description); + } +} + +function void +load_theme_file_into_live_set(Application_Links *app, char *file_name){ + Arena *arena = &global_theme_arena; + Color_Table color_table = make_color_table(app, arena); + Scratch_Block scratch(app); + Config *config = theme_parse__file_name(app, scratch, file_name, arena, &color_table); + String_Const_u8 error_text = config_stringize_errors(app, scratch, config); + print_message(app, error_text); + + String_Const_u8 name = SCu8(file_name); + name = string_front_of_path(name); + if (string_match(string_postfix(name, 7), string_u8_litexpr(".4coder"))){ + name = string_chop(name, 7); + } + save_theme(color_table, name); +} + +CUSTOM_COMMAND_SIG(load_theme_current_buffer) +CUSTOM_DOC("Parse the current buffer as a theme file and add the theme to the theme list. If the buffer has a .4coder postfix in it's name, it is removed when the name is saved.") +{ + View_ID view = get_active_view(app, Access_ReadVisible); + Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible); + + Scratch_Block scratch(app); + String_Const_u8 file_name = push_buffer_file_name(app, scratch, buffer); + if (file_name.size > 0){ + Arena *arena = &global_theme_arena; + Color_Table color_table = make_color_table(app, arena); + Config *config = theme_parse__buffer(app, scratch, buffer, arena, &color_table); + String_Const_u8 error_text = config_stringize_errors(app, scratch, config); + print_message(app, error_text); + + String_Const_u8 name = string_front_of_path(file_name); + if (string_match(string_postfix(name, 7), string_u8_litexpr(".4coder"))){ + name = string_chop(name, 7); + } + save_theme(color_table, name); + + Color_Table_Node *node = global_theme_list.last; + if (node != 0 && string_match(node->name, name)){ + active_color_table = node->table; + } + } +} + +function void +load_folder_of_themes_into_live_set(Application_Links *app, String_Const_u8 path){ + Scratch_Block scratch(app, Scratch_Share); + + File_List list = system_get_file_list(scratch, path); + for (File_Info **ptr = list.infos, **end = list.infos + list.count; + ptr < end; + ptr += 1){ + File_Info *info = *ptr; + if (!HasFlag(info->attributes.flags, FileAttribute_IsDirectory)){ + String_Const_u8 name = info->file_name; + Temp_Memory_Block temp(scratch); + String_Const_u8 full_name = push_u8_stringf(scratch, "%.*s/%.*s", + string_expand(path), + string_expand(name)); + load_theme_file_into_live_set(app, (char*)full_name.str); + } + } +} + +// BOTTOM + diff --git a/custom/4coder_config.h b/custom/4coder_config.h index 2e868610..a418b4dd 100644 --- a/custom/4coder_config.h +++ b/custom/4coder_config.h @@ -185,6 +185,9 @@ struct Config_Data{ String_Const_u8_Array code_exts; + u8 mapping_space[64]; + String_Const_u8 mapping; + u8 mode_space[64]; String_Const_u8 mode; @@ -203,15 +206,11 @@ struct Config_Data{ b8 enable_code_wrapping; b8 automatically_indent_text_on_save; b8 automatically_save_changes_on_build; - b8 automatically_adjust_wrapping; b8 automatically_load_project; b8 indent_with_tabs; i32 indent_width; - i32 default_wrap_width; - i32 default_min_base_width; - u8 default_theme_name_space[256]; String_Const_u8 default_theme_name; diff --git a/custom/4coder_default_bindings.cpp b/custom/4coder_default_bindings.cpp index 8d926fa4..a2c2866c 100644 --- a/custom/4coder_default_bindings.cpp +++ b/custom/4coder_default_bindings.cpp @@ -8,7 +8,10 @@ #define FCODER_DEFAULT_BINDINGS_CPP #include "4coder_default_include.cpp" -#include "4coder_default_map.cpp" + +// NOTE(allen): Users can declare their own managed IDs here. + +#include "generated/managed_id_metadata.cpp" void custom_layer_init(Application_Links *app){ diff --git a/custom/4coder_default_colors.cpp b/custom/4coder_default_colors.cpp index 7e9bdd53..94554e66 100644 --- a/custom/4coder_default_colors.cpp +++ b/custom/4coder_default_colors.cpp @@ -104,7 +104,7 @@ make_color_table(Application_Links *app, Arena *arena){ function void set_default_color_scheme(Application_Links *app){ if (global_theme_arena.base_allocator == 0){ - global_theme_arena = make_arena_system(); + global_theme_arena = make_arena_system(); } Arena *arena = &global_theme_arena; @@ -120,10 +120,10 @@ set_default_color_scheme(Application_Links *app){ default_color_table.arrays[defcolor_margin] = make_colors(arena, 0xFF181818); default_color_table.arrays[defcolor_margin_hover] = make_colors(arena, 0xFF252525); default_color_table.arrays[defcolor_margin_active] = make_colors(arena, 0xFF323232); - default_color_table.arrays[defcolor_list_item] = make_colors(arena, 0xFF181818); - default_color_table.arrays[defcolor_list_item_hover] = make_colors(arena, 0xFF252525); - default_color_table.arrays[defcolor_list_item_active] = make_colors(arena, 0xFF323232); - default_color_table.arrays[defcolor_cursor] = make_colors(arena, 0xFF00EE00); + default_color_table.arrays[defcolor_list_item] = make_colors(arena, 0xFF181818, 0xFF0C0C0C); + default_color_table.arrays[defcolor_list_item_hover] = make_colors(arena, 0xFF252525, 0xFF181818); + default_color_table.arrays[defcolor_list_item_active] = make_colors(arena, 0xFF323232, 0xFF323232); + default_color_table.arrays[defcolor_cursor] = make_colors(arena, 0xFF00EE00, 0xFFEE7700); default_color_table.arrays[defcolor_at_cursor] = make_colors(arena, 0xFF0C0C0C); default_color_table.arrays[defcolor_highlight_cursor_line] = make_colors(arena, 0xFF1E1E1E); default_color_table.arrays[defcolor_highlight] = make_colors(arena, 0xFFDDEE00); @@ -156,6 +156,13 @@ set_default_color_scheme(Application_Links *app){ //////////////////////////////// +function void +set_active_color(Color_Table *table){ + if (table != 0){ + active_color_table = *table; + } +} + function void save_theme(Color_Table table, String_Const_u8 name){ Color_Table_Node *node = push_array(&global_theme_arena, Color_Table_Node, 1); @@ -165,4 +172,20 @@ save_theme(Color_Table table, String_Const_u8 name){ node->table = table; } +//////////////////////////////// + +function Color_Table* +get_color_table_by_name(String_Const_u8 name){ + Color_Table *result = 0; + for (Color_Table_Node *node = global_theme_list.first; + node != 0; + node = node->next){ + if (string_match(node->name, name)){ + result = &node->table; + break; + } + } + return(result); +} + // BOTTOM diff --git a/custom/4coder_default_framework.cpp b/custom/4coder_default_framework.cpp index c4acc753..07e019f4 100644 --- a/custom/4coder_default_framework.cpp +++ b/custom/4coder_default_framework.cpp @@ -484,7 +484,7 @@ CUSTOM_DOC("Clear the theme list") global_theme_arena = make_arena_system(); } else{ - linalloc_clear(&global_theme_arena); + linalloc_clear(&global_theme_arena); } block_zero_struct(&global_theme_list); @@ -500,13 +500,18 @@ default_4coder_initialize(Application_Links *app, String_Const_u8_Array file_nam heap_init(&global_heap, tctx->allocator); #define M \ - "Welcome to " VERSION "\n" \ - "If you're new to 4coder there are some tutorials at http://4coder.net/tutorials.html\n" \ - "Direct bug reports and feature requests to https://github.com/4coder-editor/4coder/issues\n" \ - "Other questions and discussion can be directed to editor@4coder.net or 4coder.handmade.network\n" \ - "The change log can be found in CHANGES.txt\n" \ - "\n" - print_message(app, string_u8_litexpr(M)); +"Welcome to " VERSION "\n" \ +"If you're new to 4coder there is a built in tutorial\n" \ +"Use the key combination [ X Alt ] (on mac [ X Control ])\n" \ +"Type in 'hms_demo_tutorial' and press enter\n" \ +"\n" \ +"Direct bug reports and feature requests to https://github.com/4coder-editor/4coder/issues\n" \ +"\n" \ +"Other questions and discussion can be directed to editor@4coder.net or 4coder.handmade.network\n" \ +"\n" \ +"The change log can be found in CHANGES.txt\n" \ +"\n" + print_message(app, string_u8_litexpr(M)); #undef M #if 0 @@ -529,6 +534,8 @@ default_4coder_initialize(Application_Links *app, String_Const_u8_Array file_nam create_buffer(app, input_name, 0); } } + + fade_range_arena = make_arena_system(KB(8)); } function void @@ -687,5 +694,102 @@ buffer_modified_set_clear(void){ } } +//////////////////////////////// + +function Fade_Range* +alloc_fade_range(void){ + Fade_Range *result = free_fade_ranges; + if (result == 0){ + result = push_array(&fade_range_arena, Fade_Range, 1); + } + else{ + sll_stack_pop(free_fade_ranges); + } + return(result); +} + +function void +free_fade_range(Fade_Range *range){ + sll_stack_push(free_fade_ranges, range); +} + +function void +buffer_post_fade(Application_Links *app, Buffer_ID buffer_id, f32 seconds, Range_i64 range, ARGB_Color color){ + Fade_Range *fade_range = alloc_fade_range(); + sll_queue_push(buffer_fade_ranges.first, buffer_fade_ranges.last, fade_range); + buffer_fade_ranges.count += 1; + fade_range->buffer_id = buffer_id; + fade_range->t = seconds; + fade_range->full_t = seconds; + fade_range->range = range; + fade_range->color= color; +} + +function void +view_post_fade(Application_Links *app, View_ID view_id, f32 seconds, Range_i64 range, ARGB_Color color){ + Fade_Range *fade_range = alloc_fade_range(); + sll_queue_push(view_fade_ranges.first, view_fade_ranges.last, fade_range); + view_fade_ranges.count += 1; + fade_range->view_id = view_id; + fade_range->t = seconds; + fade_range->full_t = seconds; + fade_range->range = range; + fade_range->color= color; +} + +function b32 +tick_all_fade_ranges(f32 t){ + Fade_Range **prev_next = &buffer_fade_ranges.first; + for (Fade_Range *node = buffer_fade_ranges.first, *next = 0; + node != 0; + node = next){ + next = node->next; + node->t -= t; + if (node->t <= 0.f){ + *prev_next = next; + buffer_fade_ranges.count -= 1; + } + else{ + prev_next = &node->next; + } + } + + prev_next = &view_fade_ranges.first; + for (Fade_Range *node = view_fade_ranges.first, *next = 0; + node != 0; + node = next){ + next = node->next; + node->t -= t; + if (node->t <= 0.f){ + *prev_next = next; + view_fade_ranges.count -= 1; + } + else{ + prev_next = &node->next; + } + } + + return(buffer_fade_ranges.count > 0 || view_fade_ranges.count > 0); +} + +function void +paint_fade_ranges(Application_Links *app, Text_Layout_ID layout, Buffer_ID buffer, View_ID view){ + for (Fade_Range *node = buffer_fade_ranges.first; + node != 0; + node = node->next){ + if (node->buffer_id == buffer){ + paint_text_color_blend(app, layout, node->range, node->color, node->t/node->full_t); + } + } + + for (Fade_Range *node = view_fade_ranges.first; + node != 0; + node = node->next){ + if (node->view_id == view){ + paint_text_color_blend(app, layout, node->range, node->color, node->t/node->full_t); + } + } +} + // BOTTOM diff --git a/custom/4coder_default_framework.h b/custom/4coder_default_framework.h index 703a88ad..b1daa3e2 100644 --- a/custom/4coder_default_framework.h +++ b/custom/4coder_default_framework.h @@ -94,6 +94,26 @@ struct Buffer_Modified_Set{ Table_u64_u64 id_to_node; }; +//////////////////////////////// + +struct Fade_Range{ + Fade_Range *next; + union{ + Buffer_ID buffer_id; + View_ID view_id; + }; + f32 t; + f32 full_t; + Range_i64 range; + ARGB_Color color; +}; + +struct Fade_Range_List{ + Fade_Range *first; + Fade_Range *last; + i32 count; +}; + #endif // BOTTOM diff --git a/custom/4coder_default_framework_variables.cpp b/custom/4coder_default_framework_variables.cpp index bc8ded69..eebdbfb6 100644 --- a/custom/4coder_default_framework_variables.cpp +++ b/custom/4coder_default_framework_variables.cpp @@ -86,5 +86,17 @@ global Mapping framework_mapping = {}; global Buffer_Modified_Set global_buffer_modified_set = {}; +//////////////////////////////// + +global b32 global_keyboard_macro_is_recording = false; +global Range_i64 global_keyboard_macro_range = {}; + +//////////////////////////////// + +global Fade_Range_List buffer_fade_ranges = {}; +global Fade_Range_List view_fade_ranges = {}; +global Arena fade_range_arena = {}; +global Fade_Range *free_fade_ranges = 0; + // BOTTOM diff --git a/custom/4coder_default_hooks.cpp b/custom/4coder_default_hooks.cpp index 76c0db40..2444afe1 100644 --- a/custom/4coder_default_hooks.cpp +++ b/custom/4coder_default_hooks.cpp @@ -1,1122 +1,1159 @@ -/* -4coder_default_hooks.cpp - Sets up the hooks for the default framework. -*/ - -// TOP - -CUSTOM_COMMAND_SIG(default_startup) -CUSTOM_DOC("Default command for responding to a startup event") -{ - ProfileScope(app, "default startup"); - User_Input input = get_current_input(app); - if (match_core_code(&input, CoreCode_Startup)){ - String_Const_u8_Array file_names = input.event.core.file_names; - default_4coder_initialize(app, file_names); - default_4coder_side_by_side_panels(app, file_names); - if (global_config.automatically_load_project){ - load_project(app); - } - load_themes_default_folder(app); - } -} - -CUSTOM_COMMAND_SIG(default_try_exit) -CUSTOM_DOC("Default command for responding to a try-exit event") -{ - User_Input input = get_current_input(app); - if (match_core_code(&input, CoreCode_TryExit)){ - b32 do_exit = true; - if (!allow_immediate_close_without_checking_for_changes){ - b32 has_unsaved_changes = false; - for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); - buffer != 0; - buffer = get_buffer_next(app, buffer, Access_Always)){ - Dirty_State dirty = buffer_get_dirty_state(app, buffer); - if (HasFlag(dirty, DirtyState_UnsavedChanges)){ - has_unsaved_changes = true; - break; - } - } - if (has_unsaved_changes){ - View_ID view = get_active_view(app, Access_Always); - do_exit = do_4coder_close_user_check(app, view); - } - } - if (do_exit){ - // NOTE(allen): By leaving try exit unhandled we indicate - // that the core should take responsibility for handling this, - // and it will handle it by exiting 4coder. If we leave this - // event marked as handled on the other hand (for instance by - // running a confirmation GUI that cancels the exit) then 4coder - // will not exit. - leave_current_input_unhandled(app); - } - } -} - -CUSTOM_COMMAND_SIG(default_view_input_handler) -CUSTOM_DOC("Input consumption loop for default view behavior") -{ - Thread_Context *tctx = get_thread_context(app); - Scratch_Block scratch(tctx); - - { - View_ID view = get_this_ctx_view(app, Access_Always); - String_Const_u8 name = push_u8_stringf(scratch, "view %d", view); - - Profile_Global_List *list = get_core_profile_list(app); - ProfileThreadName(tctx, list, name); - - View_Context ctx = view_current_context(app, view); - ctx.mapping = &framework_mapping; - ctx.map_id = mapid_global; - view_alter_context(app, view, &ctx); - } - - for (;;){ - // NOTE(allen): Get the binding from the buffer's current map - User_Input input = get_next_input(app, EventPropertyGroup_Any, 0); - ProfileScopeNamed(app, "before view input", view_input_profile); - if (input.abort){ - break; - } - - Event_Property event_properties = get_event_properties(&input.event); - - if (suppressing_mouse && (event_properties & EventPropertyGroup_AnyMouseEvent) != 0){ - continue; - } - - View_ID view = get_this_ctx_view(app, Access_Always); - - Buffer_ID buffer = view_get_buffer(app, view, Access_Always); - Managed_Scope buffer_scope = buffer_get_managed_scope(app, buffer); - Command_Map_ID *map_id_ptr = scope_attachment(app, buffer_scope, buffer_map_id, Command_Map_ID); - if (*map_id_ptr == 0){ - *map_id_ptr = mapid_file; - } - Command_Map_ID map_id = *map_id_ptr; - - Command_Binding binding = map_get_binding_recursive(&framework_mapping, map_id, &input.event); - - Managed_Scope scope = view_get_managed_scope(app, view); - - if (binding.custom == 0){ - // NOTE(allen): we don't have anything to do with this input, - // leave it marked unhandled so that if there's a follow up - // event it is not blocked. - leave_current_input_unhandled(app); - } - else{ - // NOTE(allen): before the command is called do some book keeping - Rewrite_Type *next_rewrite = - scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); - *next_rewrite = Rewrite_None; - if (fcoder_mode == FCoderMode_NotepadLike){ - for (View_ID view_it = get_view_next(app, 0, Access_Always); - view_it != 0; - view_it = get_view_next(app, view_it, Access_Always)){ - Managed_Scope scope_it = view_get_managed_scope(app, view_it); - b32 *snap_mark_to_cursor = - scope_attachment(app, scope_it, view_snap_mark_to_cursor, - b32); - *snap_mark_to_cursor = true; - } - } - - ProfileCloseNow(view_input_profile); - - // NOTE(allen): call the command - binding.custom(app); - - // NOTE(allen): after the command is called do some book keeping - ProfileScope(app, "after view input"); - - next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); - if (next_rewrite != 0){ - Rewrite_Type *rewrite = - scope_attachment(app, scope, view_rewrite_loc, Rewrite_Type); - *rewrite = *next_rewrite; - if (fcoder_mode == FCoderMode_NotepadLike){ - for (View_ID view_it = get_view_next(app, 0, Access_Always); - view_it != 0; - view_it = get_view_next(app, view_it, Access_Always)){ - Managed_Scope scope_it = view_get_managed_scope(app, view_it); - b32 *snap_mark_to_cursor = - scope_attachment(app, scope_it, view_snap_mark_to_cursor, b32); - if (*snap_mark_to_cursor){ - i64 pos = view_get_cursor_pos(app, view_it); - view_set_mark(app, view_it, seek_pos(pos)); - } - } - } - } - } - } -} - -function void -default_tick(Application_Links *app, Frame_Info frame_info){ - Scratch_Block scratch(app); - - for (Buffer_Modified_Node *node = global_buffer_modified_set.first; - node != 0; - node = node->next){ - Temp_Memory_Block temp(scratch); - Buffer_ID buffer_id = node->buffer; - - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - - String_Const_u8 contents = push_whole_buffer(app, scratch, buffer_id); - Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); - if (tokens_ptr == 0){ - continue; - } - if (tokens_ptr->count == 0){ - continue; - } - Token_Array tokens = *tokens_ptr; - - Arena arena = make_arena_system(KB(16)); - Code_Index_File *index = push_array_zero(&arena, Code_Index_File, 1); - index->buffer = buffer_id; - - Generic_Parse_State state = {}; - generic_parse_init(app, &arena, contents, &tokens, &state); - // TODO(allen): Actually determine this in a fair way. - // Maybe switch to an enum. - state.do_cpp_parse = true; - generic_parse_full_input_breaks(index, &state, max_i32); - - code_index_lock(); - code_index_set_file(buffer_id, arena, index); - code_index_unlock(); - buffer_clear_layout_cache(app, buffer_id); - } - - buffer_modified_set_clear(); -} - -function Rect_f32 -default_buffer_region(Application_Links *app, View_ID view_id, Rect_f32 region){ - Buffer_ID buffer = view_get_buffer(app, view_id, Access_Always); - Face_ID face_id = get_face_id(app, buffer); - Face_Metrics metrics = get_face_metrics(app, face_id); - f32 line_height = metrics.line_height; - f32 digit_advance = metrics.decimal_digit_advance; - - // NOTE(allen): margins - region = rect_inner(region, 3.f); - - // NOTE(allen): file bar - b64 showing_file_bar = false; - if (view_get_setting(app, view_id, ViewSetting_ShowFileBar, &showing_file_bar) && - showing_file_bar){ - Rect_f32_Pair pair = layout_file_bar_on_top(region, line_height); - region = pair.max; - } - - // NOTE(allen): query bars - { - Query_Bar *space[32]; - Query_Bar_Ptr_Array query_bars = {}; - query_bars.ptrs = space; - if (get_active_query_bars(app, view_id, ArrayCount(space), &query_bars)){ - Rect_f32_Pair pair = layout_query_bar_on_top(region, line_height, query_bars.count); - region = pair.max; - } - } - - // NOTE(allen): FPS hud - if (show_fps_hud){ - Rect_f32_Pair pair = layout_fps_hud_on_bottom(region, line_height); - region = pair.min; - } - - // NOTE(allen): line numbers - if (global_config.show_line_number_margins){ - Rect_f32_Pair pair = layout_line_number_margin(app, buffer, region, digit_advance); - region = pair.max; - } - - return(region); -} - -function void -recursive_nest_highlight(Application_Links *app, Text_Layout_ID layout_id, Range_i64 range, - Code_Index_Nest_Ptr_Array *array, i32 counter){ - Code_Index_Nest **ptr = array->ptrs; - Code_Index_Nest **ptr_end = ptr + array->count; - - for (;ptr < ptr_end; ptr += 1){ - Code_Index_Nest *nest = *ptr; - if (!nest->is_closed){ - break; - } - if (range.first <= nest->close.max){ - break; - } - } - - ARGB_Color argb = finalize_color(defcolor_text_cycle, counter); - - for (;ptr < ptr_end; ptr += 1){ - Code_Index_Nest *nest = *ptr; - if (range.max <= nest->open.min){ - break; - } - - paint_text_color(app, layout_id, nest->open, argb); - if (nest->is_closed){ - paint_text_color(app, layout_id, nest->close, argb); - } - recursive_nest_highlight(app, layout_id, range, &nest->nest_array, counter + 1); - } -} - -function void -recursive_nest_highlight(Application_Links *app, Text_Layout_ID layout_id, Range_i64 range, - Code_Index_File *file){ - recursive_nest_highlight(app, layout_id, range, &file->nest_array, 0); -} - -function void -default_render_buffer(Application_Links *app, View_ID view_id, Face_ID face_id, - Buffer_ID buffer, Text_Layout_ID text_layout_id, - Rect_f32 rect){ - ProfileScope(app, "render buffer"); - - View_ID active_view = get_active_view(app, Access_Always); - b32 is_active_view = (active_view == view_id); - Rect_f32 prev_clip = draw_set_clip(app, rect); - - // NOTE(allen): Token colorizing - Token_Array token_array = get_token_array_from_buffer(app, buffer); - if (token_array.tokens != 0){ - draw_cpp_token_colors(app, text_layout_id, &token_array); - - // NOTE(allen): Scan for TODOs and NOTEs - if (global_config.use_comment_keyword){ - Comment_Highlight_Pair pairs[] = { - {string_u8_litexpr("NOTE"), finalize_color(defcolor_comment_pop, 0)}, - {string_u8_litexpr("TODO"), finalize_color(defcolor_comment_pop, 1)}, - }; - draw_comment_highlights(app, buffer, text_layout_id, - &token_array, pairs, ArrayCount(pairs)); - } - } - else{ - Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); - paint_text_color_fcolor(app, text_layout_id, visible_range, fcolor_id(defcolor_text_default)); - } - - i64 cursor_pos = view_correct_cursor(app, view_id); - view_correct_mark(app, view_id); - - // NOTE(allen): Scope highlight - if (global_config.use_scope_highlight){ - Color_Array colors = finalize_color_array(defcolor_back_cycle); - draw_scope_highlight(app, buffer, text_layout_id, cursor_pos, colors.vals, colors.count); - } - - if (global_config.use_error_highlight || global_config.use_jump_highlight){ - // NOTE(allen): Error highlight - String_Const_u8 name = string_u8_litexpr("*compilation*"); - Buffer_ID compilation_buffer = get_buffer_by_name(app, name, Access_Always); - if (global_config.use_error_highlight){ - draw_jump_highlights(app, buffer, text_layout_id, compilation_buffer, - fcolor_id(defcolor_highlight_junk)); - } - - // NOTE(allen): Search highlight - if (global_config.use_jump_highlight){ - Buffer_ID jump_buffer = get_locked_jump_buffer(app); - if (jump_buffer != compilation_buffer){ - draw_jump_highlights(app, buffer, text_layout_id, jump_buffer, - fcolor_id(defcolor_highlight_white)); - } - } - } - - // NOTE(allen): Color parens - if (global_config.use_paren_helper){ - Color_Array colors = finalize_color_array(defcolor_text_cycle); - draw_paren_highlight(app, buffer, text_layout_id, cursor_pos, colors.vals, colors.count); - } - - // NOTE(allen): Line highlight - if (global_config.highlight_line_at_cursor && is_active_view){ - i64 line_number = get_line_number_from_pos(app, buffer, cursor_pos); - draw_line_highlight(app, text_layout_id, line_number, - fcolor_id(defcolor_highlight_cursor_line)); - } - - // NOTE(allen): Cursor shape - Face_Metrics metrics = get_face_metrics(app, face_id); - f32 cursor_roundness = (metrics.normal_advance*0.5f)*0.9f; - f32 mark_thickness = 2.f; - - // NOTE(allen): Cursor - switch (fcoder_mode){ - case FCoderMode_Original: - { - draw_original_4coder_style_cursor_mark_highlight(app, view_id, is_active_view, buffer, text_layout_id, cursor_roundness, mark_thickness); - }break; - case FCoderMode_NotepadLike: - { - draw_notepad_style_cursor_highlight(app, view_id, buffer, text_layout_id, cursor_roundness); - }break; - } - - // NOTE(allen): put the actual text on the actual screen - draw_text_layout_default(app, text_layout_id); - - draw_set_clip(app, prev_clip); -} - -function void -default_render_caller(Application_Links *app, Frame_Info frame_info, View_ID view_id){ - ProfileScope(app, "default render caller"); - View_ID active_view = get_active_view(app, Access_Always); - b32 is_active_view = (active_view == view_id); - - Rect_f32 region = draw_background_and_margin(app, view_id, is_active_view); - Rect_f32 prev_clip = draw_set_clip(app, region); - - Buffer_ID buffer = view_get_buffer(app, view_id, Access_Always); - Face_ID face_id = get_face_id(app, buffer); - Face_Metrics face_metrics = get_face_metrics(app, face_id); - f32 line_height = face_metrics.line_height; - f32 digit_advance = face_metrics.decimal_digit_advance; - - // NOTE(allen): file bar - b64 showing_file_bar = false; - if (view_get_setting(app, view_id, ViewSetting_ShowFileBar, &showing_file_bar) && showing_file_bar){ - Rect_f32_Pair pair = layout_file_bar_on_top(region, line_height); - draw_file_bar(app, view_id, buffer, face_id, pair.min); - region = pair.max; - } - - Buffer_Scroll scroll = view_get_buffer_scroll(app, view_id); - - Buffer_Point_Delta_Result delta = delta_apply(app, view_id, - frame_info.animation_dt, scroll); - if (!block_match_struct(&scroll.position, &delta.point)){ - block_copy_struct(&scroll.position, &delta.point); - view_set_buffer_scroll(app, view_id, scroll, SetBufferScroll_NoCursorChange); - } - if (delta.still_animating){ - animate_in_n_milliseconds(app, 0); - } - - // NOTE(allen): query bars - { - Query_Bar *space[32]; - Query_Bar_Ptr_Array query_bars = {}; - query_bars.ptrs = space; - if (get_active_query_bars(app, view_id, ArrayCount(space), &query_bars)){ - for (i32 i = 0; i < query_bars.count; i += 1){ - Rect_f32_Pair pair = layout_query_bar_on_top(region, line_height, 1); - draw_query_bar(app, query_bars.ptrs[i], face_id, pair.min); - region = pair.max; - } - } - } - - // NOTE(allen): FPS hud - if (show_fps_hud){ - Rect_f32_Pair pair = layout_fps_hud_on_bottom(region, line_height); - draw_fps_hud(app, frame_info, face_id, pair.max); - region = pair.min; - animate_in_n_milliseconds(app, 1000); - } - - // NOTE(allen): layout line numbers - Rect_f32 line_number_rect = {}; - if (global_config.show_line_number_margins){ - Rect_f32_Pair pair = layout_line_number_margin(app, buffer, region, digit_advance); - line_number_rect = pair.min; - region = pair.max; - } - - // NOTE(allen): begin buffer render - Buffer_Point buffer_point = scroll.position; - Text_Layout_ID text_layout_id = text_layout_create(app, buffer, region, buffer_point); - - // NOTE(allen): draw line numbers - if (global_config.show_line_number_margins){ - draw_line_number_margin(app, view_id, buffer, face_id, text_layout_id, line_number_rect); - } - - // NOTE(allen): draw the buffer - default_render_buffer(app, view_id, face_id, buffer, text_layout_id, region); - - text_layout_free(app, text_layout_id); - draw_set_clip(app, prev_clip); -} - -HOOK_SIG(default_view_adjust){ - // NOTE(allen): Called whenever the view layout/sizes have been modified, - // including by full window resize. - return(0); -} - -BUFFER_NAME_RESOLVER_SIG(default_buffer_name_resolution){ - ProfileScope(app, "default buffer name resolution"); - if (conflict_count > 1){ - // List of unresolved conflicts - Scratch_Block scratch(app); - - i32 *unresolved = push_array(scratch, i32, conflict_count); - i32 unresolved_count = conflict_count; - for (i32 i = 0; i < conflict_count; ++i){ - unresolved[i] = i; - } - - // Resolution Loop - i32 x = 0; - for (;;){ - // Resolution Pass - ++x; - for (i32 i = 0; i < unresolved_count; ++i){ - i32 conflict_index = unresolved[i]; - Buffer_Name_Conflict_Entry *conflict = &conflicts[conflict_index]; - - u64 size = conflict->base_name.size; - size = clamp_top(size, conflict->unique_name_capacity); - conflict->unique_name_len_in_out = size; - block_copy(conflict->unique_name_in_out, conflict->base_name.str, size); - - if (conflict->file_name.str != 0){ - Temp_Memory_Block temp(scratch); - String_Const_u8 uniqueifier = {}; - - String_Const_u8 file_name = string_remove_last_folder(conflict->file_name); - if (file_name.size > 0){ - file_name = string_chop(file_name, 1); - u8 *end = file_name.str + file_name.size; - b32 past_the_end = false; - for (i32 j = 0; j < x; ++j){ - file_name = string_remove_last_folder(file_name); - if (j + 1 < x){ - file_name = string_chop(file_name, 1); - } - if (file_name.size == 0){ - if (j + 1 < x){ - past_the_end = true; - } - break; - } - } - u8 *start = file_name.str + file_name.size; - - uniqueifier = SCu8(start, end); - if (past_the_end){ - uniqueifier = push_u8_stringf(scratch, "%.*s~%d", - string_expand(uniqueifier), i); - } - } - else{ - uniqueifier = push_u8_stringf(scratch, "%d", i); - } - - String_u8 builder = Su8(conflict->unique_name_in_out, - conflict->unique_name_len_in_out, - conflict->unique_name_capacity); - string_append(&builder, string_u8_litexpr(" <")); - string_append(&builder, uniqueifier); - string_append(&builder, string_u8_litexpr(">")); - conflict->unique_name_len_in_out = builder.size; - } - } - - // Conflict Check Pass - b32 has_conflicts = false; - for (i32 i = 0; i < unresolved_count; ++i){ - i32 conflict_index = unresolved[i]; - Buffer_Name_Conflict_Entry *conflict = &conflicts[conflict_index]; - String_Const_u8 conflict_name = SCu8(conflict->unique_name_in_out, - conflict->unique_name_len_in_out); - - b32 hit_conflict = false; - if (conflict->file_name.str != 0){ - for (i32 j = 0; j < unresolved_count; ++j){ - if (i == j) continue; - - i32 conflict_j_index = unresolved[j]; - Buffer_Name_Conflict_Entry *conflict_j = &conflicts[conflict_j_index]; - - String_Const_u8 conflict_name_j = SCu8(conflict_j->unique_name_in_out, - conflict_j->unique_name_len_in_out); - - if (string_match(conflict_name, conflict_name_j)){ - hit_conflict = true; - break; - } - } - } - - if (hit_conflict){ - has_conflicts = true; - } - else{ - --unresolved_count; - unresolved[i] = unresolved[unresolved_count]; - --i; - } - } - - if (!has_conflicts){ - break; - } - } - } -} - -function void -parse_async__inner(Async_Context *actx, Buffer_ID buffer_id, - String_Const_u8 contents, Token_Array *tokens, i32 limit_factor){ - Application_Links *app = actx->app; - ProfileBlock(app, "async parse"); - - Arena arena = make_arena_system(KB(16)); - Code_Index_File *index = push_array_zero(&arena, Code_Index_File, 1); - index->buffer = buffer_id; - - Generic_Parse_State state = {}; - generic_parse_init(app, &arena, contents, tokens, &state); - - b32 canceled = false; - - for (;;){ - if (generic_parse_full_input_breaks(index, &state, limit_factor)){ - break; - } - if (async_check_canceled(actx)){ - canceled = true; - break; - } - } - - if (!canceled){ - Thread_Context *tctx = get_thread_context(app); - system_acquire_global_frame_mutex(tctx); - code_index_lock(); - code_index_set_file(buffer_id, arena, index); - code_index_unlock(); - buffer_clear_layout_cache(app, buffer_id); - system_release_global_frame_mutex(tctx); - } - else{ - linalloc_clear(&arena); - } -} - -function void -do_full_lex_async__inner(Async_Context *actx, Buffer_ID buffer_id){ - Application_Links *app = actx->app; - ProfileScope(app, "async lex"); - Thread_Context *tctx = get_thread_context(app); - Scratch_Block scratch(tctx); - - String_Const_u8 contents = {}; - { - ProfileBlock(app, "async lex contents (before mutex)"); - system_acquire_global_frame_mutex(tctx); - ProfileBlock(app, "async lex contents (after mutex)"); - contents = push_whole_buffer(app, scratch, buffer_id); - system_release_global_frame_mutex(tctx); - } - - i32 limit_factor = 10000; - - Token_List list = {}; - b32 canceled = false; - - Lex_State_Cpp state = {}; - lex_full_input_cpp_init(&state, contents); - for (;;){ - ProfileBlock(app, "async lex block"); - if (lex_full_input_cpp_breaks(scratch, &list, &state, limit_factor)){ - break; - } - if (async_check_canceled(actx)){ - canceled = true; - break; - } - } - - if (!canceled){ - ProfileBlock(app, "async lex save results (before mutex)"); - system_acquire_global_frame_mutex(tctx); - ProfileBlock(app, "async lex save results (after mutex)"); - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - if (scope != 0){ - Base_Allocator *allocator = managed_scope_allocator(app, scope); - Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, - Token_Array); - base_free(allocator, tokens_ptr->tokens); - Token_Array tokens = {}; - tokens.tokens = base_array(allocator, Token, list.total_count); - tokens.count = list.total_count; - tokens.max = list.total_count; - token_fill_memory_from_list(tokens.tokens, &list); - block_copy_struct(tokens_ptr, &tokens); - } - buffer_mark_as_modified(buffer_id); - system_release_global_frame_mutex(tctx); - } -} - -function void -do_full_lex_async(Async_Context *actx, Data data){ - if (data.size == sizeof(Buffer_ID)){ - Buffer_ID buffer = *(Buffer_ID*)data.data; - do_full_lex_async__inner(actx, buffer); - } -} - -#if 0 -function void -do_full_lex_and_parse_async__inner(Async_Context *actx, Buffer_ID buffer_id){ - Application_Links *app = actx->app; - ProfileScope(app, "async lex"); - Thread_Context *tctx = get_thread_context(app); - Scratch_Block scratch(tctx); - - String_Const_u8 contents = {}; - { - ProfileBlock(app, "async lex contents (before mutex)"); - system_acquire_global_frame_mutex(tctx); - ProfileBlock(app, "async lex contents (after mutex)"); - - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - if (scope != 0){ - Base_Allocator *allocator = managed_scope_allocator(app, scope); - Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, - Token_Array); - base_free(allocator, tokens_ptr->tokens); - block_zero_struct(tokens_ptr); - } - - contents = push_whole_buffer(app, scratch, buffer_id); - system_release_global_frame_mutex(tctx); - } - - i32 limit_factor = 10000; - - Token_List list = {}; - b32 canceled = false; - - { - Lex_State_Cpp state = {}; - lex_full_input_cpp_init(&state, contents); - for (;;){ - ProfileBlock(app, "async lex block"); - if (lex_full_input_cpp_breaks(scratch, &list, &state, limit_factor)){ - break; - } - if (async_check_canceled(actx)){ - canceled = true; - break; - } - } - } - - Token_Array tokens = {}; - if (!canceled){ - ProfileBlock(app, "async lex save results (before mutex)"); - system_acquire_global_frame_mutex(tctx); - ProfileBlock(app, "async lex save results (after mutex)"); - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - if (scope != 0){ - Base_Allocator *allocator = managed_scope_allocator(app, scope); - Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, - Token_Array); - base_free(allocator, tokens_ptr->tokens); - tokens.tokens = base_array(allocator, Token, list.total_count); - tokens.count = list.total_count; - tokens.max = list.total_count; - token_fill_memory_from_list(tokens.tokens, &list); - block_copy_struct(tokens_ptr, &tokens); - } - system_release_global_frame_mutex(tctx); - } - - if (tokens.count > 0){ - parse_async__inner(actx, buffer_id, contents, &tokens, limit_factor); - } -} - -function void -do_full_lex_and_parse_async(Async_Context *actx, Data data){ - if (data.size == sizeof(Buffer_ID)){ - Buffer_ID buffer = *(Buffer_ID*)data.data; - do_full_lex_and_parse_async__inner(actx, buffer); - } -} -#endif - -#if 0 -function void -do_parse_async__inner(Async_Context *actx, Buffer_ID buffer_id){ - Application_Links *app = actx->app; - ProfileScope(app, "async lex"); - Thread_Context *tctx = get_thread_context(app); - Scratch_Block scratch(tctx); - - String_Const_u8 contents = {}; - Token_Array tokens = {}; - { - ProfileBlock(app, "async parse contents (before mutex)"); - system_acquire_global_frame_mutex(tctx); - ProfileBlock(app, "async parse contents (after mutex)"); - - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - if (scope != 0){ - Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, - Token_Array); - tokens.count = tokens_ptr->count; - tokens.tokens = push_array_write(scratch, Token, tokens.count, tokens_ptr->tokens); - if (tokens.count > 0){ - contents = push_whole_buffer(app, scratch, buffer_id); - } - } - - system_release_global_frame_mutex(tctx); - } - - i32 limit_factor = 10000; - - if (tokens.count > 0){ - parse_async__inner(actx, buffer_id, contents, &tokens, limit_factor); - } -} - -function void -do_parse_async(Async_Context *actx, Data data){ - if (data.size == sizeof(Buffer_ID)){ - Buffer_ID buffer = *(Buffer_ID*)data.data; - do_parse_async__inner(actx, buffer); - } -} -#endif - -BUFFER_HOOK_SIG(default_begin_buffer){ - ProfileScope(app, "begin buffer"); - - Scratch_Block scratch(app); - - b32 treat_as_code = false; - String_Const_u8 file_name = push_buffer_file_name(app, scratch, buffer_id); - if (file_name.size > 0){ - String_Const_u8_Array extensions = global_config.code_exts; - String_Const_u8 ext = string_file_extension(file_name); - for (i32 i = 0; i < extensions.count; ++i){ - if (string_match(ext, extensions.strings[i])){ - - if (string_match(ext, string_u8_litexpr("cpp")) || - string_match(ext, string_u8_litexpr("h")) || - string_match(ext, string_u8_litexpr("c")) || - string_match(ext, string_u8_litexpr("hpp")) || - string_match(ext, string_u8_litexpr("cc"))){ - treat_as_code = true; - } - -#if 0 - treat_as_code = true; - - if (string_match(ext, string_u8_litexpr("cs"))){ - if (parse_context_language_cs == 0){ - init_language_cs(app); - } - parse_context_id = parse_context_language_cs; - } - - if (string_match(ext, string_u8_litexpr("java"))){ - if (parse_context_language_java == 0){ - init_language_java(app); - } - parse_context_id = parse_context_language_java; - } - - if (string_match(ext, string_u8_litexpr("rs"))){ - if (parse_context_language_rust == 0){ - init_language_rust(app); - } - parse_context_id = parse_context_language_rust; - } - - if (string_match(ext, string_u8_litexpr("cpp")) || - string_match(ext, string_u8_litexpr("h")) || - string_match(ext, string_u8_litexpr("c")) || - string_match(ext, string_u8_litexpr("hpp")) || - string_match(ext, string_u8_litexpr("cc"))){ - if (parse_context_language_cpp == 0){ - init_language_cpp(app); - } - parse_context_id = parse_context_language_cpp; - } - - // TODO(NAME): Real GLSL highlighting - if (string_match(ext, string_u8_litexpr("glsl"))){ - if (parse_context_language_cpp == 0){ - init_language_cpp(app); - } - parse_context_id = parse_context_language_cpp; - } - - // TODO(NAME): Real Objective-C highlighting - if (string_match(ext, string_u8_litexpr("m"))){ - if (parse_context_language_cpp == 0){ - init_language_cpp(app); - } - parse_context_id = parse_context_language_cpp; - } -#endif - - break; - } - } - } - - Command_Map_ID map_id = (treat_as_code)?(mapid_code):(mapid_file); - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - Command_Map_ID *map_id_ptr = scope_attachment(app, scope, buffer_map_id, Command_Map_ID); - *map_id_ptr = map_id; - - Line_Ending_Kind setting = guess_line_ending_kind_from_buffer(app, buffer_id); - Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, Line_Ending_Kind); - *eol_setting = setting; - - // NOTE(allen): Decide buffer settings - b32 wrap_lines = true; - b32 use_virtual_whitespace = false; - b32 use_lexer = false; - if (treat_as_code){ - wrap_lines = global_config.enable_code_wrapping; - use_virtual_whitespace = global_config.enable_virtual_whitespace; - use_lexer = true; - } - - String_Const_u8 buffer_name = push_buffer_base_name(app, scratch, buffer_id); - if (string_match(buffer_name, string_u8_litexpr("*compilation*"))){ - wrap_lines = false; - } - - if (use_lexer){ - ProfileBlock(app, "begin buffer kick off lexer"); - Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); - *lex_task_ptr = async_task_no_dep(&global_async_system, do_full_lex_async, make_data_struct(&buffer_id)); - } - - { - b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); - *wrap_lines_ptr = wrap_lines; - } - - if (use_virtual_whitespace){ - if (use_lexer){ - buffer_set_layout(app, buffer_id, layout_virt_indent_index_generic); - } - else{ - buffer_set_layout(app, buffer_id, layout_virt_indent_literal_generic); - } - } - else{ - buffer_set_layout(app, buffer_id, layout_generic); - } - - // no meaning for return - return(0); -} - -BUFFER_HOOK_SIG(default_new_file){ - // buffer_id - // no meaning for return - return(0); -} - -BUFFER_HOOK_SIG(default_file_save){ - // buffer_id - ProfileScope(app, "default file save"); - b32 is_virtual = false; - if (global_config.automatically_indent_text_on_save && is_virtual){ - auto_indent_buffer(app, buffer_id, buffer_range(app, buffer_id)); - } - - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - Line_Ending_Kind *eol = scope_attachment(app, scope, buffer_eol_setting, - Line_Ending_Kind); - switch (*eol){ - case LineEndingKind_LF: - { - rewrite_lines_to_lf(app, buffer_id); - }break; - case LineEndingKind_CRLF: - { - rewrite_lines_to_crlf(app, buffer_id); - }break; - } - - // no meaning for return - return(0); -} - -BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){ - // buffer_id, new_range, original_size - ProfileScope(app, "default edit range"); - - Range_i64 old_range = Ii64(new_range.first, new_range.first + original_size); - - { - code_index_lock(); - Code_Index_File *file = code_index_get_file(buffer_id); - if (file != 0){ - code_index_shift(file, old_range, range_size(new_range)); - } - code_index_unlock(); - } - - i64 insert_size = range_size(new_range); - i64 text_shift = replace_range_shift(old_range, insert_size); - - Scratch_Block scratch(app); - - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); - - Base_Allocator *allocator = managed_scope_allocator(app, scope); - b32 do_full_relex = false; - - if (async_task_is_running_or_pending(&global_async_system, *lex_task_ptr)){ - async_task_cancel(&global_async_system, *lex_task_ptr); - buffer_unmark_as_modified(buffer_id); - do_full_relex = true; - *lex_task_ptr = 0; - } - - Token_Array *ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); - if (ptr != 0 && ptr->tokens != 0){ - ProfileBlockNamed(app, "attempt resync", profile_attempt_resync); - - i64 token_index_first = token_relex_first(ptr, old_range.first, 1); - i64 token_index_resync_guess = - token_relex_resync(ptr, old_range.one_past_last, 16); - - if (token_index_resync_guess - token_index_first >= 4000){ - do_full_relex = true; - } - else{ - Token *token_first = ptr->tokens + token_index_first; - Token *token_resync = ptr->tokens + token_index_resync_guess; - - Range_i64 relex_range = Ii64(token_first->pos, token_resync->pos + token_resync->size + text_shift); - String_Const_u8 partial_text = push_buffer_range(app, scratch, buffer_id, relex_range); - - Token_List relex_list = lex_full_input_cpp(scratch, partial_text); - if (relex_range.one_past_last < buffer_get_size(app, buffer_id)){ - token_drop_eof(&relex_list); - } - - Token_Relex relex = token_relex(relex_list, relex_range.first - text_shift, ptr->tokens, token_index_first, token_index_resync_guess); - - ProfileCloseNow(profile_attempt_resync); - - if (!relex.successful_resync){ - do_full_relex = true; - } - else{ - ProfileBlock(app, "apply resync"); - - i64 token_index_resync = relex.first_resync_index; - - Range_i64 head = Ii64(0, token_index_first); - Range_i64 replaced = Ii64(token_index_first, token_index_resync); - Range_i64 tail = Ii64(token_index_resync, ptr->count); - i64 resynced_count = (token_index_resync_guess + 1) - token_index_resync; - i64 relexed_count = relex_list.total_count - resynced_count; - i64 tail_shift = relexed_count - (token_index_resync - token_index_first); - - i64 new_tokens_count = ptr->count + tail_shift; - Token *new_tokens = base_array(allocator, Token, new_tokens_count); - - Token *old_tokens = ptr->tokens; - block_copy_array_shift(new_tokens, old_tokens, head, 0); - token_fill_memory_from_list(new_tokens + replaced.first, &relex_list, relexed_count); - for (i64 i = 0, index = replaced.first; i < relexed_count; i += 1, index += 1){ - new_tokens[index].pos += relex_range.first; - } - for (i64 i = tail.first; i < tail.one_past_last; i += 1){ - old_tokens[i].pos += text_shift; - } - block_copy_array_shift(new_tokens, ptr->tokens, tail, tail_shift); - - base_free(allocator, ptr->tokens); - - ptr->tokens = new_tokens; - ptr->count = new_tokens_count; - ptr->max = new_tokens_count; - - buffer_mark_as_modified(buffer_id); - } - } - } - - if (do_full_relex){ - *lex_task_ptr = async_task_no_dep(&global_async_system, do_full_lex_async, - make_data_struct(&buffer_id)); - } - - // no meaning for return - return(0); -} - -BUFFER_HOOK_SIG(default_end_buffer){ - Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); - Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); - if (lex_task_ptr != 0){ - async_task_cancel(&global_async_system, *lex_task_ptr); - } - buffer_unmark_as_modified(buffer_id); - code_index_lock(); - code_index_erase_file(buffer_id); - code_index_unlock(); - // no meaning for return - return(0); -} - -internal void -set_all_default_hooks(Application_Links *app){ - set_custom_hook(app, HookID_BufferViewerUpdate, default_view_adjust); - - set_custom_hook(app, HookID_ViewEventHandler, default_view_input_handler); - set_custom_hook(app, HookID_Tick, default_tick); - set_custom_hook(app, HookID_RenderCaller, default_render_caller); -#if 0 - set_custom_hook(app, HookID_DeltaRule, original_delta); - set_custom_hook_memory_size(app, HookID_DeltaRule, - delta_ctx_size(original_delta_memory_size)); -#else - set_custom_hook(app, HookID_DeltaRule, fixed_time_cubic_delta); - set_custom_hook_memory_size(app, HookID_DeltaRule, - delta_ctx_size(fixed_time_cubic_delta_memory_size)); -#endif - set_custom_hook(app, HookID_BufferNameResolver, default_buffer_name_resolution); - - set_custom_hook(app, HookID_BeginBuffer, default_begin_buffer); - set_custom_hook(app, HookID_EndBuffer, end_buffer_close_jump_list); - set_custom_hook(app, HookID_NewFile, default_new_file); - set_custom_hook(app, HookID_SaveFile, default_file_save); - set_custom_hook(app, HookID_BufferEditRange, default_buffer_edit_range); - set_custom_hook(app, HookID_BufferRegion, default_buffer_region); - - set_custom_hook(app, HookID_Layout, layout_unwrapped); - //set_custom_hook(app, HookID_Layout, layout_wrap_anywhere); - //set_custom_hook(app, HookID_Layout, layout_wrap_whitespace); - //set_custom_hook(app, HookID_Layout, layout_virt_indent_unwrapped); - //set_custom_hook(app, HookID_Layout, layout_unwrapped_small_blank_lines); -} - -// BOTTOM - +/* +4coder_default_hooks.cpp - Sets up the hooks for the default framework. +*/ + +// TOP + +CUSTOM_COMMAND_SIG(default_startup) +CUSTOM_DOC("Default command for responding to a startup event") +{ + ProfileScope(app, "default startup"); + User_Input input = get_current_input(app); + if (match_core_code(&input, CoreCode_Startup)){ + String_Const_u8_Array file_names = input.event.core.file_names; + load_themes_default_folder(app); + default_4coder_initialize(app, file_names); + default_4coder_side_by_side_panels(app, file_names); + if (global_config.automatically_load_project){ + load_project(app); + } + } +} + +CUSTOM_COMMAND_SIG(default_try_exit) +CUSTOM_DOC("Default command for responding to a try-exit event") +{ + User_Input input = get_current_input(app); + if (match_core_code(&input, CoreCode_TryExit)){ + b32 do_exit = true; + if (!allow_immediate_close_without_checking_for_changes){ + b32 has_unsaved_changes = false; + for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); + buffer != 0; + buffer = get_buffer_next(app, buffer, Access_Always)){ + Dirty_State dirty = buffer_get_dirty_state(app, buffer); + if (HasFlag(dirty, DirtyState_UnsavedChanges)){ + has_unsaved_changes = true; + break; + } + } + if (has_unsaved_changes){ + View_ID view = get_active_view(app, Access_Always); + do_exit = do_4coder_close_user_check(app, view); + } + } + if (do_exit){ + hard_exit(app); + } + } +} + +CUSTOM_COMMAND_SIG(default_view_input_handler) +CUSTOM_DOC("Input consumption loop for default view behavior") +{ + Thread_Context *tctx = get_thread_context(app); + Scratch_Block scratch(tctx); + + { + View_ID view = get_this_ctx_view(app, Access_Always); + String_Const_u8 name = push_u8_stringf(scratch, "view %d", view); + + Profile_Global_List *list = get_core_profile_list(app); + ProfileThreadName(tctx, list, name); + + View_Context ctx = view_current_context(app, view); + ctx.mapping = &framework_mapping; + ctx.map_id = mapid_global; + view_alter_context(app, view, &ctx); + } + + for (;;){ + // NOTE(allen): Get the binding from the buffer's current map + User_Input input = get_next_input(app, EventPropertyGroup_Any, 0); + ProfileScopeNamed(app, "before view input", view_input_profile); + if (input.abort){ + break; + } + + Event_Property event_properties = get_event_properties(&input.event); + + if (suppressing_mouse && (event_properties & EventPropertyGroup_AnyMouseEvent) != 0){ + continue; + } + + View_ID view = get_this_ctx_view(app, Access_Always); + + Buffer_ID buffer = view_get_buffer(app, view, Access_Always); + Managed_Scope buffer_scope = buffer_get_managed_scope(app, buffer); + Command_Map_ID *map_id_ptr = scope_attachment(app, buffer_scope, buffer_map_id, Command_Map_ID); + if (*map_id_ptr == 0){ + *map_id_ptr = mapid_file; + } + Command_Map_ID map_id = *map_id_ptr; + + Command_Binding binding = map_get_binding_recursive(&framework_mapping, map_id, &input.event); + + Managed_Scope scope = view_get_managed_scope(app, view); + + if (binding.custom == 0){ + // NOTE(allen): we don't have anything to do with this input, + // leave it marked unhandled so that if there's a follow up + // event it is not blocked. + leave_current_input_unhandled(app); + } + else{ + // NOTE(allen): before the command is called do some book keeping + Rewrite_Type *next_rewrite = + scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); + *next_rewrite = Rewrite_None; + if (fcoder_mode == FCoderMode_NotepadLike){ + for (View_ID view_it = get_view_next(app, 0, Access_Always); + view_it != 0; + view_it = get_view_next(app, view_it, Access_Always)){ + Managed_Scope scope_it = view_get_managed_scope(app, view_it); + b32 *snap_mark_to_cursor = + scope_attachment(app, scope_it, view_snap_mark_to_cursor, + b32); + *snap_mark_to_cursor = true; + } + } + + ProfileCloseNow(view_input_profile); + + // NOTE(allen): call the command + binding.custom(app); + + // NOTE(allen): after the command is called do some book keeping + ProfileScope(app, "after view input"); + + next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type); + if (next_rewrite != 0){ + Rewrite_Type *rewrite = + scope_attachment(app, scope, view_rewrite_loc, Rewrite_Type); + *rewrite = *next_rewrite; + if (fcoder_mode == FCoderMode_NotepadLike){ + for (View_ID view_it = get_view_next(app, 0, Access_Always); + view_it != 0; + view_it = get_view_next(app, view_it, Access_Always)){ + Managed_Scope scope_it = view_get_managed_scope(app, view_it); + b32 *snap_mark_to_cursor = + scope_attachment(app, scope_it, view_snap_mark_to_cursor, b32); + if (*snap_mark_to_cursor){ + i64 pos = view_get_cursor_pos(app, view_it); + view_set_mark(app, view_it, seek_pos(pos)); + } + } + } + } + } + } +} + +function void +default_tick(Application_Links *app, Frame_Info frame_info){ + Scratch_Block scratch(app); + + for (Buffer_Modified_Node *node = global_buffer_modified_set.first; + node != 0; + node = node->next){ + Temp_Memory_Block temp(scratch); + Buffer_ID buffer_id = node->buffer; + + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + + String_Const_u8 contents = push_whole_buffer(app, scratch, buffer_id); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); + if (tokens_ptr == 0){ + continue; + } + if (tokens_ptr->count == 0){ + continue; + } + Token_Array tokens = *tokens_ptr; + + Arena arena = make_arena_system(KB(16)); + Code_Index_File *index = push_array_zero(&arena, Code_Index_File, 1); + index->buffer = buffer_id; + + Generic_Parse_State state = {}; + generic_parse_init(app, &arena, contents, &tokens, &state); + // TODO(allen): Actually determine this in a fair way. + // Maybe switch to an enum. + state.do_cpp_parse = true; + generic_parse_full_input_breaks(index, &state, max_i32); + + code_index_lock(); + code_index_set_file(buffer_id, arena, index); + code_index_unlock(); + buffer_clear_layout_cache(app, buffer_id); + } + + buffer_modified_set_clear(); + + if (tick_all_fade_ranges(frame_info.animation_dt)){ + animate_in_n_milliseconds(app, 0); + } +} + +function Rect_f32 +default_buffer_region(Application_Links *app, View_ID view_id, Rect_f32 region){ + Buffer_ID buffer = view_get_buffer(app, view_id, Access_Always); + Face_ID face_id = get_face_id(app, buffer); + Face_Metrics metrics = get_face_metrics(app, face_id); + f32 line_height = metrics.line_height; + f32 digit_advance = metrics.decimal_digit_advance; + + // NOTE(allen): margins + region = rect_inner(region, 3.f); + + // NOTE(allen): file bar + b64 showing_file_bar = false; + if (view_get_setting(app, view_id, ViewSetting_ShowFileBar, &showing_file_bar) && + showing_file_bar){ + Rect_f32_Pair pair = layout_file_bar_on_top(region, line_height); + region = pair.max; + } + + // NOTE(allen): query bars + { + Query_Bar *space[32]; + Query_Bar_Ptr_Array query_bars = {}; + query_bars.ptrs = space; + if (get_active_query_bars(app, view_id, ArrayCount(space), &query_bars)){ + Rect_f32_Pair pair = layout_query_bar_on_top(region, line_height, query_bars.count); + region = pair.max; + } + } + + // NOTE(allen): FPS hud + if (show_fps_hud){ + Rect_f32_Pair pair = layout_fps_hud_on_bottom(region, line_height); + region = pair.min; + } + + // NOTE(allen): line numbers + if (global_config.show_line_number_margins){ + Rect_f32_Pair pair = layout_line_number_margin(app, buffer, region, digit_advance); + region = pair.max; + } + + return(region); +} + +function void +recursive_nest_highlight(Application_Links *app, Text_Layout_ID layout_id, Range_i64 range, + Code_Index_Nest_Ptr_Array *array, i32 counter){ + Code_Index_Nest **ptr = array->ptrs; + Code_Index_Nest **ptr_end = ptr + array->count; + + for (;ptr < ptr_end; ptr += 1){ + Code_Index_Nest *nest = *ptr; + if (!nest->is_closed){ + break; + } + if (range.first <= nest->close.max){ + break; + } + } + + ARGB_Color argb = finalize_color(defcolor_text_cycle, counter); + + for (;ptr < ptr_end; ptr += 1){ + Code_Index_Nest *nest = *ptr; + if (range.max <= nest->open.min){ + break; + } + + paint_text_color(app, layout_id, nest->open, argb); + if (nest->is_closed){ + paint_text_color(app, layout_id, nest->close, argb); + } + recursive_nest_highlight(app, layout_id, range, &nest->nest_array, counter + 1); + } +} + +function void +recursive_nest_highlight(Application_Links *app, Text_Layout_ID layout_id, Range_i64 range, + Code_Index_File *file){ + recursive_nest_highlight(app, layout_id, range, &file->nest_array, 0); +} + +function void +default_render_buffer(Application_Links *app, View_ID view_id, Face_ID face_id, + Buffer_ID buffer, Text_Layout_ID text_layout_id, + Rect_f32 rect){ + ProfileScope(app, "render buffer"); + + View_ID active_view = get_active_view(app, Access_Always); + b32 is_active_view = (active_view == view_id); + Rect_f32 prev_clip = draw_set_clip(app, rect); + + // NOTE(allen): Token colorizing + Token_Array token_array = get_token_array_from_buffer(app, buffer); + if (token_array.tokens != 0){ + draw_cpp_token_colors(app, text_layout_id, &token_array); + + // NOTE(allen): Scan for TODOs and NOTEs + if (global_config.use_comment_keyword){ + Comment_Highlight_Pair pairs[] = { + {string_u8_litexpr("NOTE"), finalize_color(defcolor_comment_pop, 0)}, + {string_u8_litexpr("TODO"), finalize_color(defcolor_comment_pop, 1)}, + }; + draw_comment_highlights(app, buffer, text_layout_id, + &token_array, pairs, ArrayCount(pairs)); + } + } + else{ + Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); + paint_text_color_fcolor(app, text_layout_id, visible_range, fcolor_id(defcolor_text_default)); + } + + i64 cursor_pos = view_correct_cursor(app, view_id); + view_correct_mark(app, view_id); + + // NOTE(allen): Scope highlight + if (global_config.use_scope_highlight){ + Color_Array colors = finalize_color_array(defcolor_back_cycle); + draw_scope_highlight(app, buffer, text_layout_id, cursor_pos, colors.vals, colors.count); + } + + if (global_config.use_error_highlight || global_config.use_jump_highlight){ + // NOTE(allen): Error highlight + String_Const_u8 name = string_u8_litexpr("*compilation*"); + Buffer_ID compilation_buffer = get_buffer_by_name(app, name, Access_Always); + if (global_config.use_error_highlight){ + draw_jump_highlights(app, buffer, text_layout_id, compilation_buffer, + fcolor_id(defcolor_highlight_junk)); + } + + // NOTE(allen): Search highlight + if (global_config.use_jump_highlight){ + Buffer_ID jump_buffer = get_locked_jump_buffer(app); + if (jump_buffer != compilation_buffer){ + draw_jump_highlights(app, buffer, text_layout_id, jump_buffer, + fcolor_id(defcolor_highlight_white)); + } + } + } + + // NOTE(allen): Color parens + if (global_config.use_paren_helper){ + Color_Array colors = finalize_color_array(defcolor_text_cycle); + draw_paren_highlight(app, buffer, text_layout_id, cursor_pos, colors.vals, colors.count); + } + + // NOTE(allen): Line highlight + if (global_config.highlight_line_at_cursor && is_active_view){ + i64 line_number = get_line_number_from_pos(app, buffer, cursor_pos); + draw_line_highlight(app, text_layout_id, line_number, + fcolor_id(defcolor_highlight_cursor_line)); + } + + // NOTE(allen): Cursor shape + Face_Metrics metrics = get_face_metrics(app, face_id); + f32 cursor_roundness = (metrics.normal_advance*0.5f)*0.9f; + f32 mark_thickness = 2.f; + + // NOTE(allen): Cursor + switch (fcoder_mode){ + case FCoderMode_Original: + { + draw_original_4coder_style_cursor_mark_highlight(app, view_id, is_active_view, buffer, text_layout_id, cursor_roundness, mark_thickness); + }break; + case FCoderMode_NotepadLike: + { + draw_notepad_style_cursor_highlight(app, view_id, buffer, text_layout_id, cursor_roundness); + }break; + } + + // NOTE(allen): Fade ranges + paint_fade_ranges(app, text_layout_id, buffer, view_id); + + // NOTE(allen): put the actual text on the actual screen + draw_text_layout_default(app, text_layout_id); + + draw_set_clip(app, prev_clip); +} + +function void +default_render_caller(Application_Links *app, Frame_Info frame_info, View_ID view_id){ + ProfileScope(app, "default render caller"); + View_ID active_view = get_active_view(app, Access_Always); + b32 is_active_view = (active_view == view_id); + + Rect_f32 region = draw_background_and_margin(app, view_id, is_active_view); + Rect_f32 prev_clip = draw_set_clip(app, region); + + Buffer_ID buffer = view_get_buffer(app, view_id, Access_Always); + Face_ID face_id = get_face_id(app, buffer); + Face_Metrics face_metrics = get_face_metrics(app, face_id); + f32 line_height = face_metrics.line_height; + f32 digit_advance = face_metrics.decimal_digit_advance; + + // NOTE(allen): file bar + b64 showing_file_bar = false; + if (view_get_setting(app, view_id, ViewSetting_ShowFileBar, &showing_file_bar) && showing_file_bar){ + Rect_f32_Pair pair = layout_file_bar_on_top(region, line_height); + draw_file_bar(app, view_id, buffer, face_id, pair.min); + region = pair.max; + } + + Buffer_Scroll scroll = view_get_buffer_scroll(app, view_id); + + Buffer_Point_Delta_Result delta = delta_apply(app, view_id, + frame_info.animation_dt, scroll); + if (!block_match_struct(&scroll.position, &delta.point)){ + block_copy_struct(&scroll.position, &delta.point); + view_set_buffer_scroll(app, view_id, scroll, SetBufferScroll_NoCursorChange); + } + if (delta.still_animating){ + animate_in_n_milliseconds(app, 0); + } + + // NOTE(allen): query bars + { + Query_Bar *space[32]; + Query_Bar_Ptr_Array query_bars = {}; + query_bars.ptrs = space; + if (get_active_query_bars(app, view_id, ArrayCount(space), &query_bars)){ + for (i32 i = 0; i < query_bars.count; i += 1){ + Rect_f32_Pair pair = layout_query_bar_on_top(region, line_height, 1); + draw_query_bar(app, query_bars.ptrs[i], face_id, pair.min); + region = pair.max; + } + } + } + + // NOTE(allen): FPS hud + if (show_fps_hud){ + Rect_f32_Pair pair = layout_fps_hud_on_bottom(region, line_height); + draw_fps_hud(app, frame_info, face_id, pair.max); + region = pair.min; + animate_in_n_milliseconds(app, 1000); + } + + // NOTE(allen): layout line numbers + Rect_f32 line_number_rect = {}; + if (global_config.show_line_number_margins){ + Rect_f32_Pair pair = layout_line_number_margin(app, buffer, region, digit_advance); + line_number_rect = pair.min; + region = pair.max; + } + + // NOTE(allen): begin buffer render + Buffer_Point buffer_point = scroll.position; + Text_Layout_ID text_layout_id = text_layout_create(app, buffer, region, buffer_point); + + // NOTE(allen): draw line numbers + if (global_config.show_line_number_margins){ + draw_line_number_margin(app, view_id, buffer, face_id, text_layout_id, line_number_rect); + } + + // NOTE(allen): draw the buffer + default_render_buffer(app, view_id, face_id, buffer, text_layout_id, region); + + text_layout_free(app, text_layout_id); + draw_set_clip(app, prev_clip); +} + +HOOK_SIG(default_view_adjust){ + // NOTE(allen): Called whenever the view layout/sizes have been modified, + // including by full window resize. + return(0); +} + +BUFFER_NAME_RESOLVER_SIG(default_buffer_name_resolution){ + ProfileScope(app, "default buffer name resolution"); + if (conflict_count > 1){ + // List of unresolved conflicts + Scratch_Block scratch(app); + + i32 *unresolved = push_array(scratch, i32, conflict_count); + i32 unresolved_count = conflict_count; + for (i32 i = 0; i < conflict_count; ++i){ + unresolved[i] = i; + } + + // Resolution Loop + i32 x = 0; + for (;;){ + // Resolution Pass + ++x; + for (i32 i = 0; i < unresolved_count; ++i){ + i32 conflict_index = unresolved[i]; + Buffer_Name_Conflict_Entry *conflict = &conflicts[conflict_index]; + + u64 size = conflict->base_name.size; + size = clamp_top(size, conflict->unique_name_capacity); + conflict->unique_name_len_in_out = size; + block_copy(conflict->unique_name_in_out, conflict->base_name.str, size); + + if (conflict->file_name.str != 0){ + Temp_Memory_Block temp(scratch); + String_Const_u8 uniqueifier = {}; + + String_Const_u8 file_name = string_remove_last_folder(conflict->file_name); + if (file_name.size > 0){ + file_name = string_chop(file_name, 1); + u8 *end = file_name.str + file_name.size; + b32 past_the_end = false; + for (i32 j = 0; j < x; ++j){ + file_name = string_remove_last_folder(file_name); + if (j + 1 < x){ + file_name = string_chop(file_name, 1); + } + if (file_name.size == 0){ + if (j + 1 < x){ + past_the_end = true; + } + break; + } + } + u8 *start = file_name.str + file_name.size; + + uniqueifier = SCu8(start, end); + if (past_the_end){ + uniqueifier = push_u8_stringf(scratch, "%.*s~%d", + string_expand(uniqueifier), i); + } + } + else{ + uniqueifier = push_u8_stringf(scratch, "%d", i); + } + + String_u8 builder = Su8(conflict->unique_name_in_out, + conflict->unique_name_len_in_out, + conflict->unique_name_capacity); + string_append(&builder, string_u8_litexpr(" <")); + string_append(&builder, uniqueifier); + string_append(&builder, string_u8_litexpr(">")); + conflict->unique_name_len_in_out = builder.size; + } + } + + // Conflict Check Pass + b32 has_conflicts = false; + for (i32 i = 0; i < unresolved_count; ++i){ + i32 conflict_index = unresolved[i]; + Buffer_Name_Conflict_Entry *conflict = &conflicts[conflict_index]; + String_Const_u8 conflict_name = SCu8(conflict->unique_name_in_out, + conflict->unique_name_len_in_out); + + b32 hit_conflict = false; + if (conflict->file_name.str != 0){ + for (i32 j = 0; j < unresolved_count; ++j){ + if (i == j) continue; + + i32 conflict_j_index = unresolved[j]; + Buffer_Name_Conflict_Entry *conflict_j = &conflicts[conflict_j_index]; + + String_Const_u8 conflict_name_j = SCu8(conflict_j->unique_name_in_out, + conflict_j->unique_name_len_in_out); + + if (string_match(conflict_name, conflict_name_j)){ + hit_conflict = true; + break; + } + } + } + + if (hit_conflict){ + has_conflicts = true; + } + else{ + --unresolved_count; + unresolved[i] = unresolved[unresolved_count]; + --i; + } + } + + if (!has_conflicts){ + break; + } + } + } +} + +function void +parse_async__inner(Async_Context *actx, Buffer_ID buffer_id, + String_Const_u8 contents, Token_Array *tokens, i32 limit_factor){ + Application_Links *app = actx->app; + ProfileBlock(app, "async parse"); + + Arena arena = make_arena_system(KB(16)); + Code_Index_File *index = push_array_zero(&arena, Code_Index_File, 1); + index->buffer = buffer_id; + + Generic_Parse_State state = {}; + generic_parse_init(app, &arena, contents, tokens, &state); + + b32 canceled = false; + + for (;;){ + if (generic_parse_full_input_breaks(index, &state, limit_factor)){ + break; + } + if (async_check_canceled(actx)){ + canceled = true; + break; + } + } + + if (!canceled){ + Thread_Context *tctx = get_thread_context(app); + system_acquire_global_frame_mutex(tctx); + code_index_lock(); + code_index_set_file(buffer_id, arena, index); + code_index_unlock(); + buffer_clear_layout_cache(app, buffer_id); + system_release_global_frame_mutex(tctx); + } + else{ + linalloc_clear(&arena); + } +} + +function void +do_full_lex_async__inner(Async_Context *actx, Buffer_ID buffer_id){ + Application_Links *app = actx->app; + ProfileScope(app, "async lex"); + Thread_Context *tctx = get_thread_context(app); + Scratch_Block scratch(tctx); + + String_Const_u8 contents = {}; + { + ProfileBlock(app, "async lex contents (before mutex)"); + system_acquire_global_frame_mutex(tctx); + ProfileBlock(app, "async lex contents (after mutex)"); + contents = push_whole_buffer(app, scratch, buffer_id); + system_release_global_frame_mutex(tctx); + } + + i32 limit_factor = 10000; + + Token_List list = {}; + b32 canceled = false; + + Lex_State_Cpp state = {}; + lex_full_input_cpp_init(&state, contents); + for (;;){ + ProfileBlock(app, "async lex block"); + if (lex_full_input_cpp_breaks(scratch, &list, &state, limit_factor)){ + break; + } + if (async_check_canceled(actx)){ + canceled = true; + break; + } + } + + if (!canceled){ + ProfileBlock(app, "async lex save results (before mutex)"); + system_acquire_global_frame_mutex(tctx); + ProfileBlock(app, "async lex save results (after mutex)"); + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + if (scope != 0){ + Base_Allocator *allocator = managed_scope_allocator(app, scope); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, + Token_Array); + base_free(allocator, tokens_ptr->tokens); + Token_Array tokens = {}; + tokens.tokens = base_array(allocator, Token, list.total_count); + tokens.count = list.total_count; + tokens.max = list.total_count; + token_fill_memory_from_list(tokens.tokens, &list); + block_copy_struct(tokens_ptr, &tokens); + } + buffer_mark_as_modified(buffer_id); + system_release_global_frame_mutex(tctx); + } +} + +function void +do_full_lex_async(Async_Context *actx, Data data){ + if (data.size == sizeof(Buffer_ID)){ + Buffer_ID buffer = *(Buffer_ID*)data.data; + do_full_lex_async__inner(actx, buffer); + } +} + +#if 0 +function void +do_full_lex_and_parse_async__inner(Async_Context *actx, Buffer_ID buffer_id){ + Application_Links *app = actx->app; + ProfileScope(app, "async lex"); + Thread_Context *tctx = get_thread_context(app); + Scratch_Block scratch(tctx); + + String_Const_u8 contents = {}; + { + ProfileBlock(app, "async lex contents (before mutex)"); + system_acquire_global_frame_mutex(tctx); + ProfileBlock(app, "async lex contents (after mutex)"); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + if (scope != 0){ + Base_Allocator *allocator = managed_scope_allocator(app, scope); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, + Token_Array); + base_free(allocator, tokens_ptr->tokens); + block_zero_struct(tokens_ptr); + } + + contents = push_whole_buffer(app, scratch, buffer_id); + system_release_global_frame_mutex(tctx); + } + + i32 limit_factor = 10000; + + Token_List list = {}; + b32 canceled = false; + + { + Lex_State_Cpp state = {}; + lex_full_input_cpp_init(&state, contents); + for (;;){ + ProfileBlock(app, "async lex block"); + if (lex_full_input_cpp_breaks(scratch, &list, &state, limit_factor)){ + break; + } + if (async_check_canceled(actx)){ + canceled = true; + break; + } + } + } + + Token_Array tokens = {}; + if (!canceled){ + ProfileBlock(app, "async lex save results (before mutex)"); + system_acquire_global_frame_mutex(tctx); + ProfileBlock(app, "async lex save results (after mutex)"); + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + if (scope != 0){ + Base_Allocator *allocator = managed_scope_allocator(app, scope); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, + Token_Array); + base_free(allocator, tokens_ptr->tokens); + tokens.tokens = base_array(allocator, Token, list.total_count); + tokens.count = list.total_count; + tokens.max = list.total_count; + token_fill_memory_from_list(tokens.tokens, &list); + block_copy_struct(tokens_ptr, &tokens); + } + system_release_global_frame_mutex(tctx); + } + + if (tokens.count > 0){ + parse_async__inner(actx, buffer_id, contents, &tokens, limit_factor); + } +} + +function void +do_full_lex_and_parse_async(Async_Context *actx, Data data){ + if (data.size == sizeof(Buffer_ID)){ + Buffer_ID buffer = *(Buffer_ID*)data.data; + do_full_lex_and_parse_async__inner(actx, buffer); + } +} +#endif + +#if 0 +function void +do_parse_async__inner(Async_Context *actx, Buffer_ID buffer_id){ + Application_Links *app = actx->app; + ProfileScope(app, "async lex"); + Thread_Context *tctx = get_thread_context(app); + Scratch_Block scratch(tctx); + + String_Const_u8 contents = {}; + Token_Array tokens = {}; + { + ProfileBlock(app, "async parse contents (before mutex)"); + system_acquire_global_frame_mutex(tctx); + ProfileBlock(app, "async parse contents (after mutex)"); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + if (scope != 0){ + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, + Token_Array); + tokens.count = tokens_ptr->count; + tokens.tokens = push_array_write(scratch, Token, tokens.count, tokens_ptr->tokens); + if (tokens.count > 0){ + contents = push_whole_buffer(app, scratch, buffer_id); + } + } + + system_release_global_frame_mutex(tctx); + } + + i32 limit_factor = 10000; + + if (tokens.count > 0){ + parse_async__inner(actx, buffer_id, contents, &tokens, limit_factor); + } +} + +function void +do_parse_async(Async_Context *actx, Data data){ + if (data.size == sizeof(Buffer_ID)){ + Buffer_ID buffer = *(Buffer_ID*)data.data; + do_parse_async__inner(actx, buffer); + } +} +#endif + +BUFFER_HOOK_SIG(default_begin_buffer){ + ProfileScope(app, "begin buffer"); + + Scratch_Block scratch(app); + + b32 treat_as_code = false; + String_Const_u8 file_name = push_buffer_file_name(app, scratch, buffer_id); + if (file_name.size > 0){ + String_Const_u8_Array extensions = global_config.code_exts; + String_Const_u8 ext = string_file_extension(file_name); + for (i32 i = 0; i < extensions.count; ++i){ + if (string_match(ext, extensions.strings[i])){ + + if (string_match(ext, string_u8_litexpr("cpp")) || + string_match(ext, string_u8_litexpr("h")) || + string_match(ext, string_u8_litexpr("c")) || + string_match(ext, string_u8_litexpr("hpp")) || + string_match(ext, string_u8_litexpr("cc"))){ + treat_as_code = true; + } + +#if 0 + treat_as_code = true; + + if (string_match(ext, string_u8_litexpr("cs"))){ + if (parse_context_language_cs == 0){ + init_language_cs(app); + } + parse_context_id = parse_context_language_cs; + } + + if (string_match(ext, string_u8_litexpr("java"))){ + if (parse_context_language_java == 0){ + init_language_java(app); + } + parse_context_id = parse_context_language_java; + } + + if (string_match(ext, string_u8_litexpr("rs"))){ + if (parse_context_language_rust == 0){ + init_language_rust(app); + } + parse_context_id = parse_context_language_rust; + } + + if (string_match(ext, string_u8_litexpr("cpp")) || + string_match(ext, string_u8_litexpr("h")) || + string_match(ext, string_u8_litexpr("c")) || + string_match(ext, string_u8_litexpr("hpp")) || + string_match(ext, string_u8_litexpr("cc"))){ + if (parse_context_language_cpp == 0){ + init_language_cpp(app); + } + parse_context_id = parse_context_language_cpp; + } + + // TODO(NAME): Real GLSL highlighting + if (string_match(ext, string_u8_litexpr("glsl"))){ + if (parse_context_language_cpp == 0){ + init_language_cpp(app); + } + parse_context_id = parse_context_language_cpp; + } + + // TODO(NAME): Real Objective-C highlighting + if (string_match(ext, string_u8_litexpr("m"))){ + if (parse_context_language_cpp == 0){ + init_language_cpp(app); + } + parse_context_id = parse_context_language_cpp; + } +#endif + + break; + } + } + } + + Command_Map_ID map_id = (treat_as_code)?(mapid_code):(mapid_file); + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + Command_Map_ID *map_id_ptr = scope_attachment(app, scope, buffer_map_id, Command_Map_ID); + *map_id_ptr = map_id; + + Line_Ending_Kind setting = guess_line_ending_kind_from_buffer(app, buffer_id); + Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, Line_Ending_Kind); + *eol_setting = setting; + + // NOTE(allen): Decide buffer settings + b32 wrap_lines = true; + b32 use_virtual_whitespace = false; + b32 use_lexer = false; + if (treat_as_code){ + wrap_lines = global_config.enable_code_wrapping; + use_virtual_whitespace = global_config.enable_virtual_whitespace; + use_lexer = true; + } + + String_Const_u8 buffer_name = push_buffer_base_name(app, scratch, buffer_id); + if (string_match(buffer_name, string_u8_litexpr("*compilation*"))){ + wrap_lines = false; + } + + if (use_lexer){ + ProfileBlock(app, "begin buffer kick off lexer"); + Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); + *lex_task_ptr = async_task_no_dep(&global_async_system, do_full_lex_async, make_data_struct(&buffer_id)); + } + + { + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + *wrap_lines_ptr = wrap_lines; + } + + if (use_virtual_whitespace){ + if (use_lexer){ + buffer_set_layout(app, buffer_id, layout_virt_indent_index_generic); + } + else{ + buffer_set_layout(app, buffer_id, layout_virt_indent_literal_generic); + } + } + else{ + buffer_set_layout(app, buffer_id, layout_generic); + } + + // no meaning for return + return(0); +} + +BUFFER_HOOK_SIG(default_new_file){ + Scratch_Block scratch(app); + String_Const_u8 file_name = push_buffer_base_name(app, scratch, buffer_id); + if (!string_match(string_postfix(file_name, 2), string_u8_litexpr(".h"))) { + return(0); + } + + List_String_Const_u8 guard_list = {}; + for (u64 i = 0; i < file_name.size; ++i){ + u8 c[2] = {}; + u64 c_size = 1; + u8 ch = file_name.str[i]; + if (ch == '.'){ + c[0] = '_'; + } + else if (ch >= 'A' && ch <= 'Z'){ + c_size = 2; + c[0] = '_'; + c[1] = ch; + } + else if (ch >= 'a' && ch <= 'z'){ + c[0] = ch - ('a' - 'A'); + } + String_Const_u8 part = push_string_copy(scratch, SCu8(c, c_size)); + string_list_push(scratch, &guard_list, part); + } + String_Const_u8 guard = string_list_flatten(scratch, guard_list); + + Buffer_Insertion insert = begin_buffer_insertion_at_buffered(app, buffer_id, 0, scratch, KB(16)); + insertf(&insert, + "#ifndef %.*s\n" + "#define %.*s\n" + "\n" + "#endif //%.*s\n", + string_expand(guard), + string_expand(guard), + string_expand(guard)); + end_buffer_insertion(&insert); + + return(0); +} + +BUFFER_HOOK_SIG(default_file_save){ + // buffer_id + ProfileScope(app, "default file save"); + b32 is_virtual = global_config.enable_virtual_whitespace; + if (global_config.automatically_indent_text_on_save && is_virtual){ + auto_indent_buffer(app, buffer_id, buffer_range(app, buffer_id)); + } + + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + Line_Ending_Kind *eol = scope_attachment(app, scope, buffer_eol_setting, + Line_Ending_Kind); + switch (*eol){ + case LineEndingKind_LF: + { + rewrite_lines_to_lf(app, buffer_id); + }break; + case LineEndingKind_CRLF: + { + rewrite_lines_to_crlf(app, buffer_id); + }break; + } + + // no meaning for return + return(0); +} + +BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){ + // buffer_id, new_range, original_size + ProfileScope(app, "default edit range"); + + Range_i64 old_range = Ii64(new_range.first, new_range.first + original_size); + + { + code_index_lock(); + Code_Index_File *file = code_index_get_file(buffer_id); + if (file != 0){ + code_index_shift(file, old_range, range_size(new_range)); + } + code_index_unlock(); + } + + i64 insert_size = range_size(new_range); + i64 text_shift = replace_range_shift(old_range, insert_size); + + Scratch_Block scratch(app); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); + + Base_Allocator *allocator = managed_scope_allocator(app, scope); + b32 do_full_relex = false; + + if (async_task_is_running_or_pending(&global_async_system, *lex_task_ptr)){ + async_task_cancel(&global_async_system, *lex_task_ptr); + buffer_unmark_as_modified(buffer_id); + do_full_relex = true; + *lex_task_ptr = 0; + } + + Token_Array *ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); + if (ptr != 0 && ptr->tokens != 0){ + ProfileBlockNamed(app, "attempt resync", profile_attempt_resync); + + i64 token_index_first = token_relex_first(ptr, old_range.first, 1); + i64 token_index_resync_guess = + token_relex_resync(ptr, old_range.one_past_last, 16); + + if (token_index_resync_guess - token_index_first >= 4000){ + do_full_relex = true; + } + else{ + Token *token_first = ptr->tokens + token_index_first; + Token *token_resync = ptr->tokens + token_index_resync_guess; + + Range_i64 relex_range = Ii64(token_first->pos, token_resync->pos + token_resync->size + text_shift); + String_Const_u8 partial_text = push_buffer_range(app, scratch, buffer_id, relex_range); + + Token_List relex_list = lex_full_input_cpp(scratch, partial_text); + if (relex_range.one_past_last < buffer_get_size(app, buffer_id)){ + token_drop_eof(&relex_list); + } + + Token_Relex relex = token_relex(relex_list, relex_range.first - text_shift, ptr->tokens, token_index_first, token_index_resync_guess); + + ProfileCloseNow(profile_attempt_resync); + + if (!relex.successful_resync){ + do_full_relex = true; + } + else{ + ProfileBlock(app, "apply resync"); + + i64 token_index_resync = relex.first_resync_index; + + Range_i64 head = Ii64(0, token_index_first); + Range_i64 replaced = Ii64(token_index_first, token_index_resync); + Range_i64 tail = Ii64(token_index_resync, ptr->count); + i64 resynced_count = (token_index_resync_guess + 1) - token_index_resync; + i64 relexed_count = relex_list.total_count - resynced_count; + i64 tail_shift = relexed_count - (token_index_resync - token_index_first); + + i64 new_tokens_count = ptr->count + tail_shift; + Token *new_tokens = base_array(allocator, Token, new_tokens_count); + + Token *old_tokens = ptr->tokens; + block_copy_array_shift(new_tokens, old_tokens, head, 0); + token_fill_memory_from_list(new_tokens + replaced.first, &relex_list, relexed_count); + for (i64 i = 0, index = replaced.first; i < relexed_count; i += 1, index += 1){ + new_tokens[index].pos += relex_range.first; + } + for (i64 i = tail.first; i < tail.one_past_last; i += 1){ + old_tokens[i].pos += text_shift; + } + block_copy_array_shift(new_tokens, ptr->tokens, tail, tail_shift); + + base_free(allocator, ptr->tokens); + + ptr->tokens = new_tokens; + ptr->count = new_tokens_count; + ptr->max = new_tokens_count; + + buffer_mark_as_modified(buffer_id); + } + } + } + + if (do_full_relex){ + *lex_task_ptr = async_task_no_dep(&global_async_system, do_full_lex_async, + make_data_struct(&buffer_id)); + } + + // no meaning for return + return(0); +} + +BUFFER_HOOK_SIG(default_end_buffer){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); + Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); + if (lex_task_ptr != 0){ + async_task_cancel(&global_async_system, *lex_task_ptr); + } + buffer_unmark_as_modified(buffer_id); + code_index_lock(); + code_index_erase_file(buffer_id); + code_index_unlock(); + // no meaning for return + return(0); +} + +internal void +set_all_default_hooks(Application_Links *app){ + set_custom_hook(app, HookID_BufferViewerUpdate, default_view_adjust); + + set_custom_hook(app, HookID_ViewEventHandler, default_view_input_handler); + set_custom_hook(app, HookID_Tick, default_tick); + set_custom_hook(app, HookID_RenderCaller, default_render_caller); +#if 0 + set_custom_hook(app, HookID_DeltaRule, original_delta); + set_custom_hook_memory_size(app, HookID_DeltaRule, + delta_ctx_size(original_delta_memory_size)); +#else + set_custom_hook(app, HookID_DeltaRule, fixed_time_cubic_delta); + set_custom_hook_memory_size(app, HookID_DeltaRule, + delta_ctx_size(fixed_time_cubic_delta_memory_size)); +#endif + set_custom_hook(app, HookID_BufferNameResolver, default_buffer_name_resolution); + + set_custom_hook(app, HookID_BeginBuffer, default_begin_buffer); + set_custom_hook(app, HookID_EndBuffer, end_buffer_close_jump_list); + set_custom_hook(app, HookID_NewFile, default_new_file); + set_custom_hook(app, HookID_SaveFile, default_file_save); + set_custom_hook(app, HookID_BufferEditRange, default_buffer_edit_range); + set_custom_hook(app, HookID_BufferRegion, default_buffer_region); + + set_custom_hook(app, HookID_Layout, layout_unwrapped); + //set_custom_hook(app, HookID_Layout, layout_wrap_anywhere); + //set_custom_hook(app, HookID_Layout, layout_wrap_whitespace); + //set_custom_hook(app, HookID_Layout, layout_virt_indent_unwrapped); + //set_custom_hook(app, HookID_Layout, layout_unwrapped_small_blank_lines); +} + +// BOTTOM + diff --git a/custom/4coder_default_include.cpp b/custom/4coder_default_include.cpp index 929af268..063567c6 100644 --- a/custom/4coder_default_include.cpp +++ b/custom/4coder_default_include.cpp @@ -78,6 +78,8 @@ #include "4coder_token.cpp" #include "generated/lexer_cpp.cpp" #include "4coder_command_map.cpp" +#include "4coder_default_map.cpp" +#include "4coder_mac_map.cpp" #include "4coder_default_framework_variables.cpp" #include "4coder_default_colors.cpp" #include "4coder_helper.cpp" @@ -118,8 +120,6 @@ #include "4coder_default_hooks.cpp" -#include "generated/managed_id_metadata.cpp" - #endif // BOTTOM diff --git a/custom/4coder_doc_commands.cpp b/custom/4coder_doc_commands.cpp index 92c2f6f8..d2aa3e09 100644 --- a/custom/4coder_doc_commands.cpp +++ b/custom/4coder_doc_commands.cpp @@ -14,7 +14,7 @@ doc_commands(Arena *arena){ Doc_Cluster *cluster = new_doc_cluster(arena, "Commands", "commands"); for (i32 i = 0; i < ArrayCount(fcoder_metacmd_table); i += 1){ String_Const_u8 cmd_name = SCu8(fcoder_metacmd_table[i].name, - fcoder_metacmd_table[i].name_len); + fcoder_metacmd_table[i].name_len); String_Const_u8 title = push_u8_stringf(arena, "Command %.*s", string_expand(cmd_name)); Doc_Page *page = new_doc_page(arena, cluster, (char*)title.str, (char*)cmd_name.str); Doc_Block *block = new_doc_block(arena, page, "brief"); @@ -24,146 +24,150 @@ doc_commands(Arena *arena){ } function Doc_Cluster* -doc_default_bindings(Arena *arena, Mapping *mapping, i64 global_id, i64 file_id, i64 code_id){ +doc_default_bindings(Arena *arena, i32 map_count, Mapping *mapping_array, char **page_titles, char **page_names, + i64 global_id, i64 file_id, i64 code_id){ Doc_Cluster *cluster = new_doc_cluster(arena, "Bindings", "bindings"); - Doc_Page *page = new_doc_page(arena, cluster, "Default Bindings", "default_bindings"); - for (Command_Map *map = mapping->first_map; - map != 0; - map = map->next){ - char *map_name = ""; - if (map->id == global_id){ - map_name = "Global"; - } - else if (map->id == file_id){ - map_name = "File"; - } - else if (map->id == code_id){ - map_name = "Code"; - } - - Doc_Block *block = new_doc_block(arena, page, map_name); - Doc_Paragraph *par = new_doc_par_table(arena, block); - - struct Bind_Node{ - Bind_Node *next; - Input_Event_Kind kind; - u32 sub_code; - Input_Modifier_Set mods; - Command_Binding binding; - u32 j; - }; - - Bind_Node *first = 0; - Bind_Node *last = 0; - i32 node_count = 0; - - if (map->text_input_command.name != 0){ - Bind_Node *node = push_array_zero(arena, Bind_Node, 1); - sll_queue_push(first, last, node); - node_count += 1; - node->binding = map->text_input_command; - node->j = max_u32; - } - - u32 counts[] = { - KeyCode_COUNT, - KeyCode_COUNT, - MouseCode_COUNT, - MouseCode_COUNT, - 1, - 1, - CoreCode_COUNT, - }; - - u32 event_codes[] = { - InputEventKind_KeyStroke, - InputEventKind_KeyRelease, - InputEventKind_MouseButton, - InputEventKind_MouseButtonRelease, - InputEventKind_MouseWheel, - InputEventKind_MouseMove, - InputEventKind_Core, - }; - - char *mouse_wheel_name[] = {"MoveWheel"}; - char *mouse_move_name[] = {"MoveMove"}; - - char **event_names[] = { - key_code_name, - key_code_name, - mouse_code_name, - mouse_code_name, - mouse_wheel_name, - mouse_move_name, - core_code_name, - }; - - b32 is_release[] = { - false, - true, - false, - true, - false, - false, - false, - }; - - for (u32 j = 0; j < ArrayCount(counts); j += 1){ - for (u32 code = 0; code < counts[j]; code += 1){ - u64 key = mapping__key(event_codes[j], code); - Table_Lookup lookup = table_lookup(&map->event_code_to_binding_list, key); - if (lookup.found_match){ - u64 val = 0; - table_read(&map->event_code_to_binding_list, lookup, &val); - Command_Binding_List *list = (Command_Binding_List*)IntAsPtr(val); - for (SNode *snode = list->first; - snode != 0; - snode = snode->next){ - Command_Modified_Binding *mod_binding = CastFromMember(Command_Modified_Binding, order_node, snode); - - Bind_Node *node = push_array_zero(arena, Bind_Node, 1); - sll_queue_push(first, last, node); - node_count += 1; - node->kind = event_codes[j]; - node->sub_code = code; - node->mods = mod_binding->mods; - node->binding = mod_binding->binding; - node->j = j; + for (i32 i = 0; i < map_count; i += 1){ + Mapping *mapping = &mapping_array[i]; + Doc_Page *page = new_doc_page(arena, cluster, page_titles[i], page_names[i]); + for (Command_Map *map = mapping->first_map; + map != 0; + map = map->next){ + char *map_name = ""; + if (map->id == global_id){ + map_name = "Global"; + } + else if (map->id == file_id){ + map_name = "File"; + } + else if (map->id == code_id){ + map_name = "Code"; + } + + Doc_Block *block = new_doc_block(arena, page, map_name); + Doc_Paragraph *par = new_doc_par_table(arena, block); + + struct Bind_Node{ + Bind_Node *next; + Input_Event_Kind kind; + u32 sub_code; + Input_Modifier_Set mods; + Command_Binding binding; + u32 j; + }; + + Bind_Node *first = 0; + Bind_Node *last = 0; + i32 node_count = 0; + + if (map->text_input_command.name != 0){ + Bind_Node *node = push_array_zero(arena, Bind_Node, 1); + sll_queue_push(first, last, node); + node_count += 1; + node->binding = map->text_input_command; + node->j = max_u32; + } + + u32 counts[] = { + KeyCode_COUNT, + KeyCode_COUNT, + MouseCode_COUNT, + MouseCode_COUNT, + 1, + 1, + CoreCode_COUNT, + }; + + u32 event_codes[] = { + InputEventKind_KeyStroke, + InputEventKind_KeyRelease, + InputEventKind_MouseButton, + InputEventKind_MouseButtonRelease, + InputEventKind_MouseWheel, + InputEventKind_MouseMove, + InputEventKind_Core, + }; + + char *mouse_wheel_name[] = {"MoveWheel"}; + char *mouse_move_name[] = {"MoveMove"}; + + char **event_names[] = { + key_code_name, + key_code_name, + mouse_code_name, + mouse_code_name, + mouse_wheel_name, + mouse_move_name, + core_code_name, + }; + + b32 is_release[] = { + false, + true, + false, + true, + false, + false, + false, + }; + + for (u32 j = 0; j < ArrayCount(counts); j += 1){ + for (u32 code = 0; code < counts[j]; code += 1){ + u64 key = mapping__key(event_codes[j], code); + Table_Lookup lookup = table_lookup(&map->event_code_to_binding_list, key); + if (lookup.found_match){ + u64 val = 0; + table_read(&map->event_code_to_binding_list, lookup, &val); + Command_Binding_List *list = (Command_Binding_List*)IntAsPtr(val); + for (SNode *snode = list->first; + snode != 0; + snode = snode->next){ + Command_Modified_Binding *mod_binding = CastFromMember(Command_Modified_Binding, order_node, snode); + + Bind_Node *node = push_array_zero(arena, Bind_Node, 1); + sll_queue_push(first, last, node); + node_count += 1; + node->kind = event_codes[j]; + node->sub_code = code; + node->mods = mod_binding->mods; + node->binding = mod_binding->binding; + node->j = j; + } } } } - } - - Vec2_i32 table_dims = V2i32(2, node_count); - Doc_Content_List *vals = push_array_zero(arena, Doc_Content_List, table_dims.x*table_dims.y); - Bind_Node *bnode = first; - for (i32 y = 0; y < table_dims.y; y += 1, bnode = bnode->next){ - Doc_Content_List *line = &vals[y*table_dims.x]; - doc_text(arena, &line[0], "["); - if (bnode->j != max_u32){ - doc_text(arena, &line[0], event_names[bnode->j][bnode->sub_code]); - if (is_release[bnode->j]){ - doc_text(arena, &line[0], "Release"); - } - - Input_Modifier_Set *mods = &bnode->mods; - for (i32 k = 0; k < mods->count; k += 1){ - doc_text(arena, &line[0], key_code_name[mods->mods[k]]); - } - } - else{ - doc_text(arena, &line[0], "TextInput"); - } - doc_text(arena, &line[0], "]"); - Doc_Content *content = doc_text(arena, &line[1], bnode->binding.name); - content->page_link = SCu8(bnode->binding.name); - } - - par->table.dim = table_dims; - par->table.vals = vals; + Vec2_i32 table_dims = V2i32(2, node_count); + Doc_Content_List *vals = push_array_zero(arena, Doc_Content_List, table_dims.x*table_dims.y); + Bind_Node *bnode = first; + for (i32 y = 0; y < table_dims.y; y += 1, bnode = bnode->next){ + Doc_Content_List *line = &vals[y*table_dims.x]; + doc_text(arena, &line[0], "["); + if (bnode->j != max_u32){ + doc_text(arena, &line[0], event_names[bnode->j][bnode->sub_code]); + if (is_release[bnode->j]){ + doc_text(arena, &line[0], "Release"); + } + + Input_Modifier_Set *mods = &bnode->mods; + for (i32 k = 0; k < mods->count; k += 1){ + doc_text(arena, &line[0], key_code_name[mods->mods[k]]); + } + } + else{ + doc_text(arena, &line[0], "TextInput"); + } + doc_text(arena, &line[0], "]"); + + Doc_Content *content = doc_text(arena, &line[1], bnode->binding.name); + content->page_link = SCu8(bnode->binding.name); + } + + par->table.dim = table_dims; + par->table.vals = vals; } + } return(cluster); } diff --git a/custom/4coder_doc_content_types.cpp b/custom/4coder_doc_content_types.cpp index 423db68b..4b4a3367 100644 --- a/custom/4coder_doc_content_types.cpp +++ b/custom/4coder_doc_content_types.cpp @@ -204,5 +204,21 @@ doc_paragraph(Arena *arena, Doc_Block *block){ par->kind = DocParagraphKind_Text; } +//////////////////////////////// + +function Doc_Page* +doc_get_page(Doc_Cluster *cluster, String_Const_u8 name){ + Doc_Page *result = 0; + for (Doc_Page *page = cluster->first_page; + page != 0; + page = page->next){ + if (string_match(name, page->name)){ + result = page; + break; + } + } + return(result); +} + // BOTTOM diff --git a/custom/4coder_docs.cpp b/custom/4coder_docs.cpp index 99a3e237..c3262b8e 100644 --- a/custom/4coder_docs.cpp +++ b/custom/4coder_docs.cpp @@ -195,8 +195,10 @@ CUSTOM_DOC("Prompts the user to select a command then loads a doc buffer for tha Scratch_Block scratch(app); Doc_Cluster *docs = doc_commands(scratch); Doc_Page *page = get_doc_page_from_user(app, docs, "Doc Page:"); - Buffer_ID buffer = render_doc_page(app, page); - view_set_buffer(app, view, buffer, 0); + if (page != 0){ + Buffer_ID buffer = render_doc_page(app, page); + view_set_buffer(app, view, buffer, 0); + } } } diff --git a/custom/4coder_draw.cpp b/custom/4coder_draw.cpp index 7ee104c6..4121ae13 100644 --- a/custom/4coder_draw.cpp +++ b/custom/4coder_draw.cpp @@ -1,843 +1,874 @@ -/* -4coder_draw.cpp - Layout and rendering implementation of standard UI pieces (including buffers) -*/ - -// TOP - -function void -draw_text_layout_default(Application_Links *app, Text_Layout_ID layout_id){ - ARGB_Color special_color = finalize_color(defcolor_special_character, 0); - ARGB_Color ghost_color = finalize_color(defcolor_ghost_character, 0); - draw_text_layout(app, layout_id, special_color, ghost_color); -} - -function FColor -get_margin_color(i32 level){ - FColor margin = fcolor_zero(); - switch (level){ - default: - case UIHighlight_None: - { - margin = fcolor_id(defcolor_list_item); - }break; - case UIHighlight_Hover: - { - margin = fcolor_id(defcolor_list_item_hover); - }break; - case UIHighlight_Active: - { - margin = fcolor_id(defcolor_list_item_active); - }break; - } - return(margin); -} - -function Vec2_f32 -draw_string(Application_Links *app, Face_ID font_id, String_Const_u8 string, Vec2_f32 p, ARGB_Color color){ - return(draw_string_oriented(app, font_id, color, string, p, 0, V2f32(1.f, 0.f))); -} - -function Vec2_f32 -draw_string(Application_Links *app, Face_ID font_id, String_Const_u8 string, Vec2_f32 p, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_string(app, font_id, string, p, argb); -} - -function void -draw_rectangle_fcolor(Application_Links *app, Rect_f32 rect, f32 roundness, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_rectangle(app, rect, roundness, argb); -} - -function void -draw_rectangle_outline_fcolor(Application_Links *app, Rect_f32 rect, f32 roundness, f32 thickness, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_rectangle_outline(app, rect, roundness, thickness, argb); -} - -function void -draw_margin(Application_Links *app, Rect_f32 outer, Rect_f32 inner, ARGB_Color color){ - draw_rectangle(app, Rf32(outer.x0, outer.y0, outer.x1, inner.y0), 0.f, color); - draw_rectangle(app, Rf32(outer.x0, inner.y1, outer.x1, outer.y1), 0.f, color); - draw_rectangle(app, Rf32(outer.x0, inner.y0, inner.x0, inner.y1), 0.f, color); - draw_rectangle(app, Rf32(inner.x1, inner.y0, outer.x1, inner.y1), 0.f, color); -} - -function void -draw_margin(Application_Links *app, Rect_f32 outer, Rect_f32 inner, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_margin(app, outer, inner, argb); -} - -function void -draw_character_block(Application_Links *app, Text_Layout_ID layout, i64 pos, f32 roundness, ARGB_Color color){ - Rect_f32 rect = text_layout_character_on_screen(app, layout, pos); - draw_rectangle(app, rect, roundness, color); -} - -function void -draw_character_block(Application_Links *app, Text_Layout_ID layout, i64 pos, f32 roundness, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_character_block(app, layout, pos, roundness, argb); -} - -function void -draw_character_block(Application_Links *app, Text_Layout_ID layout, Range_i64 range, f32 roundness, ARGB_Color color){ - if (range.first < range.one_past_last){ - i64 i = range.first; - Rect_f32 first_rect = text_layout_character_on_screen(app, layout, i); - i += 1; - Range_f32 y = rect_range_y(first_rect); - Range_f32 x = rect_range_x(first_rect); - for (;i < range.one_past_last; i += 1){ - Rect_f32 rect = text_layout_character_on_screen(app, layout, i); - if (rect.x0 < rect.x1 && rect.y0 < rect.y1){ - Range_f32 new_y = rect_range_y(rect); - Range_f32 new_x = rect_range_x(rect); - b32 joinable = false; - if (new_y == y && (range_overlap(x, new_x) || x.max == new_x.min || new_x.max == x.min)){ - joinable = true; - } - - if (!joinable){ - draw_rectangle(app, Rf32(x, y), roundness, color); - y = new_y; - x = new_x; - } - else{ - x = range_union(x, new_x); - } - } - } - draw_rectangle(app, Rf32(x, y), roundness, color); - } - for (i64 i = range.first; i < range.one_past_last; i += 1){ - draw_character_block(app, layout, i, roundness, color); - } -} - -function void -draw_character_block(Application_Links *app, Text_Layout_ID layout, Range_i64 range, f32 roundness, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_character_block(app, layout, range, roundness, argb); - } - -function void -draw_character_wire_frame(Application_Links *app, Text_Layout_ID layout, i64 pos, f32 roundness, f32 thickness, ARGB_Color color){ - Rect_f32 rect = text_layout_character_on_screen(app, layout, pos); - draw_rectangle_outline(app, rect, roundness, thickness, color); -} - -function void -draw_character_wire_frame(Application_Links *app, Text_Layout_ID layout, i64 pos, f32 roundness, f32 thickness, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_character_wire_frame(app, layout, pos, roundness, thickness, argb); -} - -function void -draw_character_wire_frame(Application_Links *app, Text_Layout_ID layout, Range_i64 range, f32 roundness, f32 thickness, FColor color){ - for (i64 i = range.first; i < range.one_past_last; i += 1){ - draw_character_wire_frame(app, layout, i, roundness, thickness, color); - } -} - -function void -draw_character_i_bar(Application_Links *app, Text_Layout_ID layout, i64 pos, ARGB_Color color){ - Rect_f32 rect = text_layout_character_on_screen(app, layout, pos); - rect.x1 = rect.x0 + 1.f; - draw_rectangle(app, rect, 0.f, color); -} - -function void -draw_character_i_bar(Application_Links *app, Text_Layout_ID layout, i64 pos, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_character_i_bar(app, layout, pos, argb); -} - -function void -draw_line_highlight(Application_Links *app, Text_Layout_ID layout, Range_i64 line_range, ARGB_Color color){ - Range_f32 y1 = text_layout_line_on_screen(app, layout, line_range.min); - Range_f32 y2 = text_layout_line_on_screen(app, layout, line_range.max); - Range_f32 y = range_union(y1, y2); - if (range_size(y) > 0.f){ - Rect_f32 region = text_layout_region(app, layout); - draw_rectangle(app, Rf32(rect_range_x(region), y), 0.f, color); - } -} - -function void -draw_line_highlight(Application_Links *app, Text_Layout_ID layout, Range_i64 line_range, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - draw_line_highlight(app, layout, line_range, argb); -} - -function void -draw_line_highlight(Application_Links *app, Text_Layout_ID layout, i64 line, ARGB_Color color){ - draw_line_highlight(app, layout, Ii64(line), color); -} - -function void -draw_line_highlight(Application_Links *app, Text_Layout_ID layout, i64 line, FColor color){ - draw_line_highlight(app, layout, Ii64(line), color); -} - -function void -paint_text_color_fcolor(Application_Links *app, Text_Layout_ID layout, Range_i64 pos, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - paint_text_color(app, layout, pos, argb); -} - -function void -paint_text_color_pos(Application_Links *app, Text_Layout_ID layout, i64 pos, ARGB_Color color){ - paint_text_color(app, layout, Ii64(pos, pos + 1), color); -} - -function void -paint_text_color_pos(Application_Links *app, Text_Layout_ID layout, i64 pos, FColor color){ - ARGB_Color argb = fcolor_resolve(color); - paint_text_color_pos(app, layout, pos, argb); -} - -//////////////////////////////// - -function Rect_f32_Pair -layout_file_bar_on_top(Rect_f32 rect, f32 line_height){ - return(rect_split_top_bottom(rect, line_height + 2.f)); -} - -function Rect_f32_Pair -layout_file_bar_on_bot(Rect_f32 rect, f32 line_height){ - return(rect_split_top_bottom_neg(rect, line_height + 2.f)); -} - -function Rect_f32_Pair -layout_query_bar_on_top(Rect_f32 rect, f32 line_height, i32 bar_count){ - return(rect_split_top_bottom(rect, (line_height + 2.f)*bar_count)); -} - -function Rect_f32_Pair -layout_query_bar_on_bot(Rect_f32 rect, f32 line_height, i32 bar_count){ - return(rect_split_top_bottom_neg(rect, (line_height + 2.f)*bar_count)); -} - -function Rect_f32_Pair -layout_line_number_margin(Rect_f32 rect, f32 digit_advance, i64 digit_count){ - f32 margin_width = (f32)digit_count*digit_advance + 2.f; - return(rect_split_left_right(rect, margin_width)); -} - -function Rect_f32_Pair -layout_line_number_margin(Application_Links *app, Buffer_ID buffer, Rect_f32 rect, f32 digit_advance){ - i64 line_count = buffer_get_line_count(app, buffer); - i64 line_count_digit_count = digit_count_from_integer(line_count, 10); - return(layout_line_number_margin(rect, digit_advance, line_count_digit_count)); -} - -global_const i32 fps_history_depth = 10; -function Rect_f32_Pair -layout_fps_hud_on_bottom(Rect_f32 rect, f32 line_height){ - return(rect_split_top_bottom_neg(rect, line_height*fps_history_depth)); -} - -function Rect_f32 -draw_background_and_margin(Application_Links *app, View_ID view, ARGB_Color margin, ARGB_Color back){ - Rect_f32 view_rect = view_get_screen_rect(app, view); - Rect_f32 inner = rect_inner(view_rect, 3.f); - draw_rectangle(app, inner, 0.f, back); - draw_margin(app, view_rect, inner, margin); - return(inner); -} - -function Rect_f32 -draw_background_and_margin(Application_Links *app, View_ID view, FColor margin, FColor back){ - ARGB_Color margin_argb = fcolor_resolve(margin); - ARGB_Color back_argb = fcolor_resolve(back); - return(draw_background_and_margin(app, view, margin_argb, back_argb)); -} - -function Rect_f32 -draw_background_and_margin(Application_Links *app, View_ID view, b32 is_active_view){ - FColor margin_color = get_margin_color(is_active_view?UIHighlight_Active:UIHighlight_None); - return(draw_background_and_margin(app, view, margin_color, fcolor_id(defcolor_back))); -} - -function Rect_f32 -draw_background_and_margin(Application_Links *app, View_ID view){ - View_ID active_view = get_active_view(app, Access_Always); - b32 is_active_view = (active_view == view); - return(draw_background_and_margin(app, view, is_active_view)); -} - -function void -draw_file_bar(Application_Links *app, View_ID view_id, Buffer_ID buffer, Face_ID face_id, Rect_f32 bar){ - Scratch_Block scratch(app); - - draw_rectangle_fcolor(app, bar, 0.f, fcolor_id(defcolor_bar)); - - FColor base_color = fcolor_id(defcolor_base); - FColor pop2_color = fcolor_id(defcolor_pop2); - - i64 cursor_position = view_get_cursor_pos(app, view_id); - Buffer_Cursor cursor = view_compute_cursor(app, view_id, seek_pos(cursor_position)); - - Fancy_Line list = {}; - String_Const_u8 unique_name = push_buffer_unique_name(app, scratch, buffer); - push_fancy_string(scratch, &list, base_color, unique_name); - push_fancy_stringf(scratch, &list, base_color, " - Row: %3.lld Col: %3.lld -", cursor.line, cursor.col); - - Managed_Scope scope = buffer_get_managed_scope(app, buffer); - Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, - Line_Ending_Kind); - switch (*eol_setting){ - case LineEndingKind_Binary: - { - push_fancy_string(scratch, &list, base_color, string_u8_litexpr(" bin")); - }break; - - case LineEndingKind_LF: - { - push_fancy_string(scratch, &list, base_color, string_u8_litexpr(" lf")); - }break; - - case LineEndingKind_CRLF: - { - push_fancy_string(scratch, &list, base_color, string_u8_litexpr(" crlf")); - }break; - } - - { - Dirty_State dirty = buffer_get_dirty_state(app, buffer); - u8 space[3]; - String_u8 str = Su8(space, 0, 3); - if (dirty != 0){ - string_append(&str, string_u8_litexpr(" ")); - } - if (HasFlag(dirty, DirtyState_UnsavedChanges)){ - string_append(&str, string_u8_litexpr("*")); - } - if (HasFlag(dirty, DirtyState_UnloadedChanges)){ - string_append(&str, string_u8_litexpr("!")); - } - push_fancy_string(scratch, &list, pop2_color, str.string); - } - - Vec2_f32 p = bar.p0 + V2f32(2.f, 2.f); - draw_fancy_line(app, face_id, fcolor_zero(), &list, p); -} - -function void -draw_query_bar(Application_Links *app, Query_Bar *query_bar, Face_ID face_id, Rect_f32 bar){ - Scratch_Block scratch(app); - Fancy_Line list = {}; - push_fancy_string(scratch, &list, fcolor_id(defcolor_pop1) , query_bar->prompt); - push_fancy_string(scratch, &list, fcolor_id(defcolor_text_default), query_bar->string); - Vec2_f32 p = bar.p0 + V2f32(2.f, 2.f); - draw_fancy_line(app, face_id, fcolor_zero(), &list, p); -} - -function void -draw_line_number_margin(Application_Links *app, View_ID view_id, Buffer_ID buffer, Face_ID face_id, Text_Layout_ID text_layout_id, Rect_f32 margin){ - Rect_f32 prev_clip = draw_set_clip(app, margin); - draw_rectangle_fcolor(app, margin, 0.f, fcolor_id(defcolor_line_numbers_back)); - - Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); - - FColor line_color = fcolor_id(defcolor_line_numbers_text); - - i64 line_count = buffer_get_line_count(app, buffer); - i64 line_count_digit_count = digit_count_from_integer(line_count, 10); - - Scratch_Block scratch(app, Scratch_Share); - - Buffer_Cursor cursor = view_compute_cursor(app, view_id, seek_pos(visible_range.first)); - i64 line_number = cursor.line; - for (;cursor.pos <= visible_range.one_past_last;){ - if (line_number > line_count){ - break; - } - Range_f32 line_y = text_layout_line_on_screen(app, text_layout_id, line_number); - Vec2_f32 p = V2f32(margin.x0, line_y.min); - Temp_Memory_Block temp(scratch); - Fancy_String *string = push_fancy_stringf(scratch, 0, line_color, - "%*lld", - line_count_digit_count, - line_number); - draw_fancy_string(app, face_id, fcolor_zero(), string, p); - line_number += 1; - } - - draw_set_clip(app, prev_clip); -} - -function void -draw_fps_hud(Application_Links *app, Frame_Info frame_info, - Face_ID face_id, Rect_f32 rect){ - Face_Metrics face_metrics = get_face_metrics(app, face_id); - f32 line_height = face_metrics.line_height; - - local_persist f32 history_literal_dt[fps_history_depth] = {}; - local_persist f32 history_animation_dt[fps_history_depth] = {}; - local_persist i32 history_frame_index[fps_history_depth] = {}; - - i32 wrapped_index = frame_info.index%fps_history_depth; - history_literal_dt[wrapped_index] = frame_info.literal_dt; - history_animation_dt[wrapped_index] = frame_info.animation_dt; - history_frame_index[wrapped_index] = frame_info.index; - - draw_rectangle_fcolor(app, rect, 0.f, f_black); - draw_rectangle_outline_fcolor(app, rect, 0.f, 1.f, f_white); - - Vec2_f32 p = rect.p0; - - Scratch_Block scratch(app); - - Range_i32 ranges[2] = {}; - ranges[0].first = wrapped_index; - ranges[0].one_past_last = -1; - ranges[1].first = fps_history_depth - 1; - ranges[1].one_past_last = wrapped_index; - for (i32 i = 0; i < 2; i += 1){ - Range_i32 r = ranges[i]; - for (i32 j = r.first; j > r.one_past_last; j -= 1, p.y += line_height){ - f32 dts[2]; - dts[0] = history_literal_dt[j]; - dts[1] = history_animation_dt[j]; - i32 frame_index = history_frame_index[j]; - - Fancy_Line list = {}; - push_fancy_stringf(scratch, &list, f_pink , "FPS: "); - push_fancy_stringf(scratch, &list, f_green, "["); - push_fancy_stringf(scratch, &list, f_white, "%5d", frame_index); - push_fancy_stringf(scratch, &list, f_green, "]: "); - - for (i32 k = 0; k < 2; k += 1){ - f32 dt = dts[k]; - if (dt == 0.f){ - push_fancy_stringf(scratch, &list, f_white, "----------"); - } - else{ - push_fancy_stringf(scratch, &list, f_white, "%10.6f", dt); - } - push_fancy_stringf(scratch, &list, f_green, " | "); - } - - draw_fancy_line(app, face_id, fcolor_zero(), &list, p); - } - } -} - -function FColor -get_token_color_cpp(Token token){ - Managed_ID color = defcolor_text_default; - switch (token.kind){ - case TokenBaseKind_Preprocessor: - { - color = defcolor_preproc; - }break; - case TokenBaseKind_Keyword: - { - color = defcolor_keyword; - }break; - case TokenBaseKind_Comment: - { - color = defcolor_comment; - }break; - case TokenBaseKind_LiteralString: - { - color = defcolor_str_constant; - }break; - case TokenBaseKind_LiteralInteger: - { - color = defcolor_int_constant; - }break; - case TokenBaseKind_LiteralFloat: - { - color = defcolor_float_constant; - }break; - default: - { - switch (token.sub_kind){ - case TokenCppKind_LiteralTrue: - case TokenCppKind_LiteralFalse: - { - color = defcolor_bool_constant; - }break; - case TokenCppKind_LiteralCharacter: - case TokenCppKind_LiteralCharacterWide: - case TokenCppKind_LiteralCharacterUTF8: - case TokenCppKind_LiteralCharacterUTF16: - case TokenCppKind_LiteralCharacterUTF32: - { - color = defcolor_char_constant; - }break; - case TokenCppKind_PPIncludeFile: - { - color = defcolor_include; - }break; - } - }break; - } - return(fcolor_id(color)); -} - -function void -draw_cpp_token_colors(Application_Links *app, Text_Layout_ID text_layout_id, Token_Array *array){ - Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); - i64 first_index = token_index_from_pos(array, visible_range.first); - Token_Iterator_Array it = token_iterator_index(0, array, first_index); - for (;;){ - Token *token = token_it_read(&it); - if (token->pos >= visible_range.one_past_last){ - break; - } - FColor color = get_token_color_cpp(*token); - ARGB_Color argb = fcolor_resolve(color); - paint_text_color(app, text_layout_id, Ii64_size(token->pos, token->size), argb); - if (!token_it_inc_all(&it)){ - break; - } - } -} - -function void -draw_comment_highlights(Application_Links *app, Buffer_ID buffer, Text_Layout_ID text_layout_id, - Token_Array *array, Comment_Highlight_Pair *pairs, i32 pair_count){ - Scratch_Block scratch(app); - Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); - i64 first_index = token_index_from_pos(array, visible_range.first); - Token_Iterator_Array it = token_iterator_index(buffer, array, first_index); - for (;;){ - Temp_Memory_Block temp(scratch); - Token *token = token_it_read(&it); - if (token->pos >= visible_range.one_past_last){ - break; - } - String_Const_u8 tail = {}; - if (token_it_check_and_get_lexeme(app, scratch, &it, TokenBaseKind_Comment, &tail)){ - for (i64 index = token->pos; - tail.size > 0; - tail = string_skip(tail, 1), index += 1){ - Comment_Highlight_Pair *pair = pairs; - for (i32 i = 0; i < pair_count; i += 1, pair += 1){ - u64 needle_size = pair->needle.size; - if (needle_size == 0){ - continue; - } - String_Const_u8 prefix = string_prefix(tail, needle_size); - if (string_match(prefix, pair->needle)){ - Range_i64 range = Ii64_size(index, needle_size); - paint_text_color(app, text_layout_id, range, pair->color); - tail = string_skip(tail, needle_size - 1); - index += needle_size - 1; - break; - } - } - } - } - if (!token_it_inc_non_whitespace(&it)){ - break; - } - } -} - -function Range_i64_Array -get_enclosure_ranges(Application_Links *app, Arena *arena, Buffer_ID buffer, i64 pos, u32 flags){ - Range_i64_Array array = {}; - i32 max = 100; - array.ranges = push_array(arena, Range_i64, max); - for (;;){ - Range_i64 range = {}; - if (find_surrounding_nest(app, buffer, pos, flags, &range)){ - array.ranges[array.count] = range; - array.count += 1; - pos = range.first; - if (array.count >= max){ - break; - } - } - else{ - break; - } - } - return(array); -} - -function void -draw_enclosures(Application_Links *app, Text_Layout_ID text_layout_id, Buffer_ID buffer, - i64 pos, u32 flags, Range_Highlight_Kind kind, - ARGB_Color *back_colors, i32 back_count, - ARGB_Color *fore_colors, i32 fore_count){ - Scratch_Block scratch(app); - Range_i64_Array ranges = get_enclosure_ranges(app, scratch, buffer, pos, flags); - - i32 color_index = 0; - for (i32 i = ranges.count - 1; i >= 0; i -= 1){ - Range_i64 range = ranges.ranges[i]; - if (kind == RangeHighlightKind_LineHighlight){ - Range_i64 r[2] = {}; - if (i > 0){ - Range_i64 inner_range = ranges.ranges[i - 1]; - Range_i64 lines = get_line_range_from_pos_range(app, buffer, range); - Range_i64 inner_lines = get_line_range_from_pos_range(app, buffer, inner_range); - inner_lines.min = clamp_bot(lines.min, inner_lines.min); - inner_lines.max = clamp_top(inner_lines.max, lines.max); - inner_lines.min -= 1; - inner_lines.max += 1; - if (lines.min <= inner_lines.min){ - r[0] = Ii64(lines.min, inner_lines.min); - } - if (inner_lines.max <= lines.max){ - r[1] = Ii64(inner_lines.max, lines.max); - } - } - else{ - r[0] = get_line_range_from_pos_range(app, buffer, range); - } - for (i32 j = 0; j < 2; j += 1){ - if (r[j].min == 0){ - continue; - } - Range_i64 line_range = r[j]; - if (back_colors != 0){ - i32 back_index = color_index%back_count; - draw_line_highlight(app, text_layout_id, line_range, back_colors[back_index]); - } - if (fore_colors != 0){ - i32 fore_index = color_index%fore_count; - Range_i64 pos_range = get_pos_range_from_line_range(app, buffer, line_range); - paint_text_color(app, text_layout_id, pos_range, fore_colors[fore_index]); - } - } - } - else{ - if (back_colors != 0){ - i32 back_index = color_index%back_count; - draw_character_block(app, text_layout_id, range.min, 0.f, back_colors[back_index]); - draw_character_block(app, text_layout_id, range.max - 1, 0.f, back_colors[back_index]); - } - if (fore_colors != 0){ - i32 fore_index = color_index%fore_count; - paint_text_color_pos(app, text_layout_id, range.min, fore_colors[fore_index]); - paint_text_color_pos(app, text_layout_id, range.max - 1, fore_colors[fore_index]); - } - } - color_index += 1; - } -} - -function void -draw_scope_highlight(Application_Links *app, Buffer_ID buffer, Text_Layout_ID text_layout_id, - i64 pos, ARGB_Color *colors, i32 color_count){ - draw_enclosures(app, text_layout_id, buffer, - pos, FindNest_Scope, RangeHighlightKind_LineHighlight, - colors, color_count, 0, 0); -} - -function void -draw_paren_highlight(Application_Links *app, Buffer_ID buffer, Text_Layout_ID text_layout_id, - i64 pos, ARGB_Color *colors, i32 color_count){ - Token_Array token_array = get_token_array_from_buffer(app, buffer); - if (token_array.tokens != 0){ - Token_Iterator_Array it = token_iterator_pos(0, &token_array, pos); - Token *token = token_it_read(&it); - if (token != 0 && token->kind == TokenBaseKind_ParentheticalOpen){ - pos = token->pos + token->size; - } - else{ - if (token_it_dec_all(&it)){ - token = token_it_read(&it); - if (token->kind == TokenBaseKind_ParentheticalClose && - pos == token->pos + token->size){ - pos = token->pos; - } - } - } - } - draw_enclosures(app, text_layout_id, buffer, - pos, FindNest_Paren, RangeHighlightKind_CharacterHighlight, - 0, 0, colors, color_count); -} - -function void -draw_jump_highlights(Application_Links *app, Buffer_ID buffer, Text_Layout_ID text_layout_id, - Buffer_ID jump_buffer, FColor line_color){ - Scratch_Block scratch(app); - if (jump_buffer != 0){ - Managed_Scope scopes[2]; - scopes[0] = buffer_get_managed_scope(app, jump_buffer); - scopes[1] = buffer_get_managed_scope(app, buffer); - Managed_Scope comp_scope = get_managed_scope_with_multiple_dependencies(app, scopes, ArrayCount(scopes)); - Managed_Object *markers_object = scope_attachment(app, comp_scope, sticky_jump_marker_handle, Managed_Object); - - i32 count = managed_object_get_item_count(app, *markers_object); - Marker *markers = push_array(scratch, Marker, count); - managed_object_load_data(app, *markers_object, 0, count, markers); - for (i32 i = 0; i < count; i += 1){ - i64 line_number = get_line_number_from_pos(app, buffer, markers[i].pos); - draw_line_highlight(app, text_layout_id, line_number, line_color); - } - } -} - -function b32 -draw_highlight_range(Application_Links *app, View_ID view_id, - Buffer_ID buffer, Text_Layout_ID text_layout_id, - f32 roundness){ - b32 has_highlight_range = false; - Managed_Scope scope = view_get_managed_scope(app, view_id); - Buffer_ID *highlight_buffer = scope_attachment(app, scope, view_highlight_buffer, Buffer_ID); - if (*highlight_buffer != 0){ - if (*highlight_buffer != buffer){ - view_disable_highlight_range(app, view_id); - } - else{ - has_highlight_range = true; - Managed_Object *highlight = scope_attachment(app, scope, view_highlight_range, Managed_Object); - Marker marker_range[2]; - if (managed_object_load_data(app, *highlight, 0, 2, marker_range)){ - Range_i64 range = Ii64(marker_range[0].pos, marker_range[1].pos); - draw_character_block(app, text_layout_id, range, roundness, - fcolor_id(defcolor_highlight)); - paint_text_color_fcolor(app, text_layout_id, range, - fcolor_id(defcolor_at_highlight)); - } - } - } - return(has_highlight_range); -} - -function void -draw_original_4coder_style_cursor_mark_highlight(Application_Links *app, View_ID view_id, b32 is_active_view, - Buffer_ID buffer, Text_Layout_ID text_layout_id, - f32 roundness, f32 outline_thickness){ - b32 has_highlight_range = draw_highlight_range(app, view_id, buffer, text_layout_id, roundness); - if (!has_highlight_range){ - i64 cursor_pos = view_get_cursor_pos(app, view_id); - i64 mark_pos = view_get_mark_pos(app, view_id); - if (is_active_view){ - draw_character_block(app, text_layout_id, cursor_pos, roundness, - fcolor_id(defcolor_cursor)); - paint_text_color_pos(app, text_layout_id, cursor_pos, - fcolor_id(defcolor_at_cursor)); - draw_character_wire_frame(app, text_layout_id, mark_pos, - roundness, outline_thickness, - fcolor_id(defcolor_mark)); - } - else{ - draw_character_wire_frame(app, text_layout_id, mark_pos, - roundness, outline_thickness, - fcolor_id(defcolor_mark)); - draw_character_wire_frame(app, text_layout_id, cursor_pos, - roundness, outline_thickness, - fcolor_id(defcolor_cursor)); - } - } -} - -function void -draw_notepad_style_cursor_highlight(Application_Links *app, View_ID view_id, - Buffer_ID buffer, Text_Layout_ID text_layout_id, - f32 roundness){ - b32 has_highlight_range = draw_highlight_range(app, view_id, buffer, text_layout_id, roundness); - if (!has_highlight_range){ - i64 cursor_pos = view_get_cursor_pos(app, view_id); - i64 mark_pos = view_get_mark_pos(app, view_id); - if (cursor_pos != mark_pos){ - Range_i64 range = Ii64(cursor_pos, mark_pos); - draw_character_block(app, text_layout_id, range, roundness, - fcolor_id(defcolor_highlight)); - paint_text_color_fcolor(app, text_layout_id, range, - fcolor_id(defcolor_at_highlight)); - } - draw_character_i_bar(app, text_layout_id, cursor_pos, fcolor_id(defcolor_cursor)); - } -} - -//////////////////////////////// - -function Rect_f32 -get_contained_box_near_point(Rect_f32 container, Vec2_f32 p, Vec2_f32 box_dims){ - Vec2_f32 container_dims = rect_dim(container); - box_dims.x = clamp_top(box_dims.x, container_dims.x); - box_dims.y = clamp_top(box_dims.y, container_dims.y); - Vec2_f32 q = p + V2f32(-20.f, 22.f); - if (q.x + box_dims.x > container.x1){ - q.x = container.x1 - box_dims.x; - } - if (q.y + box_dims.y > container.y1){ - q.y = p.y - box_dims.y - 2.f; - if (q.y < container.y0){ - q.y = (container.y0 + container.y1 - box_dims.y)*0.5f; - } - } - return(Rf32_xy_wh(q, box_dims)); -} - -function Rect_f32 -draw_tool_tip(Application_Links *app, Face_ID face, Fancy_Block *block, - Vec2_f32 p, Rect_f32 region, f32 x_padding, f32 x_half_padding, - FColor back_color){ - Rect_f32 box = Rf32(p, p); - if (block->line_count > 0){ - Vec2_f32 dims = get_fancy_block_dim(app, face, block); - dims += V2f32(x_padding, 2.f); - box = get_contained_box_near_point(region, p, dims); - box.x0 = f32_round32(box.x0); - box.y0 = f32_round32(box.y0); - box.x1 = f32_round32(box.x1); - box.y1 = f32_round32(box.y1); - Rect_f32 prev_clip = draw_set_clip(app, box); - draw_rectangle_fcolor(app, box, 6.f, back_color); - draw_fancy_block(app, face, fcolor_zero(), block, - box.p0 + V2f32(x_half_padding, 1.f)); - draw_set_clip(app, prev_clip); - } - return(box); -} - -function Rect_f32 -draw_drop_down(Application_Links *app, Face_ID face, Fancy_Block *block, - Vec2_f32 p, Rect_f32 region, f32 x_padding, f32 x_half_padding, - FColor outline_color, FColor back_color){ - Rect_f32 box = Rf32(p, p); - if (block->line_count > 0){ - Vec2_f32 dims = get_fancy_block_dim(app, face, block); - dims += V2f32(x_padding, 4.f); - box = get_contained_box_near_point(region, p, dims); - box.x0 = f32_round32(box.x0); - box.y0 = f32_round32(box.y0); - box.x1 = f32_round32(box.x1); - box.y1 = f32_round32(box.y1); - Rect_f32 prev_clip = draw_set_clip(app, box); - draw_rectangle_fcolor(app, box, 0.f, back_color); - draw_margin(app, box, rect_inner(box, 1.f), outline_color); - draw_fancy_block(app, face, fcolor_zero(), block, - box.p0 + V2f32(x_half_padding, 2.f)); - draw_set_clip(app, prev_clip); - } - return(box); -} - -function b32 -draw_button(Application_Links *app, Rect_f32 rect, Vec2_f32 mouse_p, Face_ID face, String_Const_u8 text){ - b32 hovered = false; - if (rect_contains_point(rect, mouse_p)){ - hovered = true; - } - - FColor margin_color = get_margin_color(hovered?UIHighlight_Active:UIHighlight_None); - draw_rectangle_fcolor(app, rect, 3.f, margin_color); - rect = rect_inner(rect, 3.f); - draw_rectangle_fcolor(app, rect, 3.f, fcolor_id(defcolor_back)); - - Scratch_Block scratch(app); - Fancy_String *fancy = push_fancy_string(scratch, 0, face, fcolor_id(defcolor_text_default), text); - Vec2_f32 dim = get_fancy_string_dim(app, 0, fancy); - Vec2_f32 p = (rect.p0 + rect.p1 - dim)*0.5f; - draw_fancy_string(app, fancy, p); - - return(hovered); -} - -// BOTTOM - +/* +4coder_draw.cpp - Layout and rendering implementation of standard UI pieces (including buffers) +*/ + +// TOP + +function void +draw_text_layout_default(Application_Links *app, Text_Layout_ID layout_id){ + ARGB_Color special_color = finalize_color(defcolor_special_character, 0); + ARGB_Color ghost_color = finalize_color(defcolor_ghost_character, 0); + draw_text_layout(app, layout_id, special_color, ghost_color); +} + +function FColor +get_item_margin_color(i32 level, i32 sub_id){ + FColor margin = fcolor_zero(); + switch (level){ + default: + case UIHighlight_None: + { + margin = fcolor_id(defcolor_list_item, sub_id); + }break; + case UIHighlight_Hover: + { + margin = fcolor_id(defcolor_list_item_hover, sub_id); + }break; + case UIHighlight_Active: + { + margin = fcolor_id(defcolor_list_item_active, sub_id); + }break; + } + return(margin); +} +function FColor +get_item_margin_color(i32 level){ + return(get_item_margin_color(level, 0)); +} +function FColor +get_panel_margin_color(i32 level){ + FColor margin = fcolor_zero(); + switch (level){ + default: + case UIHighlight_None: + { + margin = fcolor_id(defcolor_margin); + }break; + case UIHighlight_Hover: + { + margin = fcolor_id(defcolor_margin_hover); + }break; + case UIHighlight_Active: + { + margin = fcolor_id(defcolor_margin_active); + }break; + } + return(margin); +} + +function Vec2_f32 +draw_string(Application_Links *app, Face_ID font_id, String_Const_u8 string, Vec2_f32 p, ARGB_Color color){ + return(draw_string_oriented(app, font_id, color, string, p, 0, V2f32(1.f, 0.f))); +} + +function Vec2_f32 +draw_string(Application_Links *app, Face_ID font_id, String_Const_u8 string, Vec2_f32 p, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + return(draw_string(app, font_id, string, p, argb)); +} + +function void +draw_rectangle_fcolor(Application_Links *app, Rect_f32 rect, f32 roundness, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + draw_rectangle(app, rect, roundness, argb); +} + +function void +draw_rectangle_outline_fcolor(Application_Links *app, Rect_f32 rect, f32 roundness, f32 thickness, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + draw_rectangle_outline(app, rect, roundness, thickness, argb); +} + +function void +draw_margin(Application_Links *app, Rect_f32 outer, Rect_f32 inner, ARGB_Color color){ + draw_rectangle(app, Rf32(outer.x0, outer.y0, outer.x1, inner.y0), 0.f, color); + draw_rectangle(app, Rf32(outer.x0, inner.y1, outer.x1, outer.y1), 0.f, color); + draw_rectangle(app, Rf32(outer.x0, inner.y0, inner.x0, inner.y1), 0.f, color); + draw_rectangle(app, Rf32(inner.x1, inner.y0, outer.x1, inner.y1), 0.f, color); +} + +function void +draw_margin(Application_Links *app, Rect_f32 outer, Rect_f32 inner, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + draw_margin(app, outer, inner, argb); +} + +function void +draw_character_block(Application_Links *app, Text_Layout_ID layout, i64 pos, f32 roundness, ARGB_Color color){ + Rect_f32 rect = text_layout_character_on_screen(app, layout, pos); + draw_rectangle(app, rect, roundness, color); +} + +function void +draw_character_block(Application_Links *app, Text_Layout_ID layout, i64 pos, f32 roundness, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + draw_character_block(app, layout, pos, roundness, argb); +} + +function void +draw_character_block(Application_Links *app, Text_Layout_ID layout, Range_i64 range, f32 roundness, ARGB_Color color){ + if (range.first < range.one_past_last){ + i64 i = range.first; + Rect_f32 first_rect = text_layout_character_on_screen(app, layout, i); + i += 1; + Range_f32 y = rect_range_y(first_rect); + Range_f32 x = rect_range_x(first_rect); + for (;i < range.one_past_last; i += 1){ + Rect_f32 rect = text_layout_character_on_screen(app, layout, i); + if (rect.x0 < rect.x1 && rect.y0 < rect.y1){ + Range_f32 new_y = rect_range_y(rect); + Range_f32 new_x = rect_range_x(rect); + b32 joinable = false; + if (new_y == y && (range_overlap(x, new_x) || x.max == new_x.min || new_x.max == x.min)){ + joinable = true; + } + + if (!joinable){ + draw_rectangle(app, Rf32(x, y), roundness, color); + y = new_y; + x = new_x; + } + else{ + x = range_union(x, new_x); + } + } + } + draw_rectangle(app, Rf32(x, y), roundness, color); + } +} + +function void +draw_character_block(Application_Links *app, Text_Layout_ID layout, Range_i64 range, f32 roundness, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + draw_character_block(app, layout, range, roundness, argb); +} + +function void +draw_character_wire_frame(Application_Links *app, Text_Layout_ID layout, i64 pos, f32 roundness, f32 thickness, ARGB_Color color){ + Rect_f32 rect = text_layout_character_on_screen(app, layout, pos); + draw_rectangle_outline(app, rect, roundness, thickness, color); +} + +function void +draw_character_wire_frame(Application_Links *app, Text_Layout_ID layout, i64 pos, f32 roundness, f32 thickness, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + draw_character_wire_frame(app, layout, pos, roundness, thickness, argb); +} + +function void +draw_character_wire_frame(Application_Links *app, Text_Layout_ID layout, Range_i64 range, f32 roundness, f32 thickness, FColor color){ + for (i64 i = range.first; i < range.one_past_last; i += 1){ + draw_character_wire_frame(app, layout, i, roundness, thickness, color); + } +} + +function void +draw_character_i_bar(Application_Links *app, Text_Layout_ID layout, i64 pos, ARGB_Color color){ + Rect_f32 rect = text_layout_character_on_screen(app, layout, pos); + rect.x1 = rect.x0 + 1.f; + draw_rectangle(app, rect, 0.f, color); +} + +function void +draw_character_i_bar(Application_Links *app, Text_Layout_ID layout, i64 pos, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + draw_character_i_bar(app, layout, pos, argb); +} + +function void +draw_line_highlight(Application_Links *app, Text_Layout_ID layout, Range_i64 line_range, ARGB_Color color){ + Range_f32 y1 = text_layout_line_on_screen(app, layout, line_range.min); + Range_f32 y2 = text_layout_line_on_screen(app, layout, line_range.max); + Range_f32 y = range_union(y1, y2); + if (range_size(y) > 0.f){ + Rect_f32 region = text_layout_region(app, layout); + draw_rectangle(app, Rf32(rect_range_x(region), y), 0.f, color); + } +} + +function void +draw_line_highlight(Application_Links *app, Text_Layout_ID layout, Range_i64 line_range, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + draw_line_highlight(app, layout, line_range, argb); +} + +function void +draw_line_highlight(Application_Links *app, Text_Layout_ID layout, i64 line, ARGB_Color color){ + draw_line_highlight(app, layout, Ii64(line), color); +} + +function void +draw_line_highlight(Application_Links *app, Text_Layout_ID layout, i64 line, FColor color){ + draw_line_highlight(app, layout, Ii64(line), color); +} + +function void +paint_text_color_fcolor(Application_Links *app, Text_Layout_ID layout, Range_i64 pos, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + paint_text_color(app, layout, pos, argb); +} + +function void +paint_text_color_pos(Application_Links *app, Text_Layout_ID layout, i64 pos, ARGB_Color color){ + paint_text_color(app, layout, Ii64(pos, pos + 1), color); +} + +function void +paint_text_color_pos(Application_Links *app, Text_Layout_ID layout, i64 pos, FColor color){ + ARGB_Color argb = fcolor_resolve(color); + paint_text_color_pos(app, layout, pos, argb); +} + +//////////////////////////////// + +function Rect_f32_Pair +layout_file_bar_on_top(Rect_f32 rect, f32 line_height){ + return(rect_split_top_bottom(rect, line_height + 2.f)); +} + +function Rect_f32_Pair +layout_file_bar_on_bot(Rect_f32 rect, f32 line_height){ + return(rect_split_top_bottom_neg(rect, line_height + 2.f)); +} + +function Rect_f32_Pair +layout_query_bar_on_top(Rect_f32 rect, f32 line_height, i32 bar_count){ + return(rect_split_top_bottom(rect, (line_height + 2.f)*bar_count)); +} + +function Rect_f32_Pair +layout_query_bar_on_bot(Rect_f32 rect, f32 line_height, i32 bar_count){ + return(rect_split_top_bottom_neg(rect, (line_height + 2.f)*bar_count)); +} + +function Rect_f32_Pair +layout_line_number_margin(Rect_f32 rect, f32 digit_advance, i64 digit_count){ + f32 margin_width = (f32)digit_count*digit_advance + 2.f; + return(rect_split_left_right(rect, margin_width)); +} + +function Rect_f32_Pair +layout_line_number_margin(Application_Links *app, Buffer_ID buffer, Rect_f32 rect, f32 digit_advance){ + i64 line_count = buffer_get_line_count(app, buffer); + i64 line_count_digit_count = digit_count_from_integer(line_count, 10); + return(layout_line_number_margin(rect, digit_advance, line_count_digit_count)); +} + +global_const i32 fps_history_depth = 10; +function Rect_f32_Pair +layout_fps_hud_on_bottom(Rect_f32 rect, f32 line_height){ + return(rect_split_top_bottom_neg(rect, line_height*fps_history_depth)); +} + +function Rect_f32 +draw_background_and_margin(Application_Links *app, View_ID view, ARGB_Color margin, ARGB_Color back){ + Rect_f32 view_rect = view_get_screen_rect(app, view); + Rect_f32 inner = rect_inner(view_rect, 3.f); + draw_rectangle(app, inner, 0.f, back); + draw_margin(app, view_rect, inner, margin); + return(inner); +} + +function Rect_f32 +draw_background_and_margin(Application_Links *app, View_ID view, FColor margin, FColor back){ + ARGB_Color margin_argb = fcolor_resolve(margin); + ARGB_Color back_argb = fcolor_resolve(back); + return(draw_background_and_margin(app, view, margin_argb, back_argb)); +} + +function Rect_f32 +draw_background_and_margin(Application_Links *app, View_ID view, b32 is_active_view){ + FColor margin_color = get_panel_margin_color(is_active_view?UIHighlight_Active:UIHighlight_None); + return(draw_background_and_margin(app, view, margin_color, fcolor_id(defcolor_back))); +} + +function Rect_f32 +draw_background_and_margin(Application_Links *app, View_ID view){ + View_ID active_view = get_active_view(app, Access_Always); + b32 is_active_view = (active_view == view); + return(draw_background_and_margin(app, view, is_active_view)); +} + +function void +draw_file_bar(Application_Links *app, View_ID view_id, Buffer_ID buffer, Face_ID face_id, Rect_f32 bar){ + Scratch_Block scratch(app); + + draw_rectangle_fcolor(app, bar, 0.f, fcolor_id(defcolor_bar)); + + FColor base_color = fcolor_id(defcolor_base); + FColor pop2_color = fcolor_id(defcolor_pop2); + + i64 cursor_position = view_get_cursor_pos(app, view_id); + Buffer_Cursor cursor = view_compute_cursor(app, view_id, seek_pos(cursor_position)); + + Fancy_Line list = {}; + String_Const_u8 unique_name = push_buffer_unique_name(app, scratch, buffer); + push_fancy_string(scratch, &list, base_color, unique_name); + push_fancy_stringf(scratch, &list, base_color, " - Row: %3.lld Col: %3.lld -", cursor.line, cursor.col); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, + Line_Ending_Kind); + switch (*eol_setting){ + case LineEndingKind_Binary: + { + push_fancy_string(scratch, &list, base_color, string_u8_litexpr(" bin")); + }break; + + case LineEndingKind_LF: + { + push_fancy_string(scratch, &list, base_color, string_u8_litexpr(" lf")); + }break; + + case LineEndingKind_CRLF: + { + push_fancy_string(scratch, &list, base_color, string_u8_litexpr(" crlf")); + }break; + } + + u8 space[3]; + { + Dirty_State dirty = buffer_get_dirty_state(app, buffer); + String_u8 str = Su8(space, 0, 3); + if (dirty != 0){ + string_append(&str, string_u8_litexpr(" ")); + } + if (HasFlag(dirty, DirtyState_UnsavedChanges)){ + string_append(&str, string_u8_litexpr("*")); + } + if (HasFlag(dirty, DirtyState_UnloadedChanges)){ + string_append(&str, string_u8_litexpr("!")); + } + push_fancy_string(scratch, &list, pop2_color, str.string); + } + + Vec2_f32 p = bar.p0 + V2f32(2.f, 2.f); + draw_fancy_line(app, face_id, fcolor_zero(), &list, p); +} + +function void +draw_query_bar(Application_Links *app, Query_Bar *query_bar, Face_ID face_id, Rect_f32 bar){ + Scratch_Block scratch(app); + Fancy_Line list = {}; + push_fancy_string(scratch, &list, fcolor_id(defcolor_pop1) , query_bar->prompt); + push_fancy_string(scratch, &list, fcolor_id(defcolor_text_default), query_bar->string); + Vec2_f32 p = bar.p0 + V2f32(2.f, 2.f); + draw_fancy_line(app, face_id, fcolor_zero(), &list, p); +} + +function void +draw_line_number_margin(Application_Links *app, View_ID view_id, Buffer_ID buffer, Face_ID face_id, Text_Layout_ID text_layout_id, Rect_f32 margin){ + Rect_f32 prev_clip = draw_set_clip(app, margin); + draw_rectangle_fcolor(app, margin, 0.f, fcolor_id(defcolor_line_numbers_back)); + + Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); + + FColor line_color = fcolor_id(defcolor_line_numbers_text); + + i64 line_count = buffer_get_line_count(app, buffer); + i64 line_count_digit_count = digit_count_from_integer(line_count, 10); + + Scratch_Block scratch(app, Scratch_Share); + + Buffer_Cursor cursor = view_compute_cursor(app, view_id, seek_pos(visible_range.first)); + i64 line_number = cursor.line; + for (;cursor.pos <= visible_range.one_past_last;){ + if (line_number > line_count){ + break; + } + Range_f32 line_y = text_layout_line_on_screen(app, text_layout_id, line_number); + Vec2_f32 p = V2f32(margin.x0, line_y.min); + Temp_Memory_Block temp(scratch); + Fancy_String *string = push_fancy_stringf(scratch, 0, line_color, + "%*lld", + line_count_digit_count, + line_number); + draw_fancy_string(app, face_id, fcolor_zero(), string, p); + line_number += 1; + } + + draw_set_clip(app, prev_clip); +} + +function void +draw_fps_hud(Application_Links *app, Frame_Info frame_info, + Face_ID face_id, Rect_f32 rect){ + Face_Metrics face_metrics = get_face_metrics(app, face_id); + f32 line_height = face_metrics.line_height; + + local_persist f32 history_literal_dt[fps_history_depth] = {}; + local_persist f32 history_animation_dt[fps_history_depth] = {}; + local_persist i32 history_frame_index[fps_history_depth] = {}; + + i32 wrapped_index = frame_info.index%fps_history_depth; + history_literal_dt[wrapped_index] = frame_info.literal_dt; + history_animation_dt[wrapped_index] = frame_info.animation_dt; + history_frame_index[wrapped_index] = frame_info.index; + + draw_rectangle_fcolor(app, rect, 0.f, f_black); + draw_rectangle_outline_fcolor(app, rect, 0.f, 1.f, f_white); + + Vec2_f32 p = rect.p0; + + Scratch_Block scratch(app); + + Range_i32 ranges[2] = {}; + ranges[0].first = wrapped_index; + ranges[0].one_past_last = -1; + ranges[1].first = fps_history_depth - 1; + ranges[1].one_past_last = wrapped_index; + for (i32 i = 0; i < 2; i += 1){ + Range_i32 r = ranges[i]; + for (i32 j = r.first; j > r.one_past_last; j -= 1, p.y += line_height){ + f32 dts[2]; + dts[0] = history_literal_dt[j]; + dts[1] = history_animation_dt[j]; + i32 frame_index = history_frame_index[j]; + + Fancy_Line list = {}; + push_fancy_stringf(scratch, &list, f_pink , "FPS: "); + push_fancy_stringf(scratch, &list, f_green, "["); + push_fancy_stringf(scratch, &list, f_white, "%5d", frame_index); + push_fancy_stringf(scratch, &list, f_green, "]: "); + + for (i32 k = 0; k < 2; k += 1){ + f32 dt = dts[k]; + if (dt == 0.f){ + push_fancy_stringf(scratch, &list, f_white, "----------"); + } + else{ + push_fancy_stringf(scratch, &list, f_white, "%10.6f", dt); + } + push_fancy_stringf(scratch, &list, f_green, " | "); + } + + draw_fancy_line(app, face_id, fcolor_zero(), &list, p); + } + } +} + +function FColor +get_token_color_cpp(Token token){ + Managed_ID color = defcolor_text_default; + switch (token.kind){ + case TokenBaseKind_Preprocessor: + { + color = defcolor_preproc; + }break; + case TokenBaseKind_Keyword: + { + color = defcolor_keyword; + }break; + case TokenBaseKind_Comment: + { + color = defcolor_comment; + }break; + case TokenBaseKind_LiteralString: + { + color = defcolor_str_constant; + }break; + case TokenBaseKind_LiteralInteger: + { + color = defcolor_int_constant; + }break; + case TokenBaseKind_LiteralFloat: + { + color = defcolor_float_constant; + }break; + default: + { + switch (token.sub_kind){ + case TokenCppKind_LiteralTrue: + case TokenCppKind_LiteralFalse: + { + color = defcolor_bool_constant; + }break; + case TokenCppKind_LiteralCharacter: + case TokenCppKind_LiteralCharacterWide: + case TokenCppKind_LiteralCharacterUTF8: + case TokenCppKind_LiteralCharacterUTF16: + case TokenCppKind_LiteralCharacterUTF32: + { + color = defcolor_char_constant; + }break; + case TokenCppKind_PPIncludeFile: + { + color = defcolor_include; + }break; + } + }break; + } + return(fcolor_id(color)); +} + +function void +draw_cpp_token_colors(Application_Links *app, Text_Layout_ID text_layout_id, Token_Array *array){ + Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); + i64 first_index = token_index_from_pos(array, visible_range.first); + Token_Iterator_Array it = token_iterator_index(0, array, first_index); + for (;;){ + Token *token = token_it_read(&it); + if (token->pos >= visible_range.one_past_last){ + break; + } + FColor color = get_token_color_cpp(*token); + ARGB_Color argb = fcolor_resolve(color); + paint_text_color(app, text_layout_id, Ii64_size(token->pos, token->size), argb); + if (!token_it_inc_all(&it)){ + break; + } + } +} + +function void +draw_comment_highlights(Application_Links *app, Buffer_ID buffer, Text_Layout_ID text_layout_id, + Token_Array *array, Comment_Highlight_Pair *pairs, i32 pair_count){ + Scratch_Block scratch(app); + Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); + i64 first_index = token_index_from_pos(array, visible_range.first); + Token_Iterator_Array it = token_iterator_index(buffer, array, first_index); + for (;;){ + Temp_Memory_Block temp(scratch); + Token *token = token_it_read(&it); + if (token->pos >= visible_range.one_past_last){ + break; + } + String_Const_u8 tail = {}; + if (token_it_check_and_get_lexeme(app, scratch, &it, TokenBaseKind_Comment, &tail)){ + for (i64 index = token->pos; + tail.size > 0; + tail = string_skip(tail, 1), index += 1){ + Comment_Highlight_Pair *pair = pairs; + for (i32 i = 0; i < pair_count; i += 1, pair += 1){ + u64 needle_size = pair->needle.size; + if (needle_size == 0){ + continue; + } + String_Const_u8 prefix = string_prefix(tail, needle_size); + if (string_match(prefix, pair->needle)){ + Range_i64 range = Ii64_size(index, needle_size); + paint_text_color(app, text_layout_id, range, pair->color); + tail = string_skip(tail, needle_size - 1); + index += needle_size - 1; + break; + } + } + } + } + if (!token_it_inc_non_whitespace(&it)){ + break; + } + } +} + +function Range_i64_Array +get_enclosure_ranges(Application_Links *app, Arena *arena, Buffer_ID buffer, i64 pos, u32 flags){ + Range_i64_Array array = {}; + i32 max = 100; + array.ranges = push_array(arena, Range_i64, max); + for (;;){ + Range_i64 range = {}; + if (find_surrounding_nest(app, buffer, pos, flags, &range)){ + array.ranges[array.count] = range; + array.count += 1; + pos = range.first; + if (array.count >= max){ + break; + } + } + else{ + break; + } + } + return(array); +} + +function void +draw_enclosures(Application_Links *app, Text_Layout_ID text_layout_id, Buffer_ID buffer, + i64 pos, u32 flags, Range_Highlight_Kind kind, + ARGB_Color *back_colors, i32 back_count, + ARGB_Color *fore_colors, i32 fore_count){ + Scratch_Block scratch(app); + Range_i64_Array ranges = get_enclosure_ranges(app, scratch, buffer, pos, flags); + + i32 color_index = 0; + for (i32 i = ranges.count - 1; i >= 0; i -= 1){ + Range_i64 range = ranges.ranges[i]; + if (kind == RangeHighlightKind_LineHighlight){ + Range_i64 r[2] = {}; + if (i > 0){ + Range_i64 inner_range = ranges.ranges[i - 1]; + Range_i64 lines = get_line_range_from_pos_range(app, buffer, range); + Range_i64 inner_lines = get_line_range_from_pos_range(app, buffer, inner_range); + inner_lines.min = clamp_bot(lines.min, inner_lines.min); + inner_lines.max = clamp_top(inner_lines.max, lines.max); + inner_lines.min -= 1; + inner_lines.max += 1; + if (lines.min <= inner_lines.min){ + r[0] = Ii64(lines.min, inner_lines.min); + } + if (inner_lines.max <= lines.max){ + r[1] = Ii64(inner_lines.max, lines.max); + } + } + else{ + r[0] = get_line_range_from_pos_range(app, buffer, range); + } + for (i32 j = 0; j < 2; j += 1){ + if (r[j].min == 0){ + continue; + } + Range_i64 line_range = r[j]; + if (back_colors != 0){ + i32 back_index = color_index%back_count; + draw_line_highlight(app, text_layout_id, line_range, back_colors[back_index]); + } + if (fore_colors != 0){ + i32 fore_index = color_index%fore_count; + Range_i64 pos_range = get_pos_range_from_line_range(app, buffer, line_range); + paint_text_color(app, text_layout_id, pos_range, fore_colors[fore_index]); + } + } + } + else{ + if (back_colors != 0){ + i32 back_index = color_index%back_count; + draw_character_block(app, text_layout_id, range.min, 0.f, back_colors[back_index]); + draw_character_block(app, text_layout_id, range.max - 1, 0.f, back_colors[back_index]); + } + if (fore_colors != 0){ + i32 fore_index = color_index%fore_count; + paint_text_color_pos(app, text_layout_id, range.min, fore_colors[fore_index]); + paint_text_color_pos(app, text_layout_id, range.max - 1, fore_colors[fore_index]); + } + } + color_index += 1; + } +} + +function void +draw_scope_highlight(Application_Links *app, Buffer_ID buffer, Text_Layout_ID text_layout_id, + i64 pos, ARGB_Color *colors, i32 color_count){ + draw_enclosures(app, text_layout_id, buffer, + pos, FindNest_Scope, RangeHighlightKind_LineHighlight, + colors, color_count, 0, 0); +} + +function void +draw_paren_highlight(Application_Links *app, Buffer_ID buffer, Text_Layout_ID text_layout_id, + i64 pos, ARGB_Color *colors, i32 color_count){ + Token_Array token_array = get_token_array_from_buffer(app, buffer); + if (token_array.tokens != 0){ + Token_Iterator_Array it = token_iterator_pos(0, &token_array, pos); + Token *token = token_it_read(&it); + if (token != 0 && token->kind == TokenBaseKind_ParentheticalOpen){ + pos = token->pos + token->size; + } + else{ + if (token_it_dec_all(&it)){ + token = token_it_read(&it); + if (token->kind == TokenBaseKind_ParentheticalClose && + pos == token->pos + token->size){ + pos = token->pos; + } + } + } + } + draw_enclosures(app, text_layout_id, buffer, + pos, FindNest_Paren, RangeHighlightKind_CharacterHighlight, + 0, 0, colors, color_count); +} + +function void +draw_jump_highlights(Application_Links *app, Buffer_ID buffer, Text_Layout_ID text_layout_id, + Buffer_ID jump_buffer, FColor line_color){ + Scratch_Block scratch(app); + if (jump_buffer != 0){ + Managed_Scope scopes[2]; + scopes[0] = buffer_get_managed_scope(app, jump_buffer); + scopes[1] = buffer_get_managed_scope(app, buffer); + Managed_Scope comp_scope = get_managed_scope_with_multiple_dependencies(app, scopes, ArrayCount(scopes)); + Managed_Object *markers_object = scope_attachment(app, comp_scope, sticky_jump_marker_handle, Managed_Object); + + i32 count = managed_object_get_item_count(app, *markers_object); + Marker *markers = push_array(scratch, Marker, count); + managed_object_load_data(app, *markers_object, 0, count, markers); + for (i32 i = 0; i < count; i += 1){ + i64 line_number = get_line_number_from_pos(app, buffer, markers[i].pos); + draw_line_highlight(app, text_layout_id, line_number, line_color); + } + } +} + +function b32 +draw_highlight_range(Application_Links *app, View_ID view_id, + Buffer_ID buffer, Text_Layout_ID text_layout_id, + f32 roundness){ + b32 has_highlight_range = false; + Managed_Scope scope = view_get_managed_scope(app, view_id); + Buffer_ID *highlight_buffer = scope_attachment(app, scope, view_highlight_buffer, Buffer_ID); + if (*highlight_buffer != 0){ + if (*highlight_buffer != buffer){ + view_disable_highlight_range(app, view_id); + } + else{ + has_highlight_range = true; + Managed_Object *highlight = scope_attachment(app, scope, view_highlight_range, Managed_Object); + Marker marker_range[2]; + if (managed_object_load_data(app, *highlight, 0, 2, marker_range)){ + Range_i64 range = Ii64(marker_range[0].pos, marker_range[1].pos); + draw_character_block(app, text_layout_id, range, roundness, + fcolor_id(defcolor_highlight)); + paint_text_color_fcolor(app, text_layout_id, range, + fcolor_id(defcolor_at_highlight)); + } + } + } + return(has_highlight_range); +} + +function i32 +default_cursor_sub_id(void){ + i32 result = 0; + if (global_keyboard_macro_is_recording){ + result = 1; + } + return(result); +} + +function void +draw_original_4coder_style_cursor_mark_highlight(Application_Links *app, View_ID view_id, b32 is_active_view, + Buffer_ID buffer, Text_Layout_ID text_layout_id, + f32 roundness, f32 outline_thickness){ + b32 has_highlight_range = draw_highlight_range(app, view_id, buffer, text_layout_id, roundness); + if (!has_highlight_range){ + i32 cursor_sub_id = default_cursor_sub_id(); + + i64 cursor_pos = view_get_cursor_pos(app, view_id); + i64 mark_pos = view_get_mark_pos(app, view_id); + if (is_active_view){ + draw_character_block(app, text_layout_id, cursor_pos, roundness, + fcolor_id(defcolor_cursor, cursor_sub_id)); + paint_text_color_pos(app, text_layout_id, cursor_pos, + fcolor_id(defcolor_at_cursor)); + draw_character_wire_frame(app, text_layout_id, mark_pos, + roundness, outline_thickness, + fcolor_id(defcolor_mark)); + } + else{ + draw_character_wire_frame(app, text_layout_id, mark_pos, + roundness, outline_thickness, + fcolor_id(defcolor_mark)); + draw_character_wire_frame(app, text_layout_id, cursor_pos, + roundness, outline_thickness, + fcolor_id(defcolor_cursor, cursor_sub_id)); + } + } +} + +function void +draw_notepad_style_cursor_highlight(Application_Links *app, View_ID view_id, + Buffer_ID buffer, Text_Layout_ID text_layout_id, + f32 roundness){ + b32 has_highlight_range = draw_highlight_range(app, view_id, buffer, text_layout_id, roundness); + if (!has_highlight_range){ + i32 cursor_sub_id = default_cursor_sub_id(); + i64 cursor_pos = view_get_cursor_pos(app, view_id); + i64 mark_pos = view_get_mark_pos(app, view_id); + if (cursor_pos != mark_pos){ + Range_i64 range = Ii64(cursor_pos, mark_pos); + draw_character_block(app, text_layout_id, range, roundness, fcolor_id(defcolor_highlight)); + paint_text_color_fcolor(app, text_layout_id, range, fcolor_id(defcolor_at_highlight)); + } + draw_character_i_bar(app, text_layout_id, cursor_pos, fcolor_id(defcolor_cursor, cursor_sub_id)); + } +} + +//////////////////////////////// + +function Rect_f32 +get_contained_box_near_point(Rect_f32 container, Vec2_f32 p, Vec2_f32 box_dims){ + Vec2_f32 container_dims = rect_dim(container); + box_dims.x = clamp_top(box_dims.x, container_dims.x); + box_dims.y = clamp_top(box_dims.y, container_dims.y); + Vec2_f32 q = p + V2f32(-20.f, 22.f); + if (q.x + box_dims.x > container.x1){ + q.x = container.x1 - box_dims.x; + } + if (q.y + box_dims.y > container.y1){ + q.y = p.y - box_dims.y - 2.f; + if (q.y < container.y0){ + q.y = (container.y0 + container.y1 - box_dims.y)*0.5f; + } + } + return(Rf32_xy_wh(q, box_dims)); +} + +function Rect_f32 +draw_tool_tip(Application_Links *app, Face_ID face, Fancy_Block *block, + Vec2_f32 p, Rect_f32 region, f32 x_padding, f32 x_half_padding, + FColor back_color){ + Rect_f32 box = Rf32(p, p); + if (block->line_count > 0){ + Vec2_f32 dims = get_fancy_block_dim(app, face, block); + dims += V2f32(x_padding, 2.f); + box = get_contained_box_near_point(region, p, dims); + box.x0 = f32_round32(box.x0); + box.y0 = f32_round32(box.y0); + box.x1 = f32_round32(box.x1); + box.y1 = f32_round32(box.y1); + Rect_f32 prev_clip = draw_set_clip(app, box); + draw_rectangle_fcolor(app, box, 6.f, back_color); + draw_fancy_block(app, face, fcolor_zero(), block, + box.p0 + V2f32(x_half_padding, 1.f)); + draw_set_clip(app, prev_clip); + } + return(box); +} + +function Rect_f32 +draw_drop_down(Application_Links *app, Face_ID face, Fancy_Block *block, + Vec2_f32 p, Rect_f32 region, f32 x_padding, f32 x_half_padding, + FColor outline_color, FColor back_color){ + Rect_f32 box = Rf32(p, p); + if (block->line_count > 0){ + Vec2_f32 dims = get_fancy_block_dim(app, face, block); + dims += V2f32(x_padding, 4.f); + box = get_contained_box_near_point(region, p, dims); + box.x0 = f32_round32(box.x0); + box.y0 = f32_round32(box.y0); + box.x1 = f32_round32(box.x1); + box.y1 = f32_round32(box.y1); + Rect_f32 prev_clip = draw_set_clip(app, box); + draw_rectangle_fcolor(app, box, 0.f, back_color); + draw_margin(app, box, rect_inner(box, 1.f), outline_color); + draw_fancy_block(app, face, fcolor_zero(), block, + box.p0 + V2f32(x_half_padding, 2.f)); + draw_set_clip(app, prev_clip); + } + return(box); +} + +function b32 +draw_button(Application_Links *app, Rect_f32 rect, Vec2_f32 mouse_p, Face_ID face, String_Const_u8 text){ + b32 hovered = false; + if (rect_contains_point(rect, mouse_p)){ + hovered = true; + } + + UI_Highlight_Level highlight = hovered?UIHighlight_Active:UIHighlight_None; + draw_rectangle_fcolor(app, rect, 3.f, get_item_margin_color(highlight)); + rect = rect_inner(rect, 3.f); + draw_rectangle_fcolor(app, rect, 3.f, get_item_margin_color(highlight, 1)); + + Scratch_Block scratch(app); + Fancy_String *fancy = push_fancy_string(scratch, 0, face, fcolor_id(defcolor_text_default), text); + Vec2_f32 dim = get_fancy_string_dim(app, 0, fancy); + Vec2_f32 p = (rect.p0 + rect.p1 - dim)*0.5f; + draw_fancy_string(app, fancy, p); + + return(hovered); +} + +// BOTTOM + diff --git a/custom/4coder_fancy.cpp b/custom/4coder_fancy.cpp index 9b840962..4364db02 100644 --- a/custom/4coder_fancy.cpp +++ b/custom/4coder_fancy.cpp @@ -347,11 +347,11 @@ function Fancy_String* push_fancy_string_fixed(Arena *arena, Fancy_Line *line, FColor fore, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fore, 0.f, 0.f, "%-*.*s", max, string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fore, 0.f, 0.f, "%-*.*s...", max - 3, string_expand(value))); } } @@ -360,12 +360,12 @@ push_fancy_string_fixed(Arena *arena, Fancy_Line *line, f32 pre_margin, f32 post_margin, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), pre_margin, post_margin, "%-*.*s", max, string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), pre_margin, post_margin, "%-*.*s...", max - 3, string_expand(value))); } @@ -374,11 +374,11 @@ function Fancy_String* push_fancy_string_fixed(Arena *arena, Fancy_Line *line, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), 0.f, 0.f, "%-*.*s", max, string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), 0.f, 0.f, "%-*.*s...", max - 3, string_expand(value))); } } @@ -452,11 +452,11 @@ function Fancy_String* push_fancy_string_trunc(Arena *arena, Fancy_Line *line, FColor fore, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fore, 0.f, 0.f, "%.*s", string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fore, 0.f, 0.f, "%.*s...", max - 3, value.str)); } } @@ -465,12 +465,12 @@ push_fancy_string_trunc(Arena *arena, Fancy_Line *line, f32 pre_margin, f32 post_margin, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), pre_margin, post_margin, "%.*s", string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), pre_margin, post_margin, "%.*s...", max - 3, value.str)); } @@ -479,11 +479,11 @@ function Fancy_String* push_fancy_string_trunc(Arena *arena, Fancy_Line *line, String_Const_u8 value, i32 max){ if (value.size <= max){ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), 0.f, 0.f, "%.*s", string_expand(value))); } else{ - return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + return(push_fancy_stringf(arena, line, (Face_ID)0, fcolor_zero(), 0.f, 0.f, "%.*s...", max - 3, value.str)); } } @@ -620,7 +620,7 @@ draw_fancy_string__inner(Application_Links *app, Face_ID face, FColor fore, Fanc use_fore = string->fore; } if (use_face != 0){ - ARGB_Color use_argb = fcolor_resolve(use_fore); + ARGB_Color use_argb = fcolor_resolve(use_fore); Face_Metrics metrics = get_face_metrics(app, use_face); f32 down_shift = (base_line - metrics.ascent); down_shift = clamp_bot(0.f, down_shift); @@ -668,7 +668,7 @@ get_fancy_string_height(Application_Links *app, Face_ID face, function f32 get_fancy_string_text_height(Application_Links *app, Face_ID face, - Fancy_String *string){ + Fancy_String *string){ Fancy_String *next = string->next; string->next = 0; f32 result = get_fancy_string_text_height__inner(app, face, string); @@ -700,10 +700,10 @@ function f32 get_fancy_line_width(Application_Links *app, Face_ID face, Fancy_Line *line){ f32 result = 0.f; if (line != 0){ - if (line->face != 0){ - face = line->face; - } - result = get_fancy_string_width__inner(app, face, line->first); + if (line->face != 0){ + face = line->face; + } + result = get_fancy_string_width__inner(app, face, line->first); } return(result); } @@ -749,12 +749,12 @@ draw_fancy_line(Application_Links *app, Face_ID face, FColor fore, Fancy_Line *line, Vec2_f32 p, u32 flags, Vec2_f32 delta){ Vec2_f32 result = {}; if (line != 0){ - if (line->face != 0){ - face = line->face; - } - if (fcolor_is_valid(line->fore)){ - fore = line->fore; - } + if (line->face != 0){ + face = line->face; + } + if (fcolor_is_valid(line->fore)){ + fore = line->fore; + } result = draw_fancy_string__inner(app, face, fore, line->first, p, flags, delta); } return(result); diff --git a/custom/4coder_file_moving.h b/custom/4coder_file_moving.h index b9beb7fe..9e5ea59f 100644 --- a/custom/4coder_file_moving.h +++ b/custom/4coder_file_moving.h @@ -33,11 +33,11 @@ static i32 prev_error = 0; #endif #define systemf(...) do{ \ - i32 n = snprintf(SF_CMD, sizeof(SF_CMD), __VA_ARGS__); \ - Assert(n < sizeof(SF_CMD)); \ - SYSTEMF_PRINTF("%s\n", SF_CMD); \ - prev_error = system(SF_CMD); \ - if (prev_error != 0) error_state = 1; \ +i32 n = snprintf(SF_CMD, sizeof(SF_CMD), __VA_ARGS__); \ +Assert(n < sizeof(SF_CMD)); \ +SYSTEMF_PRINTF("%s\n", SF_CMD); \ +prev_error = system(SF_CMD); \ +if (prev_error != 0) error_state = 1; \ }while(0) internal void fm_execute_in_dir(char *dir, char *str, char *args); @@ -109,18 +109,18 @@ internal void fm__swap_ptr(char **A, char **B); #if COMPILER_CL #define fm_add_to_line(line, str, ...) do{ \ - snprintf(line.build_options, \ - line.build_max, "%s "str, \ - line.build_options_prev, __VA_ARGS__); \ - fm__swap_ptr(&line.build_options, &line.build_options_prev); \ +snprintf(line.build_options, \ +line.build_max, "%s "str, \ +line.build_options_prev, __VA_ARGS__); \ +fm__swap_ptr(&line.build_options, &line.build_options_prev); \ }while(0) -#elif COMPILER_GCC +#elif COMPILER_GCC | COMPILER_CLANG #define fm_add_to_line(line, str, ...) do{ \ - snprintf(line.build_options, line.build_max, "%s " str, \ - line.build_options_prev, ##__VA_ARGS__); \ - fm__swap_ptr(&line.build_options, &line.build_options_prev); \ +snprintf(line.build_options, line.build_max, "%s " str, \ +line.build_options_prev, ##__VA_ARGS__); \ +fm__swap_ptr(&line.build_options, &line.build_options_prev); \ }while(0) #endif @@ -259,9 +259,9 @@ extern "C"{ #define OPEN_ALWAYS 4 #define TRUNCATE_EXISTING 5 -#define FILE_ATTRIBUTE_READONLY 0x00000001 -#define FILE_ATTRIBUTE_NORMAL 0x00000080 -#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define FILE_ATTRIBUTE_READONLY 0x00000001 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 global u64 perf_frequency; @@ -370,9 +370,9 @@ fm_copy_file(char *file, char *newname){ internal void fm_copy_all(char *source, char *folder){ - fprintf(stdout, "copy %s to %s\n", source, folder); - fflush(stdout); - systemf("xcopy /s /e /y /q %s %s > nul", source, folder); + fprintf(stdout, "copy %s to %s\n", source, folder); + fflush(stdout); + systemf("xcopy /s /e /y /q %s %s > nul", source, folder); } internal void @@ -510,7 +510,7 @@ fm_copy_file(char *file, char *newname){ internal void fm_copy_all(char *source, char *folder){ fprintf(stdout, "copy %s to %s\n", source, folder); - systemf("cp -rf %s %s > /dev/null", source, folder); + systemf("cp -rf %s/* %s > /dev/null", source, folder); } internal void diff --git a/custom/4coder_function_list.cpp b/custom/4coder_function_list.cpp index 1fcce23c..80ac51d8 100644 --- a/custom/4coder_function_list.cpp +++ b/custom/4coder_function_list.cpp @@ -277,13 +277,14 @@ CUSTOM_DOC("Creates a jump list of lines of the current buffer that appear to de CUSTOM_COMMAND_SIG(list_all_functions_current_buffer_lister) CUSTOM_DOC("Creates a lister of locations that look like function definitions and declarations in the buffer.") { + Heap *heap = &global_heap; View_ID view = get_active_view(app, Access_ReadVisible); Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible); if (buffer != 0){ list_all_functions(app, buffer); view = get_active_view(app, Access_Always); buffer = view_get_buffer(app, view, Access_Always); - Marker_List *list = get_marker_list_for_buffer(buffer); + Marker_List *list = get_or_make_list_for_buffer(app, heap, buffer); if (list != 0){ Jump_Lister_Result jump = get_jump_index_from_user(app, list, "Function:"); @@ -301,13 +302,13 @@ CUSTOM_DOC("Creates a jump list of lines from all buffers that appear to define CUSTOM_COMMAND_SIG(list_all_functions_all_buffers_lister) CUSTOM_DOC("Creates a lister of locations that look like function definitions and declarations all buffers.") { + Heap *heap = &global_heap; list_all_functions(app, 0); View_ID view = get_active_view(app, Access_Always); Buffer_ID buffer = view_get_buffer(app, view, Access_Always); - Marker_List *list = get_marker_list_for_buffer(buffer); + Marker_List *list = get_or_make_list_for_buffer(app, heap, buffer); if (list != 0){ - Jump_Lister_Result jump = get_jump_index_from_user(app, list, - "Function:"); + Jump_Lister_Result jump = get_jump_index_from_user(app, list, "Function:"); jump_to_jump_lister_result(app, view, list, &jump); } } diff --git a/custom/4coder_helper.cpp b/custom/4coder_helper.cpp index db627f48..c4246f52 100644 --- a/custom/4coder_helper.cpp +++ b/custom/4coder_helper.cpp @@ -68,15 +68,15 @@ character_predicate_from_function(Character_Predicate_Function *func){ v[bit_index] = func((u8)i); } predicate.b[byte_index] = ( - (v[0] << 0) | - (v[1] << 1) | - (v[2] << 2) | - (v[3] << 3) | - (v[4] << 4) | - (v[5] << 5) | - (v[6] << 6) | - (v[7] << 7) - ); + (v[0] << 0) | + (v[1] << 1) | + (v[2] << 2) | + (v[3] << 3) | + (v[4] << 4) | + (v[5] << 5) | + (v[6] << 6) | + (v[7] << 7) + ); byte_index += 1; } return(predicate); @@ -788,7 +788,7 @@ enclose_boundary(Application_Links *app, Buffer_ID buffer, Range_i64 range, range.min = new_min; } i64 new_max = func(app, buffer, Side_Max, Scan_Forward, range.max - 1); - i64 new_max_check = func(app, buffer, Side_Min, Scan_Forward, range.max - 1); + i64 new_max_check = func(app, buffer, Side_Min, Scan_Forward, range.max); if (new_max_check >= new_max && new_max > range.max){ range.max = new_max; } @@ -797,7 +797,7 @@ enclose_boundary(Application_Links *app, Buffer_ID buffer, Range_i64 range, internal Range_i64 left_enclose_boundary(Application_Links *app, Buffer_ID buffer, Range_i64 range, - Boundary_Function *func){ + Boundary_Function *func){ i64 new_min = func(app, buffer, Side_Min, Scan_Backward, range.min + 1); i64 new_min_check = func(app, buffer, Side_Max, Scan_Backward, range.min + 1); if (new_min_check <= new_min && new_min < range.min){ @@ -1227,8 +1227,8 @@ get_indent_info_range(Application_Links *app, Buffer_ID buffer, Range_i64 range, } internal Indent_Info -get_indent_info_line_start(Application_Links *app, Buffer_ID buffer, i64 line_start, i32 tab_width){ - i64 end = get_line_side_pos_from_pos(app, buffer, line_start, Side_Max); +get_indent_info_line_number_and_start(Application_Links *app, Buffer_ID buffer, i64 line_number, i64 line_start, i32 tab_width){ + i64 end = get_line_side_pos(app, buffer, line_number, Side_Max); return(get_indent_info_range(app, buffer, Ii64(line_start, end), tab_width)); } @@ -1897,7 +1897,7 @@ push_token_or_word_under_pos(Application_Links *app, Arena *arena, Buffer_ID buf String_Const_u8 result = {}; Token *token = get_token_from_pos(app, buffer, pos); if (token != 0 && token->size > 0 && token->kind != TokenBaseKind_Whitespace){ - Range_i64 range = Ii64(token->pos, token->pos + token->size); + Range_i64 range = Ii64(token); result = push_buffer_range(app, arena, buffer, range); } return(result); diff --git a/custom/4coder_insertion.cpp b/custom/4coder_insertion.cpp index e548aa29..2d250954 100644 --- a/custom/4coder_insertion.cpp +++ b/custom/4coder_insertion.cpp @@ -44,7 +44,7 @@ insert_string__no_buffering(Buffer_Insertion *insertion, String_Const_u8 string) insertion->at += string.size; } -static void +function void insert__flush(Buffer_Insertion *insertion){ Cursor *cursor = insertion->cursor; u64 pos = insertion->temp.temp_memory_cursor.pos; @@ -53,7 +53,7 @@ insert__flush(Buffer_Insertion *insertion){ end_temp(insertion->temp); } -static char* +function char* insert__reserve(Buffer_Insertion *insertion, u64 size){ char *space = push_array(insertion->cursor, char, size); if (space == 0){ @@ -63,14 +63,14 @@ insert__reserve(Buffer_Insertion *insertion, u64 size){ return(space); } -static void +function void end_buffer_insertion(Buffer_Insertion *insertion){ if (insertion->buffering){ insert__flush(insertion); } } -static void +function void insert_string(Buffer_Insertion *insertion, String_Const_u8 string){ if (!insertion->buffering){ insert_string__no_buffering(insertion, string); @@ -86,7 +86,7 @@ insert_string(Buffer_Insertion *insertion, String_Const_u8 string){ } } -static u64 +function u64 insertf(Buffer_Insertion *insertion, char *format, ...){ Scratch_Block scratch(insertion->app); va_list args; @@ -97,12 +97,12 @@ insertf(Buffer_Insertion *insertion, char *format, ...){ return(string.size); } -static void +function void insertc(Buffer_Insertion *insertion, char C){ insert_string(insertion, SCu8(&C, 1)); } -static b32 +function b32 insert_line_from_buffer(Buffer_Insertion *insertion, Buffer_ID buffer_id, i32 line, i32 truncate_at){ b32 success = is_valid_line(insertion->app, buffer_id, line); if (success){ @@ -112,7 +112,7 @@ insert_line_from_buffer(Buffer_Insertion *insertion, Buffer_ID buffer_id, i32 li return(success); } -static b32 +function b32 insert_line_from_buffer(Buffer_Insertion *insertion, Buffer_ID buffer_id, i32 line){ return(insert_line_from_buffer(insertion, buffer_id, line, 0)); } diff --git a/custom/4coder_jump_lister.cpp b/custom/4coder_jump_lister.cpp index d81cca76..5803d00c 100644 --- a/custom/4coder_jump_lister.cpp +++ b/custom/4coder_jump_lister.cpp @@ -59,9 +59,10 @@ jump_to_jump_lister_result(Application_Links *app, View_ID view, CUSTOM_COMMAND_SIG(view_jump_list_with_lister) CUSTOM_DOC("When executed on a buffer with jumps, creates a persistent lister for all the jumps") { + Heap *heap = &global_heap; View_ID view = get_active_view(app, Access_Always); Buffer_ID buffer = view_get_buffer(app, view, Access_Always); - Marker_List *list = get_marker_list_for_buffer(buffer); + Marker_List *list = get_or_make_list_for_buffer(app, heap, buffer); if (list != 0){ Jump_Lister_Result jump = get_jump_index_from_user(app, list, "Jump:"); jump_to_jump_lister_result(app, view, list, &jump); diff --git a/custom/4coder_jump_sticky.cpp b/custom/4coder_jump_sticky.cpp index 2188af7a..b39acd49 100644 --- a/custom/4coder_jump_sticky.cpp +++ b/custom/4coder_jump_sticky.cpp @@ -114,9 +114,9 @@ init_marker_list(Application_Links *app, Heap *heap, Buffer_ID buffer, Marker_Li } sort_pairs_by_key(range_index_buffer_id_pairs, buffer_ranges.count); Range_i32_Array scoped_buffer_ranges = get_ranges_of_duplicate_keys(scratch, - &range_index_buffer_id_pairs->key, - sizeof(*range_index_buffer_id_pairs), - buffer_ranges.count); + &range_index_buffer_id_pairs->key, + sizeof(*range_index_buffer_id_pairs), + buffer_ranges.count); Sticky_Jump_Stored *stored = push_array(scratch, Sticky_Jump_Stored, jumps.count); @@ -171,7 +171,9 @@ init_marker_list(Application_Links *app, Heap *heap, Buffer_ID buffer, Marker_Li Assert(managed_object_get_type(app, marker_handle) == ManagedObjectType_Markers); Managed_Object *marker_handle_ptr = scope_attachment(app, scope, sticky_jump_marker_handle, Managed_Object); - *marker_handle_ptr = marker_handle; + if (marker_handle_ptr != 0){ + *marker_handle_ptr = marker_handle; + } } Managed_Object stored_jump_array = alloc_managed_memory_in_scope(app, scope_array[0], sizeof(Sticky_Jump_Stored), jumps.count); @@ -279,7 +281,7 @@ get_jump_from_list(Application_Links *app, Marker_List *list, i32 index, ID_Pos_ Managed_Scope scope = get_managed_scope_with_multiple_dependencies(app, scope_array, ArrayCount(scope_array)); Managed_Object *marker_array = scope_attachment(app, scope, sticky_jump_marker_handle, Managed_Object); - if (*marker_array != 0){ + if (marker_array != 0 && *marker_array != 0){ Marker marker = {}; managed_object_load_data(app, *marker_array, stored.index_into_marker_array, 1, &marker); location->buffer_id = target_buffer_id; diff --git a/custom/4coder_keyboard_macro.cpp b/custom/4coder_keyboard_macro.cpp index 0d455c9c..eb721c11 100644 --- a/custom/4coder_keyboard_macro.cpp +++ b/custom/4coder_keyboard_macro.cpp @@ -4,9 +4,6 @@ // TOP -global b32 global_keyboard_macro_is_recording = false; -global Range_i64 global_keyboard_macro_range = {}; - function Buffer_ID get_keyboard_log_buffer(Application_Links *app){ return(get_buffer_by_name(app, string_u8_litexpr("*keyboard*"), Access_Always)); diff --git a/custom/4coder_layout.cpp b/custom/4coder_layout.cpp index c36c1be0..72c9d5e3 100644 --- a/custom/4coder_layout.cpp +++ b/custom/4coder_layout.cpp @@ -15,7 +15,6 @@ layout_nearest_pos_to_xy(Layout_Item_List list, Vec2_f32 p){ } else{ if (0.f < p.x && p.x < max_f32){ - f32 bottom_padding = list.bottom_padding; f32 closest_x = -max_f32; for (Layout_Item_Block *block = list.first; block != 0; @@ -30,7 +29,7 @@ layout_nearest_pos_to_xy(Layout_Item_List list, Vec2_f32 p){ if (p.y < item->rect.y0){ goto double_break; } - if (item->rect.y1 + bottom_padding <= p.y){ + if (item->padded_y1 <= p.y){ continue; } f32 dist0 = p.x - item->rect.x0; @@ -68,7 +67,7 @@ layout_nearest_pos_to_xy(Layout_Item_List list, Vec2_f32 p){ goto double_break_2; } prev_item = item; - if (item->rect.y1 <= p.y){ + if (item->padded_y1 <= p.y){ continue; } } @@ -97,7 +96,7 @@ layout_nearest_pos_to_xy(Layout_Item_List list, Vec2_f32 p){ if (p.y < item->rect.y0){ goto double_break_3; } - if (item->rect.y1 <= p.y){ + if (item->padded_y1 <= p.y){ continue; } closest_item = item; @@ -160,6 +159,19 @@ layout_box_of_pos(Layout_Item_List list, i64 index){ return(result); } +function Rect_f32 +layout_padded_box_of_pos(Layout_Item_List list, i64 index){ + Rect_f32 result = {}; + Layout_Item *item = layout_get_first_with_index(list, index); + if (item != 0){ + result.x0 = item->rect.x0; + result.y0 = item->rect.y0; + result.x1 = item->rect.x1; + result.y1 = item->padded_y1; + } + return(result); +} + internal i64 layout_get_pos_at_character(Layout_Item_List list, i64 character){ i64 result = 0; diff --git a/custom/4coder_layout_rule.cpp b/custom/4coder_layout_rule.cpp index 56056c93..ce9e5aec 100644 --- a/custom/4coder_layout_rule.cpp +++ b/custom/4coder_layout_rule.cpp @@ -56,7 +56,7 @@ layout_item_list_finish(Layout_Item_List *list, f32 bottom_padding){ } function void -layout_write(Arena *arena, Layout_Item_List *list, Face_ID face, i64 index, u32 codepoint, Layout_Item_Flag flags, Rect_f32 rect){ +layout_write(Arena *arena, Layout_Item_List *list, Face_ID face, i64 index, u32 codepoint, Layout_Item_Flag flags, Rect_f32 rect, f32 padded_y1){ Temp_Memory restore_point = begin_temp(arena); Layout_Item *item = push_array(arena, Layout_Item, 1); Layout_Item_Block *block = list->last; @@ -95,6 +95,7 @@ layout_write(Arena *arena, Layout_Item_List *list, Face_ID face, i64 index, u32 item->codepoint = codepoint; item->flags = flags; item->rect = rect; + item->padded_y1 = padded_y1; list->height = Max(list->height, rect.y1); } @@ -179,7 +180,7 @@ lr_tb_write_with_advance_with_flags(LefRig_TopBot_Layout_Vars *vars, Face_ID fac } vars->p.x = f32_ceil32(vars->p.x); f32 next_x = vars->p.x + advance; - layout_write(arena, list, face, index, codepoint, flags, Rf32(vars->p, V2f32(next_x, vars->text_y))); + layout_write(arena, list, face, index, codepoint, flags, Rf32(vars->p, V2f32(next_x, vars->text_y)), vars->line_y); vars->p.x = next_x; } @@ -219,15 +220,15 @@ lr_tb_write_byte_with_advance(LefRig_TopBot_Layout_Vars *vars, Face_ID face, f32 f32 text_y = vars->text_y; Layout_Item_Flag flags = LayoutItemFlag_Special_Character; - layout_write(arena, list, face, index, '\\', flags, Rf32(p, V2f32(next_x, text_y))); + layout_write(arena, list, face, index, '\\', flags, Rf32(p, V2f32(next_x, text_y)), vars->line_y); p.x = next_x; flags = LayoutItemFlag_Ghost_Character; next_x += metrics->byte_sub_advances[1]; - layout_write(arena, list, face, index, integer_symbols[hi], flags, Rf32(p, V2f32(next_x, text_y))); + layout_write(arena, list, face, index, integer_symbols[hi], flags, Rf32(p, V2f32(next_x, text_y)), vars->line_y); p.x = next_x; next_x += metrics->byte_sub_advances[2]; - layout_write(arena, list, face, index, integer_symbols[lo], flags, Rf32(p, V2f32(next_x, text_y))); + layout_write(arena, list, face, index, integer_symbols[lo], flags, Rf32(p, V2f32(next_x, text_y)), vars->line_y); vars->p.x = final_next_x; } @@ -242,7 +243,7 @@ lr_tb_write_byte(LefRig_TopBot_Layout_Vars *vars, Face_ID face, function void lr_tb_write_blank_dim(LefRig_TopBot_Layout_Vars *vars, Face_ID face, Vec2_f32 dim, Arena *arena, Layout_Item_List *list, i64 index){ - layout_write(arena, list, face, index, ' ', 0, Rf32_xy_wh(vars->p, dim)); + layout_write(arena, list, face, index, ' ', 0, Rf32_xy_wh(vars->p, dim), vars->line_y); vars->p.x += dim.x; } diff --git a/custom/4coder_lister_base.cpp b/custom/4coder_lister_base.cpp index 315ad374..7e98b502 100644 --- a/custom/4coder_lister_base.cpp +++ b/custom/4coder_lister_base.cpp @@ -266,8 +266,8 @@ lister_render(Application_Links *app, Frame_Info frame_info, View_ID view){ highlight = UIHighlight_Hover; } - draw_rectangle_fcolor(app, item_rect, 6.f, get_margin_color(highlight)); - draw_rectangle_fcolor(app, item_inner, 6.f, fcolor_id(defcolor_back)); + draw_rectangle_fcolor(app, item_rect, 6.f, get_item_margin_color(highlight)); + draw_rectangle_fcolor(app, item_inner, 6.f, get_item_margin_color(highlight, 1)); Fancy_Line line = {}; push_fancy_string(scratch, &line, fcolor_id(defcolor_text_default), node->string); @@ -472,7 +472,7 @@ run_lister(Application_Links *app, Lister *lister){ case InputEventKind_TextInsert: { if (lister->handlers.write_character != 0){ - lister->handlers.write_character(app); + result = lister->handlers.write_character(app); } }break; @@ -627,7 +627,7 @@ run_lister(Application_Links *app, Lister *lister){ switch (in.event.core.code){ case CoreCode_Animate: { - lister_update_filtered_list(app, lister); + lister_update_filtered_list(app, lister); }break; default: @@ -716,8 +716,9 @@ lister_add_item(Lister *lister, String_Const_u8 string, String_Const_u8 status, user_data, extra_space)); } -function void +function Lister_Activation_Code lister__write_string__default(Application_Links *app){ + Lister_Activation_Code result = ListerActivation_Continue; View_ID view = get_active_view(app, Access_Always); Lister *lister = view_get_lister(view); if (lister != 0){ @@ -731,6 +732,7 @@ lister__write_string__default(Application_Links *app){ lister_update_filtered_list(app, lister); } } + return(result); } function void diff --git a/custom/4coder_lister_base.h b/custom/4coder_lister_base.h index c38cc666..aa6fae80 100644 --- a/custom/4coder_lister_base.h +++ b/custom/4coder_lister_base.h @@ -39,6 +39,7 @@ struct Lister_Node_Ptr_Array{ i32 count; }; +typedef Lister_Activation_Code Lister_Write_Character_Function(Application_Links *app); typedef Lister_Activation_Code Lister_Key_Stroke_Function(Application_Links *app); typedef void Lister_Navigate_Function(Application_Links *app, View_ID view, struct Lister *lister, @@ -46,7 +47,7 @@ typedef void Lister_Navigate_Function(Application_Links *app, struct Lister_Handlers{ Lister_Regenerate_List_Function_Type *refresh; - Custom_Command_Function *write_character; + Lister_Write_Character_Function *write_character; Custom_Command_Function *backspace; Lister_Navigate_Function *navigate; Lister_Key_Stroke_Function *key_stroke; diff --git a/custom/4coder_lists.cpp b/custom/4coder_lists.cpp index 7438a50f..26595d4b 100644 --- a/custom/4coder_lists.cpp +++ b/custom/4coder_lists.cpp @@ -222,7 +222,7 @@ get_color_table_from_user(Application_Links *app, String_Const_u8 query, Color_T Lister_Result l_result = run_lister(app, lister); - Color_Table *result = 0; + Color_Table *result = 0; if (!l_result.canceled){ result = (Color_Table*)l_result.user_data; } @@ -236,8 +236,9 @@ get_color_table_from_user(Application_Links *app){ //////////////////////////////// -function void +function Lister_Activation_Code lister__write_character__file_path(Application_Links *app){ + Lister_Activation_Code result = ListerActivation_Continue; View_ID view = get_this_ctx_view(app, Access_Always); Lister *lister = view_get_lister(view); if (lister != 0){ @@ -245,18 +246,20 @@ lister__write_character__file_path(Application_Links *app){ String_Const_u8 string = to_writable(&in); if (string.str != 0 && string.size > 0){ lister_append_text_field(lister, string); - String_Const_u8 front_name = string_front_of_path(lister->text_field.string); - lister_set_key(lister, front_name); if (character_is_slash(string.str[0])){ - String_Const_u8 new_hot = lister->text_field.string; - set_hot_directory(app, new_hot); - lister_call_refresh_handler(app, lister); + lister->out.text_field = lister->text_field.string; + result = ListerActivation_Finished; + } + else{ + String_Const_u8 front_name = string_front_of_path(lister->text_field.string); + lister_set_key(lister, front_name); } lister->item_index = 0; lister_zero_scroll(lister); lister_update_filtered_list(app, lister); } } + return(result); } function void @@ -374,15 +377,13 @@ struct File_Name_Result{ }; function File_Name_Result -get_file_name_from_user(Application_Links *app, Arena *arena, String_Const_u8 query, - View_ID view){ +get_file_name_from_user(Application_Links *app, Arena *arena, String_Const_u8 query, View_ID view){ Lister_Handlers handlers = lister_get_default_handlers(); handlers.refresh = generate_hot_directory_file_list; handlers.write_character = lister__write_character__file_path; handlers.backspace = lister__backspace_text_field__file_path; - Lister_Result l_result = - run_lister_with_refresh_handler(app, arena, query, handlers); + Lister_Result l_result = run_lister_with_refresh_handler(app, arena, query, handlers); File_Name_Result result = {}; result.canceled = l_result.canceled; @@ -391,12 +392,18 @@ get_file_name_from_user(Application_Links *app, Arena *arena, String_Const_u8 qu if (l_result.user_data != 0){ String_Const_u8 name = SCu8((u8*)l_result.user_data); result.file_name_activated = name; - result.is_folder = - character_is_slash(string_get_character(name, name.size -1 )); + result.is_folder = character_is_slash(string_get_character(name, name.size - 1)); } result.file_name_in_text_field = string_front_of_path(l_result.text_field); - String_Const_u8 path = string_remove_front_of_path(l_result.text_field); + String_Const_u8 path = {}; + if (l_result.user_data == 0 && result.file_name_in_text_field.size == 0 && l_result.text_field.size > 0){ + result.file_name_in_text_field = string_front_folder_of_path(l_result.text_field); + path = string_remove_front_folder_of_path(l_result.text_field); + } + else{ + path = string_remove_front_of_path(l_result.text_field); + } if (character_is_slash(string_get_character(path, path.size - 1))){ path = string_chop(path, 1); } @@ -407,8 +414,7 @@ get_file_name_from_user(Application_Links *app, Arena *arena, String_Const_u8 qu } function File_Name_Result -get_file_name_from_user(Application_Links *app, Arena *arena, char *query, - View_ID view){ +get_file_name_from_user(Application_Links *app, Arena *arena, char *query, View_ID view){ return(get_file_name_from_user(app, arena, SCu8(query), view)); } @@ -429,8 +435,7 @@ do_buffer_kill_user_check(Application_Links *app, Buffer_ID buffer, View_ID view lister_choice(scratch, &list, "(Y)es" , "", KeyCode_Y, SureToKill_Yes); lister_choice(scratch, &list, "(S)ave", "", KeyCode_S, SureToKill_Save); - Lister_Choice *choice = - get_choice_from_user(app, "There are unsaved changes, close anyway?", list); + Lister_Choice *choice = get_choice_from_user(app, "There are unsaved changes, close anyway?", list); b32 do_kill = false; if (choice != 0){ @@ -507,7 +512,7 @@ CUSTOM_DOC("Interactively switch to an open buffer.") { Buffer_ID buffer = get_buffer_from_user(app, "Switch:"); if (buffer != 0){ - View_ID view = get_this_ctx_view(app, Access_Always); + View_ID view = get_this_ctx_view(app, Access_Always); view_set_buffer(app, view, buffer, 0); } } @@ -524,6 +529,50 @@ CUSTOM_DOC("Interactively kill an open buffer.") //////////////////////////////// +enum{ + SureToCreateFolder_NULL = 0, + SureToCreateFolder_No = 1, + SureToCreateFolder_Yes = 2, +}; + +function b32 +query_create_folder(Application_Links *app, String_Const_u8 folder_name){ + Scratch_Block scratch(app); + Lister_Choice_List list = {}; + lister_choice(scratch, &list, "(N)o" , "", KeyCode_N, SureToKill_No); + lister_choice(scratch, &list, "(Y)es" , "", KeyCode_Y, SureToKill_Yes); + + String_Const_u8 message = push_u8_stringf(scratch, "Create the folder %.*s?", string_expand(folder_name)); + Lister_Choice *choice = get_choice_from_user(app, message, list); + + b32 did_create_folder = false; + if (choice != 0){ + switch (choice->user_data){ + case SureToCreateFolder_No: + {}break; + + case SureToCreateFolder_Yes: + { + String_Const_u8 hot = push_hot_directory(app, scratch); + String_Const_u8 fixed_folder_name = folder_name; + for (;fixed_folder_name.size > 0 && + character_is_slash(fixed_folder_name.str[fixed_folder_name.size - 1]);){ + fixed_folder_name = string_chop(fixed_folder_name, 1); + } + if (fixed_folder_name.size > 0){ + String_Const_u8 cmd = push_u8_stringf(scratch, "mkdir %.*s", string_expand(fixed_folder_name)); + exec_system_command(app, 0, buffer_identifier(0), hot, cmd, 0); + did_create_folder = true; + } + }break; + } + } + + return(did_create_folder); +} + +//////////////////////////////// + function Lister_Activation_Code activate_open_or_new__generic(Application_Links *app, View_ID view, String_Const_u8 path, String_Const_u8 file_name, @@ -566,8 +615,7 @@ CUSTOM_DOC("Interactively open a file out of the file system.") for (;;){ Scratch_Block scratch(app); View_ID view = get_this_ctx_view(app, Access_Always); - File_Name_Result result = get_file_name_from_user(app, scratch, "Open:", - view); + File_Name_Result result = get_file_name_from_user(app, scratch, "Open:", view); if (result.canceled) break; String_Const_u8 file_name = result.file_name_activated; @@ -577,15 +625,31 @@ CUSTOM_DOC("Interactively open a file out of the file system.") if (file_name.size == 0) break; String_Const_u8 path = result.path_in_text_field; - String_Const_u8 full_file_name = - push_u8_stringf(scratch, "%.*s/%.*s", - string_expand(path), string_expand(file_name)); + String_Const_u8 full_file_name = push_u8_stringf(scratch, "%.*s/%.*s", + string_expand(path), string_expand(file_name)); if (result.is_folder){ set_hot_directory(app, full_file_name); continue; } + if (character_is_slash(file_name.str[file_name.size - 1])){ + File_Attributes attribs = system_quick_file_attributes(scratch, full_file_name); + if (HasFlag(attribs.flags, FileAttribute_IsDirectory)){ + set_hot_directory(app, full_file_name); + continue; + } + if (string_looks_like_drive_letter(file_name)){ + set_hot_directory(app, file_name); + continue; + } + if (query_create_folder(app, file_name)){ + set_hot_directory(app, full_file_name); + continue; + } + break; + } + Buffer_ID buffer = create_buffer(app, full_file_name, 0); if (buffer != 0){ view_set_buffer(app, view, buffer, 0); @@ -622,6 +686,23 @@ CUSTOM_DOC("Interactively creates a new file.") continue; } + if (character_is_slash(file_name.str[file_name.size - 1])){ + File_Attributes attribs = system_quick_file_attributes(scratch, full_file_name); + if (HasFlag(attribs.flags, FileAttribute_IsDirectory)){ + set_hot_directory(app, full_file_name); + continue; + } + if (string_looks_like_drive_letter(file_name)){ + set_hot_directory(app, file_name); + continue; + } + if (query_create_folder(app, file_name)){ + set_hot_directory(app, full_file_name); + continue; + } + break; + } + Buffer_Create_Flag flags = BufferCreate_AlwaysNew; Buffer_ID buffer = create_buffer(app, full_file_name, flags); if (buffer != 0){ @@ -637,8 +718,7 @@ CUSTOM_DOC("Interactively opens a file.") for (;;){ Scratch_Block scratch(app); View_ID view = get_this_ctx_view(app, Access_Always); - File_Name_Result result = get_file_name_from_user(app, scratch, "Open:", - view); + File_Name_Result result = get_file_name_from_user(app, scratch, "Open:", view); if (result.canceled) break; String_Const_u8 file_name = result.file_name_activated; @@ -654,6 +734,19 @@ CUSTOM_DOC("Interactively opens a file.") continue; } + if (character_is_slash(file_name.str[file_name.size - 1])){ + File_Attributes attribs = system_quick_file_attributes(scratch, full_file_name); + if (HasFlag(attribs.flags, FileAttribute_IsDirectory)){ + set_hot_directory(app, full_file_name); + continue; + } + if (query_create_folder(app, file_name)){ + set_hot_directory(app, full_file_name); + continue; + } + break; + } + Buffer_Create_Flag flags = BufferCreate_NeverNew; Buffer_ID buffer = create_buffer(app, full_file_name, flags); if (buffer != 0){ @@ -670,20 +763,20 @@ CUSTOM_DOC("Opens an interactive list of all registered commands.") { View_ID view = get_this_ctx_view(app, Access_Always); if (view != 0){ - Command_Lister_Status_Rule rule = {}; - Buffer_ID buffer = view_get_buffer(app, view, Access_Visible); - Managed_Scope buffer_scope = buffer_get_managed_scope(app, buffer); - Command_Map_ID *map_id_ptr = scope_attachment(app, buffer_scope, buffer_map_id, Command_Map_ID); - if (map_id_ptr != 0){ - rule = command_lister_status_bindings(&framework_mapping, *map_id_ptr); - } - else{ - rule = command_lister_status_descriptions(); - } - Custom_Command_Function *func = get_command_from_user(app, "Command:", &rule); - if (func != 0){ - view_enqueue_command_function(app, view, func); - } + Command_Lister_Status_Rule rule = {}; + Buffer_ID buffer = view_get_buffer(app, view, Access_Visible); + Managed_Scope buffer_scope = buffer_get_managed_scope(app, buffer); + Command_Map_ID *map_id_ptr = scope_attachment(app, buffer_scope, buffer_map_id, Command_Map_ID); + if (map_id_ptr != 0){ + rule = command_lister_status_bindings(&framework_mapping, *map_id_ptr); + } + else{ + rule = command_lister_status_descriptions(); + } + Custom_Command_Function *func = get_command_from_user(app, "Command:", &rule); + if (func != 0){ + view_enqueue_command_function(app, view, func); + } } } diff --git a/custom/4coder_log_parser.cpp b/custom/4coder_log_parser.cpp index dfbccc96..c2b8a3c9 100644 --- a/custom/4coder_log_parser.cpp +++ b/custom/4coder_log_parser.cpp @@ -672,7 +672,7 @@ log_graph_render(Application_Links *app, Frame_Info frame_info, View_ID view){ Rect_f32 view_rect = view_get_screen_rect(app, view); Rect_f32 inner = rect_inner(view_rect, 3); draw_rectangle_fcolor(app, view_rect, 0.f, - get_margin_color(is_active_view?UIHighlight_Active:UIHighlight_None)); + get_item_margin_color(is_active_view?UIHighlight_Active:UIHighlight_None)); draw_rectangle_fcolor(app, inner, 0.f, fcolor_id(defcolor_back)); Rect_f32 prev_clip = draw_set_clip(app, inner); diff --git a/custom/4coder_mac_map.cpp b/custom/4coder_mac_map.cpp new file mode 100644 index 00000000..f21d5dd2 --- /dev/null +++ b/custom/4coder_mac_map.cpp @@ -0,0 +1,160 @@ +/* +4coder_mac_map.cpp - Instantiate mac keyboard bindings. +*/ + +// TOP + +function void +setup_mac_mapping(Mapping *mapping, i64 global_id, i64 file_id, i64 code_id){ + MappingScope(); + SelectMapping(mapping); + + SelectMap(global_id); + BindCore(default_startup, CoreCode_Startup); + BindCore(default_try_exit, CoreCode_TryExit); + Bind(keyboard_macro_start_recording , KeyCode_U, KeyCode_Command); + Bind(keyboard_macro_finish_recording, KeyCode_U, KeyCode_Command, KeyCode_Shift); + Bind(keyboard_macro_replay, KeyCode_U, KeyCode_Control); + Bind(change_active_panel, KeyCode_Comma, KeyCode_Command); + Bind(change_active_panel_backwards, KeyCode_Comma, KeyCode_Command, KeyCode_Shift); + Bind(interactive_new, KeyCode_N, KeyCode_Command); + Bind(interactive_open_or_new, KeyCode_O, KeyCode_Command); + Bind(open_in_other, KeyCode_O, KeyCode_Control); + Bind(interactive_kill_buffer, KeyCode_K, KeyCode_Command); + Bind(interactive_switch_buffer, KeyCode_I, KeyCode_Command); + Bind(project_go_to_root_directory, KeyCode_H, KeyCode_Command); + Bind(save_all_dirty_buffers, KeyCode_S, KeyCode_Command, KeyCode_Shift); + Bind(change_to_build_panel, KeyCode_Period, KeyCode_Control); + Bind(close_build_panel, KeyCode_Comma, KeyCode_Control); + Bind(goto_next_jump, KeyCode_N, KeyCode_Control); + Bind(goto_prev_jump, KeyCode_N, KeyCode_Control, KeyCode_Shift); + Bind(build_in_build_panel, KeyCode_M, KeyCode_Control); + Bind(goto_first_jump, KeyCode_M, KeyCode_Control, KeyCode_Shift); + Bind(toggle_filebar, KeyCode_B, KeyCode_Control); + Bind(execute_any_cli, KeyCode_Z, KeyCode_Control); + Bind(execute_previous_cli, KeyCode_Z, KeyCode_Control, KeyCode_Shift); + Bind(command_lister, KeyCode_X, KeyCode_Control); + Bind(project_command_lister, KeyCode_X, KeyCode_Control, KeyCode_Shift); + Bind(list_all_functions_current_buffer, KeyCode_I, KeyCode_Command, KeyCode_Shift); + Bind(project_fkey_command, KeyCode_F1); + Bind(project_fkey_command, KeyCode_F2); + Bind(project_fkey_command, KeyCode_F3); + Bind(project_fkey_command, KeyCode_F4); + Bind(project_fkey_command, KeyCode_F5); + Bind(project_fkey_command, KeyCode_F6); + Bind(project_fkey_command, KeyCode_F7); + Bind(project_fkey_command, KeyCode_F8); + Bind(project_fkey_command, KeyCode_F9); + Bind(project_fkey_command, KeyCode_F10); + Bind(project_fkey_command, KeyCode_F11); + Bind(project_fkey_command, KeyCode_F12); + Bind(project_fkey_command, KeyCode_F13); + Bind(project_fkey_command, KeyCode_F14); + Bind(project_fkey_command, KeyCode_F15); + Bind(project_fkey_command, KeyCode_F16); + Bind(exit_4coder, KeyCode_F4, KeyCode_Alt); + BindMouseWheel(mouse_wheel_scroll); + BindMouseWheel(mouse_wheel_change_face_size, KeyCode_Command); + + SelectMap(file_id); + ParentMap(global_id); + BindTextInput(write_text_input); + BindMouse(click_set_cursor_and_mark, MouseCode_Left); + BindMouseRelease(click_set_cursor, MouseCode_Left); + BindCore(click_set_cursor_and_mark, CoreCode_ClickActivateView); + BindMouseMove(click_set_cursor_if_lbutton); + Bind(delete_char, KeyCode_Delete); + Bind(backspace_char, KeyCode_Backspace); + Bind(move_up, KeyCode_Up); + Bind(move_down, KeyCode_Down); + Bind(move_left, KeyCode_Left); + Bind(move_right, KeyCode_Right); + Bind(seek_end_of_line, KeyCode_End); + Bind(seek_beginning_of_line, KeyCode_Home); + Bind(page_up, KeyCode_PageUp); + Bind(page_down, KeyCode_PageDown); + Bind(goto_beginning_of_file, KeyCode_PageUp, KeyCode_Command); + Bind(goto_end_of_file, KeyCode_PageDown, KeyCode_Command); + Bind(move_up_to_blank_line_end, KeyCode_Up, KeyCode_Command); + Bind(move_down_to_blank_line_end, KeyCode_Down, KeyCode_Command); + Bind(move_left_whitespace_boundary, KeyCode_Left, KeyCode_Command); + Bind(move_right_whitespace_boundary, KeyCode_Right, KeyCode_Command); + Bind(move_line_up, KeyCode_Up, KeyCode_Alt); + Bind(move_line_down, KeyCode_Down, KeyCode_Alt); + Bind(backspace_alpha_numeric_boundary, KeyCode_Backspace, KeyCode_Command); + Bind(delete_alpha_numeric_boundary, KeyCode_Delete, KeyCode_Command); + Bind(snipe_backward_whitespace_or_token_boundary, KeyCode_Backspace, KeyCode_Control); + Bind(snipe_forward_whitespace_or_token_boundary, KeyCode_Delete, KeyCode_Control); + Bind(set_mark, KeyCode_Space, KeyCode_Control); + Bind(set_mark, KeyCode_ForwardSlash, KeyCode_Command); + Bind(replace_in_range, KeyCode_A, KeyCode_Command); + Bind(copy, KeyCode_C, KeyCode_Command); + Bind(delete_range, KeyCode_D, KeyCode_Command); + Bind(delete_line, KeyCode_D, KeyCode_Command, KeyCode_Shift); + Bind(center_view, KeyCode_E, KeyCode_Command); + Bind(left_adjust_view, KeyCode_E, KeyCode_Command, KeyCode_Shift); + Bind(search, KeyCode_F, KeyCode_Command); + Bind(list_all_locations, KeyCode_F, KeyCode_Command, KeyCode_Shift); + Bind(list_all_substring_locations_case_insensitive, KeyCode_F, KeyCode_Control); + Bind(goto_line, KeyCode_G, KeyCode_Command); + Bind(list_all_locations_of_selection, KeyCode_G, KeyCode_Command, KeyCode_Shift); + Bind(snippet_lister, KeyCode_J, KeyCode_Command); + Bind(kill_buffer, KeyCode_K, KeyCode_Command, KeyCode_Shift); + Bind(duplicate_line, KeyCode_L, KeyCode_Command); + Bind(cursor_mark_swap, KeyCode_M, KeyCode_Command); + Bind(reopen, KeyCode_O, KeyCode_Command, KeyCode_Shift); + Bind(query_replace, KeyCode_Q, KeyCode_Command); + Bind(query_replace_identifier, KeyCode_Q, KeyCode_Command, KeyCode_Shift); + Bind(query_replace_selection, KeyCode_Q, KeyCode_Control); + Bind(reverse_search, KeyCode_R, KeyCode_Command); + Bind(save, KeyCode_S, KeyCode_Command); + Bind(save_all_dirty_buffers, KeyCode_S, KeyCode_Command, KeyCode_Shift); + Bind(search_identifier, KeyCode_T, KeyCode_Command); + Bind(list_all_locations_of_identifier, KeyCode_T, KeyCode_Command, KeyCode_Shift); + Bind(paste_and_indent, KeyCode_V, KeyCode_Command); + Bind(paste_next_and_indent, KeyCode_V, KeyCode_Command, KeyCode_Shift); + Bind(cut, KeyCode_X, KeyCode_Command); + Bind(redo, KeyCode_Y, KeyCode_Command); + Bind(undo, KeyCode_Z, KeyCode_Command); + Bind(view_buffer_other_panel, KeyCode_1, KeyCode_Command); + Bind(swap_panels, KeyCode_2, KeyCode_Command); + Bind(if_read_only_goto_position, KeyCode_Return); + Bind(if_read_only_goto_position_same_panel, KeyCode_Return, KeyCode_Shift); + Bind(view_jump_list_with_lister, KeyCode_Period, KeyCode_Command, KeyCode_Shift); + + SelectMap(code_id); + ParentMap(file_id); + BindTextInput(write_text_and_auto_indent); + Bind(move_left_alpha_numeric_boundary, KeyCode_Left, KeyCode_Command); + Bind(move_right_alpha_numeric_boundary, KeyCode_Right, KeyCode_Command); + Bind(move_left_alpha_numeric_or_camel_boundary, KeyCode_Left, KeyCode_Control); + Bind(move_right_alpha_numeric_or_camel_boundary, KeyCode_Right, KeyCode_Control); + Bind(comment_line_toggle, KeyCode_Semicolon, KeyCode_Command); + Bind(word_complete, KeyCode_Tab); + Bind(auto_indent_range, KeyCode_Tab, KeyCode_Command); + Bind(auto_indent_line_at_cursor, KeyCode_Tab, KeyCode_Shift); + Bind(word_complete_drop_down, KeyCode_Tab, KeyCode_Shift, KeyCode_Command); + Bind(write_block, KeyCode_R, KeyCode_Control); + Bind(write_todo, KeyCode_T, KeyCode_Control); + Bind(write_note, KeyCode_Y, KeyCode_Control); + Bind(list_all_locations_of_type_definition, KeyCode_D, KeyCode_Control); + Bind(list_all_locations_of_type_definition_of_identifier, KeyCode_T, KeyCode_Control, KeyCode_Shift); + Bind(open_long_braces, KeyCode_LeftBracket, KeyCode_Command); + Bind(open_long_braces_semicolon, KeyCode_LeftBracket, KeyCode_Command, KeyCode_Shift); + Bind(open_long_braces_break, KeyCode_RightBracket, KeyCode_Command, KeyCode_Shift); + Bind(select_surrounding_scope, KeyCode_LeftBracket, KeyCode_Control); + Bind(select_surrounding_scope_maximal, KeyCode_LeftBracket, KeyCode_Control, KeyCode_Shift); + Bind(select_prev_scope_absolute, KeyCode_RightBracket, KeyCode_Control); + Bind(select_prev_top_most_scope, KeyCode_RightBracket, KeyCode_Control, KeyCode_Shift); + Bind(select_next_scope_absolute, KeyCode_Quote, KeyCode_Control); + Bind(select_next_scope_after_current, KeyCode_Quote, KeyCode_Control, KeyCode_Shift); + Bind(place_in_scope, KeyCode_ForwardSlash, KeyCode_Control); + Bind(delete_current_scope, KeyCode_Minus, KeyCode_Control); + Bind(if0_off, KeyCode_I, KeyCode_Control); + Bind(open_file_in_quotes, KeyCode_1, KeyCode_Control); + Bind(open_matching_file_cpp, KeyCode_2, KeyCode_Control); + Bind(write_zero_struct, KeyCode_0, KeyCode_Command); +} + +// BOTTOM + diff --git a/custom/4coder_malloc_allocator.cpp b/custom/4coder_malloc_allocator.cpp index a16b7419..8a142f86 100644 --- a/custom/4coder_malloc_allocator.cpp +++ b/custom/4coder_malloc_allocator.cpp @@ -5,7 +5,10 @@ // TOP #include -#include + +#if !OS_MAC +# include +#endif internal void* base_reserve__malloc(void *user_data, u64 size, u64 *size_out, String_Const_u8 location){ diff --git a/custom/4coder_search.cpp b/custom/4coder_search.cpp index 0b35787d..07f293a8 100644 --- a/custom/4coder_search.cpp +++ b/custom/4coder_search.cpp @@ -91,17 +91,20 @@ internal String_Const_u8_Array user_list_definition_array(Application_Links *app, Arena *arena, String_Const_u8 base_needle){ String_Const_u8_Array result = {}; if (base_needle.size > 0){ - result.count = 9; + result.count = 12; result.vals = push_array(arena, String_Const_u8, result.count); i32 i = 0; result.vals[i++] = (push_u8_stringf(arena, "struct %.*s{" , string_expand(base_needle))); result.vals[i++] = (push_u8_stringf(arena, "struct %.*s\n{", string_expand(base_needle))); + result.vals[i++] = (push_u8_stringf(arena, "struct %.*s\r\n{", string_expand(base_needle))); result.vals[i++] = (push_u8_stringf(arena, "struct %.*s {" , string_expand(base_needle))); result.vals[i++] = (push_u8_stringf(arena, "union %.*s{" , string_expand(base_needle))); result.vals[i++] = (push_u8_stringf(arena, "union %.*s\n{" , string_expand(base_needle))); + result.vals[i++] = (push_u8_stringf(arena, "union %.*s\r\n{" , string_expand(base_needle))); result.vals[i++] = (push_u8_stringf(arena, "union %.*s {" , string_expand(base_needle))); result.vals[i++] = (push_u8_stringf(arena, "enum %.*s{" , string_expand(base_needle))); result.vals[i++] = (push_u8_stringf(arena, "enum %.*s\n{" , string_expand(base_needle))); + result.vals[i++] = (push_u8_stringf(arena, "enum %.*s\r\n{" , string_expand(base_needle))); result.vals[i++] = (push_u8_stringf(arena, "enum %.*s {" , string_expand(base_needle))); Assert(i == result.count); } diff --git a/custom/4coder_tutorial.cpp b/custom/4coder_tutorial.cpp index 33067db5..6f4c86cb 100644 --- a/custom/4coder_tutorial.cpp +++ b/custom/4coder_tutorial.cpp @@ -121,7 +121,7 @@ tutorial_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ View_ID active_view = get_active_view(app, Access_Always); b32 is_active_view = (active_view == view_id); - FColor margin_color = get_margin_color(is_active_view?UIHighlight_Active:UIHighlight_None); + FColor margin_color = get_panel_margin_color(is_active_view?UIHighlight_Active:UIHighlight_None); Rect_f32 region = draw_background_and_margin(app, view_id, margin_color, margin_color); Rect_f32 prev_clip = draw_set_clip(app, region); @@ -152,9 +152,9 @@ tutorial_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ Rect_f32_Pair pair = rect_split_left_right(footer, b_width); footer = pair.max; footer.x0 += 10.f; - if (draw_button(app, pair.min, m_p, face, string_u8_litexpr("minimize"))){ - tutorial.hover_action = TutorialAction_Minimize; - } + if (draw_button(app, pair.min, m_p, face, string_u8_litexpr("minimize"))){ + tutorial.hover_action = TutorialAction_Minimize; + } } { @@ -241,7 +241,7 @@ tutorial_run_loop(Application_Links *app){ case CoreCode_ClickActivateView: { tutorial_maximize(app); - tutorial_action(app, tutorial.hover_action); + tutorial_action(app, tutorial.hover_action); change_active_panel(app); }break; diff --git a/custom/4coder_types.h b/custom/4coder_types.h index f432316f..e979bd8c 100644 --- a/custom/4coder_types.h +++ b/custom/4coder_types.h @@ -54,7 +54,7 @@ struct Color_Array{ api(custom) struct Color_Table{ - Color_Array *arrays; + Color_Array *arrays; u32 count; }; @@ -178,6 +178,7 @@ enum{ BufferSetting_Unimportant, BufferSetting_ReadOnly, BufferSetting_RecordsHistory, + BufferSetting_Unkillable, }; api(custom) @@ -707,6 +708,7 @@ struct Layout_Item{ u32 codepoint; Layout_Item_Flag flags; Rect_f32 rect; + f32 padded_y1; }; api(custom) @@ -741,7 +743,7 @@ struct View_Context{ u64 delta_rule_memory_size; b32 hides_buffer; struct Mapping *mapping; - i64 map_id; + i64 map_id; }; api(custom) @@ -777,4 +779,3 @@ struct Process_State{ }; #endif - diff --git a/custom/4coder_version.h b/custom/4coder_version.h index 98596a84..7b6ac772 100644 --- a/custom/4coder_version.h +++ b/custom/4coder_version.h @@ -1,6 +1,6 @@ #define MAJOR 4 #define MINOR 1 -#define PATCH 0 +#define PATCH 2 // string #define VN__(a,b,c) #a "." #b "." #c diff --git a/custom/bin/buildsuper_x64-mac.sh b/custom/bin/buildsuper_x64-mac.sh new file mode 100755 index 00000000..7113ed24 --- /dev/null +++ b/custom/bin/buildsuper_x64-mac.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# If any command errors, stop the script +set -e + +# Store the real CWD +ME="$(realpath "$0")" +LOCATION="$(dirname "$ME")" +CODE_HOME="$(dirname "$LOCATION")" + +# Find the most reasonable candidate build file +SOURCE="$1" +if [ -z "$SOURCE" ]; then + SOURCE="$(realpath "$CODE_HOME/4coder_default_bindings.cpp")" +fi + +# NOTE(yuval): Removed -Wno-writable-strings as it is the same as -Wno-write-strings +opts="-Wno-write-strings -Wno-null-dereference -Wno-comment -Wno-switch -Wno-missing-declarations -Wno-logical-op-parentheses -g" +arch=-m64 + +preproc_file=4coder_command_metadata.i +meta_macros="-DMETA_PASS" +clang++ -I"$CODE_HOME" $meta_macros $arch $opts $debug -std=gnu++0x "$SOURCE" -E -o $preproc_file +clang++ -I"$CODE_HOME" $opts $debug -std=gnu++0x "$CODE_HOME/4coder_metadata_generator.cpp" -o "$CODE_HOME/metadata_generator" +"$CODE_HOME/metadata_generator" -R "$CODE_HOME" "$PWD/$preproc_file" + +clang++ -I"$CODE_HOME" $arch $opts $debug -std=c++11 "$SOURCE" -shared -o custom_4coder.so -fPIC + +rm "$CODE_HOME/metadata_generator" +rm $preproc_file diff --git a/custom/bin/buildsuper_x86-mac.sh b/custom/bin/buildsuper_x86-mac.sh new file mode 100755 index 00000000..fbdb4b2c --- /dev/null +++ b/custom/bin/buildsuper_x86-mac.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# If any command errors, stop the script +set -e + +# Store the real CWD +ME="$(realpath "$0")" +LOCATION="$(dirname "$ME")" +CODE_HOME="$(dirname "$LOCATION")" + +# Find the most reasonable candidate build file +SOURCE="$1" +if [ -z "$SOURCE" ]; then + SOURCE="$(readlink -f "$CODE_HOME/4coder_default_bindings.cpp")" +fi + +# NOTE(yuval): Removed -Wno-writable-strings as it is the same as -Wno-write-strings +opts="-Wno-write-strings -Wno-null-dereference -Wno-comment -Wno-switch -Wno-missing-declarations -Wno-logical-op-parentheses -g" +arch=-m32 + +preproc_file=4coder_command_metadata.i +meta_macros="-DMETA_PASS" +clang++ -I"$CODE_HOME" $meta_macros $arch $opts $debug -std=gnu++0x "$SOURCE" -E -o $preproc_file +clang++ -I"$CODE_HOME" $opts $debug -std=gnu++0x "$CODE_HOME/4coder_metadata_generator.cpp" -o "$CODE_HOME/metadata_generator" +"$CODE_HOME/metadata_generator" -R "$CODE_HOME" "$PWD/$preproc_file" + +clang++ -I"$CODE_HOME" $arch $opts $debug -std=c++11 "$SOURCE" -shared -o custom_4coder.so -fPIC + +rm "$CODE_HOME/metadata_generator" +rm $preproc_file diff --git a/custom/bin/setup_cl_generic.bat b/custom/bin/setup_cl_generic.bat index 50246ce1..84508da2 100644 --- a/custom/bin/setup_cl_generic.bat +++ b/custom/bin/setup_cl_generic.bat @@ -22,3 +22,10 @@ IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcv SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) + diff --git a/custom/generated/4coder_event_codes.h b/custom/generated/4coder_event_codes.h index 8358d6a2..633caf07 100644 --- a/custom/generated/4coder_event_codes.h +++ b/custom/generated/4coder_event_codes.h @@ -1,212 +1,212 @@ enum{ -KeyCode_A = 1, -KeyCode_B = 2, -KeyCode_C = 3, -KeyCode_D = 4, -KeyCode_E = 5, -KeyCode_F = 6, -KeyCode_G = 7, -KeyCode_H = 8, -KeyCode_I = 9, -KeyCode_J = 10, -KeyCode_K = 11, -KeyCode_L = 12, -KeyCode_M = 13, -KeyCode_N = 14, -KeyCode_O = 15, -KeyCode_P = 16, -KeyCode_Q = 17, -KeyCode_R = 18, -KeyCode_S = 19, -KeyCode_T = 20, -KeyCode_U = 21, -KeyCode_V = 22, -KeyCode_W = 23, -KeyCode_X = 24, -KeyCode_Y = 25, -KeyCode_Z = 26, -KeyCode_0 = 27, -KeyCode_1 = 28, -KeyCode_2 = 29, -KeyCode_3 = 30, -KeyCode_4 = 31, -KeyCode_5 = 32, -KeyCode_6 = 33, -KeyCode_7 = 34, -KeyCode_8 = 35, -KeyCode_9 = 36, -KeyCode_Space = 37, -KeyCode_Tick = 38, -KeyCode_Minus = 39, -KeyCode_Equal = 40, -KeyCode_LeftBracket = 41, -KeyCode_RightBracket = 42, -KeyCode_Semicolon = 43, -KeyCode_Quote = 44, -KeyCode_Comma = 45, -KeyCode_Period = 46, -KeyCode_ForwardSlash = 47, -KeyCode_BackwardSlash = 48, -KeyCode_Tab = 49, -KeyCode_Escape = 50, -KeyCode_Pause = 51, -KeyCode_Up = 52, -KeyCode_Down = 53, -KeyCode_Left = 54, -KeyCode_Right = 55, -KeyCode_Backspace = 56, -KeyCode_Return = 57, -KeyCode_Delete = 58, -KeyCode_Insert = 59, -KeyCode_Home = 60, -KeyCode_End = 61, -KeyCode_PageUp = 62, -KeyCode_PageDown = 63, -KeyCode_CapsLock = 64, -KeyCode_NumLock = 65, -KeyCode_ScrollLock = 66, -KeyCode_Menu = 67, -KeyCode_Shift = 68, -KeyCode_Control = 69, -KeyCode_Alt = 70, -KeyCode_Command = 71, -KeyCode_F1 = 72, -KeyCode_F2 = 73, -KeyCode_F3 = 74, -KeyCode_F4 = 75, -KeyCode_F5 = 76, -KeyCode_F6 = 77, -KeyCode_F7 = 78, -KeyCode_F8 = 79, -KeyCode_F9 = 80, -KeyCode_F10 = 81, -KeyCode_F11 = 82, -KeyCode_F12 = 83, -KeyCode_F13 = 84, -KeyCode_F14 = 85, -KeyCode_F15 = 86, -KeyCode_F16 = 87, -KeyCode_COUNT = 88, + KeyCode_A = 1, + KeyCode_B = 2, + KeyCode_C = 3, + KeyCode_D = 4, + KeyCode_E = 5, + KeyCode_F = 6, + KeyCode_G = 7, + KeyCode_H = 8, + KeyCode_I = 9, + KeyCode_J = 10, + KeyCode_K = 11, + KeyCode_L = 12, + KeyCode_M = 13, + KeyCode_N = 14, + KeyCode_O = 15, + KeyCode_P = 16, + KeyCode_Q = 17, + KeyCode_R = 18, + KeyCode_S = 19, + KeyCode_T = 20, + KeyCode_U = 21, + KeyCode_V = 22, + KeyCode_W = 23, + KeyCode_X = 24, + KeyCode_Y = 25, + KeyCode_Z = 26, + KeyCode_0 = 27, + KeyCode_1 = 28, + KeyCode_2 = 29, + KeyCode_3 = 30, + KeyCode_4 = 31, + KeyCode_5 = 32, + KeyCode_6 = 33, + KeyCode_7 = 34, + KeyCode_8 = 35, + KeyCode_9 = 36, + KeyCode_Space = 37, + KeyCode_Tick = 38, + KeyCode_Minus = 39, + KeyCode_Equal = 40, + KeyCode_LeftBracket = 41, + KeyCode_RightBracket = 42, + KeyCode_Semicolon = 43, + KeyCode_Quote = 44, + KeyCode_Comma = 45, + KeyCode_Period = 46, + KeyCode_ForwardSlash = 47, + KeyCode_BackwardSlash = 48, + KeyCode_Tab = 49, + KeyCode_Escape = 50, + KeyCode_Pause = 51, + KeyCode_Up = 52, + KeyCode_Down = 53, + KeyCode_Left = 54, + KeyCode_Right = 55, + KeyCode_Backspace = 56, + KeyCode_Return = 57, + KeyCode_Delete = 58, + KeyCode_Insert = 59, + KeyCode_Home = 60, + KeyCode_End = 61, + KeyCode_PageUp = 62, + KeyCode_PageDown = 63, + KeyCode_CapsLock = 64, + KeyCode_NumLock = 65, + KeyCode_ScrollLock = 66, + KeyCode_Menu = 67, + KeyCode_Shift = 68, + KeyCode_Control = 69, + KeyCode_Alt = 70, + KeyCode_Command = 71, + KeyCode_F1 = 72, + KeyCode_F2 = 73, + KeyCode_F3 = 74, + KeyCode_F4 = 75, + KeyCode_F5 = 76, + KeyCode_F6 = 77, + KeyCode_F7 = 78, + KeyCode_F8 = 79, + KeyCode_F9 = 80, + KeyCode_F10 = 81, + KeyCode_F11 = 82, + KeyCode_F12 = 83, + KeyCode_F13 = 84, + KeyCode_F14 = 85, + KeyCode_F15 = 86, + KeyCode_F16 = 87, + KeyCode_COUNT = 88, }; global char* key_code_name[KeyCode_COUNT] = { -"None", -"A", -"B", -"C", -"D", -"E", -"F", -"G", -"H", -"I", -"J", -"K", -"L", -"M", -"N", -"O", -"P", -"Q", -"R", -"S", -"T", -"U", -"V", -"W", -"X", -"Y", -"Z", -"0", -"1", -"2", -"3", -"4", -"5", -"6", -"7", -"8", -"9", -"Space", -"Tick", -"Minus", -"Equal", -"LeftBracket", -"RightBracket", -"Semicolon", -"Quote", -"Comma", -"Period", -"ForwardSlash", -"BackwardSlash", -"Tab", -"Escape", -"Pause", -"Up", -"Down", -"Left", -"Right", -"Backspace", -"Return", -"Delete", -"Insert", -"Home", -"End", -"PageUp", -"PageDown", -"CapsLock", -"NumLock", -"ScrollLock", -"Menu", -"Shift", -"Control", -"Alt", -"Command", -"F1", -"F2", -"F3", -"F4", -"F5", -"F6", -"F7", -"F8", -"F9", -"F10", -"F11", -"F12", -"F13", -"F14", -"F15", -"F16", + "None", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "Space", + "Tick", + "Minus", + "Equal", + "LeftBracket", + "RightBracket", + "Semicolon", + "Quote", + "Comma", + "Period", + "ForwardSlash", + "BackwardSlash", + "Tab", + "Escape", + "Pause", + "Up", + "Down", + "Left", + "Right", + "Backspace", + "Return", + "Delete", + "Insert", + "Home", + "End", + "PageUp", + "PageDown", + "CapsLock", + "NumLock", + "ScrollLock", + "Menu", + "Shift", + "Control", + "Alt", + "Command", + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "F10", + "F11", + "F12", + "F13", + "F14", + "F15", + "F16", }; enum{ -MouseCode_Left = 1, -MouseCode_Middle = 2, -MouseCode_Right = 3, -MouseCode_COUNT = 4, + MouseCode_Left = 1, + MouseCode_Middle = 2, + MouseCode_Right = 3, + MouseCode_COUNT = 4, }; global char* mouse_code_name[MouseCode_COUNT] = { -"None", -"Left", -"Middle", -"Right", + "None", + "Left", + "Middle", + "Right", }; enum{ -CoreCode_Startup = 1, -CoreCode_Animate = 2, -CoreCode_ClickActivateView = 3, -CoreCode_ClickDeactivateView = 4, -CoreCode_TryExit = 5, -CoreCode_FileExternallyModified = 6, -CoreCode_NewClipboardContents = 7, -CoreCode_COUNT = 8, + CoreCode_Startup = 1, + CoreCode_Animate = 2, + CoreCode_ClickActivateView = 3, + CoreCode_ClickDeactivateView = 4, + CoreCode_TryExit = 5, + CoreCode_FileExternallyModified = 6, + CoreCode_NewClipboardContents = 7, + CoreCode_COUNT = 8, }; global char* core_code_name[CoreCode_COUNT] = { -"None", -"Startup", -"Animate", -"ClickActivateView", -"ClickDeactivateView", -"TryExit", -"FileExternallyModified", -"NewClipboardContents", + "None", + "Startup", + "Animate", + "ClickActivateView", + "ClickDeactivateView", + "TryExit", + "FileExternallyModified", + "NewClipboardContents", }; diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index a6e993c2..f4843974 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -2,7 +2,7 @@ #define command_id(c) (fcoder_metacmd_ID_##c) #define command_metadata(c) (&fcoder_metacmd_table[command_id(c)]) #define command_metadata_by_id(id) (&fcoder_metacmd_table[id]) -#define command_one_past_last_id 229 +#define command_one_past_last_id 231 #if defined(CUSTOM_COMMAND_SIG) #define PROC_LINKS(x,y) x #else @@ -99,6 +99,7 @@ CUSTOM_COMMAND_SIG(list_all_locations_of_type_definition_of_identifier); CUSTOM_COMMAND_SIG(list_all_substring_locations); CUSTOM_COMMAND_SIG(list_all_substring_locations_case_insensitive); CUSTOM_COMMAND_SIG(load_project); +CUSTOM_COMMAND_SIG(load_theme_current_buffer); CUSTOM_COMMAND_SIG(load_themes_default_folder); CUSTOM_COMMAND_SIG(load_themes_hot_directory); CUSTOM_COMMAND_SIG(make_directory_query); @@ -206,6 +207,7 @@ CUSTOM_COMMAND_SIG(snipe_forward_whitespace_or_token_boundary); CUSTOM_COMMAND_SIG(snippet_lister); CUSTOM_COMMAND_SIG(suppress_mouse); CUSTOM_COMMAND_SIG(swap_panels); +CUSTOM_COMMAND_SIG(test_double_backspace); CUSTOM_COMMAND_SIG(theme_lister); CUSTOM_COMMAND_SIG(to_lowercase); CUSTOM_COMMAND_SIG(to_uppercase); @@ -250,236 +252,238 @@ char *source_name; i32 source_name_len; i32 line_number; }; -static Command_Metadata fcoder_metacmd_table[229] = { -{ PROC_LINKS(allow_mouse, 0), false, "allow_mouse", 11, "Shows the mouse and causes all mouse input to be processed normally.", 68, "../code/custom/4coder_default_framework.cpp", 43, 409 }, -{ PROC_LINKS(auto_indent_line_at_cursor, 0), false, "auto_indent_line_at_cursor", 26, "Auto-indents the line on which the cursor sits.", 47, "../code/custom/4coder_auto_indent.cpp", 37, 375 }, -{ PROC_LINKS(auto_indent_range, 0), false, "auto_indent_range", 17, "Auto-indents the range between the cursor and the mark.", 55, "../code/custom/4coder_auto_indent.cpp", 37, 385 }, -{ PROC_LINKS(auto_indent_whole_file, 0), false, "auto_indent_whole_file", 22, "Audo-indents the entire current buffer.", 39, "../code/custom/4coder_auto_indent.cpp", 37, 366 }, -{ PROC_LINKS(backspace_alpha_numeric_boundary, 0), false, "backspace_alpha_numeric_boundary", 32, "Delete characters between the cursor position and the first alphanumeric boundary to the left.", 94, "../code/custom/4coder_base_commands.cpp", 39, 154 }, -{ PROC_LINKS(backspace_char, 0), false, "backspace_char", 14, "Deletes the character to the left of the cursor.", 48, "../code/custom/4coder_base_commands.cpp", 39, 96 }, -{ PROC_LINKS(basic_change_active_panel, 0), false, "basic_change_active_panel", 25, "Change the currently active panel, moving to the panel with the next highest view_id. Will not skipe the build panel if it is open.", 132, "../code/custom/4coder_base_commands.cpp", 39, 613 }, -{ PROC_LINKS(build_in_build_panel, 0), false, "build_in_build_panel", 20, "Looks for a build.bat, build.sh, or makefile in the current and parent directories. Runs the first that it finds and prints the output to *compilation*. Puts the *compilation* buffer in a panel at the footer of the current view.", 230, "../code/custom/4coder_build_commands.cpp", 40, 165 }, -{ PROC_LINKS(build_search, 0), false, "build_search", 12, "Looks for a build.bat, build.sh, or makefile in the current and parent directories. Runs the first that it finds and prints the output to *compilation*.", 153, "../code/custom/4coder_build_commands.cpp", 40, 128 }, -{ PROC_LINKS(center_view, 0), false, "center_view", 11, "Centers the view vertically on the line on which the cursor sits.", 65, "../code/custom/4coder_base_commands.cpp", 39, 197 }, -{ PROC_LINKS(change_active_panel, 0), false, "change_active_panel", 19, "Change the currently active panel, moving to the panel with the next highest view_id.", 85, "../code/custom/4coder_default_framework.cpp", 43, 284 }, -{ PROC_LINKS(change_active_panel_backwards, 0), false, "change_active_panel_backwards", 29, "Change the currently active panel, moving to the panel with the next lowest view_id.", 84, "../code/custom/4coder_default_framework.cpp", 43, 290 }, -{ PROC_LINKS(change_to_build_panel, 0), false, "change_to_build_panel", 21, "If the special build panel is open, makes the build panel the active panel.", 75, "../code/custom/4coder_build_commands.cpp", 40, 186 }, -{ PROC_LINKS(clean_all_lines, 0), false, "clean_all_lines", 15, "Removes trailing whitespace from all lines in the current buffer.", 65, "../code/custom/4coder_base_commands.cpp", 39, 578 }, -{ PROC_LINKS(clear_all_themes, 0), false, "clear_all_themes", 16, "Clear the theme list", 20, "../code/custom/4coder_default_framework.cpp", 43, 480 }, -{ PROC_LINKS(click_set_cursor, 0), false, "click_set_cursor", 16, "Sets the cursor position to the mouse position.", 47, "../code/custom/4coder_base_commands.cpp", 39, 233 }, -{ PROC_LINKS(click_set_cursor_and_mark, 0), false, "click_set_cursor_and_mark", 25, "Sets the cursor position and mark to the mouse position.", 56, "../code/custom/4coder_base_commands.cpp", 39, 223 }, -{ PROC_LINKS(click_set_cursor_if_lbutton, 0), false, "click_set_cursor_if_lbutton", 27, "If the mouse left button is pressed, sets the cursor position to the mouse position.", 84, "../code/custom/4coder_base_commands.cpp", 39, 243 }, -{ PROC_LINKS(click_set_mark, 0), false, "click_set_mark", 14, "Sets the mark position to the mouse position.", 45, "../code/custom/4coder_base_commands.cpp", 39, 255 }, -{ PROC_LINKS(close_all_code, 0), false, "close_all_code", 14, "Closes any buffer with a filename ending with an extension configured to be recognized as a code file type.", 107, "../code/custom/4coder_project_commands.cpp", 42, 842 }, -{ PROC_LINKS(close_build_panel, 0), false, "close_build_panel", 17, "If the special build panel is open, closes it.", 46, "../code/custom/4coder_build_commands.cpp", 40, 180 }, -{ PROC_LINKS(close_panel, 0), false, "close_panel", 11, "Closes the currently active panel if it is not the only panel open.", 67, "../code/custom/4coder_base_commands.cpp", 39, 621 }, -{ PROC_LINKS(command_documentation, 0), true, "command_documentation", 21, "Prompts the user to select a command then loads a doc buffer for that item", 74, "../code/custom/4coder_docs.cpp", 30, 190 }, -{ PROC_LINKS(command_lister, 0), true, "command_lister", 14, "Opens an interactive list of all registered commands.", 53, "../code/custom/4coder_lists.cpp", 31, 668 }, -{ PROC_LINKS(comment_line, 0), false, "comment_line", 12, "Insert '//' at the beginning of the line after leading whitespace.", 66, "../code/custom/4coder_combined_write_commands.cpp", 49, 125 }, -{ PROC_LINKS(comment_line_toggle, 0), false, "comment_line_toggle", 19, "Turns uncommented lines into commented lines and vice versa for comments starting with '//'.", 92, "../code/custom/4coder_combined_write_commands.cpp", 49, 149 }, -{ PROC_LINKS(copy, 0), false, "copy", 4, "Copy the text in the range from the cursor to the mark onto the clipboard.", 74, "../code/custom/4coder_clipboard.cpp", 35, 19 }, -{ PROC_LINKS(cursor_mark_swap, 0), false, "cursor_mark_swap", 16, "Swaps the position of the cursor and the mark.", 46, "../code/custom/4coder_base_commands.cpp", 39, 124 }, -{ PROC_LINKS(custom_api_documentation, 0), true, "custom_api_documentation", 24, "Prompts the user to select a Custom API item then loads a doc buffer for that item", 82, "../code/custom/4coder_docs.cpp", 30, 175 }, -{ PROC_LINKS(cut, 0), false, "cut", 3, "Cut the text in the range from the cursor to the mark onto the clipboard.", 73, "../code/custom/4coder_clipboard.cpp", 35, 28 }, -{ PROC_LINKS(decrease_face_size, 0), false, "decrease_face_size", 18, "Decrease the size of the face used by the current buffer.", 57, "../code/custom/4coder_base_commands.cpp", 39, 684 }, -{ PROC_LINKS(default_file_externally_modified, 0), false, "default_file_externally_modified", 32, "Notes the external modification of attached files by printing a message.", 72, "../code/custom/4coder_base_commands.cpp", 39, 1798 }, -{ PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "../code/custom/4coder_default_hooks.cpp", 39, 7 }, -{ PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "../code/custom/4coder_default_hooks.cpp", 39, 23 }, -{ PROC_LINKS(default_view_input_handler, 0), false, "default_view_input_handler", 26, "Input consumption loop for default view behavior", 48, "../code/custom/4coder_default_hooks.cpp", 39, 57 }, -{ PROC_LINKS(delete_alpha_numeric_boundary, 0), false, "delete_alpha_numeric_boundary", 29, "Delete characters between the cursor position and the first alphanumeric boundary to the right.", 95, "../code/custom/4coder_base_commands.cpp", 39, 162 }, -{ PROC_LINKS(delete_char, 0), false, "delete_char", 11, "Deletes the character to the right of the cursor.", 49, "../code/custom/4coder_base_commands.cpp", 39, 79 }, -{ PROC_LINKS(delete_current_scope, 0), false, "delete_current_scope", 20, "Deletes the braces surrounding the currently selected scope. Leaves the contents within the scope.", 99, "../code/custom/4coder_scope_commands.cpp", 40, 112 }, -{ PROC_LINKS(delete_file_query, 0), false, "delete_file_query", 17, "Deletes the file of the current buffer if 4coder has the appropriate access rights. Will ask the user for confirmation first.", 125, "../code/custom/4coder_base_commands.cpp", 39, 1221 }, -{ PROC_LINKS(delete_line, 0), false, "delete_line", 11, "Delete the line the on which the cursor sits.", 45, "../code/custom/4coder_base_commands.cpp", 39, 1396 }, -{ PROC_LINKS(delete_range, 0), false, "delete_range", 12, "Deletes the text in the range between the cursor and the mark.", 62, "../code/custom/4coder_base_commands.cpp", 39, 134 }, -{ PROC_LINKS(duplicate_line, 0), false, "duplicate_line", 14, "Create a copy of the line on which the cursor sits.", 51, "../code/custom/4coder_base_commands.cpp", 39, 1382 }, -{ PROC_LINKS(execute_any_cli, 0), false, "execute_any_cli", 15, "Queries for an output buffer name and system command, runs the system command as a CLI and prints the output to the specified buffer.", 133, "../code/custom/4coder_cli_command.cpp", 37, 22 }, -{ PROC_LINKS(execute_previous_cli, 0), false, "execute_previous_cli", 20, "If the command execute_any_cli has already been used, this will execute a CLI reusing the most recent buffer name and command.", 126, "../code/custom/4coder_cli_command.cpp", 37, 7 }, -{ PROC_LINKS(exit_4coder, 0), false, "exit_4coder", 11, "Attempts to close 4coder.", 25, "../code/custom/4coder_base_commands.cpp", 39, 740 }, -{ PROC_LINKS(goto_beginning_of_file, 0), false, "goto_beginning_of_file", 22, "Sets the cursor to the beginning of the file.", 45, "../code/custom/4coder_helper.cpp", 32, 2184 }, -{ PROC_LINKS(goto_end_of_file, 0), false, "goto_end_of_file", 16, "Sets the cursor to the end of the file.", 39, "../code/custom/4coder_helper.cpp", 32, 2192 }, -{ PROC_LINKS(goto_first_jump, 0), false, "goto_first_jump", 15, "If a buffer containing jump locations has been locked in, goes to the first jump in the buffer.", 95, "../code/custom/4coder_jump_sticky.cpp", 37, 523 }, -{ PROC_LINKS(goto_first_jump_same_panel_sticky, 0), false, "goto_first_jump_same_panel_sticky", 33, "If a buffer containing jump locations has been locked in, goes to the first jump in the buffer and views the buffer in the panel where the jump list was.", 153, "../code/custom/4coder_jump_sticky.cpp", 37, 540 }, -{ PROC_LINKS(goto_jump_at_cursor, 0), false, "goto_jump_at_cursor", 19, "If the cursor is found to be on a jump location, parses the jump location and brings up the file and position in another view and changes the active panel to the view containing the jump.", 187, "../code/custom/4coder_jump_sticky.cpp", 37, 346 }, -{ PROC_LINKS(goto_jump_at_cursor_same_panel, 0), false, "goto_jump_at_cursor_same_panel", 30, "If the cursor is found to be on a jump location, parses the jump location and brings up the file and position in this view, losing the compilation output or jump list.", 167, "../code/custom/4coder_jump_sticky.cpp", 37, 373 }, -{ PROC_LINKS(goto_line, 0), false, "goto_line", 9, "Queries the user for a number, and jumps the cursor to the corresponding line.", 78, "../code/custom/4coder_base_commands.cpp", 39, 748 }, -{ PROC_LINKS(goto_next_jump, 0), false, "goto_next_jump", 14, "If a buffer containing jump locations has been locked in, goes to the next jump in the buffer, skipping sub jump locations.", 123, "../code/custom/4coder_jump_sticky.cpp", 37, 462 }, -{ PROC_LINKS(goto_next_jump_no_skips, 0), false, "goto_next_jump_no_skips", 23, "If a buffer containing jump locations has been locked in, goes to the next jump in the buffer, and does not skip sub jump locations.", 132, "../code/custom/4coder_jump_sticky.cpp", 37, 492 }, -{ PROC_LINKS(goto_prev_jump, 0), false, "goto_prev_jump", 14, "If a buffer containing jump locations has been locked in, goes to the previous jump in the buffer, skipping sub jump locations.", 127, "../code/custom/4coder_jump_sticky.cpp", 37, 479 }, -{ PROC_LINKS(goto_prev_jump_no_skips, 0), false, "goto_prev_jump_no_skips", 23, "If a buffer containing jump locations has been locked in, goes to the previous jump in the buffer, and does not skip sub jump locations.", 136, "../code/custom/4coder_jump_sticky.cpp", 37, 509 }, -{ PROC_LINKS(hide_filebar, 0), false, "hide_filebar", 12, "Sets the current view to hide it's filebar.", 43, "../code/custom/4coder_base_commands.cpp", 39, 651 }, -{ PROC_LINKS(hide_scrollbar, 0), false, "hide_scrollbar", 14, "Sets the current view to hide it's scrollbar.", 45, "../code/custom/4coder_base_commands.cpp", 39, 637 }, -{ PROC_LINKS(hms_demo_tutorial, 0), false, "hms_demo_tutorial", 17, "Tutorial for built in 4coder bindings and features.", 51, "../code/custom/4coder_tutorial.cpp", 34, 869 }, -{ PROC_LINKS(if0_off, 0), false, "if0_off", 7, "Surround the range between the cursor and mark with an '#if 0' and an '#endif'", 78, "../code/custom/4coder_combined_write_commands.cpp", 49, 70 }, -{ PROC_LINKS(if_read_only_goto_position, 0), false, "if_read_only_goto_position", 26, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor.", 106, "../code/custom/4coder_jump_sticky.cpp", 37, 562 }, -{ PROC_LINKS(if_read_only_goto_position_same_panel, 0), false, "if_read_only_goto_position_same_panel", 37, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor_same_panel.", 117, "../code/custom/4coder_jump_sticky.cpp", 37, 579 }, -{ PROC_LINKS(increase_face_size, 0), false, "increase_face_size", 18, "Increase the size of the face used by the current buffer.", 57, "../code/custom/4coder_base_commands.cpp", 39, 673 }, -{ PROC_LINKS(interactive_kill_buffer, 0), true, "interactive_kill_buffer", 23, "Interactively kill an open buffer.", 34, "../code/custom/4coder_lists.cpp", 31, 515 }, -{ PROC_LINKS(interactive_new, 0), true, "interactive_new", 15, "Interactively creates a new file.", 33, "../code/custom/4coder_lists.cpp", 31, 597 }, -{ PROC_LINKS(interactive_open, 0), true, "interactive_open", 16, "Interactively opens a file.", 27, "../code/custom/4coder_lists.cpp", 31, 634 }, -{ PROC_LINKS(interactive_open_or_new, 0), true, "interactive_open_or_new", 23, "Interactively open a file out of the file system.", 49, "../code/custom/4coder_lists.cpp", 31, 563 }, -{ PROC_LINKS(interactive_switch_buffer, 0), true, "interactive_switch_buffer", 25, "Interactively switch to an open buffer.", 39, "../code/custom/4coder_lists.cpp", 31, 505 }, -{ PROC_LINKS(jump_to_definition, 0), true, "jump_to_definition", 18, "List all definitions in the code index and jump to one chosen by the user.", 74, "../code/custom/4coder_code_index_listers.cpp", 44, 12 }, -{ PROC_LINKS(keyboard_macro_finish_recording, 0), false, "keyboard_macro_finish_recording", 31, "Stop macro recording, do nothing if macro recording is not already started", 74, "../code/custom/4coder_keyboard_macro.cpp", 40, 57 }, -{ PROC_LINKS(keyboard_macro_replay, 0), false, "keyboard_macro_replay", 21, "Replay the most recently recorded keyboard macro", 48, "../code/custom/4coder_keyboard_macro.cpp", 40, 80 }, -{ PROC_LINKS(keyboard_macro_start_recording, 0), false, "keyboard_macro_start_recording", 30, "Start macro recording, do nothing if macro recording is already started", 71, "../code/custom/4coder_keyboard_macro.cpp", 40, 44 }, -{ PROC_LINKS(kill_buffer, 0), false, "kill_buffer", 11, "Kills the current buffer.", 25, "../code/custom/4coder_base_commands.cpp", 39, 1542 }, -{ PROC_LINKS(kill_tutorial, 0), false, "kill_tutorial", 13, "If there is an active tutorial, kill it.", 40, "../code/custom/4coder_tutorial.cpp", 34, 9 }, -{ PROC_LINKS(left_adjust_view, 0), false, "left_adjust_view", 16, "Sets the left size of the view near the x position of the cursor.", 65, "../code/custom/4coder_base_commands.cpp", 39, 211 }, -{ PROC_LINKS(list_all_functions_all_buffers, 0), false, "list_all_functions_all_buffers", 30, "Creates a jump list of lines from all buffers that appear to define or declare functions.", 89, "../code/custom/4coder_function_list.cpp", 39, 295 }, -{ PROC_LINKS(list_all_functions_all_buffers_lister, 0), false, "list_all_functions_all_buffers_lister", 37, "Creates a lister of locations that look like function definitions and declarations all buffers.", 95, "../code/custom/4coder_function_list.cpp", 39, 301 }, -{ PROC_LINKS(list_all_functions_current_buffer, 0), false, "list_all_functions_current_buffer", 33, "Creates a jump list of lines of the current buffer that appear to define or declare functions.", 94, "../code/custom/4coder_function_list.cpp", 39, 267 }, -{ PROC_LINKS(list_all_functions_current_buffer_lister, 0), false, "list_all_functions_current_buffer_lister", 40, "Creates a lister of locations that look like function definitions and declarations in the buffer.", 97, "../code/custom/4coder_function_list.cpp", 39, 277 }, -{ PROC_LINKS(list_all_locations, 0), false, "list_all_locations", 18, "Queries the user for a string and lists all exact case-sensitive matches found in all open buffers.", 99, "../code/custom/4coder_search.cpp", 32, 162 }, -{ PROC_LINKS(list_all_locations_case_insensitive, 0), false, "list_all_locations_case_insensitive", 35, "Queries the user for a string and lists all exact case-insensitive matches found in all open buffers.", 101, "../code/custom/4coder_search.cpp", 32, 174 }, -{ PROC_LINKS(list_all_locations_of_identifier, 0), false, "list_all_locations_of_identifier", 32, "Reads a token or word under the cursor and lists all exact case-sensitive mathces in all open buffers.", 102, "../code/custom/4coder_search.cpp", 32, 186 }, -{ PROC_LINKS(list_all_locations_of_identifier_case_insensitive, 0), false, "list_all_locations_of_identifier_case_insensitive", 49, "Reads a token or word under the cursor and lists all exact case-insensitive mathces in all open buffers.", 104, "../code/custom/4coder_search.cpp", 32, 192 }, -{ PROC_LINKS(list_all_locations_of_selection, 0), false, "list_all_locations_of_selection", 31, "Reads the string in the selected range and lists all exact case-sensitive mathces in all open buffers.", 102, "../code/custom/4coder_search.cpp", 32, 198 }, -{ PROC_LINKS(list_all_locations_of_selection_case_insensitive, 0), false, "list_all_locations_of_selection_case_insensitive", 48, "Reads the string in the selected range and lists all exact case-insensitive mathces in all open buffers.", 104, "../code/custom/4coder_search.cpp", 32, 204 }, -{ PROC_LINKS(list_all_locations_of_type_definition, 0), false, "list_all_locations_of_type_definition", 37, "Queries user for string, lists all locations of strings that appear to define a type whose name matches the input string.", 121, "../code/custom/4coder_search.cpp", 32, 210 }, -{ PROC_LINKS(list_all_locations_of_type_definition_of_identifier, 0), false, "list_all_locations_of_type_definition_of_identifier", 51, "Reads a token or word under the cursor and lists all locations of strings that appear to define a type whose name matches it.", 125, "../code/custom/4coder_search.cpp", 32, 218 }, -{ PROC_LINKS(list_all_substring_locations, 0), false, "list_all_substring_locations", 28, "Queries the user for a string and lists all case-sensitive substring matches found in all open buffers.", 103, "../code/custom/4coder_search.cpp", 32, 168 }, -{ PROC_LINKS(list_all_substring_locations_case_insensitive, 0), false, "list_all_substring_locations_case_insensitive", 45, "Queries the user for a string and lists all case-insensitive substring matches found in all open buffers.", 105, "../code/custom/4coder_search.cpp", 32, 180 }, -{ PROC_LINKS(load_project, 0), false, "load_project", 12, "Looks for a project.4coder file in the current directory and tries to load it. Looks in parent directories until a project file is found or there are no more parents.", 167, "../code/custom/4coder_project_commands.cpp", 42, 862 }, -{ PROC_LINKS(load_themes_default_folder, 0), false, "load_themes_default_folder", 26, "Loads all the theme files in the default theme folder.", 54, "../code/custom/4coder_default_framework.cpp", 43, 457 }, -{ PROC_LINKS(load_themes_hot_directory, 0), false, "load_themes_hot_directory", 25, "Loads all the theme files in the current hot directory.", 55, "../code/custom/4coder_default_framework.cpp", 43, 469 }, -{ PROC_LINKS(make_directory_query, 0), false, "make_directory_query", 20, "Queries the user for a name and creates a new directory with the given name.", 76, "../code/custom/4coder_base_commands.cpp", 39, 1336 }, -{ PROC_LINKS(miblo_decrement_basic, 0), false, "miblo_decrement_basic", 21, "Decrement an integer under the cursor by one.", 45, "../code/custom/4coder_miblo_numbers.cpp", 39, 44 }, -{ PROC_LINKS(miblo_decrement_time_stamp, 0), false, "miblo_decrement_time_stamp", 26, "Decrement a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss", 81, "../code/custom/4coder_miblo_numbers.cpp", 39, 237 }, -{ PROC_LINKS(miblo_decrement_time_stamp_minute, 0), false, "miblo_decrement_time_stamp_minute", 33, "Decrement a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "../code/custom/4coder_miblo_numbers.cpp", 39, 249 }, -{ PROC_LINKS(miblo_increment_basic, 0), false, "miblo_increment_basic", 21, "Increment an integer under the cursor by one.", 45, "../code/custom/4coder_miblo_numbers.cpp", 39, 29 }, -{ PROC_LINKS(miblo_increment_time_stamp, 0), false, "miblo_increment_time_stamp", 26, "Increment a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss", 81, "../code/custom/4coder_miblo_numbers.cpp", 39, 231 }, -{ PROC_LINKS(miblo_increment_time_stamp_minute, 0), false, "miblo_increment_time_stamp_minute", 33, "Increment a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "../code/custom/4coder_miblo_numbers.cpp", 39, 243 }, -{ PROC_LINKS(mouse_wheel_change_face_size, 0), false, "mouse_wheel_change_face_size", 28, "Reads the state of the mouse wheel and uses it to either increase or decrease the face size.", 92, "../code/custom/4coder_base_commands.cpp", 39, 695 }, -{ PROC_LINKS(mouse_wheel_scroll, 0), false, "mouse_wheel_scroll", 18, "Reads the scroll wheel value from the mouse state and scrolls accordingly.", 74, "../code/custom/4coder_base_commands.cpp", 39, 265 }, -{ PROC_LINKS(move_down, 0), false, "move_down", 9, "Moves the cursor down one line.", 31, "../code/custom/4coder_base_commands.cpp", 39, 338 }, -{ PROC_LINKS(move_down_10, 0), false, "move_down_10", 12, "Moves the cursor down ten lines.", 32, "../code/custom/4coder_base_commands.cpp", 39, 350 }, -{ PROC_LINKS(move_down_textual, 0), false, "move_down_textual", 17, "Moves down to the next line of actual text, regardless of line wrapping.", 72, "../code/custom/4coder_base_commands.cpp", 39, 356 }, -{ PROC_LINKS(move_down_to_blank_line, 0), false, "move_down_to_blank_line", 23, "Seeks the cursor down to the next blank line.", 45, "../code/custom/4coder_base_commands.cpp", 39, 409 }, -{ PROC_LINKS(move_down_to_blank_line_end, 0), false, "move_down_to_blank_line_end", 27, "Seeks the cursor down to the next blank line and places it at the end of the line.", 82, "../code/custom/4coder_base_commands.cpp", 39, 433 }, -{ PROC_LINKS(move_down_to_blank_line_skip_whitespace, 0), false, "move_down_to_blank_line_skip_whitespace", 39, "Seeks the cursor down to the next blank line and places it at the end of the line.", 82, "../code/custom/4coder_base_commands.cpp", 39, 421 }, -{ PROC_LINKS(move_left, 0), false, "move_left", 9, "Moves the cursor one character to the left.", 43, "../code/custom/4coder_base_commands.cpp", 39, 439 }, -{ PROC_LINKS(move_left_alpha_numeric_boundary, 0), false, "move_left_alpha_numeric_boundary", 32, "Seek left for boundary between alphanumeric characters and non-alphanumeric characters.", 87, "../code/custom/4coder_base_commands.cpp", 39, 516 }, -{ PROC_LINKS(move_left_alpha_numeric_or_camel_boundary, 0), false, "move_left_alpha_numeric_or_camel_boundary", 41, "Seek left for boundary between alphanumeric characters or camel case word and non-alphanumeric characters.", 106, "../code/custom/4coder_base_commands.cpp", 39, 530 }, -{ PROC_LINKS(move_left_token_boundary, 0), false, "move_left_token_boundary", 24, "Seek left for the next beginning of a token.", 44, "../code/custom/4coder_base_commands.cpp", 39, 488 }, -{ PROC_LINKS(move_left_whitespace_boundary, 0), false, "move_left_whitespace_boundary", 29, "Seek left for the next boundary between whitespace and non-whitespace.", 70, "../code/custom/4coder_base_commands.cpp", 39, 473 }, -{ PROC_LINKS(move_left_whitespace_or_token_boundary, 0), false, "move_left_whitespace_or_token_boundary", 38, "Seek left for the next end of a token or boundary between whitespace and non-whitespace.", 88, "../code/custom/4coder_base_commands.cpp", 39, 502 }, -{ PROC_LINKS(move_line_down, 0), false, "move_line_down", 14, "Swaps the line under the cursor with the line below it, and moves the cursor down with it.", 90, "../code/custom/4coder_base_commands.cpp", 39, 1376 }, -{ PROC_LINKS(move_line_up, 0), false, "move_line_up", 12, "Swaps the line under the cursor with the line above it, and moves the cursor up with it.", 88, "../code/custom/4coder_base_commands.cpp", 39, 1370 }, -{ PROC_LINKS(move_right, 0), false, "move_right", 10, "Moves the cursor one character to the right.", 44, "../code/custom/4coder_base_commands.cpp", 39, 447 }, -{ PROC_LINKS(move_right_alpha_numeric_boundary, 0), false, "move_right_alpha_numeric_boundary", 33, "Seek right for boundary between alphanumeric characters and non-alphanumeric characters.", 88, "../code/custom/4coder_base_commands.cpp", 39, 509 }, -{ PROC_LINKS(move_right_alpha_numeric_or_camel_boundary, 0), false, "move_right_alpha_numeric_or_camel_boundary", 42, "Seek right for boundary between alphanumeric characters or camel case word and non-alphanumeric characters.", 107, "../code/custom/4coder_base_commands.cpp", 39, 523 }, -{ PROC_LINKS(move_right_token_boundary, 0), false, "move_right_token_boundary", 25, "Seek right for the next end of a token.", 39, "../code/custom/4coder_base_commands.cpp", 39, 481 }, -{ PROC_LINKS(move_right_whitespace_boundary, 0), false, "move_right_whitespace_boundary", 30, "Seek right for the next boundary between whitespace and non-whitespace.", 71, "../code/custom/4coder_base_commands.cpp", 39, 465 }, -{ PROC_LINKS(move_right_whitespace_or_token_boundary, 0), false, "move_right_whitespace_or_token_boundary", 39, "Seek right for the next end of a token or boundary between whitespace and non-whitespace.", 89, "../code/custom/4coder_base_commands.cpp", 39, 495 }, -{ PROC_LINKS(move_up, 0), false, "move_up", 7, "Moves the cursor up one line.", 29, "../code/custom/4coder_base_commands.cpp", 39, 332 }, -{ PROC_LINKS(move_up_10, 0), false, "move_up_10", 10, "Moves the cursor up ten lines.", 30, "../code/custom/4coder_base_commands.cpp", 39, 344 }, -{ PROC_LINKS(move_up_to_blank_line, 0), false, "move_up_to_blank_line", 21, "Seeks the cursor up to the next blank line.", 43, "../code/custom/4coder_base_commands.cpp", 39, 403 }, -{ PROC_LINKS(move_up_to_blank_line_end, 0), false, "move_up_to_blank_line_end", 25, "Seeks the cursor up to the next blank line and places it at the end of the line.", 80, "../code/custom/4coder_base_commands.cpp", 39, 427 }, -{ PROC_LINKS(move_up_to_blank_line_skip_whitespace, 0), false, "move_up_to_blank_line_skip_whitespace", 37, "Seeks the cursor up to the next blank line and places it at the end of the line.", 80, "../code/custom/4coder_base_commands.cpp", 39, 415 }, -{ PROC_LINKS(open_all_code, 0), false, "open_all_code", 13, "Open all code in the current directory. File types are determined by extensions. An extension is considered code based on the extensions specified in 4coder.config.", 164, "../code/custom/4coder_project_commands.cpp", 42, 848 }, -{ PROC_LINKS(open_all_code_recursive, 0), false, "open_all_code_recursive", 23, "Works as open_all_code but also runs in all subdirectories.", 59, "../code/custom/4coder_project_commands.cpp", 42, 854 }, -{ PROC_LINKS(open_file_in_quotes, 0), false, "open_file_in_quotes", 19, "Reads a filename from surrounding '\"' characters and attempts to open the corresponding file.", 94, "../code/custom/4coder_base_commands.cpp", 39, 1461 }, -{ PROC_LINKS(open_in_other, 0), false, "open_in_other", 13, "Interactively opens a file in the other panel.", 46, "../code/custom/4coder_base_commands.cpp", 39, 1792 }, -{ PROC_LINKS(open_long_braces, 0), false, "open_long_braces", 16, "At the cursor, insert a '{' and '}' separated by a blank line.", 62, "../code/custom/4coder_combined_write_commands.cpp", 49, 46 }, -{ PROC_LINKS(open_long_braces_break, 0), false, "open_long_braces_break", 22, "At the cursor, insert a '{' and '}break;' separated by a blank line.", 68, "../code/custom/4coder_combined_write_commands.cpp", 49, 62 }, -{ PROC_LINKS(open_long_braces_semicolon, 0), false, "open_long_braces_semicolon", 26, "At the cursor, insert a '{' and '};' separated by a blank line.", 63, "../code/custom/4coder_combined_write_commands.cpp", 49, 54 }, -{ PROC_LINKS(open_matching_file_cpp, 0), false, "open_matching_file_cpp", 22, "If the current file is a *.cpp or *.h, attempts to open the corresponding *.h or *.cpp file in the other view.", 110, "../code/custom/4coder_base_commands.cpp", 39, 1493 }, -{ PROC_LINKS(open_panel_hsplit, 0), false, "open_panel_hsplit", 17, "Create a new panel by horizontally splitting the active panel.", 62, "../code/custom/4coder_default_framework.cpp", 43, 310 }, -{ PROC_LINKS(open_panel_vsplit, 0), false, "open_panel_vsplit", 17, "Create a new panel by vertically splitting the active panel.", 60, "../code/custom/4coder_default_framework.cpp", 43, 300 }, -{ PROC_LINKS(page_down, 0), false, "page_down", 9, "Scrolls the view down one view height and moves the cursor down one view height.", 80, "../code/custom/4coder_base_commands.cpp", 39, 374 }, -{ PROC_LINKS(page_up, 0), false, "page_up", 7, "Scrolls the view up one view height and moves the cursor up one view height.", 76, "../code/custom/4coder_base_commands.cpp", 39, 366 }, -{ PROC_LINKS(paste, 0), false, "paste", 5, "At the cursor, insert the text at the top of the clipboard.", 59, "../code/custom/4coder_clipboard.cpp", 35, 39 }, -{ PROC_LINKS(paste_and_indent, 0), false, "paste_and_indent", 16, "Paste from the top of clipboard and run auto-indent on the newly pasted text.", 77, "../code/custom/4coder_clipboard.cpp", 35, 110 }, -{ PROC_LINKS(paste_next, 0), false, "paste_next", 10, "If the previous command was paste or paste_next, replaces the paste range with the next text down on the clipboard, otherwise operates as the paste command.", 156, "../code/custom/4coder_clipboard.cpp", 35, 71 }, -{ PROC_LINKS(paste_next_and_indent, 0), false, "paste_next_and_indent", 21, "Paste the next item on the clipboard and run auto-indent on the newly pasted text.", 82, "../code/custom/4coder_clipboard.cpp", 35, 117 }, -{ PROC_LINKS(place_in_scope, 0), false, "place_in_scope", 14, "Wraps the code contained in the range between cursor and mark with a new curly brace scope.", 91, "../code/custom/4coder_scope_commands.cpp", 40, 106 }, -{ PROC_LINKS(profile_clear, 0), false, "profile_clear", 13, "Clear all profiling information from 4coder's self profiler.", 60, "../code/custom/4coder_profile.cpp", 33, 226 }, -{ PROC_LINKS(profile_disable, 0), false, "profile_disable", 15, "Prevent 4coder's self profiler from gathering new profiling information.", 72, "../code/custom/4coder_profile.cpp", 33, 219 }, -{ PROC_LINKS(profile_enable, 0), false, "profile_enable", 14, "Allow 4coder's self profiler to gather new profiling information.", 65, "../code/custom/4coder_profile.cpp", 33, 212 }, -{ PROC_LINKS(profile_inspect, 0), true, "profile_inspect", 15, "Inspect all currently collected profiling information in 4coder's self profiler.", 80, "../code/custom/4coder_profile_inspect.cpp", 41, 886 }, -{ PROC_LINKS(project_command_lister, 0), false, "project_command_lister", 22, "Open a lister of all commands in the currently loaded project.", 62, "../code/custom/4coder_project_commands.cpp", 42, 1289 }, -{ PROC_LINKS(project_fkey_command, 0), false, "project_fkey_command", 20, "Run an 'fkey command' configured in a project.4coder file. Determines the index of the 'fkey command' by which function key or numeric key was pressed to trigger the command.", 175, "../code/custom/4coder_project_commands.cpp", 42, 870 }, -{ PROC_LINKS(project_go_to_root_directory, 0), false, "project_go_to_root_directory", 28, "Changes 4coder's hot directory to the root directory of the currently loaded project. With no loaded project nothing hapepns.", 125, "../code/custom/4coder_project_commands.cpp", 42, 896 }, -{ PROC_LINKS(query_replace, 0), false, "query_replace", 13, "Queries the user for two strings, and incrementally replaces every occurence of the first string with the second string.", 120, "../code/custom/4coder_base_commands.cpp", 39, 1149 }, -{ PROC_LINKS(query_replace_identifier, 0), false, "query_replace_identifier", 24, "Queries the user for a string, and incrementally replace every occurence of the word or token found at the cursor with the specified string.", 140, "../code/custom/4coder_base_commands.cpp", 39, 1170 }, -{ PROC_LINKS(query_replace_selection, 0), false, "query_replace_selection", 23, "Queries the user for a string, and incrementally replace every occurence of the string found in the selected range with the specified string.", 141, "../code/custom/4coder_base_commands.cpp", 39, 1186 }, -{ PROC_LINKS(redo, 0), false, "redo", 4, "Advances forwards through the undo history of the current buffer.", 65, "../code/custom/4coder_base_commands.cpp", 39, 1631 }, -{ PROC_LINKS(redo_all_buffers, 0), false, "redo_all_buffers", 16, "Advances forward through the undo history in the buffer containing the most recent regular edit.", 96, "../code/custom/4coder_base_commands.cpp", 39, 1716 }, -{ PROC_LINKS(rename_file_query, 0), false, "rename_file_query", 17, "Queries the user for a new name and renames the file of the current buffer, altering the buffer's name too.", 107, "../code/custom/4coder_base_commands.cpp", 39, 1298 }, -{ PROC_LINKS(reopen, 0), false, "reopen", 6, "Reopen the current buffer from the hard drive.", 46, "../code/custom/4coder_base_commands.cpp", 39, 1560 }, -{ PROC_LINKS(replace_in_all_buffers, 0), false, "replace_in_all_buffers", 22, "Queries the user for a needle and string. Replaces all occurences of needle with string in all editable buffers.", 112, "../code/custom/4coder_base_commands.cpp", 39, 1059 }, -{ PROC_LINKS(replace_in_buffer, 0), false, "replace_in_buffer", 17, "Queries the user for a needle and string. Replaces all occurences of needle with string in the active buffer.", 109, "../code/custom/4coder_base_commands.cpp", 39, 1050 }, -{ PROC_LINKS(replace_in_range, 0), false, "replace_in_range", 16, "Queries the user for a needle and string. Replaces all occurences of needle with string in the range between cursor and the mark in the active buffer.", 150, "../code/custom/4coder_base_commands.cpp", 39, 1041 }, -{ PROC_LINKS(reverse_search, 0), false, "reverse_search", 14, "Begins an incremental search up through the current buffer for a user specified string.", 87, "../code/custom/4coder_base_commands.cpp", 39, 982 }, -{ PROC_LINKS(reverse_search_identifier, 0), false, "reverse_search_identifier", 25, "Begins an incremental search up through the current buffer for the word or token under the cursor.", 98, "../code/custom/4coder_base_commands.cpp", 39, 994 }, -{ PROC_LINKS(save, 0), false, "save", 4, "Saves the current buffer.", 25, "../code/custom/4coder_base_commands.cpp", 39, 1550 }, -{ PROC_LINKS(save_all_dirty_buffers, 0), false, "save_all_dirty_buffers", 22, "Saves all buffers marked dirty (showing the '*' indicator).", 59, "../code/custom/4coder_default_framework.cpp", 43, 382 }, -{ PROC_LINKS(save_to_query, 0), false, "save_to_query", 13, "Queries the user for a file name and saves the contents of the current buffer, altering the buffer's name too.", 110, "../code/custom/4coder_base_commands.cpp", 39, 1265 }, -{ PROC_LINKS(search, 0), false, "search", 6, "Begins an incremental search down through the current buffer for a user specified string.", 89, "../code/custom/4coder_base_commands.cpp", 39, 976 }, -{ PROC_LINKS(search_identifier, 0), false, "search_identifier", 17, "Begins an incremental search down through the current buffer for the word or token under the cursor.", 100, "../code/custom/4coder_base_commands.cpp", 39, 988 }, -{ PROC_LINKS(seek_beginning_of_line, 0), false, "seek_beginning_of_line", 22, "Seeks the cursor to the beginning of the visual line.", 53, "../code/custom/4coder_helper.cpp", 32, 2172 }, -{ PROC_LINKS(seek_beginning_of_textual_line, 0), false, "seek_beginning_of_textual_line", 30, "Seeks the cursor to the beginning of the line across all text.", 62, "../code/custom/4coder_helper.cpp", 32, 2160 }, -{ PROC_LINKS(seek_end_of_line, 0), false, "seek_end_of_line", 16, "Seeks the cursor to the end of the visual line.", 47, "../code/custom/4coder_helper.cpp", 32, 2178 }, -{ PROC_LINKS(seek_end_of_textual_line, 0), false, "seek_end_of_textual_line", 24, "Seeks the cursor to the end of the line across all text.", 56, "../code/custom/4coder_helper.cpp", 32, 2166 }, -{ PROC_LINKS(select_all, 0), false, "select_all", 10, "Puts the cursor at the top of the file, and the mark at the bottom of the file.", 79, "../code/custom/4coder_base_commands.cpp", 39, 539 }, -{ PROC_LINKS(select_next_scope_absolute, 0), false, "select_next_scope_absolute", 26, "Finds the first scope started by '{' after the cursor and puts the cursor and mark on the '{' and '}'.", 102, "../code/custom/4coder_scope_commands.cpp", 40, 57 }, -{ PROC_LINKS(select_next_scope_after_current, 0), false, "select_next_scope_after_current", 31, "If a scope is selected, find first scope that starts after the selected scope. Otherwise find the first scope that starts after the cursor.", 139, "../code/custom/4coder_scope_commands.cpp", 40, 66 }, -{ PROC_LINKS(select_prev_scope_absolute, 0), false, "select_prev_scope_absolute", 26, "Finds the first scope started by '{' before the cursor and puts the cursor and mark on the '{' and '}'.", 103, "../code/custom/4coder_scope_commands.cpp", 40, 82 }, -{ PROC_LINKS(select_prev_top_most_scope, 0), false, "select_prev_top_most_scope", 26, "Finds the first scope that starts before the cursor, then finds the top most scope that contains that scope.", 108, "../code/custom/4coder_scope_commands.cpp", 40, 99 }, -{ PROC_LINKS(select_surrounding_scope, 0), false, "select_surrounding_scope", 24, "Finds the scope enclosed by '{' '}' surrounding the cursor and puts the cursor and mark on the '{' and '}'.", 107, "../code/custom/4coder_scope_commands.cpp", 40, 27 }, -{ PROC_LINKS(select_surrounding_scope_maximal, 0), false, "select_surrounding_scope_maximal", 32, "Selects the top-most scope that surrounds the cursor.", 53, "../code/custom/4coder_scope_commands.cpp", 40, 39 }, -{ PROC_LINKS(set_eol_mode_from_contents, 0), false, "set_eol_mode_from_contents", 26, "Sets the buffer's line ending mode to match the contents of the buffer.", 71, "../code/custom/4coder_eol.cpp", 29, 125 }, -{ PROC_LINKS(set_eol_mode_to_binary, 0), false, "set_eol_mode_to_binary", 22, "Puts the buffer in bin line ending mode.", 40, "../code/custom/4coder_eol.cpp", 29, 112 }, -{ PROC_LINKS(set_eol_mode_to_crlf, 0), false, "set_eol_mode_to_crlf", 20, "Puts the buffer in crlf line ending mode.", 41, "../code/custom/4coder_eol.cpp", 29, 86 }, -{ PROC_LINKS(set_eol_mode_to_lf, 0), false, "set_eol_mode_to_lf", 18, "Puts the buffer in lf line ending mode.", 39, "../code/custom/4coder_eol.cpp", 29, 99 }, -{ PROC_LINKS(set_mark, 0), false, "set_mark", 8, "Sets the mark to the current position of the cursor.", 52, "../code/custom/4coder_base_commands.cpp", 39, 115 }, -{ PROC_LINKS(set_mode_to_notepad_like, 0), false, "set_mode_to_notepad_like", 24, "Sets the edit mode to Notepad like.", 35, "../code/custom/4coder_default_framework.cpp", 43, 427 }, -{ PROC_LINKS(set_mode_to_original, 0), false, "set_mode_to_original", 20, "Sets the edit mode to 4coder original.", 38, "../code/custom/4coder_default_framework.cpp", 43, 421 }, -{ PROC_LINKS(setup_build_bat, 0), false, "setup_build_bat", 15, "Queries the user for several configuration options and initializes a new build batch script.", 92, "../code/custom/4coder_project_commands.cpp", 42, 1237 }, -{ PROC_LINKS(setup_build_bat_and_sh, 0), false, "setup_build_bat_and_sh", 22, "Queries the user for several configuration options and initializes a new build batch script.", 92, "../code/custom/4coder_project_commands.cpp", 42, 1249 }, -{ PROC_LINKS(setup_build_sh, 0), false, "setup_build_sh", 14, "Queries the user for several configuration options and initializes a new build shell script.", 92, "../code/custom/4coder_project_commands.cpp", 42, 1243 }, -{ PROC_LINKS(setup_new_project, 0), false, "setup_new_project", 17, "Queries the user for several configuration options and initializes a new 4coder project with build scripts for every OS.", 120, "../code/custom/4coder_project_commands.cpp", 42, 1230 }, -{ PROC_LINKS(show_filebar, 0), false, "show_filebar", 12, "Sets the current view to show it's filebar.", 43, "../code/custom/4coder_base_commands.cpp", 39, 644 }, -{ PROC_LINKS(show_scrollbar, 0), false, "show_scrollbar", 14, "Sets the current view to show it's scrollbar.", 45, "../code/custom/4coder_base_commands.cpp", 39, 630 }, -{ PROC_LINKS(show_the_log_graph, 0), true, "show_the_log_graph", 18, "Parses *log* and displays the 'log graph' UI", 44, "../code/custom/4coder_log_parser.cpp", 36, 994 }, -{ PROC_LINKS(snipe_backward_whitespace_or_token_boundary, 0), false, "snipe_backward_whitespace_or_token_boundary", 43, "Delete a single, whole token on or to the left of the cursor and post it to the clipboard.", 90, "../code/custom/4coder_base_commands.cpp", 39, 179 }, -{ PROC_LINKS(snipe_forward_whitespace_or_token_boundary, 0), false, "snipe_forward_whitespace_or_token_boundary", 42, "Delete a single, whole token on or to the right of the cursor and post it to the clipboard.", 91, "../code/custom/4coder_base_commands.cpp", 39, 187 }, -{ PROC_LINKS(snippet_lister, 0), true, "snippet_lister", 14, "Opens a snippet lister for inserting whole pre-written snippets of text.", 72, "../code/custom/4coder_combined_write_commands.cpp", 49, 237 }, -{ PROC_LINKS(suppress_mouse, 0), false, "suppress_mouse", 14, "Hides the mouse and causes all mosue input (clicks, position, wheel) to be ignored.", 83, "../code/custom/4coder_default_framework.cpp", 43, 403 }, -{ PROC_LINKS(swap_panels, 0), false, "swap_panels", 11, "Swaps the active panel with it's sibling.", 41, "../code/custom/4coder_base_commands.cpp", 39, 1518 }, -{ PROC_LINKS(theme_lister, 0), true, "theme_lister", 12, "Opens an interactive list of all registered themes.", 51, "../code/custom/4coder_lists.cpp", 31, 692 }, -{ PROC_LINKS(to_lowercase, 0), false, "to_lowercase", 12, "Converts all ascii text in the range between the cursor and the mark to lowercase.", 82, "../code/custom/4coder_base_commands.cpp", 39, 565 }, -{ PROC_LINKS(to_uppercase, 0), false, "to_uppercase", 12, "Converts all ascii text in the range between the cursor and the mark to uppercase.", 82, "../code/custom/4coder_base_commands.cpp", 39, 552 }, -{ PROC_LINKS(toggle_filebar, 0), false, "toggle_filebar", 14, "Toggles the visibility status of the current view's filebar.", 60, "../code/custom/4coder_base_commands.cpp", 39, 658 }, -{ PROC_LINKS(toggle_fps_meter, 0), false, "toggle_fps_meter", 16, "Toggles the visibility of the FPS performance meter", 51, "../code/custom/4coder_base_commands.cpp", 39, 667 }, -{ PROC_LINKS(toggle_fullscreen, 0), false, "toggle_fullscreen", 17, "Toggle fullscreen mode on or off. The change(s) do not take effect until the next frame.", 89, "../code/custom/4coder_default_framework.cpp", 43, 451 }, -{ PROC_LINKS(toggle_highlight_enclosing_scopes, 0), false, "toggle_highlight_enclosing_scopes", 33, "In code files scopes surrounding the cursor are highlighted with distinguishing colors.", 87, "../code/custom/4coder_default_framework.cpp", 43, 439 }, -{ PROC_LINKS(toggle_highlight_line_at_cursor, 0), false, "toggle_highlight_line_at_cursor", 31, "Toggles the line highlight at the cursor.", 41, "../code/custom/4coder_default_framework.cpp", 43, 433 }, -{ PROC_LINKS(toggle_line_numbers, 0), false, "toggle_line_numbers", 19, "Toggles the left margin line numbers.", 37, "../code/custom/4coder_base_commands.cpp", 39, 721 }, -{ PROC_LINKS(toggle_line_wrap, 0), false, "toggle_line_wrap", 16, "Toggles the line wrap setting on this buffer.", 45, "../code/custom/4coder_base_commands.cpp", 39, 727 }, -{ PROC_LINKS(toggle_mouse, 0), false, "toggle_mouse", 12, "Toggles the mouse suppression mode, see suppress_mouse and allow_mouse.", 71, "../code/custom/4coder_default_framework.cpp", 43, 415 }, -{ PROC_LINKS(toggle_paren_matching_helper, 0), false, "toggle_paren_matching_helper", 28, "In code files matching parentheses pairs are colored with distinguishing colors.", 80, "../code/custom/4coder_default_framework.cpp", 43, 445 }, -{ PROC_LINKS(toggle_show_whitespace, 0), false, "toggle_show_whitespace", 22, "Toggles the current buffer's whitespace visibility status.", 58, "../code/custom/4coder_base_commands.cpp", 39, 712 }, -{ PROC_LINKS(toggle_virtual_whitespace, 0), false, "toggle_virtual_whitespace", 25, "Toggles the current buffer's virtual whitespace status.", 55, "../code/custom/4coder_code_index.cpp", 36, 1160 }, -{ PROC_LINKS(tutorial_maximize, 0), false, "tutorial_maximize", 17, "Expand the tutorial window", 26, "../code/custom/4coder_tutorial.cpp", 34, 20 }, -{ PROC_LINKS(tutorial_minimize, 0), false, "tutorial_minimize", 17, "Shrink the tutorial window", 26, "../code/custom/4coder_tutorial.cpp", 34, 34 }, -{ PROC_LINKS(uncomment_line, 0), false, "uncomment_line", 14, "If present, delete '//' at the beginning of the line after leading whitespace.", 78, "../code/custom/4coder_combined_write_commands.cpp", 49, 137 }, -{ PROC_LINKS(undo, 0), false, "undo", 4, "Advances backwards through the undo history of the current buffer.", 66, "../code/custom/4coder_base_commands.cpp", 39, 1618 }, -{ PROC_LINKS(undo_all_buffers, 0), false, "undo_all_buffers", 16, "Advances backward through the undo history in the buffer containing the most recent regular edit.", 97, "../code/custom/4coder_base_commands.cpp", 39, 1645 }, -{ PROC_LINKS(view_buffer_other_panel, 0), false, "view_buffer_other_panel", 23, "Set the other non-active panel to view the buffer that the active panel views, and switch to that panel.", 104, "../code/custom/4coder_base_commands.cpp", 39, 1506 }, -{ PROC_LINKS(view_jump_list_with_lister, 0), false, "view_jump_list_with_lister", 26, "When executed on a buffer with jumps, creates a persistent lister for all the jumps", 83, "../code/custom/4coder_jump_lister.cpp", 37, 59 }, -{ PROC_LINKS(word_complete, 0), false, "word_complete", 13, "Iteratively tries completing the word to the left of the cursor with other words in open buffers that have the same prefix string.", 130, "../code/custom/4coder_search.cpp", 32, 392 }, -{ PROC_LINKS(word_complete_drop_down, 0), false, "word_complete_drop_down", 23, "Word complete with drop down menu.", 34, "../code/custom/4coder_search.cpp", 32, 639 }, -{ PROC_LINKS(write_block, 0), false, "write_block", 11, "At the cursor, insert a block comment.", 38, "../code/custom/4coder_combined_write_commands.cpp", 49, 94 }, -{ PROC_LINKS(write_hack, 0), false, "write_hack", 10, "At the cursor, insert a '// HACK' comment, includes user name if it was specified in config.4coder.", 99, "../code/custom/4coder_combined_write_commands.cpp", 49, 82 }, -{ PROC_LINKS(write_note, 0), false, "write_note", 10, "At the cursor, insert a '// NOTE' comment, includes user name if it was specified in config.4coder.", 99, "../code/custom/4coder_combined_write_commands.cpp", 49, 88 }, -{ PROC_LINKS(write_space, 0), false, "write_space", 11, "Inserts an underscore.", 22, "../code/custom/4coder_base_commands.cpp", 39, 67 }, -{ PROC_LINKS(write_text_and_auto_indent, 0), false, "write_text_and_auto_indent", 26, "Inserts text and auto-indents the line on which the cursor sits if any of the text contains 'layout punctuation' such as ;:{}()[]# and new lines.", 145, "../code/custom/4coder_auto_indent.cpp", 37, 395 }, -{ PROC_LINKS(write_text_input, 0), false, "write_text_input", 16, "Inserts whatever text was used to trigger this command.", 55, "../code/custom/4coder_base_commands.cpp", 39, 59 }, -{ PROC_LINKS(write_todo, 0), false, "write_todo", 10, "At the cursor, insert a '// TODO' comment, includes user name if it was specified in config.4coder.", 99, "../code/custom/4coder_combined_write_commands.cpp", 49, 76 }, -{ PROC_LINKS(write_underscore, 0), false, "write_underscore", 16, "Inserts an underscore.", 22, "../code/custom/4coder_base_commands.cpp", 39, 73 }, -{ PROC_LINKS(write_zero_struct, 0), false, "write_zero_struct", 17, "At the cursor, insert a ' = {};'.", 33, "../code/custom/4coder_combined_write_commands.cpp", 49, 100 }, +static Command_Metadata fcoder_metacmd_table[231] = { +{ PROC_LINKS(allow_mouse, 0), false, "allow_mouse", 11, "Shows the mouse and causes all mouse input to be processed normally.", 68, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 409 }, +{ PROC_LINKS(auto_indent_line_at_cursor, 0), false, "auto_indent_line_at_cursor", 26, "Auto-indents the line on which the cursor sits.", 47, "c:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 407 }, +{ PROC_LINKS(auto_indent_range, 0), false, "auto_indent_range", 17, "Auto-indents the range between the cursor and the mark.", 55, "c:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 417 }, +{ PROC_LINKS(auto_indent_whole_file, 0), false, "auto_indent_whole_file", 22, "Audo-indents the entire current buffer.", 39, "c:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 398 }, +{ PROC_LINKS(backspace_alpha_numeric_boundary, 0), false, "backspace_alpha_numeric_boundary", 32, "Delete characters between the cursor position and the first alphanumeric boundary to the left.", 94, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 165 }, +{ PROC_LINKS(backspace_char, 0), false, "backspace_char", 14, "Deletes the character to the left of the cursor.", 48, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 96 }, +{ PROC_LINKS(basic_change_active_panel, 0), false, "basic_change_active_panel", 25, "Change the currently active panel, moving to the panel with the next highest view_id. Will not skipe the build panel if it is open.", 132, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 622 }, +{ PROC_LINKS(build_in_build_panel, 0), false, "build_in_build_panel", 20, "Looks for a build.bat, build.sh, or makefile in the current and parent directories. Runs the first that it finds and prints the output to *compilation*. Puts the *compilation* buffer in a panel at the footer of the current view.", 230, "c:\\4ed\\code\\custom\\4coder_build_commands.cpp", 44, 159 }, +{ PROC_LINKS(build_search, 0), false, "build_search", 12, "Looks for a build.bat, build.sh, or makefile in the current and parent directories. Runs the first that it finds and prints the output to *compilation*.", 153, "c:\\4ed\\code\\custom\\4coder_build_commands.cpp", 44, 122 }, +{ PROC_LINKS(center_view, 0), false, "center_view", 11, "Centers the view vertically on the line on which the cursor sits.", 65, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 208 }, +{ PROC_LINKS(change_active_panel, 0), false, "change_active_panel", 19, "Change the currently active panel, moving to the panel with the next highest view_id.", 85, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 284 }, +{ PROC_LINKS(change_active_panel_backwards, 0), false, "change_active_panel_backwards", 29, "Change the currently active panel, moving to the panel with the next lowest view_id.", 84, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 290 }, +{ PROC_LINKS(change_to_build_panel, 0), false, "change_to_build_panel", 21, "If the special build panel is open, makes the build panel the active panel.", 75, "c:\\4ed\\code\\custom\\4coder_build_commands.cpp", 44, 180 }, +{ PROC_LINKS(clean_all_lines, 0), false, "clean_all_lines", 15, "Removes trailing whitespace from all lines in the current buffer.", 65, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 587 }, +{ PROC_LINKS(clear_all_themes, 0), false, "clear_all_themes", 16, "Clear the theme list", 20, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 480 }, +{ PROC_LINKS(click_set_cursor, 0), false, "click_set_cursor", 16, "Sets the cursor position to the mouse position.", 47, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 244 }, +{ PROC_LINKS(click_set_cursor_and_mark, 0), false, "click_set_cursor_and_mark", 25, "Sets the cursor position and mark to the mouse position.", 56, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 234 }, +{ PROC_LINKS(click_set_cursor_if_lbutton, 0), false, "click_set_cursor_if_lbutton", 27, "If the mouse left button is pressed, sets the cursor position to the mouse position.", 84, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 254 }, +{ PROC_LINKS(click_set_mark, 0), false, "click_set_mark", 14, "Sets the mark position to the mouse position.", 45, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 266 }, +{ PROC_LINKS(close_all_code, 0), false, "close_all_code", 14, "Closes any buffer with a filename ending with an extension configured to be recognized as a code file type.", 107, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 842 }, +{ PROC_LINKS(close_build_panel, 0), false, "close_build_panel", 17, "If the special build panel is open, closes it.", 46, "c:\\4ed\\code\\custom\\4coder_build_commands.cpp", 44, 174 }, +{ PROC_LINKS(close_panel, 0), false, "close_panel", 11, "Closes the currently active panel if it is not the only panel open.", 67, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 630 }, +{ PROC_LINKS(command_documentation, 0), true, "command_documentation", 21, "Prompts the user to select a command then loads a doc buffer for that item", 74, "c:\\4ed\\code\\custom\\4coder_docs.cpp", 34, 190 }, +{ PROC_LINKS(command_lister, 0), true, "command_lister", 14, "Opens an interactive list of all registered commands.", 53, "c:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 761 }, +{ PROC_LINKS(comment_line, 0), false, "comment_line", 12, "Insert '//' at the beginning of the line after leading whitespace.", 66, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 125 }, +{ PROC_LINKS(comment_line_toggle, 0), false, "comment_line_toggle", 19, "Turns uncommented lines into commented lines and vice versa for comments starting with '//'.", 92, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 149 }, +{ PROC_LINKS(copy, 0), false, "copy", 4, "Copy the text in the range from the cursor to the mark onto the clipboard.", 74, "c:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 19 }, +{ PROC_LINKS(cursor_mark_swap, 0), false, "cursor_mark_swap", 16, "Swaps the position of the cursor and the mark.", 46, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 135 }, +{ PROC_LINKS(custom_api_documentation, 0), true, "custom_api_documentation", 24, "Prompts the user to select a Custom API item then loads a doc buffer for that item", 82, "c:\\4ed\\code\\custom\\4coder_docs.cpp", 34, 175 }, +{ PROC_LINKS(cut, 0), false, "cut", 3, "Cut the text in the range from the cursor to the mark onto the clipboard.", 73, "c:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 28 }, +{ PROC_LINKS(decrease_face_size, 0), false, "decrease_face_size", 18, "Decrease the size of the face used by the current buffer.", 57, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 693 }, +{ PROC_LINKS(default_file_externally_modified, 0), false, "default_file_externally_modified", 32, "Notes the external modification of attached files by printing a message.", 72, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1804 }, +{ PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "c:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 7 }, +{ PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "c:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 23 }, +{ PROC_LINKS(default_view_input_handler, 0), false, "default_view_input_handler", 26, "Input consumption loop for default view behavior", 48, "c:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 51 }, +{ PROC_LINKS(delete_alpha_numeric_boundary, 0), false, "delete_alpha_numeric_boundary", 29, "Delete characters between the cursor position and the first alphanumeric boundary to the right.", 95, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 173 }, +{ PROC_LINKS(delete_char, 0), false, "delete_char", 11, "Deletes the character to the right of the cursor.", 49, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 79 }, +{ PROC_LINKS(delete_current_scope, 0), false, "delete_current_scope", 20, "Deletes the braces surrounding the currently selected scope. Leaves the contents within the scope.", 99, "c:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 112 }, +{ PROC_LINKS(delete_file_query, 0), false, "delete_file_query", 17, "Deletes the file of the current buffer if 4coder has the appropriate access rights. Will ask the user for confirmation first.", 125, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1230 }, +{ PROC_LINKS(delete_line, 0), false, "delete_line", 11, "Delete the line the on which the cursor sits.", 45, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1402 }, +{ PROC_LINKS(delete_range, 0), false, "delete_range", 12, "Deletes the text in the range between the cursor and the mark.", 62, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 145 }, +{ PROC_LINKS(duplicate_line, 0), false, "duplicate_line", 14, "Create a copy of the line on which the cursor sits.", 51, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1388 }, +{ PROC_LINKS(execute_any_cli, 0), false, "execute_any_cli", 15, "Queries for an output buffer name and system command, runs the system command as a CLI and prints the output to the specified buffer.", 133, "c:\\4ed\\code\\custom\\4coder_cli_command.cpp", 41, 22 }, +{ PROC_LINKS(execute_previous_cli, 0), false, "execute_previous_cli", 20, "If the command execute_any_cli has already been used, this will execute a CLI reusing the most recent buffer name and command.", 126, "c:\\4ed\\code\\custom\\4coder_cli_command.cpp", 41, 7 }, +{ PROC_LINKS(exit_4coder, 0), false, "exit_4coder", 11, "Attempts to close 4coder.", 25, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 749 }, +{ PROC_LINKS(goto_beginning_of_file, 0), false, "goto_beginning_of_file", 22, "Sets the cursor to the beginning of the file.", 45, "c:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2184 }, +{ PROC_LINKS(goto_end_of_file, 0), false, "goto_end_of_file", 16, "Sets the cursor to the end of the file.", 39, "c:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2192 }, +{ PROC_LINKS(goto_first_jump, 0), false, "goto_first_jump", 15, "If a buffer containing jump locations has been locked in, goes to the first jump in the buffer.", 95, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 525 }, +{ PROC_LINKS(goto_first_jump_same_panel_sticky, 0), false, "goto_first_jump_same_panel_sticky", 33, "If a buffer containing jump locations has been locked in, goes to the first jump in the buffer and views the buffer in the panel where the jump list was.", 153, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 542 }, +{ PROC_LINKS(goto_jump_at_cursor, 0), false, "goto_jump_at_cursor", 19, "If the cursor is found to be on a jump location, parses the jump location and brings up the file and position in another view and changes the active panel to the view containing the jump.", 187, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 348 }, +{ PROC_LINKS(goto_jump_at_cursor_same_panel, 0), false, "goto_jump_at_cursor_same_panel", 30, "If the cursor is found to be on a jump location, parses the jump location and brings up the file and position in this view, losing the compilation output or jump list.", 167, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 375 }, +{ PROC_LINKS(goto_line, 0), false, "goto_line", 9, "Queries the user for a number, and jumps the cursor to the corresponding line.", 78, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 757 }, +{ PROC_LINKS(goto_next_jump, 0), false, "goto_next_jump", 14, "If a buffer containing jump locations has been locked in, goes to the next jump in the buffer, skipping sub jump locations.", 123, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 464 }, +{ PROC_LINKS(goto_next_jump_no_skips, 0), false, "goto_next_jump_no_skips", 23, "If a buffer containing jump locations has been locked in, goes to the next jump in the buffer, and does not skip sub jump locations.", 132, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 494 }, +{ PROC_LINKS(goto_prev_jump, 0), false, "goto_prev_jump", 14, "If a buffer containing jump locations has been locked in, goes to the previous jump in the buffer, skipping sub jump locations.", 127, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 481 }, +{ PROC_LINKS(goto_prev_jump_no_skips, 0), false, "goto_prev_jump_no_skips", 23, "If a buffer containing jump locations has been locked in, goes to the previous jump in the buffer, and does not skip sub jump locations.", 136, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 511 }, +{ PROC_LINKS(hide_filebar, 0), false, "hide_filebar", 12, "Sets the current view to hide it's filebar.", 43, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 660 }, +{ PROC_LINKS(hide_scrollbar, 0), false, "hide_scrollbar", 14, "Sets the current view to hide it's scrollbar.", 45, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 646 }, +{ PROC_LINKS(hms_demo_tutorial, 0), false, "hms_demo_tutorial", 17, "Tutorial for built in 4coder bindings and features.", 51, "c:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 869 }, +{ PROC_LINKS(if0_off, 0), false, "if0_off", 7, "Surround the range between the cursor and mark with an '#if 0' and an '#endif'", 78, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 70 }, +{ PROC_LINKS(if_read_only_goto_position, 0), false, "if_read_only_goto_position", 26, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor.", 106, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 564 }, +{ PROC_LINKS(if_read_only_goto_position_same_panel, 0), false, "if_read_only_goto_position_same_panel", 37, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor_same_panel.", 117, "c:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 581 }, +{ PROC_LINKS(increase_face_size, 0), false, "increase_face_size", 18, "Increase the size of the face used by the current buffer.", 57, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 682 }, +{ PROC_LINKS(interactive_kill_buffer, 0), true, "interactive_kill_buffer", 23, "Interactively kill an open buffer.", 34, "c:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 520 }, +{ PROC_LINKS(interactive_new, 0), true, "interactive_new", 15, "Interactively creates a new file.", 33, "c:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 661 }, +{ PROC_LINKS(interactive_open, 0), true, "interactive_open", 16, "Interactively opens a file.", 27, "c:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 715 }, +{ PROC_LINKS(interactive_open_or_new, 0), true, "interactive_open_or_new", 23, "Interactively open a file out of the file system.", 49, "c:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 612 }, +{ PROC_LINKS(interactive_switch_buffer, 0), true, "interactive_switch_buffer", 25, "Interactively switch to an open buffer.", 39, "c:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 510 }, +{ PROC_LINKS(jump_to_definition, 0), true, "jump_to_definition", 18, "List all definitions in the code index and jump to one chosen by the user.", 74, "c:\\4ed\\code\\custom\\4coder_code_index_listers.cpp", 48, 12 }, +{ PROC_LINKS(keyboard_macro_finish_recording, 0), false, "keyboard_macro_finish_recording", 31, "Stop macro recording, do nothing if macro recording is not already started", 74, "c:\\4ed\\code\\custom\\4coder_keyboard_macro.cpp", 44, 54 }, +{ PROC_LINKS(keyboard_macro_replay, 0), false, "keyboard_macro_replay", 21, "Replay the most recently recorded keyboard macro", 48, "c:\\4ed\\code\\custom\\4coder_keyboard_macro.cpp", 44, 77 }, +{ PROC_LINKS(keyboard_macro_start_recording, 0), false, "keyboard_macro_start_recording", 30, "Start macro recording, do nothing if macro recording is already started", 71, "c:\\4ed\\code\\custom\\4coder_keyboard_macro.cpp", 44, 41 }, +{ PROC_LINKS(kill_buffer, 0), false, "kill_buffer", 11, "Kills the current buffer.", 25, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1548 }, +{ PROC_LINKS(kill_tutorial, 0), false, "kill_tutorial", 13, "If there is an active tutorial, kill it.", 40, "c:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 9 }, +{ PROC_LINKS(left_adjust_view, 0), false, "left_adjust_view", 16, "Sets the left size of the view near the x position of the cursor.", 65, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 222 }, +{ PROC_LINKS(list_all_functions_all_buffers, 0), false, "list_all_functions_all_buffers", 30, "Creates a jump list of lines from all buffers that appear to define or declare functions.", 89, "c:\\4ed\\code\\custom\\4coder_function_list.cpp", 43, 296 }, +{ PROC_LINKS(list_all_functions_all_buffers_lister, 0), false, "list_all_functions_all_buffers_lister", 37, "Creates a lister of locations that look like function definitions and declarations all buffers.", 95, "c:\\4ed\\code\\custom\\4coder_function_list.cpp", 43, 302 }, +{ PROC_LINKS(list_all_functions_current_buffer, 0), false, "list_all_functions_current_buffer", 33, "Creates a jump list of lines of the current buffer that appear to define or declare functions.", 94, "c:\\4ed\\code\\custom\\4coder_function_list.cpp", 43, 267 }, +{ PROC_LINKS(list_all_functions_current_buffer_lister, 0), false, "list_all_functions_current_buffer_lister", 40, "Creates a lister of locations that look like function definitions and declarations in the buffer.", 97, "c:\\4ed\\code\\custom\\4coder_function_list.cpp", 43, 277 }, +{ PROC_LINKS(list_all_locations, 0), false, "list_all_locations", 18, "Queries the user for a string and lists all exact case-sensitive matches found in all open buffers.", 99, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 165 }, +{ PROC_LINKS(list_all_locations_case_insensitive, 0), false, "list_all_locations_case_insensitive", 35, "Queries the user for a string and lists all exact case-insensitive matches found in all open buffers.", 101, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 177 }, +{ PROC_LINKS(list_all_locations_of_identifier, 0), false, "list_all_locations_of_identifier", 32, "Reads a token or word under the cursor and lists all exact case-sensitive mathces in all open buffers.", 102, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 189 }, +{ PROC_LINKS(list_all_locations_of_identifier_case_insensitive, 0), false, "list_all_locations_of_identifier_case_insensitive", 49, "Reads a token or word under the cursor and lists all exact case-insensitive mathces in all open buffers.", 104, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 195 }, +{ PROC_LINKS(list_all_locations_of_selection, 0), false, "list_all_locations_of_selection", 31, "Reads the string in the selected range and lists all exact case-sensitive mathces in all open buffers.", 102, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 201 }, +{ PROC_LINKS(list_all_locations_of_selection_case_insensitive, 0), false, "list_all_locations_of_selection_case_insensitive", 48, "Reads the string in the selected range and lists all exact case-insensitive mathces in all open buffers.", 104, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 207 }, +{ PROC_LINKS(list_all_locations_of_type_definition, 0), false, "list_all_locations_of_type_definition", 37, "Queries user for string, lists all locations of strings that appear to define a type whose name matches the input string.", 121, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 213 }, +{ PROC_LINKS(list_all_locations_of_type_definition_of_identifier, 0), false, "list_all_locations_of_type_definition_of_identifier", 51, "Reads a token or word under the cursor and lists all locations of strings that appear to define a type whose name matches it.", 125, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 221 }, +{ PROC_LINKS(list_all_substring_locations, 0), false, "list_all_substring_locations", 28, "Queries the user for a string and lists all case-sensitive substring matches found in all open buffers.", 103, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 171 }, +{ PROC_LINKS(list_all_substring_locations_case_insensitive, 0), false, "list_all_substring_locations_case_insensitive", 45, "Queries the user for a string and lists all case-insensitive substring matches found in all open buffers.", 105, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 183 }, +{ PROC_LINKS(load_project, 0), false, "load_project", 12, "Looks for a project.4coder file in the current directory and tries to load it. Looks in parent directories until a project file is found or there are no more parents.", 167, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 862 }, +{ PROC_LINKS(load_theme_current_buffer, 0), false, "load_theme_current_buffer", 25, "Parse the current buffer as a theme file and add the theme to the theme list. If the buffer has a .4coder postfix in it's name, it is removed when the name is saved.", 165, "c:\\4ed\\code\\custom\\4coder_config.cpp", 36, 1622 }, +{ PROC_LINKS(load_themes_default_folder, 0), false, "load_themes_default_folder", 26, "Loads all the theme files in the default theme folder.", 54, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 457 }, +{ PROC_LINKS(load_themes_hot_directory, 0), false, "load_themes_hot_directory", 25, "Loads all the theme files in the current hot directory.", 55, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 469 }, +{ PROC_LINKS(make_directory_query, 0), false, "make_directory_query", 20, "Queries the user for a name and creates a new directory with the given name.", 76, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1342 }, +{ PROC_LINKS(miblo_decrement_basic, 0), false, "miblo_decrement_basic", 21, "Decrement an integer under the cursor by one.", 45, "c:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 44 }, +{ PROC_LINKS(miblo_decrement_time_stamp, 0), false, "miblo_decrement_time_stamp", 26, "Decrement a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss", 81, "c:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 237 }, +{ PROC_LINKS(miblo_decrement_time_stamp_minute, 0), false, "miblo_decrement_time_stamp_minute", 33, "Decrement a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "c:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 249 }, +{ PROC_LINKS(miblo_increment_basic, 0), false, "miblo_increment_basic", 21, "Increment an integer under the cursor by one.", 45, "c:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 29 }, +{ PROC_LINKS(miblo_increment_time_stamp, 0), false, "miblo_increment_time_stamp", 26, "Increment a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss", 81, "c:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 231 }, +{ PROC_LINKS(miblo_increment_time_stamp_minute, 0), false, "miblo_increment_time_stamp_minute", 33, "Increment a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "c:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 243 }, +{ PROC_LINKS(mouse_wheel_change_face_size, 0), false, "mouse_wheel_change_face_size", 28, "Reads the state of the mouse wheel and uses it to either increase or decrease the face size.", 92, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 704 }, +{ PROC_LINKS(mouse_wheel_scroll, 0), false, "mouse_wheel_scroll", 18, "Reads the scroll wheel value from the mouse state and scrolls accordingly.", 74, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 276 }, +{ PROC_LINKS(move_down, 0), false, "move_down", 9, "Moves the cursor down one line.", 31, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 347 }, +{ PROC_LINKS(move_down_10, 0), false, "move_down_10", 12, "Moves the cursor down ten lines.", 32, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 359 }, +{ PROC_LINKS(move_down_textual, 0), false, "move_down_textual", 17, "Moves down to the next line of actual text, regardless of line wrapping.", 72, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 365 }, +{ PROC_LINKS(move_down_to_blank_line, 0), false, "move_down_to_blank_line", 23, "Seeks the cursor down to the next blank line.", 45, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 418 }, +{ PROC_LINKS(move_down_to_blank_line_end, 0), false, "move_down_to_blank_line_end", 27, "Seeks the cursor down to the next blank line and places it at the end of the line.", 82, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 442 }, +{ PROC_LINKS(move_down_to_blank_line_skip_whitespace, 0), false, "move_down_to_blank_line_skip_whitespace", 39, "Seeks the cursor down to the next blank line and places it at the end of the line.", 82, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 430 }, +{ PROC_LINKS(move_left, 0), false, "move_left", 9, "Moves the cursor one character to the left.", 43, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 448 }, +{ PROC_LINKS(move_left_alpha_numeric_boundary, 0), false, "move_left_alpha_numeric_boundary", 32, "Seek left for boundary between alphanumeric characters and non-alphanumeric characters.", 87, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 525 }, +{ PROC_LINKS(move_left_alpha_numeric_or_camel_boundary, 0), false, "move_left_alpha_numeric_or_camel_boundary", 41, "Seek left for boundary between alphanumeric characters or camel case word and non-alphanumeric characters.", 106, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 539 }, +{ PROC_LINKS(move_left_token_boundary, 0), false, "move_left_token_boundary", 24, "Seek left for the next beginning of a token.", 44, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 497 }, +{ PROC_LINKS(move_left_whitespace_boundary, 0), false, "move_left_whitespace_boundary", 29, "Seek left for the next boundary between whitespace and non-whitespace.", 70, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 482 }, +{ PROC_LINKS(move_left_whitespace_or_token_boundary, 0), false, "move_left_whitespace_or_token_boundary", 38, "Seek left for the next end of a token or boundary between whitespace and non-whitespace.", 88, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 511 }, +{ PROC_LINKS(move_line_down, 0), false, "move_line_down", 14, "Swaps the line under the cursor with the line below it, and moves the cursor down with it.", 90, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1382 }, +{ PROC_LINKS(move_line_up, 0), false, "move_line_up", 12, "Swaps the line under the cursor with the line above it, and moves the cursor up with it.", 88, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1376 }, +{ PROC_LINKS(move_right, 0), false, "move_right", 10, "Moves the cursor one character to the right.", 44, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 456 }, +{ PROC_LINKS(move_right_alpha_numeric_boundary, 0), false, "move_right_alpha_numeric_boundary", 33, "Seek right for boundary between alphanumeric characters and non-alphanumeric characters.", 88, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 518 }, +{ PROC_LINKS(move_right_alpha_numeric_or_camel_boundary, 0), false, "move_right_alpha_numeric_or_camel_boundary", 42, "Seek right for boundary between alphanumeric characters or camel case word and non-alphanumeric characters.", 107, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 532 }, +{ PROC_LINKS(move_right_token_boundary, 0), false, "move_right_token_boundary", 25, "Seek right for the next end of a token.", 39, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 490 }, +{ PROC_LINKS(move_right_whitespace_boundary, 0), false, "move_right_whitespace_boundary", 30, "Seek right for the next boundary between whitespace and non-whitespace.", 71, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 474 }, +{ PROC_LINKS(move_right_whitespace_or_token_boundary, 0), false, "move_right_whitespace_or_token_boundary", 39, "Seek right for the next end of a token or boundary between whitespace and non-whitespace.", 89, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 504 }, +{ PROC_LINKS(move_up, 0), false, "move_up", 7, "Moves the cursor up one line.", 29, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 341 }, +{ PROC_LINKS(move_up_10, 0), false, "move_up_10", 10, "Moves the cursor up ten lines.", 30, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 353 }, +{ PROC_LINKS(move_up_to_blank_line, 0), false, "move_up_to_blank_line", 21, "Seeks the cursor up to the next blank line.", 43, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 412 }, +{ PROC_LINKS(move_up_to_blank_line_end, 0), false, "move_up_to_blank_line_end", 25, "Seeks the cursor up to the next blank line and places it at the end of the line.", 80, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 436 }, +{ PROC_LINKS(move_up_to_blank_line_skip_whitespace, 0), false, "move_up_to_blank_line_skip_whitespace", 37, "Seeks the cursor up to the next blank line and places it at the end of the line.", 80, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 424 }, +{ PROC_LINKS(open_all_code, 0), false, "open_all_code", 13, "Open all code in the current directory. File types are determined by extensions. An extension is considered code based on the extensions specified in 4coder.config.", 164, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 848 }, +{ PROC_LINKS(open_all_code_recursive, 0), false, "open_all_code_recursive", 23, "Works as open_all_code but also runs in all subdirectories.", 59, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 854 }, +{ PROC_LINKS(open_file_in_quotes, 0), false, "open_file_in_quotes", 19, "Reads a filename from surrounding '\"' characters and attempts to open the corresponding file.", 94, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1467 }, +{ PROC_LINKS(open_in_other, 0), false, "open_in_other", 13, "Interactively opens a file in the other panel.", 46, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1798 }, +{ PROC_LINKS(open_long_braces, 0), false, "open_long_braces", 16, "At the cursor, insert a '{' and '}' separated by a blank line.", 62, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 46 }, +{ PROC_LINKS(open_long_braces_break, 0), false, "open_long_braces_break", 22, "At the cursor, insert a '{' and '}break;' separated by a blank line.", 68, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 62 }, +{ PROC_LINKS(open_long_braces_semicolon, 0), false, "open_long_braces_semicolon", 26, "At the cursor, insert a '{' and '};' separated by a blank line.", 63, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 54 }, +{ PROC_LINKS(open_matching_file_cpp, 0), false, "open_matching_file_cpp", 22, "If the current file is a *.cpp or *.h, attempts to open the corresponding *.h or *.cpp file in the other view.", 110, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1499 }, +{ PROC_LINKS(open_panel_hsplit, 0), false, "open_panel_hsplit", 17, "Create a new panel by horizontally splitting the active panel.", 62, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 310 }, +{ PROC_LINKS(open_panel_vsplit, 0), false, "open_panel_vsplit", 17, "Create a new panel by vertically splitting the active panel.", 60, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 300 }, +{ PROC_LINKS(page_down, 0), false, "page_down", 9, "Scrolls the view down one view height and moves the cursor down one view height.", 80, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 383 }, +{ PROC_LINKS(page_up, 0), false, "page_up", 7, "Scrolls the view up one view height and moves the cursor up one view height.", 76, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 375 }, +{ PROC_LINKS(paste, 0), false, "paste", 5, "At the cursor, insert the text at the top of the clipboard.", 59, "c:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 39 }, +{ PROC_LINKS(paste_and_indent, 0), false, "paste_and_indent", 16, "Paste from the top of clipboard and run auto-indent on the newly pasted text.", 77, "c:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 113 }, +{ PROC_LINKS(paste_next, 0), false, "paste_next", 10, "If the previous command was paste or paste_next, replaces the paste range with the next text down on the clipboard, otherwise operates as the paste command.", 156, "c:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 72 }, +{ PROC_LINKS(paste_next_and_indent, 0), false, "paste_next_and_indent", 21, "Paste the next item on the clipboard and run auto-indent on the newly pasted text.", 82, "c:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 120 }, +{ PROC_LINKS(place_in_scope, 0), false, "place_in_scope", 14, "Wraps the code contained in the range between cursor and mark with a new curly brace scope.", 91, "c:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 106 }, +{ PROC_LINKS(profile_clear, 0), false, "profile_clear", 13, "Clear all profiling information from 4coder's self profiler.", 60, "c:\\4ed\\code\\custom\\4coder_profile.cpp", 37, 226 }, +{ PROC_LINKS(profile_disable, 0), false, "profile_disable", 15, "Prevent 4coder's self profiler from gathering new profiling information.", 72, "c:\\4ed\\code\\custom\\4coder_profile.cpp", 37, 219 }, +{ PROC_LINKS(profile_enable, 0), false, "profile_enable", 14, "Allow 4coder's self profiler to gather new profiling information.", 65, "c:\\4ed\\code\\custom\\4coder_profile.cpp", 37, 212 }, +{ PROC_LINKS(profile_inspect, 0), true, "profile_inspect", 15, "Inspect all currently collected profiling information in 4coder's self profiler.", 80, "c:\\4ed\\code\\custom\\4coder_profile_inspect.cpp", 45, 886 }, +{ PROC_LINKS(project_command_lister, 0), false, "project_command_lister", 22, "Open a lister of all commands in the currently loaded project.", 62, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 1289 }, +{ PROC_LINKS(project_fkey_command, 0), false, "project_fkey_command", 20, "Run an 'fkey command' configured in a project.4coder file. Determines the index of the 'fkey command' by which function key or numeric key was pressed to trigger the command.", 175, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 870 }, +{ PROC_LINKS(project_go_to_root_directory, 0), false, "project_go_to_root_directory", 28, "Changes 4coder's hot directory to the root directory of the currently loaded project. With no loaded project nothing hapepns.", 125, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 896 }, +{ PROC_LINKS(query_replace, 0), false, "query_replace", 13, "Queries the user for two strings, and incrementally replaces every occurence of the first string with the second string.", 120, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1158 }, +{ PROC_LINKS(query_replace_identifier, 0), false, "query_replace_identifier", 24, "Queries the user for a string, and incrementally replace every occurence of the word or token found at the cursor with the specified string.", 140, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1179 }, +{ PROC_LINKS(query_replace_selection, 0), false, "query_replace_selection", 23, "Queries the user for a string, and incrementally replace every occurence of the string found in the selected range with the specified string.", 141, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1195 }, +{ PROC_LINKS(redo, 0), false, "redo", 4, "Advances forwards through the undo history of the current buffer.", 65, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1637 }, +{ PROC_LINKS(redo_all_buffers, 0), false, "redo_all_buffers", 16, "Advances forward through the undo history in the buffer containing the most recent regular edit.", 96, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1722 }, +{ PROC_LINKS(rename_file_query, 0), false, "rename_file_query", 17, "Queries the user for a new name and renames the file of the current buffer, altering the buffer's name too.", 107, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1307 }, +{ PROC_LINKS(reopen, 0), false, "reopen", 6, "Reopen the current buffer from the hard drive.", 46, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1566 }, +{ PROC_LINKS(replace_in_all_buffers, 0), false, "replace_in_all_buffers", 22, "Queries the user for a needle and string. Replaces all occurences of needle with string in all editable buffers.", 112, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1068 }, +{ PROC_LINKS(replace_in_buffer, 0), false, "replace_in_buffer", 17, "Queries the user for a needle and string. Replaces all occurences of needle with string in the active buffer.", 109, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1059 }, +{ PROC_LINKS(replace_in_range, 0), false, "replace_in_range", 16, "Queries the user for a needle and string. Replaces all occurences of needle with string in the range between cursor and the mark in the active buffer.", 150, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1050 }, +{ PROC_LINKS(reverse_search, 0), false, "reverse_search", 14, "Begins an incremental search up through the current buffer for a user specified string.", 87, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 991 }, +{ PROC_LINKS(reverse_search_identifier, 0), false, "reverse_search_identifier", 25, "Begins an incremental search up through the current buffer for the word or token under the cursor.", 98, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1003 }, +{ PROC_LINKS(save, 0), false, "save", 4, "Saves the current buffer.", 25, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1556 }, +{ PROC_LINKS(save_all_dirty_buffers, 0), false, "save_all_dirty_buffers", 22, "Saves all buffers marked dirty (showing the '*' indicator).", 59, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 382 }, +{ PROC_LINKS(save_to_query, 0), false, "save_to_query", 13, "Queries the user for a file name and saves the contents of the current buffer, altering the buffer's name too.", 110, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1274 }, +{ PROC_LINKS(search, 0), false, "search", 6, "Begins an incremental search down through the current buffer for a user specified string.", 89, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 985 }, +{ PROC_LINKS(search_identifier, 0), false, "search_identifier", 17, "Begins an incremental search down through the current buffer for the word or token under the cursor.", 100, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 997 }, +{ PROC_LINKS(seek_beginning_of_line, 0), false, "seek_beginning_of_line", 22, "Seeks the cursor to the beginning of the visual line.", 53, "c:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2172 }, +{ PROC_LINKS(seek_beginning_of_textual_line, 0), false, "seek_beginning_of_textual_line", 30, "Seeks the cursor to the beginning of the line across all text.", 62, "c:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2160 }, +{ PROC_LINKS(seek_end_of_line, 0), false, "seek_end_of_line", 16, "Seeks the cursor to the end of the visual line.", 47, "c:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2178 }, +{ PROC_LINKS(seek_end_of_textual_line, 0), false, "seek_end_of_textual_line", 24, "Seeks the cursor to the end of the line across all text.", 56, "c:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2166 }, +{ PROC_LINKS(select_all, 0), false, "select_all", 10, "Puts the cursor at the top of the file, and the mark at the bottom of the file.", 79, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 548 }, +{ PROC_LINKS(select_next_scope_absolute, 0), false, "select_next_scope_absolute", 26, "Finds the first scope started by '{' after the cursor and puts the cursor and mark on the '{' and '}'.", 102, "c:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 57 }, +{ PROC_LINKS(select_next_scope_after_current, 0), false, "select_next_scope_after_current", 31, "If a scope is selected, find first scope that starts after the selected scope. Otherwise find the first scope that starts after the cursor.", 139, "c:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 66 }, +{ PROC_LINKS(select_prev_scope_absolute, 0), false, "select_prev_scope_absolute", 26, "Finds the first scope started by '{' before the cursor and puts the cursor and mark on the '{' and '}'.", 103, "c:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 82 }, +{ PROC_LINKS(select_prev_top_most_scope, 0), false, "select_prev_top_most_scope", 26, "Finds the first scope that starts before the cursor, then finds the top most scope that contains that scope.", 108, "c:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 99 }, +{ PROC_LINKS(select_surrounding_scope, 0), false, "select_surrounding_scope", 24, "Finds the scope enclosed by '{' '}' surrounding the cursor and puts the cursor and mark on the '{' and '}'.", 107, "c:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 27 }, +{ PROC_LINKS(select_surrounding_scope_maximal, 0), false, "select_surrounding_scope_maximal", 32, "Selects the top-most scope that surrounds the cursor.", 53, "c:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 39 }, +{ PROC_LINKS(set_eol_mode_from_contents, 0), false, "set_eol_mode_from_contents", 26, "Sets the buffer's line ending mode to match the contents of the buffer.", 71, "c:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 125 }, +{ PROC_LINKS(set_eol_mode_to_binary, 0), false, "set_eol_mode_to_binary", 22, "Puts the buffer in bin line ending mode.", 40, "c:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 112 }, +{ PROC_LINKS(set_eol_mode_to_crlf, 0), false, "set_eol_mode_to_crlf", 20, "Puts the buffer in crlf line ending mode.", 41, "c:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 86 }, +{ PROC_LINKS(set_eol_mode_to_lf, 0), false, "set_eol_mode_to_lf", 18, "Puts the buffer in lf line ending mode.", 39, "c:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 99 }, +{ PROC_LINKS(set_mark, 0), false, "set_mark", 8, "Sets the mark to the current position of the cursor.", 52, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 126 }, +{ PROC_LINKS(set_mode_to_notepad_like, 0), false, "set_mode_to_notepad_like", 24, "Sets the edit mode to Notepad like.", 35, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 427 }, +{ PROC_LINKS(set_mode_to_original, 0), false, "set_mode_to_original", 20, "Sets the edit mode to 4coder original.", 38, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 421 }, +{ PROC_LINKS(setup_build_bat, 0), false, "setup_build_bat", 15, "Queries the user for several configuration options and initializes a new build batch script.", 92, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 1237 }, +{ PROC_LINKS(setup_build_bat_and_sh, 0), false, "setup_build_bat_and_sh", 22, "Queries the user for several configuration options and initializes a new build batch script.", 92, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 1249 }, +{ PROC_LINKS(setup_build_sh, 0), false, "setup_build_sh", 14, "Queries the user for several configuration options and initializes a new build shell script.", 92, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 1243 }, +{ PROC_LINKS(setup_new_project, 0), false, "setup_new_project", 17, "Queries the user for several configuration options and initializes a new 4coder project with build scripts for every OS.", 120, "c:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 1230 }, +{ PROC_LINKS(show_filebar, 0), false, "show_filebar", 12, "Sets the current view to show it's filebar.", 43, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 653 }, +{ PROC_LINKS(show_scrollbar, 0), false, "show_scrollbar", 14, "Sets the current view to show it's scrollbar.", 45, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 639 }, +{ PROC_LINKS(show_the_log_graph, 0), true, "show_the_log_graph", 18, "Parses *log* and displays the 'log graph' UI", 44, "c:\\4ed\\code\\custom\\4coder_log_parser.cpp", 40, 994 }, +{ PROC_LINKS(snipe_backward_whitespace_or_token_boundary, 0), false, "snipe_backward_whitespace_or_token_boundary", 43, "Delete a single, whole token on or to the left of the cursor and post it to the clipboard.", 90, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 190 }, +{ PROC_LINKS(snipe_forward_whitespace_or_token_boundary, 0), false, "snipe_forward_whitespace_or_token_boundary", 42, "Delete a single, whole token on or to the right of the cursor and post it to the clipboard.", 91, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 198 }, +{ PROC_LINKS(snippet_lister, 0), true, "snippet_lister", 14, "Opens a snippet lister for inserting whole pre-written snippets of text.", 72, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 237 }, +{ PROC_LINKS(suppress_mouse, 0), false, "suppress_mouse", 14, "Hides the mouse and causes all mosue input (clicks, position, wheel) to be ignored.", 83, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 403 }, +{ PROC_LINKS(swap_panels, 0), false, "swap_panels", 11, "Swaps the active panel with it's sibling.", 41, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1524 }, +{ PROC_LINKS(test_double_backspace, 0), false, "test_double_backspace", 21, "Made for testing purposes (I should have deleted this if you are reading it let me know)", 88, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 115 }, +{ PROC_LINKS(theme_lister, 0), true, "theme_lister", 12, "Opens an interactive list of all registered themes.", 51, "c:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 785 }, +{ PROC_LINKS(to_lowercase, 0), false, "to_lowercase", 12, "Converts all ascii text in the range between the cursor and the mark to lowercase.", 82, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 574 }, +{ PROC_LINKS(to_uppercase, 0), false, "to_uppercase", 12, "Converts all ascii text in the range between the cursor and the mark to uppercase.", 82, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 561 }, +{ PROC_LINKS(toggle_filebar, 0), false, "toggle_filebar", 14, "Toggles the visibility status of the current view's filebar.", 60, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 667 }, +{ PROC_LINKS(toggle_fps_meter, 0), false, "toggle_fps_meter", 16, "Toggles the visibility of the FPS performance meter", 51, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 676 }, +{ PROC_LINKS(toggle_fullscreen, 0), false, "toggle_fullscreen", 17, "Toggle fullscreen mode on or off. The change(s) do not take effect until the next frame.", 89, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 451 }, +{ PROC_LINKS(toggle_highlight_enclosing_scopes, 0), false, "toggle_highlight_enclosing_scopes", 33, "In code files scopes surrounding the cursor are highlighted with distinguishing colors.", 87, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 439 }, +{ PROC_LINKS(toggle_highlight_line_at_cursor, 0), false, "toggle_highlight_line_at_cursor", 31, "Toggles the line highlight at the cursor.", 41, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 433 }, +{ PROC_LINKS(toggle_line_numbers, 0), false, "toggle_line_numbers", 19, "Toggles the left margin line numbers.", 37, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 730 }, +{ PROC_LINKS(toggle_line_wrap, 0), false, "toggle_line_wrap", 16, "Toggles the line wrap setting on this buffer.", 45, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 736 }, +{ PROC_LINKS(toggle_mouse, 0), false, "toggle_mouse", 12, "Toggles the mouse suppression mode, see suppress_mouse and allow_mouse.", 71, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 415 }, +{ PROC_LINKS(toggle_paren_matching_helper, 0), false, "toggle_paren_matching_helper", 28, "In code files matching parentheses pairs are colored with distinguishing colors.", 80, "c:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 445 }, +{ PROC_LINKS(toggle_show_whitespace, 0), false, "toggle_show_whitespace", 22, "Toggles the current buffer's whitespace visibility status.", 58, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 721 }, +{ PROC_LINKS(toggle_virtual_whitespace, 0), false, "toggle_virtual_whitespace", 25, "Toggles the current buffer's virtual whitespace status.", 55, "c:\\4ed\\code\\custom\\4coder_code_index.cpp", 40, 1170 }, +{ PROC_LINKS(tutorial_maximize, 0), false, "tutorial_maximize", 17, "Expand the tutorial window", 26, "c:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 20 }, +{ PROC_LINKS(tutorial_minimize, 0), false, "tutorial_minimize", 17, "Shrink the tutorial window", 26, "c:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 34 }, +{ PROC_LINKS(uncomment_line, 0), false, "uncomment_line", 14, "If present, delete '//' at the beginning of the line after leading whitespace.", 78, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 137 }, +{ PROC_LINKS(undo, 0), false, "undo", 4, "Advances backwards through the undo history of the current buffer.", 66, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1624 }, +{ PROC_LINKS(undo_all_buffers, 0), false, "undo_all_buffers", 16, "Advances backward through the undo history in the buffer containing the most recent regular edit.", 97, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1651 }, +{ PROC_LINKS(view_buffer_other_panel, 0), false, "view_buffer_other_panel", 23, "Set the other non-active panel to view the buffer that the active panel views, and switch to that panel.", 104, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1512 }, +{ PROC_LINKS(view_jump_list_with_lister, 0), false, "view_jump_list_with_lister", 26, "When executed on a buffer with jumps, creates a persistent lister for all the jumps", 83, "c:\\4ed\\code\\custom\\4coder_jump_lister.cpp", 41, 59 }, +{ PROC_LINKS(word_complete, 0), false, "word_complete", 13, "Iteratively tries completing the word to the left of the cursor with other words in open buffers that have the same prefix string.", 130, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 395 }, +{ PROC_LINKS(word_complete_drop_down, 0), false, "word_complete_drop_down", 23, "Word complete with drop down menu.", 34, "c:\\4ed\\code\\custom\\4coder_search.cpp", 36, 642 }, +{ PROC_LINKS(write_block, 0), false, "write_block", 11, "At the cursor, insert a block comment.", 38, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 94 }, +{ PROC_LINKS(write_hack, 0), false, "write_hack", 10, "At the cursor, insert a '// HACK' comment, includes user name if it was specified in config.4coder.", 99, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 82 }, +{ PROC_LINKS(write_note, 0), false, "write_note", 10, "At the cursor, insert a '// NOTE' comment, includes user name if it was specified in config.4coder.", 99, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 88 }, +{ PROC_LINKS(write_space, 0), false, "write_space", 11, "Inserts a space.", 16, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 67 }, +{ PROC_LINKS(write_text_and_auto_indent, 0), false, "write_text_and_auto_indent", 26, "Inserts text and auto-indents the line on which the cursor sits if any of the text contains 'layout punctuation' such as ;:{}()[]# and new lines.", 145, "c:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 427 }, +{ PROC_LINKS(write_text_input, 0), false, "write_text_input", 16, "Inserts whatever text was used to trigger this command.", 55, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 59 }, +{ PROC_LINKS(write_todo, 0), false, "write_todo", 10, "At the cursor, insert a '// TODO' comment, includes user name if it was specified in config.4coder.", 99, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 76 }, +{ PROC_LINKS(write_underscore, 0), false, "write_underscore", 16, "Inserts an underscore.", 22, "c:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 73 }, +{ PROC_LINKS(write_zero_struct, 0), false, "write_zero_struct", 17, "At the cursor, insert a ' = {};'.", 33, "c:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 100 }, }; static i32 fcoder_metacmd_ID_allow_mouse = 0; static i32 fcoder_metacmd_ID_auto_indent_line_at_cursor = 1; @@ -571,143 +575,145 @@ static i32 fcoder_metacmd_ID_list_all_locations_of_type_definition_of_identifier static i32 fcoder_metacmd_ID_list_all_substring_locations = 87; static i32 fcoder_metacmd_ID_list_all_substring_locations_case_insensitive = 88; static i32 fcoder_metacmd_ID_load_project = 89; -static i32 fcoder_metacmd_ID_load_themes_default_folder = 90; -static i32 fcoder_metacmd_ID_load_themes_hot_directory = 91; -static i32 fcoder_metacmd_ID_make_directory_query = 92; -static i32 fcoder_metacmd_ID_miblo_decrement_basic = 93; -static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp = 94; -static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp_minute = 95; -static i32 fcoder_metacmd_ID_miblo_increment_basic = 96; -static i32 fcoder_metacmd_ID_miblo_increment_time_stamp = 97; -static i32 fcoder_metacmd_ID_miblo_increment_time_stamp_minute = 98; -static i32 fcoder_metacmd_ID_mouse_wheel_change_face_size = 99; -static i32 fcoder_metacmd_ID_mouse_wheel_scroll = 100; -static i32 fcoder_metacmd_ID_move_down = 101; -static i32 fcoder_metacmd_ID_move_down_10 = 102; -static i32 fcoder_metacmd_ID_move_down_textual = 103; -static i32 fcoder_metacmd_ID_move_down_to_blank_line = 104; -static i32 fcoder_metacmd_ID_move_down_to_blank_line_end = 105; -static i32 fcoder_metacmd_ID_move_down_to_blank_line_skip_whitespace = 106; -static i32 fcoder_metacmd_ID_move_left = 107; -static i32 fcoder_metacmd_ID_move_left_alpha_numeric_boundary = 108; -static i32 fcoder_metacmd_ID_move_left_alpha_numeric_or_camel_boundary = 109; -static i32 fcoder_metacmd_ID_move_left_token_boundary = 110; -static i32 fcoder_metacmd_ID_move_left_whitespace_boundary = 111; -static i32 fcoder_metacmd_ID_move_left_whitespace_or_token_boundary = 112; -static i32 fcoder_metacmd_ID_move_line_down = 113; -static i32 fcoder_metacmd_ID_move_line_up = 114; -static i32 fcoder_metacmd_ID_move_right = 115; -static i32 fcoder_metacmd_ID_move_right_alpha_numeric_boundary = 116; -static i32 fcoder_metacmd_ID_move_right_alpha_numeric_or_camel_boundary = 117; -static i32 fcoder_metacmd_ID_move_right_token_boundary = 118; -static i32 fcoder_metacmd_ID_move_right_whitespace_boundary = 119; -static i32 fcoder_metacmd_ID_move_right_whitespace_or_token_boundary = 120; -static i32 fcoder_metacmd_ID_move_up = 121; -static i32 fcoder_metacmd_ID_move_up_10 = 122; -static i32 fcoder_metacmd_ID_move_up_to_blank_line = 123; -static i32 fcoder_metacmd_ID_move_up_to_blank_line_end = 124; -static i32 fcoder_metacmd_ID_move_up_to_blank_line_skip_whitespace = 125; -static i32 fcoder_metacmd_ID_open_all_code = 126; -static i32 fcoder_metacmd_ID_open_all_code_recursive = 127; -static i32 fcoder_metacmd_ID_open_file_in_quotes = 128; -static i32 fcoder_metacmd_ID_open_in_other = 129; -static i32 fcoder_metacmd_ID_open_long_braces = 130; -static i32 fcoder_metacmd_ID_open_long_braces_break = 131; -static i32 fcoder_metacmd_ID_open_long_braces_semicolon = 132; -static i32 fcoder_metacmd_ID_open_matching_file_cpp = 133; -static i32 fcoder_metacmd_ID_open_panel_hsplit = 134; -static i32 fcoder_metacmd_ID_open_panel_vsplit = 135; -static i32 fcoder_metacmd_ID_page_down = 136; -static i32 fcoder_metacmd_ID_page_up = 137; -static i32 fcoder_metacmd_ID_paste = 138; -static i32 fcoder_metacmd_ID_paste_and_indent = 139; -static i32 fcoder_metacmd_ID_paste_next = 140; -static i32 fcoder_metacmd_ID_paste_next_and_indent = 141; -static i32 fcoder_metacmd_ID_place_in_scope = 142; -static i32 fcoder_metacmd_ID_profile_clear = 143; -static i32 fcoder_metacmd_ID_profile_disable = 144; -static i32 fcoder_metacmd_ID_profile_enable = 145; -static i32 fcoder_metacmd_ID_profile_inspect = 146; -static i32 fcoder_metacmd_ID_project_command_lister = 147; -static i32 fcoder_metacmd_ID_project_fkey_command = 148; -static i32 fcoder_metacmd_ID_project_go_to_root_directory = 149; -static i32 fcoder_metacmd_ID_query_replace = 150; -static i32 fcoder_metacmd_ID_query_replace_identifier = 151; -static i32 fcoder_metacmd_ID_query_replace_selection = 152; -static i32 fcoder_metacmd_ID_redo = 153; -static i32 fcoder_metacmd_ID_redo_all_buffers = 154; -static i32 fcoder_metacmd_ID_rename_file_query = 155; -static i32 fcoder_metacmd_ID_reopen = 156; -static i32 fcoder_metacmd_ID_replace_in_all_buffers = 157; -static i32 fcoder_metacmd_ID_replace_in_buffer = 158; -static i32 fcoder_metacmd_ID_replace_in_range = 159; -static i32 fcoder_metacmd_ID_reverse_search = 160; -static i32 fcoder_metacmd_ID_reverse_search_identifier = 161; -static i32 fcoder_metacmd_ID_save = 162; -static i32 fcoder_metacmd_ID_save_all_dirty_buffers = 163; -static i32 fcoder_metacmd_ID_save_to_query = 164; -static i32 fcoder_metacmd_ID_search = 165; -static i32 fcoder_metacmd_ID_search_identifier = 166; -static i32 fcoder_metacmd_ID_seek_beginning_of_line = 167; -static i32 fcoder_metacmd_ID_seek_beginning_of_textual_line = 168; -static i32 fcoder_metacmd_ID_seek_end_of_line = 169; -static i32 fcoder_metacmd_ID_seek_end_of_textual_line = 170; -static i32 fcoder_metacmd_ID_select_all = 171; -static i32 fcoder_metacmd_ID_select_next_scope_absolute = 172; -static i32 fcoder_metacmd_ID_select_next_scope_after_current = 173; -static i32 fcoder_metacmd_ID_select_prev_scope_absolute = 174; -static i32 fcoder_metacmd_ID_select_prev_top_most_scope = 175; -static i32 fcoder_metacmd_ID_select_surrounding_scope = 176; -static i32 fcoder_metacmd_ID_select_surrounding_scope_maximal = 177; -static i32 fcoder_metacmd_ID_set_eol_mode_from_contents = 178; -static i32 fcoder_metacmd_ID_set_eol_mode_to_binary = 179; -static i32 fcoder_metacmd_ID_set_eol_mode_to_crlf = 180; -static i32 fcoder_metacmd_ID_set_eol_mode_to_lf = 181; -static i32 fcoder_metacmd_ID_set_mark = 182; -static i32 fcoder_metacmd_ID_set_mode_to_notepad_like = 183; -static i32 fcoder_metacmd_ID_set_mode_to_original = 184; -static i32 fcoder_metacmd_ID_setup_build_bat = 185; -static i32 fcoder_metacmd_ID_setup_build_bat_and_sh = 186; -static i32 fcoder_metacmd_ID_setup_build_sh = 187; -static i32 fcoder_metacmd_ID_setup_new_project = 188; -static i32 fcoder_metacmd_ID_show_filebar = 189; -static i32 fcoder_metacmd_ID_show_scrollbar = 190; -static i32 fcoder_metacmd_ID_show_the_log_graph = 191; -static i32 fcoder_metacmd_ID_snipe_backward_whitespace_or_token_boundary = 192; -static i32 fcoder_metacmd_ID_snipe_forward_whitespace_or_token_boundary = 193; -static i32 fcoder_metacmd_ID_snippet_lister = 194; -static i32 fcoder_metacmd_ID_suppress_mouse = 195; -static i32 fcoder_metacmd_ID_swap_panels = 196; -static i32 fcoder_metacmd_ID_theme_lister = 197; -static i32 fcoder_metacmd_ID_to_lowercase = 198; -static i32 fcoder_metacmd_ID_to_uppercase = 199; -static i32 fcoder_metacmd_ID_toggle_filebar = 200; -static i32 fcoder_metacmd_ID_toggle_fps_meter = 201; -static i32 fcoder_metacmd_ID_toggle_fullscreen = 202; -static i32 fcoder_metacmd_ID_toggle_highlight_enclosing_scopes = 203; -static i32 fcoder_metacmd_ID_toggle_highlight_line_at_cursor = 204; -static i32 fcoder_metacmd_ID_toggle_line_numbers = 205; -static i32 fcoder_metacmd_ID_toggle_line_wrap = 206; -static i32 fcoder_metacmd_ID_toggle_mouse = 207; -static i32 fcoder_metacmd_ID_toggle_paren_matching_helper = 208; -static i32 fcoder_metacmd_ID_toggle_show_whitespace = 209; -static i32 fcoder_metacmd_ID_toggle_virtual_whitespace = 210; -static i32 fcoder_metacmd_ID_tutorial_maximize = 211; -static i32 fcoder_metacmd_ID_tutorial_minimize = 212; -static i32 fcoder_metacmd_ID_uncomment_line = 213; -static i32 fcoder_metacmd_ID_undo = 214; -static i32 fcoder_metacmd_ID_undo_all_buffers = 215; -static i32 fcoder_metacmd_ID_view_buffer_other_panel = 216; -static i32 fcoder_metacmd_ID_view_jump_list_with_lister = 217; -static i32 fcoder_metacmd_ID_word_complete = 218; -static i32 fcoder_metacmd_ID_word_complete_drop_down = 219; -static i32 fcoder_metacmd_ID_write_block = 220; -static i32 fcoder_metacmd_ID_write_hack = 221; -static i32 fcoder_metacmd_ID_write_note = 222; -static i32 fcoder_metacmd_ID_write_space = 223; -static i32 fcoder_metacmd_ID_write_text_and_auto_indent = 224; -static i32 fcoder_metacmd_ID_write_text_input = 225; -static i32 fcoder_metacmd_ID_write_todo = 226; -static i32 fcoder_metacmd_ID_write_underscore = 227; -static i32 fcoder_metacmd_ID_write_zero_struct = 228; +static i32 fcoder_metacmd_ID_load_theme_current_buffer = 90; +static i32 fcoder_metacmd_ID_load_themes_default_folder = 91; +static i32 fcoder_metacmd_ID_load_themes_hot_directory = 92; +static i32 fcoder_metacmd_ID_make_directory_query = 93; +static i32 fcoder_metacmd_ID_miblo_decrement_basic = 94; +static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp = 95; +static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp_minute = 96; +static i32 fcoder_metacmd_ID_miblo_increment_basic = 97; +static i32 fcoder_metacmd_ID_miblo_increment_time_stamp = 98; +static i32 fcoder_metacmd_ID_miblo_increment_time_stamp_minute = 99; +static i32 fcoder_metacmd_ID_mouse_wheel_change_face_size = 100; +static i32 fcoder_metacmd_ID_mouse_wheel_scroll = 101; +static i32 fcoder_metacmd_ID_move_down = 102; +static i32 fcoder_metacmd_ID_move_down_10 = 103; +static i32 fcoder_metacmd_ID_move_down_textual = 104; +static i32 fcoder_metacmd_ID_move_down_to_blank_line = 105; +static i32 fcoder_metacmd_ID_move_down_to_blank_line_end = 106; +static i32 fcoder_metacmd_ID_move_down_to_blank_line_skip_whitespace = 107; +static i32 fcoder_metacmd_ID_move_left = 108; +static i32 fcoder_metacmd_ID_move_left_alpha_numeric_boundary = 109; +static i32 fcoder_metacmd_ID_move_left_alpha_numeric_or_camel_boundary = 110; +static i32 fcoder_metacmd_ID_move_left_token_boundary = 111; +static i32 fcoder_metacmd_ID_move_left_whitespace_boundary = 112; +static i32 fcoder_metacmd_ID_move_left_whitespace_or_token_boundary = 113; +static i32 fcoder_metacmd_ID_move_line_down = 114; +static i32 fcoder_metacmd_ID_move_line_up = 115; +static i32 fcoder_metacmd_ID_move_right = 116; +static i32 fcoder_metacmd_ID_move_right_alpha_numeric_boundary = 117; +static i32 fcoder_metacmd_ID_move_right_alpha_numeric_or_camel_boundary = 118; +static i32 fcoder_metacmd_ID_move_right_token_boundary = 119; +static i32 fcoder_metacmd_ID_move_right_whitespace_boundary = 120; +static i32 fcoder_metacmd_ID_move_right_whitespace_or_token_boundary = 121; +static i32 fcoder_metacmd_ID_move_up = 122; +static i32 fcoder_metacmd_ID_move_up_10 = 123; +static i32 fcoder_metacmd_ID_move_up_to_blank_line = 124; +static i32 fcoder_metacmd_ID_move_up_to_blank_line_end = 125; +static i32 fcoder_metacmd_ID_move_up_to_blank_line_skip_whitespace = 126; +static i32 fcoder_metacmd_ID_open_all_code = 127; +static i32 fcoder_metacmd_ID_open_all_code_recursive = 128; +static i32 fcoder_metacmd_ID_open_file_in_quotes = 129; +static i32 fcoder_metacmd_ID_open_in_other = 130; +static i32 fcoder_metacmd_ID_open_long_braces = 131; +static i32 fcoder_metacmd_ID_open_long_braces_break = 132; +static i32 fcoder_metacmd_ID_open_long_braces_semicolon = 133; +static i32 fcoder_metacmd_ID_open_matching_file_cpp = 134; +static i32 fcoder_metacmd_ID_open_panel_hsplit = 135; +static i32 fcoder_metacmd_ID_open_panel_vsplit = 136; +static i32 fcoder_metacmd_ID_page_down = 137; +static i32 fcoder_metacmd_ID_page_up = 138; +static i32 fcoder_metacmd_ID_paste = 139; +static i32 fcoder_metacmd_ID_paste_and_indent = 140; +static i32 fcoder_metacmd_ID_paste_next = 141; +static i32 fcoder_metacmd_ID_paste_next_and_indent = 142; +static i32 fcoder_metacmd_ID_place_in_scope = 143; +static i32 fcoder_metacmd_ID_profile_clear = 144; +static i32 fcoder_metacmd_ID_profile_disable = 145; +static i32 fcoder_metacmd_ID_profile_enable = 146; +static i32 fcoder_metacmd_ID_profile_inspect = 147; +static i32 fcoder_metacmd_ID_project_command_lister = 148; +static i32 fcoder_metacmd_ID_project_fkey_command = 149; +static i32 fcoder_metacmd_ID_project_go_to_root_directory = 150; +static i32 fcoder_metacmd_ID_query_replace = 151; +static i32 fcoder_metacmd_ID_query_replace_identifier = 152; +static i32 fcoder_metacmd_ID_query_replace_selection = 153; +static i32 fcoder_metacmd_ID_redo = 154; +static i32 fcoder_metacmd_ID_redo_all_buffers = 155; +static i32 fcoder_metacmd_ID_rename_file_query = 156; +static i32 fcoder_metacmd_ID_reopen = 157; +static i32 fcoder_metacmd_ID_replace_in_all_buffers = 158; +static i32 fcoder_metacmd_ID_replace_in_buffer = 159; +static i32 fcoder_metacmd_ID_replace_in_range = 160; +static i32 fcoder_metacmd_ID_reverse_search = 161; +static i32 fcoder_metacmd_ID_reverse_search_identifier = 162; +static i32 fcoder_metacmd_ID_save = 163; +static i32 fcoder_metacmd_ID_save_all_dirty_buffers = 164; +static i32 fcoder_metacmd_ID_save_to_query = 165; +static i32 fcoder_metacmd_ID_search = 166; +static i32 fcoder_metacmd_ID_search_identifier = 167; +static i32 fcoder_metacmd_ID_seek_beginning_of_line = 168; +static i32 fcoder_metacmd_ID_seek_beginning_of_textual_line = 169; +static i32 fcoder_metacmd_ID_seek_end_of_line = 170; +static i32 fcoder_metacmd_ID_seek_end_of_textual_line = 171; +static i32 fcoder_metacmd_ID_select_all = 172; +static i32 fcoder_metacmd_ID_select_next_scope_absolute = 173; +static i32 fcoder_metacmd_ID_select_next_scope_after_current = 174; +static i32 fcoder_metacmd_ID_select_prev_scope_absolute = 175; +static i32 fcoder_metacmd_ID_select_prev_top_most_scope = 176; +static i32 fcoder_metacmd_ID_select_surrounding_scope = 177; +static i32 fcoder_metacmd_ID_select_surrounding_scope_maximal = 178; +static i32 fcoder_metacmd_ID_set_eol_mode_from_contents = 179; +static i32 fcoder_metacmd_ID_set_eol_mode_to_binary = 180; +static i32 fcoder_metacmd_ID_set_eol_mode_to_crlf = 181; +static i32 fcoder_metacmd_ID_set_eol_mode_to_lf = 182; +static i32 fcoder_metacmd_ID_set_mark = 183; +static i32 fcoder_metacmd_ID_set_mode_to_notepad_like = 184; +static i32 fcoder_metacmd_ID_set_mode_to_original = 185; +static i32 fcoder_metacmd_ID_setup_build_bat = 186; +static i32 fcoder_metacmd_ID_setup_build_bat_and_sh = 187; +static i32 fcoder_metacmd_ID_setup_build_sh = 188; +static i32 fcoder_metacmd_ID_setup_new_project = 189; +static i32 fcoder_metacmd_ID_show_filebar = 190; +static i32 fcoder_metacmd_ID_show_scrollbar = 191; +static i32 fcoder_metacmd_ID_show_the_log_graph = 192; +static i32 fcoder_metacmd_ID_snipe_backward_whitespace_or_token_boundary = 193; +static i32 fcoder_metacmd_ID_snipe_forward_whitespace_or_token_boundary = 194; +static i32 fcoder_metacmd_ID_snippet_lister = 195; +static i32 fcoder_metacmd_ID_suppress_mouse = 196; +static i32 fcoder_metacmd_ID_swap_panels = 197; +static i32 fcoder_metacmd_ID_test_double_backspace = 198; +static i32 fcoder_metacmd_ID_theme_lister = 199; +static i32 fcoder_metacmd_ID_to_lowercase = 200; +static i32 fcoder_metacmd_ID_to_uppercase = 201; +static i32 fcoder_metacmd_ID_toggle_filebar = 202; +static i32 fcoder_metacmd_ID_toggle_fps_meter = 203; +static i32 fcoder_metacmd_ID_toggle_fullscreen = 204; +static i32 fcoder_metacmd_ID_toggle_highlight_enclosing_scopes = 205; +static i32 fcoder_metacmd_ID_toggle_highlight_line_at_cursor = 206; +static i32 fcoder_metacmd_ID_toggle_line_numbers = 207; +static i32 fcoder_metacmd_ID_toggle_line_wrap = 208; +static i32 fcoder_metacmd_ID_toggle_mouse = 209; +static i32 fcoder_metacmd_ID_toggle_paren_matching_helper = 210; +static i32 fcoder_metacmd_ID_toggle_show_whitespace = 211; +static i32 fcoder_metacmd_ID_toggle_virtual_whitespace = 212; +static i32 fcoder_metacmd_ID_tutorial_maximize = 213; +static i32 fcoder_metacmd_ID_tutorial_minimize = 214; +static i32 fcoder_metacmd_ID_uncomment_line = 215; +static i32 fcoder_metacmd_ID_undo = 216; +static i32 fcoder_metacmd_ID_undo_all_buffers = 217; +static i32 fcoder_metacmd_ID_view_buffer_other_panel = 218; +static i32 fcoder_metacmd_ID_view_jump_list_with_lister = 219; +static i32 fcoder_metacmd_ID_word_complete = 220; +static i32 fcoder_metacmd_ID_word_complete_drop_down = 221; +static i32 fcoder_metacmd_ID_write_block = 222; +static i32 fcoder_metacmd_ID_write_hack = 223; +static i32 fcoder_metacmd_ID_write_note = 224; +static i32 fcoder_metacmd_ID_write_space = 225; +static i32 fcoder_metacmd_ID_write_text_and_auto_indent = 226; +static i32 fcoder_metacmd_ID_write_text_input = 227; +static i32 fcoder_metacmd_ID_write_todo = 228; +static i32 fcoder_metacmd_ID_write_underscore = 229; +static i32 fcoder_metacmd_ID_write_zero_struct = 230; #endif diff --git a/custom/generated/custom_api.cpp b/custom/generated/custom_api.cpp index 0a839ac5..653783c8 100644 --- a/custom/generated/custom_api.cpp +++ b/custom/generated/custom_api.cpp @@ -25,12 +25,14 @@ vtable->buffer_line_y_difference = buffer_line_y_difference; vtable->buffer_line_shift_y = buffer_line_shift_y; vtable->buffer_pos_at_relative_xy = buffer_pos_at_relative_xy; vtable->buffer_relative_box_of_pos = buffer_relative_box_of_pos; +vtable->buffer_padded_box_of_pos = buffer_padded_box_of_pos; vtable->buffer_relative_character_from_pos = buffer_relative_character_from_pos; vtable->buffer_pos_from_relative_character = buffer_pos_from_relative_character; vtable->view_line_y_difference = view_line_y_difference; vtable->view_line_shift_y = view_line_shift_y; vtable->view_pos_at_relative_xy = view_pos_at_relative_xy; vtable->view_relative_box_of_pos = view_relative_box_of_pos; +vtable->view_padded_box_of_pos = view_padded_box_of_pos; vtable->view_relative_character_from_pos = view_relative_character_from_pos; vtable->view_pos_from_relative_character = view_pos_from_relative_character; vtable->buffer_exists = buffer_exists; @@ -90,7 +92,6 @@ vtable->view_set_buffer_scroll = view_set_buffer_scroll; vtable->view_set_mark = view_set_mark; vtable->view_quit_ui = view_quit_ui; vtable->view_set_buffer = view_set_buffer; -vtable->view_post_fade = view_post_fade; vtable->view_push_context = view_push_context; vtable->view_pop_context = view_pop_context; vtable->view_alter_context = view_alter_context; @@ -154,6 +155,7 @@ vtable->try_release_face = try_release_face; vtable->push_hot_directory = push_hot_directory; vtable->set_hot_directory = set_hot_directory; vtable->send_exit_signal = send_exit_signal; +vtable->hard_exit = hard_exit; vtable->set_window_title = set_window_title; vtable->draw_string_oriented = draw_string_oriented; vtable->get_string_advance = get_string_advance; @@ -167,6 +169,7 @@ vtable->text_layout_get_visible_range = text_layout_get_visible_range; vtable->text_layout_line_on_screen = text_layout_line_on_screen; vtable->text_layout_character_on_screen = text_layout_character_on_screen; vtable->paint_text_color = paint_text_color; +vtable->paint_text_color_blend = paint_text_color_blend; vtable->text_layout_free = text_layout_free; vtable->draw_text_layout = draw_text_layout; vtable->open_color_picker = open_color_picker; @@ -203,12 +206,14 @@ buffer_line_y_difference = vtable->buffer_line_y_difference; buffer_line_shift_y = vtable->buffer_line_shift_y; buffer_pos_at_relative_xy = vtable->buffer_pos_at_relative_xy; buffer_relative_box_of_pos = vtable->buffer_relative_box_of_pos; +buffer_padded_box_of_pos = vtable->buffer_padded_box_of_pos; buffer_relative_character_from_pos = vtable->buffer_relative_character_from_pos; buffer_pos_from_relative_character = vtable->buffer_pos_from_relative_character; view_line_y_difference = vtable->view_line_y_difference; view_line_shift_y = vtable->view_line_shift_y; view_pos_at_relative_xy = vtable->view_pos_at_relative_xy; view_relative_box_of_pos = vtable->view_relative_box_of_pos; +view_padded_box_of_pos = vtable->view_padded_box_of_pos; view_relative_character_from_pos = vtable->view_relative_character_from_pos; view_pos_from_relative_character = vtable->view_pos_from_relative_character; buffer_exists = vtable->buffer_exists; @@ -268,7 +273,6 @@ view_set_buffer_scroll = vtable->view_set_buffer_scroll; view_set_mark = vtable->view_set_mark; view_quit_ui = vtable->view_quit_ui; view_set_buffer = vtable->view_set_buffer; -view_post_fade = vtable->view_post_fade; view_push_context = vtable->view_push_context; view_pop_context = vtable->view_pop_context; view_alter_context = vtable->view_alter_context; @@ -332,6 +336,7 @@ try_release_face = vtable->try_release_face; push_hot_directory = vtable->push_hot_directory; set_hot_directory = vtable->set_hot_directory; send_exit_signal = vtable->send_exit_signal; +hard_exit = vtable->hard_exit; set_window_title = vtable->set_window_title; draw_string_oriented = vtable->draw_string_oriented; get_string_advance = vtable->get_string_advance; @@ -345,6 +350,7 @@ text_layout_get_visible_range = vtable->text_layout_get_visible_range; text_layout_line_on_screen = vtable->text_layout_line_on_screen; text_layout_character_on_screen = vtable->text_layout_character_on_screen; paint_text_color = vtable->paint_text_color; +paint_text_color_blend = vtable->paint_text_color_blend; text_layout_free = vtable->text_layout_free; draw_text_layout = vtable->draw_text_layout; open_color_picker = vtable->open_color_picker; diff --git a/custom/generated/custom_api.h b/custom/generated/custom_api.h index 27bb15db..7e65493a 100644 --- a/custom/generated/custom_api.h +++ b/custom/generated/custom_api.h @@ -23,12 +23,14 @@ #define custom_buffer_line_shift_y_sig() Line_Shift_Vertical custom_buffer_line_shift_y(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 line, f32 y_shift) #define custom_buffer_pos_at_relative_xy_sig() i64 custom_buffer_pos_at_relative_xy(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, Vec2_f32 relative_xy) #define custom_buffer_relative_box_of_pos_sig() Rect_f32 custom_buffer_relative_box_of_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos) +#define custom_buffer_padded_box_of_pos_sig() Rect_f32 custom_buffer_padded_box_of_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos) #define custom_buffer_relative_character_from_pos_sig() i64 custom_buffer_relative_character_from_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos) #define custom_buffer_pos_from_relative_character_sig() i64 custom_buffer_pos_from_relative_character(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 relative_character) #define custom_view_line_y_difference_sig() f32 custom_view_line_y_difference(Application_Links* app, View_ID view_id, i64 line_a, i64 line_b) #define custom_view_line_shift_y_sig() Line_Shift_Vertical custom_view_line_shift_y(Application_Links* app, View_ID view_id, i64 line, f32 y_shift) #define custom_view_pos_at_relative_xy_sig() i64 custom_view_pos_at_relative_xy(Application_Links* app, View_ID view_id, i64 base_line, Vec2_f32 relative_xy) #define custom_view_relative_box_of_pos_sig() Rect_f32 custom_view_relative_box_of_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos) +#define custom_view_padded_box_of_pos_sig() Rect_f32 custom_view_padded_box_of_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos) #define custom_view_relative_character_from_pos_sig() i64 custom_view_relative_character_from_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos) #define custom_view_pos_from_relative_character_sig() i64 custom_view_pos_from_relative_character(Application_Links* app, View_ID view_id, i64 base_line, i64 character) #define custom_buffer_exists_sig() b32 custom_buffer_exists(Application_Links* app, Buffer_ID buffer_id) @@ -88,7 +90,6 @@ #define custom_view_set_mark_sig() b32 custom_view_set_mark(Application_Links* app, View_ID view_id, Buffer_Seek seek) #define custom_view_quit_ui_sig() b32 custom_view_quit_ui(Application_Links* app, View_ID view_id) #define custom_view_set_buffer_sig() b32 custom_view_set_buffer(Application_Links* app, View_ID view_id, Buffer_ID buffer_id, Set_Buffer_Flag flags) -#define custom_view_post_fade_sig() b32 custom_view_post_fade(Application_Links* app, View_ID view_id, f32 seconds, Range_i64 range, ARGB_Color color) #define custom_view_push_context_sig() b32 custom_view_push_context(Application_Links* app, View_ID view_id, View_Context* ctx) #define custom_view_pop_context_sig() b32 custom_view_pop_context(Application_Links* app, View_ID view_id) #define custom_view_alter_context_sig() b32 custom_view_alter_context(Application_Links* app, View_ID view_id, View_Context* ctx) @@ -152,6 +153,7 @@ #define custom_push_hot_directory_sig() String_Const_u8 custom_push_hot_directory(Application_Links* app, Arena* arena) #define custom_set_hot_directory_sig() void custom_set_hot_directory(Application_Links* app, String_Const_u8 string) #define custom_send_exit_signal_sig() void custom_send_exit_signal(Application_Links* app) +#define custom_hard_exit_sig() void custom_hard_exit(Application_Links* app) #define custom_set_window_title_sig() void custom_set_window_title(Application_Links* app, String_Const_u8 title) #define custom_draw_string_oriented_sig() Vec2_f32 custom_draw_string_oriented(Application_Links* app, Face_ID font_id, ARGB_Color color, String_Const_u8 str, Vec2_f32 point, u32 flags, Vec2_f32 delta) #define custom_get_string_advance_sig() f32 custom_get_string_advance(Application_Links* app, Face_ID font_id, String_Const_u8 str) @@ -165,6 +167,7 @@ #define custom_text_layout_line_on_screen_sig() Range_f32 custom_text_layout_line_on_screen(Application_Links* app, Text_Layout_ID layout_id, i64 line_number) #define custom_text_layout_character_on_screen_sig() Rect_f32 custom_text_layout_character_on_screen(Application_Links* app, Text_Layout_ID layout_id, i64 pos) #define custom_paint_text_color_sig() void custom_paint_text_color(Application_Links* app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color) +#define custom_paint_text_color_blend_sig() void custom_paint_text_color_blend(Application_Links* app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color, f32 blend) #define custom_text_layout_free_sig() b32 custom_text_layout_free(Application_Links* app, Text_Layout_ID text_layout_id) #define custom_draw_text_layout_sig() void custom_draw_text_layout(Application_Links* app, Text_Layout_ID layout_id, ARGB_Color special_color, ARGB_Color ghost_color) #define custom_open_color_picker_sig() void custom_open_color_picker(Application_Links* app, Color_Picker* picker) @@ -197,12 +200,14 @@ typedef f32 custom_buffer_line_y_difference_type(Application_Links* app, Buffer_ typedef Line_Shift_Vertical custom_buffer_line_shift_y_type(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 line, f32 y_shift); typedef i64 custom_buffer_pos_at_relative_xy_type(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, Vec2_f32 relative_xy); typedef Rect_f32 custom_buffer_relative_box_of_pos_type(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); +typedef Rect_f32 custom_buffer_padded_box_of_pos_type(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); typedef i64 custom_buffer_relative_character_from_pos_type(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); typedef i64 custom_buffer_pos_from_relative_character_type(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 relative_character); typedef f32 custom_view_line_y_difference_type(Application_Links* app, View_ID view_id, i64 line_a, i64 line_b); typedef Line_Shift_Vertical custom_view_line_shift_y_type(Application_Links* app, View_ID view_id, i64 line, f32 y_shift); typedef i64 custom_view_pos_at_relative_xy_type(Application_Links* app, View_ID view_id, i64 base_line, Vec2_f32 relative_xy); typedef Rect_f32 custom_view_relative_box_of_pos_type(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); +typedef Rect_f32 custom_view_padded_box_of_pos_type(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); typedef i64 custom_view_relative_character_from_pos_type(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); typedef i64 custom_view_pos_from_relative_character_type(Application_Links* app, View_ID view_id, i64 base_line, i64 character); typedef b32 custom_buffer_exists_type(Application_Links* app, Buffer_ID buffer_id); @@ -262,7 +267,6 @@ typedef b32 custom_view_set_buffer_scroll_type(Application_Links* app, View_ID v typedef b32 custom_view_set_mark_type(Application_Links* app, View_ID view_id, Buffer_Seek seek); typedef b32 custom_view_quit_ui_type(Application_Links* app, View_ID view_id); typedef b32 custom_view_set_buffer_type(Application_Links* app, View_ID view_id, Buffer_ID buffer_id, Set_Buffer_Flag flags); -typedef b32 custom_view_post_fade_type(Application_Links* app, View_ID view_id, f32 seconds, Range_i64 range, ARGB_Color color); typedef b32 custom_view_push_context_type(Application_Links* app, View_ID view_id, View_Context* ctx); typedef b32 custom_view_pop_context_type(Application_Links* app, View_ID view_id); typedef b32 custom_view_alter_context_type(Application_Links* app, View_ID view_id, View_Context* ctx); @@ -326,6 +330,7 @@ typedef b32 custom_try_release_face_type(Application_Links* app, Face_ID id, Fac typedef String_Const_u8 custom_push_hot_directory_type(Application_Links* app, Arena* arena); typedef void custom_set_hot_directory_type(Application_Links* app, String_Const_u8 string); typedef void custom_send_exit_signal_type(Application_Links* app); +typedef void custom_hard_exit_type(Application_Links* app); typedef void custom_set_window_title_type(Application_Links* app, String_Const_u8 title); typedef Vec2_f32 custom_draw_string_oriented_type(Application_Links* app, Face_ID font_id, ARGB_Color color, String_Const_u8 str, Vec2_f32 point, u32 flags, Vec2_f32 delta); typedef f32 custom_get_string_advance_type(Application_Links* app, Face_ID font_id, String_Const_u8 str); @@ -339,6 +344,7 @@ typedef Range_i64 custom_text_layout_get_visible_range_type(Application_Links* a typedef Range_f32 custom_text_layout_line_on_screen_type(Application_Links* app, Text_Layout_ID layout_id, i64 line_number); typedef Rect_f32 custom_text_layout_character_on_screen_type(Application_Links* app, Text_Layout_ID layout_id, i64 pos); typedef void custom_paint_text_color_type(Application_Links* app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color); +typedef void custom_paint_text_color_blend_type(Application_Links* app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color, f32 blend); typedef b32 custom_text_layout_free_type(Application_Links* app, Text_Layout_ID text_layout_id); typedef void custom_draw_text_layout_type(Application_Links* app, Text_Layout_ID layout_id, ARGB_Color special_color, ARGB_Color ghost_color); typedef void custom_open_color_picker_type(Application_Links* app, Color_Picker* picker); @@ -372,12 +378,14 @@ custom_buffer_line_y_difference_type *buffer_line_y_difference; custom_buffer_line_shift_y_type *buffer_line_shift_y; custom_buffer_pos_at_relative_xy_type *buffer_pos_at_relative_xy; custom_buffer_relative_box_of_pos_type *buffer_relative_box_of_pos; +custom_buffer_padded_box_of_pos_type *buffer_padded_box_of_pos; custom_buffer_relative_character_from_pos_type *buffer_relative_character_from_pos; custom_buffer_pos_from_relative_character_type *buffer_pos_from_relative_character; custom_view_line_y_difference_type *view_line_y_difference; custom_view_line_shift_y_type *view_line_shift_y; custom_view_pos_at_relative_xy_type *view_pos_at_relative_xy; custom_view_relative_box_of_pos_type *view_relative_box_of_pos; +custom_view_padded_box_of_pos_type *view_padded_box_of_pos; custom_view_relative_character_from_pos_type *view_relative_character_from_pos; custom_view_pos_from_relative_character_type *view_pos_from_relative_character; custom_buffer_exists_type *buffer_exists; @@ -437,7 +445,6 @@ custom_view_set_buffer_scroll_type *view_set_buffer_scroll; custom_view_set_mark_type *view_set_mark; custom_view_quit_ui_type *view_quit_ui; custom_view_set_buffer_type *view_set_buffer; -custom_view_post_fade_type *view_post_fade; custom_view_push_context_type *view_push_context; custom_view_pop_context_type *view_pop_context; custom_view_alter_context_type *view_alter_context; @@ -501,6 +508,7 @@ custom_try_release_face_type *try_release_face; custom_push_hot_directory_type *push_hot_directory; custom_set_hot_directory_type *set_hot_directory; custom_send_exit_signal_type *send_exit_signal; +custom_hard_exit_type *hard_exit; custom_set_window_title_type *set_window_title; custom_draw_string_oriented_type *draw_string_oriented; custom_get_string_advance_type *get_string_advance; @@ -514,6 +522,7 @@ custom_text_layout_get_visible_range_type *text_layout_get_visible_range; custom_text_layout_line_on_screen_type *text_layout_line_on_screen; custom_text_layout_character_on_screen_type *text_layout_character_on_screen; custom_paint_text_color_type *paint_text_color; +custom_paint_text_color_blend_type *paint_text_color_blend; custom_text_layout_free_type *text_layout_free; custom_draw_text_layout_type *draw_text_layout; custom_open_color_picker_type *open_color_picker; @@ -548,12 +557,14 @@ internal f32 buffer_line_y_difference(Application_Links* app, Buffer_ID buffer_i internal Line_Shift_Vertical buffer_line_shift_y(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 line, f32 y_shift); internal i64 buffer_pos_at_relative_xy(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, Vec2_f32 relative_xy); internal Rect_f32 buffer_relative_box_of_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); +internal Rect_f32 buffer_padded_box_of_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); internal i64 buffer_relative_character_from_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); internal i64 buffer_pos_from_relative_character(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 relative_character); internal f32 view_line_y_difference(Application_Links* app, View_ID view_id, i64 line_a, i64 line_b); internal Line_Shift_Vertical view_line_shift_y(Application_Links* app, View_ID view_id, i64 line, f32 y_shift); internal i64 view_pos_at_relative_xy(Application_Links* app, View_ID view_id, i64 base_line, Vec2_f32 relative_xy); internal Rect_f32 view_relative_box_of_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); +internal Rect_f32 view_padded_box_of_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); internal i64 view_relative_character_from_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); internal i64 view_pos_from_relative_character(Application_Links* app, View_ID view_id, i64 base_line, i64 character); internal b32 buffer_exists(Application_Links* app, Buffer_ID buffer_id); @@ -613,7 +624,6 @@ internal b32 view_set_buffer_scroll(Application_Links* app, View_ID view_id, Buf internal b32 view_set_mark(Application_Links* app, View_ID view_id, Buffer_Seek seek); internal b32 view_quit_ui(Application_Links* app, View_ID view_id); internal b32 view_set_buffer(Application_Links* app, View_ID view_id, Buffer_ID buffer_id, Set_Buffer_Flag flags); -internal b32 view_post_fade(Application_Links* app, View_ID view_id, f32 seconds, Range_i64 range, ARGB_Color color); internal b32 view_push_context(Application_Links* app, View_ID view_id, View_Context* ctx); internal b32 view_pop_context(Application_Links* app, View_ID view_id); internal b32 view_alter_context(Application_Links* app, View_ID view_id, View_Context* ctx); @@ -677,6 +687,7 @@ internal b32 try_release_face(Application_Links* app, Face_ID id, Face_ID replac internal String_Const_u8 push_hot_directory(Application_Links* app, Arena* arena); internal void set_hot_directory(Application_Links* app, String_Const_u8 string); internal void send_exit_signal(Application_Links* app); +internal void hard_exit(Application_Links* app); internal void set_window_title(Application_Links* app, String_Const_u8 title); internal Vec2_f32 draw_string_oriented(Application_Links* app, Face_ID font_id, ARGB_Color color, String_Const_u8 str, Vec2_f32 point, u32 flags, Vec2_f32 delta); internal f32 get_string_advance(Application_Links* app, Face_ID font_id, String_Const_u8 str); @@ -690,6 +701,7 @@ internal Range_i64 text_layout_get_visible_range(Application_Links* app, Text_La internal Range_f32 text_layout_line_on_screen(Application_Links* app, Text_Layout_ID layout_id, i64 line_number); internal Rect_f32 text_layout_character_on_screen(Application_Links* app, Text_Layout_ID layout_id, i64 pos); internal void paint_text_color(Application_Links* app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color); +internal void paint_text_color_blend(Application_Links* app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color, f32 blend); internal b32 text_layout_free(Application_Links* app, Text_Layout_ID text_layout_id); internal void draw_text_layout(Application_Links* app, Text_Layout_ID layout_id, ARGB_Color special_color, ARGB_Color ghost_color); internal void open_color_picker(Application_Links* app, Color_Picker* picker); @@ -724,12 +736,14 @@ global custom_buffer_line_y_difference_type *buffer_line_y_difference = 0; global custom_buffer_line_shift_y_type *buffer_line_shift_y = 0; global custom_buffer_pos_at_relative_xy_type *buffer_pos_at_relative_xy = 0; global custom_buffer_relative_box_of_pos_type *buffer_relative_box_of_pos = 0; +global custom_buffer_padded_box_of_pos_type *buffer_padded_box_of_pos = 0; global custom_buffer_relative_character_from_pos_type *buffer_relative_character_from_pos = 0; global custom_buffer_pos_from_relative_character_type *buffer_pos_from_relative_character = 0; global custom_view_line_y_difference_type *view_line_y_difference = 0; global custom_view_line_shift_y_type *view_line_shift_y = 0; global custom_view_pos_at_relative_xy_type *view_pos_at_relative_xy = 0; global custom_view_relative_box_of_pos_type *view_relative_box_of_pos = 0; +global custom_view_padded_box_of_pos_type *view_padded_box_of_pos = 0; global custom_view_relative_character_from_pos_type *view_relative_character_from_pos = 0; global custom_view_pos_from_relative_character_type *view_pos_from_relative_character = 0; global custom_buffer_exists_type *buffer_exists = 0; @@ -789,7 +803,6 @@ global custom_view_set_buffer_scroll_type *view_set_buffer_scroll = 0; global custom_view_set_mark_type *view_set_mark = 0; global custom_view_quit_ui_type *view_quit_ui = 0; global custom_view_set_buffer_type *view_set_buffer = 0; -global custom_view_post_fade_type *view_post_fade = 0; global custom_view_push_context_type *view_push_context = 0; global custom_view_pop_context_type *view_pop_context = 0; global custom_view_alter_context_type *view_alter_context = 0; @@ -853,6 +866,7 @@ global custom_try_release_face_type *try_release_face = 0; global custom_push_hot_directory_type *push_hot_directory = 0; global custom_set_hot_directory_type *set_hot_directory = 0; global custom_send_exit_signal_type *send_exit_signal = 0; +global custom_hard_exit_type *hard_exit = 0; global custom_set_window_title_type *set_window_title = 0; global custom_draw_string_oriented_type *draw_string_oriented = 0; global custom_get_string_advance_type *get_string_advance = 0; @@ -866,6 +880,7 @@ global custom_text_layout_get_visible_range_type *text_layout_get_visible_range global custom_text_layout_line_on_screen_type *text_layout_line_on_screen = 0; global custom_text_layout_character_on_screen_type *text_layout_character_on_screen = 0; global custom_paint_text_color_type *paint_text_color = 0; +global custom_paint_text_color_blend_type *paint_text_color_blend = 0; global custom_text_layout_free_type *text_layout_free = 0; global custom_draw_text_layout_type *draw_text_layout = 0; global custom_open_color_picker_type *open_color_picker = 0; diff --git a/custom/generated/custom_api_constructor.cpp b/custom/generated/custom_api_constructor.cpp index f72a65da..2520a502 100644 --- a/custom/generated/custom_api_constructor.cpp +++ b/custom/generated/custom_api_constructor.cpp @@ -161,6 +161,15 @@ api_param(arena, call, "i64", "base_line"); api_param(arena, call, "i64", "pos"); } { +API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("buffer_padded_box_of_pos"), string_u8_litexpr("Rect_f32"), string_u8_litexpr("")); +api_param(arena, call, "Application_Links*", "app"); +api_param(arena, call, "Buffer_ID", "buffer_id"); +api_param(arena, call, "f32", "width"); +api_param(arena, call, "Face_ID", "face_id"); +api_param(arena, call, "i64", "base_line"); +api_param(arena, call, "i64", "pos"); +} +{ API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("buffer_relative_character_from_pos"), string_u8_litexpr("i64"), string_u8_litexpr("")); api_param(arena, call, "Application_Links*", "app"); api_param(arena, call, "Buffer_ID", "buffer_id"); @@ -207,6 +216,13 @@ api_param(arena, call, "i64", "base_line"); api_param(arena, call, "i64", "pos"); } { +API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("view_padded_box_of_pos"), string_u8_litexpr("Rect_f32"), string_u8_litexpr("")); +api_param(arena, call, "Application_Links*", "app"); +api_param(arena, call, "View_ID", "view_id"); +api_param(arena, call, "i64", "base_line"); +api_param(arena, call, "i64", "pos"); +} +{ API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("view_relative_character_from_pos"), string_u8_litexpr("i64"), string_u8_litexpr("")); api_param(arena, call, "Application_Links*", "app"); api_param(arena, call, "View_ID", "view_id"); @@ -890,6 +906,10 @@ API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("send_e api_param(arena, call, "Application_Links*", "app"); } { +API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("hard_exit"), string_u8_litexpr("void"), string_u8_litexpr("")); +api_param(arena, call, "Application_Links*", "app"); +} +{ API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("set_window_title"), string_u8_litexpr("void"), string_u8_litexpr("")); api_param(arena, call, "Application_Links*", "app"); api_param(arena, call, "String_Const_u8", "title"); @@ -968,7 +988,7 @@ api_param(arena, call, "i64", "pos"); API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("paint_text_color"), string_u8_litexpr("void"), string_u8_litexpr("")); api_param(arena, call, "Application_Links*", "app"); api_param(arena, call, "Text_Layout_ID", "layout_id"); -api_param(arena, call, "Interval_i64", "range"); +api_param(arena, call, "Range_i64", "range"); api_param(arena, call, "ARGB_Color", "color"); } { diff --git a/custom/generated/custom_api_master_list.h b/custom/generated/custom_api_master_list.h index 53c10b50..60e06631 100644 --- a/custom/generated/custom_api_master_list.h +++ b/custom/generated/custom_api_master_list.h @@ -23,12 +23,14 @@ api(custom) function f32 buffer_line_y_difference(Application_Links* app, Buffer api(custom) function Line_Shift_Vertical buffer_line_shift_y(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 line, f32 y_shift); api(custom) function i64 buffer_pos_at_relative_xy(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, Vec2_f32 relative_xy); api(custom) function Rect_f32 buffer_relative_box_of_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); +api(custom) function Rect_f32 buffer_padded_box_of_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); api(custom) function i64 buffer_relative_character_from_pos(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos); api(custom) function i64 buffer_pos_from_relative_character(Application_Links* app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 relative_character); api(custom) function f32 view_line_y_difference(Application_Links* app, View_ID view_id, i64 line_a, i64 line_b); api(custom) function Line_Shift_Vertical view_line_shift_y(Application_Links* app, View_ID view_id, i64 line, f32 y_shift); api(custom) function i64 view_pos_at_relative_xy(Application_Links* app, View_ID view_id, i64 base_line, Vec2_f32 relative_xy); api(custom) function Rect_f32 view_relative_box_of_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); +api(custom) function Rect_f32 view_padded_box_of_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); api(custom) function i64 view_relative_character_from_pos(Application_Links* app, View_ID view_id, i64 base_line, i64 pos); api(custom) function i64 view_pos_from_relative_character(Application_Links* app, View_ID view_id, i64 base_line, i64 character); api(custom) function b32 buffer_exists(Application_Links* app, Buffer_ID buffer_id); @@ -88,7 +90,6 @@ api(custom) function b32 view_set_buffer_scroll(Application_Links* app, View_ID api(custom) function b32 view_set_mark(Application_Links* app, View_ID view_id, Buffer_Seek seek); api(custom) function b32 view_quit_ui(Application_Links* app, View_ID view_id); api(custom) function b32 view_set_buffer(Application_Links* app, View_ID view_id, Buffer_ID buffer_id, Set_Buffer_Flag flags); -api(custom) function b32 view_post_fade(Application_Links* app, View_ID view_id, f32 seconds, Range_i64 range, ARGB_Color color); api(custom) function b32 view_push_context(Application_Links* app, View_ID view_id, View_Context* ctx); api(custom) function b32 view_pop_context(Application_Links* app, View_ID view_id); api(custom) function b32 view_alter_context(Application_Links* app, View_ID view_id, View_Context* ctx); @@ -152,6 +153,7 @@ api(custom) function b32 try_release_face(Application_Links* app, Face_ID id, Fa api(custom) function String_Const_u8 push_hot_directory(Application_Links* app, Arena* arena); api(custom) function void set_hot_directory(Application_Links* app, String_Const_u8 string); api(custom) function void send_exit_signal(Application_Links* app); +api(custom) function void hard_exit(Application_Links* app); api(custom) function void set_window_title(Application_Links* app, String_Const_u8 title); api(custom) function Vec2_f32 draw_string_oriented(Application_Links* app, Face_ID font_id, ARGB_Color color, String_Const_u8 str, Vec2_f32 point, u32 flags, Vec2_f32 delta); api(custom) function f32 get_string_advance(Application_Links* app, Face_ID font_id, String_Const_u8 str); @@ -165,6 +167,7 @@ api(custom) function Range_i64 text_layout_get_visible_range(Application_Links* api(custom) function Range_f32 text_layout_line_on_screen(Application_Links* app, Text_Layout_ID layout_id, i64 line_number); api(custom) function Rect_f32 text_layout_character_on_screen(Application_Links* app, Text_Layout_ID layout_id, i64 pos); api(custom) function void paint_text_color(Application_Links* app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color); +api(custom) function void paint_text_color_blend(Application_Links* app, Text_Layout_ID layout_id, Range_i64 range, ARGB_Color color, f32 blend); api(custom) function b32 text_layout_free(Application_Links* app, Text_Layout_ID text_layout_id); api(custom) function void draw_text_layout(Application_Links* app, Text_Layout_ID layout_id, ARGB_Color special_color, ARGB_Color ghost_color); api(custom) function void open_color_picker(Application_Links* app, Color_Picker* picker); diff --git a/custom/generated/lexer_cpp.cpp b/custom/generated/lexer_cpp.cpp index 150e5fbf..213d6ac5 100644 --- a/custom/generated/lexer_cpp.cpp +++ b/custom/generated/lexer_cpp.cpp @@ -43,447 +43,453 @@ lexeme_table_lookup(u64 *hash_array, String_Const_u8 *key_array, } #endif -u64 main_keys_hash_array[121] = { -0x3165da52e461ac3f,0x0000000000000000,0x3165da52f92661bd,0x0000000000000000, -0x0000000000000000,0x0000000000000000,0x3165da52f9fa6ddb,0xbfc3c777d05a650b, -0x3165da52ea1d2cb3,0x0000000000000000,0x0000000000000000,0x0000000000000000, -0x0000000000000000,0xa47e4b3347ca768b,0xa47e4b0d60643265,0xf9ddaa09147bac4d, -0x95351611c4501ef3,0x0000000000000000,0x0000000000000000,0xa47e4b33693ada65, -0x0000000000000000,0xdb05013ca08bb8f1,0xf9ddaa091485019b,0xbfc3dfcbf5462bb3, -0x0000000000000000,0x3165da52f85e6961,0x0000000000000000,0xdb0563922ce5394d, -0x0000000000000000,0xa47e4b334bfc993f,0xdb02e2748a4d7e43,0x0000000000000000, -0xb4c81ca554c806f3,0x0000000000000000,0x3165da52e0f88b5b,0x501eeeb814fbf821, -0x0000000000000000,0xdb0503951fae6cc1,0x0000000000000000,0x0000000000000000, -0xbfc3de349dfab331,0x0000000000000000,0x0000000000000000,0x3165da52f092830f, -0xa47e4b300b3f05d3,0xbfc3dfcbf546362d,0xdb05125809d1c12f,0x0000000000000000, -0xed66c2eeb45a9c73,0x0000000000000000,0xf9ddaa0914eaa03f,0x77f5a2bcd06af3a3, -0xa47e4b0cab3b440f,0x0000000000000000,0x0000000000000000,0x3165da52ebde8871, -0xa47e4b0cab0869b5,0x3165da52e5b576b7,0x0000000000000000,0x0000000000000000, -0xa47e4b336935d383,0x0000000000000000,0x0000000000000000,0xa47e4b30efc0220b, -0x0000000000000000,0x0000000000000000,0x501eeeb814fabe67,0xbfc3dfefa2fc3a77, -0x0000000000000000,0x0000000000000000,0x0000000000000000,0xf9ddaa0914bb0bf9, -0x0000000000000000,0xf9ddaa09148a58bb,0x0000000000000000,0xdb02e323971f6e8d, -0x501eeeb814fa0161,0xa9cef01e4d45a29b,0x501eeeb814fb939f,0x0000000000000000, -0xdb0517ba16b3ab83,0xbfc3dfb0ab021849,0xdb0541265bb691e9,0xbfc3df66cacb41a5, -0xa47e4b325526bb31,0x0000000000000000,0xeca54fbddbbe35d5,0xa47e4b3347a263d3, -0x0000000000000000,0x77e3dcb62d4753c1,0xdb05aa39286523b1,0x0000000000000000, -0xf9ddaa0914b809a1,0x0000000000000000,0xc6f60bbdf7c8c073,0x3165da52e44f8393, -0x0000000000000000,0x0000000000000000,0xa47e4b32f4f66927,0x0000000000000000, -0xf9ddaa0914dd4631,0x0000000000000000,0xa47e4b322642ad51,0x0000000000000000, -0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000, -0xa47e4b335ea331b5,0x0000000000000000,0x0000000000000000,0x0000000000000000, -0xdb0545d45d35a161,0xeca54fbddbbe34ff,0x44a0daa872c59baf,0x0000000000000000, -0xf9ddaa0914c5876b,0x0000000000000000,0x501eeeb814fa0b79,0xf9ddaa0914df8d85, -0xf9ddaa0914b167f3, +u64 cpp_main_keys_hash_array[124] = { +0x26092f2f0215ece3,0x0000000000000000,0x5ce5a2eda58b1f23,0xb2d6c5c6769fa3a3, +0xb9ddf454bfe26d23,0x0000000000000000,0xcd0f6cfa687dd553,0x0000000000000000, +0x0000000000000000,0x5ce5a2e0c5100279,0x5ce5a2ede7babb3d,0x0000000000000000, +0x0000000000000000,0x6f6d951cb7cb582d,0x0e10b5f7624a6565,0xf889fe35be4428e3, +0x6f6d951cb404483f,0x26092f2f02f1c5ef,0x0000000000000000,0xe2b3ddb2fb5b2e6b, +0x0000000000000000,0x6f6d951cb4ea937d,0x0000000000000000,0x0000000000000000, +0x0000000000000000,0x0e10b1af23a24eb5,0x5ce5a2f3706ea43f,0x0000000000000000, +0xb2d6ca88b991d451,0xe2b3ddb2fb5a20a9,0x0000000000000000,0x26092f2f02d33cab, +0x0000000000000000,0x0000000000000000,0x5ce5a2e66f839a73,0x0000000000000000, +0x5ce5a2eda5890521,0x0000000000000000,0x6f6d951cb4228ddb,0x6f6d951cba73c8ab, +0xb9ddf454bfe26e41,0xd50b424c05eec7e9,0x8557f78510d2bb43,0x0000000000000000, +0x0000000000000000,0x26092f2f020b132d,0x0000000000000000,0x0000000000000000, +0xe2b3ddb2fb5bc1c9,0x0000000000000000,0x8ef935ae0949ace3,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x0000000000000000,0x26092f2f02d2781b, +0x26092f2f02e7a15d,0xb2d6c74182f6a66d,0x0000000000000000,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x0000000000000000,0x26092f2f02e78453, +0xe2b3ddb2fb5bd5b5,0xb2d6c74182f6a7e9,0x0000000000000000,0x0000000000000000, +0xb2d6c6c7361150b5,0x5ce5a2e0b306cde5,0x0000000000000000,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x5ce5a2e7e5c24db3,0x26092f2f0216583b, +0x0e101bb85ac205ad,0x6f6d951cacb1aa35,0x0000000000000000,0x0000000000000000, +0x0000000000000000,0x5ce5a2e197faf9d9,0xe2b3ddb2fb5baba1,0x6f6d951cba402e7b, +0x26092f2f02e1d2eb,0x0000000000000000,0x73a9345f7aa71363,0x0000000000000000, +0x0e10b66610117f15,0x0000000000000000,0xe95e136b18f58763,0x0e10078c941fcafb, +0x0000000000000000,0x0000000000000000,0x5ce5a2f37530abf3,0xb2d6c68c37b0f1f7, +0x5ce5a2e7e4364fe9,0x5ce5a2f37536698d,0x0000000000000000,0x0000000000000000, +0x5ce5a2e049adcf39,0x0000000000000000,0x0000000000000000,0x0e100efea5987c03, +0x6f6d951c847de2fb,0x0e106caf9da9bbbd,0x0e109bd9232f3723,0x0000000000000000, +0x6f6d951c86ec6929,0x0000000000000000,0x0000000000000000,0x0e114d6868e6156b, +0x6f6d951c8f3e1899,0x0e105b1fdc2b41ad,0xb2d6c5dc5a9a53e5,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x26092f2f0212aa4b,0x0000000000000000, +0x0000000000000000,0x0000000000000000,0x5ce5a2f37ca36a8b,0xcd1ba7f6b56d6ce3, }; -u8 main_keys_key_array_0[] = {0x63,0x61,0x74,0x63,0x68,}; -u8 main_keys_key_array_2[] = {0x75,0x6e,0x69,0x6f,0x6e,}; -u8 main_keys_key_array_6[] = {0x75,0x73,0x69,0x6e,0x67,}; -u8 main_keys_key_array_7[] = {0x76,0x69,0x72,0x74,0x75,0x61,0x6c,}; -u8 main_keys_key_array_8[] = {0x66,0x6c,0x6f,0x61,0x74,}; -u8 main_keys_key_array_13[] = {0x73,0x74,0x61,0x74,0x69,0x63,}; -u8 main_keys_key_array_14[] = {0x69,0x6e,0x6c,0x69,0x6e,0x65,}; -u8 main_keys_key_array_15[] = {0x74,0x72,0x75,0x65,}; -u8 main_keys_key_array_16[] = {0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x5f,0x63,0x61,0x73,0x74,}; -u8 main_keys_key_array_19[] = {0x73,0x69,0x7a,0x65,0x6f,0x66,}; -u8 main_keys_key_array_21[] = {0x74,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,}; -u8 main_keys_key_array_22[] = {0x74,0x68,0x69,0x73,}; -u8 main_keys_key_array_23[] = {0x61,0x6c,0x69,0x67,0x6e,0x61,0x73,}; -u8 main_keys_key_array_25[] = {0x77,0x68,0x69,0x6c,0x65,}; -u8 main_keys_key_array_27[] = {0x74,0x79,0x70,0x65,0x6e,0x61,0x6d,0x65,}; -u8 main_keys_key_array_29[] = {0x73,0x77,0x69,0x74,0x63,0x68,}; -u8 main_keys_key_array_30[] = {0x65,0x78,0x70,0x6c,0x69,0x63,0x69,0x74,}; -u8 main_keys_key_array_32[] = {0x73,0x74,0x61,0x74,0x69,0x63,0x5f,0x63,0x61,0x73,0x74,}; -u8 main_keys_key_array_34[] = {0x62,0x72,0x65,0x61,0x6b,}; -u8 main_keys_key_array_35[] = {0x74,0x72,0x79,}; -u8 main_keys_key_array_37[] = {0x64,0x65,0x63,0x6c,0x74,0x79,0x70,0x65,}; -u8 main_keys_key_array_40[] = {0x70,0x72,0x69,0x76,0x61,0x74,0x65,}; -u8 main_keys_key_array_43[] = {0x73,0x68,0x6f,0x72,0x74,}; -u8 main_keys_key_array_44[] = {0x74,0x79,0x70,0x65,0x69,0x64,}; -u8 main_keys_key_array_45[] = {0x61,0x6c,0x69,0x67,0x6e,0x6f,0x66,}; -u8 main_keys_key_array_46[] = {0x6e,0x6f,0x65,0x78,0x63,0x65,0x70,0x74,}; -u8 main_keys_key_array_48[] = {0x72,0x65,0x69,0x6e,0x74,0x65,0x72,0x70,0x72,0x65,0x74,0x5f,0x63,0x61,0x73,0x74,}; -u8 main_keys_key_array_50[] = {0x67,0x6f,0x74,0x6f,}; -u8 main_keys_key_array_51[] = {0x70,0x72,0x6f,0x74,0x65,0x63,0x74,0x65,0x64,}; -u8 main_keys_key_array_52[] = {0x65,0x78,0x70,0x6f,0x72,0x74,}; -u8 main_keys_key_array_55[] = {0x66,0x61,0x6c,0x73,0x65,}; -u8 main_keys_key_array_56[] = {0x65,0x78,0x74,0x65,0x72,0x6e,}; -u8 main_keys_key_array_57[] = {0x63,0x6c,0x61,0x73,0x73,}; -u8 main_keys_key_array_60[] = {0x73,0x69,0x67,0x6e,0x65,0x64,}; -u8 main_keys_key_array_63[] = {0x70,0x75,0x62,0x6c,0x69,0x63,}; -u8 main_keys_key_array_66[] = {0x69,0x6e,0x74,}; -u8 main_keys_key_array_67[] = {0x64,0x65,0x66,0x61,0x75,0x6c,0x74,}; -u8 main_keys_key_array_71[] = {0x63,0x68,0x61,0x72,}; -u8 main_keys_key_array_73[] = {0x6c,0x6f,0x6e,0x67,}; -u8 main_keys_key_array_75[] = {0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,}; -u8 main_keys_key_array_76[] = {0x66,0x6f,0x72,}; -u8 main_keys_key_array_77[] = {0x74,0x68,0x72,0x65,0x61,0x64,0x5f,0x6c,0x6f,0x63,0x61,0x6c,}; -u8 main_keys_key_array_78[] = {0x6e,0x65,0x77,}; -u8 main_keys_key_array_80[] = {0x75,0x6e,0x73,0x69,0x67,0x6e,0x65,0x64,}; -u8 main_keys_key_array_81[] = {0x6e,0x75,0x6c,0x6c,0x70,0x74,0x72,}; -u8 main_keys_key_array_82[] = {0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,}; -u8 main_keys_key_array_83[] = {0x74,0x79,0x70,0x65,0x64,0x65,0x66,}; -u8 main_keys_key_array_84[] = {0x64,0x65,0x6c,0x65,0x74,0x65,}; -u8 main_keys_key_array_86[] = {0x69,0x66,}; -u8 main_keys_key_array_87[] = {0x73,0x74,0x72,0x75,0x63,0x74,}; -u8 main_keys_key_array_89[] = {0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,}; -u8 main_keys_key_array_90[] = {0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,}; -u8 main_keys_key_array_92[] = {0x63,0x61,0x73,0x65,}; -u8 main_keys_key_array_94[] = {0x63,0x6f,0x6e,0x73,0x74,0x5f,0x63,0x61,0x73,0x74,}; -u8 main_keys_key_array_95[] = {0x63,0x6f,0x6e,0x73,0x74,}; -u8 main_keys_key_array_98[] = {0x66,0x72,0x69,0x65,0x6e,0x64,}; -u8 main_keys_key_array_100[] = {0x65,0x6c,0x73,0x65,}; -u8 main_keys_key_array_102[] = {0x64,0x6f,0x75,0x62,0x6c,0x65,}; -u8 main_keys_key_array_108[] = {0x72,0x65,0x74,0x75,0x72,0x6e,}; -u8 main_keys_key_array_112[] = {0x76,0x6f,0x6c,0x61,0x74,0x69,0x6c,0x65,}; -u8 main_keys_key_array_113[] = {0x64,0x6f,}; -u8 main_keys_key_array_114[] = {0x73,0x74,0x61,0x74,0x69,0x63,0x5f,0x61,0x73,0x73,0x65,0x72,0x74,}; -u8 main_keys_key_array_116[] = {0x62,0x6f,0x6f,0x6c,}; -u8 main_keys_key_array_118[] = {0x61,0x73,0x6d,}; -u8 main_keys_key_array_119[] = {0x65,0x6e,0x75,0x6d,}; -u8 main_keys_key_array_120[] = {0x76,0x6f,0x69,0x64,}; -String_Const_u8 main_keys_key_array[121] = { -{main_keys_key_array_0, 5}, +u8 cpp_main_keys_key_array_0[] = {0x74,0x72,0x75,0x65,}; +u8 cpp_main_keys_key_array_2[] = {0x73,0x69,0x67,0x6e,0x65,0x64,}; +u8 cpp_main_keys_key_array_3[] = {0x76,0x69,0x72,0x74,0x75,0x61,0x6c,}; +u8 cpp_main_keys_key_array_4[] = {0x64,0x6f,}; +u8 cpp_main_keys_key_array_6[] = {0x70,0x72,0x6f,0x74,0x65,0x63,0x74,0x65,0x64,}; +u8 cpp_main_keys_key_array_9[] = {0x64,0x6f,0x75,0x62,0x6c,0x65,}; +u8 cpp_main_keys_key_array_10[] = {0x70,0x75,0x62,0x6c,0x69,0x63,}; +u8 cpp_main_keys_key_array_13[] = {0x63,0x6c,0x61,0x73,0x73,}; +u8 cpp_main_keys_key_array_14[] = {0x74,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,}; +u8 cpp_main_keys_key_array_15[] = {0x73,0x74,0x61,0x74,0x69,0x63,0x5f,0x63,0x61,0x73,0x74,}; +u8 cpp_main_keys_key_array_16[] = {0x63,0x61,0x74,0x63,0x68,}; +u8 cpp_main_keys_key_array_17[] = {0x67,0x6f,0x74,0x6f,}; +u8 cpp_main_keys_key_array_19[] = {0x61,0x73,0x6d,}; +u8 cpp_main_keys_key_array_21[] = {0x62,0x72,0x65,0x61,0x6b,}; +u8 cpp_main_keys_key_array_25[] = {0x76,0x6f,0x6c,0x61,0x74,0x69,0x6c,0x65,}; +u8 cpp_main_keys_key_array_26[] = {0x73,0x77,0x69,0x74,0x63,0x68,}; +u8 cpp_main_keys_key_array_28[] = {0x74,0x79,0x70,0x65,0x64,0x65,0x66,}; +u8 cpp_main_keys_key_array_29[] = {0x74,0x72,0x79,}; +u8 cpp_main_keys_key_array_31[] = {0x65,0x6c,0x73,0x65,}; +u8 cpp_main_keys_key_array_34[] = {0x72,0x65,0x74,0x75,0x72,0x6e,}; +u8 cpp_main_keys_key_array_36[] = {0x73,0x69,0x7a,0x65,0x6f,0x66,}; +u8 cpp_main_keys_key_array_38[] = {0x63,0x6f,0x6e,0x73,0x74,}; +u8 cpp_main_keys_key_array_39[] = {0x66,0x61,0x6c,0x73,0x65,}; +u8 cpp_main_keys_key_array_40[] = {0x69,0x66,}; +u8 cpp_main_keys_key_array_41[] = {0x73,0x74,0x61,0x74,0x69,0x63,0x5f,0x61,0x73,0x73,0x65,0x72,0x74,}; +u8 cpp_main_keys_key_array_42[] = {0x74,0x68,0x72,0x65,0x61,0x64,0x5f,0x6c,0x6f,0x63,0x61,0x6c,}; +u8 cpp_main_keys_key_array_45[] = {0x74,0x68,0x69,0x73,}; +u8 cpp_main_keys_key_array_48[] = {0x69,0x6e,0x74,}; +u8 cpp_main_keys_key_array_50[] = {0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x5f,0x63,0x61,0x73,0x74,}; +u8 cpp_main_keys_key_array_55[] = {0x65,0x6e,0x75,0x6d,}; +u8 cpp_main_keys_key_array_56[] = {0x63,0x68,0x61,0x72,}; +u8 cpp_main_keys_key_array_57[] = {0x61,0x6c,0x69,0x67,0x6e,0x61,0x73,}; +u8 cpp_main_keys_key_array_63[] = {0x63,0x61,0x73,0x65,}; +u8 cpp_main_keys_key_array_64[] = {0x66,0x6f,0x72,}; +u8 cpp_main_keys_key_array_65[] = {0x61,0x6c,0x69,0x67,0x6e,0x6f,0x66,}; +u8 cpp_main_keys_key_array_68[] = {0x64,0x65,0x66,0x61,0x75,0x6c,0x74,}; +u8 cpp_main_keys_key_array_69[] = {0x64,0x65,0x6c,0x65,0x74,0x65,}; +u8 cpp_main_keys_key_array_74[] = {0x65,0x78,0x74,0x65,0x72,0x6e,}; +u8 cpp_main_keys_key_array_75[] = {0x6c,0x6f,0x6e,0x67,}; +u8 cpp_main_keys_key_array_76[] = {0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,}; +u8 cpp_main_keys_key_array_77[] = {0x77,0x68,0x69,0x6c,0x65,}; +u8 cpp_main_keys_key_array_81[] = {0x69,0x6e,0x6c,0x69,0x6e,0x65,}; +u8 cpp_main_keys_key_array_82[] = {0x6e,0x65,0x77,}; +u8 cpp_main_keys_key_array_83[] = {0x66,0x6c,0x6f,0x61,0x74,}; +u8 cpp_main_keys_key_array_84[] = {0x62,0x6f,0x6f,0x6c,}; +u8 cpp_main_keys_key_array_86[] = {0x63,0x6f,0x6e,0x73,0x74,0x5f,0x63,0x61,0x73,0x74,}; +u8 cpp_main_keys_key_array_88[] = {0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,}; +u8 cpp_main_keys_key_array_90[] = {0x72,0x65,0x69,0x6e,0x74,0x65,0x72,0x70,0x72,0x65,0x74,0x5f,0x63,0x61,0x73,0x74,}; +u8 cpp_main_keys_key_array_91[] = {0x65,0x78,0x70,0x6c,0x69,0x63,0x69,0x74,}; +u8 cpp_main_keys_key_array_94[] = {0x73,0x74,0x72,0x75,0x63,0x74,}; +u8 cpp_main_keys_key_array_95[] = {0x6e,0x75,0x6c,0x6c,0x70,0x74,0x72,}; +u8 cpp_main_keys_key_array_96[] = {0x65,0x78,0x70,0x6f,0x72,0x74,}; +u8 cpp_main_keys_key_array_97[] = {0x73,0x74,0x61,0x74,0x69,0x63,}; +u8 cpp_main_keys_key_array_100[] = {0x66,0x72,0x69,0x65,0x6e,0x64,}; +u8 cpp_main_keys_key_array_103[] = {0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,}; +u8 cpp_main_keys_key_array_104[] = {0x75,0x73,0x69,0x6e,0x67,}; +u8 cpp_main_keys_key_array_105[] = {0x64,0x65,0x63,0x6c,0x74,0x79,0x70,0x65,}; +u8 cpp_main_keys_key_array_106[] = {0x75,0x6e,0x73,0x69,0x67,0x6e,0x65,0x64,}; +u8 cpp_main_keys_key_array_108[] = {0x73,0x68,0x6f,0x72,0x74,}; +u8 cpp_main_keys_key_array_111[] = {0x74,0x79,0x70,0x65,0x6e,0x61,0x6d,0x65,}; +u8 cpp_main_keys_key_array_112[] = {0x75,0x6e,0x69,0x6f,0x6e,}; +u8 cpp_main_keys_key_array_113[] = {0x6e,0x6f,0x65,0x78,0x63,0x65,0x70,0x74,}; +u8 cpp_main_keys_key_array_114[] = {0x70,0x72,0x69,0x76,0x61,0x74,0x65,}; +u8 cpp_main_keys_key_array_118[] = {0x76,0x6f,0x69,0x64,}; +u8 cpp_main_keys_key_array_122[] = {0x74,0x79,0x70,0x65,0x69,0x64,}; +u8 cpp_main_keys_key_array_123[] = {0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,}; +String_Const_u8 cpp_main_keys_key_array[124] = { +{cpp_main_keys_key_array_0, 4}, {0, 0}, -{main_keys_key_array_2, 5}, +{cpp_main_keys_key_array_2, 6}, +{cpp_main_keys_key_array_3, 7}, +{cpp_main_keys_key_array_4, 2}, +{0, 0}, +{cpp_main_keys_key_array_6, 9}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_9, 6}, +{cpp_main_keys_key_array_10, 6}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_13, 5}, +{cpp_main_keys_key_array_14, 8}, +{cpp_main_keys_key_array_15, 11}, +{cpp_main_keys_key_array_16, 5}, +{cpp_main_keys_key_array_17, 4}, +{0, 0}, +{cpp_main_keys_key_array_19, 3}, +{0, 0}, +{cpp_main_keys_key_array_21, 5}, {0, 0}, {0, 0}, {0, 0}, -{main_keys_key_array_6, 5}, -{main_keys_key_array_7, 7}, -{main_keys_key_array_8, 5}, +{cpp_main_keys_key_array_25, 8}, +{cpp_main_keys_key_array_26, 6}, +{0, 0}, +{cpp_main_keys_key_array_28, 7}, +{cpp_main_keys_key_array_29, 3}, +{0, 0}, +{cpp_main_keys_key_array_31, 4}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_34, 6}, +{0, 0}, +{cpp_main_keys_key_array_36, 6}, +{0, 0}, +{cpp_main_keys_key_array_38, 5}, +{cpp_main_keys_key_array_39, 5}, +{cpp_main_keys_key_array_40, 2}, +{cpp_main_keys_key_array_41, 13}, +{cpp_main_keys_key_array_42, 12}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_45, 4}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_48, 3}, +{0, 0}, +{cpp_main_keys_key_array_50, 12}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, -{main_keys_key_array_13, 6}, -{main_keys_key_array_14, 6}, -{main_keys_key_array_15, 4}, -{main_keys_key_array_16, 12}, -{0, 0}, -{0, 0}, -{main_keys_key_array_19, 6}, -{0, 0}, -{main_keys_key_array_21, 8}, -{main_keys_key_array_22, 4}, -{main_keys_key_array_23, 7}, -{0, 0}, -{main_keys_key_array_25, 5}, -{0, 0}, -{main_keys_key_array_27, 8}, -{0, 0}, -{main_keys_key_array_29, 6}, -{main_keys_key_array_30, 8}, -{0, 0}, -{main_keys_key_array_32, 11}, -{0, 0}, -{main_keys_key_array_34, 5}, -{main_keys_key_array_35, 3}, -{0, 0}, -{main_keys_key_array_37, 8}, -{0, 0}, -{0, 0}, -{main_keys_key_array_40, 7}, -{0, 0}, -{0, 0}, -{main_keys_key_array_43, 5}, -{main_keys_key_array_44, 6}, -{main_keys_key_array_45, 7}, -{main_keys_key_array_46, 8}, -{0, 0}, -{main_keys_key_array_48, 16}, -{0, 0}, -{main_keys_key_array_50, 4}, -{main_keys_key_array_51, 9}, -{main_keys_key_array_52, 6}, -{0, 0}, -{0, 0}, -{main_keys_key_array_55, 5}, -{main_keys_key_array_56, 6}, -{main_keys_key_array_57, 5}, -{0, 0}, -{0, 0}, -{main_keys_key_array_60, 6}, -{0, 0}, -{0, 0}, -{main_keys_key_array_63, 6}, -{0, 0}, -{0, 0}, -{main_keys_key_array_66, 3}, -{main_keys_key_array_67, 7}, -{0, 0}, -{0, 0}, -{0, 0}, -{main_keys_key_array_71, 4}, -{0, 0}, -{main_keys_key_array_73, 4}, -{0, 0}, -{main_keys_key_array_75, 8}, -{main_keys_key_array_76, 3}, -{main_keys_key_array_77, 12}, -{main_keys_key_array_78, 3}, -{0, 0}, -{main_keys_key_array_80, 8}, -{main_keys_key_array_81, 7}, -{main_keys_key_array_82, 8}, -{main_keys_key_array_83, 7}, -{main_keys_key_array_84, 6}, -{0, 0}, -{main_keys_key_array_86, 2}, -{main_keys_key_array_87, 6}, -{0, 0}, -{main_keys_key_array_89, 9}, -{main_keys_key_array_90, 8}, -{0, 0}, -{main_keys_key_array_92, 4}, -{0, 0}, -{main_keys_key_array_94, 10}, -{main_keys_key_array_95, 5}, -{0, 0}, -{0, 0}, -{main_keys_key_array_98, 6}, -{0, 0}, -{main_keys_key_array_100, 4}, -{0, 0}, -{main_keys_key_array_102, 6}, +{cpp_main_keys_key_array_55, 4}, +{cpp_main_keys_key_array_56, 4}, +{cpp_main_keys_key_array_57, 7}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, -{main_keys_key_array_108, 6}, +{cpp_main_keys_key_array_63, 4}, +{cpp_main_keys_key_array_64, 3}, +{cpp_main_keys_key_array_65, 7}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_68, 7}, +{cpp_main_keys_key_array_69, 6}, {0, 0}, {0, 0}, {0, 0}, -{main_keys_key_array_112, 8}, -{main_keys_key_array_113, 2}, -{main_keys_key_array_114, 13}, {0, 0}, -{main_keys_key_array_116, 4}, +{cpp_main_keys_key_array_74, 6}, +{cpp_main_keys_key_array_75, 4}, +{cpp_main_keys_key_array_76, 8}, +{cpp_main_keys_key_array_77, 5}, {0, 0}, -{main_keys_key_array_118, 3}, -{main_keys_key_array_119, 4}, -{main_keys_key_array_120, 4}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_81, 6}, +{cpp_main_keys_key_array_82, 3}, +{cpp_main_keys_key_array_83, 5}, +{cpp_main_keys_key_array_84, 4}, +{0, 0}, +{cpp_main_keys_key_array_86, 10}, +{0, 0}, +{cpp_main_keys_key_array_88, 8}, +{0, 0}, +{cpp_main_keys_key_array_90, 16}, +{cpp_main_keys_key_array_91, 8}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_94, 6}, +{cpp_main_keys_key_array_95, 7}, +{cpp_main_keys_key_array_96, 6}, +{cpp_main_keys_key_array_97, 6}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_100, 6}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_103, 8}, +{cpp_main_keys_key_array_104, 5}, +{cpp_main_keys_key_array_105, 8}, +{cpp_main_keys_key_array_106, 8}, +{0, 0}, +{cpp_main_keys_key_array_108, 5}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_111, 8}, +{cpp_main_keys_key_array_112, 5}, +{cpp_main_keys_key_array_113, 8}, +{cpp_main_keys_key_array_114, 7}, +{0, 0}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_118, 4}, +{0, 0}, +{0, 0}, +{0, 0}, +{cpp_main_keys_key_array_122, 6}, +{cpp_main_keys_key_array_123, 9}, }; -Lexeme_Table_Value main_keys_value_array[121] = { -{4, TokenCppKind_Catch}, -{0, 0}, -{4, TokenCppKind_Union}, -{0, 0}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Using}, -{4, TokenCppKind_Virtual}, -{4, TokenCppKind_Float}, -{0, 0}, -{0, 0}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Static}, -{4, TokenCppKind_Inline}, +Lexeme_Table_Value cpp_main_keys_value_array[124] = { {8, TokenCppKind_LiteralTrue}, -{4, TokenCppKind_DynamicCast}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_SizeOf}, -{0, 0}, -{4, TokenCppKind_Template}, -{4, TokenCppKind_This}, -{4, TokenCppKind_AlignAs}, -{0, 0}, -{4, TokenCppKind_While}, -{0, 0}, -{4, TokenCppKind_Typename}, -{0, 0}, -{4, TokenCppKind_Switch}, -{4, TokenCppKind_Explicit}, -{0, 0}, -{4, TokenCppKind_StaticCast}, -{0, 0}, -{4, TokenCppKind_Break}, -{4, TokenCppKind_Try}, -{0, 0}, -{4, TokenCppKind_DeclType}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Private}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Short}, -{4, TokenCppKind_TypeID}, -{4, TokenCppKind_AlignOf}, -{4, TokenCppKind_NoExcept}, -{0, 0}, -{4, TokenCppKind_ReinterpretCast}, -{0, 0}, -{4, TokenCppKind_Goto}, -{4, TokenCppKind_Protected}, -{4, TokenCppKind_Export}, -{0, 0}, -{0, 0}, -{8, TokenCppKind_LiteralFalse}, -{4, TokenCppKind_Extern}, -{4, TokenCppKind_Class}, -{0, 0}, {0, 0}, {4, TokenCppKind_Signed}, +{4, TokenCppKind_Virtual}, +{4, TokenCppKind_Do}, +{0, 0}, +{4, TokenCppKind_Protected}, {0, 0}, {0, 0}, +{4, TokenCppKind_Double}, {4, TokenCppKind_Public}, {0, 0}, {0, 0}, -{4, TokenCppKind_Int}, -{4, TokenCppKind_Default}, +{4, TokenCppKind_Class}, +{4, TokenCppKind_Template}, +{4, TokenCppKind_StaticCast}, +{4, TokenCppKind_Catch}, +{4, TokenCppKind_Goto}, {0, 0}, +{4, TokenCppKind_Asm}, {0, 0}, -{0, 0}, -{4, TokenCppKind_Char}, -{0, 0}, -{4, TokenCppKind_Long}, -{0, 0}, -{4, TokenCppKind_Continue}, -{4, TokenCppKind_For}, -{4, TokenCppKind_ThreadLocal}, -{4, TokenCppKind_New}, -{0, 0}, -{4, TokenCppKind_Unsigned}, -{4, TokenCppKind_NullPtr}, -{4, TokenCppKind_Operator}, -{4, TokenCppKind_Typedef}, -{4, TokenCppKind_Delete}, -{0, 0}, -{4, TokenCppKind_If}, -{4, TokenCppKind_Struct}, -{0, 0}, -{4, TokenCppKind_Namespace}, -{4, TokenCppKind_Register}, -{0, 0}, -{4, TokenCppKind_Case}, -{0, 0}, -{4, TokenCppKind_ConstCast}, -{4, TokenCppKind_Const}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Friend}, -{0, 0}, -{4, TokenCppKind_Else}, -{0, 0}, -{4, TokenCppKind_Double}, -{0, 0}, -{0, 0}, -{0, 0}, -{0, 0}, -{0, 0}, -{4, TokenCppKind_Return}, +{4, TokenCppKind_Break}, {0, 0}, {0, 0}, {0, 0}, {4, TokenCppKind_Volatile}, -{4, TokenCppKind_Do}, -{4, TokenCppKind_StaticAssert}, +{4, TokenCppKind_Switch}, {0, 0}, +{4, TokenCppKind_Typedef}, +{4, TokenCppKind_Try}, +{0, 0}, +{4, TokenCppKind_Else}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Return}, +{0, 0}, +{4, TokenCppKind_SizeOf}, +{0, 0}, +{4, TokenCppKind_Const}, +{8, TokenCppKind_LiteralFalse}, +{4, TokenCppKind_If}, +{4, TokenCppKind_StaticAssert}, +{4, TokenCppKind_ThreadLocal}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_This}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Int}, +{0, 0}, +{4, TokenCppKind_DynamicCast}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Enum}, +{4, TokenCppKind_Char}, +{4, TokenCppKind_AlignAs}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Case}, +{4, TokenCppKind_For}, +{4, TokenCppKind_AlignOf}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Default}, +{4, TokenCppKind_Delete}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Extern}, +{4, TokenCppKind_Long}, +{4, TokenCppKind_Register}, +{4, TokenCppKind_While}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Inline}, +{4, TokenCppKind_New}, +{4, TokenCppKind_Float}, {4, TokenCppKind_Bool}, {0, 0}, -{4, TokenCppKind_Asm}, -{4, TokenCppKind_Enum}, +{4, TokenCppKind_ConstCast}, +{0, 0}, +{4, TokenCppKind_Operator}, +{0, 0}, +{4, TokenCppKind_ReinterpretCast}, +{4, TokenCppKind_Explicit}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Struct}, +{4, TokenCppKind_NullPtr}, +{4, TokenCppKind_Export}, +{4, TokenCppKind_Static}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Friend}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Continue}, +{4, TokenCppKind_Using}, +{4, TokenCppKind_DeclType}, +{4, TokenCppKind_Unsigned}, +{0, 0}, +{4, TokenCppKind_Short}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_Typename}, +{4, TokenCppKind_Union}, +{4, TokenCppKind_NoExcept}, +{4, TokenCppKind_Private}, +{0, 0}, +{0, 0}, +{0, 0}, {4, TokenCppKind_Void}, +{0, 0}, +{0, 0}, +{0, 0}, +{4, TokenCppKind_TypeID}, +{4, TokenCppKind_Namespace}, }; -i32 main_keys_slot_count = 121; -u64 main_keys_seed = 0x32a240442a6e221f; -u64 pp_directives_hash_array[25] = { -0xa8f3b0d79807b793,0x808ba552d670368f,0x0000000000000000,0x808ba54dc047d94b, -0x3b97f7088cbf95df,0x7fd91d3d238e04c9,0x0000000000000000,0x7fd91d3dac09e067, -0x0000000000000000,0x0000000000000000,0xa8f3beab5b880ad3,0x0000000000000000, -0x3b97f7088cbffd3b,0x3b97f7088cdab44b,0x79521904bb682f3f,0x0000000000000000, -0x0000000000000000,0x7fd91d3d978c615f,0x808ba553ad911e19,0x0000000000000000, -0x808ba54ef8496067,0x7fd91d3d2fe85067,0x7fd91d3d97a21607,0x0000000000000000, +i32 cpp_main_keys_slot_count = 124; +u64 cpp_main_keys_seed = 0x8546da5e0b8a4494; +u64 cpp_pp_directives_hash_array[25] = { +0xa9c93e3b092cb44d,0x0000000000000000,0x0dd88216be8f0f45,0x0000000000000000, +0x0dd88216bc8af78d,0x92a889595c683c55,0xdab9e300145b906f,0x92a889577e972a4b, +0x0000000000000000,0x0dd88216bb8053ff,0x0000000000000000,0x0dd88216bd573601, +0x0000000000000000,0xdab9e300142a071d,0x0000000000000000,0xa9c93ef34054fce1, +0x0dd88216a4783a45,0xdab9e300145b9a25,0x92a889595b4a2105,0x0000000000000000, +0x86d1d427e10cd86d,0x0000000000000000,0x92a889590753d01d,0x0000000000000000, 0x0000000000000000, }; -u8 pp_directives_key_array_0[] = {0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,}; -u8 pp_directives_key_array_1[] = {0x70,0x72,0x61,0x67,0x6d,0x61,}; -u8 pp_directives_key_array_3[] = {0x64,0x65,0x66,0x69,0x6e,0x65,}; -u8 pp_directives_key_array_4[] = {0x65,0x6c,0x69,0x66,}; -u8 pp_directives_key_array_5[] = {0x75,0x73,0x69,0x6e,0x67,}; -u8 pp_directives_key_array_7[] = {0x69,0x66,0x64,0x65,0x66,}; -u8 pp_directives_key_array_10[] = {0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,}; -u8 pp_directives_key_array_12[] = {0x65,0x6c,0x73,0x65,}; -u8 pp_directives_key_array_13[] = {0x6c,0x69,0x6e,0x65,}; -u8 pp_directives_key_array_14[] = {0x69,0x66,}; -u8 pp_directives_key_array_17[] = {0x65,0x6e,0x64,0x69,0x66,}; -u8 pp_directives_key_array_18[] = {0x69,0x6d,0x70,0x6f,0x72,0x74,}; -u8 pp_directives_key_array_20[] = {0x69,0x66,0x6e,0x64,0x65,0x66,}; -u8 pp_directives_key_array_21[] = {0x75,0x6e,0x64,0x65,0x66,}; -u8 pp_directives_key_array_22[] = {0x65,0x72,0x72,0x6f,0x72,}; -String_Const_u8 pp_directives_key_array[25] = { -{pp_directives_key_array_0, 7}, -{pp_directives_key_array_1, 6}, +u8 cpp_pp_directives_key_array_0[] = {0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,}; +u8 cpp_pp_directives_key_array_2[] = {0x69,0x66,0x64,0x65,0x66,}; +u8 cpp_pp_directives_key_array_4[] = {0x65,0x6e,0x64,0x69,0x66,}; +u8 cpp_pp_directives_key_array_5[] = {0x69,0x66,0x6e,0x64,0x65,0x66,}; +u8 cpp_pp_directives_key_array_6[] = {0x65,0x6c,0x73,0x65,}; +u8 cpp_pp_directives_key_array_7[] = {0x70,0x72,0x61,0x67,0x6d,0x61,}; +u8 cpp_pp_directives_key_array_9[] = {0x75,0x73,0x69,0x6e,0x67,}; +u8 cpp_pp_directives_key_array_11[] = {0x65,0x72,0x72,0x6f,0x72,}; +u8 cpp_pp_directives_key_array_13[] = {0x6c,0x69,0x6e,0x65,}; +u8 cpp_pp_directives_key_array_15[] = {0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,}; +u8 cpp_pp_directives_key_array_16[] = {0x75,0x6e,0x64,0x65,0x66,}; +u8 cpp_pp_directives_key_array_17[] = {0x65,0x6c,0x69,0x66,}; +u8 cpp_pp_directives_key_array_18[] = {0x69,0x6d,0x70,0x6f,0x72,0x74,}; +u8 cpp_pp_directives_key_array_20[] = {0x69,0x66,}; +u8 cpp_pp_directives_key_array_22[] = {0x64,0x65,0x66,0x69,0x6e,0x65,}; +String_Const_u8 cpp_pp_directives_key_array[25] = { +{cpp_pp_directives_key_array_0, 7}, {0, 0}, -{pp_directives_key_array_3, 6}, -{pp_directives_key_array_4, 4}, -{pp_directives_key_array_5, 5}, +{cpp_pp_directives_key_array_2, 5}, {0, 0}, -{pp_directives_key_array_7, 5}, +{cpp_pp_directives_key_array_4, 5}, +{cpp_pp_directives_key_array_5, 6}, +{cpp_pp_directives_key_array_6, 4}, +{cpp_pp_directives_key_array_7, 6}, {0, 0}, +{cpp_pp_directives_key_array_9, 5}, {0, 0}, -{pp_directives_key_array_10, 7}, +{cpp_pp_directives_key_array_11, 5}, {0, 0}, -{pp_directives_key_array_12, 4}, -{pp_directives_key_array_13, 4}, -{pp_directives_key_array_14, 2}, +{cpp_pp_directives_key_array_13, 4}, {0, 0}, +{cpp_pp_directives_key_array_15, 7}, +{cpp_pp_directives_key_array_16, 5}, +{cpp_pp_directives_key_array_17, 4}, +{cpp_pp_directives_key_array_18, 6}, {0, 0}, -{pp_directives_key_array_17, 5}, -{pp_directives_key_array_18, 6}, +{cpp_pp_directives_key_array_20, 2}, {0, 0}, -{pp_directives_key_array_20, 6}, -{pp_directives_key_array_21, 5}, -{pp_directives_key_array_22, 5}, +{cpp_pp_directives_key_array_22, 6}, {0, 0}, {0, 0}, }; -Lexeme_Table_Value pp_directives_value_array[25] = { -{5, TokenCppKind_PPInclude}, -{5, TokenCppKind_PPPragma}, -{0, 0}, -{5, TokenCppKind_PPDefine}, -{5, TokenCppKind_PPElIf}, -{5, TokenCppKind_PPUsing}, +Lexeme_Table_Value cpp_pp_directives_value_array[25] = { +{5, TokenCppKind_PPVersion}, {0, 0}, {5, TokenCppKind_PPIfDef}, {0, 0}, -{0, 0}, -{5, TokenCppKind_PPVersion}, -{0, 0}, -{5, TokenCppKind_PPElse}, -{5, TokenCppKind_PPLine}, -{5, TokenCppKind_PPIf}, -{0, 0}, -{0, 0}, {5, TokenCppKind_PPEndIf}, -{5, TokenCppKind_PPImport}, -{0, 0}, {5, TokenCppKind_PPIfNDef}, -{5, TokenCppKind_PPUndef}, +{5, TokenCppKind_PPElse}, +{5, TokenCppKind_PPPragma}, +{0, 0}, +{5, TokenCppKind_PPUsing}, +{0, 0}, {5, TokenCppKind_PPError}, {0, 0}, +{5, TokenCppKind_PPLine}, +{0, 0}, +{5, TokenCppKind_PPInclude}, +{5, TokenCppKind_PPUndef}, +{5, TokenCppKind_PPElIf}, +{5, TokenCppKind_PPImport}, +{0, 0}, +{5, TokenCppKind_PPIf}, +{0, 0}, +{5, TokenCppKind_PPDefine}, +{0, 0}, {0, 0}, }; -i32 pp_directives_slot_count = 25; -u64 pp_directives_seed = 0x8848fb3caaf5d4d5; -u64 pp_keys_hash_array[2] = { -0x0000000000000000,0x72743f437c9f847d, +i32 cpp_pp_directives_slot_count = 25; +u64 cpp_pp_directives_seed = 0x6e8a1011f7d8dd90; +u64 cpp_pp_keys_hash_array[2] = { +0x56dd32803fcaa4ab,0x0000000000000000, }; -u8 pp_keys_key_array_1[] = {0x64,0x65,0x66,0x69,0x6e,0x65,0x64,}; -String_Const_u8 pp_keys_key_array[2] = { +u8 cpp_pp_keys_key_array_0[] = {0x64,0x65,0x66,0x69,0x6e,0x65,0x64,}; +String_Const_u8 cpp_pp_keys_key_array[2] = { +{cpp_pp_keys_key_array_0, 7}, {0, 0}, -{pp_keys_key_array_1, 7}, }; -Lexeme_Table_Value pp_keys_value_array[2] = { -{0, 0}, +Lexeme_Table_Value cpp_pp_keys_value_array[2] = { {4, TokenCppKind_PPDefined}, +{0, 0}, }; -i32 pp_keys_slot_count = 2; -u64 pp_keys_seed = 0x71428d58f01a7eed; +i32 cpp_pp_keys_slot_count = 2; +u64 cpp_pp_keys_seed = 0xbb7907ea1860ef2c; struct Lex_State_Cpp{ u32 flags_ZF0; u32 flags_KF0; @@ -971,14 +977,14 @@ token.size = (i64)(state.ptr - state.emit_ptr); token.flags = state.flags_KB0; do{ if (HasFlag(state.flags_KB0, 0x1)){ -Lexeme_Table_Lookup lookup = lexeme_table_lookup(pp_keys_hash_array, pp_keys_key_array, pp_keys_value_array, pp_keys_slot_count, pp_keys_seed, state.emit_ptr, token.size); +Lexeme_Table_Lookup lookup = lexeme_table_lookup(cpp_pp_keys_hash_array, cpp_pp_keys_key_array, cpp_pp_keys_value_array, cpp_pp_keys_slot_count, cpp_pp_keys_seed, state.emit_ptr, token.size); if (lookup.found_match){ token.kind = lookup.base_kind; token.sub_kind = lookup.sub_kind; break; } } -Lexeme_Table_Lookup lookup = lexeme_table_lookup(main_keys_hash_array, main_keys_key_array, main_keys_value_array, main_keys_slot_count, main_keys_seed, state.emit_ptr, token.size); +Lexeme_Table_Lookup lookup = lexeme_table_lookup(cpp_main_keys_hash_array, cpp_main_keys_key_array, cpp_main_keys_value_array, cpp_main_keys_slot_count, cpp_main_keys_seed, state.emit_ptr, token.size); if (lookup.found_match){ token.kind = lookup.base_kind; token.sub_kind = lookup.sub_kind; @@ -1014,14 +1020,14 @@ token.size = (i64)(state.ptr - state.emit_ptr); token.flags = state.flags_KB0; do{ if (HasFlag(state.flags_KB0, 0x1)){ -Lexeme_Table_Lookup lookup = lexeme_table_lookup(pp_keys_hash_array, pp_keys_key_array, pp_keys_value_array, pp_keys_slot_count, pp_keys_seed, state.emit_ptr, token.size); +Lexeme_Table_Lookup lookup = lexeme_table_lookup(cpp_pp_keys_hash_array, cpp_pp_keys_key_array, cpp_pp_keys_value_array, cpp_pp_keys_slot_count, cpp_pp_keys_seed, state.emit_ptr, token.size); if (lookup.found_match){ token.kind = lookup.base_kind; token.sub_kind = lookup.sub_kind; break; } } -Lexeme_Table_Lookup lookup = lexeme_table_lookup(main_keys_hash_array, main_keys_key_array, main_keys_value_array, main_keys_slot_count, main_keys_seed, state.emit_ptr, token.size); +Lexeme_Table_Lookup lookup = lexeme_table_lookup(cpp_main_keys_hash_array, cpp_main_keys_key_array, cpp_main_keys_value_array, cpp_main_keys_slot_count, cpp_main_keys_seed, state.emit_ptr, token.size); if (lookup.found_match){ token.kind = lookup.base_kind; token.sub_kind = lookup.sub_kind; @@ -2760,7 +2766,7 @@ token.pos = (i64)(state.emit_ptr - state.base); token.size = (i64)(state.ptr - state.emit_ptr); token.flags = state.flags_KB0; do{ -Lexeme_Table_Lookup lookup = lexeme_table_lookup(pp_directives_hash_array, pp_directives_key_array, pp_directives_value_array, pp_directives_slot_count, pp_directives_seed, state.delim_first, (state.delim_one_past_last - state.delim_first)); +Lexeme_Table_Lookup lookup = lexeme_table_lookup(cpp_pp_directives_hash_array, cpp_pp_directives_key_array, cpp_pp_directives_value_array, cpp_pp_directives_slot_count, cpp_pp_directives_seed, state.delim_first, (state.delim_one_past_last - state.delim_first)); if (lookup.found_match){ token.kind = lookup.base_kind; token.sub_kind = lookup.sub_kind; @@ -2797,7 +2803,7 @@ token.pos = (i64)(state.emit_ptr - state.base); token.size = (i64)(state.ptr - state.emit_ptr); token.flags = state.flags_KB0; do{ -Lexeme_Table_Lookup lookup = lexeme_table_lookup(pp_directives_hash_array, pp_directives_key_array, pp_directives_value_array, pp_directives_slot_count, pp_directives_seed, state.delim_first, (state.delim_one_past_last - state.delim_first)); +Lexeme_Table_Lookup lookup = lexeme_table_lookup(cpp_pp_directives_hash_array, cpp_pp_directives_key_array, cpp_pp_directives_value_array, cpp_pp_directives_slot_count, cpp_pp_directives_seed, state.delim_first, (state.delim_one_past_last - state.delim_first)); if (lookup.found_match){ token.kind = lookup.base_kind; token.sub_kind = lookup.sub_kind; diff --git a/custom/generated/system_api.h b/custom/generated/system_api.h index ce9536da..f67a518f 100644 --- a/custom/generated/system_api.h +++ b/custom/generated/system_api.h @@ -93,53 +93,53 @@ typedef b32 system_set_fullscreen_type(b32 full_screen); typedef b32 system_is_fullscreen_type(void); typedef Input_Modifier_Set system_get_keyboard_modifiers_type(Arena* arena); struct API_VTable_system{ -system_get_path_type *get_path; -system_get_canonical_type *get_canonical; -system_get_file_list_type *get_file_list; -system_quick_file_attributes_type *quick_file_attributes; -system_load_handle_type *load_handle; -system_load_attributes_type *load_attributes; -system_load_file_type *load_file; -system_load_close_type *load_close; -system_save_file_type *save_file; -system_load_library_type *load_library; -system_release_library_type *release_library; -system_get_proc_type *get_proc; -system_now_time_type *now_time; -system_wake_up_timer_create_type *wake_up_timer_create; -system_wake_up_timer_release_type *wake_up_timer_release; -system_wake_up_timer_set_type *wake_up_timer_set; -system_signal_step_type *signal_step; -system_sleep_type *sleep; -system_post_clipboard_type *post_clipboard; -system_cli_call_type *cli_call; -system_cli_begin_update_type *cli_begin_update; -system_cli_update_step_type *cli_update_step; -system_cli_end_update_type *cli_end_update; -system_open_color_picker_type *open_color_picker; -system_get_screen_scale_factor_type *get_screen_scale_factor; -system_thread_launch_type *thread_launch; -system_thread_join_type *thread_join; -system_thread_free_type *thread_free; -system_thread_get_id_type *thread_get_id; -system_acquire_global_frame_mutex_type *acquire_global_frame_mutex; -system_release_global_frame_mutex_type *release_global_frame_mutex; -system_mutex_make_type *mutex_make; -system_mutex_acquire_type *mutex_acquire; -system_mutex_release_type *mutex_release; -system_mutex_free_type *mutex_free; -system_condition_variable_make_type *condition_variable_make; -system_condition_variable_wait_type *condition_variable_wait; -system_condition_variable_signal_type *condition_variable_signal; -system_condition_variable_free_type *condition_variable_free; -system_memory_allocate_type *memory_allocate; -system_memory_set_protection_type *memory_set_protection; -system_memory_free_type *memory_free; -system_memory_annotation_type *memory_annotation; -system_show_mouse_cursor_type *show_mouse_cursor; -system_set_fullscreen_type *set_fullscreen; -system_is_fullscreen_type *is_fullscreen; -system_get_keyboard_modifiers_type *get_keyboard_modifiers; + system_get_path_type *get_path; + system_get_canonical_type *get_canonical; + system_get_file_list_type *get_file_list; + system_quick_file_attributes_type *quick_file_attributes; + system_load_handle_type *load_handle; + system_load_attributes_type *load_attributes; + system_load_file_type *load_file; + system_load_close_type *load_close; + system_save_file_type *save_file; + system_load_library_type *load_library; + system_release_library_type *release_library; + system_get_proc_type *get_proc; + system_now_time_type *now_time; + system_wake_up_timer_create_type *wake_up_timer_create; + system_wake_up_timer_release_type *wake_up_timer_release; + system_wake_up_timer_set_type *wake_up_timer_set; + system_signal_step_type *signal_step; + system_sleep_type *sleep; + system_post_clipboard_type *post_clipboard; + system_cli_call_type *cli_call; + system_cli_begin_update_type *cli_begin_update; + system_cli_update_step_type *cli_update_step; + system_cli_end_update_type *cli_end_update; + system_open_color_picker_type *open_color_picker; + system_get_screen_scale_factor_type *get_screen_scale_factor; + system_thread_launch_type *thread_launch; + system_thread_join_type *thread_join; + system_thread_free_type *thread_free; + system_thread_get_id_type *thread_get_id; + system_acquire_global_frame_mutex_type *acquire_global_frame_mutex; + system_release_global_frame_mutex_type *release_global_frame_mutex; + system_mutex_make_type *mutex_make; + system_mutex_acquire_type *mutex_acquire; + system_mutex_release_type *mutex_release; + system_mutex_free_type *mutex_free; + system_condition_variable_make_type *condition_variable_make; + system_condition_variable_wait_type *condition_variable_wait; + system_condition_variable_signal_type *condition_variable_signal; + system_condition_variable_free_type *condition_variable_free; + system_memory_allocate_type *memory_allocate; + system_memory_set_protection_type *memory_set_protection; + system_memory_free_type *memory_free; + system_memory_annotation_type *memory_annotation; + system_show_mouse_cursor_type *show_mouse_cursor; + system_set_fullscreen_type *set_fullscreen; + system_is_fullscreen_type *is_fullscreen; + system_get_keyboard_modifiers_type *get_keyboard_modifiers; }; #if defined(STATIC_LINK_API) internal String_Const_u8 system_get_path(Arena* arena, System_Path_Code path_code); diff --git a/custom/languages/4coder_cpp_lexer_gen.cpp b/custom/languages/4coder_cpp_lexer_gen.cpp index 8832d60c..84c3eb90 100644 --- a/custom/languages/4coder_cpp_lexer_gen.cpp +++ b/custom/languages/4coder_cpp_lexer_gen.cpp @@ -1130,7 +1130,6 @@ build_language_model(void){ sm_case_eof_peek(emit); } sm_fallback(comment_line); - } // BOTTOM diff --git a/custom/lexer_generator/4coder_lex_gen_main.cpp b/custom/lexer_generator/4coder_lex_gen_main.cpp index 357c7273..ec02a67b 100644 --- a/custom/lexer_generator/4coder_lex_gen_main.cpp +++ b/custom/lexer_generator/4coder_lex_gen_main.cpp @@ -2700,7 +2700,7 @@ opt_key_layout(Arena *arena, Keyword_Set keywords, i32 slot_count, u64 seed){ else{ run_length += 1; layout.error_score += run_length; - max_run_length = max(max_run_length, run_length); + max_run_length = Max(max_run_length, run_length); } } i32 total_run_length = run_length; @@ -2711,7 +2711,7 @@ opt_key_layout(Arena *arena, Keyword_Set keywords, i32 slot_count, u64 seed){ else{ layout.error_score += run_length; total_run_length += 1; - max_run_length = max(max_run_length, total_run_length); + max_run_length = Max(max_run_length, total_run_length); } } layout.max_single_error_score = max_run_length; @@ -3181,7 +3181,7 @@ gen_keyword_table(Arena *scratch, Token_Kind_Set tokens, Keyword_Set keywords, F Temp_Memory temp = begin_temp(scratch); Keyword_Layout key_layout = opt_key_layout(scratch, keywords); - fprintf(out, "u64 %.*s_hash_array[%d] = {\n", + fprintf(out, "u64 " LANG_NAME_LOWER_STR "_%.*s_hash_array[%d] = {\n", string_expand(keywords.pretty_name), key_layout.slot_count); for (i32 i = 0; i < key_layout.slot_count; i += 1){ if (key_layout.slots[i] == 0){ @@ -3198,7 +3198,7 @@ gen_keyword_table(Arena *scratch, Token_Kind_Set tokens, Keyword_Set keywords, F for (i32 i = 0; i < key_layout.slot_count; i += 1){ if (key_layout.slots[i] != 0){ - fprintf(out, "u8 %.*s_key_array_%d[] = {", + fprintf(out, "u8 " LANG_NAME_LOWER_STR "_%.*s_key_array_%d[] = {", string_expand(keywords.pretty_name), i); String_Const_u8 lexeme = key_layout.slots[i]->lexeme; for (u64 j = 0; j < lexeme.size; j += 1){ @@ -3208,20 +3208,20 @@ gen_keyword_table(Arena *scratch, Token_Kind_Set tokens, Keyword_Set keywords, F } } - fprintf(out, "String_Const_u8 %.*s_key_array[%d] = {\n", + fprintf(out, "String_Const_u8 " LANG_NAME_LOWER_STR "_%.*s_key_array[%d] = {\n", string_expand(keywords.pretty_name), key_layout.slot_count); for (i32 i = 0; i < key_layout.slot_count; i += 1){ if (key_layout.slots[i] == 0){ fprintf(out, "{0, 0},\n"); } else{ - fprintf(out, "{%.*s_key_array_%d, %llu},\n", + fprintf(out, "{" LANG_NAME_LOWER_STR "_%.*s_key_array_%d, %llu},\n", string_expand(keywords.pretty_name), i, key_layout.slots[i]->lexeme.size); } } fprintf(out, "};\n"); - fprintf(out, "Lexeme_Table_Value %.*s_value_array[%d] = {\n", + fprintf(out, "Lexeme_Table_Value " LANG_NAME_LOWER_STR "_%.*s_value_array[%d] = {\n", string_expand(keywords.pretty_name), key_layout.slot_count); for (i32 i = 0; i < key_layout.slot_count; i += 1){ if (key_layout.slots[i] == 0){ @@ -3245,9 +3245,9 @@ gen_keyword_table(Arena *scratch, Token_Kind_Set tokens, Keyword_Set keywords, F } fprintf(out, "};\n"); - fprintf(out, "i32 %.*s_slot_count = %d;\n", + fprintf(out, "i32 " LANG_NAME_LOWER_STR "_%.*s_slot_count = %d;\n", string_expand(keywords.pretty_name), key_layout.slot_count); - fprintf(out, "u64 %.*s_seed = 0x%016llx;\n", + fprintf(out, "u64 " LANG_NAME_LOWER_STR "_%.*s_seed = 0x%016llx;\n", string_expand(keywords.pretty_name), key_layout.seed); end_temp(temp); @@ -3453,8 +3453,12 @@ gen_SLOW_action_list__cont_flow(Arena *scratch, Token_Kind_Set tokens, Flag_Set { Keyword_Set *keywords = handler->keywords; fprintf(out, "Lexeme_Table_Lookup lookup = " - "lexeme_table_lookup(%.*s_hash_array, %.*s_key_array, " - "%.*s_value_array, %.*s_slot_count, %.*s_seed, " + "lexeme_table_lookup(" + LANG_NAME_LOWER_STR "_%.*s_hash_array, " + LANG_NAME_LOWER_STR "_%.*s_key_array, " + LANG_NAME_LOWER_STR "_%.*s_value_array, " + LANG_NAME_LOWER_STR "_%.*s_slot_count, " + LANG_NAME_LOWER_STR "_%.*s_seed, " "state.emit_ptr, token.size);\n", string_expand(keywords->pretty_name), string_expand(keywords->pretty_name), @@ -3477,8 +3481,12 @@ gen_SLOW_action_list__cont_flow(Arena *scratch, Token_Kind_Set tokens, Flag_Set { Keyword_Set *keywords = handler->keywords; fprintf(out, "Lexeme_Table_Lookup lookup = " - "lexeme_table_lookup(%.*s_hash_array, %.*s_key_array, " - "%.*s_value_array, %.*s_slot_count, %.*s_seed, " + "lexeme_table_lookup(" + LANG_NAME_LOWER_STR "_%.*s_hash_array, " + LANG_NAME_LOWER_STR "_%.*s_key_array, " + LANG_NAME_LOWER_STR "_%.*s_value_array, " + LANG_NAME_LOWER_STR "_%.*s_slot_count, " + LANG_NAME_LOWER_STR "_%.*s_seed, " "state.delim_first, (state.delim_one_past_last - state.delim_first));\n", string_expand(keywords->pretty_name), string_expand(keywords->pretty_name), diff --git a/docs/4ed_doc_custom_api_buffer.cpp b/docs/4ed_doc_custom_api_buffer.cpp index a9fac64f..e6519167 100644 --- a/docs/4ed_doc_custom_api_buffer.cpp +++ b/docs/4ed_doc_custom_api_buffer.cpp @@ -384,6 +384,39 @@ doc_custom_api__buffer(Arena *arena, API_Definition *api_def, Doc_Cluster *clust //////////////////////////////// + if (begin_doc_call(arena, cluster, api_def, "buffer_padded_box_of_pos", &func)){ + doc_function_brief(arena, &func, "Compute the rectangle around a character at a particular byte position, relative to the top left corner of a given line"); + + // params + Doc_Block *params = doc_function_begin_params(arena, &func); + doc_custom_app_ptr(arena, &func); + + doc_function_param(arena, &func, "buffer_id"); + doc_text(arena, params, "the id of the buffer who's layout will be measured"); + + doc_function_param(arena, &func, "width"); + doc_text(arena, params, "the width parameter of the layout, passed to layout rules as a recommended wrap point"); + + doc_function_param(arena, &func, "face_id"); + doc_text(arena, params, "the face parameter of the layout, passed to layout rules as a recommended face"); + + doc_function_param(arena, &func, "base_line"); + doc_text(arena, params, "the line number of the line that serves as the relative starting point of the measurement"); + + doc_function_param(arena, &func, "pos"); + doc_text(arena, params, "the absolute byte index of the position to query"); + + // return + Doc_Block *ret = doc_function_return(arena, &func); + doc_text(arena, ret, "the rectangle around a character in the layout that is closest to including the given query position in it's span, with coordinates set relative to the top left corner of the base line, on success, when the buffer exists and contains the base line and query position, cleared to zero otherwise"); + + // details + Doc_Block *det = doc_function_details(arena, &func); + doc_text(arena, det, "Line numbers are 1 based."); + } + + //////////////////////////////// + if (begin_doc_call(arena, cluster, api_def, "buffer_relative_character_from_pos", &func)){ doc_function_brief(arena, &func, "Compute a character index relative to a particular lines first character"); @@ -627,6 +660,39 @@ doc_custom_api__buffer(Arena *arena, API_Definition *api_def, Doc_Cluster *clust //////////////////////////////// + if (begin_doc_call(arena, cluster, api_def, "buffer_set_layout", &func)){ + doc_function_brief(arena, &func, "Set the layout function of a buffer"); + + // params + Doc_Block *params = doc_function_begin_params(arena, &func); + doc_custom_app_ptr(arena, &func); + + doc_function_param(arena, &func, "buffer_id"); + doc_text(arena, params, "the id of the buffer to be modified"); + + doc_function_param(arena, &func, "layout_func"); + doc_text(arena, params, "the new layout function for the buffer's layout"); + + // return + Doc_Block *ret = doc_function_return(arena, &func); + doc_text(arena, ret, "non-zero on success, when the buffer exists, otherwise zero"); + } + + //////////////////////////////// + + if (begin_doc_call(arena, cluster, api_def, "buffer_clear_layout_cache", &func)){ + doc_function_brief(arena, &func, "Clear all the layout information cached in the buffer"); + + // params + Doc_Block *params = doc_function_begin_params(arena, &func); + doc_custom_app_ptr(arena, &func); + + doc_function_param(arena, &func, "buffer_id"); + doc_text(arena, params, "the id of the buffer to be modified"); + } + + //////////////////////////////// + if (begin_doc_call(arena, cluster, api_def, "buffer_get_layout", &func)){ doc_function_brief(arena, &func, "Retrieve the layout rule of a buffer"); diff --git a/docs/4ed_doc_custom_api_global.cpp b/docs/4ed_doc_custom_api_global.cpp index 04be9f89..3071886d 100644 --- a/docs/4ed_doc_custom_api_global.cpp +++ b/docs/4ed_doc_custom_api_global.cpp @@ -1174,6 +1174,16 @@ doc_custom_api__global(Arena *arena, API_Definition *api_def, Doc_Cluster *clust //////////////////////////////// + if (begin_doc_call(arena, cluster, api_def, "hard_exit", &func)){ + doc_function_brief(arena, &func, "Exits 4coder at the end of the frame, no matter what; for instance, call from the exit signal handler to actual exit 4coder."); + + // params + doc_function_begin_params(arena, &func); + doc_custom_app_ptr(arena, &func); + } + + //////////////////////////////// + if (begin_doc_call(arena, cluster, api_def, "set_window_title", &func)){ doc_function_brief(arena, &func, "Set the title of the 4coder window"); diff --git a/docs/4ed_doc_custom_api_main.cpp b/docs/4ed_doc_custom_api_main.cpp index 96258558..6d22c1fe 100644 --- a/docs/4ed_doc_custom_api_main.cpp +++ b/docs/4ed_doc_custom_api_main.cpp @@ -60,6 +60,8 @@ int main(void){ API_Definition *api_def = api_get_api(&def_list, string_u8_litexpr("custom")); Doc_Cluster *cluster = doc_custom_api(&arena, api_def); + doc_api_check_full_coverage(&arena, cluster, api_def); + for (Doc_Log *node = cluster->first_log; node != 0; node = node->next){ diff --git a/docs/4ed_doc_custom_api_view.cpp b/docs/4ed_doc_custom_api_view.cpp index dcaaf804..b34f867f 100644 --- a/docs/4ed_doc_custom_api_view.cpp +++ b/docs/4ed_doc_custom_api_view.cpp @@ -133,6 +133,33 @@ doc_custom_api__view(Arena *arena, API_Definition *api_def, Doc_Cluster *cluster //////////////////////////////// + if (begin_doc_call(arena, cluster, api_def, "view_padded_box_of_pos", &func)){ + doc_function_brief(arena, &func, "Compute the rectangle around a character at a particular byte position, relative to the top left corner of a given line"); + + // params + Doc_Block *params = doc_function_begin_params(arena, &func); + doc_custom_app_ptr(arena, &func); + + doc_function_param(arena, &func, "view_id"); + doc_text(arena, params, "the id of the view who's layout will be measured"); + + doc_function_param(arena, &func, "base_line"); + doc_text(arena, params, "the line number of the line that serves as the relative starting point of the measurement"); + + doc_function_param(arena, &func, "pos"); + doc_text(arena, params, "the absolute byte index of the position to query"); + + // return + Doc_Block *ret = doc_function_return(arena, &func); + doc_text(arena, ret, "the rectangle around a character in the layout that is closest to including the given query position in it's span, with coordinates set relative to the top left corner of the base line, on success, when the view exists and contains the base line and query position, cleared to zero otherwise"); + + // details + Doc_Block *det = doc_function_details(arena, &func); + doc_text(arena, det, "Line numbers are 1 based."); + } + + //////////////////////////////// + if (begin_doc_call(arena, cluster, api_def, "view_relative_character_from_pos", &func)){ doc_function_brief(arena, &func, "Compute a character index relative to a particular lines first character"); @@ -888,13 +915,6 @@ doc_custom_api__view(Arena *arena, API_Definition *api_def, Doc_Cluster *cluster //////////////////////////////// - // TODO(allen): remove view_post_fade - if (begin_doc_call(arena, cluster, api_def, "view_post_fade", &func)){ - doc_function_brief(arena, &func, "Plans to deprecate - do not rely on this call!"); - } - - //////////////////////////////// - if (begin_doc_call(arena, cluster, api_def, "view_push_context", &func)){ doc_function_brief(arena, &func, "Push a view's stack of context details with a pointer to the new values for the context"); diff --git a/docs/4ed_doc_helper.cpp b/docs/4ed_doc_helper.cpp index 5ffd065e..a28f402a 100644 --- a/docs/4ed_doc_helper.cpp +++ b/docs/4ed_doc_helper.cpp @@ -155,4 +155,19 @@ doc_function_add_related(Arena *arena, Doc_Block *rel, char *name){ content->page_link = SCu8(name); } +//////////////////////////////// + +function void +doc_api_check_full_coverage(Arena *arena, Doc_Cluster *cluster, API_Definition *api_def){ + for (API_Call *call = api_def->first_call; + call != 0; + call = call->next){ + String_Const_u8 name = call->name; + Doc_Page *page = doc_get_page(cluster, name); + if (page == 0){ + doc_errorf(arena, cluster, "missing documentation for %.*s", string_expand(name)); + } + } +} + // BOTTOM diff --git a/metal/4ed_metal_render.mm b/metal/4ed_metal_render.mm new file mode 100644 index 00000000..ec9c2643 --- /dev/null +++ b/metal/4ed_metal_render.mm @@ -0,0 +1,641 @@ +/* 4coder Metal render implementation */ + +#undef clamp +#undef function +#import +#import +#define function static + +//////////////////////////////// + +struct Metal_Buffer{ + Node node; + + id buffer; + u32 size; + u64 last_reuse_time; +}; + +//////////////////////////////// + +typedef id Metal_Texture; + +// NOTE(yuval): This is a locator used to describe where a specific slot is located. +union Metal_Texture_Slot_Locator{ + u32 packed; + + struct{ + u16 bucket_index; + u16 slot_index; + }; +}; + +// NOTE(yuval): This is the ACTUAL texture slot. Each slot contains the texture handle, the slot locator, and a pointer to the next slot in the free list (in case the slot if not occupied). +struct Metal_Texture_Slot{ + // NOTE(yuval): This is a pointer to the next texture in the free texture slots list + Metal_Texture_Slot *next; + + Metal_Texture texture; + Metal_Texture_Slot_Locator locator; +}; + +global_const u32 metal__texture_slots_per_bucket = 256; + +// NOTE(yuval): This a bucket of ACTUAL texture slots. +struct Metal_Texture_Slot_Bucket{ + Metal_Texture_Slot_Bucket *next; + Metal_Texture_Slot slots[metal__texture_slots_per_bucket]; +}; + +// NOTE(yuval): This a struct contaning all texture slot buckets and a list of the currently free slots. +struct Metal_Texture_Slot_List{ + Metal_Texture_Slot_Bucket *first_bucket; + Metal_Texture_Slot_Bucket *last_bucket; + u16 bucket_count; + + Metal_Texture_Slot *first_free_slot; + Metal_Texture_Slot *last_free_slot; +}; + +global_const u32 metal__invalid_texture_slot_locator = (u32)-1; + +//////////////////////////////// + +@interface Metal_Renderer : NSObject +- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)mtkView target:(Render_Target*)target; + +- (u32)get_texture_of_dim:(Vec3_i32)dim kind:(Texture_Kind)kind; +- (b32)fill_texture:(u32)texture kind:(Texture_Kind)kind pos:(Vec3_i32)p dim:(Vec3_i32)dim data:(void*)data; +- (void)bind_texture:(u32)handle encoder:(id)render_encoder; +- (Metal_Texture_Slot*)get_texture_slot_at_locator:(Metal_Texture_Slot_Locator)locator; +- (Metal_Texture_Slot*)get_texture_slot_at_handle:(u32)handle; + +- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size; +- (void)add_reusable_buffer:(Metal_Buffer*)buffer; +@end + +//////////////////////////////// + +global_const char *metal__shaders_source = R"( +#include +#include + +using namespace metal; + +//////////////////////////////// + +typedef struct{ +float2 xy [[attribute(0)]]; +float3 uvw [[attribute(1)]]; +uint32_t color [[attribute(2)]]; +float half_thickness [[attribute(3)]]; +} Vertex; + +// NOTE(yuval): Vertex shader outputs and fragment shader inputs +typedef struct{ +// NOTE(yuval): Vertex shader output +float4 position [[position]]; + +// NOTE(yuval): Fragment shader inputs +float4 color; +float3 uvw; +float2 xy; +float2 adjusted_half_dim; +float half_thickness; +} Rasterizer_Data; + +//////////////////////////////// + +vertex Rasterizer_Data +vertex_shader(Vertex in [[stage_in]], +constant float4x4 &proj [[buffer(1)]]){ +Rasterizer_Data out; + +// NOTE(yuval): Calculate position in NDC +out.position = proj * float4(in.xy, 0.0, 1.0); + +// NOTE(yuval): Convert color to float4 format +out.color.b = ((float((in.color ) & 0xFFu)) / 255.0); +out.color.g = ((float((in.color >> 8u) & 0xFFu)) / 255.0); +out.color.r = ((float((in.color >> 16u) & 0xFFu)) / 255.0); +out.color.a = ((float((in.color >> 24u) & 0xFFu)) / 255.0); + +// NOTE(yuval): Pass uvw coordinates to the fragment shader +out.uvw = in.uvw; + +// NOTE(yuval): Calculate adjusted half dim +float2 center = in.uvw.xy; +float2 half_dim = abs(in.xy - center); +out.adjusted_half_dim = (half_dim - in.uvw.zz + float2(0.5, 0.5)); + +// NOTE(yuval): Pass half_thickness to the fragment shader +out.half_thickness = in.half_thickness; + +// NOTE(yuval): Pass xy to the fragment shader +out.xy = in.xy; + +return(out); +} + +//////////////////////////////// + +float +rectangle_sd(float2 p, float2 b){ +float2 d = (abs(p) - b); +float result = (length(max(d, float2(0.0, 0.0))) + min(max(d.x, d.y), 0.0)); + +return(result); +} + +fragment float4 +fragment_shader(Rasterizer_Data in [[stage_in]], +texture2d_array in_texture [[texture(0)]]){ +float has_thickness = step(0.49, in.half_thickness); +float does_not_have_thickness = (1.0 - has_thickness); + +constexpr sampler texture_sampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear); +half sample_value = in_texture.sample(texture_sampler, in.uvw.xy, in.uvw.z).r; +sample_value *= does_not_have_thickness; + +float2 center = in.uvw.xy; +float roundness = in.uvw.z; +float sd = rectangle_sd(in.xy - center, in.adjusted_half_dim); +sd = sd - roundness; +sd = (abs(sd + in.half_thickness) - in.half_thickness); +float shape_value = (1.0 - smoothstep(-1.0, 0.0, sd)); +shape_value *= has_thickness; + +float4 out_color = float4(in.color.xyz, in.color.a * (sample_value + shape_value)); +return(out_color); +} +)"; + +//////////////////////////////// + +function Metal_Buffer* +metal__make_buffer(u32 size, id device){ + Metal_Buffer *result = (Metal_Buffer*)malloc(sizeof(Metal_Buffer)); + + // NOTE(yuval): Create the vertex buffer + MTLResourceOptions options = MTLCPUCacheModeWriteCombined|MTLResourceStorageModeManaged; + result->buffer = [device newBufferWithLength:size options:options]; + result->size = size; + + // NOTE(yuval): Set the last_reuse_time to the current time + result->last_reuse_time = system_now_time(); + + return result; +} + +//////////////////////////////// + +@implementation Metal_Renderer{ + Render_Target *_target; + + id _device; + id _pipeline_state; + id _command_queue; + id _capture_scope; + + Node _buffer_cache; + u64 _last_buffer_cache_purge_time; + + Metal_Texture_Slot_List _texture_slots; +} + +- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)mtk_view target:(Render_Target*)target{ + self = [super init]; + if (self == nil){ + return(nil); + } + + _target = target; + + NSError *error = nil; + + _device = mtk_view.device; + + // NOTE(yuval): Compile the shaders + id vertex_function = nil; + id fragment_function = nil; + { + NSString *shaders_source_str = [NSString stringWithUTF8String:metal__shaders_source]; + + MTLCompileOptions *options = [[MTLCompileOptions alloc] init]; + options.fastMathEnabled = YES; + + id shader_library = [_device newLibraryWithSource:shaders_source_str + options:options error:&error]; + vertex_function = [shader_library newFunctionWithName:@"vertex_shader"]; + fragment_function = [shader_library newFunctionWithName:@"fragment_shader"]; + + [options release]; + } + + Assert(error == nil); + Assert((vertex_function != nil) && (fragment_function != nil)); + + // NOTE(yuval): Configure the pipeline descriptor + { + MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor]; + vertexDescriptor.attributes[0].offset = OffsetOfMember(Render_Vertex, xy); + vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position + vertexDescriptor.attributes[0].bufferIndex = 0; + vertexDescriptor.attributes[1].offset = OffsetOfMember(Render_Vertex, uvw); + vertexDescriptor.attributes[1].format = MTLVertexFormatFloat3; // texCoords + vertexDescriptor.attributes[1].bufferIndex = 0; + vertexDescriptor.attributes[2].offset = OffsetOfMember(Render_Vertex, color); + vertexDescriptor.attributes[2].format = MTLVertexFormatUInt; // color + vertexDescriptor.attributes[2].bufferIndex = 0; + vertexDescriptor.attributes[3].offset = OffsetOfMember(Render_Vertex, half_thickness); + vertexDescriptor.attributes[3].format = MTLVertexFormatFloat; // position + vertexDescriptor.attributes[3].bufferIndex = 0; + vertexDescriptor.layouts[0].stepRate = 1; + vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; + vertexDescriptor.layouts[0].stride = sizeof(Render_Vertex); + + MTLRenderPipelineDescriptor *pipeline_state_descriptor = [[MTLRenderPipelineDescriptor alloc] init]; + pipeline_state_descriptor.label = @"4coder Metal Renderer Pipeline"; + pipeline_state_descriptor.vertexFunction = vertex_function; + pipeline_state_descriptor.fragmentFunction = fragment_function; + pipeline_state_descriptor.vertexDescriptor = vertexDescriptor; + pipeline_state_descriptor.colorAttachments[0].pixelFormat = mtk_view.colorPixelFormat; + pipeline_state_descriptor.colorAttachments[0].blendingEnabled = YES; + pipeline_state_descriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + pipeline_state_descriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + pipeline_state_descriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + pipeline_state_descriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + pipeline_state_descriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; + pipeline_state_descriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + + _pipeline_state = [_device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor + error:&error]; + } + + Assert(error == nil); + + // NOTE(yuval): Create the command queue + _command_queue = [_device newCommandQueue]; + + // NOTE(yuval): Initialize buffer caching + dll_init_sentinel(&_buffer_cache); + _last_buffer_cache_purge_time = system_now_time(); + + // NOTE(yuval): Initialize the texture slot list + block_zero_struct(&_texture_slots); + + // NOTE(yuval): Create the fallback texture + _target->fallback_texture_id = [self get_texture_of_dim:V3i32(2, 2, 1) + kind:TextureKind_Mono]; + u8 white_block[] = {0xFF, 0xFF, 0xFF, 0xFF}; + [self fill_texture:_target->fallback_texture_id + kind:TextureKind_Mono + pos:V3i32(0, 0, 0) + dim:V3i32(2, 2, 1) + data:white_block]; + + // NOTE(yuval): Create a capture scope for gpu frame capture + _capture_scope = [[MTLCaptureManager sharedCaptureManager] + newCaptureScopeWithDevice:_device]; + _capture_scope.label = @"4coder Metal Capture Scope"; + + return(self); +} + +- (void)mtkView:(nonnull MTKView*)view drawableSizeWillChange:(CGSize)size{ + // NOTE(yuval): Nothing to do here because we use the render target's dimentions for rendering +} + +- (void)drawInMTKView:(nonnull MTKView*)view{ +#if FRED_INTERNAL + [_capture_scope beginScope]; +#endif + + // HACK(yuval): This is the best way I found to force valid width and height without drawing on the next draw cycle (1 frame delay). + CGSize drawable_size = [view drawableSize]; + i32 width = (i32)Min(_target->width, drawable_size.width); + i32 height = (i32)Min(_target->height, drawable_size.height); + + Font_Set *font_set = (Font_Set*)_target->font_set; + + // NOTE(yuval): Free any textures in the target's texture free list + for (Render_Free_Texture *free_texture = _target->free_texture_first; + free_texture; + free_texture = free_texture->next){ + Metal_Texture_Slot *texture_slot = [self get_texture_slot_at_handle:free_texture->tex_id]; + if (texture_slot){ + sll_queue_push(_texture_slots.first_free_slot, _texture_slots.last_free_slot, texture_slot); + } + } + _target->free_texture_first = 0; + _target->free_texture_last = 0; + + // NOTE(yuval): Create the command buffer + id command_buffer = [_command_queue commandBuffer]; + command_buffer.label = @"4coder Metal Render Command"; + + // NOTE(yuval): Obtain the render pass descriptor from the renderer's view + MTLRenderPassDescriptor *render_pass_descriptor = view.currentRenderPassDescriptor; + if (render_pass_descriptor != nil){ + render_pass_descriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0f, 0.0f, 0.0f, 1.0f); + + // NOTE(yuval): Create the render command encoder + id render_encoder = + [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor]; + render_encoder.label = @"4coder Render Encoder"; + + // NOTE(yuval): Set the region of the drawable to draw into + [render_encoder setViewport:(MTLViewport){0.0, 0.0, (double)width, (double)height, 0.0, 1.0}]; + + // NOTE(yuval): Set the render pipeline to use for drawing + [render_encoder setRenderPipelineState:_pipeline_state]; + + // NOTE(yuval): Calculate the projection matrix + float left = 0, right = (float)width; + float bottom = (float)height, top = 0; + float near_depth = -1.0f, far_depth = 1.0f; + float proj[16] = { + 2.0f / (right - left), 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f / (top - bottom), 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f / (far_depth - near_depth), 0.0f, + -((right + left) / (right - left)), -((top + bottom) / (top - bottom)), + -(near_depth / (far_depth - near_depth)), 1.0f + }; + + // NOTE(yuval): Calculate required vertex buffer size + i32 all_vertex_count = 0; + for (Render_Group *group = _target->group_first; + group; + group = group->next){ + all_vertex_count += group->vertex_list.vertex_count; + } + + u32 vertex_buffer_size = (all_vertex_count * sizeof(Render_Vertex)); + + // NOTE(yuval): Find & Get a vertex buffer matching the required size + Metal_Buffer *buffer = [self get_reusable_buffer_with_size:vertex_buffer_size]; + + // NOTE(yuval): Pass the vertex buffer to the vertex shader + [render_encoder setVertexBuffer:buffer->buffer + offset:0 + atIndex:0]; + + // NOTE(yuval): Pass the projection matrix to the vertex shader + [render_encoder setVertexBytes:&proj + length:sizeof(proj) + atIndex:1]; + + u32 buffer_offset = 0; + for (Render_Group *group = _target->group_first; + group; + group = group->next){ + // NOTE(yuval): Set scissor rect + { + Rect_i32 box = Ri32(group->clip_box); + + NSUInteger x0 = (NSUInteger)Min(Max(0, box.x0), width - 1); + NSUInteger x1 = (NSUInteger)Min(Max(0, box.x1), width); + NSUInteger y0 = (NSUInteger)Min(Max(0, box.y0), height - 1); + NSUInteger y1 = (NSUInteger)Min(Max(0, box.y1), height); + + MTLScissorRect scissor_rect; + scissor_rect.x = x0; + scissor_rect.y = y0; + scissor_rect.width = (x1 - x0); + scissor_rect.height = (y1 - y0); + + [render_encoder setScissorRect:scissor_rect]; + } + + i32 vertex_count = group->vertex_list.vertex_count; + if (vertex_count > 0){ + // NOTE(yuval): Bind a texture + { + Face* face = font_set_face_from_id(font_set, group->face_id); + if (face != 0){ + // NOTE(yuval): Bind face texture + [self bind_texture:face->texture + encoder:render_encoder]; + } else{ + // NOTE(yuval): Bind fallback texture + [self bind_texture:_target->fallback_texture_id + encoder:render_encoder]; + } + } + + // NOTE(yuval): Copy the vertex data to the vertex buffer + { + + u8 *group_buffer_contents = (u8*)[buffer->buffer contents] + buffer_offset; + u8 *cursor = group_buffer_contents; + for (Render_Vertex_Array_Node *node = group->vertex_list.first; + node; + node = node->next){ + i32 size = node->vertex_count * sizeof(*node->vertices); + memcpy(cursor, node->vertices, size); + cursor += size; + } + + NSUInteger data_size = (NSUInteger)(cursor - group_buffer_contents); + NSRange modify_range = NSMakeRange(buffer_offset, data_size); + [buffer->buffer didModifyRange:modify_range]; + } + + // NOTE(yuval): Set the vertex buffer offset to the beginning of the group's vertices + [render_encoder setVertexBufferOffset:buffer_offset atIndex:0]; + + // NOTE(yuval): Draw the vertices + [render_encoder drawPrimitives:MTLPrimitiveTypeTriangle + vertexStart:0 + vertexCount:vertex_count]; + + buffer_offset += (vertex_count * sizeof(Render_Vertex)); + } + } + + [render_encoder endEncoding]; + + // NOTE(yuval): Schedule a present once the framebuffer is complete using the current drawable + [command_buffer presentDrawable:view.currentDrawable]; + + [command_buffer addCompletedHandler:^(id){ + dispatch_async(dispatch_get_main_queue(), ^{ + [self add_reusable_buffer:buffer]; + }); + }]; + } + + // NOTE(yuval): Finalize rendering here and push the command buffer to the GPU + [command_buffer commit]; + +#if FRED_INTERNAL + [_capture_scope endScope]; +#endif +} + +- (u32)get_texture_of_dim:(Vec3_i32)dim kind:(Texture_Kind)kind{ + u32 handle = metal__invalid_texture_slot_locator; + + // NOTE(yuval): Check for a free texture slot and allocate another slot bucket if no free slot has been found + if (!_texture_slots.first_free_slot){ + // NOTE(yuval): Assert that the next bucket's index can fit in a u16 + Assert(_texture_slots.bucket_count < ((u16)-1)); + + Metal_Texture_Slot_Bucket *bucket = (Metal_Texture_Slot_Bucket*)system_memory_allocate(sizeof(Metal_Texture_Slot_Bucket), file_name_line_number_lit_u8); + + for (u16 slot_index = 0; + slot_index < ArrayCount(bucket->slots); + ++slot_index){ + Metal_Texture_Slot *slot = &bucket->slots[slot_index]; + block_zero_struct(slot); + slot->locator.bucket_index = _texture_slots.bucket_count; + slot->locator.slot_index = slot_index; + + sll_queue_push(_texture_slots.first_free_slot, _texture_slots.last_free_slot, slot); + } + + sll_queue_push(_texture_slots.first_bucket, _texture_slots.last_bucket, bucket); + _texture_slots.bucket_count += 1; + } + + // NOTE(yuval): Get the first free texture slot and remove it from the free list (a slot is guarenteed to exist because we assert that above). + if (_texture_slots.first_free_slot){ + Metal_Texture_Slot *texture_slot = _texture_slots.first_free_slot; + sll_queue_pop(_texture_slots.first_free_slot, _texture_slots.last_free_slot); + texture_slot->next = 0; + + // NOTE(yuval): Create a texture descriptor. + MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init]; + texture_descriptor.textureType = MTLTextureType2DArray; + texture_descriptor.pixelFormat = MTLPixelFormatR8Unorm; + texture_descriptor.width = dim.x; + texture_descriptor.height = dim.y; + texture_descriptor.depth = dim.z; + + // NOTE(yuval): Create the texture from the device using the descriptor and add it to the textures array. + Metal_Texture texture = [_device newTextureWithDescriptor:texture_descriptor]; + texture_slot->texture = texture; + + handle = texture_slot->locator.packed; + } + + return handle; +} + +- (b32)fill_texture:(u32)handle kind:(Texture_Kind)kind pos:(Vec3_i32)p dim:(Vec3_i32)dim data:(void*)data{ + b32 result = false; + + if (data){ + Metal_Texture_Slot *texture_slot = [self get_texture_slot_at_handle:handle]; + if (texture_slot){ + Metal_Texture texture = texture_slot->texture; + + if (texture != 0){ + MTLRegion replace_region = { + {(NSUInteger)p.x, (NSUInteger)p.y, (NSUInteger)p.z}, + {(NSUInteger)dim.x, (NSUInteger)dim.y, (NSUInteger)dim.z} + }; + + // NOTE(yuval): Fill the texture with data + [texture replaceRegion:replace_region + mipmapLevel:0 + withBytes:data + bytesPerRow:dim.x]; + + result = true; + } + } + } + + return(result); +} + +- (void)bind_texture:(u32)handle encoder:(id)render_encoder{ + Metal_Texture_Slot *texture_slot = [self get_texture_slot_at_handle:handle]; + if (texture_slot){ + Metal_Texture texture = texture_slot->texture; + if (texture != 0){ + [render_encoder setFragmentTexture:texture + atIndex:0]; + } + } +} + +- (Metal_Texture_Slot*)get_texture_slot_at_locator:(Metal_Texture_Slot_Locator)locator{ + Metal_Texture_Slot *result = 0; + + if (locator.packed != metal__invalid_texture_slot_locator){ + Metal_Texture_Slot_Bucket *bucket = _texture_slots.first_bucket; + for (u16 bucket_index = 0; + (bucket_index < locator.bucket_index) && bucket; + ++bucket_index, bucket = bucket->next); + + if (bucket && (locator.slot_index < metal__texture_slots_per_bucket)){ + result = &bucket->slots[locator.slot_index]; + } + } + + return(result); +} + +- (Metal_Texture_Slot*)get_texture_slot_at_handle:(u32)handle{ + Metal_Texture_Slot_Locator locator; + locator.packed = handle; + + Metal_Texture_Slot *result = [self get_texture_slot_at_locator:locator]; + return(result); +} + +- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size{ + // NOTE(yuval): This routine is a modified version of Dear ImGui's MetalContext::dequeueReusableBufferOfLength in imgui_impl_metal.mm + + u64 now = system_now_time(); + + // NOTE(yuval): Purge old buffers that haven't been useful for a while + if ((now - _last_buffer_cache_purge_time) > 1000000){ + Node prev_buffer_cache = _buffer_cache; + dll_init_sentinel(&_buffer_cache); + + for (Node *node = prev_buffer_cache.next; + node != &_buffer_cache; + node = node->next){ + Metal_Buffer *candidate = CastFromMember(Metal_Buffer, node, node); + if (candidate->last_reuse_time > _last_buffer_cache_purge_time){ + dll_insert(&_buffer_cache, node); + } + } + + _last_buffer_cache_purge_time = now; + } + + // NOTE(yuval): See if we have a buffer we can reuse + Metal_Buffer *best_candidate = 0; + for (Node *node = _buffer_cache.next; + node != &_buffer_cache; + node = node->next){ + Metal_Buffer *candidate = CastFromMember(Metal_Buffer, node, node); + if ((candidate->size >= size) && ((!best_candidate) || (best_candidate->last_reuse_time > candidate->last_reuse_time))){ + best_candidate = candidate; + } + } + + Metal_Buffer *result; + if (best_candidate){ + // NOTE(yuval): A best candidate has been found! Remove it from the buffer list and set its last reuse time. + dll_remove(&best_candidate->node); + best_candidate->last_reuse_time = now; + result = best_candidate; + } else{ + // NOTE(yuval): No luck; make a new buffer. + result = metal__make_buffer(size, _device); + } + + return(result); +} + +- (void)add_reusable_buffer:(Metal_Buffer*)buffer{ + // NOTE(yuval): This routine is a modified version of Dear ImGui's MetalContext::enqueueReusableBuffer in imgui_impl_metal.mm + + dll_insert(&_buffer_cache, &buffer->node); +} +@end diff --git a/opengl/4ed_opengl_defines.h b/opengl/4ed_opengl_defines.h index be20f65e..c64640cf 100644 --- a/opengl/4ed_opengl_defines.h +++ b/opengl/4ed_opengl_defines.h @@ -12,8 +12,6 @@ #if !defined(FRED_OPENGL_DEFINES_H) #define FRED_OPENGL_DEFINES_H -#include - #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_MULTISAMPLE 0x809D @@ -224,9 +222,6 @@ typedef void GL_Debug_Function(GLenum src, void *user_data); typedef GL_Debug_Function *GLDEBUGPROC; -#define GL_FUNC(N,R,P) typedef R (CALL_CONVENTION N##_Function)P; N##_Function *N = 0; -#include "4ed_opengl_funcs.h" - #endif // BOTTOM diff --git a/opengl/4ed_opengl_render.cpp b/opengl/4ed_opengl_render.cpp index 3e83095d..0d1ad918 100644 --- a/opengl/4ed_opengl_render.cpp +++ b/opengl/4ed_opengl_render.cpp @@ -9,8 +9,6 @@ // TOP -#include "4ed_opengl_defines.h" - internal void gl__bind_texture(Render_Target *t, i32 texid){ if (t->bound_texture != texid){ @@ -225,11 +223,16 @@ gl_render(Render_Target *t){ #if !SHIP_MODE glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, 0, false); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, 0, false); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, 0, true); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, 0, true); - glDebugMessageCallback(gl__error_callback, 0); + if (glDebugMessageControl){ + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, 0, false); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, 0, false); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, 0, true); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, 0, true); + } + + if (glDebugMessageCallback){ + glDebugMessageCallback(gl__error_callback, 0); + } #endif //////////////////////////////// @@ -256,7 +259,7 @@ gl_render(Render_Target *t){ //////////////////////////////// - { + { t->fallback_texture_id = gl__get_texture(V3i32(2, 2, 1), TextureKind_Mono); u8 white_block[] = { 0xFF, 0xFF, 0xFF, 0xFF, }; gl__fill_texture(TextureKind_Mono, 0, V3i32(0, 0, 0), V3i32(2, 2, 1), white_block); @@ -286,7 +289,15 @@ gl_render(Render_Target *t){ group != 0; group = group->next){ Rect_i32 box = Ri32(group->clip_box); - glScissor(box.x0, height - box.y1, box.x1 - box.x0, box.y1 - box.y0); + + Rect_i32 scissor_box = { + box.x0, height - box.y1, box.x1 - box.x0, box.y1 - box.y0, + }; + scissor_box.x0 = clamp_bot(0, scissor_box.x0); + scissor_box.y0 = clamp_bot(0, scissor_box.y0); + scissor_box.x1 = clamp_bot(0, scissor_box.x1); + scissor_box.y1 = clamp_bot(0, scissor_box.y1); + glScissor(scissor_box.x0, scissor_box.y0, scissor_box.x1, scissor_box.y1); i32 vertex_count = group->vertex_list.vertex_count; if (vertex_count > 0){ diff --git a/platform_mac/mac_4ed.mm b/platform_mac/mac_4ed.mm new file mode 100644 index 00000000..46997aff --- /dev/null +++ b/platform_mac/mac_4ed.mm @@ -0,0 +1,1393 @@ +/* Mac Objective-C layer for 4coder */ + +#define FPS 60 +#define frame_useconds (1000000 / FPS) + +#include "4coder_base_types.h" +#include "4coder_version.h" +#include "4coder_events.h" + +#include "4coder_table.h" + +// NOTE(allen): This is a very unfortunate hack, but hopefully there will never be a need to use the Marker +// type in the platform layer. If that changes then instead change the name of Marker and make a transition +// macro that is only included in custom code. +#define Marker Marker__SAVE_THIS_IDENTIFIER +#include "4coder_types.h" +#undef Marker + +#include "4coder_default_colors.h" + +#include "4coder_system_types.h" +#define STATIC_LINK_API +#include "generated/system_api.h" + +#include "4ed_font_interface.h" +#define STATIC_LINK_API +#include "generated/graphics_api.h" +#define STATIC_LINK_API +#include "generated/font_api.h" + +#include "4ed_font_set.h" +#include "4ed_render_target.h" +#include "4ed_search_list.h" +#include "4ed.h" + +#include "generated/system_api.cpp" +#include "generated/graphics_api.cpp" +#include "generated/font_api.cpp" + +#include "4coder_base_types.cpp" +#include "4coder_stringf.cpp" +#include "4coder_events.cpp" +#include "4coder_hash_functions.cpp" +#include "4coder_table.cpp" +#include "4coder_log.cpp" + +#include "4ed_search_list.cpp" + +#include "mac_objective_c_to_cpp_links.h" + +#undef function +#undef internal +#undef global +#undef external +#import + +#include // NOTE(yuval): Used for proc_pidpath +#include // NOTE(yuval): Used for virtual key codes +#include // NOTE(yuval): Used for mach_absolute_time, mach_timebase_info, mach_timebase_info_data_t + +#include // NOTE(yuval): Used for opendir, readdir +#include // NOTE(yuval): Used for dlopen, dlclose, dlsym +#include // NOTE(yuval): Used for errno +#include // NOTE(yuval): Used for open +#include // NOTE(yuval): Used for threads, mutexes, cvs +#include // NOTE(yuval): Used for getcwd, read, write, getpid +#include // NOTE(yuval): Used for mmap, munmap, mprotect +#include // NOTE(yuval): Used for stat +#include // NOTE(yuval): Used for struct stat, pid_t +#include // NOTE(yuval): Used for PATH_MAX + +#include // NOTE(yuval): Used for free + +#define function static +#define internal static +#define global static +#define external extern "C" + +struct Control_Keys{ + b8 l_ctrl; + b8 r_ctrl; + b8 l_alt; + b8 r_alt; + b8 l_shift; + b8 r_shift; + b8 l_command; + b8 r_command; +}; + +struct Mac_Input_Chunk_Transient{ + Input_List event_list; + b8 mouse_l_press; + b8 mouse_l_release; + b8 mouse_r_press; + b8 mouse_r_release; + b8 out_of_window; + i8 mouse_wheel; + b8 trying_to_kill; +}; + +struct Mac_Input_Chunk_Persistent{ + Vec2_i32 mouse; + Control_Keys controls; + Input_Modifier_Set_Fixed modifiers; + b8 mouse_l; + b8 mouse_r; +}; + +struct Mac_Input_Chunk{ + Mac_Input_Chunk_Transient trans; + Mac_Input_Chunk_Persistent pers; +}; + +//////////////////////////////// + +#define SLASH '/' +#define DLL "so" + +#include "4coder_hash_functions.cpp" +#include "4coder_system_allocator.cpp" +#include "4coder_malloc_allocator.cpp" +#include "4coder_codepoint_map.cpp" + +#include "4ed_mem.cpp" +#include "4ed_font_set.cpp" + +//////////////////////////////// + +@interface FCoder_App_Delegate : NSObject +@end + +@interface FCoder_Window_Delegate : NSObject +- (void)process_focus_event; +@end + +@interface FCoder_View : NSView +- (void)request_display; +- (void)check_clipboard; +- (void)process_keyboard_event:(NSEvent*)event down:(b8)down; +- (void)process_mouse_move_event:(NSEvent*)event; +@end + +//////////////////////////////// + +typedef i32 Mac_Object_Kind; +enum{ + MacObjectKind_ERROR = 0, + MacObjectKind_Timer = 1, + MacObjectKind_Thread = 2, + MacObjectKind_Mutex = 3, + MacObjectKind_CV = 4, +}; + +struct Mac_Object{ + Node node; + Mac_Object_Kind kind; + + union{ + NSTimer* timer; + + struct{ + pthread_t thread; + Thread_Function *proc; + void *ptr; + } thread; + + pthread_mutex_t mutex; + pthread_cond_t cv; + }; +}; + +struct Mac_Vars { + i32 width, height; + + Thread_Context *tctx; + + Arena *frame_arena; + Input_Event *active_key_stroke; + Input_Event *active_text_input; + Mac_Input_Chunk input_chunk; + b8 lctrl_lalt_is_altgr; + + b8 full_screen; + b8 do_toggle; + b32 send_exit_signal; + + i32 cursor_show; + i32 prev_cursor_show; + NSCursor *cursor_ibeam; + NSCursor *cursor_arrow; + NSCursor *cursor_leftright; + NSCursor *cursor_updown; + + String_Const_u8 binary_path; + + Arena *clipboard_arena; + String_Const_u8 clipboard_contents; + u32 clipboard_change_count; + b32 next_clipboard_is_self; + + Arena clip_post_arena; + String_Const_u8 clip_post; + + NSWindow *window; + FCoder_View *view; + f32 screen_scale_factor; + + mach_timebase_info_data_t timebase_info; + b32 first; + void *base_ptr; + + u64 timer_start; + b32 step_requested; + i32 running_cli; + + Node free_mac_objects; + Node timer_objects; + + pthread_mutex_t thread_launch_mutex; + pthread_cond_t thread_launch_cv; + b32 waiting_for_launch; + + System_Mutex global_frame_mutex; + + Log_Function *log_string; +}; + +//////////////////////////////// + +#include "mac_4ed_renderer.h" + +//////////////////////////////// + +global Mac_Vars mac_vars; +global Mac_Renderer *renderer; +global Render_Target target; +global App_Functions app; + +//////////////////////////////// + +function Mac_Object* +mac_alloc_object(Mac_Object_Kind kind){ + Mac_Object *result = 0; + + if (mac_vars.free_mac_objects.next != &mac_vars.free_mac_objects){ + result = CastFromMember(Mac_Object, node, mac_vars.free_mac_objects.next); + } + + if (!result){ + i32 count = 512; + Mac_Object *objects = (Mac_Object*)system_memory_allocate(count * sizeof(Mac_Object), file_name_line_number_lit_u8); + + // NOTE(yuval): Link the first node of the dll to the sentinel + objects[0].node.prev = &mac_vars.free_mac_objects; + mac_vars.free_mac_objects.next = &objects[0].node; + + // NOTE(yuval): Link all dll nodes to each other + for (i32 chain_index = 1; chain_index < count; chain_index += 1){ + objects[chain_index - 1].node.next = &objects[chain_index].node; + objects[chain_index].node.prev = &objects[chain_index - 1].node; + } + + // NOTE(yuval): Link the last node of the dll to the sentinel + objects[count - 1].node.next = &mac_vars.free_mac_objects; + mac_vars.free_mac_objects.prev = &objects[count - 1].node; + + result = CastFromMember(Mac_Object, node, mac_vars.free_mac_objects.next); + } + + Assert(result); + dll_remove(&result->node); + block_zero_struct(result); + result->kind = kind; + + return(result); +} + +function void +mac_free_object(Mac_Object *object){ + if (object->node.next != 0){ + dll_remove(&object->node); + } + + dll_insert(&mac_vars.free_mac_objects, &object->node); +} + +function inline Plat_Handle +mac_to_plat_handle(Mac_Object *object){ + Plat_Handle result = *(Plat_Handle*)(&object); + return(result); +} + +function inline Mac_Object* +mac_to_object(Plat_Handle handle){ + Mac_Object *result = *(Mac_Object**)(&handle); + return(result); +} + +//////////////////////////////// + +function void +mac_init_recursive_mutex(pthread_mutex_t *mutex){ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(mutex, &attr); +} + +//////////////////////////////// + +function void +mac_error_box(char *msg, b32 shutdown = true){ + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + + NSString *title_string = @"Error"; + NSString *message_string = [NSString stringWithUTF8String:msg]; + [alert setMessageText:title_string]; + [alert setInformativeText:message_string]; + + [alert runModal]; + + if (shutdown){ + exit(1); + } +} + + +function void +os_popup_error(char *title, char *message){ + // TODO(yuval): Condense this with mac_error_box + + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + + NSString *title_string = [NSString stringWithUTF8String:title]; + NSString *message_string = [NSString stringWithUTF8String:message]; + [alert setMessageText:title_string]; + [alert setInformativeText:message_string]; + + [alert runModal]; + + exit(1); +} + +//////////////////////////////// + +#if defined(FRED_INTERNAL) +function inline void +mac_profile(char *name, u64 begin, u64 end){ + printf("%s Time: %fs\n", name, ((end - begin) / 1000000.0f)); +} + +#define MacProfileScope(name) for (u64 glue(_i_, __LINE__) = 0, glue(_begin_, __LINE__) = system_now_time();\ +glue(_i_, __LINE__) == 0;\ +glue(_i_, __LINE__) = 1, mac_profile(name, glue(_begin_, __LINE__), system_now_time())) +#else +# define mac_profile(...) +# define MacProfileScope(...) +#endif + +//////////////////////////////// + +#import "mac_4ed_renderer.mm" + +#include "4ed_font_provider_freetype.h" +#include "4ed_font_provider_freetype.cpp" + +#import "mac_4ed_functions.mm" + +//////////////////////////////// + +global_const u8 kVK_Menu = 0x6E; + +global Key_Code keycode_lookup_table[255] = {}; + +function void +mac_keycode_init(void){ + keycode_lookup_table[kVK_ANSI_A] = KeyCode_A; + keycode_lookup_table[kVK_ANSI_B] = KeyCode_B; + keycode_lookup_table[kVK_ANSI_C] = KeyCode_C; + keycode_lookup_table[kVK_ANSI_D] = KeyCode_D; + keycode_lookup_table[kVK_ANSI_E] = KeyCode_E; + keycode_lookup_table[kVK_ANSI_F] = KeyCode_F; + keycode_lookup_table[kVK_ANSI_G] = KeyCode_G; + keycode_lookup_table[kVK_ANSI_H] = KeyCode_H; + keycode_lookup_table[kVK_ANSI_I] = KeyCode_I; + keycode_lookup_table[kVK_ANSI_J] = KeyCode_J; + keycode_lookup_table[kVK_ANSI_K] = KeyCode_K; + keycode_lookup_table[kVK_ANSI_L] = KeyCode_L; + keycode_lookup_table[kVK_ANSI_M] = KeyCode_M; + keycode_lookup_table[kVK_ANSI_N] = KeyCode_N; + keycode_lookup_table[kVK_ANSI_O] = KeyCode_O; + keycode_lookup_table[kVK_ANSI_P] = KeyCode_P; + keycode_lookup_table[kVK_ANSI_Q] = KeyCode_Q; + keycode_lookup_table[kVK_ANSI_R] = KeyCode_R; + keycode_lookup_table[kVK_ANSI_S] = KeyCode_S; + keycode_lookup_table[kVK_ANSI_T] = KeyCode_T; + keycode_lookup_table[kVK_ANSI_U] = KeyCode_U; + keycode_lookup_table[kVK_ANSI_V] = KeyCode_V; + keycode_lookup_table[kVK_ANSI_W] = KeyCode_W; + keycode_lookup_table[kVK_ANSI_X] = KeyCode_X; + keycode_lookup_table[kVK_ANSI_Y] = KeyCode_Y; + keycode_lookup_table[kVK_ANSI_Z] = KeyCode_Z; + + keycode_lookup_table[kVK_ANSI_0] = KeyCode_0; + keycode_lookup_table[kVK_ANSI_1] = KeyCode_1; + keycode_lookup_table[kVK_ANSI_2] = KeyCode_2; + keycode_lookup_table[kVK_ANSI_3] = KeyCode_3; + keycode_lookup_table[kVK_ANSI_4] = KeyCode_4; + keycode_lookup_table[kVK_ANSI_5] = KeyCode_5; + keycode_lookup_table[kVK_ANSI_6] = KeyCode_6; + keycode_lookup_table[kVK_ANSI_7] = KeyCode_7; + keycode_lookup_table[kVK_ANSI_8] = KeyCode_8; + keycode_lookup_table[kVK_ANSI_9] = KeyCode_9; + + keycode_lookup_table[kVK_Space] = KeyCode_Space; + keycode_lookup_table[kVK_ANSI_Grave] = KeyCode_Tick; + keycode_lookup_table[kVK_ANSI_Minus] = KeyCode_Minus; + keycode_lookup_table[kVK_ANSI_Equal] = KeyCode_Equal; + keycode_lookup_table[kVK_ANSI_LeftBracket] = KeyCode_LeftBracket; + keycode_lookup_table[kVK_ANSI_RightBracket] = KeyCode_RightBracket; + keycode_lookup_table[kVK_ANSI_Semicolon] = KeyCode_Semicolon; + keycode_lookup_table[kVK_ANSI_Quote] = KeyCode_Quote; + keycode_lookup_table[kVK_ANSI_Comma] = KeyCode_Comma; + keycode_lookup_table[kVK_ANSI_Period] = KeyCode_Period; + keycode_lookup_table[kVK_ANSI_Slash] = KeyCode_ForwardSlash; + keycode_lookup_table[kVK_ANSI_Backslash] = KeyCode_BackwardSlash; + + keycode_lookup_table[kVK_Tab] = KeyCode_Tab; + // NOTE(yuval): No Pause key on macOS! + keycode_lookup_table[kVK_Escape] = KeyCode_Escape; + + keycode_lookup_table[kVK_UpArrow] = KeyCode_Up; + keycode_lookup_table[kVK_DownArrow] = KeyCode_Down; + keycode_lookup_table[kVK_LeftArrow] = KeyCode_Left; + keycode_lookup_table[kVK_RightArrow] = KeyCode_Right; + + keycode_lookup_table[kVK_Delete] = KeyCode_Backspace; + keycode_lookup_table[kVK_Return] = KeyCode_Return; + + keycode_lookup_table[kVK_ForwardDelete] = KeyCode_Delete; + //keycode_lookup_table[] = KeyCode_Insert; // TODO(yuval): Figure how to get keyDown events for the insert key + keycode_lookup_table[kVK_Home] = KeyCode_Home; + keycode_lookup_table[kVK_End] = KeyCode_End; + keycode_lookup_table[kVK_PageUp] = KeyCode_PageUp; + keycode_lookup_table[kVK_PageDown] = KeyCode_PageDown; + + keycode_lookup_table[kVK_CapsLock] = KeyCode_CapsLock; + keycode_lookup_table[kVK_ANSI_KeypadClear] = KeyCode_NumLock; + // NOTE(yuval): No Scroll Lock key on macOS! + keycode_lookup_table[kVK_Menu] = KeyCode_Menu; + + keycode_lookup_table[kVK_Shift] = KeyCode_Shift; + keycode_lookup_table[kVK_RightShift] = KeyCode_Shift; + + keycode_lookup_table[kVK_Control] = KeyCode_Control; + keycode_lookup_table[kVK_RightControl] = KeyCode_Control; + + keycode_lookup_table[kVK_Option] = KeyCode_Alt; + keycode_lookup_table[kVK_RightOption] = KeyCode_Alt; + + keycode_lookup_table[kVK_Command] = KeyCode_Command; + keycode_lookup_table[kVK_RightCommand] = KeyCode_Command; // NOTE(yuval): Right Command + + keycode_lookup_table[kVK_F1] = KeyCode_F1; + keycode_lookup_table[kVK_F2] = KeyCode_F2; + keycode_lookup_table[kVK_F3] = KeyCode_F3; + keycode_lookup_table[kVK_F4] = KeyCode_F4; + keycode_lookup_table[kVK_F5] = KeyCode_F5; + keycode_lookup_table[kVK_F6] = KeyCode_F6; + keycode_lookup_table[kVK_F7] = KeyCode_F7; + keycode_lookup_table[kVK_F8] = KeyCode_F8; + keycode_lookup_table[kVK_F9] = KeyCode_F9; + + keycode_lookup_table[kVK_F10] = KeyCode_F10; + keycode_lookup_table[kVK_F11] = KeyCode_F11; + keycode_lookup_table[kVK_F12] = KeyCode_F12; + keycode_lookup_table[kVK_F13] = KeyCode_F13; + keycode_lookup_table[kVK_F14] = KeyCode_F14; + keycode_lookup_table[kVK_F15] = KeyCode_F15; + keycode_lookup_table[kVK_F16] = KeyCode_F16; +} + +//////////////////////////////// + +function b32 +mac_file_can_be_made(u8* filename){ + b32 result = access((char*)filename, W_OK) == 0; + return(result); +} + +//////////////////////////////// + +function void +mac_resize(float width, float height){ + if ((width > 0.0f) && (height > 0.0f)){ +#if 1 + NSSize coord_size = NSMakeSize(width, height); + NSSize backing_size = [mac_vars.view convertSizeToBacking:coord_size]; + + mac_vars.width = (i32)backing_size.width; + mac_vars.height = (i32)backing_size.height; + + target.width = (i32)backing_size.width; + target.height = (i32)backing_size.height; +#else + mac_vars.width = (i32)width; + mac_vars.height = (i32)height; + + target.width = (i32)width; + target.height = (i32)height; +#endif + } + + system_signal_step(0); +} + +function inline void +mac_resize(NSWindow *window){ + NSRect bounds = [[window contentView] bounds]; + mac_resize(bounds.size.width, bounds.size.height); +} + +//////////////////////////////// + +function u32 +mac_get_clipboard_change_count(void){ + NSPasteboard *board = [NSPasteboard generalPasteboard]; + u32 result = board.changeCount; + + return(result); +} + +function b32 +mac_read_clipboard_contents(Arena *scratch){ + b32 result = false; + + Temp_Memory temp = begin_temp(scratch); + { + NSPasteboard *board = [NSPasteboard generalPasteboard]; + NSString *utf8_type = @"public.utf8-plain-text"; + NSArray *types_array = [NSArray arrayWithObjects:utf8_type, nil]; + NSString *has_string = [board availableTypeFromArray:types_array]; + if (has_string != nil){ + NSData *data = [board dataForType:utf8_type]; + if (data != nil){ + u32 copy_length = data.length; + if (copy_length > 0){ + Arena *clip_arena = mac_vars.clipboard_arena; + linalloc_clear(clip_arena); + + mac_vars.clipboard_contents = string_const_u8_push(clip_arena, copy_length); + [data getBytes:mac_vars.clipboard_contents.str + length:mac_vars.clipboard_contents.size]; + + result = true; + } + } + } + } + end_temp(temp); + + return(result); +} + +function void +mac_post_clipboard(Arena *scratch, char *text, i32 len){ + NSPasteboard *board = [NSPasteboard generalPasteboard]; + + NSString *utf8_type = @"public.utf8-plain-text"; + NSArray *types_array = [NSArray arrayWithObjects:utf8_type, nil]; + [board declareTypes:types_array + owner:nil]; + + NSString *paste_string = [[NSString alloc] initWithBytes:text + length:len + encoding:NSUTF8StringEncoding]; + [board setString:paste_string + forType:utf8_type]; + [paste_string release]; + + mac_vars.next_clipboard_is_self = true; +} + +//////////////////////////////// + +function void +mac_toggle_fullscreen(void){ + [mac_vars.window toggleFullScreen:nil]; +} + +//////////////////////////////// + +@implementation FCoder_App_Delegate +- (void)applicationDidFinishLaunching:(id)sender{ +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender{ + return(YES); +} + +- (void)applicationWillTerminate:(NSNotification*)notification{ +} +@end + +@implementation FCoder_Window_Delegate +- (BOOL)windowShouldClose:(id)sender{ + mac_vars.input_chunk.trans.trying_to_kill = true; + system_signal_step(0); + + return(NO); +} + +- (void)windowDidResize:(NSNotification*)notification{ + mac_resize(mac_vars.window); + if (!mac_vars.do_toggle){ + [mac_vars.view display]; + } +} + +- (void)windowDidMiniaturize:(NSNotification*)notification{ +} + +- (void)windowDidDeminiaturize:(NSNotification*)notification{ +} + +- (void)windowDidBecomeKey:(NSNotification *)notification{ + // NOTE(yuval): The window is the focused window + [self process_focus_event]; +} + +- (void)windowDidResignKey:(NSNotification *)notification{ + // NOTE(yuval): The window has lost focus + [self process_focus_event]; +} + +- (void)process_focus_event{ + mac_vars.input_chunk.pers.mouse_l = false; + mac_vars.input_chunk.pers.mouse_r = false; + block_zero_struct(&mac_vars.input_chunk.pers.controls); + block_zero_struct(&mac_vars.input_chunk.pers.modifiers); + mac_vars.active_key_stroke = 0; + mac_vars.active_text_input = 0; + + system_signal_step(0); +} +@end + +@implementation FCoder_View +- (id)init{ + self = [super init]; + return(self); +} + +- (void)dealloc{ + [super dealloc]; +} + +- (void)viewDidChangeBackingProperties{ + // TODO(yuval): If the screen scale factor changed, modify the current face to use the new screen scale factor. + mac_resize(mac_vars.window); +} + +- (BOOL)wantsUpdateLayer{ + return YES; +} + +- (void)updateLayer{ + u64 prev_timer_start; + + MacProfileScope("Draw Rect"){ + mac_vars.step_requested = false; + + MacProfileScope("Acquire Frame Mutex"){ + // NOTE(yuval): Read comment in win32_4ed.cpp's main loop + system_mutex_acquire(mac_vars.global_frame_mutex); + } + + Application_Step_Input input = {}; + + // NOTE(yuval): Prepare the Frame Input + MacProfileScope("Prepare Input"){ + Mac_Input_Chunk input_chunk = mac_vars.input_chunk; + + input.first_step = mac_vars.first; + input.dt = frame_useconds / 1000000.0f; + input.events = input_chunk.trans.event_list; + + input.mouse.out_of_window = input_chunk.trans.out_of_window; + + input.mouse.l = input_chunk.pers.mouse_l; + input.mouse.press_l = input_chunk.trans.mouse_l_press; + input.mouse.release_l = input_chunk.trans.mouse_l_release; + + input.mouse.r = input_chunk.pers.mouse_r; + input.mouse.press_r = input_chunk.trans.mouse_r_press; + input.mouse.release_r = input_chunk.trans.mouse_r_release; + + input.mouse.wheel = input_chunk.trans.mouse_wheel; + input.mouse.p = input_chunk.pers.mouse; + + input.trying_to_kill = input_chunk.trans.trying_to_kill; + + block_zero_struct(&mac_vars.input_chunk.trans); + mac_vars.active_key_stroke = 0; + mac_vars.active_text_input = 0; + + // NOTE(yuval): See comment in win32_4ed.cpp's main loop + if (mac_vars.send_exit_signal){ + input.trying_to_kill = true; + mac_vars.send_exit_signal = false; + } + } + + // NOTE(yuval): Frame clipboard input + MacProfileScope("Frame Clipboard Input"){ + block_zero_struct(&mac_vars.clipboard_contents); + input.clipboard_changed = false; + + if (mac_vars.clipboard_change_count != 0){ + u32 change_count = mac_get_clipboard_change_count(); + if (change_count != mac_vars.clipboard_change_count){ + if (mac_vars.next_clipboard_is_self){ + mac_vars.next_clipboard_is_self = false; + } else{ + for (i32 r = 0; r < 4; ++r){ + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + + if (mac_read_clipboard_contents(scratch)){ + input.clipboard_changed = true; + break; + } + } + } + + mac_vars.clipboard_change_count = change_count; + } + } + + input.clipboard = mac_vars.clipboard_contents; + } + + mac_vars.clip_post.size = 0; + + // NOTE(yuval): Application Core Update + Application_Step_Result result = {}; + MacProfileScope("Step"){ + if (app.step != 0){ + result = app.step(mac_vars.tctx, &target, mac_vars.base_ptr, &input); + } + } + + // NOTE(yuval): Quit the app if requested by the application core + MacProfileScope("Perform Kill"){ + if (result.perform_kill){ + [NSApp terminate:nil]; + } + } + + // NOTE(yuval): Post new clipboard content + MacProfileScope("Post Clipboard"){ + if (mac_vars.clip_post.size > 0){ + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + mac_post_clipboard(scratch, (char*)mac_vars.clip_post.str, (i32)mac_vars.clip_post.size); + } + } + + // NOTE(yuval): Switch to a new title + MacProfileScope("Switch Title"){ + if (result.has_new_title){ + NSString *str = [NSString stringWithUTF8String:result.title_string]; + [mac_vars.window setTitle:str]; + } + } + + // NOTE(yuval): Switch to new cursor + MacProfileScope("Switch Cursor"){ + // NOTE(yuval): Switch cursor type + switch (result.mouse_cursor_type){ + case APP_MOUSE_CURSOR_ARROW: + { + [mac_vars.cursor_arrow set]; + } break; + + case APP_MOUSE_CURSOR_IBEAM: + { + [mac_vars.cursor_ibeam set]; + } break; + + case APP_MOUSE_CURSOR_LEFTRIGHT: + { + [mac_vars.cursor_leftright set]; + } break; + + case APP_MOUSE_CURSOR_UPDOWN: + { + [mac_vars.cursor_updown set]; + } break; + } + + // NOTE(yuval): Show or hide cursor + if (mac_vars.cursor_show != mac_vars.prev_cursor_show){ + switch (mac_vars.cursor_show){ + case MouseCursorShow_Never: + { + [NSCursor hide]; + } break; + + case MouseCursorShow_Always: + { + [NSCursor unhide]; + } break; + } + + mac_vars.prev_cursor_show = mac_vars.cursor_show; + } + } + + // NOTE(yuval): Update lctrl_lalt_is_altgr status + mac_vars.lctrl_lalt_is_altgr = (b8)result.lctrl_lalt_is_altgr; + + // NOTE(yuval): Render + MacProfileScope("Render"){ + renderer->render(renderer, &target); + } + + // NOTE(yuval): Toggle full screen + MacProfileScope("Toggle Full Screen"){ + if (mac_vars.do_toggle){ + mac_toggle_fullscreen(); + mac_vars.do_toggle = false; + } + } + + // NOTE(yuval): Schedule another step if needed + MacProfileScope("Schedule Step"){ + if (result.animating || (mac_vars.running_cli > 0)){ + system_signal_step(0); + } + } + + // NOTE(yuval): Sleep a bit to cool off + MacProfileScope("Cool Down"){ + system_mutex_release(mac_vars.global_frame_mutex); + { + u64 timer_end = system_now_time(); + u64 end_target = (mac_vars.timer_start + frame_useconds); + + if (timer_end < end_target){ + if ((end_target - timer_end) > 1000){ + // NOTE(yuval): Sleep until the end target minus a millisecond (to allow the scheduler to wake the process in time) + system_sleep(end_target - timer_end - 1000); + } + + // NOTE(yuval): Iterate through the rest of the time that's left using a regular for loop to make sure that we hit the end target + u64 now = system_now_time(); + while (now < end_target){ + now = system_now_time(); + } + } + + prev_timer_start = mac_vars.timer_start; + mac_vars.timer_start = system_now_time(); + } + system_mutex_acquire(mac_vars.global_frame_mutex); + } + + MacProfileScope("Cleanup"){ + mac_vars.first = false; + + linalloc_clear(mac_vars.frame_arena); + + // NOTE(yuval): Release the global frame mutex until the next drawRect call + system_mutex_release(mac_vars.global_frame_mutex); + } + } + + mac_profile("Frame", prev_timer_start, mac_vars.timer_start); +#if FRED_INTERNAL + printf("\n"); +#endif +} + +- (BOOL)acceptsFirstResponder{ + return(YES); +} + +- (BOOL)becomeFirstResponder{ + return(YES); +} + +- (BOOL)resignFirstResponder{ + return(YES); +} + +- (void)keyDown:(NSEvent*)event{ + // NOTE(yuval): Process keyboard event + [self process_keyboard_event:event down:true]; + + // NOTE(yuval): Process TextInsert event + { + NSString *characters = [event characters]; + if ([characters length] > 0){ + // NOTE(yuval): Get the first utf-16 character + u32 c = [characters characterAtIndex:0]; + if (c == '\r'){ + c = '\n'; + } + + // NOTE(yuval): Check for a valid text input + if ((c > 127) || ((' ' <= c) && (c <= '~')) || (c == '\t') || (c == '\n') || (c == '\r')){ + String_Const_u16 str_16 = SCu16((u16*)&c, 1); + String_Const_u8 str_8 = string_u8_from_string_u16(mac_vars.frame_arena, str_16).string; + + Input_Event *event = push_input_event(mac_vars.frame_arena, &mac_vars.input_chunk.trans.event_list); + event->kind = InputEventKind_TextInsert; + event->text.string = str_8; + event->text.next_text = 0; + event->text.blocked = false; + if (mac_vars.active_text_input){ + mac_vars.active_text_input->text.next_text = event; + } else if (mac_vars.active_key_stroke){ + mac_vars.active_key_stroke->key.first_dependent_text = event; + } + + mac_vars.active_text_input = event; + + system_signal_step(0); + } + } + } +} + +- (void)keyUp:(NSEvent*)event{ + [self process_keyboard_event:event down:false]; +} + +- (void)flagsChanged:(NSEvent *)event{ + NSEventModifierFlags flags = [event modifierFlags]; + b8 ctrl_pressed = ((flags & NSEventModifierFlagControl) != 0); + b8 alt_pressed = ((flags & NSEventModifierFlagOption) != 0); + b8 shift_pressed = ((flags & NSEventModifierFlagShift) != 0); + b8 command_pressed = ((flags & NSEventModifierFlagCommand) != 0); + + Control_Keys *controls = &mac_vars.input_chunk.pers.controls; + u16 event_key_code = [event keyCode]; + if (event_key_code == kVK_Control){ + controls->l_ctrl = ctrl_pressed; + [self process_keyboard_event:event down:ctrl_pressed]; + } else if (event_key_code == kVK_RightControl){ + controls->r_ctrl = ctrl_pressed; + [self process_keyboard_event:event down:ctrl_pressed]; + } else if (event_key_code == kVK_Option){ + controls->l_alt = alt_pressed; + [self process_keyboard_event:event down:alt_pressed]; + } else if (event_key_code == kVK_RightOption){ + controls->r_alt = alt_pressed; + [self process_keyboard_event:event down:alt_pressed]; + } else if (event_key_code == kVK_Shift){ + controls->l_shift = shift_pressed; + [self process_keyboard_event:event down:shift_pressed]; + } else if (event_key_code == kVK_RightShift){ + controls->r_shift = shift_pressed; + [self process_keyboard_event:event down:shift_pressed]; + } else if (event_key_code == kVK_Command){ + controls->l_command = command_pressed; + [self process_keyboard_event:event down:command_pressed]; + } else if (event_key_code == kVK_RightCommand){ + controls->r_command = command_pressed; + [self process_keyboard_event:event down:command_pressed]; + } +} + +- (void)mouseMoved:(NSEvent*)event{ + [self process_mouse_move_event:event]; +} + +- (void)mouseDragged:(NSEvent*)event{ + [self process_mouse_move_event:event]; +} + +- (void)scrollWheel:(NSEvent *)event{ + float dx = event.scrollingDeltaX; + float dy = event.scrollingDeltaY; + + i8 wheel_delta = 0; + if (dy > 0){ + wheel_delta = -100; + } else if (dy < 0){ + wheel_delta = 100; + } + mac_vars.input_chunk.trans.mouse_wheel = wheel_delta; + + system_signal_step(0); +} + +- (void)mouseDown:(NSEvent*)event{ + mac_vars.input_chunk.trans.mouse_l_press = true; + mac_vars.input_chunk.pers.mouse_l = true; + + system_signal_step(0); +} + +- (void)mouseUp:(NSEvent*)event{ + mac_vars.input_chunk.trans.mouse_l_release = true; + mac_vars.input_chunk.pers.mouse_l = false; + + system_signal_step(0); +} + +- (void)rightMouseDown:(NSEvent*)event{ + [super rightMouseDown:event]; + + mac_vars.input_chunk.trans.mouse_r_press = true; + mac_vars.input_chunk.pers.mouse_r = true; + + system_signal_step(0); +} + +- (void)rightMouseUp:(NSEvent*)event{ + mac_vars.input_chunk.trans.mouse_r_release = true; + mac_vars.input_chunk.pers.mouse_r = false; + + system_signal_step(0); +} + +- (void)request_display{ + CGRect cg_rect = CGRectMake(0, 0, mac_vars.width, mac_vars.height); + NSRect rect = NSRectFromCGRect(cg_rect); + [self setNeedsDisplayInRect:rect]; +} + +- (void)check_clipboard{ + u32 change_count = mac_get_clipboard_change_count(); + if (change_count != mac_vars.clipboard_change_count){ + system_signal_step(0); + } +} + +- (void)process_keyboard_event:(NSEvent*)event down:(b8)down{ + b8 release = !down; + + Input_Modifier_Set_Fixed *mods = &mac_vars.input_chunk.pers.modifiers; + + // NOTE(yuval): Set control modifiers + { + Control_Keys *controls = &mac_vars.input_chunk.pers.controls; + + b8 ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); + b8 alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); + if (mac_vars.lctrl_lalt_is_altgr && controls->l_alt && controls->l_ctrl){ + ctrl = false; + alt = false; + } + + b8 shift = (controls->r_shift || controls->l_shift); + b8 command = (controls->r_command || controls->l_command); + + set_modifier(mods, KeyCode_Control, ctrl); + set_modifier(mods, KeyCode_Alt, alt); + set_modifier(mods, KeyCode_Shift, shift); + set_modifier(mods, KeyCode_Command, command); + } + + // NOTE(yuval): Process KeyStroke / KeyRelease event + { + u16 event_key_code = [event keyCode]; + Key_Code key = keycode_lookup_table[(u8)event_key_code]; + if (down){ + if (key != 0){ + add_modifier(mods, key); + + Input_Event *event = push_input_event(mac_vars.frame_arena, &mac_vars.input_chunk.trans.event_list); + event->kind = InputEventKind_KeyStroke; + event->key.code = key; + event->key.modifiers = copy_modifier_set(mac_vars.frame_arena, mods); + + mac_vars.active_key_stroke = event; + + system_signal_step(0); + } + } else{ + mac_vars.active_key_stroke = 0; + mac_vars.active_text_input = 0; + + if (key != 0){ + Input_Event *event = push_input_event(mac_vars.frame_arena, &mac_vars.input_chunk.trans.event_list); + event->kind = InputEventKind_KeyRelease; + event->key.code = key; + event->key.modifiers = copy_modifier_set(mac_vars.frame_arena, mods); + + remove_modifier(mods, key); + } + + system_signal_step(0); + } + } +} + +- (void)process_mouse_move_event:(NSEvent*)event{ + NSPoint location = [event locationInWindow]; + NSPoint backing_location = [self convertPointToBacking:location]; + + Vec2_i32 new_m = V2i32(backing_location.x, mac_vars.height - backing_location.y); + if (new_m != mac_vars.input_chunk.pers.mouse){ + mac_vars.input_chunk.pers.mouse = new_m; + + Rect_i32 screen = Ri32(0, 0, target.width, target.height); + mac_vars.input_chunk.trans.out_of_window = !rect_contains_point(screen, new_m); + + } + + system_signal_step(0); +} +@end + +//////////////////////////////// + +int +main(int arg_count, char **args){ + @autoreleasepool{ + // NOTE(yuval): Create NSApplication & Delegate + [NSApplication sharedApplication]; + Assert(NSApp != nil); + + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + FCoder_App_Delegate *app_delegate = [[FCoder_App_Delegate alloc] init]; + [NSApp setDelegate:app_delegate]; + + mac_init_recursive_mutex(&memory_tracker_mutex); + + // NOTE(yuval): Context setup + Thread_Context _tctx = {}; + thread_ctx_init(&_tctx, ThreadKind_Main, + get_base_allocator_system(), + get_base_allocator_system()); + + block_zero_struct(&mac_vars); + mac_vars.tctx = &_tctx; + + API_VTable_system system_vtable = {}; + system_api_fill_vtable(&system_vtable); + + API_VTable_graphics graphics_vtable = {}; + graphics_api_fill_vtable(&graphics_vtable); + + API_VTable_font font_vtable = {}; + font_api_fill_vtable(&font_vtable); + + // NOTE(yuval): Memory + mac_vars.frame_arena = reserve_arena(mac_vars.tctx); + target.arena = make_arena_system(KB(256)); + + dll_init_sentinel(&mac_vars.free_mac_objects); + dll_init_sentinel(&mac_vars.timer_objects); + + mac_init_recursive_mutex(&mac_vars.thread_launch_mutex); + pthread_cond_init(&mac_vars.thread_launch_cv, 0); + + // NOTE(yuval): Screen scale factor calculation + { + NSScreen* screen = [NSScreen mainScreen]; + NSDictionary* desc = [screen deviceDescription]; + NSSize size = [[desc valueForKey:NSDeviceResolution] sizeValue]; + f32 max_dpi = Max(size.width, size.height); + mac_vars.screen_scale_factor = (max_dpi / 72.0f); + } + + // NOTE(yuval): Load core + System_Library core_library = {}; + { + App_Get_Functions *get_funcs = 0; + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + Path_Search_List search_list = {}; + search_list_add_system_path(scratch, &search_list, SystemPath_Binary); + + String_Const_u8 core_path = get_full_path(scratch, &search_list, SCu8("4ed_app.so")); + if (system_load_library(scratch, core_path, &core_library)){ + get_funcs = (App_Get_Functions*)system_get_proc(core_library, "app_get_functions"); + if (get_funcs != 0){ + app = get_funcs(); + } + else{ + char msg[] = "Failed to get application code from '4ed_app.so'."; + mac_error_box(msg); + } + } + else{ + char msg[] = "Could not load '4ed_app.so'. This file should be in the same directory as the main '4ed' executable."; + mac_error_box(msg); + } + } + + // NOTE(yuval): Send api vtables to core + app.load_vtables(&system_vtable, &font_vtable, &graphics_vtable); + mac_vars.log_string = app.get_logger(); + + // NOTE(yuval): Init & command line parameters + Plat_Settings plat_settings = {}; + mac_vars.base_ptr = 0; + { + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + String_Const_u8 curdir = system_get_path(scratch, SystemPath_CurrentDirectory); + curdir = string_mod_replace_character(curdir, '\\', '/'); + char **files = 0; + i32 *file_count = 0; + mac_vars.base_ptr = app.read_command_line(mac_vars.tctx, curdir, &plat_settings, &files, &file_count, arg_count, args); + { + i32 end = *file_count; + i32 i = 0, j = 0; + for (; i < end; ++i){ + if (mac_file_can_be_made((u8*)files[i])){ + files[j] = files[i]; + ++j; + } + } + *file_count = j; + } + } + + // NOTE(yuval): Load custom layer + System_Library custom_library = {}; + Custom_API custom = {}; + { + char custom_not_found_msg[] = "Did not find a library for the custom layer."; + char custom_fail_version_msg[] = "Failed to load custom code due to missing version information or a version mismatch. Try rebuilding with buildsuper."; + char custom_fail_init_apis[] = "Failed to load custom code due to missing 'init_apis' symbol. Try rebuilding with buildsuper"; + + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + String_Const_u8 default_file_name = string_u8_litexpr("custom_4coder.so"); + Path_Search_List search_list = {}; + search_list_add_system_path(scratch, &search_list, SystemPath_CurrentDirectory); + search_list_add_system_path(scratch, &search_list, SystemPath_Binary); + String_Const_u8 custom_file_names[2] = {}; + i32 custom_file_count = 1; + if (plat_settings.custom_dll != 0){ + custom_file_names[0] = SCu8(plat_settings.custom_dll); + if (!plat_settings.custom_dll_is_strict){ + custom_file_names[1] = default_file_name; + custom_file_count += 1; + } + } + else{ + custom_file_names[0] = default_file_name; + } + String_Const_u8 custom_file_name = {}; + for (i32 i = 0; i < custom_file_count; i += 1){ + custom_file_name = get_full_path(scratch, &search_list, custom_file_names[i]); + if (custom_file_name.size > 0){ + break; + } + } + b32 has_library = false; + if (custom_file_name.size > 0){ + if (system_load_library(scratch, custom_file_name, &custom_library)){ + has_library = true; + } + } + + if (!has_library){ + mac_error_box(custom_not_found_msg); + } + custom.get_version = (_Get_Version_Type*)system_get_proc(custom_library, "get_version"); + if (custom.get_version == 0 || custom.get_version(MAJOR, MINOR, PATCH) == 0){ + mac_error_box(custom_fail_version_msg); + } + custom.init_apis = (_Init_APIs_Type*)system_get_proc(custom_library, "init_apis"); + if (custom.init_apis == 0){ + mac_error_box(custom_fail_init_apis); + } + } + + // + // Window and Renderer Initialization + // + + // NOTE(yuval): Create Window & Window Delegate + i32 w; + i32 h; + if (plat_settings.set_window_size){ + w = plat_settings.window_w; + h = plat_settings.window_h; + } else{ + w = 800; + h = 600; + } + + NSRect screen_rect = [[NSScreen mainScreen] frame]; + NSRect initial_frame = NSMakeRect((f32)(screen_rect.size.width - w) * 0.5f, (f32)(screen_rect.size.height - h) * 0.5f, w, h); + + u32 style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; + + mac_vars.window = [[NSWindow alloc] initWithContentRect:initial_frame + styleMask:style_mask + backing:NSBackingStoreBuffered + defer:NO]; + + FCoder_Window_Delegate *window_delegate = [[FCoder_Window_Delegate alloc] init]; + [mac_vars.window setDelegate:window_delegate]; + + [mac_vars.window setMinSize:NSMakeSize(100, 100)]; + [mac_vars.window setBackgroundColor:NSColor.blackColor]; + [mac_vars.window setTitle:@"GRAPHICS"]; + [mac_vars.window setAcceptsMouseMovedEvents:YES]; + + NSView* content_view = [mac_vars.window contentView]; + + // NOTE(yuval): Create the 4coder view + mac_vars.view = [[FCoder_View alloc] init]; + [mac_vars.view setFrame:[content_view bounds]]; + [mac_vars.view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + mac_vars.view.wantsLayer = true; + + // NOTE(yuval): Display window and view + [content_view addSubview:mac_vars.view]; + [mac_vars.window makeKeyAndOrderFront:nil]; + + // NOTE(yuval): Initialize the renderer + renderer = mac_init_renderer(MacRenderer_Metal, mac_vars.window, &target); + + mac_resize(w, h); + + // + // NOTE(yuval): Misc System Initializations + // + + // NOTE(yuval): Initialize clipboard + { + mac_vars.clipboard_arena = reserve_arena(mac_vars.tctx); + mac_vars.clipboard_change_count = mac_get_clipboard_change_count(); + mac_vars.next_clipboard_is_self = false; + + // NOTE(yuval): Read the current clipboard + { + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + mac_read_clipboard_contents(scratch); + } + + // NOTE(yuval): Start the clipboard polling timer + [NSTimer scheduledTimerWithTimeInterval: 0.5 + target:mac_vars.view + selector:@selector(check_clipboard) + userInfo:nil repeats:YES]; + } + + // NOTE(yuval): Initialize the virtul keycodes table + mac_keycode_init(); + + // NOTE(yuval): Initialize cursors + { + mac_vars.cursor_show = MouseCursorShow_Always; + mac_vars.prev_cursor_show = MouseCursorShow_Always; + + mac_vars.cursor_arrow = [NSCursor arrowCursor]; + mac_vars.cursor_ibeam = [NSCursor IBeamCursor]; + mac_vars.cursor_leftright = [NSCursor resizeLeftRightCursor]; + mac_vars.cursor_updown = [NSCursor resizeUpDownCursor]; + } + + // NOTE(yuval): Get the timebase info + mach_timebase_info(&mac_vars.timebase_info); + + // + // App init + // + + { + Scratch_Block scratch(mac_vars.tctx, Scratch_Share); + String_Const_u8 curdir = system_get_path(scratch, SystemPath_CurrentDirectory); + curdir = string_mod_replace_character(curdir, '\\', '/'); + app.init(mac_vars.tctx, &target, mac_vars.base_ptr, mac_vars.clipboard_contents, curdir, custom); + } + + // + // Start Main Loop + // + + mac_vars.first = true; + mac_vars.step_requested = false; + mac_vars.running_cli = 0; + + if (plat_settings.fullscreen_window){ + mac_toggle_fullscreen(); + } + + mac_vars.global_frame_mutex = system_mutex_make(); + + mac_vars.timer_start = system_now_time(); + + // NOTE(yuval): Start the app's run loop + [NSApp run]; + } +} diff --git a/platform_mac/mac_4ed_functions.mm b/platform_mac/mac_4ed_functions.mm new file mode 100644 index 00000000..677af480 --- /dev/null +++ b/platform_mac/mac_4ed_functions.mm @@ -0,0 +1,937 @@ +/* macOS System/Graphics/Font API Implementations */ + +/********************/ +/* System API */ +/********************/ + +//////////////////////////////// + +function +system_get_path_sig(){ + String_Const_u8 result = {}; + + switch (path_code){ + case SystemPath_CurrentDirectory: + { + char *working_dir = getcwd(NULL, 0); + u64 working_dir_length = cstring_length(working_dir); + + // TODO(yuval): Maybe use push_string_copy instead + u8 *out = push_array(arena, u8, working_dir_length); + block_copy(out, working_dir, working_dir_length); + + free(working_dir); + + result = SCu8(out, working_dir_length); + } break; + + case SystemPath_Binary: + { + local_persist b32 has_stashed_4ed_path = false; + if (!has_stashed_4ed_path){ + local_const u32 binary_path_capacity = PATH_MAX; + u8 *memory = (u8*)system_memory_allocate(binary_path_capacity, file_name_line_number_lit_u8); + + pid_t pid = getpid(); + i32 size = proc_pidpath(pid, memory, binary_path_capacity); + Assert(size < binary_path_capacity); + + mac_vars.binary_path = SCu8(memory, size); + mac_vars.binary_path = string_remove_last_folder(mac_vars.binary_path); + mac_vars.binary_path.str[mac_vars.binary_path.size] = 0; + + has_stashed_4ed_path = true; + } + + result = push_string_copy(arena, mac_vars.binary_path); + } break; + } + + return(result); +} + +function +system_get_canonical_sig(){ + NSString *path_ns_str = + [[NSString alloc] initWithBytes:name.data length:name.size encoding:NSUTF8StringEncoding]; + + NSString *standardized_path_ns_str = [path_ns_str stringByStandardizingPath]; + String_Const_u8 standardized_path = SCu8((u8*)[standardized_path_ns_str UTF8String],[standardized_path_ns_str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); + + String_Const_u8 result = push_string_copy(arena, standardized_path); + + [path_ns_str release]; + + return(result); +} + +//////////////////////////////// + +function File_Attributes +mac_get_file_attributes(struct stat file_stat) { + File_Attributes result; + result.size = file_stat.st_size; + result.last_write_time = file_stat.st_mtimespec.tv_sec; + + result.flags = 0; + if (S_ISDIR(file_stat.st_mode)) { + result.flags |= FileAttribute_IsDirectory; + } + + return(result); +} + +function inline File_Attributes +mac_file_attributes_from_path(char *path) { + File_Attributes result = {}; + + struct stat file_stat; + if (stat(path, &file_stat) == 0){ + result = mac_get_file_attributes(file_stat); + } + + return(result); +} + +function inline File_Attributes +mac_file_attributes_from_fd(i32 fd) { + File_Attributes result = {}; + + struct stat file_stat; + if (fstat(fd, &file_stat) == 0){ + result = mac_get_file_attributes(file_stat); + } + + return(result); +} + +function +system_get_file_list_sig(){ + File_List result = {}; + + u8 *c_directory = push_array(arena, u8, directory.size + 1); + block_copy(c_directory, directory.str, directory.size); + c_directory[directory.size] = 0; + + DIR *dir = opendir((char*)c_directory); + if (dir){ + File_Info* first = 0; + File_Info* last = 0; + i32 count = 0; + + for (struct dirent *entry = readdir(dir); + entry; + entry = readdir(dir)){ + char *c_file_name = entry->d_name; + String_Const_u8 file_name = SCu8(c_file_name); + + if (string_match(file_name, string_u8_litexpr(".")) || string_match(file_name, string_u8_litexpr(".."))){ + continue; + } + + File_Info *info = push_array(arena, File_Info, 1); + sll_queue_push(first, last, info); + count += 1; + + info->file_name = push_string_copy(arena, file_name); + + // NOTE(yuval): Get file attributes + { + Temp_Memory temp = begin_temp(arena); + + b32 append_slash = false; + u64 file_path_size = directory.size + file_name.size; + if (string_get_character(directory, directory.size - 1) != '/'){ + append_slash = true; + file_path_size += 1; + } + + char *file_path = push_array(arena, char, file_path_size + 1); + char *file_path_at = file_path; + + block_copy(file_path_at, directory.str, directory.size); + file_path_at += directory.size; + + if (append_slash){ + *file_path_at = '/'; + file_path_at += 1; + } + + block_copy(file_path_at, file_name.str, file_name.size); + file_path_at += file_name.size; + + *file_path_at = 0; + + info->attributes = mac_file_attributes_from_path(file_path); + + end_temp(temp); + } + } + + closedir(dir); + + result.infos = push_array(arena, File_Info*, count); + result.count = count; + + i32 index = 0; + for (File_Info *node = first; + node != 0; + node = node->next){ + result.infos[index] = node; + index += 1; + } + } + + return(result); +} + +function +system_quick_file_attributes_sig(){ + Temp_Memory temp = begin_temp(scratch); + + char *c_file_name = push_array(scratch, char, file_name.size + 1); + block_copy(c_file_name, file_name.str, file_name.size); + c_file_name[file_name.size] = 0; + + File_Attributes result = mac_file_attributes_from_path(c_file_name); + + end_temp(temp); + + return(result); +} + +function inline Plat_Handle +mac_to_plat_handle(i32 fd){ + Plat_Handle result = *(Plat_Handle*)(&fd); + return(result); +} + +function inline i32 +mac_to_fd(Plat_Handle handle){ + i32 result = *(i32*)(&handle); + return(result); +} + +function +system_load_handle_sig(){ + b32 result = false; + + i32 fd = open(file_name, O_RDONLY); + if ((fd != -1) && (fd != 0)) { + *out = mac_to_plat_handle(fd); + result = true; + } + + return(result); +} + +function +system_load_attributes_sig(){ + i32 fd = mac_to_fd(handle); + File_Attributes result = mac_file_attributes_from_fd(fd); + + return(result); +} + +function +system_load_file_sig(){ + i32 fd = mac_to_fd(handle); + + do{ + ssize_t bytes_read = read(fd, buffer, size); + if (bytes_read == -1){ + if (errno != EINTR){ + // NOTE(yuval): An error occured while reading from the file descriptor + break; + } + } else{ + size -= bytes_read; + buffer += bytes_read; + } + } while (size > 0); + + b32 result = (size == 0); + return(result); +} + +function +system_load_close_sig(){ + b32 result = true; + + i32 fd = mac_to_fd(handle); + if (close(fd) == -1){ + // NOTE(yuval): An error occured while close the file descriptor + result = false; + } + + return(result); +} + +function +system_save_file_sig(){ + File_Attributes result = {}; + + i32 fd = open(file_name, O_WRONLY | O_TRUNC | O_CREAT, 00640); + if (fd != -1) { + do{ + ssize_t bytes_written = write(fd, data.str, data.size); + if (bytes_written == -1){ + if (errno != EINTR){ + // NOTE(yuval): An error occured while writing to the file descriptor + break; + } + } else{ + data.size -= bytes_written; + data.str += bytes_written; + } + } while (data.size > 0); + + if (data.size == 0) { + result = mac_file_attributes_from_fd(fd); + } + + close(fd); + } + + return(result); +} + +//////////////////////////////// + +function inline System_Library +mac_to_system_library(void *dl_handle){ + System_Library result = *(System_Library*)(&dl_handle); + return(result); +} + +function inline void* +mac_to_dl_handle(System_Library system_lib){ + void *result = *(void**)(&system_lib); + return(result); +} + +function +system_load_library_sig(){ + b32 result = false; + + void *lib = 0; + + // NOTE(yuval): Open library handle + { + Temp_Memory temp = begin_temp(scratch); + + char *c_file_name = push_array(scratch, char, file_name.size + 1); + block_copy(c_file_name, file_name.str, file_name.size); + c_file_name[file_name.size] = 0; + + lib = dlopen(c_file_name, RTLD_LAZY | RTLD_GLOBAL); + + end_temp(temp); + } + + if (lib){ + *out = mac_to_system_library(lib); + result = true; + } + + return(result); +} + +function +system_release_library_sig(){ + void *lib = mac_to_dl_handle(handle); + i32 rc = dlclose(lib); + + b32 result = (rc == 0); + return(result); +} + +function +system_get_proc_sig(){ + void *lib = mac_to_dl_handle(handle); + Void_Func *result = (Void_Func*)dlsym(lib, proc_name); + + return(result); +} + +//////////////////////////////// + +function +system_now_time_sig(){ + u64 now = mach_absolute_time(); + + // NOTE(yuval): Now time nanoseconds conversion + f64 now_nano = (f64)((f64)now * + ((f64)mac_vars.timebase_info.numer / + (f64)mac_vars.timebase_info.denom)); + + // NOTE(yuval): Conversion to useconds + u64 result = (u64)(now_nano * 1.0E-3); + return(result); +} + +function +system_wake_up_timer_create_sig(){ + Mac_Object *object = mac_alloc_object(MacObjectKind_Timer); + dll_insert(&mac_vars.timer_objects, &object->node); + + object->timer = nil; + + Plat_Handle result = mac_to_plat_handle(object); + return(result); +} + +function +system_wake_up_timer_release_sig(){ + Mac_Object *object = mac_to_object(handle); + if (object->kind == MacObjectKind_Timer){ + if ((object->timer != nil) && [object->timer isValid]) { + [object->timer invalidate]; + mac_free_object(object); + } + } +} + +function +system_wake_up_timer_set_sig(){ + Mac_Object *object = mac_to_object(handle); + if (object->kind == MacObjectKind_Timer){ + f64 time_seconds = ((f64)time_milliseconds / 1000.0); + object->timer = [NSTimer scheduledTimerWithTimeInterval:time_seconds + target:mac_vars.view + selector:@selector(request_display) + userInfo:nil repeats:NO]; + } +} + +function +system_signal_step_sig(){ +#if 0 + if (!mac_vars.step_requested){ + [NSTimer scheduledTimerWithTimeInterval:0.0 + target:mac_vars.view + selector:@selector(request_display) + userInfo:nil repeats:NO]; + + mac_vars.step_requested = true; + } +#else + mac_vars.step_requested = true; + dispatch_async(dispatch_get_main_queue(), + ^{ + [NSTimer scheduledTimerWithTimeInterval:0.0 + target:mac_vars.view + selector:@selector(request_display) + userInfo:nil repeats:NO]; + }); +#endif +} + +function +system_sleep_sig(){ + u64 nanoseconds = (microseconds * Thousand(1)); + u64 abs_sleep_time = (u64)((f64)nanoseconds * + ((f64)mac_vars.timebase_info.denom / + (f64)mac_vars.timebase_info.numer)); + + u64 now = mach_absolute_time(); + mach_wait_until(now + abs_sleep_time); +} + +//////////////////////////////// + +function +system_post_clipboard_sig(){ + Arena *arena = &mac_vars.clip_post_arena; + if (arena->base_allocator == 0){ + *arena = make_arena_system(); + } else{ + linalloc_clear(arena); + } + + mac_vars.clip_post.str = push_array(arena, u8, str.size + 1); + if (mac_vars.clip_post.str != 0){ + block_copy(mac_vars.clip_post.str, str.str, str.size); + mac_vars.clip_post.str[str.size] = 0; + mac_vars.clip_post.size = str.size; + } else{ + // NOTE(yuval): Failed to allocate buffer for clipboard post + } +} + +//////////////////////////////// + +function +system_cli_call_sig(){ + b32 result = false; + + int pipe_fds[2]; + if (pipe(pipe_fds) == -1){ + perror("system_cli_call: pipe"); + return(false); + } + + pid_t child_pid = fork(); + if (child_pid == -1){ + perror("system_cli_call: fork"); + return(false); + } + + enum { PIPE_FD_READ, PIPE_FD_WRITE }; + + if (child_pid == 0){ + // NOTE(yuval): Child Process + close(pipe_fds[PIPE_FD_READ]); + dup2(pipe_fds[PIPE_FD_WRITE], STDOUT_FILENO); + dup2(pipe_fds[PIPE_FD_WRITE], STDERR_FILENO); + + if (chdir(path) == -1){ + perror("system_cli_call: chdir"); + exit(1); + } + + char* argv[] = {"sh", "-c", script, 0}; + + if (execv("/bin/sh", argv) == -1){ + perror("system_cli_call: execv"); + } + + exit(1); + } else{ + // NOTE(yuval): Parent Process + close(pipe_fds[PIPE_FD_WRITE]); + + *(pid_t*)&cli_out->proc = child_pid; + *(int*)&cli_out->out_read = pipe_fds[PIPE_FD_READ]; + *(int*)&cli_out->out_write = pipe_fds[PIPE_FD_WRITE]; + + mac_vars.running_cli += 1; + } + + return(true); +} + +function +system_cli_begin_update_sig(){ + // NOTE(yuval): Nothing to do here. +} + +function +system_cli_update_step_sig(){ + int pipe_read_fd = *(int*)&cli->out_read; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(pipe_read_fd, &fds); + + struct timeval tv = {}; + + size_t space_left = max; + char* ptr = dest; + + while (space_left > 0 && (select(pipe_read_fd + 1, &fds, NULL, NULL, &tv) == 1)){ + ssize_t num = read(pipe_read_fd, ptr, space_left); + if (num == -1){ + perror("system_cli_update_step: read"); + } else if (num == 0){ + // NOTE(inso): EOF + break; + } else{ + ptr += num; + space_left -= num; + } + } + + *amount = (ptr - dest); + + b32 result = ((ptr - dest) > 0); + return(result); +} + +function +system_cli_end_update_sig(){ + b32 close_me = false; + + pid_t pid = *(pid_t*)&cli->proc; + + int status; + if (pid && (waitpid(pid, &status, WNOHANG) > 0)){ + cli->exit = WEXITSTATUS(status); + + close(*(int*)&cli->out_read); + close(*(int*)&cli->out_write); + + mac_vars.running_cli -= 1; + + close_me = true; + } + + return(close_me); +} + +//////////////////////////////// + +function +system_open_color_picker_sig(){ + NotImplemented; +} + +function +system_get_screen_scale_factor_sig(){ + f32 result = mac_vars.screen_scale_factor; + return(result); +} + +//////////////////////////////// + +function void* +mac_thread_wrapper(void *ptr){ + Mac_Object *object = (Mac_Object*)ptr; + Thread_Function *proc = object->thread.proc; + void *object_ptr = object->thread.ptr; + + pthread_mutex_lock(&mac_vars.thread_launch_mutex); + { + mac_vars.waiting_for_launch = false; + pthread_cond_signal(&mac_vars.thread_launch_cv); + } + pthread_mutex_unlock(&mac_vars.thread_launch_mutex); + + proc(object_ptr); + + return(0); +} + +function +system_thread_launch_sig(){ + Mac_Object *object = mac_alloc_object(MacObjectKind_Thread); + object->thread.proc = proc; + object->thread.ptr = ptr; + + pthread_mutex_lock(&mac_vars.thread_launch_mutex); + { + mac_vars.waiting_for_launch = true; + pthread_create(&object->thread.thread, 0, mac_thread_wrapper, object); + + while (mac_vars.waiting_for_launch){ + pthread_cond_wait(&mac_vars.thread_launch_cv, &mac_vars.thread_launch_mutex); + } + } + pthread_mutex_unlock(&mac_vars.thread_launch_mutex); + + System_Thread result = mac_to_plat_handle(object); + return(result); +} + +function +system_thread_join_sig(){ + Mac_Object *object = mac_to_object(thread); + if (object->kind == MacObjectKind_Thread){ + pthread_join(object->thread.thread, 0); + } +} + +function +system_thread_free_sig(){ + Mac_Object* object = mac_to_object(thread); + if (object->kind == MacObjectKind_Thread){ + mac_free_object(object); + } +} + +function +system_thread_get_id_sig(){ + pthread_t id = pthread_self(); + i32 result = *(i32*)(&id); + return(result); +} + +function +system_mutex_make_sig(){ + Mac_Object *object = mac_alloc_object(MacObjectKind_Mutex); + mac_init_recursive_mutex(&object->mutex); + + System_Mutex result = mac_to_plat_handle(object); + return(result); +} + +function +system_mutex_acquire_sig(){ + Mac_Object *object = mac_to_object(mutex); + if (object->kind == MacObjectKind_Mutex){ + pthread_mutex_lock(&object->mutex); + } +} + +function +system_mutex_release_sig(){ + Mac_Object *object = mac_to_object(mutex); + if (object->kind == MacObjectKind_Mutex){ + pthread_mutex_unlock(&object->mutex); + } +} + +function +system_mutex_free_sig(){ + Mac_Object *object = mac_to_object(mutex); + if (object->kind == MacObjectKind_Mutex){ + pthread_mutex_destroy(&object->mutex); + mac_free_object(object); + } +} + +function +system_acquire_global_frame_mutex_sig(){ + if (tctx->kind == ThreadKind_AsyncTasks){ + system_mutex_acquire(mac_vars.global_frame_mutex); + } +} + +function +system_release_global_frame_mutex_sig(){ + if (tctx->kind == ThreadKind_AsyncTasks){ + system_mutex_release(mac_vars.global_frame_mutex); + } +} + +function +system_condition_variable_make_sig(){ + Mac_Object *object = mac_alloc_object(MacObjectKind_CV); + pthread_cond_init(&object->cv, 0); + + System_Condition_Variable result = mac_to_plat_handle(object); + return(result); +} + +function +system_condition_variable_wait_sig(){ + Mac_Object *object_cv = mac_to_object(cv); + Mac_Object *object_mutex = mac_to_object(mutex); + if ((object_cv->kind == MacObjectKind_CV) && (object_mutex->kind == MacObjectKind_Mutex)){ + pthread_cond_wait(&object_cv->cv, &object_mutex->mutex); + } +} + +function +system_condition_variable_signal_sig(){ + Mac_Object *object = mac_to_object(cv); + if (object->kind == MacObjectKind_CV){ + pthread_cond_signal(&object->cv); + } +} + +function +system_condition_variable_free_sig(){ + Mac_Object *object = mac_to_object(cv); + if (object->kind == MacObjectKind_CV){ + pthread_cond_destroy(&object->cv); + mac_free_object(object); + } +} + +//////////////////////////////// + +struct Memory_Annotation_Tracker_Node{ + Memory_Annotation_Tracker_Node *next; + Memory_Annotation_Tracker_Node *prev; + String_Const_u8 location; + u64 size; +}; + +struct Memory_Annotation_Tracker{ + Memory_Annotation_Tracker_Node *first; + Memory_Annotation_Tracker_Node *last; + i32 count; +}; + +global Memory_Annotation_Tracker memory_tracker = {}; +global pthread_mutex_t memory_tracker_mutex; + +global_const u64 ALLOCATION_SIZE_ADJUSTMENT = 64; + +function void* +mac_memory_allocate_extended(void *base, u64 size, String_Const_u8 location){ + u64 adjusted_size = size + ALLOCATION_SIZE_ADJUSTMENT; + void *memory = mmap(base, adjusted_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + Assert(memory != MAP_FAILED); + + Memory_Annotation_Tracker_Node *node = (Memory_Annotation_Tracker_Node*)memory; + + pthread_mutex_lock(&memory_tracker_mutex); + { + zdll_push_back(memory_tracker.first, memory_tracker.last, node); + memory_tracker.count += 1; + } + pthread_mutex_unlock(&memory_tracker_mutex); + + node->location = location; + node->size = size; + + void* result = (node + 1); + return(result); +} + +function void +mac_memory_free_extended(void *ptr){ + Memory_Annotation_Tracker_Node *node = (Memory_Annotation_Tracker_Node*)ptr; + node -= 1; + + pthread_mutex_lock(&memory_tracker_mutex); + { + zdll_remove(memory_tracker.first, memory_tracker.last, node); + memory_tracker.count -= 1; + } + pthread_mutex_unlock(&memory_tracker_mutex); + + munmap(node, node->size + ALLOCATION_SIZE_ADJUSTMENT); +} + +function +system_memory_allocate_sig(){ + void* result = mac_memory_allocate_extended(0, size, location); + return(result); +} + +function +system_memory_set_protection_sig(){ + b32 result = true; + + int protect = 0; + switch (flags & 0x7){ + case 0: + { + protect = PROT_NONE; + } break; + + case MemProtect_Read: + { + protect = PROT_READ; + } break; + + case MemProtect_Write: + case MemProtect_Read | MemProtect_Write: + { + protect = PROT_READ | PROT_WRITE; + } break; + + case MemProtect_Execute: + { + protect = PROT_EXEC; + } break; + + case MemProtect_Execute | MemProtect_Read: + { + protect = PROT_READ | PROT_EXEC; + } break; + + // NOTE(inso): some W^X protection things might be unhappy about this one + case MemProtect_Execute | MemProtect_Write: + case MemProtect_Execute | MemProtect_Write | MemProtect_Read: + { + protect = PROT_READ | PROT_WRITE | PROT_EXEC; + } break; + } + + Memory_Annotation_Tracker_Node *node = (Memory_Annotation_Tracker_Node*)ptr; + node -= 1; + + if(mprotect(node, size, protect) == -1){ + result = false; + } + + return(result); +} + +function +system_memory_free_sig(){ + mac_memory_free_extended(ptr); +} + +function +system_memory_annotation_sig(){ + Memory_Annotation result = {}; + + pthread_mutex_lock(&memory_tracker_mutex); + { + for (Memory_Annotation_Tracker_Node *node = memory_tracker.first; + node != 0; + node = node->next){ + Memory_Annotation_Node *r_node = push_array(arena, Memory_Annotation_Node, 1); + sll_queue_push(result.first, result.last, r_node); + result.count += 1; + + r_node->location = node->location; + r_node->address = node + 1; + r_node->size = node->size; + } + + } + pthread_mutex_unlock(&memory_tracker_mutex); + + return(result); +} + +//////////////////////////////// + +function +system_show_mouse_cursor_sig(){ + mac_vars.cursor_show = show; +} + +function +system_set_fullscreen_sig(){ + // NOTE(yuval): Read comment in system_set_fullscreen_sig in win32_4ed.cpp + mac_vars.do_toggle = (mac_vars.full_screen != full_screen); + + b32 success = true; + return(success); +} + +function +system_is_fullscreen_sig(){ + // NOTE(yuval): Read comment in system_is_fullscreen_sig in win32_4ed.cpp + b32 result = (mac_vars.full_screen != mac_vars.do_toggle); + return(result); +} + +function +system_get_keyboard_modifiers_sig(){ + Input_Modifier_Set result = copy_modifier_set(arena, &mac_vars.input_chunk.pers.modifiers); + return(result); +} + +//////////////////////////////// + +/**********************/ +/* Graphics API */ +/**********************/ + +//////////////////////////////// + +function +graphics_get_texture_sig(){ + u32 result = renderer->get_texture(renderer, dim, texture_kind); + return(result); +} + +function +graphics_fill_texture_sig(){ + b32 result = renderer->fill_texture(renderer, texture_kind, texture, p, dim, data); + return(result); +} + +//////////////////////////////// + +/******************/ +/* Font API */ +/******************/ + +//////////////////////////////// + +function +font_make_face_sig(){ + Face* result = ft__font_make_face(arena, description, scale_factor); + return(result); +} + +//////////////////////////////// diff --git a/platform_mac/mac_4ed_metal.mm b/platform_mac/mac_4ed_metal.mm new file mode 100644 index 00000000..3b03423b --- /dev/null +++ b/platform_mac/mac_4ed_metal.mm @@ -0,0 +1,83 @@ +/* Mac Metal layer for 4coder */ + +#import "metal/4ed_metal_render.mm" + +//////////////////////////////// + +struct Mac_Metal{ + Mac_Renderer base; + + Metal_Renderer *renderer; + MTKView *view; +}; + +//////////////////////////////// + +function +mac_render_sig(mac_metal__render){ +#if defined(FRED_INTERNAL) + printf("Redering using Metal!\n"); +#endif + + Mac_Metal *metal = (Mac_Metal*)renderer; + [metal->view draw]; +} + +function +mac_get_texture_sig(mac_metal__get_texture){ + Mac_Metal *metal = (Mac_Metal*)renderer; + u32 result = [metal->renderer get_texture_of_dim:dim + kind:texture_kind]; + + return(result); +} + +function +mac_fill_texture_sig(mac_metal__fill_texture){ + Mac_Metal *metal = (Mac_Metal*)renderer; + b32 result = [metal->renderer fill_texture:texture + kind:texture_kind + pos:p + dim:dim + data:data]; + + return(result); +} + +function Mac_Metal* +mac_metal__init(NSWindow *window, Render_Target *target){ + // NOTE(yuval): Create the Mac Metal rendere + Mac_Metal *metal = (Mac_Metal*)system_memory_allocate(sizeof(Mac_Metal), + file_name_line_number_lit_u8); + metal->base.render = mac_metal__render; + metal->base.get_texture = mac_metal__get_texture; + metal->base.fill_texture = mac_metal__fill_texture; + + // NOTE(yuval): Create the Metal view + NSView *content_view = [window contentView]; + + metal->view = [[MTKView alloc] initWithFrame:[content_view bounds]]; + [metal->view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [metal->view setPaused:YES]; + [metal->view setEnableSetNeedsDisplay:NO]; + + metal->view.device = MTLCreateSystemDefaultDevice(); + + // NOTE(yuval): Add the Metal view as a subview of the window + [content_view addSubview:metal->view]; + + // NOTE(yuval): Create the Metal renderer and set it as the Metal view's delegate + metal->renderer = [[Metal_Renderer alloc] initWithMetalKitView:metal->view target:target]; + metal->view.delegate = metal->renderer; + + return(metal); +} + +//////////////////////////////// + +// TODO(yuval): This function should be exported to a DLL +function +mac_load_renderer_sig(mac_load_metal_renderer){ + Mac_Renderer *renderer = (Mac_Renderer*)mac_metal__init(window, target); + return(renderer); +} diff --git a/platform_mac/mac_4ed.cpp b/platform_mac/mac_4ed_old.cpp similarity index 99% rename from platform_mac/mac_4ed.cpp rename to platform_mac/mac_4ed_old.cpp index 77b111ec..81e7ffc3 100644 --- a/platform_mac/mac_4ed.cpp +++ b/platform_mac/mac_4ed_old.cpp @@ -782,7 +782,7 @@ osx_init(){ osxvars.input.first_step = true; // - // HACK(allen): + // HACK(allen): // Previously zipped stuff is here, it should be zipped in the new pattern now. // diff --git a/platform_mac/mac_4ed.m b/platform_mac/mac_4ed_old.m similarity index 99% rename from platform_mac/mac_4ed.m rename to platform_mac/mac_4ed_old.m index ebadc1ca..fad0565e 100644 --- a/platform_mac/mac_4ed.m +++ b/platform_mac/mac_4ed_old.m @@ -814,9 +814,9 @@ osx_list_loadable_fonts(void){ NSString *font_n = fonts[i]; char *font_n_c = (char*)[font_n UTF8String]; NSFont *font = [font_manager - fontWithFamily:font_n - traits:NSUnboldFontMask|NSUnitalicFontMask - weight:5 + fontWithFamily:font_n + traits:NSUnboldFontMask|NSUnitalicFontMask + weight:5 size:12]; NSString *path = get_font_path(font); char *path_c = 0; diff --git a/platform_mac/mac_4ed_opengl.mm b/platform_mac/mac_4ed_opengl.mm new file mode 100644 index 00000000..dcfe3715 --- /dev/null +++ b/platform_mac/mac_4ed_opengl.mm @@ -0,0 +1,183 @@ +/* Mac OpenGL layer for 4coder */ + +#include "mac_4ed_renderer.h" + +//////////////////////////////// +#include +#include + +#include "opengl/4ed_opengl_defines.h" + +#define GL_FUNC(N,R,P) typedef R (CALL_CONVENTION N##_Function)P; N##_Function *N = 0; +#include "mac_4ed_opengl_funcs.h" + +//////////////////////////////// + +#include "opengl/4ed_opengl_render.cpp" + +//////////////////////////////// + +@interface OpenGL_View : NSOpenGLView +- (void)init_gl; +- (void)render:(Render_Target*)target; +@end + +//////////////////////////////// + +struct Mac_OpenGL{ + Mac_Renderer base; + + OpenGL_View *view; +}; + +//////////////////////////////// + +@implementation OpenGL_View{ + b32 gl_is_initialized; +} + +- (id)init{ + self = [super init]; + if (self == nil){ + return nil; + } + + gl_is_initialized = false; + [self init_gl]; + + return self; +} + +- (void)dealloc{ + [super dealloc]; +} + +- (void)prepareOpenGL{ + [super prepareOpenGL]; + + [[self openGLContext] makeCurrentContext]; + + // NOTE(yuval): Setup vsync + GLint swap_int = 1; + [[self openGLContext] setValues:&swap_int forParameter:NSOpenGLCPSwapInterval]; +} + +- (void)awakeFromNib{ + [self init_gl]; +} + +- (void)reshape{ + [super reshape]; + + [[self openGLContext] makeCurrentContext]; + [[self openGLContext] update]; +} + +- (void)init_gl{ + if (gl_is_initialized){ + return; + } + + // NOTE(yuval): Setup OpenGL + NSOpenGLPixelFormatAttribute opengl_attrs[] = { + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFAAccelerated, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorSize, 32, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 24, + 0 + }; + + NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:opengl_attrs]; + if (pixel_format == nil){ + fprintf(stderr, "Error creating OpenGLPixelFormat\n"); + exit(1); + } + + NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:nil]; + + [self setPixelFormat:pixel_format]; + [self setOpenGLContext:context]; + + [context makeCurrentContext]; + + [pixel_format release]; + + gl_is_initialized = true; +} + +- (void)render:(Render_Target*)target{ + Assert(gl_is_initialized); + + CGLLockContext([[self openGLContext] CGLContextObj]); + [[self openGLContext] makeCurrentContext]; + + gl_render(target); + + [[self openGLContext] flushBuffer]; + CGLUnlockContext([[self openGLContext] CGLContextObj]); +} +@end + +//////////////////////////////// + +function +mac_render_sig(mac_gl__render){ +#if defined(FRED_INTERNAL) + printf("Redering using OpenGL!\n"); +#endif + + Mac_OpenGL *gl = (Mac_OpenGL*)renderer; + [gl->view render:target]; +} + +function +mac_get_texture_sig(mac_gl__get_texture){ + u32 result = gl__get_texture(dim, texture_kind); + return(result); +} + +function +mac_fill_texture_sig(mac_gl__fill_texture){ + b32 result = gl__fill_texture(texture_kind, texture, p, dim, data); + return(result); +} + +function Mac_OpenGL* +mac_gl__init(NSWindow *window, Render_Target *target){ + // NOTE(yuval): Create the Mac OpenGL Renderer + Mac_OpenGL *gl = (Mac_OpenGL*)system_memory_allocate(sizeof(Mac_OpenGL), + file_name_line_number_lit_u8); + gl->base.render = mac_gl__render; + gl->base.get_texture = mac_gl__get_texture; + gl->base.fill_texture = mac_gl__fill_texture; + + // NOTE(yuval): Create the OpenGL view + NSView *content_view = [window contentView]; + + gl->view = [[OpenGL_View alloc] init]; + [gl->view setFrame:[content_view bounds]]; + [gl->view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [gl->view setWantsBestResolutionOpenGLSurface:YES]; + + // NOTE(yuval): Add the OpenGL view as a subview of the window + [content_view addSubview:gl->view]; + + // NOTE(yuval): Load gl functions + void *gl_image = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY); + +#define GL_FUNC(f,R,P) ((f) = (f##_Function*)dlsym(gl_image, #f)); +#include "mac_4ed_opengl_funcs.h" + + return(gl); +} + +//////////////////////////////// + +// TODO(yuval): This function should be exported to a DLL +function +mac_load_renderer_sig(mac_load_opengl_renderer){ + Mac_Renderer *renderer = (Mac_Renderer*)mac_gl__init(window, target); + return(renderer); +} diff --git a/platform_mac/mac_4ed_opengl_funcs.h b/platform_mac/mac_4ed_opengl_funcs.h new file mode 100644 index 00000000..649847f9 --- /dev/null +++ b/platform_mac/mac_4ed_opengl_funcs.h @@ -0,0 +1,17 @@ +/* Mac OpenGL functions for 4coder */ + +// TOP +/* Usage: +#define GL_FUNC(N,R,P) ~~~~ +#include "4ed_opengl_funcs.h" +*/ + +GL_FUNC(glDebugMessageControl, void, (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled)) +GL_FUNC(glDebugMessageCallback, void, (GLDEBUGPROC callback, const void *userParam)) + +GL_FUNC(glGenVertexArrays, void, (GLsizei n, GLuint *arrays)) +GL_FUNC(glBindVertexArray, void, (GLuint array)) + +GL_FUNC(glVertexAttribIPointer, void, (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)) + +#undef GL_FUNC diff --git a/platform_mac/mac_4ed_renderer.h b/platform_mac/mac_4ed_renderer.h new file mode 100644 index 00000000..ecc11ff2 --- /dev/null +++ b/platform_mac/mac_4ed_renderer.h @@ -0,0 +1,44 @@ +/* Mac Renderer Abstraction */ + +#if !defined(FRED_MAC_RENDERER_H) +#define FRED_MAC_RENDERER_H + +//////////////////////////////// + +// TODO(yuval): This should be refactored into a platform independent renderer + +struct Mac_Renderer; + +#define mac_render_sig(name) void name(Mac_Renderer *renderer, Render_Target *target) +typedef mac_render_sig(mac_render_type); + +#define mac_get_texture_sig(name) u32 name(Mac_Renderer *renderer, Vec3_i32 dim, Texture_Kind texture_kind) +typedef mac_get_texture_sig(mac_get_texture_type); + +#define mac_fill_texture_sig(name) b32 name(Mac_Renderer *renderer, Texture_Kind texture_kind, u32 texture, Vec3_i32 p, Vec3_i32 dim, void* data) +typedef mac_fill_texture_sig(mac_fill_texture_type); + +typedef i32 Mac_Renderer_Kind; +enum{ + MacRenderer_OpenGL, + MacRenderer_Metal, + // + MacRenderer_COUNT +}; + +struct Mac_Renderer{ + mac_render_type *render; + + mac_get_texture_type *get_texture; + mac_fill_texture_type *fill_texture; +}; + +//////////////////////////////// + +// NOTE(yuval): This is the actual platform dependent function that each renderer implementation implements and should be exported into a DLL +#define mac_load_renderer_sig(name) Mac_Renderer* name(NSWindow *window, Render_Target *target) +typedef mac_load_renderer_sig(mac_load_renderer_type); + +//////////////////////////////// + +#endif \ No newline at end of file diff --git a/platform_mac/mac_4ed_renderer.mm b/platform_mac/mac_4ed_renderer.mm new file mode 100644 index 00000000..7ad171b6 --- /dev/null +++ b/platform_mac/mac_4ed_renderer.mm @@ -0,0 +1,26 @@ +/* Mac Renderer Abstraction Implementation */ + +// TODO(yuval): This should NOT be included here once the renderer is exported to a DLL +#import "mac_4ed_opengl.mm" +#import "mac_4ed_metal.mm" + +// TODO(yuval): Replace this array with an array of the paths to the renderer dlls +global mac_load_renderer_type *mac_renderer_load_functions[MacRenderer_COUNT] = { + mac_load_opengl_renderer, + mac_load_metal_renderer +}; + +function Mac_Renderer* +mac_init_renderer(Mac_Renderer_Kind kind, NSWindow *window, Render_Target *target){ + // TODO(yuval): Import renderer load function from a DLL instead of using an array of the load functions. This would allow us to switch the renderer backend and implemented new backends with ease. + + mac_load_renderer_type *load_renderer = mac_renderer_load_functions[kind]; + Mac_Renderer *result = load_renderer(window, target); + + if (!result){ + mac_error_box("Unable to initialize the renderer!"); + } + + return result; +} + diff --git a/platform_mac/mac_objective_c_to_cpp_links.h b/platform_mac/mac_objective_c_to_cpp_links.h new file mode 100644 index 00000000..ab043fc1 --- /dev/null +++ b/platform_mac/mac_objective_c_to_cpp_links.h @@ -0,0 +1,24 @@ +/* Types and functions for communication between C++ and Objective-C layers. */ + +#if !defined(MAC_OBJECTIVE_C_TO_CPP_LINKS_H) +#define MAC_OBJECTIVE_C_TO_CPP_LINKS_H + +// In C++ layer +external String_Const_u8 +mac_SCu8(u8* str, u64 size); + +external String_Const_u8 +mac_push_string_copy(Arena *arena, String_Const_u8 src); + +external void +mac_init(); + +// In Objective-C layer +external String_Const_u8 +mac_standardize_path(Arena* arena, String_Const_u8 path); + +external i32 +mac_get_binary_path(void* buffer, u32 size); + +#endif + diff --git a/platform_mac/osx_objective_c_to_cpp_links.h b/platform_mac/osx_objective_c_to_cpp_links_old.h similarity index 100% rename from platform_mac/osx_objective_c_to_cpp_links.h rename to platform_mac/osx_objective_c_to_cpp_links_old.h diff --git a/platform_unix/unix_4ed_functions.cpp b/platform_unix/unix_4ed_functions.cpp index 75e121fb..d6fe65b7 100644 --- a/platform_unix/unix_4ed_functions.cpp +++ b/platform_unix/unix_4ed_functions.cpp @@ -64,7 +64,7 @@ Sys_Memory_Allocate_Sig(system_memory_allocate){ return(result); } -internal +internal Sys_Memory_Set_Protection_Sig(system_memory_set_protection){ bool32 result = true; diff --git a/platform_win32/win32_4ed.cpp b/platform_win32/win32_4ed.cpp index 0ed48a78..c83fe429 100644 --- a/platform_win32/win32_4ed.cpp +++ b/platform_win32/win32_4ed.cpp @@ -335,7 +335,7 @@ system_set_fullscreen_sig(){ internal system_is_fullscreen_sig(){ - // NOTE(allen): Report the fullscreen status as it would be set at the beginning of the + // NOTE(allen): Report the fullscreen status as it would be set at the beginning of the // next frame. That is, take into account all fullscreen toggle requests that have come in // already this frame. Read: "full_screen XOR do_toggle" b32 result = (win32vars.full_screen != win32vars.do_toggle); @@ -605,6 +605,9 @@ os_popup_error(char *title, char *message){ #include "4ed_font_provider_freetype.cpp" #include +#include "opengl/4ed_opengl_defines.h" +#define GL_FUNC(N,R,P) typedef R (CALL_CONVENTION N##_Function)P; N##_Function *N = 0; +#include "opengl/4ed_opengl_funcs.h" #include "opengl/4ed_opengl_render.cpp" internal @@ -640,6 +643,7 @@ win32_keycode_init(void){ keycode_lookup_table[VK_SPACE] = KeyCode_Space; keycode_lookup_table[VK_OEM_3] = KeyCode_Tick; keycode_lookup_table[VK_OEM_MINUS] = KeyCode_Minus; + keycode_lookup_table[VK_OEM_PLUS] = KeyCode_Equal; keycode_lookup_table[VK_OEM_4] = KeyCode_LeftBracket; keycode_lookup_table[VK_OEM_6] = KeyCode_RightBracket; keycode_lookup_table[VK_OEM_1] = KeyCode_Semicolon; @@ -1240,10 +1244,10 @@ win32_wgl_good(Void_Func *f){ f != (Void_Func*)-1); } -typedef HGLRC (wglCreateContextAttribsARB_Function)(HDC,HGLRC,i32*); -typedef BOOL (wglChoosePixelFormatARB_Function)(HDC,i32*,f32*,u32,i32*,u32*); -typedef char* (wglGetExtensionsStringEXT_Function)(); -typedef VOID (wglSwapIntervalEXT_Function)(i32); +typedef HGLRC (CALL_CONVENTION wglCreateContextAttribsARB_Function)(HDC,HGLRC,i32*); +typedef BOOL (CALL_CONVENTION wglChoosePixelFormatARB_Function)(HDC,i32*,f32*,u32,i32*,u32*); +typedef char* (CALL_CONVENTION wglGetExtensionsStringEXT_Function)(); +typedef VOID (CALL_CONVENTION wglSwapIntervalEXT_Function)(i32); global wglCreateContextAttribsARB_Function *wglCreateContextAttribsARB = 0; global wglChoosePixelFormatARB_Function *wglChoosePixelFormatARB = 0; @@ -1308,7 +1312,7 @@ win32_gl_create_window(HWND *wnd_out, HGLRC *context_out, DWORD style, RECT rect // NOTE(allen): Load wgl extensions #define LoadWGL(f,l) Stmnt((f) = (f##_Function*)wglGetProcAddress(#f); \ - (l) = (l) && win32_wgl_good((Void_Func*)(f));) +(l) = (l) && win32_wgl_good((Void_Func*)(f));) b32 load_success = true; LoadWGL(wglCreateContextAttribsARB, load_success); @@ -1413,10 +1417,10 @@ win32_gl_create_window(HWND *wnd_out, HGLRC *context_out, DWORD style, RECT rect /*0*/WGL_CONTEXT_MAJOR_VERSION_ARB, 3, /*2*/WGL_CONTEXT_MINOR_VERSION_ARB, 2, /*4*/WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB -#if GL_DEBUG_MODE - |WGL_CONTEXT_DEBUG_BIT_ARB -#endif - , + #if GL_DEBUG_MODE + |WGL_CONTEXT_DEBUG_BIT_ARB + #endif + , /*6*/WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, /*8*/0 }; diff --git a/platform_win32/win32_4ed_functions.cpp b/platform_win32/win32_4ed_functions.cpp index 8e139ea1..5e7533b3 100644 --- a/platform_win32/win32_4ed_functions.cpp +++ b/platform_win32/win32_4ed_functions.cpp @@ -444,7 +444,7 @@ color_picker_hook(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam){ // Would it have killed you to update rgbResult continuously, or at least // provide a GetCurrentColor() call??? // - // Anyway, since the color picker doesn't tell us when the color is + // Anyway, since the color picker doesn't tell us when the color is // changed, what we do is watch for messages that repaint the color // swatch, which is dialog id 0x2c5, and then we sample it to see what // color it is. No, I'm not fucking kidding, that's what we do. @@ -533,7 +533,7 @@ internal system_open_color_picker_sig(){ // TODO(allen): review // NOTE(casey): Because this is going to be used by a semi-permanent thread, we need to - // copy it to system memory where it can live as long as it wants, no matter what we do + // copy it to system memory where it can live as long as it wants, no matter what we do // over here on the 4coder threads. Color_Picker *perm = (Color_Picker*)system_memory_allocate(sizeof(Color_Picker), string_u8_litexpr(file_name_line_number)); *perm = *picker; diff --git a/project.4coder b/project.4coder index a4a31ba8..c5484349 100644 --- a/project.4coder +++ b/project.4coder @@ -6,6 +6,7 @@ patterns = { "*.cpp", "*.h", "*.m", +"*.mm", "*.bat", "*.sh", "*.4coder", @@ -25,21 +26,23 @@ load_paths = { build_x64_win32 = "echo build: x64 & bin\\build.bat"; build_x86_win32 = "echo build: x86 & bin\\build.bat /DDEV_BUILD_X86"; -build_x64_unix = "echo build: x64 & bin/build.sh"; -build_x86_unix = "echo build: x86 & bin/build.sh -DDEV_BUILD_X86"; +build_x64_linux = "echo build: x64 & bin/build.sh"; +build_x86_linux = "echo build: x86 & bin/build.sh -DDEV_BUILD_X86"; +build_x64_mac = "echo build: x64 & bin/build-mac.sh"; +build_x86_mac = "echo build: x86 & bin/build-mac.sh -DDEV_BUILD_X86"; command_list = { { .name = "build x64", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cmd = { {build_x64_win32, .os = "win" }, - {build_x64_unix , .os = "linux"}, - {build_x64_unix , .os = "mac" }, }, }, + {build_x64_linux, .os = "linux"}, + {build_x64_mac , .os = "mac" }, }, }, { .name = "build x86", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cmd = { {build_x86_win32, .os = "win" }, - {build_x86_unix , .os = "linux"}, - {build_x86_unix , .os = "mac" }, }, }, + {build_x86_linux, .os = "linux"}, + {build_x86_mac , .os = "mac" }, }, }, { .name = "package", .out = "*compilation*", .footer_panel = false, .save_dirty_files = true, @@ -49,11 +52,13 @@ command_list = { { .name = "run one time", .out = "*run*", .footer_panel = false, .save_dirty_files = false, - .cmd = { { "pushd ..\\build & one_time", .os = "win" }, }, }, + .cmd = { { "pushd ..\\build & one_time", .os = "win" }, + { "pushd ../build & one_time", .os = "mac" }, }, }, { .name = "build custom api docs", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, - .cmd = { { "custom\\bin\\build_one_time docs\\4ed_doc_custom_api_main.cpp ..\\build", .os = "win" }, }, }, + .cmd = { { "custom\\bin\\build_one_time docs\\4ed_doc_custom_api_main.cpp ..\\build", .os = "win" }, + { "custom/bin/build_one_time.sh docs/4ed_doc_custom_api_main.cpp ../build", .os = "mac" }, }, }, { .name = "build C++ lexer generator", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, diff --git a/ship_files/README.txt b/ship_files/README.txt index d01c6fe6..03441be9 100644 --- a/ship_files/README.txt +++ b/ship_files/README.txt @@ -6,9 +6,12 @@ https://github.com/4coder-editor/4coder/issues For questions email: editor@4coder.net +Sign up for the newsletter for the most critical 4coder news: +newsletter.4coder.net + Watch the 4coder.handmade.network blog and @AllenWebster4th twitter for news about 4coder. -For documentation, feature lists, and usage tutorial videos go to: +For documentation, feature lists, and more visit the home page: 4coder.net diff --git a/ship_files/changes.txt b/ship_files/changes.txt index cde4f694..2c0837b8 100644 --- a/ship_files/changes.txt +++ b/ship_files/changes.txt @@ -1,3 +1,43 @@ + +4.1.3 + + Unkillable buffer setting + + UI elements in listers and buttons can have different highlight backgrounds + + command 'load_theme_current_buffer' for loading the current file as a theme and setting it as the theme + + Fix: search and replace never exits early + + Fix: optimized builds of the custom layer display the dirty * on the file bar correclty + + Fix: can merge "backwards" strings in the history correctly + + Fix: the helper user_list_definition_array matches both LF and CRLF line endings + + Fix: line number background and text colors in the built in theme files + + Fix: a drive letter by itself is recognized as an existing path + + Fix: the margin colors for panels are determined by the margins in theme files + + Fix: when a file is deleted outside of 4coder, the '!' dirty status is added to the buffer + + Fix: on mac file changes outside of 4coder are detected and do not stall the UI + +4.1.2 + + Cursor color changes when recording macro if the theme provides a second cursor color + + Default custom layer now has a feature for supporting fade ranges as used in pasting and undoing + + Ability to "partially" paint text with a blend factor to create blends + + In file lister, typing a slash with a name for a folder that does not exist asks the user if they would like to create a folder + + Fix: parser in code index recognizes functions with more than one parameter + + Fix: trying to create a face with a font file that doesn't exist doesn't crash + + Fix: escaping command documentation lister doesn't crash + + Fix: lexer generator switched to new macro names Max and Min + + Fix: implementation for getting previous view iterates from null to the last view in order (instead of the first) + + Fix: auto-indent when a file with virtual whitespace is saved + + Fix: can create up to sixteen panels, and doesn't crash when trying to create more + + Fix: faster text range highlighting + + Fix: side by side editing a single buffer doesn't scroll the lower view down when insterting lines in the higher view + + Fix: indentation after paren group is correct + +4.1.1 + Changes not documented + +4.1.0 + Initial beta version + +************************************************** +************************************************** + New in alpha 4.0.30: -Mouse events (clicking, scroll wheel, mouse move) can now be bound with modifier keys -New and changed commands: diff --git a/ship_files/config.4coder b/ship_files/config.4coder index bfe0fc32..cbf71c6b 100644 --- a/ship_files/config.4coder +++ b/ship_files/config.4coder @@ -1,10 +1,9 @@ // Command Mapping -// "" - Leave the bindings unaltered from their startup value. +// "" - Leave the bindings unaltered. // "choose" - Ask 4coder to choose based on platform. // "default" - Use the default keybindings 4coder has always had. // "mac-default" - Use keybindings similar to those found in other Mac applications. -// - If you use the custom layer to make a named mapping you can use that here too. -mapping = ""; +mapping = "choose"; // MODE // "4coder" - The default 4coder mode that has been around since the beginning of time (2015) @@ -23,12 +22,9 @@ lister_whole_word_backspace_when_modified = false; show_line_number_margins = false; // Code Wrapping -treat_as_code = ".cpp.c.hpp.h.cc.cs.java.rs.glsl.m"; +treat_as_code = ".cpp.c.hpp.h.cc.cs.java.rs.glsl.m.mm"; enable_virtual_whitespace = true; enable_code_wrapping = true; -automatically_adjust_wrapping = true; -default_wrap_width = 672; -default_min_base_width = 550; // This only applies to code files in code-wrapping mode. // Plain text and code files without virtual-whitespace will not be effected. diff --git a/ship_files/themes/theme-4coder.4coder b/ship_files/themes/theme-4coder.4coder index ad8da31d..b60ec7b2 100644 --- a/ship_files/themes/theme-4coder.4coder +++ b/ship_files/themes/theme-4coder.4coder @@ -3,10 +3,10 @@ defcolor_back = 0xFF0C0C0C; defcolor_margin = 0xFF181818; defcolor_margin_hover = 0xFF252525; defcolor_margin_active = 0xFF323232; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFF00EE00; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFF00EE00, 0xFFEE7700}; defcolor_at_cursor = defcolor_back; defcolor_highlight_cursor_line = 0xFF1E1E1E; defcolor_highlight = 0xFFDDEE00; @@ -41,3 +41,6 @@ defcolor_pop2 = 0xFFFF0000; defcolor_back_cycle = {0x10A00000, 0x0C00A000, 0x0C0000A0, 0x0CA0A000}; defcolor_text_cycle = {0xFFA00000, 0xFF00A000, 0xFF0030B0, 0xFFA0A000}; + +defcolor_line_numbers_back = 0xFF101010; +defcolor_line_numbers_text = 0xFF404040; diff --git a/ship_files/themes/theme-handmade-hero.4coder b/ship_files/themes/theme-handmade-hero.4coder index 1a314b8d..2ede1758 100644 --- a/ship_files/themes/theme-handmade-hero.4coder +++ b/ship_files/themes/theme-handmade-hero.4coder @@ -4,10 +4,10 @@ defcolor_back = 0xFF161616; defcolor_margin = 0xFF262626; defcolor_margin_hover = 0xFF333333; defcolor_margin_active = 0xFF404040; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFF40FF40; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFF40FF40, 0xFFFF4040}; defcolor_at_cursor = defcolor_back; defcolor_highlight_cursor_line = 0xFF121E12; defcolor_highlight = 0xFF703419; @@ -43,6 +43,5 @@ defcolor_pop2 = 0xFFFF0000; defcolor_back_cycle = {0x0CA00000, 0x0800A000, 0x080000A0, 0x08A0A000}; defcolor_text_cycle = {0xFFA00000, 0xFF00A000, 0xFF0020B0, 0xFFA0A000}; - - - +defcolor_line_numbers_back = 0xFF202020; +defcolor_line_numbers_text = 0xFF484848; diff --git a/ship_files/themes/theme-hjortshoej.4coder b/ship_files/themes/theme-hjortshoej.4coder index d7709ee4..577cbf12 100644 --- a/ship_files/themes/theme-hjortshoej.4coder +++ b/ship_files/themes/theme-hjortshoej.4coder @@ -4,10 +4,10 @@ defcolor_back = 0xFFF0F0F0; defcolor_margin = 0xFF9E9E9E; defcolor_margin_hover = 0xFF7E7E7E; defcolor_margin_active = 0xFF5C5C5C; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFF000000; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFF000000, 0xFF008080}; defcolor_at_cursor = 0xFFD6D6D6; defcolor_highlight_cursor_line = 0xFFB8B098; defcolor_mark = 0xFF525252; @@ -42,3 +42,5 @@ defcolor_pop2 = 0xFFE80505; defcolor_back_cycle = {0x1CA00000, 0x1C00A000, 0x1C0000A0, 0x1CA0A000}; defcolor_text_cycle = {0xFFF01010, 0xFF20D020, 0xFF0000F0, 0xFFD0D000}; +defcolor_line_numbers_back = 0xFFD0D0D0; +defcolor_line_numbers_text = 0xFF404040; diff --git a/ship_files/themes/theme-midnight.4coder b/ship_files/themes/theme-midnight.4coder index e77a1e46..28e09dfd 100644 --- a/ship_files/themes/theme-midnight.4coder +++ b/ship_files/themes/theme-midnight.4coder @@ -3,10 +3,10 @@ defcolor_back = 0xFF202020; defcolor_margin = 0xFF383838; defcolor_margin_hover = 0xFF404040; defcolor_margin_active = 0xFF484848; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFFDDDDDD; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFFDDDDDD, 0xFFDD7777}; defcolor_at_cursor = defcolor_back; defcolor_highlight_cursor_line = 0xFF383838; defcolor_mark = 0xFF808080; @@ -40,3 +40,6 @@ defcolor_pop2 = 0xFFFF3A00; defcolor_back_cycle = {0x08A00000, 0x0800A000, 0x080000A0, 0x08A0A000}; defcolor_text_cycle = {0xFFF01010, 0xFF20D020, 0xFF0080E0, 0xFFD0D000}; + +defcolor_line_numbers_back = 0xFF383838; +defcolor_line_numbers_text = 0xFF686860; diff --git a/ship_files/themes/theme-stb-dark.4coder b/ship_files/themes/theme-stb-dark.4coder index c52c1728..a5b0b9f5 100644 --- a/ship_files/themes/theme-stb-dark.4coder +++ b/ship_files/themes/theme-stb-dark.4coder @@ -3,10 +3,10 @@ defcolor_back = 0xFF303030; defcolor_margin = 0xFF383838; defcolor_margin_hover = 0xFF404040; defcolor_margin_active = 0xFF484848; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFFDDDDDD; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFFDDDDDD, 0xFFDDF0F0}; defcolor_at_cursor = defcolor_back; defcolor_highlight_cursor_line = 0xFF383838; defcolor_mark = 0xFF808080; @@ -40,3 +40,6 @@ defcolor_pop2 = 0xFFFF3A00; defcolor_back_cycle = {0x06A00000, 0x0600A000, 0x060000A0, 0x06A0A000}; defcolor_text_cycle = {0xFFAA0A0A, 0xFF149014, 0xFF0060A8, 0xFF909000}; + +defcolor_line_numbers_back = 0xFF808080; +defcolor_line_numbers_text = 0xFF303030; diff --git a/ship_files/themes/theme-stb.4coder b/ship_files/themes/theme-stb.4coder index b8c0fc00..9c6e9556 100644 --- a/ship_files/themes/theme-stb.4coder +++ b/ship_files/themes/theme-stb.4coder @@ -3,10 +3,10 @@ defcolor_back = 0xFFD6D6D6; defcolor_margin = 0xFF9E9E9E; defcolor_margin_hover = 0xFF7E7E7E; defcolor_margin_active = 0xFF5C5C5C; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFF000000; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFF000000, 0xFF002020}; defcolor_at_cursor = defcolor_back; defcolor_highlight_cursor_line = 0xFFBCBCBC; defcolor_mark = 0xFF525252; @@ -41,3 +41,5 @@ defcolor_pop2 = 0xFFE80505; defcolor_back_cycle = {0x10A00000, 0x1000A000, 0x100000A0, 0x10A0A000}; defcolor_text_cycle = {0xFFA00000, 0xFF00A000, 0xFF0000A0, 0xFFA0A000}; +defcolor_line_numbers_back = 0xFF808080; +defcolor_line_numbers_text = 0xFFD6D6D6; diff --git a/ship_files/themes/theme-strange.4coder b/ship_files/themes/theme-strange.4coder index b98b5d15..ffc1b76f 100644 --- a/ship_files/themes/theme-strange.4coder +++ b/ship_files/themes/theme-strange.4coder @@ -4,10 +4,10 @@ defcolor_back = 0xFF161616; defcolor_margin = 0xFF606590; defcolor_margin_hover = 0xFF606590; defcolor_margin_active = 0xFF9A99E7; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFFd96e26; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFFd96e26, 0xFFd9d926}; defcolor_at_cursor = defcolor_back; defcolor_highlight_cursor_line = 0xFF002222; defcolor_mark = 0xFF808080; @@ -42,3 +42,5 @@ defcolor_pop2 = 0xFFFF0000; defcolor_back_cycle = {0x0CA00000, 0x0C00A000, 0x0C0000A0, 0x0CA0A000}; defcolor_text_cycle = {0xFFF00000, 0xFF00F000, 0xFF0080F0, 0xFFF0F000}; +defcolor_line_numbers_back = 0xFF262626; +defcolor_line_numbers_text = 0xFF8880C0; diff --git a/ship_files/themes/theme-sunlight.4coder b/ship_files/themes/theme-sunlight.4coder index dd74810e..ccb1cd6f 100644 --- a/ship_files/themes/theme-sunlight.4coder +++ b/ship_files/themes/theme-sunlight.4coder @@ -3,10 +3,10 @@ defcolor_back = 0xFFDFD5D0; defcolor_margin = 0xFFC7C7C7; defcolor_margin_hover = 0xFFBFBFBF; defcolor_margin_active = 0xFFB7B7B7; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFF222222; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFF222222, 0xFF442244}; defcolor_at_cursor = defcolor_back; defcolor_highlight_cursor_line = 0xFFC7C7C7; defcolor_mark = 0xFF797979; @@ -40,3 +40,6 @@ defcolor_pop2 = 0xFF00C5FF; defcolor_back_cycle = {0x14A00000, 0x1400A000, 0x140000A0, 0x14A0A000}; defcolor_text_cycle = {0xFFF00000, 0xFF00C030, 0xFF0000F0, 0xFFF0F000}; + +defcolor_line_numbers_back = 0xFFC7C7C7; +defcolor_line_numbers_text = 0xFF87878F; diff --git a/ship_files/themes/theme-twilight.4coder b/ship_files/themes/theme-twilight.4coder index 95a53d5d..11f8d305 100644 --- a/ship_files/themes/theme-twilight.4coder +++ b/ship_files/themes/theme-twilight.4coder @@ -3,12 +3,12 @@ defcolor_back = 0xFF090D12; defcolor_margin = 0xFF1A2634; defcolor_margin_hover = 0xFF2D415B; defcolor_margin_active = 0xFF405D82; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFFEEE800; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFFEEE800, 0xFFEE00E8}; defcolor_at_cursor = defcolor_back; -defcolor_highlight_cursor_line = 0xFF151F2A; +defcolor_highlight_cursor_line = 0xFF1A2634; defcolor_mark = 0xFF8BA8CC; defcolor_highlight = 0xFF037A7B; defcolor_at_highlight = defcolor_back; @@ -40,3 +40,6 @@ defcolor_pop2 = 0xFFFF200D; defcolor_back_cycle = {0x0EA00000, 0x0D00A000, 0x0D0000A0, 0x0EA0A000}; defcolor_text_cycle = {0xFFF00000, 0xFF00C030, 0xFF0040F0, 0xFFB0B000}; + +defcolor_line_numbers_back = 0xFF1A2634; +defcolor_line_numbers_text = 0xFF6F817E; diff --git a/ship_files/themes/theme-wombat.4coder b/ship_files/themes/theme-wombat.4coder index 2f5e2dc7..ee927d23 100644 --- a/ship_files/themes/theme-wombat.4coder +++ b/ship_files/themes/theme-wombat.4coder @@ -4,10 +4,10 @@ defcolor_back = 0xFF242424; defcolor_margin = 0xFF181818; defcolor_margin_hover = 0xFF252525; defcolor_margin_active = 0xFF323232; -defcolor_list_item = defcolor_margin; -defcolor_list_item_hover = defcolor_margin_hover; -defcolor_list_item_active = defcolor_margin_active; -defcolor_cursor = 0xFF656565; +defcolor_list_item = {defcolor_margin, defcolor_back}; +defcolor_list_item_hover = {defcolor_margin_hover, defcolor_margin}; +defcolor_list_item_active = {defcolor_margin_active, defcolor_margin_active}; +defcolor_cursor = {0xFF656565, 0xFF654065}; defcolor_highlight = 0xFF636066; defcolor_mark = defcolor_cursor; defcolor_text_default = 0xFFe3e0d7; @@ -42,3 +42,6 @@ defcolor_pop2 = defcolor_highlight_junk; defcolor_back_cycle = {0x10A00000, 0x0C00A000, 0x0C0000A0, 0x0CA0A000}; defcolor_text_cycle = {0xFFA00000, 0xFF00A000, 0xFF0030B8, 0xFFA0A000}; + +defcolor_line_numbers_back = 0xFF202020; +defcolor_line_numbers_text = 0xFF737067; diff --git a/ship_files_super/project.4coder b/ship_files_super/project.4coder index b976c45d..261a97f0 100644 --- a/ship_files_super/project.4coder +++ b/ship_files_super/project.4coder @@ -6,6 +6,7 @@ patterns = { "*.cpp", "*.h", "*.m", +"*.mm", "*.bat", "*.sh", "*.4coder", diff --git a/site/4ed_site_render_main.cpp b/site/4ed_site_render_main.cpp index 532f5f3f..3da30516 100644 --- a/site/4ed_site_render_main.cpp +++ b/site/4ed_site_render_main.cpp @@ -33,6 +33,7 @@ #define MAP_METADATA_ONLY 1 #include "4coder_command_map.cpp" #include "4coder_default_map.cpp" +#include "4coder_mac_map.cpp" #include "generated/custom_api_constructor.cpp" #include "../docs/4ed_doc_custom_api.cpp" #include "4coder_doc_commands.cpp" @@ -151,7 +152,7 @@ render_doc_page_to_html__code(Arena *scratch, Doc_Code_Sample_List *code, FILE * "", string_expand(node->contents)); if (node->next != 0){ - fprintf(out, "
\n"); + fprintf(out, "
\n"); } } } @@ -170,7 +171,7 @@ render_doc_page_to_html__table(Arena *scratch, Vec2_i32 dim, Doc_Content_List *v } fprintf(out, ""); } - fprintf(out, ""); + fprintf(out, ""); } function void @@ -313,11 +314,11 @@ render_doc_cluster_to_html(Arena *scratch, Doc_Cluster *cluster, fprintf(file, html_footer); } -{ + { Temp_Memory_Block temp(scratch); fprintf(file_index, html_header, string_expand(cluster->title)); - + Doc_Page **ptrs = push_array(scratch, Doc_Page*, cluster->page_count); i32 counter = 0; for (Doc_Page *node = cluster->first_page; @@ -340,19 +341,19 @@ render_doc_cluster_to_html(Arena *scratch, Doc_Cluster *cluster, fprintf(file_index, "
\n"); fprintf(file_index, ""); - fprintf(file_index, "
\n"); - - fprintf(file_index, "
"); - - fprintf(file_index, "
    \n"); - for (i32 i = 0; i < counter; i += 1){ - Doc_Page *node = ptrs[i]; + "placeholder=\"Filter...\" title=\"Filter...\">"); + fprintf(file_index, "
    \n"); + + fprintf(file_index, "
    "); + + fprintf(file_index, "
      \n"); + for (i32 i = 0; i < counter; i += 1){ + Doc_Page *node = ptrs[i]; fprintf(file_index, "
    • %.*s
    • ", - string_expand(node->name), - string_expand(node->name)); - } - fprintf(file_index, "
    \n"); + string_expand(node->name), + string_expand(node->name)); + } + fprintf(file_index, "
\n"); fprintf(file_index, "
\n"); fprintf(file_index, "\n"); @@ -374,8 +375,8 @@ render_doc_cluster_to_html(Arena *scratch, Doc_Cluster *cluster, } } - fprintf(file_index, html_footer); -} + fprintf(file_index, html_footer); + } } function void @@ -421,33 +422,49 @@ int main(){ String_Const_u8 root = string_prefix(self, code_pos + 5); String_Const_u8 outside_root = string_prefix(self, code_pos); String_Const_u8 build_root = push_u8_stringf(&arena, "%.*sbuild/", - string_expand(outside_root)); + string_expand(outside_root)); String_Const_u8 site_root = push_u8_stringf(&arena, "%.*ssite/", - string_expand(build_root)); + string_expand(build_root)); String_Const_u8 docs_root = push_u8_stringf(&arena, "%.*sdocs/", string_expand(site_root)); (void)root; - Mapping mapping = {}; - mapping_init(tctx, &mapping); - setup_default_mapping(&mapping, 1, 2, 3); + i64 global_id = 1; + i64 file_id = 2; + i64 code_id = 3; + + local_const i32 map_count = 2; + Mapping mapping_array[map_count] = {}; + char *page_tiles[map_count] = {}; + char *page_names[map_count] = {}; + + mapping_init(tctx, &mapping_array[0]); + setup_default_mapping(&mapping_array[0], global_id, file_id, code_id); + page_tiles[0] = "Default Bindings"; + page_names[0] = "default_bindings"; + + mapping_init(tctx, &mapping_array[1]); + setup_mac_mapping(&mapping_array[1], global_id, file_id, code_id); + page_tiles[1] = "Default Mac Bindings"; + page_names[1] = "default_mac_bindings"; API_Definition *api_def = custom_api_construct(&arena); Doc_Cluster *cluster_array[] = { doc_custom_api(&arena, api_def), doc_commands(&arena), - doc_default_bindings(&arena, &mapping, 1, 2, 3), + doc_default_bindings(&arena, map_count, mapping_array, page_tiles, page_names, + global_id, file_id, code_id), }; for (i32 i = 0; i < ArrayCount(cluster_array); i += 1){ Doc_Cluster *cluster = cluster_array[i]; for (Doc_Page *node = cluster->first_page; - node != 0; + node != 0; node = node->next){ render_doc_page_to_html(&arena, node, docs_root); - } - render_doc_cluster_to_html(&arena, cluster, docs_root); + } + render_doc_cluster_to_html(&arena, cluster, docs_root); } return(0); diff --git a/site/static/home.html b/site/static/home.html index cd63187e..08a954a7 100644 --- a/site/static/home.html +++ b/site/static/home.html @@ -37,10 +37,6 @@ li.firstli { margin-top: 0px; } -table.normal tr { - -} - .normal a:link, a:link { color: #D08F20; } @@ -81,6 +77,16 @@ table.normal tr { text-align: left; } +.normal table { + border-spacing: 0; +} + +.normal td { + font-size: 1.25em; + color: #90B080; + padding-right: .6em; +} + .comment { margin-left: 14px; margin-right: 14px; @@ -165,11 +171,22 @@ table.normal tr {