diff --git a/4coder_custom.cpp b/4coder_custom.cpp index 634f06df..24e5a93e 100644 --- a/4coder_custom.cpp +++ b/4coder_custom.cpp @@ -407,6 +407,66 @@ CUSTOM_COMMAND_SIG(reverse_search){ isearch(app, 1); } +CUSTOM_COMMAND_SIG(rewrite_as_single_caps){ + File_View_Summary view; + Buffer_Summary buffer; + Range range; + String string; + int is_first, i; + + exec_command(app, cmdid_seek_token_left); + view = app->get_active_file_view(app); + range.min = view.cursor.pos; + + exec_command(app, cmdid_seek_token_right); + app->refresh_file_view(app, &view); + range.max = view.cursor.pos; + + string.str = (char*)app->memory; + string.size = range.max - range.min; + assert(string.size < app->memory_size); + + buffer = app->get_buffer(app, view.buffer_id); + app->buffer_read_range(app, &buffer, range.min, range.max, string.str); + + is_first = 1; + for (i = 0; i < string.size; ++i){ + if (char_is_alpha_true(string.str[i])){ + if (is_first) is_first = 0; + else string.str[i] = char_to_lower(string.str[i]); + } + else{ + is_first = 1; + } + } + + app->buffer_replace_range(app, &buffer, range.min, range.max, string.str, string.size); +} + +// TODO(allen): +// get range by specific "word" type (for example "get token range") +// read range by specific "word" type +// Dream API: for rewrite_as_single_caps +#if 0 +{ + rewrite = get_rewrite(app, ByToken); + string = get_rewrite_string(app, &rewrite, app->memory, app->memory_size); + + is_first = 1; + for (i = 0; i < string.size; ++i){ + if (char_is_alpha_true(string.str[i])){ + if (is_first) is_first = 0; + else string.str[i] = char_to_lower(string.str[i]); + } + else{ + is_first = 1; + } + } + + do_rewrite(app, &rewrite, string); +} +#endif + CUSTOM_COMMAND_SIG(replace_in_range){ Query_Bar replace; char replace_space[1024]; @@ -701,6 +761,61 @@ CUSTOM_COMMAND_SIG(write_and_auto_tab){ exec_command(app, cmdid_auto_tab_line_at_cursor); } +struct Scroll_Velocity{ + float x, y; +}; + +Scroll_Velocity scroll_velocity[16] = {0}; + +static int +smooth_camera_step(float target, float *current, float *vel, float S, float T){ + int result = 0; + float curr = *current; + float v = *vel; + if (curr != target){ + if (curr > target - .1f && curr < target + .1f){ + curr = target; + v = 1.f; + } + else{ + float L = curr + T*(target - curr); + + int sign = (target > curr) - (target < curr); + float V = curr + sign*v; + + if (sign > 0) curr = (LV)?(L):(V); + + if (curr == V){ + v *= S; + } + } + + *current = curr; + *vel = v; + result = 1; + } + return result; +} + +extern "C" SCROLL_RULE_SIG(scroll_rule){ + Scroll_Velocity *velocity = scroll_velocity + view_id; + int result = 0; + if (velocity->x == 0.f){ + velocity->x = 1.f; + velocity->y = 1.f; + } + + if (smooth_camera_step(target_y, scroll_y, &velocity->y, 40.f, 1.f/4.f)){ + result = 1; + } + if (smooth_camera_step(target_x, scroll_x, &velocity->x, 40.f, 1.f/4.f)){ + result = 1; + } + + return(result); +} + extern "C" GET_BINDING_DATA(get_bindings){ Bind_Helper context_actual = begin_bind_helper(data, size); Bind_Helper *context = &context_actual; @@ -830,14 +945,13 @@ extern "C" GET_BINDING_DATA(get_bindings){ bind(context, 'g', MDFR_CTRL, goto_line); bind(context, 'q', MDFR_CTRL, query_replace); bind(context, 'a', MDFR_CTRL, replace_in_range); + bind(context, 's', MDFR_ALT, rewrite_as_single_caps); bind(context, 'K', MDFR_CTRL, cmdid_kill_buffer); bind(context, 'O', MDFR_CTRL, cmdid_reopen); bind(context, 'w', MDFR_CTRL, cmdid_interactive_save_as); bind(context, 's', MDFR_CTRL, cmdid_save); - bind(context, ',', MDFR_ALT, switch_to_compilation); - bind(context, '\n', MDFR_SHIFT, write_and_auto_tab); bind(context, ' ', MDFR_SHIFT, cmdid_write_character); diff --git a/4coder_custom.h b/4coder_custom.h index 711c627e..7d7fea81 100644 --- a/4coder_custom.h +++ b/4coder_custom.h @@ -157,11 +157,13 @@ struct Query_Bar{ #define GET_BINDING_DATA(name) int name(void *data, int size) #define CUSTOM_COMMAND_SIG(name) void name(struct Application_Links *app) #define HOOK_SIG(name) void name(struct Application_Links *app) +#define SCROLL_RULE_SIG(name) int name(float target_x, float target_y, float *scroll_x, float *scroll_y, int view_id, int is_new_target) extern "C"{ typedef CUSTOM_COMMAND_SIG(Custom_Command_Function); typedef GET_BINDING_DATA(Get_Binding_Data_Function); typedef HOOK_SIG(Hook_Function); + typedef SCROLL_RULE_SIG(Scroll_Rule_Function); } struct Application_Links; @@ -190,6 +192,7 @@ struct Application_Links; #define BUFFER_SEEK_STRING_SIG(name) int name(Application_Links *context, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) #define BUFFER_READ_RANGE_SIG(name) int name(Application_Links *context, Buffer_Summary *buffer, int start, int end, char *out) #define BUFFER_REPLACE_RANGE_SIG(name) int name(Application_Links *context, Buffer_Summary *buffer, int start, int end, char *str, int len) +#define BUFFER_SET_POS_SIG(name) int name(Application_Links *context, Buffer_Summary *buffer, int pos) // File view manipulation #define GET_VIEW_MAX_INDEX_SIG(name) int name(Application_Links *context) @@ -245,6 +248,7 @@ extern "C"{ typedef BUFFER_SEEK_STRING_SIG(Buffer_Seek_String_Function); typedef BUFFER_READ_RANGE_SIG(Buffer_Read_Range_Function); typedef BUFFER_REPLACE_RANGE_SIG(Buffer_Replace_Range_Function); + typedef BUFFER_SET_POS_SIG(Buffer_Set_Pos_Function); // View manipulation typedef GET_VIEW_MAX_INDEX_SIG(Get_View_Max_Index_Function); @@ -294,6 +298,7 @@ struct Application_Links{ Buffer_Seek_String_Function *buffer_seek_string; Buffer_Read_Range_Function *buffer_read_range; Buffer_Replace_Range_Function *buffer_replace_range; + Buffer_Set_Pos_Function *buffer_set_pos; // View manipulation Get_View_Max_Index_Function *get_view_max_index; @@ -319,6 +324,7 @@ struct Application_Links{ struct Custom_API{ Get_Binding_Data_Function *get_bindings; + Scroll_Rule_Function *scroll_rule; }; // NOTE(allen): definitions for the buffer that communicates to 4ed.exe diff --git a/4ed.cpp b/4ed.cpp index dd7ad514..76f29788 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1,4383 +1,4422 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.12.2014 - * - * Application layer for project codename "4ed" - * - */ - -// TOP - -// App Structs - -enum App_State{ - APP_STATE_EDIT, - APP_STATE_RESIZING, - // never below this - APP_STATE_COUNT -}; - -struct App_State_Resizing{ - Panel_Divider *divider; - i32 min, max; -}; - -struct CLI_Process{ - CLI_Handles cli; - Editing_File *out_file; -}; - -struct CLI_List{ - CLI_Process *procs; - i32 count, max; -}; - -#define SysAppCreateView 0x1 -#define SysAppCreateNewBuffer 0x2 - -struct Sys_App_Binding{ - i32 sys_id; - i32 app_id; - - u32 success; - u32 fail; - Panel *panel; -}; - -struct Complete_State{ - Search_Set set; - Search_Iter iter; - Table hits; - String_Space str; - i32 word_start, word_end; - b32 initialized; -}; - -struct Command_Data{ - Mem_Options *mem; - Panel *panel; - View *view; - Working_Set *working_set; - Editing_Layout *layout; - Live_Views *live_set; - Style *style; - Delay *delay; - struct App_Vars *vars; - Exchange *exchange; - System_Functions *system; - Coroutine *current_coroutine; - - i32 screen_width, screen_height; - Key_Event_Data key; - - Partition part; -}; - -struct App_Vars{ - Mem_Options mem; - - App_Settings settings; - - Command_Map map_top; - Command_Map map_file; - Command_Map map_ui; -#if FRED_INTERNAL - Command_Map map_debug; -#endif - Command_Map *user_maps; - i32 *map_id_table; - i32 user_map_count; - Command_Binding prev_command; - - Coroutine *command_coroutine; - u32 command_coroutine_flags[2]; - - Sys_App_Binding *sys_app_bindings; - i32 sys_app_count, sys_app_max; - - Custom_Command_Function *hooks[hook_type_count]; - - Font_Set *font_set; - - Style style; - Style_Library styles; - u32 *palette; - i32 palette_size; - - Editing_Layout layout; - Live_Views live_set; - Working_Set working_set; - - char hot_dir_base_[256]; - Hot_Directory hot_directory; - - CLI_List cli_processes; - - Delay delay1, delay2; - - String mini_str; - u8 mini_buffer[512]; - - App_State state; - App_State_Resizing resizing; - Complete_State complete_state; - Panel *prev_mouse_panel; - - Command_Data command_data; - - Custom_API config_api; -}; - -internal i32 -app_get_or_add_map_index(App_Vars *vars, i32 mapid){ - i32 result; - i32 user_map_count = vars->user_map_count; - i32 *map_id_table = vars->map_id_table; - for (result = 0; result < user_map_count; ++result){ - if (map_id_table[result] == mapid) break; - if (map_id_table[result] == 0){ - map_id_table[result] = mapid; - break; - } - } - return result; -} - -internal i32 -app_get_map_index(App_Vars *vars, i32 mapid){ - i32 result; - i32 user_map_count = vars->user_map_count; - i32 *map_id_table = vars->map_id_table; - for (result = 0; result < user_map_count; ++result){ - if (map_id_table[result] == mapid) break; - if (map_id_table[result] == 0){ - result = user_map_count; - break; - } - } - return result; -} - -internal Command_Map* -app_get_map(App_Vars *vars, i32 mapid){ - Command_Map *map = 0; - if (mapid < mapid_global) map = vars->user_maps + mapid; - else if (mapid == mapid_global) map = &vars->map_top; - else if (mapid == mapid_file) map = &vars->map_file; - return map; -} - -// Commands - -globalvar Application_Links app_links; - -#define USE_MEM(n) Mem_Options *n = command->mem -#define USE_PANEL(n) Panel *n = command->panel -#define USE_VIEW(n) View *n = command->view -#define USE_FILE_VIEW(n) File_View *n = view_to_file_view(command->view) -#define USE_FILE(n,v) Editing_File *n = 0; if (v) { (n) = (v)->file; } -#define USE_WORKING_SET(n) Working_Set *n = command->working_set -#define USE_LAYOUT(n) Editing_Layout *n = command->layout -#define USE_LIVE_SET(n) Live_Views *live_set = command->live_set -#define USE_STYLE(n) Style *n = command->style -#define USE_DELAY(n) Delay *n = command->delay -#define USE_VARS(n) App_Vars *n = command->vars -#define USE_EXCHANGE(n) Exchange *n = command->exchange -#define USE_FONT_SET(n) Font_Set *n = command->vars->font_set; - -#define REQ_VIEW(n) View *n = command->view; if (!n) return -#define REQ_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n) return -#define REQ_OPEN_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n || n->locked) return -#define REQ_FILE_HISTORY(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->state.buffer) || n->state.is_dummy || !n->state.undo.undo.edits) return -#define REQ_FILE_LOADING(n,v) Editing_File *n = (v)->file; if (!n || n->state.is_dummy) return -#define REQ_FILE(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->state.buffer) || n->state.is_dummy) return -#define REQ_COLOR_VIEW(n) Color_View *n = view_to_color_view(command->view); if (!n) return -#define REQ_DBG_VIEW(n) Debug_View *n = view_to_debug_view(command->view); if (!n) return - -#define COMMAND_DECL(n) internal void command_##n(System_Functions *system, Command_Data *command, Command_Binding binding) -#define COMPOSE_DECL(n) internal void n(System_Functions *system, Command_Data *command, Command_Binding binding) - -struct Command_Parameter{ - i32 type; - union{ - struct{ - Dynamic param; - Dynamic value; - } param; - struct{ - i32 len; - char *str; - } inline_string; - }; -}; - -inline Command_Parameter* -param_next(Command_Parameter *param, Command_Parameter *end){ - Command_Parameter *result = param; - if (result->type == 0){ - ++result; - } - while (result->type != 0 && result < end){ - i32 len = result->inline_string.len; - len += sizeof(*result) - 1; - len -= (len % sizeof(*result)); - result = (Command_Parameter*)((char*)result + len + sizeof(*result)); - } - return result; -} - -inline Command_Parameter* -param_stack_first(Partition *part, Command_Parameter *end){ - Command_Parameter *result = (Command_Parameter*)part->base; - if (result->type != 0) result = param_next(result, end); - return result; -} - -inline Command_Parameter* -param_stack_end(Partition *part){ - return (Command_Parameter*)((char*)part->base + part->pos); -} - -internal File_View* -panel_make_empty(System_Functions *system, Exchange *exchange, - App_Vars *vars, Style *style, Panel *panel){ - - Mem_Options *mem = &vars->mem; - Editing_Layout *layout = &vars->layout; - Working_Set *working_set = &vars->working_set; - Delay *delay = &vars->delay1; - - File_View *file_view; - View_And_ID new_view; - - Assert(panel->view == 0); - new_view = live_set_alloc_view(&vars->live_set, mem); - panel->view = new_view.view; - panel->view->panel = panel; - - file_view = file_view_init(panel->view, layout, working_set, delay, - &vars->settings, &vars->hot_directory, mem, &vars->styles); - view_set_file(file_view, 0, vars->font_set, style, 0, 0, 0); - panel->view->map = app_get_map(vars, mapid_global); - - return(file_view); -} - -COMMAND_DECL(null){ - AllowLocal(command); -} - -COMMAND_DECL(write_character){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - char character; - i32 pos, next_cursor_pos; - - character = command->key.character; - if (character != 0){ - pos = view->cursor.pos; - next_cursor_pos = view->cursor.pos + 1; - view_replace_range(system, mem, view, layout, pos, pos, &character, 1, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - file->state.cursor_pos = view->cursor.pos; - } -} - -COMMAND_DECL(seek_whitespace_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_whitespace_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_whitespace_up){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_up(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_whitespace_down){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_down(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -internal i32 -seek_token_left(Cpp_Token_Stack *tokens, i32 pos){ - Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); - if (get.token_index == -1){ - get.token_index = 0; - } - - Cpp_Token *token = tokens->tokens + get.token_index; - if (token->start == pos && get.token_index > 0){ - --token; - } - - return token->start; -} - -internal i32 -seek_token_right(Cpp_Token_Stack *tokens, i32 pos){ - Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); - if (get.in_whitespace){ - ++get.token_index; - } - if (get.token_index >= tokens->count){ - get.token_index = tokens->count-1; - } - - Cpp_Token *token = tokens->tokens + get.token_index; - return token->start + token->size; -} - -COMMAND_DECL(seek_token_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - if (file->state.tokens_complete){ - i32 pos = seek_token_left(&file->state.token_stack, view->cursor.pos); - view_cursor_move(view, pos); - } -} - -COMMAND_DECL(seek_token_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - if (file->state.tokens_complete){ - i32 pos = seek_token_right(&file->state.token_stack, view->cursor.pos); - view_cursor_move(view, pos); - } -} - -COMMAND_DECL(seek_white_or_token_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 token_pos, white_pos; - if (file->state.tokens_complete){ - token_pos = seek_token_right(&file->state.token_stack, view->cursor.pos); - } - else{ - token_pos = buffer_size(&file->state.buffer); - } - white_pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, Min(token_pos, white_pos)); -} - -COMMAND_DECL(seek_white_or_token_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 token_pos, white_pos; - if (file->state.tokens_complete){ - token_pos = seek_token_left(&file->state.token_stack, view->cursor.pos); - } - else{ - token_pos = 0; - } - white_pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, Max(token_pos, white_pos)); -} - -COMMAND_DECL(seek_alphanumeric_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_alphanumeric_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_alphanumeric_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_alphanumeric_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_alphanumeric_or_camel_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_alphanumeric_or_camel_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_alphanumeric_or_camel_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_alphanumeric_or_camel_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(word_complete){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - USE_VARS(vars); - USE_WORKING_SET(working_set); - - Partition *part = &mem->part; - General_Memory *general = &mem->general; - Complete_State *complete_state = &vars->complete_state; - Search_Range *ranges; - Search_Match match; - - Temp_Memory temp; - - Buffer_Type *buffer; - Buffer_Backify_Type loop; - char *data; - i32 end; - i32 size_of_buffer; - - i32 cursor_pos, word_start, word_end; - char c; - - char *spare; - i32 size; - - i32 buffer_count, i, j; - Editing_File *file_ptr; - - i32 match_size; - b32 do_init = 0; - - buffer = &file->state.buffer; - size_of_buffer = buffer_size(buffer); - - if (view->mode.rewrite != 2){ - do_init = 1; - } - view->next_mode.rewrite = 2; - - if (complete_state->initialized == 0){ - do_init = 1; - } - - if (do_init){ - word_end = view->cursor.pos; - word_start = word_end; - cursor_pos = word_end - 1; - - // TODO(allen): macros for these buffer loops and some method of breaking out of them. - for (loop = buffer_backify_loop(buffer, cursor_pos, 0); - buffer_backify_good(&loop); - buffer_backify_next(&loop)){ - end = loop.absolute_pos; - data = loop.data - loop.absolute_pos; - for (; cursor_pos >= end; --cursor_pos){ - c = data[cursor_pos]; - if (char_is_alpha(c)){ - word_start = cursor_pos; - } - else if (!char_is_numeric(c)){ - goto double_break; - } - } - } - double_break:; - - size = word_end - word_start; - - if (size == 0){ - complete_state->initialized = 0; - return; - } - - complete_state->initialized = 1; - search_iter_init(general, &complete_state->iter, size); - buffer_stringify(buffer, word_start, word_end, complete_state->iter.word.str); - complete_state->iter.word.size = size; - - buffer_count = working_set->file_index_count; - search_set_init(general, &complete_state->set, buffer_count + 1); - ranges = complete_state->set.ranges; - ranges[0].buffer = buffer; - ranges[0].start = 0; - ranges[0].size = word_start; - - ranges[1].buffer = buffer; - ranges[1].start = word_end; - ranges[1].size = size_of_buffer - word_end; - - file_ptr = working_set->files; - for (i = 0, j = 2; i < buffer_count; ++i, ++file_ptr){ - if (file_ptr != file && !file_ptr->state.is_dummy){ - ranges[j].buffer = &file_ptr->state.buffer; - ranges[j].start = 0; - ranges[j].size = buffer_size(ranges[j].buffer); - ++j; - } - } - complete_state->set.count = j; - - search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); - search_hit_add(general, &complete_state->hits, &complete_state->str, - complete_state->iter.word.str, complete_state->iter.word.size); - - complete_state->word_start = word_start; - complete_state->word_end = word_end; - } - else{ - word_start = complete_state->word_start; - word_end = complete_state->word_end; - size = complete_state->iter.word.size; - } - - if (size > 0){ - for (;;){ - match = search_next_match(part, &complete_state->set, &complete_state->iter); - - if (match.found_match){ - temp = begin_temp_memory(part); - match_size = match.end - match.start; - spare = (char*)push_array(part, char, match_size); - buffer_stringify(match.buffer, match.start, match.end, spare); - - if (search_hit_add(general, &complete_state->hits, &complete_state->str, spare, match_size)){ - view_replace_range(system, mem, view, layout, word_start, word_end, spare, match_size, word_end); - - complete_state->word_end = word_start + match_size; - complete_state->set.ranges[1].start = word_start + match_size; - break; - } - end_temp_memory(temp); - } - else{ - complete_state->iter.pos = 0; - complete_state->iter.i = 0; - - search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); - search_hit_add(general, &complete_state->hits, &complete_state->str, - complete_state->iter.word.str, complete_state->iter.word.size); - - match_size = complete_state->iter.word.size; - view_replace_range(system, mem, view, layout, word_start, word_end, - complete_state->iter.word.str, match_size, word_end); - - complete_state->word_end = word_start + match_size; - complete_state->set.ranges[1].start = word_start + match_size; - break; - } - } - } -} - -COMMAND_DECL(set_mark){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - view->mark = (i32)view->cursor.pos; -} - -COMMAND_DECL(copy){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_WORKING_SET(working_set); - USE_MEM(mem); - - // TODO(allen): deduplicate - int r_start = 0, r_end = 0; - int start_set = 0, end_set = 0; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_range_start: - start_set = 1; - r_start = dynamic_to_int(¶m->param.value); - break; - - case par_range_end: - end_set = 1; - r_end = dynamic_to_int(¶m->param.value); - break; - } - } - - Range range = make_range(view->cursor.pos, view->mark); - if (start_set) range.start = r_start; - if (end_set) range.end = r_end; - if (range.start < range.end){ - clipboard_copy(system, &mem->general, working_set, range, file); - } -} - -COMMAND_DECL(cut){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_WORKING_SET(working_set); - USE_LAYOUT(layout); - USE_MEM(mem); - - // TODO(allen): deduplicate - int r_start = 0, r_end = 0; - int start_set = 0, end_set = 0; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_range_start: - start_set = 1; - r_start = dynamic_to_int(¶m->param.value); - break; - - case par_range_end: - end_set = 1; - r_end = dynamic_to_int(¶m->param.value); - break; - } - } - - Range range = make_range(view->cursor.pos, view->mark); - if (start_set) range.start = r_start; - if (end_set) range.end = r_end; - if (range.start < range.end){ - i32 next_cursor_pos = range.start; - - clipboard_copy(system, &mem->general, working_set, range, file); - view_replace_range(system, mem, view, layout, range.start, range.end, 0, 0, next_cursor_pos); - - view->mark = range.start; - view_cursor_move(view, next_cursor_pos); - } -} - -COMMAND_DECL(paste){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_WORKING_SET(working_set); - USE_LAYOUT(layout); - USE_MEM(mem); - - Panel *panel, *used_panels; - String *src; - File_View *current_view; - i32 pos_left, next_cursor_pos; - - if (working_set->clipboard_size > 0){ - view->next_mode.rewrite = 1; - - src = working_set_clipboard_head(working_set); - pos_left = view->cursor.pos; - - next_cursor_pos = pos_left+src->size; - view_replace_range(system, mem, view, layout, pos_left, pos_left, src->str, src->size, next_cursor_pos); - - view_cursor_move(view, next_cursor_pos); - view->mark = pos_left; - - used_panels = &layout->used_sentinel; - for (dll_items(panel, used_panels)){ - current_view = view_to_file_view(panel->view); - - if (current_view->file == file){ - view_post_paste_effect(current_view, 20, pos_left, src->size, - current_view->style->main.paste_color); - } - } - } -} - -COMMAND_DECL(paste_next){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_WORKING_SET(working_set); - USE_LAYOUT(layout); - USE_MEM(mem); - - Panel *panel, *used_panels; - - if (working_set->clipboard_size > 0 && view->mode.rewrite == 1){ - view->next_mode.rewrite = 1; - - Range range = make_range(view->mark, view->cursor.pos); - String *src = working_set_clipboard_roll_down(working_set); - i32 next_cursor_pos = range.start+src->size; - view_replace_range(system, - mem, view, layout, range.start, range.end, - src->str, src->size, next_cursor_pos); - - view_cursor_move(view, next_cursor_pos); - view->mark = range.start; - - used_panels = &layout->used_sentinel; - for (dll_items(panel, used_panels)){ - File_View *current_view = view_to_file_view(panel->view); - - if (current_view->file == file){ - view_post_paste_effect(current_view, 20, range.start, src->size, - current_view->style->main.paste_color); - } - } - } - else{ - command_paste(system, command, binding); - } -} - -COMMAND_DECL(delete_range){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - Range range = make_range(view->cursor.pos, view->mark); - if (range.start < range.end){ - i32 next_cursor_pos = range.start; - view_replace_range(system, mem, view, layout, range.start, range.end, - 0, 0, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - view->mark = range.start; - } -} - -COMMAND_DECL(timeline_scrub){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - - view_set_widget(view, FWIDG_TIMELINES); - view->widget.timeline.undo_line = 1; - view->widget.timeline.history_line = 1; -} - -COMMAND_DECL(undo){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_undo(system, mem, layout, view); -} - -COMMAND_DECL(redo){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_redo(system, mem, layout, view); -} - -COMMAND_DECL(history_backward){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_history_step(system, mem, layout, view, hist_backward); -} - -COMMAND_DECL(history_forward){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_history_step(system, mem, layout, view, hist_forward); -} - -#if UseFileHistoryDump -COMMAND_DECL(save_history){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_MEM(mem); - - file_dump_history(system, mem, file, "history_data.hst"); -} -#endif - -COMMAND_DECL(interactive_new){ - ProfileMomentFunction(); - USE_FILE_VIEW(fview); - USE_VARS(vars); - - view_show_interactive(system, fview, &vars->map_ui, - IAct_New, IInt_Sys_File_List, make_lit_string("New: ")); -} - -internal Sys_App_Binding* -app_push_file_binding(App_Vars *vars, int sys_id, int app_id){ - Sys_App_Binding *binding; - Assert(vars->sys_app_count < vars->sys_app_max); - binding = vars->sys_app_bindings + vars->sys_app_count++; - binding->sys_id = sys_id; - binding->app_id = app_id; - return(binding); -} - -struct App_Open_File_Result{ - Editing_File *file; - i32 sys_id; - i32 file_index; - b32 is_new; -}; - -internal App_Open_File_Result -app_open_file_background(App_Vars *vars, Exchange *exchange, Working_Set *working_set, String filename){ - Get_File_Result file; - i32 file_id; - App_Open_File_Result result = {}; - - result.file = working_set_contains(working_set, filename); - if (result.file == 0){ - result.is_new = 1; - file = working_set_get_available_file(working_set); - if (file.file){ - result.file = file.file; - file_id = exchange_request_file(exchange, filename.str, filename.size); - if (file_id){ - file_init_strings(result.file); - file_set_name(working_set, result.file, filename.str); - file_set_to_loading(result.file); - table_add(&working_set->table, result.file->name.source_path, file.index); - - result.sys_id = file_id; - result.file_index = file.index; - } - else{ - file_get_dummy(file.file); - } - } - } - - return(result); -} - -COMMAND_DECL(interactive_open){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_PANEL(panel); - USE_DELAY(delay); - - char *filename = 0; - int filename_len = 0; - int do_in_background = 0; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - if (param->param.param.type == dynamic_type_int){ - if (param->param.param.int_value == par_name && - param->param.value.type == dynamic_type_string){ - filename = param->param.value.str_value; - filename_len = param->param.value.str_len; - } - else if (param->param.param.int_value == par_do_in_background){ - do_in_background = dynamic_to_int(¶m->param.value); - } - } - } - - if (filename){ - String string = make_string(filename, filename_len); - if (do_in_background){ - delayed_open_background(delay, string); - } - else{ - delayed_open(delay, string, panel); - } - } - else{ - View *view = panel->view; - Assert(view); - - File_View *fview = view_to_file_view(view); - - view_show_interactive(system, fview, &vars->map_ui, - IAct_Open, IInt_Sys_File_List, make_lit_string("Open: ")); - } -} - -internal void -view_file_in_panel(Command_Data *cmd, Panel *panel, Editing_File *file){ - Mem_Options *mem = cmd->mem; - System_Functions *system = cmd->system; - Editing_Layout *layout = cmd->layout; - App_Vars *vars = cmd->vars; - Style *style = cmd->style; - Working_Set *working_set = &vars->working_set; - Delay *delay = &vars->delay1; - - Partition old_part; - Temp_Memory temp; - View *old_view; - File_View *file_view; - - file_view = file_view_init(panel->view, layout, working_set, delay, - &vars->settings, &vars->hot_directory, mem, &vars->styles); - - old_view = cmd->view; - cmd->view = panel->view; - - old_part = cmd->part; - temp = begin_temp_memory(&mem->part); - cmd->part = partition_sub_part(&mem->part, Kbytes(16)); - - view_set_file(file_view, file, vars->font_set, style, - system, vars->hooks[hook_open_file], &app_links); - - cmd->part = old_part; - end_temp_memory(temp); - cmd->view = old_view; - - panel->view->map = app_get_map(vars, file->settings.base_map_id); -} - -// TODO(allen): Improvements to reopen -// - Preserve existing token stack -// - Keep current version open and do some sort of diff to keep -// the cursor position correct -COMMAND_DECL(reopen){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_EXCHANGE(exchange); - USE_WORKING_SET(working_set); - USE_VARS(vars); - USE_STYLE(style); - - i32 file_id = exchange_request_file(exchange, expand_str(file->name.source_path)); - i32 index = 0; - if (file_id){ - file_set_to_loading(file); - index = working_set_get_index(working_set, file); - app_push_file_binding(vars, file_id, index); - - view_set_file(view, file, vars->font_set, style, - system, vars->hooks[hook_open_file], &app_links); - } - else{ - // TODO(allen): feedback message - } -} - -COMMAND_DECL(save){ - ProfileMomentFunction(); - USE_FILE_VIEW(view); - USE_FILE(file, view); - USE_DELAY(delay); - USE_WORKING_SET(working_set); - - char *filename = 0; - int filename_len = 0; - int buffer_id = -1; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int v = dynamic_to_int(¶m->param.param); - if (v == par_name && param->param.value.type == dynamic_type_string){ - filename = param->param.value.str_value; - filename_len = param->param.value.str_len; - } - else if (v == par_buffer_id && param->param.value.type == dynamic_type_int){ - buffer_id = dynamic_to_int(¶m->param.value); - } - } - - String name = {}; - if (filename){ - name = make_string(filename, filename_len); - } - else if (file){ - name = file->name.source_path; - } - - if (name.size != 0){ - if (buffer_id == -1){ - if (file){ - delayed_save(delay, name, file); - } - } - else{ - file = working_set->files + buffer_id; - - if (!file->state.is_dummy && file_is_ready(file)){ - delayed_save(delay, name, file); - } - else{ - delayed_save(delay, name); - } - } - } -} - -COMMAND_DECL(interactive_save_as){ - ProfileMomentFunction(); - USE_FILE_VIEW(fview); - USE_VARS(vars); - - view_show_interactive(system, fview, &vars->map_ui, - IAct_Save_As, IInt_Sys_File_List, make_lit_string("Save As: ")); -} - -COMMAND_DECL(change_active_panel){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - - panel = panel->next; - if (panel == &layout->used_sentinel){ - panel = panel->next; - } - layout->active_panel = (i32)(panel - layout->panels); -} - -COMMAND_DECL(interactive_switch_buffer){ - ProfileMomentFunction(); - USE_FILE_VIEW(fview); - USE_VARS(vars); - - view_show_interactive(system, fview, &vars->map_ui, - IAct_Switch, IInt_Live_File_List, make_lit_string("Switch Buffer: ")); -} - -COMMAND_DECL(interactive_kill_buffer){ - ProfileMomentFunction(); - USE_FILE_VIEW(fview); - USE_VARS(vars); - - view_show_interactive(system, fview, &vars->map_ui, - IAct_Kill, IInt_Live_File_List, make_lit_string("Kill Buffer: ")); -} - -COMMAND_DECL(kill_buffer){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_DELAY(delay); - - delayed_try_kill(delay, file->name.live_name, view->view_base.panel); -} - -COMMAND_DECL(toggle_line_wrap){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - Relative_Scrolling scrolling = view_get_relative_scrolling(view); - if (view->unwrapped_lines){ - view->unwrapped_lines = 0; - file->settings.unwrapped_lines = 0; - view->target_x = 0; - view->cursor = - view_compute_cursor_from_pos(view, view->cursor.pos); - view->preferred_x = view->cursor.wrapped_x; - } - else{ - view->unwrapped_lines = 1; - file->settings.unwrapped_lines = 1; - view->cursor = - view_compute_cursor_from_pos(view, view->cursor.pos); - view->preferred_x = view->cursor.unwrapped_x; - } - view_set_relative_scrolling(view, scrolling); -} - -COMMAND_DECL(toggle_show_whitespace){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - view->show_whitespace = !view->show_whitespace; -} - -COMMAND_DECL(toggle_tokens){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_MEM(mem); - - if (file->settings.tokens_exist){ - file_kill_tokens(system, &mem->general, file); - } - else{ - file_first_lex_parallel(system, &mem->general, file); - } -#endif -} - -internal void -case_change_range(System_Functions *system, - Mem_Options *mem, File_View *view, Editing_File *file, - u8 a, u8 z, u8 char_delta){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Range range = make_range(view->cursor.pos, view->mark); - if (range.start < range.end){ - Edit_Step step = {}; - step.type = ED_NORMAL; - step.edit.start = range.start; - step.edit.end = range.end; - step.edit.len = range.end - range.start; - - if (file->state.still_lexing) - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - - file_update_history_before_edit(mem, file, step, 0, hist_normal); - - u8 *data = (u8*)file->state.buffer.data; - for (i32 i = range.start; i < range.end; ++i){ - if (data[i] >= a && data[i] <= z){ - data[i] += char_delta; - } - } - - if (file->state.token_stack.tokens) - file_relex_parallel(system, mem, file, range.start, range.end, 0); - } -#endif -} - -COMMAND_DECL(to_uppercase){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_MEM(mem); - case_change_range(system, mem, view, file, 'a', 'z', (u8)('A' - 'a')); -} - -COMMAND_DECL(to_lowercase){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_MEM(mem); - case_change_range(system, mem, view, file, 'A', 'Z', (u8)('a' - 'A')); -} - -COMMAND_DECL(clean_all_lines){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_clean_whitespace(system, mem, view, layout); -} - -COMMAND_DECL(eol_dosify){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - file->settings.dos_write_mode = 1; - file->state.last_4ed_edit_time = system->time(); -} - -COMMAND_DECL(eol_nixify){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - file->settings.dos_write_mode = 0; - file->state.last_4ed_edit_time = system->time(); -} - -COMMAND_DECL(auto_tab_range){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - int r_start = 0, r_end = 0; - int start_set = 0, end_set = 0; - int clear_blank_lines = 1; - - // TODO(allen): deduplicate - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_range_start: - start_set = 1; - r_start = dynamic_to_int(¶m->param.value); - break; - - case par_range_end: - end_set = 1; - r_end = dynamic_to_int(¶m->param.value); - break; - - case par_clear_blank_lines: - clear_blank_lines = dynamic_to_bool(¶m->param.value); - break; - } - } - - if (file->state.token_stack.tokens && file->state.tokens_complete){ - Range range = make_range(view->cursor.pos, view->mark); - if (start_set) range.start = r_start; - if (end_set) range.end = r_end; - view_auto_tab_tokens(system, mem, view, layout, range.start, range.end, clear_blank_lines); - } -} - -COMMAND_DECL(auto_tab_line_at_cursor){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - int clear_blank_lines = 0; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_clear_blank_lines: - clear_blank_lines = dynamic_to_bool(¶m->param.value); - break; - } - } - - if (file->state.token_stack.tokens && file->state.tokens_complete){ - i32 pos = view->cursor.pos; - view_auto_tab_tokens(system, mem, view, layout, pos, pos, clear_blank_lines); - } -} - -COMMAND_DECL(auto_tab_whole_file){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - if (file->state.token_stack.tokens && file->state.tokens_complete){ - view_auto_tab_tokens(system, mem, view, layout, 0, buffer_size(&file->state.buffer), 1); - } -} - -COMMAND_DECL(open_panel_vsplit){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - USE_VARS(vars); - USE_STYLE(style); - - if (layout->panel_count < layout->panel_max_count){ - Split_Result split = layout_split_panel(layout, panel, 1); - - Panel *panel1 = panel; - Panel *panel2 = split.panel; - - panel2->screen_region = panel1->screen_region; - - panel2->full.x0 = split.divider->pos; - panel2->full.x1 = panel1->full.x1; - panel1->full.x1 = split.divider->pos; - - panel_fix_internal_area(panel1); - panel_fix_internal_area(panel2); - panel2->prev_inner = panel2->inner; - - layout->active_panel = (i32)(panel2 - layout->panels); - panel_make_empty(system, exchange, vars, style, panel2); - } -} - -COMMAND_DECL(open_panel_hsplit){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - USE_VARS(vars); - USE_STYLE(style); - - if (layout->panel_count < layout->panel_max_count){ - Split_Result split = layout_split_panel(layout, panel, 0); - - Panel *panel1 = panel; - Panel *panel2 = split.panel; - - panel2->screen_region = panel1->screen_region; - - panel2->full.y0 = split.divider->pos; - panel2->full.y1 = panel1->full.y1; - panel1->full.y1 = split.divider->pos; - - panel_fix_internal_area(panel1); - panel_fix_internal_area(panel2); - panel2->prev_inner = panel2->inner; - - layout->active_panel = (i32)(panel2 - layout->panels); - panel_make_empty(system, exchange, vars, style, panel2); - } -} - -COMMAND_DECL(close_panel){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - USE_VIEW(view); - USE_EXCHANGE(exchange); - - Panel *panel_ptr, *used_panels; - Divider_And_ID div, parent_div, child_div; - i32 child; - i32 parent; - i32 which_child; - i32 active; - - if (layout->panel_count > 1){ - live_set_free_view(system, exchange, command->live_set, view); - panel->view = 0; - - div = layout_get_divider(layout, panel->parent); - - // This divider cannot have two child dividers. - Assert(div.divider->child1 == -1 || div.divider->child2 == -1); - - // Get the child who needs to fill in this node's spot - child = div.divider->child1; - if (child == -1) child = div.divider->child2; - - parent = div.divider->parent; - which_child = div.divider->which_child; - - // Fill the child in the slot this node use to hold - if (parent == -1){ - Assert(layout->root == div.id); - layout->root = child; - } - else{ - parent_div = layout_get_divider(layout, parent); - if (which_child == -1){ - parent_div.divider->child1 = child; - } - else{ - parent_div.divider->child2 = child; - } - } - - // If there was a child divider, give it information about it's new parent. - if (child != -1){ - child_div = layout_get_divider(layout, child); - child_div.divider->parent = parent; - child_div.divider->which_child = div.divider->which_child; - } - - // What is the new active panel? - active = -1; - if (child == -1){ - used_panels = &layout->used_sentinel; - for (dll_items(panel_ptr, used_panels)){ - if (panel_ptr != panel && panel_ptr->parent == div.id){ - panel_ptr->parent = parent; - panel_ptr->which_child = which_child; - active = (i32)(panel_ptr - layout->panels); - break; - } - } - } - else{ - panel_ptr = panel->next; - if (panel_ptr == &layout->used_sentinel) panel_ptr = panel_ptr->next; - Assert(panel_ptr != panel); - active = (i32)(panel_ptr - layout->panels); - } - - Assert(active != -1 && panel != layout->panels + active); - layout->active_panel = active; - - layout_free_divider(layout, div.divider); - layout_free_panel(layout, panel); - layout_fix_all_panels(layout); - } -} - -COMMAND_DECL(move_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = view->cursor.pos; - if (pos > 0) --pos; - view_cursor_move(view, pos); -} - -COMMAND_DECL(move_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 size = buffer_size(&file->state.buffer); - i32 pos = view->cursor.pos; - if (pos < size) ++pos; - view_cursor_move(view, pos); -} - -COMMAND_DECL(delete){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - i32 size = buffer_size(&file->state.buffer); - i32 cursor_pos = view->cursor.pos; - if (0 < size && cursor_pos < size){ - i32 start, end; - start = cursor_pos; - end = cursor_pos+1; - - Assert(end - start > 0); - - i32 next_cursor_pos = start; - view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - } -} - -COMMAND_DECL(backspace){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - i32 size = buffer_size(&file->state.buffer); - i32 cursor_pos = view->cursor.pos; - if (cursor_pos > 0 && cursor_pos <= size){ - i32 start, end; - end = cursor_pos; - start = cursor_pos-1; - - i32 shift = (end - start); - Assert(shift > 0); - - i32 next_cursor_pos = view->cursor.pos - shift; - view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - } -} - -COMMAND_DECL(move_up){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_FONT_SET(font_set); - - f32 font_height = (f32)get_font_info(font_set, view->style->font_id)->height; - f32 cy = view_get_cursor_y(view)-font_height; - f32 px = view->preferred_x; - if (cy >= 0){ - view->cursor = view_compute_cursor_from_xy(view, px, cy); - file->state.cursor_pos = view->cursor.pos; - } -} - -COMMAND_DECL(move_down){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_FONT_SET(font_set); - - f32 font_height = (f32)get_font_info(font_set, view->style->font_id)->height; - f32 cy = view_get_cursor_y(view)+font_height; - f32 px = view->preferred_x; - view->cursor = view_compute_cursor_from_xy(view, px, cy); - file->state.cursor_pos = view->cursor.pos; -} - -COMMAND_DECL(seek_end_of_line){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = view_find_end_of_line(view, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_beginning_of_line){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = view_find_beginning_of_line(view, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(page_down){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - f32 height = view_compute_height(view); - f32 max_target_y = view_compute_max_target_y(view); - - view->target_y += height; - if (view->target_y > max_target_y) view->target_y = max_target_y; - - view->cursor = view_compute_cursor_from_xy( - view, 0, view->target_y + (height - view->font_height)*.5f); -} - -COMMAND_DECL(page_up){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - f32 height = view_compute_height(view); - - view->target_y -= height; - if (view->target_y < 0) view->target_y = 0; - - view->cursor = view_compute_cursor_from_xy( - view, 0, view->target_y + (height - view->font_height)*.5f); -} - -COMMAND_DECL(open_color_tweaker){ - ProfileMomentFunction(); - USE_FILE_VIEW(fview); - USE_VARS(vars); - - view_show_theme(fview, &vars->map_ui); -} - -COMMAND_DECL(open_config){ - ProfileMomentFunction(); - USE_FILE_VIEW(fview); - USE_VARS(vars); - - view_show_config(fview, &vars->map_ui); -} - -COMMAND_DECL(open_menu){ - ProfileMomentFunction(); - USE_FILE_VIEW(fview); - USE_VARS(vars); - - view_show_menu(fview, &vars->map_ui); -} - -COMMAND_DECL(close_minor_view){ - ProfileMomentFunction(); - REQ_VIEW(view); - USE_FILE_VIEW(fview); - USE_VARS(vars); - - Command_Map *map = &vars->map_top; - if (fview->file){ - map = app_get_map(vars, fview->file->settings.base_map_id); - } - view_show_file(fview, map); -} - -COMMAND_DECL(cursor_mark_swap){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - i32 pos = view->cursor.pos; - view_cursor_move(view, view->mark); - view->mark = pos; -} - -COMMAND_DECL(user_callback){ - ProfileMomentFunction(); - if (binding.custom) binding.custom(&app_links); -} - -COMMAND_DECL(set_settings){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_LOADING(file, view); - USE_VARS(vars); - USE_MEM(mem); - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_lex_as_cpp_file: - { -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - int v = dynamic_to_bool(¶m->param.value); - if (file->settings.tokens_exist){ - if (!v) file_kill_tokens(system, &mem->general, file); - } - else{ - if (v) file_first_lex_parallel(system, &mem->general, file); - } -#endif - }break; - - case par_wrap_lines: - { - int v = dynamic_to_bool(¶m->param.value); - if (view->unwrapped_lines){ - if (v){ - view->unwrapped_lines = 0; - file->settings.unwrapped_lines = 0; - - if (!file->state.is_loading){ - Relative_Scrolling scrolling = view_get_relative_scrolling(view); - view->target_x = 0; - view->cursor = - view_compute_cursor_from_pos(view, view->cursor.pos); - view_set_relative_scrolling(view, scrolling); - } - } - } - else{ - if (!v){ - view->unwrapped_lines = 1; - file->settings.unwrapped_lines = 1; - - if (!file->state.is_loading){ - Relative_Scrolling scrolling = view_get_relative_scrolling(view); - view->cursor = - view_compute_cursor_from_pos(view, view->cursor.pos); - view_set_relative_scrolling(view, scrolling); - } - } - } - }break; - - case par_key_mapid: - { - int v = dynamic_to_int(¶m->param.value); - if (v == mapid_global) file->settings.base_map_id = mapid_global; - else if (v == mapid_file) file->settings.base_map_id = mapid_file; - else if (v < mapid_global){ - int index = app_get_map_index(vars, v); - if (index < vars->user_map_count) file->settings.base_map_id = v; - else file->settings.base_map_id = mapid_file; - } - }break; - } - } -} - -#define CLI_OverlapWithConflict (1<<0) -#define CLI_AlwaysBindToView (2<<0) - -internal void -build(System_Functions *system, Mem_Options *mem, - App_Vars *vars, Working_Set *working_set, - Font_Set *font_set, Style *style, - Live_Views *live_set, Exchange *exchange, - Panel *panel, Command_Data *command, - String hot_directory, - char *buffer_name, i32 buffer_name_len, - char *path, i32 path_len, - char *script, i32 script_len, - u32 flags){ - if (buffer_name == 0 || path == 0 || script == 0){ - return; - } - - if (vars->cli_processes.count < vars->cli_processes.max){ - Editing_Layout *layout = &vars->layout; - Editing_File *file = working_set_contains(working_set, make_string_slowly(buffer_name)); - i32 index; - b32 bind_to_new_view = 1; - - if (!file){ - Get_File_Result get_file = working_set_get_available_file(working_set); - file = get_file.file; - index = get_file.index; - } - else{ - i32 proc_count = vars->cli_processes.count; - for (i32 i = 0; i < proc_count; ++i){ - if (vars->cli_processes.procs[i].out_file == file){ - if (flags & CLI_OverlapWithConflict) - vars->cli_processes.procs[i].out_file = 0; - else file = 0; - break; - } - } - index = (i32)(file - vars->working_set.files); - if (file){ - if (!(flags & CLI_AlwaysBindToView)){ - Panel *panel = layout->panels; - for (i32 i = 0; i < layout->panel_count; ++i, ++panel){ - File_View *fview = view_to_file_view(panel->view); - if (fview && fview->file == file){ - bind_to_new_view = 0; - break; - } - } - } - } - } - - if (file){ - file_create_super_locked(system, mem, working_set, file, buffer_name, font_set, style->font_id); - file->settings.unimportant = 1; - table_add(&working_set->table, file->name.source_path, index); - - if (bind_to_new_view){ - view_file_in_panel(command, panel, file); - } - - i32 i = vars->cli_processes.count++; - CLI_Process *proc = vars->cli_processes.procs + i; - if (!system->cli_call(path, script, &proc->cli)){ - --vars->cli_processes.count; - } - proc->out_file = file; - } - else{ - // TODO(allen): feedback message - no available file - } - } - else{ - // TODO(allen): feedback message - no available process slot - } -} - -COMMAND_DECL(command_line){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - char *buffer_name = 0; - char *path = 0; - char *script = 0; - - int buffer_name_len = 0; - int path_len = 0; - int script_len = 0; - u32 flags = CLI_OverlapWithConflict; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_name: - { - if (buffer_name == 0){ - char *new_buffer_name = dynamic_to_string(¶m->param.value, &buffer_name_len); - if (new_buffer_name){ - buffer_name = new_buffer_name; - } - } - }break; - - case par_cli_path: - { - if (path == 0){ - char *new_cli_path = dynamic_to_string(¶m->param.value, &path_len); - if (new_cli_path){ - path = new_cli_path; - } - } - }break; - - case par_cli_command: - { - if (script == 0){ - char *new_command = dynamic_to_string(¶m->param.value, &script_len); - if (new_command){ - script = new_command; - } - } - }break; - - case par_cli_overlap_with_conflict: - { - if (dynamic_to_int(¶m->param.value)) - flags |= CLI_OverlapWithConflict; - else - flags &= (~CLI_OverlapWithConflict); - }break; - - case par_cli_always_bind_to_view: - { - if (dynamic_to_int(¶m->param.value)) - flags |= CLI_OverlapWithConflict; - else - flags &= (~CLI_OverlapWithConflict); - }break; - } - } - - build(system, mem, vars, working_set, - font_set, style, live_set, exchange, - panel, command, - vars->hot_directory.string, - buffer_name, buffer_name_len, - path, path_len, - script, script_len, - flags); -} - -internal void -update_command_data(App_Vars *vars, Command_Data *cmd){ - cmd->panel = cmd->layout->panels + cmd->layout->active_panel; - cmd->view = cmd->panel->view; - cmd->style = &vars->style; -} - -globalvar Command_Function command_table[cmdid_count]; - -internal void -fill_buffer_summary(Buffer_Summary *buffer, Editing_File *file, Working_Set *working_set){ - buffer->exists = 1; - buffer->ready = file_is_ready(file); - buffer->is_lexed = file->settings.tokens_exist; - buffer->buffer_id = (int)(file - working_set->files); - buffer->size = file->state.buffer.size; - buffer->buffer_cursor_pos = file->state.cursor_pos; - - buffer->file_name_len = file->name.source_path.size; - buffer->buffer_name_len = file->name.live_name.size; - buffer->file_name = file->name.source_path.str; - buffer->buffer_name = file->name.live_name.str; - - buffer->map_id = file->settings.base_map_id; -} - -internal void -fill_view_summary(File_View_Summary *view, File_View *file_view, Live_Views *live_set, Working_Set *working_set){ - view->exists = 1; - view->view_id = (int)((char*)file_view - (char*)live_set->views) / live_set->stride; - if (file_view->file){ - view->buffer_id = (int)(file_view->file - working_set->files); - view->mark = view_compute_cursor_from_pos(file_view, file_view->mark); - view->cursor = file_view->cursor; - view->preferred_x = file_view->preferred_x; - view->line_height = file_view->font_height; - view->unwrapped_lines = file_view->unwrapped_lines; - } -} - -extern "C"{ - EXECUTE_COMMAND_SIG(external_exec_command_keep_stack){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Command_Function function = command_table[command_id]; - Command_Binding binding; - binding.function = function; - if (function) function(cmd->system, cmd, binding); - - update_command_data(cmd->vars, cmd); - } - - PUSH_PARAMETER_SIG(external_push_parameter){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Partition *part = &cmd->part; - Command_Parameter *cmd_param = push_struct(part, Command_Parameter); - cmd_param->type = 0; - cmd_param->param.param = param; - cmd_param->param.value = value; - } - - PUSH_MEMORY_SIG(external_push_memory){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Partition *part = &cmd->part; - Command_Parameter *base = push_struct(part, Command_Parameter); - char *result = push_array(part, char, len); - int full_len = len + sizeof(Command_Parameter) - 1; - full_len -= (full_len % sizeof(Command_Parameter)); - part->pos += full_len - len; - base->type = 1; - base->inline_string.str = result; - base->inline_string.len = len; - return(result); - } - - CLEAR_PARAMETERS_SIG(external_clear_parameters){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - cmd->part.pos = 0; - } - - DIRECTORY_GET_HOT_SIG(external_directory_get_hot){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Hot_Directory *hot = &cmd->vars->hot_directory; - i32 copy_max = capacity - 1; - hot_directory_clean_end(hot); - if (copy_max > hot->string.size) - copy_max = hot->string.size; - memcpy(out, hot->string.str, copy_max); - out[copy_max] = 0; - return(hot->string.size); - } - - GET_FILE_LIST_SIG(external_get_file_list){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - System_Functions *system = cmd->system; - File_List result = {}; - system->set_file_list(&result, make_string(dir, len)); - return(result); - } - - FREE_FILE_LIST_SIG(external_free_file_list){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - System_Functions *system = cmd->system; - system->set_file_list(&list, make_string(0, 0)); - } - - GET_BUFFER_MAX_INDEX_SIG(external_get_buffer_max_index){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Working_Set *working_set = cmd->working_set; - int max = working_set->file_index_count; - return(max); - } - - GET_BUFFER_SIG(external_get_buffer){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set = cmd->working_set; - int max = working_set->file_index_count; - Buffer_Summary buffer = {}; - - if (index >= 0 && index < max){ - file = working_set->files + index; - if (!file->state.is_dummy){ - fill_buffer_summary(&buffer, file, working_set); - } - } - - return(buffer); - } - - GET_ACTIVE_BUFFER_SIG(external_get_active_buffer){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - File_View *view; - Editing_File *file; - Working_Set *working_set; - Buffer_Summary buffer = {}; - - view = view_to_file_view(cmd->view); - if (view){ - file = view->file; - working_set = cmd->working_set; - - if (file && !file->state.is_dummy){ - fill_buffer_summary(&buffer, file, working_set); - } - } - - return(buffer); - } - - GET_BUFFER_BY_NAME(external_get_buffer_by_name){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - i32 index; - Buffer_Summary buffer = {}; - - working_set = cmd->working_set; - if (table_find(&working_set->table, make_string(filename, len), &index)){ - file = working_set->files + index; - if (!file->state.is_dummy && file_is_ready(file)){ - fill_buffer_summary(&buffer, file, working_set); - } - } - - return(buffer); - } - - REFRESH_BUFFER_SIG(external_refresh_buffer){ - int result; - *buffer = external_get_buffer(context, buffer->buffer_id); - result = buffer->exists; - return(result); - } - - BUFFER_SEEK_DELIMITER_SIG(external_buffer_seek_delimiter){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - int result = 0; - int size; - - if (buffer->exists){ - working_set = cmd->working_set; - file = working_set->files + buffer->buffer_id; - if (!file->state.is_dummy && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - result = 1; - - if (start < 0 && !seek_forward) *out = start; - else if (start >= size && seek_forward) *out = start; - else{ - if (seek_forward){ - *out = buffer_seek_delimiter(&file->state.buffer, start, delim); - } - else{ - *out = buffer_reverse_seek_delimiter(&file->state.buffer, start, delim); - } - } - - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - BUFFER_SEEK_STRING_SIG(external_buffer_seek_string){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - Temp_Memory temp; - Partition *part; - char *spare; - int result = 0; - int size; - - if (buffer->exists){ - working_set = cmd->working_set; - file = working_set->files + buffer->buffer_id; - if (!file->state.is_dummy && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - - if (start < 0 && !seek_forward) *out = start; - else if (start >= size && seek_forward) *out = start; - else{ - part = &cmd->mem->part; - temp = begin_temp_memory(part); - spare = push_array(part, char, len); - result = 1; - if (seek_forward){ - *out = buffer_find_string(&file->state.buffer, start, size, str, len, spare); - } - else{ - *out = buffer_rfind_string(&file->state.buffer, start, str, len, spare); - } - end_temp_memory(temp); - } - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - BUFFER_READ_RANGE_SIG(external_buffer_read_range){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - int result = 0; - int size; - - if (buffer->exists){ - working_set = cmd->working_set; - file = working_set->files + buffer->buffer_id; - if (!file->state.is_dummy && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - if (0 <= start && start <= end && end <= size){ - result = 1; - buffer_stringify(&file->state.buffer, start, end, out); - } - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - BUFFER_REPLACE_RANGE_SIG(external_buffer_replace_range){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - - System_Functions *system; - Mem_Options *mem; - Editing_Layout *layout; - - int result = 0; - int size; - int next_cursor, pos; - - if (buffer->exists){ - working_set = cmd->working_set; - file = working_set->files + buffer->buffer_id; - if (!file->state.is_dummy && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - if (0 <= start && start <= end && end <= size){ - result = 1; - - system = cmd->system; - mem = cmd->mem; - layout = cmd->layout; - - pos = file->state.cursor_pos; - if (pos < start) next_cursor = pos; - else if (pos < end) next_cursor = start + len; - else next_cursor = pos + end - start + len; - - file_replace_range(system, mem, file, layout, - start, end, str, len, next_cursor); - } - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - GET_VIEW_MAX_INDEX_SIG(external_get_view_max_index){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set = cmd->live_set; - int max = live_set->max; - return(max); - } - - GET_FILE_VIEW_SIG(external_get_file_view){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set = cmd->live_set; - int max = live_set->max; - View *vptr; - File_View *file_view; - File_View_Summary view = {}; - - if (index >= 0 && index < max){ - vptr = (View*)((char*)live_set->views + live_set->stride*index); - file_view = view_to_file_view(vptr); - if (file_view){ - fill_view_summary(&view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(view); - } - - GET_ACTIVE_FILE_VIEW_SIG(external_get_active_file_view){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - File_View_Summary view = {}; - File_View *file_view; - - file_view = view_to_file_view(cmd->view); - if (file_view){ - fill_view_summary(&view, file_view, cmd->live_set, cmd->working_set); - } - - return(view); - } - - REFRESH_FILE_VIEW_SIG(external_refresh_file_view){ - int result; - *view = external_get_file_view(context, view->view_id); - result = view->exists; - return(result); - } - - VIEW_SET_CURSOR_SIG(external_view_set_cursor){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set; - View *vptr; - File_View *file_view; - int result = 0; - - if (view->exists){ - live_set = cmd->live_set; - vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); - file_view = view_to_file_view(vptr); - if (file_view){ - result = 1; - file_view->cursor = view_compute_cursor(file_view, seek); - if (set_preferred_x){ - file_view->preferred_x = view_get_cursor_x(file_view); - } - fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(result); - } - - VIEW_SET_MARK_SIG(external_view_set_mark){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set; - View *vptr; - File_View *file_view; - Full_Cursor cursor; - int result = 0; - - if (view->exists){ - live_set = cmd->live_set; - vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); - file_view = view_to_file_view(vptr); - if (file_view){ - result = 1; - if (seek.type != buffer_seek_pos){ - cursor = view_compute_cursor(file_view, seek); - file_view->mark = cursor.pos; - } - else{ - file_view->mark = seek.pos; - } - fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(result); - } - - VIEW_SET_HIGHLIGHT_SIG(external_view_set_highlight){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set; - View *vptr; - File_View *file_view; - int result = 0; - - if (view->exists){ - live_set = cmd->live_set; - vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); - file_view = view_to_file_view(vptr); - if (file_view){ - result = 1; - if (turn_on){ - view_set_temp_highlight(file_view, start, end); - } - else{ - file_view->show_temp_highlight = 0; - } - fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(result); - } - - VIEW_SET_BUFFER_SIG(external_view_set_buffer){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set; - View *vptr; - File_View *file_view; - Editing_File *file; - Working_Set *working_set; - int max, result = 0; - - if (view->exists){ - live_set = cmd->live_set; - vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); - file_view = view_to_file_view(vptr); - if (file_view){ - working_set = cmd->working_set; - max = working_set->file_index_count; - if (buffer_id >= 0 && buffer_id < max){ - file = working_set->files + buffer_id; - if (!file->state.is_dummy){ - view_set_file(file_view, file, cmd->vars->font_set, cmd->style, - cmd->system, cmd->vars->hooks[hook_open_file], &app_links); - } - } - - fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(result); - } - - GET_USER_INPUT_SIG(external_get_user_input){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - System_Functions *system = cmd->system; - Coroutine *coroutine = cmd->current_coroutine; - User_Input result; - - Assert(coroutine); - *((u32*)coroutine->out+0) = get_type; - *((u32*)coroutine->out+1) = abort_type; - system->yield_coroutine(coroutine); - result = *(User_Input*)coroutine->in; - - return(result); - } - - START_QUERY_BAR_SIG(external_start_query_bar){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Query_Slot *slot = 0; - View *vptr; - File_View *file_view; - - vptr = cmd->view; - file_view = view_to_file_view(vptr); - - if (file_view){ - slot = alloc_query_slot(&file_view->query_set); - slot->query_bar = bar; - } - - return(slot != 0); - } - - END_QUERY_BAR_SIG(external_end_query_bar){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - View *vptr; - File_View *file_view; - - vptr = cmd->view; - file_view = view_to_file_view(vptr); - - if (file_view){ - free_query_slot(&file_view->query_set, bar); - } - } -} - -struct Command_In{ - Command_Data *cmd; - Command_Binding bind; -}; - -internal void -command_caller(Coroutine *coroutine){ - Command_In *cmd_in = (Command_In*)coroutine->in; - Command_Data *cmd = cmd_in->cmd; - View *view = cmd->view; - // TODO(allen): this isn't really super awesome, could have issues if - // the file view get's change out under us. - File_View *fview = view_to_file_view(view); - if (fview) fview->next_mode = {}; - cmd_in->bind.function(cmd->system, cmd, cmd_in->bind); - fview = view_to_file_view(view); - if (fview) fview->mode = fview->next_mode; -} - -internal void -app_links_init(System_Functions *system, void *data, int size){ - app_links.memory = data; - app_links.memory_size = size; - - app_links.exec_command_keep_stack = external_exec_command_keep_stack; - app_links.push_parameter = external_push_parameter; - app_links.push_memory = external_push_memory; - app_links.clear_parameters = external_clear_parameters; - - app_links.directory_get_hot = external_directory_get_hot; - app_links.file_exists = system->file_exists; - app_links.directory_cd = system->directory_cd; - app_links.get_file_list = external_get_file_list; - app_links.free_file_list = external_free_file_list; - - app_links.get_buffer_max_index = external_get_buffer_max_index; - app_links.get_buffer = external_get_buffer; - app_links.get_active_buffer = external_get_active_buffer; - app_links.get_buffer_by_name = external_get_buffer_by_name; - - app_links.refresh_buffer = external_refresh_buffer; - app_links.buffer_seek_delimiter = external_buffer_seek_delimiter; - app_links.buffer_seek_string = external_buffer_seek_string; - app_links.buffer_read_range = external_buffer_read_range; - app_links.buffer_replace_range = external_buffer_replace_range; - - app_links.get_view_max_index = external_get_view_max_index; - app_links.get_file_view = external_get_file_view; - app_links.get_active_file_view = external_get_active_file_view; - - app_links.refresh_file_view = external_refresh_file_view; - app_links.view_set_cursor = external_view_set_cursor; - app_links.view_set_mark = external_view_set_mark; - app_links.view_set_highlight = external_view_set_highlight; - app_links.view_set_buffer = external_view_set_buffer; - - app_links.get_user_input = external_get_user_input; - - app_links.start_query_bar = external_start_query_bar; - app_links.end_query_bar = external_end_query_bar; -} - -internal void -setup_ui_commands(Command_Map *commands, Partition *part, Command_Map *parent){ - map_init(commands, part, 32, parent); - - commands->vanilla_keyboard_default.function = command_null; - - // TODO(allen): This is hacky, when the new UI stuff happens, let's fix it, and by that - // I mean actually fix it, don't just say you fixed it with something stupid again. - u8 mdfr; - u8 mdfr_array[] = {MDFR_NONE, MDFR_SHIFT, MDFR_CTRL, MDFR_SHIFT | MDFR_CTRL}; - for (i32 i = 0; i < 4; ++i){ - mdfr = mdfr_array[i]; - map_add(commands, key_left, mdfr, command_null); - map_add(commands, key_right, mdfr, command_null); - map_add(commands, key_up, mdfr, command_null); - map_add(commands, key_down, mdfr, command_null); - map_add(commands, key_back, mdfr, command_null); - map_add(commands, key_esc, mdfr, command_close_minor_view); - } -} - -internal void -setup_file_commands(Command_Map *commands, Partition *part, Command_Map *parent){ - map_init(commands, part, 10, parent); -} - -internal void -setup_top_commands(Command_Map *commands, Partition *part, Command_Map *parent){ - map_init(commands, part, 5, parent); -} - -internal void -setup_command_table(){ -#define SET(n) command_table[cmdid_##n] = command_##n - - SET(null); - SET(write_character); - SET(seek_whitespace_right); - SET(seek_whitespace_left); - SET(seek_whitespace_up); - SET(seek_whitespace_down); - SET(seek_token_left); - SET(seek_token_right); - SET(seek_white_or_token_right); - SET(seek_white_or_token_left); - SET(seek_alphanumeric_right); - SET(seek_alphanumeric_left); - SET(seek_alphanumeric_or_camel_right); - SET(seek_alphanumeric_or_camel_left); - SET(word_complete); - SET(set_mark); - SET(copy); - SET(cut); - SET(paste); - SET(paste_next); - SET(delete_range); - SET(timeline_scrub); - SET(undo); - SET(redo); - SET(history_backward); - SET(history_forward); - SET(interactive_new); - SET(interactive_open); - SET(reopen); - SET(save); - SET(interactive_save_as); - SET(change_active_panel); - SET(interactive_switch_buffer); - SET(interactive_kill_buffer); - SET(kill_buffer); - SET(toggle_line_wrap); - SET(to_uppercase); - SET(to_lowercase); - SET(toggle_show_whitespace); - SET(clean_all_lines); - SET(eol_dosify); - SET(eol_nixify); - SET(auto_tab_range); - SET(auto_tab_line_at_cursor); - SET(auto_tab_whole_file); - SET(open_panel_vsplit); - SET(open_panel_hsplit); - SET(close_panel); - SET(move_left); - SET(move_right); - SET(delete); - SET(backspace); - SET(move_up); - SET(move_down); - SET(seek_end_of_line); - SET(seek_beginning_of_line); - SET(page_up); - SET(page_down); - SET(open_color_tweaker); - SET(close_minor_view); - SET(cursor_mark_swap); - SET(open_menu); - SET(set_settings); - SET(command_line); - -#undef SET -} - -// App Functions - -internal void -app_hardcode_styles(App_Vars *vars){ - Interactive_Style file_info_style; - Style *styles, *style; - styles = vars->styles.styles; - style = styles; - - i16 fonts = 1; - - ///////////////// - style_set_name(style, make_lit_string("4coder")); - style->font_id = fonts + 0; - - style->main.back_color = 0xFF0C0C0C; - style->main.margin_color = 0xFF181818; - style->main.margin_hover_color = 0xFF252525; - style->main.margin_active_color = 0xFF323232; - style->main.cursor_color = 0xFF00EE00; - style->main.highlight_color = 0xFFDDEE00; - style->main.mark_color = 0xFF494949; - style->main.default_color = 0xFF90B080; - style->main.at_cursor_color = style->main.back_color; - style->main.at_highlight_color = 0xFFFF44DD; - style->main.comment_color = 0xFF2090F0; - style->main.keyword_color = 0xFFD08F20; - style->main.str_constant_color = 0xFF50FF30; - style->main.char_constant_color = style->main.str_constant_color; - style->main.int_constant_color = style->main.str_constant_color; - style->main.float_constant_color = style->main.str_constant_color; - style->main.bool_constant_color = style->main.str_constant_color; - style->main.include_color = style->main.str_constant_color; - style->main.preproc_color = style->main.default_color; - style->main.special_character_color = 0xFFFF0000; - - style->main.paste_color = 0xFFDDEE00; - style->main.undo_color = 0xFF00DDEE; - - style->main.highlight_junk_color = 0xff3a0000; - style->main.highlight_white_color = 0xff003a3a; - - file_info_style.bar_color = 0xFF888888; - file_info_style.bar_active_color = 0xFF666666; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFF4444AA; - file_info_style.pop2_color = 0xFFFF0000; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - ///////////////// - *style = *(style-1); - style_set_name(style, make_lit_string("4coder-mono")); - style->font_id = fonts + 1; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("Handmade Hero")); - style->font_id = fonts + 1; - - style->main.back_color = 0xFF161616; - style->main.margin_color = 0xFF262626; - style->main.margin_hover_color = 0xFF333333; - style->main.margin_active_color = 0xFF404040; - style->main.cursor_color = 0xFF40FF40; - style->main.at_cursor_color = style->main.back_color; - style->main.mark_color = 0xFF808080; - style->main.highlight_color = 0xFF703419; - style->main.at_highlight_color = 0xFFCDAA7D; - style->main.default_color = 0xFFCDAA7D; - style->main.comment_color = 0xFF7F7F7F; - style->main.keyword_color = 0xFFCD950C; - style->main.str_constant_color = 0xFF6B8E23; - style->main.char_constant_color = style->main.str_constant_color; - style->main.int_constant_color = style->main.str_constant_color; - style->main.float_constant_color = style->main.str_constant_color; - style->main.bool_constant_color = style->main.str_constant_color; - style->main.include_color = style->main.str_constant_color; - style->main.preproc_color = style->main.default_color; - style->main.special_character_color = 0xFFFF0000; - - style->main.paste_color = 0xFFFFBB00; - style->main.undo_color = 0xFFFF00BB; - style->main.undo_color = 0xFF80005D; - - style->main.highlight_junk_color = 0xFF3A0000; - style->main.highlight_white_color = 0xFF003A3A; - - file_info_style.bar_color = 0xFFCACACA; - file_info_style.bar_active_color = 0xFFA8A8A8; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFF03CF0C; - file_info_style.pop2_color = 0xFFFF0000; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("Twilight")); - style->font_id = fonts + 2; - - style->main.back_color = 0xFF090D12; - style->main.margin_color = 0xFF1A2634; - style->main.margin_hover_color = 0xFF2D415B; - style->main.margin_active_color = 0xFF405D82; - style->main.cursor_color = 0xFFEEE800; - style->main.at_cursor_color = style->main.back_color; - style->main.mark_color = 0xFF8BA8CC; - style->main.highlight_color = 0xFF037A7B; - style->main.at_highlight_color = 0xFFFEB56C; - style->main.default_color = 0xFFB7C19E; - style->main.comment_color = 0xFF20ECF0; - style->main.keyword_color = 0xFFD86909; - style->main.str_constant_color = 0xFFC4EA5D; - style->main.char_constant_color = style->main.str_constant_color; - style->main.int_constant_color = style->main.str_constant_color; - style->main.float_constant_color = style->main.str_constant_color; - style->main.bool_constant_color = style->main.str_constant_color; - style->main.include_color = style->main.str_constant_color; - style->main.preproc_color = style->main.default_color; - style->main.special_character_color = 0xFFFF0000; - - style->main.paste_color = 0xFFDDEE00; - style->main.undo_color = 0xFF00DDEE; - - style->main.highlight_junk_color = 0xff3a0000; - style->main.highlight_white_color = 0xFF151F2A; - - file_info_style.bar_color = 0xFF315E68; - file_info_style.bar_active_color = 0xFF0F3C46; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFF1BFF0C; - file_info_style.pop2_color = 0xFFFF200D; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("Wolverine")); - style->font_id = fonts + 3; - - style->main.back_color = 0xFF070711; - style->main.margin_color = 0xFF111168; - style->main.margin_hover_color = 0xFF191996; - style->main.margin_active_color = 0xFF2121C3; - style->main.cursor_color = 0xFF7082F9; - style->main.at_cursor_color = 0xFF000014; - style->main.mark_color = 0xFF4b5028; - style->main.highlight_color = 0xFFDDEE00; - style->main.at_highlight_color = 0xFF000019; - style->main.default_color = 0xFF8C9740; - style->main.comment_color = 0xFF3A8B29; - style->main.keyword_color = 0xFFD6B109; - style->main.str_constant_color = 0xFFAF5FA7; - style->main.char_constant_color = style->main.str_constant_color; - style->main.int_constant_color = style->main.str_constant_color; - style->main.float_constant_color = style->main.str_constant_color; - style->main.bool_constant_color = style->main.str_constant_color; - style->main.include_color = style->main.str_constant_color; - style->main.preproc_color = style->main.default_color; - style->main.special_character_color = 0xFFFF0000; - - style->main.paste_color = 0xFF900090; - style->main.undo_color = 0xFF606090; - - style->main.highlight_junk_color = 0xff3a0000; - style->main.highlight_white_color = 0xff003a3a; - - file_info_style.bar_color = 0xFF7082F9; - file_info_style.bar_active_color = 0xFF4E60D7; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFFFAFA15; - file_info_style.pop2_color = 0xFFD20000; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("stb")); - style->font_id = fonts + 4; - - style->main.back_color = 0xFFD6D6D6; - style->main.margin_color = 0xFF9E9E9E; - style->main.margin_hover_color = 0xFF7E7E7E; - style->main.margin_active_color = 0xFF5C5C5C; - style->main.cursor_color = 0xFF000000; - style->main.at_cursor_color = 0xFFD6D6D6; - style->main.mark_color = 0xFF525252; - style->main.highlight_color = 0xFF0044FF; - style->main.at_highlight_color = 0xFFD6D6D6; - style->main.default_color = 0xFF000000; - style->main.comment_color = 0xFF000000; - style->main.keyword_color = 0xFF000000; - style->main.str_constant_color = 0xFF000000; - style->main.char_constant_color = style->main.str_constant_color; - style->main.int_constant_color = style->main.str_constant_color; - style->main.float_constant_color = style->main.str_constant_color; - style->main.bool_constant_color = style->main.str_constant_color; - style->main.include_color = style->main.str_constant_color; - style->main.preproc_color = style->main.default_color; - style->main.special_character_color = 0xFF9A0000; - - style->main.paste_color = 0xFF00B8B8; - style->main.undo_color = 0xFFB800B8; - - style->main.highlight_junk_color = 0xFFFF7878; - style->main.highlight_white_color = 0xFFBCBCBC; - - file_info_style.bar_color = 0xFF606060; - file_info_style.bar_active_color = 0xFF3E3E3E; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFF1111DC; - file_info_style.pop2_color = 0xFFE80505; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - vars->styles.count = (i32)(style - styles); - vars->styles.max = ArrayCount(vars->styles.styles); - style_copy(&vars->style, vars->styles.styles); - vars->style.font_changed = 0; -} - -char *_4coder_get_extension(const char *filename, int len, int *extension_len){ - char *c = (char*)(filename + len - 1); - char *end = c; - while (*c != '.' && c > filename) --c; - *extension_len = (int)(end - c); - return c+1; -} - -bool _4coder_str_match(const char *a, int len_a, const char *b, int len_b){ - bool result = 0; - if (len_a == len_b){ - char *end = (char*)(a + len_a); - while (a < end && *a == *b){ - ++a; ++b; - } - if (a == end) result = 1; - } - return result; -} - -enum Command_Line_Action{ - CLAct_Nothing, - CLAct_Ignore, - CLAct_UserFile, - CLAct_CustomDLL, - CLAct_InitialFilePosition, - CLAct_WindowSize, - CLAct_WindowMaximize, - CLAct_WindowPosition, - CLAct_Count -}; - -void -init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, - Command_Line_Parameters clparams){ - char *arg; - Command_Line_Action action = CLAct_Nothing; - i32 i,index; - b32 strict = 0; - - settings->init_files_max = ArrayCount(settings->init_files); - for (i = 1; i <= clparams.argc; ++i){ - if (i == clparams.argc) arg = ""; - else arg = clparams.argv[i]; - switch (action){ - case CLAct_Nothing: - { - if (arg[0] == '-'){ - action = CLAct_Ignore; - switch (arg[1]){ - case 'u': action = CLAct_UserFile; strict = 0; break; - case 'U': action = CLAct_UserFile; strict = 1; break; - - case 'd': action = CLAct_CustomDLL; strict = 0; break; - case 'D': action = CLAct_CustomDLL; strict = 1; 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; - } - } - else if (arg[0] != 0){ - if (settings->init_files_count < settings->init_files_max){ - index = settings->init_files_count++; - settings->init_files[index] = arg; - } - } - }break; - - case CLAct_UserFile: - { - settings->user_file_is_strict = strict; - if (i < clparams.argc){ - settings->user_file = clparams.argv[i]; - } - action = CLAct_Nothing; - }break; - - case CLAct_CustomDLL: - { - plat_settings->custom_dll_is_strict = strict; - if (i < clparams.argc){ - plat_settings->custom_dll = clparams.argv[i]; - } - action = CLAct_Nothing; - }break; - - case CLAct_InitialFilePosition: - { - if (i < clparams.argc){ - settings->initial_line = str_to_int(clparams.argv[i]); - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowSize: - { - if (i + 1 < clparams.argc){ - plat_settings->set_window_size = 1; - plat_settings->window_w = str_to_int(clparams.argv[i]); - plat_settings->window_h = str_to_int(clparams.argv[i+1]); - - ++i; - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowMaximize: - { - --i; - plat_settings->maximize_window = 1; - action = CLAct_Nothing; - }break; - - case CLAct_WindowPosition: - { - if (i + 1 < clparams.argc){ - plat_settings->set_window_pos = 1; - plat_settings->window_x = str_to_int(clparams.argv[i]); - plat_settings->window_y = str_to_int(clparams.argv[i+1]); - - ++i; - } - action = CLAct_Nothing; - }break; - } - } -} - -internal App_Vars* -app_setup_memory(Application_Memory *memory){ - Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); - App_Vars *vars = push_struct(&_partition, App_Vars); - Assert(vars); - *vars = {}; - vars->mem.part = _partition; - - general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); - - return(vars); -} - -internal i32 -execute_special_tool(void *memory, i32 size, Command_Line_Parameters clparams){ - i32 result; - char message[] = "tool was not specified or is invalid"; - result = sizeof(message) - 1; - memcpy(memory, message, result); - if (clparams.argc > 2){ - if (match(clparams.argv[2], "version")){ - result = sizeof(VERSION) - 1; - memcpy(memory, VERSION, result); - } - } - return(result); -} - -App_Read_Command_Line_Sig(app_read_command_line){ - App_Vars *vars; - i32 out_size = 0; - - if (clparams.argc > 1 && match(clparams.argv[1], "-T")){ - out_size = execute_special_tool(memory->target_memory, memory->target_memory_size, clparams); - } - else{ - vars = app_setup_memory(memory); - if (clparams.argc > 1){ - init_command_line_settings(&vars->settings, plat_settings, clparams); - } - else{ - vars->settings = {}; - } - *files = vars->settings.init_files; - *file_count = &vars->settings.init_files_count; - } - - return(out_size); -} - -App_Init_Sig(app_init){ - app_links_init(system, memory->user_memory, memory->user_memory_size); - - App_Vars *vars = (App_Vars*)memory->vars_memory; - vars->config_api = api; - app_links.cmd_context = &vars->command_data; - - Partition *partition = &vars->mem.part; - target->partition = partition; - - Panel *panels, *panel; - Panel_Divider *dividers, *div; - i32 panel_max_count; - i32 divider_max_count; - - { - i32 i; - - panel_max_count = vars->layout.panel_max_count = 16; - divider_max_count = panel_max_count - 1; - vars->layout.panel_count = 0; - - panels = push_array(partition, Panel, panel_max_count); - vars->layout.panels = panels; - - dll_init_sentinel(&vars->layout.free_sentinel); - dll_init_sentinel(&vars->layout.used_sentinel); - - panel = panels; - for (i = 0; i < panel_max_count; ++i, ++panel){ - dll_insert(&vars->layout.free_sentinel, panel); - } - - dividers = push_array(partition, Panel_Divider, divider_max_count); - vars->layout.dividers = dividers; - - div = dividers; - for (i = 0; i < divider_max_count-1; ++i, ++div){ - div->next = (div + 1); - } - div->next = 0; - vars->layout.free_divider = dividers; - } - - { - char *vptr = 0; - View *v = 0; - i32 i = 0; - i32 max = 0; - i32 view_size = sizeof(File_View); - - vars->live_set.count = 0; - vars->live_set.max = panel_max_count; - - vars->live_set.stride = view_size; - vars->live_set.views = push_block(partition, view_size*vars->live_set.max); - - dll_init_sentinel(&vars->live_set.free_sentinel); - - max = vars->live_set.max; - vptr = (char*)vars->live_set.views; - for (i = 0; i < max; ++i, vptr += view_size){ - v = (View*)(vptr); - dll_insert(&vars->live_set.free_sentinel, v); - } - } - - setup_command_table(); - - Command_Map *global = &vars->map_top; - Assert(vars->config_api.get_bindings != 0); - - i32 wanted_size = vars->config_api.get_bindings(app_links.memory, app_links.memory_size); - - b32 did_top = 0; - b32 did_file = 0; - if (wanted_size <= app_links.memory_size){ - Binding_Unit *unit = (Binding_Unit*)app_links.memory; - if (unit->type == unit_header && unit->header.error == 0){ - Binding_Unit *end = unit + unit->header.total_size; - - i32 user_map_count = unit->header.user_map_count; - - vars->map_id_table = push_array( - &vars->mem.part, i32, user_map_count); - - vars->user_maps = push_array( - &vars->mem.part, Command_Map, user_map_count); - - vars->user_map_count = user_map_count; - - Command_Map *mapptr = 0; - for (++unit; unit < end; ++unit){ - switch (unit->type){ - case unit_map_begin: - { - int table_max = unit->map_begin.bind_count * 3 / 2; - int mapid = unit->map_begin.mapid; - if (mapid == mapid_global){ - mapptr = &vars->map_top; - map_init(mapptr, &vars->mem.part, table_max, global); - did_top = 1; - } - else if (mapid == mapid_file){ - mapptr = &vars->map_file; - map_init(mapptr, &vars->mem.part, table_max, global); - did_file = 1; - } - else if (mapid < mapid_global){ - i32 index = app_get_or_add_map_index(vars, mapid); - Assert(index < user_map_count); - mapptr = vars->user_maps + index; - map_init(mapptr, &vars->mem.part, table_max, global); - } - else mapptr = 0; - }break; - - case unit_inherit: - if (mapptr){ - Command_Map *parent = 0; - int mapid = unit->map_inherit.mapid; - if (mapid == mapid_global) parent = &vars->map_top; - else if (mapid == mapid_file) parent = &vars->map_file; - else if (mapid < mapid_global){ - i32 index = app_get_or_add_map_index(vars, mapid); - if (index < user_map_count) parent = vars->user_maps + index; - else parent = 0; - } - mapptr->parent = parent; - }break; - - case unit_binding: - if (mapptr){ - Command_Function func = 0; - if (unit->binding.command_id >= 0 && unit->binding.command_id < cmdid_count) - func = command_table[unit->binding.command_id]; - if (func){ - if (unit->binding.code == 0 && unit->binding.modifiers == 0){ - mapptr->vanilla_keyboard_default.function = func; - mapptr->vanilla_keyboard_default.custom_id = unit->binding.command_id; - } - else{ - map_add(mapptr, unit->binding.code, unit->binding.modifiers, func, unit->binding.command_id); - } - } - } - break; - - case unit_callback: - if (mapptr){ - Command_Function func = command_user_callback; - Custom_Command_Function *custom = unit->callback.func; - if (func){ - if (unit->callback.code == 0 && unit->callback.modifiers == 0){ - mapptr->vanilla_keyboard_default.function = func; - mapptr->vanilla_keyboard_default.custom = custom; - } - else{ - map_add(mapptr, unit->callback.code, unit->callback.modifiers, func, custom); - } - } - } - break; - - case unit_hook: - { - int hook_id = unit->hook.hook_id; - if (hook_id >= 0 && hook_id < hook_type_count){ - vars->hooks[hook_id] = unit->hook.func; - } - }break; - } - } - } - } - - memset(app_links.memory, 0, wanted_size); - if (!did_top) setup_top_commands(&vars->map_top, &vars->mem.part, global); - if (!did_file) setup_file_commands(&vars->map_file, &vars->mem.part, global); - -#if 1 || !defined(FRED_SUPER) - vars->hooks[hook_start] = 0; -#endif - - setup_ui_commands(&vars->map_ui, &vars->mem.part, global); - - vars->font_set = &target->font_set; - - font_set_init(vars->font_set, partition, 16, 5); - - { - struct Font_Setup{ - char *c_file_name; - i32 file_name_len; - char *c_name; - i32 name_len; - i32 pt_size; - }; - -#define LitStr(n) n, sizeof(n)-1 - - Font_Setup font_setup[] = { - {LitStr("LiberationSans-Regular.ttf"), - LitStr("liberation sans"), - 16}, - - {LitStr("liberation-mono.ttf"), - LitStr("liberation mono"), - 16}, - - {LitStr("Hack-Regular.ttf"), - LitStr("hack"), - 16}, - - {LitStr("CutiveMono-Regular.ttf"), - LitStr("cutive mono"), - 16}, - - {LitStr("Inconsolata-Regular.ttf"), - LitStr("inconsolata"), - 16}, - - }; - i32 font_count = ArrayCount(font_setup); - - for (i32 i = 0; i < font_count; ++i){ - String file_name = make_string(font_setup[i].c_file_name, - font_setup[i].file_name_len); - String name = make_string(font_setup[i].c_name, - font_setup[i].name_len); - i32 pt_size = font_setup[i].pt_size; - - font_set_add(partition, vars->font_set, file_name, name, pt_size); - } - } - - // NOTE(allen): file setup - vars->working_set.file_index_count = 1; - vars->working_set.file_max_count = 120; - vars->working_set.files = - push_array(partition, Editing_File, vars->working_set.file_max_count); - - file_get_dummy(&vars->working_set.files[0]); - - vars->working_set.table.max = vars->working_set.file_max_count * 3 / 2; - vars->working_set.table.count = 0; - vars->working_set.table.table = - push_array(partition, File_Table_Entry, vars->working_set.table.max); - memset(vars->working_set.table.table, 0, sizeof(File_Table_Entry) * vars->working_set.table.max); - - // NOTE(allen): clipboard setup - vars->working_set.clipboard_max_size = ArrayCount(vars->working_set.clipboards); - vars->working_set.clipboard_size = 0; - vars->working_set.clipboard_current = 0; - vars->working_set.clipboard_rolling = 0; - - // TODO(allen): more robust allocation solution for the clipboard - if (clipboard.str){ - String *dest = working_set_next_clipboard_string(&vars->mem.general, &vars->working_set, clipboard.size); - copy(dest, make_string((char*)clipboard.str, clipboard.size)); - } - - // NOTE(allen): delay setup - vars->delay1.general = &vars->mem.general; - vars->delay1.max = 16; - vars->delay1.acts = (Delayed_Action*)general_memory_allocate( - &vars->mem.general, vars->delay1.max*sizeof(Delayed_Action), 0); - - vars->delay2.general = &vars->mem.general; - vars->delay2.max = 16; - vars->delay2.acts = (Delayed_Action*)general_memory_allocate( - &vars->mem.general, vars->delay2.max*sizeof(Delayed_Action), 0); - - // NOTE(allen): style setup - app_hardcode_styles(vars); - - vars->palette_size = 40; - vars->palette = push_array(partition, u32, vars->palette_size); - - // NOTE(allen): init first panel - Panel_And_ID p = layout_alloc_panel(&vars->layout); - panel_make_empty(system, exchange, vars, &vars->style, p.panel); - vars->layout.active_panel = p.id; - - String hdbase = make_fixed_width_string(vars->hot_dir_base_); - hot_directory_init(&vars->hot_directory, hdbase, current_directory, system->slash); - - vars->mini_str = make_string((char*)vars->mini_buffer, 0, 512); - - // NOTE(allen): child proc list setup - i32 max_children = 16; - partition_align(partition, 8); - vars->cli_processes.procs = push_array(partition, CLI_Process, max_children); - vars->cli_processes.max = max_children; - vars->cli_processes.count = 0; - - // NOTE(allen): sys app binding setup - vars->sys_app_max = exchange->file.max; - vars->sys_app_count = 0; - vars->sys_app_bindings = (Sys_App_Binding*)push_array(partition, Sys_App_Binding, vars->sys_app_max); -} - -// NOTE(allen): while I transition away from this view system to something that has -// more unified behavior, I will use this to add checks to the program's state so that I -// can make sure it behaving well. -internal void -correctness_check(App_Vars *vars){ - Panel *panel, *used_panels; - used_panels = &vars->layout.used_sentinel; - for (dll_items(panel, used_panels)){ - Assert(panel->view); - Assert(panel->parent != -1 || vars->layout.panel_count == 1); - } - panel = vars->layout.panels + vars->layout.active_panel; - Assert(panel->ALLOCED); -} - -App_Step_Sig(app_step){ - ProfileStart(OS_syncing); - Application_Step_Result app_result = *result; - app_result.redraw = force_redraw; - - App_Vars *vars = (App_Vars*)memory->vars_memory; - target->partition = &vars->mem.part; - - if (first_step || !time_step){ - app_result.redraw = 1; - } - - // NOTE(allen): OS clipboard event handling - if (clipboard.str){ - String *dest = working_set_next_clipboard_string(&vars->mem.general, &vars->working_set, clipboard.size); - dest->size = eol_convert_in(dest->str, clipboard.str, clipboard.size); - } - - // TODO(allen): profile this make sure it's not costing me too much power. - // NOTE(allen): check files are up to date - for (i32 i = 0; i < vars->working_set.file_index_count; ++i){ - Editing_File *file = vars->working_set.files + i; - - if (!file->state.is_dummy){ - u64 time_stamp = system->file_time_stamp(make_c_str(file->name.source_path)); - - if (time_stamp > 0){ - file->state.last_sys_write_time = time_stamp; - if (file->state.last_sys_write_time != file->state.last_4ed_write_time){ - app_result.redraw = 1; - } - } - } - } - - // NOTE(allen): update child processes - if (time_step){ - Temp_Memory temp = begin_temp_memory(&vars->mem.part); - u32 max = Kbytes(32); - char *dest = push_array(&vars->mem.part, char, max); - u32 amount; - - i32 count = vars->cli_processes.count; - for (i32 i = 0; i < count; ++i){ - CLI_Process *proc = vars->cli_processes.procs + i; - Editing_File *out_file = proc->out_file; - - if (out_file != 0){ - i32 new_cursor = out_file->state.cursor_pos; - - for (system->cli_begin_update(&proc->cli); - system->cli_update_step(&proc->cli, dest, max, &amount);){ - amount = eol_in_place_convert_in(dest, amount); - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.edit.start = buffer_size(&out_file->state.buffer); - spec.step.edit.end = spec.step.edit.start; - spec.step.edit.len = amount; - spec.step.pre_pos = new_cursor; - spec.step.post_pos = spec.step.edit.start + amount; - spec.str = (u8*)dest; - file_do_single_edit(system, &vars->mem, out_file, - &vars->layout, spec, hist_normal); - app_result.redraw = 1; - new_cursor = spec.step.post_pos; - } - - if (system->cli_end_update(&proc->cli)){ - *proc = vars->cli_processes.procs[--count]; - --i; - - char str_space[256]; - String str = make_fixed_width_string(str_space); - append(&str, "exited with code "); - append_int_to_str(proc->cli.exit, &str); - - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.edit.start = buffer_size(&out_file->state.buffer); - spec.step.edit.end = spec.step.edit.start; - spec.step.edit.len = str.size; - spec.step.pre_pos = new_cursor; - spec.step.post_pos = spec.step.edit.start + str.size; - spec.str = (u8*)str.str; - file_do_single_edit(system, &vars->mem, out_file, - &vars->layout, spec, hist_normal); - app_result.redraw = 1; - new_cursor = spec.step.post_pos; - } - - Panel *panel, *used_panels; - View *view; - File_View *fview; - - used_panels = &vars->layout.used_sentinel; - for (dll_items(panel, used_panels)){ - view = panel->view; - fview = view_to_file_view(view); - Assert(fview); - if (fview->file == out_file){ - view_cursor_move(fview, new_cursor); - } - } - } - } - - vars->cli_processes.count = count; - end_temp_memory(temp); - } - - // NOTE(allen): reorganizing panels on screen - { - i32 prev_width = vars->layout.full_width; - i32 prev_height = vars->layout.full_height; - i32 current_width = target->width; - i32 current_height = target->height; - - Panel *panel, *used_panels; - File_View *fview; - - vars->layout.full_width = current_width; - vars->layout.full_height = current_height; - - if (prev_width != current_width || prev_height != current_height){ - layout_refit(&vars->layout, prev_width, prev_height); - - used_panels = &vars->layout.used_sentinel; - for (dll_items(panel, used_panels)){ - fview = view_to_file_view(panel->view); - Assert(fview); - // TODO(allen): All responses to a panel changing size should - // be handled in the same place. - view_change_size(system, &vars->mem.general, fview); - } - - app_result.redraw = 1; - } - } - - // NOTE(allen): prepare input information - Key_Summary key_data = {}; - for (i32 i = 0; i < input->press_count; ++i){ - key_data.keys[key_data.count++] = input->press[i]; - } - for (i32 i = 0; i < input->hold_count; ++i){ - key_data.keys[key_data.count++] = input->hold[i]; - } - - mouse->wheel = -mouse->wheel; - - ProfileEnd(OS_syncing); - - correctness_check(vars); - - ProfileStart(hover_status); - // NOTE(allen): detect mouse hover status - i32 mx = mouse->x; - i32 my = mouse->y; - b32 mouse_in_edit_area = 0; - b32 mouse_in_margin_area = 0; - Panel *mouse_panel, *used_panels; - - used_panels = &vars->layout.used_sentinel; - for (dll_items(mouse_panel, used_panels)){ - if (hit_check(mx, my, mouse_panel->inner)){ - mouse_in_edit_area = 1; - break; - } - else if (hit_check(mx, my, mouse_panel->full)){ - mouse_in_margin_area = 1; - break; - } - } - - if (!(mouse_in_edit_area || mouse_in_margin_area)){ - mouse_panel = 0; - } - - b32 mouse_on_divider = 0; - b32 mouse_divider_vertical = 0; - i32 mouse_divider_id = 0; - i32 mouse_divider_side = 0; - - if (mouse_in_margin_area){ - Panel *panel = mouse_panel; - if (mx >= panel->inner.x0 && mx < panel->inner.x1){ - mouse_divider_vertical = 0; - if (my > panel->inner.y0){ - mouse_divider_side = -1; - } - else{ - mouse_divider_side = 1; - } - } - else{ - mouse_divider_vertical = 1; - if (mx > panel->inner.x0){ - mouse_divider_side = -1; - } - else{ - mouse_divider_side = 1; - } - } - - if (vars->layout.panel_count > 1){ - i32 which_child; - mouse_divider_id = panel->parent; - which_child = panel->which_child; - for (;;){ - Divider_And_ID div = layout_get_divider(&vars->layout, mouse_divider_id); - - if (which_child == mouse_divider_side && - div.divider->v_divider == mouse_divider_vertical){ - mouse_on_divider = 1; - break; - } - - if (mouse_divider_id == vars->layout.root){ - break; - } - else{ - mouse_divider_id = div.divider->parent; - which_child = div.divider->which_child; - } - } - } - else{ - mouse_on_divider = 0; - mouse_divider_id = 0; - } - } - ProfileEnd(hover_status); - - correctness_check(vars); - - // NOTE(allen): prepare to start executing commands - ProfileStart(prepare_commands); - - Command_Data *cmd = &vars->command_data; - - cmd->mem = &vars->mem; - cmd->panel = vars->layout.panels + vars->layout.active_panel; - cmd->view = cmd->panel->view; - cmd->working_set = &vars->working_set; - cmd->layout = &vars->layout; - cmd->live_set = &vars->live_set; - cmd->style = &vars->style; - cmd->delay = &vars->delay1; - cmd->vars = vars; - cmd->exchange = exchange; - cmd->screen_width = target->width; - cmd->screen_height = target->height; - cmd->system = system; - - Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part); - cmd->part = partition_sub_part(&vars->mem.part, 16 << 10); - - if (first_step){ - if (vars->hooks[hook_start]){ - vars->hooks[hook_start](&app_links); - cmd->part.pos = 0; - } - - i32 i; - String file_name; - Panel *panel = vars->layout.panels; - for (i = 0; i < vars->settings.init_files_count; ++i, ++panel){ - file_name = make_string_slowly(vars->settings.init_files[i]); - - if (i < vars->layout.panel_count){ - delayed_open(&vars->delay1, file_name, panel); - if (i == 0){ - delayed_set_line(&vars->delay1, panel, vars->settings.initial_line); - } - } - else{ - delayed_open_background(&vars->delay1, file_name); - } - } - } - ProfileEnd(prepare_commands); - - // NOTE(allen): process the command_coroutine if it is unfinished - ProfileStart(command_coroutine); - b8 consumed_input[6] = {0}; - - if (vars->command_coroutine != 0){ - Coroutine *command_coroutine = vars->command_coroutine; - u32 get_flags = vars->command_coroutine_flags[0]; - u32 abort_flags = vars->command_coroutine_flags[1]; - - get_flags |= abort_flags; - - if ((get_flags & EventOnAnyKey) || (get_flags & EventOnEsc)){ - for (i32 key_i = 0; key_i < key_data.count; ++key_i){ - Key_Event_Data key = get_single_key(&key_data, key_i); - View *view = cmd->view; - b32 pass_in = 0; - cmd->key = key; - - Command_Map *map = 0; - if (view) map = view->map; - if (map == 0) map = &vars->map_top; - Command_Binding cmd_bind = map_extract_recursive(map, key); - - User_Input user_in; - user_in.type = UserInputKey; - user_in.key = key; - user_in.command = (unsigned long long)cmd_bind.custom; - user_in.abort = 0; - - if ((EventOnEsc & abort_flags) && key.keycode == key_esc){ - user_in.abort = 1; - } - else if (EventOnAnyKey & abort_flags){ - user_in.abort = 1; - } - - if (EventOnAnyKey & get_flags){ - pass_in = 1; - consumed_input[0] = 1; - } - if (key.keycode == key_esc){ - if (EventOnEsc & get_flags){ - pass_in = 1; - } - consumed_input[1] = 1; - } - - if (pass_in){ - cmd->current_coroutine = vars->command_coroutine; - vars->command_coroutine = system->resume_coroutine(command_coroutine, - &user_in, vars->command_coroutine_flags); - app_result.redraw = 1; - - // TOOD(allen): Deduplicate - // TODO(allen): Allow a view to clean up however it wants after a command - // finishes, or after transfering to another view mid command. - File_View *fview = view_to_file_view(view); - if (fview != 0 && vars->command_coroutine == 0){ - init_query_set(&fview->query_set); - } - if (vars->command_coroutine == 0) break; - } - } - } - - if (vars->command_coroutine != 0 && (get_flags & EventOnMouse)){ - View *view = cmd->view; - b32 pass_in = 0; - - User_Input user_in; - user_in.type = UserInputMouse; - user_in.mouse = *mouse; - user_in.command = 0; - user_in.abort = 0; - - if (abort_flags & EventOnMouseMove){ - user_in.abort = 1; - } - if (get_flags & EventOnMouseMove){ - pass_in = 1; - consumed_input[2] = 1; - } - - if (mouse->press_l || mouse->release_l || mouse->l){ - if (abort_flags & EventOnLeftButton){ - user_in.abort = 1; - } - if (get_flags & EventOnLeftButton){ - pass_in = 1; - consumed_input[3] = 1; - } - } - - if (mouse->press_r || mouse->release_r || mouse->r){ - if (abort_flags & EventOnRightButton){ - user_in.abort = 1; - } - if (get_flags & EventOnRightButton){ - pass_in = 1; - consumed_input[4] = 1; - } - } - - if (mouse->wheel != 0){ - if (abort_flags & EventOnWheel){ - user_in.abort = 1; - } - if (get_flags & EventOnWheel){ - pass_in = 1; - consumed_input[5] = 1; - } - } - - if (pass_in){ - cmd->current_coroutine = vars->command_coroutine; - vars->command_coroutine = system->resume_coroutine(command_coroutine, &user_in, - vars->command_coroutine_flags); - app_result.redraw = 1; - - // TOOD(allen): Deduplicate - // TODO(allen): Allow a view to clean up however it wants after a command finishes, - // or after transfering to another view mid command. - File_View *fview = view_to_file_view(view); - if (fview != 0 && vars->command_coroutine == 0){ - init_query_set(&fview->query_set); - } - } - } - } - - update_command_data(vars, cmd); - - ProfileEnd(command_coroutine); - - correctness_check(vars); - - // NOTE(allen): pass raw input to the panels - ProfileStart(step); - - Input_Summary dead_input = {}; - dead_input.mouse.x = mouse->x; - dead_input.mouse.y = mouse->y; - - Input_Summary active_input = {}; - active_input.mouse.x = mouse->x; - active_input.mouse.y = mouse->y; - if (!consumed_input[0]){ - active_input.keys = key_data; - } - else if (!consumed_input[1]){ - for (i32 i = 0; i < key_data.count; ++i){ - Key_Event_Data key = get_single_key(&key_data, i); - if (key.keycode == key_esc){ - active_input.keys.count = 1; - active_input.keys.keys[0] = key; - break; - } - } - } - - Mouse_State mouse_state = *mouse; - - if (consumed_input[3]){ - mouse_state.l = 0; - mouse_state.press_l = 0; - mouse_state.release_l = 0; - } - - if (consumed_input[4]){ - mouse_state.r = 0; - mouse_state.press_r = 0; - mouse_state.release_r = 0; - } - - if (consumed_input[5]){ - mouse_state.wheel = 0; - } - - { - Panel *panel, *used_panels; - used_panels = &vars->layout.used_sentinel; - for (dll_items(panel, used_panels)){ - View *view_ = panel->view; - Assert(view_->do_view); - b32 active = (panel == cmd->panel); - Input_Summary input = (active)?(active_input):(dead_input); - if (panel == mouse_panel && !mouse->out_of_window){ - input.mouse = mouse_state; - } - if (view_->do_view(system, exchange, view_, panel->inner, cmd->view, - VMSG_STEP, 0, &input, &active_input)){ - app_result.redraw = 1; - } - } - } - - update_command_data(vars, cmd); - ProfileEnd(step); - - correctness_check(vars); - - // NOTE(allen): command execution - ProfileStart(command); - if (!consumed_input[0] || !consumed_input[1]){ - b32 consumed_input2[2] = {0}; - - for (i32 key_i = 0; key_i < key_data.count; ++key_i){ - switch (vars->state){ - case APP_STATE_EDIT: - { - Key_Event_Data key = get_single_key(&key_data, key_i); - b32 hit_esc = (key.keycode == key_esc); - cmd->key = key; - - if (hit_esc || !consumed_input[0]){ - View *view = cmd->view; - - Command_Map *map = 0; - if (view) map = view->map; - if (map == 0) map = &vars->map_top; - Command_Binding cmd_bind = map_extract_recursive(map, key); - - if (cmd_bind.function){ - if (hit_esc){ - consumed_input2[1] = 1; - } - else{ - consumed_input2[0] = 1; - } - - Coroutine *command_coroutine = system->create_coroutine(command_caller); - vars->command_coroutine = command_coroutine; - - Command_In cmd_in; - cmd_in.cmd = cmd; - cmd_in.bind = cmd_bind; - - cmd->current_coroutine = vars->command_coroutine; - vars->command_coroutine = system->launch_coroutine(vars->command_coroutine, - &cmd_in, vars->command_coroutine_flags); - vars->prev_command = cmd_bind; - app_result.redraw = 1; - } - } - }break; - - case APP_STATE_RESIZING: - { - if (key_data.count > 0){ - vars->state = APP_STATE_EDIT; - } - }break; - } - } - - consumed_input[0] |= consumed_input2[0]; - consumed_input[1] |= consumed_input2[1]; - } - - update_command_data(vars, cmd); - ProfileEnd(command); - - correctness_check(vars); - - ProfileStart(resizing); - // NOTE(allen): panel resizing - switch (vars->state){ - case APP_STATE_EDIT: - { - if (mouse->press_l && mouse_on_divider){ - vars->state = APP_STATE_RESIZING; - Divider_And_ID div = layout_get_divider(&vars->layout, mouse_divider_id); - vars->resizing.divider = div.divider; - - i32 min, max; - { - i32 mid, MIN, MAX; - mid = div.divider->pos; - if (mouse_divider_vertical){ - MIN = 0; - MAX = MIN + vars->layout.full_width; - } - else{ - MIN = 0; - MAX = MIN + vars->layout.full_height; - } - min = MIN; - max = MAX; - - i32 divider_id = div.id; - do{ - Divider_And_ID other_div = layout_get_divider(&vars->layout, divider_id); - b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); - i32 pos = other_div.divider->pos; - if (divider_match && pos > mid && pos < max){ - max = pos; - } - else if (divider_match && pos < mid && pos > min){ - min = pos; - } - divider_id = other_div.divider->parent; - }while(divider_id != -1); - - Temp_Memory temp = begin_temp_memory(&vars->mem.part); - i32 *divider_stack = push_array(&vars->mem.part, i32, vars->layout.panel_count); - i32 top = 0; - divider_stack[top++] = div.id; - - while (top > 0){ - Divider_And_ID other_div = layout_get_divider(&vars->layout, divider_stack[--top]); - b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); - i32 pos = other_div.divider->pos; - if (divider_match && pos > mid && pos < max){ - max = pos; - } - else if (divider_match && pos < mid && pos > min){ - min = pos; - } - if (other_div.divider->child1 != -1){ - divider_stack[top++] = other_div.divider->child1; - } - if (other_div.divider->child2 != -1){ - divider_stack[top++] = other_div.divider->child2; - } - } - - end_temp_memory(temp); - } - - vars->resizing.min = min; - vars->resizing.max = max; - } - }break; - - case APP_STATE_RESIZING: - { - app_result.redraw = 1; - if (mouse->l){ - Panel_Divider *divider = vars->resizing.divider; - if (divider->v_divider){ - divider->pos = mx; - } - else{ - divider->pos = my; - } - - if (divider->pos < vars->resizing.min){ - divider->pos = vars->resizing.min; - } - else if (divider->pos > vars->resizing.max){ - divider->pos = vars->resizing.max - 1; - } - - layout_fix_all_panels(&vars->layout); - } - else{ - vars->state = APP_STATE_EDIT; - } - }break; - } - - if (mouse_in_edit_area && mouse_panel != 0 && mouse->press_l){ - vars->layout.active_panel = (i32)(mouse_panel - vars->layout.panels); - app_result.redraw = 1; - } - - update_command_data(vars, cmd); - ProfileEnd(resizing); - - correctness_check(vars); - - // NOTE(allen): processing sys app bindings - ProfileStart(sys_app_bind_processing); - { - Mem_Options *mem = &vars->mem; - General_Memory *general = &mem->general; - - for (i32 i = 0; i < vars->sys_app_count; ++i){ - Sys_App_Binding *binding; - b32 remove = 0; - b32 failed = 0; - binding = vars->sys_app_bindings + i; - - byte *data; - i32 size, max; - Editing_File *ed_file; - Editing_File_Preload preload_settings; - char *filename; - - Working_Set *working_set = &vars->working_set; - - if (exchange_file_ready(exchange, binding->sys_id, &data, &size, &max)){ - ed_file = working_set->files + binding->app_id; - filename = exchange_file_filename(exchange, binding->sys_id); - preload_settings = ed_file->preload; - if (data){ - String val = make_string((char*)data, size); - file_create_from_string(system, mem, working_set, ed_file, filename, - vars->font_set, vars->style.font_id, val); - - if (ed_file->settings.tokens_exist){ - file_first_lex_parallel(system, general, ed_file); - } - - if ((binding->success & SysAppCreateView) && binding->panel != 0){ - view_file_in_panel(cmd, binding->panel, ed_file); - } - - app_result.redraw = 1; - } - else{ - if (binding->fail & SysAppCreateNewBuffer){ - file_create_empty(system, mem, working_set, ed_file, filename, - vars->font_set, vars->style.font_id); - if (binding->fail & SysAppCreateView){ - view_file_in_panel(cmd, binding->panel, ed_file); - } - } - else{ - table_remove(&vars->working_set.table, ed_file->name.source_path); - file_get_dummy(ed_file); - } - - app_result.redraw = 1; - } - - if (!ed_file->state.is_dummy){ - for (File_View_Iter iter = file_view_iter_init(&vars->layout, ed_file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - view_measure_wraps(system, general, iter.view); - view_cursor_move(iter.view, preload_settings.start_line, 0); - } - } - - exchange_free_file(exchange, binding->sys_id); - remove = 1; - } - - if (exchange_file_save_complete(exchange, binding->sys_id, &data, &size, &max, &failed)){ - Assert(remove == 0); - - if (data){ - general_memory_free(general, data); - exchange_clear_file(exchange, binding->sys_id); - } - - Editing_File *file = get_file(working_set, binding->app_id); - if (file){ - file_synchronize_times(system, file, file->name.source_path.str); - } - - exchange_free_file(exchange, binding->sys_id); - remove = 1; - - // if (failed) { TODO(allen): saving error, now what? } - } - - if (remove){ - *binding = vars->sys_app_bindings[--vars->sys_app_count]; - --i; - } - } - } - ProfileEnd(sys_app_bind_processing); - - // NOTE(allen): process as many delayed actions as possible - ProfileStart(delayed_actions); - if (vars->delay1.count > 0){ - Style *style = &vars->style; - Working_Set *working_set = &vars->working_set; - Live_Views *live_set = &vars->live_set; - Mem_Options *mem = &vars->mem; - General_Memory *general = &vars->mem.general; - - i32 count = vars->delay1.count; - vars->delay1.count = 0; - vars->delay2.count = 0; - - Delayed_Action *act = vars->delay1.acts; - for (i32 i = 0; i < count; ++i, ++act){ - String string = act->string; - Panel *panel = act->panel; - Editing_File *file = act->file; - i32 integer = act->integer; - - // TODO(allen): Paramter checking in each DACT case. - switch (act->type){ - case DACT_OPEN: - { - App_Open_File_Result result; - - result = app_open_file_background(vars, exchange, working_set, string); - - if (result.is_new){ - if (result.file){ - if (result.sys_id){ - Sys_App_Binding *binding = app_push_file_binding(vars, result.sys_id, result.file_index); - binding->success = SysAppCreateView; - binding->fail = 0; - binding->panel = panel; - } - else{ - delayed_action_repush(&vars->delay2, act); - } - } - } - else{ - if (result.file->state.is_dummy || result.file->state.is_loading){ - // do nothing - } - else{ - view_file_in_panel(cmd, panel, result.file); - } - } - }break; - - case DACT_OPEN_BACKGROUND: - { - App_Open_File_Result result; - result = app_open_file_background(vars, exchange, working_set, string); - if (result.is_new){ - if (result.file){ - if (result.sys_id){ - Sys_App_Binding *binding = app_push_file_binding(vars, result.sys_id, result.file_index); - binding->success = 0; - binding->fail = 0; - binding->panel = panel; - } - else{ - delayed_action_repush(&vars->delay2, act); - } - } - } - }break; - - case DACT_SET_LINE: - { - // TODO(allen): deduplicate - Editing_File *file = 0; - if (panel){ - File_View *fview = view_to_file_view(panel->view); - file = fview->file; - } - else if (string.str && string.size > 0){ - file = working_set_lookup_file(working_set, string); - } - if (file){ - if (file->state.is_loading){ - file->preload.start_line = integer; - } - else{ - // TODO(allen): write this case - } - } - }break; - - case DACT_SAVE_AS: - { - // TODO(allen): deduplicate - Editing_File *file = 0; - if (panel){ - File_View *fview = view_to_file_view(panel->view); - file = fview->file; - } - else if (string.str && string.size > 0){ - file = working_set_lookup_file(working_set, string); - } - if (file && !file->state.is_dummy){ - i32 sys_id = file_save_and_set_names(system, exchange, mem, working_set, file, string.str); - if (sys_id){ - app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); - } - else{ - delayed_action_repush(&vars->delay2, act); - } - } - }break; - - case DACT_SAVE: - { - if (!file){ - if (panel){ - View *view; - File_View *fview; - view = panel->view; - fview = view_to_file_view(view); - Assert(fview); - file = fview->file; - } - else{ - file = working_set_lookup_file(working_set, string); - } - } - // TODO(allen): We could handle the case where someone tries to save the same thing - // twice... that would be nice to have under control. - if (file && !file->state.is_dummy && buffer_needs_save(file)){ - i32 sys_id = file_save(system, exchange, mem, file, file->name.source_path.str); - if (sys_id){ - // TODO(allen): This is fishy! Shouldn't we bind it to a file name instead? This file - // might be killed before we get notified that the saving is done! - app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); - } - else{ - delayed_action_repush(&vars->delay2, act); - } - } - }break; - - case DACT_NEW: - { - Get_File_Result file = working_set_get_available_file(working_set); - file_create_empty(system, mem, working_set, file.file, string.str, - vars->font_set, style->font_id); - table_add(&working_set->table, file.file->name.source_path, file.index); - - View *view = panel->view; - File_View *fview = view_to_file_view(view); - - view_set_file(fview, file.file, vars->font_set, style, - system, vars->hooks[hook_open_file], &app_links); - view->map = app_get_map(vars, file.file->settings.base_map_id); -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (file.file->settings.tokens_exist) - file_first_lex_parallel(system, general, file.file); -#endif - }break; - - case DACT_SWITCH: - { - Editing_File *file = working_set_lookup_file(working_set, string); - if (file){ - View *view = panel->view; - File_View *fview = view_to_file_view(view); - - view_set_file(fview, file, vars->font_set, style, - system, vars->hooks[hook_open_file], &app_links); - view->map = app_get_map(vars, file->settings.base_map_id); - } - }break; - - case DACT_KILL: - { - Editing_File *file = working_set_lookup_file(working_set, string); - if (file){ - table_remove(&working_set->table, file->name.source_path); - kill_file(system, exchange, general, file, live_set, &vars->layout); - } - }break; - - case DACT_TRY_KILL: - { - Editing_File *file = 0; - file = working_set_lookup_file(working_set, string); - - View *view = 0; - if (panel){ - view = panel->view; - } - else{ - view = (vars->layout.panels + vars->layout.active_panel)->view; - } - - File_View *fview = view_to_file_view(view); - Assert(fview); - - if (file){ - if (buffer_needs_save(file)){ - view_show_interactive(system, fview, &vars->map_ui, - IAct_Sure_To_Kill, IInt_Sure_To_Kill, make_lit_string("Are you sure?")); - copy(&fview->dest, file->name.live_name); - } - else{ - table_remove(&working_set->table, file->name.source_path); - kill_file(system, exchange, general, file, live_set, &vars->layout); - } - } - }break; - } - - if (string.str){ - general_memory_free(&mem->general, string.str); - } - } - Swap(vars->delay1, vars->delay2); - } - - end_temp_memory(param_stack_temp); - ProfileEnd(delayed_actions); - - correctness_check(vars); - - ProfileStart(resize); - // NOTE(allen): send resize messages to panels that have changed size - { - Panel *panel, *used_panels; - used_panels = &vars->layout.used_sentinel; - for (dll_items(panel, used_panels)){ - i32_Rect prev = panel->prev_inner; - i32_Rect inner = panel->inner; - if (prev.x0 != inner.x0 || prev.y0 != inner.y0 || - prev.x1 != inner.x1 || prev.y1 != inner.y1){ - View *view = panel->view; - if (view){ - view->do_view(system, exchange, - view, inner, cmd->view, - VMSG_RESIZE, 0, &dead_input, &active_input); - } - } - panel->prev_inner = inner; - } - } - ProfileEnd(resize); - - ProfileStart(style_change); - // NOTE(allen): send style change messages if the style has changed - if (vars->style.font_changed){ - vars->style.font_changed = 0; - - Editing_File *file = vars->working_set.files; - for (i32 i = vars->working_set.file_index_count; i > 0; --i, ++file){ - if (buffer_good(&file->state.buffer) && !file->state.is_dummy){ - Render_Font *font = get_font_info(vars->font_set, vars->style.font_id)->font; - float *advance_data = 0; - if (font) advance_data = font->advance_data; - - file_measure_starts_widths(system, &vars->mem.general, - &file->state.buffer, advance_data); - } - } - - Panel *panel, *used_panels; - used_panels = &vars->layout.used_sentinel; - for (dll_items(panel, used_panels)){ - View *view = panel->view; - if (view){ - view->do_view(system, exchange, - view, panel->inner, cmd->view, - VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); - } - } - } - ProfileEnd(style_change); - - correctness_check(vars); - - ProfileStart(redraw); - if (mouse_panel != vars->prev_mouse_panel) app_result.redraw = 1; - if (app_result.redraw){ - begin_render_section(target, system); - - target->clip_top = -1; - draw_push_clip(target, rect_from_target(target)); - - // NOTE(allen): render the panels - Panel *panel, *used_panels; - used_panels = &vars->layout.used_sentinel; - for (dll_items(panel, used_panels)){ - i32_Rect full = panel->full; - i32_Rect inner = panel->inner; - - View *view = panel->view; - Style *style = &vars->style; - - b32 active = (panel == cmd->panel); - u32 back_color = style->main.back_color; - draw_rectangle(target, full, back_color); - - if (view){ - Assert(view->do_view); - draw_push_clip(target, panel->inner); - view->do_view(system, exchange, - view, panel->inner, cmd->view, - VMSG_DRAW, target, &dead_input, &active_input); - draw_pop_clip(target); - } - - u32 margin_color; - if (active){ - margin_color = style->main.margin_active_color; - } - else if (panel == mouse_panel){ - margin_color = style->main.margin_hover_color; - } - else{ - margin_color = style->main.margin_color; - } - draw_rectangle(target, i32R(full.x0, full.y0, full.x1, inner.y0), margin_color); - draw_rectangle(target, i32R(full.x0, inner.y1, full.x1, full.y1), margin_color); - draw_rectangle(target, i32R(full.x0, inner.y0, inner.x0, inner.y1), margin_color); - draw_rectangle(target, i32R(inner.x1, inner.y0, full.x1, inner.y1), margin_color); - } - - end_render_section(target, system); - } - ProfileEnd(redraw); - - ProfileStart(get_cursor); - // NOTE(allen): get cursor type - if (mouse_in_edit_area){ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; - } - else if (mouse_in_margin_area){ - if (mouse_on_divider){ - if (mouse_divider_vertical){ - 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; - } - } - vars->prev_mouse_panel = mouse_panel; - ProfileEnd(get_cursor); - - *result = app_result; - result->lctrl_lalt_is_altgr = vars->settings.lctrl_lalt_is_altgr; - - correctness_check(vars); - - // end-of-app_step -} - -external App_Get_Functions_Sig(app_get_functions){ - App_Functions result = {}; - - 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 + +// App Structs + +enum App_State{ + APP_STATE_EDIT, + APP_STATE_RESIZING, + // never below this + APP_STATE_COUNT +}; + +struct App_State_Resizing{ + Panel_Divider *divider; + i32 min, max; +}; + +struct CLI_Process{ + CLI_Handles cli; + Editing_File *out_file; +}; + +struct CLI_List{ + CLI_Process *procs; + i32 count, max; +}; + +#define SysAppCreateView 0x1 +#define SysAppCreateNewBuffer 0x2 + +struct Sys_App_Binding{ + i32 sys_id; + i32 app_id; + + u32 success; + u32 fail; + Panel *panel; +}; + +struct Complete_State{ + Search_Set set; + Search_Iter iter; + Table hits; + String_Space str; + i32 word_start, word_end; + b32 initialized; +}; + +struct Command_Data{ + Mem_Options *mem; + Panel *panel; + View *view; + Working_Set *working_set; + Editing_Layout *layout; + Live_Views *live_set; + Style *style; + Style_Font *global_font; + Delay *delay; + struct App_Vars *vars; + Exchange *exchange; + System_Functions *system; + Coroutine *current_coroutine; + + i32 screen_width, screen_height; + Key_Event_Data key; + + Partition part; +}; + +struct App_Vars{ + Mem_Options mem; + + App_Settings settings; + + Command_Map map_top; + Command_Map map_file; + Command_Map map_ui; +#if FRED_INTERNAL + Command_Map map_debug; +#endif + Command_Map *user_maps; + i32 *map_id_table; + i32 user_map_count; + Command_Binding prev_command; + + Coroutine *command_coroutine; + u32 command_coroutine_flags[2]; + + Sys_App_Binding *sys_app_bindings; + i32 sys_app_count, sys_app_max; + + Custom_Command_Function *hooks[hook_type_count]; + + Font_Set *font_set; + + Style_Font global_font; + Style style; + Style_Library styles; + u32 *palette; + i32 palette_size; + + Editing_Layout layout; + Live_Views live_set; + Working_Set working_set; + + char hot_dir_base_[256]; + Hot_Directory hot_directory; + + CLI_List cli_processes; + + Delay delay1, delay2; + + String mini_str; + u8 mini_buffer[512]; + + App_State state; + App_State_Resizing resizing; + Complete_State complete_state; + Panel *prev_mouse_panel; + + Command_Data command_data; + + Custom_API config_api; +}; + +internal i32 +app_get_or_add_map_index(App_Vars *vars, i32 mapid){ + i32 result; + i32 user_map_count = vars->user_map_count; + i32 *map_id_table = vars->map_id_table; + for (result = 0; result < user_map_count; ++result){ + if (map_id_table[result] == mapid) break; + if (map_id_table[result] == 0){ + map_id_table[result] = mapid; + break; + } + } + return result; +} + +internal i32 +app_get_map_index(App_Vars *vars, i32 mapid){ + i32 result; + i32 user_map_count = vars->user_map_count; + i32 *map_id_table = vars->map_id_table; + for (result = 0; result < user_map_count; ++result){ + if (map_id_table[result] == mapid) break; + if (map_id_table[result] == 0){ + result = user_map_count; + break; + } + } + return result; +} + +internal Command_Map* +app_get_map(App_Vars *vars, i32 mapid){ + Command_Map *map = 0; + if (mapid < mapid_global) map = vars->user_maps + mapid; + else if (mapid == mapid_global) map = &vars->map_top; + else if (mapid == mapid_file) map = &vars->map_file; + return map; +} + +// Commands + +globalvar Application_Links app_links; + +#define USE_MEM(n) Mem_Options *n = command->mem +#define USE_PANEL(n) Panel *n = command->panel +#define USE_VIEW(n) View *n = command->view +#define USE_FILE_VIEW(n) File_View *n = view_to_file_view(command->view) +#define USE_FILE(n,v) Editing_File *n = 0; if (v) { (n) = (v)->file; } +#define USE_WORKING_SET(n) Working_Set *n = command->working_set +#define USE_LAYOUT(n) Editing_Layout *n = command->layout +#define USE_LIVE_SET(n) Live_Views *live_set = command->live_set +#define USE_STYLE(n) Style *n = command->style +#define USE_FONT(n) Style_Font *n = command->global_font +#define USE_DELAY(n) Delay *n = command->delay +#define USE_VARS(n) App_Vars *n = command->vars +#define USE_EXCHANGE(n) Exchange *n = command->exchange +#define USE_FONT_SET(n) Font_Set *n = command->vars->font_set; + +#define REQ_VIEW(n) View *n = command->view; if (!n) return +#define REQ_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n) return +#define REQ_OPEN_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n || n->locked) return +#define REQ_FILE_HISTORY(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->state.buffer) || n->state.is_dummy || !n->state.undo.undo.edits) return +#define REQ_FILE_LOADING(n,v) Editing_File *n = (v)->file; if (!n || n->state.is_dummy) return +#define REQ_FILE(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->state.buffer) || n->state.is_dummy) return +#define REQ_COLOR_VIEW(n) Color_View *n = view_to_color_view(command->view); if (!n) return +#define REQ_DBG_VIEW(n) Debug_View *n = view_to_debug_view(command->view); if (!n) return + +#define COMMAND_DECL(n) internal void command_##n(System_Functions *system, Command_Data *command, Command_Binding binding) +#define COMPOSE_DECL(n) internal void n(System_Functions *system, Command_Data *command, Command_Binding binding) + +struct Command_Parameter{ + i32 type; + union{ + struct{ + Dynamic param; + Dynamic value; + } param; + struct{ + i32 len; + char *str; + } inline_string; + }; +}; + +inline Command_Parameter* +param_next(Command_Parameter *param, Command_Parameter *end){ + Command_Parameter *result = param; + if (result->type == 0){ + ++result; + } + while (result->type != 0 && result < end){ + i32 len = result->inline_string.len; + len += sizeof(*result) - 1; + len -= (len % sizeof(*result)); + result = (Command_Parameter*)((char*)result + len + sizeof(*result)); + } + return result; +} + +inline Command_Parameter* +param_stack_first(Partition *part, Command_Parameter *end){ + Command_Parameter *result = (Command_Parameter*)part->base; + if (result->type != 0) result = param_next(result, end); + return result; +} + +inline Command_Parameter* +param_stack_end(Partition *part){ + return (Command_Parameter*)((char*)part->base + part->pos); +} + +internal File_View* +panel_make_empty(System_Functions *system, Exchange *exchange, + App_Vars *vars, Style *style, Style_Font *global_font, Panel *panel){ + + Mem_Options *mem = &vars->mem; + Editing_Layout *layout = &vars->layout; + Working_Set *working_set = &vars->working_set; + Delay *delay = &vars->delay1; + + File_View *file_view; + View_And_ID new_view; + + Assert(panel->view == 0); + new_view = live_set_alloc_view(&vars->live_set, vars->config_api.scroll_rule); + panel->view = new_view.view; + panel->view->panel = panel; + + file_view = file_view_init(panel->view, layout, working_set, delay, + &vars->settings, &vars->hot_directory, mem, &vars->styles); + view_set_file(file_view, 0, vars->font_set, style, global_font, 0, 0, 0); + panel->view->map = app_get_map(vars, mapid_global); + + return(file_view); +} + +COMMAND_DECL(null){ + AllowLocal(command); +} + +COMMAND_DECL(write_character){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + char character; + i32 pos, next_cursor_pos; + + character = command->key.character; + if (character != 0){ + pos = view->cursor.pos; + next_cursor_pos = view->cursor.pos + 1; + view_replace_range(system, mem, view, layout, pos, pos, &character, 1, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + } +} + +COMMAND_DECL(seek_whitespace_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_whitespace_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_whitespace_up){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_whitespace_up(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_whitespace_down){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_whitespace_down(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +internal i32 +seek_token_left(Cpp_Token_Stack *tokens, i32 pos){ + Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); + if (get.token_index == -1){ + get.token_index = 0; + } + + Cpp_Token *token = tokens->tokens + get.token_index; + if (token->start == pos && get.token_index > 0){ + --token; + } + + return token->start; +} + +internal i32 +seek_token_right(Cpp_Token_Stack *tokens, i32 pos){ + Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); + if (get.in_whitespace){ + ++get.token_index; + } + if (get.token_index >= tokens->count){ + get.token_index = tokens->count-1; + } + + Cpp_Token *token = tokens->tokens + get.token_index; + return token->start + token->size; +} + +COMMAND_DECL(seek_token_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + if (file->state.tokens_complete){ + i32 pos = seek_token_left(&file->state.token_stack, view->cursor.pos); + view_cursor_move(view, pos); + } +} + +COMMAND_DECL(seek_token_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + if (file->state.tokens_complete){ + i32 pos = seek_token_right(&file->state.token_stack, view->cursor.pos); + view_cursor_move(view, pos); + } +} + +COMMAND_DECL(seek_white_or_token_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 token_pos, white_pos; + if (file->state.tokens_complete){ + token_pos = seek_token_right(&file->state.token_stack, view->cursor.pos); + } + else{ + token_pos = buffer_size(&file->state.buffer); + } + white_pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, Min(token_pos, white_pos)); +} + +COMMAND_DECL(seek_white_or_token_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 token_pos, white_pos; + if (file->state.tokens_complete){ + token_pos = seek_token_left(&file->state.token_stack, view->cursor.pos); + } + else{ + token_pos = 0; + } + white_pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, Max(token_pos, white_pos)); +} + +COMMAND_DECL(seek_alphanumeric_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_alphanumeric_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_alphanumeric_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_alphanumeric_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_alphanumeric_or_camel_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_alphanumeric_or_camel_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_alphanumeric_or_camel_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_alphanumeric_or_camel_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(word_complete){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + USE_VARS(vars); + USE_WORKING_SET(working_set); + + Partition *part = &mem->part; + General_Memory *general = &mem->general; + Complete_State *complete_state = &vars->complete_state; + Search_Range *ranges; + Search_Match match; + + Temp_Memory temp; + + Buffer_Type *buffer; + Buffer_Backify_Type loop; + char *data; + i32 end; + i32 size_of_buffer; + + i32 cursor_pos, word_start, word_end; + char c; + + char *spare; + i32 size; + + i32 buffer_count, i, j; + Editing_File *file_ptr; + + i32 match_size; + b32 do_init = 0; + + buffer = &file->state.buffer; + size_of_buffer = buffer_size(buffer); + + if (view->mode.rewrite != 2){ + do_init = 1; + } + view->next_mode.rewrite = 2; + + if (complete_state->initialized == 0){ + do_init = 1; + } + + if (do_init){ + word_end = view->cursor.pos; + word_start = word_end; + cursor_pos = word_end - 1; + + // TODO(allen): macros for these buffer loops and some method of breaking out of them. + for (loop = buffer_backify_loop(buffer, cursor_pos, 0); + buffer_backify_good(&loop); + buffer_backify_next(&loop)){ + end = loop.absolute_pos; + data = loop.data - loop.absolute_pos; + for (; cursor_pos >= end; --cursor_pos){ + c = data[cursor_pos]; + if (char_is_alpha(c)){ + word_start = cursor_pos; + } + else if (!char_is_numeric(c)){ + goto double_break; + } + } + } + double_break:; + + size = word_end - word_start; + + if (size == 0){ + complete_state->initialized = 0; + return; + } + + complete_state->initialized = 1; + search_iter_init(general, &complete_state->iter, size); + buffer_stringify(buffer, word_start, word_end, complete_state->iter.word.str); + complete_state->iter.word.size = size; + + buffer_count = working_set->file_index_count; + search_set_init(general, &complete_state->set, buffer_count + 1); + ranges = complete_state->set.ranges; + ranges[0].buffer = buffer; + ranges[0].start = 0; + ranges[0].size = word_start; + + ranges[1].buffer = buffer; + ranges[1].start = word_end; + ranges[1].size = size_of_buffer - word_end; + + file_ptr = working_set->files; + for (i = 0, j = 2; i < buffer_count; ++i, ++file_ptr){ + if (file_ptr != file && !file_ptr->state.is_dummy){ + ranges[j].buffer = &file_ptr->state.buffer; + ranges[j].start = 0; + ranges[j].size = buffer_size(ranges[j].buffer); + ++j; + } + } + complete_state->set.count = j; + + search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); + search_hit_add(general, &complete_state->hits, &complete_state->str, + complete_state->iter.word.str, complete_state->iter.word.size); + + complete_state->word_start = word_start; + complete_state->word_end = word_end; + } + else{ + word_start = complete_state->word_start; + word_end = complete_state->word_end; + size = complete_state->iter.word.size; + } + + if (size > 0){ + for (;;){ + match = search_next_match(part, &complete_state->set, &complete_state->iter); + + if (match.found_match){ + temp = begin_temp_memory(part); + match_size = match.end - match.start; + spare = (char*)push_array(part, char, match_size); + buffer_stringify(match.buffer, match.start, match.end, spare); + + if (search_hit_add(general, &complete_state->hits, &complete_state->str, spare, match_size)){ + view_replace_range(system, mem, view, layout, word_start, word_end, spare, match_size, word_end); + + complete_state->word_end = word_start + match_size; + complete_state->set.ranges[1].start = word_start + match_size; + break; + } + end_temp_memory(temp); + } + else{ + complete_state->iter.pos = 0; + complete_state->iter.i = 0; + + search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); + search_hit_add(general, &complete_state->hits, &complete_state->str, + complete_state->iter.word.str, complete_state->iter.word.size); + + match_size = complete_state->iter.word.size; + view_replace_range(system, mem, view, layout, word_start, word_end, + complete_state->iter.word.str, match_size, word_end); + + complete_state->word_end = word_start + match_size; + complete_state->set.ranges[1].start = word_start + match_size; + break; + } + } + } +} + +COMMAND_DECL(set_mark){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + view->mark = (i32)view->cursor.pos; +} + +COMMAND_DECL(copy){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_WORKING_SET(working_set); + USE_MEM(mem); + + // TODO(allen): deduplicate + int r_start = 0, r_end = 0; + int start_set = 0, end_set = 0; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_range_start: + start_set = 1; + r_start = dynamic_to_int(¶m->param.value); + break; + + case par_range_end: + end_set = 1; + r_end = dynamic_to_int(¶m->param.value); + break; + } + } + + Range range = make_range(view->cursor.pos, view->mark); + if (start_set) range.start = r_start; + if (end_set) range.end = r_end; + if (range.start < range.end){ + clipboard_copy(system, &mem->general, working_set, range, file); + } +} + +COMMAND_DECL(cut){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_WORKING_SET(working_set); + USE_LAYOUT(layout); + USE_MEM(mem); + + // TODO(allen): deduplicate + int r_start = 0, r_end = 0; + int start_set = 0, end_set = 0; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_range_start: + start_set = 1; + r_start = dynamic_to_int(¶m->param.value); + break; + + case par_range_end: + end_set = 1; + r_end = dynamic_to_int(¶m->param.value); + break; + } + } + + Range range = make_range(view->cursor.pos, view->mark); + if (start_set) range.start = r_start; + if (end_set) range.end = r_end; + if (range.start < range.end){ + i32 next_cursor_pos = range.start; + + clipboard_copy(system, &mem->general, working_set, range, file); + view_replace_range(system, mem, view, layout, range.start, range.end, 0, 0, next_cursor_pos); + + view->mark = range.start; + view_cursor_move(view, next_cursor_pos); + } +} + +COMMAND_DECL(paste){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_WORKING_SET(working_set); + USE_LAYOUT(layout); + USE_MEM(mem); + + Panel *panel, *used_panels; + String *src; + File_View *current_view; + i32 pos_left, next_cursor_pos; + + if (working_set->clipboard_size > 0){ + view->next_mode.rewrite = 1; + + src = working_set_clipboard_head(working_set); + pos_left = view->cursor.pos; + + next_cursor_pos = pos_left+src->size; + view_replace_range(system, mem, view, layout, pos_left, pos_left, src->str, src->size, next_cursor_pos); + + view_cursor_move(view, next_cursor_pos); + view->mark = pos_left; + + used_panels = &layout->used_sentinel; + for (dll_items(panel, used_panels)){ + current_view = view_to_file_view(panel->view); + + if (current_view->file == file){ + view_post_paste_effect(current_view, 20, pos_left, src->size, + current_view->style->main.paste_color); + } + } + } +} + +COMMAND_DECL(paste_next){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_WORKING_SET(working_set); + USE_LAYOUT(layout); + USE_MEM(mem); + + Panel *panel, *used_panels; + + if (working_set->clipboard_size > 0 && view->mode.rewrite == 1){ + view->next_mode.rewrite = 1; + + Range range = make_range(view->mark, view->cursor.pos); + String *src = working_set_clipboard_roll_down(working_set); + i32 next_cursor_pos = range.start+src->size; + view_replace_range(system, + mem, view, layout, range.start, range.end, + src->str, src->size, next_cursor_pos); + + view_cursor_move(view, next_cursor_pos); + view->mark = range.start; + + used_panels = &layout->used_sentinel; + for (dll_items(panel, used_panels)){ + File_View *current_view = view_to_file_view(panel->view); + + if (current_view->file == file){ + view_post_paste_effect(current_view, 20, range.start, src->size, + current_view->style->main.paste_color); + } + } + } + else{ + command_paste(system, command, binding); + } +} + +COMMAND_DECL(delete_range){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + Range range = make_range(view->cursor.pos, view->mark); + if (range.start < range.end){ + i32 next_cursor_pos = range.start; + view_replace_range(system, mem, view, layout, range.start, range.end, + 0, 0, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + view->mark = range.start; + } +} + +COMMAND_DECL(timeline_scrub){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + + view_set_widget(view, FWIDG_TIMELINES); + view->widget.timeline.undo_line = 1; + view->widget.timeline.history_line = 1; +} + +COMMAND_DECL(undo){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_undo(system, mem, layout, view); +} + +COMMAND_DECL(redo){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_redo(system, mem, layout, view); +} + +COMMAND_DECL(history_backward){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_history_step(system, mem, layout, view, hist_backward); +} + +COMMAND_DECL(history_forward){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_history_step(system, mem, layout, view, hist_forward); +} + +#if UseFileHistoryDump +COMMAND_DECL(save_history){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + + file_dump_history(system, mem, file, "history_data.hst"); +} +#endif + +COMMAND_DECL(interactive_new){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + view_show_interactive(system, fview, &vars->map_ui, + IAct_New, IInt_Sys_File_List, make_lit_string("New: ")); +} + +internal Sys_App_Binding* +app_push_file_binding(App_Vars *vars, int sys_id, int app_id){ + Sys_App_Binding *binding; + Assert(vars->sys_app_count < vars->sys_app_max); + binding = vars->sys_app_bindings + vars->sys_app_count++; + binding->sys_id = sys_id; + binding->app_id = app_id; + return(binding); +} + +struct App_Open_File_Result{ + Editing_File *file; + i32 sys_id; + i32 file_index; + b32 is_new; +}; + +internal App_Open_File_Result +app_open_file_background(App_Vars *vars, Exchange *exchange, Working_Set *working_set, String filename){ + Get_File_Result file; + i32 file_id; + App_Open_File_Result result = {}; + + result.file = working_set_contains(working_set, filename); + if (result.file == 0){ + result.is_new = 1; + file = working_set_get_available_file(working_set); + if (file.file){ + result.file = file.file; + file_id = exchange_request_file(exchange, filename.str, filename.size); + if (file_id){ + file_init_strings(result.file); + file_set_name(working_set, result.file, filename.str); + file_set_to_loading(result.file); + table_add(&working_set->table, result.file->name.source_path, file.index); + + result.sys_id = file_id; + result.file_index = file.index; + } + else{ + file_get_dummy(file.file); + } + } + } + + return(result); +} + +COMMAND_DECL(interactive_open){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_PANEL(panel); + USE_DELAY(delay); + + char *filename = 0; + int filename_len = 0; + int do_in_background = 0; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + if (param->param.param.type == dynamic_type_int){ + if (param->param.param.int_value == par_name && + param->param.value.type == dynamic_type_string){ + filename = param->param.value.str_value; + filename_len = param->param.value.str_len; + } + else if (param->param.param.int_value == par_do_in_background){ + do_in_background = dynamic_to_int(¶m->param.value); + } + } + } + + if (filename){ + String string = make_string(filename, filename_len); + if (do_in_background){ + delayed_open_background(delay, string); + } + else{ + delayed_open(delay, string, panel); + } + } + else{ + View *view = panel->view; + Assert(view); + + File_View *fview = view_to_file_view(view); + + view_show_interactive(system, fview, &vars->map_ui, + IAct_Open, IInt_Sys_File_List, make_lit_string("Open: ")); + } +} + +internal void +view_file_in_panel(Command_Data *cmd, Panel *panel, Editing_File *file){ + Mem_Options *mem = cmd->mem; + System_Functions *system = cmd->system; + Editing_Layout *layout = cmd->layout; + App_Vars *vars = cmd->vars; + Style *style = cmd->style; + Style_Font *global_font = cmd->global_font; + Working_Set *working_set = &vars->working_set; + Delay *delay = &vars->delay1; + + Partition old_part; + Temp_Memory temp; + View *old_view; + File_View *file_view; + + file_view = file_view_init(panel->view, layout, working_set, delay, + &vars->settings, &vars->hot_directory, mem, &vars->styles); + + old_view = cmd->view; + cmd->view = panel->view; + + old_part = cmd->part; + temp = begin_temp_memory(&mem->part); + cmd->part = partition_sub_part(&mem->part, Kbytes(16)); + + view_set_file(file_view, file, vars->font_set, style, global_font, + system, vars->hooks[hook_open_file], &app_links); + + cmd->part = old_part; + end_temp_memory(temp); + cmd->view = old_view; + + panel->view->map = app_get_map(vars, file->settings.base_map_id); +} + +// TODO(allen): Improvements to reopen +// - Preserve existing token stack +// - Keep current version open and do some sort of diff to keep +// the cursor position correct +COMMAND_DECL(reopen){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_EXCHANGE(exchange); + USE_WORKING_SET(working_set); + USE_VARS(vars); + USE_STYLE(style); + USE_FONT(global_font); + + i32 file_id = exchange_request_file(exchange, expand_str(file->name.source_path)); + i32 index = 0; + if (file_id){ + file_set_to_loading(file); + index = working_set_get_index(working_set, file); + app_push_file_binding(vars, file_id, index); + + view_set_file(view, file, vars->font_set, style, global_font, + system, vars->hooks[hook_open_file], &app_links); + } + else{ + // TODO(allen): feedback message + } +} + +COMMAND_DECL(save){ + ProfileMomentFunction(); + USE_FILE_VIEW(view); + USE_FILE(file, view); + USE_DELAY(delay); + USE_WORKING_SET(working_set); + + char *filename = 0; + int filename_len = 0; + int buffer_id = -1; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int v = dynamic_to_int(¶m->param.param); + if (v == par_name && param->param.value.type == dynamic_type_string){ + filename = param->param.value.str_value; + filename_len = param->param.value.str_len; + } + else if (v == par_buffer_id && param->param.value.type == dynamic_type_int){ + buffer_id = dynamic_to_int(¶m->param.value); + } + } + + String name = {}; + if (filename){ + name = make_string(filename, filename_len); + } + else if (file){ + name = file->name.source_path; + } + + if (name.size != 0){ + if (buffer_id == -1){ + if (file){ + delayed_save(delay, name, file); + } + } + else{ + file = working_set->files + buffer_id; + + if (!file->state.is_dummy && file_is_ready(file)){ + delayed_save(delay, name, file); + } + else{ + delayed_save(delay, name); + } + } + } +} + +COMMAND_DECL(interactive_save_as){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + view_show_interactive(system, fview, &vars->map_ui, + IAct_Save_As, IInt_Sys_File_List, make_lit_string("Save As: ")); +} + +COMMAND_DECL(change_active_panel){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + + panel = panel->next; + if (panel == &layout->used_sentinel){ + panel = panel->next; + } + layout->active_panel = (i32)(panel - layout->panels); +} + +COMMAND_DECL(interactive_switch_buffer){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + view_show_interactive(system, fview, &vars->map_ui, + IAct_Switch, IInt_Live_File_List, make_lit_string("Switch Buffer: ")); +} + +COMMAND_DECL(interactive_kill_buffer){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + view_show_interactive(system, fview, &vars->map_ui, + IAct_Kill, IInt_Live_File_List, make_lit_string("Kill Buffer: ")); +} + +COMMAND_DECL(kill_buffer){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_DELAY(delay); + + delayed_try_kill(delay, file->name.live_name, view->view_base.panel); +} + +COMMAND_DECL(toggle_line_wrap){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + Relative_Scrolling scrolling = view_get_relative_scrolling(view); + if (view->unwrapped_lines){ + view->unwrapped_lines = 0; + file->settings.unwrapped_lines = 0; + view->target_x = 0; + view->cursor = + view_compute_cursor_from_pos(view, view->cursor.pos); + view->preferred_x = view->cursor.wrapped_x; + } + else{ + view->unwrapped_lines = 1; + file->settings.unwrapped_lines = 1; + view->cursor = + view_compute_cursor_from_pos(view, view->cursor.pos); + view->preferred_x = view->cursor.unwrapped_x; + } + view_set_relative_scrolling(view, scrolling); +} + +COMMAND_DECL(toggle_show_whitespace){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + view->show_whitespace = !view->show_whitespace; +} + +COMMAND_DECL(toggle_tokens){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + + if (file->settings.tokens_exist){ + file_kill_tokens(system, &mem->general, file); + } + else{ + file_first_lex_parallel(system, &mem->general, file); + } +#endif +} + +internal void +case_change_range(System_Functions *system, + Mem_Options *mem, File_View *view, Editing_File *file, + u8 a, u8 z, u8 char_delta){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Range range = make_range(view->cursor.pos, view->mark); + if (range.start < range.end){ + Edit_Step step = {}; + step.type = ED_NORMAL; + step.edit.start = range.start; + step.edit.end = range.end; + step.edit.len = range.end - range.start; + + if (file->state.still_lexing) + system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); + + file_update_history_before_edit(mem, file, step, 0, hist_normal); + + u8 *data = (u8*)file->state.buffer.data; + for (i32 i = range.start; i < range.end; ++i){ + if (data[i] >= a && data[i] <= z){ + data[i] += char_delta; + } + } + + if (file->state.token_stack.tokens) + file_relex_parallel(system, mem, file, range.start, range.end, 0); + } +#endif +} + +COMMAND_DECL(to_uppercase){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + case_change_range(system, mem, view, file, 'a', 'z', (u8)('A' - 'a')); +} + +COMMAND_DECL(to_lowercase){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + case_change_range(system, mem, view, file, 'A', 'Z', (u8)('a' - 'A')); +} + +COMMAND_DECL(clean_all_lines){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_clean_whitespace(system, mem, view, layout); +} + +COMMAND_DECL(eol_dosify){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + file->settings.dos_write_mode = 1; + file->state.last_4ed_edit_time = system->time(); +} + +COMMAND_DECL(eol_nixify){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + file->settings.dos_write_mode = 0; + file->state.last_4ed_edit_time = system->time(); +} + +COMMAND_DECL(auto_tab_range){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + int r_start = 0, r_end = 0; + int start_set = 0, end_set = 0; + int clear_blank_lines = 1; + + // TODO(allen): deduplicate + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_range_start: + start_set = 1; + r_start = dynamic_to_int(¶m->param.value); + break; + + case par_range_end: + end_set = 1; + r_end = dynamic_to_int(¶m->param.value); + break; + + case par_clear_blank_lines: + clear_blank_lines = dynamic_to_bool(¶m->param.value); + break; + } + } + + if (file->state.token_stack.tokens && file->state.tokens_complete){ + Range range = make_range(view->cursor.pos, view->mark); + if (start_set) range.start = r_start; + if (end_set) range.end = r_end; + view_auto_tab_tokens(system, mem, view, layout, range.start, range.end, clear_blank_lines); + } +} + +COMMAND_DECL(auto_tab_line_at_cursor){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + int clear_blank_lines = 0; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_clear_blank_lines: + clear_blank_lines = dynamic_to_bool(¶m->param.value); + break; + } + } + + if (file->state.token_stack.tokens && file->state.tokens_complete){ + i32 pos = view->cursor.pos; + view_auto_tab_tokens(system, mem, view, layout, pos, pos, clear_blank_lines); + } +} + +COMMAND_DECL(auto_tab_whole_file){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + if (file->state.token_stack.tokens && file->state.tokens_complete){ + view_auto_tab_tokens(system, mem, view, layout, 0, buffer_size(&file->state.buffer), 1); + } +} + +COMMAND_DECL(open_panel_vsplit){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + USE_EXCHANGE(exchange); + USE_VARS(vars); + USE_STYLE(style); + USE_FONT(global_font); + + if (layout->panel_count < layout->panel_max_count){ + Split_Result split = layout_split_panel(layout, panel, 1); + + Panel *panel1 = panel; + Panel *panel2 = split.panel; + + panel2->screen_region = panel1->screen_region; + + panel2->full.x0 = split.divider->pos; + panel2->full.x1 = panel1->full.x1; + panel1->full.x1 = split.divider->pos; + + panel_fix_internal_area(panel1); + panel_fix_internal_area(panel2); + panel2->prev_inner = panel2->inner; + + layout->active_panel = (i32)(panel2 - layout->panels); + panel_make_empty(system, exchange, vars, style, global_font, panel2); + } +} + +COMMAND_DECL(open_panel_hsplit){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + USE_EXCHANGE(exchange); + USE_VARS(vars); + USE_STYLE(style); + USE_FONT(global_font); + + if (layout->panel_count < layout->panel_max_count){ + Split_Result split = layout_split_panel(layout, panel, 0); + + Panel *panel1 = panel; + Panel *panel2 = split.panel; + + panel2->screen_region = panel1->screen_region; + + panel2->full.y0 = split.divider->pos; + panel2->full.y1 = panel1->full.y1; + panel1->full.y1 = split.divider->pos; + + panel_fix_internal_area(panel1); + panel_fix_internal_area(panel2); + panel2->prev_inner = panel2->inner; + + layout->active_panel = (i32)(panel2 - layout->panels); + panel_make_empty(system, exchange, vars, style, global_font, panel2); + } +} + +COMMAND_DECL(close_panel){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + USE_VIEW(view); + USE_EXCHANGE(exchange); + + Panel *panel_ptr, *used_panels; + Divider_And_ID div, parent_div, child_div; + i32 child; + i32 parent; + i32 which_child; + i32 active; + + if (layout->panel_count > 1){ + live_set_free_view(system, exchange, command->live_set, view); + panel->view = 0; + + div = layout_get_divider(layout, panel->parent); + + // This divider cannot have two child dividers. + Assert(div.divider->child1 == -1 || div.divider->child2 == -1); + + // Get the child who needs to fill in this node's spot + child = div.divider->child1; + if (child == -1) child = div.divider->child2; + + parent = div.divider->parent; + which_child = div.divider->which_child; + + // Fill the child in the slot this node use to hold + if (parent == -1){ + Assert(layout->root == div.id); + layout->root = child; + } + else{ + parent_div = layout_get_divider(layout, parent); + if (which_child == -1){ + parent_div.divider->child1 = child; + } + else{ + parent_div.divider->child2 = child; + } + } + + // If there was a child divider, give it information about it's new parent. + if (child != -1){ + child_div = layout_get_divider(layout, child); + child_div.divider->parent = parent; + child_div.divider->which_child = div.divider->which_child; + } + + // What is the new active panel? + active = -1; + if (child == -1){ + used_panels = &layout->used_sentinel; + for (dll_items(panel_ptr, used_panels)){ + if (panel_ptr != panel && panel_ptr->parent == div.id){ + panel_ptr->parent = parent; + panel_ptr->which_child = which_child; + active = (i32)(panel_ptr - layout->panels); + break; + } + } + } + else{ + panel_ptr = panel->next; + if (panel_ptr == &layout->used_sentinel) panel_ptr = panel_ptr->next; + Assert(panel_ptr != panel); + active = (i32)(panel_ptr - layout->panels); + } + + Assert(active != -1 && panel != layout->panels + active); + layout->active_panel = active; + + layout_free_divider(layout, div.divider); + layout_free_panel(layout, panel); + layout_fix_all_panels(layout); + } +} + +COMMAND_DECL(move_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = view->cursor.pos; + if (pos > 0) --pos; + view_cursor_move(view, pos); +} + +COMMAND_DECL(move_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 size = buffer_size(&file->state.buffer); + i32 pos = view->cursor.pos; + if (pos < size) ++pos; + view_cursor_move(view, pos); +} + +COMMAND_DECL(delete){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + i32 size = buffer_size(&file->state.buffer); + i32 cursor_pos = view->cursor.pos; + if (0 < size && cursor_pos < size){ + i32 start, end; + start = cursor_pos; + end = cursor_pos+1; + + Assert(end - start > 0); + + i32 next_cursor_pos = start; + view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + } +} + +COMMAND_DECL(backspace){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + i32 size = buffer_size(&file->state.buffer); + i32 cursor_pos = view->cursor.pos; + if (cursor_pos > 0 && cursor_pos <= size){ + i32 start, end; + end = cursor_pos; + start = cursor_pos-1; + + i32 shift = (end - start); + Assert(shift > 0); + + i32 next_cursor_pos = view->cursor.pos - shift; + view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + } +} + +COMMAND_DECL(move_up){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_FONT_SET(font_set); + USE_FONT(global_font); + + f32 font_height = (f32)get_font_info(font_set, global_font->font_id)->height; + f32 cy = view_get_cursor_y(view)-font_height; + f32 px = view->preferred_x; + if (cy >= 0){ + view->cursor = view_compute_cursor_from_xy(view, px, cy); + file->state.cursor_pos = view->cursor.pos; + } +} + +COMMAND_DECL(move_down){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_FONT_SET(font_set); + USE_FONT(global_font); + + f32 font_height = (f32)get_font_info(font_set, global_font->font_id)->height; + f32 cy = view_get_cursor_y(view)+font_height; + f32 px = view->preferred_x; + view->cursor = view_compute_cursor_from_xy(view, px, cy); + file->state.cursor_pos = view->cursor.pos; +} + +COMMAND_DECL(seek_end_of_line){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = view_find_end_of_line(view, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_beginning_of_line){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = view_find_beginning_of_line(view, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(page_down){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + f32 height = view_compute_height(view); + f32 max_target_y = view_compute_max_target_y(view); + + view->target_y += height; + if (view->target_y > max_target_y) view->target_y = max_target_y; + + view->cursor = view_compute_cursor_from_xy( + view, 0, view->target_y + (height - view->font_height)*.5f); +} + +COMMAND_DECL(page_up){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + f32 height = view_compute_height(view); + + view->target_y -= height; + if (view->target_y < 0) view->target_y = 0; + + view->cursor = view_compute_cursor_from_xy( + view, 0, view->target_y + (height - view->font_height)*.5f); +} + +COMMAND_DECL(open_color_tweaker){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + view_show_theme(fview, &vars->map_ui); +} + +COMMAND_DECL(open_config){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + view_show_config(fview, &vars->map_ui); +} + +COMMAND_DECL(open_menu){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + view_show_menu(fview, &vars->map_ui); +} + +COMMAND_DECL(close_minor_view){ + ProfileMomentFunction(); + REQ_VIEW(view); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + Command_Map *map = &vars->map_top; + if (fview->file){ + map = app_get_map(vars, fview->file->settings.base_map_id); + } + view_show_file(fview, map); +} + +COMMAND_DECL(cursor_mark_swap){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + i32 pos = view->cursor.pos; + view_cursor_move(view, view->mark); + view->mark = pos; +} + +COMMAND_DECL(user_callback){ + ProfileMomentFunction(); + if (binding.custom) binding.custom(&app_links); +} + +COMMAND_DECL(set_settings){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_LOADING(file, view); + USE_VARS(vars); + USE_MEM(mem); + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_lex_as_cpp_file: + { +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + int v = dynamic_to_bool(¶m->param.value); + if (file->settings.tokens_exist){ + if (!v) file_kill_tokens(system, &mem->general, file); + } + else{ + if (v) file_first_lex_parallel(system, &mem->general, file); + } +#endif + }break; + + case par_wrap_lines: + { + int v = dynamic_to_bool(¶m->param.value); + if (view->unwrapped_lines){ + if (v){ + view->unwrapped_lines = 0; + file->settings.unwrapped_lines = 0; + + if (!file->state.is_loading){ + Relative_Scrolling scrolling = view_get_relative_scrolling(view); + view->target_x = 0; + view->cursor = + view_compute_cursor_from_pos(view, view->cursor.pos); + view_set_relative_scrolling(view, scrolling); + } + } + } + else{ + if (!v){ + view->unwrapped_lines = 1; + file->settings.unwrapped_lines = 1; + + if (!file->state.is_loading){ + Relative_Scrolling scrolling = view_get_relative_scrolling(view); + view->cursor = + view_compute_cursor_from_pos(view, view->cursor.pos); + view_set_relative_scrolling(view, scrolling); + } + } + } + }break; + + case par_key_mapid: + { + int v = dynamic_to_int(¶m->param.value); + if (v == mapid_global) file->settings.base_map_id = mapid_global; + else if (v == mapid_file) file->settings.base_map_id = mapid_file; + else if (v < mapid_global){ + int index = app_get_map_index(vars, v); + if (index < vars->user_map_count) file->settings.base_map_id = v; + else file->settings.base_map_id = mapid_file; + } + }break; + } + } +} + +#define CLI_OverlapWithConflict (1<<0) +#define CLI_AlwaysBindToView (2<<0) + +internal void +build(System_Functions *system, Mem_Options *mem, + App_Vars *vars, Working_Set *working_set, + Font_Set *font_set, Style *style, Style_Font *global_font, + Live_Views *live_set, Exchange *exchange, + Panel *panel, Command_Data *command, + String hot_directory, + char *buffer_name, i32 buffer_name_len, + char *path, i32 path_len, + char *script, i32 script_len, + u32 flags){ + if (buffer_name == 0 || path == 0 || script == 0){ + return; + } + + if (vars->cli_processes.count < vars->cli_processes.max){ + Editing_Layout *layout = &vars->layout; + Editing_File *file = working_set_contains(working_set, make_string_slowly(buffer_name)); + i32 index; + b32 bind_to_new_view = 1; + + if (!file){ + Get_File_Result get_file = working_set_get_available_file(working_set); + file = get_file.file; + index = get_file.index; + } + else{ + i32 proc_count = vars->cli_processes.count; + for (i32 i = 0; i < proc_count; ++i){ + if (vars->cli_processes.procs[i].out_file == file){ + if (flags & CLI_OverlapWithConflict) + vars->cli_processes.procs[i].out_file = 0; + else file = 0; + break; + } + } + index = (i32)(file - vars->working_set.files); + if (file){ + if (!(flags & CLI_AlwaysBindToView)){ + Panel *panel = layout->panels; + for (i32 i = 0; i < layout->panel_count; ++i, ++panel){ + File_View *fview = view_to_file_view(panel->view); + if (fview && fview->file == file){ + bind_to_new_view = 0; + break; + } + } + } + } + } + + if (file){ + file_create_super_locked(system, mem, working_set, file, buffer_name, font_set, global_font->font_id); + file->settings.unimportant = 1; + table_add(&working_set->table, file->name.source_path, index); + + if (bind_to_new_view){ + view_file_in_panel(command, panel, file); + } + + i32 i = vars->cli_processes.count++; + CLI_Process *proc = vars->cli_processes.procs + i; + if (!system->cli_call(path, script, &proc->cli)){ + --vars->cli_processes.count; + } + proc->out_file = file; + } + else{ + // TODO(allen): feedback message - no available file + } + } + else{ + // TODO(allen): feedback message - no available process slot + } +} + +COMMAND_DECL(command_line){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_MEM(mem); + USE_WORKING_SET(working_set); + USE_STYLE(style); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_EXCHANGE(exchange); + USE_FONT_SET(font_set); + USE_FONT(global_font); + + char *buffer_name = 0; + char *path = 0; + char *script = 0; + + int buffer_name_len = 0; + int path_len = 0; + int script_len = 0; + u32 flags = CLI_OverlapWithConflict; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_name: + { + if (buffer_name == 0){ + char *new_buffer_name = dynamic_to_string(¶m->param.value, &buffer_name_len); + if (new_buffer_name){ + buffer_name = new_buffer_name; + } + } + }break; + + case par_cli_path: + { + if (path == 0){ + char *new_cli_path = dynamic_to_string(¶m->param.value, &path_len); + if (new_cli_path){ + path = new_cli_path; + } + } + }break; + + case par_cli_command: + { + if (script == 0){ + char *new_command = dynamic_to_string(¶m->param.value, &script_len); + if (new_command){ + script = new_command; + } + } + }break; + + case par_cli_overlap_with_conflict: + { + if (dynamic_to_int(¶m->param.value)) + flags |= CLI_OverlapWithConflict; + else + flags &= (~CLI_OverlapWithConflict); + }break; + + case par_cli_always_bind_to_view: + { + if (dynamic_to_int(¶m->param.value)) + flags |= CLI_OverlapWithConflict; + else + flags &= (~CLI_OverlapWithConflict); + }break; + } + } + + build(system, mem, vars, working_set, + font_set, style, global_font, live_set, exchange, + panel, command, + vars->hot_directory.string, + buffer_name, buffer_name_len, + path, path_len, + script, script_len, + flags); +} + +internal void +update_command_data(App_Vars *vars, Command_Data *cmd){ + cmd->panel = cmd->layout->panels + cmd->layout->active_panel; + cmd->view = cmd->panel->view; + cmd->style = &vars->style; +} + +globalvar Command_Function command_table[cmdid_count]; + +internal void +fill_buffer_summary(Buffer_Summary *buffer, Editing_File *file, Working_Set *working_set){ + buffer->exists = 1; + buffer->ready = file_is_ready(file); + buffer->is_lexed = file->settings.tokens_exist; + buffer->buffer_id = (int)(file - working_set->files); + buffer->size = file->state.buffer.size; + buffer->buffer_cursor_pos = file->state.cursor_pos; + + buffer->file_name_len = file->name.source_path.size; + buffer->buffer_name_len = file->name.live_name.size; + buffer->file_name = file->name.source_path.str; + buffer->buffer_name = file->name.live_name.str; + + buffer->map_id = file->settings.base_map_id; +} + +internal void +fill_view_summary(File_View_Summary *view, File_View *file_view, Live_Views *live_set, Working_Set *working_set){ + view->exists = 1; + view->view_id = (int)((char*)file_view - (char*)live_set->views) / live_set->stride; + if (file_view->file){ + view->buffer_id = (int)(file_view->file - working_set->files); + view->mark = view_compute_cursor_from_pos(file_view, file_view->mark); + view->cursor = file_view->cursor; + view->preferred_x = file_view->preferred_x; + view->line_height = file_view->font_height; + view->unwrapped_lines = file_view->unwrapped_lines; + } +} + +extern "C"{ + EXECUTE_COMMAND_SIG(external_exec_command_keep_stack){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Command_Function function = command_table[command_id]; + Command_Binding binding; + binding.function = function; + if (function) function(cmd->system, cmd, binding); + + update_command_data(cmd->vars, cmd); + } + + PUSH_PARAMETER_SIG(external_push_parameter){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Partition *part = &cmd->part; + Command_Parameter *cmd_param = push_struct(part, Command_Parameter); + cmd_param->type = 0; + cmd_param->param.param = param; + cmd_param->param.value = value; + } + + PUSH_MEMORY_SIG(external_push_memory){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Partition *part = &cmd->part; + Command_Parameter *base = push_struct(part, Command_Parameter); + char *result = push_array(part, char, len); + int full_len = len + sizeof(Command_Parameter) - 1; + full_len -= (full_len % sizeof(Command_Parameter)); + part->pos += full_len - len; + base->type = 1; + base->inline_string.str = result; + base->inline_string.len = len; + return(result); + } + + CLEAR_PARAMETERS_SIG(external_clear_parameters){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + cmd->part.pos = 0; + } + + DIRECTORY_GET_HOT_SIG(external_directory_get_hot){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Hot_Directory *hot = &cmd->vars->hot_directory; + i32 copy_max = capacity - 1; + hot_directory_clean_end(hot); + if (copy_max > hot->string.size) + copy_max = hot->string.size; + memcpy(out, hot->string.str, copy_max); + out[copy_max] = 0; + return(hot->string.size); + } + + GET_FILE_LIST_SIG(external_get_file_list){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + System_Functions *system = cmd->system; + File_List result = {}; + system->set_file_list(&result, make_string(dir, len)); + return(result); + } + + FREE_FILE_LIST_SIG(external_free_file_list){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + System_Functions *system = cmd->system; + system->set_file_list(&list, make_string(0, 0)); + } + + GET_BUFFER_MAX_INDEX_SIG(external_get_buffer_max_index){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Working_Set *working_set = cmd->working_set; + int max = working_set->file_index_count; + return(max); + } + + GET_BUFFER_SIG(external_get_buffer){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set = cmd->working_set; + int max = working_set->file_index_count; + Buffer_Summary buffer = {}; + + if (index >= 0 && index < max){ + file = working_set->files + index; + if (!file->state.is_dummy){ + fill_buffer_summary(&buffer, file, working_set); + } + } + + return(buffer); + } + + GET_ACTIVE_BUFFER_SIG(external_get_active_buffer){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + File_View *view; + Editing_File *file; + Working_Set *working_set; + Buffer_Summary buffer = {}; + + view = view_to_file_view(cmd->view); + if (view){ + file = view->file; + working_set = cmd->working_set; + + if (file && !file->state.is_dummy){ + fill_buffer_summary(&buffer, file, working_set); + } + } + + return(buffer); + } + + GET_BUFFER_BY_NAME(external_get_buffer_by_name){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + i32 index; + Buffer_Summary buffer = {}; + + working_set = cmd->working_set; + if (table_find(&working_set->table, make_string(filename, len), &index)){ + file = working_set->files + index; + if (!file->state.is_dummy && file_is_ready(file)){ + fill_buffer_summary(&buffer, file, working_set); + } + } + + return(buffer); + } + + REFRESH_BUFFER_SIG(external_refresh_buffer){ + int result; + *buffer = external_get_buffer(context, buffer->buffer_id); + result = buffer->exists; + return(result); + } + + BUFFER_SEEK_DELIMITER_SIG(external_buffer_seek_delimiter){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + int result = 0; + int size; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + size = buffer_size(&file->state.buffer); + result = 1; + + if (start < 0 && !seek_forward) *out = start; + else if (start >= size && seek_forward) *out = start; + else{ + if (seek_forward){ + *out = buffer_seek_delimiter(&file->state.buffer, start, delim); + } + else{ + *out = buffer_reverse_seek_delimiter(&file->state.buffer, start, delim); + } + } + + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + BUFFER_SEEK_STRING_SIG(external_buffer_seek_string){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + Temp_Memory temp; + Partition *part; + char *spare; + int result = 0; + int size; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + size = buffer_size(&file->state.buffer); + + if (start < 0 && !seek_forward) *out = start; + else if (start >= size && seek_forward) *out = start; + else{ + part = &cmd->mem->part; + temp = begin_temp_memory(part); + spare = push_array(part, char, len); + result = 1; + if (seek_forward){ + *out = buffer_find_string(&file->state.buffer, start, size, str, len, spare); + } + else{ + *out = buffer_rfind_string(&file->state.buffer, start, str, len, spare); + } + end_temp_memory(temp); + } + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + BUFFER_READ_RANGE_SIG(external_buffer_read_range){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + int result = 0; + int size; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + size = buffer_size(&file->state.buffer); + if (0 <= start && start <= end && end <= size){ + result = 1; + buffer_stringify(&file->state.buffer, start, end, out); + } + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + BUFFER_REPLACE_RANGE_SIG(external_buffer_replace_range){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + + System_Functions *system; + Mem_Options *mem; + Editing_Layout *layout; + + int result = 0; + int size; + int next_cursor, pos; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + size = buffer_size(&file->state.buffer); + if (0 <= start && start <= end && end <= size){ + result = 1; + + system = cmd->system; + mem = cmd->mem; + layout = cmd->layout; + + pos = file->state.cursor_pos; + if (pos < start) next_cursor = pos; + else if (pos < end) next_cursor = start; + else next_cursor = pos + end - start - len; + + file_replace_range(system, mem, file, layout, + start, end, str, len, next_cursor); + } + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + BUFFER_SET_POS_SIG(external_buffer_set_pos){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + + int result = 0; + int size; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + result = 1; + size = buffer_size(&file->state.buffer); + if (pos < 0) pos = 0; + if (pos > size) pos = size; + file->state.cursor_pos = pos; + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + GET_VIEW_MAX_INDEX_SIG(external_get_view_max_index){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set = cmd->live_set; + int max = live_set->max; + return(max); + } + + GET_FILE_VIEW_SIG(external_get_file_view){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set = cmd->live_set; + int max = live_set->max; + View *vptr; + File_View *file_view; + File_View_Summary view = {}; + + if (index >= 0 && index < max){ + vptr = (View*)((char*)live_set->views + live_set->stride*index); + file_view = view_to_file_view(vptr); + if (file_view){ + fill_view_summary(&view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(view); + } + + GET_ACTIVE_FILE_VIEW_SIG(external_get_active_file_view){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + File_View_Summary view = {}; + File_View *file_view; + + file_view = view_to_file_view(cmd->view); + if (file_view){ + fill_view_summary(&view, file_view, cmd->live_set, cmd->working_set); + } + + return(view); + } + + REFRESH_FILE_VIEW_SIG(external_refresh_file_view){ + int result; + *view = external_get_file_view(context, view->view_id); + result = view->exists; + return(result); + } + + VIEW_SET_CURSOR_SIG(external_view_set_cursor){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set; + View *vptr; + File_View *file_view; + int result = 0; + + if (view->exists){ + live_set = cmd->live_set; + vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); + file_view = view_to_file_view(vptr); + if (file_view){ + result = 1; + file_view->cursor = view_compute_cursor(file_view, seek); + if (set_preferred_x){ + file_view->preferred_x = view_get_cursor_x(file_view); + } + fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(result); + } + + VIEW_SET_MARK_SIG(external_view_set_mark){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set; + View *vptr; + File_View *file_view; + Full_Cursor cursor; + int result = 0; + + if (view->exists){ + live_set = cmd->live_set; + vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); + file_view = view_to_file_view(vptr); + if (file_view){ + result = 1; + if (seek.type != buffer_seek_pos){ + cursor = view_compute_cursor(file_view, seek); + file_view->mark = cursor.pos; + } + else{ + file_view->mark = seek.pos; + } + fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(result); + } + + VIEW_SET_HIGHLIGHT_SIG(external_view_set_highlight){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set; + View *vptr; + File_View *file_view; + int result = 0; + + if (view->exists){ + live_set = cmd->live_set; + vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); + file_view = view_to_file_view(vptr); + if (file_view){ + result = 1; + if (turn_on){ + view_set_temp_highlight(file_view, start, end); + } + else{ + file_view->show_temp_highlight = 0; + } + fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(result); + } + + VIEW_SET_BUFFER_SIG(external_view_set_buffer){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set; + View *vptr; + File_View *file_view; + Editing_File *file; + Working_Set *working_set; + int max, result = 0; + + if (view->exists){ + live_set = cmd->live_set; + vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); + file_view = view_to_file_view(vptr); + if (file_view){ + working_set = cmd->working_set; + max = working_set->file_index_count; + if (buffer_id >= 0 && buffer_id < max){ + file = working_set->files + buffer_id; + if (!file->state.is_dummy){ + view_set_file(file_view, file, cmd->vars->font_set, cmd->style, cmd->global_font, + cmd->system, cmd->vars->hooks[hook_open_file], &app_links); + } + } + + fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(result); + } + + GET_USER_INPUT_SIG(external_get_user_input){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + System_Functions *system = cmd->system; + Coroutine *coroutine = cmd->current_coroutine; + User_Input result; + + Assert(coroutine); + *((u32*)coroutine->out+0) = get_type; + *((u32*)coroutine->out+1) = abort_type; + system->yield_coroutine(coroutine); + result = *(User_Input*)coroutine->in; + + return(result); + } + + START_QUERY_BAR_SIG(external_start_query_bar){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Query_Slot *slot = 0; + View *vptr; + File_View *file_view; + + vptr = cmd->view; + file_view = view_to_file_view(vptr); + + if (file_view){ + slot = alloc_query_slot(&file_view->query_set); + slot->query_bar = bar; + } + + return(slot != 0); + } + + END_QUERY_BAR_SIG(external_end_query_bar){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + View *vptr; + File_View *file_view; + + vptr = cmd->view; + file_view = view_to_file_view(vptr); + + if (file_view){ + free_query_slot(&file_view->query_set, bar); + } + } +} + +struct Command_In{ + Command_Data *cmd; + Command_Binding bind; +}; + +internal void +command_caller(Coroutine *coroutine){ + Command_In *cmd_in = (Command_In*)coroutine->in; + Command_Data *cmd = cmd_in->cmd; + View *view = cmd->view; + // TODO(allen): this isn't really super awesome, could have issues if + // the file view get's change out under us. + File_View *fview = view_to_file_view(view); + if (fview) fview->next_mode = {}; + cmd_in->bind.function(cmd->system, cmd, cmd_in->bind); + fview = view_to_file_view(view); + if (fview) fview->mode = fview->next_mode; +} + +internal void +app_links_init(System_Functions *system, void *data, int size){ + app_links.memory = data; + app_links.memory_size = size; + + app_links.exec_command_keep_stack = external_exec_command_keep_stack; + app_links.push_parameter = external_push_parameter; + app_links.push_memory = external_push_memory; + app_links.clear_parameters = external_clear_parameters; + + app_links.directory_get_hot = external_directory_get_hot; + app_links.file_exists = system->file_exists; + app_links.directory_cd = system->directory_cd; + app_links.get_file_list = external_get_file_list; + app_links.free_file_list = external_free_file_list; + + app_links.get_buffer_max_index = external_get_buffer_max_index; + app_links.get_buffer = external_get_buffer; + app_links.get_active_buffer = external_get_active_buffer; + app_links.get_buffer_by_name = external_get_buffer_by_name; + + app_links.refresh_buffer = external_refresh_buffer; + app_links.buffer_seek_delimiter = external_buffer_seek_delimiter; + app_links.buffer_seek_string = external_buffer_seek_string; + app_links.buffer_read_range = external_buffer_read_range; + app_links.buffer_replace_range = external_buffer_replace_range; + + app_links.get_view_max_index = external_get_view_max_index; + app_links.get_file_view = external_get_file_view; + app_links.get_active_file_view = external_get_active_file_view; + + app_links.refresh_file_view = external_refresh_file_view; + app_links.view_set_cursor = external_view_set_cursor; + app_links.view_set_mark = external_view_set_mark; + app_links.view_set_highlight = external_view_set_highlight; + app_links.view_set_buffer = external_view_set_buffer; + + app_links.get_user_input = external_get_user_input; + + app_links.start_query_bar = external_start_query_bar; + app_links.end_query_bar = external_end_query_bar; +} + +internal void +setup_ui_commands(Command_Map *commands, Partition *part, Command_Map *parent){ + map_init(commands, part, 32, parent); + + commands->vanilla_keyboard_default.function = command_null; + + // TODO(allen): This is hacky, when the new UI stuff happens, let's fix it, and by that + // I mean actually fix it, don't just say you fixed it with something stupid again. + u8 mdfr; + u8 mdfr_array[] = {MDFR_NONE, MDFR_SHIFT, MDFR_CTRL, MDFR_SHIFT | MDFR_CTRL}; + for (i32 i = 0; i < 4; ++i){ + mdfr = mdfr_array[i]; + map_add(commands, key_left, mdfr, command_null); + map_add(commands, key_right, mdfr, command_null); + map_add(commands, key_up, mdfr, command_null); + map_add(commands, key_down, mdfr, command_null); + map_add(commands, key_back, mdfr, command_null); + map_add(commands, key_esc, mdfr, command_close_minor_view); + } +} + +internal void +setup_file_commands(Command_Map *commands, Partition *part, Command_Map *parent){ + map_init(commands, part, 10, parent); +} + +internal void +setup_top_commands(Command_Map *commands, Partition *part, Command_Map *parent){ + map_init(commands, part, 5, parent); +} + +internal void +setup_command_table(){ +#define SET(n) command_table[cmdid_##n] = command_##n + + SET(null); + SET(write_character); + SET(seek_whitespace_right); + SET(seek_whitespace_left); + SET(seek_whitespace_up); + SET(seek_whitespace_down); + SET(seek_token_left); + SET(seek_token_right); + SET(seek_white_or_token_right); + SET(seek_white_or_token_left); + SET(seek_alphanumeric_right); + SET(seek_alphanumeric_left); + SET(seek_alphanumeric_or_camel_right); + SET(seek_alphanumeric_or_camel_left); + SET(word_complete); + SET(set_mark); + SET(copy); + SET(cut); + SET(paste); + SET(paste_next); + SET(delete_range); + SET(timeline_scrub); + SET(undo); + SET(redo); + SET(history_backward); + SET(history_forward); + SET(interactive_new); + SET(interactive_open); + SET(reopen); + SET(save); + SET(interactive_save_as); + SET(change_active_panel); + SET(interactive_switch_buffer); + SET(interactive_kill_buffer); + SET(kill_buffer); + SET(toggle_line_wrap); + SET(to_uppercase); + SET(to_lowercase); + SET(toggle_show_whitespace); + SET(clean_all_lines); + SET(eol_dosify); + SET(eol_nixify); + SET(auto_tab_range); + SET(auto_tab_line_at_cursor); + SET(auto_tab_whole_file); + SET(open_panel_vsplit); + SET(open_panel_hsplit); + SET(close_panel); + SET(move_left); + SET(move_right); + SET(delete); + SET(backspace); + SET(move_up); + SET(move_down); + SET(seek_end_of_line); + SET(seek_beginning_of_line); + SET(page_up); + SET(page_down); + SET(open_color_tweaker); + SET(close_minor_view); + SET(cursor_mark_swap); + SET(open_menu); + SET(set_settings); + SET(command_line); + +#undef SET +} + +// App Functions + +internal void +app_hardcode_styles(App_Vars *vars){ + Interactive_Style file_info_style; + Style *styles, *style; + styles = vars->styles.styles; + style = styles; + + i16 fonts = 1; + vars->global_font.font_id = fonts + 0; + vars->global_font.font_changed = 0; + + ///////////////// + style_set_name(style, make_lit_string("4coder")); + + style->main.back_color = 0xFF0C0C0C; + style->main.margin_color = 0xFF181818; + style->main.margin_hover_color = 0xFF252525; + style->main.margin_active_color = 0xFF323232; + style->main.cursor_color = 0xFF00EE00; + style->main.highlight_color = 0xFFDDEE00; + style->main.mark_color = 0xFF494949; + style->main.default_color = 0xFF90B080; + style->main.at_cursor_color = style->main.back_color; + style->main.at_highlight_color = 0xFFFF44DD; + style->main.comment_color = 0xFF2090F0; + style->main.keyword_color = 0xFFD08F20; + style->main.str_constant_color = 0xFF50FF30; + style->main.char_constant_color = style->main.str_constant_color; + style->main.int_constant_color = style->main.str_constant_color; + style->main.float_constant_color = style->main.str_constant_color; + style->main.bool_constant_color = style->main.str_constant_color; + style->main.include_color = style->main.str_constant_color; + style->main.preproc_color = style->main.default_color; + style->main.special_character_color = 0xFFFF0000; + + style->main.paste_color = 0xFFDDEE00; + style->main.undo_color = 0xFF00DDEE; + + style->main.highlight_junk_color = 0xff3a0000; + style->main.highlight_white_color = 0xff003a3a; + + file_info_style.bar_color = 0xFF888888; + file_info_style.bar_active_color = 0xFF666666; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFF4444AA; + file_info_style.pop2_color = 0xFFFF0000; + style->main.file_info_style = file_info_style; + ++style; + + ///////////////// + style_set_name(style, make_lit_string("Handmade Hero")); + + style->main.back_color = 0xFF161616; + style->main.margin_color = 0xFF262626; + style->main.margin_hover_color = 0xFF333333; + style->main.margin_active_color = 0xFF404040; + style->main.cursor_color = 0xFF40FF40; + style->main.at_cursor_color = style->main.back_color; + style->main.mark_color = 0xFF808080; + style->main.highlight_color = 0xFF703419; + style->main.at_highlight_color = 0xFFCDAA7D; + style->main.default_color = 0xFFCDAA7D; + style->main.comment_color = 0xFF7F7F7F; + style->main.keyword_color = 0xFFCD950C; + style->main.str_constant_color = 0xFF6B8E23; + style->main.char_constant_color = style->main.str_constant_color; + style->main.int_constant_color = style->main.str_constant_color; + style->main.float_constant_color = style->main.str_constant_color; + style->main.bool_constant_color = style->main.str_constant_color; + style->main.include_color = style->main.str_constant_color; + style->main.preproc_color = style->main.default_color; + style->main.special_character_color = 0xFFFF0000; + + style->main.paste_color = 0xFFFFBB00; + style->main.undo_color = 0xFFFF00BB; + style->main.undo_color = 0xFF80005D; + + style->main.highlight_junk_color = 0xFF3A0000; + style->main.highlight_white_color = 0xFF003A3A; + + file_info_style.bar_color = 0xFFCACACA; + file_info_style.bar_active_color = 0xFFA8A8A8; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFF03CF0C; + file_info_style.pop2_color = 0xFFFF0000; + style->main.file_info_style = file_info_style; + ++style; + + ///////////////// + style_set_name(style, make_lit_string("Twilight")); + + style->main.back_color = 0xFF090D12; + style->main.margin_color = 0xFF1A2634; + style->main.margin_hover_color = 0xFF2D415B; + style->main.margin_active_color = 0xFF405D82; + style->main.cursor_color = 0xFFEEE800; + style->main.at_cursor_color = style->main.back_color; + style->main.mark_color = 0xFF8BA8CC; + style->main.highlight_color = 0xFF037A7B; + style->main.at_highlight_color = 0xFFFEB56C; + style->main.default_color = 0xFFB7C19E; + style->main.comment_color = 0xFF20ECF0; + style->main.keyword_color = 0xFFD86909; + style->main.str_constant_color = 0xFFC4EA5D; + style->main.char_constant_color = style->main.str_constant_color; + style->main.int_constant_color = style->main.str_constant_color; + style->main.float_constant_color = style->main.str_constant_color; + style->main.bool_constant_color = style->main.str_constant_color; + style->main.include_color = style->main.str_constant_color; + style->main.preproc_color = style->main.default_color; + style->main.special_character_color = 0xFFFF0000; + + style->main.paste_color = 0xFFDDEE00; + style->main.undo_color = 0xFF00DDEE; + + style->main.highlight_junk_color = 0xff3a0000; + style->main.highlight_white_color = 0xFF151F2A; + + file_info_style.bar_color = 0xFF315E68; + file_info_style.bar_active_color = 0xFF0F3C46; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFF1BFF0C; + file_info_style.pop2_color = 0xFFFF200D; + style->main.file_info_style = file_info_style; + ++style; + + ///////////////// + style_set_name(style, make_lit_string("Wolverine")); + + style->main.back_color = 0xFF070711; + style->main.margin_color = 0xFF111168; + style->main.margin_hover_color = 0xFF191996; + style->main.margin_active_color = 0xFF2121C3; + style->main.cursor_color = 0xFF7082F9; + style->main.at_cursor_color = 0xFF000014; + style->main.mark_color = 0xFF4b5028; + style->main.highlight_color = 0xFFDDEE00; + style->main.at_highlight_color = 0xFF000019; + style->main.default_color = 0xFF8C9740; + style->main.comment_color = 0xFF3A8B29; + style->main.keyword_color = 0xFFD6B109; + style->main.str_constant_color = 0xFFAF5FA7; + style->main.char_constant_color = style->main.str_constant_color; + style->main.int_constant_color = style->main.str_constant_color; + style->main.float_constant_color = style->main.str_constant_color; + style->main.bool_constant_color = style->main.str_constant_color; + style->main.include_color = style->main.str_constant_color; + style->main.preproc_color = style->main.default_color; + style->main.special_character_color = 0xFFFF0000; + + style->main.paste_color = 0xFF900090; + style->main.undo_color = 0xFF606090; + + style->main.highlight_junk_color = 0xff3a0000; + style->main.highlight_white_color = 0xff003a3a; + + file_info_style.bar_color = 0xFF7082F9; + file_info_style.bar_active_color = 0xFF4E60D7; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFFFAFA15; + file_info_style.pop2_color = 0xFFD20000; + style->main.file_info_style = file_info_style; + ++style; + + ///////////////// + style_set_name(style, make_lit_string("stb")); + + style->main.back_color = 0xFFD6D6D6; + style->main.margin_color = 0xFF9E9E9E; + style->main.margin_hover_color = 0xFF7E7E7E; + style->main.margin_active_color = 0xFF5C5C5C; + style->main.cursor_color = 0xFF000000; + style->main.at_cursor_color = 0xFFD6D6D6; + style->main.mark_color = 0xFF525252; + style->main.highlight_color = 0xFF0044FF; + style->main.at_highlight_color = 0xFFD6D6D6; + style->main.default_color = 0xFF000000; + style->main.comment_color = 0xFF005800; + style->main.keyword_color = 0xFF000000; + style->main.str_constant_color = 0xFF000000; + style->main.char_constant_color = style->main.str_constant_color; + style->main.int_constant_color = style->main.str_constant_color; + style->main.float_constant_color = style->main.str_constant_color; + style->main.bool_constant_color = style->main.str_constant_color; + style->main.include_color = style->main.str_constant_color; + style->main.preproc_color = style->main.default_color; + style->main.special_character_color = 0xFF9A0000; + + style->main.paste_color = 0xFF00B8B8; + style->main.undo_color = 0xFFB800B8; + + style->main.highlight_junk_color = 0xFFFF7878; + style->main.highlight_white_color = 0xFFBCBCBC; + + file_info_style.bar_color = 0xFF606060; + file_info_style.bar_active_color = 0xFF3E3E3E; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFF1111DC; + file_info_style.pop2_color = 0xFFE80505; + style->main.file_info_style = file_info_style; + ++style; + + vars->styles.count = (i32)(style - styles); + vars->styles.max = ArrayCount(vars->styles.styles); + style_copy(&vars->style, vars->styles.styles); +} + +char *_4coder_get_extension(const char *filename, int len, int *extension_len){ + char *c = (char*)(filename + len - 1); + char *end = c; + while (*c != '.' && c > filename) --c; + *extension_len = (int)(end - c); + return c+1; +} + +bool _4coder_str_match(const char *a, int len_a, const char *b, int len_b){ + bool result = 0; + if (len_a == len_b){ + char *end = (char*)(a + len_a); + while (a < end && *a == *b){ + ++a; ++b; + } + if (a == end) result = 1; + } + return result; +} + +enum Command_Line_Action{ + CLAct_Nothing, + CLAct_Ignore, + CLAct_UserFile, + CLAct_CustomDLL, + CLAct_InitialFilePosition, + CLAct_WindowSize, + CLAct_WindowMaximize, + CLAct_WindowPosition, + CLAct_Count +}; + +void +init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, + Command_Line_Parameters clparams){ + char *arg; + Command_Line_Action action = CLAct_Nothing; + i32 i,index; + b32 strict = 0; + + settings->init_files_max = ArrayCount(settings->init_files); + for (i = 1; i <= clparams.argc; ++i){ + if (i == clparams.argc) arg = ""; + else arg = clparams.argv[i]; + switch (action){ + case CLAct_Nothing: + { + if (arg[0] == '-'){ + action = CLAct_Ignore; + switch (arg[1]){ + case 'u': action = CLAct_UserFile; strict = 0; break; + case 'U': action = CLAct_UserFile; strict = 1; break; + + case 'd': action = CLAct_CustomDLL; strict = 0; break; + case 'D': action = CLAct_CustomDLL; strict = 1; 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; + } + } + else if (arg[0] != 0){ + if (settings->init_files_count < settings->init_files_max){ + index = settings->init_files_count++; + settings->init_files[index] = arg; + } + } + }break; + + case CLAct_UserFile: + { + settings->user_file_is_strict = strict; + if (i < clparams.argc){ + settings->user_file = clparams.argv[i]; + } + action = CLAct_Nothing; + }break; + + case CLAct_CustomDLL: + { + plat_settings->custom_dll_is_strict = strict; + if (i < clparams.argc){ + plat_settings->custom_dll = clparams.argv[i]; + } + action = CLAct_Nothing; + }break; + + case CLAct_InitialFilePosition: + { + if (i < clparams.argc){ + settings->initial_line = str_to_int(clparams.argv[i]); + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowSize: + { + if (i + 1 < clparams.argc){ + plat_settings->set_window_size = 1; + plat_settings->window_w = str_to_int(clparams.argv[i]); + plat_settings->window_h = str_to_int(clparams.argv[i+1]); + + ++i; + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowMaximize: + { + --i; + plat_settings->maximize_window = 1; + action = CLAct_Nothing; + }break; + + case CLAct_WindowPosition: + { + if (i + 1 < clparams.argc){ + plat_settings->set_window_pos = 1; + plat_settings->window_x = str_to_int(clparams.argv[i]); + plat_settings->window_y = str_to_int(clparams.argv[i+1]); + + ++i; + } + action = CLAct_Nothing; + }break; + } + } +} + +internal App_Vars* +app_setup_memory(Application_Memory *memory){ + Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); + App_Vars *vars = push_struct(&_partition, App_Vars); + Assert(vars); + *vars = {}; + vars->mem.part = _partition; + + general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); + + return(vars); +} + +internal i32 +execute_special_tool(void *memory, i32 size, Command_Line_Parameters clparams){ + i32 result; + char message[] = "tool was not specified or is invalid"; + result = sizeof(message) - 1; + memcpy(memory, message, result); + if (clparams.argc > 2){ + if (match(clparams.argv[2], "version")){ + result = sizeof(VERSION) - 1; + memcpy(memory, VERSION, result); + } + } + return(result); +} + +App_Read_Command_Line_Sig(app_read_command_line){ + App_Vars *vars; + i32 out_size = 0; + + if (clparams.argc > 1 && match(clparams.argv[1], "-T")){ + out_size = execute_special_tool(memory->target_memory, memory->target_memory_size, clparams); + } + else{ + vars = app_setup_memory(memory); + if (clparams.argc > 1){ + init_command_line_settings(&vars->settings, plat_settings, clparams); + } + else{ + vars->settings = {}; + } + *files = vars->settings.init_files; + *file_count = &vars->settings.init_files_count; + } + + return(out_size); +} + +extern "C" SCROLL_RULE_SIG(fallback_scroll_rule){ + int result = 0; + + if (target_x != *scroll_x){ + *scroll_x = target_x; + result = 1; + } + if (target_y != *scroll_y){ + *scroll_y = target_y; + result = 1; + } + + return(result); +} + +App_Init_Sig(app_init){ + app_links_init(system, memory->user_memory, memory->user_memory_size); + + App_Vars *vars = (App_Vars*)memory->vars_memory; + vars->config_api = api; + app_links.cmd_context = &vars->command_data; + + Partition *partition = &vars->mem.part; + target->partition = partition; + + Panel *panels, *panel; + Panel_Divider *dividers, *div; + i32 panel_max_count; + i32 divider_max_count; + + { + i32 i; + + panel_max_count = vars->layout.panel_max_count = 16; + divider_max_count = panel_max_count - 1; + vars->layout.panel_count = 0; + + panels = push_array(partition, Panel, panel_max_count); + vars->layout.panels = panels; + + dll_init_sentinel(&vars->layout.free_sentinel); + dll_init_sentinel(&vars->layout.used_sentinel); + + panel = panels; + for (i = 0; i < panel_max_count; ++i, ++panel){ + dll_insert(&vars->layout.free_sentinel, panel); + } + + dividers = push_array(partition, Panel_Divider, divider_max_count); + vars->layout.dividers = dividers; + + div = dividers; + for (i = 0; i < divider_max_count-1; ++i, ++div){ + div->next = (div + 1); + } + div->next = 0; + vars->layout.free_divider = dividers; + } + + { + char *vptr = 0; + View *v = 0; + i32 i = 0; + i32 max = 0; + i32 view_size = sizeof(File_View); + + vars->live_set.count = 0; + vars->live_set.max = panel_max_count; + + vars->live_set.stride = view_size; + vars->live_set.views = push_block(partition, view_size*vars->live_set.max); + + dll_init_sentinel(&vars->live_set.free_sentinel); + + max = vars->live_set.max; + vptr = (char*)vars->live_set.views; + for (i = 0; i < max; ++i, vptr += view_size){ + v = (View*)(vptr); + dll_insert(&vars->live_set.free_sentinel, v); + } + } + + if (vars->config_api.scroll_rule == 0){ + vars->config_api.scroll_rule = fallback_scroll_rule; + } + + setup_command_table(); + + Command_Map *global = &vars->map_top; + Assert(vars->config_api.get_bindings != 0); + + i32 wanted_size = vars->config_api.get_bindings(app_links.memory, app_links.memory_size); + + b32 did_top = 0; + b32 did_file = 0; + if (wanted_size <= app_links.memory_size){ + Binding_Unit *unit = (Binding_Unit*)app_links.memory; + if (unit->type == unit_header && unit->header.error == 0){ + Binding_Unit *end = unit + unit->header.total_size; + + i32 user_map_count = unit->header.user_map_count; + + vars->map_id_table = push_array( + &vars->mem.part, i32, user_map_count); + + vars->user_maps = push_array( + &vars->mem.part, Command_Map, user_map_count); + + vars->user_map_count = user_map_count; + + Command_Map *mapptr = 0; + for (++unit; unit < end; ++unit){ + switch (unit->type){ + case unit_map_begin: + { + int table_max = unit->map_begin.bind_count * 3 / 2; + int mapid = unit->map_begin.mapid; + if (mapid == mapid_global){ + mapptr = &vars->map_top; + map_init(mapptr, &vars->mem.part, table_max, global); + did_top = 1; + } + else if (mapid == mapid_file){ + mapptr = &vars->map_file; + map_init(mapptr, &vars->mem.part, table_max, global); + did_file = 1; + } + else if (mapid < mapid_global){ + i32 index = app_get_or_add_map_index(vars, mapid); + Assert(index < user_map_count); + mapptr = vars->user_maps + index; + map_init(mapptr, &vars->mem.part, table_max, global); + } + else mapptr = 0; + }break; + + case unit_inherit: + if (mapptr){ + Command_Map *parent = 0; + int mapid = unit->map_inherit.mapid; + if (mapid == mapid_global) parent = &vars->map_top; + else if (mapid == mapid_file) parent = &vars->map_file; + else if (mapid < mapid_global){ + i32 index = app_get_or_add_map_index(vars, mapid); + if (index < user_map_count) parent = vars->user_maps + index; + else parent = 0; + } + mapptr->parent = parent; + }break; + + case unit_binding: + if (mapptr){ + Command_Function func = 0; + if (unit->binding.command_id >= 0 && unit->binding.command_id < cmdid_count) + func = command_table[unit->binding.command_id]; + if (func){ + if (unit->binding.code == 0 && unit->binding.modifiers == 0){ + mapptr->vanilla_keyboard_default.function = func; + mapptr->vanilla_keyboard_default.custom_id = unit->binding.command_id; + } + else{ + map_add(mapptr, unit->binding.code, unit->binding.modifiers, func, unit->binding.command_id); + } + } + } + break; + + case unit_callback: + if (mapptr){ + Command_Function func = command_user_callback; + Custom_Command_Function *custom = unit->callback.func; + if (func){ + if (unit->callback.code == 0 && unit->callback.modifiers == 0){ + mapptr->vanilla_keyboard_default.function = func; + mapptr->vanilla_keyboard_default.custom = custom; + } + else{ + map_add(mapptr, unit->callback.code, unit->callback.modifiers, func, custom); + } + } + } + break; + + case unit_hook: + { + int hook_id = unit->hook.hook_id; + if (hook_id >= 0 && hook_id < hook_type_count){ + vars->hooks[hook_id] = unit->hook.func; + } + }break; + } + } + } + } + + memset(app_links.memory, 0, wanted_size); + if (!did_top) setup_top_commands(&vars->map_top, &vars->mem.part, global); + if (!did_file) setup_file_commands(&vars->map_file, &vars->mem.part, global); + +#if 1 || !defined(FRED_SUPER) + vars->hooks[hook_start] = 0; +#endif + + setup_ui_commands(&vars->map_ui, &vars->mem.part, global); + + vars->font_set = &target->font_set; + + font_set_init(vars->font_set, partition, 16, 5); + + { + struct Font_Setup{ + char *c_file_name; + i32 file_name_len; + char *c_name; + i32 name_len; + i32 pt_size; + }; + +#define LitStr(n) n, sizeof(n)-1 + + Font_Setup font_setup[] = { + {LitStr("LiberationSans-Regular.ttf"), + LitStr("liberation sans"), + 16}, + + {LitStr("liberation-mono.ttf"), + LitStr("liberation mono"), + 16}, + + {LitStr("Hack-Regular.ttf"), + LitStr("hack"), + 16}, + + {LitStr("CutiveMono-Regular.ttf"), + LitStr("cutive mono"), + 16}, + + {LitStr("Inconsolata-Regular.ttf"), + LitStr("inconsolata"), + 16}, + + }; + i32 font_count = ArrayCount(font_setup); + + for (i32 i = 0; i < font_count; ++i){ + String file_name = make_string(font_setup[i].c_file_name, + font_setup[i].file_name_len); + String name = make_string(font_setup[i].c_name, + font_setup[i].name_len); + i32 pt_size = font_setup[i].pt_size; + + font_set_add(partition, vars->font_set, file_name, name, pt_size); + } + } + + // NOTE(allen): file setup + vars->working_set.file_index_count = 1; + vars->working_set.file_max_count = 120; + vars->working_set.files = + push_array(partition, Editing_File, vars->working_set.file_max_count); + + file_get_dummy(&vars->working_set.files[0]); + + vars->working_set.table.max = vars->working_set.file_max_count * 3 / 2; + vars->working_set.table.count = 0; + vars->working_set.table.table = + push_array(partition, File_Table_Entry, vars->working_set.table.max); + memset(vars->working_set.table.table, 0, sizeof(File_Table_Entry) * vars->working_set.table.max); + + // NOTE(allen): clipboard setup + vars->working_set.clipboard_max_size = ArrayCount(vars->working_set.clipboards); + vars->working_set.clipboard_size = 0; + vars->working_set.clipboard_current = 0; + vars->working_set.clipboard_rolling = 0; + + // TODO(allen): more robust allocation solution for the clipboard + if (clipboard.str){ + String *dest = working_set_next_clipboard_string(&vars->mem.general, &vars->working_set, clipboard.size); + copy(dest, make_string((char*)clipboard.str, clipboard.size)); + } + + // NOTE(allen): delay setup + vars->delay1.general = &vars->mem.general; + vars->delay1.max = 16; + vars->delay1.acts = (Delayed_Action*)general_memory_allocate( + &vars->mem.general, vars->delay1.max*sizeof(Delayed_Action), 0); + + vars->delay2.general = &vars->mem.general; + vars->delay2.max = 16; + vars->delay2.acts = (Delayed_Action*)general_memory_allocate( + &vars->mem.general, vars->delay2.max*sizeof(Delayed_Action), 0); + + // NOTE(allen): style setup + app_hardcode_styles(vars); + + vars->palette_size = 40; + vars->palette = push_array(partition, u32, vars->palette_size); + + // NOTE(allen): init first panel + Panel_And_ID p = layout_alloc_panel(&vars->layout); + panel_make_empty(system, exchange, vars, &vars->style, &vars->global_font, p.panel); + vars->layout.active_panel = p.id; + + String hdbase = make_fixed_width_string(vars->hot_dir_base_); + hot_directory_init(&vars->hot_directory, hdbase, current_directory, system->slash); + + vars->mini_str = make_string((char*)vars->mini_buffer, 0, 512); + + // NOTE(allen): child proc list setup + i32 max_children = 16; + partition_align(partition, 8); + vars->cli_processes.procs = push_array(partition, CLI_Process, max_children); + vars->cli_processes.max = max_children; + vars->cli_processes.count = 0; + + // NOTE(allen): sys app binding setup + vars->sys_app_max = exchange->file.max; + vars->sys_app_count = 0; + vars->sys_app_bindings = (Sys_App_Binding*)push_array(partition, Sys_App_Binding, vars->sys_app_max); +} + +// NOTE(allen): while I transition away from this view system to something that has +// more unified behavior, I will use this to add checks to the program's state so that I +// can make sure it behaving well. +internal void +correctness_check(App_Vars *vars){ + Panel *panel, *used_panels; + used_panels = &vars->layout.used_sentinel; + for (dll_items(panel, used_panels)){ + Assert(panel->view); + Assert(panel->parent != -1 || vars->layout.panel_count == 1); + } + panel = vars->layout.panels + vars->layout.active_panel; + Assert(panel->ALLOCED); +} + +App_Step_Sig(app_step){ + ProfileStart(OS_syncing); + Application_Step_Result app_result = *result; + app_result.redraw = force_redraw; + + App_Vars *vars = (App_Vars*)memory->vars_memory; + target->partition = &vars->mem.part; + + if (first_step || !time_step){ + app_result.redraw = 1; + } + + // NOTE(allen): OS clipboard event handling + if (clipboard.str){ + String *dest = working_set_next_clipboard_string(&vars->mem.general, &vars->working_set, clipboard.size); + dest->size = eol_convert_in(dest->str, clipboard.str, clipboard.size); + } + + // TODO(allen): profile this make sure it's not costing me too much power. + // NOTE(allen): check files are up to date + for (i32 i = 0; i < vars->working_set.file_index_count; ++i){ + Editing_File *file = vars->working_set.files + i; + + if (!file->state.is_dummy){ + u64 time_stamp = system->file_time_stamp(make_c_str(file->name.source_path)); + + if (time_stamp > 0){ + file->state.last_sys_write_time = time_stamp; + if (file->state.last_sys_write_time != file->state.last_4ed_write_time){ + app_result.redraw = 1; + } + } + } + } + + // NOTE(allen): update child processes + if (time_step){ + Temp_Memory temp = begin_temp_memory(&vars->mem.part); + u32 max = Kbytes(32); + char *dest = push_array(&vars->mem.part, char, max); + u32 amount; + + i32 count = vars->cli_processes.count; + for (i32 i = 0; i < count; ++i){ + CLI_Process *proc = vars->cli_processes.procs + i; + Editing_File *out_file = proc->out_file; + + if (out_file != 0){ + i32 new_cursor = out_file->state.cursor_pos; + + for (system->cli_begin_update(&proc->cli); + system->cli_update_step(&proc->cli, dest, max, &amount);){ + amount = eol_in_place_convert_in(dest, amount); + Edit_Spec spec = {}; + spec.step.type = ED_NORMAL; + spec.step.edit.start = buffer_size(&out_file->state.buffer); + spec.step.edit.end = spec.step.edit.start; + spec.step.edit.len = amount; + spec.step.pre_pos = new_cursor; + spec.step.post_pos = spec.step.edit.start + amount; + spec.str = (u8*)dest; + file_do_single_edit(system, &vars->mem, out_file, + &vars->layout, spec, hist_normal); + app_result.redraw = 1; + new_cursor = spec.step.post_pos; + } + + if (system->cli_end_update(&proc->cli)){ + *proc = vars->cli_processes.procs[--count]; + --i; + + char str_space[256]; + String str = make_fixed_width_string(str_space); + append(&str, "exited with code "); + append_int_to_str(proc->cli.exit, &str); + + Edit_Spec spec = {}; + spec.step.type = ED_NORMAL; + spec.step.edit.start = buffer_size(&out_file->state.buffer); + spec.step.edit.end = spec.step.edit.start; + spec.step.edit.len = str.size; + spec.step.pre_pos = new_cursor; + spec.step.post_pos = spec.step.edit.start + str.size; + spec.str = (u8*)str.str; + file_do_single_edit(system, &vars->mem, out_file, + &vars->layout, spec, hist_normal); + app_result.redraw = 1; + new_cursor = spec.step.post_pos; + } + + Panel *panel, *used_panels; + View *view; + File_View *fview; + + used_panels = &vars->layout.used_sentinel; + for (dll_items(panel, used_panels)){ + view = panel->view; + fview = view_to_file_view(view); + Assert(fview); + if (fview->file == out_file){ + view_cursor_move(fview, new_cursor); + } + } + } + } + + vars->cli_processes.count = count; + end_temp_memory(temp); + } + + // NOTE(allen): reorganizing panels on screen + { + i32 prev_width = vars->layout.full_width; + i32 prev_height = vars->layout.full_height; + i32 current_width = target->width; + i32 current_height = target->height; + + Panel *panel, *used_panels; + File_View *fview; + + vars->layout.full_width = current_width; + vars->layout.full_height = current_height; + + if (prev_width != current_width || prev_height != current_height){ + layout_refit(&vars->layout, prev_width, prev_height); + + used_panels = &vars->layout.used_sentinel; + for (dll_items(panel, used_panels)){ + fview = view_to_file_view(panel->view); + Assert(fview); + // TODO(allen): All responses to a panel changing size should + // be handled in the same place. + view_change_size(system, &vars->mem.general, fview); + } + + app_result.redraw = 1; + } + } + + // NOTE(allen): prepare input information + Key_Summary key_data = {}; + for (i32 i = 0; i < input->press_count; ++i){ + key_data.keys[key_data.count++] = input->press[i]; + } + for (i32 i = 0; i < input->hold_count; ++i){ + key_data.keys[key_data.count++] = input->hold[i]; + } + + mouse->wheel = -mouse->wheel; + + ProfileEnd(OS_syncing); + + correctness_check(vars); + + ProfileStart(hover_status); + // NOTE(allen): detect mouse hover status + i32 mx = mouse->x; + i32 my = mouse->y; + b32 mouse_in_edit_area = 0; + b32 mouse_in_margin_area = 0; + Panel *mouse_panel, *used_panels; + + used_panels = &vars->layout.used_sentinel; + for (dll_items(mouse_panel, used_panels)){ + if (hit_check(mx, my, mouse_panel->inner)){ + mouse_in_edit_area = 1; + break; + } + else if (hit_check(mx, my, mouse_panel->full)){ + mouse_in_margin_area = 1; + break; + } + } + + if (!(mouse_in_edit_area || mouse_in_margin_area)){ + mouse_panel = 0; + } + + b32 mouse_on_divider = 0; + b32 mouse_divider_vertical = 0; + i32 mouse_divider_id = 0; + i32 mouse_divider_side = 0; + + if (mouse_in_margin_area){ + Panel *panel = mouse_panel; + if (mx >= panel->inner.x0 && mx < panel->inner.x1){ + mouse_divider_vertical = 0; + if (my > panel->inner.y0){ + mouse_divider_side = -1; + } + else{ + mouse_divider_side = 1; + } + } + else{ + mouse_divider_vertical = 1; + if (mx > panel->inner.x0){ + mouse_divider_side = -1; + } + else{ + mouse_divider_side = 1; + } + } + + if (vars->layout.panel_count > 1){ + i32 which_child; + mouse_divider_id = panel->parent; + which_child = panel->which_child; + for (;;){ + Divider_And_ID div = layout_get_divider(&vars->layout, mouse_divider_id); + + if (which_child == mouse_divider_side && + div.divider->v_divider == mouse_divider_vertical){ + mouse_on_divider = 1; + break; + } + + if (mouse_divider_id == vars->layout.root){ + break; + } + else{ + mouse_divider_id = div.divider->parent; + which_child = div.divider->which_child; + } + } + } + else{ + mouse_on_divider = 0; + mouse_divider_id = 0; + } + } + ProfileEnd(hover_status); + + correctness_check(vars); + + // NOTE(allen): prepare to start executing commands + ProfileStart(prepare_commands); + + Command_Data *cmd = &vars->command_data; + + cmd->mem = &vars->mem; + cmd->panel = vars->layout.panels + vars->layout.active_panel; + cmd->view = cmd->panel->view; + cmd->working_set = &vars->working_set; + cmd->layout = &vars->layout; + cmd->live_set = &vars->live_set; + cmd->style = &vars->style; + cmd->global_font = &vars->global_font; + cmd->delay = &vars->delay1; + cmd->vars = vars; + cmd->exchange = exchange; + cmd->screen_width = target->width; + cmd->screen_height = target->height; + cmd->system = system; + + Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part); + cmd->part = partition_sub_part(&vars->mem.part, 16 << 10); + + if (first_step){ + if (vars->hooks[hook_start]){ + vars->hooks[hook_start](&app_links); + cmd->part.pos = 0; + } + + i32 i; + String file_name; + Panel *panel = vars->layout.panels; + for (i = 0; i < vars->settings.init_files_count; ++i, ++panel){ + file_name = make_string_slowly(vars->settings.init_files[i]); + + if (i < vars->layout.panel_count){ + delayed_open(&vars->delay1, file_name, panel); + if (i == 0){ + delayed_set_line(&vars->delay1, panel, vars->settings.initial_line); + } + } + else{ + delayed_open_background(&vars->delay1, file_name); + } + } + } + ProfileEnd(prepare_commands); + + // NOTE(allen): process the command_coroutine if it is unfinished + ProfileStart(command_coroutine); + b8 consumed_input[6] = {0}; + + if (vars->command_coroutine != 0){ + Coroutine *command_coroutine = vars->command_coroutine; + u32 get_flags = vars->command_coroutine_flags[0]; + u32 abort_flags = vars->command_coroutine_flags[1]; + + get_flags |= abort_flags; + + if ((get_flags & EventOnAnyKey) || (get_flags & EventOnEsc)){ + for (i32 key_i = 0; key_i < key_data.count; ++key_i){ + Key_Event_Data key = get_single_key(&key_data, key_i); + View *view = cmd->view; + b32 pass_in = 0; + cmd->key = key; + + Command_Map *map = 0; + if (view) map = view->map; + if (map == 0) map = &vars->map_top; + Command_Binding cmd_bind = map_extract_recursive(map, key); + + User_Input user_in; + user_in.type = UserInputKey; + user_in.key = key; + user_in.command = (unsigned long long)cmd_bind.custom; + user_in.abort = 0; + + if ((EventOnEsc & abort_flags) && key.keycode == key_esc){ + user_in.abort = 1; + } + else if (EventOnAnyKey & abort_flags){ + user_in.abort = 1; + } + + if (EventOnAnyKey & get_flags){ + pass_in = 1; + consumed_input[0] = 1; + } + if (key.keycode == key_esc){ + if (EventOnEsc & get_flags){ + pass_in = 1; + } + consumed_input[1] = 1; + } + + if (pass_in){ + cmd->current_coroutine = vars->command_coroutine; + vars->command_coroutine = system->resume_coroutine(command_coroutine, + &user_in, vars->command_coroutine_flags); + app_result.redraw = 1; + + // TOOD(allen): Deduplicate + // TODO(allen): Allow a view to clean up however it wants after a command + // finishes, or after transfering to another view mid command. + File_View *fview = view_to_file_view(view); + if (fview != 0 && vars->command_coroutine == 0){ + init_query_set(&fview->query_set); + } + if (vars->command_coroutine == 0) break; + } + } + } + + if (vars->command_coroutine != 0 && (get_flags & EventOnMouse)){ + View *view = cmd->view; + b32 pass_in = 0; + + User_Input user_in; + user_in.type = UserInputMouse; + user_in.mouse = *mouse; + user_in.command = 0; + user_in.abort = 0; + + if (abort_flags & EventOnMouseMove){ + user_in.abort = 1; + } + if (get_flags & EventOnMouseMove){ + pass_in = 1; + consumed_input[2] = 1; + } + + if (mouse->press_l || mouse->release_l || mouse->l){ + if (abort_flags & EventOnLeftButton){ + user_in.abort = 1; + } + if (get_flags & EventOnLeftButton){ + pass_in = 1; + consumed_input[3] = 1; + } + } + + if (mouse->press_r || mouse->release_r || mouse->r){ + if (abort_flags & EventOnRightButton){ + user_in.abort = 1; + } + if (get_flags & EventOnRightButton){ + pass_in = 1; + consumed_input[4] = 1; + } + } + + if (mouse->wheel != 0){ + if (abort_flags & EventOnWheel){ + user_in.abort = 1; + } + if (get_flags & EventOnWheel){ + pass_in = 1; + consumed_input[5] = 1; + } + } + + if (pass_in){ + cmd->current_coroutine = vars->command_coroutine; + vars->command_coroutine = system->resume_coroutine(command_coroutine, &user_in, + vars->command_coroutine_flags); + app_result.redraw = 1; + + // TOOD(allen): Deduplicate + // TODO(allen): Allow a view to clean up however it wants after a command finishes, + // or after transfering to another view mid command. + File_View *fview = view_to_file_view(view); + if (fview != 0 && vars->command_coroutine == 0){ + init_query_set(&fview->query_set); + } + } + } + } + + update_command_data(vars, cmd); + + ProfileEnd(command_coroutine); + + correctness_check(vars); + + // NOTE(allen): pass raw input to the panels + ProfileStart(step); + + Input_Summary dead_input = {}; + dead_input.mouse.x = mouse->x; + dead_input.mouse.y = mouse->y; + + Input_Summary active_input = {}; + active_input.mouse.x = mouse->x; + active_input.mouse.y = mouse->y; + if (!consumed_input[0]){ + active_input.keys = key_data; + } + else if (!consumed_input[1]){ + for (i32 i = 0; i < key_data.count; ++i){ + Key_Event_Data key = get_single_key(&key_data, i); + if (key.keycode == key_esc){ + active_input.keys.count = 1; + active_input.keys.keys[0] = key; + break; + } + } + } + + Mouse_State mouse_state = *mouse; + + if (consumed_input[3]){ + mouse_state.l = 0; + mouse_state.press_l = 0; + mouse_state.release_l = 0; + } + + if (consumed_input[4]){ + mouse_state.r = 0; + mouse_state.press_r = 0; + mouse_state.release_r = 0; + } + + if (consumed_input[5]){ + mouse_state.wheel = 0; + } + + { + Panel *panel, *used_panels; + used_panels = &vars->layout.used_sentinel; + for (dll_items(panel, used_panels)){ + View *view_ = panel->view; + Assert(view_->do_view); + b32 active = (panel == cmd->panel); + Input_Summary input = (active)?(active_input):(dead_input); + if (panel == mouse_panel && !mouse->out_of_window){ + input.mouse = mouse_state; + } + if (view_->do_view(system, exchange, view_, panel->inner, cmd->view, + VMSG_STEP, 0, &input, &active_input)){ + app_result.redraw = 1; + } + } + } + + update_command_data(vars, cmd); + ProfileEnd(step); + + correctness_check(vars); + + // NOTE(allen): command execution + ProfileStart(command); + if (!consumed_input[0] || !consumed_input[1]){ + b32 consumed_input2[2] = {0}; + + for (i32 key_i = 0; key_i < key_data.count; ++key_i){ + switch (vars->state){ + case APP_STATE_EDIT: + { + Key_Event_Data key = get_single_key(&key_data, key_i); + b32 hit_esc = (key.keycode == key_esc); + cmd->key = key; + + if (hit_esc || !consumed_input[0]){ + View *view = cmd->view; + + Command_Map *map = 0; + if (view) map = view->map; + if (map == 0) map = &vars->map_top; + Command_Binding cmd_bind = map_extract_recursive(map, key); + + if (cmd_bind.function){ + if (hit_esc){ + consumed_input2[1] = 1; + } + else{ + consumed_input2[0] = 1; + } + + Coroutine *command_coroutine = system->create_coroutine(command_caller); + vars->command_coroutine = command_coroutine; + + Command_In cmd_in; + cmd_in.cmd = cmd; + cmd_in.bind = cmd_bind; + + cmd->current_coroutine = vars->command_coroutine; + vars->command_coroutine = system->launch_coroutine(vars->command_coroutine, + &cmd_in, vars->command_coroutine_flags); + vars->prev_command = cmd_bind; + app_result.redraw = 1; + } + } + }break; + + case APP_STATE_RESIZING: + { + if (key_data.count > 0){ + vars->state = APP_STATE_EDIT; + } + }break; + } + } + + consumed_input[0] |= consumed_input2[0]; + consumed_input[1] |= consumed_input2[1]; + } + + update_command_data(vars, cmd); + ProfileEnd(command); + + correctness_check(vars); + + ProfileStart(resizing); + // NOTE(allen): panel resizing + switch (vars->state){ + case APP_STATE_EDIT: + { + if (mouse->press_l && mouse_on_divider){ + vars->state = APP_STATE_RESIZING; + Divider_And_ID div = layout_get_divider(&vars->layout, mouse_divider_id); + vars->resizing.divider = div.divider; + + i32 min, max; + { + i32 mid, MIN, MAX; + mid = div.divider->pos; + if (mouse_divider_vertical){ + MIN = 0; + MAX = MIN + vars->layout.full_width; + } + else{ + MIN = 0; + MAX = MIN + vars->layout.full_height; + } + min = MIN; + max = MAX; + + i32 divider_id = div.id; + do{ + Divider_And_ID other_div = layout_get_divider(&vars->layout, divider_id); + b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); + i32 pos = other_div.divider->pos; + if (divider_match && pos > mid && pos < max){ + max = pos; + } + else if (divider_match && pos < mid && pos > min){ + min = pos; + } + divider_id = other_div.divider->parent; + }while(divider_id != -1); + + Temp_Memory temp = begin_temp_memory(&vars->mem.part); + i32 *divider_stack = push_array(&vars->mem.part, i32, vars->layout.panel_count); + i32 top = 0; + divider_stack[top++] = div.id; + + while (top > 0){ + Divider_And_ID other_div = layout_get_divider(&vars->layout, divider_stack[--top]); + b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); + i32 pos = other_div.divider->pos; + if (divider_match && pos > mid && pos < max){ + max = pos; + } + else if (divider_match && pos < mid && pos > min){ + min = pos; + } + if (other_div.divider->child1 != -1){ + divider_stack[top++] = other_div.divider->child1; + } + if (other_div.divider->child2 != -1){ + divider_stack[top++] = other_div.divider->child2; + } + } + + end_temp_memory(temp); + } + + vars->resizing.min = min; + vars->resizing.max = max; + } + }break; + + case APP_STATE_RESIZING: + { + app_result.redraw = 1; + if (mouse->l){ + Panel_Divider *divider = vars->resizing.divider; + if (divider->v_divider){ + divider->pos = mx; + } + else{ + divider->pos = my; + } + + if (divider->pos < vars->resizing.min){ + divider->pos = vars->resizing.min; + } + else if (divider->pos > vars->resizing.max){ + divider->pos = vars->resizing.max - 1; + } + + layout_fix_all_panels(&vars->layout); + } + else{ + vars->state = APP_STATE_EDIT; + } + }break; + } + + if (mouse_in_edit_area && mouse_panel != 0 && mouse->press_l){ + vars->layout.active_panel = (i32)(mouse_panel - vars->layout.panels); + app_result.redraw = 1; + } + + update_command_data(vars, cmd); + ProfileEnd(resizing); + + correctness_check(vars); + + // NOTE(allen): processing sys app bindings + ProfileStart(sys_app_bind_processing); + { + Mem_Options *mem = &vars->mem; + General_Memory *general = &mem->general; + + for (i32 i = 0; i < vars->sys_app_count; ++i){ + Sys_App_Binding *binding; + b32 remove = 0; + b32 failed = 0; + binding = vars->sys_app_bindings + i; + + byte *data; + i32 size, max; + Editing_File *ed_file; + Editing_File_Preload preload_settings; + char *filename; + + Working_Set *working_set = &vars->working_set; + + if (exchange_file_ready(exchange, binding->sys_id, &data, &size, &max)){ + ed_file = working_set->files + binding->app_id; + filename = exchange_file_filename(exchange, binding->sys_id); + preload_settings = ed_file->preload; + if (data){ + String val = make_string((char*)data, size); + file_create_from_string(system, mem, working_set, ed_file, filename, + vars->font_set, vars->global_font.font_id, val); + + if (ed_file->settings.tokens_exist){ + file_first_lex_parallel(system, general, ed_file); + } + + if ((binding->success & SysAppCreateView) && binding->panel != 0){ + view_file_in_panel(cmd, binding->panel, ed_file); + } + + app_result.redraw = 1; + } + else{ + if (binding->fail & SysAppCreateNewBuffer){ + file_create_empty(system, mem, working_set, ed_file, filename, + vars->font_set, vars->global_font.font_id); + if (binding->fail & SysAppCreateView){ + view_file_in_panel(cmd, binding->panel, ed_file); + } + } + else{ + table_remove(&vars->working_set.table, ed_file->name.source_path); + file_get_dummy(ed_file); + } + + app_result.redraw = 1; + } + + if (!ed_file->state.is_dummy){ + for (File_View_Iter iter = file_view_iter_init(&vars->layout, ed_file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + view_measure_wraps(system, general, iter.view); + view_cursor_move(iter.view, preload_settings.start_line, 0); + } + } + + exchange_free_file(exchange, binding->sys_id); + remove = 1; + } + + if (exchange_file_save_complete(exchange, binding->sys_id, &data, &size, &max, &failed)){ + Assert(remove == 0); + + if (data){ + general_memory_free(general, data); + exchange_clear_file(exchange, binding->sys_id); + } + + Editing_File *file = get_file(working_set, binding->app_id); + if (file){ + file_synchronize_times(system, file, file->name.source_path.str); + } + + exchange_free_file(exchange, binding->sys_id); + remove = 1; + + // if (failed) { TODO(allen): saving error, now what? } + } + + if (remove){ + *binding = vars->sys_app_bindings[--vars->sys_app_count]; + --i; + } + } + } + ProfileEnd(sys_app_bind_processing); + + // NOTE(allen): process as many delayed actions as possible + ProfileStart(delayed_actions); + if (vars->delay1.count > 0){ + Style *style = &vars->style; + Style_Font *global_font = &vars->global_font; + Working_Set *working_set = &vars->working_set; + Live_Views *live_set = &vars->live_set; + Mem_Options *mem = &vars->mem; + General_Memory *general = &vars->mem.general; + + i32 count = vars->delay1.count; + vars->delay1.count = 0; + vars->delay2.count = 0; + + Delayed_Action *act = vars->delay1.acts; + for (i32 i = 0; i < count; ++i, ++act){ + String string = act->string; + Panel *panel = act->panel; + Editing_File *file = act->file; + i32 integer = act->integer; + + // TODO(allen): Paramter checking in each DACT case. + switch (act->type){ + case DACT_OPEN: + { + App_Open_File_Result result; + + result = app_open_file_background(vars, exchange, working_set, string); + + if (result.is_new){ + if (result.file){ + if (result.sys_id){ + Sys_App_Binding *binding = app_push_file_binding(vars, result.sys_id, result.file_index); + binding->success = SysAppCreateView; + binding->fail = 0; + binding->panel = panel; + } + else{ + delayed_action_repush(&vars->delay2, act); + } + } + } + else{ + if (result.file->state.is_dummy || result.file->state.is_loading){ + // do nothing + } + else{ + view_file_in_panel(cmd, panel, result.file); + } + } + }break; + + case DACT_OPEN_BACKGROUND: + { + App_Open_File_Result result; + result = app_open_file_background(vars, exchange, working_set, string); + if (result.is_new){ + if (result.file){ + if (result.sys_id){ + Sys_App_Binding *binding = app_push_file_binding(vars, result.sys_id, result.file_index); + binding->success = 0; + binding->fail = 0; + binding->panel = panel; + } + else{ + delayed_action_repush(&vars->delay2, act); + } + } + } + }break; + + case DACT_SET_LINE: + { + // TODO(allen): deduplicate + Editing_File *file = 0; + if (panel){ + File_View *fview = view_to_file_view(panel->view); + file = fview->file; + } + else if (string.str && string.size > 0){ + file = working_set_lookup_file(working_set, string); + } + if (file){ + if (file->state.is_loading){ + file->preload.start_line = integer; + } + else{ + // TODO(allen): write this case + } + } + }break; + + case DACT_SAVE_AS: + { + // TODO(allen): deduplicate + Editing_File *file = 0; + if (panel){ + File_View *fview = view_to_file_view(panel->view); + file = fview->file; + } + else if (string.str && string.size > 0){ + file = working_set_lookup_file(working_set, string); + } + if (file && !file->state.is_dummy){ + i32 sys_id = file_save_and_set_names(system, exchange, mem, working_set, file, string.str); + if (sys_id){ + app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); + } + else{ + delayed_action_repush(&vars->delay2, act); + } + } + }break; + + case DACT_SAVE: + { + if (!file){ + if (panel){ + View *view; + File_View *fview; + view = panel->view; + fview = view_to_file_view(view); + Assert(fview); + file = fview->file; + } + else{ + file = working_set_lookup_file(working_set, string); + } + } + // TODO(allen): We could handle the case where someone tries to save the same thing + // twice... that would be nice to have under control. + if (file && !file->state.is_dummy && buffer_needs_save(file)){ + i32 sys_id = file_save(system, exchange, mem, file, file->name.source_path.str); + if (sys_id){ + // TODO(allen): This is fishy! Shouldn't we bind it to a file name instead? This file + // might be killed before we get notified that the saving is done! + app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); + } + else{ + delayed_action_repush(&vars->delay2, act); + } + } + }break; + + case DACT_NEW: + { + Get_File_Result file = working_set_get_available_file(working_set); + file_create_empty(system, mem, working_set, file.file, string.str, + vars->font_set, global_font->font_id); + table_add(&working_set->table, file.file->name.source_path, file.index); + + View *view = panel->view; + File_View *fview = view_to_file_view(view); + + view_set_file(fview, file.file, vars->font_set, style, global_font, + system, vars->hooks[hook_open_file], &app_links); + view->map = app_get_map(vars, file.file->settings.base_map_id); +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + if (file.file->settings.tokens_exist) + file_first_lex_parallel(system, general, file.file); +#endif + }break; + + case DACT_SWITCH: + { + Editing_File *file = working_set_lookup_file(working_set, string); + if (file){ + View *view = panel->view; + File_View *fview = view_to_file_view(view); + + view_set_file(fview, file, vars->font_set, style, global_font, + system, vars->hooks[hook_open_file], &app_links); + view->map = app_get_map(vars, file->settings.base_map_id); + } + }break; + + case DACT_KILL: + { + Editing_File *file = working_set_lookup_file(working_set, string); + if (file){ + table_remove(&working_set->table, file->name.source_path); + kill_file(system, exchange, general, file, live_set, &vars->layout); + } + }break; + + case DACT_TRY_KILL: + { + Editing_File *file = 0; + file = working_set_lookup_file(working_set, string); + + View *view = 0; + if (panel){ + view = panel->view; + } + else{ + view = (vars->layout.panels + vars->layout.active_panel)->view; + } + + File_View *fview = view_to_file_view(view); + Assert(fview); + + if (file){ + if (buffer_needs_save(file)){ + view_show_interactive(system, fview, &vars->map_ui, + IAct_Sure_To_Kill, IInt_Sure_To_Kill, make_lit_string("Are you sure?")); + copy(&fview->dest, file->name.live_name); + } + else{ + table_remove(&working_set->table, file->name.source_path); + kill_file(system, exchange, general, file, live_set, &vars->layout); + } + } + }break; + } + + if (string.str){ + general_memory_free(&mem->general, string.str); + } + } + Swap(vars->delay1, vars->delay2); + } + + end_temp_memory(param_stack_temp); + ProfileEnd(delayed_actions); + + correctness_check(vars); + + ProfileStart(resize); + // NOTE(allen): send resize messages to panels that have changed size + { + Panel *panel, *used_panels; + used_panels = &vars->layout.used_sentinel; + for (dll_items(panel, used_panels)){ + i32_Rect prev = panel->prev_inner; + i32_Rect inner = panel->inner; + if (prev.x0 != inner.x0 || prev.y0 != inner.y0 || + prev.x1 != inner.x1 || prev.y1 != inner.y1){ + View *view = panel->view; + if (view){ + view->do_view(system, exchange, + view, inner, cmd->view, + VMSG_RESIZE, 0, &dead_input, &active_input); + } + } + panel->prev_inner = inner; + } + } + ProfileEnd(resize); + + ProfileStart(style_change); + // NOTE(allen): send style change messages if the style has changed + if (vars->global_font.font_changed){ + vars->global_font.font_changed = 0; + + Editing_File *file = vars->working_set.files; + for (i32 i = vars->working_set.file_index_count; i > 0; --i, ++file){ + if (buffer_good(&file->state.buffer) && !file->state.is_dummy){ + Render_Font *font = get_font_info(vars->font_set, vars->global_font.font_id)->font; + float *advance_data = 0; + if (font) advance_data = font->advance_data; + + file_measure_starts_widths(system, &vars->mem.general, + &file->state.buffer, advance_data); + } + } + + Panel *panel, *used_panels; + used_panels = &vars->layout.used_sentinel; + for (dll_items(panel, used_panels)){ + View *view = panel->view; + if (view){ + view->do_view(system, exchange, + view, panel->inner, cmd->view, + VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); + } + } + } + ProfileEnd(style_change); + + correctness_check(vars); + + ProfileStart(redraw); + if (mouse_panel != vars->prev_mouse_panel) app_result.redraw = 1; + if (app_result.redraw){ + begin_render_section(target, system); + + target->clip_top = -1; + draw_push_clip(target, rect_from_target(target)); + + // NOTE(allen): render the panels + Panel *panel, *used_panels; + used_panels = &vars->layout.used_sentinel; + for (dll_items(panel, used_panels)){ + i32_Rect full = panel->full; + i32_Rect inner = panel->inner; + + View *view = panel->view; + Style *style = &vars->style; + + b32 active = (panel == cmd->panel); + u32 back_color = style->main.back_color; + draw_rectangle(target, full, back_color); + + if (view){ + Assert(view->do_view); + draw_push_clip(target, panel->inner); + view->do_view(system, exchange, + view, panel->inner, cmd->view, + VMSG_DRAW, target, &dead_input, &active_input); + draw_pop_clip(target); + } + + u32 margin_color; + if (active){ + margin_color = style->main.margin_active_color; + } + else if (panel == mouse_panel){ + margin_color = style->main.margin_hover_color; + } + else{ + margin_color = style->main.margin_color; + } + draw_rectangle(target, i32R(full.x0, full.y0, full.x1, inner.y0), margin_color); + draw_rectangle(target, i32R(full.x0, inner.y1, full.x1, full.y1), margin_color); + draw_rectangle(target, i32R(full.x0, inner.y0, inner.x0, inner.y1), margin_color); + draw_rectangle(target, i32R(inner.x1, inner.y0, full.x1, inner.y1), margin_color); + } + + end_render_section(target, system); + } + ProfileEnd(redraw); + + ProfileStart(get_cursor); + // NOTE(allen): get cursor type + if (mouse_in_edit_area){ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + } + else if (mouse_in_margin_area){ + if (mouse_on_divider){ + if (mouse_divider_vertical){ + 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; + } + } + vars->prev_mouse_panel = mouse_panel; + ProfileEnd(get_cursor); + + *result = app_result; + result->lctrl_lalt_is_altgr = vars->settings.lctrl_lalt_is_altgr; + + correctness_check(vars); + + // end-of-app_step +} + +external App_Get_Functions_Sig(app_get_functions){ + App_Functions result = {}; + + result.read_command_line = app_read_command_line; + result.init = app_init; + result.step = app_step; + + return(result); +} + +// BOTTOM + diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index 3fd36292..3b49422d 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -40,10 +40,10 @@ #include "4ed_font_set.cpp" #include "4ed_rendering_helper.cpp" #include "4ed_command.cpp" -#include "4ed_layout.cpp" #include "4ed_style.cpp" #include "4ed_file.cpp" #include "4ed_gui.cpp" +#include "4ed_layout.cpp" #include "4ed_delay.cpp" #include "4ed_app_settings.h" #include "4ed_file_view.cpp" diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 8827a6e5..fff6ab93 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -25,7 +25,7 @@ enum Interactive_Interaction{ }; struct File_View_Mode{ - i8 rewrite; + i8 rewrite; }; struct Incremental_Search{ @@ -71,11 +71,12 @@ enum Color_View_Mode{ struct File_View{ View view_base; - + Editing_File *file; - + Editing_Layout *layout; - + + Style_Font *global_font; Style *style; Working_Set *working_set; Delay *delay; @@ -84,10 +85,10 @@ struct File_View{ Hot_Directory *hot_directory; Mem_Options *mem; Style_Library *styles; - + UI_State ui_state; View_UI showing_ui; - + // interactive stuff Interactive_Interaction interaction; Interactive_Action action; @@ -97,7 +98,7 @@ struct File_View{ char dest_[256]; String dest; i32 user_action; - + // theme stuff File_View *hot_file_view; u32 *palette; @@ -109,42 +110,42 @@ struct File_View{ Style_Library inspecting_styles; b8 import_export_check[64]; i32 import_file_id; - + i32 font_advance; i32 font_height; - + Full_Cursor cursor; i32 mark; - f32 scroll_y, target_y, vel_y; - f32 scroll_x, target_x, vel_x; + f32 scroll_y, target_y, prev_target_y; + f32 scroll_x, target_x, prev_target_x; f32 preferred_x; i32 scroll_i; - + union{ Incremental_Search isearch; struct{ String str; } gotoline; }; - + Full_Cursor temp_highlight; i32 temp_highlight_end_pos; b32 show_temp_highlight; - + File_View_Mode mode, next_mode; File_View_Widget widget; - + Query_Set query_set; - + i32 scrub_max; - + b32 unwrapped_lines; b32 show_whitespace; b32 locked; - + i32 line_count, line_max; f32 *line_wrap_y; - + Command_Map *map_for_file; }; @@ -171,7 +172,7 @@ get_file(Working_Set *working_set, i32 file_id){ inline bool32 starts_new_line(u8 character){ - return (character == '\n'); + return (character == '\n'); } inline void @@ -187,15 +188,15 @@ file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ Editing_File *file_ptr; i32 i, count, file_x, original_len; b32 hit_conflict; - + Assert(file->name.live_name.str != 0); f = make_string_slowly(filename); copy_checked(&file->name.source_path, f); - + file->name.live_name.size = 0; get_front_of_directory(&file->name.live_name, f); - + if (file->name.source_path.size == file->name.live_name.size){ file->name.extension.size = 0; } @@ -203,7 +204,7 @@ file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ ext = file_extension(f); copy(&file->name.extension, ext); } - + original_len = file->name.live_name.size; count = working_set->file_index_count; hit_conflict = 1; @@ -220,7 +221,7 @@ file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ } } } - + if (hit_conflict){ file->name.live_name.size = original_len; append(&file->name.live_name, " <"); @@ -242,48 +243,48 @@ file_synchronize_times(System_Functions *system, Editing_File *file, char *filen internal i32 file_save(System_Functions *system, Exchange *exchange, Mem_Options *mem, - Editing_File *file, char *filename){ - i32 result = 0; - + Editing_File *file, char *filename){ + i32 result = 0; + i32 max, size; b32 dos_write_mode = file->settings.dos_write_mode; char *data; Buffer_Type *buffer = &file->state.buffer; - + if (dos_write_mode) max = buffer_size(buffer) + buffer->line_count + 1; else max = buffer_size(buffer); - + data = (char*)general_memory_allocate(&mem->general, max, 0); Assert(data); - + if (dos_write_mode) size = buffer_convert_out(buffer, data, max); else buffer_stringify(buffer, 0, size = max, data); - + result = exchange_save_file(exchange, filename, str_size(filename), (byte*)data, size, max); - + if (result == 0){ general_memory_free(&mem->general, data); } - + file_synchronize_times(system, file, filename); - + return(result); } inline b32 file_save_and_set_names(System_Functions *system, Exchange *exchange, - Mem_Options *mem, Working_Set *working_set, Editing_File *file, - char *filename){ - b32 result = 0; + Mem_Options *mem, Working_Set *working_set, Editing_File *file, + char *filename){ + b32 result = 0; result = file_save(system, exchange, mem, file, filename); - if (result){ + if (result){ file_set_name(working_set, file, filename); - } - return result; + } + return result; } enum File_Bubble_Type{ @@ -310,14 +311,14 @@ file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, i32 count = buffer->line_count; i32 target_lines = count + additional_lines; Assert(max == buffer->widths_max); - + if (target_lines > max || max == 0){ max = LargeRoundUp(target_lines + max, Kbytes(1)); - + f32 *new_widths = (f32*)general_memory_reallocate( general, buffer->line_widths, sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); - + i32 *new_lines = (i32*)general_memory_reallocate( general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); @@ -337,13 +338,13 @@ file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, result = GROW_FAILED; } } - + return(result); } internal void file_measure_starts_widths(System_Functions *system, General_Memory *general, - Buffer_Type *buffer, float *advance_data){ + Buffer_Type *buffer, float *advance_data){ ProfileMomentFunction(); if (!buffer->line_starts){ i32 max = buffer->line_max = Kbytes(1); @@ -357,7 +358,7 @@ file_measure_starts_widths(System_Functions *system, General_Memory *general, TentativeAssert(buffer->line_starts); // TODO(allen): when unable to allocate? } - + Buffer_Measure_Starts state = {}; while (buffer_measure_starts_widths(&state, buffer, advance_data)){ i32 count = state.count; @@ -377,14 +378,14 @@ file_measure_starts_widths(System_Functions *system, General_Memory *general, { f32 *new_lines = (f32*) general_memory_reallocate(general, buffer->line_widths, - sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); - + sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); + // TODO(allen): when unable to grow? TentativeAssert(new_lines); buffer->line_widths = new_lines; buffer->widths_max = max; } - + } buffer->line_count = state.count; buffer->widths_count = state.count; @@ -392,9 +393,9 @@ file_measure_starts_widths(System_Functions *system, General_Memory *general, internal void file_remeasure_starts_(System_Functions *system, - General_Memory *general, Buffer_Type *buffer, - i32 line_start, i32 line_end, i32 line_shift, - i32 character_shift){ + General_Memory *general, Buffer_Type *buffer, + i32 line_start, i32 line_end, i32 line_shift, + i32 character_shift){ ProfileMomentFunction(); Assert(buffer->line_starts); file_grow_starts_widths_as_needed(general, buffer, line_shift); @@ -416,8 +417,8 @@ get_opaque_font_advance(Render_Font *font){ internal void file_remeasure_widths_(System_Functions *system, - General_Memory *general, Buffer_Type *buffer, Render_Font *font, - i32 line_start, i32 line_end, i32 line_shift){ + General_Memory *general, Buffer_Type *buffer, Render_Font *font, + i32 line_start, i32 line_end, i32 line_shift){ ProfileMomentFunction(); file_grow_starts_widths_as_needed(general, buffer, line_shift); buffer_remeasure_widths(buffer, font->advance_data, line_start, line_end, line_shift); @@ -433,7 +434,6 @@ view_wrapped_line_span(f32 line_width, f32 max_width){ internal i32 view_compute_lowest_line(File_View *view){ i32 lowest_line = 0; -#if BUFFER_EXPERIMENT_SCALPEL <= 3 i32 last_line = view->line_count - 1; if (last_line > 0){ if (view->unwrapped_lines){ @@ -443,7 +443,7 @@ view_compute_lowest_line(File_View *view){ f32 wrap_y = view->line_wrap_y[last_line]; lowest_line = FLOOR32(wrap_y / view->font_height); f32 max_width = view_compute_width(view); - + Editing_File *file = view->file; Assert(!file->state.is_dummy); f32 width = file->state.buffer.line_widths[last_line]; @@ -451,20 +451,18 @@ view_compute_lowest_line(File_View *view){ lowest_line += line_span - 1; } } -#endif return lowest_line; } internal void view_measure_wraps(System_Functions *system, - General_Memory *general, File_View *view){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 + General_Memory *general, File_View *view){ ProfileMomentFunction(); Buffer_Type *buffer; buffer = &view->file->state.buffer; i32 line_count = buffer->line_count; - + if (view->line_max < line_count){ i32 max = view->line_max = LargeRoundUp(line_count, Kbytes(1)); if (view->line_wrap_y){ @@ -480,9 +478,8 @@ view_measure_wraps(System_Functions *system, f32 line_height = (f32)view->font_height; f32 max_width = view_compute_width(view); buffer_measure_wrap_y(buffer, view->line_wrap_y, line_height, max_width); - + view->line_count = line_count; -#endif } internal void* @@ -497,15 +494,14 @@ file_create_from_string(System_Functions *system, Mem_Options *mem, Working_Set *working_set, Editing_File *file, char *filename, Font_Set *set, i16 font_id, String val, b8 super_locked = 0){ - + General_Memory *general = &mem->general; Partition *part = &mem->part; Buffer_Init_Type init; i32 page_size, scratch_size, init_success; - + file->state = {}; - -#if BUFFER_EXPERIMENT_SCALPEL <= 3 + init = buffer_begin_init(&file->state.buffer, val.str, val.size); for (; buffer_init_need_more(&init); ){ page_size = buffer_init_page_size(&init); @@ -520,15 +516,14 @@ file_create_from_string(System_Functions *system, Mem_Options *mem, init_success = buffer_end_init(&init, part->base + part->pos, scratch_size); AllowLocal(init_success); Assert(init_success); -#endif - + file_init_strings(file); file_set_name(working_set, file, (char*)filename); - + file->state.font_id = font_id; - + file_synchronize_times(system, file, filename); - + Render_Font *font = get_font_info(set, font_id)->font; float *advance_data = 0; if (font) advance_data = font->advance_data; @@ -568,7 +563,7 @@ file_create_empty( System_Functions *system, Mem_Options *mem, Working_Set *working_set, Editing_File *file, char *filename, Font_Set *set, i16 font_id){ - + b32 result = 1; String empty_str = {}; file_create_from_string(system, mem, working_set, file, filename, set, font_id, empty_str); @@ -594,10 +589,10 @@ struct Get_File_Result{ internal Get_File_Result working_set_get_available_file(Working_Set *working_set){ Get_File_Result result = {}; - + for (i32 buffer_index = 1; buffer_index < working_set->file_max_count; ++buffer_index){ if (buffer_index == working_set->file_index_count || - working_set->files[buffer_index].state.is_dummy){ + working_set->files[buffer_index].state.is_dummy){ result.index = buffer_index; result.file = working_set->files + buffer_index; if (buffer_index == working_set->file_index_count){ @@ -606,9 +601,9 @@ working_set_get_available_file(Working_Set *working_set){ break; } } - + if (result.file) *result.file = {}; - + return result; } @@ -630,7 +625,7 @@ file_close(System_Functions *system, General_Memory *general, Editing_File *file if (file->state.token_stack.tokens){ general_memory_free(general, file->state.token_stack.tokens); } - + #if BUFFER_EXPERIMENT_SCALPEL <= 1 Buffer_Type *buffer = &file->state.buffer; if (buffer->data){ @@ -645,10 +640,10 @@ file_close(System_Functions *system, General_Memory *general, Editing_File *file if (file->state.undo.undo.edits){ general_memory_free(general, file->state.undo.undo.strings); general_memory_free(general, file->state.undo.undo.edits); - + general_memory_free(general, file->state.undo.redo.strings); general_memory_free(general, file->state.undo.redo.edits); - + general_memory_free(general, file->state.undo.history.strings); general_memory_free(general, file->state.undo.history.edits); @@ -659,47 +654,47 @@ file_close(System_Functions *system, General_Memory *general, Editing_File *file inline void file_get_dummy(Editing_File *file){ - *file = {}; - file->state.is_dummy = 1; + *file = {}; + file->state.is_dummy = 1; } inline void file_set_to_loading(Editing_File *file){ - file->state = {}; - file->settings = {}; - file->state.is_loading = 1; + file->state = {}; + file->settings = {}; + file->state.is_loading = 1; } struct Shift_Information{ - i32 start, end, amount; + i32 start, end, amount; }; internal Job_Callback_Sig(job_full_lex){ Editing_File *file = (Editing_File*)data[0]; General_Memory *general = (General_Memory*)data[1]; - + Cpp_File cpp_file; cpp_file.data = file->state.buffer.data; cpp_file.size = file->state.buffer.size; - + Cpp_Token_Stack tokens; tokens.tokens = (Cpp_Token*)memory->data; tokens.max_count = memory->size / sizeof(Cpp_Token); tokens.count = 0; - + Cpp_Lex_Data status; status = cpp_lex_file_nonalloc(cpp_file, &tokens); - + while (!status.complete){ system->grow_thread_memory(memory); tokens.tokens = (Cpp_Token*)memory->data; tokens.max_count = memory->size / sizeof(Cpp_Token); status = cpp_lex_file_nonalloc(cpp_file, &tokens, status); } - + i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1)); - + system->acquire_lock(FRAME_LOCK); { Assert(file->state.swap_stack.tokens == 0); @@ -710,14 +705,14 @@ Job_Callback_Sig(job_full_lex){ u8 *dest = (u8*)file->state.swap_stack.tokens; u8 *src = (u8*)tokens.tokens; - + #if 1 memcpy(dest, src, tokens.count*sizeof(Cpp_Token)); #else i32 copy_amount = Kbytes(8); i32 uncoppied = tokens.count*sizeof(Cpp_Token); if (copy_amount > uncoppied) copy_amount = uncoppied; - + while (uncoppied > 0){ system->acquire_lock(FRAME_LOCK); memcpy(dest, src, copy_amount); @@ -728,7 +723,7 @@ Job_Callback_Sig(job_full_lex){ if (copy_amount > uncoppied) copy_amount = uncoppied; } #endif - + system->acquire_lock(FRAME_LOCK); { file->state.token_stack.count = tokens.count; @@ -739,9 +734,9 @@ Job_Callback_Sig(job_full_lex){ file->state.swap_stack.tokens = 0; } system->release_lock(FRAME_LOCK); - + exchange->force_redraw = 1; - + // NOTE(allen): These are outside the locked section because I don't // think getting these out of order will cause critical bugs, and I // want to minimize what's done in locked sections. @@ -752,7 +747,7 @@ Job_Callback_Sig(job_full_lex){ internal void file_kill_tokens(System_Functions *system, - General_Memory *general, Editing_File *file){ + General_Memory *general, Editing_File *file){ file->settings.tokens_exist = 0; if (file->state.still_lexing){ system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); @@ -771,19 +766,19 @@ file_kill_tokens(System_Functions *system, #if BUFFER_EXPERIMENT_SCALPEL <= 0 internal void file_first_lex_parallel(System_Functions *system, - General_Memory *general, Editing_File *file){ + General_Memory *general, Editing_File *file){ file->settings.tokens_exist = 1; - + if (file->state.is_loading == 0 && file->state.still_lexing == 0){ Assert(file->state.token_stack.tokens == 0); - + file->state.tokens_complete = 0; file->state.still_lexing = 1; #if 0 full_lex(system, file, general); #else - + Job_Data job; job.callback = job_full_lex; job.data[0] = file; @@ -796,27 +791,27 @@ file_first_lex_parallel(System_Functions *system, internal void file_relex_parallel(System_Functions *system, - Mem_Options *mem, Editing_File *file, - i32 start_i, i32 end_i, i32 amount){ + Mem_Options *mem, Editing_File *file, + i32 start_i, i32 end_i, i32 amount){ General_Memory *general = &mem->general; Partition *part = &mem->part; if (file->state.token_stack.tokens == 0){ file_first_lex_parallel(system, general, file); return; } - + b32 inline_lex = !file->state.still_lexing; if (inline_lex){ Cpp_File cpp_file; cpp_file.data = file->state.buffer.data; cpp_file.size = file->state.buffer.size; - + Cpp_Token_Stack *stack = &file->state.token_stack; - + Cpp_Relex_State state = cpp_relex_nonalloc_start(cpp_file, stack, - start_i, end_i, amount, 100); - + start_i, end_i, amount, 100); + Temp_Memory temp = begin_temp_memory(part); i32 relex_end; Cpp_Token_Stack relex_space; @@ -829,35 +824,35 @@ file_relex_parallel(System_Functions *system, else{ i32 delete_amount = relex_end - state.start_token_i; i32 shift_amount = relex_space.count - delete_amount; - + if (shift_amount != 0){ int new_count = stack->count + shift_amount; if (new_count > stack->max_count){ int new_max = LargeRoundUp(new_count, Kbytes(1)); stack->tokens = (Cpp_Token*) general_memory_reallocate(general, stack->tokens, - stack->count*sizeof(Cpp_Token), - new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); + stack->count*sizeof(Cpp_Token), + new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); stack->max_count = new_max; } - + int shift_size = stack->count - relex_end; if (shift_size > 0){ Cpp_Token *old_base = stack->tokens + relex_end; memmove(old_base + shift_amount, old_base, - sizeof(Cpp_Token)*shift_size); + sizeof(Cpp_Token)*shift_size); } - + stack->count += shift_amount; } - + memcpy(state.stack->tokens + state.start_token_i, relex_space.tokens, - sizeof(Cpp_Token)*relex_space.count); + sizeof(Cpp_Token)*relex_space.count); } - + end_temp_memory(temp); } - + if (!inline_lex){ i32 end_token_i = cpp_get_end_token(&file->state.token_stack, end_i); cpp_shift_token_starts(&file->state.token_stack, end_token_i, amount); @@ -868,13 +863,13 @@ file_relex_parallel(System_Functions *system, token->size += amount; } } - + file->state.still_lexing = 1; - + #if 0 full_lex(system, file, general); #else - + Job_Data job; job.callback = job_full_lex; job.data[0] = file; @@ -936,26 +931,26 @@ child_stack_grow_edits(General_Memory *general, Small_Edit_Stack *stack, i32 amo internal i32 undo_children_push(General_Memory *general, Small_Edit_Stack *children, - Buffer_Edit *edits, i32 edit_count, u8 *strings, i32 string_size){ + Buffer_Edit *edits, i32 edit_count, u8 *strings, i32 string_size){ i32 result = children->edit_count; if (children->edit_count + edit_count > children->edit_max) child_stack_grow_edits(general, children, edit_count); - + if (children->size + string_size > children->max) child_stack_grow_string(general, children, string_size); - + memcpy(children->edits + children->edit_count, edits, edit_count*sizeof(Buffer_Edit)); memcpy(children->strings + children->size, strings, string_size); - + Buffer_Edit *edit = children->edits + children->edit_count; i32 start_pos = children->size; for (i32 i = 0; i < edit_count; ++i, ++edit){ edit->str_start += start_pos; } - + children->edit_count += edit_count; children->size += string_size; - + return result; } @@ -964,33 +959,32 @@ struct Edit_Spec{ Edit_Step step; }; -#if BUFFER_EXPERIMENT_SCALPEL <= 3 internal Edit_Step* file_post_undo(General_Memory *general, Editing_File *file, - Edit_Step step, bool32 do_merge, bool32 can_merge){ + Edit_Step step, bool32 do_merge, bool32 can_merge){ if (step.type == ED_NORMAL){ file->state.undo.redo.size = 0; file->state.undo.redo.edit_count = 0; } - + Edit_Stack *undo = &file->state.undo.undo; Edit_Step *result = 0; - + if (step.child_count == 0){ if (step.edit.end - step.edit.start + undo->size > undo->max) undo_stack_grow_string(general, undo, step.edit.end - step.edit.start); - + Buffer_Edit inv; buffer_invert_edit(&file->state.buffer, step.edit, &inv, - (char*)undo->strings, &undo->size, undo->max); - + (char*)undo->strings, &undo->size, undo->max); + Edit_Step inv_step = {}; inv_step.edit = inv; inv_step.pre_pos = step.pre_pos; inv_step.post_pos = step.post_pos; inv_step.can_merge = (b8)can_merge; inv_step.type = ED_UNDO; - + bool32 did_merge = 0; if (do_merge && undo->edit_count > 0){ Edit_Step prev = undo->edits[undo->edit_count-1]; @@ -1002,7 +996,7 @@ file_post_undo(General_Memory *general, Editing_File *file, } } } - + if (did_merge){ result = undo->edits + (undo->edit_count-1); *result = inv_step; @@ -1022,7 +1016,7 @@ file_post_undo(General_Memory *general, Editing_File *file, inv_step.special_type = step.special_type; inv_step.child_count = step.inverse_child_count; inv_step.inverse_child_count = step.child_count; - + if (undo->edit_count == undo->edit_max) undo_stack_grow_edits(general, undo); result = undo->edits + (undo->edit_count++); @@ -1030,7 +1024,6 @@ file_post_undo(General_Memory *general, Editing_File *file, } return result; } -#endif inline void undo_stack_pop(Edit_Stack *stack){ @@ -1040,7 +1033,6 @@ undo_stack_pop(Edit_Stack *stack){ } } -#if BUFFER_EXPERIMENT_SCALPEL <= 3 internal void file_post_redo(General_Memory *general, Editing_File *file, Edit_Step step){ Edit_Stack *redo = &file->state.undo.redo; @@ -1048,17 +1040,17 @@ file_post_redo(General_Memory *general, Editing_File *file, Edit_Step step){ if (step.child_count == 0){ if (step.edit.end - step.edit.start + redo->size > redo->max) undo_stack_grow_string(general, redo, step.edit.end - step.edit.start); - + Buffer_Edit inv; buffer_invert_edit(&file->state.buffer, step.edit, &inv, - (char*)redo->strings, &redo->size, redo->max); - + (char*)redo->strings, &redo->size, redo->max); + Edit_Step inv_step = {}; inv_step.edit = inv; inv_step.pre_pos = step.pre_pos; inv_step.post_pos = step.post_pos; inv_step.type = ED_REDO; - + if (redo->edit_count == redo->edit_max) undo_stack_grow_edits(general, redo); redo->edits[redo->edit_count++] = inv_step; @@ -1071,19 +1063,18 @@ file_post_redo(General_Memory *general, Editing_File *file, Edit_Step step){ inv_step.special_type = step.special_type; inv_step.child_count = step.inverse_child_count; inv_step.inverse_child_count = step.child_count; - + if (redo->edit_count == redo->edit_max) undo_stack_grow_edits(general, redo); redo->edits[redo->edit_count++] = inv_step; } } -#endif inline void file_post_history_block(Editing_File *file, i32 pos){ Assert(file->state.undo.history_head_block < pos); Assert(pos < file->state.undo.history.edit_count); - + Edit_Step *history = file->state.undo.history.edits; Edit_Step *step = history + file->state.undo.history_head_block; step->next_block = pos; @@ -1104,10 +1095,10 @@ file_unpost_history_block(Editing_File *file){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 internal Edit_Step* file_post_history(General_Memory *general, Editing_File *file, - Edit_Step step, b32 do_merge, b32 can_merge){ + Edit_Step step, b32 do_merge, b32 can_merge){ Edit_Stack *history = &file->state.undo.history; Edit_Step *result = 0; - + persist Edit_Type reverse_types[4]; if (reverse_types[ED_UNDO] == 0){ reverse_types[ED_NORMAL] = ED_REVERSE_NORMAL; @@ -1115,22 +1106,22 @@ file_post_history(General_Memory *general, Editing_File *file, reverse_types[ED_UNDO] = ED_REDO; reverse_types[ED_REDO] = ED_UNDO; } - + if (step.child_count == 0){ if (step.edit.end - step.edit.start + history->size > history->max) undo_stack_grow_string(general, history, step.edit.end - step.edit.start); - + Buffer_Edit inv; buffer_invert_edit(&file->state.buffer, step.edit, &inv, - (char*)history->strings, &history->size, history->max); - + (char*)history->strings, &history->size, history->max); + Edit_Step inv_step = {}; inv_step.edit = inv; inv_step.pre_pos = step.pre_pos; inv_step.post_pos = step.post_pos; inv_step.can_merge = (b8)can_merge; inv_step.type = reverse_types[step.type]; - + bool32 did_merge = 0; if (do_merge && history->edit_count > 0){ Edit_Step prev = history->edits[history->edit_count-1]; @@ -1142,7 +1133,7 @@ file_post_history(General_Memory *general, Editing_File *file, } } } - + if (did_merge){ result = history->edits + (history->edit_count-1); } @@ -1151,7 +1142,7 @@ file_post_history(General_Memory *general, Editing_File *file, undo_stack_grow_edits(general, history); result = history->edits + (history->edit_count++); } - + *result = inv_step; } else{ @@ -1162,13 +1153,13 @@ file_post_history(General_Memory *general, Editing_File *file, inv_step.special_type = step.special_type; inv_step.inverse_child_count = step.child_count; inv_step.child_count = step.inverse_child_count; - + if (history->edit_count == history->edit_max) undo_stack_grow_edits(general, history); result = history->edits + (history->edit_count++); *result = inv_step; } - + return result; } #endif @@ -1176,31 +1167,28 @@ file_post_history(General_Memory *general, Editing_File *file, inline Full_Cursor view_compute_cursor_from_pos(File_View *view, i32 pos){ Editing_File *file = view->file; - Style *style = view->style; - Render_Font *font = get_font_info(view->font_set, style->font_id)->font; - + Render_Font *font = get_font_info(view->font_set, view->global_font->font_id)->font; + Full_Cursor result = {}; if (font){ f32 max_width = view_compute_width(view); result = buffer_cursor_from_pos(&file->state.buffer, pos, view->line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); + max_width, (f32)view->font_height, font->advance_data); } return result; } inline Full_Cursor -view_compute_cursor_from_unwrapped_xy(File_View *view, f32 seek_x, f32 seek_y, - b32 round_down = 0){ +view_compute_cursor_from_unwrapped_xy(File_View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ Editing_File *file = view->file; - Style *style = view->style; - Render_Font *font = get_font_info(view->font_set, style->font_id)->font; - + Render_Font *font = get_font_info(view->font_set, view->global_font->font_id)->font; + Full_Cursor result = {}; if (font){ f32 max_width = view_compute_width(view); result = buffer_cursor_from_unwrapped_xy(&file->state.buffer, seek_x, seek_y, - round_down, view->line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); + round_down, view->line_wrap_y, + max_width, (f32)view->font_height, font->advance_data); } return result; @@ -1208,60 +1196,58 @@ view_compute_cursor_from_unwrapped_xy(File_View *view, f32 seek_x, f32 seek_y, internal Full_Cursor view_compute_cursor_from_wrapped_xy(File_View *view, f32 seek_x, f32 seek_y, - b32 round_down = 0){ + b32 round_down = 0){ Editing_File *file = view->file; - Style *style = view->style; - Render_Font *font = get_font_info(view->font_set, style->font_id)->font; - + Render_Font *font = get_font_info(view->font_set, view->global_font->font_id)->font; + Full_Cursor result = {}; if (font){ f32 max_width = view_compute_width(view); result = buffer_cursor_from_wrapped_xy(&file->state.buffer, seek_x, seek_y, - round_down, view->line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); + round_down, view->line_wrap_y, + max_width, (f32)view->font_height, font->advance_data); } - + return result; } internal Full_Cursor view_compute_cursor_from_line_pos(File_View *view, i32 line, i32 pos){ Editing_File *file = view->file; - Style *style = view->style; - Render_Font *font = get_font_info(view->font_set, style->font_id)->font; - + Render_Font *font = get_font_info(view->font_set, view->global_font->font_id)->font; + Full_Cursor result = {}; if (font){ f32 max_width = view_compute_width(view); result = buffer_cursor_from_line_character(&file->state.buffer, line, pos, - view->line_wrap_y, max_width, (f32)view->font_height, font->advance_data); + view->line_wrap_y, max_width, (f32)view->font_height, font->advance_data); } - + return result; } inline Full_Cursor view_compute_cursor(File_View *view, Buffer_Seek seek){ Full_Cursor result = {}; - + switch(seek.type){ case buffer_seek_pos: result = view_compute_cursor_from_pos(view, seek.pos); break; - + case buffer_seek_wrapped_xy: result = view_compute_cursor_from_wrapped_xy(view, seek.x, seek.y); break; - + case buffer_seek_unwrapped_xy: result = view_compute_cursor_from_unwrapped_xy(view, seek.x, seek.y); break; - + case buffer_seek_line_char: result = view_compute_cursor_from_line_pos(view, seek.line, seek.character); break; } - + return result; } @@ -1270,13 +1256,13 @@ view_compute_cursor_from_xy(File_View *view, f32 seek_x, f32 seek_y){ Full_Cursor result; if (view->unwrapped_lines) result = view_compute_cursor_from_unwrapped_xy(view, seek_x, seek_y); else result = view_compute_cursor_from_wrapped_xy(view, seek_x, seek_y); - return result; + return result; } inline void view_set_temp_highlight(File_View *view, i32 pos, i32 end_pos){ - view->temp_highlight = view_compute_cursor_from_pos(view, pos); - view->temp_highlight_end_pos = end_pos; + view->temp_highlight = view_compute_cursor_from_pos(view, pos); + view->temp_highlight_end_pos = end_pos; view->show_temp_highlight = 1; } @@ -1315,13 +1301,13 @@ inline f32 view_get_cursor_y(File_View *view){ Full_Cursor *cursor; f32 result; - + if (view->show_temp_highlight) cursor = &view->temp_highlight; else cursor = &view->cursor; - + if (view->unwrapped_lines) result = cursor->unwrapped_y; else result = cursor->wrapped_y; - + return result; } @@ -1332,23 +1318,25 @@ view_set_file( Editing_File *file, Font_Set *set, Style *style, - + Style_Font *global_font, + // NOTE(allen): Necessary when file != 0 System_Functions *system, Hook_Function *open_hook, Application_Links *app){ - + Panel *panel; Font_Info *fnt_info; - + f32 w, h; f32 cursor_x, cursor_y; f32 target_x, target_y; - + panel = view->view_base.panel; - + // NOTE(allen): This is actually more like view_set_style right? - fnt_info = get_font_info(set, style->font_id); + fnt_info = get_font_info(set, global_font->font_id); + view->global_font = global_font; view->style = style; view->font_advance = fnt_info->advance; view->font_height = fnt_info->height; @@ -1356,33 +1344,33 @@ view_set_file( // NOTE(allen): Stuff that doesn't assume file exists. view->file = file; - + view->cursor = {}; - view->vel_y = 1.f; - view->vel_x = 1.f; - + view->prev_target_x = -1000.f; + view->prev_target_y = -1000.f; + target_x = 0; target_y = 0; - + // NOTE(allen): Stuff that does assume file exists. - + if (file){ // NOTE(allen): Isn't this a bit clumsy? file->settings.set = set; - + view->locked = file->settings.super_locked; view->unwrapped_lines = file->settings.unwrapped_lines; - + if (file_is_ready(file)){ view_measure_wraps(system, &view->mem->general, view); view->cursor = view_compute_cursor_from_pos(view, file->state.cursor_pos); - + cursor_x = view_get_cursor_x(view); cursor_y = view_get_cursor_y(view); - + w = (f32)(panel->inner.x1 - panel->inner.x0); h = (f32)(panel->inner.y1 - panel->inner.y0); - + Assert(cursor_x >= target_x); if (cursor_x >= target_x + w){ target_x = (f32)(cursor_x - w*.5f); @@ -1392,14 +1380,14 @@ view_set_file( if (target_y < 0) target_y = 0; } } - + // NOTE(allen): More stuff that doesn't assume file exists, but that // has to come after computing target_x, target_y view->target_x = target_x; view->target_y = target_y; view->scroll_x = target_x; view->scroll_y = target_y; - + // TODO(allen): Bypass all this nonsense, it's a hack! Hooks need parameters! // Just accept it and pass the file to the open hook when it is loaded. if (file){ @@ -1410,15 +1398,17 @@ view_set_file( } } +// TODO(allen): Somehow keep track of the scroll limits through this process. +// Maybe scroll limits should be stored in the view at each frame. struct Relative_Scrolling{ - real32 scroll_x, scroll_y; - real32 target_x, target_y; + f32 scroll_x, scroll_y; + f32 target_x, target_y; }; internal Relative_Scrolling view_get_relative_scrolling(File_View *view){ Relative_Scrolling result; - real32 cursor_x, cursor_y; + f32 cursor_x, cursor_y; cursor_x = view_get_cursor_x(view); cursor_y = view_get_cursor_y(view); result.scroll_x = cursor_x - view->scroll_x; @@ -1430,20 +1420,18 @@ view_get_relative_scrolling(File_View *view){ internal void view_set_relative_scrolling(File_View *view, Relative_Scrolling scrolling){ - real32 cursor_x, cursor_y; + f32 cursor_x, cursor_y; cursor_x = view_get_cursor_x(view); cursor_y = view_get_cursor_y(view); view->scroll_y = cursor_y - scrolling.scroll_y; view->target_y = cursor_y - scrolling.target_y; - if (view->scroll_y < 0) view->scroll_y = 0; - if (view->target_y < 0) view->target_y = 0; } inline void view_cursor_move(File_View *view, Full_Cursor cursor){ - view->cursor = cursor; + view->cursor = cursor; view->preferred_x = view_get_cursor_x(view); - view->file->state.cursor_pos = view->cursor.pos; + view->file->state.cursor_pos = view->cursor.pos; view->show_temp_highlight = 0; } @@ -1481,11 +1469,11 @@ inline i32_Rect view_widget_rect(File_View *view, i32 font_height){ Panel *panel = view->view_base.panel; i32_Rect result = panel->inner; - + if (view->file){ result.y0 = result.y0 + font_height + 2; } - + return(result); } @@ -1511,152 +1499,152 @@ enum History_Mode{ internal void file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step step, u8 *str, - History_Mode history_mode){ + History_Mode history_mode){ if (!file->state.undo.undo.edits) return; #if BUFFER_EXPERIMENT_SCALPEL <= 3 General_Memory *general = &mem->general; - + #if FRED_SLOW if (history_mode == hist_backward) debug_edit_step_check(step, file->state.undo.history.edits[file->state.undo.edit_history_cursor]); else if (history_mode == hist_forward) debug_edit_step_check(step, file->state.undo.history.edits[file->state.undo.history.edit_count]); switch (step.type){ - case ED_UNDO: - { - Assert(file->state.undo.undo.edit_count > 0); - debug_edit_step_check(step, file->state.undo.undo.edits[file->state.undo.undo.edit_count-1]); - }break; - case ED_REDO: - { - Assert(file->state.undo.redo.edit_count > 0); - debug_edit_step_check(step, file->state.undo.redo.edits[file->state.undo.redo.edit_count-1]); - }break; + case ED_UNDO: + { + Assert(file->state.undo.undo.edit_count > 0); + debug_edit_step_check(step, file->state.undo.undo.edits[file->state.undo.undo.edit_count-1]); + }break; + case ED_REDO: + { + Assert(file->state.undo.redo.edit_count > 0); + debug_edit_step_check(step, file->state.undo.redo.edits[file->state.undo.redo.edit_count-1]); + }break; } #endif - + b32 can_merge = 0, do_merge = 0; switch (step.type){ - case ED_NORMAL: - { - if (step.edit.len == 1 && str && char_is_alpha_numeric(*str)) can_merge = 1; - if (step.edit.len == 1 && str && (can_merge || char_is_whitespace(*str))) do_merge = 1; - - if (history_mode != hist_forward) - file_post_history(general, file, step, do_merge, can_merge); - - file_post_undo(general, file, step, do_merge, can_merge); - }break; - - case ED_REVERSE_NORMAL: - { - if (history_mode != hist_forward) - file_post_history(general, file, step, do_merge, can_merge); - - undo_stack_pop(&file->state.undo.undo); - - b32 restore_redos = 0; - Edit_Step *redo_end = 0; - - if (history_mode == hist_backward && file->state.undo.edit_history_cursor > 0){ - restore_redos = 1; - redo_end = file->state.undo.history.edits + (file->state.undo.edit_history_cursor - 1); - } - else if (history_mode == hist_forward && file->state.undo.history.edit_count > 0){ - restore_redos = 1; - redo_end = file->state.undo.history.edits + (file->state.undo.history.edit_count - 1); - } - - if (restore_redos){ - Edit_Step *redo_start = redo_end; - i32 steps_of_redo = 0; - i32 strings_of_redo = 0; - i32 undo_count = 0; - while (redo_start->type == ED_REDO || redo_start->type == ED_UNDO){ - if (redo_start->type == ED_REDO){ - if (undo_count > 0) --undo_count; - else{ - ++steps_of_redo; - strings_of_redo += redo_start->edit.len; - } - } - else{ - ++undo_count; - } - --redo_start; + case ED_NORMAL: + { + if (step.edit.len == 1 && str && char_is_alpha_numeric(*str)) can_merge = 1; + if (step.edit.len == 1 && str && (can_merge || char_is_whitespace(*str))) do_merge = 1; + + if (history_mode != hist_forward) + file_post_history(general, file, step, do_merge, can_merge); + + file_post_undo(general, file, step, do_merge, can_merge); + }break; + + case ED_REVERSE_NORMAL: + { + if (history_mode != hist_forward) + file_post_history(general, file, step, do_merge, can_merge); + + undo_stack_pop(&file->state.undo.undo); + + b32 restore_redos = 0; + Edit_Step *redo_end = 0; + + if (history_mode == hist_backward && file->state.undo.edit_history_cursor > 0){ + restore_redos = 1; + redo_end = file->state.undo.history.edits + (file->state.undo.edit_history_cursor - 1); } - - if (redo_start < redo_end){ - ++redo_start; - ++redo_end; - - if (file->state.undo.redo.edit_count + steps_of_redo > file->state.undo.redo.edit_max) - undo_stack_grow_edits(general, &file->state.undo.redo); - - if (file->state.undo.redo.size + strings_of_redo > file->state.undo.redo.max) - undo_stack_grow_string(general, &file->state.undo.redo, strings_of_redo); - - u8 *str_src = file->state.undo.history.strings + redo_end->edit.str_start; - u8 *str_dest_base = file->state.undo.redo.strings; - i32 str_redo_pos = file->state.undo.redo.size + strings_of_redo; - - Edit_Step *edit_src = redo_end; - Edit_Step *edit_dest = - file->state.undo.redo.edits + file->state.undo.redo.edit_count + steps_of_redo; - + else if (history_mode == hist_forward && file->state.undo.history.edit_count > 0){ + restore_redos = 1; + redo_end = file->state.undo.history.edits + (file->state.undo.history.edit_count - 1); + } + + if (restore_redos){ + Edit_Step *redo_start = redo_end; + i32 steps_of_redo = 0; + i32 strings_of_redo = 0; i32 undo_count = 0; - for (i32 i = 0; i < steps_of_redo;){ - --edit_src; - str_src -= edit_src->edit.len; - if (edit_src->type == ED_REDO){ - if (undo_count > 0){ - --undo_count; - } + while (redo_start->type == ED_REDO || redo_start->type == ED_UNDO){ + if (redo_start->type == ED_REDO){ + if (undo_count > 0) --undo_count; else{ - ++i; - - --edit_dest; - *edit_dest = *edit_src; - - str_redo_pos -= edit_dest->edit.len; - edit_dest->edit.str_start = str_redo_pos; - - memcpy(str_dest_base + str_redo_pos, str_src, edit_dest->edit.len); + ++steps_of_redo; + strings_of_redo += redo_start->edit.len; } } else{ ++undo_count; } + --redo_start; + } + + if (redo_start < redo_end){ + ++redo_start; + ++redo_end; + + if (file->state.undo.redo.edit_count + steps_of_redo > file->state.undo.redo.edit_max) + undo_stack_grow_edits(general, &file->state.undo.redo); + + if (file->state.undo.redo.size + strings_of_redo > file->state.undo.redo.max) + undo_stack_grow_string(general, &file->state.undo.redo, strings_of_redo); + + u8 *str_src = file->state.undo.history.strings + redo_end->edit.str_start; + u8 *str_dest_base = file->state.undo.redo.strings; + i32 str_redo_pos = file->state.undo.redo.size + strings_of_redo; + + Edit_Step *edit_src = redo_end; + Edit_Step *edit_dest = + file->state.undo.redo.edits + file->state.undo.redo.edit_count + steps_of_redo; + + i32 undo_count = 0; + for (i32 i = 0; i < steps_of_redo;){ + --edit_src; + str_src -= edit_src->edit.len; + if (edit_src->type == ED_REDO){ + if (undo_count > 0){ + --undo_count; + } + else{ + ++i; + + --edit_dest; + *edit_dest = *edit_src; + + str_redo_pos -= edit_dest->edit.len; + edit_dest->edit.str_start = str_redo_pos; + + memcpy(str_dest_base + str_redo_pos, str_src, edit_dest->edit.len); + } + } + else{ + ++undo_count; + } + } + Assert(undo_count == 0); + + file->state.undo.redo.size += strings_of_redo; + file->state.undo.redo.edit_count += steps_of_redo; } - Assert(undo_count == 0); - - file->state.undo.redo.size += strings_of_redo; - file->state.undo.redo.edit_count += steps_of_redo; } - } - }break; - - case ED_UNDO: - { - if (history_mode != hist_forward) - file_post_history(general, file, step, do_merge, can_merge); - file_post_redo(general, file, step); - undo_stack_pop(&file->state.undo.undo); - }break; - - case ED_REDO: - { - if (step.edit.len == 1 && str && char_is_alpha_numeric(*str)) can_merge = 1; - if (step.edit.len == 1 && str && (can_merge || char_is_whitespace(*str))) do_merge = 1; - - if (history_mode != hist_forward) - file_post_history(general, file, step, do_merge, can_merge); - - file_post_undo(general, file, step, do_merge, can_merge); - undo_stack_pop(&file->state.undo.redo); - }break; + }break; + + case ED_UNDO: + { + if (history_mode != hist_forward) + file_post_history(general, file, step, do_merge, can_merge); + file_post_redo(general, file, step); + undo_stack_pop(&file->state.undo.undo); + }break; + + case ED_REDO: + { + if (step.edit.len == 1 && str && char_is_alpha_numeric(*str)) can_merge = 1; + if (step.edit.len == 1 && str && (can_merge || char_is_whitespace(*str))) do_merge = 1; + + if (history_mode != hist_forward) + file_post_history(general, file, step, do_merge, can_merge); + + file_post_undo(general, file, step, do_merge, can_merge); + undo_stack_pop(&file->state.undo.redo); + }break; } - + if (history_mode != hist_forward){ if (step.type == ED_UNDO || step.type == ED_REDO){ if (file->state.undo.current_block_normal){ @@ -1677,7 +1665,7 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step file->state.undo.current_block_normal = !file->state.undo.current_block_normal; } } - + if (history_mode == hist_normal){ file->state.undo.edit_history_cursor = file->state.undo.history.edit_count; } @@ -1700,8 +1688,8 @@ debug_step_match(Edit_Step a, Edit_Step b){ inline void file_pre_edit_maintenance(System_Functions *system, - General_Memory *general, - Editing_File *file){ + General_Memory *general, + Editing_File *file){ if (file->state.still_lexing){ system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); if (file->state.swap_stack.tokens){ @@ -1728,65 +1716,66 @@ struct Cursor_Fix_Descriptor{ internal void file_edit_cursor_fix(System_Functions *system, - Partition *part, General_Memory *general, - Editing_File *file, Editing_Layout *layout, - Cursor_Fix_Descriptor desc){ + Partition *part, General_Memory *general, + Editing_File *file, Editing_Layout *layout, + Cursor_Fix_Descriptor desc){ + Full_Cursor temp_cursor; - File_View *current_view; Temp_Memory cursor_temp = begin_temp_memory(part); i32 cursor_max = layout->panel_max_count * 2; Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); - + f32 y_offset = 0, y_position = 0; i32 cursor_count = 0; - i32 panel_count = layout->panel_count; - Panel *current_panel = layout->panels; - for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - current_view = view_to_file_view(current_panel->view); - if (current_view && current_view->file == file){ - view_measure_wraps(system, general, current_view); - write_cursor_with_index(cursors, &cursor_count, current_view->cursor.pos); - write_cursor_with_index(cursors, &cursor_count, current_view->mark - 1); - write_cursor_with_index(cursors, &cursor_count, current_view->scroll_i - 1); + + File_View *view; + Panel *panel, *used_panels; + used_panels = &layout->used_sentinel; + + for (dll_items(panel, used_panels)){ + view = view_to_file_view(panel->view); + if (view->file == file){ + view_measure_wraps(system, general, view); + write_cursor_with_index(cursors, &cursor_count, view->cursor.pos); + write_cursor_with_index(cursors, &cursor_count, view->mark - 1); + write_cursor_with_index(cursors, &cursor_count, view->scroll_i - 1); } } - + if (cursor_count > 0){ buffer_sort_cursors(cursors, cursor_count); if (desc.is_batch){ buffer_batch_edit_update_cursors(cursors, cursor_count, - desc.batch, desc.batch_size); + desc.batch, desc.batch_size); } else{ buffer_update_cursors(cursors, cursor_count, - desc.start, desc.end, - desc.shift_amount + (desc.end - desc.start)); - + desc.start, desc.end, + desc.shift_amount + (desc.end - desc.start)); } buffer_unsort_cursors(cursors, cursor_count); cursor_count = 0; - current_panel = layout->panels; - for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - current_view = view_to_file_view(current_panel->view); - if (current_view && current_view->file == file){ - view_cursor_move(current_view, cursors[cursor_count++].pos); - current_view->preferred_x = view_get_cursor_x(current_view); + for (dll_items(panel, used_panels)){ + view = view_to_file_view(panel->view); + if (view && view->file == file){ + view_cursor_move(view, cursors[cursor_count++].pos); + view->preferred_x = view_get_cursor_x(view); - current_view->mark = cursors[cursor_count++].pos + 1; - current_view->scroll_i = cursors[cursor_count++].pos + 1; - temp_cursor = view_compute_cursor_from_pos(current_view, current_view->scroll_i); - y_offset = MOD(current_view->scroll_y, current_view->font_height); + view->mark = cursors[cursor_count++].pos + 1; + view->scroll_i = cursors[cursor_count++].pos + 1; + temp_cursor = view_compute_cursor_from_pos(view, view->scroll_i); + y_offset = MOD(view->scroll_y, view->font_height); - if (current_view->unwrapped_lines){ + if (view->unwrapped_lines){ y_position = temp_cursor.unwrapped_y + y_offset; - current_view->target_y += (y_position - current_view->scroll_y); - current_view->scroll_y = y_position; + view->target_y += (y_position - view->scroll_y); + view->scroll_y = y_position; } else{ y_position = temp_cursor.wrapped_y + y_offset; - current_view->target_y += (y_position - current_view->scroll_y); - current_view->scroll_y = y_position; + view->target_y += (y_position - view->scroll_y); + view->scroll_y = y_position; } } } @@ -1797,16 +1786,15 @@ file_edit_cursor_fix(System_Functions *system, internal void file_do_single_edit(System_Functions *system, - Mem_Options *mem, Editing_File *file, - Editing_Layout *layout, Edit_Spec spec, History_Mode history_mode){ + Mem_Options *mem, Editing_File *file, + Editing_Layout *layout, Edit_Spec spec, History_Mode history_mode){ ProfileMomentFunction(); - + // NOTE(allen): fixing stuff beforewards???? file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode); file_pre_edit_maintenance(system, &mem->general, file); // NOTE(allen): actual text replacement -#if BUFFER_EXPERIMENT_SCALPEL <= 3 i32 shift_amount = 0; General_Memory *general = &mem->general; Partition *part = &mem->part; @@ -1817,11 +1805,11 @@ file_do_single_edit(System_Functions *system, i32 str_len = spec.step.edit.len; i32 scratch_size = partition_remaining(part); - + Assert(scratch_size > 0); i32 request_amount = 0; while (buffer_replace_range(&file->state.buffer, start, end, str, str_len, &shift_amount, - part->base + part->pos, scratch_size, &request_amount)){ + part->base + part->pos, scratch_size, &request_amount)){ void *new_data = 0; if (request_amount > 0){ new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); @@ -1829,69 +1817,66 @@ file_do_single_edit(System_Functions *system, void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); if (old_data) general_memory_free(general, old_data); } - + Buffer_Type *buffer = &file->state.buffer; i32 line_start = buffer_get_line_index(&file->state.buffer, start); i32 line_end = buffer_get_line_index(&file->state.buffer, end); i32 replaced_line_count = line_end - line_start; i32 new_line_count = buffer_count_newlines(&file->state.buffer, start, start+str_len); i32 line_shift = new_line_count - replaced_line_count; - + Render_Font *font = get_font_info(file->settings.set, file->state.font_id)->font; - + file_grow_starts_widths_as_needed(general, buffer, line_shift); buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount); buffer_remeasure_widths(buffer, font->advance_data, line_start, line_end, line_shift); + + Panel *panel, *used_panels; + used_panels = &layout->used_sentinel; - i32 panel_count = layout->panel_count; - Panel *current_panel = layout->panels; - for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - File_View *current_view = view_to_file_view(current_panel->view); - if (current_view && current_view->file == file){ - view_measure_wraps(system, general, current_view); + for (dll_items(panel, used_panels)){ + File_View *view = view_to_file_view(panel->view); + if (view->file == file){ + view_measure_wraps(system, general, view); } } -#endif - + #if BUFFER_EXPERIMENT_SCALPEL <= 0 // NOTE(allen): fixing stuff afterwards if (file->settings.tokens_exist) file_relex_parallel(system, mem, file, start, end, shift_amount); #endif -#if BUFFER_EXPERIMENT_SCALPEL <= 3 Cursor_Fix_Descriptor desc = {}; desc.start = start; desc.end = end; desc.shift_amount = shift_amount; - + file_edit_cursor_fix(system, part, general, - file, layout, desc); - -#endif + file, layout, desc); } internal void view_do_white_batch_edit(System_Functions *system, Mem_Options *mem, File_View *view, Editing_File *file, - Editing_Layout *layout, Edit_Spec spec, History_Mode history_mode){ + Editing_Layout *layout, Edit_Spec spec, History_Mode history_mode){ if (view->locked) return; #if BUFFER_EXPERIMENT_SCALPEL <= 3 Assert(file); ProfileMomentFunction(); - + // NOTE(allen): fixing stuff "beforewards"???? Assert(spec.str == 0); file_update_history_before_edit(mem, file, spec.step, 0, history_mode); file_pre_edit_maintenance(system, &mem->general, file); - + // NOTE(allen): actual text replacement General_Memory *general = &mem->general; Partition *part = &mem->part; - + u8 *str_base = file->state.undo.children.strings; i32 batch_size = spec.step.child_count; Buffer_Edit *batch = file->state.undo.children.edits + spec.step.first_child; - + Assert(spec.step.first_child < file->state.undo.children.edit_count); Assert(batch_size >= 0); @@ -1899,7 +1884,7 @@ view_do_white_batch_edit(System_Functions *system, Mem_Options *mem, File_View * Buffer_Batch_State state = {}; i32 request_amount; while (buffer_batch_edit_step(&state, &file->state.buffer, batch, (char*)str_base, batch_size, - part->base + part->pos, scratch_size, &request_amount)){ + part->base + part->pos, scratch_size, &request_amount)){ void *new_data = 0; if (request_amount > 0){ new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); @@ -1907,23 +1892,23 @@ view_do_white_batch_edit(System_Functions *system, Mem_Options *mem, File_View * void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); if (old_data) general_memory_free(general, old_data); } - + // NOTE(allen): token fixing if (file->state.tokens_complete){ Cpp_Token_Stack tokens = file->state.token_stack; Cpp_Token *token = tokens.tokens; Cpp_Token *end_token = tokens.tokens + tokens.count; - + Buffer_Edit *edit = batch; Buffer_Edit *end_edit = batch + batch_size; - + i32 shift_amount = 0; i32 local_shift = 0; - + for (; token < end_token && edit < end_edit; ++edit){ local_shift = (edit->len - (edit->end - edit->start)); for (; token->start < edit->start && edit->start < token->start + token->size && - token < end_token; ++token){ + token < end_token; ++token){ token->size += local_shift; } for (; token->start < edit->start && token < end_token; ++token){ @@ -1935,7 +1920,7 @@ view_do_white_batch_edit(System_Functions *system, Mem_Options *mem, File_View * token->start += shift_amount; } } - + // NOTE(allen): meta data { Buffer_Measure_Starts state = {}; @@ -1944,16 +1929,14 @@ view_do_white_batch_edit(System_Functions *system, Mem_Options *mem, File_View * if (font) advance_data = font->advance_data; buffer_measure_starts_widths(&state, &file->state.buffer, advance_data); } - + // NOTE(allen): cursor fixing Cursor_Fix_Descriptor desc = {}; desc.is_batch = 1; desc.batch = batch; desc.batch_size = batch_size; - - file_edit_cursor_fix(system, part, general, - file, layout, desc); - + + file_edit_cursor_fix(system, part, general, file, layout, desc); #endif } @@ -1974,8 +1957,8 @@ file_replace_range(System_Functions *system, inline void view_replace_range(System_Functions *system, - Mem_Options *mem, File_View *view, Editing_Layout *layout, - i32 start, i32 end, char *str, i32 len, i32 next_cursor){ + Mem_Options *mem, File_View *view, Editing_Layout *layout, + i32 start, i32 end, char *str, i32 len, i32 next_cursor){ if (view->locked) return; Edit_Spec spec = {}; spec.step.type = ED_NORMAL; @@ -2001,29 +1984,29 @@ view_post_paste_effect(File_View *view, i32 ticks, i32 start, i32 size, u32 colo internal void view_undo_redo(System_Functions *system, - Mem_Options *mem, Editing_Layout *layout, File_View *view, Editing_File *file, - Edit_Stack *stack, Edit_Type expected_type){ + Mem_Options *mem, Editing_Layout *layout, File_View *view, Editing_File *file, + Edit_Stack *stack, Edit_Type expected_type){ if (view->locked) return; if (file && stack->edit_count > 0){ Edit_Step step = stack->edits[stack->edit_count-1]; - + Assert(step.type == expected_type); - + Edit_Spec spec = {}; spec.step = step; - + if (step.child_count == 0){ spec.step.edit.str_start = 0; spec.str = stack->strings + step.edit.str_start; - + file_do_single_edit(system, mem, file, layout, spec, hist_normal); if (expected_type == ED_UNDO) view_cursor_move(view, step.pre_pos); else view_cursor_move(view, step.post_pos); view->mark = view->cursor.pos; - + view_post_paste_effect(view, 10, step.edit.start, step.edit.len, - view->style->main.undo_color); + view->style->main.undo_color); } else{ TentativeAssert(spec.step.special_type == 1); @@ -2056,9 +2039,9 @@ write_data(u8 *ptr, void *x, i32 size){ internal void file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ if (!file->state.undo.undo.edits) return; - + i32 size = 0; - + size += sizeof(i32); size += file->state.undo.undo.edit_count*sizeof(Edit_Step); size += sizeof(i32); @@ -2067,7 +2050,7 @@ file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file size += file->state.undo.history.edit_count*sizeof(Edit_Step); size += sizeof(i32); size += file->state.undo.children.edit_count*sizeof(Buffer_Edit); - + size += sizeof(i32); size += file->state.undo.undo.size; size += sizeof(i32); @@ -2091,12 +2074,12 @@ file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file curs = write_data(curs, &file->state.undo.redo.size, 4); curs = write_data(curs, &file->state.undo.history.size, 4); curs = write_data(curs, &file->state.undo.children.size, 4); - + curs = write_data(curs, file->state.undo.undo.edits, sizeof(Edit_Step)*file->state.undo.undo.edit_count); curs = write_data(curs, file->state.undo.redo.edits, sizeof(Edit_Step)*file->state.undo.redo.edit_count); curs = write_data(curs, file->state.undo.history.edits, sizeof(Edit_Step)*file->state.undo.history.edit_count); curs = write_data(curs, file->state.undo.children.edits, sizeof(Buffer_Edit)*file->state.undo.children.edit_count); - + curs = write_data(curs, file->state.undo.undo.strings, file->state.undo.undo.size); curs = write_data(curs, file->state.undo.redo.strings, file->state.undo.redo.size); curs = write_data(curs, file->state.undo.history.strings, file->state.undo.history.size); @@ -2112,9 +2095,9 @@ internal void view_history_step(System_Functions *system, Mem_Options *mem, Editing_Layout *layout, File_View *view, History_Mode history_mode){ if (view->locked) return; Assert(history_mode != hist_normal); - + Editing_File *file = view->file; - + b32 do_history_step = 0; Edit_Step step = {}; if (history_mode == hist_backward){ @@ -2132,25 +2115,25 @@ view_history_step(System_Functions *system, Mem_Options *mem, Editing_Layout *la do_history_step = 1; } } - + if (do_history_step){ Edit_Spec spec; spec.step = step; - + if (spec.step.child_count == 0){ spec.step.edit.str_start = 0; spec.str = file->state.undo.history.strings + step.edit.str_start; - + file_do_single_edit(system, mem, file, layout, spec, history_mode); - + switch (spec.step.type){ - case ED_NORMAL: - case ED_REDO: + case ED_NORMAL: + case ED_REDO: view_cursor_move(view, step.post_pos); break; - - case ED_REVERSE_NORMAL: - case ED_UNDO: + + case ED_REVERSE_NORMAL: + case ED_UNDO: view_cursor_move(view, step.pre_pos); break; } @@ -2167,66 +2150,66 @@ view_history_step(System_Functions *system, Mem_Options *mem, Editing_Layout *la internal i32 view_find_end_of_line(File_View *view, i32 pos){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file; - char *data = file->state.buffer.data; - while (pos < file->state.buffer.size && data[pos] != '\n') ++pos; - if (pos > file->state.buffer.size) pos = file->state.buffer.size; + Editing_File *file = view->file; + char *data = file->state.buffer.data; + while (pos < file->state.buffer.size && data[pos] != '\n') ++pos; + if (pos > file->state.buffer.size) pos = file->state.buffer.size; #endif - return pos; + return pos; } internal i32 view_find_beginning_of_line(File_View *view, i32 pos){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file; - char *data = file->state.buffer.data; - if (pos > 0){ - --pos; - while (pos > 0 && data[pos] != '\n') --pos; - if (pos != 0) ++pos; - } + Editing_File *file = view->file; + char *data = file->state.buffer.data; + if (pos > 0){ + --pos; + while (pos > 0 && data[pos] != '\n') --pos; + if (pos != 0) ++pos; + } #endif - return pos; + return pos; } internal i32 view_find_beginning_of_next_line(File_View *view, i32 pos){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file; - char *data = file->state.buffer.data; - while (pos < file->state.buffer.size && - !starts_new_line(data[pos])){ - ++pos; - } - if (pos < file->state.buffer.size){ - ++pos; - } + Editing_File *file = view->file; + char *data = file->state.buffer.data; + while (pos < file->state.buffer.size && + !starts_new_line(data[pos])){ + ++pos; + } + if (pos < file->state.buffer.size){ + ++pos; + } #endif - return pos; + return pos; } internal String* working_set_next_clipboard_string(General_Memory *general, Working_Set *working, i32 str_size){ - String *result = 0; - i32 clipboard_current = working->clipboard_current; - if (working->clipboard_size == 0){ - clipboard_current = 0; - working->clipboard_size = 1; - } - else{ - ++clipboard_current; - if (clipboard_current >= working->clipboard_max_size){ - clipboard_current = 0; - } - else if (working->clipboard_size <= clipboard_current){ - working->clipboard_size = clipboard_current+1; - } - } - result = &working->clipboards[clipboard_current]; - working->clipboard_current = clipboard_current; - working->clipboard_rolling = clipboard_current; + String *result = 0; + i32 clipboard_current = working->clipboard_current; + if (working->clipboard_size == 0){ + clipboard_current = 0; + working->clipboard_size = 1; + } + else{ + ++clipboard_current; + if (clipboard_current >= working->clipboard_max_size){ + clipboard_current = 0; + } + else if (working->clipboard_size <= clipboard_current){ + working->clipboard_size = clipboard_current+1; + } + } + result = &working->clipboards[clipboard_current]; + working->clipboard_current = clipboard_current; + working->clipboard_rolling = clipboard_current; char *new_str; - if (result->str){ + if (result->str){ new_str = (char*)general_memory_reallocate(general, result->str, result->size, str_size); } else{ @@ -2234,33 +2217,33 @@ working_set_next_clipboard_string(General_Memory *general, Working_Set *working, } // TODO(allen): What if new_str == 0? *result = make_string(new_str, 0, str_size); - return result; + return result; } internal String* working_set_clipboard_head(Working_Set *working){ - String *result = 0; - if (working->clipboard_size > 0){ - i32 clipboard_index = working->clipboard_current; - working->clipboard_rolling = clipboard_index; - result = &working->clipboards[clipboard_index]; - } - return result; + String *result = 0; + if (working->clipboard_size > 0){ + i32 clipboard_index = working->clipboard_current; + working->clipboard_rolling = clipboard_index; + result = &working->clipboards[clipboard_index]; + } + return result; } internal String* working_set_clipboard_roll_down(Working_Set *working){ - String *result = 0; - if (working->clipboard_size > 0){ - i32 clipboard_index = working->clipboard_rolling; - --clipboard_index; - if (clipboard_index < 0){ - clipboard_index = working->clipboard_size-1; - } - working->clipboard_rolling = clipboard_index; - result = &working->clipboards[clipboard_index]; - } - return result; + String *result = 0; + if (working->clipboard_size > 0){ + i32 clipboard_index = working->clipboard_rolling; + --clipboard_index; + if (clipboard_index < 0){ + clipboard_index = working->clipboard_size-1; + } + working->clipboard_rolling = clipboard_index; + result = &working->clipboards[clipboard_index]; + } + return result; } internal void @@ -2274,24 +2257,24 @@ clipboard_copy(System_Functions *system, General_Memory *general, Working_Set *w internal Edit_Spec file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_pos, - Buffer_Edit *edits, char *str_base, i32 str_size, - Buffer_Edit *inverse_array, char *inv_str, i32 inv_max, - i32 edit_count){ + Buffer_Edit *edits, char *str_base, i32 str_size, + Buffer_Edit *inverse_array, char *inv_str, i32 inv_max, + i32 edit_count){ General_Memory *general = &mem->general; - + i32 inv_str_pos = 0; Buffer_Invert_Batch state = {}; if (buffer_invert_batch(&state, &file->state.buffer, edits, edit_count, - inverse_array, inv_str, &inv_str_pos, inv_max)) + inverse_array, inv_str, &inv_str_pos, inv_max)) Assert(0); - + i32 first_child = undo_children_push(general, &file->state.undo.children, - edits, edit_count, (u8*)(str_base), str_size); + edits, edit_count, (u8*)(str_base), str_size); i32 inverse_first_child = undo_children_push(general, &file->state.undo.children, - inverse_array, edit_count, (u8*)(inv_str), inv_str_pos); - + inverse_array, edit_count, (u8*)(inv_str), inv_str_pos); + Edit_Spec spec = {}; spec.step.type = ED_NORMAL; spec.step.first_child = first_child; @@ -2301,7 +2284,7 @@ file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_po spec.step.inverse_child_count = edit_count; spec.step.pre_pos = cursor_pos; spec.step.post_pos = cursor_pos; - + return spec; } @@ -2313,10 +2296,10 @@ view_clean_whitespace(System_Functions *system, Mem_Options *mem, File_View *vie i32 line_count = file->state.buffer.line_count; i32 edit_max = line_count * 2; i32 edit_count = 0; - + Temp_Memory temp = begin_temp_memory(part); Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); - + char *str_base = (char*)part->base + part->pos; i32 str_size = 0; for (i32 line_i = 0; line_i < line_count; ++line_i){ @@ -2326,10 +2309,10 @@ view_clean_whitespace(System_Functions *system, Mem_Options *mem, File_View *vie b32 all_space = 0; i32 hard_start = buffer_find_hard_start(&file->state.buffer, start, &all_whitespace, &all_space, - &preferred_indentation, 4); - + &preferred_indentation, 4); + if (all_whitespace) preferred_indentation = 0; - + if ((all_whitespace && hard_start > start) || !all_space){ Buffer_Edit new_edit; new_edit.str_start = str_size; @@ -2343,29 +2326,29 @@ view_clean_whitespace(System_Functions *system, Mem_Options *mem, File_View *vie } Assert(edit_count <= edit_max); } - + if (edit_count > 0){ Assert(buffer_batch_debug_sort_check(edits, edit_count)); - + // NOTE(allen): computing edit spec, doing batch edit Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, edit_count); Assert(inverse_array); - + char *inv_str = (char*)part->base + part->pos; Edit_Spec spec = file_compute_whitespace_edit(mem, file, view->cursor.pos, edits, str_base, str_size, - inverse_array, inv_str, part->max - part->pos, edit_count); - + inverse_array, inv_str, part->max - part->pos, edit_count); + view_do_white_batch_edit(system, mem, view, file, layout, spec, hist_normal); } - + end_temp_memory(temp); } internal void view_auto_tab_tokens(System_Functions *system, - Mem_Options *mem, File_View *view, Editing_Layout *layout, - i32 start, i32 end, b32 empty_blank_lines){ + Mem_Options *mem, File_View *view, Editing_Layout *layout, + i32 start, i32 end, b32 empty_blank_lines){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 Editing_File *file = view->file; Assert(file && !file->state.is_dummy); @@ -2373,22 +2356,22 @@ view_auto_tab_tokens(System_Functions *system, Buffer *buffer = &file->state.buffer; Cpp_Token_Stack tokens = file->state.token_stack; Assert(tokens.tokens); - + i32 line_start = buffer_get_line_index(buffer, start); i32 line_end = buffer_get_line_index(buffer, end) + 1; - + i32 edit_max = (line_end - line_start) * 2; i32 edit_count = 0; - + i32 indent_mark_count = line_end - line_start; - + Temp_Memory temp = begin_temp_memory(part); i32 *indent_marks = push_array(part, i32, indent_mark_count); { i32 current_indent = 0; i32 token_i; Cpp_Token *token, *self_token; - + { i32 start_pos = file->state.buffer.line_starts[line_start]; Cpp_Get_Token_Result result = cpp_get_token(&tokens, start_pos); @@ -2396,17 +2379,17 @@ view_auto_tab_tokens(System_Functions *system, if (result.in_whitespace) token_i += 1; self_token = tokens.tokens + token_i; } - + i32 line = line_start - 1; for (; line >= 0; --line){ i32 start = file->state.buffer.line_starts[line]; b32 all_whitespace = 0; b32 all_space = 0; buffer_find_hard_start(&file->state.buffer, start, - &all_whitespace, &all_space, ¤t_indent, 4); + &all_whitespace, &all_space, ¤t_indent, 4); if (!all_whitespace) break; } - + if (line < 0){ token_i = 0; token = tokens.tokens + token_i; @@ -2417,13 +2400,13 @@ view_auto_tab_tokens(System_Functions *system, token_i = result.token_index; if (result.in_whitespace) token_i += 1; token = tokens.tokens + token_i; - + while (token >= tokens.tokens && - token->flags & CPP_TFLAG_PP_DIRECTIVE || - token->flags & CPP_TFLAG_PP_BODY){ + token->flags & CPP_TFLAG_PP_DIRECTIVE || + token->flags & CPP_TFLAG_PP_BODY){ --token; } - + if (token < tokens.tokens){ ++token; current_indent = 0; @@ -2434,20 +2417,20 @@ view_auto_tab_tokens(System_Functions *system, b32 all_whitespace = 0; b32 all_space = 0; buffer_find_hard_start(&file->state.buffer, start, - &all_whitespace, &all_space, ¤t_indent, 4); + &all_whitespace, &all_space, ¤t_indent, 4); Assert(!all_whitespace); } } - + indent_marks -= line_start; i32 line_i = line_start; i32 next_line_start = file->state.buffer.line_starts[line_i]; switch (token->type){ - case CPP_TOKEN_BRACKET_OPEN: current_indent += 4; break; - case CPP_TOKEN_PARENTHESE_OPEN: current_indent += 4; break; - case CPP_TOKEN_BRACE_OPEN: current_indent += 4; break; + case CPP_TOKEN_BRACKET_OPEN: current_indent += 4; break; + case CPP_TOKEN_PARENTHESE_OPEN: current_indent += 4; break; + case CPP_TOKEN_BRACE_OPEN: current_indent += 4; break; } - + Cpp_Token *prev_token = token; ++token; for (; line_i < line_end; ++token_i, ++token){ @@ -2456,7 +2439,7 @@ view_auto_tab_tokens(System_Functions *system, next_line_start = file->state.buffer.line_starts[line_i+1]; i32 this_indent; if (prev_token && prev_token->type == CPP_TOKEN_COMMENT && - prev_token->start <= this_line_start && prev_token->start + prev_token->size > this_line_start){ + prev_token->start <= this_line_start && prev_token->start + prev_token->size > this_line_start){ this_indent = -1; } else{ @@ -2465,20 +2448,20 @@ view_auto_tab_tokens(System_Functions *system, if (token->flags & CPP_TFLAG_PP_DIRECTIVE) this_indent = 0; else{ switch (token->type){ - case CPP_TOKEN_BRACKET_CLOSE: this_indent -= 4; break; - case CPP_TOKEN_PARENTHESE_CLOSE: this_indent -= 4; break; - case CPP_TOKEN_BRACE_CLOSE: this_indent -= 4; break; - case CPP_TOKEN_BRACE_OPEN: break; - default: + case CPP_TOKEN_BRACKET_CLOSE: this_indent -= 4; break; + case CPP_TOKEN_PARENTHESE_CLOSE: this_indent -= 4; break; + case CPP_TOKEN_BRACE_CLOSE: this_indent -= 4; break; + case CPP_TOKEN_BRACE_OPEN: break; + default: if (current_indent > 0 && prev_token){ if (!(prev_token->flags & CPP_TFLAG_PP_BODY || - prev_token->flags & CPP_TFLAG_PP_DIRECTIVE)){ + prev_token->flags & CPP_TFLAG_PP_DIRECTIVE)){ switch (prev_token->type){ - case CPP_TOKEN_BRACKET_OPEN: case CPP_TOKEN_PARENTHESE_OPEN: - case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE: - case CPP_TOKEN_SEMICOLON: case CPP_TOKEN_COLON: break; - case CPP_TOKEN_COMMA: case CPP_TOKEN_COMMENT: break; - default: this_indent += 4; + case CPP_TOKEN_BRACKET_OPEN: case CPP_TOKEN_PARENTHESE_OPEN: + case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE: + case CPP_TOKEN_SEMICOLON: case CPP_TOKEN_COLON: break; + case CPP_TOKEN_COMMA: case CPP_TOKEN_COMMENT: break; + default: this_indent += 4; } } } @@ -2490,21 +2473,21 @@ view_auto_tab_tokens(System_Functions *system, indent_marks[line_i] = this_indent; ++line_i; } - + switch (token->type){ - case CPP_TOKEN_BRACKET_OPEN: current_indent += 4; break; - case CPP_TOKEN_BRACKET_CLOSE: current_indent -= 4; break; - case CPP_TOKEN_PARENTHESE_OPEN: current_indent += 4; break; - case CPP_TOKEN_PARENTHESE_CLOSE: current_indent -= 4; break; - case CPP_TOKEN_BRACE_OPEN: current_indent += 4; break; - case CPP_TOKEN_BRACE_CLOSE: current_indent -= 4; break; + case CPP_TOKEN_BRACKET_OPEN: current_indent += 4; break; + case CPP_TOKEN_BRACKET_CLOSE: current_indent -= 4; break; + case CPP_TOKEN_PARENTHESE_OPEN: current_indent += 4; break; + case CPP_TOKEN_PARENTHESE_CLOSE: current_indent -= 4; break; + case CPP_TOKEN_BRACE_OPEN: current_indent += 4; break; + case CPP_TOKEN_BRACE_CLOSE: current_indent -= 4; break; } prev_token = token; } } - + Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); - + char *str_base = (char*)part->base + part->pos; i32 str_size = 0; for (i32 line_i = line_start; line_i < line_end; ++line_i){ @@ -2515,12 +2498,12 @@ view_auto_tab_tokens(System_Functions *system, b32 all_space = 0; i32 hard_start = buffer_find_hard_start(&file->state.buffer, start, &all_whitespace, &all_space, - &preferred_indentation, 4); + &preferred_indentation, 4); correct_indentation = indent_marks[line_i]; if (all_whitespace && empty_blank_lines) correct_indentation = 0; if (correct_indentation == -1) correct_indentation = preferred_indentation; - + if ((all_whitespace && hard_start > start) || !all_space || correct_indentation != preferred_indentation){ Buffer_Edit new_edit; new_edit.str_start = str_size; @@ -2532,25 +2515,25 @@ view_auto_tab_tokens(System_Functions *system, new_edit.end = hard_start; edits[edit_count++] = new_edit; } - + Assert(edit_count <= edit_max); } - + if (edit_count > 0){ Assert(buffer_batch_debug_sort_check(edits, edit_count)); - + // NOTE(allen): computing edit spec, doing batch edit Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, edit_count); Assert(inverse_array); - + char *inv_str = (char*)part->base + part->pos; Edit_Spec spec = file_compute_whitespace_edit(mem, file, view->cursor.pos, edits, str_base, str_size, - inverse_array, inv_str, part->max - part->pos, edit_count); - + inverse_array, inv_str, part->max - part->pos, edit_count); + view_do_white_batch_edit(system, mem, view, file, layout, spec, hist_normal); } - + { b32 all_whitespace = 0; b32 all_space = 0; @@ -2559,10 +2542,10 @@ view_auto_tab_tokens(System_Functions *system, i32 hard_start = buffer_find_hard_start( &file->state.buffer, start, &all_whitespace, &all_space, &preferred_indentation, 4); - + view_cursor_move(view, hard_start); } - + end_temp_memory(temp); #endif } @@ -2574,10 +2557,10 @@ struct Get_Link_Result{ internal u32* style_get_color(Style *style, Cpp_Token token){ - u32 *result; + u32 *result; if (token.flags & CPP_TFLAG_IS_KEYWORD){ if (token.type == CPP_TOKEN_BOOLEAN_CONSTANT){ - result = &style->main.bool_constant_color; + result = &style->main.bool_constant_color; } else{ result = &style->main.keyword_color; @@ -2588,71 +2571,38 @@ style_get_color(Style *style, Cpp_Token token){ } else{ switch (token.type){ - case CPP_TOKEN_COMMENT: - result = &style->main.comment_color; - break; - - case CPP_TOKEN_STRING_CONSTANT: - result = &style->main.str_constant_color; + case CPP_TOKEN_COMMENT: + result = &style->main.comment_color; break; - - case CPP_TOKEN_CHARACTER_CONSTANT: - result = &style->main.char_constant_color; - break; - - case CPP_TOKEN_INTEGER_CONSTANT: - result = &style->main.int_constant_color; - break; - - case CPP_TOKEN_FLOATING_CONSTANT: - result = &style->main.float_constant_color; - break; - - case CPP_TOKEN_INCLUDE_FILE: - result = &style->main.include_color; - break; - - default: - result = &style->main.default_color; - } - } - return result; -} -internal bool32 -smooth_camera_step(real32 *target, real32 *current, real32 *vel, real32 S, real32 T){ - bool32 result = 0; - real32 targ = *target; - real32 curr = *current; - real32 v = *vel; - if (curr != targ){ - if (curr > targ - .1f && curr < targ + .1f){ - curr = targ; - v = 1.f; + case CPP_TOKEN_STRING_CONSTANT: + result = &style->main.str_constant_color; + break; + + case CPP_TOKEN_CHARACTER_CONSTANT: + result = &style->main.char_constant_color; + break; + + case CPP_TOKEN_INTEGER_CONSTANT: + result = &style->main.int_constant_color; + break; + + case CPP_TOKEN_FLOATING_CONSTANT: + result = &style->main.float_constant_color; + break; + + case CPP_TOKEN_INCLUDE_FILE: + result = &style->main.include_color; + break; + + default: + result = &style->main.default_color; } - else{ - real32 L = lerp(curr, T, targ); - - i32 sign = (targ > curr) - (targ < curr); - real32 V = curr + sign*v; - - if (sign > 0) curr = Min(L, V); - else curr = Max(L, V); - - if (curr == V){ - v *= S; - } - } - - *target = targ; - *current = curr; - *vel = v; - result = 1; } return result; } -inline real32 +inline f32 view_compute_max_target_y(i32 lowest_line, i32 line_height, real32 view_height){ real32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f; return max_target_y; @@ -2683,9 +2633,9 @@ remeasure_file_view(System_Functions *system, View *view_, i32_Rect rect){ internal void undo_shit(System_Functions *system, File_View *view, UI_State *state, UI_Layout *layout, i32 total_count, i32 undo_count, i32 scrub_max){ - + Editing_File *file = view->file; - + if (view->widget.timeline.undo_line){ if (do_button(1, state, layout, "- Undo", 1)){ view->widget.timeline.undo_line = 0; @@ -2745,7 +2695,7 @@ draw_file_view_queries(File_View *view, UI_State *state, UI_Layout *layout){ Query_Slot *slot; Query_Bar *bar; i32 i = 1; - + for (slot = view->query_set.used_slot; slot != 0; slot = slot->next){ wid = make_id(state, i++); bar = slot->query_bar; @@ -2782,9 +2732,10 @@ view_show_interactive(System_Functions *system, File_View *fview, Command_Map *g fview->action = action; fview->interaction = interaction; fview->finished = 0; - + copy(&fview->query, query); - + fview->dest.size = 0; + hot_directory_clean_end(fview->hot_directory); hot_directory_reload(system, fview->hot_directory, fview->working_set); } @@ -2819,31 +2770,31 @@ interactive_view_complete(File_View *view){ case IAct_Open: delayed_open(view->delay, view->hot_directory->string, panel); break; - + case IAct_Save_As: delayed_save_as(view->delay, view->hot_directory->string, panel); break; - + case IAct_New: delayed_new(view->delay, view->hot_directory->string, panel); break; - + case IAct_Switch: delayed_switch(view->delay, view->dest, panel); break; - + case IAct_Kill: delayed_try_kill(view->delay, view->dest, panel); break; - + case IAct_Sure_To_Kill: switch (view->user_action){ case 0: delayed_kill(view->delay, view->dest, panel); break; - + case 1:break; - + case 2: // TODO(allen): This is fishy! What if the save doesn't happen this time around? // We need to ensure delayed acts happen in order I think. @@ -2938,267 +2889,268 @@ update_highlighting(File_View *view){ internal b32 theme_library_shit(System_Functions *system, Exchange *exchange, File_View *view, UI_State *state, UI_Layout *layout){ - + Mem_Options *mem = view->mem; - + i32 result = 0; - + Library_UI ui; ui.state = state; ui.layout = layout; - + ui.fonts = view->font_set; ui.hot_directory = view->hot_directory; ui.styles = view->styles; - + Color_View_Mode mode = view->color_mode; - + i32_Rect bar_rect = ui.layout->rect; bar_rect.x0 = bar_rect.x1 - 20; do_scroll_bar(ui.state, bar_rect); - + ui.layout->y -= FLOOR32(view->ui_state.view_y); ui.layout->rect.x1 -= 20; - + b32 case_sensitive = 0; - + switch (mode){ - case CV_Mode_Library: - { - do_label(ui.state, ui.layout, literal("Current Theme - Click to Edit")); - if (do_style_preview(&ui, view->style)){ - view->color_mode = CV_Mode_Adjusting; - view->ui_state.selected = {}; - ui.state->view_y = 0; - result = 1; - } - - begin_row(ui.layout, 3); - if (ui.state->style->name.size >= 1){ - if (do_button(-2, ui.state, ui.layout, "Save", 2)){ - style_library_add(ui.styles, ui.state->style); - } - } - else{ - do_button(-2, ui.state, ui.layout, "~Need's Name~", 2); - } - if (do_button(-3, ui.state, ui.layout, "Import", 2)){ - view->color_mode = CV_Mode_Import_File; - hot_directory_clean_end(view->hot_directory); - hot_directory_reload(system, view->hot_directory, view->working_set); - } - if (do_button(-4, ui.state, ui.layout, "Export", 2)){ - view->color_mode = CV_Mode_Export; - hot_directory_clean_end(view->hot_directory); - hot_directory_reload(system, view->hot_directory, view->working_set); - memset(view->import_export_check, 0, sizeof(view->import_export_check)); - } - - do_label(ui.state, ui.layout, literal("Theme Library - Click to Select")); - - i32 style_count = view->styles->count; - Style *style = view->styles->styles; - for (i32 i = 0; i < style_count; ++i, ++style){ - if (do_style_preview(&ui, style)){ - style_copy(view->style, style); + case CV_Mode_Library: + { + do_label(ui.state, ui.layout, literal("Current Theme - Click to Edit")); + if (do_style_preview(&ui, view->style)){ + view->color_mode = CV_Mode_Adjusting; + view->ui_state.selected = {}; + ui.state->view_y = 0; result = 1; } - } - }break; - - case CV_Mode_Import_File: - { - do_label(ui.state, ui.layout, literal("Current Theme")); - do_style_preview(&ui, view->style); - - b32 file_selected = 0; - - do_label(ui.state, ui.layout, literal("Import Which File?")); - begin_row(ui.layout, 2); - if (do_button(-2, ui.state, ui.layout, "*.p4c only", 2, 1, view->p4c_only)){ - view->p4c_only = !view->p4c_only; - } - if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ - view->color_mode = CV_Mode_Library; - } - - b32 new_dir = 0; - if (do_file_list_box(system, ui.state, ui.layout, - ui.hot_directory, view->p4c_only, 1, case_sensitive, - &new_dir, &file_selected, 0)){ - result = 1; - } - if (new_dir){ - hot_directory_reload(system, ui.hot_directory, ui.state->working_set); - } - if (file_selected){ - memset(&view->inspecting_styles, 0, sizeof(Style_Library)); - memset(view->import_export_check, 1, - sizeof(view->import_export_check)); - - view->import_file_id = exchange_request_file(exchange, - view->hot_directory->string.str, - view->hot_directory->string.size); - view->color_mode = CV_Mode_Import_Wait; - - } - }break; - - case CV_Mode_Import_Wait: - { - Style *styles = view->inspecting_styles.styles; - Data file = {}; - i32 file_max = 0; - - i32 count = 0; - i32 max = ArrayCount(view->inspecting_styles.styles); - - AllowLocal(styles); - AllowLocal(max); - - if (exchange_file_ready(exchange, view->import_file_id, - &file.data, &file.size, &file_max)){ - if (file.data){ - if (0 /* && style_library_import(file, ui.fonts, styles, max, &count) */){ - view->color_mode = CV_Mode_Import; + begin_row(ui.layout, 3); + if (ui.state->style->name.size >= 1){ + if (do_button(-2, ui.state, ui.layout, "Save", 2)){ + style_library_add(ui.styles, ui.state->style); } - else{ - view->color_mode = CV_Mode_Library; - } - view->inspecting_styles.count = count; } else{ - Assert(!"this shouldn't happen!"); + do_button(-2, ui.state, ui.layout, "~Need's Name~", 2); } - - exchange_free_file(exchange, view->import_file_id); - } - }break; - - case CV_Mode_Export_File: - { - do_label(ui.state, ui.layout, literal("Current Theme")); - do_style_preview(&ui, view->style); - - b32 file_selected = 0; - - do_label(ui.state, ui.layout, literal("Export File Name?")); - begin_row(ui.layout, 2); - if (do_button(-2, ui.state, ui.layout, "Finish Export", 2)){ - file_selected = 1; - } - if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ - view->color_mode = CV_Mode_Library; - } - - b32 new_dir = 0; - if (do_file_list_box(system, ui.state, ui.layout, - ui.hot_directory, 1, 1, case_sensitive, - &new_dir, &file_selected, ".p4c")){ - result = 1; - } - - if (new_dir){ - hot_directory_reload(system, - ui.hot_directory, ui.state->working_set); - } - if (file_selected){ - i32 count = ui.styles->count; - Temp_Memory temp = begin_temp_memory(&mem->part); - Style **styles = push_array(&mem->part, Style*, sizeof(Style*)*count); - - Style *style = ui.styles->styles; - b8 *export_check = view->import_export_check; - i32 export_count = 0; - for (i32 i = 0; i < count; ++i, ++style){ - if (export_check[i]){ - styles[export_count++] = style; + if (do_button(-3, ui.state, ui.layout, "Import", 2)){ + view->color_mode = CV_Mode_Import_File; + hot_directory_clean_end(view->hot_directory); + hot_directory_reload(system, view->hot_directory, view->working_set); + } + if (do_button(-4, ui.state, ui.layout, "Export", 2)){ + view->color_mode = CV_Mode_Export; + hot_directory_clean_end(view->hot_directory); + hot_directory_reload(system, view->hot_directory, view->working_set); + memset(view->import_export_check, 0, sizeof(view->import_export_check)); + } + + do_label(ui.state, ui.layout, literal("Theme Library - Click to Select")); + + i32 style_count = view->styles->count; + Style *style = view->styles->styles; + for (i32 i = 0; i < style_count; ++i, ++style){ + if (do_style_preview(&ui, style)){ + style_copy(view->style, style); + result = 1; } } - char *data = push_array(&mem->part, char, ui.hot_directory->string.size + 5); - String str = make_string(data, 0, ui.hot_directory->string.size + 5); - copy(&str, ui.hot_directory->string); - append(&str, make_lit_string(".p4c")); - /*style_library_export(system, exchange, mem, &target->font_set, str.str, styles, export_count);*/ - - end_temp_memory(temp); - view->color_mode = CV_Mode_Library; - } - }break; - - case CV_Mode_Import: - { - do_label(ui.state, ui.layout, literal("Current Theme")); - do_style_preview(&ui, view->style); - - i32 style_count = view->inspecting_styles.count; - Style *styles = view->inspecting_styles.styles; - b8 *import_check = view->import_export_check; - - do_label(ui.state, ui.layout, literal("Pack")); - begin_row(ui.layout, 2); - if (do_button(-2, ui.state, ui.layout, "Finish Import", 2)){ + }break; + + case CV_Mode_Import_File: + { + do_label(ui.state, ui.layout, literal("Current Theme")); + do_style_preview(&ui, view->style); + + b32 file_selected = 0; + + do_label(ui.state, ui.layout, literal("Import Which File?")); + begin_row(ui.layout, 2); + if (do_button(-2, ui.state, ui.layout, "*.p4c only", 2, 1, view->p4c_only)){ + view->p4c_only = !view->p4c_only; + } + if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ + view->color_mode = CV_Mode_Library; + } + + b32 new_dir = 0; + if (do_file_list_box(system, ui.state, ui.layout, + ui.hot_directory, view->p4c_only, 1, case_sensitive, + &new_dir, &file_selected, 0)){ + result = 1; + } + + if (new_dir){ + hot_directory_reload(system, ui.hot_directory, ui.state->working_set); + } + if (file_selected){ + memset(&view->inspecting_styles, 0, sizeof(Style_Library)); + memset(view->import_export_check, 1, + sizeof(view->import_export_check)); + + view->import_file_id = exchange_request_file(exchange, + view->hot_directory->string.str, + view->hot_directory->string.size); + view->color_mode = CV_Mode_Import_Wait; + + } + }break; + + case CV_Mode_Import_Wait: + { + Style *styles = view->inspecting_styles.styles; + Data file = {}; + i32 file_max = 0; + + i32 count = 0; + i32 max = ArrayCount(view->inspecting_styles.styles); + + AllowLocal(styles); + AllowLocal(max); + + if (exchange_file_ready(exchange, view->import_file_id, + &file.data, &file.size, &file_max)){ + if (file.data){ + if (0 /* && style_library_import(file, ui.fonts, styles, max, &count) */){ + view->color_mode = CV_Mode_Import; + } + else{ + view->color_mode = CV_Mode_Library; + } + view->inspecting_styles.count = count; + } + else{ + Assert(!"this shouldn't happen!"); + } + + exchange_free_file(exchange, view->import_file_id); + } + }break; + + case CV_Mode_Export_File: + { + do_label(ui.state, ui.layout, literal("Current Theme")); + do_style_preview(&ui, view->style); + + b32 file_selected = 0; + + do_label(ui.state, ui.layout, literal("Export File Name?")); + begin_row(ui.layout, 2); + if (do_button(-2, ui.state, ui.layout, "Finish Export", 2)){ + file_selected = 1; + } + if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ + view->color_mode = CV_Mode_Library; + } + + b32 new_dir = 0; + if (do_file_list_box(system, ui.state, ui.layout, + ui.hot_directory, 1, 1, case_sensitive, + &new_dir, &file_selected, ".p4c")){ + result = 1; + } + + if (new_dir){ + hot_directory_reload(system, + ui.hot_directory, ui.state->working_set); + } + if (file_selected){ + i32 count = ui.styles->count; + Temp_Memory temp = begin_temp_memory(&mem->part); + Style **styles = push_array(&mem->part, Style*, sizeof(Style*)*count); + + Style *style = ui.styles->styles; + b8 *export_check = view->import_export_check; + i32 export_count = 0; + for (i32 i = 0; i < count; ++i, ++style){ + if (export_check[i]){ + styles[export_count++] = style; + } + } + char *data = push_array(&mem->part, char, ui.hot_directory->string.size + 5); + String str = make_string(data, 0, ui.hot_directory->string.size + 5); + copy(&str, ui.hot_directory->string); + append(&str, make_lit_string(".p4c")); + /*style_library_export(system, exchange, mem, &target->font_set, str.str, styles, export_count);*/ + + end_temp_memory(temp); + view->color_mode = CV_Mode_Library; + } + }break; + + case CV_Mode_Import: + { + do_label(ui.state, ui.layout, literal("Current Theme")); + do_style_preview(&ui, view->style); + + i32 style_count = view->inspecting_styles.count; + Style *styles = view->inspecting_styles.styles; + b8 *import_check = view->import_export_check; + + do_label(ui.state, ui.layout, literal("Pack")); + begin_row(ui.layout, 2); + if (do_button(-2, ui.state, ui.layout, "Finish Import", 2)){ + Style *style = styles; + for (i32 i = 0; i < style_count; ++i, ++style){ + if (import_check[i]) style_library_add(ui.styles, style); + } + view->color_mode = CV_Mode_Library; + } + if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ + view->color_mode = CV_Mode_Library; + } + Style *style = styles; for (i32 i = 0; i < style_count; ++i, ++style){ - if (import_check[i]) style_library_add(ui.styles, style); + if (do_style_preview(&ui, style, import_check[i])){ + import_check[i] = !import_check[i]; + result = 1; + } } - view->color_mode = CV_Mode_Library; - } - if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ - view->color_mode = CV_Mode_Library; - } - - Style *style = styles; - for (i32 i = 0; i < style_count; ++i, ++style){ - if (do_style_preview(&ui, style, import_check[i])){ - import_check[i] = !import_check[i]; - result = 1; + }break; + + case CV_Mode_Export: + { + do_label(ui.state, ui.layout, literal("Current Theme")); + do_style_preview(&ui, view->style); + + do_label(ui.state, ui.layout, literal("Export Which Themes?")); + begin_row(ui.layout, 2); + if (do_button(-2, ui.state, ui.layout, "Export", 2)){ + view->color_mode = CV_Mode_Export_File; } - } - }break; - - case CV_Mode_Export: - { - do_label(ui.state, ui.layout, literal("Current Theme")); - do_style_preview(&ui, view->style); - - do_label(ui.state, ui.layout, literal("Export Which Themes?")); - begin_row(ui.layout, 2); - if (do_button(-2, ui.state, ui.layout, "Export", 2)){ - view->color_mode = CV_Mode_Export_File; - } - if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ - view->color_mode = CV_Mode_Library; - } - - i32 style_count = view->styles->count; - Style *style = view->styles->styles; - b8 *export_check = view->import_export_check; - for (i32 i = 0; i < style_count; ++i, ++style){ - if (do_style_preview(&ui, style, export_check[i])){ - export_check[i] = !export_check[i]; - result = 1; + if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ + view->color_mode = CV_Mode_Library; } - } - }break; + + i32 style_count = view->styles->count; + Style *style = view->styles->styles; + b8 *export_check = view->import_export_check; + for (i32 i = 0; i < style_count; ++i, ++style){ + if (do_style_preview(&ui, style, export_check[i])){ + export_check[i] = !export_check[i]; + result = 1; + } + } + }break; } - + return result; } internal b32 theme_adjusting_shit(File_View *view, UI_State *state, UI_Layout *layout){ update_highlighting(view); - + Style *style = view->style; i32 result = 0; - + Color_UI ui; ui.state = state; ui.layout = layout; - + ui.fonts = view->font_set; + ui.global_font = view->global_font; ui.highlight = view->highlight; ui.color = view->color; ui.has_hover_color = 0; @@ -3206,113 +3158,113 @@ theme_adjusting_shit(File_View *view, UI_State *state, UI_Layout *layout){ ui.hex_advance = font_get_max_width(ui.fonts, ui.state->font_id, "0123456789abcdefx"); ui.palette = view->palette; ui.palette_size = view->palette_size; - + i32_Rect bar_rect = ui.layout->rect; bar_rect.x0 = bar_rect.x1 - 20; do_scroll_bar(ui.state, bar_rect); - + ui.layout->y -= FLOOR32(view->ui_state.view_y); ui.layout->rect.x1 -= 20; - + if (do_button(-1, ui.state, ui.layout, "Back to Library", 2)){ view->color_mode = CV_Mode_Library; ui.state->view_y = 0; } - + do_style_name(&ui); do_font_switch(&ui); - + do_color_adjuster(&ui, &style->main.back_color, - style->main.default_color, style->main.back_color, - "Background"); + style->main.default_color, style->main.back_color, + "Background"); do_color_adjuster(&ui, &style->main.margin_color, - style->main.default_color, style->main.margin_color, - "Margin"); + style->main.default_color, style->main.margin_color, + "Margin"); do_color_adjuster(&ui, &style->main.margin_hover_color, - style->main.default_color, style->main.margin_hover_color, - "Margin Hover"); + style->main.default_color, style->main.margin_hover_color, + "Margin Hover"); do_color_adjuster(&ui, &style->main.margin_active_color, - style->main.default_color, style->main.margin_active_color, - "Margin Active"); - + style->main.default_color, style->main.margin_active_color, + "Margin Active"); + do_color_adjuster(&ui, &style->main.cursor_color, - style->main.at_cursor_color, style->main.cursor_color, - "Cursor"); + style->main.at_cursor_color, style->main.cursor_color, + "Cursor"); do_color_adjuster(&ui, &style->main.at_cursor_color, - style->main.at_cursor_color, style->main.cursor_color, - "Text At Cursor"); + style->main.at_cursor_color, style->main.cursor_color, + "Text At Cursor"); do_color_adjuster(&ui, &style->main.mark_color, - style->main.mark_color, style->main.back_color, - "Mark"); - + style->main.mark_color, style->main.back_color, + "Mark"); + do_color_adjuster(&ui, &style->main.highlight_color, - style->main.at_highlight_color, style->main.highlight_color, - "Highlight"); + style->main.at_highlight_color, style->main.highlight_color, + "Highlight"); do_color_adjuster(&ui, &style->main.at_highlight_color, - style->main.at_highlight_color, style->main.highlight_color, - "Text At Highlight"); - + style->main.at_highlight_color, style->main.highlight_color, + "Text At Highlight"); + do_color_adjuster(&ui, &style->main.default_color, - style->main.default_color, style->main.back_color, - "Text Default"); + style->main.default_color, style->main.back_color, + "Text Default"); do_color_adjuster(&ui, &style->main.comment_color, - style->main.comment_color, style->main.back_color, - "Comment"); + style->main.comment_color, style->main.back_color, + "Comment"); do_color_adjuster(&ui, &style->main.keyword_color, - style->main.keyword_color, style->main.back_color, - "Keyword"); + style->main.keyword_color, style->main.back_color, + "Keyword"); do_color_adjuster(&ui, &style->main.str_constant_color, - style->main.str_constant_color, style->main.back_color, - "String Constant"); + style->main.str_constant_color, style->main.back_color, + "String Constant"); do_color_adjuster(&ui, &style->main.char_constant_color, - style->main.char_constant_color, style->main.back_color, - "Character Constant"); + style->main.char_constant_color, style->main.back_color, + "Character Constant"); do_color_adjuster(&ui, &style->main.int_constant_color, - style->main.int_constant_color, style->main.back_color, - "Integer Constant"); + style->main.int_constant_color, style->main.back_color, + "Integer Constant"); do_color_adjuster(&ui, &style->main.float_constant_color, - style->main.float_constant_color, style->main.back_color, - "Float Constant"); + style->main.float_constant_color, style->main.back_color, + "Float Constant"); do_color_adjuster(&ui, &style->main.bool_constant_color, - style->main.bool_constant_color, style->main.back_color, - "Boolean Constant"); + style->main.bool_constant_color, style->main.back_color, + "Boolean Constant"); do_color_adjuster(&ui, &style->main.preproc_color, - style->main.preproc_color, style->main.back_color, - "Preprocessor"); + style->main.preproc_color, style->main.back_color, + "Preprocessor"); do_color_adjuster(&ui, &style->main.include_color, - style->main.include_color, style->main.back_color, - "Include Constant"); + style->main.include_color, style->main.back_color, + "Include Constant"); do_color_adjuster(&ui, &style->main.special_character_color, - style->main.special_character_color, style->main.back_color, - "Special Character"); - + style->main.special_character_color, style->main.back_color, + "Special Character"); + do_color_adjuster(&ui, &style->main.highlight_junk_color, - style->main.default_color, style->main.highlight_junk_color, - "Junk Highlight"); + style->main.default_color, style->main.highlight_junk_color, + "Junk Highlight"); do_color_adjuster(&ui, &style->main.highlight_white_color, - style->main.default_color, style->main.highlight_white_color, - "Whitespace Highlight"); - + style->main.default_color, style->main.highlight_white_color, + "Whitespace Highlight"); + do_color_adjuster(&ui, &style->main.paste_color, - style->main.paste_color, style->main.back_color, - "Paste Color"); - + style->main.paste_color, style->main.back_color, + "Paste Color"); + Interactive_Style *bar_style = &style->main.file_info_style; do_color_adjuster(&ui, &bar_style->bar_color, - bar_style->base_color, bar_style->bar_color, - "Bar"); + bar_style->base_color, bar_style->bar_color, + "Bar"); do_color_adjuster(&ui, &bar_style->base_color, - bar_style->base_color, bar_style->bar_color, - "Bar Text"); + bar_style->base_color, bar_style->bar_color, + "Bar Text"); do_color_adjuster(&ui, &bar_style->pop1_color, - bar_style->pop1_color, bar_style->bar_color, - "Bar Pop 1"); + bar_style->pop1_color, bar_style->bar_color, + "Bar Pop 1"); do_color_adjuster(&ui, &bar_style->pop2_color, - bar_style->pop2_color, bar_style->bar_color, - "Bar Pop 2"); + bar_style->pop2_color, bar_style->bar_color, + "Bar Pop 2"); view->color = ui.color; - + return result; } @@ -3320,12 +3272,12 @@ internal b32 theme_shit(System_Functions *system, Exchange *exchange, File_View *view, View *active, UI_State *state, UI_Layout *layout){ b32 result = 0; - + File_View *factive = view_to_file_view(active); if (view != factive){ view->hot_file_view = factive; } - + switch (view->color_mode){ case CV_Mode_Library: case CV_Mode_Import_File: @@ -3337,14 +3289,14 @@ theme_shit(System_Functions *system, Exchange *exchange, result = 1; } break; - + case CV_Mode_Adjusting: if (theme_adjusting_shit(view, state, layout)){ result = 1; } break; } - + return(result); } @@ -3353,94 +3305,94 @@ interactive_shit(System_Functions *system, File_View *view, UI_State *state, UI_ b32 result = 0; b32 new_dir = 0; b32 complete = 0; - + do_label(state, layout, view->query, 1.f); - + b32 case_sensitive = 0; - + b32 input_stage = state->input_stage; Key_Summary *keys = state->keys; - + switch (view->interaction){ - case IInt_Sys_File_List: - { - b32 is_new = (view->action == IAct_New); - - if (do_file_list_box(system, state, - layout, view->hot_directory, 0, !is_new, case_sensitive, - &new_dir, &complete, 0)){ - result = 1; - } - if (new_dir){ - hot_directory_reload(system, - view->hot_directory, view->working_set); - } - }break; - - case IInt_Live_File_List: - { - if (do_live_file_list_box(system, state, layout, view->working_set, &view->dest, &complete)){ - result = 1; - } - }break; - - case IInt_Sure_To_Kill: - { - i32 action = -1; - char s_[256]; - String s = make_fixed_width_string(s_); - append(&s, view->dest); - append(&s, " has unsaved changes, kill it?"); - do_label(state, layout, s, 1.f); - - i32 id = 0; - if (do_list_option(++id, state, layout, make_lit_string("(Y)es"))){ - action = 0; - } - - if (do_list_option(++id, state, layout, make_lit_string("(N)o"))){ - action = 1; - } - - if (do_list_option(++id, state, layout, make_lit_string("(S)ave and kill"))){ - action = 2; - } - - if (action == -1 && input_stage){ - i32 key_count = keys->count; - for (i32 i = 0; i < key_count; ++i){ - Key_Event_Data key = keys->keys[i]; - switch (key.character){ - case 'y': case 'Y': action = 0; break; - case 'n': case 'N': action = 1; break; - case 's': case 'S': action = 2; break; - } - if (action == -1 && key.keycode == key_esc) action = 1; - if (action != -1) break; + case IInt_Sys_File_List: + { + b32 is_new = (view->action == IAct_New); + + if (do_file_list_box(system, state, + layout, view->hot_directory, 0, !is_new, case_sensitive, + &new_dir, &complete, 0)){ + result = 1; } - } - - if (action != -1){ - complete = 1; - view->user_action = action; - } - }break; + if (new_dir){ + hot_directory_reload(system, + view->hot_directory, view->working_set); + } + }break; + + case IInt_Live_File_List: + { + if (do_live_file_list_box(system, state, layout, view->working_set, &view->dest, &complete)){ + result = 1; + } + }break; + + case IInt_Sure_To_Kill: + { + i32 action = -1; + char s_[256]; + String s = make_fixed_width_string(s_); + append(&s, view->dest); + append(&s, " has unsaved changes, kill it?"); + do_label(state, layout, s, 1.f); + + i32 id = 0; + if (do_list_option(++id, state, layout, make_lit_string("(Y)es"))){ + action = 0; + } + + if (do_list_option(++id, state, layout, make_lit_string("(N)o"))){ + action = 1; + } + + if (do_list_option(++id, state, layout, make_lit_string("(S)ave and kill"))){ + action = 2; + } + + if (action == -1 && input_stage){ + i32 key_count = keys->count; + for (i32 i = 0; i < key_count; ++i){ + Key_Event_Data key = keys->keys[i]; + switch (key.character){ + case 'y': case 'Y': action = 0; break; + case 'n': case 'N': action = 1; break; + case 's': case 'S': action = 2; break; + } + if (action == -1 && key.keycode == key_esc) action = 1; + if (action != -1) break; + } + } + + if (action != -1){ + complete = 1; + view->user_action = action; + } + }break; } - + if (complete){ view->finished = 1; interactive_view_complete(view); } - + return(result); } internal void menu_shit(File_View *view, UI_State *state, UI_Layout *layout){ i32 id = 0; - + do_label(state, layout, literal("Menu"), 2.f); - + if (do_list_option(++id, state, layout, make_lit_string("Theme Options"))){ view_show_theme(view, view->view_base.map); } @@ -3453,7 +3405,7 @@ menu_shit(File_View *view, UI_State *state, UI_Layout *layout){ internal void config_shit(File_View *view, UI_State *state, UI_Layout *layout){ i32 id = 0; - + do_label(state, layout, literal("Config"), 2.f); if (do_checkbox_list_option(++id, state, layout, make_lit_string("Left Ctrl + Left Alt = AltGr"), @@ -3462,6 +3414,60 @@ config_shit(File_View *view, UI_State *state, UI_Layout *layout){ } } +internal void +do_file_bar(File_View *view, Editing_File *file, UI_Layout *layout, Render_Target *target){ + Interactive_Bar bar; + Style_Font *font = view->global_font; + i32 line_height = view->font_height; + Interactive_Style bar_style = view->style->main.file_info_style; + + u32 back_color = bar_style.bar_color; + u32 base_color = bar_style.base_color; + u32 pop2_color = bar_style.pop2_color; + + bar.rect = layout_rect(layout, line_height + 2); + + if (target){ + bar.font_id = font->font_id; + bar.pos_x = (f32)bar.rect.x0; + bar.pos_y = (f32)bar.rect.y0; + bar.text_shift_y = 2; + bar.text_shift_x = 0; + + draw_rectangle(target, bar.rect, back_color); + intbar_draw_string(target, &bar, file->name.live_name, base_color); + intbar_draw_string(target, &bar, make_lit_string(" - "), base_color); + + if (file->state.is_loading){ + intbar_draw_string(target, &bar, make_lit_string(" loading"), base_color); + } + else{ + char line_number_space[30]; + String line_number = make_string(line_number_space, 0, 30); + append(&line_number, "L#"); + append_int_to_str(view->cursor.line, &line_number); + + intbar_draw_string(target, &bar, line_number, base_color); + + if (!file->settings.unimportant){ + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: + { + persist String out_of_sync = make_lit_string(" !"); + intbar_draw_string(target, &bar, out_of_sync, pop2_color); + }break; + + case SYNC_UNSAVED: + { + persist String out_of_sync = make_lit_string(" *"); + intbar_draw_string(target, &bar, out_of_sync, pop2_color); + }break; + } + } + } + } +} + internal i32 step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Rect rect, b32 is_active, Input_Summary *user_input){ @@ -3472,18 +3478,20 @@ step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Re i32 widget_height = 0; { - i32_Rect widg_rect = view_widget_rect(view, view->font_height); - UI_State state = ui_state_init(&view->widget.state, 0, user_input, - view->style, view->font_set, 0, 1); + view->style, view->global_font->font_id, view->font_set, 0, 1); UI_Layout layout; - begin_layout(&layout, widg_rect); + begin_layout(&layout, rect); switch (view->widget.type){ case FWIDG_NONE: { + if (file){ + do_file_bar(view, file, &layout, 0); + } + draw_file_view_queries(view, &state, &layout); }break; @@ -3498,8 +3506,8 @@ step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Re }break; } - widget_height = layout.y - widg_rect.y0; - if (ui_finish_frame(&view->widget.state, &state, &layout, widg_rect, 0, 0)){ + widget_height = layout.y - rect.y0; + if (ui_finish_frame(&view->widget.state, &state, &layout, rect, 0, 0)){ result = 1; } } @@ -3524,7 +3532,7 @@ step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Re if (target_y < -taken_top_space) target_y = -taken_top_space; if (target_y > max_target_y) target_y = max_target_y; - real32 old_cursor_y = cursor_y; + f32 old_cursor_y = cursor_y; if (cursor_y >= target_y + max_y) cursor_y = target_y + max_y; if (cursor_y < target_y + taken_top_space) cursor_y = target_y + taken_top_space; @@ -3560,22 +3568,30 @@ step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Re } view->target_x = target_x; + + b32 is_new_target = 0; + if (view->target_x != view->prev_target_x) is_new_target = 1; + if (view->target_y != view->prev_target_y) is_new_target = 1; - if (smooth_camera_step(&view->target_y, &view->scroll_y, &view->vel_y, 40.f, 1.f/4.f)){ - result = 1; - } - if (smooth_camera_step(&view->target_x, &view->scroll_x, &view->vel_x, 40.f, 1.f/4.f)){ + if (view_->scroll_rule( + view->target_x, view->target_y, + &view->scroll_x, &view->scroll_y, + view_->id, is_new_target)){ result = 1; } + + view->prev_target_x = view->target_x; + view->prev_target_y = view->target_y; + if (file->state.paste_effect.tick_down > 0){ --file->state.paste_effect.tick_down; result = 1; } - - if (is_active && user_input->mouse.press_l){ + + if (user_input->mouse.press_l && is_active){ f32 max_y = view_compute_height(view); f32 rx = (f32)(user_input->mouse.x - rect.x0); - f32 ry = (f32)(user_input->mouse.y - rect.y0 - line_height - 2); + f32 ry = (f32)(user_input->mouse.y - rect.y0); if (ry >= extra_top){ view_set_widget(view, FWIDG_NONE); @@ -3593,7 +3609,7 @@ step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Re { UI_State state = ui_state_init(&view->ui_state, 0, user_input, - view->style, view->font_set, view->working_set, 1); + view->style, view->global_font->font_id, view->font_set, view->working_set, 1); UI_Layout layout; begin_layout(&layout, rect); @@ -3628,60 +3644,6 @@ step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Re return(result); } -internal void -draw_file_setup_bar(Style *style, i32 line_height, Interactive_Bar *bar, i32_Rect *rect){ - bar->style = style->main.file_info_style; - bar->font_id = style->font_id; - bar->pos_x = (f32)rect->x0; - bar->pos_y = (f32)rect->y0; - bar->text_shift_y = 2; - bar->text_shift_x = 0; - bar->rect = *rect; - bar->rect.y1 = bar->rect.y0 + line_height + 2; - rect->y0 += line_height + 2; -} - -internal void -draw_file_bar(File_View *view, Interactive_Bar *bar, Render_Target *target){ - Editing_File *file = view->file; - - u32 back_color = bar->style.bar_color; - u32 base_color = bar->style.base_color; - u32 pop2_color = bar->style.pop2_color; - - draw_rectangle(target, bar->rect, back_color); - intbar_draw_string(target, bar, file->name.live_name, base_color); - intbar_draw_string(target, bar, make_lit_string(" - "), base_color); - - if (file->state.is_loading){ - intbar_draw_string(target, bar, make_lit_string(" loading"), base_color); - } - else{ - char line_number_space[30]; - String line_number = make_string(line_number_space, 0, 30); - append(&line_number, "L#"); - append_int_to_str(view->cursor.line, &line_number); - - intbar_draw_string(target, bar, line_number, base_color); - - if (!file->settings.unimportant){ - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: - { - persist String out_of_sync = make_lit_string(" !"); - intbar_draw_string(target, bar, out_of_sync, pop2_color); - }break; - - case SYNC_UNSAVED: - { - persist String out_of_sync = make_lit_string(" *"); - intbar_draw_string(target, bar, out_of_sync, pop2_color); - }break; - } - } - } -} - internal i32 draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *target){ Editing_File *file = view->file; @@ -3708,7 +3670,7 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t i32 max = partition_remaining(part) / sizeof(Buffer_Render_Item); Buffer_Render_Item *items = push_array(part, Buffer_Render_Item, max); - i16 font_id = style->font_id; + i16 font_id = view->global_font->font_id; Render_Font *font = get_font_info(view->font_set, font_id)->font; float *advance_data = 0; if (font) advance_data = font->advance_data; @@ -3851,31 +3813,34 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t internal i32 draw_file_view(System_Functions *system, Exchange *exchange, - View *view_, View *active, i32_Rect rect, b32 is_active, Render_Target *target, Input_Summary *user_input){ + View *view_, View *active, i32_Rect rect, b32 is_active, + Render_Target *target, Input_Summary *user_input){ File_View *view = (File_View*)view_; + Editing_File *file = view->file; i32 result = 0; - + i32 widget_height = 0; { - i32_Rect widg_rect = view_widget_rect(view, view->font_height); - UI_State state = ui_state_init(&view->widget.state, target, 0, - view->style, view->font_set, 0, 0); - + view->style, view->global_font->font_id, view->font_set, 0, 0); + UI_Layout layout; - begin_layout(&layout, widg_rect); - + begin_layout(&layout, rect); + switch (view->widget.type){ case FWIDG_NONE: { + if (file){ + do_file_bar(view, file, &layout, target); + } + draw_file_view_queries(view, &state, &layout); }break; case FWIDG_TIMELINES: { - if (view->file){ - Editing_File *file = view->file; + if (file){ i32 undo_count = file->state.undo.undo.edit_count; i32 redo_count = file->state.undo.redo.edit_count; i32 total_count = undo_count + redo_count; @@ -3887,17 +3852,17 @@ draw_file_view(System_Functions *system, Exchange *exchange, }break; } - widget_height = layout.y - widg_rect.y0; - ui_finish_frame(&view->widget.state, &state, &layout, widg_rect, 0, 0); + widget_height = layout.y - rect.y0; + ui_finish_frame(&view->widget.state, &state, &layout, rect, 0, 0); } - + { rect.y0 += widget_height; target->push_clip(target, rect); UI_State state = ui_state_init(&view->ui_state, target, user_input, - view->style, view->font_set, view->working_set, 0); + view->style, view->global_font->font_id, view->font_set, view->working_set, 0); UI_Layout layout; begin_layout(&layout, rect); @@ -3907,15 +3872,8 @@ draw_file_view(System_Functions *system, Exchange *exchange, switch (view->showing_ui){ case VUI_None: { - if (view->file){ - Interactive_Bar bar; - draw_file_setup_bar(view->style, view->font_height, &bar, &rect); - - if (file_is_ready(view->file)){ - result = draw_file_loaded(view, rect, is_active, target); - } - - draw_file_bar(view, &bar, target); + if (file && file_is_ready(file)){ + result = draw_file_loaded(view, rect, is_active, target); } }break; @@ -3953,22 +3911,19 @@ kill_file( General_Memory *general, Editing_File *file, Live_Views *live_set, Editing_Layout *layout){ - View *view; File_View *fview; - Panel *panel; - i32 panel_count, i; - - panel_count = layout->panel_count; - panel = layout->panels; - for (i = 0; i < panel_count; ++i, ++panel){ - view = panel->view; - fview = view_to_file_view(view); + + Panel *panel, *used_panels; + used_panels = &layout->used_sentinel; + + for (dll_items(panel, used_panels)){ + fview = view_to_file_view(panel->view); Assert(fview); - if (fview->file == file){ fview->file = 0; } } + file_close(system, general, file); file_get_dummy(file); } @@ -4038,24 +3993,18 @@ struct File_View_Iter{ Editing_File *file; File_View *skip; - Panel *panels; - i32 panel_count; - i32 i; + Panel *used_panels; + Panel *panel; }; internal File_View_Iter file_view_iter_next(File_View_Iter iter){ Panel *panel; - View *view; File_View *file_view; - - ++iter.i; - for (panel = iter.panels + iter.i; - iter.i < iter.panel_count; - ++iter.i, ++panel){ - view = panel->view; - file_view = view_to_file_view(view); - if (file_view && file_view != iter.skip && file_view->file == iter.file){ + + for (panel = iter.panel; panel != iter.used_panels; panel = panel->next){ + file_view = view_to_file_view(panel->view); + if (file_view != iter.skip && file_view->file == iter.file){ iter.view = file_view; break; } @@ -4066,22 +4015,19 @@ file_view_iter_next(File_View_Iter iter){ internal File_View_Iter file_view_iter_init(Editing_Layout *layout, Editing_File *file, File_View *skip){ - File_View_Iter result = {}; - result.panels = layout->panels; - result.panel_count = layout->panel_count; + File_View_Iter result; + result.used_panels = &layout->used_sentinel; + result.panel = result.used_panels->next; result.file = file; result.skip = skip; - result.i = -1; - result = file_view_iter_next(result); - return(result); } internal b32 file_view_iter_good(File_View_Iter iter){ b32 result = 1; - if (iter.i >= iter.panel_count) result = 0; + if (iter.panel != iter.used_panels) result = 0; return(result); } diff --git a/4ed_gui.cpp b/4ed_gui.cpp index 955c4064..d6b57246 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -550,12 +550,13 @@ get_pop_color(UI_State *state, u32 *pop, Widget_ID wid, UI_Style style){ internal UI_State ui_state_init(UI_State *state_in, Render_Target *target, Input_Summary *user_input, - Style *style, Font_Set *font_set, Working_Set *working_set, b32 input_stage){ + Style *style, i16 font_id, Font_Set *font_set, Working_Set *working_set, + b32 input_stage){ UI_State state = {}; state.target = target; state.style = style; state.font_set = font_set; - state.font_id = style->font_id; + state.font_id = font_id; state.working_set = working_set; if (user_input){ state.mouse = &user_input->mouse; @@ -821,7 +822,7 @@ internal b32 do_button(i32 id, UI_State *state, UI_Layout *layout, char *text, i32 height_mult, b32 is_toggle = 0, b32 on = 0){ b32 result = 0; - i16 font_id = state->style->font_id; + i16 font_id = state->font_id; i32 character_h = get_font_info(state->font_set, font_id)->height; i32_Rect btn_rect = layout_rect(layout, character_h * height_mult); @@ -869,7 +870,7 @@ do_button(i32 id, UI_State *state, UI_Layout *layout, char *text, i32 height_mul internal b32 do_undo_slider(Widget_ID wid, UI_State *state, UI_Layout *layout, i32 max, i32 v, Undo_Data *undo, i32 *out){ b32 result = 0; - i16 font_id = state->style->font_id; + i16 font_id = state->font_id; i32 character_h = get_font_info(state->font_set, font_id)->height; i32_Rect containing_rect = layout_rect(layout, character_h); @@ -1013,7 +1014,7 @@ do_undo_slider(Widget_ID wid, UI_State *state, UI_Layout *layout, i32 max, i32 v internal void do_label(UI_State *state, UI_Layout *layout, char *text, int text_size, f32 height = 2.f){ Style *style = state->style; - i16 font_id = style->font_id; + i16 font_id = state->font_id; i32 line_height = get_font_info(state->font_set, font_id)->height; i32_Rect label = layout_rect(layout, FLOOR32(line_height * height)); @@ -1178,13 +1179,13 @@ draw_gradient_slider(Render_Target *target, Vec4 base, i32 channel, inline void draw_hsl_slider(Render_Target *target, Vec4 base, i32 channel, - i32 steps, real32 top, f32_Rect slider){ + i32 steps, f32 top, f32_Rect slider){ draw_gradient_slider(target, base, channel, steps, top, slider, 1); } inline void draw_rgb_slider(Render_Target *target, Vec4 base, i32 channel, - i32 steps, f32 top, f32_Rect slider){ + i32 steps, f32 top, f32_Rect slider){ draw_gradient_slider(target, base, channel, steps, top, slider, 0); } @@ -1195,7 +1196,7 @@ do_main_file_box(System_Functions *system, UI_State *state, UI_Layout *layout, Style *style = state->style; String *string = &hot_directory->string; - i16 font_id = style->font_id; + i16 font_id = state->font_id; i32 line_height = get_font_info(state->font_set, font_id)->height; i32_Rect box = layout_rect(layout, line_height + 2); @@ -1224,7 +1225,7 @@ do_main_string_box(System_Functions *system, UI_State *state, UI_Layout *layout, b32 result = 0; Style *style = state->style; - i16 font_id = style->font_id; + i16 font_id = state->font_id; i32 line_height = get_font_info(state->font_set, font_id)->height; i32_Rect box = layout_rect(layout, line_height + 2); @@ -1251,7 +1252,7 @@ do_list_option(i32 id, UI_State *state, UI_Layout *layout, String text){ b32 result = 0; Style *style = state->style; - i16 font_id = style->font_id; + i16 font_id = state->font_id; i32 character_h = get_font_info(state->font_set, font_id)->height; i32_Rect box = layout_rect(layout, character_h*2); @@ -1287,7 +1288,7 @@ do_checkbox_list_option(i32 id, UI_State *state, UI_Layout *layout, String text, b32 result = 0; Style *style = state->style; - i16 font_id = style->font_id; + i16 font_id = state->font_id; i32 character_h = get_font_info(state->font_set, font_id)->height; i32_Rect box = layout_rect(layout, character_h*2); @@ -1332,7 +1333,7 @@ internal b32 do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, b32 is_folder, String extra, char slash){ b32 result = 0; Style *style = state->style; - i16 font_id = style->font_id; + i16 font_id = state->font_id; i32 character_h = get_font_info(state->font_set, font_id)->height; char slash_buf[2] = { slash, 0 }; @@ -1556,6 +1557,7 @@ struct Color_UI{ UI_Layout *layout; Font_Set *fonts; + Style_Font *global_font; f32 hex_advance; u32 *palette; @@ -1964,7 +1966,7 @@ do_palette(Color_UI *ui, i32_Rect rect){ if (!ui->state->input_stage){ Render_Target *target = ui->state->target; - draw_string(target, style->font_id, "Global Palette: right click to save color", + draw_string(target, ui->state->font_id, "Global Palette: right click to save color", layout.x, layout.rect.y0, style->main.default_color); } @@ -2233,8 +2235,8 @@ do_font_switch(Color_UI *ui){ for (i16 i = 1; i < count; ++i){ if (i == font_id) continue; if (do_font_option(ui, i)){ - ui->state->style->font_id = i; - ui->state->style->font_changed = 1; + ui->global_font->font_id = i; + ui->global_font->font_changed = 1; } } @@ -2251,7 +2253,7 @@ do_style_preview(Library_UI *ui, Style *style, i32 toggle = -1){ if (style == ui->state->style) id = 2; else id = raw_ptr_dif(style, ui->styles->styles) + 100; - i16 font_id = style->font_id; + i16 font_id = ui->state->font_id; Font_Info *info = get_font_info(ui->state->font_set, font_id); i32_Rect prect = layout_rect(ui->layout, info->height*3 + 6); diff --git a/4ed_layout.cpp b/4ed_layout.cpp index aee86581..f76cc2af 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -332,6 +332,8 @@ struct View{ Panel *panel; Command_Map *map; Do_View_Function *do_view; + Scroll_Rule_Function *scroll_rule; + i32 id; }; struct Live_Views{ @@ -353,7 +355,7 @@ live_set_get_view(Live_Views *live_set, i32 id){ } internal View_And_ID -live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){ +live_set_alloc_view(Live_Views *live_set, Scroll_Rule_Function *scroll_rule){ View_And_ID result = {}; Assert(live_set->count < live_set->max); @@ -361,9 +363,11 @@ live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){ result.view = live_set->free_sentinel.next; result.id = (i32)((char*)result.view - (char*)live_set->views); + result.view->id = result.id; dll_remove(result.view); memset(result.view, 0, live_set->stride); + result.view->scroll_rule = scroll_rule; return(result); } @@ -397,45 +401,5 @@ view_base_compute_height(View *view){ #define view_compute_width(view) (view_base_compute_width(&(view)->view_base)) #define view_compute_height(view) (view_base_compute_height(&(view)->view_base)) -struct Interactive_Style{ - u32 bar_color; - u32 bar_active_color; - u32 base_color; - u32 pop1_color; - u32 pop2_color; -}; - -struct Interactive_Bar{ - Interactive_Style style; - f32 pos_x, pos_y; - f32 text_shift_x, text_shift_y; - i32_Rect rect; - i16 font_id; -}; - -internal void -intbar_draw_string(Render_Target *target, - Interactive_Bar *bar, u8 *str, u32 char_color){ - i16 font_id = bar->font_id; - - draw_string(target, font_id, (char*)str, - (i32)(bar->pos_x + bar->text_shift_x), - (i32)(bar->pos_y + bar->text_shift_y), - char_color); - bar->pos_x += font_string_width(target, font_id, (char*)str); -} - -internal void -intbar_draw_string(Render_Target *target, Interactive_Bar *bar, - String str, u32 char_color){ - i16 font_id = bar->font_id; - - draw_string(target, font_id, str, - (i32)(bar->pos_x + bar->text_shift_x), - (i32)(bar->pos_y + bar->text_shift_y), - char_color); - bar->pos_x += font_string_width(target, font_id, str); -} - // BOTTOM diff --git a/4ed_style.cpp b/4ed_style.cpp index ab0fc20e..de7fb1d1 100644 --- a/4ed_style.cpp +++ b/4ed_style.cpp @@ -9,6 +9,42 @@ // TOP +// TODO(allen): +// Font changing UI should be in the library menu now, it's not tied to the fonts any more +// Get the import export stuff up and running for styles again + +struct Interactive_Style{ + u32 bar_color; + u32 bar_active_color; + u32 base_color; + u32 pop1_color; + u32 pop2_color; +}; + +struct Interactive_Bar{ + f32 pos_x, pos_y; + f32 text_shift_x, text_shift_y; + i32_Rect rect; + i16 font_id; +}; + +internal void +intbar_draw_string(Render_Target *target, Interactive_Bar *bar, + String str, u32 char_color){ + i16 font_id = bar->font_id; + + draw_string(target, font_id, str, + (i32)(bar->pos_x + bar->text_shift_x), + (i32)(bar->pos_y + bar->text_shift_y), + char_color); + bar->pos_x += font_string_width(target, font_id, str); +} + +struct Style_Font{ + i16 font_id; + i16 font_changed; +}; + struct Style_Main_Data{ u32 back_color; u32 margin_color; @@ -37,51 +73,39 @@ struct Style_Main_Data{ Interactive_Style file_info_style; }; -struct Style_File_Format_v4{ - i32 name_size; - char name[24]; - i32 font_name_size; - char font_name[24]; - Style_Main_Data main; -}; - -enum Style_Color_Tag{ - STAG_BAR_COLOR, - STAG_BAR_ACTIVE_COLOR, - STAG_BAR_BASE_COLOR, - STAG_BAR_POP1_COLOR, - STAG_BAR_POP2_COLOR, - STAG_BACK_COLOR, - STAG_MARGIN_COLOR, - STAG_MARGIN_HOVER_COLOR, - STAG_MARGIN_ACTIVE_COLOR, - STAG_CURSOR_COLOR, - STAG_AT_CURSOR_COLOR, - STAG_HIGHLIGHT_COLOR, - STAG_AT_HIGHLIGHT_COLOR, - STAG_MARK_COLOR, - STAG_DEFAULT_COLOR, - STAG_COMMENT_COLOR, - STAG_KEYWORD_COLOR, - STAG_STR_CONSTANT_COLOR, - STAG_CHAR_CONSTANT_COLOR, - STAG_INT_CONSTANT_COLOR, - STAG_FLOAT_CONSTANT_COLOR, - STAG_BOOL_CONSTANT_COLOR, - STAG_PREPROC_COLOR, - STAG_INCLUDE_COLOR, - STAG_SPECIAL_CHARACTER_COLOR, - STAG_HIGHLIGHT_JUNK_COLOR, - STAG_HIGHLIGHT_WHITE_COLOR, - STAG_PASTE_COLOR, - STAG_UNDO_COLOR, - STAG_NEXT_UNDO_COLOR, - STAG_RESULT_LINK_COLOR, - STAG_RELATED_LINK_COLOR, - STAG_ERROR_LINK_COLOR, - STAG_WARNING_LINK_COLOR, +enum Style_Tag{ + Stag_Bar, + Stag_Bar_Active, + Stag_Bar_Base, + Stag_Bar_Pop1, + Stag_Bar_Pop2, + Stag_Back, + Stag_Margin, + Stag_Margin_Hover, + Stag_Margin_Active, + Stag_Cursor, + Stag_At_Cursor, + Stag_Highlight, + Stag_At_Highlight, + Stag_Mark, + Stag_Default, + Stag_Comment, + Stag_Keyword, + Stag_Str_Constant, + Stag_Char_Constant, + Stag_Int_Constant, + Stag_Float_Constant, + Stag_Bool_Constant, + Stag_Preproc, + Stag_Include, + Stag_Special_Character, + Stag_Highlight_Junk, + Stag_Highlight_White, + Stag_Paste, + Stag_Undo, + Stag_Next_Undo, // never below this - STAG_COUNT + Stag_Count }; struct Style_Color_Specifier{ @@ -92,8 +116,6 @@ struct Style_Color_Specifier{ struct Style_File_Format{ i32 name_size; char name[24]; - i32 font_name_size; - char font_name[24]; i32 color_specifier_count; }; @@ -102,8 +124,6 @@ struct Style{ char name_[24]; String name; Style_Main_Data main; - b32 font_changed; - i16 font_id; }; struct Style_Library{ @@ -120,51 +140,51 @@ style_copy(Style *dst, Style *src){ internal void style_set_name(Style *style, String name){ i32 count = ArrayCount(style->name_); - style->name_[count - 1] = 0; style->name = make_string(style->name_, 0, count - 1); copy(&style->name, name); + terminate_with_null(&style->name); } inline u32* style_index_by_tag(Style *s, u32 tag){ u32 *result = 0; switch (tag){ - case STAG_BAR_COLOR: result = &s->main.file_info_style.bar_color; break; - case STAG_BAR_ACTIVE_COLOR: result = &s->main.file_info_style.bar_active_color; break; - case STAG_BAR_BASE_COLOR: result = &s->main.file_info_style.base_color; break; - case STAG_BAR_POP1_COLOR: result = &s->main.file_info_style.pop1_color; break; - case STAG_BAR_POP2_COLOR: result = &s->main.file_info_style.pop2_color; break; + case Stag_Bar: result = &s->main.file_info_style.bar_color; break; + case Stag_Bar_Active: result = &s->main.file_info_style.bar_active_color; break; + case Stag_Bar_Base: result = &s->main.file_info_style.base_color; break; + case Stag_Bar_Pop1: result = &s->main.file_info_style.pop1_color; break; + case Stag_Bar_Pop2: result = &s->main.file_info_style.pop2_color; break; - case STAG_BACK_COLOR: result = &s->main.back_color; break; - case STAG_MARGIN_COLOR: result = &s->main.margin_color; break; - case STAG_MARGIN_HOVER_COLOR: result = &s->main.margin_hover_color; break; - case STAG_MARGIN_ACTIVE_COLOR: result = &s->main.margin_active_color; break; + case Stag_Back: result = &s->main.back_color; break; + case Stag_Margin: result = &s->main.margin_color; break; + case Stag_Margin_Hover: result = &s->main.margin_hover_color; break; + case Stag_Margin_Active: result = &s->main.margin_active_color; break; - case STAG_CURSOR_COLOR: result = &s->main.cursor_color; break; - case STAG_AT_CURSOR_COLOR: result = &s->main.at_cursor_color; break; - case STAG_HIGHLIGHT_COLOR: result = &s->main.highlight_color; break; - case STAG_AT_HIGHLIGHT_COLOR: result = &s->main.at_highlight_color; break; - case STAG_MARK_COLOR: result = &s->main.mark_color; break; + case Stag_Cursor: result = &s->main.cursor_color; break; + case Stag_At_Cursor: result = &s->main.at_cursor_color; break; + case Stag_Highlight: result = &s->main.highlight_color; break; + case Stag_At_Highlight: result = &s->main.at_highlight_color; break; + case Stag_Mark: result = &s->main.mark_color; break; - case STAG_DEFAULT_COLOR: result = &s->main.default_color; break; - case STAG_COMMENT_COLOR: result = &s->main.comment_color; break; - case STAG_KEYWORD_COLOR: result = &s->main.keyword_color; break; - case STAG_STR_CONSTANT_COLOR: result = &s->main.str_constant_color; break; - case STAG_CHAR_CONSTANT_COLOR: result = &s->main.char_constant_color; break; - case STAG_INT_CONSTANT_COLOR: result = &s->main.int_constant_color; break; - case STAG_FLOAT_CONSTANT_COLOR: result = &s->main.float_constant_color; break; - case STAG_BOOL_CONSTANT_COLOR: result = &s->main.bool_constant_color; break; + case Stag_Default: result = &s->main.default_color; break; + case Stag_Comment: result = &s->main.comment_color; break; + case Stag_Keyword: result = &s->main.keyword_color; break; + case Stag_Str_Constant: result = &s->main.str_constant_color; break; + case Stag_Char_Constant: result = &s->main.char_constant_color; break; + case Stag_Int_Constant: result = &s->main.int_constant_color; break; + case Stag_Float_Constant: result = &s->main.float_constant_color; break; + case Stag_Bool_Constant: result = &s->main.bool_constant_color; break; - case STAG_PREPROC_COLOR: result = &s->main.preproc_color; break; - case STAG_INCLUDE_COLOR: result = &s->main.include_color; break; + case Stag_Preproc: result = &s->main.preproc_color; break; + case Stag_Include: result = &s->main.include_color; break; - case STAG_SPECIAL_CHARACTER_COLOR: result = &s->main.special_character_color; break; + case Stag_Special_Character: result = &s->main.special_character_color; break; - case STAG_HIGHLIGHT_JUNK_COLOR: result = &s->main.highlight_junk_color; break; - case STAG_HIGHLIGHT_WHITE_COLOR: result = &s->main.highlight_white_color; break; + case Stag_Highlight_Junk: result = &s->main.highlight_junk_color; break; + case Stag_Highlight_White: result = &s->main.highlight_white_color; break; - case STAG_PASTE_COLOR: result = &s->main.paste_color; break; - case STAG_UNDO_COLOR: result = &s->main.undo_color; break; + case Stag_Paste: result = &s->main.paste_color; break; + case Stag_Undo: result = &s->main.undo_color; break; } return result; } @@ -197,15 +217,11 @@ internal Style_File_Format* style_format_for_file(Font_Set *set, Style *style, Style_File_Format *out){ out->name_size = style->name.size; memcpy(out->name, style->name.str, ArrayCount(out->name)); - - String font_name = get_font_info(set, style->font_id)->name; - out->font_name_size = font_name.size; - memcpy(out->font_name, font_name.str, font_name.size); Style_Color_Specifier *spec = (Style_Color_Specifier*)(out + 1); i32 count = 0; - for (u32 i = 0; i < STAG_COUNT; ++i){ + for (u32 i = 0; i < Stag_Count; ++i){ u32 *color = style_index_by_tag(style, i); if (color){ spec->tag = i; diff --git a/buildsuper.bat b/buildsuper.bat index 4e187a6b..92264923 100644 --- a/buildsuper.bat +++ b/buildsuper.bat @@ -7,7 +7,7 @@ SET clset=64 SET WARNINGS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /WX SET STUFF=/GR- /nologo SET DEBUG=/Zi -SET EXPORTS=/EXPORT:get_bindings +SET EXPORTS=/EXPORT:get_bindings /EXPORT:scroll_rule SET SRC=4coder_custom.cpp cl %WARNINGS% %STUFF% %DEBUG% %SRC% /Fe4coder_custom /LD /link /INCREMENTAL:NO /OPT:REF %EXPORTS% diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 80e4c4ae..e82d5ec0 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -1754,6 +1754,9 @@ main(int argc, char **argv){ if (win32vars.custom){ win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) GetProcAddress(win32vars.custom, "get_bindings"); + + win32vars.custom_api.scroll_rule = (Scroll_Rule_Function*) + GetProcAddress(win32vars.custom, "scroll_rule"); } #endif