diff --git a/4ed.cpp b/4ed.cpp index 155c53a5..78818d9c 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1,839 +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->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 - +/* + * 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 5829cd27..5cbb28de 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -531,8 +531,8 @@ buffer_padded_box_of_pos(Application_Links *app, Buffer_ID buffer_id, f32 width, 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); + layout_func, width, face, + base_line, pos); } } return(result); @@ -1706,23 +1706,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; @@ -2019,7 +2002,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 } @@ -2418,7 +2401,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); @@ -2861,10 +2844,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); @@ -3022,13 +3005,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_file.h b/4ed_file.h index 1eb82013..8844aad7 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; @@ -62,8 +53,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_layout.cpp b/4ed_layout.cpp index e64c12da..fd493dee 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -289,7 +289,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_view.cpp b/4ed_view.cpp index 1d5a2e0b..3a25ea21 100644 --- a/4ed_view.cpp +++ b/4ed_view.cpp @@ -236,13 +236,13 @@ view_relative_xy_of_pos(Thread_Context *tctx, Models *models, View *view, function Rect_f32 view_padded_box_of_pos(Thread_Context *tctx, Models *models, View *view, - i64 base_line, i64 pos){ + 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)); + layout_func, width, face, base_line, pos)); } internal Buffer_Point @@ -441,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 @@ -529,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/custom/4coder_clipboard.cpp b/custom/4coder_clipboard.cpp index fdb44353..ba37ad61 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); @@ -61,9 +61,8 @@ CUSTOM_DOC("At the cursor, insert the text at the top of the clipboard.") view_set_mark(app, view, seek_pos(pos)); view_set_cursor_and_preferred_x(app, view, seek_pos(pos + (i32)string.size)); - // 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); + buffer_post_fade(app, buffer, 0.667f, Ii64_size(pos, string.size), argb); } } } @@ -99,7 +98,7 @@ CUSTOM_DOC("If the previous command was paste or paste_next, replaces the paste 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); + buffer_post_fade(app, buffer, 0.667f, Ii64_size(pos, string.size), argb); } else{ paste(app); @@ -150,9 +149,7 @@ CUSTOM_COMMAND_SIG(multi_paste){ 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); + view_post_fade(app, buffer, 0.667f, Ii64(range.max + 1, range.max + insert_string.size), argb); } else{ paste(app); @@ -207,9 +204,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_default_bindings.cpp b/custom/4coder_default_bindings.cpp index 8d926fa4..fb2f4a03 100644 --- a/custom/4coder_default_bindings.cpp +++ b/custom/4coder_default_bindings.cpp @@ -8,7 +8,11 @@ #define FCODER_DEFAULT_BINDINGS_CPP #include "4coder_default_include.cpp" + +// NOTE(allen): Users can declare their own managed IDs here. + #include "4coder_default_map.cpp" +#include "generated/managed_id_metadata.cpp" void custom_layer_init(Application_Links *app){ diff --git a/custom/4coder_default_framework.cpp b/custom/4coder_default_framework.cpp index c4acc753..28588d3a 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,13 @@ 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 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)); #undef M #if 0 @@ -529,6 +529,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 +689,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 859143ff..eebdbfb6 100644 --- a/custom/4coder_default_framework_variables.cpp +++ b/custom/4coder_default_framework_variables.cpp @@ -91,5 +91,12 @@ 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 3824ca00..2444afe1 100644 --- a/custom/4coder_default_hooks.cpp +++ b/custom/4coder_default_hooks.cpp @@ -1,1152 +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; - 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(); -} - -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){ - 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 - +/* +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..51ee72b2 100644 --- a/custom/4coder_default_include.cpp +++ b/custom/4coder_default_include.cpp @@ -118,8 +118,6 @@ #include "4coder_default_hooks.cpp" -#include "generated/managed_id_metadata.cpp" - #endif // BOTTOM diff --git a/custom/4coder_draw.cpp b/custom/4coder_draw.cpp index 006bbd31..2f719f74 100644 --- a/custom/4coder_draw.cpp +++ b/custom/4coder_draw.cpp @@ -1,854 +1,849 @@ -/* -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 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; - } - - 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_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); + } +} + +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 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; + } + + 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 + diff --git a/custom/4coder_lists.cpp b/custom/4coder_lists.cpp index 27a15d89..ab7593bf 100644 --- a/custom/4coder_lists.cpp +++ b/custom/4coder_lists.cpp @@ -710,8 +710,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; diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index ebda7adb..1c461ef6 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -274,7 +274,7 @@ static Command_Metadata fcoder_metacmd_table[229] = { { PROC_LINKS(close_build_panel, 0), false, "close_build_panel", 17, "If the special build panel is open, closes it.", 46, "w:\\4ed\\code\\custom\\4coder_build_commands.cpp", 44, 180 }, { PROC_LINKS(close_panel, 0), false, "close_panel", 11, "Closes the currently active panel if it is not the only panel open.", 67, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 619 }, { 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, "w:\\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, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 754 }, +{ PROC_LINKS(command_lister, 0), true, "command_lister", 14, "Opens an interactive list of all registered commands.", 53, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 753 }, { PROC_LINKS(comment_line, 0), false, "comment_line", 12, "Insert '//' at the beginning of the line after leading whitespace.", 66, "w:\\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, "w:\\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, "w:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 19 }, @@ -390,9 +390,9 @@ static Command_Metadata fcoder_metacmd_table[229] = { { 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, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 372 }, { 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, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 364 }, { PROC_LINKS(paste, 0), false, "paste", 5, "At the cursor, insert the text at the top of the clipboard.", 59, "w:\\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, "w:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 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, "w:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 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, "w:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 117 }, +{ 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, "w:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 109 }, +{ 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, "w:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 70 }, +{ 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, "w:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 116 }, { 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, "w:\\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, "w:\\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, "w:\\4ed\\code\\custom\\4coder_profile.cpp", 37, 219 }, @@ -448,7 +448,7 @@ static Command_Metadata fcoder_metacmd_table[229] = { { PROC_LINKS(snippet_lister, 0), true, "snippet_lister", 14, "Opens a snippet lister for inserting whole pre-written snippets of text.", 72, "w:\\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, "w:\\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, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1513 }, -{ PROC_LINKS(theme_lister, 0), true, "theme_lister", 12, "Opens an interactive list of all registered themes.", 51, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 778 }, +{ PROC_LINKS(theme_lister, 0), true, "theme_lister", 12, "Opens an interactive list of all registered themes.", 51, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 777 }, { 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, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 563 }, { 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, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 550 }, { PROC_LINKS(toggle_filebar, 0), false, "toggle_filebar", 14, "Toggles the visibility status of the current view's filebar.", 60, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 656 }, diff --git a/custom/generated/custom_api.cpp b/custom/generated/custom_api.cpp index 0aef628d..653783c8 100644 --- a/custom/generated/custom_api.cpp +++ b/custom/generated/custom_api.cpp @@ -92,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; @@ -170,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; @@ -273,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; @@ -351,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 178479d4..7e65493a 100644 --- a/custom/generated/custom_api.h +++ b/custom/generated/custom_api.h @@ -90,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) @@ -168,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) @@ -267,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); @@ -345,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); @@ -445,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; @@ -523,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; @@ -624,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); @@ -702,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); @@ -803,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; @@ -881,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_master_list.h b/custom/generated/custom_api_master_list.h index 97617c5e..60e06631 100644 --- a/custom/generated/custom_api_master_list.h +++ b/custom/generated/custom_api_master_list.h @@ -90,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); @@ -168,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/docs/4ed_doc_custom_api_view.cpp b/docs/4ed_doc_custom_api_view.cpp index 37c3bde5..b34f867f 100644 --- a/docs/4ed_doc_custom_api_view.cpp +++ b/docs/4ed_doc_custom_api_view.cpp @@ -915,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");