├── .gitignore ├── README.md ├── bindings.4coder ├── config.4coder ├── custom ├── 4coder_code_index.cpp ├── 4coder_code_index.h ├── 4coder_default_hooks.cpp ├── 4coder_jumping.cpp └── languages │ └── 4coder_cpp_lexer_gen.cpp ├── custom_4coder.dll ├── custom_4coder.so ├── lex.bat ├── lex.sh ├── release.bat ├── release.sh └── themes ├── theme-horizon.4coder ├── theme-nord.4coder └── theme-solarized-dark.4coder /.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | /external -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 4Coder Customization Layer for [Odin](http://odin-lang.org/) 2 | 4Coder Customization Layer that I use daily for **Odin** 3 | Customizations are kept minimal for my / your sake 4 | 5 | ## Odin Features 6 | * Keywords + Highlight 7 | * Code Indexing (*proc, structs, enums, unions, constants*) 8 | * Goto jumping since Code Indexing works 9 | * Error / Lister Jumping 10 | 11 | ## How to try out :tada: 12 | Windows: Replace your `custom_4coder.dll` with mine 13 | Linux: Replace your `custom_4coder.so` with mine 14 | 15 | ## How to build 16 | Replace all files to their corresponding locations, i.e. `custom` folder files belong to custom etc. 17 | To get **odin** keyword lexing you have to rebuild the lexer with my custom language file 18 | The scripts have to live in the root `4coder` folder 19 | 20 | Release script rebuilds code 21 | Lex script rebuilds the lexer and calls release script 22 | 23 | Windows: `release.bat` | `lex.bat` 24 | Linux: `release.sh` | `lex.sh` 25 | 26 | ## Themes 27 | * Solarized Dark 28 | * Nord 29 | * Horizon 30 | 31 | ## Old 32 | You can browse the repo history for other extensions i used to use 33 | -------------------------------------------------------------------------------- /bindings.4coder: -------------------------------------------------------------------------------- 1 | 2 | keys_global = { 3 | { "keyboard_macro_start_recording", "U", "Control" }, 4 | { "keyboard_macro_finish_recording", "U", "Control", "Shift" }, 5 | { "keyboard_macro_replay", "U", "Alt" }, 6 | { "change_active_panel", "Comma", "Control" }, 7 | { "change_active_panel", "Period", "Control" }, 8 | { "change_active_panel_backwards", "Comma", "Control", "Shift" }, 9 | { "interactive_new", "N", "Control" }, 10 | { "interactive_open_or_new", "O", "Control" }, 11 | { "open_in_other", "O", "Alt" }, 12 | { "interactive_kill_buffer", "K", "Control" }, 13 | { "interactive_switch_buffer", "I", "Control" }, 14 | { "project_go_to_root_directory", "H", "Control" }, 15 | { "save_all_dirty_buffers", "S", "Control", "Shift" }, 16 | { "change_to_build_panel", "Period", "Alt" }, 17 | { "close_build_panel", "Comma", "Alt" }, 18 | { "goto_next_jump", "N", "Alt" }, 19 | { "goto_prev_jump", "N", "Alt", "Shift" }, 20 | { "build_in_build_panel", "M", "Alt" }, 21 | { "goto_first_jump", "M", "Alt", "Shift" }, 22 | { "toggle_filebar", "B", "Alt" }, 23 | { "execute_any_cli", "Z", "Alt" }, 24 | { "execute_previous_cli", "Z", "Alt", "Shift" }, 25 | { "command_lister", "X", "Alt" }, 26 | { "project_command_lister", "X", "Alt", "Shift" }, 27 | { "quick_swap_buffer", "P", "Alt" }, 28 | { "jump_to_last_point", "P", "Control" }, 29 | { "list_all_functions_current_buffer_lister", "I", "Control", "Shift" }, 30 | { "exit_4coder", "F4", "Alt" }, 31 | { "project_fkey_command", "F1" }, 32 | { "project_fkey_command", "F2" }, 33 | { "project_fkey_command", "F3" }, 34 | { "project_fkey_command", "F4" }, 35 | { "project_fkey_command", "F5" }, 36 | { "project_fkey_command", "F6" }, 37 | { "project_fkey_command", "F7" }, 38 | { "project_fkey_command", "F8" }, 39 | { "project_fkey_command", "F9" }, 40 | { "project_fkey_command", "F10" }, 41 | { "project_fkey_command", "F11" }, 42 | { "project_fkey_command", "F12" }, 43 | { "project_fkey_command", "F13" }, 44 | { "project_fkey_command", "F14" }, 45 | { "project_fkey_command", "F15" }, 46 | { "project_fkey_command", "F16" }, 47 | }; 48 | 49 | keys_file = { 50 | { "delete_char", "Delete" }, 51 | { "backspace_char", "Backspace" }, 52 | { "move_up", "Up" }, 53 | { "move_down", "Down" }, 54 | { "move_left", "Left" }, 55 | { "move_right", "Right" }, 56 | { "seek_end_of_line", "End" }, 57 | { "seek_beginning_of_line", "Home" }, 58 | { "page_up", "PageUp" }, 59 | { "page_down", "PageDown" }, 60 | { "goto_beginning_of_file", "PageUp", "Control" }, 61 | { "goto_end_of_file", "PageDown", "Control" }, 62 | { "move_up_to_blank_line_end", "Up", "Control" }, 63 | { "move_down_to_blank_line_end", "Down", "Control" }, 64 | { "move_left_whitespace_boundary", "Left", "Control" }, 65 | { "move_right_whitespace_boundary", "Right", "Control" }, 66 | { "move_line_up", "Up", "Alt" }, 67 | { "move_line_down", "Down", "Alt" }, 68 | { "backspace_alpha_numeric_boundary", "Backspace", "Control" }, 69 | { "delete_alpha_numeric_boundary", "Delete", "Control" }, 70 | { "snipe_backward_whitespace_or_token_boundary", "Backspace", "Alt" }, 71 | { "snipe_forward_whitespace_or_token_boundary", "Delete", "Alt" }, 72 | { "set_mark", "Space", "Control" }, 73 | { "replace_in_range", "A", "Control" }, 74 | { "copy", "C", "Control" }, 75 | { "delete_range", "D", "Control" }, 76 | { "delete_line", "D", "Control", "Shift" }, 77 | { "center_view", "E", "Control" }, 78 | { "left_adjust_view", "E", "Control", "Shift" }, 79 | { "search", "F", "Control" }, 80 | { "list_all_locations", "F", "Control", "Shift" }, 81 | { "list_all_substring_locations_case_insensitive", "F", "Alt" }, 82 | { "goto_line", "G", "Control" }, 83 | { "list_all_locations_of_selection", "G", "Control", "Shift" }, 84 | { "snippet_lister", "J", "Control" }, 85 | { "kill_buffer", "K", "Control", "Shift" }, 86 | { "duplicate_line", "L", "Control" }, 87 | { "cursor_mark_swap", "M", "Control" }, 88 | { "reopen", "O", "Control", "Shift" }, 89 | { "query_replace", "Q", "Control" }, 90 | { "query_replace_identifier", "Q", "Control", "Shift" }, 91 | { "query_replace_selection", "Q", "Alt" }, 92 | { "reverse_search", "R", "Control" }, 93 | { "save", "S", "Control" }, 94 | { "save_all_dirty_buffers", "S", "Control", "Shift" }, 95 | { "search_identifier", "T", "Control" }, 96 | { "list_all_locations_of_identifier", "T", "Control", "Shift" }, 97 | { "paste_and_indent", "V", "Control" }, 98 | { "paste_next_and_indent", "V", "Control", "Shift" }, 99 | { "cut", "X", "Control" }, 100 | { "redo", "Y", "Control" }, 101 | { "undo", "Z", "Control" }, 102 | { "view_buffer_other_panel", "1", "Control" }, 103 | { "swap_panels", "2", "Control" }, 104 | { "if_read_only_goto_position", "Return" }, 105 | { "if_read_only_goto_position_same_panel", "Return", "Shift" }, 106 | { "view_jump_list_with_lister", "Period", "Control", "Shift" }, 107 | }; 108 | 109 | keys_code = { 110 | { "move_left_alpha_numeric_boundary", "Left", "Control" }, 111 | { "move_right_alpha_numeric_boundary", "Right", "Control" }, 112 | { "move_left_alpha_numeric_or_camel_boundary", "Left", "Alt" }, 113 | { "move_right_alpha_numeric_or_camel_boundary", "Right", "Alt" }, 114 | { "comment_line_toggle", "W", "Alt" }, 115 | { "word_complete", "Tab" }, 116 | { "auto_indent_range", "Tab", "Control" }, 117 | { "auto_indent_line_at_cursor", "Tab", "Shift" }, 118 | { "word_complete_drop_down", "Tab", "Shift", "Control" }, 119 | { "write_block", "R", "Alt" }, 120 | { "write_todo", "T", "Alt" }, 121 | { "write_note", "Y", "Alt" }, 122 | { "list_all_locations_of_type_definition", "D", "Alt" }, 123 | { "list_all_locations_of_type_definition_of_identifier", "T", "Alt", "Shift" }, 124 | { "open_long_braces", "LeftBracket", "Control" }, 125 | { "open_long_braces_semicolon", "LeftBracket", "Control", "Shift" }, 126 | { "open_long_braces_break", "RightBracket", "Control", "Shift" }, 127 | { "select_surrounding_scope", "LeftBracket", "Alt" }, 128 | { "select_surrounding_scope_maximal", "LeftBracket", "Alt", "Shift" }, 129 | { "select_prev_scope_absolute", "RightBracket", "Alt" }, 130 | { "select_prev_top_most_scope", "RightBracket", "Alt", "Shift" }, 131 | { "select_next_scope_absolute", "Quote", "Alt" }, 132 | { "select_next_scope_after_current", "Quote", "Alt", "Shift" }, 133 | { "place_in_scope", "ForwardSlash", "Alt" }, 134 | { "delete_current_scope", "Minus", "Alt" }, 135 | { "if0_off", "I", "Alt" }, 136 | { "open_file_in_quotes", "1", "Alt" }, 137 | { "open_matching_file_cpp", "2", "Alt" }, 138 | // { "write_zero_struct", "0", "Control" }, 139 | { "jump_to_definition_at_cursor", "W", "Control" }, 140 | }; 141 | 142 | -------------------------------------------------------------------------------- /config.4coder: -------------------------------------------------------------------------------- 1 | // Command Mapping 2 | // "" - Leave the bindings unaltered - use this when writing your own customization! 3 | // "choose" - Ask 4coder to choose based on platform. 4 | // "default" - Use the default keybindings 4coder has always had. 5 | // "mac-default" - Use keybindings similar to those found in other Mac applications. 6 | mapping = ""; 7 | 8 | // MODE 9 | // "4coder" - The default 4coder mode that has been around since the beginning of time (2015) 10 | // "notepad-like" - Single "thin" cursor and highlight ranges like in notepad, sublime, notepad++, etc 11 | mode = "4coder"; 12 | bind_by_physical_key = false; 13 | 14 | // UI 15 | use_file_bars = true; 16 | hide_file_bar_in_ui = true; 17 | use_error_highlight = true; 18 | use_jump_highlight = true; 19 | use_scope_highlight = true; 20 | use_paren_helper = true; 21 | use_comment_keywords = true; 22 | lister_whole_word_backspace_when_modified = true; 23 | show_line_number_margins = false; 24 | enable_output_wrapping = false; 25 | 26 | enable_undo_fade_out = true; 27 | 28 | // cursor_roundess is a value [0,50] setting the radius of 29 | // the cursor and mark's roundness as a percentage of their width 30 | // (At 50 the left and right corners will be so round they form a semi-circle, 31 | // hence 50 is the max) 32 | cursor_roundness = 45; 33 | 34 | // mark_thickness is a pixel count value setting the 35 | // thickness of the mark wire box in original mode 36 | mark_thickness = 2; 37 | 38 | // lister_roundess is a value [0,50] setting the radius of 39 | // the lister items' roundness as a percentage of their height 40 | lister_roundness = 20; 41 | 42 | // Code Wrapping 43 | treat_as_code = ".cpp.c.hpp.h.cc.cs.java.rs.glsl.m.mm.odin"; 44 | enable_virtual_whitespace = true; 45 | virtual_whitespace_regular_indent = 2; 46 | enable_code_wrapping = true; 47 | 48 | // This only applies to code files in code-wrapping mode. 49 | // Plain text and code files without virtual-whitespace will not be effected. 50 | automatically_indent_text_on_save = true; 51 | 52 | // When set to true, all unsaved changes will be saved on a build. 53 | automatically_save_changes_on_build = true; 54 | 55 | // Load project on startup 56 | automatically_load_project = true; 57 | 58 | // Indentation 59 | indent_with_tabs = true; 60 | indent_width = 2; 61 | default_tab_width = 2; 62 | 63 | // Theme 64 | default_theme_name = "theme-solarized-dark"; 65 | 66 | // Font 67 | default_font_name = "liberation-mono.ttf"; 68 | default_font_size = 15; 69 | default_font_hinting = false; 70 | 71 | // aa modes: 72 | // 8bit - mono-chrome 0-255 opacity channel per pixel 73 | // 1bit - mono-chrome 0/1 opacity channel per pixel 74 | default_font_aa_mode = "8bit"; 75 | 76 | // User 77 | user_name = "Skytrias"; 78 | 79 | // Keyboard AltGr setting 80 | lalt_lctrl_is_altgr = false; 81 | 82 | // Project setup configuration 83 | default_compiler_bat = "cl"; 84 | default_flags_bat = "-FC -GR- -EHa- -nologo -Zi"; 85 | default_compiler_sh = "g++"; 86 | default_flags_sh = "-g"; 87 | 88 | -------------------------------------------------------------------------------- /custom/4coder_code_index.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_code_index.cpp - Generic code indexing system for layout, definition jumps, etc. 3 | */ 4 | 5 | // TOP 6 | 7 | global Code_Index global_code_index = {}; 8 | 9 | //////////////////////////////// 10 | // NOTE(allen): Lookups 11 | 12 | // TODO(allen): accelerator for these nest lookups? 13 | // Looks like the only one I ever actually use is the file one, not the array one. 14 | function Code_Index_Nest* 15 | code_index_get_nest_(Code_Index_Nest_Ptr_Array *array, i64 pos){ 16 | Code_Index_Nest *result = 0; 17 | i32 count = array->count; 18 | Code_Index_Nest **nest_ptrs = array->ptrs; 19 | for (i32 i = 0; i < count; i += 1){ 20 | Code_Index_Nest *nest = nest_ptrs[i]; 21 | if (nest->open.max <= pos && pos <= nest->close.min){ 22 | Code_Index_Nest *sub_nest = code_index_get_nest_(&nest->nest_array, pos); 23 | if (sub_nest != 0){ 24 | result = sub_nest; 25 | } 26 | else{ 27 | result = nest; 28 | } 29 | break; 30 | } 31 | } 32 | return(result); 33 | } 34 | 35 | function Code_Index_Nest* 36 | code_index_get_nest(Code_Index_File *file, i64 pos){ 37 | return(code_index_get_nest_(&file->nest_array, pos)); 38 | } 39 | 40 | function Code_Index_Note_List* 41 | code_index__list_from_string(String_Const_u8 string){ 42 | u64 hash = table_hash_u8(string.str, string.size); 43 | Code_Index_Note_List *result = &global_code_index.name_hash[hash % ArrayCount(global_code_index.name_hash)]; 44 | return(result); 45 | } 46 | 47 | function Code_Index_Note* 48 | code_index_note_from_string(String_Const_u8 string){ 49 | Code_Index_Note_List *list = code_index__list_from_string(string); 50 | Code_Index_Note *result = 0; 51 | for (Code_Index_Note *node = list->first; 52 | node != 0; 53 | node = node->next_in_hash){ 54 | if (string_match(string, node->text)){ 55 | result = node; 56 | break; 57 | } 58 | } 59 | return(result); 60 | } 61 | 62 | 63 | //////////////////////////////// 64 | // NOTE(allen): Global Code Index 65 | 66 | function void 67 | code_index_init(void){ 68 | global_code_index.mutex = system_mutex_make(); 69 | global_code_index.node_arena = make_arena_system(KB(4)); 70 | global_code_index.buffer_to_index_file = make_table_u64_u64(global_code_index.node_arena.base_allocator, 500); 71 | } 72 | 73 | function Code_Index_File_Storage* 74 | code_index__alloc_storage(void){ 75 | Code_Index_File_Storage *result = global_code_index.free_storage; 76 | if (result == 0){ 77 | result = push_array_zero(&global_code_index.node_arena, Code_Index_File_Storage, 1); 78 | } 79 | else{ 80 | sll_stack_pop(global_code_index.free_storage); 81 | } 82 | zdll_push_back(global_code_index.storage_first, global_code_index.storage_last, result); 83 | global_code_index.storage_count += 1; 84 | return(result); 85 | } 86 | 87 | function void 88 | code_index__free_storage(Code_Index_File_Storage *storage){ 89 | zdll_remove(global_code_index.storage_first, global_code_index.storage_last, storage); 90 | global_code_index.storage_count -= 1; 91 | sll_stack_push(global_code_index.free_storage, storage); 92 | } 93 | 94 | function void 95 | code_index_push_nest(Code_Index_Nest_List *list, Code_Index_Nest *nest){ 96 | sll_queue_push(list->first, list->last, nest); 97 | list->count += 1; 98 | } 99 | 100 | function Code_Index_Nest_Ptr_Array 101 | code_index_nest_ptr_array_from_list(Arena *arena, Code_Index_Nest_List *list){ 102 | Code_Index_Nest_Ptr_Array array = {}; 103 | array.ptrs = push_array_zero(arena, Code_Index_Nest*, list->count); 104 | array.count = list->count; 105 | i32 counter = 0; 106 | for (Code_Index_Nest *node = list->first; 107 | node != 0; 108 | node = node->next){ 109 | array.ptrs[counter] = node; 110 | counter += 1; 111 | } 112 | return(array); 113 | } 114 | 115 | function Code_Index_Note_Ptr_Array 116 | code_index_note_ptr_array_from_list(Arena *arena, Code_Index_Note_List *list){ 117 | Code_Index_Note_Ptr_Array array = {}; 118 | array.ptrs = push_array_zero(arena, Code_Index_Note*, list->count); 119 | array.count = list->count; 120 | i32 counter = 0; 121 | for (Code_Index_Note *node = list->first; 122 | node != 0; 123 | node = node->next){ 124 | array.ptrs[counter] = node; 125 | counter += 1; 126 | } 127 | return(array); 128 | } 129 | 130 | function void 131 | code_index_lock(void){ 132 | system_mutex_acquire(global_code_index.mutex); 133 | } 134 | 135 | function void 136 | code_index_unlock(void){ 137 | system_mutex_release(global_code_index.mutex); 138 | } 139 | 140 | function void 141 | code_index__hash_file(Code_Index_File *file){ 142 | for (Code_Index_Note *node = file->note_list.first; 143 | node != 0; 144 | node = node->next){ 145 | Code_Index_Note_List *list = code_index__list_from_string(node->text); 146 | zdll_push_back_NP_(list->first, list->last, node, next_in_hash, prev_in_hash); 147 | list->count += 1; 148 | } 149 | } 150 | 151 | function void 152 | code_index__clear_file(Code_Index_File *file){ 153 | for (Code_Index_Note *node = file->note_list.first; 154 | node != 0; 155 | node = node->next){ 156 | Code_Index_Note_List *list = code_index__list_from_string(node->text); 157 | zdll_remove_NP_(list->first, list->last, node, next_in_hash, prev_in_hash); 158 | list->count -= 1; 159 | } 160 | } 161 | 162 | function void 163 | code_index_set_file(Buffer_ID buffer, Arena arena, Code_Index_File *index){ 164 | Code_Index_File_Storage *storage = 0; 165 | Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); 166 | if (lookup.found_match){ 167 | u64 val = 0; 168 | table_read(&global_code_index.buffer_to_index_file, lookup, &val); 169 | storage = (Code_Index_File_Storage*)IntAsPtr(val); 170 | code_index__clear_file(storage->file); 171 | linalloc_clear(&storage->arena); 172 | } 173 | else{ 174 | storage = code_index__alloc_storage(); 175 | table_insert(&global_code_index.buffer_to_index_file, buffer, (u64)PtrAsInt(storage)); 176 | } 177 | storage->arena = arena; 178 | storage->file = index; 179 | 180 | code_index__hash_file(index); 181 | } 182 | 183 | function void 184 | code_index_erase_file(Buffer_ID buffer){ 185 | Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); 186 | if (lookup.found_match){ 187 | u64 val = 0; 188 | table_read(&global_code_index.buffer_to_index_file, lookup, &val); 189 | Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); 190 | 191 | code_index__clear_file(storage->file); 192 | 193 | linalloc_clear(&storage->arena); 194 | table_erase(&global_code_index.buffer_to_index_file, lookup); 195 | code_index__free_storage(storage); 196 | } 197 | } 198 | 199 | function Code_Index_File* 200 | code_index_get_file(Buffer_ID buffer){ 201 | Code_Index_File *result = 0; 202 | Table_Lookup lookup = table_lookup(&global_code_index.buffer_to_index_file, buffer); 203 | if (lookup.found_match){ 204 | u64 val = 0; 205 | table_read(&global_code_index.buffer_to_index_file, lookup, &val); 206 | Code_Index_File_Storage *storage = (Code_Index_File_Storage*)IntAsPtr(val); 207 | result = storage->file; 208 | } 209 | return(result); 210 | } 211 | 212 | function void 213 | index_shift(i64 *ptr, Range_i64 old_range, u64 new_size){ 214 | i64 i = *ptr; 215 | if (old_range.min <= i && i < old_range.max){ 216 | *ptr = old_range.first; 217 | } 218 | else if (old_range.max <= i){ 219 | *ptr = i + new_size - (old_range.max - old_range.min); 220 | } 221 | } 222 | 223 | function void 224 | code_index_shift(Code_Index_Nest_Ptr_Array *array, 225 | Range_i64 old_range, u64 new_size){ 226 | i32 count = array->count; 227 | Code_Index_Nest **nest_ptr = array->ptrs; 228 | for (i32 i = 0; i < count; i += 1, nest_ptr += 1){ 229 | Code_Index_Nest *nest = *nest_ptr; 230 | index_shift(&nest->open.min, old_range, new_size); 231 | index_shift(&nest->open.max, old_range, new_size); 232 | if (nest->is_closed){ 233 | index_shift(&nest->close.min, old_range, new_size); 234 | index_shift(&nest->close.max, old_range, new_size); 235 | } 236 | code_index_shift(&nest->nest_array, old_range, new_size); 237 | } 238 | } 239 | 240 | function void 241 | code_index_shift(Code_Index_File *file, Range_i64 old_range, u64 new_size){ 242 | code_index_shift(&file->nest_array, old_range, new_size); 243 | } 244 | 245 | 246 | //////////////////////////////// 247 | // NOTE(allen): Parser Helpers 248 | 249 | // NOTE(Skytrias): simple iterator 250 | function void 251 | generic_parse_inc(Generic_Parse_State *state){ 252 | if (!token_it_inc_all(&state->it)){ 253 | state->finished = true; 254 | } 255 | } 256 | 257 | function void 258 | generic_parse_skip_soft_tokens(Code_Index_File *index, Generic_Parse_State *state){ 259 | Token *token = token_it_read(&state->it); 260 | for (;token != 0 && !state->finished;){ 261 | if (state->in_preprocessor && !HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ 262 | break; 263 | } 264 | if (token->kind == TokenBaseKind_Comment){ 265 | state->handle_comment(state->app, state->arena, index, token, state->contents); 266 | } 267 | else if (token->kind == TokenBaseKind_Whitespace){ 268 | Range_i64 range = Ii64(token); 269 | u8 *ptr = state->contents.str + range.one_past_last - 1; 270 | for (i64 i = range.one_past_last - 1; 271 | i >= range.first; 272 | i -= 1, ptr -= 1){ 273 | if (*ptr == '\n'){ 274 | state->prev_line_start = ptr + 1; 275 | break; 276 | } 277 | } 278 | } 279 | else{ 280 | break; 281 | } 282 | generic_parse_inc(state); 283 | token = token_it_read(&state->it); 284 | } 285 | } 286 | 287 | function void 288 | generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_Comment_Function *handle_comment, Generic_Parse_State *state){ 289 | state->app = app; 290 | state->arena = arena; 291 | state->contents = contents; 292 | state->it = token_iterator(0, tokens); 293 | state->handle_comment = handle_comment; 294 | state->prev_line_start = contents.str; 295 | } 296 | 297 | //////////////////////////////// 298 | // NOTE(allen): Parser 299 | 300 | #if 0 301 | /* 302 | // NOTE(allen): grammar syntax 303 | (X) = X 304 | X Y = X and then Y 305 | X? = zero or one X 306 | $X = check for X but don't consume 307 | [X] = zero or more Xs 308 | X | Y = either X or Y 309 | * = anything that does not match previous options in a X | Y | ... chain 310 | * - X = anything that does not match X or previous options in a Y | Z | ... chain 311 | = a token of type X 312 | "X" = literally the string "X" 313 | X{Y} = X with flag Y 314 | 315 | // NOTE(allen): grammar of code index parse 316 | file: [preprocessor | scope | parens | function | type | * - ] 317 | preprocessor: [scope | parens | stmnt]{pp-body} 318 | scope: [preprocessor | scope | parens | * - ] 319 | paren: [preprocessor | scope | parens | * - ] 320 | stmnt-close-pattern: | | | | | 321 | stmnt: [type | * - stmnt-close-pattern] stmnt-close-pattern 322 | type: struct | union | enum | typedef 323 | struct: "struct" $(";" | "{") 324 | union: "union" $(";" | "{") 325 | enum: "enum" $(";" | "{") 326 | typedef: "typedef" [* - ( (";" | "("))] $(";" | "(") 327 | function: >"(" ["(" ")" | * - ("(" | ")")] ")" ("{" | ";") 328 | */ 329 | #endif 330 | 331 | function Code_Index_Note* 332 | index_new_note(Code_Index_File *index, Generic_Parse_State *state, Range_i64 range, Code_Index_Note_Kind kind, Code_Index_Nest *parent){ 333 | Code_Index_Note *result = push_array(state->arena, Code_Index_Note, 1); 334 | sll_queue_push(index->note_list.first, index->note_list.last, result); 335 | index->note_list.count += 1; 336 | result->note_kind = kind; 337 | result->pos = range; 338 | result->text = push_string_copy(state->arena, string_substring(state->contents, range)); 339 | result->file = index; 340 | result->parent = parent; 341 | return(result); 342 | } 343 | 344 | function void 345 | _cpp_parse_type_structure(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ 346 | generic_parse_inc(state); 347 | generic_parse_skip_soft_tokens(index, state); 348 | if (state->finished){ 349 | return; 350 | } 351 | Token *token = token_it_read(&state->it); 352 | if (token != 0 && token->kind == TokenBaseKind_Identifier){ 353 | generic_parse_inc(state); 354 | generic_parse_skip_soft_tokens(index, state); 355 | Token *peek = token_it_read(&state->it); 356 | if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || 357 | peek->kind == TokenBaseKind_ScopeOpen){ 358 | index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); 359 | } 360 | } 361 | } 362 | 363 | function void 364 | cpp_parse_type_def(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ 365 | generic_parse_inc(state); 366 | generic_parse_skip_soft_tokens(index, state); 367 | for (;;){ 368 | b32 did_advance = false; 369 | Token *token = token_it_read(&state->it); 370 | if (token == 0 || state->finished){ 371 | break; 372 | } 373 | if (token->kind == TokenBaseKind_Identifier){ 374 | generic_parse_inc(state); 375 | generic_parse_skip_soft_tokens(index, state); 376 | did_advance = true; 377 | Token *peek = token_it_read(&state->it); 378 | if (peek != 0 && peek->kind == TokenBaseKind_StatementClose || 379 | peek->kind == TokenBaseKind_ParentheticalOpen){ 380 | index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); 381 | break; 382 | } 383 | } 384 | else if (token->kind == TokenBaseKind_StatementClose || 385 | token->kind == TokenBaseKind_ScopeOpen || 386 | token->kind == TokenBaseKind_ScopeClose || 387 | token->kind == TokenBaseKind_ScopeOpen || 388 | token->kind == TokenBaseKind_ScopeClose){ 389 | break; 390 | } 391 | else if (token->kind == TokenBaseKind_Keyword){ 392 | String_Const_u8 lexeme = string_substring(state->contents, Ii64(token)); 393 | if (string_match(lexeme, string_u8_litexpr("struct")) || 394 | string_match(lexeme, string_u8_litexpr("union")) || 395 | string_match(lexeme, string_u8_litexpr("enum"))){ 396 | break; 397 | } 398 | } 399 | if (!did_advance){ 400 | generic_parse_inc(state); 401 | generic_parse_skip_soft_tokens(index, state); 402 | } 403 | } 404 | } 405 | 406 | function void 407 | _cpp_parse_function(Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent){ 408 | Token *token = token_it_read(&state->it); 409 | generic_parse_inc(state); 410 | generic_parse_skip_soft_tokens(index, state); 411 | if (state->finished){ 412 | return; 413 | } 414 | Token *peek = token_it_read(&state->it); 415 | Token *reset_point = peek; 416 | if (peek != 0 && peek->sub_kind == TokenCppKind_ParenOp){ 417 | b32 at_paren_close = false; 418 | i32 paren_nest_level = 0; 419 | for (; peek != 0;){ 420 | generic_parse_inc(state); 421 | generic_parse_skip_soft_tokens(index, state); 422 | peek = token_it_read(&state->it); 423 | if (peek == 0 || state->finished){ 424 | break; 425 | } 426 | 427 | if (peek->kind == TokenBaseKind_ParentheticalOpen){ 428 | paren_nest_level += 1; 429 | } 430 | else if (peek->kind == TokenBaseKind_ParentheticalClose){ 431 | if (paren_nest_level > 0){ 432 | paren_nest_level -= 1; 433 | } 434 | else{ 435 | at_paren_close = true; 436 | break; 437 | } 438 | } 439 | } 440 | 441 | if (at_paren_close){ 442 | generic_parse_inc(state); 443 | generic_parse_skip_soft_tokens(index, state); 444 | peek = token_it_read(&state->it); 445 | if (peek != 0 && 446 | peek->kind == TokenBaseKind_ScopeOpen || 447 | peek->kind == TokenBaseKind_StatementClose){ 448 | index_new_note(index, state, Ii64(token), CodeIndexNote_Function, parent); 449 | printf("test"); 450 | } 451 | } 452 | } 453 | state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); 454 | } 455 | 456 | function void 457 | odin_parse_generic(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent, i64 search, i64 note) { 458 | Token *token = token_it_read(&state->it); 459 | generic_parse_inc(state); 460 | generic_parse_skip_soft_tokens(index, state); 461 | if (state->finished){ 462 | return; 463 | } 464 | 465 | Token *peek = token_it_read(&state->it); 466 | Token *reset_point = peek; 467 | 468 | i64 line_start = get_line_number_from_pos(app, index->buffer, peek->pos); 469 | 470 | if (peek != 0 && (peek->sub_kind == TokenCppKind_ColonColon || peek->kind == TokenCppKind_ColonColon)) { 471 | for (; peek != 0;) { 472 | generic_parse_inc(state); 473 | peek = token_it_read(&state->it); 474 | i64 current_line = get_line_number_from_pos(app, index->buffer, peek->pos); 475 | 476 | if (peek == 0 || state->finished || line_start != current_line) { 477 | break; 478 | } 479 | 480 | if (peek->sub_kind == search) { 481 | index_new_note(index, state, Ii64(token), note, parent); 482 | break; 483 | } 484 | } 485 | } 486 | 487 | state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); 488 | } 489 | 490 | function void 491 | odin_parse_generic(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent) { 492 | Token *token = token_it_read(&state->it); 493 | Token *reset_point = token; // NECESSARY 494 | generic_parse_inc(state); 495 | generic_parse_skip_soft_tokens(index, state); 496 | if (state->finished){ 497 | return; 498 | } 499 | 500 | Token *peek = token_it_read(&state->it); 501 | 502 | i64 line_start = get_line_number_from_pos(app, index->buffer, token->pos); 503 | 504 | if (peek != 0 && (peek->sub_kind == TokenCppKind_ColonColon || peek->kind == TokenCppKind_ColonColon)) { 505 | for (; peek != 0;) { 506 | generic_parse_inc(state); 507 | peek = token_it_read(&state->it); 508 | i64 current_line = get_line_number_from_pos(app, index->buffer, peek->pos); 509 | 510 | if (peek == 0 || state->finished || line_start != current_line) { 511 | break; 512 | } 513 | 514 | if (peek->kind == TokenBaseKind_Keyword) { 515 | String_Const_u8 lexeme = string_substring(state->contents, Ii64(peek)); 516 | if (string_match(lexeme, string_u8_litexpr("struct")) || 517 | string_match(lexeme, string_u8_litexpr("union")) || 518 | string_match(lexeme, string_u8_litexpr("enum"))){ 519 | index_new_note(index, state, Ii64(token), CodeIndexNote_Type, parent); 520 | break; 521 | } 522 | } 523 | 524 | if (peek->sub_kind == TokenCppKind_proc) { 525 | index_new_note(index, state, Ii64(token), CodeIndexNote_Function, parent); 526 | break; 527 | } 528 | } 529 | } 530 | 531 | state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); 532 | } 533 | 534 | function void 535 | odin_parse_consts(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state, Code_Index_Nest *parent) { 536 | Token *token = token_it_read(&state->it); 537 | generic_parse_inc(state); 538 | generic_parse_skip_soft_tokens(index, state); 539 | if (state->finished){ 540 | return; 541 | } 542 | 543 | Token *peek = token_it_read(&state->it); 544 | Token *reset_point = peek; 545 | 546 | i64 start_line = get_line_number_from_pos(app, index->buffer, token->pos); 547 | i64 colons = 0; 548 | 549 | for (;;) { 550 | if (peek == 0 || state->finished) { 551 | break; 552 | } 553 | 554 | if (peek->kind == TokenCppKind_Colon || peek->sub_kind == TokenCppKind_Colon) { 555 | colons += 1; 556 | } 557 | 558 | if (peek->kind == TokenCppKind_ColonColon || peek->sub_kind == TokenCppKind_ColonColon) { 559 | colons += 2; 560 | } 561 | 562 | if (colons > 1 && (peek->sub_kind == TokenCppKind_Semicolon || peek->kind == TokenCppKind_Semicolon)) { 563 | //Scratch_Block scratch(app); 564 | //String_Const_u8 text = push_stringf(scratch, "%d \n", (colons)); 565 | //print_message(app, text); 566 | index_new_note(index, state, Ii64(token), CodeIndexNote_Constant, parent); 567 | break; 568 | } 569 | 570 | generic_parse_inc(state); 571 | peek = token_it_read(&state->it); 572 | i64 current_line = get_line_number_from_pos(app, index->buffer, peek->pos); 573 | 574 | if (start_line != current_line) { 575 | break; 576 | } 577 | } 578 | 579 | state->it = token_iterator(state->it.user_id, state->it.tokens, state->it.count, reset_point); 580 | } 581 | 582 | function Code_Index_Nest* 583 | generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state); 584 | 585 | function Code_Index_Nest* 586 | generic_parse_preprocessor(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state); 587 | 588 | function Code_Index_Nest* 589 | generic_parse_scope(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state); 590 | 591 | function Code_Index_Nest* 592 | generic_parse_paren(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state); 593 | 594 | function Code_Index_Nest* 595 | generic_parse_statement(Code_Index_File *index, Generic_Parse_State *state){ 596 | Token *token = token_it_read(&state->it); 597 | Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); 598 | result->kind = CodeIndexNest_Statement; 599 | result->open = Ii64(token->pos); 600 | result->close = Ii64(max_i64); 601 | result->file = index; 602 | 603 | state->in_statement = true; 604 | 605 | for (;;){ 606 | generic_parse_skip_soft_tokens(index, state); 607 | token = token_it_read(&state->it); 608 | if (token == 0 || state->finished){ 609 | break; 610 | } 611 | 612 | if (state->in_preprocessor){ 613 | if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || 614 | token->kind == TokenBaseKind_Preprocessor){ 615 | result->is_closed = true; 616 | result->close = Ii64(token->pos); 617 | break; 618 | } 619 | } 620 | else{ 621 | if (token->kind == TokenBaseKind_Preprocessor){ 622 | result->is_closed = true; 623 | result->close = Ii64(token->pos); 624 | break; 625 | } 626 | } 627 | 628 | if (token->kind == TokenBaseKind_ScopeOpen || 629 | token->kind == TokenBaseKind_ScopeClose || 630 | token->kind == TokenBaseKind_ParentheticalOpen){ 631 | result->is_closed = true; 632 | result->close = Ii64(token->pos); 633 | break; 634 | } 635 | 636 | if (token->kind == TokenBaseKind_StatementClose){ 637 | result->is_closed = true; 638 | result->close = Ii64(token); 639 | generic_parse_inc(state); 640 | break; 641 | } 642 | 643 | generic_parse_inc(state); 644 | } 645 | 646 | state->in_statement = false; 647 | 648 | return(result); 649 | } 650 | 651 | function Code_Index_Nest* 652 | generic_parse_preprocessor(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state){ 653 | Token *token = token_it_read(&state->it); 654 | Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); 655 | result->kind = CodeIndexNest_Preprocessor; 656 | result->open = Ii64(token->pos); 657 | result->close = Ii64(max_i64); 658 | result->file = index; 659 | 660 | state->in_preprocessor = true; 661 | 662 | b32 potential_macro = false; 663 | if (state->do_cpp_parse){ 664 | if (token->sub_kind == TokenCppKind_PPDefine){ 665 | potential_macro = true; 666 | } 667 | } 668 | 669 | generic_parse_inc(state); 670 | for (;;){ 671 | generic_parse_skip_soft_tokens(index, state); 672 | token = token_it_read(&state->it); 673 | if (token == 0 || state->finished){ 674 | break; 675 | } 676 | 677 | if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || 678 | token->kind == TokenBaseKind_Preprocessor){ 679 | result->is_closed = true; 680 | result->close = Ii64(token->pos); 681 | break; 682 | } 683 | 684 | if (state->do_cpp_parse && potential_macro){ 685 | if (token->sub_kind == TokenCppKind_Identifier){ 686 | index_new_note(index, state, Ii64(token), CodeIndexNote_Macro, result); 687 | } 688 | potential_macro = false; 689 | } 690 | 691 | if (token->kind == TokenBaseKind_ScopeOpen){ 692 | Code_Index_Nest *nest = generic_parse_scope(app, index, state); 693 | nest->parent = result; 694 | code_index_push_nest(&result->nest_list, nest); 695 | continue; 696 | } 697 | 698 | if (token->kind == TokenBaseKind_ParentheticalOpen){ 699 | Code_Index_Nest *nest = generic_parse_paren(app, index, state); 700 | nest->parent = result; 701 | code_index_push_nest(&result->nest_list, nest); 702 | continue; 703 | } 704 | 705 | generic_parse_inc(state); 706 | } 707 | 708 | result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); 709 | 710 | state->in_preprocessor = false; 711 | 712 | return(result); 713 | } 714 | 715 | function Code_Index_Nest* 716 | generic_parse_scope(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state){ 717 | Token *token = token_it_read(&state->it); 718 | Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); 719 | result->kind = CodeIndexNest_Scope; 720 | result->open = Ii64(token); 721 | result->close = Ii64(max_i64); 722 | result->file = index; 723 | 724 | state->scope_counter += 1; 725 | 726 | generic_parse_inc(state); 727 | for (;;){ 728 | generic_parse_skip_soft_tokens(index, state); 729 | token = token_it_read(&state->it); 730 | if (token == 0 || state->finished){ 731 | break; 732 | } 733 | 734 | if (token->kind == TokenBaseKind_Identifier) { 735 | //odin_parse_generic(app, index, state, 0); 736 | } 737 | 738 | if (state->in_preprocessor){ 739 | if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || 740 | token->kind == TokenBaseKind_Preprocessor){ 741 | break; 742 | } 743 | } 744 | else{ 745 | if (token->kind == TokenBaseKind_Preprocessor){ 746 | Code_Index_Nest *nest = generic_parse_preprocessor(app, index, state); 747 | code_index_push_nest(&index->nest_list, nest); 748 | continue; 749 | } 750 | } 751 | 752 | if (token->kind == TokenBaseKind_ScopeClose){ 753 | result->is_closed = true; 754 | result->close = Ii64(token); 755 | generic_parse_inc(state); 756 | break; 757 | } 758 | 759 | if (token->kind == TokenBaseKind_ScopeOpen){ 760 | Code_Index_Nest *nest = generic_parse_scope(app, index, state); 761 | nest->parent = result; 762 | code_index_push_nest(&result->nest_list, nest); 763 | continue; 764 | } 765 | 766 | if (token->kind == TokenBaseKind_ParentheticalClose){ 767 | generic_parse_inc(state); 768 | continue; 769 | } 770 | 771 | if (token->kind == TokenBaseKind_ParentheticalOpen){ 772 | Code_Index_Nest *nest = generic_parse_paren(app, index, state); 773 | nest->parent = result; 774 | code_index_push_nest(&result->nest_list, nest); 775 | 776 | // NOTE(allen): after a parenthetical group we consider ourselves immediately 777 | // transitioning into a statement 778 | nest = generic_parse_statement(index, state); 779 | nest->parent = result; 780 | code_index_push_nest(&result->nest_list, nest); 781 | 782 | continue; 783 | } 784 | 785 | { 786 | Code_Index_Nest *nest = generic_parse_statement(index, state); 787 | nest->parent = result; 788 | code_index_push_nest(&result->nest_list, nest); 789 | } 790 | } 791 | 792 | result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); 793 | 794 | state->scope_counter -= 1; 795 | 796 | return(result); 797 | } 798 | 799 | function Code_Index_Nest* 800 | generic_parse_paren(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state){ 801 | Token *token = token_it_read(&state->it); 802 | Code_Index_Nest *result = push_array_zero(state->arena, Code_Index_Nest, 1); 803 | result->kind = CodeIndexNest_Paren; 804 | result->open = Ii64(token); 805 | result->close = Ii64(max_i64); 806 | result->file = index; 807 | 808 | i64 manifested_characters_on_line = 0; 809 | { 810 | u8 *ptr = state->prev_line_start; 811 | u8 *end_ptr = state->contents.str + token->pos; 812 | // NOTE(allen): Initial whitespace 813 | for (;ptr < end_ptr; ptr += 1){ 814 | if (!character_is_whitespace(*ptr)){ 815 | break; 816 | } 817 | } 818 | // NOTE(allen): Manifested characters 819 | manifested_characters_on_line = (i64)(end_ptr - ptr) + token->size; 820 | } 821 | 822 | state->paren_counter += 1; 823 | 824 | generic_parse_inc(state); 825 | for (;;){ 826 | generic_parse_skip_soft_tokens(index, state); 827 | token = token_it_read(&state->it); 828 | if (token == 0 || state->finished){ 829 | break; 830 | } 831 | 832 | if (state->in_preprocessor){ 833 | if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody) || 834 | token->kind == TokenBaseKind_Preprocessor){ 835 | break; 836 | } 837 | } 838 | else{ 839 | if (token->kind == TokenBaseKind_Preprocessor){ 840 | Code_Index_Nest *nest = generic_parse_preprocessor(app, index, state); 841 | code_index_push_nest(&index->nest_list, nest); 842 | continue; 843 | } 844 | } 845 | 846 | if (token->kind == TokenBaseKind_ParentheticalClose){ 847 | result->is_closed = true; 848 | result->close = Ii64(token); 849 | generic_parse_inc(state); 850 | break; 851 | } 852 | 853 | if (token->kind == TokenBaseKind_ScopeClose){ 854 | break; 855 | } 856 | 857 | if (token->kind == TokenBaseKind_ScopeOpen){ 858 | Code_Index_Nest *nest = generic_parse_scope(app, index, state); 859 | nest->parent = result; 860 | code_index_push_nest(&result->nest_list, nest); 861 | continue; 862 | } 863 | 864 | if (token->kind == TokenBaseKind_ParentheticalOpen){ 865 | Code_Index_Nest *nest = generic_parse_paren(app, index, state); 866 | nest->parent = result; 867 | code_index_push_nest(&result->nest_list, nest); 868 | continue; 869 | } 870 | 871 | generic_parse_inc(state); 872 | } 873 | 874 | result->nest_array = code_index_nest_ptr_array_from_list(state->arena, &result->nest_list); 875 | 876 | state->paren_counter -= 1; 877 | 878 | return(result); 879 | } 880 | 881 | function b32 882 | generic_parse_full_input_breaks(Application_Links *app, Code_Index_File *index, Generic_Parse_State *state, i32 limit){ 883 | b32 result = false; 884 | 885 | i64 first_index = token_it_index(&state->it); 886 | i64 one_past_last_index = first_index + limit; 887 | for (;;){ 888 | generic_parse_skip_soft_tokens(index, state); 889 | Token *token = token_it_read(&state->it); 890 | 891 | if (token == 0 || state->finished){ 892 | result = true; 893 | break; 894 | } 895 | 896 | if (token->kind == TokenBaseKind_Preprocessor){ 897 | Code_Index_Nest *nest = generic_parse_preprocessor(app, index, state); 898 | code_index_push_nest(&index->nest_list, nest); 899 | } 900 | // TODO(Skytrias): do function check in scope 901 | else if (token->kind == TokenBaseKind_ScopeOpen){ 902 | Code_Index_Nest *nest = generic_parse_scope(app, index, state); 903 | code_index_push_nest(&index->nest_list, nest); 904 | } 905 | else if (token->kind == TokenBaseKind_ParentheticalOpen){ 906 | Code_Index_Nest *nest = generic_parse_paren(app, index, state); 907 | code_index_push_nest(&index->nest_list, nest); 908 | } 909 | else if (state->do_cpp_parse){ 910 | if (token->sub_kind == TokenCppKind_Identifier) { 911 | odin_parse_generic(app, index, state, 0); 912 | odin_parse_consts(app, index, state, 0); 913 | } else { 914 | generic_parse_inc(state); 915 | } 916 | } 917 | else{ 918 | generic_parse_inc(state); 919 | } 920 | 921 | i64 index = token_it_index(&state->it); 922 | if (index >= one_past_last_index){ 923 | token = token_it_read(&state->it); 924 | if (token == 0){ 925 | result = true; 926 | } 927 | break; 928 | } 929 | } 930 | 931 | if (result){ 932 | index->nest_array = code_index_nest_ptr_array_from_list(state->arena, &index->nest_list); 933 | index->note_array = code_index_note_ptr_array_from_list(state->arena, &index->note_list); 934 | } 935 | 936 | return(result); 937 | } 938 | 939 | 940 | //////////////////////////////// 941 | // NOTE(allen): Not sure 942 | 943 | function void 944 | default_comment_index(Application_Links *app, Arena *arena, Code_Index_File *index, Token *token, String_Const_u8 contents){ 945 | 946 | } 947 | 948 | function void 949 | generic_parse_init(Application_Links *app, Arena *arena, String_Const_u8 contents, Token_Array *tokens, Generic_Parse_State *state){ 950 | generic_parse_init(app, arena, contents, tokens, default_comment_index, state); 951 | } 952 | 953 | 954 | //////////////////////////////// 955 | // NOTE(allen): Virtual Whitespace Layout 956 | 957 | function Token_Pair 958 | layout_token_pair(Token_Array *tokens, i64 pos){ 959 | Token_Pair result = {}; 960 | Token_Iterator_Array it = token_iterator_pos(0, tokens, pos); 961 | Token *b = token_it_read(&it); 962 | if (b != 0){ 963 | if (b->kind == TokenBaseKind_Whitespace){ 964 | token_it_inc_non_whitespace(&it); 965 | b = token_it_read(&it); 966 | } 967 | } 968 | token_it_dec_non_whitespace(&it); 969 | Token *a = token_it_read(&it); 970 | if (a != 0){ 971 | result.a = *a; 972 | } 973 | if (b != 0){ 974 | result.b = *b; 975 | } 976 | return(result); 977 | } 978 | 979 | function f32 980 | layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 regular_indent, b32 *unresolved_dependence){ 981 | f32 result = 0.f; 982 | if (nest != 0){ 983 | switch (nest->kind){ 984 | case CodeIndexNest_Scope: 985 | case CodeIndexNest_Preprocessor: 986 | { 987 | result = layout_index_x_shift(app, reflex, nest->parent, pos, regular_indent, unresolved_dependence); 988 | if (nest->open.min < pos && nest->open.max <= pos && 989 | (!nest->is_closed || pos < nest->close.min)){ 990 | result += regular_indent; 991 | } 992 | }break; 993 | 994 | case CodeIndexNest_Statement: 995 | { 996 | result = layout_index_x_shift(app, reflex, nest->parent, pos, regular_indent, unresolved_dependence); 997 | if (nest->open.min < pos && nest->open.max <= pos && 998 | (!nest->is_closed || pos < nest->close.min)){ 999 | result += regular_indent; 1000 | } 1001 | }break; 1002 | 1003 | case CodeIndexNest_Paren: 1004 | { 1005 | Rect_f32 box = layout_reflex_get_rect(app, reflex, nest->open.max - 1, unresolved_dependence); 1006 | result = box.x1; 1007 | }break; 1008 | } 1009 | } 1010 | return(result); 1011 | } 1012 | 1013 | function f32 1014 | layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_Nest *nest, i64 pos, f32 regular_indent){ 1015 | b32 ignore; 1016 | return(layout_index_x_shift(app, reflex, nest, pos, regular_indent, &ignore)); 1017 | } 1018 | 1019 | function f32 1020 | layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 regular_indent, b32 *unresolved_dependence){ 1021 | f32 indent = 0; 1022 | Code_Index_Nest *nest = code_index_get_nest(file, pos); 1023 | if (nest != 0){ 1024 | indent = layout_index_x_shift(app, reflex, nest, pos, regular_indent, unresolved_dependence); 1025 | } 1026 | return(indent); 1027 | } 1028 | 1029 | function f32 1030 | layout_index_x_shift(Application_Links *app, Layout_Reflex *reflex, Code_Index_File *file, i64 pos, f32 regular_indent){ 1031 | b32 ignore; 1032 | return(layout_index_x_shift(app, reflex, file, pos, regular_indent, &ignore)); 1033 | } 1034 | 1035 | function void 1036 | layout_index__emit_chunk(LefRig_TopBot_Layout_Vars *pos_vars, Face_ID face, Arena *arena, u8 *text_str, i64 range_first, u8 *ptr, u8 *end, Layout_Item_List *list){ 1037 | for (;ptr < end;){ 1038 | Character_Consume_Result consume = utf8_consume(ptr, (u64)(end - ptr)); 1039 | if (consume.codepoint != '\r'){ 1040 | i64 index = layout_index_from_ptr(ptr, text_str, range_first); 1041 | if (consume.codepoint != max_u32){ 1042 | lr_tb_write(pos_vars, face, arena, list, index, consume.codepoint); 1043 | } 1044 | else{ 1045 | lr_tb_write_byte(pos_vars, face, arena, list, index, *ptr); 1046 | } 1047 | } 1048 | ptr += consume.inc; 1049 | } 1050 | } 1051 | 1052 | function i32 1053 | layout_token_score_wrap_token(Token_Pair *pair, Token_Cpp_Kind kind){ 1054 | i32 result = 0; 1055 | if (pair->a.sub_kind != kind && pair->b.sub_kind == kind){ 1056 | result -= 1; 1057 | } 1058 | else if (pair->a.sub_kind == kind && pair->b.sub_kind != kind){ 1059 | result += 1; 1060 | } 1061 | return(result); 1062 | } 1063 | 1064 | function Layout_Item_List 1065 | layout_index__inner(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Code_Index_File *file, Layout_Wrap_Kind kind){ 1066 | Scratch_Block scratch(app, arena); 1067 | 1068 | Token_Array tokens = get_token_array_from_buffer(app, buffer); 1069 | Token_Array *tokens_ptr = &tokens; 1070 | 1071 | Layout_Item_List list = get_empty_item_list(range); 1072 | String_Const_u8 text = push_buffer_range(app, scratch, buffer, range); 1073 | 1074 | Face_Advance_Map advance_map = get_face_advance_map(app, face); 1075 | Face_Metrics metrics = get_face_metrics(app, face); 1076 | f32 tab_width = (f32)def_get_config_u64(app, vars_save_string_lit("default_tab_width")); 1077 | tab_width = clamp_bot(1, tab_width); 1078 | LefRig_TopBot_Layout_Vars pos_vars = get_lr_tb_layout_vars(&advance_map, &metrics, tab_width, width); 1079 | 1080 | u64 vw_indent = def_get_config_u64(app, vars_save_string_lit("virtual_whitespace_regular_indent")); 1081 | f32 regular_indent = metrics.space_advance*vw_indent; 1082 | f32 wrap_align_x = width - metrics.normal_advance; 1083 | 1084 | Layout_Reflex reflex = get_layout_reflex(&list, buffer, width, face); 1085 | 1086 | if (text.size == 0){ 1087 | lr_tb_write_blank(&pos_vars, face, arena, &list, range.start); 1088 | } 1089 | else{ 1090 | b32 first_of_the_line = true; 1091 | Newline_Layout_Vars newline_vars = get_newline_layout_vars(); 1092 | 1093 | u8 *ptr = text.str; 1094 | u8 *end_ptr = ptr + text.size; 1095 | u8 *word_ptr = ptr; 1096 | 1097 | u8 *pending_wrap_ptr = ptr; 1098 | f32 pending_wrap_x = 0.f; 1099 | i32 pending_wrap_paren_nest_count = 0; 1100 | i32 pending_wrap_token_score = 0; 1101 | f32 pending_wrap_accumulated_w = 0.f; 1102 | 1103 | start: 1104 | if (ptr == end_ptr){ 1105 | i64 index = layout_index_from_ptr(ptr, text.str, range.first); 1106 | f32 shift = layout_index_x_shift(app, &reflex, file, index, regular_indent); 1107 | lr_tb_advance_x_without_item(&pos_vars, shift); 1108 | goto finish; 1109 | } 1110 | 1111 | if (!character_is_whitespace(*ptr)){ 1112 | i64 index = layout_index_from_ptr(ptr, text.str, range.first); 1113 | f32 shift = layout_index_x_shift(app, &reflex, file, index, regular_indent); 1114 | lr_tb_advance_x_without_item(&pos_vars, shift); 1115 | goto consuming_non_whitespace; 1116 | } 1117 | 1118 | { 1119 | for (;ptr < end_ptr; ptr += 1){ 1120 | if (!character_is_whitespace(*ptr)){ 1121 | pending_wrap_ptr = ptr; 1122 | word_ptr = ptr; 1123 | i64 index = layout_index_from_ptr(ptr, text.str, range.first); 1124 | f32 shift = layout_index_x_shift(app, &reflex, file, index, regular_indent); 1125 | lr_tb_advance_x_without_item(&pos_vars, shift); 1126 | goto consuming_non_whitespace; 1127 | } 1128 | if (*ptr == '\r'){ 1129 | i64 index = layout_index_from_ptr(ptr, text.str, range.first); 1130 | newline_layout_consume_CR(&newline_vars, index); 1131 | } 1132 | else if (*ptr == '\n'){ 1133 | pending_wrap_ptr = ptr; 1134 | i64 index = layout_index_from_ptr(ptr, text.str, range.first); 1135 | f32 shift = layout_index_x_shift(app, &reflex, file, index, regular_indent); 1136 | lr_tb_advance_x_without_item(&pos_vars, shift); 1137 | goto consuming_normal_whitespace; 1138 | } 1139 | } 1140 | 1141 | if (ptr == end_ptr){ 1142 | pending_wrap_ptr = ptr; 1143 | i64 index = layout_index_from_ptr(ptr - 1, text.str, range.first); 1144 | f32 shift = layout_index_x_shift(app, &reflex, file, index, regular_indent); 1145 | lr_tb_advance_x_without_item(&pos_vars, shift); 1146 | goto finish; 1147 | } 1148 | } 1149 | 1150 | consuming_non_whitespace: 1151 | { 1152 | for (;ptr <= end_ptr; ptr += 1){ 1153 | if (ptr == end_ptr || character_is_whitespace(*ptr)){ 1154 | break; 1155 | } 1156 | } 1157 | 1158 | // NOTE(allen): measure this word 1159 | newline_layout_consume_default(&newline_vars); 1160 | String_Const_u8 word = SCu8(word_ptr, ptr); 1161 | u8 *word_end = ptr; 1162 | { 1163 | f32 word_advance = 0.f; 1164 | ptr = word.str; 1165 | for (;ptr < word_end;){ 1166 | Character_Consume_Result consume = utf8_consume(ptr, (u64)(word_end - ptr)); 1167 | if (consume.codepoint != max_u32){ 1168 | word_advance += lr_tb_advance(&pos_vars, face, consume.codepoint); 1169 | } 1170 | else{ 1171 | word_advance += lr_tb_advance_byte(&pos_vars); 1172 | } 1173 | ptr += consume.inc; 1174 | } 1175 | pending_wrap_accumulated_w += word_advance; 1176 | } 1177 | 1178 | if (!first_of_the_line && (kind == Layout_Wrapped) && lr_tb_crosses_width(&pos_vars, pending_wrap_accumulated_w)){ 1179 | i64 index = layout_index_from_ptr(pending_wrap_ptr, text.str, range.first); 1180 | lr_tb_align_rightward(&pos_vars, wrap_align_x); 1181 | lr_tb_write_ghost(&pos_vars, face, arena, &list, index, '\\'); 1182 | 1183 | lr_tb_next_line(&pos_vars); 1184 | #if 0 1185 | f32 shift = layout_index_x_shift(app, &reflex, file, index, regular_indent); 1186 | lr_tb_advance_x_without_item(&pos_vars, shift); 1187 | #endif 1188 | 1189 | ptr = pending_wrap_ptr; 1190 | pending_wrap_accumulated_w = 0.f; 1191 | first_of_the_line = true; 1192 | goto start; 1193 | } 1194 | } 1195 | 1196 | consuming_normal_whitespace: 1197 | for (; ptr < end_ptr; ptr += 1){ 1198 | if (!character_is_whitespace(*ptr)){ 1199 | u8 *new_wrap_ptr = ptr; 1200 | 1201 | i64 index = layout_index_from_ptr(new_wrap_ptr, text.str, range.first); 1202 | Code_Index_Nest *new_wrap_nest = code_index_get_nest(file, index); 1203 | b32 invalid_wrap_x = false; 1204 | f32 new_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, regular_indent, &invalid_wrap_x); 1205 | if (invalid_wrap_x){ 1206 | new_wrap_x = max_f32; 1207 | } 1208 | 1209 | i32 new_wrap_paren_nest_count = 0; 1210 | for (Code_Index_Nest *nest = new_wrap_nest; 1211 | nest != 0; 1212 | nest = nest->parent){ 1213 | if (nest->kind == CodeIndexNest_Paren){ 1214 | new_wrap_paren_nest_count += 1; 1215 | } 1216 | } 1217 | 1218 | Token_Pair new_wrap_token_pair = layout_token_pair(tokens_ptr, index); 1219 | 1220 | // TODO(allen): pull out the token scoring part and make it replacable for other 1221 | // language's token based wrap scoring needs. 1222 | i32 token_score = 0; 1223 | if (new_wrap_token_pair.a.kind == TokenBaseKind_Keyword){ 1224 | if (new_wrap_token_pair.b.kind == TokenBaseKind_ParentheticalOpen || 1225 | new_wrap_token_pair.b.kind == TokenBaseKind_Keyword){ 1226 | token_score -= 2; 1227 | } 1228 | } 1229 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Eq); 1230 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_PlusEq); 1231 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_MinusEq); 1232 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_StarEq); 1233 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_DivEq); 1234 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_ModEq); 1235 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_LeftLeftEq); 1236 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_RightRightEq); 1237 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Comma); 1238 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_AndAnd); 1239 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_OrOr); 1240 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Ternary); 1241 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Colon); 1242 | token_score += layout_token_score_wrap_token(&new_wrap_token_pair, TokenCppKind_Semicolon); 1243 | 1244 | i32 new_wrap_token_score = token_score; 1245 | 1246 | b32 new_wrap_ptr_is_better = false; 1247 | if (first_of_the_line){ 1248 | new_wrap_ptr_is_better = true; 1249 | } 1250 | else{ 1251 | if (new_wrap_token_score > pending_wrap_token_score){ 1252 | new_wrap_ptr_is_better = true; 1253 | } 1254 | else if (new_wrap_token_score == pending_wrap_token_score){ 1255 | f32 new_score = new_wrap_paren_nest_count*10.f + new_wrap_x; 1256 | f32 old_score = pending_wrap_paren_nest_count*10.f + pending_wrap_x + metrics.normal_advance*4.f + pending_wrap_accumulated_w*0.5f; 1257 | 1258 | if (new_score < old_score){ 1259 | new_wrap_ptr_is_better = true; 1260 | } 1261 | } 1262 | } 1263 | 1264 | if (new_wrap_ptr_is_better){ 1265 | layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, new_wrap_ptr, &list); 1266 | first_of_the_line = false; 1267 | 1268 | pending_wrap_ptr = new_wrap_ptr; 1269 | pending_wrap_paren_nest_count = new_wrap_paren_nest_count; 1270 | pending_wrap_x = layout_index_x_shift(app, &reflex, new_wrap_nest, index, regular_indent); 1271 | pending_wrap_paren_nest_count = new_wrap_paren_nest_count; 1272 | pending_wrap_token_score = new_wrap_token_score; 1273 | pending_wrap_accumulated_w = 0.f; 1274 | } 1275 | 1276 | word_ptr = ptr; 1277 | goto consuming_non_whitespace; 1278 | } 1279 | 1280 | i64 index = layout_index_from_ptr(ptr, text.str, range.first); 1281 | switch (*ptr){ 1282 | default: 1283 | { 1284 | newline_layout_consume_default(&newline_vars); 1285 | pending_wrap_accumulated_w += lr_tb_advance(&pos_vars, face, *ptr); 1286 | }break; 1287 | 1288 | case '\r': 1289 | { 1290 | newline_layout_consume_CR(&newline_vars, index); 1291 | }break; 1292 | 1293 | case '\n': 1294 | { 1295 | layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); 1296 | pending_wrap_ptr = ptr + 1; 1297 | pending_wrap_accumulated_w = 0.f; 1298 | 1299 | u64 newline_index = newline_layout_consume_LF(&newline_vars, index); 1300 | lr_tb_write_blank(&pos_vars, face, arena, &list, newline_index); 1301 | lr_tb_next_line(&pos_vars); 1302 | first_of_the_line = true; 1303 | ptr += 1; 1304 | goto start; 1305 | }break; 1306 | } 1307 | } 1308 | 1309 | finish: 1310 | if (newline_layout_consume_finish(&newline_vars)){ 1311 | layout_index__emit_chunk(&pos_vars, face, arena, text.str, range.first, pending_wrap_ptr, ptr, &list); 1312 | i64 index = layout_index_from_ptr(ptr, text.str, range.first); 1313 | lr_tb_write_blank(&pos_vars, face, arena, &list, index); 1314 | } 1315 | } 1316 | 1317 | layout_item_list_finish(&list, -pos_vars.line_to_text_shift); 1318 | 1319 | return(list); 1320 | } 1321 | 1322 | function Layout_Item_List 1323 | layout_virt_indent_index(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width, Layout_Wrap_Kind kind){ 1324 | Layout_Item_List result = {}; 1325 | 1326 | b32 enable_virtual_whitespace = def_get_config_b32(vars_save_string_lit("enable_virtual_whitespace")); 1327 | if (enable_virtual_whitespace){ 1328 | code_index_lock(); 1329 | Code_Index_File *file = code_index_get_file(buffer); 1330 | if (file != 0){ 1331 | result = layout_index__inner(app, arena, buffer, range, face, width, file, kind); 1332 | } 1333 | code_index_unlock(); 1334 | if (file == 0){ 1335 | result = layout_virt_indent_literal(app, arena, buffer, range, face, width, kind); 1336 | } 1337 | } 1338 | else{ 1339 | result = layout_basic(app, arena, buffer, range, face, width, kind); 1340 | } 1341 | 1342 | return(result); 1343 | } 1344 | 1345 | function Layout_Item_List 1346 | layout_virt_indent_index_unwrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ 1347 | return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Unwrapped)); 1348 | } 1349 | 1350 | function Layout_Item_List 1351 | layout_virt_indent_index_wrapped(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ 1352 | return(layout_virt_indent_index(app, arena, buffer, range, face, width, Layout_Wrapped)); 1353 | } 1354 | 1355 | function Layout_Item_List 1356 | layout_virt_indent_index_generic(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range, Face_ID face, f32 width){ 1357 | Managed_Scope scope = buffer_get_managed_scope(app, buffer); 1358 | b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); 1359 | b32 wrap_lines = (wrap_lines_ptr != 0 && *wrap_lines_ptr); 1360 | return(layout_virt_indent_index(app, arena, buffer, range, face, width, wrap_lines?Layout_Wrapped:Layout_Unwrapped)); 1361 | } 1362 | 1363 | CUSTOM_COMMAND_SIG(toggle_virtual_whitespace) 1364 | CUSTOM_DOC("Toggles virtual whitespace for all files.") 1365 | { 1366 | String_ID key = vars_save_string_lit("enable_virtual_whitespace"); 1367 | b32 enable_virtual_whitespace = def_get_config_b32(key); 1368 | def_set_config_b32(key, !enable_virtual_whitespace); 1369 | } 1370 | 1371 | // BOTTOM 1372 | -------------------------------------------------------------------------------- /custom/4coder_code_index.h: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_code_index.h - Generic code indexing system for layout, definition jumps, etc. 3 | */ 4 | 5 | // TOP 6 | 7 | #if !defined(FCODER_CODE_INDEX_H) 8 | #define FCODER_CODE_INDEX_H 9 | 10 | struct Code_Index_Nest_List{ 11 | struct Code_Index_Nest *first; 12 | struct Code_Index_Nest *last; 13 | i32 count; 14 | }; 15 | 16 | struct Code_Index_Nest_Ptr_Array{ 17 | struct Code_Index_Nest **ptrs; 18 | i32 count; 19 | }; 20 | 21 | typedef i32 Code_Index_Nest_Kind; 22 | enum{ 23 | CodeIndexNest_Scope, 24 | CodeIndexNest_Paren, 25 | CodeIndexNest_Preprocessor, 26 | CodeIndexNest_Statement, 27 | }; 28 | 29 | struct Code_Index_Nest{ 30 | Code_Index_Nest *next; 31 | 32 | Code_Index_Nest_Kind kind; 33 | b32 is_closed; 34 | Range_i64 open; 35 | Range_i64 close; 36 | 37 | struct Code_Index_File *file; 38 | Code_Index_Nest *parent; 39 | 40 | Code_Index_Nest_List nest_list; 41 | Code_Index_Nest_Ptr_Array nest_array; 42 | }; 43 | 44 | typedef i64 Code_Index_Note_Kind; 45 | enum{ 46 | CodeIndexNote_Type, 47 | CodeIndexNote_Function, 48 | CodeIndexNote_Macro, 49 | CodeIndexNote_4coderCommand, 50 | CodeIndexNote_Constant, // NOTE(Skytrias): NEW 51 | }; 52 | 53 | struct Code_Index_Note{ 54 | Code_Index_Note *next; 55 | Code_Index_Note_Kind note_kind; 56 | Range_i64 pos; 57 | String_Const_u8 text; 58 | struct Code_Index_File *file; 59 | Code_Index_Nest *parent; 60 | 61 | Code_Index_Note *prev_in_hash; 62 | Code_Index_Note *next_in_hash; 63 | }; 64 | 65 | struct Code_Index_Note_List{ 66 | Code_Index_Note *first; 67 | Code_Index_Note *last; 68 | i32 count; 69 | }; 70 | 71 | struct Code_Index_Note_Ptr_Array{ 72 | Code_Index_Note **ptrs; 73 | i32 count; 74 | }; 75 | 76 | struct Code_Index_File { 77 | Code_Index_Nest_List nest_list; 78 | Code_Index_Nest_Ptr_Array nest_array; 79 | Code_Index_Note_List note_list; 80 | Code_Index_Note_Ptr_Array note_array; 81 | Buffer_ID buffer; 82 | }; 83 | 84 | struct Code_Index_File_Storage{ 85 | Code_Index_File_Storage *next; 86 | Code_Index_File_Storage *prev; 87 | Arena arena; 88 | Code_Index_File *file; 89 | }; 90 | 91 | struct Code_Index{ 92 | System_Mutex mutex; 93 | Arena node_arena; 94 | Table_u64_u64 buffer_to_index_file; 95 | Code_Index_File_Storage *free_storage; 96 | Code_Index_File_Storage *storage_first; 97 | Code_Index_File_Storage *storage_last; 98 | i32 storage_count; 99 | 100 | Code_Index_Note_List name_hash[4099]; 101 | }; 102 | 103 | //////////////////////////////// 104 | 105 | typedef void Generic_Parse_Comment_Function(Application_Links *app, Arena *arena, Code_Index_File *index, 106 | Token *token, String_Const_u8 contents); 107 | 108 | struct Generic_Parse_State{ 109 | Application_Links *app; 110 | Arena *arena; 111 | String_Const_u8 contents; 112 | Token_Iterator_Array it; 113 | Generic_Parse_Comment_Function *handle_comment; 114 | u8 *prev_line_start; 115 | b32 finished; 116 | 117 | i32 scope_counter; 118 | i32 paren_counter; 119 | b32 in_preprocessor; 120 | b32 in_statement; 121 | 122 | b32 do_cpp_parse; 123 | }; 124 | 125 | #endif 126 | 127 | // BOTTOM 128 | 129 | -------------------------------------------------------------------------------- /custom/4coder_default_hooks.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_default_hooks.cpp - Sets up the hooks for the default framework. 3 | */ 4 | 5 | // solarized dark 6 | ARGB_Color argb_function = 0xFF268bd2; 7 | ARGB_Color argb_type = 0xFF859900; // struct, enum, union 8 | ARGB_Color argb_const = 0xffcb4b16; // "::" ending with ";" 9 | ARGB_Color argb_highlight = 0x44cb4b16; 10 | ARGB_Color argb_highlight_minor = 0x33cb4b16; 11 | 12 | static f32 13 | MinimumF32(f32 a, f32 b) 14 | { 15 | return a < b ? a : b; 16 | } 17 | 18 | static f32 19 | MaximumF32(f32 a, f32 b) 20 | { 21 | return a > b ? a : b; 22 | } 23 | 24 | enum F4_RangeHighlightKind 25 | { 26 | F4_RangeHighlightKind_Whole, 27 | F4_RangeHighlightKind_Underline, 28 | }; 29 | 30 | function void 31 | F4_RenderRangeHighlight(Application_Links *app, View_ID view_id, Text_Layout_ID text_layout_id, 32 | Range_i64 range, F4_RangeHighlightKind kind, ARGB_Color color) 33 | { 34 | Rect_f32 range_start_rect = text_layout_character_on_screen(app, text_layout_id, range.start); 35 | Rect_f32 range_end_rect = text_layout_character_on_screen(app, text_layout_id, range.end-1); 36 | Rect_f32 total_range_rect = {0}; 37 | total_range_rect.x0 = MinimumF32(range_start_rect.x0, range_end_rect.x0); 38 | total_range_rect.y0 = MinimumF32(range_start_rect.y0, range_end_rect.y0); 39 | total_range_rect.x1 = MaximumF32(range_start_rect.x1, range_end_rect.x1); 40 | total_range_rect.y1 = MaximumF32(range_start_rect.y1, range_end_rect.y1); 41 | 42 | switch (kind) { 43 | case F4_RangeHighlightKind_Underline: { 44 | total_range_rect.y0 = total_range_rect.y1 - 1.f; 45 | total_range_rect.y1 += 1.f; 46 | } break; 47 | } 48 | draw_rectangle(app, total_range_rect, 4.f, color); 49 | } 50 | 51 | // TOP 52 | 53 | CUSTOM_COMMAND_SIG(default_startup) 54 | CUSTOM_DOC("Default command for responding to a startup event") 55 | { 56 | ProfileScope(app, "default startup"); 57 | User_Input input = get_current_input(app); 58 | if (match_core_code(&input, CoreCode_Startup)){ 59 | String_Const_u8_Array file_names = input.event.core.file_names; 60 | load_themes_default_folder(app); 61 | default_4coder_initialize(app, file_names); 62 | default_4coder_side_by_side_panels(app, file_names); 63 | b32 auto_load = def_get_config_b32(vars_save_string_lit("automatically_load_project")); 64 | if (auto_load){ 65 | load_project(app); 66 | } 67 | } 68 | 69 | { 70 | def_audio_init(); 71 | 72 | Scratch_Block scratch(app); 73 | FILE *file = def_search_normal_fopen(scratch, "audio_test/raygun_zap.wav", "rb"); 74 | if (file != 0){ 75 | Audio_Clip test_clip = audio_clip_from_wav_FILE(&global_permanent_arena, file); 76 | fclose(file); 77 | 78 | local_persist Audio_Control test_control = {}; 79 | test_control.channel_volume[0] = 1.f; 80 | test_control.channel_volume[1] = 1.f; 81 | def_audio_play_clip(test_clip, &test_control); 82 | } 83 | } 84 | 85 | { 86 | def_enable_virtual_whitespace = def_get_config_b32(vars_save_string_lit("enable_virtual_whitespace")); 87 | clear_all_layouts(app); 88 | } 89 | } 90 | 91 | CUSTOM_COMMAND_SIG(default_try_exit) 92 | CUSTOM_DOC("Default command for responding to a try-exit event") 93 | { 94 | User_Input input = get_current_input(app); 95 | if (match_core_code(&input, CoreCode_TryExit)){ 96 | b32 do_exit = true; 97 | if (!allow_immediate_close_without_checking_for_changes){ 98 | b32 has_unsaved_changes = false; 99 | for (Buffer_ID buffer = get_buffer_next(app, 0, Access_Always); 100 | buffer != 0; 101 | buffer = get_buffer_next(app, buffer, Access_Always)){ 102 | Dirty_State dirty = buffer_get_dirty_state(app, buffer); 103 | if (HasFlag(dirty, DirtyState_UnsavedChanges)){ 104 | has_unsaved_changes = true; 105 | break; 106 | } 107 | } 108 | if (has_unsaved_changes){ 109 | View_ID view = get_active_view(app, Access_Always); 110 | do_exit = do_4coder_close_user_check(app, view); 111 | } 112 | } 113 | if (do_exit){ 114 | hard_exit(app); 115 | } 116 | } 117 | } 118 | 119 | function Implicit_Map_Result 120 | default_implicit_map(Application_Links *app, String_ID lang, String_ID mode, Input_Event *event){ 121 | Implicit_Map_Result result = {}; 122 | 123 | View_ID view = get_this_ctx_view(app, Access_Always); 124 | 125 | Command_Map_ID map_id = default_get_map_id(app, view); 126 | Command_Binding binding = map_get_binding_recursive(&framework_mapping, map_id, event); 127 | 128 | // TODO(allen): map_id <-> map name? 129 | result.map = 0; 130 | result.command = binding.custom; 131 | 132 | return(result); 133 | } 134 | 135 | CUSTOM_COMMAND_SIG(default_view_input_handler) 136 | CUSTOM_DOC("Input consumption loop for default view behavior") 137 | { 138 | Scratch_Block scratch(app); 139 | default_input_handler_init(app, scratch); 140 | 141 | View_ID view = get_this_ctx_view(app, Access_Always); 142 | Managed_Scope scope = view_get_managed_scope(app, view); 143 | 144 | for (;;){ 145 | // NOTE(allen): Get input 146 | User_Input input = get_next_input(app, EventPropertyGroup_Any, 0); 147 | if (input.abort){ 148 | break; 149 | } 150 | 151 | ProfileScopeNamed(app, "before view input", view_input_profile); 152 | 153 | // NOTE(allen): Mouse Suppression 154 | Event_Property event_properties = get_event_properties(&input.event); 155 | if (suppressing_mouse && (event_properties & EventPropertyGroup_AnyMouseEvent) != 0){ 156 | continue; 157 | } 158 | 159 | // NOTE(allen): Get binding 160 | if (implicit_map_function == 0){ 161 | implicit_map_function = default_implicit_map; 162 | } 163 | Implicit_Map_Result map_result = implicit_map_function(app, 0, 0, &input.event); 164 | if (map_result.command == 0){ 165 | leave_current_input_unhandled(app); 166 | continue; 167 | } 168 | 169 | // NOTE(allen): Run the command and pre/post command stuff 170 | default_pre_command(app, scope); 171 | ProfileCloseNow(view_input_profile); 172 | map_result.command(app); 173 | ProfileScope(app, "after view input"); 174 | default_post_command(app, scope); 175 | } 176 | } 177 | 178 | function void 179 | code_index_update_tick(Application_Links *app){ 180 | Scratch_Block scratch(app); 181 | for (Buffer_Modified_Node *node = global_buffer_modified_set.first; 182 | node != 0; 183 | node = node->next){ 184 | Temp_Memory_Block temp(scratch); 185 | Buffer_ID buffer_id = node->buffer; 186 | 187 | String_Const_u8 contents = push_whole_buffer(app, scratch, buffer_id); 188 | Token_Array tokens = get_token_array_from_buffer(app, buffer_id); 189 | if (tokens.count == 0){ 190 | continue; 191 | } 192 | 193 | Arena arena = make_arena_system(KB(16)); 194 | Code_Index_File *index = push_array_zero(&arena, Code_Index_File, 1); 195 | index->buffer = buffer_id; 196 | 197 | Generic_Parse_State state = {}; 198 | generic_parse_init(app, &arena, contents, &tokens, &state); 199 | // TODO(allen): Actually determine this in a fair way. 200 | // Maybe switch to an enum? 201 | // Actually probably a pointer to a struct that defines the language. 202 | state.do_cpp_parse = true; 203 | generic_parse_full_input_breaks(app, index, &state, max_i32); 204 | 205 | code_index_lock(); 206 | code_index_set_file(buffer_id, arena, index); 207 | code_index_unlock(); 208 | buffer_clear_layout_cache(app, buffer_id); 209 | } 210 | 211 | buffer_modified_set_clear(); 212 | } 213 | 214 | function void 215 | default_tick(Application_Links *app, Frame_Info frame_info){ 216 | //////////////////////////////// 217 | // NOTE(allen): Update code index 218 | 219 | code_index_update_tick(app); 220 | 221 | //////////////////////////////// 222 | // NOTE(allen): Update fade ranges 223 | 224 | if (tick_all_fade_ranges(app, frame_info.animation_dt)){ 225 | animate_in_n_milliseconds(app, 0); 226 | } 227 | 228 | //////////////////////////////// 229 | // NOTE(allen): Clear layouts if virtual whitespace setting changed. 230 | 231 | { 232 | b32 enable_virtual_whitespace = def_get_config_b32(vars_save_string_lit("enable_virtual_whitespace")); 233 | if (enable_virtual_whitespace != def_enable_virtual_whitespace){ 234 | def_enable_virtual_whitespace = enable_virtual_whitespace; 235 | clear_all_layouts(app); 236 | } 237 | } 238 | } 239 | 240 | function Rect_f32 241 | default_buffer_region(Application_Links *app, View_ID view_id, Rect_f32 region){ 242 | Buffer_ID buffer = view_get_buffer(app, view_id, Access_Always); 243 | Face_ID face_id = get_face_id(app, buffer); 244 | Face_Metrics metrics = get_face_metrics(app, face_id); 245 | f32 line_height = metrics.line_height; 246 | f32 digit_advance = metrics.decimal_digit_advance; 247 | 248 | // NOTE(allen): margins 249 | region = rect_inner(region, 3.f); 250 | 251 | // NOTE(allen): file bar 252 | b64 showing_file_bar = false; 253 | if (view_get_setting(app, view_id, ViewSetting_ShowFileBar, &showing_file_bar) && 254 | showing_file_bar){ 255 | Rect_f32_Pair pair = layout_file_bar_on_top(region, line_height); 256 | region = pair.max; 257 | } 258 | 259 | // NOTE(allen): query bars 260 | { 261 | Query_Bar *space[32]; 262 | Query_Bar_Ptr_Array query_bars = {}; 263 | query_bars.ptrs = space; 264 | if (get_active_query_bars(app, view_id, ArrayCount(space), &query_bars)){ 265 | Rect_f32_Pair pair = layout_query_bar_on_top(region, line_height, query_bars.count); 266 | region = pair.max; 267 | } 268 | } 269 | 270 | // NOTE(allen): FPS hud 271 | if (show_fps_hud){ 272 | Rect_f32_Pair pair = layout_fps_hud_on_bottom(region, line_height); 273 | region = pair.min; 274 | } 275 | 276 | // NOTE(allen): line numbers 277 | b32 show_line_number_margins = def_get_config_b32(vars_save_string_lit("show_line_number_margins")); 278 | if (show_line_number_margins){ 279 | Rect_f32_Pair pair = layout_line_number_margin(app, buffer, region, digit_advance); 280 | region = pair.max; 281 | } 282 | 283 | return(region); 284 | } 285 | 286 | function void 287 | recursive_nest_highlight(Application_Links *app, Text_Layout_ID layout_id, Range_i64 range, 288 | Code_Index_Nest_Ptr_Array *array, i32 counter){ 289 | Code_Index_Nest **ptr = array->ptrs; 290 | Code_Index_Nest **ptr_end = ptr + array->count; 291 | 292 | for (;ptr < ptr_end; ptr += 1){ 293 | Code_Index_Nest *nest = *ptr; 294 | if (!nest->is_closed){ 295 | break; 296 | } 297 | if (range.first <= nest->close.max){ 298 | break; 299 | } 300 | } 301 | 302 | ARGB_Color argb = finalize_color(defcolor_text_cycle, counter); 303 | 304 | for (;ptr < ptr_end; ptr += 1){ 305 | Code_Index_Nest *nest = *ptr; 306 | if (range.max <= nest->open.min){ 307 | break; 308 | } 309 | 310 | paint_text_color(app, layout_id, nest->open, argb); 311 | if (nest->is_closed){ 312 | paint_text_color(app, layout_id, nest->close, argb); 313 | } 314 | recursive_nest_highlight(app, layout_id, range, &nest->nest_array, counter + 1); 315 | } 316 | } 317 | 318 | function void 319 | recursive_nest_highlight(Application_Links *app, Text_Layout_ID layout_id, Range_i64 range, 320 | Code_Index_File *file){ 321 | recursive_nest_highlight(app, layout_id, range, &file->nest_array, 0); 322 | } 323 | 324 | function void 325 | default_render_buffer(Application_Links *app, View_ID view_id, Face_ID face_id, 326 | Buffer_ID buffer, Text_Layout_ID text_layout_id, 327 | Rect_f32 rect){ 328 | ProfileScope(app, "render buffer"); 329 | 330 | View_ID active_view = get_active_view(app, Access_Always); 331 | b32 is_active_view = (active_view == view_id); 332 | Rect_f32 prev_clip = draw_set_clip(app, rect); 333 | 334 | Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id); 335 | 336 | // NOTE(allen): Cursor shape 337 | Face_Metrics metrics = get_face_metrics(app, face_id); 338 | u64 cursor_roundness_100 = def_get_config_u64(app, vars_save_string_lit("cursor_roundness")); 339 | f32 cursor_roundness = metrics.normal_advance*cursor_roundness_100*0.01f; 340 | f32 mark_thickness = (f32)def_get_config_u64(app, vars_save_string_lit("mark_thickness")); 341 | 342 | // NOTE(allen): Token colorizing 343 | Token_Array token_array = get_token_array_from_buffer(app, buffer); 344 | if (token_array.tokens != 0){ 345 | draw_cpp_token_colors(app, text_layout_id, &token_array); 346 | 347 | // NOTE(allen): Scan for TODOs and NOTEs 348 | b32 use_comment_keyword = def_get_config_b32(vars_save_string_lit("use_comment_keyword")); 349 | if (use_comment_keyword){ 350 | Comment_Highlight_Pair pairs[] = { 351 | {string_u8_litexpr("NOTE"), finalize_color(defcolor_comment_pop, 0)}, 352 | {string_u8_litexpr("TODO"), finalize_color(defcolor_comment_pop, 1)}, 353 | }; 354 | draw_comment_highlights(app, buffer, text_layout_id, &token_array, pairs, ArrayCount(pairs)); 355 | } 356 | 357 | #if 1 358 | // TODO(allen): Put in 4coder_draw.cpp 359 | // NOTE(allen): Color functions 360 | 361 | Scratch_Block scratch(app); 362 | //ARGB_Color argb_struct = 0xFFFF00FF; 363 | 364 | // nord 365 | //global u32 FUNCTION_HIGHLIGHT_COLOR = 0xFF5e81ac; 366 | //global u32 STRUCT_HIGHLIGHT_COLOR = 0xFFbf616a; 367 | 368 | // horizon 369 | //global u32 FUNCTION_HIGHLIGHT_COLOR = 0xFF5577e8; 370 | //global u32 STRUCT_HIGHLIGHT_COLOR = 0xFF77e855; 371 | 372 | Token_Iterator_Array it = token_iterator_pos(0, &token_array, visible_range.first); 373 | for (;;){ 374 | if (!token_it_inc_non_whitespace(&it)){ 375 | break; 376 | } 377 | Token *token = token_it_read(&it); 378 | String_Const_u8 lexeme = push_token_lexeme(app, scratch, buffer, token); 379 | Code_Index_Note *note = code_index_note_from_string(lexeme); 380 | if (note != 0) { 381 | if (note->note_kind == CodeIndexNote_Function) { 382 | paint_text_color(app, text_layout_id, Ii64_size(token->pos, token->size), argb_function); 383 | } else if (note->note_kind == CodeIndexNote_Type) { 384 | paint_text_color(app, text_layout_id, Ii64_size(token->pos, token->size), argb_type); 385 | } else if (note->note_kind == CodeIndexNote_Constant) { 386 | paint_text_color(app, text_layout_id, Ii64_size(token->pos, token->size), argb_const); 387 | } 388 | } 389 | } 390 | #endif 391 | } 392 | else{ 393 | paint_text_color_fcolor(app, text_layout_id, visible_range, fcolor_id(defcolor_text_default)); 394 | } 395 | 396 | i64 cursor_pos = view_correct_cursor(app, view_id); 397 | view_correct_mark(app, view_id); 398 | 399 | // NOTE(allen): Scope highlight 400 | b32 use_scope_highlight = def_get_config_b32(vars_save_string_lit("use_scope_highlight")); 401 | if (use_scope_highlight){ 402 | Color_Array colors = finalize_color_array(defcolor_back_cycle); 403 | draw_scope_highlight(app, buffer, text_layout_id, cursor_pos, colors.vals, colors.count); 404 | } 405 | 406 | b32 use_error_highlight = def_get_config_b32(vars_save_string_lit("use_error_highlight")); 407 | b32 use_jump_highlight = def_get_config_b32(vars_save_string_lit("use_jump_highlight")); 408 | if (use_error_highlight || use_jump_highlight){ 409 | // NOTE(allen): Error highlight 410 | String_Const_u8 name = string_u8_litexpr("*compilation*"); 411 | Buffer_ID compilation_buffer = get_buffer_by_name(app, name, Access_Always); 412 | if (use_error_highlight){ 413 | draw_jump_highlights(app, buffer, text_layout_id, compilation_buffer, 414 | fcolor_id(defcolor_highlight_junk)); 415 | } 416 | 417 | // NOTE(allen): Search highlight 418 | if (use_jump_highlight){ 419 | Buffer_ID jump_buffer = get_locked_jump_buffer(app); 420 | if (jump_buffer != compilation_buffer){ 421 | draw_jump_highlights(app, buffer, text_layout_id, jump_buffer, 422 | fcolor_id(defcolor_highlight_white)); 423 | } 424 | } 425 | } 426 | 427 | // NOTE(Skytrias): new 428 | // NOTE(jack): Token Occurance Highlight 429 | { 430 | Scratch_Block scratch(app); 431 | 432 | // NOTE(jack): Get the active cursor's token string 433 | Buffer_ID active_cursor_buffer = view_get_buffer(app, active_view, Access_Always); 434 | i64 active_cursor_pos = view_get_cursor_pos(app, active_view); 435 | Token_Array active_cursor_buffer_tokens = get_token_array_from_buffer(app, active_cursor_buffer); 436 | Token_Iterator_Array active_cursor_it = token_iterator_pos(0, &active_cursor_buffer_tokens, active_cursor_pos); 437 | Token *active_cursor_token = token_it_read(&active_cursor_it); 438 | 439 | String_Const_u8 active_cursor_string = string_u8_litexpr(""); 440 | if(active_cursor_token) 441 | { 442 | active_cursor_string = push_buffer_range(app, scratch, active_cursor_buffer, Ii64(active_cursor_token)); 443 | 444 | // Loop the visible tokens 445 | Range_i64 local_visible_range = text_layout_get_visible_range(app, text_layout_id); 446 | i64 first_index = token_index_from_pos(&token_array, local_visible_range.first); 447 | Token_Iterator_Array it = token_iterator_index(0, &token_array, first_index); 448 | for (;;) 449 | { 450 | Token *token = token_it_read(&it); 451 | if(!token || token->pos >= local_visible_range.one_past_last) 452 | { 453 | break; 454 | } 455 | 456 | if (token->kind == TokenBaseKind_Identifier) 457 | { 458 | Range_i64 token_range = Ii64(token); 459 | String_Const_u8 token_string = push_buffer_range(app, scratch, buffer, token_range); 460 | 461 | // NOTE(jack) If this is the buffers cursor token, highlight it with an Underline 462 | if (range_contains(token_range, view_get_cursor_pos(app, view_id))) 463 | { 464 | F4_RenderRangeHighlight(app, view_id, text_layout_id, 465 | token_range, F4_RangeHighlightKind_Whole, 466 | argb_highlight); 467 | } 468 | // NOTE(jack): If the token matches the active buffer token. highlight it with a Minor Underline 469 | else if(active_cursor_token->kind == TokenBaseKind_Identifier && 470 | string_match(token_string, active_cursor_string)) 471 | { 472 | F4_RenderRangeHighlight(app, view_id, text_layout_id, 473 | token_range, F4_RangeHighlightKind_Whole, 474 | argb_highlight_minor); 475 | 476 | } 477 | } 478 | 479 | if(!token_it_inc_non_whitespace(&it)) 480 | { 481 | break; 482 | } 483 | } 484 | } 485 | } 486 | 487 | // NOTE(allen): Color parens 488 | b32 use_paren_helper = def_get_config_b32(vars_save_string_lit("use_paren_helper")); 489 | if (use_paren_helper){ 490 | Color_Array colors = finalize_color_array(defcolor_text_cycle); 491 | draw_paren_highlight(app, buffer, text_layout_id, cursor_pos, colors.vals, colors.count); 492 | } 493 | 494 | // NOTE(allen): Line highlight 495 | b32 highlight_line_at_cursor = def_get_config_b32(vars_save_string_lit("highlight_line_at_cursor")); 496 | if (highlight_line_at_cursor && is_active_view){ 497 | i64 line_number = get_line_number_from_pos(app, buffer, cursor_pos); 498 | draw_line_highlight(app, text_layout_id, line_number, fcolor_id(defcolor_highlight_cursor_line)); 499 | } 500 | 501 | // NOTE(allen): Whitespace highlight 502 | b64 show_whitespace = false; 503 | view_get_setting(app, view_id, ViewSetting_ShowWhitespace, &show_whitespace); 504 | if (show_whitespace){ 505 | if (token_array.tokens == 0){ 506 | draw_whitespace_highlight(app, buffer, text_layout_id, cursor_roundness); 507 | } 508 | else{ 509 | draw_whitespace_highlight(app, text_layout_id, &token_array, cursor_roundness); 510 | } 511 | } 512 | 513 | // NOTE(allen): Cursor 514 | switch (fcoder_mode){ 515 | case FCoderMode_Original: 516 | { 517 | draw_original_4coder_style_cursor_mark_highlight(app, view_id, is_active_view, buffer, text_layout_id, cursor_roundness, mark_thickness); 518 | }break; 519 | case FCoderMode_NotepadLike: 520 | { 521 | draw_notepad_style_cursor_highlight(app, view_id, buffer, text_layout_id, cursor_roundness); 522 | }break; 523 | } 524 | 525 | // NOTE(allen): Fade ranges 526 | paint_fade_ranges(app, text_layout_id, buffer); 527 | 528 | // NOTE(allen): put the actual text on the actual screen 529 | draw_text_layout_default(app, text_layout_id); 530 | 531 | draw_set_clip(app, prev_clip); 532 | } 533 | 534 | function Rect_f32 535 | default_draw_query_bars(Application_Links *app, Rect_f32 region, View_ID view_id, Face_ID face_id){ 536 | Face_Metrics face_metrics = get_face_metrics(app, face_id); 537 | f32 line_height = face_metrics.line_height; 538 | 539 | Query_Bar *space[32]; 540 | Query_Bar_Ptr_Array query_bars = {}; 541 | query_bars.ptrs = space; 542 | if (get_active_query_bars(app, view_id, ArrayCount(space), &query_bars)){ 543 | for (i32 i = 0; i < query_bars.count; i += 1){ 544 | Rect_f32_Pair pair = layout_query_bar_on_top(region, line_height, 1); 545 | draw_query_bar(app, query_bars.ptrs[i], face_id, pair.min); 546 | region = pair.max; 547 | } 548 | } 549 | return(region); 550 | } 551 | 552 | function void 553 | default_render_caller(Application_Links *app, Frame_Info frame_info, View_ID view_id){ 554 | ProfileScope(app, "default render caller"); 555 | View_ID active_view = get_active_view(app, Access_Always); 556 | b32 is_active_view = (active_view == view_id); 557 | 558 | Rect_f32 region = draw_background_and_margin(app, view_id, is_active_view); 559 | Rect_f32 prev_clip = draw_set_clip(app, region); 560 | 561 | Buffer_ID buffer = view_get_buffer(app, view_id, Access_Always); 562 | Face_ID face_id = get_face_id(app, buffer); 563 | Face_Metrics face_metrics = get_face_metrics(app, face_id); 564 | f32 line_height = face_metrics.line_height; 565 | f32 digit_advance = face_metrics.decimal_digit_advance; 566 | 567 | // NOTE(allen): file bar 568 | b64 showing_file_bar = false; 569 | if (view_get_setting(app, view_id, ViewSetting_ShowFileBar, &showing_file_bar) && showing_file_bar){ 570 | Rect_f32_Pair pair = layout_file_bar_on_top(region, line_height); 571 | draw_file_bar(app, view_id, buffer, face_id, pair.min); 572 | region = pair.max; 573 | } 574 | 575 | Buffer_Scroll scroll = view_get_buffer_scroll(app, view_id); 576 | 577 | Buffer_Point_Delta_Result delta = delta_apply(app, view_id, 578 | frame_info.animation_dt, scroll); 579 | if (!block_match_struct(&scroll.position, &delta.point)){ 580 | block_copy_struct(&scroll.position, &delta.point); 581 | view_set_buffer_scroll(app, view_id, scroll, SetBufferScroll_NoCursorChange); 582 | } 583 | if (delta.still_animating){ 584 | animate_in_n_milliseconds(app, 0); 585 | } 586 | 587 | // NOTE(allen): query bars 588 | region = default_draw_query_bars(app, region, view_id, face_id); 589 | 590 | // NOTE(allen): FPS hud 591 | if (show_fps_hud){ 592 | Rect_f32_Pair pair = layout_fps_hud_on_bottom(region, line_height); 593 | draw_fps_hud(app, frame_info, face_id, pair.max); 594 | region = pair.min; 595 | animate_in_n_milliseconds(app, 1000); 596 | } 597 | 598 | // NOTE(allen): layout line numbers 599 | b32 show_line_number_margins = def_get_config_b32(vars_save_string_lit("show_line_number_margins")); 600 | Rect_f32 line_number_rect = {}; 601 | if (show_line_number_margins){ 602 | Rect_f32_Pair pair = layout_line_number_margin(app, buffer, region, digit_advance); 603 | line_number_rect = pair.min; 604 | region = pair.max; 605 | } 606 | 607 | // NOTE(allen): begin buffer render 608 | Buffer_Point buffer_point = scroll.position; 609 | Text_Layout_ID text_layout_id = text_layout_create(app, buffer, region, buffer_point); 610 | 611 | // NOTE(allen): draw line numbers 612 | if (show_line_number_margins){ 613 | draw_line_number_margin(app, view_id, buffer, face_id, text_layout_id, line_number_rect); 614 | } 615 | 616 | // NOTE(allen): draw the buffer 617 | default_render_buffer(app, view_id, face_id, buffer, text_layout_id, region); 618 | 619 | text_layout_free(app, text_layout_id); 620 | draw_set_clip(app, prev_clip); 621 | } 622 | 623 | function void 624 | default_whole_screen_render_caller(Application_Links *app, Frame_Info frame_info){ 625 | #if 0 626 | Rect_f32 region = global_get_screen_rectangle(app); 627 | Vec2_f32 center = rect_center(region); 628 | 629 | Face_ID face_id = get_face_id(app, 0); 630 | Scratch_Block scratch(app); 631 | draw_string_oriented(app, face_id, finalize_color(defcolor_text_default, 0), 632 | SCu8("Hello, World!"), center - V2f32(200.f, 300.f), 633 | 0, V2f32(0.f, -1.f)); 634 | draw_string_oriented(app, face_id, finalize_color(defcolor_text_default, 0), 635 | SCu8("Hello, World!"), center - V2f32(240.f, 300.f), 636 | 0, V2f32(0.f, 1.f)); 637 | draw_string_oriented(app, face_id, finalize_color(defcolor_text_default, 0), 638 | SCu8("Hello, World!"), center - V2f32(400.f, 400.f), 639 | 0, V2f32(-1.f, 0.f)); 640 | draw_string_oriented(app, face_id, finalize_color(defcolor_text_default, 0), 641 | SCu8("Hello, World!"), center - V2f32(400.f, -100.f), 642 | 0, V2f32(cos_f32(pi_f32*.333f), sin_f32(pi_f32*.333f))); 643 | #endif 644 | } 645 | 646 | HOOK_SIG(default_view_adjust){ 647 | // NOTE(allen): Called whenever the view layout/sizes have been modified, 648 | // including by full window resize. 649 | return(0); 650 | } 651 | 652 | BUFFER_NAME_RESOLVER_SIG(default_buffer_name_resolution){ 653 | ProfileScope(app, "default buffer name resolution"); 654 | if (conflict_count > 1){ 655 | // List of unresolved conflicts 656 | Scratch_Block scratch(app); 657 | 658 | i32 *unresolved = push_array(scratch, i32, conflict_count); 659 | i32 unresolved_count = conflict_count; 660 | for (i32 i = 0; i < conflict_count; ++i){ 661 | unresolved[i] = i; 662 | } 663 | 664 | // Resolution Loop 665 | i32 x = 0; 666 | for (;;){ 667 | // Resolution Pass 668 | ++x; 669 | for (i32 i = 0; i < unresolved_count; ++i){ 670 | i32 conflict_index = unresolved[i]; 671 | Buffer_Name_Conflict_Entry *conflict = &conflicts[conflict_index]; 672 | 673 | u64 size = conflict->base_name.size; 674 | size = clamp_top(size, conflict->unique_name_capacity); 675 | conflict->unique_name_len_in_out = size; 676 | block_copy(conflict->unique_name_in_out, conflict->base_name.str, size); 677 | 678 | if (conflict->file_name.str != 0){ 679 | Temp_Memory_Block temp(scratch); 680 | String_Const_u8 uniqueifier = {}; 681 | 682 | String_Const_u8 file_name = string_remove_last_folder(conflict->file_name); 683 | if (file_name.size > 0){ 684 | file_name = string_chop(file_name, 1); 685 | u8 *end = file_name.str + file_name.size; 686 | b32 past_the_end = false; 687 | for (i32 j = 0; j < x; ++j){ 688 | file_name = string_remove_last_folder(file_name); 689 | if (j + 1 < x){ 690 | file_name = string_chop(file_name, 1); 691 | } 692 | if (file_name.size == 0){ 693 | if (j + 1 < x){ 694 | past_the_end = true; 695 | } 696 | break; 697 | } 698 | } 699 | u8 *start = file_name.str + file_name.size; 700 | 701 | uniqueifier = SCu8(start, end); 702 | if (past_the_end){ 703 | uniqueifier = push_u8_stringf(scratch, "%.*s~%d", 704 | string_expand(uniqueifier), i); 705 | } 706 | } 707 | else{ 708 | uniqueifier = push_u8_stringf(scratch, "%d", i); 709 | } 710 | 711 | String_u8 builder = Su8(conflict->unique_name_in_out, 712 | conflict->unique_name_len_in_out, 713 | conflict->unique_name_capacity); 714 | string_append(&builder, string_u8_litexpr(" <")); 715 | string_append(&builder, uniqueifier); 716 | string_append(&builder, string_u8_litexpr(">")); 717 | conflict->unique_name_len_in_out = builder.size; 718 | } 719 | } 720 | 721 | // Conflict Check Pass 722 | b32 has_conflicts = false; 723 | for (i32 i = 0; i < unresolved_count; ++i){ 724 | i32 conflict_index = unresolved[i]; 725 | Buffer_Name_Conflict_Entry *conflict = &conflicts[conflict_index]; 726 | String_Const_u8 conflict_name = SCu8(conflict->unique_name_in_out, 727 | conflict->unique_name_len_in_out); 728 | 729 | b32 hit_conflict = false; 730 | if (conflict->file_name.str != 0){ 731 | for (i32 j = 0; j < unresolved_count; ++j){ 732 | if (i == j) continue; 733 | 734 | i32 conflict_j_index = unresolved[j]; 735 | Buffer_Name_Conflict_Entry *conflict_j = &conflicts[conflict_j_index]; 736 | 737 | String_Const_u8 conflict_name_j = SCu8(conflict_j->unique_name_in_out, 738 | conflict_j->unique_name_len_in_out); 739 | 740 | if (string_match(conflict_name, conflict_name_j)){ 741 | hit_conflict = true; 742 | break; 743 | } 744 | } 745 | } 746 | 747 | if (hit_conflict){ 748 | has_conflicts = true; 749 | } 750 | else{ 751 | --unresolved_count; 752 | unresolved[i] = unresolved[unresolved_count]; 753 | --i; 754 | } 755 | } 756 | 757 | if (!has_conflicts){ 758 | break; 759 | } 760 | } 761 | } 762 | } 763 | 764 | function void 765 | parse_async__inner(Async_Context *actx, Buffer_ID buffer_id, 766 | String_Const_u8 contents, Token_Array *tokens, i32 limit_factor){ 767 | Application_Links *app = actx->app; 768 | ProfileBlock(app, "async parse"); 769 | 770 | Arena arena = make_arena_system(KB(16)); 771 | Code_Index_File *index = push_array_zero(&arena, Code_Index_File, 1); 772 | index->buffer = buffer_id; 773 | 774 | Generic_Parse_State state = {}; 775 | generic_parse_init(app, &arena, contents, tokens, &state); 776 | 777 | b32 canceled = false; 778 | 779 | for (;;){ 780 | if (generic_parse_full_input_breaks(app, index, &state, limit_factor)){ 781 | break; 782 | } 783 | if (async_check_canceled(actx)){ 784 | canceled = true; 785 | break; 786 | } 787 | } 788 | 789 | if (!canceled){ 790 | acquire_global_frame_mutex(app); 791 | code_index_lock(); 792 | code_index_set_file(buffer_id, arena, index); 793 | code_index_unlock(); 794 | buffer_clear_layout_cache(app, buffer_id); 795 | release_global_frame_mutex(app); 796 | } 797 | else{ 798 | linalloc_clear(&arena); 799 | } 800 | } 801 | 802 | function void 803 | do_full_lex_async__inner(Async_Context *actx, Buffer_ID buffer_id){ 804 | Application_Links *app = actx->app; 805 | ProfileScope(app, "async lex"); 806 | Scratch_Block scratch(app); 807 | 808 | String_Const_u8 contents = {}; 809 | { 810 | ProfileBlock(app, "async lex contents (before mutex)"); 811 | acquire_global_frame_mutex(app); 812 | ProfileBlock(app, "async lex contents (after mutex)"); 813 | contents = push_whole_buffer(app, scratch, buffer_id); 814 | release_global_frame_mutex(app); 815 | } 816 | 817 | i32 limit_factor = 10000; 818 | 819 | Token_List list = {}; 820 | b32 canceled = false; 821 | 822 | Lex_State_Cpp state = {}; 823 | lex_full_input_cpp_init(&state, contents); 824 | for (;;){ 825 | ProfileBlock(app, "async lex block"); 826 | if (lex_full_input_cpp_breaks(scratch, &list, &state, limit_factor)){ 827 | break; 828 | } 829 | if (async_check_canceled(actx)){ 830 | canceled = true; 831 | break; 832 | } 833 | } 834 | 835 | if (!canceled){ 836 | ProfileBlock(app, "async lex save results (before mutex)"); 837 | acquire_global_frame_mutex(app); 838 | ProfileBlock(app, "async lex save results (after mutex)"); 839 | Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); 840 | if (scope != 0){ 841 | Base_Allocator *allocator = managed_scope_allocator(app, scope); 842 | Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); 843 | base_free(allocator, tokens_ptr->tokens); 844 | Token_Array tokens = {}; 845 | tokens.tokens = base_array(allocator, Token, list.total_count); 846 | tokens.count = list.total_count; 847 | tokens.max = list.total_count; 848 | token_fill_memory_from_list(tokens.tokens, &list); 849 | block_copy_struct(tokens_ptr, &tokens); 850 | } 851 | buffer_mark_as_modified(buffer_id); 852 | release_global_frame_mutex(app); 853 | } 854 | } 855 | 856 | function void 857 | do_full_lex_async(Async_Context *actx, String_Const_u8 data){ 858 | if (data.size == sizeof(Buffer_ID)){ 859 | Buffer_ID buffer = *(Buffer_ID*)data.str; 860 | do_full_lex_async__inner(actx, buffer); 861 | } 862 | } 863 | 864 | BUFFER_HOOK_SIG(default_begin_buffer){ 865 | ProfileScope(app, "begin buffer"); 866 | 867 | Scratch_Block scratch(app); 868 | 869 | b32 treat_as_code = false; 870 | String_Const_u8 file_name = push_buffer_file_name(app, scratch, buffer_id); 871 | if (file_name.size > 0){ 872 | String_Const_u8 treat_as_code_string = def_get_config_string(scratch, vars_save_string_lit("treat_as_code")); 873 | String_Const_u8_Array extensions = parse_extension_line_to_extension_list(app, scratch, treat_as_code_string); 874 | String_Const_u8 ext = string_file_extension(file_name); 875 | for (i32 i = 0; i < extensions.count; ++i){ 876 | if (string_match(ext, extensions.strings[i])){ 877 | 878 | if (string_match(ext, string_u8_litexpr("cpp")) || 879 | string_match(ext, string_u8_litexpr("h")) || 880 | string_match(ext, string_u8_litexpr("c")) || 881 | string_match(ext, string_u8_litexpr("hpp")) || 882 | string_match(ext, string_u8_litexpr("cc")) || 883 | string_match(ext, string_u8_litexpr("odin"))) { 884 | treat_as_code = true; 885 | } 886 | 887 | #if 0 888 | treat_as_code = true; 889 | 890 | if (string_match(ext, string_u8_litexpr("cs"))){ 891 | if (parse_context_language_cs == 0){ 892 | init_language_cs(app); 893 | } 894 | parse_context_id = parse_context_language_cs; 895 | } 896 | 897 | if (string_match(ext, string_u8_litexpr("java"))){ 898 | if (parse_context_language_java == 0){ 899 | init_language_java(app); 900 | } 901 | parse_context_id = parse_context_language_java; 902 | } 903 | 904 | if (string_match(ext, string_u8_litexpr("rs"))){ 905 | if (parse_context_language_rust == 0){ 906 | init_language_rust(app); 907 | } 908 | parse_context_id = parse_context_language_rust; 909 | } 910 | 911 | if (string_match(ext, string_u8_litexpr("cpp")) || 912 | string_match(ext, string_u8_litexpr("h")) || 913 | string_match(ext, string_u8_litexpr("c")) || 914 | string_match(ext, string_u8_litexpr("hpp")) || 915 | string_match(ext, string_u8_litexpr("cc"))){ 916 | if (parse_context_language_cpp == 0){ 917 | init_language_cpp(app); 918 | } 919 | parse_context_id = parse_context_language_cpp; 920 | } 921 | 922 | // TODO(NAME): Real GLSL highlighting 923 | if (string_match(ext, string_u8_litexpr("glsl"))){ 924 | if (parse_context_language_cpp == 0){ 925 | init_language_cpp(app); 926 | } 927 | parse_context_id = parse_context_language_cpp; 928 | } 929 | 930 | // TODO(NAME): Real Objective-C highlighting 931 | if (string_match(ext, string_u8_litexpr("m"))){ 932 | if (parse_context_language_cpp == 0){ 933 | init_language_cpp(app); 934 | } 935 | parse_context_id = parse_context_language_cpp; 936 | } 937 | #endif 938 | 939 | break; 940 | } 941 | } 942 | } 943 | 944 | String_ID file_map_id = vars_save_string_lit("keys_file"); 945 | String_ID code_map_id = vars_save_string_lit("keys_code"); 946 | 947 | Command_Map_ID map_id = (treat_as_code)?(code_map_id):(file_map_id); 948 | Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); 949 | Command_Map_ID *map_id_ptr = scope_attachment(app, scope, buffer_map_id, Command_Map_ID); 950 | *map_id_ptr = map_id; 951 | 952 | Line_Ending_Kind setting = guess_line_ending_kind_from_buffer(app, buffer_id); 953 | Line_Ending_Kind *eol_setting = scope_attachment(app, scope, buffer_eol_setting, Line_Ending_Kind); 954 | *eol_setting = setting; 955 | 956 | // NOTE(allen): Decide buffer settings 957 | b32 wrap_lines = true; 958 | b32 use_lexer = false; 959 | if (treat_as_code){ 960 | wrap_lines = def_get_config_b32(vars_save_string_lit("enable_code_wrapping")); 961 | use_lexer = true; 962 | } 963 | 964 | String_Const_u8 buffer_name = push_buffer_base_name(app, scratch, buffer_id); 965 | if (buffer_name.size > 0 && buffer_name.str[0] == '*' && buffer_name.str[buffer_name.size - 1] == '*'){ 966 | wrap_lines = def_get_config_b32(vars_save_string_lit("enable_output_wrapping")); 967 | } 968 | 969 | if (use_lexer){ 970 | ProfileBlock(app, "begin buffer kick off lexer"); 971 | Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); 972 | *lex_task_ptr = async_task_no_dep(&global_async_system, do_full_lex_async, make_data_struct(&buffer_id)); 973 | } 974 | 975 | { 976 | b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32); 977 | *wrap_lines_ptr = wrap_lines; 978 | } 979 | 980 | if (use_lexer){ 981 | buffer_set_layout(app, buffer_id, layout_virt_indent_index_generic); 982 | } 983 | else{ 984 | if (treat_as_code){ 985 | buffer_set_layout(app, buffer_id, layout_virt_indent_literal_generic); 986 | } 987 | else{ 988 | buffer_set_layout(app, buffer_id, layout_generic); 989 | } 990 | } 991 | 992 | // no meaning for return 993 | return(0); 994 | } 995 | 996 | BUFFER_HOOK_SIG(default_new_file){ 997 | Scratch_Block scratch(app); 998 | String_Const_u8 file_name = push_buffer_base_name(app, scratch, buffer_id); 999 | if (!string_match(string_postfix(file_name, 2), string_u8_litexpr(".h"))) { 1000 | return(0); 1001 | } 1002 | 1003 | List_String_Const_u8 guard_list = {}; 1004 | for (u64 i = 0; i < file_name.size; ++i){ 1005 | u8 c[2] = {}; 1006 | u64 c_size = 1; 1007 | u8 ch = file_name.str[i]; 1008 | if ('A' <= ch && ch <= 'Z'){ 1009 | c_size = 2; 1010 | c[0] = '_'; 1011 | c[1] = ch; 1012 | } 1013 | else if ('0' <= ch && ch <= '9'){ 1014 | c[0] = ch; 1015 | } 1016 | else if ('a' <= ch && ch <= 'z'){ 1017 | c[0] = ch - ('a' - 'A'); 1018 | } 1019 | else{ 1020 | c[0] = '_'; 1021 | } 1022 | String_Const_u8 part = push_string_copy(scratch, SCu8(c, c_size)); 1023 | string_list_push(scratch, &guard_list, part); 1024 | } 1025 | String_Const_u8 guard = string_list_flatten(scratch, guard_list); 1026 | 1027 | Date_Time date_time = system_now_date_time_universal(); 1028 | date_time = system_local_date_time_from_universal(&date_time); 1029 | String_Const_u8 date_string = date_time_format(scratch, "month day yyyy h:mimi ampm", &date_time); 1030 | 1031 | Buffer_Insertion insert = begin_buffer_insertion_at_buffered(app, buffer_id, 0, scratch, KB(16)); 1032 | insertf(&insert, 1033 | "/* date = %.*s */\n" 1034 | "\n", 1035 | string_expand(date_string)); 1036 | insertf(&insert, 1037 | "#ifndef %.*s\n" 1038 | "#define %.*s\n" 1039 | "\n" 1040 | "#endif //%.*s\n", 1041 | string_expand(guard), 1042 | string_expand(guard), 1043 | string_expand(guard)); 1044 | end_buffer_insertion(&insert); 1045 | 1046 | return(0); 1047 | } 1048 | 1049 | BUFFER_HOOK_SIG(default_file_save){ 1050 | // buffer_id 1051 | ProfileScope(app, "default file save"); 1052 | 1053 | b32 auto_indent = def_get_config_b32(vars_save_string_lit("automatically_indent_text_on_save")); 1054 | b32 is_virtual = def_get_config_b32(vars_save_string_lit("enable_virtual_whitespace")); 1055 | if (auto_indent && is_virtual){ 1056 | auto_indent_buffer(app, buffer_id, buffer_range(app, buffer_id)); 1057 | } 1058 | 1059 | Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); 1060 | Line_Ending_Kind *eol = scope_attachment(app, scope, buffer_eol_setting, 1061 | Line_Ending_Kind); 1062 | switch (*eol){ 1063 | case LineEndingKind_LF: 1064 | { 1065 | rewrite_lines_to_lf(app, buffer_id); 1066 | }break; 1067 | case LineEndingKind_CRLF: 1068 | { 1069 | rewrite_lines_to_crlf(app, buffer_id); 1070 | }break; 1071 | } 1072 | 1073 | // no meaning for return 1074 | return(0); 1075 | } 1076 | 1077 | BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){ 1078 | // buffer_id, new_range, original_size 1079 | ProfileScope(app, "default edit range"); 1080 | 1081 | Range_i64 old_range = Ii64(old_cursor_range.min.pos, old_cursor_range.max.pos); 1082 | 1083 | buffer_shift_fade_ranges(buffer_id, old_range.max, (new_range.max - old_range.max)); 1084 | 1085 | { 1086 | code_index_lock(); 1087 | Code_Index_File *file = code_index_get_file(buffer_id); 1088 | if (file != 0){ 1089 | code_index_shift(file, old_range, range_size(new_range)); 1090 | } 1091 | code_index_unlock(); 1092 | } 1093 | 1094 | i64 insert_size = range_size(new_range); 1095 | i64 text_shift = replace_range_shift(old_range, insert_size); 1096 | 1097 | Scratch_Block scratch(app); 1098 | 1099 | Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); 1100 | Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); 1101 | 1102 | Base_Allocator *allocator = managed_scope_allocator(app, scope); 1103 | b32 do_full_relex = false; 1104 | 1105 | if (async_task_is_running_or_pending(&global_async_system, *lex_task_ptr)){ 1106 | async_task_cancel(app, &global_async_system, *lex_task_ptr); 1107 | buffer_unmark_as_modified(buffer_id); 1108 | do_full_relex = true; 1109 | *lex_task_ptr = 0; 1110 | } 1111 | 1112 | Token_Array *ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); 1113 | if (ptr != 0 && ptr->tokens != 0){ 1114 | ProfileBlockNamed(app, "attempt resync", profile_attempt_resync); 1115 | 1116 | i64 token_index_first = token_relex_first(ptr, old_range.first, 1); 1117 | i64 token_index_resync_guess = 1118 | token_relex_resync(ptr, old_range.one_past_last, 16); 1119 | 1120 | if (token_index_resync_guess - token_index_first >= 4000){ 1121 | do_full_relex = true; 1122 | } 1123 | else{ 1124 | Token *token_first = ptr->tokens + token_index_first; 1125 | Token *token_resync = ptr->tokens + token_index_resync_guess; 1126 | 1127 | Range_i64 relex_range = Ii64(token_first->pos, token_resync->pos + token_resync->size + text_shift); 1128 | String_Const_u8 partial_text = push_buffer_range(app, scratch, buffer_id, relex_range); 1129 | 1130 | Token_List relex_list = lex_full_input_cpp(scratch, partial_text); 1131 | if (relex_range.one_past_last < buffer_get_size(app, buffer_id)){ 1132 | token_drop_eof(&relex_list); 1133 | } 1134 | 1135 | Token_Relex relex = token_relex(relex_list, relex_range.first - text_shift, ptr->tokens, token_index_first, token_index_resync_guess); 1136 | 1137 | ProfileCloseNow(profile_attempt_resync); 1138 | 1139 | if (!relex.successful_resync){ 1140 | do_full_relex = true; 1141 | } 1142 | else{ 1143 | ProfileBlock(app, "apply resync"); 1144 | 1145 | i64 token_index_resync = relex.first_resync_index; 1146 | 1147 | Range_i64 head = Ii64(0, token_index_first); 1148 | Range_i64 replaced = Ii64(token_index_first, token_index_resync); 1149 | Range_i64 tail = Ii64(token_index_resync, ptr->count); 1150 | i64 resynced_count = (token_index_resync_guess + 1) - token_index_resync; 1151 | i64 relexed_count = relex_list.total_count - resynced_count; 1152 | i64 tail_shift = relexed_count - (token_index_resync - token_index_first); 1153 | 1154 | i64 new_tokens_count = ptr->count + tail_shift; 1155 | Token *new_tokens = base_array(allocator, Token, new_tokens_count); 1156 | 1157 | Token *old_tokens = ptr->tokens; 1158 | block_copy_array_shift(new_tokens, old_tokens, head, 0); 1159 | token_fill_memory_from_list(new_tokens + replaced.first, &relex_list, relexed_count); 1160 | for (i64 i = 0, index = replaced.first; i < relexed_count; i += 1, index += 1){ 1161 | new_tokens[index].pos += relex_range.first; 1162 | } 1163 | for (i64 i = tail.first; i < tail.one_past_last; i += 1){ 1164 | old_tokens[i].pos += text_shift; 1165 | } 1166 | block_copy_array_shift(new_tokens, ptr->tokens, tail, tail_shift); 1167 | 1168 | base_free(allocator, ptr->tokens); 1169 | 1170 | ptr->tokens = new_tokens; 1171 | ptr->count = new_tokens_count; 1172 | ptr->max = new_tokens_count; 1173 | 1174 | buffer_mark_as_modified(buffer_id); 1175 | } 1176 | } 1177 | } 1178 | 1179 | if (do_full_relex){ 1180 | *lex_task_ptr = async_task_no_dep(&global_async_system, do_full_lex_async, 1181 | make_data_struct(&buffer_id)); 1182 | } 1183 | 1184 | // no meaning for return 1185 | return(0); 1186 | } 1187 | 1188 | BUFFER_HOOK_SIG(default_end_buffer){ 1189 | Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); 1190 | Async_Task *lex_task_ptr = scope_attachment(app, scope, buffer_lex_task, Async_Task); 1191 | if (lex_task_ptr != 0){ 1192 | async_task_cancel(app, &global_async_system, *lex_task_ptr); 1193 | } 1194 | buffer_unmark_as_modified(buffer_id); 1195 | code_index_lock(); 1196 | code_index_erase_file(buffer_id); 1197 | code_index_unlock(); 1198 | // no meaning for return 1199 | return(0); 1200 | } 1201 | 1202 | function void 1203 | default_view_change_buffer(Application_Links *app, View_ID view_id, 1204 | Buffer_ID old_buffer_id, Buffer_ID new_buffer_id){ 1205 | Managed_Scope scope = view_get_managed_scope(app, view_id); 1206 | Buffer_ID *prev_buffer_id = scope_attachment(app, scope, view_previous_buffer, Buffer_ID); 1207 | if (prev_buffer_id != 0){ 1208 | *prev_buffer_id = old_buffer_id; 1209 | } 1210 | } 1211 | 1212 | internal void 1213 | set_all_default_hooks(Application_Links *app){ 1214 | set_custom_hook(app, HookID_BufferViewerUpdate, default_view_adjust); 1215 | 1216 | set_custom_hook(app, HookID_ViewEventHandler, default_view_input_handler); 1217 | set_custom_hook(app, HookID_Tick, default_tick); 1218 | set_custom_hook(app, HookID_RenderCaller, default_render_caller); 1219 | set_custom_hook(app, HookID_WholeScreenRenderCaller, default_whole_screen_render_caller); 1220 | 1221 | set_custom_hook(app, HookID_DeltaRule, fixed_time_cubic_delta); 1222 | set_custom_hook_memory_size(app, HookID_DeltaRule, 1223 | delta_ctx_size(fixed_time_cubic_delta_memory_size)); 1224 | 1225 | set_custom_hook(app, HookID_BufferNameResolver, default_buffer_name_resolution); 1226 | 1227 | set_custom_hook(app, HookID_BeginBuffer, default_begin_buffer); 1228 | set_custom_hook(app, HookID_EndBuffer, end_buffer_close_jump_list); 1229 | set_custom_hook(app, HookID_NewFile, default_new_file); 1230 | set_custom_hook(app, HookID_SaveFile, default_file_save); 1231 | set_custom_hook(app, HookID_BufferEditRange, default_buffer_edit_range); 1232 | set_custom_hook(app, HookID_BufferRegion, default_buffer_region); 1233 | set_custom_hook(app, HookID_ViewChangeBuffer, default_view_change_buffer); 1234 | 1235 | set_custom_hook(app, HookID_Layout, layout_unwrapped); 1236 | //set_custom_hook(app, HookID_Layout, layout_wrap_anywhere); 1237 | //set_custom_hook(app, HookID_Layout, layout_wrap_whitespace); 1238 | //set_custom_hook(app, HookID_Layout, layout_virt_indent_unwrapped); 1239 | //set_custom_hook(app, HookID_Layout, layout_unwrapped_small_blank_lines); 1240 | } 1241 | 1242 | // BOTTOM 1243 | 1244 | -------------------------------------------------------------------------------- /custom/4coder_jumping.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_jumping.cpp - Routines commonly used when writing code to jump to locations and seek through jump lists. 3 | */ 4 | 5 | // TOP 6 | 7 | function b32 8 | ms_style_verify(String_Const_u8 line, u64 left_paren_pos, u64 right_paren_pos){ 9 | i32 result = false; 10 | String_Const_u8 line_part = string_skip(line, right_paren_pos); 11 | if (string_match(string_prefix(line_part, 4), string_u8_litexpr(") : ")) || 12 | string_match(string_prefix(line_part, 3), string_u8_litexpr("): "))){ 13 | result = true; 14 | } 15 | if (result){ 16 | String_Const_u8 number = string_skip(string_prefix(line, right_paren_pos), left_paren_pos + 1); 17 | if (!string_is_integer(number, 10)){ 18 | result = false; 19 | u64 comma_pos = string_find_first(number, ','); 20 | if (comma_pos < number.size){ 21 | String_Const_u8 sub_number0 = string_prefix(number, comma_pos); 22 | String_Const_u8 sub_number1 = string_skip(number, comma_pos + 1); 23 | if (string_is_integer(sub_number0, 10) && string_is_integer(sub_number1, 10)){ 24 | result = true; 25 | } 26 | } 27 | } 28 | } 29 | return(result); 30 | } 31 | 32 | function u64 33 | try_skip_rust_arrow(String_Const_u8 line){ 34 | u64 pos = 0; 35 | if (string_match(string_prefix(line, 3), string_u8_litexpr("-->"))){ 36 | String_Const_u8 sub = string_skip(line, 3); 37 | sub = string_skip_chop_whitespace(sub); 38 | pos = (u64)(sub.str - line.str); 39 | } 40 | return(pos); 41 | } 42 | 43 | function b32 44 | check_is_note(String_Const_u8 line, u64 colon_pos){ 45 | b32 is_note = false; 46 | u64 note_pos = colon_pos + string_find_first(string_skip(line, colon_pos), string_u8_litexpr("note")); 47 | if (note_pos < line.size){ 48 | b32 is_all_whitespace = true; 49 | for (u64 i = colon_pos + 1; i < note_pos; i += 1){ 50 | if (!character_is_whitespace(line.str[i])){ 51 | is_all_whitespace = false; 52 | break; 53 | } 54 | } 55 | if (is_all_whitespace){ 56 | is_note = true; 57 | } 58 | } 59 | return(is_note); 60 | } 61 | 62 | function Parsed_Jump 63 | parse_jump_location(String_Const_u8 line){ 64 | Parsed_Jump jump = {}; 65 | jump.sub_jump_indented = (string_get_character(line, 0) == ' '); 66 | 67 | String_Const_u8 reduced_line = string_skip_chop_whitespace(line); 68 | line = reduced_line; 69 | 70 | u64 first_colon = (string_find_first(line, ':')); 71 | u64 second_colon = first_colon + 1 + string_find_first(string_skip(line, first_colon + 1), ':'); 72 | u64 third_colon = second_colon + 1 + string_find_first(string_skip(line, second_colon + 1), ':'); 73 | 74 | // odin lister jumps 75 | if (!jump.is_ms_style && first_colon != 0 && second_colon != 0 && third_colon != 0 && first_colon < line.size && third_colon < line.size) { 76 | jump.is_ms_style = true; 77 | 78 | String_Const_u8 location_str = string_prefix(line, first_colon); 79 | jump.location.file = location_str; 80 | 81 | String_Const_u8 line_number = string_skip(string_prefix(line, second_colon), first_colon + 1); 82 | jump.location.line = (i32) string_to_integer(line_number, 10); 83 | 84 | String_Const_u8 column_number = string_skip(string_prefix(line, third_colon), second_colon + 1); 85 | jump.location.column = (i32) string_to_integer(column_number, 10); 86 | 87 | jump.colon_position = (i32) first_colon; 88 | jump.success = true; 89 | } 90 | 91 | if (!jump.is_ms_style) { 92 | u64 left_paren_pos = string_find_first(line, '('); 93 | u64 colon_seperator = left_paren_pos + string_find_first(string_skip(line, left_paren_pos), ':'); 94 | u64 right_paren_pos = left_paren_pos + string_find_first(string_skip(line, left_paren_pos), ')'); 95 | 96 | String_Const_u8 file_name = string_prefix(line, left_paren_pos); 97 | jump.location.file = file_name; 98 | 99 | String_Const_u8 line_number = string_skip(string_prefix(line, colon_seperator), left_paren_pos + 1); 100 | jump.location.line = (i32) string_to_integer(line_number, 10); 101 | 102 | String_Const_u8 column_number = string_skip(string_prefix(line, right_paren_pos), colon_seperator + 1); 103 | jump.location.column = (i32) string_to_integer(column_number, 10); 104 | 105 | jump.colon_position = (i32) colon_seperator; 106 | jump.success = true; 107 | } 108 | 109 | if (!jump.success){ 110 | block_zero_struct(&jump); 111 | } 112 | else{ 113 | jump.is_sub_jump = (jump.sub_jump_indented || jump.sub_jump_note); 114 | } 115 | return(jump); 116 | } 117 | 118 | function Parsed_Jump 119 | parse_jump_location(String_Const_u8 line, Jump_Flag flags){ 120 | Parsed_Jump jump = parse_jump_location(line); 121 | if (HasFlag(flags, JumpFlag_SkipSubs) && jump.is_sub_jump){ 122 | block_zero_struct(&jump); 123 | } 124 | return(jump); 125 | } 126 | 127 | function Parsed_Jump 128 | parse_jump_from_buffer_line(Application_Links *app, Arena *arena, Buffer_ID buffer, i64 line, Jump_Flag flags){ 129 | Parsed_Jump jump = {}; 130 | String_Const_u8 line_str = push_buffer_line(app, arena, buffer, line); 131 | if (line_str.size > 0){ 132 | jump = parse_jump_location(line_str, flags); 133 | } 134 | return(jump); 135 | } 136 | 137 | //////////////////////////////// 138 | 139 | function b32 140 | get_jump_buffer(Application_Links *app, Buffer_ID *buffer, Name_Line_Column_Location *location){ 141 | return(open_file(app, buffer, location->file, false, true)); 142 | } 143 | 144 | function b32 145 | get_jump_buffer(Application_Links *app, Buffer_ID *buffer, ID_Pos_Jump_Location *location, Access_Flag access){ 146 | *buffer = location->buffer_id; 147 | return(buffer_exists(app, *buffer)); 148 | } 149 | 150 | function b32 151 | get_jump_buffer(Application_Links *app, Buffer_ID *buffer, ID_Pos_Jump_Location *location){ 152 | return(get_jump_buffer(app, buffer, location, Access_Always)); 153 | } 154 | 155 | function View_ID 156 | switch_to_existing_view(Application_Links *app, View_ID view, Buffer_ID buffer){ 157 | Buffer_ID current_buffer = view_get_buffer(app, view, Access_Always); 158 | if (view != 0 || current_buffer != buffer){ 159 | View_ID existing_view = get_first_view_with_buffer(app, buffer); 160 | if (existing_view != 0){ 161 | view = existing_view; 162 | } 163 | } 164 | return(view); 165 | } 166 | 167 | function void 168 | set_view_to_location(Application_Links *app, View_ID view, Buffer_ID buffer, Buffer_Seek seek){ 169 | Buffer_ID current_buffer = view_get_buffer(app, view, Access_Always); 170 | if (current_buffer != buffer){ 171 | view_set_buffer(app, view, buffer, 0); 172 | } 173 | view_set_cursor_and_preferred_x(app, view, seek); 174 | } 175 | 176 | function void 177 | jump_to_location(Application_Links *app, View_ID view, Buffer_ID buffer, i64 pos){ 178 | view_set_active(app, view); 179 | set_view_to_location(app, view, buffer, seek_pos(pos)); 180 | if (auto_center_after_jumps){ 181 | center_view(app); 182 | } 183 | } 184 | 185 | function void 186 | jump_to_location(Application_Links *app, View_ID view, Buffer_ID buffer, 187 | Name_Line_Column_Location location){ 188 | view_set_active(app, view); 189 | set_view_to_location(app, view, buffer, seek_line_col(location.line, location.column)); 190 | if (auto_center_after_jumps){ 191 | center_view(app); 192 | } 193 | } 194 | 195 | function void 196 | jump_to_location(Application_Links *app, View_ID view, 197 | Name_Line_Column_Location location){ 198 | Buffer_ID buffer = 0; 199 | if (get_jump_buffer(app, &buffer, &location)){ 200 | jump_to_location(app, view, buffer, location); 201 | } 202 | } 203 | 204 | function void 205 | jump_to_location(Application_Links *app, View_ID view, Buffer_ID buffer, ID_Pos_Jump_Location location){ 206 | view_set_active(app, view); 207 | set_view_to_location(app, view, buffer, seek_pos(location.pos)); 208 | if (auto_center_after_jumps){ 209 | center_view(app); 210 | } 211 | } 212 | 213 | function void 214 | jump_to_location(Application_Links *app, View_ID view, String_Const_u8 location){ 215 | Parsed_Jump jump = parse_jump_location(location); 216 | if (jump.success){ 217 | jump_to_location(app, view, jump.location); 218 | } 219 | } 220 | 221 | //////////////////////////////// 222 | 223 | // TODO(allen): rewrite 224 | static Parsed_Jump 225 | seek_next_jump_in_buffer(Application_Links *app, Arena *arena, 226 | Buffer_ID buffer, i64 first_line, Jump_Flag flags, Scan_Direction direction, 227 | i64 *line_out){ 228 | Assert(direction == 1 || direction == -1); 229 | Parsed_Jump jump = {}; 230 | i64 line = first_line; 231 | for (;;){ 232 | if (is_valid_line(app, buffer, line)){ 233 | String_Const_u8 line_str = push_buffer_line(app, arena, buffer, line); 234 | jump = parse_jump_location(line_str, flags); 235 | if (jump.success){ 236 | break; 237 | } 238 | line += direction; 239 | } 240 | else{ 241 | break; 242 | } 243 | } 244 | if (jump.success){ 245 | *line_out = clamp_bot(line, 0); 246 | } 247 | return(jump); 248 | } 249 | 250 | static ID_Line_Column_Jump_Location 251 | convert_name_based_to_id_based(Application_Links *app, Name_Line_Column_Location loc){ 252 | ID_Line_Column_Jump_Location result = {}; 253 | Buffer_ID buffer = get_buffer_by_name(app, loc.file, Access_Always); 254 | if (buffer != 0){ 255 | result.buffer_id = buffer; 256 | result.line = loc.line; 257 | result.column = loc.column; 258 | } 259 | return(result); 260 | } 261 | 262 | static Parsed_Jump 263 | seek_next_jump_in_view(Application_Links *app, Arena *arena, View_ID view, i32 skip_sub_errors, Scan_Direction direction, i64 *line_out){ 264 | i64 cursor_position = view_get_cursor_pos(app, view); 265 | Buffer_Cursor cursor = view_compute_cursor(app, view, seek_pos(cursor_position)); 266 | i64 line = cursor.line; 267 | Buffer_ID buffer = view_get_buffer(app, view, Access_Always); 268 | Parsed_Jump jump = seek_next_jump_in_buffer(app, arena, buffer, line + direction, skip_sub_errors, direction, &line); 269 | if (jump.success){ 270 | *line_out = line; 271 | } 272 | return(jump); 273 | } 274 | 275 | static b32 276 | skip_this_jump(ID_Line_Column_Jump_Location prev, ID_Line_Column_Jump_Location jump){ 277 | b32 result = false; 278 | if (prev.buffer_id != 0 && prev.buffer_id == jump.buffer_id && prev.line == jump.line && prev.column <= jump.column){ 279 | result = true; 280 | } 281 | return(result); 282 | } 283 | 284 | #if 0 285 | static b32 286 | advance_cursor_in_jump_view(Application_Links *app, View_ID view, b32 skip_repeats, b32 skip_sub_error, Scan_Direction direction, Name_Line_Column_Location *location_out){ 287 | b32 result = true; 288 | 289 | Name_Line_Column_Location location = {}; 290 | ID_Line_Column_Jump_Location jump = {}; 291 | i64 line = 0; 292 | i64 colon_index = 0; 293 | 294 | do{ 295 | Arena *scratch = context_get_arena(app); 296 | Temp_Memory temp = begin_temp(scratch); 297 | Parsed_Jump parsed_jump = seek_next_jump_in_view(app, scratch, view, skip_sub_error, direction, &line); 298 | if (parsed_jump.success){ 299 | jump = convert_name_based_to_id_based(app, parsed_jump.location); 300 | view_set_cursor(app, view, seek_line_char(line, parsed_jump.colon_position + 1), true); 301 | result = true; 302 | } 303 | else{ 304 | jump.buffer_id = 0; 305 | result = false; 306 | } 307 | end_temp(temp); 308 | }while(skip_repeats && skip_this_jump(prev_location, jump)); 309 | 310 | if (result){ 311 | *location_out = location; 312 | view_set_cursor(app, view, seek_line_char(line, colon_index + 1), true); 313 | } 314 | 315 | prev_location = jump; 316 | 317 | return(result); 318 | } 319 | 320 | static b32 321 | seek_jump_(Application_Links *app, b32 skip_repeats, b32 skip_sub_errors, i32 direction){ 322 | b32 result = false; 323 | 324 | View_ID view = get_view_for_locked_jump_buffer(app); 325 | if (view != 0){ 326 | Name_Line_Column_Location location = {}; 327 | if (advance_cursor_in_jump_view(app, view, skip_repeats, skip_sub_errors, direction, &location)){ 328 | Buffer_ID buffer = {}; 329 | if (get_jump_buffer(app, &buffer, &location)){ 330 | View_ID target_view = get_active_view(app, Access_Always); 331 | if (target_view == view){ 332 | change_active_panel(app); 333 | target_view = get_active_view(app, Access_Always); 334 | } 335 | switch_to_existing_view(app, target_view, buffer); 336 | jump_to_location(app, target_view, buffer, location); 337 | result = true; 338 | } 339 | } 340 | } 341 | 342 | return(result); 343 | } 344 | #endif 345 | 346 | // BOTTOM 347 | 348 | -------------------------------------------------------------------------------- /custom/languages/4coder_cpp_lexer_gen.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 4coder_lex_gen_cpp.cpp - Model definition for a C++ lexer. 3 | */ 4 | 5 | // TOP 6 | 7 | #define LANG_NAME_LOWER cpp 8 | #define LANG_NAME_CAMEL Cpp 9 | 10 | #include "lexer_generator/4coder_lex_gen_main.cpp" 11 | 12 | internal void 13 | build_language_model(void){ 14 | u8 utf8[129]; 15 | smh_utf8_fill(utf8); 16 | 17 | smh_set_base_character_names(); 18 | smh_typical_tokens(); 19 | 20 | // CPP Names 21 | sm_char_name('!', "Not"); 22 | sm_char_name('&', "And"); 23 | sm_char_name('|', "Or"); 24 | sm_char_name('%', "Mod"); 25 | sm_char_name('^', "Xor"); 26 | sm_char_name('?', "Ternary"); 27 | sm_char_name('/', "Div"); 28 | 29 | // CPP Direct Toke Kinds 30 | sm_select_base_kind(TokenBaseKind_Comment); 31 | sm_direct_token_kind("BlockComment"); 32 | sm_direct_token_kind("LineComment"); 33 | 34 | sm_select_base_kind(TokenBaseKind_Whitespace); 35 | sm_direct_token_kind("Backslash"); 36 | 37 | sm_select_base_kind(TokenBaseKind_LiteralInteger); 38 | sm_direct_token_kind("LiteralInteger"); 39 | sm_direct_token_kind("LiteralIntegerU"); 40 | sm_direct_token_kind("LiteralIntegerL"); 41 | sm_direct_token_kind("LiteralIntegerUL"); 42 | sm_direct_token_kind("LiteralIntegerLL"); 43 | sm_direct_token_kind("LiteralIntegerULL"); 44 | sm_direct_token_kind("LiteralIntegerHex"); 45 | sm_direct_token_kind("LiteralIntegerHexU"); 46 | sm_direct_token_kind("LiteralIntegerHexL"); 47 | sm_direct_token_kind("LiteralIntegerHexUL"); 48 | sm_direct_token_kind("LiteralIntegerHexLL"); 49 | sm_direct_token_kind("LiteralIntegerHexULL"); 50 | sm_direct_token_kind("LiteralIntegerOct"); 51 | sm_direct_token_kind("LiteralIntegerOctU"); 52 | sm_direct_token_kind("LiteralIntegerOctL"); 53 | sm_direct_token_kind("LiteralIntegerOctUL"); 54 | sm_direct_token_kind("LiteralIntegerOctLL"); 55 | sm_direct_token_kind("LiteralIntegerOctULL"); 56 | 57 | sm_select_base_kind(TokenBaseKind_LiteralFloat); 58 | sm_direct_token_kind("LiteralFloat32"); 59 | sm_direct_token_kind("LiteralFloat64"); 60 | 61 | sm_select_base_kind(TokenBaseKind_LiteralString); 62 | sm_direct_token_kind("LiteralString"); 63 | sm_direct_token_kind("LiteralStringWide"); 64 | sm_direct_token_kind("LiteralStringUTF8"); 65 | sm_direct_token_kind("LiteralStringUTF16"); 66 | sm_direct_token_kind("LiteralStringUTF32"); 67 | sm_direct_token_kind("LiteralStringRaw"); 68 | sm_direct_token_kind("LiteralStringWideRaw"); 69 | sm_direct_token_kind("LiteralStringUTF8Raw"); 70 | sm_direct_token_kind("LiteralStringUTF16Raw"); 71 | sm_direct_token_kind("LiteralStringUTF32Raw"); 72 | sm_direct_token_kind("LiteralCharacter"); 73 | sm_direct_token_kind("LiteralCharacterWide"); 74 | sm_direct_token_kind("LiteralCharacterUTF8"); 75 | sm_direct_token_kind("LiteralCharacterUTF16"); 76 | sm_direct_token_kind("LiteralCharacterUTF32"); 77 | sm_direct_token_kind("PPIncludeFile"); 78 | sm_direct_token_kind("PPErrorMessage"); 79 | 80 | sm_select_base_kind(TokenBaseKind_Keyword); 81 | sm_direct_token_kind("KeywordGeneric"); 82 | 83 | // CPP Operators 84 | Operator_Set *main_ops = sm_begin_op_set(); 85 | 86 | sm_select_base_kind(TokenBaseKind_ScopeOpen); 87 | sm_op("{"); 88 | sm_select_base_kind(TokenBaseKind_ScopeClose); 89 | sm_op("}"); 90 | sm_select_base_kind(TokenBaseKind_ParentheticalOpen); 91 | sm_op("("); 92 | sm_op("["); 93 | sm_select_base_kind(TokenBaseKind_ParentheticalClose); 94 | sm_op(")"); 95 | sm_op("]"); 96 | sm_select_base_kind(TokenBaseKind_StatementClose); 97 | sm_op(";"); 98 | sm_op(":"); 99 | sm_select_base_kind(TokenBaseKind_Operator); 100 | sm_op("..."); 101 | 102 | sm_op("::"); 103 | sm_op("++"); 104 | sm_op("--"); 105 | sm_op("."); 106 | sm_op("->", "Arrow"); 107 | sm_op("+"); 108 | sm_op("-"); 109 | sm_op("!"); 110 | sm_op("~"); 111 | sm_op("*"); 112 | sm_op("&"); 113 | sm_op(".*"); 114 | sm_op("->*", "ArrowStar"); 115 | sm_op("/"); 116 | sm_op("%"); 117 | 118 | sm_char_name('<', "Left"); 119 | sm_char_name('>', "Right"); 120 | sm_op("<<"); 121 | sm_op(">>"); 122 | 123 | sm_op("<=>", "Compare"); 124 | 125 | sm_char_name('<', "Less"); 126 | sm_char_name('>', "Grtr"); 127 | sm_op("<"); 128 | sm_op("<="); 129 | sm_op(">"); 130 | sm_op(">="); 131 | sm_op("=="); 132 | sm_op("!="); 133 | 134 | sm_op("^"); 135 | sm_op("|"); 136 | sm_op("&&"); 137 | sm_op("||"); 138 | sm_op("?"); 139 | sm_op("="); 140 | sm_op("+="); 141 | sm_op("-="); 142 | sm_op("*="); 143 | sm_op("/="); 144 | sm_op("%="); 145 | 146 | sm_char_name('<', "Left"); 147 | sm_char_name('>', "Right"); 148 | sm_op("<<="); 149 | sm_op(">>="); 150 | 151 | sm_select_base_kind(TokenBaseKind_StatementClose); 152 | sm_op(","); 153 | 154 | // CPP Preprocess Operators 155 | Operator_Set *pp_ops = sm_begin_op_set(); 156 | 157 | sm_op("#", "PPStringify"); 158 | sm_op("##", "PPConcat"); 159 | 160 | // CPP Keywords 161 | Keyword_Set *main_keys = sm_begin_key_set("main_keys"); 162 | 163 | sm_select_base_kind(TokenBaseKind_Keyword); 164 | sm_key("Void"); 165 | sm_key("Bool"); 166 | sm_key("Char"); 167 | sm_key("Int"); 168 | sm_key("Float"); 169 | sm_key("Double"); 170 | sm_key("Long"); 171 | sm_key("Short"); 172 | sm_key("Unsigned"); 173 | sm_key("Signed"); 174 | sm_key("Const"); 175 | sm_key("Volatile"); 176 | sm_key("Asm"); 177 | sm_key("Break"); 178 | sm_key("Case"); 179 | sm_key("Catch"); 180 | sm_key("Continue"); 181 | sm_key("Default"); 182 | sm_key("Do"); 183 | sm_key("Else"); 184 | sm_key("For"); 185 | sm_key("Goto"); 186 | sm_key("If"); 187 | sm_key("Return"); 188 | sm_key("Switch"); 189 | sm_key("Try"); 190 | sm_key("While"); 191 | sm_key("StaticAssert", "static_assert"); 192 | sm_key("ConstCast", "const_cast"); 193 | sm_key("DynamicCast", "dynamic_cast"); 194 | sm_key("ReinterpretCast", "reinterpret_cast"); 195 | sm_key("StaticCast", "static_cast"); 196 | sm_key("Class"); 197 | sm_key("Enum"); 198 | sm_key("Struct"); 199 | sm_key("Typedef"); 200 | sm_key("Union"); 201 | sm_key("Template"); 202 | sm_key("Typename"); 203 | sm_key("Friend"); 204 | sm_key("Namespace"); 205 | sm_key("Private"); 206 | sm_key("Protected"); 207 | sm_key("Public"); 208 | sm_key("Using"); 209 | sm_key("Extern"); 210 | sm_key("Export"); 211 | sm_key("Inline"); 212 | sm_key("Static"); 213 | sm_key("Virtual"); 214 | sm_key("AlignAs"); 215 | sm_key("Explicit"); 216 | sm_key("NoExcept"); 217 | sm_key("NullPtr"); 218 | sm_key("Operator"); 219 | sm_key("Register"); 220 | sm_key("This"); 221 | sm_key("ThreadLocal", "thread_local"); 222 | sm_key("SizeOf"); 223 | sm_key("AlignOf"); 224 | sm_key("DeclType"); 225 | sm_key("TypeID"); 226 | sm_key("New"); 227 | sm_key("Delete"); 228 | 229 | // NOTE(Skytrias): odin 230 | sm_key("f32"); 231 | sm_key("bool"); 232 | sm_key("u32"); 233 | sm_key("u16"); 234 | sm_key("int"); 235 | sm_key("i32"); 236 | sm_key("i16"); 237 | sm_key("i8"); 238 | sm_key("string"); 239 | sm_key("cstring"); 240 | sm_key("rawptr"); 241 | sm_key("nil"); 242 | sm_key("u8"); 243 | sm_key("byte"); 244 | sm_key("any"); 245 | 246 | sm_key("package"); 247 | sm_key("import"); 248 | sm_key("foreign"); 249 | sm_key("when"); 250 | sm_key("defer"); 251 | sm_key("case"); 252 | sm_key("in"); 253 | sm_key("not_in"); 254 | sm_key("fallthrough"); 255 | sm_key("proc"); 256 | sm_key("bit_field"); 257 | sm_key("bit_set"); 258 | sm_key("map"); 259 | sm_key("dynamic"); 260 | sm_key("cast"); 261 | sm_key("auto_cast"); 262 | sm_key("transmute"); 263 | sm_key("delete"); 264 | sm_key("using"); 265 | sm_key("inline"); 266 | sm_key("no_inline"); 267 | sm_key("context"); 268 | sm_key("size_of"); 269 | sm_key("align_of"); 270 | sm_key("offset_of"); 271 | sm_key("type_of"); 272 | sm_key("distinct"); 273 | sm_key("opaque"); 274 | 275 | sm_select_base_kind(TokenBaseKind_LiteralInteger); 276 | sm_key("LiteralTrue", "true"); 277 | sm_key("LiteralFalse", "false"); 278 | 279 | sm_select_base_kind(TokenBaseKind_Identifier); 280 | sm_key_fallback("Identifier"); 281 | 282 | // CPP Preprocess Directives 283 | Keyword_Set *pp_directive_set = sm_begin_key_set("pp_directives"); 284 | 285 | sm_select_base_kind(TokenBaseKind_Preprocessor); 286 | sm_key("PPInclude", "include"); 287 | sm_key("PPVersion", "version"); 288 | sm_key("PPDefine", "define"); 289 | sm_key("PPUndef", "undef"); 290 | sm_key("PPIf", "if"); 291 | sm_key("PPIfDef", "ifdef"); 292 | sm_key("PPIfNDef", "ifndef"); 293 | sm_key("PPElse", "else"); 294 | sm_key("PPElIf", "elif"); 295 | sm_key("PPEndIf", "endif"); 296 | sm_key("PPError", "error"); 297 | sm_key("PPImport", "import"); 298 | sm_key("PPUsing", "using"); 299 | sm_key("PPLine", "line"); 300 | sm_key("PPPragma", "pragma"); 301 | 302 | sm_select_base_kind(TokenBaseKind_LexError); 303 | sm_key_fallback("PPUnknown"); 304 | 305 | // CPP Preprocess Keywords 306 | Keyword_Set *pp_keys = sm_begin_key_set("pp_keys"); 307 | 308 | sm_select_base_kind(TokenBaseKind_Keyword); 309 | sm_key("PPDefined", "defined"); 310 | 311 | // State Machine 312 | State *root = sm_begin_state_machine(); 313 | 314 | Flag *is_hex = sm_add_flag(FlagResetRule_AutoZero); 315 | Flag *is_oct = sm_add_flag(FlagResetRule_AutoZero); 316 | Flag *is_wide = sm_add_flag(FlagResetRule_AutoZero); 317 | Flag *is_utf8 = sm_add_flag(FlagResetRule_AutoZero); 318 | Flag *is_utf16 = sm_add_flag(FlagResetRule_AutoZero); 319 | Flag *is_utf32 = sm_add_flag(FlagResetRule_AutoZero); 320 | Flag *is_char = sm_add_flag(FlagResetRule_AutoZero); 321 | 322 | Flag *is_pp_body = sm_add_flag(FlagResetRule_KeepState); 323 | Flag *is_include_body = sm_add_flag(FlagResetRule_KeepState); 324 | Flag *is_error_body = sm_add_flag(FlagResetRule_KeepState); 325 | 326 | sm_flag_bind(is_pp_body, TokenBaseFlag_PreprocessorBody); 327 | 328 | #define AddState(N) State *N = sm_add_state(#N) 329 | 330 | AddState(identifier); 331 | AddState(whitespace); 332 | AddState(whitespace_end_pp); 333 | AddState(error_body); 334 | AddState(backslash); 335 | 336 | AddState(operator_or_fnumber_dot); 337 | AddState(operator_or_comment_slash); 338 | 339 | AddState(number); 340 | AddState(znumber); 341 | 342 | AddState(fnumber_decimal); 343 | AddState(fnumber_exponent); 344 | AddState(fnumber_exponent_sign); 345 | AddState(fnumber_exponent_digits); 346 | 347 | AddState(number_hex_first); 348 | AddState(number_hex); 349 | AddState(number_oct); 350 | 351 | AddState(U_number); 352 | AddState(L_number); 353 | AddState(UL_number); 354 | AddState(LU_number); 355 | AddState(l_number); 356 | AddState(Ul_number); 357 | AddState(lU_number); 358 | AddState(LL_number); 359 | AddState(ULL_number); 360 | 361 | AddState(pp_directive_whitespace); 362 | AddState(pp_directive_first); 363 | AddState(pp_directive); 364 | AddState(pp_directive_emit); 365 | 366 | AddState(include_pointy); 367 | AddState(include_quotes); 368 | 369 | AddState(pre_L); 370 | AddState(pre_u); 371 | AddState(pre_U); 372 | AddState(pre_u8); 373 | AddState(pre_R); 374 | 375 | AddState(character); 376 | AddState(string); 377 | AddState(string_esc); 378 | AddState(string_esc_oct2); 379 | AddState(string_esc_oct1); 380 | AddState(string_esc_hex); 381 | AddState(string_esc_universal_8); 382 | AddState(string_esc_universal_7); 383 | AddState(string_esc_universal_6); 384 | AddState(string_esc_universal_5); 385 | AddState(string_esc_universal_4); 386 | AddState(string_esc_universal_3); 387 | AddState(string_esc_universal_2); 388 | AddState(string_esc_universal_1); 389 | 390 | AddState(raw_string); 391 | AddState(raw_string_get_delim); 392 | AddState(raw_string_finish_delim); 393 | AddState(raw_string_find_close); 394 | AddState(raw_string_try_delim); 395 | AddState(raw_string_try_quote); 396 | 397 | AddState(comment_block); 398 | AddState(comment_block_try_close); 399 | AddState(comment_block_newline); 400 | AddState(comment_line); 401 | AddState(comment_line_backslashing); 402 | 403 | Operator_Set *main_ops_without_dot_or_slash = smo_copy_op_set(main_ops); 404 | smo_remove_ops_with_prefix(main_ops_without_dot_or_slash, "."); 405 | smo_remove_ops_with_prefix(main_ops_without_dot_or_slash, "/"); 406 | 407 | Operator_Set *main_ops_with_dot = smo_copy_op_set(main_ops); 408 | smo_remove_ops_without_prefix(main_ops_with_dot, "."); 409 | smo_ops_string_skip(main_ops_with_dot, 1); 410 | 411 | //// 412 | 413 | sm_select_state(root); 414 | 415 | { 416 | Emit_Rule *emit = sm_emit_rule(); 417 | sm_emit_handler_direct("EOF"); 418 | sm_case_eof(emit); 419 | } 420 | 421 | sm_case("abcdefghijklmnopqrstvwxyz" 422 | "ABCDEFGHIJKMNOPQSTVWXYZ" 423 | "_$", 424 | identifier); 425 | sm_case(utf8, identifier); 426 | sm_case("L", pre_L); 427 | sm_case("u", pre_u); 428 | sm_case("U", pre_U); 429 | sm_case("R", pre_R); 430 | 431 | sm_case_flagged(is_error_body, true, " \r\t\f\v", error_body); 432 | sm_case_flagged(is_error_body, false, " \r\t\f\v", whitespace); 433 | sm_case("\n", whitespace_end_pp); 434 | sm_case("\\", backslash); 435 | 436 | sm_case(".", operator_or_fnumber_dot); 437 | sm_case("/", operator_or_comment_slash); 438 | { 439 | Character_Set *char_set = smo_new_char_set(); 440 | smo_char_set_union_ops_firsts(char_set, main_ops_without_dot_or_slash); 441 | smo_char_set_remove(char_set, ".", emit); 882 | } 883 | { 884 | Emit_Rule *emit = sm_emit_rule(); 885 | sm_emit_handler_direct("LexError"); 886 | sm_fallback_peek(emit); 887 | } 888 | 889 | //// 890 | 891 | sm_select_state(include_quotes); 892 | sm_case("abcdefghijklmnopqrstuvwxyz" 893 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 894 | "_. /\\" 895 | "0123456789", 896 | include_quotes); 897 | { 898 | Emit_Rule *emit = sm_emit_rule(); 899 | sm_emit_handler_direct("PPIncludeFile"); 900 | sm_case("\"", emit); 901 | } 902 | { 903 | Emit_Rule *emit = sm_emit_rule(); 904 | sm_emit_handler_direct("LexError"); 905 | sm_fallback_peek(emit); 906 | } 907 | 908 | //// 909 | 910 | sm_select_state(pre_L); 911 | sm_set_flag(is_wide, true); 912 | sm_case("\"", string); 913 | sm_case("R", pre_R); 914 | sm_fallback_peek(identifier); 915 | 916 | //// 917 | 918 | sm_select_state(pre_u); 919 | sm_set_flag(is_utf16, true); 920 | sm_case("\"", string); 921 | sm_case("8", pre_u8); 922 | sm_case("R", pre_R); 923 | sm_fallback_peek(identifier); 924 | 925 | //// 926 | 927 | sm_select_state(pre_U); 928 | sm_set_flag(is_utf32, true); 929 | sm_case("\"", string); 930 | sm_case("R", pre_R); 931 | sm_fallback_peek(identifier); 932 | 933 | //// 934 | 935 | sm_select_state(pre_u8); 936 | sm_set_flag(is_utf8, true); 937 | sm_case("\"", string); 938 | sm_case("R", pre_R); 939 | sm_fallback_peek(identifier); 940 | 941 | //// 942 | 943 | sm_select_state(pre_R); 944 | sm_case("\"", raw_string); 945 | sm_fallback_peek(identifier); 946 | 947 | //// 948 | 949 | sm_select_state(character); 950 | sm_set_flag(is_char, true); 951 | sm_fallback_peek(string); 952 | 953 | //// 954 | 955 | sm_select_state(string); 956 | { 957 | Emit_Rule *emit = sm_emit_rule(); 958 | sm_emit_handler_direct(is_wide, "LiteralStringWide"); 959 | sm_emit_handler_direct(is_utf8 , "LiteralStringUTF8"); 960 | sm_emit_handler_direct(is_utf16, "LiteralStringUTF16"); 961 | sm_emit_handler_direct(is_utf32, "LiteralStringUTF32"); 962 | sm_emit_handler_direct("LiteralString"); 963 | sm_case_flagged(is_char, false, "\"", emit); 964 | } 965 | { 966 | Emit_Rule *emit = sm_emit_rule(); 967 | sm_emit_handler_direct(is_wide, "LiteralCharacterWide"); 968 | sm_emit_handler_direct(is_utf8 , "LiteralCharacterUTF8"); 969 | sm_emit_handler_direct(is_utf16, "LiteralCharacterUTF16"); 970 | sm_emit_handler_direct(is_utf32, "LiteralCharacterUTF32"); 971 | sm_emit_handler_direct("LiteralCharacter"); 972 | sm_case_flagged(is_char, true, "\'", emit); 973 | } 974 | sm_case("\\", string_esc); 975 | { 976 | Emit_Rule *emit = sm_emit_rule(); 977 | sm_emit_handler_direct("LexError"); 978 | sm_case_peek("\n", emit); 979 | } 980 | { 981 | Emit_Rule *emit = sm_emit_rule(); 982 | sm_emit_handler_direct("LexError"); 983 | sm_case_eof_peek(emit); 984 | } 985 | sm_case_flagged(is_char, true, "\"", string); 986 | sm_case_flagged(is_char, false, "\'", string); 987 | sm_fallback(string); 988 | 989 | //// 990 | 991 | sm_select_state(string_esc); 992 | sm_case("\n'\"?\\abfnrtv", string); 993 | sm_case("01234567", string_esc_oct2); 994 | sm_case("x", string_esc_hex); 995 | sm_case("u", string_esc_universal_4); 996 | sm_case("U", string_esc_universal_8); 997 | { 998 | Emit_Rule *emit = sm_emit_rule(); 999 | sm_emit_handler_direct("LexError"); 1000 | sm_case_peek("\n", emit); 1001 | } 1002 | { 1003 | Emit_Rule *emit = sm_emit_rule(); 1004 | sm_emit_handler_direct("LexError"); 1005 | sm_case_eof_peek(emit); 1006 | } 1007 | sm_fallback(string); 1008 | 1009 | //// 1010 | 1011 | sm_select_state(string_esc_oct2); 1012 | sm_case("01234567", string_esc_oct1); 1013 | sm_fallback_peek(string); 1014 | 1015 | //// 1016 | 1017 | sm_select_state(string_esc_oct1); 1018 | sm_case("01234567", string); 1019 | sm_fallback_peek(string); 1020 | 1021 | //// 1022 | 1023 | sm_select_state(string_esc_hex); 1024 | sm_case("0123456789abcdefABCDEF", string_esc_hex); 1025 | sm_fallback_peek(string); 1026 | 1027 | //// 1028 | 1029 | sm_select_state(string_esc_universal_8); 1030 | sm_case("0123456789abcdefABCDEF", string_esc_universal_7); 1031 | sm_fallback_peek(string); 1032 | 1033 | //// 1034 | 1035 | sm_select_state(string_esc_universal_7); 1036 | sm_case("0123456789abcdefABCDEF", string_esc_universal_6); 1037 | sm_fallback_peek(string); 1038 | 1039 | //// 1040 | 1041 | sm_select_state(string_esc_universal_6); 1042 | sm_case("0123456789abcdefABCDEF", string_esc_universal_5); 1043 | sm_fallback_peek(string); 1044 | 1045 | //// 1046 | 1047 | sm_select_state(string_esc_universal_5); 1048 | sm_case("0123456789abcdefABCDEF", string_esc_universal_4); 1049 | sm_fallback_peek(string); 1050 | 1051 | //// 1052 | 1053 | sm_select_state(string_esc_universal_4); 1054 | sm_case("0123456789abcdefABCDEF", string_esc_universal_3); 1055 | sm_fallback_peek(string); 1056 | 1057 | //// 1058 | 1059 | sm_select_state(string_esc_universal_3); 1060 | sm_case("0123456789abcdefABCDEF", string_esc_universal_2); 1061 | sm_fallback_peek(string); 1062 | 1063 | //// 1064 | 1065 | sm_select_state(string_esc_universal_2); 1066 | sm_case("0123456789abcdefABCDEF", string_esc_universal_1); 1067 | sm_fallback_peek(string); 1068 | 1069 | //// 1070 | 1071 | sm_select_state(string_esc_universal_1); 1072 | sm_case("0123456789abcdefABCDEF", string); 1073 | sm_fallback_peek(string); 1074 | 1075 | //// 1076 | 1077 | sm_select_state(raw_string); 1078 | sm_delim_mark_first(); 1079 | sm_fallback_peek(raw_string_get_delim); 1080 | 1081 | //// 1082 | 1083 | sm_select_state(raw_string_get_delim); 1084 | sm_case_peek("(", raw_string_finish_delim); 1085 | { 1086 | Emit_Rule *emit = sm_emit_rule(); 1087 | sm_emit_handler_direct("LexError"); 1088 | sm_case(" \\)", emit); 1089 | } 1090 | { 1091 | Emit_Rule *emit = sm_emit_rule(); 1092 | sm_emit_handler_direct("LexError"); 1093 | sm_case_eof_peek(emit); 1094 | } 1095 | sm_fallback(raw_string_get_delim); 1096 | 1097 | //// 1098 | 1099 | sm_select_state(raw_string_finish_delim); 1100 | sm_delim_mark_one_past_last(); 1101 | sm_fallback_peek(raw_string_find_close); 1102 | 1103 | //// 1104 | 1105 | sm_select_state(raw_string_find_close); 1106 | sm_case(")", raw_string_try_delim); 1107 | { 1108 | Emit_Rule *emit = sm_emit_rule(); 1109 | sm_emit_handler_direct("LexError"); 1110 | sm_case_eof_peek(emit); 1111 | } 1112 | sm_fallback(raw_string_find_close); 1113 | 1114 | //// 1115 | 1116 | sm_select_state(raw_string_try_delim); 1117 | sm_match_delim(raw_string_try_quote, raw_string_find_close); 1118 | 1119 | //// 1120 | 1121 | sm_select_state(raw_string_try_quote); 1122 | { 1123 | Emit_Rule *emit = sm_emit_rule(); 1124 | sm_emit_handler_direct(is_wide, "LiteralStringWideRaw"); 1125 | sm_emit_handler_direct(is_utf8 , "LiteralStringUTF8Raw"); 1126 | sm_emit_handler_direct(is_utf16, "LiteralStringUTF16Raw"); 1127 | sm_emit_handler_direct(is_utf32, "LiteralStringUTF32Raw"); 1128 | sm_emit_handler_direct("LiteralStringRaw"); 1129 | sm_case("\"", emit); 1130 | } 1131 | sm_fallback_peek(raw_string_find_close); 1132 | 1133 | //// 1134 | 1135 | sm_select_state(comment_block); 1136 | sm_case("*", comment_block_try_close); 1137 | sm_case("\n", comment_block_newline); 1138 | { 1139 | Emit_Rule *emit = sm_emit_rule(); 1140 | sm_emit_handler_direct("BlockComment"); 1141 | sm_case_eof_peek(emit); 1142 | } 1143 | sm_fallback(comment_block); 1144 | 1145 | //// 1146 | 1147 | sm_select_state(comment_block_try_close); 1148 | { 1149 | Emit_Rule *emit = sm_emit_rule(); 1150 | sm_emit_handler_direct("BlockComment"); 1151 | sm_case("/", emit); 1152 | } 1153 | { 1154 | Emit_Rule *emit = sm_emit_rule(); 1155 | sm_emit_handler_direct("BlockComment"); 1156 | sm_case_eof_peek(emit); 1157 | } 1158 | sm_case("*", comment_block_try_close); 1159 | sm_fallback(comment_block); 1160 | 1161 | //// 1162 | 1163 | sm_select_state(comment_block_newline); 1164 | sm_set_flag(is_pp_body, false); 1165 | sm_set_flag(is_include_body, false); 1166 | sm_fallback_peek(comment_block); 1167 | 1168 | //// 1169 | 1170 | sm_select_state(comment_line); 1171 | { 1172 | Emit_Rule *emit = sm_emit_rule(); 1173 | sm_emit_handler_direct("LineComment"); 1174 | sm_case_peek("\n", emit); 1175 | } 1176 | { 1177 | Emit_Rule *emit = sm_emit_rule(); 1178 | sm_emit_handler_direct("LineComment"); 1179 | sm_case_eof_peek(emit); 1180 | } 1181 | sm_case("\\", comment_line_backslashing); 1182 | sm_fallback(comment_line); 1183 | 1184 | sm_select_state(comment_line_backslashing); 1185 | sm_case("\r", comment_line_backslashing); 1186 | sm_fallback(comment_line); 1187 | } 1188 | 1189 | // BOTTOM 1190 | 1191 | -------------------------------------------------------------------------------- /custom_4coder.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skytrias/4coder_skytrias/637333c7864f63749bd976bc517dfa77e9e04cb2/custom_4coder.dll -------------------------------------------------------------------------------- /custom_4coder.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skytrias/4coder_skytrias/637333c7864f63749bd976bc517dfa77e9e04cb2/custom_4coder.so -------------------------------------------------------------------------------- /lex.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call custom\bin\build_one_time.bat custom\languages\4coder_cpp_lexer_gen.cpp 3 | call one_time.exe 4 | call release.bat -------------------------------------------------------------------------------- /lex.sh: -------------------------------------------------------------------------------- 1 | custom/bin/build_one_time.sh custom/languages/4coder_cpp_lexer_gen.cpp ; ./one_time ; sh release.sh 2 | -------------------------------------------------------------------------------- /release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call custom\bin\buildsuper_x64-win.bat custom\4coder_default_bindings.cpp 3 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | sh custom/bin/buildsuper_x64-linux.sh custom/4coder_default_bindings.cpp 2 | -------------------------------------------------------------------------------- /themes/theme-horizon.4coder: -------------------------------------------------------------------------------- 1 | 2 | defcolor_back = 0xFF1C1E26; 3 | defcolor_margin = 0xFF82162f; // below with lower brightness 4 | defcolor_margin_hover = 0xFFb5304f; 5 | defcolor_margin_active = 0xFFE95678; 6 | defcolor_list_item = 0x116C6F93; 7 | defcolor_list_item_hover = 0x336C6F93; 8 | defcolor_list_item_active = 0x336C6F93; 9 | defcolor_cursor = 0xAAE9436F; 10 | defcolor_at_cursor = 0xFF16161C; 11 | defcolor_highlight_cursor_line = 0x08FAB28E; 12 | defcolor_highlight = 0xFFF43E5C; 13 | defcolor_mark = 0xFF25B2BC; 14 | defcolor_text_default = 0xFFFAC29A; 15 | defcolor_at_highlight = defcolor_back; 16 | defcolor_comment = 0xFF6C6F93; 17 | defcolor_comment_pop = {0xFF00A000, 0xFFA00000}; 18 | defcolor_keyword = 0xFFE95678; 19 | 20 | defcolor_str_constant = 0xFFF09383; 21 | defcolor_char_constant = defcolor_str_constant; 22 | 23 | defcolor_int_constant = 0xFF9af9c2; 24 | defcolor_float_constant = defcolor_int_constant; 25 | defcolor_bool_constant = defcolor_int_constant; 26 | defcolor_include = defcolor_int_constant; 27 | defcolor_preproc = 0xFF09F7A0; 28 | defcolor_special_character = 0xFF09F7A0; 29 | defcolor_ghost_character = 0xFF09F7A0; 30 | 31 | defcolor_paste = 0xFFDDEE00; 32 | defcolor_undo = 0xFF00DDEE; 33 | 34 | defcolor_highlight_junk = 0x33859900; 35 | defcolor_highlight_white = 0x33859900; 36 | 37 | defcolor_bar = defcolor_back; 38 | defcolor_bar_active = 0xFF21BFC2; 39 | //defcolor_base = 0xFF6C6F93; 40 | defcolor_base = 0xFFE95678; 41 | defcolor_pop1 = 0xff21BFC2; 42 | defcolor_pop2 = 0xff21BFC2; 43 | 44 | // default 45 | defcolor_back_cycle = {0x00A00000, 0x0000A000, 0x000000A0, 0x00A0A000}; 46 | defcolor_text_cycle = {0xFFF01010, 0xFF20D020, 0xFF0080E0, 0xFFD0D000}; 47 | 48 | // default 49 | defcolor_line_numbers_back = 0xFF101010; 50 | defcolor_line_numbers_text = 0xFF404040; -------------------------------------------------------------------------------- /themes/theme-nord.4coder: -------------------------------------------------------------------------------- 1 | defcolor_back = 0xFF2e3440; 2 | defcolor_margin = 0xFF3b4252; // nord1 3 | defcolor_margin_hover = 0xFF3b4252; // nord1 4 | defcolor_margin_active = 0xFF434c5e; //nord2 5 | defcolor_list_item = 0x334c566a; // nord2 6 | defcolor_list_item_hover = 0x554c566a; // nord2 7 | defcolor_list_item_active = 0x774c566a; // nord2 8 | defcolor_cursor = 0xAA81a1c1; // BLUE with lower alpha 9 | defcolor_at_cursor = defcolor_back; 10 | defcolor_highlight_cursor_line = 0xFF3b4252; 11 | defcolor_highlight = 0xFF8fbcbb; // prolly hover 12 | defcolor_mark = 0xFF8fbcbb; 13 | defcolor_text_default = 0xFFd8dee9; 14 | defcolor_at_highlight = 0xFFbf616a; 15 | defcolor_comment = 0xFF4C566A; 16 | defcolor_comment_pop = {0xFF00A000, 0xFFA00000}; 17 | defcolor_keyword = 0xFF88c0d0; 18 | 19 | defcolor_str_constant = 0xFFa3be8c; 20 | defcolor_char_constant = 0xFFa3be8c; 21 | 22 | defcolor_int_constant = 0xFFb48ead; 23 | defcolor_float_constant = 0xFFb48ead; 24 | defcolor_bool_constant = 0xFF88c0d0; 25 | defcolor_include = 0xFFa3be8c; 26 | defcolor_preproc = 0xFFebcb8b; 27 | defcolor_special_character = 0xFFebcb8b; 28 | defcolor_ghost_character = 0xFFebcb8b; 29 | 30 | defcolor_paste = 0xFFbf616a; 31 | defcolor_undo = 0xFFbf616a; 32 | 33 | defcolor_highlight_junk = 0xFFbf616a; 34 | defcolor_highlight_white = 0xFFbf616a; 35 | 36 | defcolor_bar = 0xFF434c5e; // nord2 37 | defcolor_bar_active = 0xFFbf616a; // RESEARCH 38 | defcolor_base = 0xFFb48ead; // string in title 39 | defcolor_pop1 = 0xFFbf616a; 40 | defcolor_pop2 = 0xFFbf616a; 41 | 42 | // DISABLED 43 | defcolor_back_cycle = { x00A0000, 0x0000A000, 0x000000A0, 0x00A0A000 }; 44 | // NOTE and TODO 45 | defcolor_text_cycle = { 0xFFF01010, 0xFF20D020, 0xFF0080E0, 0xFFD0D000 }; 46 | -------------------------------------------------------------------------------- /themes/theme-solarized-dark.4coder: -------------------------------------------------------------------------------- 1 | defcolor_back = 0xFF002b36; 2 | defcolor_margin = 0xFF073642; // below with lower brightness 3 | defcolor_margin_hover = 0xFF073642; 4 | defcolor_margin_active = 0xFF073642; 5 | defcolor_list_item = {0x11586e75, defcolor_back}; 6 | defcolor_list_item_hover = {0x33586e75, defcolor_margin}; 7 | defcolor_list_item_active = {0x33586e75, defcolor_margin_active}; 8 | defcolor_cursor = {0xFFdc322f, 0xFFEE7700}; 9 | defcolor_at_cursor = defcolor_back; 10 | defcolor_highlight_cursor_line = 0x77073642; 11 | defcolor_highlight = 0xFF6c7100; 12 | defcolor_mark = 0xFF2aa198; 13 | defcolor_text_default = 0xFF93a1a1; 14 | defcolor_at_highlight = defcolor_back; 15 | defcolor_comment = 0xFF586e75; 16 | defcolor_comment_pop = {0xFF00A000, 0xFFA00000}; 17 | defcolor_keyword = 0xFFdc322f; 18 | 19 | defcolor_str_constant = 0xFF2aa198; 20 | defcolor_char_constant = defcolor_str_constant; 21 | 22 | defcolor_int_constant = 0xFF2aa198; 23 | defcolor_float_constant = defcolor_int_constant; 24 | defcolor_bool_constant = defcolor_int_constant; 25 | defcolor_include = defcolor_int_constant; 26 | defcolor_preproc = 0xFF4E5E46; 27 | defcolor_special_character = 0xFF4E5E46; 28 | defcolor_ghost_character = 0xFF4E5E46; 29 | 30 | defcolor_paste = 0xFFDDEE00; 31 | defcolor_undo = 0xFF00DDEE; 32 | 33 | defcolor_highlight_junk = 0x33859900; 34 | defcolor_highlight_white = 0x33859900; 35 | 36 | defcolor_bar = defcolor_back; 37 | defcolor_bar_active = 0xff586e75; 38 | defcolor_base = 0xffdc322f; 39 | defcolor_pop1 = 0xffdc322f; 40 | defcolor_pop2 = 0xffdc322f; 41 | 42 | // default 43 | //defcolor_back_cycle = {0x00A00000, 0x0000A000, 0x000000A0, 0x00A0A000}; 44 | defcolor_text_cycle = {0xFFF01010, 0xFF20D020, 0xFF0080E0, 0xFFD0D000}; 45 | defcolor_back_cycle = {0x05A00000, 0x0500A000, 0x050000A0, 0x05A0A000}; 46 | //defcolor_text_cycle = {0xFFA00000, 0xFF00A000, 0xFF0030B0, 0xFFA0A000}; 47 | 48 | // default 49 | defcolor_line_numbers_back = 0xFF101010; 50 | defcolor_line_numbers_text = 0xFF404040; --------------------------------------------------------------------------------