From a690547aa2d1d4814e74cbef7a16d6cf65d0cf11 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Fri, 13 May 2016 15:15:38 -0400 Subject: [PATCH] working on removing open_hook from view_set_file --- 4coder_custom.h | 1 + 4ed_app_models.h | 1 + 4ed_data.ctm | Bin 0 -> 84 bytes 4ed_file_view.cpp | 15 +-- README.txt | 2 +- SUPERREADME.txt | 2 +- build_all.bat | 17 ++- power/4coder_casey.cpp | 161 +++++++++++++++++++----- power/4coder_experiments.cpp | 232 ++++++++++++++++++++++++++++++++++- 9 files changed, 380 insertions(+), 51 deletions(-) create mode 100644 4ed_data.ctm diff --git a/4coder_custom.h b/4coder_custom.h index 188b7fe3..1f656981 100644 --- a/4coder_custom.h +++ b/4coder_custom.h @@ -357,6 +357,7 @@ struct Application_Links; #define GET_PARAMETER_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app, int param_index) #define GET_BUFFER_BY_NAME(n) Buffer_Summary n(Application_Links *app, char *filename, int len) +// TODO(allen): Need more flexible seek system somehow. Regex? Just expose the text stream to the user? #define BUFFER_SEEK_DELIMITER_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, char delim, int seek_forward, int *out) #define BUFFER_SEEK_STRING_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) #define BUFFER_SEEK_STRING_INSENSITIVE_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) diff --git a/4ed_app_models.h b/4ed_app_models.h index 8cb3402d..c058398d 100644 --- a/4ed_app_models.h +++ b/4ed_app_models.h @@ -40,6 +40,7 @@ struct Models{ u32 command_coroutine_flags[2]; Hook_Function *hooks[hook_type_count]; + Application_Links *app; i32 *buffer_param_indices; i32 buffer_param_count, buffer_param_max; diff --git a/4ed_data.ctm b/4ed_data.ctm new file mode 100644 index 0000000000000000000000000000000000000000..2962ef74c578b752fa6c80edaf8caff6f56114d6 GIT binary patch literal 84 zcmcC7j5`%~)i2Lz?L|gr1_p+Fb_RxbVxH~D{IzqHR(n9@UD+5Ie$-y6^9J%6f$HN} Q85lOGIkmy~|5+Fq05HK9eEstate.undo.history_head_block = 0; file->state.undo.current_block_normal = 1; } + + Hook_Function *open_hook = models->hooks[hook_open_file]; + open_hook(models->app); } internal b32 @@ -1283,9 +1286,8 @@ view_set_file( view->reinit_scrolling = 1; } } - - // TODO(allen): Bypass all this nonsense, it's a hack! Hooks need parameters! - // Just accept it and pass the file to the open hook when it is loaded. + +#if 0 if (file){ if (open_hook && file->settings.is_initialized == 0){ models->buffer_param_indices[models->buffer_param_count++] = file->id.id; @@ -1294,13 +1296,6 @@ view_set_file( file->settings.is_initialized = 1; } } - -#if 0 - if (set_vui){ - // TODO(allen): Fix this! There should be a way to easily separate setting a file, - // and switching to file mode, so that they don't cross over eachother like this. - view->showing_ui = VUI_None; - } #endif } diff --git a/README.txt b/README.txt index 03a98b58..83939728 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -Distribution Date: 12.5.2016 (dd.mm.yyyy) +Distribution Date: 13.5.2016 (dd.mm.yyyy) Thank you for contributing to the 4coder project! diff --git a/SUPERREADME.txt b/SUPERREADME.txt index 0f775ff9..66cae0f4 100644 --- a/SUPERREADME.txt +++ b/SUPERREADME.txt @@ -1,4 +1,4 @@ -Distribution Date: 12.5.2016 (dd.mm.yyyy) +Distribution Date: 13.5.2016 (dd.mm.yyyy) Thank you for contributing to the 4coder project! diff --git a/build_all.bat b/build_all.bat index 7305ade0..84300df0 100644 --- a/build_all.bat +++ b/build_all.bat @@ -1,29 +1,42 @@ @echo off +call "ctime" -begin 4ed_data.ctm + set OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4390 /WX set OPTS=%OPTS% /GR- /EHa- /nologo /FC set INCLUDES=/I..\foreign set LIBS=user32.lib winmm.lib gdi32.lib opengl32.lib set ICON=..\res\icon.res set DEFINES= +set FirstError=0 pushd ..\meta cl %OPTS% ..\code\4ed_metagen.cpp /Femetagen +if %ERRORLEVEL% neq 0 (set FirstError=1) popd + pushd ..\code "..\meta\metagen" +if %ERRORLEVEL% neq 0 (set FirstError=1) popd pushd ..\build -REM call "..\code\buildsuper.bat" ..\code\4coder_default_bindings.cpp -call "..\code\buildsuper.bat" ..\code\power\4coder_experiments.cpp +call "..\code\buildsuper.bat" ..\code\4coder_default_bindings.cpp +REM call "..\code\buildsuper.bat" ..\code\power\4coder_experiments.cpp +REM call "..\code\buildsuper.bat" ..\code\power\4coder_casey.cpp +if %ERRORLEVEL% neq 0 (set FirstError=1) set EXPORTS=/EXPORT:app_get_functions cl %OPTS% %INCLUDES% %DEFINES% ..\code\4ed_app_target.cpp %* /Fe4ed_app /LD /link /INCREMENTAL:NO /OPT:REF %EXPORTS% +if %ERRORLEVEL% neq 0 (set FirstError=1) cl %OPTS% %INCLUDES% %DEFINES% ..\code\win32_4ed.cpp %LIBS% %ICON% %* /Fe4ed +if %ERRORLEVEL% neq 0 (set FirstError=1) popd +call "ctime" -end 4ed_data.ctm %FirstError% + + diff --git a/power/4coder_casey.cpp b/power/4coder_casey.cpp index e14f5023..d2fa9b01 100644 --- a/power/4coder_casey.cpp +++ b/power/4coder_casey.cpp @@ -14,6 +14,13 @@ /* TODO(casey): Here are our current issues - 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? + But maybe I'm imagining things? + - High-DPI settings break rendering and all fonts just show up as solid squares + - 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? - Would like the option to indent to hanging parentheses, equals signs, etc. instead of always just "one tab in from the previous line". - Actually, maybe just expose the dirty state, so that the user can decide whether to @@ -24,18 +31,29 @@ - Auto-complete doesn't pick nearby words first, it seems, which makes it much slower to use? - Bug with not being able to switch-to-corresponding-file in another buffer without accidentally bringing up the file open dialog? - + - Up/down arrows and mouse clicks on wrapped lines don't seem to work properly with several wraps. + (eg., a line wrapped to more than 2 physical lines on the screen often doesn't work anymore, + with up or down jumping to totally wrong places, and mouse clicking jumping to wrong places + 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) + - Display: + - 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. - 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 ?FIXED First go-to-line for a file seems to still just go to the beginning of the buffer? Not sure Allen's right about the slash problem, but either way, we need some way to fix it. - - Need a way of highlighting the current line like Emacs does for the benefit - of people on The Stream(TM) - NOTE / IMPORTANT / TODO highlighting? Ability to customize? Whatever. - Some kind of parentheses highlighting? I can write this myself, but I would need some way of adding highlight information to the buffer. + - Need a way of highlighting the current line like Emacs does for the benefit + 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? @@ -44,28 +62,44 @@ the same margin as the prev. line (4coder just goes back to column 1). It'd be nice if it go _better_ than Emacs, with no need to manually flow comments, etc. - - Up/down arrows and mouse clicks on wrapped lines don't seem to work properly after the second wrap - (eg., a line wrapped to more than 2 physical lines on the screen.) - Buffer management: - - Switch-to-buffer with no typing, just return, should switch to the most recently - used buffer that is not currently displayed in a view. - ?FIXED Kill-buffer should perform this switch automatically, or it should be easy - to build a custom kill buffer that does - Seems like there's no way to switch to buffers whose names are substrings of other buffers' names without using the mouse? - Also, mouse-clicking on buffers doesn't seem to work reliably? Often it just goes to a blank window? + - 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? + - Still can't seem to open a zero-length file? + - 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? - - Default directory for file open / build search should be that of the current - buffer, not tracked separately? Probably I should code this on my own. - - Macro recording/playback + + - Arbitrary cool features: + - LOC count for the buffer and for all buffers summed shown in the title bar? + - Show auto-parsed #if/if/for/while/etc. statements at else and closing places. + - Automatic highlighting of the region in side the parentheses / etc. + - 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 + - To-do list dependent on project? + - Repeat last replace? + - Maybe search could be a permanent thing, so instead of initiating a search, + you're just _changing_ the search term with MODAL-S, and then there's _always_ + a next-of-these-in... and that could go through buffers in order, to... */ // NOTE(casey): Microsoft/Windows is poopsauce. @@ -73,10 +107,10 @@ #include #include -#include "..\4coder_default_includes.cpp" +#include "..\4coder_default_include.cpp" enum maps{ - my_code_map + my_code_map }; #ifndef Assert @@ -90,6 +124,7 @@ struct Parsed_Error String target_file_name; int target_line_number; + int target_column_number; int source_buffer_id; int source_position; @@ -114,6 +149,7 @@ enum token_type Token_Percent, Token_Colon, Token_Number, + Token_Comma, Token_EndOfStream, }; @@ -231,6 +267,7 @@ GetToken(tokenizer *Tokenizer) case '/': {Token.Type = Token_ForwardSlash;} break; case '%': {Token.Type = Token_Percent;} break; case ':': {Token.Type = Token_Colon;} break; + case ',': {Token.Type = Token_Comma;} break; default: { @@ -380,6 +417,7 @@ CUSTOM_COMMAND_SIG(casey_kill_to_end_of_line) Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); app->buffer_replace_range(app, &buffer, range.min, range.max, 0, 0); + exec_command(app, auto_tab_line_at_cursor); } CUSTOM_COMMAND_SIG(casey_paste_and_tab) @@ -396,6 +434,12 @@ CUSTOM_COMMAND_SIG(casey_seek_beginning_of_line_and_tab) exec_command(app, auto_tab_line_at_cursor); } +CUSTOM_COMMAND_SIG(casey_seek_beginning_of_line) +{ + exec_command(app, auto_tab_line_at_cursor); + exec_command(app, cmdid_seek_beginning_of_line); +} + struct switch_to_result { bool Switched; @@ -621,7 +665,7 @@ casey_goto_error(Application_Links *app, Parsed_Error e) switch_to_result Switch = SwitchToOrLoadFile(app, e.target_file_name, false); if(Switch.Switched) { - app->view_set_cursor(app, &Switch.view, seek_line_char(e.target_line_number, 0), 1); + 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); @@ -667,6 +711,18 @@ 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) + { + token ColumnToken = GetToken(&Tokenizer); + if(ColumnToken.Type == Token_Number) + { + column_number = atoi(ColumnToken.Text); + CloseToken = GetToken(&Tokenizer); + } + } + if(CloseToken.Type == Token_CloseParen) { token ColonToken = GetToken(&Tokenizer); @@ -693,6 +749,7 @@ casey_parse_error(Application_Links *app, Buffer_Summary buffer, View_Summary vi 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); @@ -1066,7 +1123,8 @@ CUSTOM_COMMAND_SIG(casey_execute_arbitrary_command) internal void UpdateModalIndicator(Application_Links *app) { - Theme_Color normal_colors[] = { + Theme_Color normal_colors[] = + { {Stag_Cursor, 0x40FF40}, {Stag_At_Cursor, 0x161616}, {Stag_Mark, 0x808080}, @@ -1076,7 +1134,8 @@ UpdateModalIndicator(Application_Links *app) {Stag_Bar, 0xCACACA} }; - Theme_Color edit_colors[] = { + Theme_Color edit_colors[] = + { {Stag_Cursor, 0xFF0000}, {Stag_At_Cursor, 0x00FFFF}, {Stag_Mark, 0xFF6F1A}, @@ -1137,22 +1196,22 @@ DEFINE_MODAL_KEY(modal_forward_slash, cmdid_change_active_panel); DEFINE_MODAL_KEY(modal_semicolon, cmdid_cursor_mark_swap); // TODO(casey): Maybe cmdid_history_backward? DEFINE_BIMODAL_KEY(modal_open_bracket, casey_begin_keyboard_macro_recording, write_and_auto_tab); DEFINE_BIMODAL_KEY(modal_close_bracket, casey_end_keyboard_macro_recording, write_and_auto_tab); -DEFINE_MODAL_KEY(modal_a, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_a, cmdid_write_character); // TODO(casey): Arbitrary command + casey_quick_calc DEFINE_MODAL_KEY(modal_b, cmdid_interactive_switch_buffer); DEFINE_MODAL_KEY(modal_c, casey_find_corresponding_file); -DEFINE_MODAL_KEY(modal_d, cmdid_write_character); // TODO(casey): Available +DEFINE_MODAL_KEY(modal_d, casey_kill_to_end_of_line); DEFINE_MODAL_KEY(modal_e, cmdid_write_character); // TODO(casey): Available DEFINE_MODAL_KEY(modal_f, casey_paste_and_tab); DEFINE_MODAL_KEY(modal_g, goto_line); DEFINE_MODAL_KEY(modal_h, cmdid_auto_tab_range); -DEFINE_MODAL_KEY(modal_i, cmdid_redo); -DEFINE_MODAL_KEY(modal_j, casey_imenu); -DEFINE_MODAL_KEY(modal_k, casey_kill_to_end_of_line); -DEFINE_MODAL_KEY(modal_l, replace_in_range); +DEFINE_MODAL_KEY(modal_i, cmdid_move_up); +DEFINE_MODAL_KEY(modal_j, seek_white_or_token_left); +DEFINE_MODAL_KEY(modal_k, cmdid_move_down); +DEFINE_MODAL_KEY(modal_l, seek_white_or_token_right); DEFINE_MODAL_KEY(modal_m, casey_save_and_make_without_asking); DEFINE_MODAL_KEY(modal_n, casey_goto_next_error); DEFINE_MODAL_KEY(modal_o, query_replace); -DEFINE_MODAL_KEY(modal_p, casey_quick_calc); +DEFINE_MODAL_KEY(modal_p, replace_in_range); DEFINE_MODAL_KEY(modal_q, cmdid_copy); DEFINE_MODAL_KEY(modal_r, reverse_search); // NOTE(allen): I've modified my default search so you can use it now. DEFINE_MODAL_KEY(modal_s, search); @@ -1161,7 +1220,7 @@ DEFINE_MODAL_KEY(modal_u, cmdid_undo); DEFINE_MODAL_KEY(modal_v, casey_switch_buffer_other_window); DEFINE_MODAL_KEY(modal_w, cmdid_cut); DEFINE_MODAL_KEY(modal_x, casey_find_corresponding_file_other_window); -DEFINE_MODAL_KEY(modal_y, auto_tab_line_at_cursor); +DEFINE_MODAL_KEY(modal_y, cmdid_redo); DEFINE_MODAL_KEY(modal_z, cmdid_interactive_open); DEFINE_MODAL_KEY(modal_1, casey_build_search); // TODO(casey): Shouldn't need to bind a key for this? @@ -1183,7 +1242,7 @@ DEFINE_BIMODAL_KEY(modal_down, cmdid_move_down, cmdid_move_down); DEFINE_BIMODAL_KEY(modal_left, seek_white_or_token_left, cmdid_move_left); DEFINE_BIMODAL_KEY(modal_right, seek_white_or_token_right, cmdid_move_right); DEFINE_BIMODAL_KEY(modal_delete, casey_delete_token_right, cmdid_delete); -DEFINE_BIMODAL_KEY(modal_home, cmdid_seek_beginning_of_line, casey_seek_beginning_of_line_and_tab); +DEFINE_BIMODAL_KEY(modal_home, casey_seek_beginning_of_line, casey_seek_beginning_of_line_and_tab); DEFINE_BIMODAL_KEY(modal_end, cmdid_seek_end_of_line, cmdid_seek_end_of_line); DEFINE_BIMODAL_KEY(modal_page_up, cmdid_page_up, cmdid_seek_whitespace_up); DEFINE_BIMODAL_KEY(modal_page_down, cmdid_page_down, cmdid_seek_whitespace_down); @@ -1365,14 +1424,50 @@ HOOK_SIG(casey_start) app->change_theme(app, literal("Handmade Hero")); app->change_font(app, literal("liberation mono")); + Theme_Color colors[] = + { + {Stag_Default, 0xA08563}, + // {Stag_Bar, }, + // {Stag_Bar_Active, }, + // {Stag_Base, }, + // {Stag_Pop1, }, + // {Stag_Pop2, }, + // {Stag_Back, }, + // {Stag_Margin, }, + // {Stag_Margin_Hover, }, + // {Stag_Margin_Active, }, + // {Stag_Cursor, }, + // {Stag_At_Cursor, }, + // {Stag_Highlight, }, + // {Stag_At_Highlight, }, + {Stag_Comment, 0x7D7D7D}, + {Stag_Keyword, 0xCD950C}, + // {Stag_Str_Constant, }, + // {Stag_Char_Constant, }, + // {Stag_Int_Constant, }, + // {Stag_Float_Constant, }, + // {Stag_Bool_Constant, }, + {Stag_Preproc, 0xDAB98F}, + {Stag_Include, 0x6B8E23}, + // {Stag_Special_Character, }, + // {Stag_Highlight_Junk, }, + // {Stag_Highlight_White, }, + // {Stag_Paste, }, + // {Stag_Undo, }, + // {Stag_Next_Undo, }, + }; + app->set_theme_colors(app, colors, ArrayCount(colors)); + win32_toggle_fullscreen(); return(0); } -void -get_bindings(Bind_Helper *context) +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_hook(context, hook_open_file, casey_file_settings); set_scroll_rule(context, casey_smooth_scroll_rule); @@ -1388,18 +1483,12 @@ get_bindings(Bind_Helper *context) bind(context, 'b', MDFR_NONE, cmdid_interactive_switch_buffer); bind(context, key_page_up, MDFR_NONE, search); bind(context, key_page_down, MDFR_NONE, reverse_search); - - // NOTE(allen): I added this here myself, I believe this is what you want. bind(context, 'm', MDFR_NONE, casey_save_and_make_without_asking); } end_map(context); begin_map(context, mapid_file); - // NOTE(allen): This is a new concept in the API. Binding this can be thought of as binding - // all combos which have an ascii code (shifted or not) and unmodified by CTRL or ALT. - // As of now, if this is used it cannot be overriden for particular combos; this overrides - // normal bindings. bind_vanilla_keys(context, cmdid_write_character); bind(context, key_insert, MDFR_NONE, begin_free_typing); @@ -1496,4 +1585,8 @@ get_bindings(Bind_Helper *context) bind(context, '\t', MDFR_SHIFT, modal_tab); end_map(context); + + end_bind_helper(context); + return context->write_total; } + diff --git a/power/4coder_experiments.cpp b/power/4coder_experiments.cpp index 23205901..0bf102e6 100644 --- a/power/4coder_experiments.cpp +++ b/power/4coder_experiments.cpp @@ -26,6 +26,230 @@ CUSTOM_COMMAND_SIG(kill_rect){ } } +// NOTE(allen): This stream stuff will be moved to helper if it looks +// like it will be helpful. So if you want to use it to build your own +// commands I suggest you move it there first. +struct Stream_Chunk{ + Application_Links *app; + Buffer_Summary *buffer; + + char *base_data; + int start, end; + int data_size; + + char *data; +}; + +int +round_down(int x, int b){ + int r = 0; + if (x >= 0){ + r = x - (x % b); + } + return(r); +} + +int +round_up(int x, int b){ + int r = 0; + if (x >= 0){ + r = x - (x % b) + b; + } + return(r); +} + +int +init_stream_chunk(Stream_Chunk *chunk, + Application_Links *app, Buffer_Summary *buffer, + int pos, char *data, int size){ + int result = 0; + + app->refresh_buffer(app, buffer); + if (pos >= 0 && pos < buffer->size && size > 0){ + result = 1; + chunk->app = app; + chunk->buffer = buffer; + chunk->base_data = data; + chunk->data_size = size; + chunk->start = round_down(pos, size); + chunk->end = round_up(pos, size); + if (chunk->end > buffer->size){ + chunk->end = buffer->size; + } + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + } + return(result); +} + +int +forward_stream_chunk(Stream_Chunk *chunk){ + Application_Links *app = chunk->app; + Buffer_Summary *buffer = chunk->buffer; + int result = 0; + + app->refresh_buffer(app, buffer); + if (chunk->end < buffer->size){ + result = 1; + chunk->start = chunk->end; + chunk->end += chunk->data_size; + if (chunk->end > buffer->size){ + chunk->end = buffer->size; + } + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + } + return(result); +} + +int +backward_stream_chunk(Stream_Chunk *chunk){ + Application_Links *app = chunk->app; + Buffer_Summary *buffer = chunk->buffer; + int result = 0; + + app->refresh_buffer(app, buffer); + if (chunk->start > 0){ + result = 1; + chunk->end = chunk->start; + chunk->start -= chunk->data_size; + if (chunk->start < 0){ + chunk->start = 0; + } + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + } + return(result); +} + +// TODO(allen): Both of these brace related commands would work better +// if the API exposed access to the tokens in a code file. +CUSTOM_COMMAND_SIG(mark_matching_brace){ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + + int start_pos = view.cursor.pos; + + // NOTE(allen): The user provides the memory that the chunk uses, + // this chunk will then be filled at each step of the text stream loop. + // This way you can look for something that should be nearby without + // having to copy the whole file in at once. + Stream_Chunk chunk; + char chunk_space[(1 << 10)]; + + int result = 0; + int found_result = 0; + + int i = start_pos; + int still_looping = 1; + int nesting_counter = 0; + char at_cursor = 0; + + if (init_stream_chunk(&chunk, app, &buffer, i, chunk_space, sizeof(chunk_space))){ + + // NOTE(allen): This is important! The data array is a pointer that is adjusted + // so that indexing it with "i" will put it with the chunk that is actually loaded. + // If i goes below chunk.start or above chunk.end _that_ is an invalid access. + at_cursor = chunk.data[i]; + if (at_cursor == '{'){ + do{ + for (++i; i < chunk.end; ++i){ + at_cursor = chunk.data[i]; + if (at_cursor == '{'){ + ++nesting_counter; + } + else if (at_cursor == '}'){ + if (nesting_counter == 0){ + found_result = 1; + result = i; + goto finished; + } + else{ + --nesting_counter; + } + } + } + still_looping = forward_stream_chunk(&chunk); + } + while (still_looping); + } + else if (at_cursor == '}'){ + do{ + for (--i; i >= chunk.start; --i){ + at_cursor = chunk.data[i]; + if (at_cursor == '}'){ + ++nesting_counter; + } + else if (at_cursor == '{'){ + if (nesting_counter == 0){ + found_result = 1; + result = i; + goto finished; + } + else{ + --nesting_counter; + } + } + } + still_looping = backward_stream_chunk(&chunk); + } + while (still_looping); + } + } + + finished: + if (found_result){ + app->view_set_mark(app, &view, seek_pos(result)); + } +} + +CUSTOM_COMMAND_SIG(cursor_to_surrounding_scope){ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + + int start_pos = view.cursor.pos - 1; + + Stream_Chunk chunk; + char chunk_space[(1 << 10)]; + + int result = 0; + int found_result = 0; + + int i = start_pos; + int still_looping = 1; + int nesting_counter = 0; + char at_cursor = 0; + + if (init_stream_chunk(&chunk, app, &buffer, i, chunk_space, sizeof(chunk_space))){ + do{ + for (; i >= chunk.start; --i){ + at_cursor = chunk.data[i]; + if (at_cursor == '}'){ + ++nesting_counter; + } + else if (at_cursor == '{'){ + if (nesting_counter == 0){ + found_result = 1; + result = i; + goto finished; + } + else{ + --nesting_counter; + } + } + } + still_looping = backward_stream_chunk(&chunk); + } while(still_looping); + } + + finished: + if (found_result){ + app->view_set_cursor(app, &view, seek_pos(result), 0); + } +} + +// NOTE(allen): Incomplete +#if 0 CUSTOM_COMMAND_SIG(complete_word){ app->print_message(app, literal("complete_word\n")); @@ -44,7 +268,7 @@ CUSTOM_COMMAND_SIG(complete_word){ start = view.cursor.pos; String complete_string; - int size = (start - end); + int size = (end - start); char complete_space[256]; if (size < sizeof(complete_space) - 1){ @@ -54,11 +278,12 @@ CUSTOM_COMMAND_SIG(complete_word){ complete_string.str[size] = 0; // TODO(allen): Complete this when the heavy duty coroutine stuff - // and the hash table are available + // and the hash table are available. app->print_message(app, complete_string.str, complete_string.size); } } +#endif // TODO(allen): Query theme settings #if 0 @@ -83,7 +308,8 @@ CUSTOM_COMMAND_SIG(save_theme_settings){ void experiment_extension(Bind_Helper *context){ bind(context, 'k', MDFR_ALT, kill_rect); - bind(context, '+', MDFR_CTRL, complete_word); + bind(context, '/', MDFR_ALT, mark_matching_brace); + bind(context, '\'', MDFR_ALT, cursor_to_surrounding_scope); } #include