From 7009115967171938518e7c04bace068a8bcd78f3 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sat, 16 Jan 2016 20:34:48 -0500 Subject: [PATCH] right alt --- 4coder_custom.cpp | 2 + 4coder_custom.h | 3 +- 4cpp_lexer.h | 68 +- 4ed.cpp | 7377 +++++++++++++++++++------------------- 4ed.h | 29 +- 4ed_color_view.cpp | 43 +- 4ed_command.cpp | 10 +- 4ed_debug_view.cpp | 9 +- 4ed_file_view.cpp | 59 +- 4ed_font_set.cpp | 2 +- 4ed_interactive_view.cpp | 5 +- 4ed_layout.cpp | 2 +- 4ed_mem.cpp | 2 +- 4ed_menu_view.cpp | 9 +- 4ed_meta.h | 4 + 4ed_rendering.cpp | 36 +- 4ed_rendering.h | 1 - 4ed_rendering_helper.cpp | 7 +- 4ed_system.h | 3 + vc120.pdb | Bin 94208 -> 94208 bytes win32_4ed.cpp | 1034 +++--- 21 files changed, 4490 insertions(+), 4215 deletions(-) diff --git a/4coder_custom.cpp b/4coder_custom.cpp index be856f74..2be30003 100644 --- a/4coder_custom.cpp +++ b/4coder_custom.cpp @@ -17,7 +17,9 @@ clear_parameters(cmd_context) #define push_memory(cmd_context, len) app->push_memory(cmd_context, len) +#ifndef literal #define literal(s) s, (sizeof(s)-1) +#endif // NOTE(allen|a3.1): All of your custom ids should be >= mapid_user_custom. // I recommend enumerating your own map ids as shown here. diff --git a/4coder_custom.h b/4coder_custom.h index b0a5c344..359ca5f2 100644 --- a/4coder_custom.h +++ b/4coder_custom.h @@ -132,6 +132,7 @@ enum Param_ID{ par_cli_path, par_cli_command, par_cli_overlap_with_conflict, + par_cli_always_bind_to_view, // never below this par_type_count }; @@ -284,7 +285,7 @@ struct Application_Links{ Directory_CD *directory_cd; }; -struct Config_API{ +struct Custom_API{ Get_Binding_Data_Function *get_bindings; Set_Extra_Font_Function *set_extra_font; }; diff --git a/4cpp_lexer.h b/4cpp_lexer.h index 69f974a0..0fa00cb8 100644 --- a/4cpp_lexer.h +++ b/4cpp_lexer.h @@ -1537,41 +1537,47 @@ cpp_get_token(Cpp_Token_Stack *token_stack, int pos){ last = token_stack->count; Cpp_Get_Token_Result result = {}; - while (1){ - result.token_index = (first + last)/2; + if (token_stack->count > 0){ + for (;;){ + result.token_index = (first + last)/2; - int this_start = token_stack->tokens[result.token_index].start; - int next_start; - if (result.token_index + 1 < token_stack->count){ - next_start = token_stack->tokens[result.token_index+1].start; + int this_start = token_stack->tokens[result.token_index].start; + int next_start; + if (result.token_index + 1 < token_stack->count){ + next_start = token_stack->tokens[result.token_index+1].start; + } + else{ + next_start = this_start + token_stack->tokens[result.token_index].size; + } + if (this_start <= pos && pos < next_start){ + break; + } + else if (pos < this_start){ + last = result.token_index; + } + else{ + first = result.token_index + 1; + } + if (first == last){ + result.token_index = first; + break; + } } - else{ - next_start = this_start + token_stack->tokens[result.token_index].size; - } - if (this_start <= pos && pos < next_start){ - break; - } - else if (pos < this_start){ - last = result.token_index; - } - else{ - first = result.token_index + 1; - } - if (first == last){ - result.token_index = first; - break; - } - } - if (result.token_index == token_stack->count){ - --result.token_index; - result.in_whitespace = 1; - } - else{ - Cpp_Token *token = token_stack->tokens + result.token_index; - if (token->start + token->size <= pos){ + if (result.token_index == token_stack->count){ + --result.token_index; result.in_whitespace = 1; } + else{ + Cpp_Token *token = token_stack->tokens + result.token_index; + if (token->start + token->size <= pos){ + result.in_whitespace = 1; + } + } + } + else{ + result.token_index = -1; + result.in_whitespace = 1; } return result; @@ -1612,7 +1618,7 @@ cpp_relex_nonalloc_start(Cpp_File file, Cpp_Token_Stack *stack, else{ state.start_token_i = result.token_index-1; } - + result = cpp_get_token(stack, end); if (result.token_index < 0) result.token_index = 0; else if (end > stack->tokens[result.token_index].start) ++result.token_index; diff --git a/4ed.cpp b/4ed.cpp index 71366e04..a0335209 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1,3677 +1,3700 @@ -/* - * 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; -}; - -struct Sys_App_Binding{ - i32 sys_id; - i32 app_id; -}; - -struct App_Vars{ - Mem_Options mem; - 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; - - 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; - - char query_[256]; - char dest_[256]; - - Delay delay; - - String mini_str; - u8 mini_buffer[512]; - - App_State state; - App_State_Resizing resizing; - Panel *prev_mouse_panel; - - Config_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_user_custom) map = vars->user_maps + mapid - mapid_user_custom; - 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_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_Data{ - Mem_Options *mem; - Panel *panel; - View *view; - Working_Set *working_set; - Editing_Layout *layout; - Live_Views *live_set; - Style *style; - Delay *delay; - App_Vars *vars; - Exchange *exchange; - - i32 screen_width, screen_height; - Key_Single key; - - Partition part; - System_Functions *system; -}; - -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); -} - -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); - - u8 character = (u8)command->key.key.character; - char str_space[2]; - String string = make_string(str_space, 2); - str_space[0] = character; - string.size = 1; - - i32 pos; - pos = view->cursor.pos; - i32 next_cursor_pos = view->cursor.pos + string.size; - view_replace_range(system, mem, view, layout, pos, pos, (u8*)string.str, string.size, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - file->state.cursor_pos = view->cursor.pos; -} - -COMMAND_DECL(seek_whitespace_right){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 - 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); -#endif -} - -COMMAND_DECL(seek_whitespace_left){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 - 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); -#endif -} - -COMMAND_DECL(seek_whitespace_up){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 - 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); -#endif -} - -COMMAND_DECL(seek_whitespace_down){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 - 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); -#endif -} - -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){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 token_pos, white_pos; - token_pos = file->state.buffer.size; - if (file->state.tokens_complete){ - token_pos = seek_token_right(&file->state.token_stack, view->cursor.pos); - } - white_pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, Min(token_pos, white_pos)); -#endif -} - -COMMAND_DECL(seek_white_or_token_left){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 token_pos, white_pos; - token_pos = file->state.buffer.size; - if (file->state.tokens_complete){ - token_pos = seek_token_left(&file->state.token_stack, view->cursor.pos); - } - white_pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, Max(token_pos, white_pos)); -#endif -} - -COMMAND_DECL(seek_alphanumeric_right){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 - 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); -#endif -} - -COMMAND_DECL(seek_alphanumeric_left){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 - 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); -#endif -} - -COMMAND_DECL(seek_alphanumeric_or_camel_right){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 an_pos = buffer_seek_alphanumeric_right(&file->state.buffer, view->cursor.pos); - i32 pos = buffer_seek_alphanumeric_or_camel_right(&file->state.buffer, view->cursor.pos, an_pos); - view_cursor_move(view, pos); -#endif -} - -COMMAND_DECL(seek_alphanumeric_or_camel_left){ -#if BUFFER_EXPERIMENT_SCALPEL <= 3 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 an_pos = buffer_seek_alphanumeric_left(&file->state.buffer, view->cursor.pos); - i32 pos = buffer_seek_alphanumeric_or_camel_left(&file->state.buffer, view->cursor.pos, an_pos); - view_cursor_move(view, pos); -#endif -} - -COMMAND_DECL(search){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(fixed, view); - USE_VARS(vars); - - view_set_widget(view, FWIDG_SEARCH); - view->isearch.str = vars->mini_str; - view->isearch.reverse = 0; - view->isearch.pos = view->cursor.pos; -} - -COMMAND_DECL(rsearch){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(fixed, view); - USE_VARS(vars); - - view_set_widget(view, FWIDG_SEARCH); - view->isearch.str = vars->mini_str; - view->isearch.reverse = 1; - view->isearch.pos = view->cursor.pos; -} - -COMMAND_DECL(goto_line){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(fixed, view); - USE_VARS(vars); - - view_set_widget(view, FWIDG_GOTO_LINE); - view->isearch.str = vars->mini_str; - view->isearch.reverse = 1; - view->isearch.pos = view->cursor.pos; -} - -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); - - Range range = get_range(view->cursor.pos, view->mark); - 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); - - Range range = get_range(view->cursor.pos, view->mark); - 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); - - if (working_set->clipboard_size > 0){ - view->next_mode.rewrite = 1; - - String *src = working_set_clipboard_head(working_set); - i32 pos_left = view->cursor.pos; - - i32 next_cursor_pos = pos_left+src->size; - view_replace_range(system, mem, view, layout, pos_left, pos_left, (u8*)src->str, src->size, next_cursor_pos); - - view_cursor_move(view, next_cursor_pos); - view->mark = pos_left; - - Editing_Layout *layout = command->layout; - Panel *panels = layout->panels; - i32 panel_count = layout->panel_count; - for (i32 i = 0; i < panel_count; ++i){ - Panel *current_panel = panels + i; - File_View *current_view = view_to_file_view(current_panel->view); - - if (current_view && 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); - - if (working_set->clipboard_size > 0 && view->mode.rewrite){ - view->next_mode.rewrite = 1; - - Range range = get_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, - (u8*)src->str, src->size, next_cursor_pos); - - view_cursor_move(view, next_cursor_pos); - view->mark = range.start; - - Editing_Layout *layout = command->layout; - Panel *panels = layout->panels; - i32 panel_count = layout->panel_count; - for (i32 i = 0; i < panel_count; ++i){ - Panel *current_panel = panels + i; - File_View *current_view = view_to_file_view(current_panel->view); - - if (current_view && 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 = get_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(increase_rewind_speed){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - - i32 rewind_speed = ROUND32(view->rewind_speed * 4.f); - if (rewind_speed > 1) rewind_speed >>= 1; - else if (rewind_speed == 1) rewind_speed = 0; - else if (rewind_speed == 0) rewind_speed = -1; - else rewind_speed *= 2; - - view->rewind_speed = rewind_speed * 0.25f; -} - -COMMAND_DECL(increase_fastforward_speed){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - - i32 neg_rewind_speed = -ROUND32(view->rewind_speed * 4.f); - if (neg_rewind_speed > 1) neg_rewind_speed >>= 1; - else if (neg_rewind_speed == 1) neg_rewind_speed = 0; - else if (neg_rewind_speed == 0) neg_rewind_speed = -1; - else neg_rewind_speed *= 2; - - view->rewind_speed = -neg_rewind_speed * 0.25f; -} - -COMMAND_DECL(stop_rewind_fastforward){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - - view->rewind_speed = 0; -} - -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_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, - style, working_set, - font_set, delay); - int_view->interaction = INTV_SYS_FILE_LIST; - int_view->action = INTV_NEW; - copy(&int_view->query, "New: "); -} - -#if 0 -internal File_View* -app_open_file(System_Functions *system, Exchange *exchange, - App_Vars *vars, Mem_Options *mem, Panel *panel, - Working_Set *working_set, String *string, Style *style, - Live_Views *live_set, Command_Data *command_data){ - File_View *result = 0; - Editing_File *target_file = 0; - b32 created_file = 0; - - target_file = working_set_contains(working_set, *string); - if (!target_file){ - Get_File_Result file = working_set_get_available_file(working_set); - if (file.file){ - file_get_dummy(file.file); - created_file = file_create(system, mem, file.file, string->str, style->font); - table_add(&working_set->table, file.file->source_path, file.index); - if (created_file){ - target_file = file.file; - } - } - } - - if (target_file){ - View *new_view = live_set_alloc_view(live_set, &vars->mem); - - view_replace_major(system, exchange, new_view, panel, live_set); - - File_View *file_view = file_view_init(new_view, &vars->layout); - result = file_view; - - View *old_view = command_data->view; - command_data->view = new_view; - - Partition old_part = command_data->part; - Temp_Memory temp = begin_temp_memory(&vars->mem.part); - command_data->part = partition_sub_part(&vars->mem.part, 16 << 10); - - view_set_file(system, - file_view, target_file, style, - vars->hooks[hook_open_file], command_data, &app_links); - - command_data->part = old_part; - end_temp_memory(temp); - command_data->view = old_view; - - new_view->map = app_get_map(vars, target_file->base_map_id); - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (created_file && target_file->tokens_exist && - target_file->token_stack.tokens == 0){ - file_first_lex_parallel(system, &mem->general, target_file); - } -#endif - } - - return result; -} -#endif - -internal void -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.sys_id = sys_id; - binding.app_id = app_id; - vars->sys_app_bindings[vars->sys_app_count++] = binding; -} - -internal File_View* -app_open_file(System_Functions *system, App_Vars *vars, Exchange *exchange, - Live_Views *live_set, Working_Set *working_set, Panel *panel, - Command_Data *command_data, char *filename, int len){ - String filename_str; - i32 file_id; - File_View *result; - Mem_Options *mem; - Editing_File *target_file = 0; - b32 created_file = 0; - - filename_str = make_string(filename, len); - mem = &vars->mem; - - result = 0; - target_file = working_set_contains(working_set, filename_str); - if (!target_file){ - Get_File_Result file = working_set_get_available_file(working_set); - if (file.file){ - file_id = exchange_request_file(exchange, filename, len); - if (file_id){ - created_file = 1; - target_file = file.file; - file_get_loading(target_file); - table_add(&working_set->table, target_file->state.source_path, file.index); - file_init_strings(target_file); - file_set_name(target_file, filename); - - app_push_file_binding(vars, file_id, file.index); - } - else{ - file_get_dummy(file.file); - } - } - } - - if (target_file){ - Style *style = command_data->style; - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(system, exchange, new_view, panel, live_set); - - File_View *file_view = file_view_init(new_view, &vars->layout); - result = file_view; - - View *old_view = command_data->view; - command_data->view = new_view; - - Partition old_part = command_data->part; - Temp_Memory temp = begin_temp_memory(&mem->part); - command_data->part = partition_sub_part(&mem->part, Kbytes(16)); - - view_set_file(system, file_view, target_file, vars->font_set, - style, vars->hooks[hook_open_file], command_data, - &app_links); - - command_data->part = old_part; - end_temp_memory(temp); - command_data->view = old_view; - - new_view->map = app_get_map(vars, target_file->settings.base_map_id); - } - -#if 0 - file_id = exchange_request_file(exchange, filename, len); - - if (file_id){ - Get_File_Result - - - result = live_set_alloc_view(live_set, &vars->mem); - } - //exchange_free_file(exchange, file_id); -#endif - - return(result); -} - - -COMMAND_DECL(interactive_open){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - char *filename = 0; - int filename_len = 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 && - 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; - break; - } - } - - if (filename){ - String string = make_string(filename, filename_len); - app_open_file(system, vars, exchange, - live_set, working_set, panel, - command, string.str, string.size); - } - else{ - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, - style, working_set, font_set, delay); - int_view->interaction = INTV_SYS_FILE_LIST; - int_view->action = INTV_OPEN; - copy(&int_view->query, "Open: "); - } -} - -// 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){ -#if 0 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_STYLE(style); - USE_LAYOUT(layout); - USE_MEM(mem); - USE_VARS(vars); - - Editing_File temp_file; - if (file_create(system, mem, &temp_file, make_c_str(file->source_path), style->font)){ - file_close(system, &mem->general, file); - *file = temp_file; - file->source_path.str = file->source_path_; - file->live_name.str = file->live_name_; -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (file->tokens_exist) - file_first_lex_parallel(system, &mem->general, file); -#endif - - Partition old_part = command->part; - Temp_Memory temp = begin_temp_memory(&vars->mem.part); - command->part = partition_sub_part(&vars->mem.part, 16 << 10); - - view_set_file(system, - view, file, style, - vars->hooks[hook_open_file], command, app_links); - - command->part = old_part; - end_temp_memory(temp); - - i32 panel_count = layout->panel_count; - Panel *panels = layout->panels; - for (i32 i = 0; i < panel_count; ++i){ - Panel *current_panel = panels + i; - View *current_view_ = current_panel->view; - File_View *current_view = view_to_file_view(current_view_); - if (current_view && current_view != view && current_view->file == file){ - view_set_file(system, current_view, current_view->file, style, 0, command, app_links); - } - } - } -#endif -} - -COMMAND_DECL(save){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_VARS(vars); - USE_MEM(mem); - USE_EXCHANGE(exchange); - USE_WORKING_SET(working_set); - - String *file_path = &file->state.source_path; - if (file_path->size > 0){ - i32 sys_id = file_save(system, exchange, mem, file, file_path->str); - app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); - } -} - -COMMAND_DECL(interactive_save_as){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, style, - working_set, font_set, delay); - int_view->interaction = INTV_SYS_FILE_LIST; - int_view->action = INTV_SAVE_AS; - copy(&int_view->query, "Save As: "); -} - -COMMAND_DECL(change_active_panel){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - if (layout->panel_count > 1){ - ++layout->active_panel; - if (layout->active_panel >= layout->panel_count){ - layout->active_panel = 0; - } - } -} - -COMMAND_DECL(interactive_switch_buffer){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, style, - working_set, font_set, delay); - int_view->interaction = INTV_LIVE_FILE_LIST; - int_view->action = INTV_SWITCH; - copy(&int_view->query, "Switch File: "); -} - -COMMAND_DECL(interactive_kill_buffer){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, style, - working_set, font_set, delay); - int_view->interaction = INTV_LIVE_FILE_LIST; - int_view->action = INTV_KILL; - copy(&int_view->query, "Kill File: "); -} - -COMMAND_DECL(kill_buffer){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_DELAY(delay); - - delayed_action(delay, DACT_TRY_KILL, file->state.live_name, view->view_base.panel); -} - -COMMAND_DECL(toggle_line_wrap){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - Relative_Scrolling scrolling = view_get_relative_scrolling(view); - if (view->unwrapped_lines){ - view->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; - 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 = get_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){ -#if 0 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - if (file->token_stack.tokens && file->tokens_complete){ - Range range = get_range(view->cursor.pos, view->mark); - view_auto_tab_tokens(mem, view, layout, range.start, range.end); - } -#endif -} - -COMMAND_DECL(auto_tab_range){ - 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){ - Range range = get_range(view->cursor.pos, view->mark); - view_auto_tab_tokens(system, mem, view, layout, range.start, range.end, 1); - } -} - -COMMAND_DECL(auto_tab_line_at_cursor){ - 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){ - i32 pos = view->cursor.pos; - view_auto_tab_tokens(system, mem, view, layout, pos, pos, 0); - } -} - -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); - - i32 panel_count = layout->panel_count; - if (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); - } -} - -COMMAND_DECL(open_panel_hsplit){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - - i32 panel_count = layout->panel_count; - if (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); - } -} - -COMMAND_DECL(close_panel){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - USE_VIEW(view); - USE_EXCHANGE(exchange); - - if (layout->panel_count > 1){ - if (view){ - live_set_free_view(system, exchange, command->live_set, view); - panel->view = 0; - } - - Divider_And_ID div = layout_get_divider(layout, panel->parent); - Assert(div.divider->child1 == -1 || div.divider->child2 == -1); - - i32 child; - if (div.divider->child1 == -1){ - child = div.divider->child2; - } - else{ - child = div.divider->child1; - } - - i32 parent = div.divider->parent; - i32 which_child = div.divider->which_child; - if (parent != -1){ - Divider_And_ID par = layout_get_divider(layout, parent); - if (which_child == -1){ - par.divider->child1 = child; - } - else{ - par.divider->child2 = child; - } - } - else{ - Assert(layout->root == div.id); - layout->root = child; - } - - if (child != -1){ - Divider_And_ID chi = layout_get_divider(layout, child); - chi.divider->parent = parent; - chi.divider->which_child = div.divider->which_child; - } - - layout_free_divider(layout, div.divider); - layout_free_panel(layout, panel); - - if (child == -1){ - panel = layout->panels; - layout->active_panel = -1; - for (i32 i = 0; i < layout->panel_count; ++i){ - if (panel->parent == div.id){ - panel->parent = parent; - panel->which_child = which_child; - layout->active_panel = i; - break; - } - ++panel; - } - Assert(layout->active_panel != -1); - } - else{ - layout->active_panel = layout->active_panel % layout->panel_count; - } - - 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; - - i32 shift = (end - start); - Assert(shift > 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); - - real32 height = view_compute_height(view); - real32 max_target_y = view_compute_max_target_y(view); - real32 cursor_y = view_get_cursor_y(view); - - view->target_y += height; - if (view->target_y > max_target_y) view->target_y = max_target_y; - - if (view->target_y >= cursor_y){ - view->cursor = - view_compute_cursor_from_xy(view, 0, view->target_y); - } -} - -COMMAND_DECL(page_up){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - real32 height = view_compute_height(view); - real32 cursor_y = view_get_cursor_y(view); - - view->target_y -= height; - if (view->target_y < 0) view->target_y = 0; - - if (view->target_y + height <= cursor_y){ - view->cursor = - view_compute_cursor_from_xy(view, 0, view->target_y + height - view->font_height); - } -} - -inline void -open_theme_options(System_Functions *system, Exchange *exchange, - App_Vars *vars, Live_Views *live_set, Mem_Options *mem, Panel *panel){ - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Color_View *color_view = color_view_init(new_view, &vars->working_set); - color_view->hot_directory = &vars->hot_directory; - color_view->main_style = &vars->style; - color_view->styles = &vars->styles; - color_view->palette = vars->palette; - color_view->palette_size = vars->palette_size; - color_view->font_set = vars->font_set; -} - -COMMAND_DECL(open_color_tweaker){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_MEM(mem); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - - open_theme_options(system, exchange, vars, live_set, mem, panel); -} - -COMMAND_DECL(open_menu){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_EXCHANGE(exchange); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Menu_View *menu_view = menu_view_init(new_view, style, working_set, &vars->delay); - AllowLocal(menu_view); -} - -#if FRED_INTERNAL -COMMAND_DECL(open_debug_view){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_STYLE(style); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_EXCHANGE(exchange); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_debug; - Debug_View *debug_view = debug_view_init(new_view); - debug_view->font_id = style->font_id; - debug_view->mode = DBG_MEMORY; -} - -COMMAND_DECL(debug_memory){ - ProfileMomentFunction(); - REQ_DBG_VIEW(view); - view->mode = DBG_MEMORY; -} - -COMMAND_DECL(debug_os_events){ - ProfileMomentFunction(); - REQ_DBG_VIEW(view); - view->mode = DBG_OS_EVENTS; -} - -#endif - -COMMAND_DECL(close_minor_view){ - ProfileMomentFunction(); - REQ_VIEW(view); - USE_PANEL(panel); - USE_LIVE_SET(live_set); - USE_EXCHANGE(exchange); - - view_remove_minor(system, exchange, panel, live_set); -} - -COMMAND_DECL(cursor_mark_swap){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - i32 pos = view->cursor.pos; - view->cursor = view_compute_cursor_from_pos(view, view->mark); - view->mark = pos; -} - -COMMAND_DECL(user_callback){ - ProfileMomentFunction(); - if (binding.custom) binding.custom(command, &app_links); -} - -COMMAND_DECL(set_settings){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_LOADING(file, view); - USE_VARS(vars); - USE_MEM(mem); - AllowLocal(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; - 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; - - 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_user_custom){ - 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; - } - } -} - -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, - char *buffer_name, i32 buffer_name_len, - char *path, i32 path_len, - char *script, i32 script_len, - b32 overlap_with_conflict){ - if (buffer_name == 0 || path == 0 || script == 0){ - return; - } - - if (vars->cli_processes.count < vars->cli_processes.max){ - Editing_File *file = working_set_contains(working_set, make_string_slowly(buffer_name)); - i32 index; - - 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 (overlap_with_conflict) - vars->cli_processes.procs[i].out_file = 0; - else file = 0; - break; - } - } - index = (i32)(file - vars->working_set.files); - } - - if (file){ - file_create_super_locked(system, mem, file, buffer_name, font_set, style->font_id); - table_add(&working_set->table, file->state.live_name, index); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(system, exchange, new_view, panel, live_set); - - File_View *file_view = file_view_init(new_view, &vars->layout); - view_set_file(system, file_view, file, font_set, style, - vars->hooks[hook_open_file], command, &app_links); - new_view->map = app_get_map(vars, file->settings.base_map_id); - - 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(build){ - 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; - b32 overlap_with_conflict = 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 p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_target_buffer_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: - { - overlap_with_conflict = dynamic_to_int(¶m->param.value); - }break; - } - } - - build(system, mem, vars, working_set, - font_set, style, live_set, exchange, - panel, command, - buffer_name, buffer_name_len, - path, path_len, - script, script_len, - overlap_with_conflict); -} - -COMMAND_DECL(build_here){ - 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); - - b32 overlap_with_conflict = 0; - - char *buffer_name = "*compilation*"; - int buffer_name_len = sizeof("*compilation*")-1; - - char path_space[512]; - String path = make_fixed_width_string(path_space); - path.size = app_links.directory_get_hot(command, path.str, path.memory_size); - - char dir_space[512]; - String dir = make_fixed_width_string(dir_space); - dir.size = app_links.directory_get_hot(command, dir.str, dir.memory_size); - - for (;;){ - if (app_links.directory_has_file(dir, "build.bat")){ - if (append(&dir, "build")){ - break; - } - } - - if (app_links.directory_cd(&dir, "..") == 0){ - copy(&dir, "build"); - break; - } - } - terminate_with_null(&dir); - - build(system, mem, vars, working_set, - font_set, style, live_set, exchange, - panel, command, - buffer_name, buffer_name_len, - path.str, path.size, - dir.str, dir.size, - overlap_with_conflict); -} - -internal void -update_command_data(App_Vars *vars, Command_Data *cmd){ - Command_Data command_data; - command_data.vars = vars; - command_data.mem = &vars->mem; - command_data.working_set = &vars->working_set; - command_data.layout = &vars->layout; - command_data.panel = command_data.layout->panels + command_data.layout->active_panel; - command_data.view = command_data.panel->view; - command_data.live_set = &vars->live_set; - command_data.style = &vars->style; - command_data.delay = &vars->delay; - command_data.screen_width = cmd->screen_width; - command_data.screen_height = cmd->screen_height; - command_data.key = cmd->key; - command_data.part = cmd->part; - command_data.system = cmd->system; - command_data.exchange = cmd->exchange; - - *cmd = command_data; -} - -COMPOSE_DECL(compose_write_auto_tab_line){ - command_write_character(system, command, binding); - update_command_data(command->vars, command); - command_auto_tab_line_at_cursor(system, command, binding); - update_command_data(command->vars, command); -} - -globalvar Command_Function command_table[cmdid_count]; - -extern "C"{ - EXECUTE_COMMAND_SIG(external_exec_command_keep_stack){ - Command_Data *cmd = (Command_Data*)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*)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*)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*)cmd_context; - cmd->part.pos = 0; - } - - GET_ACTIVE_BUFFER_SIG(external_get_active_buffer){ - Command_Data *cmd = (Command_Data*)cmd_context; - Buffer_Summary buffer = {}; - - File_View *view = view_to_file_view(cmd->view); - if (view){ - Editing_File *file = view->file; - if (file && !file->state.is_dummy){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Working_Set *working_set = cmd->working_set; - buffer.file_id = (int)(file - working_set->files); - buffer.size = file->state.buffer.size; - buffer.file_name_len = file->state.source_path.size; - buffer.buffer_name_len = file->state.live_name.size; - buffer.file_name = file->state.source_path.str; - buffer.buffer_name = file->state.live_name.str; - buffer.file_cursor_pos = file->state.cursor_pos; - buffer.is_lexed = file->settings.tokens_exist; - buffer.map_id = file->settings.base_map_id; -#endif - } - } - - return(buffer); - } - - DIRECTORY_GET_HOT_SIG(external_directory_get_hot){ - Command_Data *cmd = (Command_Data*)cmd_context; - Hot_Directory *hot = &cmd->vars->hot_directory; - i32 copy_max = max - 1; - hot_directory_clean_end(hot); - if (copy_max > hot->string.size) - copy_max = hot->string.size; - memcpy(buffer, hot->string.str, copy_max); - buffer[copy_max] = 0; - return(copy_max); - } -} - -inline void -app_links_init(System_Functions *system){ - 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.get_active_buffer = external_get_active_buffer; - app_links.directory_get_hot = external_directory_get_hot; - app_links.directory_has_file = system->directory_has_file; - app_links.directory_cd = system->directory_cd; -} - -#if FRED_INTERNAL -internal void -setup_debug_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ - map_init(commands, part, 6, parent); - - map_add(commands, 'm', MDFR_NONE, command_debug_memory); - map_add(commands, 'o', MDFR_NONE, command_debug_os_events); -} -#endif - -internal void -setup_ui_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ - map_init(commands, part, 12, parent); - - commands->vanilla_keyboard_default.function = command_null; - - map_add(commands, codes->left, MDFR_NONE, command_null); - map_add(commands, codes->right, MDFR_NONE, command_null); - map_add(commands, codes->up, MDFR_NONE, command_null); - map_add(commands, codes->down, MDFR_NONE, command_null); - map_add(commands, codes->back, MDFR_NONE, command_null); - map_add(commands, codes->esc, MDFR_NONE, command_close_minor_view); -} - -internal void -setup_file_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ - map_init(commands, part, 101, parent); - - commands->vanilla_keyboard_default.function = command_write_character; - - map_add(commands, codes->left, MDFR_NONE, command_move_left); - map_add(commands, codes->right, MDFR_NONE, command_move_right); - map_add(commands, codes->del, MDFR_NONE, command_delete); - map_add(commands, codes->back, MDFR_NONE, command_backspace); - map_add(commands, codes->up, MDFR_NONE, command_move_up); - map_add(commands, codes->down, MDFR_NONE, command_move_down); - map_add(commands, codes->end, MDFR_NONE, command_seek_end_of_line); - map_add(commands, codes->home, MDFR_NONE, command_seek_beginning_of_line); - map_add(commands, codes->page_up, MDFR_NONE, command_page_up); - map_add(commands, codes->page_down, MDFR_NONE, command_page_down); - - map_add(commands, codes->right, MDFR_CTRL, command_seek_alphanumeric_or_camel_right); - map_add(commands, codes->left, MDFR_CTRL, command_seek_alphanumeric_or_camel_left); - map_add(commands, codes->up, MDFR_CTRL, command_seek_whitespace_up); - map_add(commands, codes->down, MDFR_CTRL, command_seek_whitespace_down); - - map_add(commands, ' ', MDFR_CTRL, command_set_mark); - map_add(commands, 'm', MDFR_CTRL, command_cursor_mark_swap); - map_add(commands, 'c', MDFR_CTRL, command_copy); - map_add(commands, 'x', MDFR_CTRL, command_cut); - map_add(commands, 'v', MDFR_CTRL, command_paste); - map_add(commands, 'V', MDFR_CTRL, command_paste_next); - map_add(commands, 'z', MDFR_CTRL, command_undo); - map_add(commands, 'y', MDFR_CTRL, command_redo); - map_add(commands, 'Z', MDFR_CTRL, command_timeline_scrub); - map_add(commands, codes->left, MDFR_ALT, command_increase_rewind_speed); - map_add(commands, codes->right, MDFR_ALT, command_increase_fastforward_speed); - map_add(commands, codes->down, MDFR_ALT, command_stop_rewind_fastforward); - map_add(commands, 'h', MDFR_CTRL, command_history_backward); - map_add(commands, 'H', MDFR_CTRL, command_history_forward); - map_add(commands, 'd', MDFR_CTRL, command_delete_range); - map_add(commands, 'l', MDFR_CTRL, command_toggle_line_wrap); - map_add(commands, '?', MDFR_CTRL, command_toggle_show_whitespace); - map_add(commands, '|', MDFR_CTRL, command_toggle_tokens); - map_add(commands, 'u', MDFR_CTRL, command_to_uppercase); - map_add(commands, 'j', MDFR_CTRL, command_to_lowercase); - map_add(commands, '~', MDFR_CTRL, command_clean_all_lines); - map_add(commands, 'f', MDFR_CTRL, command_search); - map_add(commands, 'r', MDFR_CTRL, command_rsearch); - map_add(commands, 'g', MDFR_CTRL, command_goto_line); - - map_add(commands, '\n', MDFR_NONE, compose_write_auto_tab_line); - map_add(commands, '}', MDFR_NONE, compose_write_auto_tab_line); - map_add(commands, ')', MDFR_NONE, compose_write_auto_tab_line); - map_add(commands, ']', MDFR_NONE, compose_write_auto_tab_line); - map_add(commands, ';', MDFR_NONE, compose_write_auto_tab_line); - - map_add(commands, '\t', MDFR_NONE, command_auto_tab_line_at_cursor); - map_add(commands, '\t', MDFR_CTRL, command_auto_tab_range); - map_add(commands, '\t', MDFR_CTRL | MDFR_SHIFT, command_write_character); - - map_add(commands, 'K', MDFR_CTRL, command_kill_buffer); - map_add(commands, 'O', MDFR_CTRL, command_reopen); - map_add(commands, 's', MDFR_CTRL, command_save); - map_add(commands, 'w', MDFR_CTRL, command_interactive_save_as); - -#if UseFileHistoryDump - map_add(commands, 'h', MDFR_ALT, command_save_history); -#endif -} - -internal void -setup_top_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ - map_init(commands, part, 51, parent); - -#if FRED_INTERNAL - map_add(commands, 'd', MDFR_ALT, command_open_debug_view); -#endif - - map_add(commands, 'p', MDFR_CTRL, command_open_panel_vsplit); - map_add(commands, '-', MDFR_CTRL, command_open_panel_hsplit); - map_add(commands, 'P', MDFR_CTRL, command_close_panel); - map_add(commands, 'n', MDFR_CTRL, command_interactive_new); - map_add(commands, 'o', MDFR_CTRL, command_interactive_open); - map_add(commands, ',', MDFR_CTRL, command_change_active_panel); - map_add(commands, 'k', MDFR_CTRL, command_interactive_kill_buffer); - map_add(commands, 'i', MDFR_CTRL, command_interactive_switch_buffer); - map_add(commands, 'c', MDFR_ALT, command_open_color_tweaker); - map_add(commands, 'x', MDFR_ALT, command_open_menu); - map_add(commands, 'm', MDFR_ALT, command_build_here); -} - -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(search); - SET(rsearch); - SET(goto_line); - SET(set_mark); - SET(copy); - SET(cut); - SET(paste); - SET(paste_next); - SET(delete_range); - SET(timeline_scrub); - SET(undo); - SET(redo); - SET(increase_rewind_speed); - SET(increase_fastforward_speed); - SET(stop_rewind_fastforward); - 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); - 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(build); - -#undef SET -} - -// Interactive Bar - -internal void -hot_directory_draw_helper(Render_Target *target, - Hot_Directory *hot_directory, - Interactive_Bar *bar, String *string, - bool32 include_files){ - persist u8 str_open_bracket[] = " {"; - persist u8 str_close_bracket[] = "}"; - persist u8 str_comma[] = ", "; - - intbar_draw_string(target, bar, *string, bar->style.pop1_color); - intbar_draw_string(target, bar, str_open_bracket, bar->style.base_color); - - char front_name_[256]; - String front_name = make_fixed_width_string(front_name_); - get_front_of_directory(&front_name, *string); - - bool32 is_first_string = 1; - File_List *files = &hot_directory->file_list; - - Absolutes absolutes; - get_absolutes(front_name, &absolutes, 1, 1); - - File_Info *info, *end; - end = files->infos + files->count; - for (info = files->infos; info != end; ++info){ - String filename = info->filename; - - if (filename_match(front_name, &absolutes, filename)){ - if (is_first_string){ - is_first_string = 0; - } - else{ - intbar_draw_string(target, bar, str_comma, bar->style.base_color); - } - if (info->folder){ - intbar_draw_string(target, bar, filename, bar->style.pop1_color); - intbar_draw_string(target, bar, (u8*)"/", bar->style.pop1_color); - } - else{ - intbar_draw_string(target, bar, filename, bar->style.base_color); - } - } - } - - intbar_draw_string(target, bar, str_close_bracket, bar->style.base_color); -} - -internal void -live_file_draw_helper(Render_Target *target, Working_Set *working_set, - Interactive_Bar *bar, String *string){ - persist u8 str_open_bracket[] = " {"; - persist u8 str_close_bracket[] = "}"; - persist u8 str_comma[] = ", "; - - intbar_draw_string(target, bar, *string, bar->style.base_color); - - intbar_draw_string(target, bar, str_open_bracket, bar->style.base_color); - - bool32 is_first_string = 1; - for (i32 file_i = 0; - file_i < working_set->file_index_count; - ++file_i){ - Editing_File *file = &working_set->files[file_i]; - if (file->state.live_name.str && - (string->size == 0 || has_substr_unsensitive(file->state.live_name, *string))){ - if (is_first_string){ - is_first_string = 0; - } - else{ - intbar_draw_string(target, bar, str_comma, bar->style.base_color); - } - intbar_draw_string(target, bar, file->state.live_name, bar->style.base_color); - } - } - intbar_draw_string(target, bar, str_close_bracket, bar->style.base_color); -} - -// 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 + 4; - - 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; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("Handmade Hero")); - style->font_id = fonts; - - 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 = 0xFF191970; - 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 = 0xFF1504CF; - 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 + 1; - - 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 + 3; - - 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; -} - -#define literal(s) s, (sizeof(s) - 1) - -HOOK_SIG(default_open_file_hook){ - Buffer_Summary buffer = app->get_active_buffer(cmd_context); - - int treat_as_code = 0; - - if (buffer.file_name && buffer.size < (16 << 20)){ - int extension_len; - char *extension = _4coder_get_extension(buffer.file_name, buffer.file_name_len, &extension_len); - if (_4coder_str_match(extension, extension_len, literal("cpp"))) treat_as_code = 1; - else if (_4coder_str_match(extension, extension_len, literal("h"))) treat_as_code = 1; - else if (_4coder_str_match(extension, extension_len, literal("c"))) treat_as_code = 1; - else if (_4coder_str_match(extension, extension_len, literal("hpp"))) treat_as_code = 1; - } - - app->push_parameter(cmd_context, dynamic_int(par_lex_as_cpp_file), dynamic_int(treat_as_code)); - app->push_parameter(cmd_context, dynamic_int(par_wrap_lines), dynamic_int(!treat_as_code)); - app->push_parameter(cmd_context, dynamic_int(par_key_mapid), dynamic_int(mapid_file)); - - app->exec_command_keep_stack(cmd_context, cmdid_set_settings); - app->clear_parameters(cmd_context); -} - -App_Init_Sig(app_init){ - app_links_init(system); - - Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); - App_Vars *vars = push_struct(&_partition, App_Vars); - Assert(vars); - *vars = {}; - vars->config_api = api; - vars->mem.part = _partition; - Partition *partition = &vars->mem.part; - target->partition = partition; - general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); - - i32 panel_max_count = vars->layout.panel_max_count = 16; - i32 panel_count = vars->layout.panel_count = 1; - i32 divider_max_count = panel_max_count - 1; - - Panel *panels = vars->layout.panels = - push_array(partition, Panel, panel_max_count); - - Panel_Divider *dividers = vars->layout.dividers = - push_array(partition, Panel_Divider, divider_max_count); - - Panel_Divider *divider = dividers; - for (i32 i = 0; i < divider_max_count-1; ++i, ++divider){ - divider->next_free = (divider + 1); - } - divider->next_free = 0; - vars->layout.free_divider = dividers; - - vars->live_set.count = 0; - vars->live_set.max = 1 + 2*panel_max_count; - i32 view_sizes[] = { - sizeof(File_View), - sizeof(Color_View), - sizeof(Interactive_View), -#if FRED_INTERNAL - sizeof(Debug_View), -#endif - }; - - i32 view_chunk_size = 0; - for (i32 i = 0; i < ArrayCount(view_sizes); ++i){ - view_chunk_size = Max(view_chunk_size, view_sizes[i]); - } - vars->live_set.stride = view_chunk_size; - vars->live_set.views = (File_View*) - push_block(partition, view_chunk_size*vars->live_set.max); - - char *views_ = (char*)vars->live_set.views; - for (i32 i = panel_max_count-2; i >= 0; --i){ - View *view = (View*)(views_ + i*view_chunk_size); - View *view_next = (View*)((char*)view + view_chunk_size); - view->next_free = view_next; - } - { - View *view = (View*)(views_ + (panel_max_count-1)*view_chunk_size); - view->next_free = 0; - } - vars->live_set.free_view = (View*)views_; - - setup_command_table(); - - Command_Map *global = &vars->map_top; - if (vars->config_api.get_bindings){ - i32 size = partition_remaining(partition); - void *data = partition_current(partition); - - // TODO(allen): Use a giant bubble of general memory for this. - // So that it doesn't interfere with the command maps as they allocate - // their own memory. - i32 wanted_size = vars->config_api.get_bindings(data, size, loose_codes); - - bool32 did_top = 0; - bool32 did_file = 0; - if (wanted_size <= size){ - partition_allocate(partition, wanted_size); - - Binding_Unit *unit = (Binding_Unit*)data; - 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_user_custom){ - 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_user_custom){ - 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; - } - else{ - map_add(mapptr, unit->binding.code, unit->binding.modifiers, func); - } - } - } - 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; - } - } - } - } - - if (!did_top) setup_top_commands(&vars->map_top, &vars->mem.part, loose_codes, global); - if (!did_file) setup_file_commands(&vars->map_file, &vars->mem.part, loose_codes, global); - } - else{ - setup_top_commands(&vars->map_top, &vars->mem.part, loose_codes, global); - setup_file_commands(&vars->map_file, &vars->mem.part, loose_codes, global); - } - - setup_ui_commands(&vars->map_ui, &vars->mem.part, loose_codes, global); -#if FRED_INTERNAL - setup_debug_commands(&vars->map_debug, &vars->mem.part, loose_codes, global); -#endif - - if (vars->hooks[hook_open_file] == 0){ - vars->hooks[hook_open_file] = default_open_file_hook; - } - - vars->font_set = &target->font_set; - - font_set_init(vars->font_set, partition, 16, 4); - - { - 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("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}, - - {LitStr("LiberationSans-Regular.ttf"), - LitStr("liberation sans"), - 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); - } - -#if 0 - if (vars->config_api.set_extra_font){ - Extra_Font extra; - extra.size = 17; - vars->config_api.set_extra_font(&extra); - memory_used = 0; - if (app_load_font(target, - vars->fonts.fonts + font_count, extra.file_name, extra.size, - partition_current(partition), - &memory_used, 4, make_string_slowly(extra.font_name))){ - ++font_count; - } - else{ - vars->fonts.fonts[font_count] = {}; - } - push_block(partition, memory_used); - } - - vars->fonts.count = font_count; -#endif - } - - // NOTE(allen): file setup - vars->working_set.file_index_count = 1; - vars->working_set.file_max_count = 29; - 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->delay.max = ArrayCount(vars->delay.acts); - - // NOTE(allen): style setup - app_hardcode_styles(vars); - - vars->palette_size = 40; - vars->palette = push_array(partition, u32, vars->palette_size); - - AllowLocal(panel_count); - panel_init(&panels[0]); - - String hdbase = make_fixed_width_string(vars->hot_dir_base_); - hot_directory_init(&vars->hot_directory, hdbase, current_directory); - - 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); - - return 1; -} - -App_Step_Sig(app_step){ - ProfileStart(OS_syncing); - Application_Step_Result app_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; - } - - Panel *panels = vars->layout.panels; - Panel *active_panel = &panels[vars->layout.active_panel]; - - // NOTE(allen): OS clipboard event handling - 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): 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->state.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; - } - - Panel *panel = vars->layout.panels; - i32 panel_count = vars->layout.panel_count; - for (i32 i = 0; i < panel_count; ++i, ++panel){ - View *view = panel->view; - if (view && view->is_minor) view = view->major; - File_View *fview = view_to_file_view(view); - if (fview){ - 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 prev_y_off = 0; - i32 prev_x_off = 0; - - i32 y_off = 0; - i32 x_off = 0; - i32 full_width = vars->layout.full_width = target->width; - i32 full_height = vars->layout.full_height = target->height; - - if (prev_width != full_width || prev_height != full_height || - prev_x_off != x_off || prev_y_off != y_off){ - layout_refit(&vars->layout, prev_x_off, prev_y_off, prev_width, prev_height); - int view_count = vars->layout.panel_max_count; - for (i32 view_i = 0; view_i < view_count; ++view_i){ - View *view_ = live_set_get_view(&vars->live_set, view_i); - if (!view_->is_active) continue; - File_View *view = view_to_file_view(view_); - if (!view) continue; - view_measure_wraps(system, &vars->mem.general, view); - view->cursor = view_compute_cursor_from_pos(view, view->cursor.pos); - } - app_result.redraw = 1; - } - - // NOTE(allen): collect 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]; - } - - for (i32 i = 0; i < CONTROL_KEY_COUNT; ++i){ - key_data.modifiers[i] = input->control_keys[i]; - } - - Mouse_Summary mouse_data; - mouse_data.mx = mouse->x; - mouse_data.my = mouse->y; - - mouse_data.l = mouse->left_button; - mouse_data.r = mouse->right_button; - mouse_data.press_l = mouse_data.l && !mouse->left_button_prev; - mouse_data.press_r = mouse_data.r && !mouse->right_button_prev; - mouse_data.release_l = !mouse_data.l && mouse->left_button_prev; - mouse_data.release_r = !mouse_data.r && mouse->right_button_prev; - - mouse_data.out_of_window = mouse->out_of_window; - mouse_data.wheel_used = (mouse->wheel != 0); - mouse_data.wheel_amount = -mouse->wheel; - ProfileEnd(OS_syncing); - - ProfileStart(hover_status); - // NOTE(allen): detect mouse hover status - i32 mx = mouse_data.mx; - i32 my = mouse_data.my; - b32 mouse_in_edit_area = 0; - b32 mouse_in_margin_area = 0; - Panel *mouse_panel = 0; - i32 mouse_panel_i = 0; - - { - Panel *panel = 0; - b32 in_edit_area = 0; - b32 in_margin_area = 0; - i32 panel_count = vars->layout.panel_count; - i32 panel_i; - - for (panel_i = 0; panel_i < panel_count; ++panel_i){ - panel = panels + panel_i; - if (hit_check(mx, my, panel->inner)){ - in_edit_area = 1; - break; - } - else if (hit_check(mx, my, panel->full)){ - in_margin_area = 1; - break; - } - } - - mouse_in_edit_area = in_edit_area; - mouse_in_margin_area = in_margin_area; - if (in_edit_area || in_margin_area){ - mouse_panel = panel; - mouse_panel_i = panel_i; - } - } - - 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){ - b32 resize_area = 0; - i32 divider_id = 0; - b32 seeking_v_divider = 0; - i32 seeking_child_on_side = 0; - Panel *panel = mouse_panel; - if (mx >= panel->inner.x0 && mx < panel->inner.x1){ - seeking_v_divider = 0; - if (my > panel->inner.y0){ - seeking_child_on_side = -1; - } - else{ - seeking_child_on_side = 1; - } - } - else{ - seeking_v_divider = 1; - if (mx > panel->inner.x0){ - seeking_child_on_side = -1; - } - else{ - seeking_child_on_side = 1; - } - } - mouse_divider_vertical = seeking_v_divider; - mouse_divider_side = seeking_child_on_side; - - if (vars->layout.panel_count > 1){ - i32 which_child; - divider_id = panel->parent; - which_child = panel->which_child; - for (;;){ - Divider_And_ID div = layout_get_divider(&vars->layout, divider_id); - - if (which_child == seeking_child_on_side && - div.divider->v_divider == seeking_v_divider){ - resize_area = 1; - break; - } - - if (divider_id == vars->layout.root){ - break; - } - else{ - divider_id = div.divider->parent; - which_child = div.divider->which_child; - } - } - - mouse_on_divider = resize_area; - mouse_divider_id = divider_id; - } - } - ProfileEnd(hover_status); - - ProfileStart(resizing); - // NOTE(allen): panel resizing - switch (vars->state){ - case APP_STATE_EDIT: - { - if (mouse_data.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_data.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; - } - ProfileEnd(resizing); - - ProfileStart(command); - // NOTE(allen): update active panel - if (mouse_in_edit_area && mouse_panel != 0 && mouse_data.press_l){ - active_panel = mouse_panel; - vars->layout.active_panel = mouse_panel_i; - app_result.redraw = 1; - } - - Command_Data command_data; - command_data.mem = &vars->mem; - command_data.panel = active_panel; - command_data.view = active_panel->view; - command_data.working_set = &vars->working_set; - command_data.layout = &vars->layout; - command_data.live_set = &vars->live_set; - command_data.style = &vars->style; - command_data.delay = &vars->delay; - command_data.vars = vars; - command_data.exchange = exchange; - command_data.screen_width = target->width; - command_data.screen_height = target->height; - command_data.system = system; - - Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part); - command_data.part = partition_sub_part(&vars->mem.part, 16 << 10); - - if (first_step && vars->hooks[hook_start]){ - vars->hooks[hook_start](&command_data, &app_links); - command_data.part.pos = 0; - } - - // NOTE(allen): command input to active view - for (i32 key_i = 0; key_i < key_data.count; ++key_i){ - Command_Binding cmd = {}; - Command_Map *map = 0; - View *view = active_panel->view; - - Key_Single key = get_single_key(&key_data, key_i); - command_data.key = key; - - Command_Map *visited_maps[16] = {}; - i32 visited_top = 0; - - if (view) map = view->map; - if (map == 0) map = &vars->map_top; - while (map){ - cmd = map_extract(map, key); - if (cmd.function == 0){ - if (visited_top < ArrayCount(visited_maps)){ - visited_maps[visited_top++] = map; - map = map->parent; - for (i32 i = 0; i < visited_top; ++i){ - if (map == visited_maps[i]){ - map = 0; - break; - } - } - } - else map = 0; - } - else map = 0; - } - - switch (vars->state){ - case APP_STATE_EDIT: - { - Handle_Command_Function *handle_command = 0; - if (view) handle_command = view->handle_command; - if (handle_command){ - handle_command(system, view, &command_data, cmd, key, codes); - app_result.redraw = 1; - } - else{ - if (cmd.function){ - cmd.function(system, &command_data, cmd); - app_result.redraw = 1; - } - } - }break; - - case APP_STATE_RESIZING: - { - if (key_data.count > 0){ - vars->state = APP_STATE_EDIT; - } - }break; - } - } - - active_panel = panels + vars->layout.active_panel; - ProfileEnd(command); - - ProfileStart(step); - View *active_view = active_panel->view; - - Input_Summary dead_input = {}; - dead_input.mouse.mx = mouse_data.mx; - dead_input.mouse.my = mouse_data.my; - dead_input.codes = codes; - dead_input.keys.modifiers[0] = key_data.modifiers[0]; - dead_input.keys.modifiers[1] = key_data.modifiers[1]; - dead_input.keys.modifiers[2] = key_data.modifiers[2]; - - Input_Summary active_input = {}; - dead_input.mouse.mx = mouse_data.mx; - dead_input.mouse.my = mouse_data.my; - active_input.keys = key_data; - active_input.codes = codes; - - // NOTE(allen): pass raw input to the panels - { - Panel *panel = panels; - for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ - View *view_ = panel->view; - if (view_){ - Assert(view_->do_view); - b32 active = (panel == active_panel); - Input_Summary input = (active)?(active_input):(dead_input); - if (panel == mouse_panel){ - input.mouse = mouse_data; - } - if (view_->do_view(system, exchange, view_, panel->inner, active_view, - VMSG_STEP, 0, &input, &active_input)){ - app_result.redraw = 1; - } - } - } - } - ProfileEnd(step); - - ProfileStart(delayed_actions); - if (vars->delay.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->delay.count; - vars->delay.count = 0; - - for (i32 i = 0; i < count; ++i){ - Delayed_Action *act = vars->delay.acts + i; - String *string = &act->string; - Panel *panel = act->panel; - - switch (act->type){ - case DACT_OPEN: - { - command_data.view = (View*) - app_open_file(system, vars, exchange, - live_set, working_set, panel, - &command_data, string->str, string->size); - }break; - - case DACT_SAVE_AS: - { - View *view = panel->view; - File_View *fview = view_to_file_view(view); - - if (!fview && view->is_minor) fview = view_to_file_view(view->major); - if (fview){ - Editing_File *file = fview->file; - if (file && !file->state.is_dummy){ - file_save_and_set_names(system, exchange, mem, file, string->str); - } - } - }break; - - case DACT_SAVE: - { - Editing_File *file = working_set_lookup_file(working_set, *string); - if (!file->state.is_dummy){ - file_save(system, exchange, mem, file, file->state.source_path.str); - } - }break; - - case DACT_NEW: - { - Get_File_Result file = working_set_get_available_file(working_set); - file_create_empty(system, mem, file.file, string->str, - vars->font_set, style->font_id); - table_add(&working_set->table, file.file->state.source_path, file.index); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(system, exchange, new_view, panel, live_set); - - File_View *file_view = file_view_init(new_view, &vars->layout); - command_data.view = (View*)file_view; - view_set_file(system, file_view, file.file, vars->font_set, style, - vars->hooks[hook_open_file], &command_data, &app_links); - new_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 *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(system, exchange, new_view, panel, live_set); - - File_View *file_view = file_view_init(new_view, &vars->layout); - command_data.view = (View*)file_view; - - view_set_file(system, file_view, file, vars->font_set, style, - vars->hooks[hook_open_file], &command_data, &app_links); - - new_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->state.source_path); - kill_file(system, exchange, general, file, live_set, &vars->layout); - } - }break; - - case DACT_TRY_KILL: - { - Editing_File *file = working_set_lookup_file(working_set, *string); - if (file){ - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: - case SYNC_GOOD: - { - table_remove(&working_set->table, file->state.source_path); - kill_file(system, exchange, general, file, live_set, &vars->layout); - view_remove_minor(system, exchange, panel, live_set); - }break; - - case SYNC_UNSAVED: - { - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, style, - working_set, vars->font_set, &vars->delay); - int_view->interaction = INTV_SURE_TO_KILL_INTER; - int_view->action = INTV_SURE_TO_KILL; - copy(&int_view->query, "Are you sure?"); - copy(&int_view->dest, file->state.live_name); - }break; - - default: Assert(!"invalid path"); - } - } - }break; - - case DACT_CLOSE_MINOR: - { - view_remove_minor(system, exchange, panel, live_set); - }break; - - case DACT_CLOSE_MAJOR: - { - view_remove_major(system, exchange, panel, live_set); - }break; - - case DACT_THEME_OPTIONS: - { - open_theme_options(system, exchange, vars, live_set, mem, panel); - }break; - } - } - } - ProfileEnd(delayed_actions); - - end_temp_memory(param_stack_temp); - - ProfileStart(resize); - // NOTE(allen): send resize messages to panels that have changed size - { - Panel *panel = panels; - for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ - 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, active_view, - VMSG_RESIZE, 0, &dead_input, &active_input); - view = (view->is_minor)?view->major:0; - if (view){ - view->do_view(system, exchange, - view, inner, active_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 = panels; - for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ - View *view = panel->view; - if (view){ - view->do_view(system, exchange, - view, panel->inner, active_view, - VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); - view = (view->is_minor)?view->major:0; - if (view){ - view->do_view(system, exchange, - view, panel->inner, active_view, - VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); - } - } - } - } - ProfileEnd(style_change); - - // NOTE(allen): processing bindings between system and application - ProfileStart(sys_app_bind_processing); - for (i32 i = 0; i < vars->sys_app_count; ++i){ - Sys_App_Binding *binding; - b32 remove = 0; - binding = vars->sys_app_bindings + i; - - byte *data; - i32 size, max; - - if (exchange_file_ready(exchange, binding->sys_id, &data, &size, &max)){ - Editing_File *ed_file = vars->working_set.files + binding->app_id; - char *filename = exchange_file_filename(exchange, binding->sys_id); - if (data){ - String val = make_string((char*)data, size); - file_create_from_string(system, &vars->mem, ed_file, filename, - vars->font_set, vars->style.font_id, val); - - if (ed_file->settings.tokens_exist) - file_first_lex_parallel(system, &vars->mem.general, ed_file); - - 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_file_loaded_init(system, iter.view, 0); - } - } - else{ - file_create_empty(system, &vars->mem, ed_file, filename, - vars->font_set, vars->style.font_id); - } - - exchange_free_file(exchange, binding->sys_id); - remove = 1; - } - - if (exchange_file_save_complete(exchange, binding->sys_id, &data, &size, &max)){ - Assert(remove == 0); - - if (data){ - general_memory_free(&vars->mem.general, data); - exchange_clear_file(exchange, binding->sys_id); - } - - Editing_File *file = get_file(&vars->working_set, binding->app_id); - if (file){ - file_synchronize_times(system, file, file->state.source_path.str); - } - - exchange_free_file(exchange, binding->sys_id); - remove = 1; - } - - if (remove){ - *binding = vars->sys_app_bindings[--vars->sys_app_count]; - --i; - } - } - ProfileEnd(sys_app_bind_processing); - - ProfileStart(redraw); - if (mouse_panel != vars->prev_mouse_panel) app_result.redraw = 1; - if (app_result.redraw){ - begin_render_section(target); - - target->clip_top = -1; - draw_push_clip(target, rect_from_target(target)); - - // NOTE(allen): render the panels - Panel *panel = panels; - for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ - i32_Rect full = panel->full; - i32_Rect inner = panel->inner; - - View *view = panel->view; - Style *style = &vars->style; - - b32 active = (panel == active_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, active_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); - } - ProfileEnd(redraw); - - ProfileStart(get_cursor); - // NOTE(allen): get cursor type - if (mouse_in_edit_area){ - View *view = mouse_panel->view; - if (view){ - app_result.mouse_cursor_type = view->mouse_cursor_type; - } - else{ - 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); - - return app_result; -} - -internal -App_Alloc_Sig(app_alloc){ - Mem_Options *mem = (Mem_Options*)(handle); - void *result = general_memory_allocate(&mem->general, size, 0); - return(result); -} - -internal -App_Free_Sig(app_free){ - Mem_Options *mem = (Mem_Options*)(handle); - general_memory_free(&mem->general, block); -} - -external App_Get_Functions_Sig(app_get_functions){ - App_Functions result = {}; - - result.init = app_init; - result.step = app_step; - - result.alloc = app_alloc; - result.free = app_free; - - 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; +}; + +struct Sys_App_Binding{ + i32 sys_id; + i32 app_id; +}; + +struct App_Vars{ + Mem_Options mem; + 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; + + 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; + + char query_[256]; + char dest_[256]; + + Delay delay; + + String mini_str; + u8 mini_buffer[512]; + + App_State state; + App_State_Resizing resizing; + Panel *prev_mouse_panel; + + 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_user_custom) map = vars->user_maps + mapid - mapid_user_custom; + 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_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_Data{ + Mem_Options *mem; + Panel *panel; + View *view; + Working_Set *working_set; + Editing_Layout *layout; + Live_Views *live_set; + Style *style; + Delay *delay; + App_Vars *vars; + Exchange *exchange; + + i32 screen_width, screen_height; + Key_Event_Data key; + + Partition part; + System_Functions *system; +}; + +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); +} + +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); + + u8 character = (u8)command->key.character; + char str_space[2]; + String string = make_string(str_space, 2); + str_space[0] = character; + string.size = 1; + + i32 pos; + pos = view->cursor.pos; + i32 next_cursor_pos = view->cursor.pos + string.size; + view_replace_range(system, mem, view, layout, pos, pos, (u8*)string.str, string.size, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + file->state.cursor_pos = view->cursor.pos; +} + +COMMAND_DECL(seek_whitespace_right){ +#if BUFFER_EXPERIMENT_SCALPEL <= 3 + 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); +#endif +} + +COMMAND_DECL(seek_whitespace_left){ +#if BUFFER_EXPERIMENT_SCALPEL <= 3 + 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); +#endif +} + +COMMAND_DECL(seek_whitespace_up){ +#if BUFFER_EXPERIMENT_SCALPEL <= 3 + 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); +#endif +} + +COMMAND_DECL(seek_whitespace_down){ +#if BUFFER_EXPERIMENT_SCALPEL <= 3 + 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); +#endif +} + +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){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 token_pos, white_pos; + token_pos = file->state.buffer.size; + if (file->state.tokens_complete){ + token_pos = seek_token_right(&file->state.token_stack, view->cursor.pos); + } + white_pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, Min(token_pos, white_pos)); +#endif +} + +COMMAND_DECL(seek_white_or_token_left){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 token_pos, white_pos; + token_pos = file->state.buffer.size; + if (file->state.tokens_complete){ + token_pos = seek_token_left(&file->state.token_stack, view->cursor.pos); + } + white_pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, Max(token_pos, white_pos)); +#endif +} + +COMMAND_DECL(seek_alphanumeric_right){ +#if BUFFER_EXPERIMENT_SCALPEL <= 3 + 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); +#endif +} + +COMMAND_DECL(seek_alphanumeric_left){ +#if BUFFER_EXPERIMENT_SCALPEL <= 3 + 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); +#endif +} + +COMMAND_DECL(seek_alphanumeric_or_camel_right){ +#if BUFFER_EXPERIMENT_SCALPEL <= 3 + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 an_pos = buffer_seek_alphanumeric_right(&file->state.buffer, view->cursor.pos); + i32 pos = buffer_seek_alphanumeric_or_camel_right(&file->state.buffer, view->cursor.pos, an_pos); + view_cursor_move(view, pos); +#endif +} + +COMMAND_DECL(seek_alphanumeric_or_camel_left){ +#if BUFFER_EXPERIMENT_SCALPEL <= 3 + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 an_pos = buffer_seek_alphanumeric_left(&file->state.buffer, view->cursor.pos); + i32 pos = buffer_seek_alphanumeric_or_camel_left(&file->state.buffer, view->cursor.pos, an_pos); + view_cursor_move(view, pos); +#endif +} + +COMMAND_DECL(search){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(fixed, view); + USE_VARS(vars); + + view_set_widget(view, FWIDG_SEARCH); + view->isearch.str = vars->mini_str; + view->isearch.reverse = 0; + view->isearch.pos = view->cursor.pos; +} + +COMMAND_DECL(rsearch){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(fixed, view); + USE_VARS(vars); + + view_set_widget(view, FWIDG_SEARCH); + view->isearch.str = vars->mini_str; + view->isearch.reverse = 1; + view->isearch.pos = view->cursor.pos; +} + +COMMAND_DECL(goto_line){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(fixed, view); + USE_VARS(vars); + + view_set_widget(view, FWIDG_GOTO_LINE); + view->isearch.str = vars->mini_str; + view->isearch.reverse = 1; + view->isearch.pos = view->cursor.pos; +} + +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); + + Range range = get_range(view->cursor.pos, view->mark); + 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); + + Range range = get_range(view->cursor.pos, view->mark); + 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); + + if (working_set->clipboard_size > 0){ + view->next_mode.rewrite = 1; + + String *src = working_set_clipboard_head(working_set); + i32 pos_left = view->cursor.pos; + + i32 next_cursor_pos = pos_left+src->size; + view_replace_range(system, mem, view, layout, pos_left, pos_left, (u8*)src->str, src->size, next_cursor_pos); + + view_cursor_move(view, next_cursor_pos); + view->mark = pos_left; + + Editing_Layout *layout = command->layout; + Panel *panels = layout->panels; + i32 panel_count = layout->panel_count; + for (i32 i = 0; i < panel_count; ++i){ + Panel *current_panel = panels + i; + File_View *current_view = view_to_file_view(current_panel->view); + + if (current_view && 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); + + if (working_set->clipboard_size > 0 && view->mode.rewrite){ + view->next_mode.rewrite = 1; + + Range range = get_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, + (u8*)src->str, src->size, next_cursor_pos); + + view_cursor_move(view, next_cursor_pos); + view->mark = range.start; + + Editing_Layout *layout = command->layout; + Panel *panels = layout->panels; + i32 panel_count = layout->panel_count; + for (i32 i = 0; i < panel_count; ++i){ + Panel *current_panel = panels + i; + File_View *current_view = view_to_file_view(current_panel->view); + + if (current_view && 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 = get_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(increase_rewind_speed){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + + i32 rewind_speed = ROUND32(view->rewind_speed * 4.f); + if (rewind_speed > 1) rewind_speed >>= 1; + else if (rewind_speed == 1) rewind_speed = 0; + else if (rewind_speed == 0) rewind_speed = -1; + else rewind_speed *= 2; + + view->rewind_speed = rewind_speed * 0.25f; +} + +COMMAND_DECL(increase_fastforward_speed){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + + i32 neg_rewind_speed = -ROUND32(view->rewind_speed * 4.f); + if (neg_rewind_speed > 1) neg_rewind_speed >>= 1; + else if (neg_rewind_speed == 1) neg_rewind_speed = 0; + else if (neg_rewind_speed == 0) neg_rewind_speed = -1; + else neg_rewind_speed *= 2; + + view->rewind_speed = -neg_rewind_speed * 0.25f; +} + +COMMAND_DECL(stop_rewind_fastforward){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + + view->rewind_speed = 0; +} + +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_VARS(vars); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_MEM(mem); + USE_WORKING_SET(working_set); + USE_STYLE(style); + USE_DELAY(delay); + USE_EXCHANGE(exchange); + USE_FONT_SET(font_set); + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + Interactive_View *int_view = + interactive_view_init(system, new_view, &vars->hot_directory, + style, working_set, + font_set, delay); + int_view->interaction = INTV_SYS_FILE_LIST; + int_view->action = INTV_NEW; + copy(&int_view->query, "New: "); +} + +#if 0 +internal File_View* +app_open_file(System_Functions *system, Exchange *exchange, + App_Vars *vars, Mem_Options *mem, Panel *panel, + Working_Set *working_set, String *string, Style *style, + Live_Views *live_set, Command_Data *command_data){ + File_View *result = 0; + Editing_File *target_file = 0; + b32 created_file = 0; + + target_file = working_set_contains(working_set, *string); + if (!target_file){ + Get_File_Result file = working_set_get_available_file(working_set); + if (file.file){ + file_get_dummy(file.file); + created_file = file_create(system, mem, file.file, string->str, style->font); + table_add(&working_set->table, file.file->source_path, file.index); + if (created_file){ + target_file = file.file; + } + } + } + + if (target_file){ + View *new_view = live_set_alloc_view(live_set, &vars->mem); + + view_replace_major(system, exchange, new_view, panel, live_set); + + File_View *file_view = file_view_init(new_view, &vars->layout); + result = file_view; + + View *old_view = command_data->view; + command_data->view = new_view; + + Partition old_part = command_data->part; + Temp_Memory temp = begin_temp_memory(&vars->mem.part); + command_data->part = partition_sub_part(&vars->mem.part, 16 << 10); + + view_set_file(system, + file_view, target_file, style, + vars->hooks[hook_open_file], command_data, &app_links); + + command_data->part = old_part; + end_temp_memory(temp); + command_data->view = old_view; + + new_view->map = app_get_map(vars, target_file->base_map_id); + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + if (created_file && target_file->tokens_exist && + target_file->token_stack.tokens == 0){ + file_first_lex_parallel(system, &mem->general, target_file); + } +#endif + } + + return result; +} +#endif + +internal void +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.sys_id = sys_id; + binding.app_id = app_id; + vars->sys_app_bindings[vars->sys_app_count++] = binding; +} + +internal File_View* +app_open_file(System_Functions *system, App_Vars *vars, Exchange *exchange, + Live_Views *live_set, Working_Set *working_set, Panel *panel, + Command_Data *command_data, char *filename, int len){ + String filename_str; + i32 file_id; + File_View *result; + Mem_Options *mem; + Editing_File *target_file = 0; + b32 created_file = 0; + + filename_str = make_string(filename, len); + mem = &vars->mem; + + result = 0; + target_file = working_set_contains(working_set, filename_str); + if (!target_file){ + Get_File_Result file = working_set_get_available_file(working_set); + if (file.file){ + file_id = exchange_request_file(exchange, filename, len); + if (file_id){ + created_file = 1; + target_file = file.file; + file_get_loading(target_file); + table_add(&working_set->table, filename_str, file.index); + file_init_strings(target_file); + file_set_name(target_file, filename); + + app_push_file_binding(vars, file_id, file.index); + } + else{ + file_get_dummy(file.file); + } + } + } + + if (target_file){ + Style *style = command_data->style; + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_major(system, exchange, new_view, panel, live_set); + + File_View *file_view = file_view_init(new_view, &vars->layout); + result = file_view; + + View *old_view = command_data->view; + command_data->view = new_view; + + Partition old_part = command_data->part; + Temp_Memory temp = begin_temp_memory(&mem->part); + command_data->part = partition_sub_part(&mem->part, Kbytes(16)); + + view_set_file(system, file_view, target_file, vars->font_set, + style, vars->hooks[hook_open_file], command_data, + &app_links); + + command_data->part = old_part; + end_temp_memory(temp); + command_data->view = old_view; + + new_view->map = app_get_map(vars, target_file->settings.base_map_id); + } + +#if 0 + file_id = exchange_request_file(exchange, filename, len); + + if (file_id){ + Get_File_Result + + + result = live_set_alloc_view(live_set, &vars->mem); + } + //exchange_free_file(exchange, file_id); +#endif + + return(result); +} + + +COMMAND_DECL(interactive_open){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_MEM(mem); + USE_WORKING_SET(working_set); + USE_STYLE(style); + USE_DELAY(delay); + USE_EXCHANGE(exchange); + USE_FONT_SET(font_set); + + char *filename = 0; + int filename_len = 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 && + 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; + break; + } + } + + if (filename){ + String string = make_string(filename, filename_len); + app_open_file(system, vars, exchange, + live_set, working_set, panel, + command, string.str, string.size); + } + else{ + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + Interactive_View *int_view = + interactive_view_init(system, new_view, &vars->hot_directory, + style, working_set, font_set, delay); + int_view->interaction = INTV_SYS_FILE_LIST; + int_view->action = INTV_OPEN; + copy(&int_view->query, "Open: "); + } +} + +// 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){ +#if 0 + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_STYLE(style); + USE_LAYOUT(layout); + USE_MEM(mem); + USE_VARS(vars); + + Editing_File temp_file; + if (file_create(system, mem, &temp_file, make_c_str(file->source_path), style->font)){ + file_close(system, &mem->general, file); + *file = temp_file; + file->source_path.str = file->source_path_; + file->live_name.str = file->live_name_; +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + if (file->tokens_exist) + file_first_lex_parallel(system, &mem->general, file); +#endif + + Partition old_part = command->part; + Temp_Memory temp = begin_temp_memory(&vars->mem.part); + command->part = partition_sub_part(&vars->mem.part, 16 << 10); + + view_set_file(system, + view, file, style, + vars->hooks[hook_open_file], command, app_links); + + command->part = old_part; + end_temp_memory(temp); + + i32 panel_count = layout->panel_count; + Panel *panels = layout->panels; + for (i32 i = 0; i < panel_count; ++i){ + Panel *current_panel = panels + i; + View *current_view_ = current_panel->view; + File_View *current_view = view_to_file_view(current_view_); + if (current_view && current_view != view && current_view->file == file){ + view_set_file(system, current_view, current_view->file, style, 0, command, app_links); + } + } + } +#endif +} + +COMMAND_DECL(save){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_VARS(vars); + USE_MEM(mem); + USE_EXCHANGE(exchange); + USE_WORKING_SET(working_set); + + String *file_path = &file->state.source_path; + if (file_path->size > 0){ + i32 sys_id = file_save(system, exchange, mem, file, file_path->str); + app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); + } +} + +COMMAND_DECL(interactive_save_as){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_MEM(mem); + USE_WORKING_SET(working_set); + USE_STYLE(style); + USE_DELAY(delay); + USE_EXCHANGE(exchange); + USE_FONT_SET(font_set); + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + Interactive_View *int_view = + interactive_view_init(system, new_view, &vars->hot_directory, style, + working_set, font_set, delay); + int_view->interaction = INTV_SYS_FILE_LIST; + int_view->action = INTV_SAVE_AS; + copy(&int_view->query, "Save As: "); +} + +COMMAND_DECL(change_active_panel){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + if (layout->panel_count > 1){ + ++layout->active_panel; + if (layout->active_panel >= layout->panel_count){ + layout->active_panel = 0; + } + } +} + +COMMAND_DECL(interactive_switch_buffer){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_MEM(mem); + USE_WORKING_SET(working_set); + USE_STYLE(style); + USE_DELAY(delay); + USE_EXCHANGE(exchange); + USE_FONT_SET(font_set); + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + Interactive_View *int_view = + interactive_view_init(system, new_view, &vars->hot_directory, style, + working_set, font_set, delay); + int_view->interaction = INTV_LIVE_FILE_LIST; + int_view->action = INTV_SWITCH; + copy(&int_view->query, "Switch File: "); +} + +COMMAND_DECL(interactive_kill_buffer){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_MEM(mem); + USE_WORKING_SET(working_set); + USE_STYLE(style); + USE_DELAY(delay); + USE_EXCHANGE(exchange); + USE_FONT_SET(font_set); + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + Interactive_View *int_view = + interactive_view_init(system, new_view, &vars->hot_directory, style, + working_set, font_set, delay); + int_view->interaction = INTV_LIVE_FILE_LIST; + int_view->action = INTV_KILL; + copy(&int_view->query, "Kill File: "); +} + +COMMAND_DECL(kill_buffer){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_DELAY(delay); + + delayed_action(delay, DACT_TRY_KILL, file->state.live_name, view->view_base.panel); +} + +COMMAND_DECL(toggle_line_wrap){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + Relative_Scrolling scrolling = view_get_relative_scrolling(view); + if (view->unwrapped_lines){ + view->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; + 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 = get_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){ +#if 0 + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + if (file->token_stack.tokens && file->tokens_complete){ + Range range = get_range(view->cursor.pos, view->mark); + view_auto_tab_tokens(mem, view, layout, range.start, range.end); + } +#endif +} + +COMMAND_DECL(auto_tab_range){ + 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){ + Range range = get_range(view->cursor.pos, view->mark); + view_auto_tab_tokens(system, mem, view, layout, range.start, range.end, 1); + } +} + +COMMAND_DECL(auto_tab_line_at_cursor){ + 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){ + i32 pos = view->cursor.pos; + view_auto_tab_tokens(system, mem, view, layout, pos, pos, 0); + } +} + +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); + + i32 panel_count = layout->panel_count; + if (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); + } +} + +COMMAND_DECL(open_panel_hsplit){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + + i32 panel_count = layout->panel_count; + if (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); + } +} + +COMMAND_DECL(close_panel){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + USE_VIEW(view); + USE_EXCHANGE(exchange); + + if (layout->panel_count > 1){ + if (view){ + live_set_free_view(system, exchange, command->live_set, view); + panel->view = 0; + } + + Divider_And_ID div = layout_get_divider(layout, panel->parent); + Assert(div.divider->child1 == -1 || div.divider->child2 == -1); + + i32 child; + if (div.divider->child1 == -1){ + child = div.divider->child2; + } + else{ + child = div.divider->child1; + } + + i32 parent = div.divider->parent; + i32 which_child = div.divider->which_child; + if (parent != -1){ + Divider_And_ID par = layout_get_divider(layout, parent); + if (which_child == -1){ + par.divider->child1 = child; + } + else{ + par.divider->child2 = child; + } + } + else{ + Assert(layout->root == div.id); + layout->root = child; + } + + if (child != -1){ + Divider_And_ID chi = layout_get_divider(layout, child); + chi.divider->parent = parent; + chi.divider->which_child = div.divider->which_child; + } + + layout_free_divider(layout, div.divider); + layout_free_panel(layout, panel); + + if (child == -1){ + panel = layout->panels; + layout->active_panel = -1; + for (i32 i = 0; i < layout->panel_count; ++i){ + if (panel->parent == div.id){ + panel->parent = parent; + panel->which_child = which_child; + layout->active_panel = i; + break; + } + ++panel; + } + Assert(layout->active_panel != -1); + } + else{ + layout->active_panel = layout->active_panel % layout->panel_count; + } + + 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; + + i32 shift = (end - start); + Assert(shift > 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); + + real32 height = view_compute_height(view); + real32 max_target_y = view_compute_max_target_y(view); + real32 cursor_y = view_get_cursor_y(view); + + view->target_y += height; + if (view->target_y > max_target_y) view->target_y = max_target_y; + + if (view->target_y >= cursor_y){ + view->cursor = + view_compute_cursor_from_xy(view, 0, view->target_y); + } +} + +COMMAND_DECL(page_up){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + real32 height = view_compute_height(view); + real32 cursor_y = view_get_cursor_y(view); + + view->target_y -= height; + if (view->target_y < 0) view->target_y = 0; + + if (view->target_y + height <= cursor_y){ + view->cursor = + view_compute_cursor_from_xy(view, 0, view->target_y + height - view->font_height); + } +} + +inline void +open_theme_options(System_Functions *system, Exchange *exchange, + App_Vars *vars, Live_Views *live_set, Mem_Options *mem, Panel *panel){ + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + Color_View *color_view = color_view_init(new_view, &vars->working_set); + color_view->hot_directory = &vars->hot_directory; + color_view->main_style = &vars->style; + color_view->styles = &vars->styles; + color_view->palette = vars->palette; + color_view->palette_size = vars->palette_size; + color_view->font_set = vars->font_set; +} + +COMMAND_DECL(open_color_tweaker){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_LIVE_SET(live_set); + USE_MEM(mem); + USE_PANEL(panel); + USE_EXCHANGE(exchange); + + open_theme_options(system, exchange, vars, live_set, mem, panel); +} + +COMMAND_DECL(open_menu){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_MEM(mem); + USE_WORKING_SET(working_set); + USE_STYLE(style); + USE_EXCHANGE(exchange); + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + Menu_View *menu_view = menu_view_init(new_view, style, working_set, + &vars->delay, vars->font_set); + AllowLocal(menu_view); +} + +#if FRED_INTERNAL +COMMAND_DECL(open_debug_view){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_STYLE(style); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_MEM(mem); + USE_EXCHANGE(exchange); + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_major(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_debug; + Debug_View *debug_view = debug_view_init(new_view); + debug_view->font_id = style->font_id; + debug_view->mode = DBG_MEMORY; +} + +COMMAND_DECL(debug_memory){ + ProfileMomentFunction(); + REQ_DBG_VIEW(view); + view->mode = DBG_MEMORY; +} + +COMMAND_DECL(debug_os_events){ + ProfileMomentFunction(); + REQ_DBG_VIEW(view); + view->mode = DBG_OS_EVENTS; +} + +#endif + +COMMAND_DECL(close_minor_view){ + ProfileMomentFunction(); + REQ_VIEW(view); + USE_PANEL(panel); + USE_LIVE_SET(live_set); + USE_EXCHANGE(exchange); + + view_remove_minor(system, exchange, panel, live_set); +} + +COMMAND_DECL(cursor_mark_swap){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + i32 pos = view->cursor.pos; + view->cursor = view_compute_cursor_from_pos(view, view->mark); + view->mark = pos; +} + +COMMAND_DECL(user_callback){ + ProfileMomentFunction(); + if (binding.custom) binding.custom(command, &app_links); +} + +COMMAND_DECL(set_settings){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_LOADING(file, view); + USE_VARS(vars); + USE_MEM(mem); + AllowLocal(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; + 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; + + 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_user_custom){ + 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, + 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, file, buffer_name, font_set, style->font_id); + table_add(&working_set->table, file->state.live_name, index); + + if (bind_to_new_view){ + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_major(system, exchange, new_view, panel, live_set); + + File_View *file_view = file_view_init(new_view, layout); + view_set_file(system, file_view, file, font_set, style, + vars->hooks[hook_open_file], command, &app_links); + new_view->map = app_get_map(vars, file->settings.base_map_id); + + } + + 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(build){ + 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_target_buffer_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, + buffer_name, buffer_name_len, + path, path_len, + script, script_len, + flags); +} + +COMMAND_DECL(build_here){ + 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); + + u32 flags = 0; + + char *buffer_name = "*compilation*"; + int buffer_name_len = sizeof("*compilation*")-1; + + char path_space[512]; + String path = make_fixed_width_string(path_space); + path.size = app_links.directory_get_hot(command, path.str, path.memory_size); + + char dir_space[512]; + String dir = make_fixed_width_string(dir_space); + dir.size = app_links.directory_get_hot(command, dir.str, dir.memory_size); + + for (;;){ + if (app_links.directory_has_file(dir, "build.bat")){ + if (append(&dir, "build")){ + break; + } + } + + if (app_links.directory_cd(&dir, "..") == 0){ + copy(&dir, "build"); + break; + } + } + terminate_with_null(&dir); + + build(system, mem, vars, working_set, + font_set, style, live_set, exchange, + panel, command, + buffer_name, buffer_name_len, + path.str, path.size, + dir.str, dir.size, + flags); +} + +internal void +update_command_data(App_Vars *vars, Command_Data *cmd){ + Command_Data command_data; + command_data.vars = vars; + command_data.mem = &vars->mem; + command_data.working_set = &vars->working_set; + command_data.layout = &vars->layout; + command_data.panel = command_data.layout->panels + command_data.layout->active_panel; + command_data.view = command_data.panel->view; + command_data.live_set = &vars->live_set; + command_data.style = &vars->style; + command_data.delay = &vars->delay; + command_data.screen_width = cmd->screen_width; + command_data.screen_height = cmd->screen_height; + command_data.key = cmd->key; + command_data.part = cmd->part; + command_data.system = cmd->system; + command_data.exchange = cmd->exchange; + + *cmd = command_data; +} + +COMPOSE_DECL(compose_write_auto_tab_line){ + command_write_character(system, command, binding); + update_command_data(command->vars, command); + command_auto_tab_line_at_cursor(system, command, binding); + update_command_data(command->vars, command); +} + +globalvar Command_Function command_table[cmdid_count]; + +extern "C"{ + EXECUTE_COMMAND_SIG(external_exec_command_keep_stack){ + Command_Data *cmd = (Command_Data*)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*)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*)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*)cmd_context; + cmd->part.pos = 0; + } + + GET_ACTIVE_BUFFER_SIG(external_get_active_buffer){ + Command_Data *cmd = (Command_Data*)cmd_context; + Buffer_Summary buffer = {}; + + File_View *view = view_to_file_view(cmd->view); + if (view){ + Editing_File *file = view->file; + if (file && !file->state.is_dummy){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Working_Set *working_set = cmd->working_set; + buffer.file_id = (int)(file - working_set->files); + buffer.size = file->state.buffer.size; + buffer.file_name_len = file->state.source_path.size; + buffer.buffer_name_len = file->state.live_name.size; + buffer.file_name = file->state.source_path.str; + buffer.buffer_name = file->state.live_name.str; + buffer.file_cursor_pos = file->state.cursor_pos; + buffer.is_lexed = file->settings.tokens_exist; + buffer.map_id = file->settings.base_map_id; +#endif + } + } + + return(buffer); + } + + DIRECTORY_GET_HOT_SIG(external_directory_get_hot){ + Command_Data *cmd = (Command_Data*)cmd_context; + Hot_Directory *hot = &cmd->vars->hot_directory; + i32 copy_max = max - 1; + hot_directory_clean_end(hot); + if (copy_max > hot->string.size) + copy_max = hot->string.size; + memcpy(buffer, hot->string.str, copy_max); + buffer[copy_max] = 0; + return(copy_max); + } +} + +inline void +app_links_init(System_Functions *system){ + 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.get_active_buffer = external_get_active_buffer; + app_links.directory_get_hot = external_directory_get_hot; + app_links.directory_has_file = system->directory_has_file; + app_links.directory_cd = system->directory_cd; +} + +#if FRED_INTERNAL +internal void +setup_debug_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ + map_init(commands, part, 6, parent); + + map_add(commands, 'm', MDFR_NONE, command_debug_memory); + map_add(commands, 'o', MDFR_NONE, command_debug_os_events); +} +#endif + +internal void +setup_ui_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ + map_init(commands, part, 12, parent); + + commands->vanilla_keyboard_default.function = command_null; + + map_add(commands, codes->left, MDFR_NONE, command_null); + map_add(commands, codes->right, MDFR_NONE, command_null); + map_add(commands, codes->up, MDFR_NONE, command_null); + map_add(commands, codes->down, MDFR_NONE, command_null); + map_add(commands, codes->back, MDFR_NONE, command_null); + map_add(commands, codes->esc, MDFR_NONE, command_close_minor_view); +} + +internal void +setup_file_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ + map_init(commands, part, 101, parent); + + commands->vanilla_keyboard_default.function = command_write_character; + + map_add(commands, codes->left, MDFR_NONE, command_move_left); + map_add(commands, codes->right, MDFR_NONE, command_move_right); + map_add(commands, codes->del, MDFR_NONE, command_delete); + map_add(commands, codes->back, MDFR_NONE, command_backspace); + map_add(commands, codes->up, MDFR_NONE, command_move_up); + map_add(commands, codes->down, MDFR_NONE, command_move_down); + map_add(commands, codes->end, MDFR_NONE, command_seek_end_of_line); + map_add(commands, codes->home, MDFR_NONE, command_seek_beginning_of_line); + map_add(commands, codes->page_up, MDFR_NONE, command_page_up); + map_add(commands, codes->page_down, MDFR_NONE, command_page_down); + + map_add(commands, codes->right, MDFR_CTRL, command_seek_alphanumeric_or_camel_right); + map_add(commands, codes->left, MDFR_CTRL, command_seek_alphanumeric_or_camel_left); + map_add(commands, codes->up, MDFR_CTRL, command_seek_whitespace_up); + map_add(commands, codes->down, MDFR_CTRL, command_seek_whitespace_down); + + map_add(commands, ' ', MDFR_CTRL, command_set_mark); + map_add(commands, 'm', MDFR_CTRL, command_cursor_mark_swap); + map_add(commands, 'c', MDFR_CTRL, command_copy); + map_add(commands, 'x', MDFR_CTRL, command_cut); + map_add(commands, 'v', MDFR_CTRL, command_paste); + map_add(commands, 'V', MDFR_CTRL, command_paste_next); + map_add(commands, 'z', MDFR_CTRL, command_undo); + map_add(commands, 'y', MDFR_CTRL, command_redo); + map_add(commands, 'Z', MDFR_CTRL, command_timeline_scrub); + map_add(commands, codes->left, MDFR_ALT, command_increase_rewind_speed); + map_add(commands, codes->right, MDFR_ALT, command_increase_fastforward_speed); + map_add(commands, codes->down, MDFR_ALT, command_stop_rewind_fastforward); + map_add(commands, 'h', MDFR_CTRL, command_history_backward); + map_add(commands, 'H', MDFR_CTRL, command_history_forward); + map_add(commands, 'd', MDFR_CTRL, command_delete_range); + map_add(commands, 'l', MDFR_CTRL, command_toggle_line_wrap); + map_add(commands, '?', MDFR_CTRL, command_toggle_show_whitespace); + map_add(commands, '|', MDFR_CTRL, command_toggle_tokens); + map_add(commands, 'u', MDFR_CTRL, command_to_uppercase); + map_add(commands, 'j', MDFR_CTRL, command_to_lowercase); + map_add(commands, '~', MDFR_CTRL, command_clean_all_lines); + map_add(commands, 'f', MDFR_CTRL, command_search); + map_add(commands, 'r', MDFR_CTRL, command_rsearch); + map_add(commands, 'g', MDFR_CTRL, command_goto_line); + + map_add(commands, '\n', MDFR_NONE, compose_write_auto_tab_line); + map_add(commands, '}', MDFR_NONE, compose_write_auto_tab_line); + map_add(commands, ')', MDFR_NONE, compose_write_auto_tab_line); + map_add(commands, ']', MDFR_NONE, compose_write_auto_tab_line); + map_add(commands, ';', MDFR_NONE, compose_write_auto_tab_line); + + map_add(commands, '\t', MDFR_NONE, command_auto_tab_line_at_cursor); + map_add(commands, '\t', MDFR_CTRL, command_auto_tab_range); + map_add(commands, '\t', MDFR_CTRL | MDFR_SHIFT, command_write_character); + + map_add(commands, 'K', MDFR_CTRL, command_kill_buffer); + map_add(commands, 'O', MDFR_CTRL, command_reopen); + map_add(commands, 's', MDFR_CTRL, command_save); + map_add(commands, 'w', MDFR_CTRL, command_interactive_save_as); + +#if UseFileHistoryDump + map_add(commands, 'h', MDFR_ALT, command_save_history); +#endif +} + +internal void +setup_top_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ + map_init(commands, part, 51, parent); + +#if FRED_INTERNAL + map_add(commands, 'd', MDFR_ALT, command_open_debug_view); +#endif + + map_add(commands, 'p', MDFR_CTRL, command_open_panel_vsplit); + map_add(commands, '-', MDFR_CTRL, command_open_panel_hsplit); + map_add(commands, 'P', MDFR_CTRL, command_close_panel); + map_add(commands, 'n', MDFR_CTRL, command_interactive_new); + map_add(commands, 'o', MDFR_CTRL, command_interactive_open); + map_add(commands, ',', MDFR_CTRL, command_change_active_panel); + map_add(commands, 'k', MDFR_CTRL, command_interactive_kill_buffer); + map_add(commands, 'i', MDFR_CTRL, command_interactive_switch_buffer); + map_add(commands, 'c', MDFR_ALT, command_open_color_tweaker); + map_add(commands, 'x', MDFR_ALT, command_open_menu); + map_add(commands, 'm', MDFR_ALT, command_build_here); +} + +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(search); + SET(rsearch); + SET(goto_line); + SET(set_mark); + SET(copy); + SET(cut); + SET(paste); + SET(paste_next); + SET(delete_range); + SET(timeline_scrub); + SET(undo); + SET(redo); + SET(increase_rewind_speed); + SET(increase_fastforward_speed); + SET(stop_rewind_fastforward); + 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); + 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(build); + +#undef SET +} + +// Interactive Bar + +internal void +hot_directory_draw_helper(Render_Target *target, + Hot_Directory *hot_directory, + Interactive_Bar *bar, String *string, + bool32 include_files){ + persist u8 str_open_bracket[] = " {"; + persist u8 str_close_bracket[] = "}"; + persist u8 str_comma[] = ", "; + + intbar_draw_string(target, bar, *string, bar->style.pop1_color); + intbar_draw_string(target, bar, str_open_bracket, bar->style.base_color); + + char front_name_[256]; + String front_name = make_fixed_width_string(front_name_); + get_front_of_directory(&front_name, *string); + + bool32 is_first_string = 1; + File_List *files = &hot_directory->file_list; + + Absolutes absolutes; + get_absolutes(front_name, &absolutes, 1, 1); + + File_Info *info, *end; + end = files->infos + files->count; + for (info = files->infos; info != end; ++info){ + String filename = info->filename; + + if (filename_match(front_name, &absolutes, filename)){ + if (is_first_string){ + is_first_string = 0; + } + else{ + intbar_draw_string(target, bar, str_comma, bar->style.base_color); + } + if (info->folder){ + intbar_draw_string(target, bar, filename, bar->style.pop1_color); + intbar_draw_string(target, bar, (u8*)"/", bar->style.pop1_color); + } + else{ + intbar_draw_string(target, bar, filename, bar->style.base_color); + } + } + } + + intbar_draw_string(target, bar, str_close_bracket, bar->style.base_color); +} + +internal void +live_file_draw_helper(Render_Target *target, Working_Set *working_set, + Interactive_Bar *bar, String *string){ + persist u8 str_open_bracket[] = " {"; + persist u8 str_close_bracket[] = "}"; + persist u8 str_comma[] = ", "; + + intbar_draw_string(target, bar, *string, bar->style.base_color); + + intbar_draw_string(target, bar, str_open_bracket, bar->style.base_color); + + bool32 is_first_string = 1; + for (i32 file_i = 0; + file_i < working_set->file_index_count; + ++file_i){ + Editing_File *file = &working_set->files[file_i]; + if (file->state.live_name.str && + (string->size == 0 || has_substr_unsensitive(file->state.live_name, *string))){ + if (is_first_string){ + is_first_string = 0; + } + else{ + intbar_draw_string(target, bar, str_comma, bar->style.base_color); + } + intbar_draw_string(target, bar, file->state.live_name, bar->style.base_color); + } + } + intbar_draw_string(target, bar, str_close_bracket, bar->style.base_color); +} + +// 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 = 0xFF191970; + 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 = 0xFF1504CF; + 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; +} + +HOOK_SIG(default_open_file_hook){ + Buffer_Summary buffer = app->get_active_buffer(cmd_context); + + int treat_as_code = 0; + + if (buffer.file_name && buffer.size < (16 << 20)){ + int extension_len; + char *extension = _4coder_get_extension(buffer.file_name, buffer.file_name_len, &extension_len); + if (_4coder_str_match(extension, extension_len, literal("cpp"))) treat_as_code = 1; + else if (_4coder_str_match(extension, extension_len, literal("h"))) treat_as_code = 1; + else if (_4coder_str_match(extension, extension_len, literal("c"))) treat_as_code = 1; + else if (_4coder_str_match(extension, extension_len, literal("hpp"))) treat_as_code = 1; + } + + app->push_parameter(cmd_context, dynamic_int(par_lex_as_cpp_file), dynamic_int(treat_as_code)); + app->push_parameter(cmd_context, dynamic_int(par_wrap_lines), dynamic_int(!treat_as_code)); + app->push_parameter(cmd_context, dynamic_int(par_key_mapid), dynamic_int(mapid_file)); + + app->exec_command_keep_stack(cmd_context, cmdid_set_settings); + app->clear_parameters(cmd_context); +} + +App_Init_Sig(app_init){ + app_links_init(system); + + Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); + App_Vars *vars = push_struct(&_partition, App_Vars); + Assert(vars); + *vars = {}; + vars->config_api = api; + vars->mem.part = _partition; + Partition *partition = &vars->mem.part; + target->partition = partition; + general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); + + i32 panel_max_count = vars->layout.panel_max_count = 16; + i32 panel_count = vars->layout.panel_count = 1; + i32 divider_max_count = panel_max_count - 1; + + Panel *panels = vars->layout.panels = + push_array(partition, Panel, panel_max_count); + + Panel_Divider *dividers = vars->layout.dividers = + push_array(partition, Panel_Divider, divider_max_count); + + Panel_Divider *divider = dividers; + for (i32 i = 0; i < divider_max_count-1; ++i, ++divider){ + divider->next_free = (divider + 1); + } + divider->next_free = 0; + vars->layout.free_divider = dividers; + + vars->live_set.count = 0; + vars->live_set.max = 1 + 2*panel_max_count; + i32 view_sizes[] = { + sizeof(File_View), + sizeof(Color_View), + sizeof(Interactive_View), +#if FRED_INTERNAL + sizeof(Debug_View), +#endif + }; + + i32 view_chunk_size = 0; + for (i32 i = 0; i < ArrayCount(view_sizes); ++i){ + view_chunk_size = Max(view_chunk_size, view_sizes[i]); + } + vars->live_set.stride = view_chunk_size; + vars->live_set.views = (File_View*) + push_block(partition, view_chunk_size*vars->live_set.max); + + char *views_ = (char*)vars->live_set.views; + for (i32 i = panel_max_count-2; i >= 0; --i){ + View *view = (View*)(views_ + i*view_chunk_size); + View *view_next = (View*)((char*)view + view_chunk_size); + view->next_free = view_next; + } + { + View *view = (View*)(views_ + (panel_max_count-1)*view_chunk_size); + view->next_free = 0; + } + vars->live_set.free_view = (View*)views_; + + setup_command_table(); + + Command_Map *global = &vars->map_top; + if (vars->config_api.get_bindings){ + i32 size = partition_remaining(partition); + void *data = partition_current(partition); + + // TODO(allen): Use a giant bubble of general memory for this. + // So that it doesn't interfere with the command maps as they allocate + // their own memory. + i32 wanted_size = vars->config_api.get_bindings(data, size, loose_codes); + + bool32 did_top = 0; + bool32 did_file = 0; + if (wanted_size <= size){ + partition_allocate(partition, wanted_size); + + Binding_Unit *unit = (Binding_Unit*)data; + 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_user_custom){ + 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_user_custom){ + 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; + } + else{ + map_add(mapptr, unit->binding.code, unit->binding.modifiers, func); + } + } + } + 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; + } + } + } + } + + if (!did_top) setup_top_commands(&vars->map_top, &vars->mem.part, loose_codes, global); + if (!did_file) setup_file_commands(&vars->map_file, &vars->mem.part, loose_codes, global); + } + else{ + setup_top_commands(&vars->map_top, &vars->mem.part, loose_codes, global); + setup_file_commands(&vars->map_file, &vars->mem.part, loose_codes, global); + } + + setup_ui_commands(&vars->map_ui, &vars->mem.part, loose_codes, global); +#if FRED_INTERNAL + setup_debug_commands(&vars->map_debug, &vars->mem.part, loose_codes, global); +#endif + + if (vars->hooks[hook_open_file] == 0){ + vars->hooks[hook_open_file] = default_open_file_hook; + } + + vars->font_set = &target->font_set; + + font_set_init(vars->font_set, partition, 16, 4); + + { + 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); + } + +#if 0 + if (vars->config_api.set_extra_font){ + Extra_Font extra; + extra.size = 17; + vars->config_api.set_extra_font(&extra); + memory_used = 0; + if (app_load_font(target, + vars->fonts.fonts + font_count, extra.file_name, extra.size, + partition_current(partition), + &memory_used, 4, make_string_slowly(extra.font_name))){ + ++font_count; + } + else{ + vars->fonts.fonts[font_count] = {}; + } + push_block(partition, memory_used); + } + + vars->fonts.count = font_count; +#endif + } + + // NOTE(allen): file setup + vars->working_set.file_index_count = 1; + vars->working_set.file_max_count = 29; + 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->delay.max = ArrayCount(vars->delay.acts); + + // NOTE(allen): style setup + app_hardcode_styles(vars); + + vars->palette_size = 40; + vars->palette = push_array(partition, u32, vars->palette_size); + + AllowLocal(panel_count); + panel_init(&panels[0]); + + String hdbase = make_fixed_width_string(vars->hot_dir_base_); + hot_directory_init(&vars->hot_directory, hdbase, current_directory); + + 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); + + return 1; +} + +App_Step_Sig(app_step){ + ProfileStart(OS_syncing); + Application_Step_Result app_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; + } + + Panel *panels = vars->layout.panels; + Panel *active_panel = &panels[vars->layout.active_panel]; + + // NOTE(allen): OS clipboard event handling + 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): 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->state.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; + } + + Panel *panel = vars->layout.panels; + i32 panel_count = vars->layout.panel_count; + for (i32 i = 0; i < panel_count; ++i, ++panel){ + View *view = panel->view; + if (view && view->is_minor) view = view->major; + File_View *fview = view_to_file_view(view); + if (fview){ + 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 prev_y_off = 0; + i32 prev_x_off = 0; + + i32 y_off = 0; + i32 x_off = 0; + i32 full_width = vars->layout.full_width = target->width; + i32 full_height = vars->layout.full_height = target->height; + + if (prev_width != full_width || prev_height != full_height || + prev_x_off != x_off || prev_y_off != y_off){ + layout_refit(&vars->layout, prev_x_off, prev_y_off, prev_width, prev_height); + int view_count = vars->layout.panel_max_count; + for (i32 view_i = 0; view_i < view_count; ++view_i){ + View *view_ = live_set_get_view(&vars->live_set, view_i); + if (!view_->is_active) continue; + File_View *view = view_to_file_view(view_); + if (!view) continue; + view_measure_wraps(system, &vars->mem.general, view); + view->cursor = view_compute_cursor_from_pos(view, view->cursor.pos); + } + app_result.redraw = 1; + } + + // NOTE(allen): collect 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_Summary mouse_data; + mouse_data.mx = mouse->x; + mouse_data.my = mouse->y; + + mouse_data.l = mouse->left_button; + mouse_data.r = mouse->right_button; + mouse_data.press_l = mouse->left_button_pressed; + mouse_data.press_r = mouse->right_button_pressed; + mouse_data.release_l = mouse->left_button_released; + mouse_data.release_r = mouse->right_button_released; + + mouse_data.out_of_window = mouse->out_of_window; + mouse_data.wheel_used = (mouse->wheel != 0); + mouse_data.wheel_amount = -mouse->wheel; + ProfileEnd(OS_syncing); + + ProfileStart(hover_status); + // NOTE(allen): detect mouse hover status + i32 mx = mouse_data.mx; + i32 my = mouse_data.my; + b32 mouse_in_edit_area = 0; + b32 mouse_in_margin_area = 0; + Panel *mouse_panel = 0; + i32 mouse_panel_i = 0; + + { + Panel *panel = 0; + b32 in_edit_area = 0; + b32 in_margin_area = 0; + i32 panel_count = vars->layout.panel_count; + i32 panel_i; + + for (panel_i = 0; panel_i < panel_count; ++panel_i){ + panel = panels + panel_i; + if (hit_check(mx, my, panel->inner)){ + in_edit_area = 1; + break; + } + else if (hit_check(mx, my, panel->full)){ + in_margin_area = 1; + break; + } + } + + mouse_in_edit_area = in_edit_area; + mouse_in_margin_area = in_margin_area; + if (in_edit_area || in_margin_area){ + mouse_panel = panel; + mouse_panel_i = panel_i; + } + } + + 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){ + b32 resize_area = 0; + i32 divider_id = 0; + b32 seeking_v_divider = 0; + i32 seeking_child_on_side = 0; + Panel *panel = mouse_panel; + if (mx >= panel->inner.x0 && mx < panel->inner.x1){ + seeking_v_divider = 0; + if (my > panel->inner.y0){ + seeking_child_on_side = -1; + } + else{ + seeking_child_on_side = 1; + } + } + else{ + seeking_v_divider = 1; + if (mx > panel->inner.x0){ + seeking_child_on_side = -1; + } + else{ + seeking_child_on_side = 1; + } + } + mouse_divider_vertical = seeking_v_divider; + mouse_divider_side = seeking_child_on_side; + + if (vars->layout.panel_count > 1){ + i32 which_child; + divider_id = panel->parent; + which_child = panel->which_child; + for (;;){ + Divider_And_ID div = layout_get_divider(&vars->layout, divider_id); + + if (which_child == seeking_child_on_side && + div.divider->v_divider == seeking_v_divider){ + resize_area = 1; + break; + } + + if (divider_id == vars->layout.root){ + break; + } + else{ + divider_id = div.divider->parent; + which_child = div.divider->which_child; + } + } + + mouse_on_divider = resize_area; + mouse_divider_id = divider_id; + } + } + ProfileEnd(hover_status); + + ProfileStart(resizing); + // NOTE(allen): panel resizing + switch (vars->state){ + case APP_STATE_EDIT: + { + if (mouse_data.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_data.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; + } + ProfileEnd(resizing); + + ProfileStart(command); + // NOTE(allen): update active panel + if (mouse_in_edit_area && mouse_panel != 0 && mouse_data.press_l){ + active_panel = mouse_panel; + vars->layout.active_panel = mouse_panel_i; + app_result.redraw = 1; + } + + Command_Data command_data; + command_data.mem = &vars->mem; + command_data.panel = active_panel; + command_data.view = active_panel->view; + command_data.working_set = &vars->working_set; + command_data.layout = &vars->layout; + command_data.live_set = &vars->live_set; + command_data.style = &vars->style; + command_data.delay = &vars->delay; + command_data.vars = vars; + command_data.exchange = exchange; + command_data.screen_width = target->width; + command_data.screen_height = target->height; + command_data.system = system; + + Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part); + command_data.part = partition_sub_part(&vars->mem.part, 16 << 10); + + if (first_step && vars->hooks[hook_start]){ + vars->hooks[hook_start](&command_data, &app_links); + command_data.part.pos = 0; + } + + // NOTE(allen): command input to active view + for (i32 key_i = 0; key_i < key_data.count; ++key_i){ + Command_Binding cmd = {}; + Command_Map *map = 0; + View *view = active_panel->view; + + Key_Event_Data key = get_single_key(&key_data, key_i); + command_data.key = key; + + Command_Map *visited_maps[16] = {}; + i32 visited_top = 0; + + if (view) map = view->map; + if (map == 0) map = &vars->map_top; + while (map){ + cmd = map_extract(map, key); + if (cmd.function == 0){ + if (visited_top < ArrayCount(visited_maps)){ + visited_maps[visited_top++] = map; + map = map->parent; + for (i32 i = 0; i < visited_top; ++i){ + if (map == visited_maps[i]){ + map = 0; + break; + } + } + } + else map = 0; + } + else map = 0; + } + + switch (vars->state){ + case APP_STATE_EDIT: + { + Handle_Command_Function *handle_command = 0; + if (view) handle_command = view->handle_command; + if (handle_command){ + handle_command(system, view, &command_data, cmd, key, codes); + app_result.redraw = 1; + } + else{ + if (cmd.function){ + cmd.function(system, &command_data, cmd); + app_result.redraw = 1; + } + } + }break; + + case APP_STATE_RESIZING: + { + if (key_data.count > 0){ + vars->state = APP_STATE_EDIT; + } + }break; + } + } + + active_panel = panels + vars->layout.active_panel; + ProfileEnd(command); + + ProfileStart(step); + View *active_view = active_panel->view; + + Input_Summary dead_input = {}; + dead_input.mouse.mx = mouse_data.mx; + dead_input.mouse.my = mouse_data.my; + dead_input.codes = codes; + + Input_Summary active_input = {}; + dead_input.mouse.mx = mouse_data.mx; + dead_input.mouse.my = mouse_data.my; + active_input.keys = key_data; + active_input.codes = codes; + + // NOTE(allen): pass raw input to the panels + { + Panel *panel = panels; + for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ + View *view_ = panel->view; + if (view_){ + Assert(view_->do_view); + b32 active = (panel == active_panel); + Input_Summary input = (active)?(active_input):(dead_input); + if (panel == mouse_panel){ + input.mouse = mouse_data; + } + if (view_->do_view(system, exchange, view_, panel->inner, active_view, + VMSG_STEP, 0, &input, &active_input)){ + app_result.redraw = 1; + } + } + } + } + ProfileEnd(step); + + ProfileStart(delayed_actions); + if (vars->delay.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->delay.count; + vars->delay.count = 0; + + for (i32 i = 0; i < count; ++i){ + Delayed_Action *act = vars->delay.acts + i; + String *string = &act->string; + Panel *panel = act->panel; + + switch (act->type){ + case DACT_OPEN: + { + command_data.view = (View*) + app_open_file(system, vars, exchange, + live_set, working_set, panel, + &command_data, string->str, string->size); + }break; + + case DACT_SAVE_AS: + { + View *view = panel->view; + File_View *fview = view_to_file_view(view); + + if (!fview && view->is_minor) fview = view_to_file_view(view->major); + if (fview){ + Editing_File *file = fview->file; + if (file && !file->state.is_dummy){ + file_save_and_set_names(system, exchange, mem, file, string->str); + } + } + }break; + + case DACT_SAVE: + { + Editing_File *file = working_set_lookup_file(working_set, *string); + if (!file->state.is_dummy){ + file_save(system, exchange, mem, file, file->state.source_path.str); + } + }break; + + case DACT_NEW: + { + Get_File_Result file = working_set_get_available_file(working_set); + file_create_empty(system, mem, file.file, string->str, + vars->font_set, style->font_id); + table_add(&working_set->table, file.file->state.source_path, file.index); + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_major(system, exchange, new_view, panel, live_set); + + File_View *file_view = file_view_init(new_view, &vars->layout); + command_data.view = (View*)file_view; + view_set_file(system, file_view, file.file, vars->font_set, style, + vars->hooks[hook_open_file], &command_data, &app_links); + new_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 *new_view = live_set_alloc_view(live_set, mem); + view_replace_major(system, exchange, new_view, panel, live_set); + + File_View *file_view = file_view_init(new_view, &vars->layout); + command_data.view = (View*)file_view; + + view_set_file(system, file_view, file, vars->font_set, style, + vars->hooks[hook_open_file], &command_data, &app_links); + + new_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->state.source_path); + kill_file(system, exchange, general, file, live_set, &vars->layout); + } + }break; + + case DACT_TRY_KILL: + { + Editing_File *file = working_set_lookup_file(working_set, *string); + if (file){ + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: + case SYNC_GOOD: + { + table_remove(&working_set->table, file->state.source_path); + kill_file(system, exchange, general, file, live_set, &vars->layout); + view_remove_minor(system, exchange, panel, live_set); + }break; + + case SYNC_UNSAVED: + { + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + Interactive_View *int_view = + interactive_view_init(system, new_view, &vars->hot_directory, style, + working_set, vars->font_set, &vars->delay); + int_view->interaction = INTV_SURE_TO_KILL_INTER; + int_view->action = INTV_SURE_TO_KILL; + copy(&int_view->query, "Are you sure?"); + copy(&int_view->dest, file->state.live_name); + }break; + + default: Assert(!"invalid path"); + } + } + }break; + + case DACT_CLOSE_MINOR: + { + view_remove_minor(system, exchange, panel, live_set); + }break; + + case DACT_CLOSE_MAJOR: + { + view_remove_major(system, exchange, panel, live_set); + }break; + + case DACT_THEME_OPTIONS: + { + open_theme_options(system, exchange, vars, live_set, mem, panel); + }break; + } + } + } + ProfileEnd(delayed_actions); + + end_temp_memory(param_stack_temp); + + ProfileStart(resize); + // NOTE(allen): send resize messages to panels that have changed size + { + Panel *panel = panels; + for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ + 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, active_view, + VMSG_RESIZE, 0, &dead_input, &active_input); + view = (view->is_minor)?view->major:0; + if (view){ + view->do_view(system, exchange, + view, inner, active_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 = panels; + for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ + View *view = panel->view; + if (view){ + view->do_view(system, exchange, + view, panel->inner, active_view, + VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); + view = (view->is_minor)?view->major:0; + if (view){ + view->do_view(system, exchange, + view, panel->inner, active_view, + VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); + } + } + } + } + ProfileEnd(style_change); + + // NOTE(allen): processing bindings between system and application + ProfileStart(sys_app_bind_processing); + for (i32 i = 0; i < vars->sys_app_count; ++i){ + Sys_App_Binding *binding; + b32 remove = 0; + binding = vars->sys_app_bindings + i; + + byte *data; + i32 size, max; + + if (exchange_file_ready(exchange, binding->sys_id, &data, &size, &max)){ + Editing_File *ed_file = vars->working_set.files + binding->app_id; + char *filename = exchange_file_filename(exchange, binding->sys_id); + if (data){ + String val = make_string((char*)data, size); + file_create_from_string(system, &vars->mem, ed_file, filename, + vars->font_set, vars->style.font_id, val); + + if (ed_file->settings.tokens_exist) + file_first_lex_parallel(system, &vars->mem.general, ed_file); + + 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_file_loaded_init(system, iter.view, 0); + } + } + else{ + file_create_empty(system, &vars->mem, ed_file, filename, + vars->font_set, vars->style.font_id); + } + + exchange_free_file(exchange, binding->sys_id); + remove = 1; + } + + if (exchange_file_save_complete(exchange, binding->sys_id, &data, &size, &max)){ + Assert(remove == 0); + + if (data){ + general_memory_free(&vars->mem.general, data); + exchange_clear_file(exchange, binding->sys_id); + } + + Editing_File *file = get_file(&vars->working_set, binding->app_id); + if (file){ + file_synchronize_times(system, file, file->state.source_path.str); + } + + exchange_free_file(exchange, binding->sys_id); + remove = 1; + } + + if (remove){ + *binding = vars->sys_app_bindings[--vars->sys_app_count]; + --i; + } + } + ProfileEnd(sys_app_bind_processing); + + 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 = panels; + for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ + i32_Rect full = panel->full; + i32_Rect inner = panel->inner; + + View *view = panel->view; + Style *style = &vars->style; + + b32 active = (panel == active_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, active_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){ + View *view = mouse_panel->view; + if (view){ + app_result.mouse_cursor_type = view->mouse_cursor_type; + } + else{ + 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); + + return app_result; +} + +internal +App_Alloc_Sig(app_alloc){ + Mem_Options *mem = (Mem_Options*)(handle); + void *result = general_memory_allocate(&mem->general, size, 0); + return(result); +} + +internal +App_Free_Sig(app_free){ + Mem_Options *mem = (Mem_Options*)(handle); + general_memory_free(&mem->general, block); +} + +external App_Get_Functions_Sig(app_get_functions){ + App_Functions result = {}; + + result.init = app_init; + result.step = app_step; + + result.alloc = app_alloc; + result.free = app_free; + + return(result); +} + +// BOTTOM + diff --git a/4ed.h b/4ed.h index c417324c..f75bfa52 100644 --- a/4ed.h +++ b/4ed.h @@ -26,15 +26,17 @@ enum Key_Control{ CONTROL_KEY_SHIFT, CONTROL_KEY_CONTROL, CONTROL_KEY_ALT, + CONTROL_KEY_CAPS, // always last CONTROL_KEY_COUNT }; struct Key_Event_Data{ u8 keycode; - //u8 apply_shift; u8 character; u8 character_no_caps_lock; + + b8 modifiers[CONTROL_KEY_COUNT]; }; struct Key_Input_Data{ @@ -42,37 +44,28 @@ struct Key_Input_Data{ Key_Event_Data hold[KEY_INPUT_BUFFER_SIZE]; i32 press_count; i32 hold_count; - - b8 control_keys[CONTROL_KEY_COUNT]; - b8 caps_lock; }; struct Key_Summary{ i32 count; Key_Event_Data keys[KEY_INPUT_BUFFER_DSIZE]; - bool8 modifiers[CONTROL_KEY_COUNT]; }; -struct Key_Single{ - Key_Event_Data key; - b8 *modifiers; -}; - -inline Key_Single +inline Key_Event_Data get_single_key(Key_Summary *summary, i32 index){ Assert(index >= 0 && index < summary->count); - Key_Single key; - key.key = summary->keys[index]; - key.modifiers = summary->modifiers; + Key_Event_Data key; + key = summary->keys[index]; return key; } struct Mouse_State{ b32 out_of_window; - b32 left_button, right_button; - b32 left_button_prev, right_button_prev; - i32 x, y; + b8 left_button, right_button; + b8 left_button_pressed, right_button_pressed; + b8 left_button_released, right_button_released; i16 wheel; + i32 x, y; }; struct Mouse_Summary{ @@ -135,7 +128,7 @@ struct Exchange{ Key_Codes *loose_codes, \ Clipboard_Contents clipboard, \ String current_directory, \ - Config_API api) + Custom_API api) typedef App_Init_Sig(App_Init); diff --git a/4ed_color_view.cpp b/4ed_color_view.cpp index 6c7b88fe..e2c95427 100644 --- a/4ed_color_view.cpp +++ b/4ed_color_view.cpp @@ -190,7 +190,7 @@ draw_rgb_slider(Render_Target *target, Vec4 base, i32 channel, } internal void -do_label(UI_State *state, UI_Layout *layout, char *text, f32 height = 2.f){ +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; i32 line_height = get_font_info(state->font_set, font_id)->height; @@ -202,11 +202,18 @@ do_label(UI_State *state, UI_Layout *layout, char *text, f32 height = 2.f){ u32 fore = style->main.default_color; draw_rectangle(target, label, back); i32 height = label.y1 - label.y0; - draw_string(target, font_id, text, label.x0, + + String textstr = make_string(text, text_size); + draw_string(target, font_id, textstr, label.x0, label.y0 + (height - line_height)/2, fore); } } +inline void +do_label(UI_State *state, UI_Layout *layout, String text, f32 height = 2.f){ + do_label(state, layout, text.str, text.size, height); +} + internal void do_scroll_bar(UI_State *state, i32_Rect rect){ i32 id = 1; @@ -447,19 +454,19 @@ do_channel_field(i32 sub_id, Color_UI *ui, u8 *channel, Channel_Field_Type ftype Key_Summary *keys = ui->state.keys; Key_Codes *codes = ui->state.codes; for (i32 key_i = 0; key_i < keys->count; ++key_i){ - Key_Single key = get_single_key(keys, key_i); + Key_Event_Data key = get_single_key(keys, key_i); - if (key.key.keycode == codes->right){ + if (key.keycode == codes->right){ ++indx; if (indx > digit_count-1) indx = 0; } - if (key.key.keycode == codes->left){ + if (key.keycode == codes->left){ --indx; if (indx < 0) indx = digit_count-1; } i32 new_value = *channel; - if (key.key.keycode == codes->up || key.key.keycode == codes->down){ + if (key.keycode == codes->up || key.keycode == codes->down){ i32 place = digit_count-1-indx; i32 base = (ftype == CF_DEC)?10:0x10; i32 step_amount = 1; @@ -467,13 +474,13 @@ do_channel_field(i32 sub_id, Color_UI *ui, u8 *channel, Channel_Field_Type ftype step_amount *= base; --place; } - if (key.key.keycode == codes->down){ + if (key.keycode == codes->down){ step_amount = 0 - step_amount; } new_value += step_amount; } - u8 c = (u8)key.key.character; + u8 c = (u8)key.character; bool32 is_good = (ftype == CF_DEC)?char_is_numeric(c):char_is_hex(c); if (is_good){ string_buffer[indx] = c; @@ -1563,7 +1570,7 @@ step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem switch (mode){ case CV_MODE_LIBRARY: { - do_label(&ui.state, &ui.layout, "Current Theme - Click to Edit"); + do_label(&ui.state, &ui.layout, literal("Current Theme - Click to Edit")); if (do_style_preview(&ui, color_view->main_style)){ color_view->mode = CV_MODE_ADJUSTING; color_view->state.selected = {}; @@ -1592,7 +1599,7 @@ step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem memset(color_view->import_export_check, 0, sizeof(color_view->import_export_check)); } - do_label(&ui.state, &ui.layout, "Theme Library - Click to Select"); + do_label(&ui.state, &ui.layout, literal("Theme Library - Click to Select")); i32 style_count = color_view->styles->count; Style *style = color_view->styles->styles; @@ -1606,12 +1613,12 @@ step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem case CV_MODE_IMPORT_FILE: { - do_label(&ui.state, &ui.layout, "Current Theme"); + do_label(&ui.state, &ui.layout, literal("Current Theme")); do_style_preview(&ui, color_view->main_style); b32 file_selected = 0; - do_label(&ui.state, &ui.layout, "Import Which File?"); + 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, color_view->p4c_only)){ color_view->p4c_only = !color_view->p4c_only; @@ -1671,12 +1678,12 @@ step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem case CV_MODE_EXPORT_FILE: { - do_label(&ui.state, &ui.layout, "Current Theme"); + do_label(&ui.state, &ui.layout, literal("Current Theme")); do_style_preview(&ui, color_view->main_style); b32 file_selected = 0; - do_label(&ui.state, &ui.layout, "Export File Name?"); + 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; @@ -1722,14 +1729,14 @@ step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem case CV_MODE_IMPORT: { - do_label(&ui.state, &ui.layout, "Current Theme"); + do_label(&ui.state, &ui.layout, literal("Current Theme")); do_style_preview(&ui, color_view->main_style); i32 style_count = color_view->inspecting_styles.count; Style *styles = color_view->inspecting_styles.styles; bool8 *import_check = color_view->import_export_check; - do_label(&ui.state, &ui.layout, "Pack"); + 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; @@ -1753,10 +1760,10 @@ step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem case CV_MODE_EXPORT: { - do_label(&ui.state, &ui.layout, "Current Theme"); + do_label(&ui.state, &ui.layout, literal("Current Theme")); do_style_preview(&ui, color_view->main_style); - do_label(&ui.state, &ui.layout, "Export Which Themes?"); + 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)){ color_view->mode = CV_MODE_EXPORT_FILE; diff --git a/4ed_command.cpp b/4ed_command.cpp index faf43d0a..8a378312 100644 --- a/4ed_command.cpp +++ b/4ed_command.cpp @@ -126,7 +126,7 @@ apply_shift_to_code(u8 keycode){ } internal Command_Binding -map_extract(Command_Map *map, Key_Single key){ +map_extract(Command_Map *map, Key_Event_Data key){ Command_Binding bind = {}; b32 ctrl = key.modifiers[CONTROL_KEY_CONTROL]; @@ -135,16 +135,16 @@ map_extract(Command_Map *map, Key_Single key){ u16 code; u8 command = MDFR_NONE; - if (key.key.character_no_caps_lock != 0 && - key.key.character_no_caps_lock != ' ') shift = 0; + if (key.character_no_caps_lock != 0 && + key.character_no_caps_lock != ' ') shift = 0; if (shift) command |= MDFR_SHIFT; if (ctrl) command |= MDFR_CTRL; if (alt) command |= MDFR_ALT; - code = key.key.character_no_caps_lock; + code = key.character_no_caps_lock; if (code == 0){ - code = key.key.keycode; + code = key.keycode; map_find(map, code, command, &bind); } else{ diff --git a/4ed_debug_view.cpp b/4ed_debug_view.cpp index cdc83988..558a9c27 100644 --- a/4ed_debug_view.cpp +++ b/4ed_debug_view.cpp @@ -218,9 +218,12 @@ draw_os_events(Debug_View *view, i32_Rect rect, Render_Target *target, i16 font_id = view->font_id; i32 line_height = get_font_info(&target->font_set, font_id)->height; - + +#if 0 draw_modifiers(view, target, active_input->keys.modifiers, 0xFFFFFFFF, 0xFF444444, &x, y); +#endif + max_x = x; x = rect.x0; y += line_height; @@ -325,7 +328,8 @@ step_debug_view(Debug_View *view, i32_Rect rect, Render_Target *target, Input_Summary *active_input){ persist i32 max_past = ArrayCount(view->past_keys); - bool8 *modifiers = active_input->keys.modifiers; +#if 0 + b8 *modifiers = active_input->keys.modifiers; for (i32 i = 0; i < active_input->keys.count; ++i){ Dbg_Past_Key *past_key = view->past_keys + view->past_key_pos; ++view->past_key_pos; @@ -350,6 +354,7 @@ step_debug_view(Debug_View *view, i32_Rect rect, Render_Target *target, if (active_input->mouse.wheel_used) view->prev_mouse_wheel = active_input->mouse.wheel_amount; +#endif } internal diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index f663b1e2..9c40a8e2 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -95,6 +95,7 @@ struct Editing_File_Settings{ i32 dos_write_mode; b32 tokens_exist; b32 super_locked; + b32 is_initialized; }; // NOTE(allen): This part of the Editing_File is cleared whenever @@ -425,10 +426,10 @@ struct Single_Line_Mode{ internal Single_Line_Input_Step app_single_line_input_core(System_Functions *system, Key_Codes *codes, Working_Set *working_set, - Key_Single key, Single_Line_Mode mode){ + Key_Event_Data key, Single_Line_Mode mode){ Single_Line_Input_Step result = {}; - if (key.key.keycode == codes->back){ + if (key.keycode == codes->back){ result.hit_backspace = 1; if (mode.string->size > 0){ result.made_a_change = 1; @@ -453,7 +454,7 @@ app_single_line_input_core(System_Functions *system, } } - else if (key.key.character == '\n' || key.key.character == '\t'){ + else if (key.character == '\n' || key.character == '\t'){ result.made_a_change = 1; if (key.modifiers[CONTROL_KEY_CONTROL] || key.modifiers[CONTROL_KEY_ALT]){ @@ -490,17 +491,17 @@ app_single_line_input_core(System_Functions *system, } } - else if (key.key.keycode == codes->esc){ + else if (key.keycode == codes->esc){ result.hit_esc = 1; result.made_a_change = 1; } - else if (key.key.character){ + else if (key.character){ result.hit_a_character = 1; if (!key.modifiers[CONTROL_KEY_CONTROL] && !key.modifiers[CONTROL_KEY_ALT]){ if (mode.string->size+1 < mode.string->memory_size){ - u8 new_character = (u8)key.key.character; + u8 new_character = (u8)key.character; mode.string->str[mode.string->size] = new_character; mode.string->size++; mode.string->str[mode.string->size] = 0; @@ -521,7 +522,7 @@ app_single_line_input_core(System_Functions *system, inline Single_Line_Input_Step app_single_line_input_step(System_Functions *system, - Key_Codes *codes, Key_Single key, String *string){ + Key_Codes *codes, Key_Event_Data key, String *string){ Single_Line_Mode mode = {}; mode.type = SINGLE_LINE_STRING; mode.string = string; @@ -530,7 +531,7 @@ app_single_line_input_step(System_Functions *system, inline Single_Line_Input_Step app_single_file_input_step(System_Functions *system, - Key_Codes *codes, Working_Set *working_set, Key_Single key, + Key_Codes *codes, Working_Set *working_set, Key_Event_Data key, String *string, Hot_Directory *hot_directory, bool32 fast_folder_select){ Single_Line_Mode mode = {}; @@ -543,13 +544,13 @@ app_single_file_input_step(System_Functions *system, inline Single_Line_Input_Step app_single_number_input_step(System_Functions *system, - Key_Codes *codes, Key_Single key, String *string){ + Key_Codes *codes, Key_Event_Data key, String *string){ Single_Line_Input_Step result = {}; Single_Line_Mode mode = {}; mode.type = SINGLE_LINE_STRING; mode.string = string; - char c = (char)key.key.character; + char c = (char)key.character; if (c == 0 || c == '\n' || char_is_numeric(c)) result = app_single_line_input_core(system, codes, 0, key, mode); return result; @@ -936,8 +937,8 @@ ui_do_text_field_input(UI_State *state, String *str){ bool32 result = 0; Key_Summary *keys = state->keys; for (i32 key_i = 0; key_i < keys->count; ++key_i){ - Key_Single key = get_single_key(keys, key_i); - char c = (char)key.key.character; + Key_Event_Data key = get_single_key(keys, key_i); + char c = (char)key.character; if (char_is_basic(c) && str->size < str->memory_size-1){ str->str[str->size++] = c; str->str[str->size] = 0; @@ -945,7 +946,7 @@ ui_do_text_field_input(UI_State *state, String *str){ else if (c == '\n'){ result = 1; } - else if (key.key.keycode == state->codes->back && str->size > 0){ + else if (key.keycode == state->codes->back && str->size > 0){ str->str[--str->size] = 0; } } @@ -958,7 +959,7 @@ ui_do_file_field_input(System_Functions *system, bool32 result = 0; Key_Summary *keys = state->keys; for (i32 key_i = 0; key_i < keys->count; ++key_i){ - Key_Single key = get_single_key(keys, key_i); + Key_Event_Data key = get_single_key(keys, key_i); String *str = &hot_dir->string; terminate_with_null(str); Single_Line_Input_Step step = @@ -974,7 +975,7 @@ ui_do_line_field_input(System_Functions *system, bool32 result = 0; Key_Summary *keys = state->keys; for (i32 key_i = 0; key_i < keys->count; ++key_i){ - Key_Single key = get_single_key(keys, key_i); + Key_Event_Data key = get_single_key(keys, key_i); terminate_with_null(string); Single_Line_Input_Step step = app_single_line_input_step(system, state->codes, key, string); @@ -1552,10 +1553,8 @@ working_set_get_available_file(Working_Set *working_set){ break; } } - - if (result.file){ - *result.file = {}; - } + + if (result.file) *result.file = {}; return result; } @@ -1639,7 +1638,7 @@ Job_Callback_Sig(job_full_lex){ status = cpp_lex_file_nonalloc(cpp_file, &tokens, status); } - i32 new_max = LargeRoundUp(tokens.count, Kbytes(1)); + i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1)); system->acquire_lock(FRAME_LOCK); { @@ -2247,9 +2246,9 @@ view_file_loaded_init(System_Functions *system, File_View *view, i32 cursor_pos) } internal void -view_set_file(System_Functions *system, File_View *view, Editing_File *file, - Font_Set *set, Style *style, Custom_Command_Function *open_hook, - void *cmd_context, Application_Links *app){ +view_set_file(System_Functions *system, File_View *view, + Editing_File *file, Font_Set *set, Style *style, + Hook_Function *open_hook, void *cmd_context, Application_Links *app){ Panel *panel = view->view_base.panel; view->file = file; view->locked = file->settings.super_locked; @@ -2295,8 +2294,11 @@ view_set_file(System_Functions *system, File_View *view, Editing_File *file, view->vel_y = 1.f; view->vel_x = 1.f; - - if (open_hook) open_hook(cmd_context, app); + + if (open_hook && file->settings.is_initialized == 0){ + open_hook(cmd_context, app); + file->settings.is_initialized = 1; + } } struct Relative_Scrolling{ @@ -2723,8 +2725,7 @@ file_do_single_edit(System_Functions *system, } internal void -view_do_white_batch_edit(System_Functions *system, - Mem_Options *mem, File_View *view, Editing_File *file, +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){ if (view->locked) return; #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -2871,7 +2872,7 @@ view_undo_redo(System_Functions *system, Assert(step.type == expected_type); - Edit_Spec spec; + Edit_Spec spec = {}; spec.step = step; if (step.child_count == 0){ @@ -4341,7 +4342,7 @@ HANDLE_COMMAND_SIG(handle_command_file_view){ if (binding.function) binding.function(system, command, binding); file_view->mode = file_view->next_mode; - if (key.key.keycode == codes->esc) + if (key.keycode == codes->esc) view_set_widget(file_view, FWIDG_NONE); }break; diff --git a/4ed_font_set.cpp b/4ed_font_set.cpp index 3c7d504e..16502b14 100644 --- a/4ed_font_set.cpp +++ b/4ed_font_set.cpp @@ -115,7 +115,7 @@ font_set_load(Partition *partition, Font_Set *set, i16 font_id){ font__insert(&set->used_slots, slot); Render_Font *font = (Render_Font*)(slot + 1); - set->font_load(partition, font, info->filename.str, info->pt_size, 4); + set->font_load(font, info->filename.str, info->pt_size, 4); info->font = font; slot->font_id = font_id; } diff --git a/4ed_interactive_view.cpp b/4ed_interactive_view.cpp index 221c80b5..fea58350 100644 --- a/4ed_interactive_view.cpp +++ b/4ed_interactive_view.cpp @@ -113,8 +113,7 @@ step_draw_int_view(System_Functions *system, Interactive_View *view, b32 new_dir = 0; b32 complete = 0; - terminate_with_null(&view->query); - do_label(&state, &layout, view->query.str, 1.f); + do_label(&state, &layout, view->query, 1.f); switch (view->interaction){ case INTV_SYS_FILE_LIST: @@ -142,7 +141,7 @@ step_draw_int_view(System_Functions *system, Interactive_View *view, String s = make_fixed_width_string(s_); append(&s, view->dest); append(&s, " has unsaved changes, kill it?"); - do_label(&state, &layout, s.str, 1.f); + do_label(&state, &layout, s, 1.f); i32 id = 0; if (do_list_option(++id, &state, &layout, make_lit_string("(Y)es"))){ diff --git a/4ed_layout.cpp b/4ed_layout.cpp index d3a9a17b..2ef14da0 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -49,7 +49,7 @@ typedef Do_View_Sig(Do_View_Function); #define HANDLE_COMMAND_SIG(name) \ void (name)(System_Functions *system, View *view, \ Command_Data *command, Command_Binding binding, \ - Key_Single key, Key_Codes *codes) + Key_Event_Data key, Key_Codes *codes) typedef HANDLE_COMMAND_SIG(Handle_Command_Function); diff --git a/4ed_mem.cpp b/4ed_mem.cpp index 9d7913a4..7ac150e0 100644 --- a/4ed_mem.cpp +++ b/4ed_mem.cpp @@ -47,7 +47,7 @@ struct Mem_Options{ inline Partition partition_open(void *memory, i32 size){ Partition partition; - partition.base = (u8*)memory;; + partition.base = (u8*)memory; partition.pos = 0; partition.max = size; return partition; diff --git a/4ed_menu_view.cpp b/4ed_menu_view.cpp index b8a73a0e..6d16ed72 100644 --- a/4ed_menu_view.cpp +++ b/4ed_menu_view.cpp @@ -14,6 +14,7 @@ struct Menu_View{ Style *style; Working_Set *working_set; Delay *delay; + Font_Set *font_set; UI_State state; }; @@ -33,14 +34,14 @@ step_draw_menu_view(Menu_View *view, Render_Target *target, i32_Rect rect, UI_State state = ui_state_init(&view->state, target, user_input, - view->style, &target->font_set, view->working_set, input_stage); + view->style, view->font_set, view->working_set, input_stage); UI_Layout layout; begin_layout(&layout, rect); i32 id = 0; - do_label(&state, &layout, "Menu", 2.f); + do_label(&state, &layout, literal("Menu"), 2.f); if (do_list_option_lit(++id, &state, &layout, "Theme Options")){ delayed_action(view->delay, DACT_THEME_OPTIONS, {}, view->view_base.panel); @@ -67,7 +68,8 @@ Do_View_Sig(do_menu_view){ } internal Menu_View* -menu_view_init(View *view, Style *style, Working_Set *working_set, Delay *delay){ +menu_view_init(View *view, Style *style, Working_Set *working_set, + Delay *delay, Font_Set *font_set){ view->type = VIEW_TYPE_INTERACTIVE; view->do_view = do_menu_view; @@ -76,6 +78,7 @@ menu_view_init(View *view, Style *style, Working_Set *working_set, Delay *delay) result->style = style; result->working_set = working_set; result->delay = delay; + result->font_set = font_set; return result; } diff --git a/4ed_meta.h b/4ed_meta.h index c4fe1f5d..50cfc4e9 100644 --- a/4ed_meta.h +++ b/4ed_meta.h @@ -101,6 +101,10 @@ _OutDbgStr(u8*); #define Swap(a,b) {auto t = a; a = b; b = t;} +#ifndef literal +#define literal(s) s, (sizeof(s)-1) +#endif + #define Min(a,b) (((a)<(b))?(a):(b)) #define Max(a,b) (((a)>(b))?(a):(b)) diff --git a/4ed_rendering.cpp b/4ed_rendering.cpp index 19d2b394..601dd66d 100644 --- a/4ed_rendering.cpp +++ b/4ed_rendering.cpp @@ -269,11 +269,16 @@ launch_rendering(Render_Target *target){ #undef ExtractStruct -internal -Font_Info_Load_Sig(draw_font_info_load){ +internal i32 +draw_font_info_load(Partition *partition, + char *filename, + i32 pt_size, + i32 *height, + i32 *advance){ i32 result = 1; Data file; file = system_load_file(filename); + Temp_Memory temp = begin_temp_memory(partition); stbtt_packedchar *chardata = push_array(partition, stbtt_packedchar, 256); @@ -283,7 +288,7 @@ Font_Info_Load_Sig(draw_font_info_load){ tex_width = pt_size*128*oversample; tex_height = pt_size*2*oversample; void *block = push_block(partition, tex_width * tex_height); - + if (!file.data){ result = 0; } @@ -342,18 +347,25 @@ Font_Info_Load_Sig(draw_font_info_load){ system_free_memory(file.data); } - + end_temp_memory(temp); return(result); } -internal -Font_Load_Sig(draw_font_load){ +internal i32 +draw_font_load(void *base_block, i32 size, + Render_Font *font_out, + char *filename, + i32 pt_size, + i32 tab_width){ i32 result = 1; Data file; file = system_load_file(filename); - Temp_Memory temp = begin_temp_memory(partition); + + Partition partition_ = partition_open(base_block, size); + Partition *partition = &partition_; + stbtt_packedchar *chardata = font_out->chardata; i32 oversample = 2; @@ -395,14 +407,6 @@ Font_Load_Sig(draw_font_load){ stbtt_pack_context spc; -#if 0 - if (stbtt_BakeFontBitmap((u8*)file.data, 0, (f32)pt_size, - memory_cursor, tex_width, tex_height, 0, 128, - font_out->chardata, partition) <= 0){ - result = 0; - } -#endif - if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, tex_width, 1, partition)){ stbtt_PackSetOversampling(&spc, oversample, oversample); if (stbtt_PackFontRange(&spc, (u8*)file.data, 0, @@ -456,8 +460,6 @@ Font_Load_Sig(draw_font_load){ } system_free_memory(file.data); } - - end_temp_memory(temp); return result; } diff --git a/4ed_rendering.h b/4ed_rendering.h index 44552a16..cd2b52bb 100644 --- a/4ed_rendering.h +++ b/4ed_rendering.h @@ -107,7 +107,6 @@ struct Render_Piece_Combined{ typedef Draw_Push_Piece_Sig(Draw_Push_Piece); #define Font_Load_Sig(name) i32 name( \ - Partition *partition, \ Render_Font *font_out, \ char *filename, \ i32 pt_size, \ diff --git a/4ed_rendering_helper.cpp b/4ed_rendering_helper.cpp index d03bb2c8..b09dfa29 100644 --- a/4ed_rendering_helper.cpp +++ b/4ed_rendering_helper.cpp @@ -20,15 +20,18 @@ draw_pop_clip(Render_Target *target){ } internal void -begin_render_section(Render_Target *target){ +begin_render_section(Render_Target *target, System_Functions *system){ Font_Set *font_set = &target->font_set; font_set->used_this_frame = 0; memset(font_set->font_used_flags, 0, font_set->max); + target->size = 0; + system->acquire_lock(RENDER_LOCK); } internal void -end_render_section(Render_Target *target){ +end_render_section(Render_Target *target, System_Functions *system){ //Font_Set *font_set = &target->font_set; + system->release_lock(RENDER_LOCK); } internal void diff --git a/4ed_system.h b/4ed_system.h index e35545b1..6c0dd5cb 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -61,6 +61,9 @@ struct Thread_Context; enum Lock_ID{ FRAME_LOCK, + INPUT_LOCK, + FONT_LOCK, + RENDER_LOCK, CANCEL_LOCK0, CANCEL_LOCK1, CANCEL_LOCK2, diff --git a/vc120.pdb b/vc120.pdb index 01fe61a0f0c67310204dfa282f5b865b3d5e4d9c..cc1f5af16337abc3de783129a0d9ccbaa898873e 100644 GIT binary patch delta 923 zcmcK2Pe@cj7y$5Z-amD>-o9mhYKFUes1{LViw+w_J(S2qVyg{GgZH*JVnHn0B`YG8 zIz>=8he)#M(m`C>8e{8{UhM2eFJ1Q5(bh_~KWN|JXNL|RgciP;`OW*jnPK@x%KAuI zFYfop8a;q2#1z2a#_W+dW{Ac_zyGDCcy~q6S_<%}WvbBh`!C+aZwD2F@xfPPyt@$Q zVP{w5;y~6-4-BPm=G+U}!Hk=~;$F{Q8iM7DVyjTc(}l)5AApj_i%;^=LPQih&u&-V zGvP}rR!gx{z6hW_46p;|j1J&v05-1m$E``$CQ{y)RL#@`gXuX{be(zY8=Kv>`*aZC z2G$y|wub3AsyG7lV!ezeTxZ1I*^s@}((?12wh2bValGl41<;HqHiOon^U6wy&sQ}* z|5MYd_=Ue%>E_X2lfyp{%N1GFhbseP9E+q~a*VC}GWh^GPd-GJ7s~p>e2^|Ug@2p$9ZKjT zbMi5A9P@cGah_kjS1TT^_UdM;1z_eOgLh9<2z2o9wGM9O>dkYw-Ggxg11#}6_tB4y zu*bx6zTsBQKaG&Uu8>iS*^XA)XR*o9e>ytO76aJOC7;7K>1YEVQqNnxwo)p|rXqg; DH!!Z5 delta 413 zcmZp8z}oPDb%P1Fx{x{p!w&`)CI%pY(FssKjAl?^*&NNijD<;}XS1Ndd;ZA^0({I2 z37_GdO$IfBn`;8MFmE<+y}`w_i(xZY0F!`hjU&iZ28IjL3=EP$I);^j;R!PXgD8;A zI$bk>QG0Vp!iSK}E}?t4CLQ2W4HRTxZ~^LJWBC7{1*qo#f1qL@Z~^KAVF@5RX0zb| zVNp`GJeV)N`GU0p%NE8v%uEadn>Q9K@c?a9`!2x1Fazj1b~GFB04)Y#4xo)sn711V mFs>3NN1p-XHGW`lZ0B-d#1kHDKwCs6YbI!K4+&sgBM$%>cU|uQ diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 9859ed12..cdb3d6b0 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -38,6 +38,9 @@ #define FPS 30 #define frame_useconds (1000000 / FPS) +#define WM_4coder_LOAD_FONT (WM_USER + 1) +#define WM_4coder_PAINT (WM_USER + 2) + struct Thread_Context{ u32 job_id; b32 running; @@ -56,16 +59,59 @@ struct Thread_Group{ #define UseWinDll 1 #define UseThreadMemory 1 +struct Control_Keys{ + b8 l_ctrl; + b8 r_ctrl; + b8 l_alt; + b8 r_alt; +}; + +struct Win32_Input_Chunk_Transient{ + Key_Input_Data key_data; + + b8 mouse_l_press, mouse_l_release; + b8 mouse_r_press, mouse_r_release; + b32 out_of_window; + i16 mouse_wheel; +}; + +struct Win32_Input_Chunk_Persistent{ + i32 mouse_x, mouse_y; + b8 mouse_l, mouse_r; + + b8 keep_playing; + + Control_Keys controls; + b8 control_keys[CONTROL_KEY_COUNT]; +}; + +struct Win32_Input_Chunk{ + Win32_Input_Chunk_Transient trans; + Win32_Input_Chunk_Persistent pers; +}; + +struct Win32_Font_Load_Parameters{ + Win32_Font_Load_Parameters *next; + Win32_Font_Load_Parameters *prev; + + Render_Font *font_out; + char *filename; + i32 pt_size; + i32 tab_width; +}; + + struct Win32_Vars{ HWND window_handle; - Key_Codes key_codes; - Key_Input_Data input_data, previous_data; - + HDC window_hdc; Render_Target target; - Mouse_State mouse; - b32 focus; - b32 keep_playing; + HANDLE update_loop_thread; + DWORD update_loop_thread_id; + + Key_Codes key_codes; + Win32_Input_Chunk input_chunk; + HCURSOR cursor_ibeam; HCURSOR cursor_arrow; HCURSOR cursor_leftright; @@ -75,8 +121,6 @@ struct Win32_Vars{ b32 next_clipboard_is_self; DWORD clipboard_sequence; - Thread_Context main_thread; - Thread_Group groups[THREAD_GROUP_COUNT]; HANDLE locks[LOCK_COUNT]; HANDLE DEBUG_sysmem_lock; @@ -89,20 +133,27 @@ struct Win32_Vars{ u64 start_pcount; u64 start_time; - HMODULE custom; #if UseWinDll HMODULE app_code; + HMODULE custom; #else DLL_Loaded app_dll; + DLL_Loaded custom_dll; #endif System_Functions *system; App_Functions app; - Config_API config_api; + Custom_API custom_api; + b32 first; #if FRED_INTERNAL Sys_Bubble internal_bubble; #endif + + Win32_Font_Load_Parameters fnt_params[8]; + Win32_Font_Load_Parameters used_font_param; + Win32_Font_Load_Parameters free_font_param; + Partition fnt_part; }; globalvar Win32_Vars win32vars; @@ -163,6 +214,31 @@ Win32FreeMemory(void *block){ } } +internal Partition +Win32ScratchPartition(i32 size){ + Partition part; + void *data; + data = Win32GetMemory(size); + part = partition_open(data, size); + return(part); +} + +internal void +Win32ScratchPartitionGrow(Partition *part, i32 new_size){ + void *data; + if (new_size > part->max){ + data = Win32GetMemory(new_size); + memcpy(data, part->base, part->pos); + Win32FreeMemory(part->base); + part->base = (u8*)data; + } +} + +internal void +Win32ScratchPartitionDouble(Partition *part){ + Win32ScratchPartitionGrow(part, part->max*2); +} + inline void system_free_memory(void *block){ Win32FreeMemory(block); @@ -433,9 +509,16 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){ internal void Win32RedrawScreen(HDC hdc){ launch_rendering(&win32vars.target); - win32vars.target.size = 0; glFlush(); - SwapBuffers(hdc); + //SwapBuffers(hdc); +} + +internal void +Win32RedrawFromUpdate(){ + SendMessage( + win32vars.window_handle, + WM_4coder_PAINT, + 0, 0); } internal void @@ -452,220 +535,6 @@ Win32Resize(i32 width, i32 height){ } } -#define HOTKEY_ALT_ID 0 - -internal LRESULT -Win32Callback(HWND hwnd, UINT uMsg, - WPARAM wParam, LPARAM lParam){ - LRESULT result = {}; - switch (uMsg){ - case WM_MENUCHAR: - case WM_SYSCHAR:break; - - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - case WM_KEYDOWN: - case WM_KEYUP: - { - switch (wParam){ - case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL: - case VK_MENU:case VK_LMENU:case VK_RMENU: - case VK_SHIFT:case VK_LSHIFT:case VK_RSHIFT: break; - - default: - b8 previous_state, current_state; - previous_state = ((lParam & Bit_30)?(1):(0)); - current_state = ((lParam & Bit_31)?(0):(1)); - - if (current_state){ - u8 key = keycode_lookup((u8)wParam); - - i32 *count = 0; - Key_Event_Data *data = 0; - - if (!previous_state){ - count = &win32vars.input_data.press_count; - data = win32vars.input_data.press; - } - else{ - count = &win32vars.input_data.hold_count; - data = win32vars.input_data.hold; - } - - if (*count < KEY_INPUT_BUFFER_SIZE){ - if (!key){ - UINT vk = (UINT)wParam; - UINT scan = (UINT)((lParam >> 16) & 0x7F); - BYTE state[256]; - WORD x; - int result; - - GetKeyboardState(state); - if (win32vars.input_data.control_keys[CONTROL_KEY_CONTROL] && - !win32vars.input_data.control_keys[CONTROL_KEY_ALT]) - state[VK_CONTROL] = 0; - result = ToAscii(vk, scan, state, &x, 0); - if (result == 1 && x < 128){ - key = (u8)x; - if (key == '\r') key = '\n'; - data[*count].character = key; - - state[VK_CAPITAL] = 0; - result = ToAscii(vk, scan, state, &x, 0); - if (result == 1 && x < 128){ - key = (u8)x; - if (key == '\r') key = '\n'; - data[*count].character_no_caps_lock = key; - data[*count].keycode = key; - } - } - if (result != 1 || x >= 128){ - data[*count].character = 0; - data[*count].character_no_caps_lock = 0; - data[*count].keycode = 0; - } - } - else{ - data[*count].character = 0; - data[*count].character_no_caps_lock = 0; - data[*count].keycode = key; - } - ++(*count); - } - } - - result = DefWindowProc(hwnd, uMsg, wParam, lParam); - } - }break; - - case WM_INPUT: - { - char buffer[sizeof(RAWINPUT)] = {}; - UINT size = sizeof(RAWINPUT); - GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER)); - - RAWINPUT *rawinput = (RAWINPUT*)(buffer); - if (rawinput->header.dwType == RIM_TYPEKEYBOARD){ - RAWKEYBOARD *raw = &rawinput->data.keyboard; - UINT vk = raw->VKey; - UINT flags = raw->Flags; - b8 down = !(flags & 1); - - if (vk != 255){ - if (vk == VK_SHIFT){ - win32vars.input_data.control_keys[CONTROL_KEY_SHIFT] = down; - } - else if (vk == VK_CONTROL){ - win32vars.input_data.control_keys[CONTROL_KEY_CONTROL] = down; - } - else if (vk == VK_MENU){ - UINT is_gr = ((flags & RI_KEY_E0) != 0); - if (!is_gr){ - win32vars.input_data.control_keys[CONTROL_KEY_ALT] = down; - } - } - } - } - - result = DefWindowProcA(hwnd, uMsg, wParam, lParam); - }break; - - case WM_MOUSEMOVE: - { - win32vars.mouse.x = LOWORD(lParam); - win32vars.mouse.y = HIWORD(lParam); - }break; - - case WM_MOUSEWHEEL: - { - i16 rotation = GET_WHEEL_DELTA_WPARAM(wParam); - if (rotation > 0){ - win32vars.mouse.wheel = 1; - } - else{ - win32vars.mouse.wheel = -1; - } - }break; - - case WM_LBUTTONDOWN: - { - win32vars.mouse.left_button = true; - }break; - - case WM_RBUTTONDOWN: - { - win32vars.mouse.right_button = true; - }break; - - case WM_LBUTTONUP: - { - win32vars.mouse.left_button = false; - }break; - - case WM_RBUTTONUP: - { - win32vars.mouse.right_button = false; - }break; - - case WM_KILLFOCUS: - { - win32vars.focus = 0; - win32vars.mouse.left_button = false; - win32vars.mouse.right_button = false; - }break; - - case WM_SETFOCUS: - { - win32vars.focus = 1; - for (int i = 0; i < CONTROL_KEY_COUNT; ++i){ - win32vars.input_data.control_keys[i] = 0; - } - }break; - - case WM_SIZE: - { - if (win32vars.target.handle){ - i32 new_width = LOWORD(lParam); - i32 new_height = HIWORD(lParam); - - Win32Resize(new_width, new_height); - } - }break; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - - Clipboard_Contents empty_contents = {}; - win32vars.app.step(win32vars.system, - &win32vars.key_codes, - &win32vars.previous_data, - &win32vars.mouse, - &win32vars.target, - &memory_vars, - &exchange_vars, - empty_contents, - 0, 0, 1); - - Win32RedrawScreen(hdc); - EndPaint(hwnd, &ps); - }break; - - case WM_CLOSE: // NOTE(allen): I expect WM_CLOSE not WM_DESTROY - case WM_DESTROY: - { - win32vars.keep_playing = 0; - }break; - - default: - { - result = DefWindowProc(hwnd, uMsg, wParam, lParam); - }break; - } - return result; -} - internal HANDLE Win32Handle(Plat_Handle h){ HANDLE result; @@ -966,6 +835,41 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ return close_me; } +internal void +fnt__remove(Win32_Font_Load_Parameters *params){ + params->next->prev = params->prev; + params->prev->next = params->next; +} + +internal void +fnt__insert(Win32_Font_Load_Parameters *pos, Win32_Font_Load_Parameters *params){ + params->next = pos->next; + pos->next->prev = params; + pos->next = params; + params->prev = pos; +} + +internal +Font_Load_Sig(system_draw_font_load){ + Win32_Font_Load_Parameters *params; + + system_acquire_lock(FONT_LOCK); + params = win32vars.free_font_param.next; + fnt__remove(params); + fnt__insert(&win32vars.used_font_param, params); + system_release_lock(FONT_LOCK); + + params->font_out = font_out; + params->filename = filename; + params->pt_size = pt_size; + params->tab_width = tab_width; + + SendMessage(win32vars.window_handle, + WM_4coder_LOAD_FONT, + 0, (i32)(params - win32vars.fnt_params)); + return(1); +} + internal b32 Win32LoadAppCode(){ b32 result = 0; @@ -1089,6 +993,464 @@ ex__check(File_Exchange *file_exchange){ ex__check_file(&file_exchange->free_list); } +internal LRESULT +Win32Callback(HWND hwnd, UINT uMsg, + WPARAM wParam, LPARAM lParam){ + LRESULT result = {}; + switch (uMsg){ + case WM_MENUCHAR: + case WM_SYSCHAR:break; + + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: + { + switch (wParam){ + case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL: + case VK_MENU:case VK_LMENU:case VK_RMENU: + case VK_SHIFT:case VK_LSHIFT:case VK_RSHIFT: break; + + default: + b8 previous_state, current_state; + previous_state = ((lParam & Bit_30)?(1):(0)); + current_state = ((lParam & Bit_31)?(0):(1)); + + if (current_state){ + u8 key = keycode_lookup((u8)wParam); + + i32 *count = 0; + Key_Event_Data *data = 0; + b8 *control_keys = 0; + i32 control_keys_size = 0; + + system_acquire_lock(INPUT_LOCK); + if (!previous_state){ + count = &win32vars.input_chunk.trans.key_data.press_count; + data = win32vars.input_chunk.trans.key_data.press; + } + else{ + count = &win32vars.input_chunk.trans.key_data.hold_count; + data = win32vars.input_chunk.trans.key_data.hold; + } + control_keys = win32vars.input_chunk.pers.control_keys; + control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys); + + if (*count < KEY_INPUT_BUFFER_SIZE){ + if (!key){ + UINT vk = (UINT)wParam; + UINT scan = (UINT)((lParam >> 16) & 0x7F); + BYTE state[256]; + WORD x; + int result; + + GetKeyboardState(state); + if (control_keys[CONTROL_KEY_CONTROL] && + !control_keys[CONTROL_KEY_ALT]) + state[VK_CONTROL] = 0; + x = 0; + result = ToAscii(vk, scan, state, &x, 0); + if (result == 1 && x < 128){ + key = (u8)x; + if (key == '\r') key = '\n'; + data[*count].character = key; + + state[VK_CAPITAL] = 0; + x = 0; + result = ToAscii(vk, scan, state, &x, 0); + if (result == 1 && x < 128){ + key = (u8)x; + if (key == '\r') key = '\n'; + data[*count].character_no_caps_lock = key; + data[*count].keycode = key; + } + } + if (result != 1 || x >= 128){ + data[*count].character = 0; + data[*count].character_no_caps_lock = 0; + data[*count].keycode = 0; + } + } + else{ + data[*count].character = 0; + data[*count].character_no_caps_lock = 0; + data[*count].keycode = key; + } + memcpy(data[*count].modifiers, control_keys, control_keys_size); + ++(*count); + } + } + system_release_lock(INPUT_LOCK); + + result = DefWindowProc(hwnd, uMsg, wParam, lParam); + } + }break; + + case WM_INPUT: + { + char buffer[sizeof(RAWINPUT)] = {}; + UINT size = sizeof(RAWINPUT); + GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER)); + + system_acquire_lock(INPUT_LOCK); + Control_Keys *controls = 0; + b8 *control_keys = 0; + controls = &win32vars.input_chunk.pers.controls; + control_keys = win32vars.input_chunk.pers.control_keys; + + RAWINPUT *rawinput = (RAWINPUT*)(buffer); + if (rawinput->header.dwType == RIM_TYPEKEYBOARD){ + RAWKEYBOARD *raw = &rawinput->data.keyboard; + UINT vk = raw->VKey; + UINT flags = raw->Flags; + b8 down = !(flags & 1); + UINT is_left = ((flags & RI_KEY_E0) != 0); + + if (vk != 255){ + switch (vk){ + case VK_SHIFT: + { + control_keys[CONTROL_KEY_SHIFT] = down; + }break; + + case VK_CONTROL: + { + if (is_left) controls->l_ctrl = down; + else controls->r_ctrl = down; + }break; + + case VK_MENU: + { + if (is_left) controls->l_alt = down; + else controls->r_alt = down; + }break; + } + + b8 ctrl, alt; + ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); + alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); + control_keys[CONTROL_KEY_CONTROL] = ctrl; + control_keys[CONTROL_KEY_ALT] = alt; + } + } + system_release_lock(INPUT_LOCK); + + result = DefWindowProcA(hwnd, uMsg, wParam, lParam); + }break; + + case WM_MOUSEMOVE: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.mouse_x = LOWORD(lParam); + win32vars.input_chunk.pers.mouse_y = HIWORD(lParam); + system_release_lock(INPUT_LOCK); + }break; + + case WM_MOUSEWHEEL: + { + system_acquire_lock(INPUT_LOCK); + i16 rotation = GET_WHEEL_DELTA_WPARAM(wParam); + if (rotation > 0){ + win32vars.input_chunk.trans.mouse_wheel = 1; + } + else{ + win32vars.input_chunk.trans.mouse_wheel = -1; + } + system_release_lock(INPUT_LOCK); + }break; + + case WM_LBUTTONDOWN: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_l_press = 1; + win32vars.input_chunk.pers.mouse_l = 1; + system_release_lock(INPUT_LOCK); + }break; + + case WM_RBUTTONDOWN: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_r_press = 1; + win32vars.input_chunk.pers.mouse_r = 1; + system_release_lock(INPUT_LOCK); + }break; + + case WM_LBUTTONUP: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_l_release = 1; + win32vars.input_chunk.pers.mouse_l = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_RBUTTONUP: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_r_release = 1; + win32vars.input_chunk.pers.mouse_r = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.mouse_l = 0; + win32vars.input_chunk.pers.mouse_r = 0; + + b8 *control_keys = win32vars.input_chunk.pers.control_keys; + for (int i = 0; i < CONTROL_KEY_COUNT; ++i) control_keys[i] = 0; + win32vars.input_chunk.pers.controls = {}; + + system_release_lock(INPUT_LOCK); + }break; + + case WM_SIZE: + { + if (win32vars.target.handle){ + i32 new_width = LOWORD(lParam); + i32 new_height = HIWORD(lParam); + + Win32Resize(new_width, new_height); + } + }break; + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + system_acquire_lock(RENDER_LOCK); + Win32RedrawScreen(hdc); + system_release_lock(RENDER_LOCK); + EndPaint(hwnd, &ps); + + }break; + + case WM_4coder_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + system_acquire_lock(RENDER_LOCK); + Win32RedrawScreen(hdc); + system_release_lock(RENDER_LOCK); + EndPaint(hwnd, &ps); + }break; + + case WM_CLOSE: // NOTE(allen): I expect WM_CLOSE not WM_DESTROY + case WM_DESTROY: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.keep_playing = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_4coder_LOAD_FONT: + { + if (win32vars.fnt_part.base == 0){ + win32vars.fnt_part = Win32ScratchPartition(Mbytes(8)); + } + + Win32_Font_Load_Parameters *params = win32vars.fnt_params + lParam; + + for (b32 success = 0; success == 0;){ + + success = draw_font_load(win32vars.fnt_part.base, + win32vars.fnt_part.max, + params->font_out, + params->filename, + params->pt_size, + params->tab_width); + + if (!success){ + Win32ScratchPartitionDouble(&win32vars.fnt_part); + } + } + + system_acquire_lock(FONT_LOCK); + fnt__remove(params); + fnt__insert(&win32vars.free_font_param, params); + system_release_lock(FONT_LOCK); + }break; + + default: + { + result = DefWindowProc(hwnd, uMsg, wParam, lParam); + }break; + } + return result; +} + +DWORD +UpdateLoop(LPVOID param){ + for (;win32vars.input_chunk.pers.keep_playing;){ + i64 timer_start = system_time(); + + system_acquire_lock(INPUT_LOCK); + Win32_Input_Chunk input_chunk = win32vars.input_chunk; + win32vars.input_chunk.trans = {}; + system_release_lock(INPUT_LOCK); + + input_chunk.pers.control_keys[CONTROL_KEY_CAPS] = GetKeyState(VK_CAPITAL) & 0x1; + + POINT mouse_point; + if (GetCursorPos(&mouse_point) && ScreenToClient(win32vars.window_handle, &mouse_point)){ + if (mouse_point.x < 0 || mouse_point.x >= win32vars.target.width || + mouse_point.y < 0 || mouse_point.y >= win32vars.target.height){ + input_chunk.trans.out_of_window = 1; + } + } + else{ + input_chunk.trans.out_of_window = 1; + } + + win32vars.clipboard_contents = {}; + if (win32vars.clipboard_sequence != 0){ + DWORD new_number = GetClipboardSequenceNumber(); + if (new_number != win32vars.clipboard_sequence){ + win32vars.clipboard_sequence = new_number; + if (win32vars.next_clipboard_is_self){ + win32vars.next_clipboard_is_self = 0; + } + else if (IsClipboardFormatAvailable(CF_TEXT)){ + if (OpenClipboard(win32vars.window_handle)){ + HANDLE clip_data; + clip_data = GetClipboardData(CF_TEXT); + if (clip_data){ + win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); + if (win32vars.clipboard_contents.str){ + win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); + GlobalUnlock(clip_data); + } + } + CloseClipboard(); + } + } + } + } + + u32 redraw = exchange_vars.thread.force_redraw; + if (redraw) exchange_vars.thread.force_redraw = 0; + + Key_Input_Data input_data; + Mouse_State mouse; + Application_Step_Result result; + + input_data = input_chunk.trans.key_data; + mouse.out_of_window = input_chunk.trans.out_of_window; + + mouse.left_button = input_chunk.pers.mouse_l; + mouse.left_button_pressed = input_chunk.trans.mouse_l_press; + mouse.left_button_released = input_chunk.trans.mouse_l_release; + + mouse.right_button = input_chunk.pers.mouse_r; + mouse.right_button_pressed = input_chunk.trans.mouse_r_press; + mouse.right_button_released = input_chunk.trans.mouse_r_release; + + mouse.wheel = input_chunk.trans.mouse_wheel; + + mouse.x = input_chunk.pers.mouse_x; + mouse.y = input_chunk.pers.mouse_y; + + result = + win32vars.app.step(win32vars.system, + &win32vars.key_codes, + &input_data, + &mouse, + &win32vars.target, + &memory_vars, + &exchange_vars, + win32vars.clipboard_contents, + 1, win32vars.first, redraw); + + ProfileStart(OS_frame_out); + win32vars.first = 0; + switch (result.mouse_cursor_type){ + case APP_MOUSE_CURSOR_ARROW: + SetCursor(win32vars.cursor_arrow); break; + case APP_MOUSE_CURSOR_IBEAM: + SetCursor(win32vars.cursor_ibeam); break; + case APP_MOUSE_CURSOR_LEFTRIGHT: + SetCursor(win32vars.cursor_leftright); break; + case APP_MOUSE_CURSOR_UPDOWN: + SetCursor(win32vars.cursor_updown); break; + } + + if (result.redraw){ + Win32RedrawFromUpdate(); + } + + ProfileEnd(OS_frame_out); + + ProfileStart(OS_file_process); + { + File_Slot *file; + int d = 0; + + for (file = exchange_vars.file.active.next; + file != &exchange_vars.file.active; + file = file->next){ + ++d; + + if (file->flags & FEx_Save){ + Assert((file->flags & FEx_Request) == 0); + file->flags &= (~FEx_Save); + system_save_file(file->filename, file->data, file->size); + file->flags |= FEx_Save_Complete; + } + + if (file->flags & FEx_Request){ + Assert((file->flags & FEx_Save) == 0); + file->flags &= (~FEx_Request); + Data sysfile = + system_load_file(file->filename); + if (sysfile.data == 0){ + file->flags |= FEx_Not_Exist; + } + else{ + file->flags |= FEx_Ready; + file->data = sysfile.data; + file->size = sysfile.size; + } + } + } + + Assert(d == exchange_vars.file.num_active); + + for (file = exchange_vars.file.free_list.next; + file != &exchange_vars.file.free_list; + file = file->next){ + if (file->data){ + system_free_memory(file->data); + } + } + + if (exchange_vars.file.free_list.next != &exchange_vars.file.free_list){ + ex__insert_range(exchange_vars.file.free_list.next, exchange_vars.file.free_list.prev, + &exchange_vars.file.available); + } + + ex__check(&exchange_vars.file); + } + ProfileEnd(OS_file_process); + + ProfileStart(frame_sleep); + i64 timer_end = system_time(); + i64 end_target = (timer_start + frame_useconds); + + system_release_lock(FRAME_LOCK); + while (timer_end < end_target){ + DWORD samount = (DWORD)((end_target - timer_end) / 1000); + if (samount > 0) Sleep(samount); + timer_end = system_time(); + } + system_acquire_lock(FRAME_LOCK); + timer_start = system_time(); + ProfileEnd(frame_sleep); + } + + return(0); +} + int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, @@ -1130,10 +1492,10 @@ WinMain(HINSTANCE hInstance, #ifdef FRED_SUPER win32vars.custom = LoadLibraryA("4coder_custom.dll"); if (win32vars.custom){ - win32vars.config_api.get_bindings = (Get_Binding_Data_Function*) + win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) GetProcAddress(win32vars.custom, "get_bindings"); - win32vars.config_api.set_extra_font = (Set_Extra_Font_Function*) + win32vars.custom_api.set_extra_font = (Set_Extra_Font_Function*) GetProcAddress(win32vars.custom, "set_extra_font"); } #endif @@ -1148,7 +1510,6 @@ WinMain(HINSTANCE hInstance, Thread_Memory thread_memory[ArrayCount(background)]; win32vars.thread_memory = thread_memory; #endif - exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = Win32GenHandle( @@ -1219,6 +1580,7 @@ WinMain(HINSTANCE hInstance, // TODO(allen): errors? win32vars.window_handle = window_handle; HDC hdc = GetDC(window_handle); + win32vars.window_hdc = hdc; GetClientRect(window_handle, &window_rect); @@ -1232,9 +1594,7 @@ WinMain(HINSTANCE hInstance, static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, - PFD_DRAW_TO_WINDOW | - PFD_SUPPORT_OPENGL | - PFD_DOUBLEBUFFER, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, @@ -1325,7 +1685,7 @@ WinMain(HINSTANCE hInstance, win32vars.target.push_piece = draw_push_piece; win32vars.target.font_set.font_info_load = draw_font_info_load; - win32vars.target.font_set.font_load = draw_font_load; + win32vars.target.font_set.font_load = system_draw_font_load; win32vars.target.font_set.release_font = draw_release_font; win32vars.target.max = Mbytes(1); @@ -1367,186 +1727,50 @@ WinMain(HINSTANCE hInstance, String current_directory = make_string(current_directory_mem, written, required); terminate_with_null(¤t_directory); + win32vars.free_font_param.next = &win32vars.free_font_param; + win32vars.free_font_param.prev = &win32vars.free_font_param; + + win32vars.used_font_param.next = &win32vars.used_font_param; + win32vars.used_font_param.prev = &win32vars.used_font_param; + + for (i32 i = 0; i < ArrayCount(win32vars.fnt_params); ++i){ + fnt__insert(&win32vars.free_font_param, win32vars.fnt_params + i); + } + if (!win32vars.app.init(win32vars.system, &win32vars.target, &memory_vars, &exchange_vars, &win32vars.key_codes, win32vars.clipboard_contents, current_directory, - win32vars.config_api)){ - return 5; + win32vars.custom_api)){ + return(5); } - win32vars.keep_playing = 1; + win32vars.input_chunk.pers.keep_playing = 1; + win32vars.first = 1; timeBeginPeriod(1); - - system_acquire_lock(FRAME_LOCK); - Thread_Context *thread = &win32vars.main_thread; - AllowLocal(thread); - b32 first = 1; - i64 timer_start = system_time(); - while (win32vars.keep_playing){ - ProfileStart(OS_input); - win32vars.previous_data = win32vars.input_data; - win32vars.input_data.press_count = 0; - win32vars.input_data.hold_count = 0; - win32vars.input_data.caps_lock = GetKeyState(VK_CAPITAL) & 0x1; - - win32vars.mouse.left_button_prev = win32vars.mouse.left_button; - win32vars.mouse.right_button_prev = win32vars.mouse.right_button; - win32vars.mouse.wheel = 0; - - MSG msg; - while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) && win32vars.keep_playing){ - if (msg.message == WM_QUIT){ - win32vars.keep_playing = 0; - }else{ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - if (!win32vars.keep_playing){ - break; - } - - win32vars.mouse.out_of_window = 0; - POINT mouse_point; - if (GetCursorPos(&mouse_point) && - ScreenToClient(window_handle, &mouse_point)){ - - if (mouse_point.x < 0 || mouse_point.x >= win32vars.target.width || - mouse_point.y < 0 || mouse_point.y >= win32vars.target.height){ - win32vars.mouse.out_of_window = 1; - } - } - else{ - win32vars.mouse.out_of_window = 1; - } - - win32vars.clipboard_contents = {}; - if (win32vars.clipboard_sequence != 0){ - DWORD new_number = GetClipboardSequenceNumber(); - if (new_number != win32vars.clipboard_sequence){ - win32vars.clipboard_sequence = new_number; - if (win32vars.next_clipboard_is_self){ - win32vars.next_clipboard_is_self = 0; - } - else if (IsClipboardFormatAvailable(CF_TEXT)){ - if (OpenClipboard(win32vars.window_handle)){ - HANDLE clip_data; - clip_data = GetClipboardData(CF_TEXT); - if (clip_data){ - win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); - if (win32vars.clipboard_contents.str){ - win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); - GlobalUnlock(clip_data); - } - } - CloseClipboard(); - } - } - } - } - - u32 redraw = exchange_vars.thread.force_redraw; - if (redraw){ - exchange_vars.thread.force_redraw = 0; + win32vars.update_loop_thread = + CreateThread(0, + 0, + UpdateLoop, + 0, + CREATE_SUSPENDED, + &win32vars.update_loop_thread_id); + + system_acquire_lock(FRAME_LOCK); + + ResumeThread(win32vars.update_loop_thread); + + MSG msg; + for (;win32vars.input_chunk.pers.keep_playing && GetMessage(&msg, 0, 0, 0);){ + if (msg.message == WM_QUIT){ + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.keep_playing = 0; + system_release_lock(INPUT_LOCK); + }else{ + TranslateMessage(&msg); + DispatchMessage(&msg); } - - ProfileEnd(OS_input); - - Application_Step_Result result = - win32vars.app.step(win32vars.system, - &win32vars.key_codes, - &win32vars.input_data, - &win32vars.mouse, - &win32vars.target, - &memory_vars, - &exchange_vars, - win32vars.clipboard_contents, - 1, first, redraw); - - ProfileStart(OS_frame_out); - first = 0; - switch (result.mouse_cursor_type){ - case APP_MOUSE_CURSOR_ARROW: - SetCursor(win32vars.cursor_arrow); break; - case APP_MOUSE_CURSOR_IBEAM: - SetCursor(win32vars.cursor_ibeam); break; - case APP_MOUSE_CURSOR_LEFTRIGHT: - SetCursor(win32vars.cursor_leftright); break; - case APP_MOUSE_CURSOR_UPDOWN: - SetCursor(win32vars.cursor_updown); break; - } - - if (result.redraw) Win32RedrawScreen(hdc); - ProfileEnd(OS_frame_out); - - ProfileStart(OS_file_process); - { - File_Slot *file; - int d = 0; - - for (file = exchange_vars.file.active.next; - file != &exchange_vars.file.active; - file = file->next){ - ++d; - - if (file->flags & FEx_Save){ - Assert((file->flags & FEx_Request) == 0); - file->flags &= (~FEx_Save); - system_save_file(file->filename, file->data, file->size); - file->flags |= FEx_Save_Complete; - } - - if (file->flags & FEx_Request){ - Assert((file->flags & FEx_Save) == 0); - file->flags &= (~FEx_Request); - Data sysfile = - system_load_file(file->filename); - if (sysfile.data == 0){ - file->flags |= FEx_Not_Exist; - } - else{ - file->flags |= FEx_Ready; - file->data = sysfile.data; - file->size = sysfile.size; - } - } - } - - Assert(d == exchange_vars.file.num_active); - - for (file = exchange_vars.file.free_list.next; - file != &exchange_vars.file.free_list; - file = file->next){ - if (file->data){ - system_free_memory(file->data); - } - } - - if (exchange_vars.file.free_list.next != &exchange_vars.file.free_list){ - ex__insert_range(exchange_vars.file.free_list.next, exchange_vars.file.free_list.prev, - &exchange_vars.file.available); - } - - ex__check(&exchange_vars.file); - } - ProfileEnd(OS_file_process); - - ProfileStart(frame_sleep); - i64 timer_end = system_time(); - i64 end_target = (timer_start + frame_useconds); - - system_release_lock(FRAME_LOCK); - while (timer_end < end_target){ - DWORD samount = (DWORD)((end_target - timer_end) / 1000); - if (samount > 0) Sleep(samount); - timer_end = system_time(); - } - system_acquire_lock(FRAME_LOCK); - timer_start = system_time();7 - ProfileEnd(frame_sleep); - } + } return 0; }