§5.4.2: cpp_lex_step
Cpp_Lex_Result cpp_lex_step(
Cpp_Lex_Data *S_ptr,
char *chunk,
int32_t size,
int32_t full_size,
Cpp_Token_Array *token_array_out,
int32_t max_tokens_out
)
Parameters
S_ptr
The lexer state. Go to the Cpp_Lex_Data section to see how to initialize the state.
chunk
The first or next chunk of the file being lexed.
size
The number of bytes in the chunk including the null terminator if the chunk ends in a null terminator. If the chunk ends in a null terminator the system will interpret it as the end of the file.
full_size
If the final chunk is not null terminated this parameter should specify the length of the file in bytes. To rely on an eventual null terminator use HAS_NULL_TERM for this parameter.
token_array_out
The token array structure that will receive the tokens output by the lexer.
max_tokens_out
The maximum number of tokens to be output to the token array. To rely on the
+max built into the token array pass NO_OUT_LIMIT here.
Description
This call is the primary interface of the lexing system. It is quite general so it can be used in a lot of different ways. I will explain the general rules first, and then give some examples of common ways it might be used.
First a lexing state, Cpp_Lex_Data, must be initialized. The file to lex must be read into N contiguous chunks
of memory. An output Cpp_Token_Array must be allocated and initialized with the appropriate count and max_count
values. Then each chunk of the file must be passed to cpp_lex_step in order using the same lexing state for each call.
diff --git a/4coder_auto_indent.cpp b/4coder_auto_indent.cpp
index 76790477..94f2c7e5 100644
--- a/4coder_auto_indent.cpp
+++ b/4coder_auto_indent.cpp
@@ -511,7 +511,7 @@ get_indent_lines_whole_tokens(Application_Links *app, Buffer_Summary *buffer, Cp
for (;line_start > 0;){
int32_t line_start_pos = 0;
Cpp_Token *token = get_first_token_at_line(app, buffer, tokens, line_start, &line_start_pos);
- if (token->start < line_start_pos){
+ if (token && token->start < line_start_pos){
line_start = buffer_get_line_index(app, buffer, token->start);
}
else{
diff --git a/4coder_custom_api.h b/4coder_custom_api.h
index b1e8075f..8bcfdd38 100644
--- a/4coder_custom_api.h
+++ b/4coder_custom_api.h
@@ -55,6 +55,7 @@
#define DIRECTORY_GET_HOT_SIG(n) int32_t n(Application_Links *app, char *out, int32_t capacity)
#define GET_FILE_LIST_SIG(n) File_List n(Application_Links *app, char *dir, int32_t len)
#define FREE_FILE_LIST_SIG(n) void n(Application_Links *app, File_List list)
+#define SET_GUI_UP_DOWN_KEYS_SIG(n) void n(Application_Links *app, int16_t up_key, int16_t down_key)
#define MEMORY_ALLOCATE_SIG(n) void* n(Application_Links *app, int32_t size)
#define MEMORY_SET_PROTECTION_SIG(n) bool32 n(Application_Links *app, void *ptr, int32_t size, Memory_Protect_Flags flags)
#define MEMORY_FREE_SIG(n) void n(Application_Links *app, void *ptr, int32_t size)
@@ -122,6 +123,7 @@ typedef GET_THEME_COLORS_SIG(Get_Theme_Colors_Function);
typedef DIRECTORY_GET_HOT_SIG(Directory_Get_Hot_Function);
typedef GET_FILE_LIST_SIG(Get_File_List_Function);
typedef FREE_FILE_LIST_SIG(Free_File_List_Function);
+typedef SET_GUI_UP_DOWN_KEYS_SIG(Set_GUI_Up_Down_Keys_Function);
typedef MEMORY_ALLOCATE_SIG(Memory_Allocate_Function);
typedef MEMORY_SET_PROTECTION_SIG(Memory_Set_Protection_Function);
typedef MEMORY_FREE_SIG(Memory_Free_Function);
@@ -191,6 +193,7 @@ Get_Theme_Colors_Function *get_theme_colors;
Directory_Get_Hot_Function *directory_get_hot;
Get_File_List_Function *get_file_list;
Free_File_List_Function *free_file_list;
+Set_GUI_Up_Down_Keys_Function *set_gui_up_down_keys;
Memory_Allocate_Function *memory_allocate;
Memory_Set_Protection_Function *memory_set_protection;
Memory_Free_Function *memory_free;
@@ -259,6 +262,7 @@ Get_Theme_Colors_Function *get_theme_colors_;
Directory_Get_Hot_Function *directory_get_hot_;
Get_File_List_Function *get_file_list_;
Free_File_List_Function *free_file_list_;
+Set_GUI_Up_Down_Keys_Function *set_gui_up_down_keys_;
Memory_Allocate_Function *memory_allocate_;
Memory_Set_Protection_Function *memory_set_protection_;
Memory_Free_Function *memory_free_;
@@ -335,6 +339,7 @@ app_links->get_theme_colors_ = Get_Theme_Colors;\
app_links->directory_get_hot_ = Directory_Get_Hot;\
app_links->get_file_list_ = Get_File_List;\
app_links->free_file_list_ = Free_File_List;\
+app_links->set_gui_up_down_keys_ = Set_GUI_Up_Down_Keys;\
app_links->memory_allocate_ = Memory_Allocate;\
app_links->memory_set_protection_ = Memory_Set_Protection;\
app_links->memory_free_ = Memory_Free;\
@@ -403,6 +408,7 @@ static inline void get_theme_colors(Application_Links *app, Theme_Color *colors,
static inline int32_t directory_get_hot(Application_Links *app, char *out, int32_t capacity){return(app->directory_get_hot(app, out, capacity));}
static inline File_List get_file_list(Application_Links *app, char *dir, int32_t len){return(app->get_file_list(app, dir, len));}
static inline void free_file_list(Application_Links *app, File_List list){(app->free_file_list(app, list));}
+static inline void set_gui_up_down_keys(Application_Links *app, int16_t up_key, int16_t down_key){(app->set_gui_up_down_keys(app, up_key, down_key));}
static inline void* memory_allocate(Application_Links *app, int32_t size){return(app->memory_allocate(app, size));}
static inline bool32 memory_set_protection(Application_Links *app, void *ptr, int32_t size, Memory_Protect_Flags flags){return(app->memory_set_protection(app, ptr, size, flags));}
static inline void memory_free(Application_Links *app, void *ptr, int32_t size){(app->memory_free(app, ptr, size));}
@@ -471,6 +477,7 @@ static inline void get_theme_colors(Application_Links *app, Theme_Color *colors,
static inline int32_t directory_get_hot(Application_Links *app, char *out, int32_t capacity){return(app->directory_get_hot_(app, out, capacity));}
static inline File_List get_file_list(Application_Links *app, char *dir, int32_t len){return(app->get_file_list_(app, dir, len));}
static inline void free_file_list(Application_Links *app, File_List list){(app->free_file_list_(app, list));}
+static inline void set_gui_up_down_keys(Application_Links *app, int16_t up_key, int16_t down_key){(app->set_gui_up_down_keys_(app, up_key, down_key));}
static inline void* memory_allocate(Application_Links *app, int32_t size){return(app->memory_allocate_(app, size));}
static inline bool32 memory_set_protection(Application_Links *app, void *ptr, int32_t size, Memory_Protect_Flags flags){return(app->memory_set_protection_(app, ptr, size, flags));}
static inline void memory_free(Application_Links *app, void *ptr, int32_t size){(app->memory_free_(app, ptr, size));}
diff --git a/4coder_default_bindings.cpp b/4coder_default_bindings.cpp
index bc060812..fbfab126 100644
--- a/4coder_default_bindings.cpp
+++ b/4coder_default_bindings.cpp
@@ -124,9 +124,88 @@ CUSTOM_COMMAND_SIG(seek_whitespace_down_end_line){
exec_command(app, seek_end_of_line);
}
+static bool32 enable_code_wrapping = 1;
+static int32_t default_wrap_width = 672;
+
HOOK_SIG(my_start){
init_memory(app);
+ {
+ FILE *file = fopen("config.4coder", "rb");
+ if (file){
+ Temp_Memory temp = begin_temp_memory(&global_part);
+
+ fseek(file, 0, SEEK_END);
+ int32_t size = ftell(file);
+ char *mem = (char*)push_block(&global_part, size+1);
+ fseek(file, 0, SEEK_SET);
+ fread(mem, 1, size+1, file);
+ fclose(file);
+
+ Cpp_Token_Array array;
+ array.count = 0;
+ array.max_count = (1 << 20)/sizeof(Cpp_Token);
+ array.tokens = push_array(&global_part, Cpp_Token, array.max_count);
+
+ Cpp_Lex_Data S = cpp_lex_data_init();
+ Cpp_Lex_Result result = cpp_lex_step(&S, mem, size, HAS_NULL_TERM, &array, NO_OUT_LIMIT);
+
+ if (result == LexResult_Finished){
+
+ for (int32_t i = 0; i < array.count; ++i){
+ int32_t read_setting_failed = 1;
+ Cpp_Token id_token = array.tokens[i];
+ if (id_token.type == CPP_TOKEN_IDENTIFIER){
+ ++i;
+ if (i < array.count){
+ Cpp_Token eq_token = array.tokens[i];
+ if (eq_token.type == CPP_TOKEN_EQEQ){
+ ++i;
+ if (i < array.count){
+ Cpp_Token val_token = array.tokens[i];
+ {
+ ++i;
+ if (i < array.count){
+ Cpp_Token semicolon_token = array.tokens[i];
+ if (semicolon_token.type == CPP_TOKEN_SEMICOLON){
+ read_setting_failed = 0;
+
+ String id = make_string(mem + id_token.start, id_token.size);
+
+ if (match(id, "enable_code_wrapping")){
+ if (val_token.type == CPP_TOKEN_BOOLEAN_CONSTANT){
+ String val = make_string(mem + val_token.start, val_token.size);
+ if (val.str[0] == 't'){
+ enable_code_wrapping = 1;
+ }
+ else{
+ enable_code_wrapping = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (read_setting_failed){
+ for (; i < array.count; ++i){
+ Cpp_Token token = array.tokens[i];
+ if (token.type == CPP_TOKEN_SEMICOLON){
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ end_temp_memory(temp);
+ }
+ }
+
change_theme(app, literal("4coder"));
change_font(app, literal("Liberation Sans"), true);
@@ -135,6 +214,12 @@ HOOK_SIG(my_start){
exec_command(app, change_active_panel);
exec_command(app, hide_scrollbar);
+ {
+ View_Summary view = get_active_view(app, AccessAll);
+ int32_t width = view.file_region.x1 - view.file_region.x0;
+ default_wrap_width = width - 40;
+ }
+
// Theme options:
// "4coder"
// "Handmade Hero"
@@ -214,8 +299,13 @@ OPEN_FILE_HOOK_SIG(my_file_settings){
buffer_set_setting(app, &buffer, BufferSetting_Lex, treat_as_code);
buffer_set_setting(app, &buffer, BufferSetting_WrapLine, wrap_lines);
- buffer_set_setting(app, &buffer, BufferSetting_MapID,
- (treat_as_code)?((int32_t)my_code_map):((int32_t)mapid_file));
+ buffer_set_setting(app, &buffer, BufferSetting_WrapPosition, default_wrap_width);
+ buffer_set_setting(app, &buffer, BufferSetting_MapID, (treat_as_code)?((int32_t)my_code_map):((int32_t)mapid_file));
+
+ if (treat_as_code && enable_code_wrapping && buffer.size < (1 << 20)){
+ buffer_set_setting(app, &buffer, BufferSetting_WrapLine, 1);
+ buffer_set_setting(app, &buffer, BufferSetting_VirtualWhitespace, 1);
+ }
// no meaning for return
return(0);
diff --git a/4coder_default_include.cpp b/4coder_default_include.cpp
index fa595830..d87709e4 100644
--- a/4coder_default_include.cpp
+++ b/4coder_default_include.cpp
@@ -1354,16 +1354,14 @@ buffer_seek_whitespace_up(Application_Links *app, Buffer_Summary *buffer, int32_
int32_t chunk_size = sizeof(chunk);
Stream_Chunk stream = {0};
- int32_t no_hard;
- int32_t still_looping;
char at_pos;
--pos;
if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){
// Step 1: Find the first non-whitespace character
// behind the current position.
- still_looping = true;
- do{
+ int32_t still_looping = 1;
+ while (still_looping){
for (; pos >= stream.start; --pos){
at_pos = stream.data[pos];
if (!char_is_whitespace(at_pos)){
@@ -1371,7 +1369,7 @@ buffer_seek_whitespace_up(Application_Links *app, Buffer_Summary *buffer, int32_
}
}
still_looping = backward_stream_chunk(&stream);
- } while(still_looping);
+ }
double_break_1:;
// Step 2: Continue scanning backward, at each '\n'
@@ -1379,7 +1377,7 @@ buffer_seek_whitespace_up(Application_Links *app, Buffer_Summary *buffer, int32_
// no_hard to true, set it back to false if a
// non-whitespace character is discovered before
// the next '\n'
- no_hard = false;
+ int32_t no_hard = false;
while (still_looping){
for (; pos >= stream.start; --pos){
at_pos = stream.data[pos];
@@ -2119,15 +2117,11 @@ CUSTOM_COMMAND_SIG(delete_word){
CUSTOM_COMMAND_SIG(snipe_token_or_word){
uint32_t access = AccessOpen;
- View_Summary view;
- Buffer_Summary buffer;
- int32_t pos1, pos2;
+ View_Summary view = get_active_view(app, access);
+ Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
- view = get_active_view(app, access);
- buffer = get_buffer(app, view.buffer_id, access);
-
- pos1 = buffer_boundary_seek(app, &buffer, view.cursor.pos, false, BoundaryToken | BoundaryWhitespace);
- pos2 = buffer_boundary_seek(app, &buffer, pos1, true, BoundaryToken | BoundaryWhitespace);
+ int32_t pos1 = buffer_boundary_seek(app, &buffer, view.cursor.pos, false, BoundaryToken | BoundaryWhitespace);
+ int32_t pos2 = buffer_boundary_seek(app, &buffer, pos1, true, BoundaryToken | BoundaryWhitespace);
Range range = make_range(pos1, pos2);
buffer_replace_range(app, &buffer, range.start, range.end, 0, 0);
diff --git a/4coder_types.h b/4coder_types.h
index c159781a..2a0d0996 100644
--- a/4coder_types.h
+++ b/4coder_types.h
@@ -123,6 +123,18 @@ ENUM(int32_t, Event_Message_Type_ID){
EventMessage_CloseView
};
+/* DOC(A Wrap_Indicator_Mode is used in the buffer setting BufferSetting_WrapIndicator to specify how to indicate that line has been wrapped.) */
+ENUM(int32_t, Wrap_Indicator_Mode){
+ /* DOC(WrapIndicator_Hide tells the buffer rendering system not to put any indicator on wrapped lines.) */
+ WrapIndicator_Hide,
+
+ /* DOC(WrapIndicator_Show_After_Line tells the buffer rendering system to put a backslash indicator on wrapped lines right after the last character of the line.) */
+ WrapIndicator_Show_After_Line,
+
+ /* DOC(WrapIndicator_Show_At_Wrap_Edge tells the buffer rendering system to put a backslash indicator on wrapped lines aligned with the wrap position for that line.) */
+ WrapIndicator_Show_At_Wrap_Edge,
+};
+
/* DOC(A Buffer_Setting_ID names a setting in a buffer.) */
ENUM(int32_t, Buffer_Setting_ID){
/* DOC(BufferSetting_Null is not a valid setting, it is reserved to detect errors.) */
@@ -145,6 +157,12 @@ ENUM(int32_t, Buffer_Setting_ID){
best behavior try to only set this setting once per frame, if possible.) */
BufferSetting_WrapPosition,
+ /* DOC(The BufferSetting_MinimumBaseWrapPosition setting is used to increase the with in pixels allotted to a line for wrapping, by setting a minimum position away from the base of the line. The base of a line is always 0, or the left hand side of the view, in text files. In code files the base of a line is the amount the line is shifted to the right due to brace nesting. This setting allows for deeply nested code to remain readable by ensuring lines deep in the nesting get some minimum base width which may be more wrapping space than the non base adjusted wrap position would have allowed. In any case where the (default wrapping position) is greater than (the base + minimum base position), the larger ) the default will still be used. */
+ BufferSetting_MinimumBaseWrapPosition,
+
+ /* DOC(The BufferSetting_WrapIndicator setting is used to specify how wrapped lines should be marked so the user can see that they have been wrapped. The value should be one of the values in the Wrap_Indicator_Mode enum.) DOC_SEE(Wrap_Indicator_Mode) */
+ BufferSetting_WrapIndicator,
+
/* DOC(The BufferSetting_MapID setting specifies the id of the command map that should be
active when a buffer is active.) */
BufferSetting_MapID,
diff --git a/4cpp_lexer.h b/4cpp_lexer.h
index 25020c72..cfa20e95 100644
--- a/4cpp_lexer.h
+++ b/4cpp_lexer.h
@@ -954,21 +954,15 @@ cpp_lex_nonalloc_no_null_out_limit(Cpp_Lex_Data *S_ptr, char *chunk, int32_t siz
#define NO_OUT_LIMIT ((int32_t)(-1))
FCPP_LINK Cpp_Lex_Result
-cpp_lex_step(Cpp_Lex_Data *S_ptr, char *chunk, int32_t size, int32_t full_size,
- Cpp_Token_Array *token_array_out, int32_t max_tokens_out)/*
+cpp_lex_step(Cpp_Lex_Data *S_ptr, char *chunk, int32_t size, int32_t full_size, Cpp_Token_Array *token_array_out, int32_t max_tokens_out)/*
DOC_PARAM(S_ptr, The lexer state. Go to the Cpp_Lex_Data section to see how to initialize the state.)
DOC_PARAM(chunk, The first or next chunk of the file being lexed.)
-DOC_PARAM(size, The number of bytes in the chunk including the null terminator if the chunk ends in a null terminator.
-If the chunk ends in a null terminator the system will interpret it as the end of the file.)
-DOC_PARAM(full_size, If the final chunk is not null terminated this parameter should specify the length of the
-file in bytes. To rely on an eventual null terminator use HAS_NULL_TERM for this parameter.)
+DOC_PARAM(size, The number of bytes in the chunk including the null terminator if the chunk ends in a null terminator. If the chunk ends in a null terminator the system will interpret it as the end of the file.)
+DOC_PARAM(full_size, If the final chunk is not null terminated this parameter should specify the length of the file in bytes. To rely on an eventual null terminator use HAS_NULL_TERM for this parameter.)
DOC_PARAM(token_array_out, The token array structure that will receive the tokens output by the lexer.)
DOC_PARAM(max_tokens_out, The maximum number of tokens to be output to the token array. To rely on the
max built into the token array pass NO_OUT_LIMIT here.)
-
-DOC(This call is the primary interface of the lexing system. It is quite general so it can be used in
-a lot of different ways. I will explain the general rules first, and then give some examples of common
-ways it might be used.
+DOC(This call is the primary interface of the lexing system. It is quite general so it can be used in a lot of different ways. I will explain the general rules first, and then give some examples of common ways it might be used.
First a lexing state, Cpp_Lex_Data, must be initialized. The file to lex must be read into N contiguous chunks
of memory. An output Cpp_Token_Array must be allocated and initialized with the appropriate count and max_count
diff --git a/4ed.cpp b/4ed.cpp
index b3983af1..0d7569f3 100644
--- a/4ed.cpp
+++ b/4ed.cpp
@@ -1733,6 +1733,10 @@ App_Init_Sig(app_init){
vars->cli_processes.procs = push_array(partition, CLI_Process, max_children);
vars->cli_processes.max = max_children;
vars->cli_processes.count = 0;
+
+ // NOTE(allen): init GUI keys
+ models->user_up_key = key_up;
+ models->user_down_key = key_down;
}
internal i32
diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp
index 28d452bb..2aebafc1 100644
--- a/4ed_api_implementation.cpp
+++ b/4ed_api_implementation.cpp
@@ -787,6 +787,24 @@ DOC_SEE(Buffer_Setting_ID)
}
}break;
+ case BufferSetting_MinimumBaseWrapPosition:
+ {
+ i32 new_value = value;
+ if (new_value < 0){
+ new_value = 0;
+ }
+ if (new_value != file->settings.minimum_base_display_width){
+ i16 font_id = file->settings.font_id;
+ Render_Font *font = get_font_info(models->font_set, font_id)->font;
+ file_set_minimum_base_display_width_and_fix_cursor(system, models, file, new_value, (f32)font->height, font->advance_data);
+ }
+ }break;
+
+ case BufferSetting_WrapIndicator:
+ {
+ file->settings.wrap_indicator = value;
+ }break;
+
case BufferSetting_MapID:
{
if (value == mapid_global){
@@ -2226,5 +2244,14 @@ DOC(After this call the file list passed in should not be read or written to.)
system->set_file_list(&list, make_string(0, 0));
}
+API_EXPORT void
+Set_GUI_Up_Down_Keys(Application_Links *app, int16_t up_key, int16_t down_key)
+{
+ Command_Data *cmd = (Command_Data*)app->cmd_context;
+ Models *models = cmd->models;
+ models->user_up_key = up_key;
+ models->user_down_key = down_key;
+}
+
// BOTTOM
diff --git a/4ed_app_models.h b/4ed_app_models.h
index 59f61ad2..32017f1e 100644
--- a/4ed_app_models.h
+++ b/4ed_app_models.h
@@ -89,6 +89,9 @@ struct Models{
b32 keep_playing;
Debug_Data debug;
+
+ i16 user_up_key;
+ i16 user_down_key;
};
// BOTTOM
diff --git a/4ed_file.cpp b/4ed_file.cpp
index 9644b18e..053957c4 100644
--- a/4ed_file.cpp
+++ b/4ed_file.cpp
@@ -92,6 +92,7 @@ struct Editing_File_Settings{
i32 base_map_id;
i32 display_width;
i32 minimum_base_display_width;
+ i32 wrap_indicator;
b32 dos_write_mode;
b32 virtual_white;
i16 font_id;
@@ -439,22 +440,21 @@ editing_file_zero(){
internal Editing_File*
working_set_alloc(Working_Set *working_set){
Editing_File *result = 0;
- File_Node *node;
- Buffer_Slot_ID id;
if (working_set->file_count < working_set->file_max){
- node = working_set->free_sentinel.next;
+ File_Node *node = working_set->free_sentinel.next;
Assert(node != &working_set->free_sentinel);
result = (Editing_File*)node;
dll_remove(node);
- id = result->id;
+ Buffer_Slot_ID id = result->id;
*result = editing_file_zero();
result->id = id;
result->unique_buffer_id = ++working_set->unique_file_counter;
dll_insert(&working_set->used_sentinel, node);
result->settings.display_width = working_set->default_display_width;
result->settings.minimum_base_display_width = working_set->default_minimum_base_display_width;
+ result->settings.wrap_indicator = WrapIndicator_Show_At_Wrap_Edge;
++working_set->file_count;
}
diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp
index 551b9290..b6849f07 100644
--- a/4ed_file_view.cpp
+++ b/4ed_file_view.cpp
@@ -1861,6 +1861,12 @@ file_set_display_width_and_fix_cursor(System_Functions *system, Models *models,
file_measure_wraps_and_fix_cursor(system, models, file, font_height, adv);
}
+internal void
+file_set_minimum_base_display_width_and_fix_cursor(System_Functions *system, Models *models, Editing_File *file, i32 minimum_base_display_width, f32 font_height, f32 *adv){
+ file->settings.minimum_base_display_width = minimum_base_display_width;
+ file_measure_wraps_and_fix_cursor(system, models, file, font_height, adv);
+}
+
//
//
//
@@ -4893,6 +4899,9 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su
GUI_id scroll_context = {0};
scroll_context.id[1] = VUI_Interactive + ((u64)view->interaction << 32);
+ i16 user_up_key = models->user_up_key;
+ i16 user_down_key = models->user_down_key;
+
switch (view->interaction){
case IInt_Sys_File_List:
{
@@ -4954,9 +4963,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su
if (gui_begin_list(target, id, view->list_i, 0,
snap_into_view, &update)){
// TODO(allen): Allow me to handle key consumption correctly here!
- gui_standard_list(target, id, &view->gui_scroll,
- view->scroll_region,
- &keys, &view->list_i, &update);
+ gui_standard_list(target, id, &view->gui_scroll, view->scroll_region, &keys, &view->list_i, &update, user_up_key, user_down_key);
}
begin_exhaustive_loop(&loop, hdir);
@@ -5038,15 +5045,11 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su
if (gui_scroll_was_activated(target, scroll_context)){
snap_into_view = 1;
}
- gui_begin_scrollable(target, scroll_context, view->gui_scroll,
- 9 * view->line_height, show_scrollbar);
+ gui_begin_scrollable(target, scroll_context, view->gui_scroll, 9 * view->line_height, show_scrollbar);
id.id[0] = (u64)(working_set) + 1;
- if (gui_begin_list(target, id, view->list_i,
- 0, snap_into_view, &update)){
- gui_standard_list(target, id, &view->gui_scroll,
- view->scroll_region,
- &keys, &view->list_i, &update);
+ if (gui_begin_list(target, id, view->list_i, 0, snap_into_view, &update)){
+ gui_standard_list(target, id, &view->gui_scroll, view->scroll_region, &keys, &view->list_i, &update, user_up_key, user_down_key);
}
{
@@ -5940,7 +5943,7 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target
params.font_height = (f32)line_height;
params.adv = advance_data;
params.virtual_white = file->settings.virtual_white;
- params.wrap_slashes = BRWrapSlash_Show_At_Wrap_Edge;
+ params.wrap_slashes = file->settings.wrap_indicator;
Buffer_Render_State state = {0};
Buffer_Layout_Stop stop = {0};
diff --git a/4ed_gui.cpp b/4ed_gui.cpp
index 4410e963..db53c229 100644
--- a/4ed_gui.cpp
+++ b/4ed_gui.cpp
@@ -1258,7 +1258,7 @@ gui_do_jump(GUI_Target *target, GUI_View_Jump jump, GUI_Scroll_Vars vars){
internal void
gui_standard_list(GUI_Target *target, GUI_id id, GUI_Scroll_Vars *vars, i32_Rect scroll_region,
Key_Summary *keys, i32 *list_i, GUI_Item_Update *update,
- i16 key_user_up = 0, i16 key_user_down = 0){
+ i16 user_up_key, i16 user_down_key){
if (update->has_adjustment){
*list_i = update->adjustment_value;
@@ -1276,10 +1276,10 @@ gui_standard_list(GUI_Target *target, GUI_id id, GUI_Scroll_Vars *vars, i32_Rect
for (i32 j = 0; j < keys->count; ++j){
i16 key = keys->keys[j].keycode;
- if (key == key_up || key == key_user_up){
+ if (key == user_up_key){
--*list_i;
}
- else if (key == key_down || key == key_user_down){
+ else if (key == user_down_key){
++*list_i;
}
else if (key == '\n' || key == '\t'){
diff --git a/TODO.txt b/TODO.txt
index 2891744b..a51e2dc4 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -90,10 +90,8 @@
;
; [X] query buffer font info
; [X] issues with drive letters
-; [] ad hoc call for setting up/down keys for interactive screens
-; [] option to not open *messages* every startup
-; [] API docs have duplicate ids?
-; [] miblo's various number editors
+; [X] ad hoc call for setting up/down keys for interactive screens
+; [X] miblo's various number editors
; [] decent options for indentation rules for text & presentation
;
@@ -194,6 +192,8 @@
; [] support full length unicode file names
; [] user file bar string
+; [] option to not open *messages* every startup
+; [] API docs have duplicate ids?
; [] API docs as text file
; [] read only files
; [] option to hide hidden files
diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp
index 141bbacc..8a2ff23f 100644
--- a/buffer/4coder_buffer_abstract.cpp
+++ b/buffer/4coder_buffer_abstract.cpp
@@ -1188,12 +1188,6 @@ struct Buffer_Render_Params{
i32 wrap_slashes;
};
-enum Wrap_Slash_Mode{
- BRWrapSlash_Hide,
- BRWrapSlash_Show_After_Line,
- BRWrapSlash_Show_At_Wrap_Edge,
-};
-
struct Buffer_Render_State{
Buffer_Stream_Type stream;
b32 still_looping;
@@ -1295,12 +1289,12 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32
if (params.wrapped){
switch (params.wrap_slashes){
- case BRWrapSlash_Show_After_Line:
+ case WrapIndicator_Show_After_Line:
{
S.write = write_render_item(S.write, S.i-1, '\\', BRFlag_Ghost_Character);
}break;
- case BRWrapSlash_Show_At_Wrap_Edge:
+ case WrapIndicator_Show_At_Wrap_Edge:
{
if (S.write.x < shift_x + params.width){
S.write.x = shift_x + params.width;
diff --git a/package.bat b/package.bat
index 64ebd203..baaf09d7 100644
--- a/package.bat
+++ b/package.bat
@@ -1,47 +1,3 @@
@echo off
-REM pushd W:\4ed\meta
-REM cl %OPTS% ..\code\readme_generator.c /Fereadmegen
-REM popd
-
-REM pushd W:\4ed\code
-
-REM ..\meta\readmegen
-
-REM call "build_all.bat" /O2 /DFRED_KEEP_ASSERT /Zi
-REM del ..\current_dist\4coder\*.html
-REM copy ..\build\4ed.exe ..\current_dist\4coder\*
-REM copy ..\build\4ed.pdb ..\current_dist\4coder\*
-REM copy ..\build\4ed_app.dll ..\current_dist\4coder\*
-REM copy ..\build\4ed_app.pdb ..\current_dist\4coder\*
-REM copy ..\data\* ..\current_dist\4coder\*
-REM copy README.txt ..\current_dist\4coder\*
-REM copy TODO.txt ..\current_dist\4coder\*
-REM del ..\current_dist\4coder\.4coder_settings
-
-REM call "build_all.bat" /O2 /DFRED_SUPER /DFRED_KEEP_ASSERT /Zi
-REM del ..\current_dist\4coder\*.html
-REM copy ..\build\4ed.exe ..\current_dist_super\4coder\*
-REM copy ..\build\4ed.pdb ..\current_dist_super\4coder\*
-REM copy ..\build\4ed_app.dll ..\current_dist_super\4coder\*
-REM copy ..\build\4ed_app.pdb ..\current_dist_super\4coder\*
-REM copy buildsuper.bat ..\current_dist_super\4coder\*
-REM copy ..\data\* ..\current_dist_super\4coder\*
-REM del ..\current_dist_super\4coder\basic.cpp
-REM copy 4coder_*.h ..\current_dist_super\4coder\*
-REM copy 4coder_*.cpp ..\current_dist_super\4coder\*
-REM copy README.txt ..\current_dist_super\4coder\*
-REM copy TODO.txt ..\current_dist_super\4coder\*
-REM copy ..\current_dist\4coder\3rdparty\* ..\current_dist_super\4coder\3rdparty\*
-REM del ..\current_dist_super\4coder\*.lib
-REM del ..\current_dist_super\4coder\*.obj
-REM del ..\current_dist_super\4coder\4coder_custom.dll
-REM del ..\current_dist_super\4coder\.4coder_settings
-
-REM copy 4coder_API.html ..\current_dist_super\*
-
-REM del ..\current_dist_power\power\* /F /Q
-REM copy power\* ..\current_dist_power\power\*
-
-REM popd
build.bat /DPACKAGE
diff --git a/power/4coder_experiments.cpp b/power/4coder_experiments.cpp
index eae0e1b3..770c1714 100644
--- a/power/4coder_experiments.cpp
+++ b/power/4coder_experiments.cpp
@@ -10,6 +10,8 @@
# define BIND_4CODER_TESTS(context) ((void)context)
#endif
+#include "4coder_miblo_numbers.cpp"
+
#include
CUSTOM_COMMAND_SIG(kill_rect){
@@ -697,6 +699,13 @@ get_bindings(void *data, int size){
begin_map(context, mapid_file);
bind(context, 'k', MDFR_ALT, kill_rect);
bind(context, ' ', MDFR_ALT, multi_line_edit);
+
+ bind(context, key_page_up, MDFR_ALT, miblo_increment_time_stamp);
+ bind(context, key_page_down, MDFR_ALT, miblo_decrement_time_stamp);
+
+ bind(context, key_home, MDFR_ALT, miblo_increment_time_stamp_minute);
+ bind(context, key_end, MDFR_ALT, miblo_decrement_time_stamp_minute);
+
end_map(context);
begin_map(context, my_code_map);
diff --git a/power/4coder_miblo_numbers.cpp b/power/4coder_miblo_numbers.cpp
new file mode 100644
index 00000000..15d53e07
--- /dev/null
+++ b/power/4coder_miblo_numbers.cpp
@@ -0,0 +1,381 @@
+
+#if !defined(MIBLO_NUMBERS_4CODER)
+#define MIBLO_NUMBERS_4CODER
+
+// TODO(allen): thevaber number converter idea
+
+static int32_t
+get_numeric_string_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t start_pos, int32_t *numeric_start, int32_t *numeric_end){
+ int32_t result = 0;
+
+ char current = buffer_get_char(app, buffer, start_pos);
+
+ if (char_is_numeric(current)){
+ char chunk[1024];
+ int32_t chunk_size = sizeof(chunk);
+ Stream_Chunk stream = {0};
+
+ int32_t pos = start_pos;
+
+ int32_t pos1 = 0;
+ int32_t pos2 = 0;
+
+ if (init_stream_chunk(&stream, app, buffer, start_pos, chunk, chunk_size)){
+
+ int32_t still_looping = 1;
+ while (still_looping){
+ for (; pos >= stream.start; --pos){
+ char at_pos = stream.data[pos];
+ if (!char_is_numeric(at_pos)){
+ ++pos;
+ goto double_break_1;
+ }
+ }
+ still_looping = backward_stream_chunk(&stream);
+ }
+ double_break_1:;
+ pos1 = pos;
+
+ if (init_stream_chunk(&stream, app, buffer, start_pos, chunk, chunk_size)){
+
+ still_looping = 1;
+ while (still_looping){
+ for (; pos < stream.end; ++pos){
+ char at_pos = stream.data[pos];
+ if (!char_is_numeric(at_pos)){
+ goto double_break_2;
+ }
+ }
+ still_looping = forward_stream_chunk(&stream);
+ }
+ double_break_2:;
+ pos2 = pos;
+
+ result = 1;
+ *numeric_start = pos1;
+ *numeric_end = pos2;
+ }
+ }
+ }
+
+ return(result);
+}
+
+struct Miblo_Number_Info{
+ int32_t start, end;
+ int32_t x;
+};
+
+static int32_t
+get_numeric_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t pos, Miblo_Number_Info *info){
+ int32_t result = 0;
+
+ int32_t numeric_start = 0, numeric_end = 0;
+ if (get_numeric_string_at_cursor(app, buffer, pos, &numeric_start, &numeric_end)){
+ char numeric_string[1024];
+ String str = make_string(numeric_string, numeric_end - numeric_start, sizeof(numeric_string));
+ if (str.size < str.memory_size){
+ buffer_read_range(app, buffer, numeric_start, numeric_end, numeric_string);
+
+ int32_t x = str_to_int(str);
+ int_to_str(&str, x+1);
+
+ info->start = numeric_start;
+ info->end = numeric_end;
+ info->x = x;
+ result = 1;
+ }
+ }
+
+ return(result);
+}
+
+CUSTOM_COMMAND_SIG(miblo_increment_basic){
+ View_Summary view = get_active_view(app, AccessOpen);
+ Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessOpen);
+
+ Miblo_Number_Info number = {0};
+ if (get_numeric_at_cursor(app, &buffer, view.cursor.pos, &number)){
+ char str_space[1024];
+ String str = make_fixed_width_string(str_space);
+ int_to_str(&str, number.x + 1);
+ buffer_replace_range(app, &buffer, number.start, number.end, str.str, str.size);
+ view_set_cursor(app, &view, seek_pos(number.start + str.size - 1), 1);
+ }
+}
+
+CUSTOM_COMMAND_SIG(miblo_decrement_basic){
+ View_Summary view = get_active_view(app, AccessOpen);
+ Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessOpen);
+
+ Miblo_Number_Info number = {0};
+ if (get_numeric_at_cursor(app, &buffer, view.cursor.pos, &number)){
+ char str_space[1024];
+ String str = make_fixed_width_string(str_space);
+ int_to_str(&str, number.x - 1);
+ buffer_replace_range(app, &buffer, number.start, number.end, str.str, str.size);
+ view_set_cursor(app, &view, seek_pos(number.start + str.size - 1), 1);
+ }
+}
+
+// NOTE(allen): miblo time stamp format
+// (h+:)?m?m:ss
+
+static int32_t
+get_timestamp_string_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t start_pos, int32_t *timestamp_start, int32_t *timestamp_end){
+ int32_t result = 0;
+
+ char current = buffer_get_char(app, buffer, start_pos);
+
+ if (char_is_numeric(current) || current == ':'){
+ char chunk[1024];
+ int32_t chunk_size = sizeof(chunk);
+ Stream_Chunk stream = {0};
+
+ int32_t pos = start_pos;
+
+ int32_t pos1 = 0;
+ int32_t pos2 = 0;
+
+ if (init_stream_chunk(&stream, app, buffer, start_pos, chunk, chunk_size)){
+
+ int32_t still_looping = 1;
+ while (still_looping){
+ for (; pos >= stream.start; --pos){
+ char at_pos = stream.data[pos];
+ if (!(char_is_numeric(at_pos) || at_pos == ':')){
+ ++pos;
+ goto double_break_1;
+ }
+ }
+ still_looping = backward_stream_chunk(&stream);
+ }
+ double_break_1:;
+ pos1 = pos;
+
+ if (init_stream_chunk(&stream, app, buffer, start_pos, chunk, chunk_size)){
+
+ still_looping = 1;
+ while (still_looping){
+ for (; pos < stream.end; ++pos){
+ char at_pos = stream.data[pos];
+ if (!(char_is_numeric(at_pos) || at_pos == ':')){
+ goto double_break_2;
+ }
+ }
+ still_looping = forward_stream_chunk(&stream);
+ }
+ double_break_2:;
+ pos2 = pos;
+
+ result = 1;
+ *timestamp_start = pos1;
+ *timestamp_end = pos2;
+ }
+ }
+ }
+
+ return(result);
+}
+
+struct Miblo_Timestamp{
+ int32_t hour, minute, second;
+};
+static Miblo_Timestamp null_miblo_timestamp = {0};
+
+enum{
+ MIBLO_SECOND,
+ MIBLO_MINUTE,
+ MIBLO_HOUR
+};
+
+static Miblo_Timestamp
+increment_timestamp(Miblo_Timestamp t, int32_t type, int32_t amt){
+ Miblo_Timestamp r = t;
+ switch (type){
+ case MIBLO_SECOND:
+ r.second += amt;
+ amt = 0;
+
+ // TODO(allen): someday do the math, instead of being lazy.
+ while (r.second < 0){
+ --amt;
+ r.second += 60;
+ }
+
+ while (r.second >= 60){
+ ++amt;
+ r.second -= 60;
+ }
+
+ case MIBLO_MINUTE:
+ r.minute += amt;
+ amt = 0;
+
+ // TODO(allen): someday do the math, instead of being lazy.
+ while (r.minute < 0){
+ --amt;
+ r.minute += 60;
+ }
+
+ while (r.minute >= 60){
+ ++amt;
+ r.minute -= 60;
+ }
+
+ case MIBLO_HOUR:
+ r.hour += amt;
+ }
+
+ return(r);
+}
+
+static void
+timestamp_to_str(String *dest, Miblo_Timestamp t){
+ dest->size = 0;
+
+ if (t.hour > 0){
+ append_int_to_str(dest, t.hour);
+ append(dest, ":");
+ }
+
+ if (t.minute >= 10){
+ append_int_to_str(dest, t.minute);
+ }
+ else if (t.hour > 0){
+ append(dest, "0");
+ append_int_to_str(dest, t.minute);
+ }
+ else{
+ append_int_to_str(dest, t.minute);
+ }
+ append(dest, ":");
+
+ if (t.second >= 10){
+ append_int_to_str(dest, t.second);
+ }
+ else{
+ append(dest, "0");
+ append_int_to_str(dest, t.second);
+ }
+}
+
+struct Miblo_Timestamp_Info{
+ int32_t start, end;
+ Miblo_Timestamp time;
+};
+
+static int32_t
+get_timestamp_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t pos, Miblo_Timestamp_Info *info){
+ int32_t result = 0;
+
+ int32_t timestamp_start = 0, timestamp_end = 0;
+ if (get_timestamp_string_at_cursor(app, buffer, pos, ×tamp_start, ×tamp_end)){
+ char timestamp_string[1024];
+ String str = make_string(timestamp_string, timestamp_end - timestamp_start, sizeof(timestamp_string));
+ if (str.size < str.memory_size){
+ buffer_read_range(app, buffer, timestamp_start, timestamp_end, timestamp_string);
+
+ int32_t count_colons = 0;
+ for (int32_t i = 0; i < str.size; ++i){
+ if (str.str[i] == ':'){
+ ++count_colons;
+ }
+ }
+
+ if (count_colons == 1 || count_colons == 2){
+ Miblo_Timestamp t = {0};
+
+ int32_t success = 0;
+
+ int32_t i = 0;
+ int32_t number_start[3], number_end[3];
+ for (int32_t k = 0; k < 3; ++k){
+ number_start[k] = i;
+ for (; i <= str.size; ++i){
+ if (i == str.size || str.str[i] == ':'){
+ number_end[k] = i;
+ break;
+ }
+ }
+ ++i;
+ if (i >= timestamp_end){
+ break;
+ }
+ }
+
+ if (count_colons == 2){
+ t.hour = str_to_int(make_string(str.str + number_start[0], number_end[0] - number_start[0]));
+
+ if (number_end[1] - number_start[1] == 2){
+
+ t.minute = str_to_int(make_string(str.str + number_start[1], number_end[1] - number_start[1]));
+
+ if (number_end[2] - number_start[2] == 2){
+ t.second = str_to_int(make_string(str.str + number_start[2], number_end[2] - number_start[2]));
+
+ success = 1;
+ }
+ }
+ }
+ else{
+ if (number_end[0] - number_start[0] == 2 || number_end[0] - number_start[0] == 1){
+ t.minute = str_to_int(make_string(str.str + number_start[0], number_end[0] - number_start[0]));
+
+ if (number_end[1] - number_start[1] == 2){
+ t.second = str_to_int(make_string(str.str + number_start[1], number_end[1] - number_start[1]));
+
+ success = 1;
+ }
+ }
+ }
+
+ if (success){
+ info->start = timestamp_start;
+ info->end = timestamp_end;
+ info->time = t;
+ result = 1;
+ }
+ }
+ }
+ }
+
+ return(result);
+}
+
+static void
+miblo_time_stamp_alter(Application_Links *app, int32_t unit_type, int32_t amt){
+ View_Summary view = get_active_view(app, AccessOpen);
+ Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessOpen);
+
+ Miblo_Timestamp_Info timestamp = {0};
+ if (get_timestamp_at_cursor(app, &buffer, view.cursor.pos, ×tamp)){
+ char str_space[1024];
+ String str = make_fixed_width_string(str_space);
+
+ Miblo_Timestamp inc_timestamp = increment_timestamp(timestamp.time, unit_type, amt);
+ timestamp_to_str(&str, inc_timestamp);
+ buffer_replace_range(app, &buffer, timestamp.start, timestamp.end, str.str, str.size);
+ view_set_cursor(app, &view, seek_pos(timestamp.start + str.size - 1), 1);
+ }
+}
+
+CUSTOM_COMMAND_SIG(miblo_increment_time_stamp){
+ miblo_time_stamp_alter(app, MIBLO_SECOND, 1);
+}
+
+CUSTOM_COMMAND_SIG(miblo_decrement_time_stamp){
+ miblo_time_stamp_alter(app, MIBLO_SECOND, -1);
+}
+
+CUSTOM_COMMAND_SIG(miblo_increment_time_stamp_minute){
+ miblo_time_stamp_alter(app, MIBLO_MINUTE, 1);
+}
+
+CUSTOM_COMMAND_SIG(miblo_decrement_time_stamp_minute){
+ miblo_time_stamp_alter(app, MIBLO_MINUTE, -1);
+}
+
+#endif
+
+