diff --git a/custom/4coder_base_types.cpp b/custom/4coder_base_types.cpp index 09717a43..677029a2 100644 --- a/custom/4coder_base_types.cpp +++ b/custom/4coder_base_types.cpp @@ -2978,7 +2978,7 @@ make_base_allocator(Base_Allocator_Reserve_Signature *func_reserve, } function Data base_allocate__inner(Base_Allocator *allocator, u64 size, String_Const_u8 location){ - u64 full_size = 0; + u64 full_size = 0; void *memory = allocator->reserve(allocator->user_data, size, &full_size, location); allocator->commit(allocator->user_data, memory, full_size); return(make_data(memory, (u64)full_size)); @@ -4399,6 +4399,26 @@ string_front_of_path(String_Const_u32 str){ return(str); } +function String_Const_u8 +string_remove_front_folder_of_path(String_Const_u8 str){ + i64 slash_pos = string_find_last_slash(string_chop(str, 1)); + if (slash_pos < 0){ + str.size = 0; + } + else{ + str.size = slash_pos + 1; + } + return(str); +} +function String_Const_u8 +string_front_folder_of_path(String_Const_u8 str){ + i64 slash_pos = string_find_last_slash(string_chop(str, 1)); + if (slash_pos >= 0){ + str = string_skip(str, slash_pos + 1); + } + return(str); +} + function String_Const_char string_file_extension(String_Const_char string){ return(string_skip(string, string_find_last(string, '.') + 1)); @@ -4752,7 +4772,7 @@ string_find_first(String_Const_u8 str, String_Const_u8 needle, String_Match_Rule i = str.size; if (str.size >= needle.size){ i = 0; - u8 c = character_to_upper(needle.str[0]); + u8 c = character_to_upper(needle.str[0]); u64 one_past_last = str.size - needle.size + 1; for (;i < one_past_last; i += 1){ if (character_to_upper(str.str[i]) == c){ @@ -4776,7 +4796,7 @@ string_find_first(String_Const_u16 str, String_Const_u16 needle, String_Match_Ru i = str.size; if (str.size >= needle.size){ i = 0; - u16 c = character_to_upper(needle.str[0]); + u16 c = character_to_upper(needle.str[0]); u64 one_past_last = str.size - needle.size + 1; for (;i < one_past_last; i += 1){ if (character_to_upper(str.str[i]) == c){ @@ -4800,7 +4820,7 @@ string_find_first(String_Const_u32 str, String_Const_u32 needle, String_Match_Ru i = str.size; if (str.size >= needle.size){ i = 0; - u32 c = character_to_upper(needle.str[0]); + u32 c = character_to_upper(needle.str[0]); u64 one_past_last = str.size - needle.size + 1; for (;i < one_past_last; i += 1){ if (character_to_upper(str.str[i]) == c){ @@ -5285,7 +5305,7 @@ push_string_copy(Arena *arena, u64 size, String_Const_Any src){ return(string); } - function String_Const_u8_Array +function String_Const_u8_Array push_string_array_copy(Arena *arena, String_Const_u8_Array src){ String_Const_u8_Array result = {}; result.vals = push_array(arena, String_Const_u8, src.count); diff --git a/custom/4coder_lister_base.cpp b/custom/4coder_lister_base.cpp index 315ad374..06341b16 100644 --- a/custom/4coder_lister_base.cpp +++ b/custom/4coder_lister_base.cpp @@ -472,7 +472,7 @@ run_lister(Application_Links *app, Lister *lister){ case InputEventKind_TextInsert: { if (lister->handlers.write_character != 0){ - lister->handlers.write_character(app); + result = lister->handlers.write_character(app); } }break; @@ -627,7 +627,7 @@ run_lister(Application_Links *app, Lister *lister){ switch (in.event.core.code){ case CoreCode_Animate: { - lister_update_filtered_list(app, lister); + lister_update_filtered_list(app, lister); }break; default: @@ -716,8 +716,9 @@ lister_add_item(Lister *lister, String_Const_u8 string, String_Const_u8 status, user_data, extra_space)); } -function void +function Lister_Activation_Code lister__write_string__default(Application_Links *app){ + Lister_Activation_Code result = ListerActivation_Continue; View_ID view = get_active_view(app, Access_Always); Lister *lister = view_get_lister(view); if (lister != 0){ @@ -731,6 +732,7 @@ lister__write_string__default(Application_Links *app){ lister_update_filtered_list(app, lister); } } + return(result); } function void diff --git a/custom/4coder_lister_base.h b/custom/4coder_lister_base.h index c38cc666..aa6fae80 100644 --- a/custom/4coder_lister_base.h +++ b/custom/4coder_lister_base.h @@ -39,6 +39,7 @@ struct Lister_Node_Ptr_Array{ i32 count; }; +typedef Lister_Activation_Code Lister_Write_Character_Function(Application_Links *app); typedef Lister_Activation_Code Lister_Key_Stroke_Function(Application_Links *app); typedef void Lister_Navigate_Function(Application_Links *app, View_ID view, struct Lister *lister, @@ -46,7 +47,7 @@ typedef void Lister_Navigate_Function(Application_Links *app, struct Lister_Handlers{ Lister_Regenerate_List_Function_Type *refresh; - Custom_Command_Function *write_character; + Lister_Write_Character_Function *write_character; Custom_Command_Function *backspace; Lister_Navigate_Function *navigate; Lister_Key_Stroke_Function *key_stroke; diff --git a/custom/4coder_lists.cpp b/custom/4coder_lists.cpp index 7438a50f..bc27d363 100644 --- a/custom/4coder_lists.cpp +++ b/custom/4coder_lists.cpp @@ -222,7 +222,7 @@ get_color_table_from_user(Application_Links *app, String_Const_u8 query, Color_T Lister_Result l_result = run_lister(app, lister); - Color_Table *result = 0; + Color_Table *result = 0; if (!l_result.canceled){ result = (Color_Table*)l_result.user_data; } @@ -236,8 +236,9 @@ get_color_table_from_user(Application_Links *app){ //////////////////////////////// -function void +function Lister_Activation_Code lister__write_character__file_path(Application_Links *app){ + Lister_Activation_Code result = ListerActivation_Continue; View_ID view = get_this_ctx_view(app, Access_Always); Lister *lister = view_get_lister(view); if (lister != 0){ @@ -245,18 +246,20 @@ lister__write_character__file_path(Application_Links *app){ String_Const_u8 string = to_writable(&in); if (string.str != 0 && string.size > 0){ lister_append_text_field(lister, string); - String_Const_u8 front_name = string_front_of_path(lister->text_field.string); - lister_set_key(lister, front_name); if (character_is_slash(string.str[0])){ - String_Const_u8 new_hot = lister->text_field.string; - set_hot_directory(app, new_hot); - lister_call_refresh_handler(app, lister); + lister->out.text_field = lister->text_field.string; + result = ListerActivation_Finished; + } + else{ + String_Const_u8 front_name = string_front_of_path(lister->text_field.string); + lister_set_key(lister, front_name); } lister->item_index = 0; lister_zero_scroll(lister); lister_update_filtered_list(app, lister); } } + return(result); } function void @@ -374,15 +377,13 @@ struct File_Name_Result{ }; function File_Name_Result -get_file_name_from_user(Application_Links *app, Arena *arena, String_Const_u8 query, - View_ID view){ +get_file_name_from_user(Application_Links *app, Arena *arena, String_Const_u8 query, View_ID view){ Lister_Handlers handlers = lister_get_default_handlers(); handlers.refresh = generate_hot_directory_file_list; handlers.write_character = lister__write_character__file_path; handlers.backspace = lister__backspace_text_field__file_path; - Lister_Result l_result = - run_lister_with_refresh_handler(app, arena, query, handlers); + Lister_Result l_result = run_lister_with_refresh_handler(app, arena, query, handlers); File_Name_Result result = {}; result.canceled = l_result.canceled; @@ -391,12 +392,18 @@ get_file_name_from_user(Application_Links *app, Arena *arena, String_Const_u8 qu if (l_result.user_data != 0){ String_Const_u8 name = SCu8((u8*)l_result.user_data); result.file_name_activated = name; - result.is_folder = - character_is_slash(string_get_character(name, name.size -1 )); + result.is_folder = character_is_slash(string_get_character(name, name.size - 1)); } result.file_name_in_text_field = string_front_of_path(l_result.text_field); - String_Const_u8 path = string_remove_front_of_path(l_result.text_field); + String_Const_u8 path = {}; + if (result.file_name_in_text_field.size == 0 && l_result.text_field.size > 0){ + result.file_name_in_text_field = string_front_folder_of_path(l_result.text_field); + path = string_remove_front_folder_of_path(l_result.text_field); + } + else{ + path = string_remove_front_of_path(l_result.text_field); + } if (character_is_slash(string_get_character(path, path.size - 1))){ path = string_chop(path, 1); } @@ -407,8 +414,7 @@ get_file_name_from_user(Application_Links *app, Arena *arena, String_Const_u8 qu } function File_Name_Result -get_file_name_from_user(Application_Links *app, Arena *arena, char *query, - View_ID view){ +get_file_name_from_user(Application_Links *app, Arena *arena, char *query, View_ID view){ return(get_file_name_from_user(app, arena, SCu8(query), view)); } @@ -429,8 +435,7 @@ do_buffer_kill_user_check(Application_Links *app, Buffer_ID buffer, View_ID view lister_choice(scratch, &list, "(Y)es" , "", KeyCode_Y, SureToKill_Yes); lister_choice(scratch, &list, "(S)ave", "", KeyCode_S, SureToKill_Save); - Lister_Choice *choice = - get_choice_from_user(app, "There are unsaved changes, close anyway?", list); + Lister_Choice *choice = get_choice_from_user(app, "There are unsaved changes, close anyway?", list); b32 do_kill = false; if (choice != 0){ @@ -507,7 +512,7 @@ CUSTOM_DOC("Interactively switch to an open buffer.") { Buffer_ID buffer = get_buffer_from_user(app, "Switch:"); if (buffer != 0){ - View_ID view = get_this_ctx_view(app, Access_Always); + View_ID view = get_this_ctx_view(app, Access_Always); view_set_buffer(app, view, buffer, 0); } } @@ -524,6 +529,50 @@ CUSTOM_DOC("Interactively kill an open buffer.") //////////////////////////////// +enum{ + SureToCreateFolder_NULL = 0, + SureToCreateFolder_No = 1, + SureToCreateFolder_Yes = 2, +}; + +function b32 +query_create_folder(Application_Links *app, String_Const_u8 folder_name){ + Scratch_Block scratch(app); + Lister_Choice_List list = {}; + lister_choice(scratch, &list, "(N)o" , "", KeyCode_N, SureToKill_No); + lister_choice(scratch, &list, "(Y)es" , "", KeyCode_Y, SureToKill_Yes); + + String_Const_u8 message = push_u8_stringf(scratch, "Create the folder %.*s?", string_expand(folder_name)); + Lister_Choice *choice = get_choice_from_user(app, message, list); + + b32 did_create_folder = false; + if (choice != 0){ + switch (choice->user_data){ + case SureToCreateFolder_No: + {}break; + + case SureToCreateFolder_Yes: + { + String_Const_u8 hot = push_hot_directory(app, scratch); + String_Const_u8 fixed_folder_name = folder_name; + for (;fixed_folder_name.size > 0 && + character_is_slash(fixed_folder_name.str[fixed_folder_name.size - 1]);){ + fixed_folder_name = string_chop(fixed_folder_name, 1); + } + if (fixed_folder_name.size > 0){ + String_Const_u8 cmd = push_u8_stringf(scratch, "mkdir %.*s", string_expand(fixed_folder_name)); + exec_system_command(app, 0, buffer_identifier(0), hot, cmd, 0); + did_create_folder = true; + } + }break; + } + } + + return(did_create_folder); +} + +//////////////////////////////// + function Lister_Activation_Code activate_open_or_new__generic(Application_Links *app, View_ID view, String_Const_u8 path, String_Const_u8 file_name, @@ -566,8 +615,7 @@ CUSTOM_DOC("Interactively open a file out of the file system.") for (;;){ Scratch_Block scratch(app); View_ID view = get_this_ctx_view(app, Access_Always); - File_Name_Result result = get_file_name_from_user(app, scratch, "Open:", - view); + File_Name_Result result = get_file_name_from_user(app, scratch, "Open:", view); if (result.canceled) break; String_Const_u8 file_name = result.file_name_activated; @@ -577,15 +625,27 @@ CUSTOM_DOC("Interactively open a file out of the file system.") if (file_name.size == 0) break; String_Const_u8 path = result.path_in_text_field; - String_Const_u8 full_file_name = - push_u8_stringf(scratch, "%.*s/%.*s", - string_expand(path), string_expand(file_name)); + String_Const_u8 full_file_name = push_u8_stringf(scratch, "%.*s/%.*s", + string_expand(path), string_expand(file_name)); if (result.is_folder){ set_hot_directory(app, full_file_name); continue; } + if (character_is_slash(file_name.str[file_name.size - 1])){ + File_Attributes attribs = system_quick_file_attributes(scratch, full_file_name); + if (HasFlag(attribs.flags, FileAttribute_IsDirectory)){ + set_hot_directory(app, full_file_name); + continue; + } + if (query_create_folder(app, file_name)){ + set_hot_directory(app, full_file_name); + continue; + } + break; + } + Buffer_ID buffer = create_buffer(app, full_file_name, 0); if (buffer != 0){ view_set_buffer(app, view, buffer, 0); @@ -670,20 +730,20 @@ CUSTOM_DOC("Opens an interactive list of all registered commands.") { View_ID view = get_this_ctx_view(app, Access_Always); if (view != 0){ - Command_Lister_Status_Rule rule = {}; - Buffer_ID buffer = view_get_buffer(app, view, Access_Visible); - Managed_Scope buffer_scope = buffer_get_managed_scope(app, buffer); - Command_Map_ID *map_id_ptr = scope_attachment(app, buffer_scope, buffer_map_id, Command_Map_ID); - if (map_id_ptr != 0){ - rule = command_lister_status_bindings(&framework_mapping, *map_id_ptr); - } - else{ - rule = command_lister_status_descriptions(); - } - Custom_Command_Function *func = get_command_from_user(app, "Command:", &rule); - if (func != 0){ - view_enqueue_command_function(app, view, func); - } + Command_Lister_Status_Rule rule = {}; + Buffer_ID buffer = view_get_buffer(app, view, Access_Visible); + Managed_Scope buffer_scope = buffer_get_managed_scope(app, buffer); + Command_Map_ID *map_id_ptr = scope_attachment(app, buffer_scope, buffer_map_id, Command_Map_ID); + if (map_id_ptr != 0){ + rule = command_lister_status_bindings(&framework_mapping, *map_id_ptr); + } + else{ + rule = command_lister_status_descriptions(); + } + Custom_Command_Function *func = get_command_from_user(app, "Command:", &rule); + if (func != 0){ + view_enqueue_command_function(app, view, func); + } } } diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index a1d0cdde..8e9958d0 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -274,7 +274,7 @@ static Command_Metadata fcoder_metacmd_table[229] = { { PROC_LINKS(close_build_panel, 0), false, "close_build_panel", 17, "If the special build panel is open, closes it.", 46, "w:\\4ed\\code\\custom\\4coder_build_commands.cpp", 44, 180 }, { PROC_LINKS(close_panel, 0), false, "close_panel", 11, "Closes the currently active panel if it is not the only panel open.", 67, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 619 }, { PROC_LINKS(command_documentation, 0), true, "command_documentation", 21, "Prompts the user to select a command then loads a doc buffer for that item", 74, "w:\\4ed\\code\\custom\\4coder_docs.cpp", 34, 190 }, -{ PROC_LINKS(command_lister, 0), true, "command_lister", 14, "Opens an interactive list of all registered commands.", 53, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 668 }, +{ PROC_LINKS(command_lister, 0), true, "command_lister", 14, "Opens an interactive list of all registered commands.", 53, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 728 }, { PROC_LINKS(comment_line, 0), false, "comment_line", 12, "Insert '//' at the beginning of the line after leading whitespace.", 66, "w:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 125 }, { PROC_LINKS(comment_line_toggle, 0), false, "comment_line_toggle", 19, "Turns uncommented lines into commented lines and vice versa for comments starting with '//'.", 92, "w:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 149 }, { PROC_LINKS(copy, 0), false, "copy", 4, "Copy the text in the range from the cursor to the mark onto the clipboard.", 74, "w:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 19 }, @@ -314,11 +314,11 @@ static Command_Metadata fcoder_metacmd_table[229] = { { PROC_LINKS(if_read_only_goto_position, 0), false, "if_read_only_goto_position", 26, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor.", 106, "w:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 562 }, { PROC_LINKS(if_read_only_goto_position_same_panel, 0), false, "if_read_only_goto_position_same_panel", 37, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor_same_panel.", 117, "w:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 579 }, { PROC_LINKS(increase_face_size, 0), false, "increase_face_size", 18, "Increase the size of the face used by the current buffer.", 57, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 671 }, -{ PROC_LINKS(interactive_kill_buffer, 0), true, "interactive_kill_buffer", 23, "Interactively kill an open buffer.", 34, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 515 }, -{ PROC_LINKS(interactive_new, 0), true, "interactive_new", 15, "Interactively creates a new file.", 33, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 597 }, -{ PROC_LINKS(interactive_open, 0), true, "interactive_open", 16, "Interactively opens a file.", 27, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 634 }, -{ PROC_LINKS(interactive_open_or_new, 0), true, "interactive_open_or_new", 23, "Interactively open a file out of the file system.", 49, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 563 }, -{ PROC_LINKS(interactive_switch_buffer, 0), true, "interactive_switch_buffer", 25, "Interactively switch to an open buffer.", 39, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 505 }, +{ PROC_LINKS(interactive_kill_buffer, 0), true, "interactive_kill_buffer", 23, "Interactively kill an open buffer.", 34, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 520 }, +{ PROC_LINKS(interactive_new, 0), true, "interactive_new", 15, "Interactively creates a new file.", 33, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 657 }, +{ PROC_LINKS(interactive_open, 0), true, "interactive_open", 16, "Interactively opens a file.", 27, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 694 }, +{ PROC_LINKS(interactive_open_or_new, 0), true, "interactive_open_or_new", 23, "Interactively open a file out of the file system.", 49, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 612 }, +{ PROC_LINKS(interactive_switch_buffer, 0), true, "interactive_switch_buffer", 25, "Interactively switch to an open buffer.", 39, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 510 }, { PROC_LINKS(jump_to_definition, 0), true, "jump_to_definition", 18, "List all definitions in the code index and jump to one chosen by the user.", 74, "w:\\4ed\\code\\custom\\4coder_code_index_listers.cpp", 48, 12 }, { PROC_LINKS(keyboard_macro_finish_recording, 0), false, "keyboard_macro_finish_recording", 31, "Stop macro recording, do nothing if macro recording is not already started", 74, "w:\\4ed\\code\\custom\\4coder_keyboard_macro.cpp", 44, 54 }, { PROC_LINKS(keyboard_macro_replay, 0), false, "keyboard_macro_replay", 21, "Replay the most recently recorded keyboard macro", 48, "w:\\4ed\\code\\custom\\4coder_keyboard_macro.cpp", 44, 77 }, @@ -448,7 +448,7 @@ static Command_Metadata fcoder_metacmd_table[229] = { { PROC_LINKS(snippet_lister, 0), true, "snippet_lister", 14, "Opens a snippet lister for inserting whole pre-written snippets of text.", 72, "w:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 237 }, { PROC_LINKS(suppress_mouse, 0), false, "suppress_mouse", 14, "Hides the mouse and causes all mosue input (clicks, position, wheel) to be ignored.", 83, "w:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 403 }, { PROC_LINKS(swap_panels, 0), false, "swap_panels", 11, "Swaps the active panel with it's sibling.", 41, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1513 }, -{ PROC_LINKS(theme_lister, 0), true, "theme_lister", 12, "Opens an interactive list of all registered themes.", 51, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 692 }, +{ PROC_LINKS(theme_lister, 0), true, "theme_lister", 12, "Opens an interactive list of all registered themes.", 51, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 752 }, { PROC_LINKS(to_lowercase, 0), false, "to_lowercase", 12, "Converts all ascii text in the range between the cursor and the mark to lowercase.", 82, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 563 }, { PROC_LINKS(to_uppercase, 0), false, "to_uppercase", 12, "Converts all ascii text in the range between the cursor and the mark to uppercase.", 82, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 550 }, { PROC_LINKS(toggle_filebar, 0), false, "toggle_filebar", 14, "Toggles the visibility status of the current view's filebar.", 60, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 656 },