diff --git a/4coder_base_commands.cpp b/4coder_base_commands.cpp index 3c81d73f..1318e4d5 100644 --- a/4coder_base_commands.cpp +++ b/4coder_base_commands.cpp @@ -306,6 +306,16 @@ CUSTOM_COMMAND_SIG(seek_end_of_line){ view_set_cursor(app, &view, seek_xy(100000.f, y, 1, view.unwrapped_lines), 1); } +CUSTOM_COMMAND_SIG(seek_whitespace_up_end_line){ + exec_command(app, seek_whitespace_up); + exec_command(app, seek_end_of_line); +} + +CUSTOM_COMMAND_SIG(seek_whitespace_down_end_line){ + exec_command(app, seek_whitespace_down); + exec_command(app, seek_end_of_line); +} + // // Fancy Editing diff --git a/4coder_build_commands.cpp b/4coder_build_commands.cpp new file mode 100644 index 00000000..1e76bdfe --- /dev/null +++ b/4coder_build_commands.cpp @@ -0,0 +1,234 @@ +/* +4coder_build_commands.cpp - Commands for building. + +TYPE: 'drop-in-command-pack' +*/ + +// TOP + +#if !defined(FCODER_BUILD_COMMANDS_CPP) +#define FCODER_BUILD_COMMANDS_CPP + +#include "4coder_helper/4coder_helper.h" + +#include "4coder_default_framework.h" + +// NOTE(allen|a4.0.9): This is provided to establish a default method of getting +// a "build directory". This function tries to setup the build directory in the +// directory of the given buffer, if it cannot get that information it get's the +// 4coder hot directory. +// +// There is no requirement that a custom build system in 4coder actually use the +// directory given by this function. +enum Get_Build_Directory_Result{ + BuildDir_None, + BuildDir_AtFile, + BuildDir_AtHot +}; + +static int32_t +get_build_directory(Application_Links *app, Buffer_Summary *buffer, String *dir_out){ + int32_t result = BuildDir_None; + + if (buffer && buffer->file_name){ + if (!match_cc(buffer->file_name, buffer->buffer_name)){ + String dir = make_string_cap(buffer->file_name, + buffer->file_name_len, + buffer->file_name_len+1); + remove_last_folder(&dir); + append_ss(dir_out, dir); + result = BuildDir_AtFile; + } + } + + if (!result){ + int32_t len = directory_get_hot(app, dir_out->str, + dir_out->memory_size - dir_out->size); + if (len + dir_out->size < dir_out->memory_size){ + dir_out->size += len; + result = BuildDir_AtHot; + } + } + + return(result); +} + +// TODO(allen): Better names for the "standard build search" family. +static int32_t +standard_build_search(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer, String *dir, String *command, int32_t perform_backup, int32_t use_path_in_command, String filename, String commandname){ + int32_t result = false; + + for(;;){ + int32_t old_size = dir->size; + append_ss(dir, filename); + + if (file_exists(app, dir->str, dir->size)){ + dir->size = old_size; + + if (use_path_in_command){ + append_s_char(command, '"'); + append_ss(command, *dir); + append_ss(command, commandname); + append_s_char(command, '"'); + } + else{ + append_ss(command, commandname); + } + + char space[512]; + String message = make_fixed_width_string(space); + append_ss(&message, make_lit_string("Building with: ")); + append_ss(&message, *command); + append_s_char(&message, '\n'); + print_message(app, message.str, message.size); + + exec_system_command(app, view, buffer_identifier(literal("*compilation*")), dir->str, dir->size, command->str, command->size, CLI_OverlapWithConflict); + result = true; + break; + } + dir->size = old_size; + + if (directory_cd(app, dir->str, &dir->size, dir->memory_size, literal("..")) == 0){ + if (perform_backup){ + dir->size = directory_get_hot(app, dir->str, dir->memory_size); + char backup_space[256]; + String backup_command = make_fixed_width_string(backup_space); + append_ss(&backup_command, make_lit_string("echo could not find ")); + append_ss(&backup_command, filename); + exec_system_command(app, view, buffer_identifier(literal("*compilation*")), dir->str, dir->size, backup_command.str, backup_command.size, CLI_OverlapWithConflict); + } + break; + } + } + + return(result); +} + +#if defined(_WIN32) + +// NOTE(allen): Build search rule for windows. +static int32_t +execute_standard_build_search(Application_Links *app, View_Summary *view, + Buffer_Summary *active_buffer, + String *dir, String *command, int32_t perform_backup){ + int32_t result = standard_build_search(app, view, active_buffer, dir, command, perform_backup, true, make_lit_string("build.bat"), make_lit_string("build")); + return(result); +} + +#elif defined(__linux__) + +// NOTE(allen): Build search rule for linux. +static int32_t +execute_standard_build_search(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer, String *dir, String *command, bool32 perform_backup){ + char dir_space[512]; + String dir_copy = make_fixed_width_string(dir_space); + copy(&dir_copy, *dir); + + int32_t result = standard_build_search(app, view, active_buffer, dir, command, 0, 1, make_lit_string("build.sh"), make_lit_string("build.sh")); + + if (!result){ + result = standard_build_search(app, view, active_buffer, &dir_copy, command, perform_backup, 0, make_lit_string("Makefile"), make_lit_string("make")); + } + + return(result); +} + +#else +# error No build search rule for this platform. +#endif + +// NOTE(allen): This searches first using the active file's directory, +// then if no build script is found, it searches from 4coders hot directory. +static void +execute_standard_build(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer){ + char dir_space[512]; + String dir = make_fixed_width_string(dir_space); + + char command_str_space[512]; + String command = make_fixed_width_string(command_str_space); + + int32_t build_dir_type = get_build_directory(app, active_buffer, &dir); + + if (build_dir_type == BuildDir_AtFile){ + if (!execute_standard_build_search(app, view, active_buffer, &dir, &command, false)){ + dir.size = 0; + command.size = 0; + build_dir_type = get_build_directory(app, 0, &dir); + } + } + + if (build_dir_type == BuildDir_AtHot){ + execute_standard_build_search(app, view, active_buffer, &dir, &command, true); + } +} + +CUSTOM_COMMAND_SIG(build_search){ + uint32_t access = AccessAll; + View_Summary view = get_active_view(app, access); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + execute_standard_build(app, &view, &buffer); + prev_location = null_location; + lock_jump_buffer(literal("*compilation*")); +} + +#define GET_COMP_BUFFER(app) get_buffer_by_name(app, literal("*compilation*"), AccessAll) + +static View_Summary +get_or_open_build_panel(Application_Links *app){ + View_Summary view = {0}; + + Buffer_Summary buffer = GET_COMP_BUFFER(app); + if (buffer.exists){ + view = get_first_view_with_buffer(app, buffer.buffer_id); + } + if (!view.exists){ + view = open_special_note_view(app); + } + + return(view); +} + +static void +set_fancy_compilation_buffer_font(Application_Links *app){ + Buffer_Summary comp_buffer = get_buffer_by_name(app, literal("*compilation*"), AccessAll); + buffer_set_font(app, &comp_buffer, literal("Inconsolata")); +} + +CUSTOM_COMMAND_SIG(build_in_build_panel){ + uint32_t access = AccessAll; + View_Summary view = get_active_view(app, access); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + + View_Summary build_view = get_or_open_build_panel(app); + + execute_standard_build(app, &build_view, &buffer); + set_fancy_compilation_buffer_font(app); + + prev_location = null_location; + lock_jump_buffer(literal("*compilation*")); +} + +CUSTOM_COMMAND_SIG(close_build_panel){ + close_special_note_view(app); +} + +CUSTOM_COMMAND_SIG(change_to_build_panel){ + View_Summary view = open_special_note_view(app, false); + + if (!view.exists){ + Buffer_Summary buffer = GET_COMP_BUFFER(app); + if (buffer.exists){ + view = open_special_note_view(app); + view_set_buffer(app, &view, buffer.buffer_id, 0); + } + } + + if (view.exists){ + set_active_view(app, &view); + } +} + +#endif + +// BOTTOM + diff --git a/4coder_clipboard.cpp b/4coder_clipboard.cpp new file mode 100644 index 00000000..56e13c01 --- /dev/null +++ b/4coder_clipboard.cpp @@ -0,0 +1,147 @@ +/* +4coder_clipboard.cpp - Copy paste commands and clipboard related setup. + +TYPE: 'drop-in-command-pack' +*/ + +// TOP + +#if !defined(FCODER_CLIPBOARD_CPP) +#define FCODER_CLIPBOARD_CPP + +#include "4coder_default_framework.h" + +#include "4coder_helper/4coder_helper.h" + +static bool32 +clipboard_copy(Application_Links *app, int32_t start, int32_t end, Buffer_Summary *buffer_out, uint32_t access){ + View_Summary view = get_active_view(app, access); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + bool32 result = 0; + + if (buffer.exists){ + if (0 <= start && start <= end && end <= buffer.size){ + int32_t size = (end - start); + char *str = (char*)app->memory; + + if (size <= app->memory_size){ + buffer_read_range(app, &buffer, start, end, str); + clipboard_post(app, 0, str, size); + if (buffer_out){*buffer_out = buffer;} + result = 1; + } + } + } + + return(result); +} + +static int32_t +clipboard_cut(Application_Links *app, int32_t start, int32_t end, Buffer_Summary *buffer_out, uint32_t access){ + Buffer_Summary buffer = {0}; + int32_t result = false; + + if (clipboard_copy(app, start, end, &buffer, access)){ + buffer_replace_range(app, &buffer, start, end, 0, 0); + if (buffer_out){*buffer_out = buffer;} + } + + return(result); +} + +CUSTOM_COMMAND_SIG(copy){ + uint32_t access = AccessProtected; + View_Summary view = get_active_view(app, access); + Range range = get_range(&view); + clipboard_copy(app, range.min, range.max, 0, access); +} + +CUSTOM_COMMAND_SIG(cut){ + uint32_t access = AccessOpen; + View_Summary view = get_active_view(app, access); + Range range = get_range(&view); + clipboard_cut(app, range.min, range.max, 0, access); +} + +CUSTOM_COMMAND_SIG(paste){ + uint32_t access = AccessOpen; + int32_t count = clipboard_count(app, 0); + if (count > 0){ + View_Summary view = get_active_view(app, access); + + view_paste_index[view.view_id].next_rewrite = RewritePaste; + + int32_t paste_index = 0; + view_paste_index[view.view_id].index = paste_index; + + int32_t len = clipboard_index(app, 0, paste_index, 0, 0); + char *str = 0; + + if (len <= app->memory_size){ + str = (char*)app->memory; + } + + if (str){ + clipboard_index(app, 0, paste_index, str, len); + + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + int32_t pos = view.cursor.pos; + buffer_replace_range(app, &buffer, pos, pos, str, len); + view_set_mark(app, &view, seek_pos(pos)); + view_set_cursor(app, &view, seek_pos(pos + len), true); + + // TODO(allen): Send this to all views. + Theme_Color paste; + paste.tag = Stag_Paste; + get_theme_colors(app, &paste, 1); + view_post_fade(app, &view, 0.667f, pos, pos + len, paste.color); + } + } +} + +CUSTOM_COMMAND_SIG(paste_next){ + uint32_t access = AccessOpen; + int32_t count = clipboard_count(app, 0); + if (count > 0){ + View_Summary view = get_active_view(app, access); + + if (view_paste_index[view.view_id].rewrite == RewritePaste){ + view_paste_index[view.view_id].next_rewrite = RewritePaste; + + int32_t paste_index = view_paste_index[view.view_id].index + 1; + view_paste_index[view.view_id].index = paste_index; + + int32_t len = clipboard_index(app, 0, paste_index, 0, 0); + char *str = 0; + + if (len <= app->memory_size){ + str = (char*)app->memory; + } + + if (str){ + clipboard_index(app, 0, paste_index, str, len); + + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + Range range = get_range(&view); + int32_t pos = range.min; + + buffer_replace_range(app, &buffer, range.min, range.max, str, len); + view_set_cursor(app, &view, seek_pos(pos + len), true); + + // TODO(allen): Send this to all views. + Theme_Color paste; + paste.tag = Stag_Paste; + get_theme_colors(app, &paste, 1); + view_post_fade(app, &view, 0.667f, pos, pos + len, paste.color); + } + } + else{ + exec_command(app, paste); + } + } +} + +#endif + +// BOTTOM + diff --git a/4coder_default_bindings.cpp b/4coder_default_bindings.cpp index 354530b1..d1f8f1c1 100644 --- a/4coder_default_bindings.cpp +++ b/4coder_default_bindings.cpp @@ -1,314 +1,23 @@ +/* +4coder_default_bidings.cpp - Supplies the default bindings used for default 4coder behavior. + +TYPE: 'build-target' +*/ // TOP -#ifndef FCODER_DEFAULT_BINDINGS +#if !defined(FCODER_DEFAULT_BINDINGS) #define FCODER_DEFAULT_BINDINGS #include "4coder_default_include.cpp" -// NOTE(allen|a3.3): All of your custom ids should be enumerated -// as shown here, they may start at 0, and you can only have -// 2^24 of them so don't be wasteful! -enum My_Maps{ - my_code_map, - my_maps_count -}; - -CUSTOM_COMMAND_SIG(write_allen_todo){ - write_string(app, make_lit_string("// TODO(allen): ")); -} - -CUSTOM_COMMAND_SIG(write_allen_note){ - write_string(app, make_lit_string("// NOTE(allen): ")); -} - -CUSTOM_COMMAND_SIG(write_allen_doc){ - write_string(app, make_lit_string("/* DOC() */")); -} - -CUSTOM_COMMAND_SIG(write_zero_struct){ - write_string(app, make_lit_string(" = {0};")); -} - -CUSTOM_COMMAND_SIG(switch_to_compilation){ - - char name[] = "*compilation*"; - int32_t name_size = sizeof(name)-1; - - uint32_t access = AccessOpen; - View_Summary view = get_active_view(app, access); - Buffer_Summary buffer = get_buffer_by_name(app, name, name_size, access); - - view_set_buffer(app, &view, buffer.buffer_id, 0); -} - -CUSTOM_COMMAND_SIG(rewrite_as_single_caps){ - uint32_t access = AccessOpen; - View_Summary view = get_active_view(app, access); - Full_Cursor cursor = view.cursor; - - // TODO(allen): This can be rewritten now without moving the - // cursor around, instead just calling the boundary seek. - Range range = {0}; - exec_command(app, seek_token_left); - refresh_view(app, &view); - range.min = view.cursor.pos; - - exec_command(app, seek_token_right); - refresh_view(app, &view); - range.max = view.cursor.pos; - - String string = {0}; - string.str = (char*)app->memory; - string.size = range.max - range.min; - assert(string.size < app->memory_size); - - Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - buffer_read_range(app, &buffer, range.min, range.max, string.str); - - int32_t is_first = true; - for (int32_t i = 0; i < string.size; ++i){ - if (char_is_alpha_true(string.str[i])){ - if (is_first){ - is_first = false; - } - else{ - string.str[i] = char_to_lower(string.str[i]); - } - } - else{ - is_first = true; - } - } - - buffer_replace_range(app, &buffer, range.min, range.max, string.str, string.size); - - view_set_cursor(app, &view, seek_line_char(cursor.line+1, cursor.character), true); -} - -CUSTOM_COMMAND_SIG(open_my_files){ - uint32_t access = AccessAll; - View_Summary view = get_active_view(app, access); - view_open_file(app, &view, literal("w:/4ed/data/test/basic.cpp"), true); -} - -CUSTOM_COMMAND_SIG(build_at_launch_location){ - uint32_t access = AccessAll; - View_Summary view = get_active_view(app, access); - exec_system_command(app, &view, buffer_identifier(literal("*compilation*")),literal("."), literal("build"), CLI_OverlapWithConflict); -} - -CUSTOM_COMMAND_SIG(seek_whitespace_up_end_line){ - exec_command(app, seek_whitespace_up); - exec_command(app, seek_end_of_line); -} - -CUSTOM_COMMAND_SIG(seek_whitespace_down_end_line){ - exec_command(app, seek_whitespace_down); - exec_command(app, seek_end_of_line); -} - -HOOK_SIG(my_start){ - default_4coder_initialize(app); - default_4coder_side_by_side_panels(app); - - // no meaning for return - return(0); -} - -HOOK_SIG(my_exit){ - // if this returns zero it cancels the exit. - return(1); -} - -HOOK_SIG(my_view_adjust){ - int32_t count = 0; - int32_t new_wrap_width = 0; - for (View_Summary view = get_view_first(app, AccessAll); - view.exists; - get_view_next(app, &view, AccessAll)){ - new_wrap_width += view.view_region.x1 - view.view_region.x0; - ++count; - } - - new_wrap_width /= count; - new_wrap_width = (int32_t)(new_wrap_width * .9f); - - int32_t new_min_base_width = (int32_t)(new_wrap_width * .77f); - if (automatically_adjust_wrapping){ - adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width); - } - - // no meaning for return - return(0); -} - -CUSTOM_COMMAND_SIG(newline_or_goto_position){ - View_Summary view = get_active_view(app, AccessProtected); - Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessProtected); - - if (buffer.lock_flags & AccessProtected){ - exec_command(app, goto_jump_at_cursor); - lock_jump_buffer(buffer); - } - else{ - exec_command(app, write_character); - } -} - -// TODO(allen): Eliminate this hook if you can. -OPEN_FILE_HOOK_SIG(my_file_settings){ - // NOTE(allen|a4.0.8): The get_parameter_buffer was eliminated - // and instead the buffer is passed as an explicit parameter through - // the function call. That is where buffer_id comes from here. - uint32_t access = AccessAll; - Buffer_Summary buffer = get_buffer(app, buffer_id, access); - assert(buffer.exists); - - int32_t treat_as_code = 0; - int32_t wrap_lines = 1; - - if (buffer.file_name && buffer.size < (16 << 20)){ - String ext = file_extension(make_string(buffer.file_name, buffer.file_name_len)); - if (match_ss(ext, make_lit_string("cpp"))) treat_as_code = 1; - else if (match_ss(ext, make_lit_string("h"))) treat_as_code = 1; - else if (match_ss(ext, make_lit_string("c"))) treat_as_code = 1; - else if (match_ss(ext, make_lit_string("hpp"))) treat_as_code = 1; - } - - if (treat_as_code){ - wrap_lines = 0; - } - if (buffer.file_name[0] == '*'){ - wrap_lines = 0; - } - - buffer_set_setting(app, &buffer, BufferSetting_WrapPosition, default_wrap_width); - buffer_set_setting(app, &buffer, BufferSetting_MinimumBaseWrapPosition, default_min_base_width); - buffer_set_setting(app, &buffer, BufferSetting_MapID, (treat_as_code)?((int32_t)my_code_map):((int32_t)mapid_file)); - - if (treat_as_code && enable_code_wrapping && buffer.size < (1 << 18)){ - // NOTE(allen|a4.0.12): There is a little bit of grossness going on here. - // If we set BufferSetting_Lex to true, it will launch a lexing job. - // If a lexing job is active when we set BufferSetting_VirtualWhitespace, the call can fail. - // Unfortunantely without tokens virtual whitespace doesn't really make sense. - // So for now I have it automatically turning on lexing when virtual whitespace is turned on. - // Cleaning some of that up is a goal for future versions. - buffer_set_setting(app, &buffer, BufferSetting_WrapLine, 1); - buffer_set_setting(app, &buffer, BufferSetting_VirtualWhitespace, 1); - } - else{ - buffer_set_setting(app, &buffer, BufferSetting_WrapLine, wrap_lines); - buffer_set_setting(app, &buffer, BufferSetting_Lex, treat_as_code); - } - - // no meaning for return - return(0); -} - -OPEN_FILE_HOOK_SIG(my_file_save){ - uint32_t access = AccessAll; - Buffer_Summary buffer = get_buffer(app, buffer_id, access); - assert(buffer.exists); - - int32_t is_virtual = 0; - if (automatically_indent_text_on_save && buffer_get_setting(app, &buffer, BufferSetting_VirtualWhitespace, &is_virtual)){ - if (is_virtual){ - auto_tab_whole_file_by_summary(app, &buffer); - } - } - - // no meaning for return - return(0); -} - -// NOTE(allen|a4.0.9): The input filter allows you to modify the input -// to a frame before 4coder starts processing it at all. -// -// Right now it only has access to the mouse state, but it will be -// extended to have access to the key presses soon. -static bool32 suppressing_mouse = false; - -INPUT_FILTER_SIG(my_suppress_mouse_filter){ - if (suppressing_mouse){ - *mouse = null_mouse_state; - mouse->x = -100; - mouse->y = -100; - } -} - -static void -set_mouse_suppression(Application_Links *app, int32_t suppress){ - if (suppress){ - suppressing_mouse = 1; - show_mouse_cursor(app, MouseCursorShow_Never); - } - else{ - suppressing_mouse = 0; - show_mouse_cursor(app, MouseCursorShow_Always); - } -} - -CUSTOM_COMMAND_SIG(suppress_mouse){ - set_mouse_suppression(app, true); -} - -CUSTOM_COMMAND_SIG(allow_mouse){ - set_mouse_suppression(app, false); -} - -CUSTOM_COMMAND_SIG(toggle_mouse){ - set_mouse_suppression(app, !suppressing_mouse); -} - -CUSTOM_COMMAND_SIG(execute_arbitrary_command){ - // NOTE(allen): This isn't a super powerful version of this command, I will expand - // upon it so that it has all the cmdid_* commands by default. However, with this - // 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]; - bar.prompt = make_lit_string("Command: "); - bar.string = make_fixed_width_string(space); - - if (!query_user_string(app, &bar)) return; - - // NOTE(allen): Here I chose to end this query bar because when I call another - // command it might ALSO have query bars and I don't want this one hanging - // around at that point. Since the bar exists on my stack the result of the query - // is still available in bar.string though. - end_query_bar(app, &bar, 0); - - if (match_ss(bar.string, make_lit_string("load project"))){ - exec_command(app, load_project); - } - else if (match_ss(bar.string, make_lit_string("open all code"))){ - exec_command(app, open_all_code); - } - else if(match_ss(bar.string, make_lit_string("close all code"))){ - exec_command(app, close_all_code); - } - else if (match_ss(bar.string, make_lit_string("open menu"))){ - exec_command(app, cmdid_open_menu); - } - else if (match_ss(bar.string, make_lit_string("dos lines"))){ - exec_command(app, eol_dosify); - } - else if (match_ss(bar.string, make_lit_string("nix lines"))){ - exec_command(app, eol_nixify); - } - else{ - print_message(app, literal("unrecognized command\n")); - } -} - void default_keys(Bind_Helper *context){ begin_map(context, mapid_global); - bind(context, 'p', MDFR_CTRL, open_panel_vsplit); - bind(context, '_', MDFR_CTRL, open_panel_hsplit); - bind(context, 'P', MDFR_CTRL, close_panel); + //bind(context, 'p', MDFR_CTRL, open_panel_vsplit); + //bind(context, '_', MDFR_CTRL, open_panel_hsplit); + //bind(context, 'P', MDFR_CTRL, close_panel); bind(context, ',', MDFR_CTRL, change_active_panel); bind(context, 'n', MDFR_CTRL, interactive_new); @@ -318,8 +27,8 @@ default_keys(Bind_Helper *context){ bind(context, 'i', MDFR_CTRL, interactive_switch_buffer); bind(context, 'w', MDFR_CTRL, save_as); - bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker); - bind(context, 'd', MDFR_ALT, cmdid_open_debug); + bind(context, 'c', MDFR_ALT, open_color_tweaker); + bind(context, 'd', MDFR_ALT, open_debug); bind(context, '.', MDFR_ALT, change_to_build_panel); bind(context, ',', MDFR_ALT, close_build_panel); @@ -336,7 +45,7 @@ default_keys(Bind_Helper *context){ bind(context, 's', MDFR_ALT, show_scrollbar); bind(context, 'w', MDFR_ALT, hide_scrollbar); - // TODO(allen): This is apparently not working on Linux. Need to try it on windows still. + // TODO(allen): This is apparently not working on Linux, must investigate. bind(context, key_f2, MDFR_CTRL, toggle_mouse); bind(context, key_page_up, MDFR_CTRL, toggle_fullscreen); bind(context, 'E', MDFR_ALT, exit_4coder); @@ -363,9 +72,9 @@ default_keys(Bind_Helper *context){ end_map(context); - begin_map(context, my_code_map); + begin_map(context, default_code_map); - // NOTE(allen|a3.1): Set this map (my_code_map == mapid_user_custom) to + // NOTE(allen|a3.1): Set this map (default_code_map == mapid_user_custom) to // inherit from mapid_file. When searching if a key is bound // in this map, if it is not found here it will then search mapid_file. // @@ -391,15 +100,16 @@ default_keys(Bind_Helper *context){ bind(context, '\t', MDFR_CTRL, auto_tab_range); bind(context, '\t', MDFR_SHIFT, auto_tab_line_at_cursor); - bind(context, 't', MDFR_ALT, write_allen_todo); - bind(context, 'y', MDFR_ALT, write_allen_note); - bind(context, 'r', MDFR_ALT, write_allen_doc); + bind(context, 't', MDFR_ALT, write_todo); + bind(context, 'y', MDFR_ALT, write_note); + bind(context, 'r', MDFR_ALT, write_block); bind(context, '[', MDFR_CTRL, open_long_braces); bind(context, '{', MDFR_CTRL, open_long_braces_semicolon); bind(context, '}', MDFR_CTRL, open_long_braces_break); bind(context, 'i', MDFR_ALT, if0_off); bind(context, '1', MDFR_ALT, open_file_in_quotes); bind(context, '0', MDFR_CTRL, write_zero_struct); + bind(context, 'I', MDFR_CTRL, list_all_functions_current_buffer); end_map(context); @@ -460,25 +170,21 @@ default_keys(Bind_Helper *context){ bind(context, 'F', MDFR_ALT, list_all_substring_locations_case_insensitive); bind(context, 'g', MDFR_CTRL, goto_line); bind(context, 'j', MDFR_CTRL, to_lowercase); - bind(context, 'K', MDFR_CTRL, cmdid_kill_buffer); + bind(context, 'K', MDFR_CTRL, kill_buffer); bind(context, 'l', MDFR_CTRL, toggle_line_wrap); bind(context, 'm', MDFR_CTRL, cursor_mark_swap); - bind(context, 'O', MDFR_CTRL, cmdid_reopen); + bind(context, 'O', MDFR_CTRL, reopen); bind(context, 'q', MDFR_CTRL, query_replace); bind(context, 'r', MDFR_CTRL, reverse_search); - bind(context, 's', MDFR_CTRL, cmdid_save); + bind(context, 's', MDFR_CTRL, save); bind(context, 'T', MDFR_CTRL, list_all_locations_of_identifier); bind(context, 'u', MDFR_CTRL, to_uppercase); - bind(context, 'U', MDFR_CTRL, rewrite_as_single_caps); bind(context, 'v', MDFR_CTRL, paste_and_indent); bind(context, 'v', MDFR_ALT, toggle_virtual_whitespace); bind(context, 'V', MDFR_CTRL, paste_next_and_indent); bind(context, 'x', MDFR_CTRL, cut); - bind(context, 'y', MDFR_CTRL, cmdid_redo); - bind(context, 'z', MDFR_CTRL, cmdid_undo); - - bind(context, '1', MDFR_CTRL, eol_dosify); - bind(context, '!', MDFR_CTRL, eol_nixify); + bind(context, 'y', MDFR_CTRL, redo); + bind(context, 'z', MDFR_CTRL, undo); bind(context, '2', MDFR_CTRL, decrease_line_wrap); bind(context, '3', MDFR_CTRL, increase_line_wrap); @@ -492,8 +198,6 @@ default_keys(Bind_Helper *context){ end_map(context); } - - #ifndef NO_BINDING extern "C" int32_t @@ -501,18 +205,7 @@ get_bindings(void *data, int32_t size){ Bind_Helper context_ = begin_bind_helper(data, size); Bind_Helper *context = &context_; - // NOTE(allen|a3.1): Hooks have no loyalties to maps. All hooks are global - // and once set they always apply, regardless of what map is active. - set_hook(context, hook_start, my_start); - set_hook(context, hook_exit, my_exit); - set_hook(context, hook_view_size_change, my_view_adjust); - - set_open_file_hook(context, my_file_settings); - set_save_file_hook(context, my_file_save); - set_command_caller(context, default_command_caller); - set_input_filter(context, my_suppress_mouse_filter); - set_scroll_rule(context, smooth_scroll_rule); - + set_all_default_hooks(context); default_keys(context); int32_t result = end_bind_helper(context); @@ -524,3 +217,4 @@ get_bindings(void *data, int32_t size){ #endif //FCODER_DEFAULT_BINDINGS // BOTTOM + diff --git a/4coder_default_framework.h b/4coder_default_framework.h index 23e6528c..0ead6276 100644 --- a/4coder_default_framework.h +++ b/4coder_default_framework.h @@ -10,8 +10,20 @@ TYPE: 'internal-for-default-system' #if !defined(FCODER_DEFAULT_FRAMEWORK_H) #define FCODER_DEFAULT_FRAMEWORK_H +#include "4coder_base_commands.cpp" + #include "4coder_helper/4coder_helper.h" #include "4coder_lib/4coder_mem.h" +#include "4cpp/4cpp_lexer.h" + +// +// Command Maps +// + +enum Default_Maps{ + default_code_map, + default_maps_count +}; // // Global Memory @@ -34,12 +46,14 @@ unlock_jump_buffer(){ static void lock_jump_buffer(char *name, int32_t size){ - copy(&locked_buffer, make_string(name, size)); + if (size <= locked_buffer.memory_size){ + copy(&locked_buffer, make_string(name, size)); + } } static void lock_jump_buffer(Buffer_Summary buffer){ - copy(&locked_buffer, make_string(buffer.buffer_name, buffer.buffer_name_len)); + lock_jump_buffer(buffer.buffer_name, buffer.buffer_name_len); } static View_Summary @@ -125,6 +139,601 @@ struct View_Paste_Index{ View_Paste_Index view_paste_index_[16]; View_Paste_Index *view_paste_index = view_paste_index_ - 1; + +// +// System Buffer Names +// + +static char out_buffer_space[1024]; +static char command_space[1024]; +static char hot_directory_space[1024]; + + +// +// Mouse Suppression +// + +static bool32 suppressing_mouse = false; + +static void +set_mouse_suppression(Application_Links *app, int32_t suppress){ + if (suppress){ + suppressing_mouse = 1; + show_mouse_cursor(app, MouseCursorShow_Never); + } + else{ + suppressing_mouse = 0; + show_mouse_cursor(app, MouseCursorShow_Always); + } +} + +CUSTOM_COMMAND_SIG(suppress_mouse){ + set_mouse_suppression(app, true); +} + +CUSTOM_COMMAND_SIG(allow_mouse){ + set_mouse_suppression(app, false); +} + +CUSTOM_COMMAND_SIG(toggle_mouse){ + set_mouse_suppression(app, !suppressing_mouse); +} + + +// +// Projects +// + +static char *default_extensions[] = { + "cpp", + "hpp", + "c", + "h", + "cc" +}; + +struct Fkey_Command{ + char command[128]; + char out[128]; + bool32 use_build_panel; +}; + +struct Project{ + char dir_space[256]; + char *dir; + int32_t dir_len; + + char extension_space[256]; + char *extensions[94]; + int32_t extension_count; + + Fkey_Command fkey_commands[16]; + + bool32 close_all_code_when_this_project_closes; + bool32 close_all_files_when_project_opens; +}; + +static Project null_project = {}; +static Project current_project = {}; + +static void +set_project_extensions(Project *project, String src){ + int32_t mode = 0; + int32_t j = 0, k = 0; + for (int32_t i = 0; i < src.size; ++i){ + switch (mode){ + case 0: + { + if (src.str[i] == '.'){ + mode = 1; + project->extensions[k++] = &project->extension_space[j]; + } + }break; + + case 1: + { + if (src.str[i] == '.'){ + project->extension_space[j++] = 0; + project->extensions[k++] = &project->extension_space[j]; + } + else{ + project->extension_space[j++] = src.str[i]; + } + }break; + } + } + project->extension_space[j++] = 0; + project->extension_count = k; +} + +static char** +get_current_code_extensions(int32_t *extension_count_out){ + char **extension_list = default_extensions; + int32_t extension_count = ArrayCount(default_extensions); + if (current_project.dir != 0){ + extension_list = current_project.extensions; + extension_count = current_project.extension_count; + } + *extension_count_out = extension_count; + return(extension_list); +} + + +// +// Location Jumping State +// + +typedef struct ID_Based_Jump_Location{ + int32_t buffer_id; + int32_t line; + int32_t column; +} ID_Based_Jump_Location; + +static ID_Based_Jump_Location null_location = {0}; +static ID_Based_Jump_Location prev_location = {0}; + + +// +// Config File Parsing +// + +struct Config_Line{ + Cpp_Token id_token; + Cpp_Token subscript_token; + Cpp_Token eq_token; + Cpp_Token val_token; + int32_t val_array_start; + int32_t val_array_end; + int32_t val_array_count; + bool32 read_success; +}; + +struct Config_Item{ + Config_Line line; + Cpp_Token_Array array; + char *mem; + String id; + int32_t subscript_index; + bool32 has_subscript; +}; + +struct Config_Array_Reader{ + Cpp_Token_Array array; + char *mem; + int32_t i; + int32_t val_array_end; + bool32 good; +}; + +static Cpp_Token +read_config_token(Cpp_Token_Array array, int32_t *i_ptr){ + Cpp_Token token = {0}; + + int32_t i = *i_ptr; + + for (; i < array.count; ++i){ + Cpp_Token comment_token = array.tokens[i]; + if (comment_token.type != CPP_TOKEN_COMMENT){ + break; + } + } + + if (i < array.count){ + token = array.tokens[i]; + } + + *i_ptr = i; + + return(token); +} + +static Config_Line +read_config_line(Cpp_Token_Array array, int32_t *i_ptr){ + Config_Line config_line = {0}; + + int32_t i = *i_ptr; + + config_line.id_token = read_config_token(array, &i); + if (config_line.id_token.type == CPP_TOKEN_IDENTIFIER){ + ++i; + if (i < array.count){ + Cpp_Token token = read_config_token(array, &i); + + bool32 subscript_success = 1; + if (token.type == CPP_TOKEN_BRACKET_OPEN){ + subscript_success = 0; + ++i; + if (i < array.count){ + config_line.subscript_token = read_config_token(array, &i); + if (config_line.subscript_token.type == CPP_TOKEN_INTEGER_CONSTANT){ + ++i; + if (i < array.count){ + token = read_config_token(array, &i); + if (token.type == CPP_TOKEN_BRACKET_CLOSE){ + ++i; + if (i < array.count){ + token = read_config_token(array, &i); + subscript_success = 1; + } + } + } + } + } + } + + if (subscript_success){ + if (token.type == CPP_TOKEN_EQ){ + config_line.eq_token = read_config_token(array, &i); + ++i; + if (i < array.count){ + Cpp_Token val_token = read_config_token(array, &i); + + bool32 array_success = 1; + if (val_token.type == CPP_TOKEN_BRACE_OPEN){ + array_success = 0; + ++i; + if (i < array.count){ + config_line.val_array_start = i; + + bool32 expecting_array_item = 1; + for (; i < array.count; ++i){ + Cpp_Token array_token = read_config_token(array, &i); + if (array_token.size == 0){ + break; + } + if (array_token.type == CPP_TOKEN_BRACE_CLOSE){ + config_line.val_array_end = i; + array_success = 1; + break; + } + else{ + if (array_token.type == CPP_TOKEN_COMMA){ + if (!expecting_array_item){ + expecting_array_item = 1; + } + else{ + break; + } + } + else{ + if (expecting_array_item){ + expecting_array_item = 0; + ++config_line.val_array_count; + } + } + } + } + } + } + + if (array_success){ + config_line.val_token = val_token; + ++i; + if (i < array.count){ + Cpp_Token semicolon_token = read_config_token(array, &i); + if (semicolon_token.type == CPP_TOKEN_SEMICOLON){ + config_line.read_success = 1; + } + } + } + } + } + } + } + } + + if (!config_line.read_success){ + for (; i < array.count; ++i){ + Cpp_Token token = read_config_token(array, &i); + if (token.type == CPP_TOKEN_SEMICOLON){ + break; + } + } + } + + *i_ptr = i; + + return(config_line); +} + +static Config_Item +get_config_item(Config_Line line, char *mem, Cpp_Token_Array array){ + Config_Item item = {0}; + item.line = line; + item.array = array; + item.mem = mem; + if (line.id_token.size != 0){ + item.id = make_string(mem + line.id_token.start, line.id_token.size); + } + + if (line.subscript_token.size != 0){ + String subscript_str = make_string(mem + line.subscript_token.start,line.subscript_token.size); + item.subscript_index = str_to_int_s(subscript_str); + item.has_subscript = 1; + } + + return(item); +} + +static bool32 +config_var(Config_Item item, char *var_name, int32_t *subscript, uint32_t token_type, void *var_out){ + bool32 result = 0; + bool32 subscript_succes = 1; + if (item.line.val_token.type == token_type){ + if ((var_name == 0 && item.id.size == 0) || match(item.id, var_name)){ + if (subscript){ + if (item.has_subscript){ + *subscript = item.subscript_index; + } + else{ + subscript_succes = 0; + } + } + + if (subscript_succes){ + if (var_out){ + switch (token_type){ + case CPP_TOKEN_BOOLEAN_CONSTANT: + { + *(bool32*)var_out = (item.mem[item.line.val_token.start] == 't'); + }break; + + case CPP_TOKEN_INTEGER_CONSTANT: + { + String val = make_string(item.mem + item.line.val_token.start, item.line.val_token.size); + *(int32_t*)var_out = str_to_int(val); + }break; + + case CPP_TOKEN_STRING_CONSTANT: + { + *(String*)var_out = make_string(item.mem + item.line.val_token.start + 1,item.line.val_token.size - 2); + }break; + + case CPP_TOKEN_BRACE_OPEN: + { + Config_Array_Reader *array_reader = (Config_Array_Reader*)var_out; + array_reader->array = item.array; + array_reader->mem = item.mem; + array_reader->i = item.line.val_array_start; + array_reader->val_array_end = item.line.val_array_end; + array_reader->good = 1; + }break; + } + } + result = 1; + } + } + } + return(result); +} + +static bool32 +config_bool_var(Config_Item item, char *var_name, int32_t *subscript, bool32 *var_out){ + bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_BOOLEAN_CONSTANT, var_out); + return(result); +} + +static bool32 +config_int_var(Config_Item item, char *var_name, int32_t *subscript, int32_t *var_out){ + bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_INTEGER_CONSTANT, var_out); + return(result); +} + +static bool32 +config_string_var(Config_Item item, char *var_name, int32_t *subscript, String *var_out){ + bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_STRING_CONSTANT, var_out); + return(result); +} + +static bool32 +config_array_var(Config_Item item, char *var_name, int32_t *subscript, Config_Array_Reader *array_reader){ + bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_BRACE_OPEN, array_reader); + return(result); +} + +static bool32 +config_array_next_item(Config_Array_Reader *array_reader, Config_Item *item){ + bool32 result = 0; + + for (;array_reader->i < array_reader->val_array_end; + ++array_reader->i){ + Cpp_Token array_token = read_config_token(array_reader->array, &array_reader->i); + if (array_token.size == 0 || array_reader->i >= array_reader->val_array_end){ + break; + } + + if (array_token.type == CPP_TOKEN_BRACE_CLOSE){ + break; + } + + switch (array_token.type){ + case CPP_TOKEN_BOOLEAN_CONSTANT: + case CPP_TOKEN_INTEGER_CONSTANT: + case CPP_TOKEN_STRING_CONSTANT: + { + Config_Line line = {0}; + line.val_token = array_token; + line.read_success = 1; + *item = get_config_item(line, array_reader->mem, array_reader->array); + result = 1; + ++array_reader->i; + goto doublebreak; + }break; + } + } + doublebreak:; + + array_reader->good = result; + return(result); +} + +static bool32 +config_array_good(Config_Array_Reader *array_reader){ + bool32 result = (array_reader->good); + return(result); +} + + +// +// Configuration +// + +static bool32 enable_code_wrapping = 1; +static bool32 automatically_adjust_wrapping = 1; +static int32_t default_wrap_width = 672; +static int32_t default_min_base_width = 550; +static bool32 automatically_indent_text_on_save = 1; + +static String default_theme_name = make_lit_string("4coder"); +static String default_font_name = make_lit_string("Liberation Sans"); + +static String user_name = {0}; + +static bool32 +get_current_name(char **name_out, int32_t *len_out){ + bool32 result = false; + *name_out = 0; + if (user_name.str != 0){ + *name_out = user_name.str; + *len_out = user_name.size; + result = true; + } + return(result); +} + +// TODO(allen): Stop handling files this way! My own API should be able to do this!!?!?!?!!?!?!!!!? +#include + +static bool32 +file_handle_dump(Partition *part, FILE *file, char **mem_ptr, int32_t *size_ptr){ + bool32 success = 0; + + fseek(file, 0, SEEK_END); + int32_t size = ftell(file); + char *mem = (char*)push_block(part, size+1); + fseek(file, 0, SEEK_SET); + int32_t check_size = (int32_t)fread(mem, 1, size, file); + if (check_size == size){ + mem[size] = 0; + success = 1; + } + + *mem_ptr = mem; + *size_ptr = size; + + return(success); +} + +static void +process_config_file(Application_Links *app){ + Partition *part = &global_part; + FILE *file = fopen("config.4coder", "rb"); + + if (!file){ + char space[256]; + int32_t size = get_4ed_path(app, space, sizeof(space)); + String str = make_string_cap(space, size, sizeof(space)); + append_sc(&str, "/config.4coder"); + terminate_with_null(&str); + file = fopen(str.str, "rb"); + } + + if (file){ + Temp_Memory temp = begin_temp_memory(part); + + char *mem = 0; + int32_t size = 0; + bool32 file_read_success = file_handle_dump(part, file, &mem, &size); + + if (file_read_success){ + fclose(file); + + Cpp_Token_Array array; + array.count = 0; + array.max_count = (1 << 20)/sizeof(Cpp_Token); + array.tokens = push_array(&global_part, Cpp_Token, array.max_count); + + Cpp_Lex_Data S = cpp_lex_data_init(); + Cpp_Lex_Result result = cpp_lex_step(&S, mem, size+1, HAS_NULL_TERM, &array, NO_OUT_LIMIT); + + if (result == LexResult_Finished){ + int32_t new_wrap_width = default_wrap_width; + int32_t new_min_base_width = default_min_base_width; + + for (int32_t i = 0; i < array.count; ++i){ + Config_Line config_line = read_config_line(array, &i); + + if (config_line.read_success){ + Config_Item item = get_config_item(config_line, mem, array); + + config_bool_var(item, "enable_code_wrapping", 0, &enable_code_wrapping); + config_bool_var(item, "automatically_adjust_wrapping", 0, &automatically_adjust_wrapping); + config_bool_var(item, "automatically_indent_text_on_save", 0, &automatically_indent_text_on_save); + + config_int_var(item, "default_wrap_width", 0, &new_wrap_width); + config_int_var(item, "default_min_base_width", 0, &new_min_base_width); + + config_string_var(item, "default_theme_name", 0, &default_theme_name); + config_string_var(item, "default_font_name", 0, &default_font_name); + config_string_var(item, "user_name", 0, &user_name); + } + } + adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width); + default_wrap_width = new_wrap_width; + default_min_base_width = new_min_base_width; + } + } + + end_temp_memory(temp); + } + else{ + print_message(app, literal("Did not find config.4coder, using default settings\n")); + } +} + + +// +// Framework Init Functions +// + +void +init_memory(Application_Links *app){ + int32_t part_size = (32 << 20); + int32_t general_size = (4 << 20); + + void *part_mem = memory_allocate(app, part_size); + global_part = make_part(part_mem, part_size); + + void *general_mem = memory_allocate(app, general_size); + general_memory_open(&global_general, general_mem, general_size); +} + +static void +default_4coder_initialize(Application_Links *app){ + init_memory(app); + process_config_file(app); + change_theme(app, default_theme_name.str, default_theme_name.size); + change_font(app, default_font_name.str, default_font_name.size, 1); +} + +static void +default_4coder_side_by_side_panels(Application_Links *app){ + exec_command(app, open_panel_vsplit); + exec_command(app, hide_scrollbar); + exec_command(app, change_active_panel); + exec_command(app, hide_scrollbar); +} + +static void +default_4coder_one_panel(Application_Links *app){ + exec_command(app, hide_scrollbar); +} + +static void +default_4coder_full_width_bottom_side_by_side_panels(Application_Links){ + // TODO(allen): +} + #endif // BOTTOM diff --git a/4coder_default_hooks.cpp b/4coder_default_hooks.cpp new file mode 100644 index 00000000..7ae0efd4 --- /dev/null +++ b/4coder_default_hooks.cpp @@ -0,0 +1,255 @@ +/* +4coder_default_hooks.cpp - Sets up the hooks for the default framework. + +TYPE: 'internal-for-default-system' +*/ + +// TOP + +#if !defined(FCODER_DEFAULT_HOOKS_CPP) +#define FCODER_DEFAULT_HOOKS_CPP + +#include "4coder_default_framework.h" +#include "4coder_helper/4coder_bind_helper.h" + +HOOK_SIG(default_start){ + default_4coder_initialize(app); + default_4coder_side_by_side_panels(app); + + // no meaning for return + return(0); +} + +// NOTE(allen|a4.0.9): All command calls can now go through this hook +// If this hook is not implemented a default behavior of calling the +// command is used. It is important to note that paste_next does not +// work without this hook. +// NOTE(allen|a4.0.10): As of this version the word_complete command +// also relies on this particular command caller hook. +COMMAND_CALLER_HOOK(default_command_caller){ + View_Summary view = get_active_view(app, AccessAll); + + view_paste_index[view.view_id].next_rewrite = 0; + exec_command(app, cmd); + view_paste_index[view.view_id].rewrite = view_paste_index[view.view_id].next_rewrite; + + return(0); +} + +HOOK_SIG(default_exit){ + // if this returns zero it cancels the exit. + return(1); +} + +HOOK_SIG(default_view_adjust){ + int32_t count = 0; + int32_t new_wrap_width = 0; + for (View_Summary view = get_view_first(app, AccessAll); + view.exists; + get_view_next(app, &view, AccessAll)){ + new_wrap_width += view.view_region.x1 - view.view_region.x0; + ++count; + } + + new_wrap_width /= count; + new_wrap_width = (int32_t)(new_wrap_width * .9f); + + int32_t new_min_base_width = (int32_t)(new_wrap_width * .77f); + if (automatically_adjust_wrapping){ + adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width); + default_wrap_width = new_wrap_width; + default_min_base_width = new_min_base_width; + } + + // no meaning for return + return(0); +} + +// TODO(allen): Eliminate this hook if you can. +OPEN_FILE_HOOK_SIG(default_file_settings){ + // NOTE(allen|a4.0.8): The get_parameter_buffer was eliminated + // and instead the buffer is passed as an explicit parameter through + // the function call. That is where buffer_id comes from here. + uint32_t access = AccessAll; + Buffer_Summary buffer = get_buffer(app, buffer_id, access); + Assert(buffer.exists); + + int32_t treat_as_code = 0; + int32_t wrap_lines = 1; + + if (buffer.file_name && buffer.size < (16 << 20)){ + String ext = file_extension(make_string(buffer.file_name, buffer.file_name_len)); + + if (match_ss(ext, make_lit_string("cpp")) || + match_ss(ext, make_lit_string("h")) || + match_ss(ext, make_lit_string("c")) || + match_ss(ext, make_lit_string("hpp"))){ + treat_as_code = 1; + } + } + + if (treat_as_code){ + wrap_lines = 0; + } + if (buffer.file_name[0] == '*'){ + wrap_lines = 0; + } + + buffer_set_setting(app, &buffer, BufferSetting_WrapPosition, default_wrap_width); + buffer_set_setting(app, &buffer, BufferSetting_MinimumBaseWrapPosition, default_min_base_width); + buffer_set_setting(app, &buffer, BufferSetting_MapID, (treat_as_code)?((int32_t)default_code_map):((int32_t)mapid_file)); + + if (treat_as_code && enable_code_wrapping && buffer.size < (1 << 18)){ + // NOTE(allen|a4.0.12): There is a little bit of grossness going on here. + // If we set BufferSetting_Lex to true, it will launch a lexing job. + // If a lexing job is active when we set BufferSetting_VirtualWhitespace, the call can fail. + // Unfortunantely without tokens virtual whitespace doesn't really make sense. + // So for now I have it automatically turning on lexing when virtual whitespace is turned on. + // Cleaning some of that up is a goal for future versions. + buffer_set_setting(app, &buffer, BufferSetting_WrapLine, 1); + buffer_set_setting(app, &buffer, BufferSetting_VirtualWhitespace, 1); + } + else{ + buffer_set_setting(app, &buffer, BufferSetting_WrapLine, wrap_lines); + buffer_set_setting(app, &buffer, BufferSetting_Lex, treat_as_code); + } + + // no meaning for return + return(0); +} + +OPEN_FILE_HOOK_SIG(default_file_save){ + uint32_t access = AccessAll; + Buffer_Summary buffer = get_buffer(app, buffer_id, access); + Assert(buffer.exists); + +#if defined(FCODER_AUTO_INDENT_CPP) + int32_t is_virtual = 0; + if (automatically_indent_text_on_save && buffer_get_setting(app, &buffer, BufferSetting_VirtualWhitespace, &is_virtual)){ + if (is_virtual){ + auto_tab_whole_file_by_summary(app, &buffer); + } + } +#endif + + // no meaning for return + return(0); +} + +// NOTE(allen|a4.0.9): The input filter allows you to modify the input +// to a frame before 4coder starts processing it at all. +// +// Right now it only has access to the mouse state, but it will be +// extended to have access to the key presses soon. +INPUT_FILTER_SIG(default_suppress_mouse_filter){ + if (suppressing_mouse){ + *mouse = null_mouse_state; + mouse->x = -100; + mouse->y = -100; + } +} + +// NOTE(allen|a4): scroll rule information +// +// The parameters: +// target_x, target_y +// This is where the view would like to be for the purpose of +// following the cursor, doing mouse wheel work, etc. +// +// scroll_x, scroll_y +// These are pointers to where the scrolling actually is. If you bind +// the scroll rule it is you have to update these in some way to move +// the actual location of the scrolling. +// +// view_id +// This corresponds to which view is computing it's new scrolling position. +// This id DOES correspond to the views that View_Summary contains. +// This will always be between 1 and 16 (0 is a null id). +// See below for an example of having state that carries across scroll udpates. +// +// is_new_target +// If the target of the view is different from the last target in either x or y +// this is true, otherwise it is false. +// +// The return: +// Should be true if and only if scroll_x or scroll_y are changed. +// +// Don't try to use the app pointer in a scroll rule, you're asking for trouble. +// +// If you don't bind scroll_rule, nothing bad will happen, yo will get default +// 4coder scrolling behavior. +// + +struct Scroll_Velocity{ + float x, y; +}; + +Scroll_Velocity scroll_velocity_[16] = {0}; +Scroll_Velocity *scroll_velocity = scroll_velocity_ - 1; + +static int32_t +smooth_camera_step(float target, float *current, float *vel, float S, float T){ + int32_t result = 0; + float curr = *current; + float v = *vel; + if (curr != target){ + if (curr > target - .1f && curr < target + .1f){ + curr = target; + v = 1.f; + } + else{ + float L = curr + T*(target - curr); + + int32_t sign = (target > curr) - (target < curr); + float V = curr + sign*v; + + if (sign > 0) curr = (LV)?(L):(V); + + if (curr == V){ + v *= S; + } + } + + *current = curr; + *vel = v; + result = 1; + } + return(result); +} + +SCROLL_RULE_SIG(smooth_scroll_rule){ + Scroll_Velocity *velocity = scroll_velocity + view_id; + int32_t result = 0; + if (velocity->x == 0.f){ + velocity->x = 1.f; + velocity->y = 1.f; + } + + if (smooth_camera_step(target_y, scroll_y, &velocity->y, 80.f, 1.f/2.f)){ + result = 1; + } + if (smooth_camera_step(target_x, scroll_x, &velocity->x, 80.f, 1.f/2.f)){ + result = 1; + } + + return(result); +} + +static void +set_all_default_hooks(Bind_Helper *context){ + set_hook(context, hook_start, default_start); + set_hook(context, hook_exit, default_exit); + set_hook(context, hook_view_size_change, default_view_adjust); + + set_open_file_hook(context, default_file_settings); + set_save_file_hook(context, default_file_save); + set_command_caller(context, default_command_caller); + set_input_filter(context, default_suppress_mouse_filter); + set_scroll_rule(context, smooth_scroll_rule); +} + +#endif + +// BOTTOM + diff --git a/4coder_default_include.cpp b/4coder_default_include.cpp index 038017dc..2dc6ad68 100644 --- a/4coder_default_include.cpp +++ b/4coder_default_include.cpp @@ -1,16 +1,28 @@ +/* +4coder_default_include.cpp - Default set of commands and setup used in 4coder. -#ifndef FCODER_DEFAULT_INCLUDE -#define FCODER_DEFAULT_INCLUDE +TYPE: 'major-system-include' +*/ + +// TOP + +#if !defined(FCODER_DEFAULT_INCLUDE_CPP) +#define FCODER_DEFAULT_INCLUDE_CPP + +#include "4coder_function_list.cpp" #include "4coder_API/custom.h" - -#include "4coder_jump_parsing.cpp" - #include "4coder_default_framework.h" #include "4coder_base_commands.cpp" #include "4coder_auto_indent.cpp" #include "4coder_search.cpp" +#include "4coder_jump_parsing.cpp" +#include "4coder_clipboard.cpp" +#include "4coder_system_command.cpp" +#include "4coder_build_commands.cpp" +#include "4coder_project_commands.cpp" +#include "4coder_default_hooks.cpp" #include "4coder_helper/4coder_bind_helper.h" #include "4coder_helper/4coder_helper.h" @@ -45,157 +57,80 @@ basic_seek(Application_Links *app, int32_t seek_type, uint32_t flags){ view_set_cursor(app, &view, seek_pos(pos), true); } -#define seek_command(n, dir, flags) CUSTOM_COMMAND_SIG(seek_##n##_##dir){ basic_seek(app, dir, flags); } - #define right true #define left false -seek_command(whitespace, right, BoundaryWhitespace) -seek_command(whitespace, left, BoundaryWhitespace) -seek_command(token, right, BoundaryToken) -seek_command(token, left, BoundaryToken) -seek_command(white_or_token, right, BoundaryToken | BoundaryWhitespace) -seek_command(white_or_token, left, BoundaryToken | BoundaryWhitespace) -seek_command(alphanumeric, right, BoundaryAlphanumeric) -seek_command(alphanumeric, left, BoundaryAlphanumeric) -seek_command(alphanumeric_or_camel, right, BoundaryAlphanumeric | BoundaryCamelCase) -seek_command(alphanumeric_or_camel, left, BoundaryAlphanumeric | BoundaryCamelCase) +CUSTOM_COMMAND_SIG(seek_whitespace_right){ basic_seek(app, right, BoundaryWhitespace); } +CUSTOM_COMMAND_SIG(seek_whitespace_left){ basic_seek(app, left, BoundaryWhitespace); } +CUSTOM_COMMAND_SIG(seek_token_right){ basic_seek(app, right, BoundaryToken); } +CUSTOM_COMMAND_SIG(seek_token_left){ basic_seek(app, left, BoundaryToken); } +CUSTOM_COMMAND_SIG(seek_white_or_token_right){basic_seek(app, right, BoundaryToken | BoundaryWhitespace);} +CUSTOM_COMMAND_SIG(seek_white_or_token_left){basic_seek(app, left, BoundaryToken | BoundaryWhitespace);} +CUSTOM_COMMAND_SIG(seek_alphanumeric_right){ basic_seek(app, right, BoundaryAlphanumeric); } +CUSTOM_COMMAND_SIG(seek_alphanumeric_left){ basic_seek(app, left, BoundaryAlphanumeric); } +CUSTOM_COMMAND_SIG(seek_alphanumeric_or_camel_right){ basic_seek(app, right, BoundaryAlphanumeric | BoundaryCamelCase); } +CUSTOM_COMMAND_SIG(seek_alphanumeric_or_camel_left){ basic_seek(app, left, BoundaryAlphanumeric | BoundaryCamelCase); } #undef right #undef left // -// Clipboard +// Fast Deletes // -static bool32 -clipboard_copy(Application_Links *app, int32_t start, int32_t end, Buffer_Summary *buffer_out, - uint32_t access){ +CUSTOM_COMMAND_SIG(backspace_word){ + uint32_t access = AccessOpen; + View_Summary view = get_active_view(app, access); Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - bool32 result = 0; if (buffer.exists){ - if (0 <= start && start <= end && end <= buffer.size){ - int32_t size = (end - start); - char *str = (char*)app->memory; - - if (size <= app->memory_size){ - buffer_read_range(app, &buffer, start, end, str); - clipboard_post(app, 0, str, size); - if (buffer_out){*buffer_out = buffer;} - result = 1; - } - } + int32_t pos2 = 0, pos1 = 0; + + pos2 = view.cursor.pos; + exec_command(app, seek_alphanumeric_left); + refresh_view(app, &view); + pos1 = view.cursor.pos; + + buffer_replace_range(app, &buffer, pos1, pos2, 0, 0); } - - return(result); } -static int32_t -clipboard_cut(Application_Links *app, int32_t start, int32_t end, Buffer_Summary *buffer_out, uint32_t access){ - Buffer_Summary buffer = {0}; - int32_t result = false; +CUSTOM_COMMAND_SIG(delete_word){ + uint32_t access = AccessOpen; - if (clipboard_copy(app, start, end, &buffer, access)){ - buffer_replace_range(app, &buffer, start, end, 0, 0); - if (buffer_out){*buffer_out = buffer;} - } - - return(result); -} - -CUSTOM_COMMAND_SIG(copy){ - uint32_t access = AccessProtected; View_Summary view = get_active_view(app, access); - Range range = get_range(&view); - clipboard_copy(app, range.min, range.max, 0, access); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + + if (buffer.exists){ + int32_t pos2 = 0, pos1 = 0; + + pos1 = view.cursor.pos; + exec_command(app, seek_alphanumeric_right); + refresh_view(app, &view); + pos2 = view.cursor.pos; + + buffer_replace_range(app, &buffer, pos1, pos2, 0, 0); + } } -CUSTOM_COMMAND_SIG(cut){ +CUSTOM_COMMAND_SIG(snipe_token_or_word){ uint32_t access = AccessOpen; + View_Summary view = get_active_view(app, access); - Range range = get_range(&view); - clipboard_cut(app, range.min, range.max, 0, access); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + + int32_t pos1 = buffer_boundary_seek(app, &buffer, view.cursor.pos, 0, BoundaryToken | BoundaryWhitespace); + int32_t pos2 = buffer_boundary_seek(app, &buffer, pos1, 1, BoundaryToken | BoundaryWhitespace); + + Range range = make_range(pos1, pos2); + buffer_replace_range(app, &buffer, range.start, range.end, 0, 0); } -CUSTOM_COMMAND_SIG(paste){ - uint32_t access = AccessOpen; - int32_t count = clipboard_count(app, 0); - if (count > 0){ - View_Summary view = get_active_view(app, access); - - view_paste_index[view.view_id].next_rewrite = RewritePaste; - - int32_t paste_index = 0; - view_paste_index[view.view_id].index = paste_index; - - int32_t len = clipboard_index(app, 0, paste_index, 0, 0); - char *str = 0; - - if (len <= app->memory_size){ - str = (char*)app->memory; - } - - if (str){ - clipboard_index(app, 0, paste_index, str, len); - - Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - int32_t pos = view.cursor.pos; - buffer_replace_range(app, &buffer, pos, pos, str, len); - view_set_mark(app, &view, seek_pos(pos)); - view_set_cursor(app, &view, seek_pos(pos + len), true); - - // TODO(allen): Send this to all views. - Theme_Color paste; - paste.tag = Stag_Paste; - get_theme_colors(app, &paste, 1); - view_post_fade(app, &view, 0.667f, pos, pos + len, paste.color); - } - } -} -CUSTOM_COMMAND_SIG(paste_next){ - uint32_t access = AccessOpen; - int32_t count = clipboard_count(app, 0); - if (count > 0){ - View_Summary view = get_active_view(app, access); - - if (view_paste_index[view.view_id].rewrite == RewritePaste){ - view_paste_index[view.view_id].next_rewrite = RewritePaste; - - int32_t paste_index = view_paste_index[view.view_id].index + 1; - view_paste_index[view.view_id].index = paste_index; - - int32_t len = clipboard_index(app, 0, paste_index, 0, 0); - char *str = 0; - - if (len <= app->memory_size){ - str = (char*)app->memory; - } - - if (str){ - clipboard_index(app, 0, paste_index, str, len); - - Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - Range range = get_range(&view); - int32_t pos = range.min; - - buffer_replace_range(app, &buffer, range.min, range.max, str, len); - view_set_cursor(app, &view, seek_pos(pos + len), true); - - // TODO(allen): Send this to all views. - Theme_Color paste; - paste.tag = Stag_Paste; - get_theme_colors(app, &paste, 1); - view_post_fade(app, &view, 0.667f, pos, pos + len, paste.color); - } - } - else{ - exec_command(app, paste); - } - } -} +// +// Clipboard + Indent Combo Command +// CUSTOM_COMMAND_SIG(paste_and_indent){ exec_command(app, paste); @@ -207,7 +142,10 @@ CUSTOM_COMMAND_SIG(paste_next_and_indent){ exec_command(app, auto_tab_range); } -////////////////////////// + +// +// Combined Write Commands +// static void write_string(Application_Links *app, View_Summary *view, Buffer_Summary *buffer, String string){ @@ -302,60 +240,49 @@ CUSTOM_COMMAND_SIG(if0_off){ } } - -// -// Fast Deletes -// - -CUSTOM_COMMAND_SIG(backspace_word){ - uint32_t access = AccessOpen; +CUSTOM_COMMAND_SIG(write_todo){ + char space[512]; + String str = make_fixed_width_string(space); - View_Summary view = get_active_view(app, access); - Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - - if (buffer.exists){ - int32_t pos2 = 0, pos1 = 0; - - pos2 = view.cursor.pos; - exec_command(app, seek_alphanumeric_left); - refresh_view(app, &view); - pos1 = view.cursor.pos; - - buffer_replace_range(app, &buffer, pos1, pos2, 0, 0); + char *name = 0; + int32_t name_len = 0; + if (get_current_name(&name, &name_len)){ + append(&str, "// TODO("); + append(&str, make_string(name, name_len)); + append(&str, "): "); } -} - -CUSTOM_COMMAND_SIG(delete_word){ - uint32_t access = AccessOpen; - - View_Summary view = get_active_view(app, access); - Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - - if (buffer.exists){ - int32_t pos2 = 0, pos1 = 0; - - pos1 = view.cursor.pos; - exec_command(app, seek_alphanumeric_right); - refresh_view(app, &view); - pos2 = view.cursor.pos; - - buffer_replace_range(app, &buffer, pos1, pos2, 0, 0); + else{ + append(&str, "// TODO: "); } + + write_string(app, str); } -CUSTOM_COMMAND_SIG(snipe_token_or_word){ - uint32_t access = AccessOpen; +CUSTOM_COMMAND_SIG(write_note){ + char space[512]; + String str = make_fixed_width_string(space); - View_Summary view = get_active_view(app, access); - Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + char *name = 0; + int32_t name_len = 0; + if (get_current_name(&name, &name_len)){ + append(&str, "// NOTE("); + append(&str, make_string(name, name_len)); + append(&str, "): "); + } + else{ + append(&str, "// NOTE: "); + } - int32_t pos1 = buffer_boundary_seek(app, &buffer, view.cursor.pos, 0, BoundaryToken | BoundaryWhitespace); - int32_t pos2 = buffer_boundary_seek(app, &buffer, pos1, 1, BoundaryToken | BoundaryWhitespace); - - Range range = make_range(pos1, pos2); - buffer_replace_range(app, &buffer, range.start, range.end, 0, 0); + write_string(app, str); } +CUSTOM_COMMAND_SIG(write_block){ + write_string(app, make_lit_string("/* */")); +} + +CUSTOM_COMMAND_SIG(write_zero_struct){ + write_string(app, make_lit_string(" = {0};")); +} // @@ -413,1289 +340,51 @@ CUSTOM_COMMAND_SIG(open_in_other){ // -// System Commands +// Execute Arbitrary Command // -static char out_buffer_space[1024]; -static char command_space[1024]; -static char hot_directory_space[1024]; - -CUSTOM_COMMAND_SIG(execute_any_cli){ - Query_Bar bar_out = {0}; - Query_Bar bar_cmd = {0}; +CUSTOM_COMMAND_SIG(execute_arbitrary_command){ + // NOTE(allen): This isn't a super powerful version of this command, I will expand + // upon it so that it has all the cmdid_* commands by default. However, with this + // 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]; + bar.prompt = make_lit_string("Command: "); + bar.string = make_fixed_width_string(space); - bar_out.prompt = make_lit_string("Output Buffer: "); - bar_out.string = make_fixed_width_string(out_buffer_space); - if (!query_user_string(app, &bar_out)) return; + if (!query_user_string(app, &bar)) return; - bar_cmd.prompt = make_lit_string("Command: "); - bar_cmd.string = make_fixed_width_string(command_space); - if (!query_user_string(app, &bar_cmd)) return; + // NOTE(allen): Here I chose to end this query bar because when I call another + // command it might ALSO have query bars and I don't want this one hanging + // around at that point. Since the bar exists on my stack the result of the query + // is still available in bar.string though. + end_query_bar(app, &bar, 0); - String hot_directory = make_fixed_width_string(hot_directory_space); - hot_directory.size = directory_get_hot(app, hot_directory.str, hot_directory.memory_size); - - uint32_t access = AccessAll; - View_Summary view = get_active_view(app, access); - - exec_system_command(app, &view, buffer_identifier(bar_out.string.str, bar_out.string.size), hot_directory.str, hot_directory.size, bar_cmd.string.str, bar_cmd.string.size, CLI_OverlapWithConflict | CLI_CursorAtEnd); -} - -CUSTOM_COMMAND_SIG(execute_previous_cli){ - String out_buffer = make_string_slowly(out_buffer_space); - String cmd = make_string_slowly(command_space); - String hot_directory = make_string_slowly(hot_directory_space); - - if (out_buffer.size > 0 && cmd.size > 0 && hot_directory.size > 0){ - uint32_t access = AccessAll; - View_Summary view = get_active_view(app, access); - - exec_system_command(app, &view, buffer_identifier(out_buffer.str, out_buffer.size), hot_directory.str, hot_directory.size, cmd.str, cmd.size, CLI_OverlapWithConflict | CLI_CursorAtEnd); + if (match_ss(bar.string, make_lit_string("load project"))){ + exec_command(app, load_project); } -} - - -// -// Default Building Stuff -// - -// NOTE(allen|a4.0.9): This is provided to establish a default method of getting -// a "build directory". This function tries to setup the build directory in the -// directory of the given buffer, if it cannot get that information it get's the -// 4coder hot directory. -// -// There is no requirement that a custom build system in 4coder actually use the -// directory given by this function. -enum Get_Build_Directory_Result{ - BuildDir_None, - BuildDir_AtFile, - BuildDir_AtHot -}; - -static int32_t -get_build_directory(Application_Links *app, Buffer_Summary *buffer, String *dir_out){ - int32_t result = BuildDir_None; - - if (buffer && buffer->file_name){ - if (!match_cc(buffer->file_name, buffer->buffer_name)){ - String dir = make_string_cap(buffer->file_name, - buffer->file_name_len, - buffer->file_name_len+1); - remove_last_folder(&dir); - append_ss(dir_out, dir); - result = BuildDir_AtFile; - } + else if (match_ss(bar.string, make_lit_string("open all code"))){ + exec_command(app, open_all_code); } - - if (!result){ - int32_t len = directory_get_hot(app, dir_out->str, - dir_out->memory_size - dir_out->size); - if (len + dir_out->size < dir_out->memory_size){ - dir_out->size += len; - result = BuildDir_AtHot; - } + else if(match_ss(bar.string, make_lit_string("close all code"))){ + exec_command(app, close_all_code); } - - return(result); -} - -// TODO(allen): Better names for the "standard build search" family. -static int32_t -standard_build_search(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer, String *dir, String *command, int32_t perform_backup, int32_t use_path_in_command, String filename, String commandname){ - int32_t result = false; - - for(;;){ - int32_t old_size = dir->size; - append_ss(dir, filename); - - if (file_exists(app, dir->str, dir->size)){ - dir->size = old_size; - - if (use_path_in_command){ - append_s_char(command, '"'); - append_ss(command, *dir); - append_ss(command, commandname); - append_s_char(command, '"'); - } - else{ - append_ss(command, commandname); - } - - char space[512]; - String message = make_fixed_width_string(space); - append_ss(&message, make_lit_string("Building with: ")); - append_ss(&message, *command); - append_s_char(&message, '\n'); - print_message(app, message.str, message.size); - - exec_system_command(app, view, buffer_identifier(literal("*compilation*")), dir->str, dir->size, command->str, command->size, CLI_OverlapWithConflict); - result = true; - break; - } - dir->size = old_size; - - if (directory_cd(app, dir->str, &dir->size, dir->memory_size, literal("..")) == 0){ - if (perform_backup){ - dir->size = directory_get_hot(app, dir->str, dir->memory_size); - char backup_space[256]; - String backup_command = make_fixed_width_string(backup_space); - append_ss(&backup_command, make_lit_string("echo could not find ")); - append_ss(&backup_command, filename); - exec_system_command(app, view, buffer_identifier(literal("*compilation*")), dir->str, dir->size, backup_command.str, backup_command.size, CLI_OverlapWithConflict); - } - break; - } + else if (match_ss(bar.string, make_lit_string("open menu"))){ + exec_command(app, cmdid_open_menu); } - - return(result); -} - -#if defined(_WIN32) - -// NOTE(allen): Build search rule for windows. -static int32_t -execute_standard_build_search(Application_Links *app, View_Summary *view, - Buffer_Summary *active_buffer, - String *dir, String *command, int32_t perform_backup){ - int32_t result = standard_build_search(app, view, active_buffer, dir, command, perform_backup, true, make_lit_string("build.bat"), make_lit_string("build")); - return(result); -} - -#elif defined(__linux__) - -// NOTE(allen): Build search rule for linux. -static int32_t -execute_standard_build_search(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer, String *dir, String *command, bool32 perform_backup){ - char dir_space[512]; - String dir_copy = make_fixed_width_string(dir_space); - copy(&dir_copy, *dir); - - int32_t result = standard_build_search(app, view, active_buffer, dir, command, 0, 1, make_lit_string("build.sh"), make_lit_string("build.sh")); - - if (!result){ - result = standard_build_search(app, view, active_buffer, &dir_copy, command, perform_backup, 0, make_lit_string("Makefile"), make_lit_string("make")); + else if (match_ss(bar.string, make_lit_string("dos lines"))){ + exec_command(app, eol_dosify); } - - return(result); -} - -#else -# error No build search rule for this platform. -#endif - - -// NOTE(allen): This searches first using the active file's directory, -// then if no build script is found, it searches from 4coders hot directory. -static void -execute_standard_build(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer){ - char dir_space[512]; - String dir = make_fixed_width_string(dir_space); - - char command_str_space[512]; - String command = make_fixed_width_string(command_str_space); - - int32_t build_dir_type = get_build_directory(app, active_buffer, &dir); - - if (build_dir_type == BuildDir_AtFile){ - if (!execute_standard_build_search(app, view, active_buffer, &dir, &command, false)){ - dir.size = 0; - command.size = 0; - build_dir_type = get_build_directory(app, 0, &dir); - } - } - - if (build_dir_type == BuildDir_AtHot){ - execute_standard_build_search(app, view, active_buffer, &dir, &command, true); - } -} - -CUSTOM_COMMAND_SIG(build_search){ - uint32_t access = AccessAll; - View_Summary view = get_active_view(app, access); - Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - execute_standard_build(app, &view, &buffer); - prev_location = null_location; - lock_jump_buffer(literal("*compilation*")); -} - -#define GET_COMP_BUFFER(app) get_buffer_by_name(app, literal("*compilation*"), AccessAll) - -static View_Summary -get_or_open_build_panel(Application_Links *app){ - View_Summary view = {0}; - - Buffer_Summary buffer = GET_COMP_BUFFER(app); - if (buffer.exists){ - view = get_first_view_with_buffer(app, buffer.buffer_id); - } - if (!view.exists){ - view = open_special_note_view(app); - } - - return(view); -} - -static void -set_fancy_compilation_buffer_font(Application_Links *app){ - Buffer_Summary comp_buffer = get_buffer_by_name(app, literal("*compilation*"), AccessAll); - buffer_set_font(app, &comp_buffer, literal("Inconsolata")); -} - -CUSTOM_COMMAND_SIG(build_in_build_panel){ - uint32_t access = AccessAll; - View_Summary view = get_active_view(app, access); - Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - - View_Summary build_view = get_or_open_build_panel(app); - - execute_standard_build(app, &build_view, &buffer); - set_fancy_compilation_buffer_font(app); - - prev_location = null_location; - lock_jump_buffer(literal("*compilation*")); -} - -CUSTOM_COMMAND_SIG(close_build_panel){ - close_special_note_view(app); -} - -CUSTOM_COMMAND_SIG(change_to_build_panel){ - View_Summary view = open_special_note_view(app, false); - - if (!view.exists){ - Buffer_Summary buffer = GET_COMP_BUFFER(app); - if (buffer.exists){ - view = open_special_note_view(app); - view_set_buffer(app, &view, buffer.buffer_id, 0); - } - } - - if (view.exists){ - set_active_view(app, &view); - } -} - -// NOTE(allen|a4): scroll rule information -// -// The parameters: -// target_x, target_y -// This is where the view would like to be for the purpose of -// following the cursor, doing mouse wheel work, etc. -// -// scroll_x, scroll_y -// These are pointers to where the scrolling actually is. If you bind -// the scroll rule it is you have to update these in some way to move -// the actual location of the scrolling. -// -// view_id -// This corresponds to which view is computing it's new scrolling position. -// This id DOES correspond to the views that View_Summary contains. -// This will always be between 1 and 16 (0 is a null id). -// See below for an example of having state that carries across scroll udpates. -// -// is_new_target -// If the target of the view is different from the last target in either x or y -// this is true, otherwise it is false. -// -// The return: -// Should be true if and only if scroll_x or scroll_y are changed. -// -// Don't try to use the app pointer in a scroll rule, you're asking for trouble. -// -// If you don't bind scroll_rule, nothing bad will happen, yo will get default -// 4coder scrolling behavior. -// - -struct Scroll_Velocity{ - float x, y; -}; - -Scroll_Velocity scroll_velocity_[16] = {0}; -Scroll_Velocity *scroll_velocity = scroll_velocity_ - 1; - -static int32_t -smooth_camera_step(float target, float *current, float *vel, float S, float T){ - int32_t result = 0; - float curr = *current; - float v = *vel; - if (curr != target){ - if (curr > target - .1f && curr < target + .1f){ - curr = target; - v = 1.f; - } - else{ - float L = curr + T*(target - curr); - - int32_t sign = (target > curr) - (target < curr); - float V = curr + sign*v; - - if (sign > 0) curr = (LV)?(L):(V); - - if (curr == V){ - v *= S; - } - } - - *current = curr; - *vel = v; - result = 1; - } - return(result); -} - -SCROLL_RULE_SIG(smooth_scroll_rule){ - Scroll_Velocity *velocity = scroll_velocity + view_id; - int32_t result = 0; - if (velocity->x == 0.f){ - velocity->x = 1.f; - velocity->y = 1.f; - } - - if (smooth_camera_step(target_y, scroll_y, &velocity->y, 80.f, 1.f/2.f)){ - result = 1; - } - if (smooth_camera_step(target_x, scroll_x, &velocity->x, 80.f, 1.f/2.f)){ - result = 1; - } - - return(result); -} - -// NOTE(allen|a4.0.9): All command calls can now go through this hook -// If this hook is not implemented a default behavior of calling the -// command is used. It is important to note that paste_next does not -// work without this hook. -// NOTE(allen|a4.0.10): As of this version the word_complete command -// also relies on this particular command caller hook. -COMMAND_CALLER_HOOK(default_command_caller){ - View_Summary view = get_active_view(app, AccessAll); - - view_paste_index[view.view_id].next_rewrite = 0; - exec_command(app, cmd); - view_paste_index[view.view_id].rewrite = view_paste_index[view.view_id].next_rewrite; - - return(0); -} - -struct Config_Line{ - Cpp_Token id_token; - Cpp_Token subscript_token; - Cpp_Token eq_token; - Cpp_Token val_token; - int32_t val_array_start; - int32_t val_array_end; - int32_t val_array_count; - bool32 read_success; -}; - -struct Config_Item{ - Config_Line line; - Cpp_Token_Array array; - char *mem; - String id; - int32_t subscript_index; - bool32 has_subscript; -}; - -struct Config_Array_Reader{ - Cpp_Token_Array array; - char *mem; - int32_t i; - int32_t val_array_end; - bool32 good; -}; - -static Cpp_Token -read_config_token(Cpp_Token_Array array, int32_t *i_ptr){ - Cpp_Token token = {0}; - - int32_t i = *i_ptr; - - for (; i < array.count; ++i){ - Cpp_Token comment_token = array.tokens[i]; - if (comment_token.type != CPP_TOKEN_COMMENT){ - break; - } - } - - if (i < array.count){ - token = array.tokens[i]; - } - - *i_ptr = i; - - return(token); -} - -static Config_Line -read_config_line(Cpp_Token_Array array, int32_t *i_ptr){ - Config_Line config_line = {0}; - - int32_t i = *i_ptr; - - config_line.id_token = read_config_token(array, &i); - if (config_line.id_token.type == CPP_TOKEN_IDENTIFIER){ - ++i; - if (i < array.count){ - Cpp_Token token = read_config_token(array, &i); - - bool32 subscript_success = 1; - if (token.type == CPP_TOKEN_BRACKET_OPEN){ - subscript_success = 0; - ++i; - if (i < array.count){ - config_line.subscript_token = read_config_token(array, &i); - if (config_line.subscript_token.type == CPP_TOKEN_INTEGER_CONSTANT){ - ++i; - if (i < array.count){ - token = read_config_token(array, &i); - if (token.type == CPP_TOKEN_BRACKET_CLOSE){ - ++i; - if (i < array.count){ - token = read_config_token(array, &i); - subscript_success = 1; - } - } - } - } - } - } - - if (subscript_success){ - if (token.type == CPP_TOKEN_EQ){ - config_line.eq_token = read_config_token(array, &i); - ++i; - if (i < array.count){ - Cpp_Token val_token = read_config_token(array, &i); - - bool32 array_success = 1; - if (val_token.type == CPP_TOKEN_BRACE_OPEN){ - array_success = 0; - ++i; - if (i < array.count){ - config_line.val_array_start = i; - - bool32 expecting_array_item = 1; - for (; i < array.count; ++i){ - Cpp_Token array_token = read_config_token(array, &i); - if (array_token.size == 0){ - break; - } - if (array_token.type == CPP_TOKEN_BRACE_CLOSE){ - config_line.val_array_end = i; - array_success = 1; - break; - } - else{ - if (array_token.type == CPP_TOKEN_COMMA){ - if (!expecting_array_item){ - expecting_array_item = 1; - } - else{ - break; - } - } - else{ - if (expecting_array_item){ - expecting_array_item = 0; - ++config_line.val_array_count; - } - } - } - } - } - } - - if (array_success){ - config_line.val_token = val_token; - ++i; - if (i < array.count){ - Cpp_Token semicolon_token = read_config_token(array, &i); - if (semicolon_token.type == CPP_TOKEN_SEMICOLON){ - config_line.read_success = 1; - } - } - } - } - } - } - } - } - - if (!config_line.read_success){ - for (; i < array.count; ++i){ - Cpp_Token token = read_config_token(array, &i); - if (token.type == CPP_TOKEN_SEMICOLON){ - break; - } - } - } - - *i_ptr = i; - - return(config_line); -} - -static Config_Item -get_config_item(Config_Line line, char *mem, Cpp_Token_Array array){ - Config_Item item = {0}; - item.line = line; - item.array = array; - item.mem = mem; - if (line.id_token.size != 0){ - item.id = make_string(mem + line.id_token.start, line.id_token.size); - } - - if (line.subscript_token.size != 0){ - String subscript_str = make_string(mem + line.subscript_token.start,line.subscript_token.size); - item.subscript_index = str_to_int_s(subscript_str); - item.has_subscript = 1; - } - - return(item); -} - -static bool32 -config_var(Config_Item item, char *var_name, int32_t *subscript, uint32_t token_type, void *var_out){ - bool32 result = 0; - bool32 subscript_succes = 1; - if (item.line.val_token.type == token_type){ - if ((var_name == 0 && item.id.size == 0) || match(item.id, var_name)){ - if (subscript){ - if (item.has_subscript){ - *subscript = item.subscript_index; - } - else{ - subscript_succes = 0; - } - } - - if (subscript_succes){ - if (var_out){ - switch (token_type){ - case CPP_TOKEN_BOOLEAN_CONSTANT: - { - *(bool32*)var_out = (item.mem[item.line.val_token.start] == 't'); - }break; - - case CPP_TOKEN_INTEGER_CONSTANT: - { - String val = make_string(item.mem + item.line.val_token.start, item.line.val_token.size); - *(int32_t*)var_out = str_to_int(val); - }break; - - case CPP_TOKEN_STRING_CONSTANT: - { - *(String*)var_out = make_string(item.mem + item.line.val_token.start + 1,item.line.val_token.size - 2); - }break; - - case CPP_TOKEN_BRACE_OPEN: - { - Config_Array_Reader *array_reader = (Config_Array_Reader*)var_out; - array_reader->array = item.array; - array_reader->mem = item.mem; - array_reader->i = item.line.val_array_start; - array_reader->val_array_end = item.line.val_array_end; - array_reader->good = 1; - }break; - } - } - result = 1; - } - } - } - return(result); -} - -static bool32 -config_bool_var(Config_Item item, char *var_name, int32_t *subscript, bool32 *var_out){ - bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_BOOLEAN_CONSTANT, var_out); - return(result); -} - -static bool32 -config_int_var(Config_Item item, char *var_name, int32_t *subscript, int32_t *var_out){ - bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_INTEGER_CONSTANT, var_out); - return(result); -} - -static bool32 -config_string_var(Config_Item item, char *var_name, int32_t *subscript, String *var_out){ - bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_STRING_CONSTANT, var_out); - return(result); -} - -static bool32 -config_array_var(Config_Item item, char *var_name, int32_t *subscript, Config_Array_Reader *array_reader){ - bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_BRACE_OPEN, array_reader); - return(result); -} - -static bool32 -config_array_next_item(Config_Array_Reader *array_reader, Config_Item *item){ - bool32 result = 0; - - for (;array_reader->i < array_reader->val_array_end; - ++array_reader->i){ - Cpp_Token array_token = read_config_token(array_reader->array, &array_reader->i); - if (array_token.size == 0 || array_reader->i >= array_reader->val_array_end){ - break; - } - - if (array_token.type == CPP_TOKEN_BRACE_CLOSE){ - break; - } - - switch (array_token.type){ - case CPP_TOKEN_BOOLEAN_CONSTANT: - case CPP_TOKEN_INTEGER_CONSTANT: - case CPP_TOKEN_STRING_CONSTANT: - { - Config_Line line = {0}; - line.val_token = array_token; - line.read_success = 1; - *item = get_config_item(line, array_reader->mem, array_reader->array); - result = 1; - ++array_reader->i; - goto doublebreak; - }break; - } - } - doublebreak:; - - array_reader->good = result; - return(result); -} - -static bool32 -config_array_good(Config_Array_Reader *array_reader){ - bool32 result = (array_reader->good); - return(result); -} - -// NOTE(allen|a4.0.12): A primordial config system (actually really hate this but it seems best at least right now... arg) - -static bool32 enable_code_wrapping = 1; -static bool32 automatically_adjust_wrapping = 1; -static int32_t default_wrap_width = 672; -static int32_t default_min_base_width = 550; -static bool32 automatically_indent_text_on_save = 1; - -static String default_theme_name = make_lit_string("4coder"); -static String default_font_name = make_lit_string("Liberation Sans"); - -#include - -static void -adjust_all_buffer_wrap_widths(Application_Links *app, int32_t wrap_widths, int32_t min_base_width){ - for (Buffer_Summary buffer = get_buffer_first(app, AccessAll); - buffer.exists; - get_buffer_next(app, &buffer, AccessAll)){ - buffer_set_setting(app, &buffer, BufferSetting_WrapPosition, wrap_widths); - buffer_set_setting(app, &buffer, BufferSetting_MinimumBaseWrapPosition, min_base_width); - } - default_wrap_width = wrap_widths; - default_min_base_width = min_base_width; -} - -static bool32 -file_handle_dump(Partition *part, FILE *file, char **mem_ptr, int32_t *size_ptr){ - bool32 success = 0; - - fseek(file, 0, SEEK_END); - int32_t size = ftell(file); - char *mem = (char*)push_block(part, size+1); - fseek(file, 0, SEEK_SET); - int32_t check_size = (int32_t)fread(mem, 1, size, file); - if (check_size == size){ - mem[size] = 0; - success = 1; - } - - *mem_ptr = mem; - *size_ptr = size; - - return(success); -} - -static void -process_config_file(Application_Links *app){ - Partition *part = &global_part; - FILE *file = fopen("config.4coder", "rb"); - - if (!file){ - char space[256]; - int32_t size = get_4ed_path(app, space, sizeof(space)); - String str = make_string_cap(space, size, sizeof(space)); - append_sc(&str, "/config.4coder"); - terminate_with_null(&str); - file = fopen(str.str, "rb"); - } - - if (file){ - Temp_Memory temp = begin_temp_memory(part); - - char *mem = 0; - int32_t size = 0; - bool32 file_read_success = file_handle_dump(part, file, &mem, &size); - - if (file_read_success){ - fclose(file); - - Cpp_Token_Array array; - array.count = 0; - array.max_count = (1 << 20)/sizeof(Cpp_Token); - array.tokens = push_array(&global_part, Cpp_Token, array.max_count); - - Cpp_Lex_Data S = cpp_lex_data_init(); - Cpp_Lex_Result result = cpp_lex_step(&S, mem, size+1, HAS_NULL_TERM, &array, NO_OUT_LIMIT); - - if (result == LexResult_Finished){ - int32_t new_wrap_width = default_wrap_width; - int32_t new_min_base_width = default_min_base_width; - - for (int32_t i = 0; i < array.count; ++i){ - Config_Line config_line = read_config_line(array, &i); - - if (config_line.read_success){ - Config_Item item = get_config_item(config_line, mem, array); - - config_bool_var(item, "enable_code_wrapping", 0, &enable_code_wrapping); - config_bool_var(item, "automatically_adjust_wrapping", 0, &automatically_adjust_wrapping); - config_bool_var(item, "automatically_indent_text_on_save", 0, &automatically_indent_text_on_save); - - config_int_var(item, "default_wrap_width", 0, &new_wrap_width); - config_int_var(item, "default_min_base_width", 0, &new_min_base_width); - - config_string_var(item, "default_theme_name", 0, &default_theme_name); - config_string_var(item, "default_font_name", 0, &default_font_name); - } - } - adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width); - } - } - - end_temp_memory(temp); + else if (match_ss(bar.string, make_lit_string("nix lines"))){ + exec_command(app, eol_nixify); } else{ - print_message(app, literal("Did not find config.4coder, using default settings\n")); + print_message(app, literal("unrecognized command\n")); } } -// NOTE(allen): Project system setup - -static char *default_extensions[] = { - "cpp", - "hpp", - "c", - "h", - "cc" -}; - -struct Fkey_Command{ - char command[128]; - char out[128]; - bool32 use_build_panel; -}; - -struct Project{ - char dir_space[256]; - char *dir; - int32_t dir_len; - - char extension_space[256]; - char *extensions[94]; - int32_t extension_count; - - Fkey_Command fkey_commands[16]; - - bool32 close_all_code_when_this_project_closes; - bool32 close_all_files_when_project_opens; -}; - -static Project null_project = {}; -static Project current_project = {}; - -static void -set_project_extensions(Project *project, String src){ - int32_t mode = 0; - int32_t j = 0, k = 0; - for (int32_t i = 0; i < src.size; ++i){ - switch (mode){ - case 0: - { - if (src.str[i] == '.'){ - mode = 1; - project->extensions[k++] = &project->extension_space[j]; - } - }break; - - case 1: - { - if (src.str[i] == '.'){ - project->extension_space[j++] = 0; - project->extensions[k++] = &project->extension_space[j]; - } - else{ - project->extension_space[j++] = src.str[i]; - } - }break; - } - } - project->extension_space[j++] = 0; - project->extension_count = k; -} - -// TODO(allen): make this a string operation or a lexer operation or something -static void -interpret_escaped_string(char *dst, String src){ - int32_t mode = 0; - int32_t j = 0; - for (int32_t i = 0; i < src.size; ++i){ - switch (mode){ - case 0: - { - if (src.str[i] == '\\'){ - mode = 1; - } - else{ - dst[j++] = src.str[i]; - } - }break; - - case 1: - { - switch (src.str[i]){ - case '\\':{dst[j++] = '\\'; mode = 0;}break; - case 'n': {dst[j++] = '\n'; mode = 0;}break; - case 't': {dst[j++] = '\t'; mode = 0;}break; - case '"': {dst[j++] = '"'; mode = 0;}break; - case '0': {dst[j++] = '\0'; mode = 0;}break; - } - }break; - } - } - dst[j] = 0; -} - -static void -close_all_files_with_extension(Application_Links *app, Partition *scratch_part, char **extension_list, int32_t extension_count){ - Temp_Memory temp = begin_temp_memory(scratch_part); - - int32_t buffers_to_close_max = partition_remaining(scratch_part)/sizeof(int32_t); - int32_t *buffers_to_close = push_array(scratch_part, int32_t, buffers_to_close_max); - - int32_t buffers_to_close_count = 0; - bool32 do_repeat = 0; - do{ - buffers_to_close_count = 0; - do_repeat = 0; - - uint32_t access = AccessAll; - Buffer_Summary buffer = {0}; - for (buffer = get_buffer_first(app, access); - buffer.exists; - get_buffer_next(app, &buffer, access)){ - - bool32 is_match = 1; - if (extension_count > 0){ - String extension = file_extension(make_string(buffer.file_name, buffer.file_name_len)); - is_match = 0; - for (int32_t i = 0; i < extension_count; ++i){ - if (match(extension, extension_list[i])){ - is_match = 1; - break; - } - } - } - - if (is_match){ - if (buffers_to_close_count >= buffers_to_close_max){ - do_repeat = 1; - break; - } - buffers_to_close[buffers_to_close_count++] = buffer.buffer_id; - } - } - - for (int32_t i = 0; i < buffers_to_close_count; ++i){ - kill_buffer(app, buffer_identifier(buffers_to_close[i]), true, 0); - } - } - while(do_repeat); - - end_temp_memory(temp); -} - -static void -open_all_files_with_extension(Application_Links *app, Partition *scratch_part, char **extension_list, int32_t extension_count){ - Temp_Memory temp = begin_temp_memory(scratch_part); - - int32_t max_size = partition_remaining(scratch_part); - char *memory = push_array(scratch_part, char, max_size); - - String dir = make_string_cap(memory, 0, max_size); - dir.size = directory_get_hot(app, dir.str, dir.memory_size); - int32_t dir_size = dir.size; - - // NOTE(allen|a3.4.4): Here we get the list of files in this directory. - // Notice that we free_file_list at the end. - File_List list = get_file_list(app, dir.str, dir.size); - - for (int32_t i = 0; i < list.count; ++i){ - File_Info *info = list.infos + i; - if (!info->folder){ - bool32 is_match = 1; - - if (extension_count > 0){ - is_match = 0; - - String extension = make_string_cap(info->filename, info->filename_len, info->filename_len+1); - extension = file_extension(extension); - for (int32_t j = 0; j < extension_count; ++j){ - if (match(extension, extension_list[j])){ - is_match = 1; - break; - } - } - - if (is_match){ - // 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_sc(&dir, info->filename); - create_buffer(app, dir.str, dir.size, 0); - } - } - } - } - - free_file_list(app, list); - - end_temp_memory(temp); -} - -static char** -get_standard_code_extensions(int32_t *extension_count_out){ - char **extension_list = default_extensions; - int32_t extension_count = ArrayCount(default_extensions); - if (current_project.dir != 0){ - extension_list = current_project.extensions; - extension_count = current_project.extension_count; - } - *extension_count_out = extension_count; - return(extension_list); -} - -// NOTE(allen|a4.0.14): open_all_code and close_all_code now use the extensions set in the loaded project. If there is no project loaded the extensions ".cpp.hpp.c.h.cc" are used. -CUSTOM_COMMAND_SIG(open_all_code){ - int32_t extension_count = 0; - char **extension_list = get_standard_code_extensions(&extension_count); - open_all_files_with_extension(app, &global_part, extension_list, extension_count); -} - -CUSTOM_COMMAND_SIG(close_all_code){ - int32_t extension_count = 0; - char **extension_list = get_standard_code_extensions(&extension_count); - close_all_files_with_extension(app, &global_part, extension_list, extension_count); -} - -CUSTOM_COMMAND_SIG(load_project){ - Partition *part = &global_part; - - char project_file_space[512]; - String project_name = make_fixed_width_string(project_file_space); - project_name.size = directory_get_hot(app, project_name.str, project_name.memory_size); - if (project_name.size >= project_name.memory_size){ - project_name.size = 0; - } - - if (project_name.size != 0){ - int32_t original_size = project_name.size; - append_sc(&project_name, "project.4coder"); - terminate_with_null(&project_name); - - // TODO(allen): make sure we do nothing when this project is already open - - FILE *file = fopen(project_name.str, "rb"); - if (file){ - project_name.size = original_size; - terminate_with_null(&project_name); - - Temp_Memory temp = begin_temp_memory(part); - - char *mem = 0; - int32_t size = 0; - bool32 file_read_success = file_handle_dump(part, file, &mem, &size); - if (file_read_success){ - fclose(file); - - Cpp_Token_Array array; - array.count = 0; - array.max_count = (1 << 20)/sizeof(Cpp_Token); - array.tokens = push_array(&global_part, Cpp_Token, array.max_count); - - Cpp_Lex_Data S = cpp_lex_data_init(); - Cpp_Lex_Result result = cpp_lex_step(&S, mem, size+1, HAS_NULL_TERM, &array, NO_OUT_LIMIT); - - if (result == LexResult_Finished){ - // Clear out current project - if (current_project.close_all_code_when_this_project_closes){ - exec_command(app, close_all_code); - } - current_project = null_project; - - // Set new project directory - { - current_project.dir = current_project.dir_space; - String str = make_fixed_width_string(current_project.dir_space); - copy(&str, project_name); - terminate_with_null(&str); - current_project.dir_len = str.size; - } - - // Read the settings from project.4coder - for (int32_t i = 0; i < array.count; ++i){ - Config_Line config_line = read_config_line(array, &i); - if (config_line.read_success){ - Config_Item item = get_config_item(config_line, mem, array); - - { - String str = {0}; - if (config_string_var(item, "extensions", 0, &str)){ - if (str.size < sizeof(current_project.extension_space)){ - set_project_extensions(¤t_project, str); - print_message(app, str.str, str.size); - print_message(app, "\n", 1); - } - else{ - print_message(app, literal("STRING TOO LONG!\n")); - } - } - } - - { -#if defined(_WIN32) -#define FKEY_COMMAND "fkey_command_win" -#elif defined(__linux__) -#define FKEY_COMMAND "fkey_command_linux" -#else -#error no project configuration names for this platform -#endif - - int32_t index = 0; - Config_Array_Reader array_reader = {0}; - if (config_array_var(item, FKEY_COMMAND, &index, &array_reader)){ - if (index >= 1 && index <= 16){ - Config_Item array_item = {0}; - int32_t item_index = 0; - - char space[256]; - String msg = make_fixed_width_string(space); - append(&msg, FKEY_COMMAND"["); - append_int_to_str(&msg, index); - append(&msg, "] = {"); - - for (config_array_next_item(&array_reader, &array_item); - config_array_good(&array_reader); - config_array_next_item(&array_reader, &array_item)){ - - if (item_index >= 3){ - break; - } - - append(&msg, "["); - append_int_to_str(&msg, item_index); - append(&msg, "] = "); - - bool32 read_string = 0; - bool32 read_bool = 0; - - char *dest_str = 0; - int32_t dest_str_size = 0; - - bool32 *dest_bool = 0; - - switch (item_index){ - case 0: - { - dest_str = current_project.fkey_commands[index-1].command; - dest_str_size = sizeof(current_project.fkey_commands[index-1].command); - read_string = 1; - }break; - - case 1: - { - dest_str = current_project.fkey_commands[index-1].out; - dest_str_size = sizeof(current_project.fkey_commands[index-1].out); - read_string = 1; - }break; - - case 2: - { - dest_bool = ¤t_project.fkey_commands[index-1].use_build_panel; - read_bool = 1; - }break; - } - - if (read_string){ - if (config_int_var(array_item, 0, 0, 0)){ - append(&msg, "NULL, "); - dest_str[0] = 0; - } - - String str = {0}; - if (config_string_var(array_item, 0, 0, &str)){ - if (str.size < dest_str_size){ - interpret_escaped_string(dest_str, str); - append(&msg, dest_str); - append(&msg, ", "); - } - else{ - append(&msg, "STRING TOO LONG!, "); - } - } - } - - if (read_bool){ - if (config_bool_var(array_item, 0, 0, dest_bool)){ - if (dest_bool){ - append(&msg, "true, "); - } - else{ - append(&msg, "false, "); - } - } - } - - item_index++; - } - - append(&msg, "}\n"); - print_message(app, msg.str, msg.size); - } - } - } - } - } - - if (current_project.close_all_files_when_project_opens){ - close_all_files_with_extension(app, &global_part, 0, 0); - } - - // Open all project files - exec_command(app, open_all_code); - } - } - - end_temp_memory(temp); - } - else{ - char message_space[512]; - String message = make_fixed_width_string(message_space); - append_sc(&message, "Did not find project.4coder. "); - if (current_project.dir != 0){ - append_sc(&message, "Continuing with: "); - append_sc(&message, current_project.dir); - } - else{ - append_sc(&message, "Continuing without a project"); - } - print_message(app, message.str, message.size); - } - } - else{ - print_message(app, literal("Failed trying to get project file name")); - } -} - -CUSTOM_COMMAND_SIG(project_fkey_command){ - User_Input input = get_command_input(app); - if (input.type == UserInputKey){ - if (input.key.keycode >= key_f1 && input.key.keycode <= key_f16){ - int32_t ind = (input.key.keycode - key_f1); - - char *command = current_project.fkey_commands[ind].command; - char *out = current_project.fkey_commands[ind].out; - bool32 use_build_panel = current_project.fkey_commands[ind].use_build_panel; - - if (command[0] != 0){ - int32_t command_len = str_size(command); - - View_Summary view_ = {0}; - View_Summary *view = 0; - Buffer_Identifier buffer_id = {0}; - uint32_t flags = 0; - - bool32 set_fancy_font = 0; - - if (out[0] != 0){ - int32_t out_len = str_size(out); - buffer_id = buffer_identifier(out, out_len); - - view = &view_; - - if (use_build_panel){ - view_ = get_or_open_build_panel(app); - if (match(out, "*compilation*")){ - set_fancy_font = 1; - } - } - else{ - view_ = get_active_view(app, AccessAll); - } - - prev_location = null_location; - lock_jump_buffer(out, out_len); - } - else{ - // TODO(allen): fix the exec_system_command call so it can take a null buffer_id. - buffer_id = buffer_identifier(literal("*dump*")); - } - - exec_system_command(app, view, buffer_id, current_project.dir, current_project.dir_len, command, command_len, flags); - if (set_fancy_font){ - set_fancy_compilation_buffer_font(app); - } - } - } - } -} - -// -// Default Framework -// - -void -init_memory(Application_Links *app){ - int32_t part_size = (32 << 20); - int32_t general_size = (4 << 20); - - void *part_mem = memory_allocate(app, part_size); - global_part = make_part(part_mem, part_size); - - void *general_mem = memory_allocate(app, general_size); - general_memory_open(&global_general, general_mem, general_size); -} - -static void -default_4coder_initialize(Application_Links *app){ - init_memory(app); - process_config_file(app); - change_theme(app, default_theme_name.str, default_theme_name.size); - change_font(app, default_font_name.str, default_font_name.size, 1); -} - -static void -default_4coder_side_by_side_panels(Application_Links *app){ - exec_command(app, open_panel_vsplit); - exec_command(app, hide_scrollbar); - exec_command(app, change_active_panel); - exec_command(app, hide_scrollbar); -} - #endif +// BOTTOM + diff --git a/power/4coder_function_list.cpp b/4coder_function_list.cpp similarity index 96% rename from power/4coder_function_list.cpp rename to 4coder_function_list.cpp index 0fc79e4f..618fcf59 100644 --- a/power/4coder_function_list.cpp +++ b/4coder_function_list.cpp @@ -1,6 +1,23 @@ +/* +4coder_function_list.cpp - Command for listing all functions in a C/C++ file in a jump list. + +TYPE: 'drop-in-command-pack' +*/ // TOP +#if !defined(FCODER_FUNCTION_LIST_CPP) +#define FCODER_FUNCTION_LIST_CPP + +#include "4coder_API/custom.h" + +#include "4coder_default_framework.h" + +#include "4coder_helper/4coder_helper.h" +#include "4coder_helper/4coder_streaming.h" + +#include "4coder_lib/4coder_mem.h" + // NOTE(allen|a4.0.14): This turned out to be a nasty little routine. There might // be a better way to do it with just tokens that I didn't see the first time // through. Once I build a real parser this should become almost just as easy as @@ -10,7 +27,6 @@ // will then provide the "list_all_functions_current_buffer" command. // - // // Declaration list // @@ -278,5 +294,7 @@ CUSTOM_COMMAND_SIG(list_all_functions_current_buffer){ list_all_functions(app, &global_part, &buffer); } +#endif + // BOTTOM diff --git a/4coder_helper/4coder_helper.h b/4coder_helper/4coder_helper.h index 28b26898..d25ae354 100644 --- a/4coder_helper/4coder_helper.h +++ b/4coder_helper/4coder_helper.h @@ -1,327 +1,337 @@ -/* - * Miscellaneous helpers for common operations. - */ - -#if !defined(FCODER_HELPER_H) -#define FCODER_HELPER_H - -#include "4coder_seek_types.h" - -inline void -exec_command(Application_Links *app, Custom_Command_Function *func){ - func(app); -} - -inline void -exec_command(Application_Links *app, Generic_Command cmd){ - if (cmd.cmdid < cmdid_count){ - exec_command(app, cmd.cmdid); - } - else{ - exec_command(app, cmd.command); - } -} - -inline View_Summary -get_first_view_with_buffer(Application_Links *app, int32_t buffer_id){ - View_Summary result = {}; - View_Summary test = {}; - - if (buffer_id != 0){ - uint32_t access = AccessAll; - for(test = get_view_first(app, access); - test.exists; - get_view_next(app, &test, access)){ - - Buffer_Summary buffer = get_buffer(app, test.buffer_id, access); - - if(buffer.buffer_id == buffer_id){ - result = test; - break; - } - } - } - - return(result); -} - -inline int32_t -key_is_unmodified(Key_Event_Data *key){ - char *mods = key->modifiers; - int32_t unmodified = !mods[MDFR_CONTROL_INDEX] && !mods[MDFR_ALT_INDEX]; - return(unmodified); -} - -static int32_t -query_user_general(Application_Links *app, Query_Bar *bar, bool32 force_number){ - User_Input in; - int32_t success = 1; - int32_t good_character = 0; - - // NOTE(allen|a3.4.4): It will not cause an *error* if we continue on after failing to. - // start a query bar, but it will be unusual behavior from the point of view of the - // user, if this command starts intercepting input even though no prompt is shown. - // This will only happen if you have a lot of bars open already or if the current view - // doesn't support query bars. - if (start_query_bar(app, bar, 0) == 0) return 0; - - for (;;){ - // NOTE(allen|a3.4.4): This call will block until the user does one of the input - // types specified in the flags. The first set of flags are inputs you'd like to intercept - // that you don't want to abort on. The second set are inputs that you'd like to cause - // the command to abort. If an event satisfies both flags, it is treated as an abort. - in = get_user_input(app, EventOnAnyKey, EventOnEsc | EventOnButton); - - // NOTE(allen|a3.4.4): The responsible thing to do on abort is to end the command - // without waiting on get_user_input again. - if (in.abort){ - success = 0; - break; - } - - good_character = 0; - if (key_is_unmodified(&in.key)){ - if (force_number){ - if (in.key.character >= '0' && in.key.character <= '9'){ - good_character = 1; - } - } - else{ - if (in.key.character != 0){ - good_character = 1; - } - } - } - - // NOTE(allen|a3.4.4): All we have to do to update the query bar is edit our - // local Query_Bar struct! This is handy because it means our Query_Bar - // is always correct for typical use without extra work updating the bar. - if (in.type == UserInputKey){ - if (in.key.keycode == '\n' || in.key.keycode == '\t'){ - break; - } - else if (in.key.keycode == key_back){ - if (bar->string.size > 0){ - --bar->string.size; - } - } - else if (good_character){ - append_s_char(&bar->string, in.key.character); - } - } - } - - terminate_with_null(&bar->string); - - return(success); -} - -inline int32_t -query_user_string(Application_Links *app, Query_Bar *bar){ - int32_t success = query_user_general(app, bar, false); - return(success); -} - -inline int32_t -query_user_number(Application_Links *app, Query_Bar *bar){ - int32_t success = query_user_general(app, bar, true); - return(success); -} - -inline char -buffer_get_char(Application_Links *app, Buffer_Summary *buffer, int32_t pos){ - char result = ' '; - *buffer = get_buffer(app, buffer->buffer_id, AccessAll); - if (pos >= 0 && pos < buffer->size){ - buffer_read_range(app, buffer, pos, pos+1, &result); - } - return(result); -} - -inline Buffer_Identifier -buffer_identifier(char *str, int32_t len){ - Buffer_Identifier identifier; - identifier.name = str; - identifier.name_len = len; - identifier.id = 0; - return(identifier); -} - -inline Buffer_Identifier -buffer_identifier(int32_t id){ - Buffer_Identifier identifier; - identifier.name = 0; - identifier.name_len = 0; - identifier.id = id; - return(identifier); -} - -static Buffer_Summary -create_buffer(Application_Links *app, char *filename, int32_t filename_len, Buffer_Create_Flag flags){ - Buffer_Summary buffer = {0}; - - Buffer_Creation_Data data = {0}; - begin_buffer_creation(app, &data, flags); - buffer_creation_name(app, &data, filename, filename_len, 0); - buffer = end_buffer_creation(app, &data); - - return(buffer); -} - -inline Range -make_range(int32_t p1, int32_t p2){ - Range range; - if (p1 < p2){ - range.min = p1; - range.max = p2; - } - else{ - range.min = p2; - range.max = p1; - } - return(range); -} - -struct Buffer_Rect{ - int32_t char0, line0; - int32_t char1, line1; -}; - -#ifndef Swap -#define Swap(T,a,b) do{ T t = a; a = b; b = t; } while(0) -#endif - -inline Buffer_Rect -get_rect(View_Summary *view){ - Buffer_Rect rect = {0}; - - rect.char0 = view->mark.character; - rect.line0 = view->mark.line; - - rect.char1 = view->cursor.character; - rect.line1 = view->cursor.line; - - if (rect.line0 > rect.line1){ - Swap(int32_t, rect.line0, rect.line1); - } - if (rect.char0 > rect.char1){ - Swap(int32_t, rect.char0, rect.char1); - } - - return(rect); -} - -inline i32_Rect -get_line_x_rect(View_Summary *view){ - i32_Rect rect = {0}; - - if (view->unwrapped_lines){ - rect.x0 = (int32_t)view->mark.unwrapped_x; - rect.x1 = (int32_t)view->cursor.unwrapped_x; - } - else{ - rect.x0 = (int32_t)view->mark.wrapped_x; - rect.x1 = (int32_t)view->cursor.wrapped_x; - } - rect.y0 = view->mark.line; - rect.y1 = view->cursor.line; - - if (rect.y0 > rect.y1){ - Swap(int32_t, rect.y0, rect.y1); - } - if (rect.x0 > rect.x1){ - Swap(int32_t, rect.x0, rect.x1); - } - - return(rect); -} - -static int32_t -open_file(Application_Links *app, Buffer_Summary *buffer_out, char *filename, int32_t filename_len, int32_t background, int32_t never_new){ - int32_t result = false; - Buffer_Summary buffer = get_buffer_by_name(app, filename, filename_len, AccessProtected|AccessHidden); - - if (buffer.exists){ - if (buffer_out) *buffer_out = buffer; - result = true; - } - else{ - Buffer_Create_Flag flags = 0; - if (background){ - flags |= BufferCreate_Background; - } - if (never_new){ - flags |= BufferCreate_NeverNew; - } - buffer = create_buffer(app, filename, filename_len, flags); - if (buffer.exists){ - if (buffer_out) *buffer_out = buffer; - result = true; - } - } - - return(result); -} - -static int32_t -view_open_file(Application_Links *app, View_Summary *view, char *filename, int32_t filename_len, int32_t never_new){ - int32_t result = 0; - - if (view){ - Buffer_Summary buffer = {0}; - if (open_file(app, &buffer, filename, filename_len, false, never_new)){ - view_set_buffer(app, view, buffer.buffer_id, 0); - result = 1; - } - } - - return(result); -} - -static void -get_view_next_looped(Application_Links *app, View_Summary *view, uint32_t access){ - get_view_next(app, view, access); - if (!view->exists){ - *view = get_view_first(app, access); - } -} - -static void -refresh_buffer(Application_Links *app, Buffer_Summary *buffer){ - *buffer = get_buffer(app, buffer->buffer_id, AccessAll); -} - -static void -refresh_view(Application_Links *app, View_Summary *view){ - *view = get_view(app, view->view_id, AccessAll); -} - -inline float -get_view_y(View_Summary *view){ - float y = view->cursor.wrapped_y; - if (view->unwrapped_lines){ - y = view->cursor.unwrapped_y; - } - return(y); -} - -inline float -get_view_x(View_Summary *view){ - float x = view->cursor.wrapped_x; - if (view->unwrapped_lines){ - x = view->cursor.unwrapped_x; - } - return(x); -} - -inline Range -get_range(View_Summary *view){ - Range range = make_range(view->cursor.pos, view->mark.pos); - return(range); -} - -#if !defined(ArrayCount) -# define ArrayCount(a) (sizeof(a)/sizeof(a[0])) -#endif - -#endif +/* + * Miscellaneous helpers for common operations. + */ + +#if !defined(FCODER_HELPER_H) +#define FCODER_HELPER_H + +#include "4coder_seek_types.h" + +inline void +exec_command(Application_Links *app, Custom_Command_Function *func){ + func(app); +} + +inline void +exec_command(Application_Links *app, Generic_Command cmd){ + if (cmd.cmdid < cmdid_count){ + exec_command(app, cmd.cmdid); + } + else{ + exec_command(app, cmd.command); + } +} + +inline View_Summary +get_first_view_with_buffer(Application_Links *app, int32_t buffer_id){ + View_Summary result = {}; + View_Summary test = {}; + + if (buffer_id != 0){ + uint32_t access = AccessAll; + for(test = get_view_first(app, access); + test.exists; + get_view_next(app, &test, access)){ + + Buffer_Summary buffer = get_buffer(app, test.buffer_id, access); + + if(buffer.buffer_id == buffer_id){ + result = test; + break; + } + } + } + + return(result); +} + +inline int32_t +key_is_unmodified(Key_Event_Data *key){ + char *mods = key->modifiers; + int32_t unmodified = !mods[MDFR_CONTROL_INDEX] && !mods[MDFR_ALT_INDEX]; + return(unmodified); +} + +static int32_t +query_user_general(Application_Links *app, Query_Bar *bar, bool32 force_number){ + User_Input in; + int32_t success = 1; + int32_t good_character = 0; + + // NOTE(allen|a3.4.4): It will not cause an *error* if we continue on after failing to. + // start a query bar, but it will be unusual behavior from the point of view of the + // user, if this command starts intercepting input even though no prompt is shown. + // This will only happen if you have a lot of bars open already or if the current view + // doesn't support query bars. + if (start_query_bar(app, bar, 0) == 0) return 0; + + for (;;){ + // NOTE(allen|a3.4.4): This call will block until the user does one of the input + // types specified in the flags. The first set of flags are inputs you'd like to intercept + // that you don't want to abort on. The second set are inputs that you'd like to cause + // the command to abort. If an event satisfies both flags, it is treated as an abort. + in = get_user_input(app, EventOnAnyKey, EventOnEsc | EventOnButton); + + // NOTE(allen|a3.4.4): The responsible thing to do on abort is to end the command + // without waiting on get_user_input again. + if (in.abort){ + success = 0; + break; + } + + good_character = 0; + if (key_is_unmodified(&in.key)){ + if (force_number){ + if (in.key.character >= '0' && in.key.character <= '9'){ + good_character = 1; + } + } + else{ + if (in.key.character != 0){ + good_character = 1; + } + } + } + + // NOTE(allen|a3.4.4): All we have to do to update the query bar is edit our + // local Query_Bar struct! This is handy because it means our Query_Bar + // is always correct for typical use without extra work updating the bar. + if (in.type == UserInputKey){ + if (in.key.keycode == '\n' || in.key.keycode == '\t'){ + break; + } + else if (in.key.keycode == key_back){ + if (bar->string.size > 0){ + --bar->string.size; + } + } + else if (good_character){ + append_s_char(&bar->string, in.key.character); + } + } + } + + terminate_with_null(&bar->string); + + return(success); +} + +inline int32_t +query_user_string(Application_Links *app, Query_Bar *bar){ + int32_t success = query_user_general(app, bar, false); + return(success); +} + +inline int32_t +query_user_number(Application_Links *app, Query_Bar *bar){ + int32_t success = query_user_general(app, bar, true); + return(success); +} + +inline char +buffer_get_char(Application_Links *app, Buffer_Summary *buffer, int32_t pos){ + char result = ' '; + *buffer = get_buffer(app, buffer->buffer_id, AccessAll); + if (pos >= 0 && pos < buffer->size){ + buffer_read_range(app, buffer, pos, pos+1, &result); + } + return(result); +} + +inline Buffer_Identifier +buffer_identifier(char *str, int32_t len){ + Buffer_Identifier identifier; + identifier.name = str; + identifier.name_len = len; + identifier.id = 0; + return(identifier); +} + +inline Buffer_Identifier +buffer_identifier(int32_t id){ + Buffer_Identifier identifier; + identifier.name = 0; + identifier.name_len = 0; + identifier.id = id; + return(identifier); +} + +static Buffer_Summary +create_buffer(Application_Links *app, char *filename, int32_t filename_len, Buffer_Create_Flag flags){ + Buffer_Summary buffer = {0}; + + Buffer_Creation_Data data = {0}; + begin_buffer_creation(app, &data, flags); + buffer_creation_name(app, &data, filename, filename_len, 0); + buffer = end_buffer_creation(app, &data); + + return(buffer); +} + +inline Range +make_range(int32_t p1, int32_t p2){ + Range range; + if (p1 < p2){ + range.min = p1; + range.max = p2; + } + else{ + range.min = p2; + range.max = p1; + } + return(range); +} + +static void +adjust_all_buffer_wrap_widths(Application_Links *app, int32_t wrap_width, int32_t min_base_width){ + for (Buffer_Summary buffer = get_buffer_first(app, AccessAll); + buffer.exists; + get_buffer_next(app, &buffer, AccessAll)){ + buffer_set_setting(app, &buffer, BufferSetting_WrapPosition, wrap_width); + buffer_set_setting(app, &buffer, BufferSetting_MinimumBaseWrapPosition, min_base_width); + } +} + +struct Buffer_Rect{ + int32_t char0, line0; + int32_t char1, line1; +}; + +#ifndef Swap +#define Swap(T,a,b) do{ T t = a; a = b; b = t; } while(0) +#endif + +inline Buffer_Rect +get_rect(View_Summary *view){ + Buffer_Rect rect = {0}; + + rect.char0 = view->mark.character; + rect.line0 = view->mark.line; + + rect.char1 = view->cursor.character; + rect.line1 = view->cursor.line; + + if (rect.line0 > rect.line1){ + Swap(int32_t, rect.line0, rect.line1); + } + if (rect.char0 > rect.char1){ + Swap(int32_t, rect.char0, rect.char1); + } + + return(rect); +} + +inline i32_Rect +get_line_x_rect(View_Summary *view){ + i32_Rect rect = {0}; + + if (view->unwrapped_lines){ + rect.x0 = (int32_t)view->mark.unwrapped_x; + rect.x1 = (int32_t)view->cursor.unwrapped_x; + } + else{ + rect.x0 = (int32_t)view->mark.wrapped_x; + rect.x1 = (int32_t)view->cursor.wrapped_x; + } + rect.y0 = view->mark.line; + rect.y1 = view->cursor.line; + + if (rect.y0 > rect.y1){ + Swap(int32_t, rect.y0, rect.y1); + } + if (rect.x0 > rect.x1){ + Swap(int32_t, rect.x0, rect.x1); + } + + return(rect); +} + +static int32_t +open_file(Application_Links *app, Buffer_Summary *buffer_out, char *filename, int32_t filename_len, int32_t background, int32_t never_new){ + int32_t result = false; + Buffer_Summary buffer = get_buffer_by_name(app, filename, filename_len, AccessProtected|AccessHidden); + + if (buffer.exists){ + if (buffer_out) *buffer_out = buffer; + result = true; + } + else{ + Buffer_Create_Flag flags = 0; + if (background){ + flags |= BufferCreate_Background; + } + if (never_new){ + flags |= BufferCreate_NeverNew; + } + buffer = create_buffer(app, filename, filename_len, flags); + if (buffer.exists){ + if (buffer_out) *buffer_out = buffer; + result = true; + } + } + + return(result); +} + +static int32_t +view_open_file(Application_Links *app, View_Summary *view, char *filename, int32_t filename_len, int32_t never_new){ + int32_t result = 0; + + if (view){ + Buffer_Summary buffer = {0}; + if (open_file(app, &buffer, filename, filename_len, false, never_new)){ + view_set_buffer(app, view, buffer.buffer_id, 0); + result = 1; + } + } + + return(result); +} + +static void +get_view_next_looped(Application_Links *app, View_Summary *view, uint32_t access){ + get_view_next(app, view, access); + if (!view->exists){ + *view = get_view_first(app, access); + } +} + +static void +refresh_buffer(Application_Links *app, Buffer_Summary *buffer){ + *buffer = get_buffer(app, buffer->buffer_id, AccessAll); +} + +static void +refresh_view(Application_Links *app, View_Summary *view){ + *view = get_view(app, view->view_id, AccessAll); +} + +inline float +get_view_y(View_Summary *view){ + float y = view->cursor.wrapped_y; + if (view->unwrapped_lines){ + y = view->cursor.unwrapped_y; + } + return(y); +} + +inline float +get_view_x(View_Summary *view){ + float x = view->cursor.wrapped_x; + if (view->unwrapped_lines){ + x = view->cursor.unwrapped_x; + } + return(x); +} + +inline Range +get_range(View_Summary *view){ + Range range = make_range(view->cursor.pos, view->mark.pos); + return(range); +} + +#if !defined(ArrayCount) +# define ArrayCount(a) (sizeof(a)/sizeof(a[0])) +#endif + +#endif diff --git a/4coder_helper/4coder_long_seek.h b/4coder_helper/4coder_long_seek.h index 83cc91f0..e625c903 100644 --- a/4coder_helper/4coder_long_seek.h +++ b/4coder_helper/4coder_long_seek.h @@ -884,7 +884,7 @@ read_line(Application_Links *app, Partition *part, Buffer_Summary *buffer, int32 int32_t success = 0; if (buffer_compute_cursor(app, buffer, seek_line_char(line, 1), &begin)){ - if (buffer_compute_cursor(app, buffer, seek_line_char(line, 65536), &end)){ + if (buffer_compute_cursor(app, buffer, seek_line_char(line, -1), &end)){ if (begin.line == line){ if (0 <= begin.pos && begin.pos <= end.pos && end.pos <= buffer->size){ int32_t size = (end.pos - begin.pos); @@ -919,7 +919,7 @@ buffer_get_line_end(Application_Links *app, Buffer_Summary *buffer, int32_t line Partial_Cursor partial_cursor; int32_t result = buffer->size; if (line <= buffer->line_count){ - buffer_compute_cursor(app, buffer, seek_line_char(line, 65536), &partial_cursor); + buffer_compute_cursor(app, buffer, seek_line_char(line, -1), &partial_cursor); result = partial_cursor.pos; } return(result); @@ -931,7 +931,7 @@ buffer_line_is_blank(Application_Links *app, Buffer_Summary *buffer, int32_t lin bool32 result = 0; if (line <= buffer->line_count){ buffer_compute_cursor(app, buffer, seek_line_char(line, 1), &start); - buffer_compute_cursor(app, buffer, seek_line_char(line, 65536), &end); + buffer_compute_cursor(app, buffer, seek_line_char(line, -1), &end); static const int32_t chunk_size = 1024; char chunk[chunk_size]; diff --git a/4coder_jump_parsing.cpp b/4coder_jump_parsing.cpp index 84f30ad2..a0bb4c44 100644 --- a/4coder_jump_parsing.cpp +++ b/4coder_jump_parsing.cpp @@ -22,13 +22,6 @@ typedef struct Name_Based_Jump_Location{ int32_t column; } Name_Based_Jump_Location; -typedef struct ID_Based_Jump_Location{ - int32_t buffer_id; - int32_t line; - int32_t column; -} ID_Based_Jump_Location; -static ID_Based_Jump_Location null_location = {0}; - static void jump_to_location(Application_Links *app, View_Summary *view, Name_Based_Jump_Location *l){ if (view_open_file(app, view, l->file.str, l->file.size, true)){ @@ -55,8 +48,9 @@ static int32_t parse_jump_location(String line, Name_Based_Jump_Location *location, int32_t skip_sub_errors, int32_t *colon_char){ int32_t result = false; + int32_t whitespace_length = 0; String original_line = line; - line = skip_chop_whitespace(line); + line = skip_chop_whitespace(line, &whitespace_length); int32_t colon_pos = 0; int32_t is_ms_style = 0; @@ -102,7 +96,7 @@ parse_jump_location(String line, Name_Based_Jump_Location *location, int32_t ski location->column = 1; } - *colon_char = colon_pos; + *colon_char = colon_pos + whitespace_length; result = true; } } @@ -137,7 +131,7 @@ parse_jump_location(String line, Name_Based_Jump_Location *location, int32_t ski location->file = filename; location->line = str_to_int_s(line_number); location->column = str_to_int_s(column_number); - *colon_char = colon_pos3; + *colon_char = colon_pos3 + whitespace_length; result = true; } } @@ -151,7 +145,7 @@ parse_jump_location(String line, Name_Based_Jump_Location *location, int32_t ski location->file = filename; location->line = str_to_int_s(line_number); location->column = 0; - *colon_char = colon_pos2; + *colon_char = colon_pos2 + whitespace_length; result = true; } } @@ -253,9 +247,7 @@ seek_next_jump_in_view(Application_Links *app, Partition *part, View_Summary *vi Name_Based_Jump_Location location = {0}; int32_t line = view->cursor.line; int32_t colon_index = 0; - if (seek_next_jump_in_buffer(app, part, view->buffer_id, - line+direction, skip_sub_errors, direction, - &line, &colon_index, &location)){ + if (seek_next_jump_in_buffer(app, part, view->buffer_id, line+direction, skip_sub_errors, direction, &line, &colon_index, &location)){ result = true; *line_out = line; *colon_index_out = colon_index; @@ -277,8 +269,6 @@ skip_this_jump(ID_Based_Jump_Location prev, ID_Based_Jump_Location jump){ return(result); } -static ID_Based_Jump_Location prev_location = {0}; - static int32_t advance_cursor_in_jump_view(Application_Links *app, Partition *part, View_Summary *view, int32_t skip_repeats, int32_t skip_sub_error, int32_t direction, Name_Based_Jump_Location *location_out){ int32_t result = true; @@ -289,10 +279,9 @@ advance_cursor_in_jump_view(Application_Links *app, Partition *part, View_Summar do{ Temp_Memory temp = begin_temp_memory(part); - if (seek_next_jump_in_view(app, part, view, - skip_sub_error, direction, - &line, &colon_index, &location)){ + if (seek_next_jump_in_view(app, part, view, skip_sub_error, direction, &line, &colon_index, &location)){ jump = convert_name_based_to_id_based(app, location); + view_set_cursor(app, view, seek_line_char(line, colon_index+1), true); result = true; } else{ @@ -313,16 +302,14 @@ advance_cursor_in_jump_view(Application_Links *app, Partition *part, View_Summar } static int32_t -seek_error(Application_Links *app, Partition *part, int32_t skip_repeats, int32_t skip_sub_errors, int32_t direction){ +seek_jump(Application_Links *app, Partition *part, int32_t skip_repeats, int32_t skip_sub_errors, int32_t direction){ int32_t result = 0; View_Summary view = get_view_for_locked_jump_buffer(app); if (view.exists){ Name_Based_Jump_Location location = {0}; - if (advance_cursor_in_jump_view(app, &global_part, &view, - skip_repeats, skip_sub_errors, direction, - &location)){ + if (advance_cursor_in_jump_view(app, &global_part, &view, skip_repeats, skip_sub_errors, direction, &location)){ View_Summary active_view = get_active_view(app, AccessAll); if (active_view.view_id == view.view_id){ exec_command(app, change_active_panel); @@ -342,28 +329,28 @@ CUSTOM_COMMAND_SIG(goto_next_jump){ int32_t skip_repeats = true; int32_t skip_sub_errors = true; int32_t dir = 1; - seek_error(app, &global_part, skip_repeats, skip_sub_errors, dir); + seek_jump(app, &global_part, skip_repeats, skip_sub_errors, dir); } CUSTOM_COMMAND_SIG(goto_prev_jump){ int32_t skip_repeats = true; int32_t skip_sub_errors = true; int32_t dir = -1; - seek_error(app, &global_part, skip_repeats, skip_sub_errors, dir); + seek_jump(app, &global_part, skip_repeats, skip_sub_errors, dir); } CUSTOM_COMMAND_SIG(goto_next_jump_no_skips){ int32_t skip_repeats = false; int32_t skip_sub_errors = true; int32_t dir = 1; - seek_error(app, &global_part, skip_repeats, skip_sub_errors, dir); + seek_jump(app, &global_part, skip_repeats, skip_sub_errors, dir); } CUSTOM_COMMAND_SIG(goto_prev_jump_no_skips){ int32_t skip_repeats = false; int32_t skip_sub_errors = true; int32_t dir = -1; - seek_error(app, &global_part, skip_repeats, skip_sub_errors, dir); + seek_jump(app, &global_part, skip_repeats, skip_sub_errors, dir); } CUSTOM_COMMAND_SIG(goto_first_jump){ @@ -374,11 +361,29 @@ CUSTOM_COMMAND_SIG(goto_first_jump){ view_set_cursor(app, &view, seek_pos(0), true); prev_location = null_location; - seek_error(app, &global_part, false, true, 1); + seek_jump(app, &global_part, false, true, 1); } end_temp_memory(temp); } +// +// Insert Newline - or Tigger Jump on Read Only Buffer +// + +CUSTOM_COMMAND_SIG(newline_or_goto_position){ + View_Summary view = get_active_view(app, AccessProtected); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessProtected); + + if (buffer.lock_flags & AccessProtected){ + exec_command(app, goto_jump_at_cursor); + lock_jump_buffer(buffer); + } + else{ + exec_command(app, write_character); + } +} + +#define seek_error seek_jump #define goto_next_error goto_next_jump #define goto_prev_error goto_prev_jump #define goto_next_error_no_skips goto_next_jump_no_skips diff --git a/4coder_lib/4coder_string.h b/4coder_lib/4coder_string.h index 958c81dd..84dfa847 100644 --- a/4coder_lib/4coder_string.h +++ b/4coder_lib/4coder_string.h @@ -1,5 +1,5 @@ /* -4coder_string.h - Version 1.0.14 +4coder_string.h - Version 1.0.59 no warranty implied; use at your own risk This software is in the public domain. Where that dedication is not @@ -94,8 +94,10 @@ FSTRING_INLINE String make_string_slowly(void *str); FSTRING_INLINE String substr_tail(String str, i32_4tech start); FSTRING_INLINE String substr(String str, i32_4tech start, i32_4tech size); FSTRING_LINK String skip_whitespace(String str); +FSTRING_LINK String skip_whitespace_measure(String str, i32_4tech *skip_length); FSTRING_LINK String chop_whitespace(String str); FSTRING_LINK String skip_chop_whitespace(String str); +FSTRING_LINK String skip_chop_whitespace_measure(String str, i32_4tech *skip_length); FSTRING_INLINE String tailstr(String str); FSTRING_LINK b32_4tech match_cc(char *a, char *b); FSTRING_LINK b32_4tech match_sc(String a, char *b); @@ -199,6 +201,8 @@ FSTRING_LINK String get_first_word(String source); FSTRING_INLINE String make_string(void *str, i32_4tech size, i32_4tech mem_size){return(make_string_cap(str,size,mem_size));} FSTRING_INLINE String substr(String str, i32_4tech start){return(substr_tail(str,start));} +FSTRING_LINK String skip_whitespace(String str, i32_4tech *skip_length){return(skip_whitespace_measure(str,skip_length));} +FSTRING_LINK String skip_chop_whitespace(String str, i32_4tech *skip_length){return(skip_chop_whitespace_measure(str,skip_length));} FSTRING_LINK b32_4tech match(char *a, char *b){return(match_cc(a,b));} FSTRING_LINK b32_4tech match(String a, char *b){return(match_sc(a,b));} FSTRING_INLINE b32_4tech match(char *a, String b){return(match_cs(a,b));} @@ -460,6 +464,20 @@ skip_whitespace(String str) } #endif + +#if defined(FSTRING_IMPLEMENTATION) +FSTRING_LINK String +skip_whitespace_measure(String str, i32_4tech *skip_length) +{ + String result = {0}; + i32_4tech i = 0; + for (; i < str.size && char_is_whitespace(str.str[i]); ++i); + result = substr(str, i, str.size - i); + *skip_length = i; + return(result); +} +#endif + #if defined(FSTRING_IMPLEMENTATION) FSTRING_LINK String chop_whitespace(String str) @@ -482,6 +500,17 @@ skip_chop_whitespace(String str) } #endif + +#if defined(FSTRING_IMPLEMENTATION) +FSTRING_LINK String +skip_chop_whitespace_measure(String str, i32_4tech *skip_length) +{ + str = skip_whitespace_measure(str, skip_length); + str = chop_whitespace(str); + return(str); +} +#endif + #if !defined(FSTRING_GUARD) FSTRING_INLINE String tailstr(String str) @@ -2031,7 +2060,7 @@ static void get_absolutes(String name, Absolutes *absolutes, b32_4tech implicit_first, b32_4tech implicit_last){ if (name.size != 0){ i32_4tech count = 0; - i32_4tech max = sizeof(absolutes->a)/sizeof(absolutes->a[0]) - 1; + i32_4tech max = (sizeof(absolutes->a)/sizeof(*absolutes->a)) - 1; if (implicit_last) --max; String str; diff --git a/4coder_project_commands.cpp b/4coder_project_commands.cpp new file mode 100644 index 00000000..4b17e100 --- /dev/null +++ b/4coder_project_commands.cpp @@ -0,0 +1,428 @@ +/* +4coder_project_commands.cpp - Commands for loading and using a project. + +TYPE: 'drop-in-command-pack' +*/ + +// TOP + +#if !defined(FCODER_PROJECT_COMMANDS_CPP) +#define FCODER_PROJECT_COMMANDS_CPP + +#include "4coder_default_framework.h" +#include "4coder_lib/4coder_mem.h" + +#include "4coder_build_commands.cpp" + +// TODO(allen): make this a string operation or a lexer operation or something +static void +interpret_escaped_string(char *dst, String src){ + int32_t mode = 0; + int32_t j = 0; + for (int32_t i = 0; i < src.size; ++i){ + switch (mode){ + case 0: + { + if (src.str[i] == '\\'){ + mode = 1; + } + else{ + dst[j++] = src.str[i]; + } + }break; + + case 1: + { + switch (src.str[i]){ + case '\\':{dst[j++] = '\\'; mode = 0;}break; + case 'n': {dst[j++] = '\n'; mode = 0;}break; + case 't': {dst[j++] = '\t'; mode = 0;}break; + case '"': {dst[j++] = '"'; mode = 0;}break; + case '0': {dst[j++] = '\0'; mode = 0;}break; + } + }break; + } + } + dst[j] = 0; +} + +static void +close_all_files_with_extension(Application_Links *app, Partition *scratch_part, char **extension_list, int32_t extension_count){ + Temp_Memory temp = begin_temp_memory(scratch_part); + + int32_t buffers_to_close_max = partition_remaining(scratch_part)/sizeof(int32_t); + int32_t *buffers_to_close = push_array(scratch_part, int32_t, buffers_to_close_max); + + int32_t buffers_to_close_count = 0; + bool32 do_repeat = 0; + do{ + buffers_to_close_count = 0; + do_repeat = 0; + + uint32_t access = AccessAll; + Buffer_Summary buffer = {0}; + for (buffer = get_buffer_first(app, access); + buffer.exists; + get_buffer_next(app, &buffer, access)){ + + bool32 is_match = 1; + if (extension_count > 0){ + String extension = file_extension(make_string(buffer.file_name, buffer.file_name_len)); + is_match = 0; + for (int32_t i = 0; i < extension_count; ++i){ + if (match(extension, extension_list[i])){ + is_match = 1; + break; + } + } + } + + if (is_match){ + if (buffers_to_close_count >= buffers_to_close_max){ + do_repeat = 1; + break; + } + buffers_to_close[buffers_to_close_count++] = buffer.buffer_id; + } + } + + for (int32_t i = 0; i < buffers_to_close_count; ++i){ + kill_buffer(app, buffer_identifier(buffers_to_close[i]), true, 0); + } + } + while(do_repeat); + + end_temp_memory(temp); +} + +static void +open_all_files_with_extension(Application_Links *app, Partition *scratch_part, char **extension_list, int32_t extension_count){ + Temp_Memory temp = begin_temp_memory(scratch_part); + + int32_t max_size = partition_remaining(scratch_part); + char *memory = push_array(scratch_part, char, max_size); + + String dir = make_string_cap(memory, 0, max_size); + dir.size = directory_get_hot(app, dir.str, dir.memory_size); + int32_t dir_size = dir.size; + + // NOTE(allen|a3.4.4): Here we get the list of files in this directory. + // Notice that we free_file_list at the end. + File_List list = get_file_list(app, dir.str, dir.size); + + for (int32_t i = 0; i < list.count; ++i){ + File_Info *info = list.infos + i; + if (!info->folder){ + bool32 is_match = 1; + + if (extension_count > 0){ + is_match = 0; + + String extension = make_string_cap(info->filename, info->filename_len, info->filename_len+1); + extension = file_extension(extension); + for (int32_t j = 0; j < extension_count; ++j){ + if (match(extension, extension_list[j])){ + is_match = 1; + break; + } + } + + if (is_match){ + // 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_sc(&dir, info->filename); + create_buffer(app, dir.str, dir.size, 0); + } + } + } + } + + free_file_list(app, list); + + end_temp_memory(temp); +} + +// NOTE(allen|a4.0.14): open_all_code and close_all_code now use the extensions set in the loaded project. If there is no project loaded the extensions ".cpp.hpp.c.h.cc" are used. +CUSTOM_COMMAND_SIG(open_all_code){ + int32_t extension_count = 0; + char **extension_list = get_current_code_extensions(&extension_count); + open_all_files_with_extension(app, &global_part, extension_list, extension_count); +} + +CUSTOM_COMMAND_SIG(close_all_code){ + int32_t extension_count = 0; + char **extension_list = get_current_code_extensions(&extension_count); + close_all_files_with_extension(app, &global_part, extension_list, extension_count); +} + +CUSTOM_COMMAND_SIG(load_project){ + Partition *part = &global_part; + + char project_file_space[512]; + String project_name = make_fixed_width_string(project_file_space); + project_name.size = directory_get_hot(app, project_name.str, project_name.memory_size); + if (project_name.size >= project_name.memory_size){ + project_name.size = 0; + } + + if (project_name.size != 0){ + int32_t original_size = project_name.size; + append_sc(&project_name, "project.4coder"); + terminate_with_null(&project_name); + + FILE *file = fopen(project_name.str, "rb"); + if (file){ + project_name.size = original_size; + terminate_with_null(&project_name); + + Temp_Memory temp = begin_temp_memory(part); + + char *mem = 0; + int32_t size = 0; + bool32 file_read_success = file_handle_dump(part, file, &mem, &size); + if (file_read_success){ + fclose(file); + + Cpp_Token_Array array; + array.count = 0; + array.max_count = (1 << 20)/sizeof(Cpp_Token); + array.tokens = push_array(&global_part, Cpp_Token, array.max_count); + + Cpp_Lex_Data S = cpp_lex_data_init(); + Cpp_Lex_Result result = cpp_lex_step(&S, mem, size+1, HAS_NULL_TERM, &array, NO_OUT_LIMIT); + + if (result == LexResult_Finished){ + // Clear out current project + if (current_project.close_all_code_when_this_project_closes){ + exec_command(app, close_all_code); + } + current_project = null_project; + + // Set new project directory + { + current_project.dir = current_project.dir_space; + String str = make_fixed_width_string(current_project.dir_space); + copy(&str, project_name); + terminate_with_null(&str); + current_project.dir_len = str.size; + } + + // Read the settings from project.4coder + for (int32_t i = 0; i < array.count; ++i){ + Config_Line config_line = read_config_line(array, &i); + if (config_line.read_success){ + Config_Item item = get_config_item(config_line, mem, array); + + { + String str = {0}; + if (config_string_var(item, "extensions", 0, &str)){ + if (str.size < sizeof(current_project.extension_space)){ + set_project_extensions(¤t_project, str); + print_message(app, str.str, str.size); + print_message(app, "\n", 1); + } + else{ + print_message(app, literal("STRING TOO LONG!\n")); + } + } + } + + { +#if defined(_WIN32) +#define FKEY_COMMAND "fkey_command_win" +#elif defined(__linux__) +#define FKEY_COMMAND "fkey_command_linux" +#else +#error no project configuration names for this platform +#endif + + int32_t index = 0; + Config_Array_Reader array_reader = {0}; + if (config_array_var(item, FKEY_COMMAND, &index, &array_reader)){ + if (index >= 1 && index <= 16){ + Config_Item array_item = {0}; + int32_t item_index = 0; + + char space[256]; + String msg = make_fixed_width_string(space); + append(&msg, FKEY_COMMAND"["); + append_int_to_str(&msg, index); + append(&msg, "] = {"); + + for (config_array_next_item(&array_reader, &array_item); + config_array_good(&array_reader); + config_array_next_item(&array_reader, &array_item)){ + + if (item_index >= 3){ + break; + } + + append(&msg, "["); + append_int_to_str(&msg, item_index); + append(&msg, "] = "); + + bool32 read_string = 0; + bool32 read_bool = 0; + + char *dest_str = 0; + int32_t dest_str_size = 0; + + bool32 *dest_bool = 0; + + switch (item_index){ + case 0: + { + dest_str = current_project.fkey_commands[index-1].command; + dest_str_size = sizeof(current_project.fkey_commands[index-1].command); + read_string = 1; + }break; + + case 1: + { + dest_str = current_project.fkey_commands[index-1].out; + dest_str_size = sizeof(current_project.fkey_commands[index-1].out); + read_string = 1; + }break; + + case 2: + { + dest_bool = ¤t_project.fkey_commands[index-1].use_build_panel; + read_bool = 1; + }break; + } + + if (read_string){ + if (config_int_var(array_item, 0, 0, 0)){ + append(&msg, "NULL, "); + dest_str[0] = 0; + } + + String str = {0}; + if (config_string_var(array_item, 0, 0, &str)){ + if (str.size < dest_str_size){ + interpret_escaped_string(dest_str, str); + append(&msg, dest_str); + append(&msg, ", "); + } + else{ + append(&msg, "STRING TOO LONG!, "); + } + } + } + + if (read_bool){ + if (config_bool_var(array_item, 0, 0, dest_bool)){ + if (dest_bool){ + append(&msg, "true, "); + } + else{ + append(&msg, "false, "); + } + } + } + + item_index++; + } + + append(&msg, "}\n"); + print_message(app, msg.str, msg.size); + } + } + } + } + } + + if (current_project.close_all_files_when_project_opens){ + close_all_files_with_extension(app, &global_part, 0, 0); + } + + // Open all project files + exec_command(app, open_all_code); + } + } + + end_temp_memory(temp); + } + else{ + char message_space[512]; + String message = make_fixed_width_string(message_space); + append_sc(&message, "Did not find project.4coder. "); + if (current_project.dir != 0){ + append_sc(&message, "Continuing with: "); + append_sc(&message, current_project.dir); + } + else{ + append_sc(&message, "Continuing without a project"); + } + print_message(app, message.str, message.size); + } + } + else{ + print_message(app, literal("Failed trying to get project file name")); + } +} + +static void +exec_project_fkey_command(Application_Links *app, int32_t command_ind){ + char *command = current_project.fkey_commands[command_ind].command; + char *out = current_project.fkey_commands[command_ind].out; + bool32 use_build_panel = current_project.fkey_commands[command_ind].use_build_panel; + + if (command[0] != 0){ + int32_t command_len = str_size(command); + + View_Summary view_ = {0}; + View_Summary *view = 0; + Buffer_Identifier buffer_id = {0}; + uint32_t flags = 0; + + bool32 set_fancy_font = 0; + + if (out[0] != 0){ + int32_t out_len = str_size(out); + buffer_id = buffer_identifier(out, out_len); + + view = &view_; + + if (use_build_panel){ + view_ = get_or_open_build_panel(app); + if (match(out, "*compilation*")){ + set_fancy_font = 1; + } + } + else{ + view_ = get_active_view(app, AccessAll); + } + + prev_location = null_location; + lock_jump_buffer(out, out_len); + } + else{ + // TODO(allen): fix the exec_system_command call so it can take a null buffer_id. + buffer_id = buffer_identifier(literal("*dump*")); + } + + exec_system_command(app, view, buffer_id, current_project.dir, current_project.dir_len, command, command_len, flags); + if (set_fancy_font){ + set_fancy_compilation_buffer_font(app); + } + } +} + +CUSTOM_COMMAND_SIG(project_fkey_command){ + User_Input input = get_command_input(app); + if (input.type == UserInputKey){ + if (input.key.keycode >= key_f1 && input.key.keycode <= key_f16){ + int32_t ind = (input.key.keycode - key_f1); + exec_project_fkey_command(app, ind); + } + } +} + +#endif + +// BOTTOM + diff --git a/4coder_system_command.cpp b/4coder_system_command.cpp new file mode 100644 index 00000000..3737a8f0 --- /dev/null +++ b/4coder_system_command.cpp @@ -0,0 +1,53 @@ +/* +4coder_system_command.cpp - Commands for executing arbitrary system command line instructions. + +TYPE: 'drop-in-command-pack' +*/ + +// TOP + +#if !defined(FCODER_SYSTEM_COMMAND_CPP) +#define FCODER_SYSTEM_COMMAND_CPP + +#include "4coder_default_framework.h" + +CUSTOM_COMMAND_SIG(execute_any_cli){ + Query_Bar bar_out = {0}; + Query_Bar bar_cmd = {0}; + + bar_out.prompt = make_lit_string("Output Buffer: "); + bar_out.string = make_fixed_width_string(out_buffer_space); + if (!query_user_string(app, &bar_out)) return; + + bar_cmd.prompt = make_lit_string("Command: "); + bar_cmd.string = make_fixed_width_string(command_space); + if (!query_user_string(app, &bar_cmd)) return; + + String hot_directory = make_fixed_width_string(hot_directory_space); + hot_directory.size = directory_get_hot(app, hot_directory.str, hot_directory.memory_size); + + uint32_t access = AccessAll; + View_Summary view = get_active_view(app, access); + + exec_system_command(app, &view, buffer_identifier(bar_out.string.str, bar_out.string.size), hot_directory.str, hot_directory.size, bar_cmd.string.str, bar_cmd.string.size, CLI_OverlapWithConflict | CLI_CursorAtEnd); + lock_jump_buffer(bar_out.string.str, bar_out.string.size); +} + +CUSTOM_COMMAND_SIG(execute_previous_cli){ + String out_buffer = make_string_slowly(out_buffer_space); + String cmd = make_string_slowly(command_space); + String hot_directory = make_string_slowly(hot_directory_space); + + if (out_buffer.size > 0 && cmd.size > 0 && hot_directory.size > 0){ + uint32_t access = AccessAll; + View_Summary view = get_active_view(app, access); + + exec_system_command(app, &view, buffer_identifier(out_buffer.str, out_buffer.size), hot_directory.str, hot_directory.size, cmd.str, cmd.size, CLI_OverlapWithConflict | CLI_CursorAtEnd); + lock_jump_buffer(out_buffer.str, out_buffer.size); + } +} + +#endif + +// BOTTOM + diff --git a/4ed.cpp b/4ed.cpp index cc42e158..1f2063da 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -62,22 +62,22 @@ typedef struct Consumption_Record{ } Consumption_Record; typedef struct Available_Input{ - Key_Summary *keys; + Key_Input_Data *keys; Mouse_State *mouse; Consumption_Record records[Input_Count]; } Available_Input; internal Available_Input -init_available_input(Key_Summary *keys, Mouse_State *mouse){ +init_available_input(Key_Input_Data *keys, Mouse_State *mouse){ Available_Input result = {0}; result.keys = keys; result.mouse = mouse; return(result); } -internal Key_Summary +internal Key_Input_Data direct_get_key_data(Available_Input *available){ - Key_Summary result = *available->keys; + Key_Input_Data result = *available->keys; return(result); } @@ -87,9 +87,9 @@ direct_get_mouse_state(Available_Input *available){ return(result); } -internal Key_Summary +internal Key_Input_Data get_key_data(Available_Input *available){ - Key_Summary result = {0}; + Key_Input_Data result = {0}; if (!available->records[Input_AnyKey].consumed){ result = *available->keys; @@ -1688,46 +1688,32 @@ App_Step_Sig(app_step){ if (prev_width != current_width || prev_height != current_height){ layout_refit(&models->layout, prev_width, prev_height); - } } // NOTE(allen): prepare input information - Key_Summary key_summary = {0}; - { - for (i32 i = 0; i < input->keys.press_count; ++i){ - key_summary.keys[key_summary.count++] = input->keys.press[i]; - } - for (i32 i = 0; i < input->keys.hold_count; ++i){ - key_summary.keys[key_summary.count++] = input->keys.hold[i]; - } - if (models->input_filter){ models->input_filter(&input->mouse); } Key_Event_Data mouse_event = {0}; - memcpy(mouse_event.modifiers, input->keys.modifiers, sizeof(input->keys.modifiers)); - if (input->mouse.press_l){ mouse_event.keycode = key_mouse_left; - key_summary.keys[key_summary.count++] = mouse_event; + input->keys.keys[input->keys.count++] = mouse_event; + } + else if (input->mouse.release_l){ + mouse_event.keycode = key_mouse_left_release; + input->keys.keys[input->keys.count++] = mouse_event; } if (input->mouse.press_r){ mouse_event.keycode = key_mouse_right; - key_summary.keys[key_summary.count++] = mouse_event; + input->keys.keys[input->keys.count++] = mouse_event; } - - if (input->mouse.release_l){ - mouse_event.keycode = key_mouse_left_release; - key_summary.keys[key_summary.count++] = mouse_event; - } - - if (input->mouse.release_r){ + else if (input->mouse.release_r){ mouse_event.keycode = key_mouse_right_release; - key_summary.keys[key_summary.count++] = mouse_event; + input->keys.keys[input->keys.count++] = mouse_event; } input->mouse.wheel = -input->mouse.wheel; @@ -1996,11 +1982,11 @@ App_Step_Sig(app_step){ } // NOTE(allen): pass events to debug - vars->available_input = init_available_input(&key_summary, &input->mouse); + vars->available_input = init_available_input(&input->keys, &input->mouse); { Debug_Data *debug = &models->debug; - Key_Summary key_data = get_key_data(&vars->available_input); + Key_Input_Data key_data = get_key_data(&vars->available_input); Debug_Input_Event *events = debug->input_events; @@ -2033,7 +2019,7 @@ App_Step_Sig(app_step){ get_flags |= abort_flags; if ((get_flags & EventOnAnyKey) || (get_flags & EventOnEsc)){ - Key_Summary key_data = get_key_data(&vars->available_input); + Key_Input_Data key_data = get_key_data(&vars->available_input); for (i32 key_i = 0; key_i < key_data.count; ++key_i){ Key_Event_Data key = get_single_key(&key_data, key_i); @@ -2259,7 +2245,7 @@ App_Step_Sig(app_step){ // NOTE(allen): command execution { - Key_Summary key_data = get_key_data(&vars->available_input); + Key_Input_Data key_data = get_key_data(&vars->available_input); b32 hit_something = 0; b32 hit_esc = 0; @@ -2379,6 +2365,11 @@ App_Step_Sig(app_step){ "If you're new to 4coder there are some tutorials at http://4coder.net/tutorials.html\n" "\n" "Newest features:\n" + "- find all functions in the current buffer and list them in a jump buffer\n" + "-option to set user name in config.4coder\n" + " The user name is used in and comment writing commands\n" + "\n" + "New in alpha 4.0.14:\n" "-Option to have wrap widths automatically adjust based on average view width\n" "-The 'config.4coder' file can now be placed with the 4ed executable file\n" "-New options in 'config.4coder' to specify the font and color theme\n" @@ -2389,7 +2380,7 @@ App_Step_Sig(app_step){ "New in alpha 4.0.12 and 4.0.13:\n" "-Text files wrap lines at whitespace when possible\n" "-New code wrapping feature is on by default\n" - "-Introduced a 'config.4coder' for setting several wrapping options:" + "-Introduced a 'config.4coder' for setting several wrapping options:\n" " enable_code_wrapping: set to false if you want the text like behavior\n" " default_wrap_width: the wrap width to set in new files\n" "- decrease the current buffer's wrap width\n" @@ -2635,8 +2626,7 @@ App_Step_Sig(app_step){ } } - do_render_file_view(system, view, scroll_vars, active_view, - panel->inner, active, target, &dead_input); + do_render_file_view(system, view, scroll_vars, active_view, panel->inner, active, target, &dead_input); draw_pop_clip(target); diff --git a/4ed.h b/4ed.h index 8776af83..dfc66d68 100644 --- a/4ed.h +++ b/4ed.h @@ -23,35 +23,24 @@ struct Application_Memory{ i32 user_memory_size; }; -#define KEY_INPUT_BUFFER_SIZE 4 -#define KEY_INPUT_BUFFER_DSIZE (KEY_INPUT_BUFFER_SIZE << 1) +#define KEY_INPUT_BUFFER_SIZE 8 +#define KEY_EXTRA_SIZE 2 struct Key_Input_Data{ - Key_Event_Data press[KEY_INPUT_BUFFER_SIZE]; - Key_Event_Data hold[KEY_INPUT_BUFFER_SIZE]; - i32 press_count; - i32 hold_count; - - // TODO(allen): determine if we still need this. - char modifiers[MDFR_INDEX_COUNT]; + Key_Event_Data keys[KEY_INPUT_BUFFER_SIZE + KEY_EXTRA_SIZE]; + i32 count; }; static Key_Input_Data null_key_input_data = {0}; -struct Key_Summary{ - i32 count; - Key_Event_Data keys[KEY_INPUT_BUFFER_DSIZE + 2]; -}; - inline Key_Event_Data -get_single_key(Key_Summary *summary, i32 index){ - Key_Event_Data key; - key = summary->keys[index]; - return key; +get_single_key(Key_Input_Data *data, i32 index){ + Key_Event_Data key = data->keys[index]; + return(key); } typedef struct Input_Summary{ Mouse_State mouse; - Key_Summary keys; + Key_Input_Data keys; f32 dt; } Input_Summary; diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index 26aec44a..acf1fec7 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -187,8 +187,7 @@ API_EXPORT bool32 Exec_System_Command(Application_Links *app, View_Summary *view, Buffer_Identifier buffer, char *path, int32_t path_len, char *command, int32_t command_len, Command_Line_Interface_Flag flags) /* DOC_PARAM(view, If the view parameter is non-null it specifies a view to display the command's output buffer, otherwise the command will still work but if there is a buffer capturing the output it will not automatically be displayed.) -DOC_PARAM(buffer, The buffer the command will output to is specified by the buffer parameter. -See Buffer_Identifier for information on how this type specifies a buffer. The command will cause a crash if no file is specified.) +DOC_PARAM(buffer, The buffer the command will output to is specified by the buffer parameter. See Buffer_Identifier for information on how this type specifies a buffer. The command will cause a crash if no file is specified.) DOC_PARAM(path, The path parameter specifies the path in which the command shall be executed. The string need not be null terminated.) DOC_PARAM(path_len, The parameter path_len specifies the length of the path string.) DOC_PARAM(command, The command parameter specifies the command that shall be executed. The string need not be null terminated.) @@ -1636,9 +1635,6 @@ DOC_SEE(Full_Cursor) if (vptr){ file = vptr->file_data.file; if (file && !file->is_loading){ - if (seek.type == buffer_seek_line_char && seek.character <= 0){ - seek.character = 1; - } result = true; *cursor_out = view_compute_cursor(vptr, seek, 0); fill_view_summary(view, vptr, cmd); @@ -1673,9 +1669,6 @@ DOC_SEE(Buffer_Seek) Assert(file); if (!file->is_loading){ result = true; - if (seek.type == buffer_seek_line_char && seek.character <= 0){ - seek.character = 1; - } Full_Cursor cursor = view_compute_cursor(vptr, seek, 0); view_set_cursor(vptr, cursor, set_preferred_x, file->settings.unwrapped_lines); fill_view_summary(view, vptr, cmd); @@ -1726,12 +1719,13 @@ DOC_SEE(Buffer_Seek) if (vptr){ file = vptr->file_data.file; if (file && !file->is_loading){ - result = true; if (seek.type != buffer_seek_pos){ + result = true; cursor = view_compute_cursor(vptr, seek, 0); vptr->edit_pos->mark = cursor.pos; } else{ + result = true; vptr->edit_pos->mark = seek.pos; } fill_view_summary(view, vptr, cmd); @@ -1905,17 +1899,17 @@ DOC_SEE(Mouse_State) /* API_EXPORT Event_Message Get_Event_Message (Application_Links *app){ - Event_Message message = {0}; - System_Functions *system = (System_Functions*)app->system_links; - Coroutine *coroutine = (Coroutine*)app->current_coroutine; - - if (app->type_coroutine == Co_View){ - Assert(coroutine); - system->yield_coroutine(coroutine); - message = *(Event_Message*)coroutine->in; - } - - return(message); +Event_Message message = {0}; +System_Functions *system = (System_Functions*)app->system_links; +Coroutine *coroutine = (Coroutine*)app->current_coroutine; + +if (app->type_coroutine == Co_View){ +Assert(coroutine); +system->yield_coroutine(coroutine); +message = *(Event_Message*)coroutine->in; +} + +return(message); } */ diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index b73e6753..1cdfe2a0 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -853,7 +853,7 @@ file_grow_starts_as_needed(General_Memory *general, Gap_Buffer *buffer, i32 addi i32 target_lines = count + additional_lines; if (target_lines > max || max == 0){ - max = l_round_up(target_lines + max, KB(1)); + max = l_round_up_i32(target_lines + max, KB(1)); i32 *new_lines = (i32*)general_memory_reallocate(general, buffer->line_starts, sizeof(i32)*count, sizeof(f32)*max); @@ -1904,7 +1904,7 @@ file_create_from_string(System_Functions *system, Models *models, Editing_File * Gap_Buffer_Init init = buffer_begin_init(&file->state.buffer, val.str, val.size); for (; buffer_init_need_more(&init); ){ i32 page_size = buffer_init_page_size(&init); - page_size = l_round_up(page_size, KB(4)); + page_size = l_round_up_i32(page_size, KB(4)); if (page_size < KB(4)){ page_size = KB(4); } @@ -2080,7 +2080,7 @@ Job_Callback_Sig(job_full_lex){ } } while (still_lexing); - i32 new_max = l_round_up(tokens.count+1, KB(1)); + i32 new_max = l_round_up_i32(tokens.count+1, KB(1)); system->acquire_lock(FRAME_LOCK); { @@ -2207,7 +2207,7 @@ file_first_lex_serial(Mem_Options *mem, Editing_File *file){ } } while (still_lexing); - i32 new_max = l_round_up(tokens.count+1, KB(1)); + i32 new_max = l_round_up_i32(tokens.count+1, KB(1)); { Assert(file->state.swap_array.tokens == 0); @@ -2321,7 +2321,7 @@ file_relex_parallel(System_Functions *system, Mem_Options *mem, Editing_File *fi if (inline_lex){ i32 new_count = cpp_relex_get_new_count(&state, array->count, &relex_array); if (new_count > array->max_count){ - i32 new_max = l_round_up(new_count, KB(1)); + i32 new_max = l_round_up_i32(new_count, KB(1)); array->tokens = (Cpp_Token*) general_memory_reallocate(general, array->tokens, array->count*sizeof(Cpp_Token), new_max*sizeof(Cpp_Token)); array->max_count = new_max; @@ -2436,7 +2436,7 @@ file_relex_serial(Mem_Options *mem, Editing_File *file, i32 start_i, i32 end_i, i32 new_count = cpp_relex_get_new_count(&state, array->count, &relex_array); if (new_count > array->max_count){ - i32 new_max = l_round_up(new_count, KB(1)); + i32 new_max = l_round_up_i32(new_count, KB(1)); array->tokens = (Cpp_Token*)general_memory_reallocate(general, array->tokens, array->count*sizeof(Cpp_Token), new_max*sizeof(Cpp_Token)); array->max_count = new_max; } @@ -2766,6 +2766,22 @@ view_cursor_move(View *view, i32 line, i32 character){ view_cursor_move(view, cursor); } +inline void +view_show_file(View *view){ + Editing_File *file = view->file_data.file; + if (file){ + view->map = get_map(view->persistent.models, file->settings.base_map_id); + } + else{ + view->map = get_map(view->persistent.models, mapid_global); + } + + if (view->showing_ui != VUI_None){ + view->showing_ui = VUI_None; + view->changed_context_in_step = 1; + } +} + internal void view_set_file(View *view, Editing_File *file, Models *models){ Assert(file); @@ -2792,6 +2808,10 @@ view_set_file(View *view, Editing_File *file, Models *models){ if (edit_pos->cursor.line == 0){ view_cursor_move(view, 0); } + + if (view->showing_ui == VUI_None){ + view_show_file(view); + } } struct Relative_Scrolling{ @@ -3714,22 +3734,6 @@ view_show_theme(View *view){ view->changed_context_in_step = 1; } -inline void -view_show_file(View *view){ - Editing_File *file = view->file_data.file; - if (file){ - view->map = get_map(view->persistent.models, file->settings.base_map_id); - } - else{ - view->map = get_map(view->persistent.models, mapid_global); - } - - if (view->showing_ui != VUI_None){ - view->showing_ui = VUI_None; - view->changed_context_in_step = 1; - } -} - internal String make_string_terminated(Partition *part, char *str, i32 len){ char *space = (char*)push_array(part, char, len + 1); @@ -4600,7 +4604,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su View_Step_Result result = {0}; GUI_Target *target = &view->gui_target; Models *models = view->persistent.models; - Key_Summary keys = input.keys; + Key_Input_Data keys = input.keys; b32 show_scrollbar = !view->hide_scrollbar; @@ -5754,23 +5758,19 @@ do_step_file_view(System_Functions *system, } { - Key_Event_Data key; - Key_Summary *keys = &user_input->keys; + Key_Input_Data *keys = &user_input->keys; void *ptr = (b + 1); - String string; - char activation_key; + String string = gui_read_string(&ptr); + AllowLocal(string); - i32 i, count; - - string = gui_read_string(&ptr); - activation_key = *(char*)ptr; + char activation_key = *(char*)ptr; activation_key = char_to_upper(activation_key); if (activation_key != 0){ - count = keys->count; - for (i = 0; i < count; ++i){ - key = get_single_key(keys, i); + i32 count = keys->count; + for (i32 i = 0; i < count; ++i){ + Key_Event_Data key = get_single_key(keys, i); if (char_to_upper(key.character) == activation_key){ target->active = b->id; result.is_animating = 1; diff --git a/4ed_gui.cpp b/4ed_gui.cpp index f21be2c2..8e9764f4 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -1254,9 +1254,7 @@ gui_do_jump(GUI_Target *target, GUI_View_Jump jump, GUI_Scroll_Vars vars){ } internal void -gui_standard_list(GUI_Target *target, GUI_id id, GUI_Scroll_Vars *vars, i32_Rect scroll_region, - Key_Summary *keys, i32 *list_i, GUI_Item_Update *update, - i16 user_up_key, i16 user_down_key){ +gui_standard_list(GUI_Target *target, GUI_id id, GUI_Scroll_Vars *vars, i32_Rect scroll_region, Key_Input_Data *keys, i32 *list_i, GUI_Item_Update *update, i16 user_up_key, i16 user_down_key){ if (update->has_adjustment){ *list_i = update->adjustment_value; diff --git a/4ed_layout.cpp b/4ed_layout.cpp index 11cdb68f..4fa49eec 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -277,29 +277,25 @@ layout_get_rect(Editing_Layout *layout, i32 id, i32 which_child){ internal i32_Rect layout_get_panel_rect(Editing_Layout *layout, Panel *panel){ Assert(layout->panel_count > 1); - i32_Rect r = layout_get_rect(layout, panel->parent, panel->which_child); - return(r); } internal void layout_fix_all_panels(Editing_Layout *layout){ - Panel *panel; Panel_Divider *dividers = layout->dividers; AllowLocal(dividers); i32 panel_count = layout->panel_count; if (panel_count > 1){ - for (panel = layout->used_sentinel.next; + for (Panel *panel = layout->used_sentinel.next; panel != &layout->used_sentinel; panel = panel->next){ panel->full = layout_get_panel_rect(layout, panel); panel_fix_internal_area(panel); } } - else{ - panel = layout->used_sentinel.next; + Panel *panel = layout->used_sentinel.next; panel->full.x0 = 0; panel->full.y0 = 0; panel->full.x1 = layout->full_width; @@ -316,10 +312,8 @@ layout_refit(Editing_Layout *layout, i32 prev_width, i32 prev_height){ i32 max = layout->panel_max_count - 1; Panel_Divider *divider = dividers; - if (layout->panel_count > 1){ Assert(prev_width != 0 && prev_height != 0); - for (i32 i = 0; i < max; ++i, ++divider){ if (divider->v_divider){ divider->pos = divider->pos; @@ -373,8 +367,8 @@ layout_compute_position(Editing_Layout *layout, Panel_Divider *divider, i32 pos) internal void layout_compute_abs_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i32 *abs_pos){ Panel_Divider *div = layout->dividers + divider_id; - i32 p0 = 0, p1 = 0; + i32 p0 = 0, p1 = 0; if (div->v_divider){ p0 = rect.x0; p1 = rect.x1; } @@ -405,11 +399,7 @@ layout_compute_abs_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i internal void layout_compute_absolute_positions(Editing_Layout *layout, i32 *abs_pos){ - i32_Rect r; - r.x0 = 0; - r.y0 = 0; - r.x1 = layout->full_width; - r.y1 = layout->full_height; + i32_Rect r = i32R(0, 0, layout->full_width, layout->full_height); if (layout->panel_count > 1){ layout_compute_abs_step(layout, layout->root, r, abs_pos); } @@ -434,14 +424,12 @@ layout_get_min_max_step_up(Editing_Layout *layout, b32 v, i32 divider_id, i32 wh } if (divider->parent != -1){ - layout_get_min_max_step_up(layout, v, divider->parent, divider->which_child, - abs_pos, min_out, max_out); + layout_get_min_max_step_up(layout, v, divider->parent, divider->which_child, abs_pos, min_out, max_out); } } internal void -layout_get_min_max_step_down(Editing_Layout *layout, b32 v, i32 divider_id, i32 which_child, - i32 *abs_pos, i32 *min_out, i32 *max_out){ +layout_get_min_max_step_down(Editing_Layout *layout, b32 v, i32 divider_id, i32 which_child, i32 *abs_pos, i32 *min_out, i32 *max_out){ Panel_Divider *divider = layout->dividers + divider_id; // NOTE(allen): The min/max is switched here, because children on the -1 side @@ -504,8 +492,8 @@ layout_get_min_max(Editing_Layout *layout, Panel_Divider *divider, i32 *abs_pos, internal void layout_update_pos_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i32 *abs_pos){ Panel_Divider *div = layout->dividers + divider_id; - i32 p0 = 0, p1 = 0; + i32 p0 = 0, p1 = 0; if (div->v_divider){ p0 = rect.x0; p1 = rect.x1; } @@ -516,6 +504,7 @@ layout_update_pos_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i3 i32 pos = abs_pos[divider_id]; i32_Rect r1 = rect, r2 = rect; f32 lpos = unlerp((f32)p0, (f32)pos, (f32)p1); + lpos = clamp(0.f, lpos, 1.f); div->pos = lpos; @@ -539,11 +528,7 @@ layout_update_pos_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i3 internal void layout_update_all_positions(Editing_Layout *layout, i32 *abs_pos){ - i32_Rect r; - r.x0 = 0; - r.y0 = 0; - r.x1 = layout->full_width; - r.y1 = layout->full_height; + i32_Rect r = i32R(0, 0, layout->full_width, layout->full_height); if (layout->panel_count > 1){ layout_update_pos_step(layout, layout->root, r, abs_pos); } diff --git a/4ed_math.h b/4ed_math.h index 57f41c23..468972be 100644 --- a/4ed_math.h +++ b/4ed_math.h @@ -647,13 +647,28 @@ hit_check(int32_t x, int32_t y, i32_Rect rect){ } inline i32_Rect -get_inner_rect(i32_Rect outer, int32_t margin){ +get_inner_rect(i32_Rect outer, i32 margin){ i32_Rect r; r.x0 = outer.x0 + margin; r.y0 = outer.y0 + margin; r.x1 = outer.x1 - margin; r.y1 = outer.y1 - margin; - return r; + return(r); +} + +inline f32_Rect +get_inner_rect(f32_Rect outer, f32 margin){ + f32_Rect r; + r.x0 = outer.x0 + margin; + r.y0 = outer.y0 + margin; + r.x1 = outer.x1 - margin; + r.y1 = outer.y1 - margin; + return(r); +} + +inline int32_t +fits_inside(i32_Rect rect, i32_Rect outer){ + return(rect.x0 >= outer.x0 && rect.x1 <= outer.x1 && rect.y0 >= outer.y0 && rect.y1 <= outer.y1); } // BOTTOM diff --git a/4ed_rendering.h b/4ed_rendering.h index bae1a73e..75cf926c 100644 --- a/4ed_rendering.h +++ b/4ed_rendering.h @@ -151,6 +151,7 @@ struct Render_Target{ void *context; i32_Rect clip_boxes[5]; i32 clip_top; + b32 clip_all; i32 width, height; i32 bound_texture; u32 color; @@ -166,8 +167,6 @@ struct Render_Target{ Draw_Push_Clip *push_clip; Draw_Pop_Clip *pop_clip; Draw_Push_Piece *push_piece; - - //i32 dpi; }; #define DpiMultiplier(n,dpi) ((n) * (dpi) / 96) diff --git a/4ed_rendering_helper.cpp b/4ed_rendering_helper.cpp index 4836b146..9c30d292 100644 --- a/4ed_rendering_helper.cpp +++ b/4ed_rendering_helper.cpp @@ -9,20 +9,6 @@ // TOP -#if 0 -inline i32_Rect -i32_rect_zero(){ - i32_Rect rect={0}; - return(rect); -} - -inline f32_Rect -f32_rect_zero(){ - f32_Rect rect={0}; - return(rect); -} -#endif - inline void draw_push_clip(Render_Target *target, i32_Rect clip_box){ target->push_clip(target, clip_box); diff --git a/4ed_site.ctm b/4ed_site.ctm index 354cc4e3..d6332672 100644 Binary files a/4ed_site.ctm and b/4ed_site.ctm differ diff --git a/4ed_system_shared.cpp b/4ed_system_shared.cpp index d4a2abb8..c327c9a0 100644 --- a/4ed_system_shared.cpp +++ b/4ed_system_shared.cpp @@ -266,69 +266,66 @@ draw_safe_push(Render_Target *target, i32 size, void *x){ internal void draw_push_piece(Render_Target *target, Render_Piece_Combined piece){ - PutStruct(Render_Piece_Header, piece.header); - - switch (piece.header.type){ - case piece_type_rectangle: - case piece_type_outline: - PutStruct(Render_Piece_Rectangle, piece.rectangle); - break; + if (!target->clip_all){ + PutStruct(Render_Piece_Header, piece.header); - case piece_type_gradient: - PutStruct(Render_Piece_Gradient, piece.gradient); - break; + switch (piece.header.type){ + case piece_type_rectangle: + case piece_type_outline: + PutStruct(Render_Piece_Rectangle, piece.rectangle); + break; + + case piece_type_gradient: + PutStruct(Render_Piece_Gradient, piece.gradient); + break; + + case piece_type_glyph: + case piece_type_mono_glyph: + PutStruct(Render_Piece_Glyph, piece.glyph); + break; + + case piece_type_mono_glyph_advance: + PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance); + break; + } - case piece_type_glyph: - case piece_type_mono_glyph: - PutStruct(Render_Piece_Glyph, piece.glyph); - break; - - case piece_type_mono_glyph_advance: - PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance); - break; + Assert(target->size <= target->max); } - - Assert(target->size <= target->max); } internal void draw_push_piece_clip(Render_Target *target, i32_Rect clip_box){ - // TODO(allen): optimize out if there are two clip box changes in a row - Render_Piece_Change_Clip clip; - Render_Piece_Header header; - - header.type = piece_type_change_clip; - clip.box = clip_box; - - PutStruct(Render_Piece_Header, header); - PutStruct(Render_Piece_Change_Clip, clip); -} - -inline int32_t -fits_inside(i32_Rect rect, i32_Rect outer){ - return (rect.x0 >= outer.x0 && rect.x1 <= outer.x1 && - rect.y0 >= outer.y0 && rect.y1 <= outer.y1); + if (!target->clip_all){ + // TODO(allen): optimize out if there are two clip box changes in a row + Render_Piece_Change_Clip clip; + Render_Piece_Header header; + + header.type = piece_type_change_clip; + clip.box = clip_box; + + PutStruct(Render_Piece_Header, header); + PutStruct(Render_Piece_Change_Clip, clip); + } } internal void draw_push_clip(Render_Target *target, i32_Rect clip_box){ - Assert(target->clip_top == -1 || - fits_inside(clip_box, target->clip_boxes[target->clip_top])); + Assert(target->clip_top == -1 || fits_inside(clip_box, target->clip_boxes[target->clip_top])); Assert(target->clip_top+1 < ArrayCount(target->clip_boxes)); target->clip_boxes[++target->clip_top] = clip_box; + target->clip_all = (clip_box.x0 >= clip_box.x1 || clip_box.y0 >= clip_box.y1); draw_push_piece_clip(target, clip_box); } internal i32_Rect draw_pop_clip(Render_Target *target){ - i32_Rect result = {0}; - i32_Rect clip_box = {0}; - Assert(target->clip_top > 0); - result = target->clip_boxes[target->clip_top]; + i32_Rect result = target->clip_boxes[target->clip_top]; --target->clip_top; - clip_box = target->clip_boxes[target->clip_top]; + i32_Rect clip_box = target->clip_boxes[target->clip_top]; + + target->clip_all = (clip_box.x0 >= clip_box.x1 || clip_box.y0 >= clip_box.y1); draw_push_piece_clip(target, clip_box); return(result); @@ -352,12 +349,7 @@ private_draw_rectangle(Render_Target *target, f32_Rect rect, u32 color){ inline void private_draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){ - f32_Rect r; - r.x0 = rect.x0 + .5f; - r.y0 = rect.y0 + .5f; - r.x1 = rect.x1 - .5f; - r.y1 = rect.y1 - .5f; - + f32_Rect r = get_inner_rect(rect, .5f); draw_set_color(target, color); draw_bind_texture(target, 0); glBegin(GL_LINE_STRIP); diff --git a/4tech_defines.h b/4tech_defines.h index a30a4842..f916793a 100644 --- a/4tech_defines.h +++ b/4tech_defines.h @@ -59,18 +59,34 @@ typedef double f64; #define Max(a,b) (((a)>(b))?(a):(b)) #define Min(a,b) (((a)<(b))?(a):(b)) -#define ceil32(v) (((v)>0)?( (v == (i32)(v))?((i32)(v)):((i32)((v)+1.f)) ):( ((i32)(v)) )) - -#define floor32(v) (((v)<0)?( (v == (i32)(v))?((i32)(v)):((i32)((v)-1.f)) ):( ((i32)(v)) )) - -#define round32(v) (floor32(v + 0.5f)) - -#define trunc32(v) (i32)(v) - -#define div_ceil(n,d) ( ((n) % (d) != 0) + ((n) / (d)) ) - -#define l_round_up(x,b) ( ((x)+(b)-1) - (((x)+(b)-1)%(b)) ) - +inline i32 ceil32(f32 v){ + return(((v)>0)?( (v == (i32)(v))?((i32)(v)):((i32)((v)+1.f)) ):( ((i32)(v)) )); + } + + inline i32 floor32(f32 v){ + return(((v)<0)?( (v == (i32)(v))?((i32)(v)):((i32)((v)-1.f)) ):( ((i32)(v)) )); + } + + inline i32 round32(f32 v){ + return(floor32(v + 0.5f)); + } + + inline i32 trun32(f32 v){ + return((i32)(v)); + } + + inline i32 div_ceil(i32 n, i32 d){ + return( ((n) % (d) != 0) + ((n) / (d)) ); + } + + inline i32 l_round_up_i32(i32 x, i32 b){ +return( ((x)+(b)-1) - (((x)+(b)-1)%(b)) ); + } + + inline u32 l_round_up_u32(u32 x, u32 b){ + return( ((x)+(b)-1) - (((x)+(b)-1)%(b)) ); + } + #define STR__(s) #s #define STR_(s) STR__(s) diff --git a/custom_4coder.dll b/custom_4coder.dll new file mode 100644 index 00000000..8ca698f1 Binary files /dev/null and b/custom_4coder.dll differ diff --git a/custom_4coder.pdb b/custom_4coder.pdb new file mode 100644 index 00000000..7fb61c82 Binary files /dev/null and b/custom_4coder.pdb differ diff --git a/file/4coder_buffer.cpp b/file/4coder_buffer.cpp index 4dd15d45..9668505f 100644 --- a/file/4coder_buffer.cpp +++ b/file/4coder_buffer.cpp @@ -502,7 +502,7 @@ buffer_replace_range(Gap_Buffer *buffer, i32 start, i32 end, char *str, i32 len, assert(buffer->size1 + buffer->gap_size + buffer->size2 == buffer->max); } else{ - *request_amount = l_round_up(2*(*shift_amount + size), 4 << 10); + *request_amount = l_round_up_i32(2*(*shift_amount + size), 4 << 10); result = 1; } @@ -1235,6 +1235,7 @@ buffer_partial_from_line_character(Gap_Buffer *buffer, i32 line, i32 character){ } i32 size = buffer_size(buffer); + i32 this_start = buffer->line_starts[line_index]; i32 max_character = (size-this_start) + 1; if (line_index+1 < buffer->line_count){ @@ -1242,14 +1243,28 @@ buffer_partial_from_line_character(Gap_Buffer *buffer, i32 line, i32 character){ max_character = (next_start-this_start); } - if (character <= 0){ - character = 1; + i32 adjusted_pos = 0; + if (character > 0){ + if (character > max_character){ + adjusted_pos = max_character - 1; + } + else{ + adjusted_pos = character - 1; + } } - if (character > max_character){ - character = max_character; + else if (character == 0){ + adjusted_pos = 0; + } + else{ + if (-character > max_character){ + adjusted_pos = 0; + } + else{ + adjusted_pos = max_character + character; + } } - result.pos = this_start + character - 1; + result.pos = this_start + adjusted_pos; result.line = line_index + 1; result.character = character; diff --git a/file/4coder_file.cpp b/file/4coder_file.cpp index 6ccb01b5..8f1a5ada 100644 --- a/file/4coder_file.cpp +++ b/file/4coder_file.cpp @@ -285,7 +285,7 @@ file_compute_cursor_from_line_character(Editing_File *file, i32 line, i32 charac inline b32 file_compute_partial_cursor(Editing_File *file, Buffer_Seek seek, Partial_Cursor *cursor){ - b32 result = 1; + b32 result = true; switch (seek.type){ case buffer_seek_pos: { @@ -299,7 +299,7 @@ file_compute_partial_cursor(Editing_File *file, Buffer_Seek seek, Partial_Cursor default: { - result = 0; + result = false; }break; } return(result); diff --git a/meta/build.cpp b/meta/build.cpp index 632936cc..0134e9e6 100644 --- a/meta/build.cpp +++ b/meta/build.cpp @@ -445,6 +445,7 @@ standard_build(char *cdir, u32 flags){ fsm_generator(cdir); metagen(cdir); do_buildsuper(cdir, Custom_Experiments); + //do_buildsuper(cdir, Custom_Casey); //do_buildsuper(cdir, Custom_ChronalVim); build_main(cdir, flags); } diff --git a/power/4coder_casey.cpp b/power/4coder_casey.cpp index 9996b98a..8f41ab89 100644 --- a/power/4coder_casey.cpp +++ b/power/4coder_casey.cpp @@ -4,7 +4,7 @@ to know what I'm actually even doing. So if you decide to use the code in here, be advised that it might be super crashy or break something or cause you to lose work or who knows what else! - + DON'T SAY I WE DIDN'T WARN YA: This custom extension provided "as is" without warranty of any kind, either express or implied, including without limitation any implied warranties of condition, uninterrupted use, @@ -16,9 +16,9 @@ - High priority: - Buffer switching still seems a little bit broken. I find I can't reliably hit switch-return and switch to the most recently viewed file that wasn't one of the two currently viewed buffers? - + - High-DPI settings break rendering and all fonts just show up as solid squares <<< Check this again - + - Pretty sure auto-indent has some bugs. Things that should be pretty easy to indent properly even from only a few surrounding lines seem to be indented improperly at the moment - Multi-line comments should default to indenting to the indentation of the line prior? @@ -34,24 +34,24 @@ as well - similarly, scrolling breaks, in that it thinks it has "hit the end" of the buffer when you cursor down, but the cursor and the rest of the wrapped lines are actually off the bottom of the screen) - + - Search: - Should highlight all matches in the buffer - Seems to buggily break out of the search sometimes for no reason? (eg., you hit the end and it just drops out of the search instead of stopping?) - Tracked this one down: I think it is because spurious mousewheel or other inputs break out of the search. How can this be prevented? - + - Display: - When switching _back_ to a buffer, it seems like it loses the scroll position, instead preferring to center the cursor? This is undesirable IMO... <<< Check this again - + - I'd like to be able to hide the mark in text entry mode, and show the whole highlighted region in edit mode - perhaps even with a magic split at the top or bottom that shows where the mark is if it's off screen? - There are often repaint bugs with 4coder coming to the front / unminimizing, etc. I think this might have something to do with the way you're doing lots of semaphore locking but I haven't investigated yet. <<< How are we doing on this bug? It might be fixed but I haven't heard from anyone. - + - Need a word-wrap mode that wraps at word boundaries instead of characters - Need to be able to set a word wrap length at something other than the window - First go-to-line for a file seems to still just go to the beginning of the buffer? @@ -64,7 +64,7 @@ of people on The Stream(TM) - Some kind of matching brace display so in long ifs, etc., you can see what they match (maybe draw it directly into the buffer?) - + - Indentation: - Multiple // lines don't seem to indent properly. The first one will go to the correct place, but the subsequent ones will go to the first column regardless? - Need to have better indentation / wrapping control for typing in comments. @@ -74,13 +74,13 @@ etc. - It should never reindent text in comments that it doesn't know how to indent - eg., in a comment block, it shouldn't decide to move things around if it doesn't know what they are - Sometimes when I hit [ it inserts a [ _and_ a space? I think this is related to the auto-indent? <<< Check this again - + - Buffer management: - I'd like to be able to set a buffer to "auto-revert", so it reloads automatically whenever it changes externally - If you undo back to where there are no changes, the "buffer changed" flag should be cleared - Seems like there's no way to switch to buffers whose names are substrings of other buffers' names without using the mouse? <<< Check this again - + - File system - When switching to a buffer that has changed on disk, notify? Really this can just be some way to query the modification flag and then the customization layer can do it? @@ -88,14 +88,14 @@ - I'd prefer it if file-open could create new files, and that I could get called on that so I can insert my boilerplate headers on new files - I'd prefer it if file-open deleted per-character instead of deleting entire path sections - + - Need auto-complete for things like "arbitrary command", with options listed, etc., so this should either be built into 4ed, or the custom DLL should have the ability to display possible completions and iterate over internal cmdid's, etc. Possibly the latter, for maximal ability of customizers to add their own commands? - + - Macro recording/playback - + - Arbitrary cool features: - Once you can highlight things in 4coder buffers, I could make it so that my metacompiler output _ranges_ for errors, so it highlights the whole token rather @@ -107,7 +107,7 @@ - You should just implement a shell inside 4coder which can call all the 4coder stuff as well as execute system stuff, so that from now on you just write scripts "in 4coder", etc., so they are always portable everywhere 4coder runs? - + - Things I should write: - Ability to do "file open from same directory as the current buffer" - Spell-checker @@ -139,11 +139,11 @@ struct Parsed_Error { int exists; - + String target_file_name; int target_line_number; int target_column_number; - + int source_buffer_id; int source_position; }; @@ -157,7 +157,7 @@ static char BuildDirectory[4096] = "./"; enum token_type { Token_Unknown, - + Token_OpenParen, Token_CloseParen, Token_Asterisk, @@ -168,13 +168,13 @@ enum token_type Token_Colon, Token_Number, Token_Comma, - + Token_EndOfStream, }; struct token { token_type Type; - + size_t TextLength; char *Text; }; @@ -189,7 +189,7 @@ IsEndOfLine(char C) { bool Result = ((C == '\n') || (C == '\r')); - + return(Result); } @@ -201,7 +201,7 @@ IsWhitespace(char C) (C == '\v') || (C == '\f') || IsEndOfLine(C)); - + return(Result); } @@ -210,7 +210,7 @@ IsAlpha(char C) { bool Result = (((C >= 'a') && (C <= 'z')) || ((C >= 'A') && (C <= 'Z'))); - + return(Result); } @@ -218,7 +218,7 @@ inline bool IsNumeric(char C) { bool Result = ((C >= '0') && (C <= '9')); - + return(Result); } @@ -250,7 +250,7 @@ EatAllWhitespace(tokenizer *Tokenizer) { ++Tokenizer->At; } - + if(Tokenizer->At[0] == '*') { Tokenizer->At += 2; @@ -267,7 +267,7 @@ static token GetToken(tokenizer *Tokenizer) { EatAllWhitespace(Tokenizer); - + token Token = {}; Token.TextLength = 1; Token.Text = Tokenizer->At; @@ -276,7 +276,7 @@ GetToken(tokenizer *Tokenizer) 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; @@ -286,7 +286,7 @@ GetToken(tokenizer *Tokenizer) case '%': {Token.Type = Token_Percent;} break; case ':': {Token.Type = Token_Colon;} break; case ',': {Token.Type = Token_Comma;} break; - + default: { if(IsNumeric(C)) @@ -307,7 +307,7 @@ GetToken(tokenizer *Tokenizer) } } break; } - + return(Token); } @@ -325,7 +325,7 @@ 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); } @@ -335,7 +335,7 @@ 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); } @@ -343,7 +343,7 @@ inline bool IsINL(String extension) { bool Result = (match(extension, make_lit_string("inl")) != 0); - + return(Result); } @@ -351,7 +351,7 @@ inline bool IsCode(String extension) { bool Result = (IsH(extension) || IsCPP(extension) || IsINL(extension)); - + return(Result); } @@ -404,7 +404,7 @@ DeleteAfterCommand(struct Application_Links *app, unsigned long long CommandID) { unsigned int access = AccessOpen; View_Summary view = get_active_view(app, access); - + int pos2 = view.cursor.pos; if (CommandID < cmdid_count){ exec_command(app, (Command_ID)CommandID); @@ -414,9 +414,9 @@ DeleteAfterCommand(struct Application_Links *app, unsigned long long CommandID) } refresh_view(app, &view); int pos1 = view.cursor.pos; - + Range range = make_range(pos1, pos2); - + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); buffer_replace_range(app, &buffer, range.min, range.max, 0, 0); } @@ -435,18 +435,18 @@ CUSTOM_COMMAND_SIG(casey_kill_to_end_of_line) { unsigned int access = AccessOpen; View_Summary view = get_active_view(app, access); - + int pos2 = view.cursor.pos; exec_command(app, seek_end_of_line); refresh_view(app, &view); int pos1 = view.cursor.pos; - + Range range = make_range(pos1, pos2); if(pos1 == pos2) { range.max += 1; } - + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); buffer_replace_range(app, &buffer, range.min, range.max, 0, 0); exec_command(app, auto_tab_line_at_cursor); @@ -496,16 +496,16 @@ inline switch_to_result SwitchToOrLoadFile(struct Application_Links *app, String FileName, bool CreateIfNotFound = false) { switch_to_result Result = {}; - + SanitizeSlashes(FileName); unsigned int access = AccessAll; View_Summary view = get_active_view(app, access); Buffer_Summary buffer = get_buffer_by_name(app, FileName.str, FileName.size, access); - + Result.view = view; Result.buffer = buffer; - + if(buffer.exists) { view_set_buffer(app, &view, buffer.buffer_id, 0); @@ -525,7 +525,7 @@ SwitchToOrLoadFile(struct Application_Links *app, String FileName, bool CreateIf Result.Switched = true; } } - + return(Result); } @@ -543,29 +543,29 @@ CUSTOM_COMMAND_SIG(casey_build_search) // we should properly suballocating from app->memory. String dir = make_string(app->memory, 0, app->memory_size); dir.size = directory_get_hot(app, dir.str, dir.memory_size); - + while (keep_going) { old_size = dir.size; append(&dir, "build.bat"); - + if (file_exists(app, dir.str, dir.size)) { dir.size = old_size; memcpy(BuildDirectory, dir.str, dir.size); BuildDirectory[dir.size] = 0; - + // TODO(allen): There are ways this could be boiled down // to one print message which would be better. print_message(app, literal("Building with: ")); print_message(app, BuildDirectory, dir.size); print_message(app, literal("build.bat\n")); - + return; } - + dir.size = old_size; - + if (directory_cd(app, dir.str, &dir.size, dir.memory_size, literal("..")) == 0) { keep_going = 0; @@ -579,7 +579,7 @@ CUSTOM_COMMAND_SIG(casey_find_corresponding_file) unsigned int access = AccessProtected; View_Summary view = get_active_view(app, access); Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - + String extension = file_extension(make_string(buffer.file_name, buffer.file_name_len)); if (extension.str) { @@ -589,14 +589,14 @@ CUSTOM_COMMAND_SIG(casey_find_corresponding_file) "hin", "h", }; - + char *CExtensions[] = { "c", "cin", "cpp", }; - + int ExtensionCount = 0; char **Extensions = 0; if(IsH(extension)) @@ -609,7 +609,7 @@ CUSTOM_COMMAND_SIG(casey_find_corresponding_file) 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); @@ -621,7 +621,7 @@ CUSTOM_COMMAND_SIG(casey_find_corresponding_file) TestFileName.size = 0; append(&TestFileName, FileNameStem); append(&TestFileName, Extensions[ExtensionIndex]); - + if(SwitchToOrLoadFile(app, TestFileName, ((ExtensionIndex + 1) == ExtensionCount)).Switched) { break; @@ -635,12 +635,12 @@ CUSTOM_COMMAND_SIG(casey_find_corresponding_file_other_window) unsigned int access = AccessProtected; View_Summary old_view = get_active_view(app, access); Buffer_Summary buffer = get_buffer(app, old_view.buffer_id, access); - + exec_command(app, change_active_panel); View_Summary new_view = get_active_view(app, AccessAll); view_set_buffer(app, &new_view, buffer.buffer_id, 0); - -// exec_command(app, casey_find_corresponding_file); + + // exec_command(app, casey_find_corresponding_file); } CUSTOM_COMMAND_SIG(casey_save_and_make_without_asking) @@ -657,11 +657,6 @@ CUSTOM_COMMAND_SIG(casey_save_and_make_without_asking) save_buffer(app, &buffer, buffer.file_name, buffer.file_name_len, 0); } - // NOTE(allen): The parameter pushing made it a little easier - // to deal with this particular pattern where two similar strings - // were both used. Now both strings need to exist at the same - // time on the users side. - int size = app->memory_size/2; String dir = make_string(app->memory, 0, size); String command = make_string((char*)app->memory + size, 0, size); @@ -683,14 +678,17 @@ CUSTOM_COMMAND_SIG(casey_save_and_make_without_asking) { unsigned int access = AccessAll; View_Summary view = get_active_view(app, access); + char *BufferName = GlobalCompilationBufferName; + int BufferNameLength = (int)strlen(GlobalCompilationBufferName); exec_system_command(app, &view, - buffer_identifier(GlobalCompilationBufferName, (int)strlen(GlobalCompilationBufferName)), + buffer_identifier(BufferName, BufferNameLength), dir.str, dir.size, command.str, command.size, CLI_OverlapWithConflict); + lock_jump_buffer(BufferName, BufferNameLength); } - exec_command(app, change_active_panel); + exec_command(app, change_active_panel); prev_location = null_location; } @@ -699,7 +697,7 @@ internal bool casey_errors_are_the_same(Parsed_Error a, Parsed_Error b) { bool result = ((a.exists == b.exists) && compare(a.target_file_name, b.target_file_name) && (a.target_line_number == b.target_line_number)); - + return(result); } @@ -713,7 +711,7 @@ casey_goto_error(Application_Links *app, Parsed_Error e) { app->view_set_cursor(app, &Switch.view, seek_line_char(e.target_line_number, e.target_column_number), 1); } - + View_Summary compilation_view = get_first_view_with_buffer(app, e.source_buffer_id); if(compilation_view.exists) { @@ -726,24 +724,24 @@ internal Parsed_Error casey_parse_error(Application_Links *app, Buffer_Summary buffer, View_Summary view) { Parsed_Error result = {}; - + refresh_view(app, &view); int restore_pos = view.cursor.pos; - + // TODO(allen): view_compute_cursor can get these // positions without ever changing the position of the cursor. app->view_set_cursor(app, &view, seek_line_char(view.cursor.line, 1), 1); int start = view.cursor.pos; - + app->view_set_cursor(app, &view, seek_line_char(view.cursor.line, 65536), 1); int end = view.cursor.pos; - + app->view_set_cursor(app, &view, seek_pos(restore_pos), 1); - + int size = end - start; - + char *ParsingRegion = (char *)malloc(size + 1); -// char *ParsingRegion = (char *)app->push_memory(app, size + 1); + // char *ParsingRegion = (char *)app->push_memory(app, size + 1); app->buffer_read_range(app, &buffer, start, end, ParsingRegion); ParsingRegion[size] = 0; tokenizer Tokenizer = {ParsingRegion}; @@ -756,7 +754,7 @@ casey_parse_error(Application_Links *app, Buffer_Summary buffer, View_Summary vi if(LineToken.Type == Token_Number) { token CloseToken = GetToken(&Tokenizer); - + int column_number = 0; if(CloseToken.Type == Token_Comma) { @@ -767,7 +765,7 @@ casey_parse_error(Application_Links *app, Buffer_Summary buffer, View_Summary vi CloseToken = GetToken(&Tokenizer); } } - + if(CloseToken.Type == Token_CloseParen) { token ColonToken = GetToken(&Tokenizer); @@ -775,7 +773,7 @@ casey_parse_error(Application_Links *app, Buffer_Summary buffer, View_Summary vi { // NOTE(casey): We maybe found an error! int line_number = atoi(LineToken.Text); - + char *Seek = Token.Text; while(Seek != ParsingRegion) { @@ -787,17 +785,17 @@ casey_parse_error(Application_Links *app, Buffer_Summary buffer, View_Summary vi } break; } - + --Seek; } - + result.exists = true; result.target_file_name = make_string(Seek, (int)(Token.Text - Seek));; result.target_line_number = line_number; result.target_column_number = column_number; result.source_buffer_id = buffer.buffer_id; result.source_position = start + (int)(ColonToken.Text - ParsingRegion); - + break; } } @@ -809,7 +807,7 @@ casey_parse_error(Application_Links *app, Buffer_Summary buffer, View_Summary vi } } free(ParsingRegion); - + return(result); } @@ -818,10 +816,10 @@ casey_seek_error_dy(Application_Links *app, int dy) { Buffer_Summary Buffer = app->get_buffer_by_name(app, GlobalCompilationBufferName, (int)strlen(GlobalCompilationBufferName), AccessAll); View_Summary compilation_view = get_first_view_with_buffer(app, Buffer.buffer_id); - + // NOTE(casey): First get the current error (which may be none, if we've never parsed before) Parsed_Error StartingError = casey_parse_error(app, Buffer, compilation_view); - + // NOTE(casey): Now hunt for the previous distinct error for(;;) { @@ -846,7 +844,7 @@ casey_seek_error_dy(Application_Links *app, int dy) CUSTOM_COMMAND_SIG(casey_goto_previous_error) { -// casey_seek_error_dy(app, -1); + // casey_seek_error_dy(app, -1); seek_error(app, &global_part, true, false, -1); } @@ -888,13 +886,13 @@ CUSTOM_COMMAND_SIG(casey_fill_paragraph) enum calc_node_type { CalcNode_UnaryMinus, - + CalcNode_Add, CalcNode_Subtract, CalcNode_Multiply, CalcNode_Divide, CalcNode_Mod, - + CalcNode_Constant, }; struct calc_node @@ -909,7 +907,7 @@ internal double ExecCalcNode(calc_node *Node) { double Result = 0.0f; - + if(Node) { switch(Node->Type) @@ -924,7 +922,7 @@ ExecCalcNode(calc_node *Node) default: {Assert(!"AHHHHH!");} } } - + return(Result); } @@ -954,10 +952,10 @@ internal calc_node * ParseNumber(tokenizer *Tokenizer) { calc_node *Result = AddNode(CalcNode_Constant); - + token Token = GetToken(Tokenizer); Result->Value = atof(Token.Text); - + return(Result); } @@ -965,7 +963,7 @@ internal calc_node * ParseConstant(tokenizer *Tokenizer) { calc_node *Result = 0; - + token Token = PeekToken(Tokenizer); if(Token.Type == Token_Minus) { @@ -977,7 +975,7 @@ ParseConstant(tokenizer *Tokenizer) { Result = ParseNumber(Tokenizer); } - + return(Result); } @@ -985,7 +983,7 @@ internal calc_node * ParseMultiplyExpression(tokenizer *Tokenizer) { calc_node *Result = 0; - + token Token = PeekToken(Tokenizer); if((Token.Type == Token_Minus) || (Token.Type == Token_Number)) @@ -1003,7 +1001,7 @@ ParseMultiplyExpression(tokenizer *Tokenizer) Result = AddNode(CalcNode_Multiply, Result, ParseNumber(Tokenizer)); } } - + return(Result); } @@ -1011,7 +1009,7 @@ internal calc_node * ParseAddExpression(tokenizer *Tokenizer) { calc_node *Result = 0; - + token Token = PeekToken(Tokenizer); if((Token.Type == Token_Minus) || (Token.Type == Token_Number)) @@ -1029,7 +1027,7 @@ ParseAddExpression(tokenizer *Tokenizer) Result = AddNode(CalcNode_Subtract, Result, ParseMultiplyExpression(Tokenizer)); } } - + return(Result); } @@ -1037,7 +1035,7 @@ internal calc_node * ParseCalc(tokenizer *Tokenizer) { calc_node *Node = ParseAddExpression(Tokenizer); - + return(Node); } @@ -1045,26 +1043,26 @@ CUSTOM_COMMAND_SIG(casey_quick_calc) { unsigned int access = AccessOpen; View_Summary view = get_active_view(app, access); - + Range range = get_range(&view); - + size_t Size = range.max - range.min; char *Stuff = (char *)malloc(Size + 1); Stuff[Size] = 0; - + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); 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); - + buffer_replace_range(app, &buffer, range.min, range.max, ResultBuffer, ResultSize); - + free(Stuff); } @@ -1072,7 +1070,7 @@ internal void OpenProject(Application_Links *app, char *ProjectFileName) { int TotalOpenAttempts = 0; - + FILE *ProjectFile = fopen(ProjectFileName, "r"); if(ProjectFile) { @@ -1082,13 +1080,13 @@ OpenProject(Application_Links *app, char *ProjectFileName) { --BuildDirSize; } - + if((BuildDirSize) && (BuildDirectory[BuildDirSize - 1] != '/')) { BuildDirectory[BuildDirSize++] = '/'; BuildDirectory[BuildDirSize] = 0; } - + char SourceFileDirectoryName[4096]; char FileDirectoryName[4096]; while(fgets(SourceFileDirectoryName, sizeof(SourceFileDirectoryName) - 1, ProjectFile)) @@ -1101,15 +1099,15 @@ OpenProject(Application_Links *app, char *ProjectFileName) { --dir.size; } - + if(dir.size && dir.str[dir.size-1] != '/') { dir.str[dir.size++] = '/'; } - + File_List list = 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; @@ -1125,16 +1123,16 @@ OpenProject(Application_Links *app, char *ProjectFileName) // was originally, so that new appends overwrite old ones. dir.size = dir_size; append(&dir, info->filename); - + open_file(app, 0, dir.str, dir.size, true, true); ++TotalOpenAttempts; } } } - + free_file_list(app, list); } - + fclose(ProjectFile); } } @@ -1145,13 +1143,13 @@ CUSTOM_COMMAND_SIG(casey_execute_arbitrary_command) char space[1024], more_space[1024]; bar.prompt = make_lit_string("Command: "); bar.string = make_fixed_width_string(space); - + if (!query_user_string(app, &bar)) return; end_query_bar(app, &bar, 0); - + if(match(bar.string, make_lit_string("project"))) { -// exec_command(app, open_all_code); + // exec_command(app, open_all_code); } else if(match(bar.string, make_lit_string("open menu"))) { @@ -1163,7 +1161,7 @@ CUSTOM_COMMAND_SIG(casey_execute_arbitrary_command) append(&bar.prompt, make_lit_string("Unrecognized: ")); append(&bar.prompt, bar.string); bar.string.size = 0; - + start_query_bar(app, &bar, 0); get_user_input(app, EventOnAnyKey | EventOnButton, 0); } @@ -1182,7 +1180,7 @@ UpdateModalIndicator(Application_Links *app) {Stag_Margin_Active, 0x404040}, {Stag_Bar, 0xCACACA} }; - + Theme_Color edit_colors[] = { {Stag_Cursor, 0xFF0000}, @@ -1193,7 +1191,7 @@ UpdateModalIndicator(Application_Links *app) {Stag_Margin_Active, 0x934420}, {Stag_Bar, 0x934420} }; - + if (GlobalEditMode){ set_theme_colors(app, edit_colors, ArrayCount(edit_colors)); } @@ -1304,10 +1302,10 @@ OPEN_FILE_HOOK_SIG(casey_file_settings) unsigned int access = AccessAll; //Buffer_Summary buffer = app->get_parameter_buffer(app, 0, access); Buffer_Summary buffer = get_buffer(app, buffer_id, access); - + int treat_as_code = 0; int treat_as_project = 0; - + if (buffer.file_name && buffer.size < (16 << 20)) { String ext = file_extension(make_string(buffer.file_name, buffer.file_name_len)); @@ -1323,10 +1321,10 @@ OPEN_FILE_HOOK_SIG(casey_file_settings) { OpenProject(app, buffer.file_name); // NOTE(casey): Don't actually want to kill this, or you can never edit the project. -// exec_command(app, cmdid_kill_buffer); - + // exec_command(app, cmdid_kill_buffer); + } - + return(0); } @@ -1334,7 +1332,7 @@ bool CubicUpdateFixedDuration1(float *P0, float *V0, float P1, float V1, float Duration, float dt) { bool Result = false; - + if(dt > 0) { if(Duration < dt) @@ -1347,27 +1345,27 @@ CubicUpdateFixedDuration1(float *P0, float *V0, float P1, float V1, float Durati { float t = (dt / Duration); float u = (1.0f - t); - + float C0 = 1*u*u*u; float C1 = 3*u*u*t; float C2 = 3*u*t*t; float C3 = 1*t*t*t; - + float dC0 = -3*u*u; float dC1 = -6*u*t + 3*u*u; float dC2 = 6*u*t - 3*t*t; float dC3 = 3*t*t; - + float B0 = *P0; float B1 = *P0 + (Duration / 3.0f) * *V0; float B2 = P1 - (Duration / 3.0f) * V1; float B3 = P1; - + *P0 = C0*B0 + C1*B1 + C2*B2 + C3*B3; *V0 = (dC0*B0 + dC1*B1 + dC2*B2 + dC3*B3) * (1.0f / Duration); } } - + return(Result); } @@ -1385,18 +1383,18 @@ SCROLL_RULE_SIG(casey_smooth_scroll_rule){ if(is_new_target) { if((*scroll_x != target_x) || - (*scroll_y != target_y)) + (*scroll_y != target_y)) { velocity->t = 0.1f; } } - + if(velocity->t > 0) { result = !(CubicUpdateFixedDuration1(scroll_x, &velocity->x, target_x, 0.0f, velocity->t, dt) || - CubicUpdateFixedDuration1(scroll_y, &velocity->y, target_y, 0.0f, velocity->t, dt)); + CubicUpdateFixedDuration1(scroll_y, &velocity->y, target_y, 0.0f, velocity->t, dt)); } - + velocity->t -= dt; if(velocity->t < 0) { @@ -1404,7 +1402,7 @@ SCROLL_RULE_SIG(casey_smooth_scroll_rule){ *scroll_x = target_x; *scroll_y = target_y; } - + return(result); } @@ -1415,7 +1413,7 @@ static WINDOWPLACEMENT GlobalWindowPosition = {sizeof(GlobalWindowPosition)}; internal BOOL CALLBACK win32_find_4coder_window(HWND Window, LPARAM LParam) { BOOL Result = TRUE; - + char TestClassName[256]; GetClassName(Window, TestClassName, sizeof(TestClassName)); if((strcmp("4coder-win32-wndclass", TestClassName) == 0) && @@ -1424,7 +1422,7 @@ internal BOOL CALLBACK win32_find_4coder_window(HWND Window, LPARAM LParam) GlobalWindowHandle = Window; Result = FALSE; } - + return(Result); } @@ -1435,21 +1433,21 @@ win32_toggle_fullscreen(void) // NOTE(casey): This follows Raymond Chen's prescription // for fullscreen toggling, see: // http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx - + HWND Window = GlobalWindowHandle; DWORD Style = GetWindowLong(Window, GWL_STYLE); if(Style & WS_OVERLAPPEDWINDOW) { MONITORINFO MonitorInfo = {sizeof(MonitorInfo)}; if(GetWindowPlacement(Window, &GlobalWindowPosition) && - GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), &MonitorInfo)) + GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), &MonitorInfo)) { SetWindowLong(Window, GWL_STYLE, Style & ~WS_OVERLAPPEDWINDOW); SetWindowPos(Window, HWND_TOP, - MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top, - MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left, - MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top, - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top, + MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left, + MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top, + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } } else @@ -1457,8 +1455,8 @@ win32_toggle_fullscreen(void) SetWindowLong(Window, GWL_STYLE, Style | WS_OVERLAPPEDWINDOW); SetWindowPlacement(Window, &GlobalWindowPosition); SetWindowPos(Window, 0, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } #else ShowWindow(GlobalWindowHandle, SW_MAXIMIZE); @@ -1477,10 +1475,10 @@ HOOK_SIG(casey_start) exec_command(app, open_panel_vsplit); exec_command(app, hide_scrollbar); exec_command(app, change_active_panel); - + change_theme(app, literal("Handmade Hero")); change_font(app, literal("Liberation Mono"), true); - + Theme_Color colors[] = { {Stag_Default, 0xA08563}, @@ -1514,9 +1512,9 @@ HOOK_SIG(casey_start) // {Stag_Next_Undo, }, }; set_theme_colors(app, colors, ArrayCount(colors)); - + win32_toggle_fullscreen(); - + return(0); } @@ -1524,14 +1522,14 @@ extern "C" GET_BINDING_DATA(get_bindings) { Bind_Helper context_actual = begin_bind_helper(data, size); Bind_Helper *context = &context_actual; - + set_hook(context, hook_start, casey_start); set_command_caller(context, default_command_caller); set_open_file_hook(context, casey_file_settings); set_scroll_rule(context, casey_smooth_scroll_rule); - + EnumWindows(win32_find_4coder_window, 0); - + begin_map(context, mapid_global); { bind(context, 'z', MDFR_NONE, cmdid_interactive_open); @@ -1542,28 +1540,28 @@ extern "C" GET_BINDING_DATA(get_bindings) bind(context, key_page_up, MDFR_NONE, search); bind(context, key_page_down, MDFR_NONE, reverse_search); bind(context, 'm', MDFR_NONE, casey_save_and_make_without_asking); - + // NOTE(allen): Added this so mouse would keep working rougly as before. // Of course now there could be a modal click behavior if that will be useful. // As well as right click. bind(context, key_mouse_left, MDFR_NONE, click_set_cursor); } end_map(context); - + begin_map(context, mapid_file); - + bind_vanilla_keys(context, write_character); - + bind(context, key_insert, MDFR_NONE, begin_free_typing); bind(context, '`', MDFR_NONE, begin_free_typing); bind(context, key_esc, MDFR_NONE, end_free_typing); bind(context, '\n', MDFR_NONE, casey_newline_and_indent); bind(context, '\n', MDFR_SHIFT, casey_newline_and_indent); - + // 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); @@ -1600,7 +1598,7 @@ extern "C" GET_BINDING_DATA(get_bindings) 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); @@ -1613,42 +1611,42 @@ extern "C" GET_BINDING_DATA(get_bindings) 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_back, MDFR_SHIFT, modal_backspace); - + bind(context, key_up, MDFR_NONE, modal_up); bind(context, key_up, MDFR_SHIFT, modal_up); - + bind(context, key_down, MDFR_NONE, modal_down); bind(context, key_down, MDFR_SHIFT, modal_down); - + bind(context, key_left, MDFR_NONE, modal_left); bind(context, key_left, MDFR_SHIFT, modal_left); - + bind(context, key_right, MDFR_NONE, modal_right); bind(context, key_right, MDFR_SHIFT, modal_right); - + bind(context, key_del, MDFR_NONE, modal_delete); bind(context, key_del, MDFR_SHIFT, modal_delete); - + bind(context, key_home, MDFR_NONE, modal_home); bind(context, key_home, MDFR_SHIFT, modal_home); - + bind(context, key_end, MDFR_NONE, modal_end); bind(context, key_end, MDFR_SHIFT, modal_end); - + bind(context, key_page_up, MDFR_NONE, modal_page_up); bind(context, key_page_up, MDFR_SHIFT, modal_page_up); - + bind(context, key_page_down, MDFR_NONE, modal_page_down); bind(context, key_page_down, MDFR_SHIFT, modal_page_down); - + bind(context, '\t', MDFR_NONE, modal_tab); bind(context, '\t', MDFR_SHIFT, modal_tab); - + end_map(context); - + end_bind_helper(context); return context->write_total; } \ No newline at end of file diff --git a/power/4coder_experiments.cpp b/power/4coder_experiments.cpp index dc729fb2..812fd754 100644 --- a/power/4coder_experiments.cpp +++ b/power/4coder_experiments.cpp @@ -1,9 +1,16 @@ +/* +4coder_experiments.cpp - Supplies extension bindings to the defaults with experimental new features. + +TYPE: 'build-target' +*/ // TOP -#include "4coder_default_include.cpp" +#if !defined(FCODER_EXPERIMENTS_CPP) +#define FCODER_EXPERIMENTS_CPP -#include "4coder_function_list.cpp" +#include "4coder_default_include.cpp" +#include "4coder_miblo_numbers.cpp" #define NO_BINDING #include "4coder_default_bindings.cpp" @@ -12,8 +19,6 @@ # define BIND_4CODER_TESTS(context) ((void)context) #endif -#include "4coder_miblo_numbers.cpp" - #include static float @@ -108,8 +113,8 @@ multi-cursor showing but it is unclear to me how to do that conveniently. Since this won't exist inside a coroutine what does such an API even look like??? It's clear to me now that I may need to start pushing for the view routine before -I am even able to support the GUI. Because that will the -system up to allow me to think about the problem in more ways. +I am even able to support the GUI. Because that will set up the +system to allow me to think about the problem in more ways. Finally I have decided not to pursue this direction any more, it just seems like the wrong way to do it, so I'll stop without @@ -540,7 +545,7 @@ view_set_to_region(Application_Links *app, View_Summary *view, int32_t major_pos static float scope_center_threshold = 0.75f; -CUSTOM_COMMAND_SIG(highlight_surroundng_scope){ +CUSTOM_COMMAND_SIG(highlight_surrounding_scope){ uint32_t access = AccessProtected; View_Summary view = get_active_view(app, access); Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); @@ -714,6 +719,334 @@ CUSTOM_COMMAND_SIG(place_in_scope){ } } +CUSTOM_COMMAND_SIG(delete_current_scope){ + uint32_t access = AccessOpen; + View_Summary view = get_active_view(app, access); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + + int32_t top = view.cursor.pos; + int32_t bottom = view.mark.pos; + + if (top > bottom){ + int32_t x = top; + top = bottom; + bottom = x; + } + + if (buffer_get_char(app, &buffer, top) == '{' && buffer_get_char(app, &buffer, bottom-1) == '}'){ + int32_t top_len = 1; + int32_t bottom_len = 1; + if (buffer_get_char(app, &buffer, top-1) == '\n'){ + top_len = 2; + } + if (buffer_get_char(app, &buffer, bottom+1) == '\n'){ + bottom_len = 2; + } + + Buffer_Edit edits[2]; + edits[0].str_start = 0; + edits[0].len = 0; + edits[0].start = top+1 - top_len; + edits[0].end = top+1; + + edits[1].str_start = 0; + edits[1].len = 0; + edits[1].start = bottom-1; + edits[1].end = bottom-1 + bottom_len; + + buffer_batch_edit(app, &buffer, 0, 0, edits, 2, BatchEdit_Normal); + } +} + +struct Statement_Parser{ + Stream_Tokens stream; + int32_t token_index; + Buffer_Summary *buffer; +}; + +static Cpp_Token* +parser_next_token(Statement_Parser *parser){ + Cpp_Token *result = 0; + bool32 still_looping = true; + while (parser->token_index >= parser->stream.end && still_looping){ + still_looping = forward_stream_tokens(&parser->stream); + } + if (parser->token_index < parser->stream.end){ + result = &parser->stream.tokens[parser->token_index]; + ++parser->token_index; + } + return(result); +} + +static bool32 parse_statement_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out); + +static bool32 +parse_for_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out){ + bool32 success = false; + Cpp_Token *token = parser_next_token(parser); + + int32_t paren_level = 0; + while (token != 0){ + if (!(token->flags & CPP_TFLAG_PP_BODY)){ + switch (token->type){ + case CPP_TOKEN_PARENTHESE_OPEN: + { + ++paren_level; + }break; + + case CPP_TOKEN_PARENTHESE_CLOSE: + { + --paren_level; + if (paren_level == 0){ + success = parse_statement_down(app, parser, token_out); + goto finished; + } + else if (paren_level < 0){ + success = false; + goto finished; + } + }break; + } + } + + token = parser_next_token(parser); + } + + finished:; + return(success); +} + +static bool32 +parse_if_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out){ + bool32 success = false; + Cpp_Token *token = parser_next_token(parser); + + if (token != 0){ + success = parse_statement_down(app, parser, token_out); + if (success){ + token = parser_next_token(parser); + if (token != 0 && token->type == CPP_TOKEN_KEY_CONTROL_FLOW){ + char lexeme[32]; + if (sizeof(lexeme)-1 >= token->size){ + if (buffer_read_range(app, parser->buffer, token->start, token->start + token->size, lexeme)){ + lexeme[token->size] = 0; + if (match(lexeme, "else")){ + success = parse_statement_down(app, parser, token_out); + } + } + } + } + } + } + + return(success); +} + +static bool32 +parse_block_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out){ + bool32 success = false; + Cpp_Token *token = parser_next_token(parser); + + int32_t nest_level = 0; + while (token != 0){ + switch (token->type){ + case CPP_TOKEN_BRACE_OPEN: + { + ++nest_level; + }break; + + case CPP_TOKEN_BRACE_CLOSE: + { + if (nest_level == 0){ + *token_out = *token; + success = true; + goto finished; + } + --nest_level; + }break; + } + token = parser_next_token(parser); + } + + finished:; + return(success); +} + +static bool32 +parse_statement_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out){ + bool32 success = false; + Cpp_Token *token = parser_next_token(parser); + + if (token != 0){ + bool32 not_getting_block = false; + + do{ + switch (token->type){ + case CPP_TOKEN_BRACE_CLOSE: + { + goto finished; + }break; + + case CPP_TOKEN_KEY_CONTROL_FLOW: + { + char lexeme[32]; + if (sizeof(lexeme)-1 >= token->size){ + if (buffer_read_range(app, parser->buffer, token->start, token->start + token->size, lexeme)){ + lexeme[token->size] = 0; + if (match(lexeme, "for")){ + success = parse_for_down(app, parser, token_out); + goto finished; + } + else if (match(lexeme, "if")){ + success = parse_if_down(app, parser, token_out); + goto finished; + } + else if (match(lexeme, "else")){ + success = false; + goto finished; + } + } + } + }break; + + case CPP_TOKEN_BRACE_OPEN: + { + if (!not_getting_block){ + success = parse_block_down(app, parser, token_out); + goto finished; + } + }break; + + case CPP_TOKEN_SEMICOLON: + { + success = true; + *token_out = *token; + goto finished; + }break; + + case CPP_TOKEN_EQ: + { + not_getting_block = true; + }break; + } + + token = parser_next_token(parser); + }while(token != 0); + } + + finished:; + return(success); +} + +static bool32 +find_whole_statement_down(Application_Links *app, Buffer_Summary *buffer, int32_t pos, int32_t *start_out, int32_t *end_out){ + bool32 result = false; + int32_t start = pos; + int32_t end = start; + + Cpp_Get_Token_Result get_result = {0}; + + if (buffer_get_token_index(app, buffer, pos, &get_result)){ + Statement_Parser parser = {0}; + parser.token_index = get_result.token_index; + + if (parser.token_index < 0){ + parser.token_index = 0; + } + if (get_result.in_whitespace){ + parser.token_index += 1; + } + + static const int32_t chunk_cap = 512; + Cpp_Token chunk[chunk_cap]; + + if (init_stream_tokens(&parser.stream, app, buffer, parser.token_index, chunk, chunk_cap)){ + parser.buffer = buffer; + + Cpp_Token end_token = {0}; + if (parse_statement_down(app, &parser, &end_token)){ + end = end_token.start + end_token.size; + result = true; + } + } + } + + *start_out = start; + *end_out = end; + return(result); +} + +CUSTOM_COMMAND_SIG(scope_absorb_down){ + uint32_t access = AccessOpen; + View_Summary view = get_active_view(app, access); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + + int32_t top = view.cursor.pos; + int32_t bottom = view.mark.pos; + + if (top > bottom){ + int32_t x = top; + top = bottom; + bottom = x; + } + + Partition *part = &global_part; + + Temp_Memory temp = begin_temp_memory(part); + if (buffer_get_char(app, &buffer, top) == '{' && buffer_get_char(app, &buffer, bottom-1) == '}'){ + Range range; + if (find_whole_statement_down(app, &buffer, bottom, &range.start, &range.end)){ + char *string_space = push_array(part, char, range.end - range.start); + buffer_read_range(app, &buffer, range.start, range.end, string_space); + + String string = make_string(string_space, range.end - range.start); + string = skip_chop_whitespace(string); + + int32_t newline_count = 0; + for (char *ptr = string_space; ptr < string.str; ++ptr){ + if (*ptr == '\n'){ + ++newline_count; + } + } + + bool32 extra_newline = false; + if (newline_count >= 2){ + extra_newline = true; + } + + int32_t edit_len = string.size + 1; + if (extra_newline){ + edit_len += 1; + } + + char *edit_str = push_array(part, char, edit_len); + if (extra_newline){ + edit_str[0] = '\n'; + copy_fast_unsafe(edit_str+1, string); + edit_str[edit_len-1] = '\n'; + } + else{ + copy_fast_unsafe(edit_str, string); + edit_str[edit_len-1] = '\n'; + } + + Buffer_Edit edits[2]; + edits[0].str_start = 0; + edits[0].len = edit_len; + edits[0].start = bottom-1; + edits[0].end = bottom-1; + + edits[1].str_start = 0; + edits[1].len = 0; + edits[1].start = range.start; + edits[1].end = range.end; + + buffer_batch_edit(app, &buffer, edit_str, edit_len, edits, 2, BatchEdit_Normal); + } + } + end_temp_memory(temp); +} + // NOTE(allen): Some basic code manipulation ideas. CUSTOM_COMMAND_SIG(rename_parameter){ @@ -890,17 +1223,17 @@ CUSTOM_COMMAND_SIG(write_explicit_enum_values){ ++token_index; - int32_t closed_correctly = 0; int32_t seeker_index = token_index; Stream_Tokens seek_stream = begin_temp_stream_token(&stream); - int32_t still_looping = 0; + bool32 closed_correctly = false; + bool32 still_looping = false; do{ for (; seeker_index < stream.end; ++seeker_index){ Cpp_Token *token_seeker = stream.tokens + seeker_index; switch (token_seeker->type){ case CPP_TOKEN_BRACE_CLOSE: - closed_correctly = 1; + closed_correctly = true; goto finished_seek; case CPP_TOKEN_BRACE_OPEN: @@ -915,15 +1248,15 @@ CUSTOM_COMMAND_SIG(write_explicit_enum_values){ if (closed_correctly){ int32_t count_estimate = 1 + (seeker_index - token_index)/2; - Buffer_Edit *edits = push_array(part, Buffer_Edit, count_estimate); int32_t edit_count = 0; + Buffer_Edit *edits = push_array(part, Buffer_Edit, count_estimate); char *string_base = (char*)partition_current(part); String string = make_string(string_base, 0, partition_remaining(part)); + closed_correctly = false; + still_looping = false; int32_t value = 0; - closed_correctly = 0; - still_looping = 0; do{ for (;token_index < stream.end; ++token_index){ Cpp_Token *token_ptr = stream.tokens + token_index; @@ -1016,12 +1349,12 @@ get_bindings(void *data, int32_t size){ Bind_Helper context_ = begin_bind_helper(data, size); Bind_Helper *context = &context_; - set_hook(context, hook_start, my_start); - set_hook(context, hook_view_size_change, my_view_adjust); + set_hook(context, hook_start, default_start); + set_hook(context, hook_view_size_change, default_view_adjust); - set_open_file_hook(context, my_file_settings); - set_save_file_hook(context, my_file_save); - set_input_filter(context, my_suppress_mouse_filter); + set_open_file_hook(context, default_file_settings); + set_save_file_hook(context, default_file_save); + set_input_filter(context, default_suppress_mouse_filter); set_command_caller(context, default_command_caller); set_scroll_rule(context, smooth_scroll_rule); @@ -1048,14 +1381,17 @@ get_bindings(void *data, int32_t size){ end_map(context); - begin_map(context, my_code_map); - bind(context, '[', MDFR_ALT, highlight_surroundng_scope); + begin_map(context, default_code_map); + bind(context, '[', MDFR_ALT, highlight_surrounding_scope); bind(context, ']', MDFR_ALT, highlight_prev_scope_absolute); bind(context, '\'', MDFR_ALT, highlight_next_scope_absolute); + bind(context, '/', MDFR_ALT, place_in_scope); + bind(context, '-', MDFR_ALT, delete_current_scope); + bind(context, 'j', MDFR_ALT, scope_absorb_down); + bind(context, key_insert, MDFR_CTRL, write_explicit_enum_values); bind(context, 'p', MDFR_ALT, rename_parameter); - bind(context, 'I', MDFR_CTRL, list_all_functions_current_buffer); end_map(context); BIND_4CODER_TESTS(context); @@ -1064,5 +1400,7 @@ get_bindings(void *data, int32_t size){ return(result); } +#endif + // BOTTOM diff --git a/power/4coder_miblo_numbers.cpp b/power/4coder_miblo_numbers.cpp index 15d53e07..803e9dad 100644 --- a/power/4coder_miblo_numbers.cpp +++ b/power/4coder_miblo_numbers.cpp @@ -1,8 +1,18 @@ +/* +4coder_miblo_numbers.cpp - Commands for so called "Miblo Number Operations" which involve incrementing +and decrementing various forms of number as numerical objects despite being encoded as text objects. -#if !defined(MIBLO_NUMBERS_4CODER) -#define MIBLO_NUMBERS_4CODER +TYPE: 'drop-in-command-pack' +*/ -// TODO(allen): thevaber number converter idea +// TOP + +#if !defined(FCODER_MIBLO_NUMBERS_CPP) +#define FCODER_MIBLO_NUMBERS_CPP + +#include "4coder_API/custom.h" +#include "4coder_helper/4coder_helper.h" +#include "4coder_helper/4coder_streaming.h" static int32_t get_numeric_string_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t start_pos, int32_t *numeric_start, int32_t *numeric_end){ @@ -198,14 +208,14 @@ increment_timestamp(Miblo_Timestamp t, int32_t type, int32_t amt){ amt = 0; // TODO(allen): someday do the math, instead of being lazy. - while (r.second < 0){ - --amt; - r.second += 60; + while (r.second < 0){ + --amt; + r.second += 60; } - while (r.second >= 60){ - ++amt; - r.second -= 60; + while (r.second >= 60){ + ++amt; + r.second -= 60; } case MIBLO_MINUTE: @@ -236,7 +246,7 @@ timestamp_to_str(String *dest, Miblo_Timestamp t){ if (t.hour > 0){ append_int_to_str(dest, t.hour); - append(dest, ":"); + append(dest, ":"); } if (t.minute >= 10){ @@ -279,7 +289,7 @@ get_timestamp_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t int32_t count_colons = 0; for (int32_t i = 0; i < str.size; ++i){ if (str.str[i] == ':'){ - ++count_colons; + ++count_colons; } } @@ -305,19 +315,19 @@ get_timestamp_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t } if (count_colons == 2){ - t.hour = str_to_int(make_string(str.str + number_start[0], number_end[0] - number_start[0])); - - if (number_end[1] - number_start[1] == 2){ - - t.minute = str_to_int(make_string(str.str + number_start[1], number_end[1] - number_start[1])); - - if (number_end[2] - number_start[2] == 2){ - t.second = str_to_int(make_string(str.str + number_start[2], number_end[2] - number_start[2])); + t.hour = str_to_int(make_string(str.str + number_start[0], number_end[0] - number_start[0])); + + if (number_end[1] - number_start[1] == 2){ - success = 1; + t.minute = str_to_int(make_string(str.str + number_start[1], number_end[1] - number_start[1])); + + if (number_end[2] - number_start[2] == 2){ + t.second = str_to_int(make_string(str.str + number_start[2], number_end[2] - number_start[2])); + + success = 1; + } } } - } else{ if (number_end[0] - number_start[0] == 2 || number_end[0] - number_start[0] == 1){ t.minute = str_to_int(make_string(str.str + number_start[0], number_end[0] - number_start[0])); @@ -331,10 +341,10 @@ get_timestamp_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t } if (success){ - info->start = timestamp_start; - info->end = timestamp_end; - info->time = t; - result = 1; + info->start = timestamp_start; + info->end = timestamp_end; + info->time = t; + result = 1; } } } @@ -378,4 +388,4 @@ CUSTOM_COMMAND_SIG(miblo_decrement_time_stamp_minute){ #endif - +// BOTTOM diff --git a/project.4coder b/project.4coder index 39cda7cd..c12965db 100644 --- a/project.4coder +++ b/project.4coder @@ -3,33 +3,14 @@ extensions=".c.cpp.h.hpp.bat.sh"; fkey_command_win[1] = {"build.bat", "*compilation*", true}; fkey_command_win[2] = {"site\\build.bat", "*compilation*", true}; fkey_command_win[3] = {"string\\build.bat", "*compilation*", true}; -fkey_command_win[4] = {0, 0}; + fkey_command_win[5] = {"..\\misc\\run.bat", "*run*"}; -fkey_command_win[6] = {0, 0}; -fkey_command_win[7] = {0, 0}; -fkey_command_win[8] = {0, 0}; -fkey_command_win[9] = {0, 0}; -fkey_command_win[10] = {0, 0}; -fkey_command_win[11] = {0, 0}; -fkey_command_win[8] = {"package.bat", "*package*"}; -fkey_command_win[13] = {0, 0}; -fkey_command_win[14] = {0, 0}; -fkey_command_win[15] = {0, 0}; -fkey_command_win[16] = {0, 0}; + +fkey_command_win[12] = {"package.bat", "*package*"}; fkey_command_linux[1] = {"./build.sh", "*compilation*", true}; fkey_command_linux[2] = {"site/build.sh", "*compilation*", true}; -fkey_command_linux[3] = {0, 0}; -fkey_command_linux[4] = {0, 0}; + fkey_command_linux[5] = {"../build/4ed", "*run*"}; -fkey_command_linux[6] = {0, 0}; -fkey_command_linux[7] = {0, 0}; -fkey_command_linux[8] = {0, 0}; -fkey_command_linux[9] = {0, 0}; -fkey_command_linux[10] = {0, 0}; -fkey_command_linux[11] = {0, 0}; + fkey_command_linux[12] = {"./package.sh", "*package*"}; -fkey_command_linux[13] = {0, 0}; -fkey_command_linux[14] = {0, 0}; -fkey_command_linux[15] = {0, 0}; -fkey_command_linux[16] = {0, 0}; diff --git a/string/4coder_string_build_num.txt b/string/4coder_string_build_num.txt index 34184db2..fb61d50d 100644 --- a/string/4coder_string_build_num.txt +++ b/string/4coder_string_build_num.txt @@ -1,5 +1,5 @@ 1 0 -59 +61 diff --git a/string/_4coder_string.ctm b/string/_4coder_string.ctm index c333a406..97e7ccb8 100644 Binary files a/string/_4coder_string.ctm and b/string/_4coder_string.ctm differ diff --git a/string/internal_4coder_string.cpp b/string/internal_4coder_string.cpp index 43364683..41a05ce0 100644 --- a/string/internal_4coder_string.cpp +++ b/string/internal_4coder_string.cpp @@ -230,6 +230,20 @@ considered immutable.) DOC_SEE(substr) */{ return(result); } +CPP_NAME(skip_whitespace) +API_EXPORT FSTRING_LINK String +skip_whitespace_measure(String str, i32_4tech *skip_length) +/* DOC(This call creates a substring that starts with the first non-whitespace character of str. +Like other substr calls, the new string uses the underlying memory and so should usually be +considered immutable.) DOC_SEE(substr) */{ + String result = {0}; + i32_4tech i = 0; + for (; i < str.size && char_is_whitespace(str.str[i]); ++i); + result = substr(str, i, str.size - i); + *skip_length = i; + return(result); +} + API_EXPORT FSTRING_LINK String chop_whitespace(String str) /* DOC(This call creates a substring that ends with the last non-whitespace character of str. @@ -251,6 +265,16 @@ DOC_SEE(skip_whitespace) DOC_SEE(chop_whitespace)*/{ return(str); } +CPP_NAME(skip_chop_whitespace) +API_EXPORT FSTRING_LINK String +skip_chop_whitespace_measure(String str, i32_4tech *skip_length) +/* DOC(This call is equivalent to calling skip_whitespace and chop_whitespace together.) +DOC_SEE(skip_whitespace) DOC_SEE(chop_whitespace)*/{ + str = skip_whitespace_measure(str, skip_length); + str = chop_whitespace(str); + return(str); +} + API_EXPORT_INLINE FSTRING_INLINE String tailstr(String str) /* DOC(This call returns an empty String with underlying memory taken from @@ -1880,7 +1904,7 @@ static void get_absolutes(String name, Absolutes *absolutes, b32_4tech implicit_first, b32_4tech implicit_last){ if (name.size != 0){ i32_4tech count = 0; - i32_4tech max = ArrayCount(absolutes->a) - 1; + i32_4tech max = (sizeof(absolutes->a)/sizeof(*absolutes->a)) - 1; if (implicit_last) --max; String str; diff --git a/win32_4ed.cpp b/win32_4ed.cpp index c041ce13..25d0b473 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -38,6 +38,7 @@ #include #include +#include "win32_gl.h" #define GL_TEXTURE_MAX_LEVEL 0x813D @@ -594,7 +595,7 @@ Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){ system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); void *old_data = memory->data; i32 old_size = memory->size; - i32 new_size = l_round_up(memory->size*2, KB(4)); + i32 new_size = l_round_up_i32(memory->size*2, KB(4)); memory->data = system_get_memory(new_size); memory->size = new_size; if (old_data){ @@ -1575,6 +1576,148 @@ Win32Resize(i32 width, i32 height){ } } +internal void* +win32_load_gl_always(char *name, HMODULE module){ + void *p = (void *)wglGetProcAddress(name), *r = 0; + if(p == 0 || + (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || + (p == (void*)-1) ){ + r = (void *)GetProcAddress(module, name); + } + else{ + r = p; + } + return(r); +} + +internal void +OpenGLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam) +{ + OutputDebugStringA(message); + OutputDebugStringA("\n"); +} + +internal void +Win32InitGL(){ + // GL context initialization + { + PIXELFORMATDESCRIPTOR format; + int format_id; + BOOL success; + HDC dc; + + format.nSize = sizeof(format); + format.nVersion = 1; + format.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + format.iPixelType = PFD_TYPE_RGBA; + format.cColorBits = 32; + format.cRedBits = 0; + format.cRedShift = 0; + format.cGreenBits = 0; + format.cGreenShift = 0; + format.cBlueBits = 0; + format.cBlueShift = 0; + format.cAlphaBits = 0; + format.cAlphaShift = 0; + format.cAccumBits = 0; + format.cAccumRedBits = 0; + format.cAccumGreenBits = 0; + format.cAccumBlueBits = 0; + format.cAccumAlphaBits = 0; + format.cDepthBits = 24; + format.cStencilBits = 8; + format.cAuxBuffers = 0; + format.iLayerType = PFD_MAIN_PLANE; + format.bReserved = 0; + format.dwLayerMask = 0; + format.dwVisibleMask = 0; + format.dwDamageMask = 0; + + dc = GetDC(win32vars.window_handle); + Assert(dc); + format_id = ChoosePixelFormat(dc, &format); + Assert(format_id != 0); + success = SetPixelFormat(dc, format_id, &format); + Assert(success == TRUE); + + HGLRC glcontext = wglCreateContext(dc); + wglMakeCurrent(dc, glcontext); + + { + HMODULE module = LoadLibraryA("opengl32.dll"); + + wglCreateContextAttribsARB_Function *wglCreateContextAttribsARB = 0; + wglCreateContextAttribsARB = (wglCreateContextAttribsARB_Function*) + win32_load_gl_always("wglCreateContextAttribsARB", module); + + wglChoosePixelFormatARB_Function *wglChoosePixelFormatARB = 0; + wglChoosePixelFormatARB = (wglChoosePixelFormatARB_Function*) + win32_load_gl_always("wglChoosePixelFormatARB", module); + + if (wglCreateContextAttribsARB != 0 && wglChoosePixelFormatARB != 0){ + const int choosePixel_attribList[] = + { + WGL_DRAW_TO_WINDOW_ARB, TRUE, + WGL_SUPPORT_OPENGL_ARB, TRUE, + //WGL_DOUBLE_BUFFER_ARB, GL_TRUE, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_COLOR_BITS_ARB, 32, + WGL_DEPTH_BITS_ARB, 24, + WGL_STENCIL_BITS_ARB, 8, + 0, + }; + + i32 extended_format_id; + UINT num_formats = 0; + BOOL result = 0; + + result = wglChoosePixelFormatARB(dc, choosePixel_attribList, 0, 1, &extended_format_id, &num_formats); + + if (result != 0 && num_formats > 0){ + const int createContext_attribList[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 2, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + 0 + }; + + if (extended_format_id == format_id){ + HGLRC extended_context = wglCreateContextAttribsARB(dc, 0, createContext_attribList); + if (extended_context){ + wglMakeCurrent(dc, extended_context); + wglDeleteContext(glcontext); + glcontext = extended_context; + } + } + } + } + } + + ReleaseDC(win32vars.window_handle, dc); + } + +#if FRED_INTERNAL + // NOTE(casey): This slows down GL but puts error messages to + // the debug console immediately whenever you do something wrong + glDebugMessageCallback_type *glDebugMessageCallback = + (glDebugMessageCallback_type *)wglGetProcAddress("glDebugMessageCallback"); + glDebugMessageControl_type *glDebugMessageControl = + (glDebugMessageControl_type *)wglGetProcAddress("glDebugMessageControl"); + if(glDebugMessageCallback && glDebugMessageControl) + { + glDebugMessageCallback(OpenGLDebugCallback, 0); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + } +#endif + + glEnable(GL_TEXTURE_2D); + glEnable(GL_SCISSOR_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + internal void Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ switch (cursor){ @@ -1602,6 +1745,120 @@ Win32HighResolutionTime(){ return(result); } +internal void +Win32Foo(WPARAM wParam, LPARAM lParam){ + b8 previous_state = ((lParam & Bit_30)?(1):(0)); + b8 current_state = ((lParam & Bit_31)?(0):(1)); + + if (current_state){ + u8 key = keycode_lookup_table[(u8)wParam]; + + i32 *count = &win32vars.input_chunk.trans.key_data.count; + Key_Event_Data *data = win32vars.input_chunk.trans.key_data.keys; + b8 *control_keys = win32vars.input_chunk.pers.control_keys; + i32 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]; + BYTE control_state = 0; + WORD x1 = 0, x2 = 0, x = 0, junk_x; + i32 result1 = 0, result2 = 0, result = 0; + + GetKeyboardState(state); + x1 = 0; + result1 = ToAscii(vk, scan, state, &x1, 0); + if (result1 < 0){ + ToAscii(vk, scan, state, &junk_x, 0); + } + result1 = (result1 == 1); + if (!usable_ascii((char)x1)){ + result1 = 0; + } + + control_state = state[VK_CONTROL]; + state[VK_CONTROL] = 0; + x2 = 0; + result2 = ToAscii(vk, scan, state, &x2, 0); + if (result2 < 0){ + ToAscii(vk, scan, state, &junk_x, 0); + } + result2 = (result2 == 1); + if (!usable_ascii((char)x2)){ + result2 = 0; + } + + // TODO(allen): This is becoming a really major issue. + // Apparently control + i outputs a '\t' which is VALID ascii + // according to this system. So it reports the key as '\t'. + // This wasn't an issue before because we were ignoring control + // when computing character_no_caps_lock which is what is used + // for commands. But that is incorrect for some keyboard layouts + // where control+alt is used to signal AltGr for important keys. + if (result1 && result2){ + char c1 = char_to_upper((char)x1); + char cParam = char_to_upper((char)wParam); + + if ((c1 == '\n' || c1 == '\r') && cParam != VK_RETURN){ + result1 = 0; + } + if (c1 == '\t' && cParam != VK_TAB){ + result1 = 0; + } + } + + if (result1){ + x = x1; + state[VK_CONTROL] = control_state; + result = 1; + } + else if (result2){ + x = x2; + result = 1; + } + + 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 < 0){ + ToAscii(vk, scan, state, &junk_x, 0); + } + result = (result == 1); + if (!usable_ascii((char)x)){ + result = 0; + } + + if (result){ + 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); + data[*count].modifiers[MDFR_HOLD_INDEX] = previous_state; + ++(*count); + } + } +} internal LRESULT @@ -1609,8 +1866,7 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ LRESULT result = 0; switch (uMsg){ - case WM_MENUCHAR: - case WM_SYSCHAR:break; + case WM_MENUCHAR:break; case WM_SYSKEYDOWN: case WM_SYSKEYUP: @@ -1648,9 +1904,8 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ }break; } - b8 ctrl, alt; - ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); - alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); + b8 ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); + b8 alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); if (win32vars.lctrl_lalt_is_altgr){ if (controls->l_alt && controls->l_ctrl){ @@ -1666,136 +1921,71 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ default: { - b8 previous_state = ((lParam & Bit_30)?(1):(0)); b8 current_state = ((lParam & Bit_31)?(0):(1)); - win32vars.got_useful_event = 1; - if (current_state){ u8 key = keycode_lookup_table[(u8)wParam]; - i32 *count = 0; - Key_Event_Data *data = 0; - b8 *control_keys = 0; - i32 control_keys_size = 0; - - 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]; - BYTE control_state = 0; - WORD x1 = 0, x2 = 0, x = 0, junk_x; - i32 result1 = 0, result2 = 0, result = 0; - - GetKeyboardState(state); - x1 = 0; - result1 = ToAscii(vk, scan, state, &x1, 0); - if (result1 < 0){ - ToAscii(vk, scan, state, &junk_x, 0); - } - result1 = (result1 == 1); - if (!usable_ascii((char)x1)){ - result1 = 0; - } - - control_state = state[VK_CONTROL]; - state[VK_CONTROL] = 0; - x2 = 0; - result2 = ToAscii(vk, scan, state, &x2, 0); - if (result2 < 0){ - ToAscii(vk, scan, state, &junk_x, 0); - } - result2 = (result2 == 1); - if (!usable_ascii((char)x2)){ - result2 = 0; - } - - // TODO(allen): This is becoming a really major issue. - // Apparently control + i outputs a '\t' which is VALID ascii - // according to this system. So it reports the key as '\t'. - // This wasn't an issue before because we were ignoring control - // when computing character_no_caps_lock which is what is used - // for commands. But that is incorrect for some keyboard layouts - // where control+alt is used to signal AltGr for important keys. - if (result1 && result2){ - char c1 = char_to_upper((char)x1); - char cParam = char_to_upper((char)wParam); - - if ((c1 == '\n' || c1 == '\r') && cParam != VK_RETURN){ - result1 = 0; - } - if (c1 == '\t' && cParam != VK_TAB){ - result1 = 0; - } - } - - if (result1){ - x = x1; - state[VK_CONTROL] = control_state; - result = 1; - } - else if (result2){ - x = x2; - result = 1; - } - - 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 < 0){ - ToAscii(vk, scan, state, &junk_x, 0); - } - result = (result == 1); - if (!usable_ascii((char)x)){ - result = 0; - } - - if (result){ - 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; - } + if (key != 0){ + i32 *count = &win32vars.input_chunk.trans.key_data.count; + Key_Event_Data *data = win32vars.input_chunk.trans.key_data.keys; + b8 *control_keys = win32vars.input_chunk.pers.control_keys; + i32 control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys); + + Assert(*count < KEY_INPUT_BUFFER_SIZE); + data[*count].character = 0; + data[*count].character_no_caps_lock = 0; + data[*count].keycode = key; memcpy(data[*count].modifiers, control_keys, control_keys_size); - data[*count].modifiers[MDFR_HOLD_INDEX] = previous_state; ++(*count); + + win32vars.got_useful_event = 1; } } - - result = DefWindowProc(hwnd, uMsg, wParam, lParam); }break; }/* switch */ }break; + case WM_CHAR: case WM_SYSCHAR: case WM_UNICHAR: + { + u8 character = wParam & 0x7F; + + if (character == '\r'){ + character = '\n'; + } + else if ((character < 32 && character != '\t') || character == 127){ + break; + } + + u8 character_no_caps_lock = character; + + i32 *count = &win32vars.input_chunk.trans.key_data.count; + Key_Event_Data *data = win32vars.input_chunk.trans.key_data.keys; + b8 *control_keys = win32vars.input_chunk.pers.control_keys; + i32 control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys); + + BYTE state[256]; + GetKeyboardState(state); + if (state[VK_CAPITAL]){ + if (character_no_caps_lock >= 'a' && character_no_caps_lock <= 'z'){ + character_no_caps_lock += (u8)('A' - 'a'); + } + else if (character_no_caps_lock >= 'A' && character_no_caps_lock <= 'Z'){ + character_no_caps_lock += (u8)('a' - 'A'); + } + } + + Assert(*count < KEY_INPUT_BUFFER_SIZE); + data[*count].character = character; + data[*count].character_no_caps_lock = character_no_caps_lock; + data[*count].keycode = character_no_caps_lock; + memcpy(data[*count].modifiers, control_keys, control_keys_size); + ++(*count); + + result = DefWindowProc(hwnd, uMsg, wParam, lParam); + win32vars.got_useful_event = 1; + }break; + case WM_MOUSEMOVE: { i32 new_x = LOWORD(lParam); @@ -1865,12 +2055,10 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ case WM_SIZE: { win32vars.got_useful_event = 1; - if (win32vars.target.handle){ - i32 new_width = LOWORD(lParam); - i32 new_height = HIWORD(lParam); - - Win32Resize(new_width, new_height); - } + i32 new_width = LOWORD(lParam); + i32 new_height = HIWORD(lParam); + + Win32Resize(new_width, new_height); }break; case WM_PAINT: @@ -1907,21 +2095,6 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ return(result); } -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 -#define GL_DEBUG_OUTPUT 0x92E0 - -typedef void GLDEBUGPROC_TYPE(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char * message, const GLvoid * userParam); -typedef GLDEBUGPROC_TYPE * GLDEBUGPROC; -typedef void glDebugMessageControl_type(GLenum source, GLenum type, GLenum severity, GLsizei count, GLuint * ids, GLboolean enabled); -typedef void glDebugMessageCallback_type(GLDEBUGPROC callback, void * userParam); - -internal void -OpenGLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam) -{ - OutputDebugStringA(message); - OutputDebugStringA("\n"); -} - int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, @@ -2177,65 +2350,9 @@ WinMain(HINSTANCE hInstance, #endif GetClientRect(win32vars.window_handle, &window_rect); - - DWORD pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - - // NOTE(allen): This is probably not an issue on linux and - // does not need to be ported. - if (!win32vars.settings.stream_mode){ - pfd_flags |= PFD_DOUBLEBUFFER; - } - - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - pfd_flags, - PFD_TYPE_RGBA, - 32, - 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 16, - 0, - 0, - PFD_MAIN_PLANE, - 0, - 0, 0, 0 }; - // TODO(allen): get an upgraded context to see if that fixes the nvidia card issues. - { - i32 pixel_format; - pixel_format = ChoosePixelFormat(hdc, &pfd); - SetPixelFormat(hdc, pixel_format, &pfd); - - win32vars.target.handle = hdc; - win32vars.target.context = wglCreateContext(hdc); - wglMakeCurrent(hdc, (HGLRC)win32vars.target.context); - } ReleaseDC(win32vars.window_handle, hdc); -#if FRED_INTERNAL - // NOTE(casey): This slows down GL but puts error messages to - // the debug console immediately whenever you do something wrong - glDebugMessageCallback_type *glDebugMessageCallback = - (glDebugMessageCallback_type *)wglGetProcAddress("glDebugMessageCallback"); - glDebugMessageControl_type *glDebugMessageControl = - (glDebugMessageControl_type *)wglGetProcAddress("glDebugMessageControl"); - if(glDebugMessageCallback && glDebugMessageControl) - { - glDebugMessageCallback(OpenGLDebugCallback, 0); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - } -#endif - - glEnable(GL_TEXTURE_2D); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + Win32InitGL(); Win32Resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); @@ -2316,28 +2433,96 @@ WinMain(HINSTANCE hInstance, if (!(win32vars.first && win32vars.settings.stream_mode)){ system_release_lock(FRAME_LOCK); - if (win32vars.running_cli == 0){ - win32vars.got_useful_event = 0; - for (;win32vars.got_useful_event == 0;){ - if (GetMessage(&msg, 0, 0, 0)){ - if (msg.message == WM_QUIT){ - keep_playing = 0; - }else{ + b32 get_more_messages = true; + do{ + if (win32vars.got_useful_event == 0){ + get_more_messages = GetMessage(&msg, 0, 0, 0); + } + else{ + get_more_messages = PeekMessage(&msg, 0, 0, 0, 1); + } + + if (get_more_messages){ + if (msg.message == WM_QUIT){ + keep_playing = 0; + }else{ + b32 treat_normally = true; + if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN){ + switch (msg.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: treat_normally = false; break; + } + } + + if (treat_normally){ TranslateMessage(&msg); DispatchMessage(&msg); } + else{ + Control_Keys *controls = &win32vars.input_chunk.pers.controls; + + b8 ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); + b8 alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); + + if (win32vars.lctrl_lalt_is_altgr){ + if (controls->l_alt && controls->l_ctrl){ + ctrl = 0; + alt = 0; + } + } + + BYTE ctrl_state = 0, alt_state = 0; + BYTE state[256]; + if (ctrl || alt){ + GetKeyboardState(state); + if (ctrl){ + ctrl_state = state[VK_CONTROL]; + state[VK_CONTROL] = 0; + } + if (alt){ + alt_state = state[VK_MENU]; + state[VK_MENU] = 0; + } + SetKeyboardState(state); + + TranslateMessage(&msg); + DispatchMessage(&msg); + + if (ctrl){ + state[VK_CONTROL] = ctrl_state; + } + if (alt){ + state[VK_MENU] = alt_state; + } + SetKeyboardState(state); + } + else{ + TranslateMessage(&msg); + DispatchMessage(&msg); + } +#if 0 + UINT count = 0; + INPUT in[1]; + if (ctrl){ + in[count].type = INPUT_KEYBOARD; + in[count].ki.wVk = VK_CONTROL; + in[count].ki.wScan = 0; + in[count].ki.dwFlags = KEYEVENTF_KEYUP; + in[count].ki.time = 0; + in[count].ki.dwExtraInfo = GetMessageExtraInfo(); + ++count; + } + if(count > 0){ + SendInput(count, in, sizeof(in)); + } +#endif + } } } - } - - while (PeekMessage(&msg, 0, 0, 0, 1)){ - if (msg.message == WM_QUIT){ - keep_playing = 0; - }else{ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } + }while(get_more_messages); system_acquire_lock(FRAME_LOCK); } @@ -2398,7 +2583,6 @@ WinMain(HINSTANCE hInstance, input.dt = frame_useconds / 1000000.f; input.keys = input_chunk.trans.key_data; - memcpy(input.keys.modifiers, input_chunk.pers.control_keys, sizeof(input_chunk.pers.control_keys)); input.mouse.out_of_window = input_chunk.trans.out_of_window; diff --git a/win32_gl.h b/win32_gl.h new file mode 100644 index 00000000..c5a4a7d6 --- /dev/null +++ b/win32_gl.h @@ -0,0 +1,83 @@ +/* +WGL declarations for 4coder. +By Allen Webster +Created 27.01.2017 (dd.mm.yyyy) +*/ + +// TOP + +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +typedef BOOL wglChoosePixelFormatARB_Function(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +typedef HGLRC wglCreateContextAttribsARB_Function(HDC hDC, HGLRC hshareContext, const int *attribList); + +typedef const char* wglGetExtensionsStringARB_Function(HDC hdc); + +typedef void GLDEBUGPROC_TYPE(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char * message, const GLvoid * userParam); +typedef GLDEBUGPROC_TYPE * GLDEBUGPROC; +typedef void glDebugMessageControl_type(GLenum source, GLenum type, GLenum severity, GLsizei count, GLuint * ids, GLboolean enabled); +typedef void glDebugMessageCallback_type(GLDEBUGPROC callback, void * userParam); + +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_OUTPUT 0x92E0 + +// BOTTOM +