diff --git a/4ed.cpp b/4ed.cpp index afaf03fe..baf3dfbf 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1,891 +1,891 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.12.2014 - * - * Application layer for project codename "4ed" - * - */ - -// TOP - -internal void -fill_hardcode_default_style(Color_Table color_table){ - color_table.vals[Stag_Back] = 0xFF0C0C0C; - color_table.vals[Stag_Margin] = 0xFF181818; - color_table.vals[Stag_Margin_Hover] = 0xFF252525; - color_table.vals[Stag_Margin_Active] = 0xFF323232; - color_table.vals[Stag_List_Item] = color_table.vals[Stag_Margin]; - color_table.vals[Stag_List_Item_Hover] = color_table.vals[Stag_Margin_Hover]; - color_table.vals[Stag_List_Item_Active] = color_table.vals[Stag_Margin_Active]; - color_table.vals[Stag_Cursor] = 0xFF00EE00; - color_table.vals[Stag_Highlight] = 0xFFDDEE00; - color_table.vals[Stag_Mark] = 0xFF494949; - color_table.vals[Stag_Default] = 0xFF90B080; - color_table.vals[Stag_At_Cursor] = color_table.vals[Stag_Back]; - color_table.vals[Stag_Highlight_Cursor_Line] = 0xFF1E1E1E; - color_table.vals[Stag_At_Highlight] = 0xFFFF44DD; - color_table.vals[Stag_Comment] = 0xFF2090F0; - color_table.vals[Stag_Keyword] = 0xFFD08F20; - color_table.vals[Stag_Str_Constant] = 0xFF50FF30; - color_table.vals[Stag_Char_Constant] = color_table.vals[Stag_Str_Constant]; - color_table.vals[Stag_Int_Constant] = color_table.vals[Stag_Str_Constant]; - color_table.vals[Stag_Float_Constant] = color_table.vals[Stag_Str_Constant]; - color_table.vals[Stag_Bool_Constant] = color_table.vals[Stag_Str_Constant]; - color_table.vals[Stag_Include] = color_table.vals[Stag_Str_Constant]; - color_table.vals[Stag_Preproc] = color_table.vals[Stag_Default]; - color_table.vals[Stag_Special_Character] = 0xFFFF0000; - color_table.vals[Stag_Ghost_Character] = color_blend(color_table.vals[Stag_Default], 0.5f, color_table.vals[Stag_Back]); - - color_table.vals[Stag_Paste] = 0xFFDDEE00; - color_table.vals[Stag_Undo] = 0xFF00DDEE; - - color_table.vals[Stag_Highlight_Junk] = 0xff3a0000; - color_table.vals[Stag_Highlight_White] = 0xff003a3a; - - color_table.vals[Stag_Bar] = 0xFF888888; - color_table.vals[Stag_Base] = 0xFF000000; - color_table.vals[Stag_Pop1] = 0xFF3C57DC; - color_table.vals[Stag_Pop2] = 0xFFFF0000; - - color_table.vals[Stag_Back_Cycle_1] = 0x10A00000; - color_table.vals[Stag_Back_Cycle_2] = 0x0C00A000; - color_table.vals[Stag_Back_Cycle_3] = 0x0C0000A0; - color_table.vals[Stag_Back_Cycle_4] = 0x0CA0A000; - color_table.vals[Stag_Text_Cycle_1] = 0xFFA00000; - color_table.vals[Stag_Text_Cycle_2] = 0xFF00A000; - color_table.vals[Stag_Text_Cycle_3] = 0xFF0030B0; - color_table.vals[Stag_Text_Cycle_4] = 0xFFA0A000; - - color_table.vals[Stag_Line_Numbers_Back] = 0xFF101010; - color_table.vals[Stag_Line_Numbers_Text] = 0xFF404040; -} - -internal void -app_hardcode_default_style(Models *models){ - Color_Table color_table = {}; - color_table.count = Stag_COUNT; - color_table.vals = push_array(models->arena, u32, color_table.count); - fill_hardcode_default_style(color_table); - models->fallback_color_table = color_table; -} - -internal void -init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, i32 argc, char **argv){ - char *arg = 0; - Command_Line_Mode mode = CLMode_App; - Command_Line_Action action = CLAct_Nothing; - b32 strict = false; - - settings->init_files_max = ArrayCount(settings->init_files); - for (i32 i = 1; i <= argc; ++i){ - if (i == argc){ - arg = ""; - } - else{ - arg = argv[i]; - } - - if (arg[0] == '-' && arg[1] == '-'){ - char *long_arg_name = arg+2; - if (string_match(SCu8(long_arg_name), string_u8_litexpr("custom"))){ - mode = CLMode_Custom; - continue; - } - } - - switch (mode){ - case CLMode_App: - { - switch (action){ - case CLAct_Nothing: - { - if (arg[0] == '-'){ - action = CLAct_Ignore; - switch (arg[1]){ - case 'd': action = CLAct_CustomDLL; strict = false; break; - case 'D': action = CLAct_CustomDLL; strict = true; break; - - case 'i': action = CLAct_InitialFilePosition; break; - - case 'w': action = CLAct_WindowSize; break; - case 'W': action = CLAct_WindowMaximize; break; - case 'p': action = CLAct_WindowPosition; break; - case 'F': action = CLAct_WindowFullscreen; break; - - case 'f': action = CLAct_FontSize; break; - case 'h': action = CLAct_FontUseHinting; --i; break; - } - } - else if (arg[0] != 0){ - if (settings->init_files_count < settings->init_files_max){ - i32 index = settings->init_files_count++; - settings->init_files[index] = arg; - } - } - }break; - - case CLAct_CustomDLL: - { - plat_settings->custom_dll_is_strict = (b8)strict; - if (i < argc){ - plat_settings->custom_dll = argv[i]; - } - action = CLAct_Nothing; - }break; - - case CLAct_InitialFilePosition: - { - if (i < argc){ - settings->initial_line = (i32)string_to_integer(SCu8(argv[i]), 10); - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowSize: - { - if (i + 1 < argc){ - plat_settings->set_window_size = true; - - i32 w = (i32)string_to_integer(SCu8(argv[i]), 10); - i32 h = (i32)string_to_integer(SCu8(argv[i + 1]), 10); - if (w > 0){ - plat_settings->window_w = w; - } - if (h > 0){ - plat_settings->window_h = h; - } - - ++i; - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowMaximize: - { - --i; - plat_settings->maximize_window = true; - action = CLAct_Nothing; - }break; - - case CLAct_WindowPosition: - { - if (i + 1 < argc){ - plat_settings->set_window_pos = true; - - i32 x = (i32)string_to_integer(SCu8(argv[i]), 10); - i32 y = (i32)string_to_integer(SCu8(argv[i + 1]), 10); - if (x > 0){ - plat_settings->window_x = x; - } - if (y > 0){ - plat_settings->window_y = y; - } - - ++i; - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowFullscreen: - { - --i; - plat_settings->fullscreen_window = true; - action = CLAct_Nothing; - }break; - - case CLAct_FontSize: - { - if (i < argc){ - settings->font_size = (i32)string_to_integer(SCu8(argv[i]), 10); - } - action = CLAct_Nothing; - }break; - - case CLAct_FontUseHinting: - { - plat_settings->use_hinting = true; - settings->use_hinting = plat_settings->use_hinting; - action = CLAct_Nothing; - }break; - } - }break; - - case CLMode_Custom: - { - settings->custom_flags = argv + i; - settings->custom_flags_count = argc - i; - i = argc; - mode = CLMode_App; - }break; - } - } -} - -//////////////////////////////// - -internal Models* -models_init(void){ - Arena arena = make_arena_system(); - Models *models = push_array_zero(&arena, Models, 1); - models->arena_ = arena; - models->arena = &models->arena_; - heap_init(&models->heap, get_base_allocator_system()); - return(models); -} - -internal void -app_load_vtables(API_VTable_system *vtable_system, API_VTable_font *vtable_font, API_VTable_graphics *vtable_graphics){ - system_api_read_vtable(vtable_system); - font_api_read_vtable(vtable_font); - graphics_api_read_vtable(vtable_graphics); -} - -internal Log_Function* -app_get_logger(void){ - log_init(); - return(log_string); -} - -App_Read_Command_Line_Sig(app_read_command_line){ - Models *models = models_init(); - App_Settings *settings = &models->settings; - block_zero_struct(settings); - if (argc > 1){ - init_command_line_settings(&models->settings, plat_settings, argc, argv); - } - *files = models->settings.init_files; - *file_count = &models->settings.init_files_count; - return(models); -} - -App_Init_Sig(app_init){ - Models *models = (Models*)base_ptr; - models->keep_playing = true; - - models->config_api = api; - - profile_init(&models->profile_list); - - 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); - - Application_Links app = {}; - app.tctx = tctx; - app.cmd_context = models; - custom_init(&app); - - // 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; - } - } - - managed_ids_init(tctx->allocator, &models->managed_id_set); - 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 - { - Face_Description description = {}; - description.font.file_name = string_u8_litexpr("liberation-mono.ttf"); - description.font.in_4coder_font_folder = true; - description.parameters.pt_size = 12; - Face *new_face = font_set_new_face(&models->font_set, &description); - models->global_face_id = new_face->id; - } - app_hardcode_default_style(models); - - // 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): 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 , }, - }; - - 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); - } - - // 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(); -} - -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; - } - } - - if (input_node == 0){ - break; - } - input_node_next = input_node->next; - - b32 event_was_handled = false; - Input_Event *event = &input_node->event; - - if (event->kind == InputEventKind_TextInsert && event->text.blocked){ - continue; - } - - 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; - } - } - } - - // NOTE(allen): send panel size update - if (models->layout.panel_state_dirty){ - models->layout.panel_state_dirty = false; - if (models->buffer_viewer_update != 0){ - Application_Links app = {}; - app.tctx = tctx; - app.cmd_context = models; - models->buffer_viewer_update(&app); - } - } - - // NOTE(allen): dt - f32 literal_dt = 0.f; - u64 now_usecond_stamp = system_now_time(); - if (!input->first_step){ - u64 elapsed_useconds = now_usecond_stamp - models->last_render_usecond_stamp; - literal_dt = (f32)((f64)(elapsed_useconds)/1000000.f); - } - models->last_render_usecond_stamp = now_usecond_stamp; - f32 animation_dt = 0.f; - if (models->animated_last_frame){ - animation_dt = literal_dt; - } - - // NOTE(allen): on the first frame there should be no scrolling - if (input->first_step){ - for (Panel *panel = layout_get_first_open_panel(layout); - panel != 0; - panel = layout_get_next_open_panel(layout, panel)){ - View *view = panel->view; - File_Edit_Positions edit_pos = view_get_edit_pos(view); - edit_pos.scroll.position = view_normalize_buffer_point(tctx, models, view, edit_pos.scroll.target); - block_zero_struct(&edit_pos.scroll.target); - view_set_edit_pos(view, edit_pos); - } - } - - // NOTE(allen): hook for files reloaded - { - Working_Set *working_set = &models->working_set; - Assert(working_set->has_external_mod_sentinel.next != 0); - if (working_set->has_external_mod_sentinel.next != &working_set->has_external_mod_sentinel){ - for (Node *node = working_set->has_external_mod_sentinel.next, *next = 0; - node != &working_set->has_external_mod_sentinel; - node = next){ - next = node->next; - Editing_File *file = CastFromMember(Editing_File, external_mod_node, node); - dll_remove(node); - block_zero_struct(node); - co_send_core_event(tctx, models, CoreCode_FileExternallyModified, file->id); - } - } - } - - // NOTE(allen): if the exit signal has been sent, run the exit hook. - if (input->trying_to_kill){ - models->keep_playing = false; - } - if (!models->keep_playing){ - if (co_send_core_event(tctx, models, CoreCode_TryExit)){ - models->keep_playing = true; - } - } - - // NOTE(allen): rendering - { - Frame_Info frame = {}; - frame.index = models->frame_counter; - frame.literal_dt = literal_dt; - frame.animation_dt = animation_dt; - - { - Color_Table color_table = models->fallback_color_table; -#if 0 - if (models->modify_color_table != 0){ - color_table = models->modify_color_table(&models->app_links, frame); - if (color_table.count < models->fallback_color_table.count){ - block_copy(models->fallback_color_table.vals, color_table.vals, color_table.count*sizeof(*color_table.vals)); - color_table = models->fallback_color_table; - } - } -#endif - models->color_table = color_table; - } - - Application_Links app = {}; - app.tctx = tctx; - app.cmd_context = models; - - if (models->tick != 0){ - models->tick(&app, frame); - } - - begin_render_section(target, models->frame_counter, literal_dt, animation_dt); - models->in_render_mode = true; - - Live_Views *live_views = &models->view_set; - for (Node *node = layout->open_panels.next; - node != &layout->open_panels; - node = node->next){ - Panel *panel = CastFromMember(Panel, node, node); - View *view = panel->view; - View_Context_Node *ctx = view->ctx; - if (ctx != 0){ - Render_Caller_Function *render_caller = ctx->ctx.render_caller; - if (render_caller != 0){ - render_caller(&app, frame, view_get_id(live_views, view)); - } - } - } - - models->in_render_mode = false; - end_render_section(target); - } - - // NOTE(allen): flush the log - log_flush(tctx, models); - - // NOTE(allen): set the app_result - Application_Step_Result app_result = {}; - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; - app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; - - // NOTE(allen): get new window title - if (models->has_new_title){ - models->has_new_title = false; - app_result.has_new_title = true; - app_result.title_string = models->title_space; - } - - // NOTE(allen): get cursor type - if (mouse_panel != 0 && !mouse_in_margin){ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; - } - else if (divider_panel != 0){ - if (divider_panel->vertical_split){ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_LEFTRIGHT; - } - else{ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_UPDOWN; - } - } - else{ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; - } - - models->prev_mouse_panel = mouse_panel; - app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; - app_result.perform_kill = !models->keep_playing; - app_result.animating = models->animate_next_frame; - if (models->animate_next_frame){ - // NOTE(allen): Silence the timer, because we're going to do another frame right away anyways. - system_wake_up_timer_set(models->period_wakeup_timer, max_u32); - } - else{ - // NOTE(allen): Set the timer's wakeup period, possibly to max_u32 thus effectively silencing it. - system_wake_up_timer_set(models->period_wakeup_timer, models->next_animate_delay); - } - - // NOTE(allen): Update Frame to Frame States - models->prev_p = input->mouse.p; - models->animated_last_frame = app_result.animating; - models->frame_counter += 1; - - // end-of-app_step - return(app_result); -} - -extern "C" App_Get_Functions_Sig(app_get_functions){ - App_Functions result = {}; - - result.load_vtables = app_load_vtables; - result.get_logger = app_get_logger; - result.read_command_line = app_read_command_line; - result.init = app_init; - result.step = app_step; - - return(result); -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.12.2014 + * + * Application layer for project codename "4ed" + * + */ + +// TOP + +internal void +fill_hardcode_default_style(Color_Table color_table){ + color_table.vals[Stag_Back] = 0xFF0C0C0C; + color_table.vals[Stag_Margin] = 0xFF181818; + color_table.vals[Stag_Margin_Hover] = 0xFF252525; + color_table.vals[Stag_Margin_Active] = 0xFF323232; + color_table.vals[Stag_List_Item] = color_table.vals[Stag_Margin]; + color_table.vals[Stag_List_Item_Hover] = color_table.vals[Stag_Margin_Hover]; + color_table.vals[Stag_List_Item_Active] = color_table.vals[Stag_Margin_Active]; + color_table.vals[Stag_Cursor] = 0xFF00EE00; + color_table.vals[Stag_Highlight] = 0xFFDDEE00; + color_table.vals[Stag_Mark] = 0xFF494949; + color_table.vals[Stag_Default] = 0xFF90B080; + color_table.vals[Stag_At_Cursor] = color_table.vals[Stag_Back]; + color_table.vals[Stag_Highlight_Cursor_Line] = 0xFF1E1E1E; + color_table.vals[Stag_At_Highlight] = 0xFFFF44DD; + color_table.vals[Stag_Comment] = 0xFF2090F0; + color_table.vals[Stag_Keyword] = 0xFFD08F20; + color_table.vals[Stag_Str_Constant] = 0xFF50FF30; + color_table.vals[Stag_Char_Constant] = color_table.vals[Stag_Str_Constant]; + color_table.vals[Stag_Int_Constant] = color_table.vals[Stag_Str_Constant]; + color_table.vals[Stag_Float_Constant] = color_table.vals[Stag_Str_Constant]; + color_table.vals[Stag_Bool_Constant] = color_table.vals[Stag_Str_Constant]; + color_table.vals[Stag_Include] = color_table.vals[Stag_Str_Constant]; + color_table.vals[Stag_Preproc] = color_table.vals[Stag_Default]; + color_table.vals[Stag_Special_Character] = 0xFFFF0000; + color_table.vals[Stag_Ghost_Character] = color_blend(color_table.vals[Stag_Default], 0.5f, color_table.vals[Stag_Back]); + + color_table.vals[Stag_Paste] = 0xFFDDEE00; + color_table.vals[Stag_Undo] = 0xFF00DDEE; + + color_table.vals[Stag_Highlight_Junk] = 0xff3a0000; + color_table.vals[Stag_Highlight_White] = 0xff003a3a; + + color_table.vals[Stag_Bar] = 0xFF888888; + color_table.vals[Stag_Base] = 0xFF000000; + color_table.vals[Stag_Pop1] = 0xFF3C57DC; + color_table.vals[Stag_Pop2] = 0xFFFF0000; + + color_table.vals[Stag_Back_Cycle_1] = 0x10A00000; + color_table.vals[Stag_Back_Cycle_2] = 0x0C00A000; + color_table.vals[Stag_Back_Cycle_3] = 0x0C0000A0; + color_table.vals[Stag_Back_Cycle_4] = 0x0CA0A000; + color_table.vals[Stag_Text_Cycle_1] = 0xFFA00000; + color_table.vals[Stag_Text_Cycle_2] = 0xFF00A000; + color_table.vals[Stag_Text_Cycle_3] = 0xFF0030B0; + color_table.vals[Stag_Text_Cycle_4] = 0xFFA0A000; + + color_table.vals[Stag_Line_Numbers_Back] = 0xFF101010; + color_table.vals[Stag_Line_Numbers_Text] = 0xFF404040; +} + +internal void +app_hardcode_default_style(Models *models){ + Color_Table color_table = {}; + color_table.count = Stag_COUNT; + color_table.vals = push_array(models->arena, u32, color_table.count); + fill_hardcode_default_style(color_table); + models->fallback_color_table = color_table; +} + +internal void +init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, i32 argc, char **argv){ + char *arg = 0; + Command_Line_Mode mode = CLMode_App; + Command_Line_Action action = CLAct_Nothing; + b32 strict = false; + + settings->init_files_max = ArrayCount(settings->init_files); + for (i32 i = 1; i <= argc; ++i){ + if (i == argc){ + arg = ""; + } + else{ + arg = argv[i]; + } + + if (arg[0] == '-' && arg[1] == '-'){ + char *long_arg_name = arg+2; + if (string_match(SCu8(long_arg_name), string_u8_litexpr("custom"))){ + mode = CLMode_Custom; + continue; + } + } + + switch (mode){ + case CLMode_App: + { + switch (action){ + case CLAct_Nothing: + { + if (arg[0] == '-'){ + action = CLAct_Ignore; + switch (arg[1]){ + case 'd': action = CLAct_CustomDLL; strict = false; break; + case 'D': action = CLAct_CustomDLL; strict = true; break; + + case 'i': action = CLAct_InitialFilePosition; break; + + case 'w': action = CLAct_WindowSize; break; + case 'W': action = CLAct_WindowMaximize; break; + case 'p': action = CLAct_WindowPosition; break; + case 'F': action = CLAct_WindowFullscreen; break; + + case 'f': action = CLAct_FontSize; break; + case 'h': action = CLAct_FontUseHinting; --i; break; + } + } + else if (arg[0] != 0){ + if (settings->init_files_count < settings->init_files_max){ + i32 index = settings->init_files_count++; + settings->init_files[index] = arg; + } + } + }break; + + case CLAct_CustomDLL: + { + plat_settings->custom_dll_is_strict = (b8)strict; + if (i < argc){ + plat_settings->custom_dll = argv[i]; + } + action = CLAct_Nothing; + }break; + + case CLAct_InitialFilePosition: + { + if (i < argc){ + settings->initial_line = (i32)string_to_integer(SCu8(argv[i]), 10); + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowSize: + { + if (i + 1 < argc){ + plat_settings->set_window_size = true; + + i32 w = (i32)string_to_integer(SCu8(argv[i]), 10); + i32 h = (i32)string_to_integer(SCu8(argv[i + 1]), 10); + if (w > 0){ + plat_settings->window_w = w; + } + if (h > 0){ + plat_settings->window_h = h; + } + + ++i; + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowMaximize: + { + --i; + plat_settings->maximize_window = true; + action = CLAct_Nothing; + }break; + + case CLAct_WindowPosition: + { + if (i + 1 < argc){ + plat_settings->set_window_pos = true; + + i32 x = (i32)string_to_integer(SCu8(argv[i]), 10); + i32 y = (i32)string_to_integer(SCu8(argv[i + 1]), 10); + if (x > 0){ + plat_settings->window_x = x; + } + if (y > 0){ + plat_settings->window_y = y; + } + + ++i; + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowFullscreen: + { + --i; + plat_settings->fullscreen_window = true; + action = CLAct_Nothing; + }break; + + case CLAct_FontSize: + { + if (i < argc){ + settings->font_size = (i32)string_to_integer(SCu8(argv[i]), 10); + } + action = CLAct_Nothing; + }break; + + case CLAct_FontUseHinting: + { + plat_settings->use_hinting = true; + settings->use_hinting = plat_settings->use_hinting; + action = CLAct_Nothing; + }break; + } + }break; + + case CLMode_Custom: + { + settings->custom_flags = argv + i; + settings->custom_flags_count = argc - i; + i = argc; + mode = CLMode_App; + }break; + } + } +} + +//////////////////////////////// + +internal Models* +models_init(void){ + Arena arena = make_arena_system(); + Models *models = push_array_zero(&arena, Models, 1); + models->arena_ = arena; + models->arena = &models->arena_; + heap_init(&models->heap, get_base_allocator_system()); + return(models); +} + +internal void +app_load_vtables(API_VTable_system *vtable_system, API_VTable_font *vtable_font, API_VTable_graphics *vtable_graphics){ + system_api_read_vtable(vtable_system); + font_api_read_vtable(vtable_font); + graphics_api_read_vtable(vtable_graphics); +} + +internal Log_Function* +app_get_logger(void){ + log_init(); + return(log_string); +} + +App_Read_Command_Line_Sig(app_read_command_line){ + Models *models = models_init(); + App_Settings *settings = &models->settings; + block_zero_struct(settings); + if (argc > 1){ + init_command_line_settings(&models->settings, plat_settings, argc, argv); + } + *files = models->settings.init_files; + *file_count = &models->settings.init_files_count; + return(models); +} + +App_Init_Sig(app_init){ + Models *models = (Models*)base_ptr; + models->keep_playing = true; + + models->config_api = api; + + profile_init(&models->profile_list); + + 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); + + Application_Links app = {}; + app.tctx = tctx; + app.cmd_context = models; + custom_init(&app); + + // 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; + } + } + + managed_ids_init(tctx->allocator, &models->managed_id_set); + 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 + { + Face_Description description = {}; + description.font.file_name = string_u8_litexpr("liberation-mono.ttf"); + description.font.in_4coder_font_folder = true; + description.parameters.pt_size = 12; + Face *new_face = font_set_new_face(&models->font_set, &description); + models->global_face_id = new_face->id; + } + app_hardcode_default_style(models); + + // 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): 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 , }, + }; + + 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); + } + + // 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(); +} + +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; + } + } + + if (input_node == 0){ + break; + } + input_node_next = input_node->next; + + b32 event_was_handled = false; + Input_Event *event = &input_node->event; + + if (event->kind == InputEventKind_TextInsert && event->text.blocked){ + continue; + } + + 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; + } + } + } + + // NOTE(allen): send panel size update + if (models->layout.panel_state_dirty){ + models->layout.panel_state_dirty = false; + if (models->buffer_viewer_update != 0){ + Application_Links app = {}; + app.tctx = tctx; + app.cmd_context = models; + models->buffer_viewer_update(&app); + } + } + + // NOTE(allen): dt + f32 literal_dt = 0.f; + u64 now_usecond_stamp = system_now_time(); + if (!input->first_step){ + u64 elapsed_useconds = now_usecond_stamp - models->last_render_usecond_stamp; + literal_dt = (f32)((f64)(elapsed_useconds)/1000000.f); + } + models->last_render_usecond_stamp = now_usecond_stamp; + f32 animation_dt = 0.f; + if (models->animated_last_frame){ + animation_dt = literal_dt; + } + + // NOTE(allen): on the first frame there should be no scrolling + if (input->first_step){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ + View *view = panel->view; + File_Edit_Positions edit_pos = view_get_edit_pos(view); + edit_pos.scroll.position = view_normalize_buffer_point(tctx, models, view, edit_pos.scroll.target); + block_zero_struct(&edit_pos.scroll.target); + view_set_edit_pos(view, edit_pos); + } + } + + // NOTE(allen): hook for files reloaded + { + Working_Set *working_set = &models->working_set; + Assert(working_set->has_external_mod_sentinel.next != 0); + if (working_set->has_external_mod_sentinel.next != &working_set->has_external_mod_sentinel){ + for (Node *node = working_set->has_external_mod_sentinel.next, *next = 0; + node != &working_set->has_external_mod_sentinel; + node = next){ + next = node->next; + Editing_File *file = CastFromMember(Editing_File, external_mod_node, node); + dll_remove(node); + block_zero_struct(node); + co_send_core_event(tctx, models, CoreCode_FileExternallyModified, file->id); + } + } + } + + // NOTE(allen): if the exit signal has been sent, run the exit hook. + if (input->trying_to_kill){ + models->keep_playing = false; + } + if (!models->keep_playing){ + if (co_send_core_event(tctx, models, CoreCode_TryExit)){ + models->keep_playing = true; + } + } + + // NOTE(allen): rendering + { + Frame_Info frame = {}; + frame.index = models->frame_counter; + frame.literal_dt = literal_dt; + frame.animation_dt = animation_dt; + + { + Color_Table color_table = models->fallback_color_table; +#if 0 + if (models->modify_color_table != 0){ + color_table = models->modify_color_table(&models->app_links, frame); + if (color_table.count < models->fallback_color_table.count){ + block_copy(models->fallback_color_table.vals, color_table.vals, color_table.count*sizeof(*color_table.vals)); + color_table = models->fallback_color_table; + } + } +#endif + models->color_table = color_table; + } + + Application_Links app = {}; + app.tctx = tctx; + app.cmd_context = models; + + if (models->tick != 0){ + models->tick(&app, frame); + } + + begin_render_section(target, models->frame_counter, literal_dt, animation_dt); + models->in_render_mode = true; + + Live_Views *live_views = &models->view_set; + for (Node *node = layout->open_panels.next; + node != &layout->open_panels; + node = node->next){ + Panel *panel = CastFromMember(Panel, node, node); + View *view = panel->view; + View_Context_Node *ctx = view->ctx; + if (ctx != 0){ + Render_Caller_Function *render_caller = ctx->ctx.render_caller; + if (render_caller != 0){ + render_caller(&app, frame, view_get_id(live_views, view)); + } + } + } + + models->in_render_mode = false; + end_render_section(target); + } + + // NOTE(allen): flush the log + log_flush(tctx, models); + + // NOTE(allen): set the app_result + Application_Step_Result app_result = {}; + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; + app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; + + // NOTE(allen): get new window title + if (models->has_new_title){ + models->has_new_title = false; + app_result.has_new_title = true; + app_result.title_string = models->title_space; + } + + // NOTE(allen): get cursor type + if (mouse_panel != 0 && !mouse_in_margin){ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + } + else if (divider_panel != 0){ + if (divider_panel->vertical_split){ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_LEFTRIGHT; + } + else{ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_UPDOWN; + } + } + else{ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + } + + models->prev_mouse_panel = mouse_panel; + app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; + app_result.perform_kill = !models->keep_playing; + app_result.animating = models->animate_next_frame; + if (models->animate_next_frame){ + // NOTE(allen): Silence the timer, because we're going to do another frame right away anyways. + system_wake_up_timer_set(models->period_wakeup_timer, max_u32); + } + else{ + // NOTE(allen): Set the timer's wakeup period, possibly to max_u32 thus effectively silencing it. + system_wake_up_timer_set(models->period_wakeup_timer, models->next_animate_delay); + } + + // NOTE(allen): Update Frame to Frame States + models->prev_p = input->mouse.p; + models->animated_last_frame = app_result.animating; + models->frame_counter += 1; + + // end-of-app_step + return(app_result); +} + +extern "C" App_Get_Functions_Sig(app_get_functions){ + App_Functions result = {}; + + result.load_vtables = app_load_vtables; + result.get_logger = app_get_logger; + result.read_command_line = app_read_command_line; + result.init = app_init; + result.step = app_step; + + return(result); +} + +// BOTTOM + diff --git a/custom/4coder_base_commands.cpp b/custom/4coder_base_commands.cpp index d2f0f5b4..c0c249a3 100644 --- a/custom/4coder_base_commands.cpp +++ b/custom/4coder_base_commands.cpp @@ -732,6 +732,19 @@ CUSTOM_DOC("Toggles the left margin line numbers.") global_config.show_line_number_margins = !global_config.show_line_number_margins; } +CUSTOM_COMMAND_SIG(toggle_line_wrap) +CUSTOM_DOC("Toggles the line wrap setting on this buffer.") +{ + View_ID view = get_active_view(app, Access_ReadVisible); + Buffer_ID buffer = view_get_buffer(app, view, Access_Always); + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + if (wrap_lines_ptr != 0){ + *wrap_lines_ptr = !(*wrap_lines_ptr); + buffer_clear_layout_cache(app, buffer); + } +} + CUSTOM_COMMAND_SIG(exit_4coder) CUSTOM_DOC("Attempts to close 4coder.") { diff --git a/custom/4coder_code_index.cpp b/custom/4coder_code_index.cpp index 61fa6003..bdc2916f 100644 --- a/custom/4coder_code_index.cpp +++ b/custom/4coder_code_index.cpp @@ -1,811 +1,960 @@ -/* -4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. -*/ - -// TOP - -global Code_Index global_code_index = {}; - -function void -code_index_init(void){ - global_code_index.mutex = system_mutex_make(); - global_code_index.node_arena = make_arena_system(KB(4)); - global_code_index.buffer_to_index_file = - make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); -} - -function Code_Index_File_Storage* -code_index__alloc_storage(void){ - Code_Index_File_Storage *result = global_code_index.free_storage; - if (result == 0){ - result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); - } - else{ - sll_stack_pop(global_code_index.free_storage); - } - zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); - global_code_index.storage_count += 1; - return(result); -} - -function void -code_index__free_storage(Code_Index_File_Storage *storage){ - zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); - global_code_index.storage_count -= 1; - sll_stack_push(global_code_index.free_storage, storage); -} - -function void -code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ - sll_queue_push(list->first, list->last, nest); - list->count += 1; -} - -function Code_Index_Nest_Ptr_Array -code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ - Code_Index_Nest_Ptr_Array array = {}; - array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); - array.count = list->count; - i32 counter = 0; - for (Code_Index_Nest *node = list->first; - node != 0; - node = node->next){ - array.ptrs[counter] = node; - counter += 1; - } - return(array); -} - -function void -code_index_lock(void){ - system_mutex_acquire(global_code_index.mutex); -} - -function void -code_index_unlock(void){ - system_mutex_release(global_code_index.mutex); -} - -function void -code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ - Code_Index_File_Storage *storage = 0; - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - storage = (Code_Index_File_Storage*)IntAsPtr(val); - linalloc_clear(&storage->arena); - } - else{ - storage = code_index__alloc_storage(); - table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); - } - storage->arena = arena; - storage->file = index; -} - -function void -code_index_erase_file(Buffer_ID buffer){ - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); - linalloc_clear(&storage->arena); - table_erase(&global_code_index.buffer_to_index_file, lookup); - code_index__free_storage(storage); - } -} - -function Code_Index_File* -code_index_get_file(Buffer_ID buffer){ - Code_Index_File *result = 0; - Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); - if (lookup.found_match){ - u64 val = 0; - table_read(&global_code_index.buffer_to_index_file, lookup, &val); - Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); - result = storage->file; - } - return(result); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_Nest_Ptr_Array *array, i64 pos){ - Code_Index_Nest *result = 0; - i32 count = array->count; - Code_Index_Nest **nest_ptrs = array->ptrs; - for (i32 i = 0; i < count; i += 1){ - Code_Index_Nest *nest = nest_ptrs[i]; - if (nest->open.max <= pos && pos <= nest->close.min){ - Code_Index_Nest *sub_nest = - code_index_get_nest(&nest->nest_array, pos); - if (sub_nest != 0){ - result = sub_nest; - } - else{ - result = nest; - } - break; - } - } - return(result); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_Nest *nest, i64 pos){ - return(code_index_get_nest(&nest->nest_array, pos)); -} - -function Code_Index_Nest* -code_index_get_nest(Code_Index_File *file, i64 pos){ - return(code_index_get_nest(&file->nest_array, pos)); -} - -function void -index_shift(i64 *ptr, Range_i64 old_range, umem new_size){ - i64 i = *ptr; - if (old_range.min <= i && i < old_range.max){ - *ptr = old_range.first; - } - else if (old_range.max <= i){ - *ptr = i + new_size - (old_range.max - old_range.min); - } -} - -function void -code_index_shift(Code_Index_Nest_Ptr_Array *array, - Range_i64 old_range, umem new_size){ - i32 count = array->count; - Code_Index_Nest **nest_ptr = array->ptrs; - for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ - Code_Index_Nest *nest = *nest_ptr; - index_shift(&nest->open.min, old_range, new_size); - index_shift(&nest->open.max, old_range, new_size); - if (nest->is_closed){ - index_shift(&nest->close.min, old_range, new_size); - index_shift(&nest->close.max, old_range, new_size); - } - code_index_shift(&nest->nest_array, old_range, new_size); - } -} - -function void -code_index_shift(Code_Index_File *file, Range_i64 old_range, umem new_size){ - code_index_shift(&file->nest_array, old_range, new_size); -} - -//////////////////////////////// - -function void -generic_parse_inc(Generic_Parse_State *state){ - if (!token_it_inc_all(&state->it)){ - state->finished = true; - } -} - -function void -generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - for (;token != 0 && !state->finished;){ - if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ - break; - } - if (token->kind == TokenBaseKind_Comment){ - state->handle_comment(state->app, state->arena, index, token, state->contents); - } - else if (token->kind == TokenBaseKind_Whitespace){ - Range_i64 range = Ii64(token); - u8 *ptr = state->contents.str + range.one_past_last - 1; - for (i64 i = range.one_past_last - 1; - i >= range.first; - i -= 1, ptr -= 1){ - if (*ptr == '\n'){ - state->prev_line_start = ptr + 1; - break; - } - } - } - else{ - break; - } - generic_parse_inc(state); - token = token_it_read(&state->it); - } -} - -function void -generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ - state->app = app; - state->arena = arena; - state->contents = contents; - state->it = token_iterator(0, tokens); - state->handle_comment = handle_comment; - state->prev_line_start = contents.str; -} - -function Code_Index_Nest* -generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state); - -function Code_Index_Nest* -generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Statement; - result->open = Ii64(token->pos); - result->close = Ii64(max_i64); - result->file = index; - - state->in_statement = true; - - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - } - - if (token->kind == TokenBaseKind_ScopeOpen || - token->kind == TokenBaseKind_ScopeClose || - token->kind == TokenBaseKind_ParentheticalOpen || - token->kind == TokenBaseKind_ParentheticalClose){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - - if (token->kind == TokenBaseKind_StatementClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - generic_parse_inc(state); - } - - state->in_statement = false; - - return(result); -} - -function Code_Index_Nest* -generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Preprocessor; - result->open = Ii64(token->pos); - result->close = Ii64(max_i64); - result->file = index; - - state->in_preprocessor = true; - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - result->is_closed = true; - result->close = Ii64(token->pos); - break; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - generic_parse_inc(state); - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->in_preprocessor = false; - - return(result); -} - -function Code_Index_Nest* -generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Scope; - result->open = Ii64(token); - result->close = Ii64(max_i64); - result->file = index; - - state->scope_counter += 1; - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - continue; - } - } - - if (token->kind == TokenBaseKind_ScopeClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalClose){ - generic_parse_inc(state); - continue; - } - - { - Code_Index_Nest *nest = generic_parse_statement(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - } - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->scope_counter -= 1; - - return(result); -} - -function Code_Index_Nest* -generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state){ - Token *token = token_it_read(&state->it); - Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); - result->kind = CodeIndexNest_Paren; - result->open = Ii64(token); - result->close = Ii64(max_i64); - result->file = index; - - i64 manifested_characters_on_line = 0; - { - u8 *ptr = state->prev_line_start; - u8 *end_ptr = state->contents.str + token->pos; - // NOTE(allen): Initial whitespace - for (;ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - break; - } - } - // NOTE(allen): Manifested characters - manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; - } - - state->paren_counter += 1; - - generic_parse_inc(state); - for (;;){ - generic_parse_skip_soft_tokens(index, state); - token = token_it_read(&state->it); - if (token == 0 || state->finished){ - break; - } - - if (state->in_preprocessor){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || - token->kind == TokenBaseKind_Preprocessor){ - break; - } - } - else{ - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - continue; - } - } - - if (token->kind == TokenBaseKind_ParentheticalClose){ - result->is_closed = true; - result->close = Ii64(token); - generic_parse_inc(state); - break; - } - - if (token->kind == TokenBaseKind_ScopeClose){ - break; - } - - if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - nest->parent = result; - code_index_push_nest(&result->nest_list, nest); - continue; - } - - generic_parse_inc(state); - } - - result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); - - state->paren_counter -= 1; - - return(result); -} - -function b32 -generic_parse_full_input_breaks(Code_Index_File *index, Generic_Parse_State *state, i32 limit){ - b32 result = false; - - i64 first_index = token_it_index(&state->it); - i64 one_past_last_index = first_index + limit; - for (;;){ - generic_parse_skip_soft_tokens(index, state); - Token *token = token_it_read(&state->it); - - if (token == 0 || state->finished){ - result = true; - break; - } - - if (token->kind == TokenBaseKind_Preprocessor){ - Code_Index_Nest *nest = generic_parse_preprocessor(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else if (token->kind == TokenBaseKind_ScopeOpen){ - Code_Index_Nest *nest = generic_parse_scope(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else if (token->kind == TokenBaseKind_ParentheticalOpen){ - Code_Index_Nest *nest = generic_parse_paren(index, state); - code_index_push_nest(&index->nest_list, nest); - } - else{ - generic_parse_inc(state); - } - - i64 index = token_it_index(&state->it); - if (index >= one_past_last_index){ - token = token_it_read(&state->it); - if (token == 0){ - result = true; - } - break; - } - } - - if (result){ - index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); - } - - return(result); -} - -//////////////////////////////// - -function void -default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, - Token *token, String_Const_u8 contents){ - -} - -function void -generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ - generic_parse_init(app, arena, contents, tokens, default_comment_index, state); -} - -//////////////////////////////// - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance){ - f32 result = 0.f; - if (nest != 0){ - switch (nest->kind){ - case CodeIndexNest_Scope: - case CodeIndexNest_Preprocessor: - { - - result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance); - if (nest->open.min < pos && nest->open.max <= pos && - (!nest->is_closed || pos < nest->close.min)){ - result += 4.f*space_advance; - } - }break; - - case CodeIndexNest_Statement: - { - result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance); - if (nest->open.min < pos && nest->open.max <= pos && - (!nest->is_closed || pos < nest->close.min)){ - result += 4.f*space_advance; - } - }break; - - case CodeIndexNest_Paren: - { - Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1); - result = box.x1; - }break; - } - } - return(result); -} - -function f32 -layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance){ - f32 indent = 0; - Code_Index_Nest *nest = code_index_get_nest(file, pos); - if (nest != 0){ - indent = layout_index_x_shift(app, reflex, nest, pos, space_advance); - } - return(indent); -} - -function Layout_Item_List -layout_index_unwrapped__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file){ - Scratch_Block scratch(app); - - Layout_Item_List list = get_empty_item_list(range); - String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); - - Face_Advance_Map advance_map = get_face_advance_map(app, face); - Face_Metrics metrics = get_face_metrics(app, face); - LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); - - f32 wrap_align_x = width - metrics.normal_advance; - - Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); - - if (text.size == 0){ - lr_tb_write_blank(&pos_vars, arena, &list, range.start); - } - else{ - b32 first_of_the_line = true; - Newline_Layout_Vars newline_vars = get_newline_layout_vars(); - - u8 *ptr = text.str; - u8 *end_ptr = ptr + text.size; - u8 *word_ptr = ptr; - - if (!character_is_whitespace(*ptr)){ - goto consuming_non_whitespace; - } - - skipping_leading_whitespace: - for (;ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - word_ptr = ptr; - goto consuming_non_whitespace; - } - if (*ptr == '\n'){ - goto consuming_normal_whitespace; - } - } - - if (ptr == end_ptr){ - goto finish; - } - - consuming_non_whitespace: - for (;ptr <= end_ptr; ptr += 1){ - if (ptr == end_ptr || character_is_whitespace(*ptr)){ - break; - } - } - - { - newline_layout_consume_default(&newline_vars); - - String_Const_u8 word = SCu8(word_ptr, ptr); - u8 *word_end = ptr; - - if (!first_of_the_line){ - f32 total_advance = 0.f; - ptr = word.str; - for (;ptr < word_end;){ - Character_Consume_Result consume = - utf8_consume(ptr, (umem)(word_end - ptr)); - if (consume.codepoint != max_u32){ - total_advance += lr_tb_advance(&pos_vars, consume.codepoint); - } - else{ - total_advance += lr_tb_advance_byte(&pos_vars); - } - ptr += consume.inc; - } - - if (lr_tb_crosses_width(&pos_vars, total_advance)){ - i64 index = layout_index_from_ptr(word.str, text.str, range.first); - lr_tb_align_rightward(&pos_vars, wrap_align_x); - lr_tb_write_ghost(&pos_vars, arena, &list, index, '\\'); - - lr_tb_next_line(&pos_vars); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - } - } - else{ - i64 index = layout_index_from_ptr(word.str, text.str, range.first); - f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - } - - ptr = word.str; - - for (;ptr < word_end;){ - Character_Consume_Result consume = - utf8_consume(ptr, (umem)(word_end - ptr)); - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - - if (consume.codepoint != max_u32){ - lr_tb_write(&pos_vars, arena, &list, index, consume.codepoint); - } - else{ - lr_tb_write_byte(&pos_vars, arena, &list, index, *ptr); - } - - ptr += consume.inc; - } - - first_of_the_line = false; - } - - consuming_normal_whitespace: - for (; ptr < end_ptr; ptr += 1){ - if (!character_is_whitespace(*ptr)){ - word_ptr = ptr; - goto consuming_non_whitespace; - } - - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - switch (*ptr){ - default: - { - newline_layout_consume_default(&newline_vars); - lr_tb_write(&pos_vars, arena, &list, index, *ptr); - first_of_the_line = false; - }break; - - case '\r': - { - newline_layout_consume_CR(&newline_vars, index); - }break; - - case '\n': - { - if (first_of_the_line){ - f32 shift = layout_index_x_shift(app, &reflex, file, index, - metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - } - - u64 newline_index = newline_layout_consume_LF(&newline_vars, index); - lr_tb_write_blank(&pos_vars, arena, &list, newline_index); - lr_tb_next_line(&pos_vars); - first_of_the_line = true; - ptr += 1; - goto skipping_leading_whitespace; - }break; - } - } - - finish: - if (newline_layout_consume_finish(&newline_vars)){ - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - if (first_of_the_line){ - f32 shift = layout_index_x_shift(app, &reflex, file, index, - metrics.space_advance); - lr_tb_advance_x_without_item(&pos_vars, shift); - } - lr_tb_write_blank(&pos_vars, arena, &list, index); - } - } - - layout_item_list_finish(&list, -pos_vars.line_to_text_shift); - - return(list); -} - - - -function Layout_Item_List -layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, - Buffer_ID buffer, Range_i64 range, Face_ID face, - f32 width){ - Layout_Item_List result = {}; - - if (global_config.enable_virtual_whitespace){ - code_index_lock(); - Code_Index_File *file = code_index_get_file(buffer); - if (file != 0){ - result = layout_index_unwrapped__inner(app, arena, buffer, range, face, width, file); - } - code_index_unlock(); - if (file == 0){ - result = layout_virt_indent_literal_unwrapped(app, arena, buffer, range, face, width); - } - } - else{ - result = layout_wrap_whitespace(app, arena, buffer, range, face, width); - } - - return(result); -} - -CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) -CUSTOM_DOC("Toggles the current buffer's virtual whitespace status.") -{ - global_config.enable_virtual_whitespace = !global_config.enable_virtual_whitespace; - - for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); - buffer != 0; - buffer = get_buffer_next(app, buffer, Access_Always)){ - buffer_clear_layout_cache(app, buffer); - } -} - -// BOTTOM - +/* +4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. +*/ + +// TOP + +global Code_Index global_code_index = {}; + +function void +code_index_init(void){ + global_code_index.mutex = system_mutex_make(); + global_code_index.node_arena = make_arena_system(KB(4)); + global_code_index.buffer_to_index_file = make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); +} + +function Code_Index_File_Storage* +code_index__alloc_storage(void){ + Code_Index_File_Storage *result = global_code_index.free_storage; + if (result == 0){ + result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); + } + else{ + sll_stack_pop(global_code_index.free_storage); + } + zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); + global_code_index.storage_count += 1; + return(result); +} + +function void +code_index__free_storage(Code_Index_File_Storage *storage){ + zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); + global_code_index.storage_count -= 1; + sll_stack_push(global_code_index.free_storage, storage); +} + +function void +code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ + sll_queue_push(list->first, list->last, nest); + list->count += 1; +} + +function Code_Index_Nest_Ptr_Array +code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ + Code_Index_Nest_Ptr_Array array = {}; + array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); + array.count = list->count; + i32 counter = 0; + for (Code_Index_Nest *node = list->first; + node != 0; + node = node->next){ + array.ptrs[counter] = node; + counter += 1; + } + return(array); +} + +function void +code_index_lock(void){ + system_mutex_acquire(global_code_index.mutex); +} + +function void +code_index_unlock(void){ + system_mutex_release(global_code_index.mutex); +} + +function void +code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ + Code_Index_File_Storage *storage = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + } + else{ + storage = code_index__alloc_storage(); + table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); + } + storage->arena = arena; + storage->file = index; +} + +function void +code_index_erase_file(Buffer_ID buffer){ + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + linalloc_clear(&storage->arena); + table_erase(&global_code_index.buffer_to_index_file, lookup); + code_index__free_storage(storage); + } +} + +function Code_Index_File* +code_index_get_file(Buffer_ID buffer){ + Code_Index_File *result = 0; + Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); + if (lookup.found_match){ + u64 val = 0; + table_read(&global_code_index.buffer_to_index_file, lookup, &val); + Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); + result = storage->file; + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest_Ptr_Array *array, i64 pos){ + Code_Index_Nest *result = 0; + i32 count = array->count; + Code_Index_Nest **nest_ptrs = array->ptrs; + for (i32 i = 0; i < count; i += 1){ + Code_Index_Nest *nest = nest_ptrs[i]; + if (nest->open.max <= pos && pos <= nest->close.min){ + Code_Index_Nest *sub_nest = + code_index_get_nest(&nest->nest_array, pos); + if (sub_nest != 0){ + result = sub_nest; + } + else{ + result = nest; + } + break; + } + } + return(result); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_Nest *nest, i64 pos){ + return(code_index_get_nest(&nest->nest_array, pos)); +} + +function Code_Index_Nest* +code_index_get_nest(Code_Index_File *file, i64 pos){ + return(code_index_get_nest(&file->nest_array, pos)); +} + +function void +index_shift(i64 *ptr, Range_i64 old_range, umem new_size){ + i64 i = *ptr; + if (old_range.min <= i && i < old_range.max){ + *ptr = old_range.first; + } + else if (old_range.max <= i){ + *ptr = i + new_size - (old_range.max - old_range.min); + } +} + +function void +code_index_shift(Code_Index_Nest_Ptr_Array *array, + Range_i64 old_range, umem new_size){ + i32 count = array->count; + Code_Index_Nest **nest_ptr = array->ptrs; + for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ + Code_Index_Nest *nest = *nest_ptr; + index_shift(&nest->open.min, old_range, new_size); + index_shift(&nest->open.max, old_range, new_size); + if (nest->is_closed){ + index_shift(&nest->close.min, old_range, new_size); + index_shift(&nest->close.max, old_range, new_size); + } + code_index_shift(&nest->nest_array, old_range, new_size); + } +} + +function void +code_index_shift(Code_Index_File *file, Range_i64 old_range, umem new_size){ + code_index_shift(&file->nest_array, old_range, new_size); +} + +//////////////////////////////// + +function void +generic_parse_inc(Generic_Parse_State *state){ + if (!token_it_inc_all(&state->it)){ + state->finished = true; + } +} + +function void +generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + for (;token != 0 && !state->finished;){ + if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ + break; + } + if (token->kind == TokenBaseKind_Comment){ + state->handle_comment(state->app, state->arena, index, token, state->contents); + } + else if (token->kind == TokenBaseKind_Whitespace){ + Range_i64 range = Ii64(token); + u8 *ptr = state->contents.str + range.one_past_last - 1; + for (i64 i = range.one_past_last - 1; + i >= range.first; + i -= 1, ptr -= 1){ + if (*ptr == '\n'){ + state->prev_line_start = ptr + 1; + break; + } + } + } + else{ + break; + } + generic_parse_inc(state); + token = token_it_read(&state->it); + } +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ + state->app = app; + state->arena = arena; + state->contents = contents; + state->it = token_iterator(0, tokens); + state->handle_comment = handle_comment; + state->prev_line_start = contents.str; +} + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state); + +function Code_Index_Nest* +generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Statement; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_statement = true; + + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + } + + if (token->kind == TokenBaseKind_ScopeOpen || + token->kind == TokenBaseKind_ScopeClose || + token->kind == TokenBaseKind_ParentheticalOpen || + token->kind == TokenBaseKind_ParentheticalClose){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (token->kind == TokenBaseKind_StatementClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + generic_parse_inc(state); + } + + state->in_statement = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_preprocessor(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Preprocessor; + result->open = Ii64(token->pos); + result->close = Ii64(max_i64); + result->file = index; + + state->in_preprocessor = true; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + result->is_closed = true; + result->close = Ii64(token->pos); + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->in_preprocessor = false; + + return(result); +} + +function Code_Index_Nest* +generic_parse_scope(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Scope; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + state->scope_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ScopeClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + generic_parse_inc(state); + continue; + } + + { + Code_Index_Nest *nest = generic_parse_statement(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + } + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->scope_counter -= 1; + + return(result); +} + +function Code_Index_Nest* +generic_parse_paren(Code_Index_File *index, Generic_Parse_State *state){ + Token *token = token_it_read(&state->it); + Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); + result->kind = CodeIndexNest_Paren; + result->open = Ii64(token); + result->close = Ii64(max_i64); + result->file = index; + + i64 manifested_characters_on_line = 0; + { + u8 *ptr = state->prev_line_start; + u8 *end_ptr = state->contents.str + token->pos; + // NOTE(allen): Initial whitespace + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + break; + } + } + // NOTE(allen): Manifested characters + manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; + } + + state->paren_counter += 1; + + generic_parse_inc(state); + for (;;){ + generic_parse_skip_soft_tokens(index, state); + token = token_it_read(&state->it); + if (token == 0 || state->finished){ + break; + } + + if (state->in_preprocessor){ + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || + token->kind == TokenBaseKind_Preprocessor){ + break; + } + } + else{ + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + continue; + } + } + + if (token->kind == TokenBaseKind_ParentheticalClose){ + result->is_closed = true; + result->close = Ii64(token); + generic_parse_inc(state); + break; + } + + if (token->kind == TokenBaseKind_ScopeClose){ + break; + } + + if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + nest->parent = result; + code_index_push_nest(&result->nest_list, nest); + continue; + } + + generic_parse_inc(state); + } + + result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); + + state->paren_counter -= 1; + + return(result); +} + +function b32 +generic_parse_full_input_breaks(Code_Index_File *index, Generic_Parse_State *state, i32 limit){ + b32 result = false; + + i64 first_index = token_it_index(&state->it); + i64 one_past_last_index = first_index + limit; + for (;;){ + generic_parse_skip_soft_tokens(index, state); + Token *token = token_it_read(&state->it); + + if (token == 0 || state->finished){ + result = true; + break; + } + + if (token->kind == TokenBaseKind_Preprocessor){ + Code_Index_Nest *nest = generic_parse_preprocessor(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ScopeOpen){ + Code_Index_Nest *nest = generic_parse_scope(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else if (token->kind == TokenBaseKind_ParentheticalOpen){ + Code_Index_Nest *nest = generic_parse_paren(index, state); + code_index_push_nest(&index->nest_list, nest); + } + else{ + generic_parse_inc(state); + } + + i64 index = token_it_index(&state->it); + if (index >= one_past_last_index){ + token = token_it_read(&state->it); + if (token == 0){ + result = true; + } + break; + } + } + + if (result){ + index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); + } + + return(result); +} + +//////////////////////////////// + +function void +default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, Token *token, String_Const_u8 contents){ + +} + +function void +generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ + generic_parse_init(app, arena, contents, tokens, default_comment_index, state); +} + +//////////////////////////////// + +function Token_Pair +layout_token_pair(Token_Array *tokens, i64 pos){ + Token_Iterator_Array it = token_iterator_pos(0, tokens, pos); + Token *b = token_it_read(&it); + if (b->kind == TokenBaseKind_Whitespace){ + token_it_inc_non_whitespace(&it); + b = token_it_read(&it); + } + token_it_dec_non_whitespace(&it); + Token *a = token_it_read(&it); + Token_Pair result = {}; + if (a != 0){ + result.a = *a; + } + if (b != 0){ + result.b = *b; + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 result = 0.f; + if (nest != 0){ + switch (nest->kind){ + case CodeIndexNest_Scope: + case CodeIndexNest_Preprocessor: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Statement: + { + result = layout_index_x_shift(app, reflex, nest->parent, pos, space_advance, unresolved_dependence); + if (nest->open.min < pos && nest->open.max <= pos && + (!nest->is_closed || pos < nest->close.min)){ + result += 4.f*space_advance; + } + }break; + + case CodeIndexNest_Paren: + { + Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1, unresolved_dependence); + result = box.x1; + }break; + } + } + return(result); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, nest, pos, space_advance, &ignore)); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance, b32 *unresolved_dependence){ + f32 indent = 0; + Code_Index_Nest *nest = code_index_get_nest(file, pos); + if (nest != 0){ + indent = layout_index_x_shift(app, reflex, nest, pos, space_advance, unresolved_dependence); + } + return(indent); +} + +function f32 +layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 space_advance){ + b32 ignore; + return(layout_index_x_shift(app, reflex, file, pos, space_advance, &ignore)); +} + +function void +layout_index__emit_chunk(LefRig_TopBot_Layout_Vars *pos_vars, Arena *arena, u8 *text_str, i64 range_first, u8 *ptr, u8 *end, Layout_Item_List *list){ + for (;ptr < end;){ + Character_Consume_Result consume = utf8_consume(ptr, (umem)(end - ptr)); + if (consume.codepoint != '\r'){ + i64 index = layout_index_from_ptr(ptr, text_str, range_first); + if (consume.codepoint != max_u32){ + lr_tb_write(pos_vars, arena, list, index, consume.codepoint); + } + else{ + lr_tb_write_byte(pos_vars, arena, list, index, *ptr); + } + } + ptr += consume.inc; + } +} + + function i32 + layout_token_score_wrap_token(Token_Pair *pair, Token_Cpp_Kind kind){ + i32 result = 0; + if (pair->a.sub_kind != kind && pair->b.sub_kind == kind){ + result -= 1; + } + else if (pair->a.sub_kind == kind && pair->b.sub_kind != kind){ + result += 1; + } + return(result); + } + +function Layout_Item_List +layout_index__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file, Layout_Wrap_Kind kind){ + Scratch_Block scratch(app); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); + + Layout_Item_List list = get_empty_item_list(range); + String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); + + Face_Advance_Map advance_map = get_face_advance_map(app, face); + Face_Metrics metrics = get_face_metrics(app, face); + LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); + + f32 wrap_align_x = width - metrics.normal_advance; + + Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); + + if (text.size == 0){ + lr_tb_write_blank(&pos_vars, arena, &list, range.start); + } + else{ + b32 first_of_the_line = true; + Newline_Layout_Vars newline_vars = get_newline_layout_vars(); + + u8 *ptr = text.str; + u8 *end_ptr = ptr + text.size; + u8 *word_ptr = ptr; + + u8 *pending_wrap_ptr = ptr; + f32 pending_wrap_x = 0.f; + i32 pending_wrap_paren_nest_count = 0; + i32 pending_wrap_token_score = 0; + f32 pending_wrap_accumulated_w = 0.f; + + start: + if (ptr == end_ptr){ + goto finish; + } + + if (!character_is_whitespace(*ptr)){ + goto consuming_non_whitespace; + } + + { + for (;ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + pending_wrap_ptr = ptr; + word_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_non_whitespace; + } + if (*ptr == '\n'){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto consuming_normal_whitespace; + } + } + + if (ptr == end_ptr){ + pending_wrap_ptr = ptr; + i64 index = layout_index_from_ptr(ptr - 1, text.str, range.first); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + goto finish; + } + } + + consuming_non_whitespace: + { + for (;ptr <= end_ptr; ptr += 1){ + if (ptr == end_ptr || character_is_whitespace(*ptr)){ + break; + } + } + + // NOTE(allen): measure this word + newline_layout_consume_default(&newline_vars); + String_Const_u8 word = SCu8(word_ptr, ptr); + u8 *word_end = ptr; + { + f32 word_advance = 0.f; + ptr = word.str; + for (;ptr < word_end;){ + Character_Consume_Result consume = utf8_consume(ptr, (umem)(word_end - ptr)); + if (consume.codepoint != max_u32){ + word_advance += lr_tb_advance(&pos_vars, consume.codepoint); + } + else{ + word_advance += lr_tb_advance_byte(&pos_vars); + } + ptr += consume.inc; + } + pending_wrap_accumulated_w += word_advance; + } + + if (!first_of_the_line && (kind == Layout_Wrapped) && lr_tb_crosses_width(&pos_vars, pending_wrap_accumulated_w)){ + i64 index = layout_index_from_ptr(pending_wrap_ptr, text.str, range.first); + lr_tb_align_rightward(&pos_vars, wrap_align_x); + lr_tb_write_ghost(&pos_vars, arena, &list, index, '\\'); + + lr_tb_next_line(&pos_vars); + f32 shift = layout_index_x_shift(app, &reflex, file, index, metrics.space_advance); + lr_tb_advance_x_without_item(&pos_vars, shift); + + ptr = pending_wrap_ptr; + pending_wrap_accumulated_w = 0.f; + first_of_the_line = true; + goto start; + } + } + + consuming_normal_whitespace: + for (; ptr < end_ptr; ptr += 1){ + if (!character_is_whitespace(*ptr)){ + u8 *new_wrap_ptr = ptr; + + i64 index = layout_index_from_ptr(new_wrap_ptr, text.str, range.first); + Code_Index_Nest *new_wrap_nest = code_index_get_nest(file, index); + b32 invalid_wrap_x = false; + f32 new_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance, &invalid_wrap_x); + if (invalid_wrap_x){ + new_wrap_x = max_f32; + } + + i32 new_wrap_paren_nest_count = 0; + for (Code_Index_Nest *nest = new_wrap_nest; + nest != 0; + nest = nest->parent){ + if (nest->kind == CodeIndexNest_Paren){ + new_wrap_paren_nest_count += 1; + } + } + + Token_Pair new_wrap_token_pair = layout_token_pair(tokens_ptr, index); + + // TODO(allen): pull out the token scoring part and make it replacable for other + // language's token based wrap scoring needs. + i32 token_score = 0; + if (new_wrap_token_pair.a.kind == TokenBaseKind_Keyword){ + if (new_wrap_token_pair.b.kind == TokenBaseKind_ParentheticalOpen || + new_wrap_token_pair.b.kind == TokenBaseKind_Keyword){ + token_score -= 2; + } + } + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Eq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_PlusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_MinusEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_StarEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_DivEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_ModEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_LeftLeftEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_RightRightEq); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Comma); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_AndAnd); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_OrOr); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Ternary); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Colon); + token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Semicolon); + + i32 new_wrap_token_score = token_score; + + b32 new_wrap_ptr_is_better = false; + if (first_of_the_line){ + new_wrap_ptr_is_better = true; + } + else{ + if (new_wrap_token_score > pending_wrap_token_score){ + new_wrap_ptr_is_better = true; + } + else if (new_wrap_token_score == pending_wrap_token_score){ + f32 new_score = new_wrap_paren_nest_count*10.f + new_wrap_x; + f32 old_score = pending_wrap_paren_nest_count*10.f + pending_wrap_x + metrics.normal_advance*4.f + pending_wrap_accumulated_w*0.5f; + + if (new_score < old_score){ + new_wrap_ptr_is_better = true; + } + } + } + + if (new_wrap_ptr_is_better){ + layout_index__emit_chunk(&pos_vars, arena, text.str, range.first, pending_wrap_ptr, new_wrap_ptr, &list); + first_of_the_line = false; + + pending_wrap_ptr = new_wrap_ptr; + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, metrics.space_advance); + pending_wrap_paren_nest_count = new_wrap_paren_nest_count; + pending_wrap_token_score = new_wrap_token_score; + pending_wrap_accumulated_w = 0.f; + } + + word_ptr = ptr; + goto consuming_non_whitespace; + } + + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + switch (*ptr){ + default: + { + newline_layout_consume_default(&newline_vars); + pending_wrap_accumulated_w += lr_tb_advance(&pos_vars, *ptr); + }break; + + case '\r': + { + newline_layout_consume_CR(&newline_vars, index); + }break; + + case '\n': + { + layout_index__emit_chunk(&pos_vars, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + pending_wrap_ptr = ptr + 1; + pending_wrap_accumulated_w = 0.f; + + u64 newline_index = newline_layout_consume_LF(&newline_vars, index); + lr_tb_write_blank(&pos_vars, arena, &list, newline_index); + lr_tb_next_line(&pos_vars); + first_of_the_line = true; + ptr += 1; + goto start; + }break; + } + } + + finish: + if (newline_layout_consume_finish(&newline_vars)){ + layout_index__emit_chunk(&pos_vars, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + lr_tb_write_blank(&pos_vars, arena, &list, index); + } + } + + layout_item_list_finish(&list, -pos_vars.line_to_text_shift); + + return(list); +} + +function Layout_Item_List +layout_virt_indent_index(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ + Layout_Item_List result = {}; + + if (global_config.enable_virtual_whitespace){ + code_index_lock(); + Code_Index_File *file = code_index_get_file(buffer); + if (file != 0){ + result = layout_index__inner(app, arena, buffer, range, face, width, file, kind); + } + code_index_unlock(); + if (file == 0){ + result = layout_virt_indent_literal(app, arena, buffer, range, face, width, kind); + } + } + else{ + result = layout_basic(app, arena, buffer, range, face, width, kind); + } + + return(result); +} + +function Layout_Item_List +layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Unwrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Wrapped)); +} + +function Layout_Item_List +layout_virt_indent_index_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); + return(layout_virt_indent_index(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); +} + +CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) +CUSTOM_DOC("Toggles the current buffer's virtual whitespace status.") +{ + global_config.enable_virtual_whitespace = !global_config.enable_virtual_whitespace; + + for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); + buffer != 0; + buffer = get_buffer_next(app, buffer, Access_Always)){ + buffer_clear_layout_cache(app, buffer); + } +} + +// BOTTOM + diff --git a/custom/4coder_default_framework_variables.cpp b/custom/4coder_default_framework_variables.cpp index b127b6a8..a68097d1 100644 --- a/custom/4coder_default_framework_variables.cpp +++ b/custom/4coder_default_framework_variables.cpp @@ -45,6 +45,7 @@ global Managed_ID view_word_complete_menu = 0; global Managed_ID buffer_map_id = 0; global Managed_ID buffer_eol_setting = 0; global Managed_ID buffer_lex_task = 0; +global Managed_ID buffer_wrap_lines = 0; global Managed_ID sticky_jump_marker_handle = 0; diff --git a/custom/4coder_default_hooks.cpp b/custom/4coder_default_hooks.cpp index c6587eb3..b3fe5dba 100644 --- a/custom/4coder_default_hooks.cpp +++ b/custom/4coder_default_hooks.cpp @@ -955,12 +955,12 @@ BUFFER_HOOK_SIG(default_begin_buffer){ buffer_map_id = managed_id_declare(app, SCu8("DEFAULT.buffer_map_id")); buffer_eol_setting = managed_id_declare(app, SCu8("DEFAULT.buffer_eol_setting")); buffer_lex_task = managed_id_declare(app, SCu8("DEFAULT.buffer_lex_task")); + buffer_wrap_lines = managed_id_declare(app, SCu8("DEFAULT.buffer_wrap_lines")); } Command_Map_ID map_id = (treat_as_code)?(default_code_map):(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); + 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_contents(app, buffer_id); @@ -988,34 +988,21 @@ BUFFER_HOOK_SIG(default_begin_buffer){ *lex_task_ptr = async_task_no_dep(&global_async_system, do_full_lex_async, make_data_struct(&buffer_id)); } - if (wrap_lines){ + { + 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_unwrapped); - //buffer_set_layout(app, buffer_id, layout_virt_indent_literal_unwrapped); + buffer_set_layout(app, buffer_id, layout_virt_indent_index_generic); } else{ - buffer_set_layout(app, buffer_id, layout_virt_indent_literal_unwrapped); + buffer_set_layout(app, buffer_id, layout_virt_indent_literal_generic); } } else{ - buffer_set_layout(app, buffer_id, layout_wrap_whitespace); + buffer_set_layout(app, buffer_id, layout_generic); } - } - else{ - if (use_virtual_whitespace){ - if (use_lexer){ - buffer_set_layout(app, buffer_id, layout_virt_indent_index_unwrapped); - //buffer_set_layout(app, buffer_id, layout_virt_indent_literal_unwrapped); - } - else{ - buffer_set_layout(app, buffer_id, layout_virt_indent_literal_unwrapped); - } - } - else{ - buffer_set_layout(app, buffer_id, layout_unwrapped); - } - } // no meaning for return return(0); diff --git a/custom/4coder_layout_rule.cpp b/custom/4coder_layout_rule.cpp index d8aecb23..56901a0f 100644 --- a/custom/4coder_layout_rule.cpp +++ b/custom/4coder_layout_rule.cpp @@ -15,14 +15,21 @@ get_layout_reflex(Layout_Item_List *list, Buffer_ID buffer, f32 width, Face_ID f } function Rect_f32 -layout_reflex_get_rect(Application_Links *app, Layout_Reflex *reflex, i64 pos){ +layout_reflex_get_rect(Application_Links *app, Layout_Reflex *reflex, i64 pos, b32 *unresolved_dependence){ Rect_f32 rect = {}; if (range_contains(reflex->list->input_index_range, pos)){ - rect = layout_box_of_pos(*reflex->list, pos); + if (range_contains(reflex->list->manifested_index_range, pos)){ + rect = layout_box_of_pos(*reflex->list, pos); + *unresolved_dependence = false; + } + else{ + *unresolved_dependence = true; + } } else{ Buffer_Cursor cursor = buffer_compute_cursor(app, reflex->buffer, seek_pos(pos)); - rect = buffer_relative_box_of_pos(app, reflex->buffer, reflex->width, reflex->face, cursor.line, cursor.pos); + rect = buffer_relative_box_of_pos(app, reflex->buffer, reflex->width, reflex->face, cursor.line, cursor.pos); + *unresolved_dependence = false; } return(rect); } @@ -272,9 +279,7 @@ lr_tb_align_rightward(LefRig_TopBot_Layout_Vars *vars, f32 align_x){ //////////////////////////////// function Layout_Item_List -layout_unwrapped_small_blank_lines(Application_Links *app, Arena *arena, - Buffer_ID buffer, Range_i64 range, Face_ID face, - f32 width){ +layout_unwrapped_small_blank_lines(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ Layout_Item_List list = get_empty_item_list(range); Scratch_Block scratch(app); @@ -368,72 +373,7 @@ layout_unwrapped_small_blank_lines(Application_Links *app, Arena *arena, } function Layout_Item_List -layout_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, - Range_i64 range, Face_ID face, f32 width){ - Layout_Item_List list = get_empty_item_list(range); - - Scratch_Block scratch(app); - String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); - - Face_Advance_Map advance_map = get_face_advance_map(app, face); - Face_Metrics metrics = get_face_metrics(app, face); - LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); - - if (text.size == 0){ - lr_tb_write_blank(&pos_vars, arena, &list, range.first); - } - else{ - Newline_Layout_Vars newline_vars = get_newline_layout_vars(); - - u8 *ptr = text.str; - u8 *end_ptr = ptr + text.size; - for (;ptr < end_ptr;){ - Character_Consume_Result consume = utf8_consume(ptr, (umem)(end_ptr - ptr)); - - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - switch (consume.codepoint){ - default: - { - newline_layout_consume_default(&newline_vars); - lr_tb_write(&pos_vars, arena, &list, index, consume.codepoint); - }break; - - case '\r': - { - newline_layout_consume_CR(&newline_vars, index); - }break; - - case '\n': - { - i64 newline_index = newline_layout_consume_LF(&newline_vars, index); - lr_tb_write_blank(&pos_vars, arena, &list, newline_index); - lr_tb_next_line(&pos_vars); - }break; - - case max_u32: - { - newline_layout_consume_default(&newline_vars); - lr_tb_write_byte(&pos_vars, arena, &list, index, *ptr); - }break; - } - - ptr += consume.inc; - } - - if (newline_layout_consume_finish(&newline_vars)){ - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - lr_tb_write_blank(&pos_vars, arena, &list, index); - } - } - - layout_item_list_finish(&list, -pos_vars.line_to_text_shift); - - return(list); -} - -function Layout_Item_List -layout_wrap_anywhere(Application_Links *app, Arena *arena, Buffer_ID buffer, - Range_i64 range, Face_ID face, f32 width){ +layout_wrap_anywhere(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ Scratch_Block scratch(app); Layout_Item_List list = get_empty_item_list(range); @@ -509,8 +449,84 @@ layout_wrap_anywhere(Application_Links *app, Arena *arena, Buffer_ID buffer, } function Layout_Item_List -layout_wrap_whitespace(Application_Links *app, Arena *arena, Buffer_ID buffer, - Range_i64 range, Face_ID face, f32 width){ +layout_unwrapped__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Virtual_Indent virt_indent){ + Layout_Item_List list = get_empty_item_list(range); + + Scratch_Block scratch(app); + String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); + + Face_Advance_Map advance_map = get_face_advance_map(app, face); + Face_Metrics metrics = get_face_metrics(app, face); + LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); + + if (text.size == 0){ + lr_tb_write_blank(&pos_vars, arena, &list, range.first); + } + else{ + b32 skipping_leading_whitespace = (virt_indent == LayoutVirtualIndent_On); + Newline_Layout_Vars newline_vars = get_newline_layout_vars(); + + u8 *ptr = text.str; + u8 *end_ptr = ptr + text.size; + for (;ptr < end_ptr;){ + Character_Consume_Result consume = utf8_consume(ptr, (umem)(end_ptr - ptr)); + + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + switch (consume.codepoint){ + case '\t': + case ' ': + { + newline_layout_consume_default(&newline_vars); + f32 advance = lr_tb_advance(&pos_vars, consume.codepoint); + if (!skipping_leading_whitespace){ + lr_tb_write_with_advance(&pos_vars, advance, arena, &list, index, consume.codepoint); + } + else{ + lr_tb_advance_x_without_item(&pos_vars, advance); + } + }break; + + default: + { + newline_layout_consume_default(&newline_vars); + lr_tb_write(&pos_vars, arena, &list, index, consume.codepoint); + }break; + + case '\r': + { + newline_layout_consume_CR(&newline_vars, index); + }break; + + case '\n': + { + i64 newline_index = newline_layout_consume_LF(&newline_vars, index); + lr_tb_write_blank(&pos_vars, arena, &list, newline_index); + lr_tb_next_line(&pos_vars); + }break; + + case max_u32: + { + newline_layout_consume_default(&newline_vars); + lr_tb_write_byte(&pos_vars, arena, &list, index, *ptr); + }break; + } + + ptr += consume.inc; + } + + if (newline_layout_consume_finish(&newline_vars)){ + i64 index = layout_index_from_ptr(ptr, text.str, range.first); + lr_tb_write_blank(&pos_vars, arena, &list, index); + } + } + + layout_item_list_finish(&list, -pos_vars.line_to_text_shift); + + return(list); +} + +function Layout_Item_List +layout_wrap_whitespace__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Virtual_Indent virt_indent){ Scratch_Block scratch(app); Layout_Item_List list = get_empty_item_list(range); @@ -525,6 +541,7 @@ layout_wrap_whitespace(Application_Links *app, Arena *arena, Buffer_ID buffer, lr_tb_write_blank(&pos_vars, arena, &list, range.first); } else{ + b32 skipping_leading_whitespace = false; b32 first_of_the_line = true; Newline_Layout_Vars newline_vars = get_newline_layout_vars(); @@ -533,6 +550,7 @@ layout_wrap_whitespace(Application_Links *app, Arena *arena, Buffer_ID buffer, u8 *word_ptr = ptr; if (character_is_whitespace(*ptr)){ + skipping_leading_whitespace = (virt_indent == LayoutVirtualIndent_On); goto consuming_whitespace; } @@ -598,6 +616,23 @@ layout_wrap_whitespace(Application_Links *app, Arena *arena, Buffer_ID buffer, i64 index = layout_index_from_ptr(ptr, text.str, range.first); switch (*ptr){ + case '\t': + case ' ': + { + newline_layout_consume_default(&newline_vars); + f32 advance = lr_tb_advance(&pos_vars, *ptr); + if (!skipping_leading_whitespace){ + if (!first_of_the_line && lr_tb_crosses_width(&pos_vars, advance)){ + lr_tb_next_line(&pos_vars); + } + lr_tb_write_with_advance(&pos_vars, advance, arena, &list, index, *ptr); + first_of_the_line = false; + } + else{ + lr_tb_advance_x_without_item(&pos_vars, advance); + } + }break; + default: { newline_layout_consume_default(&newline_vars); @@ -605,8 +640,7 @@ layout_wrap_whitespace(Application_Links *app, Arena *arena, Buffer_ID buffer, if (!first_of_the_line && lr_tb_crosses_width(&pos_vars, advance)){ lr_tb_next_line(&pos_vars); } - lr_tb_write_with_advance(&pos_vars, advance, - arena, &list, index, *ptr); + lr_tb_write_with_advance(&pos_vars, advance, arena, &list, index, *ptr); first_of_the_line = false; }break; @@ -637,89 +671,71 @@ layout_wrap_whitespace(Application_Links *app, Arena *arena, Buffer_ID buffer, } function Layout_Item_List -layout_virt_indent_literal_unwrapped(Application_Links *app, Arena *arena, - Buffer_ID buffer, Range_i64 range, Face_ID face, - f32 width){ - Scratch_Block scratch(app); - - Layout_Item_List list = get_empty_item_list(range); - - String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); - - Face_Advance_Map advance_map = get_face_advance_map(app, face); - Face_Metrics metrics = get_face_metrics(app, face); - LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, width); - - if (text.size == 0){ - lr_tb_write_blank(&pos_vars, arena, &list, range.start); +layout_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_unwrapped__inner(app, arena, buffer, range, face, width, LayoutVirtualIndent_Off)); +} + +function Layout_Item_List +layout_wrap_whitespace(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_wrap_whitespace__inner(app, arena, buffer, range, face, width, LayoutVirtualIndent_Off)); +} + +function Layout_Item_List +layout_basic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ + Layout_Item_List result = {}; + switch (kind){ + case Layout_Unwrapped: + { + result = layout_unwrapped(app, arena, buffer, range, face, width); + }break; + case Layout_Wrapped: + { + result = layout_wrap_whitespace(app, arena, buffer, range, face, width); + }break; } - else{ - b32 skipping_leading_whitespace = true; - Newline_Layout_Vars newline_vars = get_newline_layout_vars(); - - u8 *ptr = text.str; - u8 *end_ptr = ptr + text.size; - for (;ptr < end_ptr;){ - Character_Consume_Result consume = utf8_consume(ptr, (umem)(end_ptr - ptr)); - - if (!character_is_whitespace(consume.codepoint)){ - skipping_leading_whitespace = false; - } - - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - switch (consume.codepoint){ - case '\t': - case ' ': - { - newline_layout_consume_default(&newline_vars); - f32 advance = lr_tb_advance(&pos_vars, consume.codepoint); - if (!skipping_leading_whitespace){ - lr_tb_write_with_advance(&pos_vars, advance, - arena, &list, index, - consume.codepoint); - } - else{ - lr_tb_advance_x_without_item(&pos_vars, advance); - } - }break; - - default: - { - newline_layout_consume_default(&newline_vars); - lr_tb_write(&pos_vars, arena, &list, index, consume.codepoint); - }break; - - case '\r': - { - newline_layout_consume_CR(&newline_vars, index); - }break; - - case '\n': - { - i64 newline_index = newline_layout_consume_LF(&newline_vars, index); - lr_tb_write_blank(&pos_vars, arena, &list, newline_index); - lr_tb_next_line(&pos_vars); - }break; - - case max_u32: - { - newline_layout_consume_default(&newline_vars); - lr_tb_write_byte(&pos_vars, arena, &list, index, *ptr); - }break; - } - - ptr += consume.inc; - } - - if (newline_layout_consume_finish(&newline_vars)){ - i64 index = layout_index_from_ptr(ptr, text.str, range.first); - lr_tb_write_blank(&pos_vars, arena, &list, index); - } + return(result); +} + +function Layout_Item_List +layout_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); + return(layout_basic(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); +} + +function Layout_Item_List +layout_virt_indent_literal_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_unwrapped__inner(app, arena, buffer, range, face, width, LayoutVirtualIndent_On)); +} + +function Layout_Item_List +layout_virt_indent_literal_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + return(layout_wrap_whitespace__inner(app, arena, buffer, range, face, width, LayoutVirtualIndent_On)); +} + +function Layout_Item_List +layout_virt_indent_literal(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ + Layout_Item_List result = {}; + switch (kind){ + case Layout_Unwrapped: + { + result = layout_virt_indent_literal_unwrapped(app, arena, buffer, range, face, width); + }break; + case Layout_Wrapped: + { + result = layout_virt_indent_literal_wrapped(app, arena, buffer, range, face, width); + }break; } - - layout_item_list_finish(&list, -pos_vars.line_to_text_shift); - - return(list); + return(result); +} + +function Layout_Item_List +layout_virt_indent_literal_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); + b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); + return(layout_virt_indent_literal(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); } // BOTTOM diff --git a/custom/4coder_layout_rule.h b/custom/4coder_layout_rule.h index 0fd1cc43..702e1783 100644 --- a/custom/4coder_layout_rule.h +++ b/custom/4coder_layout_rule.h @@ -33,6 +33,18 @@ struct Layout_Reflex{ Face_ID face; }; +typedef i32 Layout_Wrap_Kind; +enum{ + Layout_Unwrapped, + Layout_Wrapped, +}; + +typedef i32 Layout_Virtual_Indent; +enum{ + LayoutVirtualIndent_Off, + LayoutVirtualIndent_On, +}; + #endif // BOTTOM diff --git a/custom/4coder_token.h b/custom/4coder_token.h index 4a138e47..fbb14591 100644 --- a/custom/4coder_token.h +++ b/custom/4coder_token.h @@ -61,6 +61,11 @@ struct Token{ u16 sub_flags; }; +struct Token_Pair{ + Token a; + Token b; +}; + struct Token_Array{ Token *tokens; i64 count; diff --git a/custom/4coder_tutorial.cpp b/custom/4coder_tutorial.cpp index fdfde628..79b5b811 100644 --- a/custom/4coder_tutorial.cpp +++ b/custom/4coder_tutorial.cpp @@ -90,7 +90,6 @@ tutorial_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ Face_ID face = get_face_id(app, 0); tutorial_init_title_face(app); Face_Metrics metrics = get_face_metrics(app, face); - Face_Metrics tut_metrics = get_face_metrics(app, tutorial.face); //////// @@ -125,7 +124,7 @@ tutorial_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ if (is_active_view){ if (!tutorial.is_active){ view_enqueue_command_function(app, view_id, tutorial_activate); - } + } } else{ if (tutorial.is_active){ @@ -152,25 +151,25 @@ tutorial_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ Rect_f32_Pair pair = rect_split_left_right(footer, b_width); footer = pair.max; footer.x0 += 10.f; - if (tutorial.slide_index > 0){ - if (draw_button(app, pair.min, m_p, face, string_u8_litexpr("prev"))){ - tutorial.hover_action = TutorialAction_Prev; + if (tutorial.slide_index > 0){ + if (draw_button(app, pair.min, m_p, face, string_u8_litexpr("prev"))){ + tutorial.hover_action = TutorialAction_Prev; + } } } -} -{ + { Rect_f32_Pair pair = rect_split_left_right(footer, b_width); footer = pair.max; footer.x0 += 10.f; - if (tutorial.slide_index < tutorial.slide_count - 1){ - if (draw_button(app, pair.min, m_p, face, string_u8_litexpr("next"))){ - tutorial.hover_action = TutorialAction_Next; + if (tutorial.slide_index < tutorial.slide_count - 1){ + if (draw_button(app, pair.min, m_p, face, string_u8_litexpr("next"))){ + tutorial.hover_action = TutorialAction_Next; + } } } - } - -{ + + { Rect_f32_Pair pair = rect_split_left_right(footer, b_width); footer = pair.max; footer.x0 += 10.f; @@ -178,16 +177,16 @@ tutorial_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ pair = rect_split_left_right(footer, b_width); Rect_f32 restart_box = pair.min; - if (tutorial.slide_index == tutorial.slide_count - 1){ - if (draw_button(app, exit_box, m_p, face, string_u8_litexpr("end"))){ - tutorial.hover_action = TutorialAction_Exit; - } - + if (tutorial.slide_index == tutorial.slide_count - 1){ + if (draw_button(app, exit_box, m_p, face, string_u8_litexpr("end"))){ + tutorial.hover_action = TutorialAction_Exit; + } + if (draw_button(app, restart_box, m_p, face, string_u8_litexpr("restart"))){ - tutorial.hover_action = TutorialAction_Restart; + tutorial.hover_action = TutorialAction_Restart; + } } } -} } else{ draw_fancy_line(app, 0, fcolor_zero(), &slide.short_details, title_p); @@ -214,7 +213,7 @@ tutorial_run_loop(Application_Links *app) break; } - b32 handled = true; + b32 handled = true; switch (in.event.kind){ case InputEventKind_MouseButton: { @@ -257,7 +256,7 @@ tutorial_run_loop(Application_Links *app) handled = false; }break; } - + if (!handled){ Mapping *mapping = ctx.mapping; Command_Map *map = mapping_get_map(mapping, ctx.map_id); @@ -335,7 +334,7 @@ hms_demo_tutorial_binding_line(Application_Links *app, Arena *arena, Fancy_Block } f32 pad_size = 0.f; if (fill_size < 40.f){ - pad_size = 40.f - fill_size; + pad_size = 40.f - fill_size; } Fancy_Line *line = line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index 4544f6c5..ed8071de 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -2,7 +2,7 @@ #define command_id(c) (fcoder_metacmd_ID_##c) #define command_metadata(c) (&fcoder_metacmd_table[command_id(c)]) #define command_metadata_by_id(id) (&fcoder_metacmd_table[id]) -#define command_one_past_last_id 216 +#define command_one_past_last_id 217 #if defined(CUSTOM_COMMAND_SIG) #define PROC_LINKS(x,y) x #else @@ -94,6 +94,7 @@ CUSTOM_COMMAND_SIG(decrease_face_size); CUSTOM_COMMAND_SIG(mouse_wheel_change_face_size); CUSTOM_COMMAND_SIG(toggle_show_whitespace); CUSTOM_COMMAND_SIG(toggle_line_numbers); +CUSTOM_COMMAND_SIG(toggle_line_wrap); CUSTOM_COMMAND_SIG(exit_4coder); CUSTOM_COMMAND_SIG(goto_line); CUSTOM_COMMAND_SIG(search); @@ -237,7 +238,7 @@ char *source_name; i32 source_name_len; i32 line_number; }; -static Command_Metadata fcoder_metacmd_table[216] = { +static Command_Metadata fcoder_metacmd_table[217] = { { PROC_LINKS(default_view_input_handler, 0), false, "default_view_input_handler", 26, "Input consumption loop for default view behavior", 48, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 56 }, { PROC_LINKS(profile_enable, 0), false, "profile_enable", 14, "Allow 4coder's self profiler to gather new profiling information.", 65, "w:\\4ed\\code\\custom\\4coder_profile.cpp", 37, 207 }, { 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, 214 }, @@ -248,7 +249,7 @@ static Command_Metadata fcoder_metacmd_table[216] = { { PROC_LINKS(seek_end_of_line, 0), false, "seek_end_of_line", 16, "Seeks the cursor to the end of the visual line.", 47, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2175 }, { PROC_LINKS(goto_beginning_of_file, 0), false, "goto_beginning_of_file", 22, "Sets the cursor to the beginning of the file.", 45, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2181 }, { PROC_LINKS(goto_end_of_file, 0), false, "goto_end_of_file", 16, "Sets the cursor to the end of the file.", 39, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2189 }, -{ PROC_LINKS(toggle_virtual_whitespace, 0), false, "toggle_virtual_whitespace", 25, "Toggles the current buffer's virtual whitespace status.", 55, "w:\\4ed\\code\\custom\\4coder_code_index.cpp", 40, 798 }, +{ PROC_LINKS(toggle_virtual_whitespace, 0), false, "toggle_virtual_whitespace", 25, "Toggles the current buffer's virtual whitespace status.", 55, "w:\\4ed\\code\\custom\\4coder_code_index.cpp", 40, 945 }, { PROC_LINKS(change_active_panel, 0), false, "change_active_panel", 19, "Change the currently active panel, moving to the panel with the next highest view_id.", 85, "w:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 284 }, { PROC_LINKS(change_active_panel_backwards, 0), false, "change_active_panel_backwards", 29, "Change the currently active panel, moving to the panel with the next lowest view_id.", 84, "w:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 290 }, { PROC_LINKS(open_panel_vsplit, 0), false, "open_panel_vsplit", 17, "Create a new panel by vertically splitting the active panel.", 60, "w:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 300 }, @@ -323,40 +324,41 @@ static Command_Metadata fcoder_metacmd_table[216] = { { PROC_LINKS(mouse_wheel_change_face_size, 0), false, "mouse_wheel_change_face_size", 28, "Reads the state of the mouse wheel and uses it to either increase or decrease the face size.", 92, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 703 }, { PROC_LINKS(toggle_show_whitespace, 0), false, "toggle_show_whitespace", 22, "Toggles the current buffer's whitespace visibility status.", 58, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 720 }, { PROC_LINKS(toggle_line_numbers, 0), false, "toggle_line_numbers", 19, "Toggles the left margin line numbers.", 37, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 729 }, -{ PROC_LINKS(exit_4coder, 0), false, "exit_4coder", 11, "Attempts to close 4coder.", 25, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 735 }, -{ PROC_LINKS(goto_line, 0), false, "goto_line", 9, "Queries the user for a number, and jumps the cursor to the corresponding line.", 78, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 743 }, -{ PROC_LINKS(search, 0), false, "search", 6, "Begins an incremental search down through the current buffer for a user specified string.", 89, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 971 }, -{ PROC_LINKS(reverse_search, 0), false, "reverse_search", 14, "Begins an incremental search up through the current buffer for a user specified string.", 87, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 977 }, -{ PROC_LINKS(search_identifier, 0), false, "search_identifier", 17, "Begins an incremental search down through the current buffer for the word or token under the cursor.", 100, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 983 }, -{ PROC_LINKS(reverse_search_identifier, 0), false, "reverse_search_identifier", 25, "Begins an incremental search up through the current buffer for the word or token under the cursor.", 98, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 989 }, -{ PROC_LINKS(replace_in_range, 0), false, "replace_in_range", 16, "Queries the user for a needle and string. Replaces all occurences of needle with string in the range between cursor and the mark in the active buffer.", 150, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1036 }, -{ PROC_LINKS(replace_in_buffer, 0), false, "replace_in_buffer", 17, "Queries the user for a needle and string. Replaces all occurences of needle with string in the active buffer.", 109, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1045 }, -{ PROC_LINKS(replace_in_all_buffers, 0), false, "replace_in_all_buffers", 22, "Queries the user for a needle and string. Replaces all occurences of needle with string in all editable buffers.", 112, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1054 }, -{ PROC_LINKS(query_replace, 0), false, "query_replace", 13, "Queries the user for two strings, and incrementally replaces every occurence of the first string with the second string.", 120, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1144 }, -{ PROC_LINKS(query_replace_identifier, 0), false, "query_replace_identifier", 24, "Queries the user for a string, and incrementally replace every occurence of the word or token found at the cursor with the specified string.", 140, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1165 }, -{ PROC_LINKS(query_replace_selection, 0), false, "query_replace_selection", 23, "Queries the user for a string, and incrementally replace every occurence of the string found in the selected range with the specified string.", 141, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1181 }, -{ PROC_LINKS(save_all_dirty_buffers, 0), false, "save_all_dirty_buffers", 22, "Saves all buffers marked dirty (showing the '*' indicator).", 59, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1217 }, -{ PROC_LINKS(delete_file_query, 0), false, "delete_file_query", 17, "Deletes the file of the current buffer if 4coder has the appropriate access rights. Will ask the user for confirmation first.", 125, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1242 }, -{ PROC_LINKS(save_to_query, 0), false, "save_to_query", 13, "Queries the user for a file name and saves the contents of the current buffer, altering the buffer's name too.", 110, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1286 }, -{ PROC_LINKS(rename_file_query, 0), false, "rename_file_query", 17, "Queries the user for a new name and renames the file of the current buffer, altering the buffer's name too.", 107, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1319 }, -{ PROC_LINKS(make_directory_query, 0), false, "make_directory_query", 20, "Queries the user for a name and creates a new directory with the given name.", 76, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1357 }, -{ PROC_LINKS(move_line_up, 0), false, "move_line_up", 12, "Swaps the line under the cursor with the line above it, and moves the cursor up with it.", 88, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1391 }, -{ PROC_LINKS(move_line_down, 0), false, "move_line_down", 14, "Swaps the line under the cursor with the line below it, and moves the cursor down with it.", 90, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1397 }, -{ PROC_LINKS(duplicate_line, 0), false, "duplicate_line", 14, "Create a copy of the line on which the cursor sits.", 51, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1403 }, -{ PROC_LINKS(delete_line, 0), false, "delete_line", 11, "Delete the line the on which the cursor sits.", 45, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1417 }, -{ PROC_LINKS(open_file_in_quotes, 0), false, "open_file_in_quotes", 19, "Reads a filename from surrounding '\"' characters and attempts to open the corresponding file.", 94, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1482 }, -{ PROC_LINKS(open_matching_file_cpp, 0), false, "open_matching_file_cpp", 22, "If the current file is a *.cpp or *.h, attempts to open the corresponding *.h or *.cpp file in the other view.", 110, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1514 }, -{ PROC_LINKS(view_buffer_other_panel, 0), false, "view_buffer_other_panel", 23, "Set the other non-active panel to view the buffer that the active panel views, and switch to that panel.", 104, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1527 }, -{ 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, 1539 }, -{ PROC_LINKS(kill_buffer, 0), false, "kill_buffer", 11, "Kills the current buffer.", 25, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1563 }, -{ PROC_LINKS(save, 0), false, "save", 4, "Saves the current buffer.", 25, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1571 }, -{ PROC_LINKS(reopen, 0), false, "reopen", 6, "Reopen the current buffer from the hard drive.", 46, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1581 }, -{ PROC_LINKS(undo, 0), false, "undo", 4, "Advances backwards through the undo history of the current buffer.", 66, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1806 }, -{ PROC_LINKS(redo, 0), false, "redo", 4, "Advances forwards through the undo history of the current buffer.", 65, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1819 }, -{ PROC_LINKS(undo_all_buffers, 0), false, "undo_all_buffers", 16, "Advances backward through the undo history in the buffer containing the most recent regular edit.", 97, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1833 }, -{ PROC_LINKS(redo_all_buffers, 0), false, "redo_all_buffers", 16, "Advances forward through the undo history in the buffer containing the most recent regular edit.", 96, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1904 }, -{ PROC_LINKS(open_in_other, 0), false, "open_in_other", 13, "Interactively opens a file in the other panel.", 46, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2005 }, -{ PROC_LINKS(default_file_externally_modified, 0), false, "default_file_externally_modified", 32, "Notes the external modification of attached files by printing a message.", 72, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2011 }, +{ PROC_LINKS(toggle_line_wrap, 0), false, "toggle_line_wrap", 16, "Toggles the line wrap setting on this buffer.", 45, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 735 }, +{ PROC_LINKS(exit_4coder, 0), false, "exit_4coder", 11, "Attempts to close 4coder.", 25, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 748 }, +{ PROC_LINKS(goto_line, 0), false, "goto_line", 9, "Queries the user for a number, and jumps the cursor to the corresponding line.", 78, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 756 }, +{ PROC_LINKS(search, 0), false, "search", 6, "Begins an incremental search down through the current buffer for a user specified string.", 89, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 984 }, +{ PROC_LINKS(reverse_search, 0), false, "reverse_search", 14, "Begins an incremental search up through the current buffer for a user specified string.", 87, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 990 }, +{ PROC_LINKS(search_identifier, 0), false, "search_identifier", 17, "Begins an incremental search down through the current buffer for the word or token under the cursor.", 100, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 996 }, +{ PROC_LINKS(reverse_search_identifier, 0), false, "reverse_search_identifier", 25, "Begins an incremental search up through the current buffer for the word or token under the cursor.", 98, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1002 }, +{ PROC_LINKS(replace_in_range, 0), false, "replace_in_range", 16, "Queries the user for a needle and string. Replaces all occurences of needle with string in the range between cursor and the mark in the active buffer.", 150, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1049 }, +{ PROC_LINKS(replace_in_buffer, 0), false, "replace_in_buffer", 17, "Queries the user for a needle and string. Replaces all occurences of needle with string in the active buffer.", 109, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1058 }, +{ PROC_LINKS(replace_in_all_buffers, 0), false, "replace_in_all_buffers", 22, "Queries the user for a needle and string. Replaces all occurences of needle with string in all editable buffers.", 112, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1067 }, +{ PROC_LINKS(query_replace, 0), false, "query_replace", 13, "Queries the user for two strings, and incrementally replaces every occurence of the first string with the second string.", 120, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1157 }, +{ PROC_LINKS(query_replace_identifier, 0), false, "query_replace_identifier", 24, "Queries the user for a string, and incrementally replace every occurence of the word or token found at the cursor with the specified string.", 140, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1178 }, +{ PROC_LINKS(query_replace_selection, 0), false, "query_replace_selection", 23, "Queries the user for a string, and incrementally replace every occurence of the string found in the selected range with the specified string.", 141, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1194 }, +{ PROC_LINKS(save_all_dirty_buffers, 0), false, "save_all_dirty_buffers", 22, "Saves all buffers marked dirty (showing the '*' indicator).", 59, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1230 }, +{ PROC_LINKS(delete_file_query, 0), false, "delete_file_query", 17, "Deletes the file of the current buffer if 4coder has the appropriate access rights. Will ask the user for confirmation first.", 125, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1255 }, +{ PROC_LINKS(save_to_query, 0), false, "save_to_query", 13, "Queries the user for a file name and saves the contents of the current buffer, altering the buffer's name too.", 110, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1299 }, +{ PROC_LINKS(rename_file_query, 0), false, "rename_file_query", 17, "Queries the user for a new name and renames the file of the current buffer, altering the buffer's name too.", 107, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1332 }, +{ PROC_LINKS(make_directory_query, 0), false, "make_directory_query", 20, "Queries the user for a name and creates a new directory with the given name.", 76, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1370 }, +{ PROC_LINKS(move_line_up, 0), false, "move_line_up", 12, "Swaps the line under the cursor with the line above it, and moves the cursor up with it.", 88, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1404 }, +{ PROC_LINKS(move_line_down, 0), false, "move_line_down", 14, "Swaps the line under the cursor with the line below it, and moves the cursor down with it.", 90, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1410 }, +{ PROC_LINKS(duplicate_line, 0), false, "duplicate_line", 14, "Create a copy of the line on which the cursor sits.", 51, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1416 }, +{ PROC_LINKS(delete_line, 0), false, "delete_line", 11, "Delete the line the on which the cursor sits.", 45, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1430 }, +{ PROC_LINKS(open_file_in_quotes, 0), false, "open_file_in_quotes", 19, "Reads a filename from surrounding '\"' characters and attempts to open the corresponding file.", 94, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1495 }, +{ PROC_LINKS(open_matching_file_cpp, 0), false, "open_matching_file_cpp", 22, "If the current file is a *.cpp or *.h, attempts to open the corresponding *.h or *.cpp file in the other view.", 110, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1527 }, +{ PROC_LINKS(view_buffer_other_panel, 0), false, "view_buffer_other_panel", 23, "Set the other non-active panel to view the buffer that the active panel views, and switch to that panel.", 104, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1540 }, +{ 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, 1552 }, +{ PROC_LINKS(kill_buffer, 0), false, "kill_buffer", 11, "Kills the current buffer.", 25, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1576 }, +{ PROC_LINKS(save, 0), false, "save", 4, "Saves the current buffer.", 25, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1584 }, +{ PROC_LINKS(reopen, 0), false, "reopen", 6, "Reopen the current buffer from the hard drive.", 46, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1594 }, +{ PROC_LINKS(undo, 0), false, "undo", 4, "Advances backwards through the undo history of the current buffer.", 66, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1819 }, +{ PROC_LINKS(redo, 0), false, "redo", 4, "Advances forwards through the undo history of the current buffer.", 65, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1832 }, +{ PROC_LINKS(undo_all_buffers, 0), false, "undo_all_buffers", 16, "Advances backward through the undo history in the buffer containing the most recent regular edit.", 97, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1846 }, +{ PROC_LINKS(redo_all_buffers, 0), false, "redo_all_buffers", 16, "Advances forward through the undo history in the buffer containing the most recent regular edit.", 96, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1917 }, +{ PROC_LINKS(open_in_other, 0), false, "open_in_other", 13, "Interactively opens a file in the other panel.", 46, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2018 }, +{ PROC_LINKS(default_file_externally_modified, 0), false, "default_file_externally_modified", 32, "Notes the external modification of attached files by printing a message.", 72, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2024 }, { PROC_LINKS(set_eol_mode_to_crlf, 0), false, "set_eol_mode_to_crlf", 20, "Puts the buffer in crlf line ending mode.", 41, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 86 }, { PROC_LINKS(set_eol_mode_to_lf, 0), false, "set_eol_mode_to_lf", 18, "Puts the buffer in lf line ending mode.", 39, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 97 }, { PROC_LINKS(set_eol_mode_to_binary, 0), false, "set_eol_mode_to_binary", 22, "Puts the buffer in bin line ending mode.", 40, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 108 }, @@ -451,7 +453,7 @@ static Command_Metadata fcoder_metacmd_table[216] = { { PROC_LINKS(miblo_decrement_time_stamp_minute, 0), false, "miblo_decrement_time_stamp_minute", 33, "Decrement a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 249 }, { PROC_LINKS(profile_inspect, 0), true, "profile_inspect", 15, "Inspect all currently collected profiling information in 4coder's self profiler.", 80, "w:\\4ed\\code\\custom\\4coder_profile_inspect.cpp", 45, 779 }, { PROC_LINKS(kill_tutorial, 0), false, "kill_tutorial", 13, "If there is an active tutorial, kill it.", 40, "w:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 9 }, -{ PROC_LINKS(hms_demo_tutorial, 0), false, "hms_demo_tutorial", 17, "Tutorial for built in 4coder bindings and features.", 51, "w:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 801 }, +{ PROC_LINKS(hms_demo_tutorial, 0), false, "hms_demo_tutorial", 17, "Tutorial for built in 4coder bindings and features.", 51, "w:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 821 }, { PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 7 }, { PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 22 }, }; @@ -540,135 +542,136 @@ static i32 fcoder_metacmd_ID_decrease_face_size = 81; static i32 fcoder_metacmd_ID_mouse_wheel_change_face_size = 82; static i32 fcoder_metacmd_ID_toggle_show_whitespace = 83; static i32 fcoder_metacmd_ID_toggle_line_numbers = 84; -static i32 fcoder_metacmd_ID_exit_4coder = 85; -static i32 fcoder_metacmd_ID_goto_line = 86; -static i32 fcoder_metacmd_ID_search = 87; -static i32 fcoder_metacmd_ID_reverse_search = 88; -static i32 fcoder_metacmd_ID_search_identifier = 89; -static i32 fcoder_metacmd_ID_reverse_search_identifier = 90; -static i32 fcoder_metacmd_ID_replace_in_range = 91; -static i32 fcoder_metacmd_ID_replace_in_buffer = 92; -static i32 fcoder_metacmd_ID_replace_in_all_buffers = 93; -static i32 fcoder_metacmd_ID_query_replace = 94; -static i32 fcoder_metacmd_ID_query_replace_identifier = 95; -static i32 fcoder_metacmd_ID_query_replace_selection = 96; -static i32 fcoder_metacmd_ID_save_all_dirty_buffers = 97; -static i32 fcoder_metacmd_ID_delete_file_query = 98; -static i32 fcoder_metacmd_ID_save_to_query = 99; -static i32 fcoder_metacmd_ID_rename_file_query = 100; -static i32 fcoder_metacmd_ID_make_directory_query = 101; -static i32 fcoder_metacmd_ID_move_line_up = 102; -static i32 fcoder_metacmd_ID_move_line_down = 103; -static i32 fcoder_metacmd_ID_duplicate_line = 104; -static i32 fcoder_metacmd_ID_delete_line = 105; -static i32 fcoder_metacmd_ID_open_file_in_quotes = 106; -static i32 fcoder_metacmd_ID_open_matching_file_cpp = 107; -static i32 fcoder_metacmd_ID_view_buffer_other_panel = 108; -static i32 fcoder_metacmd_ID_swap_panels = 109; -static i32 fcoder_metacmd_ID_kill_buffer = 110; -static i32 fcoder_metacmd_ID_save = 111; -static i32 fcoder_metacmd_ID_reopen = 112; -static i32 fcoder_metacmd_ID_undo = 113; -static i32 fcoder_metacmd_ID_redo = 114; -static i32 fcoder_metacmd_ID_undo_all_buffers = 115; -static i32 fcoder_metacmd_ID_redo_all_buffers = 116; -static i32 fcoder_metacmd_ID_open_in_other = 117; -static i32 fcoder_metacmd_ID_default_file_externally_modified = 118; -static i32 fcoder_metacmd_ID_set_eol_mode_to_crlf = 119; -static i32 fcoder_metacmd_ID_set_eol_mode_to_lf = 120; -static i32 fcoder_metacmd_ID_set_eol_mode_to_binary = 121; -static i32 fcoder_metacmd_ID_set_eol_mode_from_contents = 122; -static i32 fcoder_metacmd_ID_interactive_switch_buffer = 123; -static i32 fcoder_metacmd_ID_interactive_kill_buffer = 124; -static i32 fcoder_metacmd_ID_interactive_open_or_new = 125; -static i32 fcoder_metacmd_ID_interactive_new = 126; -static i32 fcoder_metacmd_ID_interactive_open = 127; -static i32 fcoder_metacmd_ID_command_lister = 128; -static i32 fcoder_metacmd_ID_auto_indent_whole_file = 129; -static i32 fcoder_metacmd_ID_auto_indent_line_at_cursor = 130; -static i32 fcoder_metacmd_ID_auto_indent_range = 131; -static i32 fcoder_metacmd_ID_write_text_and_auto_indent = 132; -static i32 fcoder_metacmd_ID_list_all_locations = 133; -static i32 fcoder_metacmd_ID_list_all_substring_locations = 134; -static i32 fcoder_metacmd_ID_list_all_locations_case_insensitive = 135; -static i32 fcoder_metacmd_ID_list_all_substring_locations_case_insensitive = 136; -static i32 fcoder_metacmd_ID_list_all_locations_of_identifier = 137; -static i32 fcoder_metacmd_ID_list_all_locations_of_identifier_case_insensitive = 138; -static i32 fcoder_metacmd_ID_list_all_locations_of_selection = 139; -static i32 fcoder_metacmd_ID_list_all_locations_of_selection_case_insensitive = 140; -static i32 fcoder_metacmd_ID_list_all_locations_of_type_definition = 141; -static i32 fcoder_metacmd_ID_list_all_locations_of_type_definition_of_identifier = 142; -static i32 fcoder_metacmd_ID_word_complete = 143; -static i32 fcoder_metacmd_ID_word_complete_drop_down = 144; -static i32 fcoder_metacmd_ID_goto_jump_at_cursor = 145; -static i32 fcoder_metacmd_ID_goto_jump_at_cursor_same_panel = 146; -static i32 fcoder_metacmd_ID_goto_next_jump = 147; -static i32 fcoder_metacmd_ID_goto_prev_jump = 148; -static i32 fcoder_metacmd_ID_goto_next_jump_no_skips = 149; -static i32 fcoder_metacmd_ID_goto_prev_jump_no_skips = 150; -static i32 fcoder_metacmd_ID_goto_first_jump = 151; -static i32 fcoder_metacmd_ID_goto_first_jump_same_panel_sticky = 152; -static i32 fcoder_metacmd_ID_if_read_only_goto_position = 153; -static i32 fcoder_metacmd_ID_if_read_only_goto_position_same_panel = 154; -static i32 fcoder_metacmd_ID_view_jump_list_with_lister = 155; -static i32 fcoder_metacmd_ID_show_the_log_graph = 156; -static i32 fcoder_metacmd_ID_copy = 157; -static i32 fcoder_metacmd_ID_cut = 158; -static i32 fcoder_metacmd_ID_paste = 159; -static i32 fcoder_metacmd_ID_paste_next = 160; -static i32 fcoder_metacmd_ID_paste_and_indent = 161; -static i32 fcoder_metacmd_ID_paste_next_and_indent = 162; -static i32 fcoder_metacmd_ID_execute_previous_cli = 163; -static i32 fcoder_metacmd_ID_execute_any_cli = 164; -static i32 fcoder_metacmd_ID_build_search = 165; -static i32 fcoder_metacmd_ID_build_in_build_panel = 166; -static i32 fcoder_metacmd_ID_close_build_panel = 167; -static i32 fcoder_metacmd_ID_change_to_build_panel = 168; -static i32 fcoder_metacmd_ID_close_all_code = 169; -static i32 fcoder_metacmd_ID_open_all_code = 170; -static i32 fcoder_metacmd_ID_open_all_code_recursive = 171; -static i32 fcoder_metacmd_ID_load_project = 172; -static i32 fcoder_metacmd_ID_project_fkey_command = 173; -static i32 fcoder_metacmd_ID_project_go_to_root_directory = 174; -static i32 fcoder_metacmd_ID_setup_new_project = 175; -static i32 fcoder_metacmd_ID_setup_build_bat = 176; -static i32 fcoder_metacmd_ID_setup_build_sh = 177; -static i32 fcoder_metacmd_ID_setup_build_bat_and_sh = 178; -static i32 fcoder_metacmd_ID_project_command_lister = 179; -static i32 fcoder_metacmd_ID_list_all_functions_current_buffer = 180; -static i32 fcoder_metacmd_ID_list_all_functions_current_buffer_lister = 181; -static i32 fcoder_metacmd_ID_list_all_functions_all_buffers = 182; -static i32 fcoder_metacmd_ID_list_all_functions_all_buffers_lister = 183; -static i32 fcoder_metacmd_ID_select_surrounding_scope = 184; -static i32 fcoder_metacmd_ID_select_surrounding_scope_maximal = 185; -static i32 fcoder_metacmd_ID_select_next_scope_absolute = 186; -static i32 fcoder_metacmd_ID_select_next_scope_after_current = 187; -static i32 fcoder_metacmd_ID_select_prev_scope_absolute = 188; -static i32 fcoder_metacmd_ID_select_prev_top_most_scope = 189; -static i32 fcoder_metacmd_ID_place_in_scope = 190; -static i32 fcoder_metacmd_ID_delete_current_scope = 191; -static i32 fcoder_metacmd_ID_open_long_braces = 192; -static i32 fcoder_metacmd_ID_open_long_braces_semicolon = 193; -static i32 fcoder_metacmd_ID_open_long_braces_break = 194; -static i32 fcoder_metacmd_ID_if0_off = 195; -static i32 fcoder_metacmd_ID_write_todo = 196; -static i32 fcoder_metacmd_ID_write_hack = 197; -static i32 fcoder_metacmd_ID_write_note = 198; -static i32 fcoder_metacmd_ID_write_block = 199; -static i32 fcoder_metacmd_ID_write_zero_struct = 200; -static i32 fcoder_metacmd_ID_comment_line = 201; -static i32 fcoder_metacmd_ID_uncomment_line = 202; -static i32 fcoder_metacmd_ID_comment_line_toggle = 203; -static i32 fcoder_metacmd_ID_snippet_lister = 204; -static i32 fcoder_metacmd_ID_miblo_increment_basic = 205; -static i32 fcoder_metacmd_ID_miblo_decrement_basic = 206; -static i32 fcoder_metacmd_ID_miblo_increment_time_stamp = 207; -static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp = 208; -static i32 fcoder_metacmd_ID_miblo_increment_time_stamp_minute = 209; -static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp_minute = 210; -static i32 fcoder_metacmd_ID_profile_inspect = 211; -static i32 fcoder_metacmd_ID_kill_tutorial = 212; -static i32 fcoder_metacmd_ID_hms_demo_tutorial = 213; -static i32 fcoder_metacmd_ID_default_startup = 214; -static i32 fcoder_metacmd_ID_default_try_exit = 215; +static i32 fcoder_metacmd_ID_toggle_line_wrap = 85; +static i32 fcoder_metacmd_ID_exit_4coder = 86; +static i32 fcoder_metacmd_ID_goto_line = 87; +static i32 fcoder_metacmd_ID_search = 88; +static i32 fcoder_metacmd_ID_reverse_search = 89; +static i32 fcoder_metacmd_ID_search_identifier = 90; +static i32 fcoder_metacmd_ID_reverse_search_identifier = 91; +static i32 fcoder_metacmd_ID_replace_in_range = 92; +static i32 fcoder_metacmd_ID_replace_in_buffer = 93; +static i32 fcoder_metacmd_ID_replace_in_all_buffers = 94; +static i32 fcoder_metacmd_ID_query_replace = 95; +static i32 fcoder_metacmd_ID_query_replace_identifier = 96; +static i32 fcoder_metacmd_ID_query_replace_selection = 97; +static i32 fcoder_metacmd_ID_save_all_dirty_buffers = 98; +static i32 fcoder_metacmd_ID_delete_file_query = 99; +static i32 fcoder_metacmd_ID_save_to_query = 100; +static i32 fcoder_metacmd_ID_rename_file_query = 101; +static i32 fcoder_metacmd_ID_make_directory_query = 102; +static i32 fcoder_metacmd_ID_move_line_up = 103; +static i32 fcoder_metacmd_ID_move_line_down = 104; +static i32 fcoder_metacmd_ID_duplicate_line = 105; +static i32 fcoder_metacmd_ID_delete_line = 106; +static i32 fcoder_metacmd_ID_open_file_in_quotes = 107; +static i32 fcoder_metacmd_ID_open_matching_file_cpp = 108; +static i32 fcoder_metacmd_ID_view_buffer_other_panel = 109; +static i32 fcoder_metacmd_ID_swap_panels = 110; +static i32 fcoder_metacmd_ID_kill_buffer = 111; +static i32 fcoder_metacmd_ID_save = 112; +static i32 fcoder_metacmd_ID_reopen = 113; +static i32 fcoder_metacmd_ID_undo = 114; +static i32 fcoder_metacmd_ID_redo = 115; +static i32 fcoder_metacmd_ID_undo_all_buffers = 116; +static i32 fcoder_metacmd_ID_redo_all_buffers = 117; +static i32 fcoder_metacmd_ID_open_in_other = 118; +static i32 fcoder_metacmd_ID_default_file_externally_modified = 119; +static i32 fcoder_metacmd_ID_set_eol_mode_to_crlf = 120; +static i32 fcoder_metacmd_ID_set_eol_mode_to_lf = 121; +static i32 fcoder_metacmd_ID_set_eol_mode_to_binary = 122; +static i32 fcoder_metacmd_ID_set_eol_mode_from_contents = 123; +static i32 fcoder_metacmd_ID_interactive_switch_buffer = 124; +static i32 fcoder_metacmd_ID_interactive_kill_buffer = 125; +static i32 fcoder_metacmd_ID_interactive_open_or_new = 126; +static i32 fcoder_metacmd_ID_interactive_new = 127; +static i32 fcoder_metacmd_ID_interactive_open = 128; +static i32 fcoder_metacmd_ID_command_lister = 129; +static i32 fcoder_metacmd_ID_auto_indent_whole_file = 130; +static i32 fcoder_metacmd_ID_auto_indent_line_at_cursor = 131; +static i32 fcoder_metacmd_ID_auto_indent_range = 132; +static i32 fcoder_metacmd_ID_write_text_and_auto_indent = 133; +static i32 fcoder_metacmd_ID_list_all_locations = 134; +static i32 fcoder_metacmd_ID_list_all_substring_locations = 135; +static i32 fcoder_metacmd_ID_list_all_locations_case_insensitive = 136; +static i32 fcoder_metacmd_ID_list_all_substring_locations_case_insensitive = 137; +static i32 fcoder_metacmd_ID_list_all_locations_of_identifier = 138; +static i32 fcoder_metacmd_ID_list_all_locations_of_identifier_case_insensitive = 139; +static i32 fcoder_metacmd_ID_list_all_locations_of_selection = 140; +static i32 fcoder_metacmd_ID_list_all_locations_of_selection_case_insensitive = 141; +static i32 fcoder_metacmd_ID_list_all_locations_of_type_definition = 142; +static i32 fcoder_metacmd_ID_list_all_locations_of_type_definition_of_identifier = 143; +static i32 fcoder_metacmd_ID_word_complete = 144; +static i32 fcoder_metacmd_ID_word_complete_drop_down = 145; +static i32 fcoder_metacmd_ID_goto_jump_at_cursor = 146; +static i32 fcoder_metacmd_ID_goto_jump_at_cursor_same_panel = 147; +static i32 fcoder_metacmd_ID_goto_next_jump = 148; +static i32 fcoder_metacmd_ID_goto_prev_jump = 149; +static i32 fcoder_metacmd_ID_goto_next_jump_no_skips = 150; +static i32 fcoder_metacmd_ID_goto_prev_jump_no_skips = 151; +static i32 fcoder_metacmd_ID_goto_first_jump = 152; +static i32 fcoder_metacmd_ID_goto_first_jump_same_panel_sticky = 153; +static i32 fcoder_metacmd_ID_if_read_only_goto_position = 154; +static i32 fcoder_metacmd_ID_if_read_only_goto_position_same_panel = 155; +static i32 fcoder_metacmd_ID_view_jump_list_with_lister = 156; +static i32 fcoder_metacmd_ID_show_the_log_graph = 157; +static i32 fcoder_metacmd_ID_copy = 158; +static i32 fcoder_metacmd_ID_cut = 159; +static i32 fcoder_metacmd_ID_paste = 160; +static i32 fcoder_metacmd_ID_paste_next = 161; +static i32 fcoder_metacmd_ID_paste_and_indent = 162; +static i32 fcoder_metacmd_ID_paste_next_and_indent = 163; +static i32 fcoder_metacmd_ID_execute_previous_cli = 164; +static i32 fcoder_metacmd_ID_execute_any_cli = 165; +static i32 fcoder_metacmd_ID_build_search = 166; +static i32 fcoder_metacmd_ID_build_in_build_panel = 167; +static i32 fcoder_metacmd_ID_close_build_panel = 168; +static i32 fcoder_metacmd_ID_change_to_build_panel = 169; +static i32 fcoder_metacmd_ID_close_all_code = 170; +static i32 fcoder_metacmd_ID_open_all_code = 171; +static i32 fcoder_metacmd_ID_open_all_code_recursive = 172; +static i32 fcoder_metacmd_ID_load_project = 173; +static i32 fcoder_metacmd_ID_project_fkey_command = 174; +static i32 fcoder_metacmd_ID_project_go_to_root_directory = 175; +static i32 fcoder_metacmd_ID_setup_new_project = 176; +static i32 fcoder_metacmd_ID_setup_build_bat = 177; +static i32 fcoder_metacmd_ID_setup_build_sh = 178; +static i32 fcoder_metacmd_ID_setup_build_bat_and_sh = 179; +static i32 fcoder_metacmd_ID_project_command_lister = 180; +static i32 fcoder_metacmd_ID_list_all_functions_current_buffer = 181; +static i32 fcoder_metacmd_ID_list_all_functions_current_buffer_lister = 182; +static i32 fcoder_metacmd_ID_list_all_functions_all_buffers = 183; +static i32 fcoder_metacmd_ID_list_all_functions_all_buffers_lister = 184; +static i32 fcoder_metacmd_ID_select_surrounding_scope = 185; +static i32 fcoder_metacmd_ID_select_surrounding_scope_maximal = 186; +static i32 fcoder_metacmd_ID_select_next_scope_absolute = 187; +static i32 fcoder_metacmd_ID_select_next_scope_after_current = 188; +static i32 fcoder_metacmd_ID_select_prev_scope_absolute = 189; +static i32 fcoder_metacmd_ID_select_prev_top_most_scope = 190; +static i32 fcoder_metacmd_ID_place_in_scope = 191; +static i32 fcoder_metacmd_ID_delete_current_scope = 192; +static i32 fcoder_metacmd_ID_open_long_braces = 193; +static i32 fcoder_metacmd_ID_open_long_braces_semicolon = 194; +static i32 fcoder_metacmd_ID_open_long_braces_break = 195; +static i32 fcoder_metacmd_ID_if0_off = 196; +static i32 fcoder_metacmd_ID_write_todo = 197; +static i32 fcoder_metacmd_ID_write_hack = 198; +static i32 fcoder_metacmd_ID_write_note = 199; +static i32 fcoder_metacmd_ID_write_block = 200; +static i32 fcoder_metacmd_ID_write_zero_struct = 201; +static i32 fcoder_metacmd_ID_comment_line = 202; +static i32 fcoder_metacmd_ID_uncomment_line = 203; +static i32 fcoder_metacmd_ID_comment_line_toggle = 204; +static i32 fcoder_metacmd_ID_snippet_lister = 205; +static i32 fcoder_metacmd_ID_miblo_increment_basic = 206; +static i32 fcoder_metacmd_ID_miblo_decrement_basic = 207; +static i32 fcoder_metacmd_ID_miblo_increment_time_stamp = 208; +static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp = 209; +static i32 fcoder_metacmd_ID_miblo_increment_time_stamp_minute = 210; +static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp_minute = 211; +static i32 fcoder_metacmd_ID_profile_inspect = 212; +static i32 fcoder_metacmd_ID_kill_tutorial = 213; +static i32 fcoder_metacmd_ID_hms_demo_tutorial = 214; +static i32 fcoder_metacmd_ID_default_startup = 215; +static i32 fcoder_metacmd_ID_default_try_exit = 216; #endif