cleaned up some rusty old debug stuff
parent
8d40cc1eca
commit
8cd14b79ca
|
@ -14,6 +14,7 @@
|
|||
#include "4coder_mem.h"
|
||||
#include "4cpp_lexer_types.h"
|
||||
|
||||
// TODO(allen): We need to eliminate this soon.
|
||||
#ifndef FSTRING_STRUCT
|
||||
#define FSTRING_STRUCT
|
||||
typedef struct String{
|
||||
|
@ -34,6 +35,7 @@ enum Hook_ID{
|
|||
hook_start,
|
||||
hook_file_out_of_sync,
|
||||
hook_exit,
|
||||
hook_view_size_change,
|
||||
// never below this
|
||||
hook_type_count
|
||||
};
|
||||
|
@ -78,12 +80,12 @@ make_range(int32_t p1, int32_t p2){
|
|||
}
|
||||
|
||||
#define HOOK_SIG(name) int32_t name(struct Application_Links *app)
|
||||
#define OPEN_FILE_HOOK_SIG(name) int32_t name(struct Application_Links *app, int32_t buffer_id)
|
||||
#define SCROLL_RULE_SIG(name) int32_t name(float target_x, float target_y, float *scroll_x, float *scroll_y, int32_t view_id, int32_t is_new_target, float dt)
|
||||
#define OPEN_FILE_HOOK_SIG(name) int32_t name(struct Application_Links *app, int32_t buffer_id)
|
||||
#define INPUT_FILTER_SIG(name) void name(Mouse_State *mouse)
|
||||
|
||||
typedef HOOK_SIG(Hook_Function);
|
||||
typedef OPEN_FILE_HOOK_SIG(Open_File_Hook_Function);
|
||||
typedef HOOK_SIG(Hook_Function);
|
||||
typedef SCROLL_RULE_SIG(Scroll_Rule_Function);
|
||||
typedef INPUT_FILTER_SIG(Input_Filter_Function);
|
||||
|
||||
|
|
|
@ -152,30 +152,50 @@ HOOK_SIG(my_start){
|
|||
HOOK_SIG(my_exit){
|
||||
// if this returns zero it cancels the exit.
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
HOOK_SIG(my_view_adjust){
|
||||
int32_t count = 0;
|
||||
int32_t new_wrap_width = 0;
|
||||
for (View_Summary view = get_view_first(app, AccessAll);
|
||||
view.exists;
|
||||
get_view_next(app, &view, AccessAll)){
|
||||
new_wrap_width += view.file_region.x1 - view.file_region.x0;
|
||||
++count;
|
||||
}
|
||||
|
||||
new_wrap_width /= count;
|
||||
new_wrap_width = (int32_t)(new_wrap_width * .9f);
|
||||
|
||||
int32_t new_min_base_width = (int32_t)(new_wrap_width * .77f);
|
||||
adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width);
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
// TODO(allen): delete this
|
||||
CUSTOM_COMMAND_SIG(weird_buffer_test){
|
||||
for (Buffer_Summary buffer = get_buffer_first(app, AccessAll);
|
||||
buffer.exists;
|
||||
get_buffer_next(app, &buffer, AccessAll)){
|
||||
print_message(app, literal("filename:"));
|
||||
if (buffer.file_name){
|
||||
print_message(app, buffer.file_name, buffer.file_name_len);
|
||||
}
|
||||
else{
|
||||
print_message(app, literal("*NULL*"));
|
||||
}
|
||||
print_message(app, literal("buffername:"));
|
||||
if (buffer.buffer_name){
|
||||
print_message(app, buffer.buffer_name, buffer.buffer_name_len);
|
||||
}
|
||||
else{
|
||||
print_message(app, literal("*NULL*"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(allen): delete this
|
||||
CUSTOM_COMMAND_SIG(weird_buffer_test){
|
||||
for (Buffer_Summary buffer = get_buffer_first(app, AccessAll);
|
||||
buffer.exists;
|
||||
get_buffer_next(app, &buffer, AccessAll)){
|
||||
print_message(app, literal("filename:"));
|
||||
if (buffer.file_name){
|
||||
print_message(app, buffer.file_name, buffer.file_name_len);
|
||||
}
|
||||
else{
|
||||
print_message(app, literal("*NULL*"));
|
||||
}
|
||||
print_message(app, literal("buffername:"));
|
||||
if (buffer.buffer_name){
|
||||
print_message(app, buffer.buffer_name, buffer.buffer_name_len);
|
||||
}
|
||||
else{
|
||||
print_message(app, literal("*NULL*"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(allen|a4.0.12): This is for testing it may be removed and replaced with a better test for the buffer_get_font when you eventally read this and wonder what it's about.
|
||||
CUSTOM_COMMAND_SIG(write_name_of_font){
|
||||
View_Summary view = get_active_view(app, AccessOpen);
|
||||
|
@ -186,7 +206,7 @@ CUSTOM_COMMAND_SIG(write_name_of_font){
|
|||
int32_t font_len = buffer_get_font(app, &buffer, font_name, font_max);
|
||||
|
||||
if (font_len != 0){
|
||||
write_string(app, &view, &buffer, make_string(font_name, font_len));
|
||||
write_string(app, &view, &buffer, make_string(font_name, font_len));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,6 +501,7 @@ get_bindings(void *data, int32_t size){
|
|||
// and once set they always apply, regardless of what map is active.
|
||||
set_hook(context, hook_start, my_start);
|
||||
set_hook(context, hook_exit, my_exit);
|
||||
set_hook(context, hook_view_size_change, my_view_adjust);
|
||||
|
||||
set_open_file_hook(context, my_file_settings);
|
||||
set_command_caller(context, default_command_caller);
|
||||
|
|
|
@ -375,8 +375,7 @@ backward_stream_tokens(Stream_Tokens *stream){
|
|||
}
|
||||
|
||||
void
|
||||
buffer_seek_delimiter_forward(Application_Links *app, Buffer_Summary *buffer,
|
||||
int32_t pos, char delim, int32_t *result){
|
||||
buffer_seek_delimiter_forward(Application_Links *app, Buffer_Summary *buffer, int32_t pos, char delim, int32_t *result){
|
||||
if (buffer->exists){
|
||||
char chunk[1024];
|
||||
int32_t size = sizeof(chunk);
|
||||
|
@ -403,8 +402,7 @@ buffer_seek_delimiter_forward(Application_Links *app, Buffer_Summary *buffer,
|
|||
}
|
||||
|
||||
static void
|
||||
buffer_seek_delimiter_backward(Application_Links *app, Buffer_Summary *buffer,
|
||||
int32_t pos, char delim, int32_t *result){
|
||||
buffer_seek_delimiter_backward(Application_Links *app, Buffer_Summary *buffer, int32_t pos, char delim, int32_t *result){
|
||||
if (buffer->exists){
|
||||
char chunk[1024];
|
||||
int32_t size = sizeof(chunk);
|
||||
|
@ -437,8 +435,7 @@ buffer_seek_delimiter_backward(Application_Links *app, Buffer_Summary *buffer,
|
|||
// You can push it up or do something more clever by just
|
||||
// replacing char read_buffer[512]; with more memory.
|
||||
static void
|
||||
buffer_seek_string_forward(Application_Links *app, Buffer_Summary *buffer,
|
||||
int32_t pos, int32_t end, char *str, int32_t size, int32_t *result){
|
||||
buffer_seek_string_forward(Application_Links *app, Buffer_Summary *buffer, int32_t pos, int32_t end, char *str, int32_t size, int32_t *result){
|
||||
char read_buffer[512];
|
||||
|
||||
if (size <= 0){
|
||||
|
@ -492,8 +489,7 @@ buffer_seek_string_forward(Application_Links *app, Buffer_Summary *buffer,
|
|||
// You can push it up or do something more clever by just
|
||||
// replacing char read_buffer[512]; with more memory.
|
||||
static void
|
||||
buffer_seek_string_backward(Application_Links *app, Buffer_Summary *buffer,
|
||||
int32_t pos, int32_t min, char *str, int32_t size, int32_t *result){
|
||||
buffer_seek_string_backward(Application_Links *app, Buffer_Summary *buffer, int32_t pos, int32_t min, char *str, int32_t size, int32_t *result){
|
||||
char read_buffer[512];
|
||||
if (size <= 0){
|
||||
*result = min-1;
|
||||
|
@ -541,8 +537,7 @@ buffer_seek_string_backward(Application_Links *app, Buffer_Summary *buffer,
|
|||
// You can push it up or do something more clever by just
|
||||
// replacing char read_buffer[512]; with more memory.
|
||||
static void
|
||||
buffer_seek_string_insensitive_forward(Application_Links *app, Buffer_Summary *buffer,
|
||||
int32_t pos, int32_t end, char *str, int32_t size, int32_t *result){
|
||||
buffer_seek_string_insensitive_forward(Application_Links *app, Buffer_Summary *buffer, int32_t pos, int32_t end, char *str, int32_t size, int32_t *result){
|
||||
char read_buffer[512];
|
||||
char chunk[1024];
|
||||
int32_t chunk_size = sizeof(chunk);
|
||||
|
@ -591,8 +586,7 @@ buffer_seek_string_insensitive_forward(Application_Links *app, Buffer_Summary *b
|
|||
// You can push it up or do something more clever by just
|
||||
// replacing char read_buffer[512]; with more memory.
|
||||
static void
|
||||
buffer_seek_string_insensitive_backward(Application_Links *app, Buffer_Summary *buffer,
|
||||
int32_t pos, int32_t min, char *str, int32_t size, int32_t *result){
|
||||
buffer_seek_string_insensitive_backward(Application_Links *app, Buffer_Summary *buffer, int32_t pos, int32_t min, char *str, int32_t size, int32_t *result){
|
||||
char read_buffer[512];
|
||||
char chunk[1024];
|
||||
int32_t chunk_size = sizeof(chunk);
|
||||
|
@ -1041,10 +1035,7 @@ CUSTOM_COMMAND_SIG(auto_tab_line_at_cursor){
|
|||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
|
||||
buffer_auto_indent(app, &buffer,
|
||||
view.cursor.pos, view.cursor.pos,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
||||
buffer_auto_indent(app, &buffer, view.cursor.pos, view.cursor.pos, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
|
||||
|
@ -1065,10 +1056,7 @@ CUSTOM_COMMAND_SIG(auto_tab_range){
|
|||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
Range range = get_range(&view);
|
||||
|
||||
buffer_auto_indent(app, &buffer,
|
||||
range.min, range.max,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
||||
buffer_auto_indent(app, &buffer, range.min, range.max, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
|
||||
|
@ -1079,10 +1067,7 @@ CUSTOM_COMMAND_SIG(write_and_auto_tab){
|
|||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
|
||||
buffer_auto_indent(app, &buffer,
|
||||
view.cursor.pos, view.cursor.pos,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS | AutoIndent_ExactAlignBlock);
|
||||
buffer_auto_indent(app, &buffer, view.cursor.pos, view.cursor.pos, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_ExactAlignBlock);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
|
||||
|
@ -1103,8 +1088,7 @@ CUSTOM_COMMAND_SIG(clean_all_lines){
|
|||
Stream_Chunk chunk = {0};
|
||||
|
||||
int32_t i = 0;
|
||||
if (init_stream_chunk(&chunk, app, &buffer,
|
||||
i, data, sizeof(data))){
|
||||
if (init_stream_chunk(&chunk, app, &buffer, i, data, sizeof(data))){
|
||||
Buffer_Edit *edit = edits;
|
||||
|
||||
int32_t buffer_size = buffer.size;
|
||||
|
@ -1177,8 +1161,7 @@ clipboard_copy(Application_Links *app, int32_t start, int32_t end, Buffer_Summar
|
|||
}
|
||||
|
||||
static int32_t
|
||||
clipboard_cut(Application_Links *app, int32_t start, int32_t end, Buffer_Summary *buffer_out,
|
||||
uint32_t access){
|
||||
clipboard_cut(Application_Links *app, int32_t start, int32_t end, Buffer_Summary *buffer_out, uint32_t access){
|
||||
Buffer_Summary buffer = {0};
|
||||
int32_t result = false;
|
||||
|
||||
|
@ -1994,10 +1977,7 @@ long_braces(Application_Links *app, char *text, int32_t size){
|
|||
buffer_replace_range(app, &buffer, pos, pos, text, size);
|
||||
view_set_cursor(app, &view, seek_pos(pos + 2), true);
|
||||
|
||||
buffer_auto_indent(app, &buffer,
|
||||
pos, pos + size,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
||||
buffer_auto_indent(app, &buffer, pos, pos + size, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
|
||||
|
@ -2052,26 +2032,18 @@ CUSTOM_COMMAND_SIG(if0_off){
|
|||
edits[1].start = range.max;
|
||||
edits[1].end = range.max;
|
||||
|
||||
buffer_batch_edit(app,&buffer,
|
||||
base, global_part.pos,
|
||||
edits, ArrayCount(edits), BatchEdit_Normal);
|
||||
buffer_batch_edit(app,&buffer, base, global_part.pos, edits, ArrayCount(edits), BatchEdit_Normal);
|
||||
|
||||
view = get_view(app, view.view_id, AccessAll);
|
||||
if (view.cursor.pos > view.mark.pos){
|
||||
view_set_cursor(app, &view,
|
||||
seek_line_char(view.cursor.line+1, view.cursor.character),
|
||||
true);
|
||||
view_set_cursor(app, &view, seek_line_char(view.cursor.line+1, view.cursor.character), 1);
|
||||
}
|
||||
else{
|
||||
view_set_mark(app, &view,
|
||||
seek_line_char(view.mark.line+1, view.mark.character));
|
||||
view_set_mark(app, &view, seek_line_char(view.mark.line+1, view.mark.character));
|
||||
}
|
||||
|
||||
range = get_range(&view);
|
||||
buffer_auto_indent(app, &buffer,
|
||||
range.min, range.max,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
||||
buffer_auto_indent(app, &buffer, range.min, range.max, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
}
|
||||
|
@ -2123,8 +2095,8 @@ CUSTOM_COMMAND_SIG(snipe_token_or_word){
|
|||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
|
||||
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);
|
||||
int32_t pos1 = buffer_boundary_seek(app, &buffer, view.cursor.pos, 0, BoundaryToken | BoundaryWhitespace);
|
||||
int32_t pos2 = buffer_boundary_seek(app, &buffer, pos1, 1, BoundaryToken | BoundaryWhitespace);
|
||||
|
||||
Range range = make_range(pos1, pos2);
|
||||
buffer_replace_range(app, &buffer, range.start, range.end, 0, 0);
|
||||
|
@ -3480,6 +3452,18 @@ static int32_t default_min_base_width = 550;
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
static void
|
||||
adjust_all_buffer_wrap_widths(Application_Links *app, int32_t wrap_widths, int32_t min_base_width){
|
||||
for (Buffer_Summary buffer = get_buffer_first(app, AccessAll);
|
||||
buffer.exists;
|
||||
get_buffer_next(app, &buffer, AccessAll)){
|
||||
buffer_set_setting(app, &buffer, BufferSetting_WrapPosition, wrap_widths);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_MinimumBaseWrapPosition, min_base_width);
|
||||
}
|
||||
default_wrap_width = wrap_widths;
|
||||
default_min_base_width = min_base_width;
|
||||
}
|
||||
|
||||
static void
|
||||
process_config_file(Application_Links *app){
|
||||
FILE *file = fopen("config.4coder", "rb");
|
||||
|
@ -3515,6 +3499,9 @@ process_config_file(Application_Links *app){
|
|||
|
||||
if (result == LexResult_Finished){
|
||||
|
||||
int32_t new_wrap_width = default_wrap_width;
|
||||
int32_t new_min_base_width = default_min_base_width;
|
||||
|
||||
for (int32_t i = 0; i < array.count; ++i){
|
||||
int32_t read_setting_failed = 1;
|
||||
Cpp_Token id_token = array.tokens[i];
|
||||
|
@ -3526,7 +3513,6 @@ process_config_file(Application_Links *app){
|
|||
++i;
|
||||
if (i < array.count){
|
||||
Cpp_Token val_token = array.tokens[i];
|
||||
{
|
||||
++i;
|
||||
if (i < array.count){
|
||||
Cpp_Token semicolon_token = array.tokens[i];
|
||||
|
@ -3549,19 +3535,18 @@ process_config_file(Application_Links *app){
|
|||
else if (match(id, "default_wrap_width")){
|
||||
if (val_token.type == CPP_TOKEN_INTEGER_CONSTANT){
|
||||
String val = make_string(mem + val_token.start, val_token.size);
|
||||
default_wrap_width = str_to_int(val);
|
||||
new_wrap_width = str_to_int(val);
|
||||
}
|
||||
}
|
||||
else if (match(id, "default_min_base_width")){
|
||||
if (val_token.type == CPP_TOKEN_INTEGER_CONSTANT){
|
||||
String val = make_string(mem + val_token.start, val_token.size);
|
||||
default_min_base_width = str_to_int(val);
|
||||
new_min_base_width = str_to_int(val);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3576,6 +3561,8 @@ process_config_file(Application_Links *app){
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width);
|
||||
}
|
||||
|
||||
end_temp_memory(temp);
|
||||
|
|
|
@ -150,10 +150,10 @@ set_hook(Bind_Helper *helper, int32_t hook_id, Hook_Function *func){
|
|||
}
|
||||
|
||||
inline void
|
||||
set_open_file_hook(Bind_Helper *helper, Open_File_Hook_Function *func){
|
||||
set_scroll_rule(Bind_Helper *helper, Scroll_Rule_Function *func){
|
||||
Binding_Unit unit;
|
||||
unit.type = unit_hook;
|
||||
unit.hook.hook_id = _hook_open_file;
|
||||
unit.hook.hook_id = _hook_scroll_rule;
|
||||
unit.hook.func = (void*) func;
|
||||
|
||||
write_unit(helper, unit);
|
||||
|
@ -169,6 +169,16 @@ set_new_file_hook(Bind_Helper *helper, Open_File_Hook_Function *func){
|
|||
write_unit(helper, unit);
|
||||
}
|
||||
|
||||
inline void
|
||||
set_open_file_hook(Bind_Helper *helper, Open_File_Hook_Function *func){
|
||||
Binding_Unit unit;
|
||||
unit.type = unit_hook;
|
||||
unit.hook.hook_id = _hook_open_file;
|
||||
unit.hook.func = (void*) func;
|
||||
|
||||
write_unit(helper, unit);
|
||||
}
|
||||
|
||||
inline void
|
||||
set_command_caller(Bind_Helper *helper, Command_Caller_Hook_Function *func){
|
||||
Binding_Unit unit;
|
||||
|
@ -189,16 +199,6 @@ set_input_filter(Bind_Helper *helper, Input_Filter_Function *func){
|
|||
write_unit(helper, unit);
|
||||
}
|
||||
|
||||
inline void
|
||||
set_scroll_rule(Bind_Helper *helper, Scroll_Rule_Function *func){
|
||||
Binding_Unit unit;
|
||||
unit.type = unit_hook;
|
||||
unit.hook.hook_id = _hook_scroll_rule;
|
||||
unit.hook.func = (void*) func;
|
||||
|
||||
write_unit(helper, unit);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
end_bind_helper(Bind_Helper *helper){
|
||||
int32_t result;
|
||||
|
|
|
@ -649,29 +649,27 @@ STRUCT View_Summary{
|
|||
int32_t view_id;
|
||||
/* DOC(If this is not a null summary, then this is the id of the buffer this view currently sees.) */
|
||||
int32_t buffer_id;
|
||||
/*
|
||||
DOC(If this is not a null summary, this field contains flags describing the protection status of the view.)
|
||||
*/
|
||||
/* DOC(If this is not a null summary, this field contains flags describing the protection status of the view.) */
|
||||
Access_Flag lock_flags;
|
||||
|
||||
/*
|
||||
DOC(If this is not a null summary, this describes the position of the cursor.)
|
||||
*/
|
||||
/* DOC(If this is not a null summary, this describes the position of the cursor.) */
|
||||
Full_Cursor cursor;
|
||||
/*
|
||||
DOC(If this is not a null summary, this describes the position of the mark.)
|
||||
*/
|
||||
/* DOC(If this is not a null summary, this describes the position of the mark.) */
|
||||
Full_Cursor mark;
|
||||
/* DOC(If this is not a null summary, this is the x position that is maintained in vertical navigation.) */
|
||||
float preferred_x;
|
||||
/* DOC(If this is not a null summary, this specifies the height of a line rendered in the view.) */
|
||||
float line_height;
|
||||
/* DOC(If this is not a null summary, this indicates that the view is set to render with unwrapped lines.) */
|
||||
/*
|
||||
DOC(If this is not a null summary, this indicates that the view is set to render with unwrapped lines.)
|
||||
*/
|
||||
bool32 unwrapped_lines;
|
||||
/* DOC(If this is not a null summary, this indicates that the view is set to highlight white space.) */
|
||||
bool32 show_whitespace;
|
||||
|
||||
/* DOC(If this is not a null summary, this describes the screen position in which this view's buffer is displayed.) */
|
||||
/*
|
||||
DOC(If this is not a null summary, this describes the screen position in which this view's buffer is displayed.)
|
||||
*/
|
||||
i32_Rect file_region;
|
||||
/* DOC(If this is not a null summary, this describes the scrolling position inside the view.) */
|
||||
GUI_Scroll_Vars scroll_vars;
|
||||
|
@ -683,9 +681,7 @@ DOC_SEE(User_Input_Type_ID)
|
|||
DOC_SEE(Generic_Command)
|
||||
*/
|
||||
STRUCT User_Input{
|
||||
/*
|
||||
DOC(This field specifies whether the event was a key press or mouse event.)
|
||||
*/
|
||||
/* DOC(This field specifies whether the event was a key press or mouse event.) */
|
||||
User_Input_Type_ID type;
|
||||
/* DOC(This field indicates that an abort event has occurred and the command needs to shut down.) */
|
||||
bool32 abort;
|
||||
|
@ -695,9 +691,7 @@ DOC_SEE(Generic_Command)
|
|||
/* DOC(This field describes a mouse input event.) */
|
||||
Mouse_State mouse;
|
||||
};
|
||||
/*
|
||||
DOC(If this event would trigger a command, this field specifies what the command would be.)
|
||||
*/
|
||||
/* DOC(If this event would trigger a command, this field specifies what the command would be.) */
|
||||
Generic_Command command;
|
||||
};
|
||||
|
||||
|
|
70
4ed.cpp
70
4ed.cpp
|
@ -148,7 +148,7 @@ consume_input(Available_Input *available, i32 input_type, char *consumer){
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct App_Vars{
|
||||
struct App_Vars{
|
||||
Models models;
|
||||
// TODO(allen): This wants to live in
|
||||
// models with everyone else but the order
|
||||
|
@ -163,7 +163,7 @@ typedef struct App_Vars{
|
|||
Command_Data command_data;
|
||||
|
||||
Available_Input available_input;
|
||||
} App_Vars;
|
||||
};
|
||||
|
||||
typedef enum Coroutine_Type{
|
||||
Co_View,
|
||||
|
@ -1869,6 +1869,7 @@ App_Step_Sig(app_step){
|
|||
|
||||
if (prev_width != current_width || prev_height != current_height){
|
||||
layout_refit(&models->layout, prev_width, prev_height);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2178,7 +2179,6 @@ App_Step_Sig(app_step){
|
|||
// NOTE(allen): pass events to debug
|
||||
vars->available_input = init_available_input(&key_summary, &input->mouse);
|
||||
|
||||
#if FRED_INTERNAL
|
||||
{
|
||||
Debug_Data *debug = &models->debug;
|
||||
Key_Summary key_data = get_key_data(&vars->available_input);
|
||||
|
@ -2204,7 +2204,6 @@ App_Step_Sig(app_step){
|
|||
events[i].is_shift = key.modifiers[MDFR_SHIFT_INDEX];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOTE(allen): Keyboard input to command coroutine.
|
||||
if (models->command_coroutine != 0){
|
||||
|
@ -2244,23 +2243,18 @@ App_Step_Sig(app_step){
|
|||
|
||||
if (EventOnAnyKey & get_flags){
|
||||
pass_in = 1;
|
||||
consume_input(&vars->available_input, Input_AnyKey,
|
||||
"command coroutine");
|
||||
consume_input(&vars->available_input, Input_AnyKey, "command coroutine");
|
||||
}
|
||||
if (key.keycode == key_esc){
|
||||
if (EventOnEsc & get_flags){
|
||||
pass_in = 1;
|
||||
}
|
||||
consume_input(&vars->available_input, Input_Esc,
|
||||
"command coroutine");
|
||||
consume_input(&vars->available_input, Input_Esc, "command coroutine");
|
||||
}
|
||||
|
||||
if (pass_in){
|
||||
models->command_coroutine =
|
||||
app_resume_coroutine(system, &models->app_links, Co_Command,
|
||||
command_coroutine,
|
||||
&user_in,
|
||||
models->command_coroutine_flags);
|
||||
app_resume_coroutine(system, &models->app_links, Co_Command, command_coroutine, &user_in, models->command_coroutine_flags);
|
||||
|
||||
app_result.animating = 1;
|
||||
|
||||
|
@ -2292,8 +2286,7 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
if (get_flags & EventOnMouseMove){
|
||||
pass_in = 1;
|
||||
consume_input(&vars->available_input, Input_MouseMove,
|
||||
"command coroutine");
|
||||
consume_input(&vars->available_input, Input_MouseMove, "command coroutine");
|
||||
}
|
||||
|
||||
if (input->mouse.press_l || input->mouse.release_l || input->mouse.l){
|
||||
|
@ -2302,8 +2295,7 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
if (get_flags & EventOnLeftButton){
|
||||
pass_in = 1;
|
||||
consume_input(&vars->available_input, Input_MouseLeftButton,
|
||||
"command coroutine");
|
||||
consume_input(&vars->available_input, Input_MouseLeftButton, "command coroutine");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2313,8 +2305,7 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
if (get_flags & EventOnRightButton){
|
||||
pass_in = 1;
|
||||
consume_input(&vars->available_input, Input_MouseRightButton,
|
||||
"command coroutine");
|
||||
consume_input(&vars->available_input, Input_MouseRightButton, "command coroutine");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2324,17 +2315,13 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
if (get_flags & EventOnWheel){
|
||||
pass_in = 1;
|
||||
consume_input(&vars->available_input, Input_MouseWheel,
|
||||
"command coroutine");
|
||||
consume_input(&vars->available_input, Input_MouseWheel, "command coroutine");
|
||||
}
|
||||
}
|
||||
|
||||
if (pass_in){
|
||||
models->command_coroutine =
|
||||
app_resume_coroutine(system, &models->app_links, Co_Command,
|
||||
command_coroutine,
|
||||
&user_in,
|
||||
models->command_coroutine_flags);
|
||||
app_resume_coroutine(system, &models->app_links, Co_Command, command_coroutine, &user_in, models->command_coroutine_flags);
|
||||
|
||||
app_result.animating = 1;
|
||||
|
||||
|
@ -2387,12 +2374,10 @@ App_Step_Sig(app_step){
|
|||
app_result.animating = 1;
|
||||
}
|
||||
if (result.consume_keys){
|
||||
consume_input(&vars->available_input, Input_AnyKey,
|
||||
"file view step");
|
||||
consume_input(&vars->available_input, Input_AnyKey, "file view step");
|
||||
}
|
||||
if (result.consume_keys || result.consume_esc){
|
||||
consume_input(&vars->available_input, Input_Esc,
|
||||
"file view step");
|
||||
consume_input(&vars->available_input, Input_Esc, "file view step");
|
||||
}
|
||||
|
||||
if (view->changed_context_in_step == 0){
|
||||
|
@ -2423,20 +2408,16 @@ App_Step_Sig(app_step){
|
|||
max_y = view->gui_max_y;
|
||||
}
|
||||
|
||||
Input_Process_Result ip_result =
|
||||
do_step_file_view(system, view, panel->inner, active,
|
||||
&summary, *scroll_vars, view->scroll_region, max_y);
|
||||
Input_Process_Result ip_result = do_step_file_view(system, view, panel->inner, active, &summary, *scroll_vars, view->scroll_region, max_y);
|
||||
|
||||
if (ip_result.is_animating){
|
||||
app_result.animating = 1;
|
||||
}
|
||||
if (ip_result.consumed_l){
|
||||
consume_input(&vars->available_input, Input_MouseLeftButton,
|
||||
"file view step");
|
||||
consume_input(&vars->available_input, Input_MouseLeftButton, "file view step");
|
||||
}
|
||||
if (ip_result.consumed_r){
|
||||
consume_input(&vars->available_input, Input_MouseRightButton,
|
||||
"file view step");
|
||||
consume_input(&vars->available_input, Input_MouseRightButton, "file view step");
|
||||
}
|
||||
|
||||
if (ip_result.has_max_y_suggestion){
|
||||
|
@ -2499,11 +2480,7 @@ App_Step_Sig(app_step){
|
|||
cmd_in.cmd = cmd;
|
||||
cmd_in.bind = cmd_bind;
|
||||
|
||||
models->command_coroutine =
|
||||
app_launch_coroutine(system, &models->app_links, Co_Command,
|
||||
models->command_coroutine,
|
||||
&cmd_in,
|
||||
models->command_coroutine_flags);
|
||||
models->command_coroutine = app_launch_coroutine(system, &models->app_links, Co_Command, models->command_coroutine, &cmd_in, models->command_coroutine_flags);
|
||||
|
||||
models->prev_command = cmd_bind;
|
||||
|
||||
|
@ -2521,12 +2498,10 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
|
||||
if (hit_something){
|
||||
consume_input(&vars->available_input, Input_AnyKey,
|
||||
"command dispatcher");
|
||||
consume_input(&vars->available_input, Input_AnyKey, "command dispatcher");
|
||||
}
|
||||
if (hit_esc){
|
||||
consume_input(&vars->available_input, Input_Esc,
|
||||
"command dispatcher");
|
||||
consume_input(&vars->available_input, Input_Esc, "command dispatcher");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2586,7 +2561,7 @@ App_Step_Sig(app_step){
|
|||
"you can use the key combo <ctrl o> to look for a file\n"
|
||||
"and if you load README.txt you'll find all the key combos there are.\n"
|
||||
"\n"
|
||||
"Newest features:\n"
|
||||
"New in alpha 4.0.12:\n"
|
||||
"-Text files wrap lines at whitespace when possible\n"
|
||||
"-New code wrapping feature is on by default\n"
|
||||
"-Introduced a 'config.4coder' for setting several wrapping options:"
|
||||
|
@ -2763,6 +2738,11 @@ App_Step_Sig(app_step){
|
|||
}break;
|
||||
}
|
||||
|
||||
if (models->layout.panel_state_dirty && models->hooks[hook_view_size_change] != 0){
|
||||
models->layout.panel_state_dirty = 0;
|
||||
models->hooks[hook_view_size_change](&models->app_links);
|
||||
}
|
||||
|
||||
if (mouse_in_edit_area && mouse_panel != 0 && input->mouse.press_l){
|
||||
models->layout.active_panel = (i32)(mouse_panel - models->layout.panels);
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ fill_view_summary(View_Summary *view, View *vptr, Live_Views *live_set, Working_
|
|||
view->cursor = vptr->edit_pos->cursor;
|
||||
view->preferred_x = vptr->edit_pos->preferred_x;
|
||||
|
||||
view->file_region = vptr->file_region;
|
||||
view->file_region = vptr->panel->inner;
|
||||
view->scroll_vars = vptr->edit_pos->scroll;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ struct Editing_Layout{
|
|||
i32 root;
|
||||
i32 active_panel;
|
||||
i32 full_width, full_height;
|
||||
b32 panel_state_dirty;
|
||||
};
|
||||
|
||||
struct Divider_And_ID{
|
||||
|
@ -305,11 +306,12 @@ layout_fix_all_panels(Editing_Layout *layout){
|
|||
panel->full.y1 = layout->full_height;
|
||||
panel_fix_internal_area(panel);
|
||||
}
|
||||
|
||||
layout->panel_state_dirty = 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
layout_refit(Editing_Layout *layout, i32 prev_width, i32 prev_height){
|
||||
|
||||
Panel_Divider *dividers = layout->dividers;
|
||||
i32 max = layout->panel_max_count - 1;
|
||||
|
||||
|
|
10
4ed_system.h
10
4ed_system.h
|
@ -201,15 +201,9 @@ typedef Sys_Acquire_Lock_Sig(System_Acquire_Lock);
|
|||
typedef Sys_Release_Lock_Sig(System_Release_Lock);
|
||||
|
||||
// debug
|
||||
#define INTERNAL_Sys_Sentinel_Sig(name) Bubble* name()
|
||||
typedef INTERNAL_Sys_Sentinel_Sig(INTERNAL_System_Sentinel);
|
||||
|
||||
#define INTERNAL_Sys_Get_Thread_States_Sig(name) void name(Thread_Group_ID id, b8 *running, i32 *pending)
|
||||
typedef INTERNAL_Sys_Get_Thread_States_Sig(INTERNAL_System_Get_Thread_States);
|
||||
|
||||
#define INTERNAL_Sys_Debug_Message_Sig(name) void name(char *message)
|
||||
typedef INTERNAL_Sys_Debug_Message_Sig(INTERNAL_System_Debug_Message);
|
||||
|
||||
struct System_Functions{
|
||||
|
||||
// files (tracked api): 10
|
||||
|
@ -262,10 +256,8 @@ struct System_Functions{
|
|||
System_Acquire_Lock *acquire_lock;
|
||||
System_Release_Lock *release_lock;
|
||||
|
||||
// debug: 3
|
||||
INTERNAL_System_Sentinel *internal_sentinel;
|
||||
// debug: 1
|
||||
INTERNAL_System_Get_Thread_States *internal_get_thread_states;
|
||||
INTERNAL_System_Debug_Message *internal_debug_message;
|
||||
|
||||
// non-function details
|
||||
char slash;
|
||||
|
|
|
@ -139,15 +139,6 @@ struct Application_Links;
|
|||
// Linux structs / enums
|
||||
//
|
||||
|
||||
#if FRED_INTERNAL
|
||||
|
||||
struct Sys_Bubble : public Bubble{
|
||||
i32 line_number;
|
||||
char *file_name;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
enum {
|
||||
LINUX_4ED_EVENT_X11 = (UINT64_C(1) << 32),
|
||||
LINUX_4ED_EVENT_X11_INTERNAL = (UINT64_C(2) << 32),
|
||||
|
@ -253,11 +244,6 @@ struct Linux_Vars{
|
|||
Custom_API custom_api;
|
||||
b32 vsync;
|
||||
|
||||
#if FRED_INTERNAL
|
||||
Sys_Bubble internal_bubble;
|
||||
pthread_mutex_t DEBUG_sysmem_lock;
|
||||
#endif
|
||||
|
||||
Linux_Coroutine coroutine_data[18];
|
||||
Linux_Coroutine *coroutine_free;
|
||||
};
|
||||
|
@ -309,21 +295,6 @@ LinuxGetMemory_(i32 size, i32 line_number, char *file_name){
|
|||
|
||||
Assert(size != 0);
|
||||
|
||||
#if FRED_INTERNAL
|
||||
result = mmap(0, size + sizeof(Sys_Bubble), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
Sys_Bubble* bubble = (Sys_Bubble*)result;
|
||||
bubble->flags = 0;
|
||||
bubble->line_number = line_number;
|
||||
bubble->file_name = file_name;
|
||||
bubble->size = size;
|
||||
|
||||
pthread_mutex_lock(&linuxvars.DEBUG_sysmem_lock);
|
||||
insert_bubble(&linuxvars.internal_bubble, bubble);
|
||||
pthread_mutex_unlock(&linuxvars.DEBUG_sysmem_lock);
|
||||
|
||||
result = bubble + 1;
|
||||
#else
|
||||
size_t real_size = size + sizeof(size_t);
|
||||
result = mmap(0, real_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if(result == MAP_FAILED){
|
||||
|
@ -333,7 +304,6 @@ LinuxGetMemory_(i32 size, i32 line_number, char *file_name){
|
|||
memcpy(result, &real_size, sizeof(size_t));
|
||||
result = (char*)result + sizeof(size_t);
|
||||
}
|
||||
#endif
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
@ -341,21 +311,9 @@ LinuxGetMemory_(i32 size, i32 line_number, char *file_name){
|
|||
internal void
|
||||
LinuxFreeMemory(void *block){
|
||||
if (block){
|
||||
#if FRED_INTERNAL
|
||||
Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1;
|
||||
|
||||
size_t size = bubble->size + sizeof(Sys_Bubble);
|
||||
|
||||
pthread_mutex_lock(&linuxvars.DEBUG_sysmem_lock);
|
||||
remove_bubble(bubble);
|
||||
pthread_mutex_unlock(&linuxvars.DEBUG_sysmem_lock);
|
||||
|
||||
munmap(bubble, size);
|
||||
#else
|
||||
block = (char*)block - sizeof(size_t);
|
||||
size_t size = *(size_t*)block;
|
||||
munmap(block, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1343,11 +1301,6 @@ Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
|||
|
||||
#if FRED_INTERNAL
|
||||
|
||||
internal
|
||||
INTERNAL_Sys_Sentinel_Sig(internal_sentinel){
|
||||
return (&linuxvars.internal_bubble);
|
||||
}
|
||||
|
||||
#ifdef OLD_JOB_QUEUE
|
||||
internal
|
||||
INTERNAL_Sys_Get_Thread_States_Sig(internal_get_thread_states){
|
||||
|
@ -1379,11 +1332,6 @@ INTERNAL_Sys_Get_Thread_States_Sig(internal_get_thread_states){
|
|||
}
|
||||
#endif
|
||||
|
||||
internal
|
||||
INTERNAL_Sys_Debug_Message_Sig(internal_debug_message){
|
||||
fprintf(stderr, "%s", message);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
|
@ -1534,9 +1482,7 @@ LinuxLoadSystemCode(){
|
|||
|
||||
// debug
|
||||
#if FRED_INTERNAL
|
||||
linuxvars.system.internal_sentinel = internal_sentinel;
|
||||
linuxvars.system.internal_get_thread_states = internal_get_thread_states;
|
||||
linuxvars.system.internal_debug_message = internal_debug_message;
|
||||
#endif
|
||||
|
||||
// non-function details
|
||||
|
@ -3026,14 +2972,6 @@ main(int argc, char **argv)
|
|||
// System & Memory init
|
||||
//
|
||||
|
||||
#if FRED_INTERNAL
|
||||
linuxvars.internal_bubble.next = &linuxvars.internal_bubble;
|
||||
linuxvars.internal_bubble.prev = &linuxvars.internal_bubble;
|
||||
linuxvars.internal_bubble.flags = 0;
|
||||
|
||||
pthread_mutex_init(&linuxvars.DEBUG_sysmem_lock, 0);
|
||||
#endif
|
||||
|
||||
char base_dir_mem[PATH_MAX];
|
||||
String base_dir = make_fixed_width_string(base_dir_mem);
|
||||
|
||||
|
|
|
@ -659,6 +659,8 @@ get_bindings(void *data, int size){
|
|||
Bind_Helper *context = &context_;
|
||||
|
||||
set_hook(context, hook_start, experimental_start);
|
||||
set_hook(context, hook_view_size_change, my_view_adjust);
|
||||
|
||||
set_open_file_hook(context, my_file_settings);
|
||||
set_input_filter(context, my_suppress_mouse_filter);
|
||||
set_command_caller(context, default_command_caller);
|
||||
|
|
|
@ -142,14 +142,6 @@ typedef struct Win32_Coroutine{
|
|||
i32 done;
|
||||
} Win32_Coroutine;
|
||||
|
||||
#if FRED_INTERNAL
|
||||
struct Sys_Bubble : public Bubble{
|
||||
i32 line_number;
|
||||
char *file_name;
|
||||
};
|
||||
typedef struct Sys_Bubble Sys_Bubble;
|
||||
#endif
|
||||
|
||||
enum CV_ID{
|
||||
CANCEL_CV0,
|
||||
CANCEL_CV1,
|
||||
|
@ -209,10 +201,6 @@ typedef struct Win32_Vars{
|
|||
b32 first;
|
||||
i32 running_cli;
|
||||
|
||||
#if FRED_INTERNAL
|
||||
CRITICAL_SECTION DEBUG_sysmem_lock;
|
||||
Sys_Bubble internal_bubble;
|
||||
#endif
|
||||
} Win32_Vars;
|
||||
|
||||
globalvar Win32_Vars win32vars;
|
||||
|
@ -261,20 +249,7 @@ internal
|
|||
Sys_Get_Memory_Sig(system_get_memory_){
|
||||
void *ptr = 0;
|
||||
if (size > 0){
|
||||
#if FRED_INTERNAL
|
||||
ptr = VirtualAlloc(0, size + sizeof(Sys_Bubble), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
Sys_Bubble *bubble = (Sys_Bubble*)ptr;
|
||||
bubble->flags = 0;
|
||||
bubble->line_number = line_number;
|
||||
bubble->file_name = file_name;
|
||||
bubble->size = size;
|
||||
EnterCriticalSection(&win32vars.DEBUG_sysmem_lock);
|
||||
insert_bubble(&win32vars.internal_bubble, bubble);
|
||||
LeaveCriticalSection(&win32vars.DEBUG_sysmem_lock);
|
||||
ptr = bubble + 1;
|
||||
#else
|
||||
ptr = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
#endif
|
||||
}
|
||||
return(ptr);
|
||||
}
|
||||
|
@ -282,15 +257,7 @@ Sys_Get_Memory_Sig(system_get_memory_){
|
|||
internal
|
||||
Sys_Free_Memory_Sig(system_free_memory){
|
||||
if (block){
|
||||
#if FRED_INTERNAL
|
||||
Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1;
|
||||
EnterCriticalSection(&win32vars.DEBUG_sysmem_lock);
|
||||
remove_bubble(bubble);
|
||||
LeaveCriticalSection(&win32vars.DEBUG_sysmem_lock);
|
||||
VirtualFree(bubble, 0, MEM_RELEASE);
|
||||
#else
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,11 +269,6 @@ Sys_Free_Memory_Sig(system_free_memory){
|
|||
#define Win32ScratchPartitionDouble sysshared_partition_double
|
||||
|
||||
#if FRED_INTERNAL
|
||||
internal Bubble*
|
||||
INTERNAL_system_sentinel(){
|
||||
return (&win32vars.internal_bubble);
|
||||
}
|
||||
|
||||
internal void
|
||||
INTERNAL_system_debug_message(char *message){
|
||||
OutputDebugStringA(message);
|
||||
|
@ -1410,9 +1372,7 @@ Win32LoadSystemCode(){
|
|||
win32vars.system.release_lock = system_release_lock;
|
||||
|
||||
#if FRED_INTERNAL
|
||||
win32vars.system.internal_sentinel = INTERNAL_system_sentinel;
|
||||
win32vars.system.internal_get_thread_states = INTERNAL_get_thread_states;
|
||||
win32vars.system.internal_debug_message = INTERNAL_system_debug_message;
|
||||
#endif
|
||||
|
||||
win32vars.system.slash = '/';
|
||||
|
@ -1856,18 +1816,6 @@ WinMain(HINSTANCE hInstance,
|
|||
// Threads and Coroutines
|
||||
//
|
||||
|
||||
// NOTE(allen): These should come before threads are started!
|
||||
// Threads now get memory right away and so they use
|
||||
// the internal_bubble and DEBUG_sysmem_lock
|
||||
|
||||
#if FRED_INTERNAL
|
||||
win32vars.internal_bubble.next = &win32vars.internal_bubble;
|
||||
win32vars.internal_bubble.prev = &win32vars.internal_bubble;
|
||||
win32vars.internal_bubble.flags = 0;
|
||||
|
||||
InitializeCriticalSection(&win32vars.DEBUG_sysmem_lock);
|
||||
#endif
|
||||
|
||||
for (i32 i = 0; i < LOCK_COUNT; ++i){
|
||||
InitializeCriticalSection(&win32vars.locks[i]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue