From d71d10434a98414fc0ed955fb06a6ee3f7374e35 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sat, 5 Mar 2016 03:10:43 -0500 Subject: [PATCH] 4coder_handmade_hero.cpp ready to go --- 4coder_custom.cpp | 67 +- 4coder_custom.h | 78 +- 4coder_handmade_hero.cpp | 1260 +++++++++++++++++++++++++++++ 4coder_helper.h | 19 + 4ed.cpp | 48 +- 4ed_app_target.cpp | 3 +- 4ed_file_view.cpp | 11 +- 4ed_font_set.cpp | 462 ++++++----- 4ed_style.cpp | 5 - buffer/4coder_buffer_abstract.cpp | 4 + buildsuper.bat | 4 +- 11 files changed, 1651 insertions(+), 310 deletions(-) create mode 100644 4coder_handmade_hero.cpp diff --git a/4coder_custom.cpp b/4coder_custom.cpp index 43454603..e42ed10d 100644 --- a/4coder_custom.cpp +++ b/4coder_custom.cpp @@ -1,11 +1,8 @@ -/* - * Example use of customization API - */ +// Alternative customizations, set Custom_Current to select which to apply. +#define Custom_Default 0 +#define Custom_HandmadeHero 1 -// NOTE(allen): See exec_command and surrounding code in 4coder_helper.h -// to decide whether you want macro translations, without them you will -// have to manipulate the command and parameter stack through -// "app->" which may be more or less clear depending on your use. +#define Custom_Current Custom_Default #include "4coder_custom.h" @@ -30,6 +27,23 @@ enum My_Maps{ HOOK_SIG(my_start){ exec_command(app, cmdid_open_panel_vsplit); exec_command(app, cmdid_change_active_panel); + + app->change_theme(app, literal("4coder")); + app->change_font(app, literal("liberation mono")); + + // Theme options: + // "4coder" + // "Handmade Hero" + // "Twilight" + // "Woverine" + // "stb" + + // Font options: + // "liberation sans" + // "liberation mono" + // "hack" + // "cutive mono" + // "inconsolata" } HOOK_SIG(my_file_settings){ @@ -367,8 +381,10 @@ isearch(Application_Links *app, int start_reversed){ int step_forward = 0; int step_backward = 0; - if (CommandEqual(in.command, search)) step_forward = 1; - if (CommandEqual(in.command, reverse_search)) step_backward = 1; + if (CommandEqual(in.command, search) || + in.key.keycode == key_page_down || in.key.keycode == key_down) step_forward = 1; + if (CommandEqual(in.command, reverse_search) || + in.key.keycode == key_page_down || in.key.keycode == key_up) step_backward = 1; int start_pos = pos; if (step_forward && reverse){ @@ -682,7 +698,7 @@ CUSTOM_COMMAND_SIG(execute_arbitrary_command){ // as an example you have everything you need to make it work already. You could // even use app->memory to create a hash table in the start hook. Query_Bar bar; - char space[1024], more_space[1024]; + char space[1024]; bar.prompt = make_lit_string("Command: "); bar.string = make_fixed_width_string(space); @@ -700,20 +716,11 @@ CUSTOM_COMMAND_SIG(execute_arbitrary_command){ else if(match(bar.string, make_lit_string("close all code"))){ exec_command(app, close_all_code); } - else if (match(bar.string, make_lit_string("open in quotes"))){ - exec_command(app, open_file_in_quotes); - } else if (match(bar.string, make_lit_string("open menu"))){ exec_command(app, cmdid_open_menu); } else{ - bar.prompt = make_fixed_width_string(more_space); - append(&bar.prompt, make_lit_string("Unrecognized: ")); - append(&bar.prompt, bar.string); - bar.string.size = 0; - - app->start_query_bar(app, &bar, 0); - app->get_user_input(app, EventOnAnyKey | EventOnButton, 0); + // TODO(allen): feedback message } } @@ -840,6 +847,8 @@ CUSTOM_COMMAND_SIG(write_and_auto_tab){ exec_command(app, cmdid_auto_tab_line_at_cursor); } +// NOTE(allen|a4) See 4coder_styles.h for a list of available style tags. +// There are style tags corresponding to every color in the theme editor. CUSTOM_COMMAND_SIG(improve_theme){ Theme_Color colors[] = { {Stag_Bar, 0xFF0088}, @@ -868,7 +877,7 @@ CUSTOM_COMMAND_SIG(ruin_theme){ app->set_theme_colors(app, colors, count); } -// NOTE(allen|a4.0.0): scroll rule information +// NOTE(allen|a4): scroll rule information // // The parameters: // target_x, target_y @@ -955,10 +964,17 @@ SCROLL_RULE_SIG(smooth_scroll_rule){ return(result); } +#if Custom_Current == Custom_HandmadeHero +# include "4coder_handmade_hero.cpp" +#endif + extern "C" GET_BINDING_DATA(get_bindings){ Bind_Helper context_actual = begin_bind_helper(data, size); Bind_Helper *context = &context_actual; +#if Custom_Current == Custom_HandmadeHero + casey_get_bindings(context); +#else // NOTE(allen|a3.1): Right now hooks have no loyalties to maps, all hooks are // global and once set they always apply, regardless of what map is active. @@ -1037,10 +1053,10 @@ extern "C" GET_BINDING_DATA(get_bindings){ begin_map(context, mapid_file); - // NOTE(allen|a3.4.4): Binding this essentially binds all key combos that - // would normally insert a character into a buffer. - // Or apply this rule: if the code for the key is not an enum value - // such as key_left or key_back then it is a vanilla key. + // NOTE(allen|a3.4.4): Binding this essentially binds + // all key combos that would normally insert a character + // into a buffer. If the code for the key is not an enum + // value such as key_left or key_back then it is a vanilla key. // It is possible to override this binding for individual keys. bind_vanilla_keys(context, cmdid_write_character); @@ -1104,6 +1120,7 @@ extern "C" GET_BINDING_DATA(get_bindings){ bind(context, ' ', MDFR_SHIFT, cmdid_write_character); end_map(context); +#endif end_bind_helper(context); diff --git a/4coder_custom.h b/4coder_custom.h index 8e5bac54..4af548cf 100644 --- a/4coder_custom.h +++ b/4coder_custom.h @@ -341,57 +341,59 @@ extern "C"{ struct Application_Links; // Command exectuion -#define PUSH_PARAMETER_SIG(name) void name(Application_Links *app, Dynamic param, Dynamic value) -#define PUSH_MEMORY_SIG(name) char* name(Application_Links *app, int len) -#define EXECUTE_COMMAND_SIG(name) void name(Application_Links *app, int command_id) -#define CLEAR_PARAMETERS_SIG(name) void name(Application_Links *app) +#define PUSH_PARAMETER_SIG(n) void n(Application_Links *app, Dynamic param, Dynamic value) +#define PUSH_MEMORY_SIG(n) char* n(Application_Links *app, int len) +#define EXECUTE_COMMAND_SIG(n) void n(Application_Links *app, int command_id) +#define CLEAR_PARAMETERS_SIG(n) void n(Application_Links *app) // File system navigation -#define DIRECTORY_GET_HOT_SIG(name) int name(Application_Links *app, char *out, int capacity) -#define FILE_EXISTS_SIG(name) int name(Application_Links *app, char *filename, int len) -#define DIRECTORY_CD_SIG(name) int name(Application_Links *app, char *dir, int *len, int capacity, char *rel_path, int rel_len) -#define GET_FILE_LIST_SIG(name) File_List name(Application_Links *app, char *dir, int len) -#define FREE_FILE_LIST_SIG(name) void name(Application_Links *app, File_List list) +#define DIRECTORY_GET_HOT_SIG(n) int n(Application_Links *app, char *out, int capacity) +#define FILE_EXISTS_SIG(n) int n(Application_Links *app, char *filename, int len) +#define DIRECTORY_CD_SIG(n) int n(Application_Links *app, char *dir, int *len, int capacity, char *rel_path, int rel_len) +#define GET_FILE_LIST_SIG(n) File_List n(Application_Links *app, char *dir, int len) +#define FREE_FILE_LIST_SIG(n) void n(Application_Links *app, File_List list) // Direct buffer manipulation -#define GET_BUFFER_FIRST_SIG(name) Buffer_Summary name(Application_Links *app) -#define GET_BUFFER_NEXT_SIG(name) void name(Application_Links *app, Buffer_Summary *buffer) +#define GET_BUFFER_FIRST_SIG(n) Buffer_Summary n(Application_Links *app) +#define GET_BUFFER_NEXT_SIG(n) void n(Application_Links *app, Buffer_Summary *buffer) -#define GET_BUFFER_SIG(name) Buffer_Summary name(Application_Links *app, int index) -#define GET_ACTIVE_BUFFER_SIG(name) Buffer_Summary name(Application_Links *app) -#define GET_PARAMETER_BUFFER_SIG(name) Buffer_Summary name(Application_Links *app, int param_index) -#define GET_BUFFER_BY_NAME(name) Buffer_Summary name(Application_Links *app, char *filename, int len) +#define GET_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app, int index) +#define GET_ACTIVE_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app) +#define GET_PARAMETER_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app, int param_index) +#define GET_BUFFER_BY_NAME(n) Buffer_Summary n(Application_Links *app, char *filename, int len) -#define BUFFER_SEEK_DELIMITER_SIG(name) int name(Application_Links *app, Buffer_Summary *buffer, int start, char delim, int seek_forward, int *out) -#define BUFFER_SEEK_STRING_SIG(name) int name(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) +#define BUFFER_SEEK_DELIMITER_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, char delim, int seek_forward, int *out) +#define BUFFER_SEEK_STRING_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) -#define REFRESH_BUFFER_SIG(name) int name(Application_Links *app, Buffer_Summary *buffer) -#define BUFFER_READ_RANGE_SIG(name) int name(Application_Links *app, Buffer_Summary *buffer, int start, int end, char *out) -#define BUFFER_REPLACE_RANGE_SIG(name) int name(Application_Links *app, Buffer_Summary *buffer, int start, int end, char *str, int len) -#define BUFFER_SET_POS_SIG(name) int name(Application_Links *app, Buffer_Summary *buffer, int pos) +#define REFRESH_BUFFER_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer) +#define BUFFER_READ_RANGE_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, int end, char *out) +#define BUFFER_REPLACE_RANGE_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, int end, char *str, int len) +#define BUFFER_SET_POS_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int pos) // File view manipulation -#define GET_VIEW_FIRST_SIG(name) View_Summary name(Application_Links *app) -#define GET_VIEW_NEXT_SIG(name) void name(Application_Links *app, View_Summary *view) +#define GET_VIEW_FIRST_SIG(n) View_Summary n(Application_Links *app) +#define GET_VIEW_NEXT_SIG(n) void n(Application_Links *app, View_Summary *view) -#define GET_VIEW_SIG(name) View_Summary name(Application_Links *app, int index) -#define GET_ACTIVE_VIEW_SIG(name) View_Summary name(Application_Links *app) +#define GET_VIEW_SIG(n) View_Summary n(Application_Links *app, int index) +#define GET_ACTIVE_VIEW_SIG(n) View_Summary n(Application_Links *app) -#define REFRESH_VIEW_SIG(name) int name(Application_Links *app, View_Summary *view) -#define VIEW_SET_CURSOR_SIG(name) int name(Application_Links *app, View_Summary *view, Buffer_Seek seek, int set_preferred_x) -#define VIEW_SET_MARK_SIG(name) int name(Application_Links *app, View_Summary *view, Buffer_Seek seek) -#define VIEW_SET_HIGHLIGHT_SIG(name) int name(Application_Links *app, View_Summary *view, int start, int end, int turn_on) -#define VIEW_SET_BUFFER_SIG(name) int name(Application_Links *app, View_Summary *view, int buffer_id) +#define REFRESH_VIEW_SIG(n) int n(Application_Links *app, View_Summary *view) +#define VIEW_SET_CURSOR_SIG(n) int n(Application_Links *app, View_Summary *view, Buffer_Seek seek, int set_preferred_x) +#define VIEW_SET_MARK_SIG(n) int n(Application_Links *app, View_Summary *view, Buffer_Seek seek) +#define VIEW_SET_HIGHLIGHT_SIG(n) int n(Application_Links *app, View_Summary *view, int start, int end, int turn_on) +#define VIEW_SET_BUFFER_SIG(n) int n(Application_Links *app, View_Summary *view, int buffer_id) // Directly get user input -#define GET_USER_INPUT_SIG(name) User_Input name(Application_Links *context, unsigned int get_type, unsigned int abort_type) +#define GET_USER_INPUT_SIG(n) User_Input n(Application_Links *app, unsigned int get_type, unsigned int abort_type) // Queries -#define START_QUERY_BAR_SIG(name) int name(Application_Links *context, Query_Bar *bar, unsigned int flags) -#define END_QUERY_BAR_SIG(name) void name(Application_Links *context, Query_Bar *bar, unsigned int flags) +#define START_QUERY_BAR_SIG(n) int n(Application_Links *app, Query_Bar *bar, unsigned int flags) +#define END_QUERY_BAR_SIG(n) void n(Application_Links *app, Query_Bar *bar, unsigned int flags) -// Setting colors -#define SET_THEME_COLORS_SIG(name) void name(Application_Links *context, Theme_Color *colors, int count) +// Color settings +#define CHANGE_THEME_SIG(n) void n(Application_Links *app, char *name, int len) +#define CHANGE_FONT_SIG(n) void n(Application_Links *app, char *name, int len) +#define SET_THEME_COLORS_SIG(n) void n(Application_Links *app, Theme_Color *colors, int count) // Boundry type flags @@ -467,7 +469,9 @@ extern "C"{ typedef START_QUERY_BAR_SIG(Start_Query_Bar_Function); typedef END_QUERY_BAR_SIG(End_Query_Bar_Function); - // Set theme colors + // Color settings + typedef CHANGE_THEME_SIG(Change_Theme_Function); + typedef CHANGE_FONT_SIG(Change_Font_Function); typedef SET_THEME_COLORS_SIG(Set_Theme_Colors_Function); } @@ -527,6 +531,8 @@ struct Application_Links{ End_Query_Bar_Function *end_query_bar; // Theme + Change_Theme_Function *change_theme; + Change_Font_Function *change_font; Set_Theme_Colors_Function *set_theme_colors; // Internal diff --git a/4coder_handmade_hero.cpp b/4coder_handmade_hero.cpp new file mode 100644 index 00000000..d5885578 --- /dev/null +++ b/4coder_handmade_hero.cpp @@ -0,0 +1,1260 @@ +/* NOTE(casey): + + This is my attempt to make 4coder work close enough to Emacs + for me to switch! + + NOTE(casey): Microsoft/Windows is poopsauce. + + TODO(casey): Here are our current issues + + - Have buffers normalize slashes to always be forward-slash + - Cursor setting seems to do no movement first time, and then weird scrolling behavior on + jump-to-same-line subsequently + + - Switch-to-buffer with no typing, just return, should switch to the most recently + used buffer that is not currently displayed in a view. + - Kill-buffer should perform this switch automatically, or it should be easy + to build a custom kill buffer that does + + - Need a way of highlighting the current line like Emacs does for the benefit + of people on The Stream(TM) + - Need a way of changing some things visually so we can indicate the modal state (this has + to be something very obvious - ideally something like + 1) Change the line highlight color + 2) In modal mode, highlight the whole selected region (mark to cursor) potentially? + - Macros + - Some way to recenter the view so that the line containing the cursor becomes the + center line vertically. + - NOTE / IMPORTANT / TODO highlighting? Ability to customize? Whatever. + + + NOTE(allen): Things that were on the issue list that are now fixed + + - Need a way of calling things by name, so infrequently used functions won't need keybindings + - Need a way of changing some things visually so we can indicate the modal state (this has + to be something very obvious - ideally something like + 1) Change the cursor color + 2) X + 3) X + 4) Change the header bar color? + - Need a way to set the theme from the custom config file so I don't have to pick it every + time. +*/ + +#include +#include +#include + +#define UseHack4Coder 0 + +#ifndef Assert +#define internal static +#define Assert assert +#endif + +static bool GlobalEditMode; +static char *GlobalCompilationBufferName = "*compilation*"; +static HWND GlobalModalIndicator; +static HBRUSH GlobalEditModeBrush; +static HBRUSH GlobalNormalModeBrush; +static WNDPROC global_old_4coder_winproc; + +// TODO(casey): If 4coder gets variables at some point, this would go in a variable. +static char BuildDirectory[4096] = "./"; +static int ErrorParsingPosition; +static int ErrorParsingLastJumpLine; +static int ErrorParsingLastBufferID; + +enum token_type +{ + Token_Unknown, + + Token_OpenParen, + Token_CloseParen, + Token_Asterisk, + Token_Minus, + Token_Plus, + Token_ForwardSlash, + Token_Percent, + Token_Colon, + Token_Number, + + Token_EndOfStream, +}; +struct token +{ + token_type Type; + + size_t TextLength; + char *Text; +}; + +struct tokenizer +{ + char *At; +}; + +inline bool +IsEndOfLine(char C) +{ + bool Result = ((C == '\n') || + (C == '\r')); + + return(Result); +} + +inline bool +IsWhitespace(char C) +{ + bool Result = ((C == ' ') || + (C == '\t') || + (C == '\v') || + (C == '\f') || + IsEndOfLine(C)); + + return(Result); +} + +inline bool +IsAlpha(char C) +{ + bool Result = (((C >= 'a') && (C <= 'z')) || + ((C >= 'A') && (C <= 'Z'))); + + return(Result); +} + +inline bool +IsNumeric(char C) +{ + bool Result = ((C >= '0') && (C <= '9')); + + return(Result); +} + +static void +EatAllWhitespace(tokenizer *Tokenizer) +{ + for(;;) + { + if(IsWhitespace(Tokenizer->At[0])) + { + ++Tokenizer->At; + } + else if((Tokenizer->At[0] == '/') && + (Tokenizer->At[1] == '/')) + { + Tokenizer->At += 2; + while(Tokenizer->At[0] && !IsEndOfLine(Tokenizer->At[0])) + { + ++Tokenizer->At; + } + } + else if((Tokenizer->At[0] == '/') && + (Tokenizer->At[1] == '*')) + { + Tokenizer->At += 2; + while(Tokenizer->At[0] && + !((Tokenizer->At[0] == '*') && + (Tokenizer->At[1] == '/'))) + { + ++Tokenizer->At; + } + + if(Tokenizer->At[0] == '*') + { + Tokenizer->At += 2; + } + } + else + { + break; + } + } +} + +static token +GetToken(tokenizer *Tokenizer) +{ + EatAllWhitespace(Tokenizer); + + token Token = {}; + Token.TextLength = 1; + Token.Text = Tokenizer->At; + char C = Tokenizer->At[0]; + ++Tokenizer->At; + switch(C) + { + case '0': {--Tokenizer->At; Token.Type = Token_EndOfStream;} break; + + case '(': {Token.Type = Token_OpenParen;} break; + case ')': {Token.Type = Token_CloseParen;} break; + case '*': {Token.Type = Token_Asterisk;} break; + case '-': {Token.Type = Token_Minus;} break; + case '+': {Token.Type = Token_Plus;} break; + case '/': {Token.Type = Token_ForwardSlash;} break; + case '%': {Token.Type = Token_Percent;} break; + case ':': {Token.Type = Token_Colon;} break; + + default: + { + if(IsNumeric(C)) + { + // TODO(casey): Real number + Token.Type = Token_Number; + while(IsNumeric(Tokenizer->At[0]) || + (Tokenizer->At[0] == '.') || + (Tokenizer->At[0] == 'f')) + { + ++Tokenizer->At; + Token.TextLength = Tokenizer->At - Token.Text; + } + } + else + { + Token.Type = Token_Unknown; + } + } break; + } + + return(Token); +} + +static token +PeekToken(tokenizer *Tokenizer) +{ + tokenizer Tokenizer2 = *Tokenizer; + token Result = GetToken(&Tokenizer2); + return(Result); +} + +inline bool +IsH(String extension) +{ + bool Result = (match(extension, make_lit_string("h")) || + match(extension, make_lit_string("hpp")) || + match(extension, make_lit_string("hin"))); + + return(Result); +} + +inline bool +IsCPP(String extension) +{ + bool Result = (match(extension, make_lit_string("c")) || + match(extension, make_lit_string("cpp")) || + match(extension, make_lit_string("cin"))); + + return(Result); +} + +inline bool +IsINL(String extension) +{ + bool Result = (match(extension, make_lit_string("inl"))); + + return(Result); +} + +inline bool +IsCode(String extension) +{ + bool Result = (IsH(extension) || IsCPP(extension) || IsINL(extension)); + + return(Result); +} + +HOOK_SIG(casey_start) +{ + exec_command(app, cmdid_open_panel_vsplit); + app->change_theme(app, literal("Handmade Hero")); + app->change_font(app, literal("liberation mono")); +} + +CUSTOM_COMMAND_SIG(casey_open_in_other) +{ + exec_command(app, cmdid_change_active_panel); + exec_command(app, cmdid_interactive_open); +} + +CUSTOM_COMMAND_SIG(casey_clean_and_save) +{ + exec_command(app, cmdid_clean_all_lines); + exec_command(app, cmdid_eol_nixify); + exec_command(app, cmdid_save); +} + +CUSTOM_COMMAND_SIG(casey_newline_and_indent) +{ + exec_command(app, cmdid_write_character); + exec_command(app, cmdid_auto_tab_line_at_cursor); +} + +CUSTOM_COMMAND_SIG(casey_open_file_other_window) +{ + exec_command(app, cmdid_change_active_panel); + exec_command(app, cmdid_interactive_open); +} + +CUSTOM_COMMAND_SIG(casey_switch_buffer_other_window) +{ + exec_command(app, cmdid_change_active_panel); + exec_command(app, cmdid_interactive_switch_buffer); +} + +internal void +DeleteAfterCommand(struct Application_Links *app, Command_ID CommandID) +{ + View_Summary view = app->get_active_view(app); + + int pos2 = view.cursor.pos; + exec_command(app, CommandID); + app->refresh_view(app, &view); + int pos1 = view.cursor.pos; + + Range range = make_range(pos1, pos2); + + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + app->buffer_replace_range(app, &buffer, range.min, range.max, 0, 0); +} + +CUSTOM_COMMAND_SIG(casey_delete_token_left) +{ + DeleteAfterCommand(app, cmdid_seek_white_or_token_left); +} + +CUSTOM_COMMAND_SIG(casey_delete_token_right) +{ + DeleteAfterCommand(app, cmdid_seek_white_or_token_right); +} + +CUSTOM_COMMAND_SIG(casey_kill_to_end_of_line) +{ + View_Summary view = app->get_active_view(app); + + int pos2 = view.cursor.pos; + exec_command(app, cmdid_seek_end_of_line); + app->refresh_view(app, &view); + int pos1 = view.cursor.pos; + + Range range = make_range(pos1, pos2); + if(pos1 == pos2) + { + range.max += 1; + } + + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + app->buffer_replace_range(app, &buffer, range.min, range.max, 0, 0); +} + +CUSTOM_COMMAND_SIG(casey_paste_and_tab) +{ + // NOTE(allen): Paste puts the mark at the beginning and the cursor at + // the end of the pasted chunk, so it is all set for cmdid_auto_tab_range + exec_command(app, cmdid_paste); + exec_command(app, cmdid_auto_tab_range); +} + +CUSTOM_COMMAND_SIG(casey_seek_beginning_of_line_and_tab) +{ + exec_command(app, cmdid_seek_beginning_of_line); + exec_command(app, cmdid_auto_tab_line_at_cursor); +} + +struct switch_to_result +{ + bool Switched; + View_Summary view; + Buffer_Summary buffer; +}; + +inline switch_to_result +SwitchToOrLoadFile(struct Application_Links *app, String FileName, bool CreateIfNotFound = false) +{ + switch_to_result Result = {}; + + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer_by_name(app, FileName.str, FileName.size); + + Result.view = view; + Result.buffer = buffer; + + if(buffer.exists) + { + app->view_set_buffer(app, &view, buffer.buffer_id); + Result.Switched = true; + } + else + { + if(app->file_exists(app, FileName.str, FileName.size) || CreateIfNotFound) + { + push_parameter(app, par_name, expand_str(FileName)); + // TODO(casey): Do I have to check for existence, or can I pass a parameter + // to interactive open to tell it to fail if the file isn't there? + exec_command(app, cmdid_interactive_open); + + Result.buffer = app->get_buffer_by_name(app, FileName.str, FileName.size); + + Result.Switched = true; + } + } + + return(Result); +} + +CUSTOM_COMMAND_SIG(casey_load_todo) +{ + String ToDoFileName = make_lit_string("w:/handmade/code/todo.txt"); + SwitchToOrLoadFile(app, ToDoFileName, true); +} + +CUSTOM_COMMAND_SIG(casey_load_handmade) +{ + // NOTE(allen|a3.4.4): Here we get the list of files in this directory. + // Notice that we free_file_list at the end. + String dir = make_string(app->memory, 0, app->memory_size); + append(&dir, "w:/handmade/code/"); + File_List list = app->get_file_list(app, dir.str, dir.size); + int dir_size = dir.size; + + for (int i = 0; i < list.count; ++i) + { + File_Info *info = list.infos + i; + if (!info->folder) + { + String extension = file_extension(info->filename); + if (IsCode(extension)) + { + // NOTE(allen): There's no way in the 4coder API to use relative + // paths at the moment, so everything should be full paths. Which is + // managable. Here simply set the dir string size back to where it + // was originally, so that new appends overwrite old ones. + dir.size = dir_size; + append(&dir, info->filename); + push_parameter(app, par_name, dir.str, dir.size); + if (!match(info->filename, make_lit_string("handmade.cpp"))){ + push_parameter(app, par_do_in_background, 1); + } + exec_command(app, cmdid_interactive_open); + } + } + } + + app->free_file_list(app, list); + + strcpy(BuildDirectory, "w:/handmade/code/"); +} + +CUSTOM_COMMAND_SIG(casey_build_search) +{ + int keep_going = 1; + int old_size; + // TODO(allen): It's fine to get memory this way for now, eventually + // we should properly suballocating from app->memory. + String dir = make_string(app->memory, 0, app->memory_size); + dir.size = app->directory_get_hot(app, dir.str, dir.memory_size); + + while (keep_going) + { + old_size = dir.size; + append(&dir, "build.bat"); + + if (app->file_exists(app, dir.str, dir.size)) + { + dir.size = old_size; + memcpy(BuildDirectory, dir.str, dir.size); + BuildDirectory[dir.size] = 0; + + return; + } + + dir.size = old_size; + + if (app->directory_cd(app, dir.str, &dir.size, dir.memory_size, literal("..")) == 0) + { + keep_going = 0; + } + } + + // TODO(casey): How do I print out that it found or didn't find something? +} + +CUSTOM_COMMAND_SIG(casey_find_corresponding_file) +{ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + + String extension = file_extension(make_string(buffer.file_name, buffer.file_name_len)); + if (extension.str) + { + char *HExtensions[] = + { + "hpp", + "hin", + "h", + }; + + char *CExtensions[] = + { + "c", + "cin", + "cpp", + }; + + int ExtensionCount = 0; + char **Extensions = 0; + if(IsH(extension)) + { + ExtensionCount = ArrayCount(CExtensions); + Extensions = CExtensions; + } + else if(IsCPP(extension) || IsINL(extension)) + { + ExtensionCount = ArrayCount(HExtensions); + Extensions = HExtensions; + } + + int MaxExtensionLength = 3; + int Space = (int)(buffer.file_name_len + MaxExtensionLength); + String FileNameStem = make_string(buffer.file_name, (int)(extension.str - buffer.file_name), 0); + String TestFileName = make_string(app->push_memory(app, Space), 0, Space); + for(int ExtensionIndex = 0; + ExtensionCount; + ++ExtensionIndex) + { + TestFileName.size = 0; + append(&TestFileName, FileNameStem); + append(&TestFileName, Extensions[ExtensionIndex]); + + if(SwitchToOrLoadFile(app, TestFileName, ((ExtensionIndex + 1) == ExtensionCount)).Switched) + { + break; + } + } + } +} + +CUSTOM_COMMAND_SIG(casey_save_and_make_without_asking) +{ + exec_command(app, cmdid_change_active_panel); + + Buffer_Summary buffer = {}; + + for(buffer = app->get_buffer_first(app); + buffer.exists; + app->get_buffer_next(app, &buffer)) + { + push_parameter(app, par_name, buffer.file_name, buffer.file_name_len); + push_parameter(app, par_buffer_id, buffer.buffer_id); + exec_command(app, cmdid_save); + } + + String dir = make_string(app->memory, 0, app->memory_size); + append(&dir, BuildDirectory); + + push_parameter(app, par_flags, CLI_OverlapWithConflict); + push_parameter(app, par_name, GlobalCompilationBufferName, (int)strlen(GlobalCompilationBufferName)); + push_parameter(app, par_cli_path, dir.str, dir.size); + + if(append(&dir, "build")) + { + push_parameter(app, par_cli_command, dir.str, dir.size); + exec_command(app, cmdid_command_line); + ErrorParsingPosition = 0; + ErrorParsingLastJumpLine = 0; + ErrorParsingLastBufferID = 0; + + exec_command(app, cmdid_change_active_panel); + } + else{ + app->clear_parameters(app); + } +} + +CUSTOM_COMMAND_SIG(casey_goto_previous_error) +{ + // TODO(casey): Implement +// Buffer_Summary Buffer = app->get_buffer_by_name(app, GlobalCompilationBufferName, (int)strlen(GlobalCompilationBufferName)); +} + +CUSTOM_COMMAND_SIG(casey_goto_next_error) +{ + Buffer_Summary Buffer = app->get_buffer_by_name(app, GlobalCompilationBufferName, (int)strlen(GlobalCompilationBufferName)); + + int Size = Buffer.size - ErrorParsingPosition; + if(Size > 0) + { + char *ParsingRegion = (char *)malloc(Size + 1); + app->buffer_read_range(app, &Buffer, ErrorParsingPosition, Buffer.size, ParsingRegion); + ParsingRegion[Size] = 0; + + tokenizer Tokenizer = {ParsingRegion}; + for(;;) + { + token Token = GetToken(&Tokenizer); + if(Token.Type == Token_OpenParen) + { + token LineToken = GetToken(&Tokenizer); + if(LineToken.Type == Token_Number) + { + token CloseToken = GetToken(&Tokenizer); + if(CloseToken.Type == Token_CloseParen) + { + token ColonToken = GetToken(&Tokenizer); + if(ColonToken.Type == Token_Colon) + { + // NOTE(casey): We maybe found an error! + int line_number = atoi(LineToken.Text); + + char *Seek = Token.Text; + while(Seek != ParsingRegion) + { + if(IsEndOfLine(*Seek)) + { + while(IsWhitespace(*Seek)) + { + ++Seek; + } + break; + } + + --Seek; + } + + String FileName = make_string(Seek, (int)(Token.Text - Seek)); + switch_to_result Switch = SwitchToOrLoadFile(app, FileName, false); + if(Switch.Switched) + { + app->view_set_cursor(app, &Switch.view, seek_line_char(line_number, 0), 1); + } + + if((line_number != ErrorParsingLastJumpLine) || + (Switch.buffer.buffer_id != ErrorParsingLastBufferID)) + { + ErrorParsingLastJumpLine = line_number; + ErrorParsingLastBufferID = Switch.buffer.buffer_id; + ErrorParsingPosition += (int)(ColonToken.Text - ParsingRegion); + + View_Summary compilation_view = + get_first_view_for_buffer(app, Buffer.buffer_id); + if(compilation_view.exists) + { + app->view_set_cursor(app, &compilation_view, seek_pos(ErrorParsingPosition), 1); + } + + break; + } + } + } + } + } + else if(Token.Type == Token_EndOfStream) + { + break; + } + } + + free(ParsingRegion); + } +} + +CUSTOM_COMMAND_SIG(casey_imenu) +{ + // TODO(casey): Implement! +} + +// +// TODO(casey): Everything below this line probably isn't possible yet +// + +CUSTOM_COMMAND_SIG(casey_call_keyboard_macro) +{ + // TODO(casey): Implement! +} + +CUSTOM_COMMAND_SIG(casey_begin_keyboard_macro_recording) +{ + // TODO(casey): Implement! +} + +CUSTOM_COMMAND_SIG(casey_end_keyboard_macro_recording) +{ + // TODO(casey): Implement! +} + +CUSTOM_COMMAND_SIG(casey_fill_paragraph) +{ + // TODO(casey): Implement! +} + +enum calc_node_type +{ + CalcNode_UnaryMinus, + + CalcNode_Add, + CalcNode_Subtract, + CalcNode_Multiply, + CalcNode_Divide, + CalcNode_Mod, + + CalcNode_Constant, +}; +struct calc_node +{ + calc_node_type Type; + double Value; + calc_node *Left; + calc_node *Right; +}; + +internal double +ExecCalcNode(calc_node *Node) +{ + double Result = 0.0f; + + if(Node) + { + switch(Node->Type) + { + case CalcNode_UnaryMinus: {Result = -ExecCalcNode(Node->Left);} break; + case CalcNode_Add: {Result = ExecCalcNode(Node->Left) + ExecCalcNode(Node->Right);} break; + case CalcNode_Subtract: {Result = ExecCalcNode(Node->Left) - ExecCalcNode(Node->Right);} break; + case CalcNode_Multiply: {Result = ExecCalcNode(Node->Left) * ExecCalcNode(Node->Right);} break; + case CalcNode_Divide: {/*TODO(casey): Guard 0*/Result = ExecCalcNode(Node->Left) / ExecCalcNode(Node->Right);} break; + case CalcNode_Mod: {/*TODO(casey): Guard 0*/Result = fmod(ExecCalcNode(Node->Left), ExecCalcNode(Node->Right));} break; + case CalcNode_Constant: {Result = Node->Value;} break; + default: {Assert(!"AHHHHH!");} + } + } + + return(Result); +} + +internal void +FreeCalcNode(calc_node *Node) +{ + if(Node) + { + FreeCalcNode(Node->Left); + FreeCalcNode(Node->Right); + free(Node); + } +} + +internal calc_node * +AddNode(calc_node_type Type, calc_node *Left = 0, calc_node *Right = 0) +{ + calc_node *Node = (calc_node *)malloc(sizeof(calc_node)); + Node->Type = Type; + Node->Value = 0; + Node->Left = Left; + Node->Right = Right; + return(Node); +} + +internal calc_node * +ParseNumber(tokenizer *Tokenizer) +{ + calc_node *Result = AddNode(CalcNode_Constant); + + token Token = GetToken(Tokenizer); + Result->Value = atof(Token.Text); + + return(Result); +} + +internal calc_node * +ParseConstant(tokenizer *Tokenizer) +{ + calc_node *Result = 0; + + token Token = PeekToken(Tokenizer); + if(Token.Type == Token_Minus) + { + Token = GetToken(Tokenizer); + Result = AddNode(CalcNode_UnaryMinus); + Result->Left = ParseNumber(Tokenizer); + } + else + { + Result = ParseNumber(Tokenizer); + } + + return(Result); +} + +internal calc_node * +ParseMultiplyExpression(tokenizer *Tokenizer) +{ + calc_node *Result = 0; + + token Token = PeekToken(Tokenizer); + if((Token.Type == Token_Minus) || + (Token.Type == Token_Number)) + { + Result = ParseConstant(Tokenizer); + token Token = PeekToken(Tokenizer); + if(Token.Type == Token_ForwardSlash) + { + GetToken(Tokenizer); + Result = AddNode(CalcNode_Divide, Result, ParseNumber(Tokenizer)); + } + else if(Token.Type == Token_Asterisk) + { + GetToken(Tokenizer); + Result = AddNode(CalcNode_Multiply, Result, ParseNumber(Tokenizer)); + } + } + + return(Result); +} + +internal calc_node * +ParseAddExpression(tokenizer *Tokenizer) +{ + calc_node *Result = 0; + + token Token = PeekToken(Tokenizer); + if((Token.Type == Token_Minus) || + (Token.Type == Token_Number)) + { + Result = ParseMultiplyExpression(Tokenizer); + token Token = PeekToken(Tokenizer); + if(Token.Type == Token_Plus) + { + GetToken(Tokenizer); + Result = AddNode(CalcNode_Add, Result, ParseMultiplyExpression(Tokenizer)); + } + else if(Token.Type == Token_Minus) + { + GetToken(Tokenizer); + Result = AddNode(CalcNode_Subtract, Result, ParseMultiplyExpression(Tokenizer)); + } + } + + return(Result); +} + +internal calc_node * +ParseCalc(tokenizer *Tokenizer) +{ + calc_node *Node = ParseAddExpression(Tokenizer); + + return(Node); +} + +CUSTOM_COMMAND_SIG(casey_quick_calc) +{ + View_Summary view = app->get_active_view(app); + + Range range = get_range(&view); + + size_t Size = range.max - range.min; + if (Size == 0) return; + + char *Stuff = (char *)malloc(Size + 1); + Stuff[Size] = 0; + + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + app->buffer_read_range(app, &buffer, range.min, range.max, Stuff); + + tokenizer Tokenizer = {Stuff}; + calc_node *CalcTree = ParseCalc(&Tokenizer); + double ComputedValue = ExecCalcNode(CalcTree); + FreeCalcNode(CalcTree); + + char ResultBuffer[256]; + int ResultSize = sprintf(ResultBuffer, "%f", ComputedValue); + + app->buffer_replace_range(app, &buffer, range.min, range.max, ResultBuffer, ResultSize); + + free(Stuff); +} + +CUSTOM_COMMAND_SIG(modal_toggle) +{ + Theme_Color normal_colors[] = { + {Stag_Cursor, 0x40FF40}, + {Stag_At_Cursor, 0x161616}, + {Stag_Mark, 0x808080}, + {Stag_Margin, 0x262626}, + {Stag_Margin_Hover, 0x333333}, + {Stag_Margin_Active, 0x404040}, + {Stag_Bar, 0xCACACA} + }; + + Theme_Color edit_colors[] = { + {Stag_Cursor, 0xFF0000}, + {Stag_At_Cursor, 0x00FFFF}, + {Stag_Mark, 0xFF6F1A}, + {Stag_Margin, 0x33170B}, + {Stag_Margin_Hover, 0x49200F}, + {Stag_Margin_Active, 0x934420}, + {Stag_Bar, 0x934420} + }; + + GlobalEditMode = !GlobalEditMode; + + if (GlobalEditMode){ + app->set_theme_colors(app, edit_colors, ArrayCount(edit_colors)); + } + else{ + app->set_theme_colors(app, normal_colors, ArrayCount(normal_colors)); + } + +#if UseHack4Coder + RECT Rect; + GetClientRect(GlobalModalIndicator, &Rect); + InvalidateRect(GlobalModalIndicator, &Rect, FALSE); +#endif + +} + +CUSTOM_COMMAND_SIG(casey_arbitrary_command){ + Query_Bar bar; + char space[1024]; + bar.prompt = make_lit_string("Command: "); + bar.string = make_fixed_width_string(space); + + if (!query_user_string(app, &bar)) return; + app->end_query_bar(app, &bar, 0); + + if (match(bar.string, make_lit_string("build search"))){ + exec_command(app, casey_build_search); + } + else if (match(bar.string, make_lit_string("open hmh"))){ + exec_command(app, casey_load_handmade); + } + else if (match(bar.string, make_lit_string("open menu"))){ + exec_command(app, cmdid_open_menu); + } + else{ + // TODO(allen): feedback message + } +} + +#define DEFINE_FULL_BIMODAL_KEY(binding_name,edit_code,normal_code) \ +CUSTOM_COMMAND_SIG(binding_name) \ +{ \ + if(GlobalEditMode) \ + { \ + edit_code; \ + } \ + else \ + { \ + normal_code; \ + } \ +} + +#define DEFINE_BIMODAL_KEY(binding_name,edit_code,normal_code) DEFINE_FULL_BIMODAL_KEY(binding_name,exec_command(app,edit_code),exec_command(app,normal_code)) +#define DEFINE_MODAL_KEY(binding_name,edit_code) DEFINE_BIMODAL_KEY(binding_name,edit_code,cmdid_write_character) + +// cmdid_paste_next ? +// cmdid_timeline_scrub ? +// cmdid_history_backward, +// cmdid_history_forward, +// cmdid_toggle_line_wrap, +// cmdid_close_minor_view, + +DEFINE_MODAL_KEY(modal_space, cmdid_set_mark); +DEFINE_MODAL_KEY(modal_back_slash, casey_clean_and_save); +DEFINE_MODAL_KEY(modal_single_quote, casey_call_keyboard_macro); +DEFINE_MODAL_KEY(modal_comma, casey_goto_previous_error); +DEFINE_MODAL_KEY(modal_period, casey_fill_paragraph); +DEFINE_MODAL_KEY(modal_forward_slash, cmdid_change_active_panel); +DEFINE_MODAL_KEY(modal_semicolon, cmdid_cursor_mark_swap); // TODO(casey): Maybe cmdid_history_backward? +DEFINE_MODAL_KEY(modal_open_bracket, casey_begin_keyboard_macro_recording); +DEFINE_MODAL_KEY(modal_close_bracket, casey_end_keyboard_macro_recording); +DEFINE_MODAL_KEY(modal_a, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_b, cmdid_interactive_switch_buffer); +DEFINE_MODAL_KEY(modal_c, casey_find_corresponding_file); +DEFINE_MODAL_KEY(modal_d, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_e, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_f, casey_paste_and_tab); +DEFINE_MODAL_KEY(modal_g, goto_line); +DEFINE_MODAL_KEY(modal_h, cmdid_auto_tab_range); +DEFINE_MODAL_KEY(modal_i, cmdid_redo); +DEFINE_MODAL_KEY(modal_j, casey_imenu); +DEFINE_MODAL_KEY(modal_k, casey_kill_to_end_of_line); +DEFINE_MODAL_KEY(modal_l, replace_in_range); +DEFINE_MODAL_KEY(modal_m, casey_save_and_make_without_asking); +DEFINE_MODAL_KEY(modal_n, casey_goto_next_error); +DEFINE_MODAL_KEY(modal_o, query_replace); +DEFINE_MODAL_KEY(modal_p, casey_quick_calc); +DEFINE_MODAL_KEY(modal_q, cmdid_copy); +DEFINE_MODAL_KEY(modal_r, reverse_search); // NOTE(allen): I've modified my default search so you can use it now. +DEFINE_MODAL_KEY(modal_s, search); +DEFINE_MODAL_KEY(modal_t, casey_load_todo); +DEFINE_MODAL_KEY(modal_u, cmdid_undo); +DEFINE_MODAL_KEY(modal_v, casey_switch_buffer_other_window); +DEFINE_MODAL_KEY(modal_w, cmdid_cut); +DEFINE_MODAL_KEY(modal_x, casey_open_file_other_window); +DEFINE_MODAL_KEY(modal_y, cmdid_auto_tab_line_at_cursor); +DEFINE_MODAL_KEY(modal_z, cmdid_interactive_open); + +DEFINE_MODAL_KEY(modal_1, casey_build_search); // TODO(casey): Shouldn't need to bind a key for this? +DEFINE_MODAL_KEY(modal_2, casey_load_handmade); // TODO(casey): Shouldn't need to bind a key for this? +DEFINE_MODAL_KEY(modal_3, casey_arbitrary_command); // NOTE(allen): I set this for testing stuff modal_1 and modal_2 don't need to be set anymore +DEFINE_MODAL_KEY(modal_4, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_5, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_6, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_7, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_8, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_9, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_0, cmdid_kill_buffer); +DEFINE_MODAL_KEY(modal_minus, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_equals, cmdid_write_character); // TODO(casey): Available + +DEFINE_BIMODAL_KEY(modal_backspace, casey_delete_token_left, cmdid_backspace); +DEFINE_BIMODAL_KEY(modal_up, cmdid_move_up, cmdid_move_up); +DEFINE_BIMODAL_KEY(modal_down, cmdid_move_down, cmdid_move_down); +DEFINE_BIMODAL_KEY(modal_left, cmdid_seek_white_or_token_left, cmdid_move_left); +DEFINE_BIMODAL_KEY(modal_right, cmdid_seek_white_or_token_right, cmdid_move_right); +DEFINE_BIMODAL_KEY(modal_delete, casey_delete_token_right, cmdid_delete); +DEFINE_BIMODAL_KEY(modal_home, cmdid_seek_beginning_of_line, casey_seek_beginning_of_line_and_tab); +DEFINE_BIMODAL_KEY(modal_end, cmdid_seek_end_of_line, cmdid_seek_end_of_line); +DEFINE_BIMODAL_KEY(modal_page_up, cmdid_page_up, cmdid_seek_whitespace_up); +DEFINE_BIMODAL_KEY(modal_page_down, cmdid_page_down, cmdid_seek_whitespace_down); +//DEFINE_BIMODAL_KEY(modal_escape, cmdid_write_character, cmdid_write_character); // TODO(casey): Available +DEFINE_BIMODAL_KEY(modal_tab, cmdid_word_complete, cmdid_word_complete); + +HOOK_SIG(casey_file_settings) +{ + // NOTE(allen|a4): As of alpha 4 hooks can have parameters which are + // received through functions like this app->get_parameter_buffer. + // This is different from the past where this hook got a buffer + // from app->get_active_buffer. + Buffer_Summary buffer = app->get_parameter_buffer(app, 0); + + int treat_as_code = 0; + + if (buffer.file_name && buffer.size < (16 << 20)) + { + String ext = file_extension(make_string(buffer.file_name, buffer.file_name_len)); + treat_as_code = IsCode(ext); + } + + push_parameter(app, par_lex_as_cpp_file, treat_as_code); + push_parameter(app, par_wrap_lines, !treat_as_code); + push_parameter(app, par_key_mapid, (treat_as_code)?((int)my_code_map):((int)mapid_file)); + exec_command(app, cmdid_set_settings); +} + +// NOTE(allen): This was a bit of fun so I'll leave it in, +// incase anyone would like to hack 4coder again. +#if UseHack4Coder +internal void +hack_place_modal_indicator(void) +{ + static RECT LastParentRect; + + HWND ParentWindow = GetParent(GlobalModalIndicator); + RECT ParentRect; + GetClientRect(ParentWindow, &ParentRect); + + if((LastParentRect.bottom != ParentRect.bottom) || + (LastParentRect.right != ParentRect.right)) + { + SetWindowPos(GlobalModalIndicator, 0, + (ParentRect.left+ParentRect.right)/2 - 10, + ParentRect.top, + 10, + ParentRect.bottom - ParentRect.top, + SWP_NOOWNERZORDER|SWP_NOACTIVATE); + } + + LastParentRect = ParentRect; +} + +internal LRESULT CALLBACK +main_window_intercept(HWND Window, + UINT Message, + WPARAM WParam, + LPARAM LParam) +{ + LRESULT Result = CallWindowProc(global_old_4coder_winproc, Window, Message, WParam, LParam); + + if(Message == WM_SIZE) + { + hack_place_modal_indicator(); + } + + return(Result); +} + +internal LRESULT CALLBACK +modal_indicator_window_callback(HWND Window, + UINT Message, + WPARAM WParam, + LPARAM LParam) +{ + LRESULT Result = 0; + + switch(Message) + { + case WM_PAINT: + { + PAINTSTRUCT Paint; + HDC DeviceContext = BeginPaint(Window, &Paint); + FillRect(DeviceContext, &Paint.rcPaint, GlobalEditMode ? GlobalEditModeBrush : GlobalNormalModeBrush); + EndPaint(Window, &Paint); + } break; + + default: + { + Result = DefWindowProcA(Window, Message, WParam, LParam); + } break; + } + + return(Result); +} + +internal void +hack_4coder(void) +{ + HWND Window = FindWindow("4coder-win32-wndclass", "4coder-window"); + ShowWindow(Window, SW_MAXIMIZE); + + WNDCLASSA WindowClass = {}; + + HINSTANCE Instance = GetModuleHandle(0); + + WindowClass.style = CS_HREDRAW|CS_VREDRAW; + WindowClass.lpfnWndProc = modal_indicator_window_callback; + WindowClass.hInstance = Instance; + WindowClass.hCursor = LoadCursor(0, IDC_ARROW); + WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + WindowClass.lpszClassName = "4coderhackmodaldisplay"; + + if(RegisterClassA(&WindowClass)) + { + GlobalModalIndicator = + CreateWindowEx( + 0, + WindowClass.lpszClassName, + 0, + WS_VISIBLE|WS_CHILD, + 0, 0, 10, 10, + Window, + 0, + Instance, + 0); + GlobalEditModeBrush = CreateSolidBrush(RGB(100, 20, 20)); + GlobalNormalModeBrush = CreateSolidBrush(RGB(20, 100, 20)); + + hack_place_modal_indicator(); + } + + global_old_4coder_winproc = (WNDPROC)SetWindowLongPtr(Window, GWLP_WNDPROC, (LONG_PTR)main_window_intercept); +} +#endif + +void +casey_get_bindings(Bind_Helper *context) +{ + set_hook(context, hook_start, casey_start); + set_hook(context, hook_open_file, casey_file_settings); + + set_scroll_rule(context, smooth_scroll_rule); + +#if UseHack4Coder + hack_4coder(); +#endif + + begin_map(context, mapid_global); + { + bind(context, 'z', MDFR_NONE, cmdid_interactive_open); + bind(context, 'x', MDFR_NONE, casey_open_in_other); + bind(context, 't', MDFR_NONE, casey_load_todo); + bind(context, '/', MDFR_NONE, cmdid_change_active_panel); + bind(context, 'b', MDFR_NONE, cmdid_interactive_switch_buffer); + bind(context, '3', MDFR_NONE, casey_arbitrary_command); + bind(context, key_page_up, MDFR_NONE, search); + bind(context, key_page_down, MDFR_NONE, reverse_search); + + // NOTE(allen): These don't necessarily need to be here anymore. + // They are now bound to long form commands in casey_arbitrary_command. + bind(context, '2', MDFR_NONE, casey_load_handmade); + bind(context, '4', MDFR_NONE, cmdid_open_color_tweaker); + + // NOTE(allen): I added this here myself, I believe this is what you want. + bind(context, 'm', MDFR_NONE, casey_save_and_make_without_asking); + } + end_map(context); + + begin_map(context, mapid_file); + + bind_vanilla_keys(context, cmdid_write_character); + + bind(context, key_insert, MDFR_NONE, modal_toggle); + bind(context, '`', MDFR_NONE, modal_toggle); + bind(context, '\n', MDFR_NONE, casey_newline_and_indent); + + bind(context, 't', MDFR_CTRL, cmdid_timeline_scrub); + + // NOTE(casey): Modal keys come here. + bind(context, ' ', MDFR_NONE, modal_space); + bind(context, ' ', MDFR_SHIFT, modal_space); + bind(context, '\\', MDFR_NONE, modal_back_slash); + bind(context, '\'', MDFR_NONE, modal_single_quote); + bind(context, ',', MDFR_NONE, modal_comma); + bind(context, '.', MDFR_NONE, modal_period); + bind(context, '/', MDFR_NONE, modal_forward_slash); + bind(context, ';', MDFR_NONE, modal_semicolon); + bind(context, '[', MDFR_NONE, modal_open_bracket); + bind(context, ']', MDFR_NONE, modal_close_bracket); + bind(context, 'a', MDFR_NONE, modal_a); + bind(context, 'b', MDFR_NONE, modal_b); + bind(context, 'c', MDFR_NONE, modal_c); + bind(context, 'd', MDFR_NONE, modal_d); + bind(context, 'e', MDFR_NONE, modal_e); + bind(context, 'f', MDFR_NONE, modal_f); + bind(context, 'g', MDFR_NONE, modal_g); + bind(context, 'h', MDFR_NONE, modal_h); + bind(context, 'i', MDFR_NONE, modal_i); + bind(context, 'j', MDFR_NONE, modal_j); + bind(context, 'k', MDFR_NONE, modal_k); + bind(context, 'l', MDFR_NONE, modal_l); + bind(context, 'm', MDFR_NONE, modal_m); + bind(context, 'n', MDFR_NONE, modal_n); + bind(context, 'o', MDFR_NONE, modal_o); + bind(context, 'p', MDFR_NONE, modal_p); + bind(context, 'q', MDFR_NONE, modal_q); + bind(context, 'r', MDFR_NONE, modal_r); + bind(context, 's', MDFR_NONE, modal_s); + bind(context, 't', MDFR_NONE, modal_t); + bind(context, 'u', MDFR_NONE, modal_u); + bind(context, 'v', MDFR_NONE, modal_v); + bind(context, 'w', MDFR_NONE, modal_w); + bind(context, 'x', MDFR_NONE, modal_x); + bind(context, 'y', MDFR_NONE, modal_y); + bind(context, 'z', MDFR_NONE, modal_z); + + bind(context, '1', MDFR_NONE, modal_1); + bind(context, '2', MDFR_NONE, modal_2); + bind(context, '3', MDFR_NONE, modal_3); + bind(context, '4', MDFR_NONE, modal_4); + bind(context, '5', MDFR_NONE, modal_5); + bind(context, '6', MDFR_NONE, modal_6); + bind(context, '7', MDFR_NONE, modal_7); + bind(context, '8', MDFR_NONE, modal_8); + bind(context, '9', MDFR_NONE, modal_9); + bind(context, '0', MDFR_NONE, modal_0); + bind(context, '-', MDFR_NONE, modal_minus); + bind(context, '=', MDFR_NONE, modal_equals); + + bind(context, key_back, MDFR_NONE, modal_backspace); + bind(context, key_up, MDFR_NONE, modal_up); + bind(context, key_down, MDFR_NONE, modal_down); + bind(context, key_left, MDFR_NONE, modal_left); + bind(context, key_right, MDFR_NONE, modal_right); + bind(context, key_del, MDFR_NONE, modal_delete); + bind(context, key_home, MDFR_NONE, modal_home); + bind(context, key_end, MDFR_NONE, modal_end); + bind(context, key_page_up, MDFR_NONE, modal_page_up); + bind(context, key_page_down, MDFR_NONE, modal_page_down); + bind(context, '\t', MDFR_NONE, modal_tab); +// bind(context, key_esc, MDFR_NONE, modal_escape); + + end_map(context); +} diff --git a/4coder_helper.h b/4coder_helper.h index 97d0c033..5817595f 100644 --- a/4coder_helper.h +++ b/4coder_helper.h @@ -244,6 +244,23 @@ active_view_to_line(Application_Links *app, int line_number){ app->view_set_cursor(app, &view, seek_line_char(line_number, 0), 1); } +inline View_Summary +get_first_view_with_buffer(Application_Links *app, int buffer_id){ + View_Summary result = {}; + View_Summary test = {}; + + for(test = app->get_view_first(app); + test.exists; + app->get_view_next(app, &test)){ + if(test.buffer_id == buffer_id){ + result = test; + break; + } + } + + return(result); +} + inline int key_is_unmodified(Key_Event_Data *key){ char *mods = key->modifiers; @@ -322,3 +339,5 @@ query_user_number(Application_Links *app, Query_Bar *bar){ int success = query_user_general(app, bar, 1); return(success); } + +inline String empty_string() {String Result = {}; return(Result);} diff --git a/4ed.cpp b/4ed.cpp index b6aab82d..f7797d15 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -948,6 +948,10 @@ COMMAND_DECL(interactive_open){ delayed_open_background(delay, string); } else{ + // TODO(allen): Change the behavior of all delayed_open/background + // calls so that they still allocate the buffer right away. This way + // it's still possible to get at the buffer if so wished in the API. + // The switch for this view doesn't need to happen until the file is ready. delayed_open(delay, string, panel); } } @@ -2454,7 +2458,7 @@ extern "C"{ } GET_USER_INPUT_SIG(external_get_user_input){ - Command_Data *cmd = (Command_Data*)context->cmd_context; + Command_Data *cmd = (Command_Data*)app->cmd_context; System_Functions *system = cmd->system; Coroutine *coroutine = cmd->models->command_coroutine; User_Input result; @@ -2469,7 +2473,7 @@ extern "C"{ } START_QUERY_BAR_SIG(external_start_query_bar){ - Command_Data *cmd = (Command_Data*)context->cmd_context; + Command_Data *cmd = (Command_Data*)app->cmd_context; Query_Slot *slot = 0; View *vptr; @@ -2482,19 +2486,49 @@ extern "C"{ } END_QUERY_BAR_SIG(external_end_query_bar){ - Command_Data *cmd = (Command_Data*)context->cmd_context; + Command_Data *cmd = (Command_Data*)app->cmd_context; View *vptr; vptr = cmd->view; free_query_slot(&vptr->query_set, bar); } - + + CHANGE_THEME_SIG(external_change_theme){ + Command_Data *cmd = (Command_Data*)app->cmd_context; + Style_Library *styles = &cmd->models->styles; + String theme_name = make_string(name, len); + Style *s; + i32 i, count; + + count = styles->count; + s = styles->styles; + for (i = 0; i < count; ++i, ++s){ + if (match(s->name, theme_name)){ + style_copy(&cmd->models->style, s); + break; + } + } + } + + CHANGE_FONT_SIG(external_change_font){ + Command_Data *cmd = (Command_Data*)app->cmd_context; + Font_Set *set = cmd->models->font_set; + Style_Font *global_font = &cmd->models->global_font; + String font_name = make_string(name, len); + i16 font_id; + + if (font_set_extract(set, font_name, &font_id)){ + global_font->font_id = font_id; + global_font->font_changed = 1; + } + } + SET_THEME_COLORS_SIG(external_set_theme_colors){ - Command_Data *cmd = (Command_Data*)context->cmd_context; + Command_Data *cmd = (Command_Data*)app->cmd_context; Style *style = &cmd->models->style; Theme_Color *theme_color; - i32 i; u32 *color; + i32 i; theme_color = colors; for (i = 0; i < count; ++i, ++theme_color){ @@ -2569,6 +2603,8 @@ app_links_init(System_Functions *system, void *data, int size){ app_links.start_query_bar = external_start_query_bar; app_links.end_query_bar = external_end_query_bar; + app_links.change_theme = external_change_theme; + app_links.change_font = external_change_font; app_links.set_theme_colors = external_set_theme_colors; } diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index dd53115f..08883d2a 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -35,12 +35,13 @@ #define FCPP_LEXER_IMPLEMENTATION #include "4cpp_lexer.h" +#include "4ed_template.cpp" + #include "4ed_font_set.cpp" #include "4ed_rendering_helper.cpp" #include "4ed_style.h" #include "4ed_style.cpp" -#include "4ed_template.cpp" #include "4ed_exchange.cpp" #include "4ed_command.cpp" #include "4ed_file.cpp" diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index d6563586..221b136a 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1724,6 +1724,11 @@ file_do_white_batch_edit(System_Functions *system, App_Models *models, Editing_F Mem_Options *mem = &models->mem; Editing_Layout *layout = &models->layout; + // NOTE(allen): fixing stuff "beforewards"??? + Assert(spec.str == 0); + file_update_history_before_edit(mem, file, spec.step, 0, history_mode); + file_pre_edit_maintenance(system, &mem->general, file); + // NOTE(allen): actual text replacement General_Memory *general = &mem->general; Partition *part = &mem->part; @@ -3286,7 +3291,7 @@ do_file_bar(View *view, Editing_File *file, UI_Layout *layout, Render_Target *ta u32 pop2_color = bar_style.pop2_color; bar.rect = layout_rect(layout, line_height + 2); - + if (target){ bar.font_id = font->font_id; bar.pos_x = (f32)bar.rect.x0; @@ -3383,7 +3388,7 @@ step_file_view(System_Functions *system, Exchange *exchange, View *view, i32_Rec switch (view->widget.type){ case FWIDG_NONE: { - if (file){ + if (file && view->showing_ui == VUI_None){ do_file_bar(view, file, &layout, 0); } @@ -3733,7 +3738,7 @@ draw_file_view(System_Functions *system, Exchange *exchange, switch (view->widget.type){ case FWIDG_NONE: { - if (file){ + if (file && view->showing_ui == VUI_None){ do_file_bar(view, file, &layout, target); } diff --git a/4ed_font_set.cpp b/4ed_font_set.cpp index 16502b14..e0410920 100644 --- a/4ed_font_set.cpp +++ b/4ed_font_set.cpp @@ -1,232 +1,230 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 18.12.2015 - * - * Font set for 4coder - * - */ - -// TOP - -inline u32 -font_hash(String name){ - u32 x = 5381; - char *p = name.str; - for (i32 i = 0; i < name.size; ++i, ++p){ - x = ((x << 5) + x) ^ (*p); - } - return(x); -} - -inline void -font__insert(Font_Slot *pos, Font_Slot *slot){ - Font_Slot *nex; - nex = pos->next; - - slot->next = nex; - slot->prev = pos; - nex->prev = slot; - pos->next = slot; -} - -inline void -font__remove(Font_Slot *slot){ - Font_Slot *n, *p; - n = slot->next; - p = slot->prev; - - p->next = n; - n->prev = p; -} - -internal void -font_set_init(Font_Set *set, Partition *partition, i32 max, i16 live_max){ - partition_align(partition, 8); - set->info = push_array(partition, Font_Info, max); - partition_align(partition, 8); - set->entries = push_array(partition, Font_Table_Entry, max); - set->count = 0; - set->max = max; - - partition_align(partition, 8); - set->font_block = push_block(partition, live_max*(sizeof(Render_Font) + sizeof(Font_Slot))); - - set->free_slots = {}; - set->used_slots = {}; - - set->free_slots.next = &set->free_slots; - set->free_slots.prev = &set->free_slots; - set->used_slots.next = &set->used_slots; - set->used_slots.prev = &set->used_slots; - - char *ptr = (char*)set->font_block; - for (i32 i = 0; i < live_max; ++i){ - font__insert(&set->free_slots, (Font_Slot*)ptr); - ptr += sizeof(Font_Slot) + sizeof(Render_Font); - } - - set->font_used_flags = push_array(partition, b8, max); - set->live_max = live_max; -} - -internal b32 -font_set_can_add(Font_Set *set){ - b32 result = 0; - if (set->count*8 < set->max*7) result = 1; - return(result); -} - -internal void -font_set_add_hash(Font_Set *set, String name, i16 font_id){ - Font_Table_Entry entry; - entry.hash = font_hash(name); - entry.name = name; - entry.font_id = font_id; - - u32 i, j; - i = entry.hash % set->max; - j = i - 1; - if (i <= 1) j += set->max; - - for (; i != j; ++i){ - if (i == set->max) i = 0; - if (set->entries[i].font_id == 0){ - set->entries[i] = entry; - break; - } - } - - Assert(i != j); -} - -inline b32 -font_set_can_load(Font_Set *set){ - b32 result = (set->free_slots.next != &set->free_slots); - return(result); -} - -internal void -font_set_load(Partition *partition, Font_Set *set, i16 font_id){ - Font_Info *info = get_font_info(set, font_id); - Font_Slot *slot = set->free_slots.next; - Assert(slot != &set->free_slots); - font__remove(slot); - font__insert(&set->used_slots, slot); - - Render_Font *font = (Render_Font*)(slot + 1); - set->font_load(font, info->filename.str, info->pt_size, 4); - info->font = font; - slot->font_id = font_id; -} - -internal void -font_set_evict_lru(Font_Set *set){ - Font_Slot *slot = set->used_slots.prev; - Assert(slot != &set->used_slots); - - i16 font_id = slot->font_id; - Font_Info *info = get_font_info(set, font_id); - Assert(((Font_Slot*)info->font) - 1 == slot); - - set->release_font(info->font); - - info->font = 0; - slot->font_id = 0; - font__remove(slot); - font__insert(&set->free_slots, slot); -} - -internal void -font_set_use(Partition *partition, Font_Set *set, i16 font_id){ - b8 already_used; - already_used = set->font_used_flags[font_id-1]; - - if (!already_used){ - if (set->used_this_frame < set->live_max){ - ++set->used_this_frame; - set->font_used_flags[font_id-1] = 1; - already_used = 1; - } - } - - if (already_used){ - // TODO(allen): optimize if you don't mind!!!! - Font_Info *info = get_font_info(set, font_id); - Font_Slot *slot; - if (info->font == 0){ - if (!font_set_can_load(set)){ - font_set_evict_lru(set); - } - font_set_load(partition, set, font_id); - } - slot = ((Font_Slot*)info->font) - 1; - - font__remove(slot); - font__insert(&set->used_slots, slot); - } -} - -internal b32 -font_set_add(Partition *partition, Font_Set *set, - String filename, String name, i32 pt_size){ - b32 result = 0; - if (font_set_can_add(set)){ - i16 font_id = (i16)(++set->count); - Font_Info *info = get_font_info(set, font_id); - info->filename = filename; - info->name = name; - info->pt_size = pt_size; - set->font_info_load(partition, filename.str, pt_size, &info->height, &info->advance); - font_set_add_hash(set, name, font_id); - - if (font_set_can_load(set)){ - font_set_load(partition, set, font_id); - } - - result = 1; - } - return(result); -} - -internal b32 -font_set_find_pos(Font_Set *set, String name, u32 *position){ - b32 result; - u32 hash, i, j; - hash = font_hash(name); - i = hash % set->max; - j = i - 1; - if (j <= 1) j += set->max; - - result = 0; - Font_Table_Entry *entry; - for (; i != j; ++i){ - if (i == set->max) i = 0; - entry = set->entries + i; - if (entry->hash == hash){ - if (match(name, entry->name)){ - result = 1; - *position = i; - break; - } - } - } - - return(result); -} - -internal b32 -font_set_extract(Font_Set *set, String name, i16 *font_id){ - b32 result; - u32 position; - - result = font_set_find_pos(set, name, &position); - if (result){ - *font_id = set->entries[position].font_id; - } - - return(result); -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 18.12.2015 + * + * Font set for 4coder + * + */ + +// TOP + +inline u32 +font_hash(String name){ + u32 x = 5381; + char *p = name.str; + for (i32 i = 0; i < name.size; ++i, ++p){ + x = ((x << 5) + x) ^ (*p); + } + return(x); +} + +inline void +font__insert(Font_Slot *pos, Font_Slot *slot){ + Font_Slot *nex; + nex = pos->next; + + slot->next = nex; + slot->prev = pos; + nex->prev = slot; + pos->next = slot; +} + +inline void +font__remove(Font_Slot *slot){ + Font_Slot *n, *p; + n = slot->next; + p = slot->prev; + + p->next = n; + n->prev = p; +} + +internal void +font_set_init(Font_Set *set, Partition *partition, i32 max, i16 live_max){ + partition_align(partition, 8); + set->info = push_array(partition, Font_Info, max); + partition_align(partition, 8); + set->entries = push_array(partition, Font_Table_Entry, max); + set->count = 0; + set->max = max; + + partition_align(partition, 8); + set->font_block = push_block(partition, live_max*(sizeof(Render_Font) + sizeof(Font_Slot))); + + set->free_slots = {}; + set->used_slots = {}; + + dll_init_sentinel(&set->free_slots); + dll_init_sentinel(&set->used_slots); + + char *ptr = (char*)set->font_block; + for (i32 i = 0; i < live_max; ++i){ + dll_insert(&set->free_slots, (Font_Slot*)ptr); + ptr += sizeof(Font_Slot) + sizeof(Render_Font); + } + + set->font_used_flags = push_array(partition, b8, max); + set->live_max = live_max; +} + +internal b32 +font_set_can_add(Font_Set *set){ + b32 result = 0; + if (set->count*8 < set->max*7) result = 1; + return(result); +} + +internal void +font_set_add_hash(Font_Set *set, String name, i16 font_id){ + Font_Table_Entry entry; + entry.hash = font_hash(name); + entry.name = name; + entry.font_id = font_id; + + u32 i, j; + i = entry.hash % set->max; + j = i - 1; + if (i <= 1) j += set->max; + + for (; i != j; ++i){ + if (i == set->max) i = 0; + if (set->entries[i].font_id == 0){ + set->entries[i] = entry; + break; + } + } + + Assert(i != j); +} + +inline b32 +font_set_can_load(Font_Set *set){ + b32 result = (set->free_slots.next != &set->free_slots); + return(result); +} + +internal void +font_set_load(Partition *partition, Font_Set *set, i16 font_id){ + Font_Info *info = get_font_info(set, font_id); + Font_Slot *slot = set->free_slots.next; + Assert(slot != &set->free_slots); + font__remove(slot); + font__insert(&set->used_slots, slot); + + Render_Font *font = (Render_Font*)(slot + 1); + set->font_load(font, info->filename.str, info->pt_size, 4); + info->font = font; + slot->font_id = font_id; +} + +internal void +font_set_evict_lru(Font_Set *set){ + Font_Slot *slot = set->used_slots.prev; + Assert(slot != &set->used_slots); + + i16 font_id = slot->font_id; + Font_Info *info = get_font_info(set, font_id); + Assert(((Font_Slot*)info->font) - 1 == slot); + + set->release_font(info->font); + + info->font = 0; + slot->font_id = 0; + font__remove(slot); + font__insert(&set->free_slots, slot); +} + +internal void +font_set_use(Partition *partition, Font_Set *set, i16 font_id){ + b8 already_used; + already_used = set->font_used_flags[font_id-1]; + + if (!already_used){ + if (set->used_this_frame < set->live_max){ + ++set->used_this_frame; + set->font_used_flags[font_id-1] = 1; + already_used = 1; + } + } + + if (already_used){ + // TODO(allen): optimize if you don't mind!!!! + Font_Info *info = get_font_info(set, font_id); + Font_Slot *slot; + if (info->font == 0){ + if (!font_set_can_load(set)){ + font_set_evict_lru(set); + } + font_set_load(partition, set, font_id); + } + slot = ((Font_Slot*)info->font) - 1; + + font__remove(slot); + font__insert(&set->used_slots, slot); + } +} + +internal b32 +font_set_add(Partition *partition, Font_Set *set, + String filename, String name, i32 pt_size){ + b32 result = 0; + if (font_set_can_add(set)){ + i16 font_id = (i16)(++set->count); + Font_Info *info = get_font_info(set, font_id); + info->filename = filename; + info->name = name; + info->pt_size = pt_size; + set->font_info_load(partition, filename.str, pt_size, &info->height, &info->advance); + font_set_add_hash(set, name, font_id); + + if (font_set_can_load(set)){ + font_set_load(partition, set, font_id); + } + + result = 1; + } + return(result); +} + +internal b32 +font_set_find_pos(Font_Set *set, String name, u32 *position){ + b32 result; + u32 hash, i, j; + hash = font_hash(name); + i = hash % set->max; + j = i - 1; + if (j <= 1) j += set->max; + + result = 0; + Font_Table_Entry *entry; + for (; i != j; ++i){ + if (i == set->max) i = 0; + entry = set->entries + i; + if (entry->hash == hash){ + if (match(name, entry->name)){ + result = 1; + *position = i; + break; + } + } + } + + return(result); +} + +internal b32 +font_set_extract(Font_Set *set, String name, i16 *font_id){ + b32 result; + u32 position; + + result = font_set_find_pos(set, name, &position); + if (result){ + *font_id = set->entries[position].font_id; + } + + return(result); +} + +// BOTTOM + diff --git a/4ed_style.cpp b/4ed_style.cpp index a17f66da..903f8c15 100644 --- a/4ed_style.cpp +++ b/4ed_style.cpp @@ -44,11 +44,6 @@ struct Style_Library{ }; #if 0 -struct Style_Color_Specifier{ - u32 tag; - u32 color; -}; - struct Style_File_Format{ i32 name_size; char name[24]; diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp index 7433b014..a4bebeb4 100644 --- a/buffer/4coder_buffer_abstract.cpp +++ b/buffer/4coder_buffer_abstract.cpp @@ -1056,15 +1056,19 @@ buffer_cursor_seek(Buffer_Type *buffer, Buffer_Seek seek, float max_width, switch(seek.type){ case buffer_seek_pos: if (cursor.pos >= seek.pos) goto buffer_cursor_seek_end; + break; case buffer_seek_wrapped_xy: if (seek.x == 0 && cursor.wrapped_y >= seek.y) goto buffer_cursor_seek_end; + break; case buffer_seek_unwrapped_xy: if (seek.x == 0 && cursor.unwrapped_y >= seek.y) goto buffer_cursor_seek_end; + break; case buffer_seek_line_char: if (cursor.line >= seek.line && cursor.character >= seek.character) goto buffer_cursor_seek_end; + break; } if (advance_data){ diff --git a/buildsuper.bat b/buildsuper.bat index 20a80a32..28350c9b 100644 --- a/buildsuper.bat +++ b/buildsuper.bat @@ -9,8 +9,8 @@ SET STUFF=/GR- /nologo SET DEBUG=/Zi SET EXPORTS=/EXPORT:get_bindings SET SRC=4coder_custom.cpp -REM SET LINKS=user32.lib gdi32.lib -SET LINKS= +SET LINKS=user32.lib gdi32.lib +REM SET LINKS= cl %WARNINGS% %STUFF% %DEBUG% %SRC% %LINKS% /Fe4coder_custom /LD /link /INCREMENTAL:NO /OPT:REF %EXPORTS%