4.0.15 various bug fixes, feature polish, added experimental scope command
This commit is contained in:
parent
e410404208
commit
0417cab3d0
|
@ -306,6 +306,16 @@ CUSTOM_COMMAND_SIG(seek_end_of_line){
|
|||
view_set_cursor(app, &view, seek_xy(100000.f, y, 1, view.unwrapped_lines), 1);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(seek_whitespace_up_end_line){
|
||||
exec_command(app, seek_whitespace_up);
|
||||
exec_command(app, seek_end_of_line);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(seek_whitespace_down_end_line){
|
||||
exec_command(app, seek_whitespace_down);
|
||||
exec_command(app, seek_end_of_line);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Fancy Editing
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
4coder_build_commands.cpp - Commands for building.
|
||||
|
||||
TYPE: 'drop-in-command-pack'
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#if !defined(FCODER_BUILD_COMMANDS_CPP)
|
||||
#define FCODER_BUILD_COMMANDS_CPP
|
||||
|
||||
#include "4coder_helper/4coder_helper.h"
|
||||
|
||||
#include "4coder_default_framework.h"
|
||||
|
||||
// NOTE(allen|a4.0.9): This is provided to establish a default method of getting
|
||||
// a "build directory". This function tries to setup the build directory in the
|
||||
// directory of the given buffer, if it cannot get that information it get's the
|
||||
// 4coder hot directory.
|
||||
//
|
||||
// There is no requirement that a custom build system in 4coder actually use the
|
||||
// directory given by this function.
|
||||
enum Get_Build_Directory_Result{
|
||||
BuildDir_None,
|
||||
BuildDir_AtFile,
|
||||
BuildDir_AtHot
|
||||
};
|
||||
|
||||
static int32_t
|
||||
get_build_directory(Application_Links *app, Buffer_Summary *buffer, String *dir_out){
|
||||
int32_t result = BuildDir_None;
|
||||
|
||||
if (buffer && buffer->file_name){
|
||||
if (!match_cc(buffer->file_name, buffer->buffer_name)){
|
||||
String dir = make_string_cap(buffer->file_name,
|
||||
buffer->file_name_len,
|
||||
buffer->file_name_len+1);
|
||||
remove_last_folder(&dir);
|
||||
append_ss(dir_out, dir);
|
||||
result = BuildDir_AtFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result){
|
||||
int32_t len = directory_get_hot(app, dir_out->str,
|
||||
dir_out->memory_size - dir_out->size);
|
||||
if (len + dir_out->size < dir_out->memory_size){
|
||||
dir_out->size += len;
|
||||
result = BuildDir_AtHot;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
// TODO(allen): Better names for the "standard build search" family.
|
||||
static int32_t
|
||||
standard_build_search(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer, String *dir, String *command, int32_t perform_backup, int32_t use_path_in_command, String filename, String commandname){
|
||||
int32_t result = false;
|
||||
|
||||
for(;;){
|
||||
int32_t old_size = dir->size;
|
||||
append_ss(dir, filename);
|
||||
|
||||
if (file_exists(app, dir->str, dir->size)){
|
||||
dir->size = old_size;
|
||||
|
||||
if (use_path_in_command){
|
||||
append_s_char(command, '"');
|
||||
append_ss(command, *dir);
|
||||
append_ss(command, commandname);
|
||||
append_s_char(command, '"');
|
||||
}
|
||||
else{
|
||||
append_ss(command, commandname);
|
||||
}
|
||||
|
||||
char space[512];
|
||||
String message = make_fixed_width_string(space);
|
||||
append_ss(&message, make_lit_string("Building with: "));
|
||||
append_ss(&message, *command);
|
||||
append_s_char(&message, '\n');
|
||||
print_message(app, message.str, message.size);
|
||||
|
||||
exec_system_command(app, view, buffer_identifier(literal("*compilation*")), dir->str, dir->size, command->str, command->size, CLI_OverlapWithConflict);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
dir->size = old_size;
|
||||
|
||||
if (directory_cd(app, dir->str, &dir->size, dir->memory_size, literal("..")) == 0){
|
||||
if (perform_backup){
|
||||
dir->size = directory_get_hot(app, dir->str, dir->memory_size);
|
||||
char backup_space[256];
|
||||
String backup_command = make_fixed_width_string(backup_space);
|
||||
append_ss(&backup_command, make_lit_string("echo could not find "));
|
||||
append_ss(&backup_command, filename);
|
||||
exec_system_command(app, view, buffer_identifier(literal("*compilation*")), dir->str, dir->size, backup_command.str, backup_command.size, CLI_OverlapWithConflict);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
// NOTE(allen): Build search rule for windows.
|
||||
static int32_t
|
||||
execute_standard_build_search(Application_Links *app, View_Summary *view,
|
||||
Buffer_Summary *active_buffer,
|
||||
String *dir, String *command, int32_t perform_backup){
|
||||
int32_t result = standard_build_search(app, view, active_buffer, dir, command, perform_backup, true, make_lit_string("build.bat"), make_lit_string("build"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
// NOTE(allen): Build search rule for linux.
|
||||
static int32_t
|
||||
execute_standard_build_search(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer, String *dir, String *command, bool32 perform_backup){
|
||||
char dir_space[512];
|
||||
String dir_copy = make_fixed_width_string(dir_space);
|
||||
copy(&dir_copy, *dir);
|
||||
|
||||
int32_t result = standard_build_search(app, view, active_buffer, dir, command, 0, 1, make_lit_string("build.sh"), make_lit_string("build.sh"));
|
||||
|
||||
if (!result){
|
||||
result = standard_build_search(app, view, active_buffer, &dir_copy, command, perform_backup, 0, make_lit_string("Makefile"), make_lit_string("make"));
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
#else
|
||||
# error No build search rule for this platform.
|
||||
#endif
|
||||
|
||||
// NOTE(allen): This searches first using the active file's directory,
|
||||
// then if no build script is found, it searches from 4coders hot directory.
|
||||
static void
|
||||
execute_standard_build(Application_Links *app, View_Summary *view, Buffer_Summary *active_buffer){
|
||||
char dir_space[512];
|
||||
String dir = make_fixed_width_string(dir_space);
|
||||
|
||||
char command_str_space[512];
|
||||
String command = make_fixed_width_string(command_str_space);
|
||||
|
||||
int32_t build_dir_type = get_build_directory(app, active_buffer, &dir);
|
||||
|
||||
if (build_dir_type == BuildDir_AtFile){
|
||||
if (!execute_standard_build_search(app, view, active_buffer, &dir, &command, false)){
|
||||
dir.size = 0;
|
||||
command.size = 0;
|
||||
build_dir_type = get_build_directory(app, 0, &dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (build_dir_type == BuildDir_AtHot){
|
||||
execute_standard_build_search(app, view, active_buffer, &dir, &command, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(build_search){
|
||||
uint32_t access = AccessAll;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
execute_standard_build(app, &view, &buffer);
|
||||
prev_location = null_location;
|
||||
lock_jump_buffer(literal("*compilation*"));
|
||||
}
|
||||
|
||||
#define GET_COMP_BUFFER(app) get_buffer_by_name(app, literal("*compilation*"), AccessAll)
|
||||
|
||||
static View_Summary
|
||||
get_or_open_build_panel(Application_Links *app){
|
||||
View_Summary view = {0};
|
||||
|
||||
Buffer_Summary buffer = GET_COMP_BUFFER(app);
|
||||
if (buffer.exists){
|
||||
view = get_first_view_with_buffer(app, buffer.buffer_id);
|
||||
}
|
||||
if (!view.exists){
|
||||
view = open_special_note_view(app);
|
||||
}
|
||||
|
||||
return(view);
|
||||
}
|
||||
|
||||
static void
|
||||
set_fancy_compilation_buffer_font(Application_Links *app){
|
||||
Buffer_Summary comp_buffer = get_buffer_by_name(app, literal("*compilation*"), AccessAll);
|
||||
buffer_set_font(app, &comp_buffer, literal("Inconsolata"));
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(build_in_build_panel){
|
||||
uint32_t access = AccessAll;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
|
||||
View_Summary build_view = get_or_open_build_panel(app);
|
||||
|
||||
execute_standard_build(app, &build_view, &buffer);
|
||||
set_fancy_compilation_buffer_font(app);
|
||||
|
||||
prev_location = null_location;
|
||||
lock_jump_buffer(literal("*compilation*"));
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(close_build_panel){
|
||||
close_special_note_view(app);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(change_to_build_panel){
|
||||
View_Summary view = open_special_note_view(app, false);
|
||||
|
||||
if (!view.exists){
|
||||
Buffer_Summary buffer = GET_COMP_BUFFER(app);
|
||||
if (buffer.exists){
|
||||
view = open_special_note_view(app);
|
||||
view_set_buffer(app, &view, buffer.buffer_id, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (view.exists){
|
||||
set_active_view(app, &view);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
4coder_clipboard.cpp - Copy paste commands and clipboard related setup.
|
||||
|
||||
TYPE: 'drop-in-command-pack'
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#if !defined(FCODER_CLIPBOARD_CPP)
|
||||
#define FCODER_CLIPBOARD_CPP
|
||||
|
||||
#include "4coder_default_framework.h"
|
||||
|
||||
#include "4coder_helper/4coder_helper.h"
|
||||
|
||||
static bool32
|
||||
clipboard_copy(Application_Links *app, int32_t start, int32_t end, Buffer_Summary *buffer_out, uint32_t access){
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
bool32 result = 0;
|
||||
|
||||
if (buffer.exists){
|
||||
if (0 <= start && start <= end && end <= buffer.size){
|
||||
int32_t size = (end - start);
|
||||
char *str = (char*)app->memory;
|
||||
|
||||
if (size <= app->memory_size){
|
||||
buffer_read_range(app, &buffer, start, end, str);
|
||||
clipboard_post(app, 0, str, size);
|
||||
if (buffer_out){*buffer_out = buffer;}
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
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;
|
||||
|
||||
if (clipboard_copy(app, start, end, &buffer, access)){
|
||||
buffer_replace_range(app, &buffer, start, end, 0, 0);
|
||||
if (buffer_out){*buffer_out = buffer;}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(copy){
|
||||
uint32_t access = AccessProtected;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Range range = get_range(&view);
|
||||
clipboard_copy(app, range.min, range.max, 0, access);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(cut){
|
||||
uint32_t access = AccessOpen;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Range range = get_range(&view);
|
||||
clipboard_cut(app, range.min, range.max, 0, access);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(paste){
|
||||
uint32_t access = AccessOpen;
|
||||
int32_t count = clipboard_count(app, 0);
|
||||
if (count > 0){
|
||||
View_Summary view = get_active_view(app, access);
|
||||
|
||||
view_paste_index[view.view_id].next_rewrite = RewritePaste;
|
||||
|
||||
int32_t paste_index = 0;
|
||||
view_paste_index[view.view_id].index = paste_index;
|
||||
|
||||
int32_t len = clipboard_index(app, 0, paste_index, 0, 0);
|
||||
char *str = 0;
|
||||
|
||||
if (len <= app->memory_size){
|
||||
str = (char*)app->memory;
|
||||
}
|
||||
|
||||
if (str){
|
||||
clipboard_index(app, 0, paste_index, str, len);
|
||||
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
int32_t pos = view.cursor.pos;
|
||||
buffer_replace_range(app, &buffer, pos, pos, str, len);
|
||||
view_set_mark(app, &view, seek_pos(pos));
|
||||
view_set_cursor(app, &view, seek_pos(pos + len), true);
|
||||
|
||||
// TODO(allen): Send this to all views.
|
||||
Theme_Color paste;
|
||||
paste.tag = Stag_Paste;
|
||||
get_theme_colors(app, &paste, 1);
|
||||
view_post_fade(app, &view, 0.667f, pos, pos + len, paste.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(paste_next){
|
||||
uint32_t access = AccessOpen;
|
||||
int32_t count = clipboard_count(app, 0);
|
||||
if (count > 0){
|
||||
View_Summary view = get_active_view(app, access);
|
||||
|
||||
if (view_paste_index[view.view_id].rewrite == RewritePaste){
|
||||
view_paste_index[view.view_id].next_rewrite = RewritePaste;
|
||||
|
||||
int32_t paste_index = view_paste_index[view.view_id].index + 1;
|
||||
view_paste_index[view.view_id].index = paste_index;
|
||||
|
||||
int32_t len = clipboard_index(app, 0, paste_index, 0, 0);
|
||||
char *str = 0;
|
||||
|
||||
if (len <= app->memory_size){
|
||||
str = (char*)app->memory;
|
||||
}
|
||||
|
||||
if (str){
|
||||
clipboard_index(app, 0, paste_index, str, len);
|
||||
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
Range range = get_range(&view);
|
||||
int32_t pos = range.min;
|
||||
|
||||
buffer_replace_range(app, &buffer, range.min, range.max, str, len);
|
||||
view_set_cursor(app, &view, seek_pos(pos + len), true);
|
||||
|
||||
// TODO(allen): Send this to all views.
|
||||
Theme_Color paste;
|
||||
paste.tag = Stag_Paste;
|
||||
get_theme_colors(app, &paste, 1);
|
||||
view_post_fade(app, &view, 0.667f, pos, pos + len, paste.color);
|
||||
}
|
||||
}
|
||||
else{
|
||||
exec_command(app, paste);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -1,314 +1,23 @@
|
|||
/*
|
||||
4coder_default_bidings.cpp - Supplies the default bindings used for default 4coder behavior.
|
||||
|
||||
TYPE: 'build-target'
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#ifndef FCODER_DEFAULT_BINDINGS
|
||||
#if !defined(FCODER_DEFAULT_BINDINGS)
|
||||
#define FCODER_DEFAULT_BINDINGS
|
||||
|
||||
#include "4coder_default_include.cpp"
|
||||
|
||||
// NOTE(allen|a3.3): All of your custom ids should be enumerated
|
||||
// as shown here, they may start at 0, and you can only have
|
||||
// 2^24 of them so don't be wasteful!
|
||||
enum My_Maps{
|
||||
my_code_map,
|
||||
my_maps_count
|
||||
};
|
||||
|
||||
CUSTOM_COMMAND_SIG(write_allen_todo){
|
||||
write_string(app, make_lit_string("// TODO(allen): "));
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(write_allen_note){
|
||||
write_string(app, make_lit_string("// NOTE(allen): "));
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(write_allen_doc){
|
||||
write_string(app, make_lit_string("/* DOC() */"));
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(write_zero_struct){
|
||||
write_string(app, make_lit_string(" = {0};"));
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(switch_to_compilation){
|
||||
|
||||
char name[] = "*compilation*";
|
||||
int32_t name_size = sizeof(name)-1;
|
||||
|
||||
uint32_t access = AccessOpen;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer_by_name(app, name, name_size, access);
|
||||
|
||||
view_set_buffer(app, &view, buffer.buffer_id, 0);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(rewrite_as_single_caps){
|
||||
uint32_t access = AccessOpen;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Full_Cursor cursor = view.cursor;
|
||||
|
||||
// TODO(allen): This can be rewritten now without moving the
|
||||
// cursor around, instead just calling the boundary seek.
|
||||
Range range = {0};
|
||||
exec_command(app, seek_token_left);
|
||||
refresh_view(app, &view);
|
||||
range.min = view.cursor.pos;
|
||||
|
||||
exec_command(app, seek_token_right);
|
||||
refresh_view(app, &view);
|
||||
range.max = view.cursor.pos;
|
||||
|
||||
String string = {0};
|
||||
string.str = (char*)app->memory;
|
||||
string.size = range.max - range.min;
|
||||
assert(string.size < app->memory_size);
|
||||
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
buffer_read_range(app, &buffer, range.min, range.max, string.str);
|
||||
|
||||
int32_t is_first = true;
|
||||
for (int32_t i = 0; i < string.size; ++i){
|
||||
if (char_is_alpha_true(string.str[i])){
|
||||
if (is_first){
|
||||
is_first = false;
|
||||
}
|
||||
else{
|
||||
string.str[i] = char_to_lower(string.str[i]);
|
||||
}
|
||||
}
|
||||
else{
|
||||
is_first = true;
|
||||
}
|
||||
}
|
||||
|
||||
buffer_replace_range(app, &buffer, range.min, range.max, string.str, string.size);
|
||||
|
||||
view_set_cursor(app, &view, seek_line_char(cursor.line+1, cursor.character), true);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(open_my_files){
|
||||
uint32_t access = AccessAll;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
view_open_file(app, &view, literal("w:/4ed/data/test/basic.cpp"), true);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(build_at_launch_location){
|
||||
uint32_t access = AccessAll;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
exec_system_command(app, &view, buffer_identifier(literal("*compilation*")),literal("."), literal("build"), CLI_OverlapWithConflict);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(seek_whitespace_up_end_line){
|
||||
exec_command(app, seek_whitespace_up);
|
||||
exec_command(app, seek_end_of_line);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(seek_whitespace_down_end_line){
|
||||
exec_command(app, seek_whitespace_down);
|
||||
exec_command(app, seek_end_of_line);
|
||||
}
|
||||
|
||||
HOOK_SIG(my_start){
|
||||
default_4coder_initialize(app);
|
||||
default_4coder_side_by_side_panels(app);
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
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.view_region.x1 - view.view_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);
|
||||
if (automatically_adjust_wrapping){
|
||||
adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width);
|
||||
}
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(newline_or_goto_position){
|
||||
View_Summary view = get_active_view(app, AccessProtected);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessProtected);
|
||||
|
||||
if (buffer.lock_flags & AccessProtected){
|
||||
exec_command(app, goto_jump_at_cursor);
|
||||
lock_jump_buffer(buffer);
|
||||
}
|
||||
else{
|
||||
exec_command(app, write_character);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(allen): Eliminate this hook if you can.
|
||||
OPEN_FILE_HOOK_SIG(my_file_settings){
|
||||
// NOTE(allen|a4.0.8): The get_parameter_buffer was eliminated
|
||||
// and instead the buffer is passed as an explicit parameter through
|
||||
// the function call. That is where buffer_id comes from here.
|
||||
uint32_t access = AccessAll;
|
||||
Buffer_Summary buffer = get_buffer(app, buffer_id, access);
|
||||
assert(buffer.exists);
|
||||
|
||||
int32_t treat_as_code = 0;
|
||||
int32_t wrap_lines = 1;
|
||||
|
||||
if (buffer.file_name && buffer.size < (16 << 20)){
|
||||
String ext = file_extension(make_string(buffer.file_name, buffer.file_name_len));
|
||||
if (match_ss(ext, make_lit_string("cpp"))) treat_as_code = 1;
|
||||
else if (match_ss(ext, make_lit_string("h"))) treat_as_code = 1;
|
||||
else if (match_ss(ext, make_lit_string("c"))) treat_as_code = 1;
|
||||
else if (match_ss(ext, make_lit_string("hpp"))) treat_as_code = 1;
|
||||
}
|
||||
|
||||
if (treat_as_code){
|
||||
wrap_lines = 0;
|
||||
}
|
||||
if (buffer.file_name[0] == '*'){
|
||||
wrap_lines = 0;
|
||||
}
|
||||
|
||||
buffer_set_setting(app, &buffer, BufferSetting_WrapPosition, default_wrap_width);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_MinimumBaseWrapPosition, default_min_base_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 << 18)){
|
||||
// NOTE(allen|a4.0.12): There is a little bit of grossness going on here.
|
||||
// If we set BufferSetting_Lex to true, it will launch a lexing job.
|
||||
// If a lexing job is active when we set BufferSetting_VirtualWhitespace, the call can fail.
|
||||
// Unfortunantely without tokens virtual whitespace doesn't really make sense.
|
||||
// So for now I have it automatically turning on lexing when virtual whitespace is turned on.
|
||||
// Cleaning some of that up is a goal for future versions.
|
||||
buffer_set_setting(app, &buffer, BufferSetting_WrapLine, 1);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_VirtualWhitespace, 1);
|
||||
}
|
||||
else{
|
||||
buffer_set_setting(app, &buffer, BufferSetting_WrapLine, wrap_lines);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_Lex, treat_as_code);
|
||||
}
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
OPEN_FILE_HOOK_SIG(my_file_save){
|
||||
uint32_t access = AccessAll;
|
||||
Buffer_Summary buffer = get_buffer(app, buffer_id, access);
|
||||
assert(buffer.exists);
|
||||
|
||||
int32_t is_virtual = 0;
|
||||
if (automatically_indent_text_on_save && buffer_get_setting(app, &buffer, BufferSetting_VirtualWhitespace, &is_virtual)){
|
||||
if (is_virtual){
|
||||
auto_tab_whole_file_by_summary(app, &buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
// NOTE(allen|a4.0.9): The input filter allows you to modify the input
|
||||
// to a frame before 4coder starts processing it at all.
|
||||
//
|
||||
// Right now it only has access to the mouse state, but it will be
|
||||
// extended to have access to the key presses soon.
|
||||
static bool32 suppressing_mouse = false;
|
||||
|
||||
INPUT_FILTER_SIG(my_suppress_mouse_filter){
|
||||
if (suppressing_mouse){
|
||||
*mouse = null_mouse_state;
|
||||
mouse->x = -100;
|
||||
mouse->y = -100;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_mouse_suppression(Application_Links *app, int32_t suppress){
|
||||
if (suppress){
|
||||
suppressing_mouse = 1;
|
||||
show_mouse_cursor(app, MouseCursorShow_Never);
|
||||
}
|
||||
else{
|
||||
suppressing_mouse = 0;
|
||||
show_mouse_cursor(app, MouseCursorShow_Always);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(suppress_mouse){
|
||||
set_mouse_suppression(app, true);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(allow_mouse){
|
||||
set_mouse_suppression(app, false);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(toggle_mouse){
|
||||
set_mouse_suppression(app, !suppressing_mouse);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(execute_arbitrary_command){
|
||||
// NOTE(allen): This isn't a super powerful version of this command, I will expand
|
||||
// upon it so that it has all the cmdid_* commands by default. However, with this
|
||||
// as an example you have everything you need to make it work already. You could
|
||||
// even use app->memory to create a hash table in the start hook.
|
||||
Query_Bar bar;
|
||||
char space[1024];
|
||||
bar.prompt = make_lit_string("Command: ");
|
||||
bar.string = make_fixed_width_string(space);
|
||||
|
||||
if (!query_user_string(app, &bar)) return;
|
||||
|
||||
// NOTE(allen): Here I chose to end this query bar because when I call another
|
||||
// command it might ALSO have query bars and I don't want this one hanging
|
||||
// around at that point. Since the bar exists on my stack the result of the query
|
||||
// is still available in bar.string though.
|
||||
end_query_bar(app, &bar, 0);
|
||||
|
||||
if (match_ss(bar.string, make_lit_string("load project"))){
|
||||
exec_command(app, load_project);
|
||||
}
|
||||
else if (match_ss(bar.string, make_lit_string("open all code"))){
|
||||
exec_command(app, open_all_code);
|
||||
}
|
||||
else if(match_ss(bar.string, make_lit_string("close all code"))){
|
||||
exec_command(app, close_all_code);
|
||||
}
|
||||
else if (match_ss(bar.string, make_lit_string("open menu"))){
|
||||
exec_command(app, cmdid_open_menu);
|
||||
}
|
||||
else if (match_ss(bar.string, make_lit_string("dos lines"))){
|
||||
exec_command(app, eol_dosify);
|
||||
}
|
||||
else if (match_ss(bar.string, make_lit_string("nix lines"))){
|
||||
exec_command(app, eol_nixify);
|
||||
}
|
||||
else{
|
||||
print_message(app, literal("unrecognized command\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
default_keys(Bind_Helper *context){
|
||||
begin_map(context, mapid_global);
|
||||
|
||||
bind(context, 'p', MDFR_CTRL, open_panel_vsplit);
|
||||
bind(context, '_', MDFR_CTRL, open_panel_hsplit);
|
||||
bind(context, 'P', MDFR_CTRL, close_panel);
|
||||
//bind(context, 'p', MDFR_CTRL, open_panel_vsplit);
|
||||
//bind(context, '_', MDFR_CTRL, open_panel_hsplit);
|
||||
//bind(context, 'P', MDFR_CTRL, close_panel);
|
||||
bind(context, ',', MDFR_CTRL, change_active_panel);
|
||||
|
||||
bind(context, 'n', MDFR_CTRL, interactive_new);
|
||||
|
@ -318,8 +27,8 @@ default_keys(Bind_Helper *context){
|
|||
bind(context, 'i', MDFR_CTRL, interactive_switch_buffer);
|
||||
bind(context, 'w', MDFR_CTRL, save_as);
|
||||
|
||||
bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker);
|
||||
bind(context, 'd', MDFR_ALT, cmdid_open_debug);
|
||||
bind(context, 'c', MDFR_ALT, open_color_tweaker);
|
||||
bind(context, 'd', MDFR_ALT, open_debug);
|
||||
|
||||
bind(context, '.', MDFR_ALT, change_to_build_panel);
|
||||
bind(context, ',', MDFR_ALT, close_build_panel);
|
||||
|
@ -336,7 +45,7 @@ default_keys(Bind_Helper *context){
|
|||
bind(context, 's', MDFR_ALT, show_scrollbar);
|
||||
bind(context, 'w', MDFR_ALT, hide_scrollbar);
|
||||
|
||||
// TODO(allen): This is apparently not working on Linux. Need to try it on windows still.
|
||||
// TODO(allen): This is apparently not working on Linux, must investigate.
|
||||
bind(context, key_f2, MDFR_CTRL, toggle_mouse);
|
||||
bind(context, key_page_up, MDFR_CTRL, toggle_fullscreen);
|
||||
bind(context, 'E', MDFR_ALT, exit_4coder);
|
||||
|
@ -363,9 +72,9 @@ default_keys(Bind_Helper *context){
|
|||
|
||||
end_map(context);
|
||||
|
||||
begin_map(context, my_code_map);
|
||||
begin_map(context, default_code_map);
|
||||
|
||||
// NOTE(allen|a3.1): Set this map (my_code_map == mapid_user_custom) to
|
||||
// NOTE(allen|a3.1): Set this map (default_code_map == mapid_user_custom) to
|
||||
// inherit from mapid_file. When searching if a key is bound
|
||||
// in this map, if it is not found here it will then search mapid_file.
|
||||
//
|
||||
|
@ -391,15 +100,16 @@ default_keys(Bind_Helper *context){
|
|||
bind(context, '\t', MDFR_CTRL, auto_tab_range);
|
||||
bind(context, '\t', MDFR_SHIFT, auto_tab_line_at_cursor);
|
||||
|
||||
bind(context, 't', MDFR_ALT, write_allen_todo);
|
||||
bind(context, 'y', MDFR_ALT, write_allen_note);
|
||||
bind(context, 'r', MDFR_ALT, write_allen_doc);
|
||||
bind(context, 't', MDFR_ALT, write_todo);
|
||||
bind(context, 'y', MDFR_ALT, write_note);
|
||||
bind(context, 'r', MDFR_ALT, write_block);
|
||||
bind(context, '[', MDFR_CTRL, open_long_braces);
|
||||
bind(context, '{', MDFR_CTRL, open_long_braces_semicolon);
|
||||
bind(context, '}', MDFR_CTRL, open_long_braces_break);
|
||||
bind(context, 'i', MDFR_ALT, if0_off);
|
||||
bind(context, '1', MDFR_ALT, open_file_in_quotes);
|
||||
bind(context, '0', MDFR_CTRL, write_zero_struct);
|
||||
bind(context, 'I', MDFR_CTRL, list_all_functions_current_buffer);
|
||||
|
||||
end_map(context);
|
||||
|
||||
|
@ -460,25 +170,21 @@ default_keys(Bind_Helper *context){
|
|||
bind(context, 'F', MDFR_ALT, list_all_substring_locations_case_insensitive);
|
||||
bind(context, 'g', MDFR_CTRL, goto_line);
|
||||
bind(context, 'j', MDFR_CTRL, to_lowercase);
|
||||
bind(context, 'K', MDFR_CTRL, cmdid_kill_buffer);
|
||||
bind(context, 'K', MDFR_CTRL, kill_buffer);
|
||||
bind(context, 'l', MDFR_CTRL, toggle_line_wrap);
|
||||
bind(context, 'm', MDFR_CTRL, cursor_mark_swap);
|
||||
bind(context, 'O', MDFR_CTRL, cmdid_reopen);
|
||||
bind(context, 'O', MDFR_CTRL, reopen);
|
||||
bind(context, 'q', MDFR_CTRL, query_replace);
|
||||
bind(context, 'r', MDFR_CTRL, reverse_search);
|
||||
bind(context, 's', MDFR_CTRL, cmdid_save);
|
||||
bind(context, 's', MDFR_CTRL, save);
|
||||
bind(context, 'T', MDFR_CTRL, list_all_locations_of_identifier);
|
||||
bind(context, 'u', MDFR_CTRL, to_uppercase);
|
||||
bind(context, 'U', MDFR_CTRL, rewrite_as_single_caps);
|
||||
bind(context, 'v', MDFR_CTRL, paste_and_indent);
|
||||
bind(context, 'v', MDFR_ALT, toggle_virtual_whitespace);
|
||||
bind(context, 'V', MDFR_CTRL, paste_next_and_indent);
|
||||
bind(context, 'x', MDFR_CTRL, cut);
|
||||
bind(context, 'y', MDFR_CTRL, cmdid_redo);
|
||||
bind(context, 'z', MDFR_CTRL, cmdid_undo);
|
||||
|
||||
bind(context, '1', MDFR_CTRL, eol_dosify);
|
||||
bind(context, '!', MDFR_CTRL, eol_nixify);
|
||||
bind(context, 'y', MDFR_CTRL, redo);
|
||||
bind(context, 'z', MDFR_CTRL, undo);
|
||||
|
||||
bind(context, '2', MDFR_CTRL, decrease_line_wrap);
|
||||
bind(context, '3', MDFR_CTRL, increase_line_wrap);
|
||||
|
@ -492,8 +198,6 @@ default_keys(Bind_Helper *context){
|
|||
end_map(context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef NO_BINDING
|
||||
|
||||
extern "C" int32_t
|
||||
|
@ -501,18 +205,7 @@ get_bindings(void *data, int32_t size){
|
|||
Bind_Helper context_ = begin_bind_helper(data, size);
|
||||
Bind_Helper *context = &context_;
|
||||
|
||||
// NOTE(allen|a3.1): Hooks have no loyalties to maps. All hooks are global
|
||||
// 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_save_file_hook(context, my_file_save);
|
||||
set_command_caller(context, default_command_caller);
|
||||
set_input_filter(context, my_suppress_mouse_filter);
|
||||
set_scroll_rule(context, smooth_scroll_rule);
|
||||
|
||||
set_all_default_hooks(context);
|
||||
default_keys(context);
|
||||
|
||||
int32_t result = end_bind_helper(context);
|
||||
|
@ -524,3 +217,4 @@ get_bindings(void *data, int32_t size){
|
|||
#endif //FCODER_DEFAULT_BINDINGS
|
||||
|
||||
// BOTTOM
|
||||
|
||||
|
|
|
@ -10,8 +10,20 @@ TYPE: 'internal-for-default-system'
|
|||
#if !defined(FCODER_DEFAULT_FRAMEWORK_H)
|
||||
#define FCODER_DEFAULT_FRAMEWORK_H
|
||||
|
||||
#include "4coder_base_commands.cpp"
|
||||
|
||||
#include "4coder_helper/4coder_helper.h"
|
||||
#include "4coder_lib/4coder_mem.h"
|
||||
#include "4cpp/4cpp_lexer.h"
|
||||
|
||||
//
|
||||
// Command Maps
|
||||
//
|
||||
|
||||
enum Default_Maps{
|
||||
default_code_map,
|
||||
default_maps_count
|
||||
};
|
||||
|
||||
//
|
||||
// Global Memory
|
||||
|
@ -34,12 +46,14 @@ unlock_jump_buffer(){
|
|||
|
||||
static void
|
||||
lock_jump_buffer(char *name, int32_t size){
|
||||
copy(&locked_buffer, make_string(name, size));
|
||||
if (size <= locked_buffer.memory_size){
|
||||
copy(&locked_buffer, make_string(name, size));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lock_jump_buffer(Buffer_Summary buffer){
|
||||
copy(&locked_buffer, make_string(buffer.buffer_name, buffer.buffer_name_len));
|
||||
lock_jump_buffer(buffer.buffer_name, buffer.buffer_name_len);
|
||||
}
|
||||
|
||||
static View_Summary
|
||||
|
@ -125,6 +139,601 @@ struct View_Paste_Index{
|
|||
View_Paste_Index view_paste_index_[16];
|
||||
View_Paste_Index *view_paste_index = view_paste_index_ - 1;
|
||||
|
||||
|
||||
//
|
||||
// System Buffer Names
|
||||
//
|
||||
|
||||
static char out_buffer_space[1024];
|
||||
static char command_space[1024];
|
||||
static char hot_directory_space[1024];
|
||||
|
||||
|
||||
//
|
||||
// Mouse Suppression
|
||||
//
|
||||
|
||||
static bool32 suppressing_mouse = false;
|
||||
|
||||
static void
|
||||
set_mouse_suppression(Application_Links *app, int32_t suppress){
|
||||
if (suppress){
|
||||
suppressing_mouse = 1;
|
||||
show_mouse_cursor(app, MouseCursorShow_Never);
|
||||
}
|
||||
else{
|
||||
suppressing_mouse = 0;
|
||||
show_mouse_cursor(app, MouseCursorShow_Always);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(suppress_mouse){
|
||||
set_mouse_suppression(app, true);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(allow_mouse){
|
||||
set_mouse_suppression(app, false);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(toggle_mouse){
|
||||
set_mouse_suppression(app, !suppressing_mouse);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Projects
|
||||
//
|
||||
|
||||
static char *default_extensions[] = {
|
||||
"cpp",
|
||||
"hpp",
|
||||
"c",
|
||||
"h",
|
||||
"cc"
|
||||
};
|
||||
|
||||
struct Fkey_Command{
|
||||
char command[128];
|
||||
char out[128];
|
||||
bool32 use_build_panel;
|
||||
};
|
||||
|
||||
struct Project{
|
||||
char dir_space[256];
|
||||
char *dir;
|
||||
int32_t dir_len;
|
||||
|
||||
char extension_space[256];
|
||||
char *extensions[94];
|
||||
int32_t extension_count;
|
||||
|
||||
Fkey_Command fkey_commands[16];
|
||||
|
||||
bool32 close_all_code_when_this_project_closes;
|
||||
bool32 close_all_files_when_project_opens;
|
||||
};
|
||||
|
||||
static Project null_project = {};
|
||||
static Project current_project = {};
|
||||
|
||||
static void
|
||||
set_project_extensions(Project *project, String src){
|
||||
int32_t mode = 0;
|
||||
int32_t j = 0, k = 0;
|
||||
for (int32_t i = 0; i < src.size; ++i){
|
||||
switch (mode){
|
||||
case 0:
|
||||
{
|
||||
if (src.str[i] == '.'){
|
||||
mode = 1;
|
||||
project->extensions[k++] = &project->extension_space[j];
|
||||
}
|
||||
}break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
if (src.str[i] == '.'){
|
||||
project->extension_space[j++] = 0;
|
||||
project->extensions[k++] = &project->extension_space[j];
|
||||
}
|
||||
else{
|
||||
project->extension_space[j++] = src.str[i];
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
project->extension_space[j++] = 0;
|
||||
project->extension_count = k;
|
||||
}
|
||||
|
||||
static char**
|
||||
get_current_code_extensions(int32_t *extension_count_out){
|
||||
char **extension_list = default_extensions;
|
||||
int32_t extension_count = ArrayCount(default_extensions);
|
||||
if (current_project.dir != 0){
|
||||
extension_list = current_project.extensions;
|
||||
extension_count = current_project.extension_count;
|
||||
}
|
||||
*extension_count_out = extension_count;
|
||||
return(extension_list);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Location Jumping State
|
||||
//
|
||||
|
||||
typedef struct ID_Based_Jump_Location{
|
||||
int32_t buffer_id;
|
||||
int32_t line;
|
||||
int32_t column;
|
||||
} ID_Based_Jump_Location;
|
||||
|
||||
static ID_Based_Jump_Location null_location = {0};
|
||||
static ID_Based_Jump_Location prev_location = {0};
|
||||
|
||||
|
||||
//
|
||||
// Config File Parsing
|
||||
//
|
||||
|
||||
struct Config_Line{
|
||||
Cpp_Token id_token;
|
||||
Cpp_Token subscript_token;
|
||||
Cpp_Token eq_token;
|
||||
Cpp_Token val_token;
|
||||
int32_t val_array_start;
|
||||
int32_t val_array_end;
|
||||
int32_t val_array_count;
|
||||
bool32 read_success;
|
||||
};
|
||||
|
||||
struct Config_Item{
|
||||
Config_Line line;
|
||||
Cpp_Token_Array array;
|
||||
char *mem;
|
||||
String id;
|
||||
int32_t subscript_index;
|
||||
bool32 has_subscript;
|
||||
};
|
||||
|
||||
struct Config_Array_Reader{
|
||||
Cpp_Token_Array array;
|
||||
char *mem;
|
||||
int32_t i;
|
||||
int32_t val_array_end;
|
||||
bool32 good;
|
||||
};
|
||||
|
||||
static Cpp_Token
|
||||
read_config_token(Cpp_Token_Array array, int32_t *i_ptr){
|
||||
Cpp_Token token = {0};
|
||||
|
||||
int32_t i = *i_ptr;
|
||||
|
||||
for (; i < array.count; ++i){
|
||||
Cpp_Token comment_token = array.tokens[i];
|
||||
if (comment_token.type != CPP_TOKEN_COMMENT){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < array.count){
|
||||
token = array.tokens[i];
|
||||
}
|
||||
|
||||
*i_ptr = i;
|
||||
|
||||
return(token);
|
||||
}
|
||||
|
||||
static Config_Line
|
||||
read_config_line(Cpp_Token_Array array, int32_t *i_ptr){
|
||||
Config_Line config_line = {0};
|
||||
|
||||
int32_t i = *i_ptr;
|
||||
|
||||
config_line.id_token = read_config_token(array, &i);
|
||||
if (config_line.id_token.type == CPP_TOKEN_IDENTIFIER){
|
||||
++i;
|
||||
if (i < array.count){
|
||||
Cpp_Token token = read_config_token(array, &i);
|
||||
|
||||
bool32 subscript_success = 1;
|
||||
if (token.type == CPP_TOKEN_BRACKET_OPEN){
|
||||
subscript_success = 0;
|
||||
++i;
|
||||
if (i < array.count){
|
||||
config_line.subscript_token = read_config_token(array, &i);
|
||||
if (config_line.subscript_token.type == CPP_TOKEN_INTEGER_CONSTANT){
|
||||
++i;
|
||||
if (i < array.count){
|
||||
token = read_config_token(array, &i);
|
||||
if (token.type == CPP_TOKEN_BRACKET_CLOSE){
|
||||
++i;
|
||||
if (i < array.count){
|
||||
token = read_config_token(array, &i);
|
||||
subscript_success = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subscript_success){
|
||||
if (token.type == CPP_TOKEN_EQ){
|
||||
config_line.eq_token = read_config_token(array, &i);
|
||||
++i;
|
||||
if (i < array.count){
|
||||
Cpp_Token val_token = read_config_token(array, &i);
|
||||
|
||||
bool32 array_success = 1;
|
||||
if (val_token.type == CPP_TOKEN_BRACE_OPEN){
|
||||
array_success = 0;
|
||||
++i;
|
||||
if (i < array.count){
|
||||
config_line.val_array_start = i;
|
||||
|
||||
bool32 expecting_array_item = 1;
|
||||
for (; i < array.count; ++i){
|
||||
Cpp_Token array_token = read_config_token(array, &i);
|
||||
if (array_token.size == 0){
|
||||
break;
|
||||
}
|
||||
if (array_token.type == CPP_TOKEN_BRACE_CLOSE){
|
||||
config_line.val_array_end = i;
|
||||
array_success = 1;
|
||||
break;
|
||||
}
|
||||
else{
|
||||
if (array_token.type == CPP_TOKEN_COMMA){
|
||||
if (!expecting_array_item){
|
||||
expecting_array_item = 1;
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (expecting_array_item){
|
||||
expecting_array_item = 0;
|
||||
++config_line.val_array_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (array_success){
|
||||
config_line.val_token = val_token;
|
||||
++i;
|
||||
if (i < array.count){
|
||||
Cpp_Token semicolon_token = read_config_token(array, &i);
|
||||
if (semicolon_token.type == CPP_TOKEN_SEMICOLON){
|
||||
config_line.read_success = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!config_line.read_success){
|
||||
for (; i < array.count; ++i){
|
||||
Cpp_Token token = read_config_token(array, &i);
|
||||
if (token.type == CPP_TOKEN_SEMICOLON){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*i_ptr = i;
|
||||
|
||||
return(config_line);
|
||||
}
|
||||
|
||||
static Config_Item
|
||||
get_config_item(Config_Line line, char *mem, Cpp_Token_Array array){
|
||||
Config_Item item = {0};
|
||||
item.line = line;
|
||||
item.array = array;
|
||||
item.mem = mem;
|
||||
if (line.id_token.size != 0){
|
||||
item.id = make_string(mem + line.id_token.start, line.id_token.size);
|
||||
}
|
||||
|
||||
if (line.subscript_token.size != 0){
|
||||
String subscript_str = make_string(mem + line.subscript_token.start,line.subscript_token.size);
|
||||
item.subscript_index = str_to_int_s(subscript_str);
|
||||
item.has_subscript = 1;
|
||||
}
|
||||
|
||||
return(item);
|
||||
}
|
||||
|
||||
static bool32
|
||||
config_var(Config_Item item, char *var_name, int32_t *subscript, uint32_t token_type, void *var_out){
|
||||
bool32 result = 0;
|
||||
bool32 subscript_succes = 1;
|
||||
if (item.line.val_token.type == token_type){
|
||||
if ((var_name == 0 && item.id.size == 0) || match(item.id, var_name)){
|
||||
if (subscript){
|
||||
if (item.has_subscript){
|
||||
*subscript = item.subscript_index;
|
||||
}
|
||||
else{
|
||||
subscript_succes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (subscript_succes){
|
||||
if (var_out){
|
||||
switch (token_type){
|
||||
case CPP_TOKEN_BOOLEAN_CONSTANT:
|
||||
{
|
||||
*(bool32*)var_out = (item.mem[item.line.val_token.start] == 't');
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_INTEGER_CONSTANT:
|
||||
{
|
||||
String val = make_string(item.mem + item.line.val_token.start, item.line.val_token.size);
|
||||
*(int32_t*)var_out = str_to_int(val);
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_STRING_CONSTANT:
|
||||
{
|
||||
*(String*)var_out = make_string(item.mem + item.line.val_token.start + 1,item.line.val_token.size - 2);
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_BRACE_OPEN:
|
||||
{
|
||||
Config_Array_Reader *array_reader = (Config_Array_Reader*)var_out;
|
||||
array_reader->array = item.array;
|
||||
array_reader->mem = item.mem;
|
||||
array_reader->i = item.line.val_array_start;
|
||||
array_reader->val_array_end = item.line.val_array_end;
|
||||
array_reader->good = 1;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool32
|
||||
config_bool_var(Config_Item item, char *var_name, int32_t *subscript, bool32 *var_out){
|
||||
bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_BOOLEAN_CONSTANT, var_out);
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool32
|
||||
config_int_var(Config_Item item, char *var_name, int32_t *subscript, int32_t *var_out){
|
||||
bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_INTEGER_CONSTANT, var_out);
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool32
|
||||
config_string_var(Config_Item item, char *var_name, int32_t *subscript, String *var_out){
|
||||
bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_STRING_CONSTANT, var_out);
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool32
|
||||
config_array_var(Config_Item item, char *var_name, int32_t *subscript, Config_Array_Reader *array_reader){
|
||||
bool32 result = config_var(item, var_name, subscript, CPP_TOKEN_BRACE_OPEN, array_reader);
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool32
|
||||
config_array_next_item(Config_Array_Reader *array_reader, Config_Item *item){
|
||||
bool32 result = 0;
|
||||
|
||||
for (;array_reader->i < array_reader->val_array_end;
|
||||
++array_reader->i){
|
||||
Cpp_Token array_token = read_config_token(array_reader->array, &array_reader->i);
|
||||
if (array_token.size == 0 || array_reader->i >= array_reader->val_array_end){
|
||||
break;
|
||||
}
|
||||
|
||||
if (array_token.type == CPP_TOKEN_BRACE_CLOSE){
|
||||
break;
|
||||
}
|
||||
|
||||
switch (array_token.type){
|
||||
case CPP_TOKEN_BOOLEAN_CONSTANT:
|
||||
case CPP_TOKEN_INTEGER_CONSTANT:
|
||||
case CPP_TOKEN_STRING_CONSTANT:
|
||||
{
|
||||
Config_Line line = {0};
|
||||
line.val_token = array_token;
|
||||
line.read_success = 1;
|
||||
*item = get_config_item(line, array_reader->mem, array_reader->array);
|
||||
result = 1;
|
||||
++array_reader->i;
|
||||
goto doublebreak;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
doublebreak:;
|
||||
|
||||
array_reader->good = result;
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool32
|
||||
config_array_good(Config_Array_Reader *array_reader){
|
||||
bool32 result = (array_reader->good);
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Configuration
|
||||
//
|
||||
|
||||
static bool32 enable_code_wrapping = 1;
|
||||
static bool32 automatically_adjust_wrapping = 1;
|
||||
static int32_t default_wrap_width = 672;
|
||||
static int32_t default_min_base_width = 550;
|
||||
static bool32 automatically_indent_text_on_save = 1;
|
||||
|
||||
static String default_theme_name = make_lit_string("4coder");
|
||||
static String default_font_name = make_lit_string("Liberation Sans");
|
||||
|
||||
static String user_name = {0};
|
||||
|
||||
static bool32
|
||||
get_current_name(char **name_out, int32_t *len_out){
|
||||
bool32 result = false;
|
||||
*name_out = 0;
|
||||
if (user_name.str != 0){
|
||||
*name_out = user_name.str;
|
||||
*len_out = user_name.size;
|
||||
result = true;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
// TODO(allen): Stop handling files this way! My own API should be able to do this!!?!?!?!!?!?!!!!?
|
||||
#include <stdio.h>
|
||||
|
||||
static bool32
|
||||
file_handle_dump(Partition *part, FILE *file, char **mem_ptr, int32_t *size_ptr){
|
||||
bool32 success = 0;
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
int32_t size = ftell(file);
|
||||
char *mem = (char*)push_block(part, size+1);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
int32_t check_size = (int32_t)fread(mem, 1, size, file);
|
||||
if (check_size == size){
|
||||
mem[size] = 0;
|
||||
success = 1;
|
||||
}
|
||||
|
||||
*mem_ptr = mem;
|
||||
*size_ptr = size;
|
||||
|
||||
return(success);
|
||||
}
|
||||
|
||||
static void
|
||||
process_config_file(Application_Links *app){
|
||||
Partition *part = &global_part;
|
||||
FILE *file = fopen("config.4coder", "rb");
|
||||
|
||||
if (!file){
|
||||
char space[256];
|
||||
int32_t size = get_4ed_path(app, space, sizeof(space));
|
||||
String str = make_string_cap(space, size, sizeof(space));
|
||||
append_sc(&str, "/config.4coder");
|
||||
terminate_with_null(&str);
|
||||
file = fopen(str.str, "rb");
|
||||
}
|
||||
|
||||
if (file){
|
||||
Temp_Memory temp = begin_temp_memory(part);
|
||||
|
||||
char *mem = 0;
|
||||
int32_t size = 0;
|
||||
bool32 file_read_success = file_handle_dump(part, file, &mem, &size);
|
||||
|
||||
if (file_read_success){
|
||||
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+1, HAS_NULL_TERM, &array, NO_OUT_LIMIT);
|
||||
|
||||
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){
|
||||
Config_Line config_line = read_config_line(array, &i);
|
||||
|
||||
if (config_line.read_success){
|
||||
Config_Item item = get_config_item(config_line, mem, array);
|
||||
|
||||
config_bool_var(item, "enable_code_wrapping", 0, &enable_code_wrapping);
|
||||
config_bool_var(item, "automatically_adjust_wrapping", 0, &automatically_adjust_wrapping);
|
||||
config_bool_var(item, "automatically_indent_text_on_save", 0, &automatically_indent_text_on_save);
|
||||
|
||||
config_int_var(item, "default_wrap_width", 0, &new_wrap_width);
|
||||
config_int_var(item, "default_min_base_width", 0, &new_min_base_width);
|
||||
|
||||
config_string_var(item, "default_theme_name", 0, &default_theme_name);
|
||||
config_string_var(item, "default_font_name", 0, &default_font_name);
|
||||
config_string_var(item, "user_name", 0, &user_name);
|
||||
}
|
||||
}
|
||||
adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width);
|
||||
default_wrap_width = new_wrap_width;
|
||||
default_min_base_width = new_min_base_width;
|
||||
}
|
||||
}
|
||||
|
||||
end_temp_memory(temp);
|
||||
}
|
||||
else{
|
||||
print_message(app, literal("Did not find config.4coder, using default settings\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Framework Init Functions
|
||||
//
|
||||
|
||||
void
|
||||
init_memory(Application_Links *app){
|
||||
int32_t part_size = (32 << 20);
|
||||
int32_t general_size = (4 << 20);
|
||||
|
||||
void *part_mem = memory_allocate(app, part_size);
|
||||
global_part = make_part(part_mem, part_size);
|
||||
|
||||
void *general_mem = memory_allocate(app, general_size);
|
||||
general_memory_open(&global_general, general_mem, general_size);
|
||||
}
|
||||
|
||||
static void
|
||||
default_4coder_initialize(Application_Links *app){
|
||||
init_memory(app);
|
||||
process_config_file(app);
|
||||
change_theme(app, default_theme_name.str, default_theme_name.size);
|
||||
change_font(app, default_font_name.str, default_font_name.size, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
default_4coder_side_by_side_panels(Application_Links *app){
|
||||
exec_command(app, open_panel_vsplit);
|
||||
exec_command(app, hide_scrollbar);
|
||||
exec_command(app, change_active_panel);
|
||||
exec_command(app, hide_scrollbar);
|
||||
}
|
||||
|
||||
static void
|
||||
default_4coder_one_panel(Application_Links *app){
|
||||
exec_command(app, hide_scrollbar);
|
||||
}
|
||||
|
||||
static void
|
||||
default_4coder_full_width_bottom_side_by_side_panels(Application_Links){
|
||||
// TODO(allen):
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
4coder_default_hooks.cpp - Sets up the hooks for the default framework.
|
||||
|
||||
TYPE: 'internal-for-default-system'
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#if !defined(FCODER_DEFAULT_HOOKS_CPP)
|
||||
#define FCODER_DEFAULT_HOOKS_CPP
|
||||
|
||||
#include "4coder_default_framework.h"
|
||||
#include "4coder_helper/4coder_bind_helper.h"
|
||||
|
||||
HOOK_SIG(default_start){
|
||||
default_4coder_initialize(app);
|
||||
default_4coder_side_by_side_panels(app);
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
// NOTE(allen|a4.0.9): All command calls can now go through this hook
|
||||
// If this hook is not implemented a default behavior of calling the
|
||||
// command is used. It is important to note that paste_next does not
|
||||
// work without this hook.
|
||||
// NOTE(allen|a4.0.10): As of this version the word_complete command
|
||||
// also relies on this particular command caller hook.
|
||||
COMMAND_CALLER_HOOK(default_command_caller){
|
||||
View_Summary view = get_active_view(app, AccessAll);
|
||||
|
||||
view_paste_index[view.view_id].next_rewrite = 0;
|
||||
exec_command(app, cmd);
|
||||
view_paste_index[view.view_id].rewrite = view_paste_index[view.view_id].next_rewrite;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
HOOK_SIG(default_exit){
|
||||
// if this returns zero it cancels the exit.
|
||||
return(1);
|
||||
}
|
||||
|
||||
HOOK_SIG(default_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.view_region.x1 - view.view_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);
|
||||
if (automatically_adjust_wrapping){
|
||||
adjust_all_buffer_wrap_widths(app, new_wrap_width, new_min_base_width);
|
||||
default_wrap_width = new_wrap_width;
|
||||
default_min_base_width = new_min_base_width;
|
||||
}
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
// TODO(allen): Eliminate this hook if you can.
|
||||
OPEN_FILE_HOOK_SIG(default_file_settings){
|
||||
// NOTE(allen|a4.0.8): The get_parameter_buffer was eliminated
|
||||
// and instead the buffer is passed as an explicit parameter through
|
||||
// the function call. That is where buffer_id comes from here.
|
||||
uint32_t access = AccessAll;
|
||||
Buffer_Summary buffer = get_buffer(app, buffer_id, access);
|
||||
Assert(buffer.exists);
|
||||
|
||||
int32_t treat_as_code = 0;
|
||||
int32_t wrap_lines = 1;
|
||||
|
||||
if (buffer.file_name && buffer.size < (16 << 20)){
|
||||
String ext = file_extension(make_string(buffer.file_name, buffer.file_name_len));
|
||||
|
||||
if (match_ss(ext, make_lit_string("cpp")) ||
|
||||
match_ss(ext, make_lit_string("h")) ||
|
||||
match_ss(ext, make_lit_string("c")) ||
|
||||
match_ss(ext, make_lit_string("hpp"))){
|
||||
treat_as_code = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (treat_as_code){
|
||||
wrap_lines = 0;
|
||||
}
|
||||
if (buffer.file_name[0] == '*'){
|
||||
wrap_lines = 0;
|
||||
}
|
||||
|
||||
buffer_set_setting(app, &buffer, BufferSetting_WrapPosition, default_wrap_width);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_MinimumBaseWrapPosition, default_min_base_width);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_MapID, (treat_as_code)?((int32_t)default_code_map):((int32_t)mapid_file));
|
||||
|
||||
if (treat_as_code && enable_code_wrapping && buffer.size < (1 << 18)){
|
||||
// NOTE(allen|a4.0.12): There is a little bit of grossness going on here.
|
||||
// If we set BufferSetting_Lex to true, it will launch a lexing job.
|
||||
// If a lexing job is active when we set BufferSetting_VirtualWhitespace, the call can fail.
|
||||
// Unfortunantely without tokens virtual whitespace doesn't really make sense.
|
||||
// So for now I have it automatically turning on lexing when virtual whitespace is turned on.
|
||||
// Cleaning some of that up is a goal for future versions.
|
||||
buffer_set_setting(app, &buffer, BufferSetting_WrapLine, 1);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_VirtualWhitespace, 1);
|
||||
}
|
||||
else{
|
||||
buffer_set_setting(app, &buffer, BufferSetting_WrapLine, wrap_lines);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_Lex, treat_as_code);
|
||||
}
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
OPEN_FILE_HOOK_SIG(default_file_save){
|
||||
uint32_t access = AccessAll;
|
||||
Buffer_Summary buffer = get_buffer(app, buffer_id, access);
|
||||
Assert(buffer.exists);
|
||||
|
||||
#if defined(FCODER_AUTO_INDENT_CPP)
|
||||
int32_t is_virtual = 0;
|
||||
if (automatically_indent_text_on_save && buffer_get_setting(app, &buffer, BufferSetting_VirtualWhitespace, &is_virtual)){
|
||||
if (is_virtual){
|
||||
auto_tab_whole_file_by_summary(app, &buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// no meaning for return
|
||||
return(0);
|
||||
}
|
||||
|
||||
// NOTE(allen|a4.0.9): The input filter allows you to modify the input
|
||||
// to a frame before 4coder starts processing it at all.
|
||||
//
|
||||
// Right now it only has access to the mouse state, but it will be
|
||||
// extended to have access to the key presses soon.
|
||||
INPUT_FILTER_SIG(default_suppress_mouse_filter){
|
||||
if (suppressing_mouse){
|
||||
*mouse = null_mouse_state;
|
||||
mouse->x = -100;
|
||||
mouse->y = -100;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(allen|a4): scroll rule information
|
||||
//
|
||||
// The parameters:
|
||||
// target_x, target_y
|
||||
// This is where the view would like to be for the purpose of
|
||||
// following the cursor, doing mouse wheel work, etc.
|
||||
//
|
||||
// scroll_x, scroll_y
|
||||
// These are pointers to where the scrolling actually is. If you bind
|
||||
// the scroll rule it is you have to update these in some way to move
|
||||
// the actual location of the scrolling.
|
||||
//
|
||||
// view_id
|
||||
// This corresponds to which view is computing it's new scrolling position.
|
||||
// This id DOES correspond to the views that View_Summary contains.
|
||||
// This will always be between 1 and 16 (0 is a null id).
|
||||
// See below for an example of having state that carries across scroll udpates.
|
||||
//
|
||||
// is_new_target
|
||||
// If the target of the view is different from the last target in either x or y
|
||||
// this is true, otherwise it is false.
|
||||
//
|
||||
// The return:
|
||||
// Should be true if and only if scroll_x or scroll_y are changed.
|
||||
//
|
||||
// Don't try to use the app pointer in a scroll rule, you're asking for trouble.
|
||||
//
|
||||
// If you don't bind scroll_rule, nothing bad will happen, yo will get default
|
||||
// 4coder scrolling behavior.
|
||||
//
|
||||
|
||||
struct Scroll_Velocity{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
Scroll_Velocity scroll_velocity_[16] = {0};
|
||||
Scroll_Velocity *scroll_velocity = scroll_velocity_ - 1;
|
||||
|
||||
static int32_t
|
||||
smooth_camera_step(float target, float *current, float *vel, float S, float T){
|
||||
int32_t result = 0;
|
||||
float curr = *current;
|
||||
float v = *vel;
|
||||
if (curr != target){
|
||||
if (curr > target - .1f && curr < target + .1f){
|
||||
curr = target;
|
||||
v = 1.f;
|
||||
}
|
||||
else{
|
||||
float L = curr + T*(target - curr);
|
||||
|
||||
int32_t sign = (target > curr) - (target < curr);
|
||||
float V = curr + sign*v;
|
||||
|
||||
if (sign > 0) curr = (L<V)?(L):(V);
|
||||
else curr = (L>V)?(L):(V);
|
||||
|
||||
if (curr == V){
|
||||
v *= S;
|
||||
}
|
||||
}
|
||||
|
||||
*current = curr;
|
||||
*vel = v;
|
||||
result = 1;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
SCROLL_RULE_SIG(smooth_scroll_rule){
|
||||
Scroll_Velocity *velocity = scroll_velocity + view_id;
|
||||
int32_t result = 0;
|
||||
if (velocity->x == 0.f){
|
||||
velocity->x = 1.f;
|
||||
velocity->y = 1.f;
|
||||
}
|
||||
|
||||
if (smooth_camera_step(target_y, scroll_y, &velocity->y, 80.f, 1.f/2.f)){
|
||||
result = 1;
|
||||
}
|
||||
if (smooth_camera_step(target_x, scroll_x, &velocity->x, 80.f, 1.f/2.f)){
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static void
|
||||
set_all_default_hooks(Bind_Helper *context){
|
||||
set_hook(context, hook_start, default_start);
|
||||
set_hook(context, hook_exit, default_exit);
|
||||
set_hook(context, hook_view_size_change, default_view_adjust);
|
||||
|
||||
set_open_file_hook(context, default_file_settings);
|
||||
set_save_file_hook(context, default_file_save);
|
||||
set_command_caller(context, default_command_caller);
|
||||
set_input_filter(context, default_suppress_mouse_filter);
|
||||
set_scroll_rule(context, smooth_scroll_rule);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,23 @@
|
|||
/*
|
||||
4coder_function_list.cpp - Command for listing all functions in a C/C++ file in a jump list.
|
||||
|
||||
TYPE: 'drop-in-command-pack'
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#if !defined(FCODER_FUNCTION_LIST_CPP)
|
||||
#define FCODER_FUNCTION_LIST_CPP
|
||||
|
||||
#include "4coder_API/custom.h"
|
||||
|
||||
#include "4coder_default_framework.h"
|
||||
|
||||
#include "4coder_helper/4coder_helper.h"
|
||||
#include "4coder_helper/4coder_streaming.h"
|
||||
|
||||
#include "4coder_lib/4coder_mem.h"
|
||||
|
||||
// NOTE(allen|a4.0.14): This turned out to be a nasty little routine. There might
|
||||
// be a better way to do it with just tokens that I didn't see the first time
|
||||
// through. Once I build a real parser this should become almost just as easy as
|
||||
|
@ -10,7 +27,6 @@
|
|||
// will then provide the "list_all_functions_current_buffer" command.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// Declaration list
|
||||
//
|
||||
|
@ -278,5 +294,7 @@ CUSTOM_COMMAND_SIG(list_all_functions_current_buffer){
|
|||
list_all_functions(app, &global_part, &buffer);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -1,327 +1,337 @@
|
|||
/*
|
||||
* Miscellaneous helpers for common operations.
|
||||
*/
|
||||
|
||||
#if !defined(FCODER_HELPER_H)
|
||||
#define FCODER_HELPER_H
|
||||
|
||||
#include "4coder_seek_types.h"
|
||||
|
||||
inline void
|
||||
exec_command(Application_Links *app, Custom_Command_Function *func){
|
||||
func(app);
|
||||
}
|
||||
|
||||
inline void
|
||||
exec_command(Application_Links *app, Generic_Command cmd){
|
||||
if (cmd.cmdid < cmdid_count){
|
||||
exec_command(app, cmd.cmdid);
|
||||
}
|
||||
else{
|
||||
exec_command(app, cmd.command);
|
||||
}
|
||||
}
|
||||
|
||||
inline View_Summary
|
||||
get_first_view_with_buffer(Application_Links *app, int32_t buffer_id){
|
||||
View_Summary result = {};
|
||||
View_Summary test = {};
|
||||
|
||||
if (buffer_id != 0){
|
||||
uint32_t access = AccessAll;
|
||||
for(test = get_view_first(app, access);
|
||||
test.exists;
|
||||
get_view_next(app, &test, access)){
|
||||
|
||||
Buffer_Summary buffer = get_buffer(app, test.buffer_id, access);
|
||||
|
||||
if(buffer.buffer_id == buffer_id){
|
||||
result = test;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
key_is_unmodified(Key_Event_Data *key){
|
||||
char *mods = key->modifiers;
|
||||
int32_t unmodified = !mods[MDFR_CONTROL_INDEX] && !mods[MDFR_ALT_INDEX];
|
||||
return(unmodified);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
query_user_general(Application_Links *app, Query_Bar *bar, bool32 force_number){
|
||||
User_Input in;
|
||||
int32_t success = 1;
|
||||
int32_t good_character = 0;
|
||||
|
||||
// NOTE(allen|a3.4.4): It will not cause an *error* if we continue on after failing to.
|
||||
// start a query bar, but it will be unusual behavior from the point of view of the
|
||||
// user, if this command starts intercepting input even though no prompt is shown.
|
||||
// This will only happen if you have a lot of bars open already or if the current view
|
||||
// doesn't support query bars.
|
||||
if (start_query_bar(app, bar, 0) == 0) return 0;
|
||||
|
||||
for (;;){
|
||||
// NOTE(allen|a3.4.4): This call will block until the user does one of the input
|
||||
// types specified in the flags. The first set of flags are inputs you'd like to intercept
|
||||
// that you don't want to abort on. The second set are inputs that you'd like to cause
|
||||
// the command to abort. If an event satisfies both flags, it is treated as an abort.
|
||||
in = get_user_input(app, EventOnAnyKey, EventOnEsc | EventOnButton);
|
||||
|
||||
// NOTE(allen|a3.4.4): The responsible thing to do on abort is to end the command
|
||||
// without waiting on get_user_input again.
|
||||
if (in.abort){
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
good_character = 0;
|
||||
if (key_is_unmodified(&in.key)){
|
||||
if (force_number){
|
||||
if (in.key.character >= '0' && in.key.character <= '9'){
|
||||
good_character = 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (in.key.character != 0){
|
||||
good_character = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(allen|a3.4.4): All we have to do to update the query bar is edit our
|
||||
// local Query_Bar struct! This is handy because it means our Query_Bar
|
||||
// is always correct for typical use without extra work updating the bar.
|
||||
if (in.type == UserInputKey){
|
||||
if (in.key.keycode == '\n' || in.key.keycode == '\t'){
|
||||
break;
|
||||
}
|
||||
else if (in.key.keycode == key_back){
|
||||
if (bar->string.size > 0){
|
||||
--bar->string.size;
|
||||
}
|
||||
}
|
||||
else if (good_character){
|
||||
append_s_char(&bar->string, in.key.character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
terminate_with_null(&bar->string);
|
||||
|
||||
return(success);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
query_user_string(Application_Links *app, Query_Bar *bar){
|
||||
int32_t success = query_user_general(app, bar, false);
|
||||
return(success);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
query_user_number(Application_Links *app, Query_Bar *bar){
|
||||
int32_t success = query_user_general(app, bar, true);
|
||||
return(success);
|
||||
}
|
||||
|
||||
inline char
|
||||
buffer_get_char(Application_Links *app, Buffer_Summary *buffer, int32_t pos){
|
||||
char result = ' ';
|
||||
*buffer = get_buffer(app, buffer->buffer_id, AccessAll);
|
||||
if (pos >= 0 && pos < buffer->size){
|
||||
buffer_read_range(app, buffer, pos, pos+1, &result);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline Buffer_Identifier
|
||||
buffer_identifier(char *str, int32_t len){
|
||||
Buffer_Identifier identifier;
|
||||
identifier.name = str;
|
||||
identifier.name_len = len;
|
||||
identifier.id = 0;
|
||||
return(identifier);
|
||||
}
|
||||
|
||||
inline Buffer_Identifier
|
||||
buffer_identifier(int32_t id){
|
||||
Buffer_Identifier identifier;
|
||||
identifier.name = 0;
|
||||
identifier.name_len = 0;
|
||||
identifier.id = id;
|
||||
return(identifier);
|
||||
}
|
||||
|
||||
static Buffer_Summary
|
||||
create_buffer(Application_Links *app, char *filename, int32_t filename_len, Buffer_Create_Flag flags){
|
||||
Buffer_Summary buffer = {0};
|
||||
|
||||
Buffer_Creation_Data data = {0};
|
||||
begin_buffer_creation(app, &data, flags);
|
||||
buffer_creation_name(app, &data, filename, filename_len, 0);
|
||||
buffer = end_buffer_creation(app, &data);
|
||||
|
||||
return(buffer);
|
||||
}
|
||||
|
||||
inline Range
|
||||
make_range(int32_t p1, int32_t p2){
|
||||
Range range;
|
||||
if (p1 < p2){
|
||||
range.min = p1;
|
||||
range.max = p2;
|
||||
}
|
||||
else{
|
||||
range.min = p2;
|
||||
range.max = p1;
|
||||
}
|
||||
return(range);
|
||||
}
|
||||
|
||||
struct Buffer_Rect{
|
||||
int32_t char0, line0;
|
||||
int32_t char1, line1;
|
||||
};
|
||||
|
||||
#ifndef Swap
|
||||
#define Swap(T,a,b) do{ T t = a; a = b; b = t; } while(0)
|
||||
#endif
|
||||
|
||||
inline Buffer_Rect
|
||||
get_rect(View_Summary *view){
|
||||
Buffer_Rect rect = {0};
|
||||
|
||||
rect.char0 = view->mark.character;
|
||||
rect.line0 = view->mark.line;
|
||||
|
||||
rect.char1 = view->cursor.character;
|
||||
rect.line1 = view->cursor.line;
|
||||
|
||||
if (rect.line0 > rect.line1){
|
||||
Swap(int32_t, rect.line0, rect.line1);
|
||||
}
|
||||
if (rect.char0 > rect.char1){
|
||||
Swap(int32_t, rect.char0, rect.char1);
|
||||
}
|
||||
|
||||
return(rect);
|
||||
}
|
||||
|
||||
inline i32_Rect
|
||||
get_line_x_rect(View_Summary *view){
|
||||
i32_Rect rect = {0};
|
||||
|
||||
if (view->unwrapped_lines){
|
||||
rect.x0 = (int32_t)view->mark.unwrapped_x;
|
||||
rect.x1 = (int32_t)view->cursor.unwrapped_x;
|
||||
}
|
||||
else{
|
||||
rect.x0 = (int32_t)view->mark.wrapped_x;
|
||||
rect.x1 = (int32_t)view->cursor.wrapped_x;
|
||||
}
|
||||
rect.y0 = view->mark.line;
|
||||
rect.y1 = view->cursor.line;
|
||||
|
||||
if (rect.y0 > rect.y1){
|
||||
Swap(int32_t, rect.y0, rect.y1);
|
||||
}
|
||||
if (rect.x0 > rect.x1){
|
||||
Swap(int32_t, rect.x0, rect.x1);
|
||||
}
|
||||
|
||||
return(rect);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
open_file(Application_Links *app, Buffer_Summary *buffer_out, char *filename, int32_t filename_len, int32_t background, int32_t never_new){
|
||||
int32_t result = false;
|
||||
Buffer_Summary buffer = get_buffer_by_name(app, filename, filename_len, AccessProtected|AccessHidden);
|
||||
|
||||
if (buffer.exists){
|
||||
if (buffer_out) *buffer_out = buffer;
|
||||
result = true;
|
||||
}
|
||||
else{
|
||||
Buffer_Create_Flag flags = 0;
|
||||
if (background){
|
||||
flags |= BufferCreate_Background;
|
||||
}
|
||||
if (never_new){
|
||||
flags |= BufferCreate_NeverNew;
|
||||
}
|
||||
buffer = create_buffer(app, filename, filename_len, flags);
|
||||
if (buffer.exists){
|
||||
if (buffer_out) *buffer_out = buffer;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
view_open_file(Application_Links *app, View_Summary *view, char *filename, int32_t filename_len, int32_t never_new){
|
||||
int32_t result = 0;
|
||||
|
||||
if (view){
|
||||
Buffer_Summary buffer = {0};
|
||||
if (open_file(app, &buffer, filename, filename_len, false, never_new)){
|
||||
view_set_buffer(app, view, buffer.buffer_id, 0);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static void
|
||||
get_view_next_looped(Application_Links *app, View_Summary *view, uint32_t access){
|
||||
get_view_next(app, view, access);
|
||||
if (!view->exists){
|
||||
*view = get_view_first(app, access);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
refresh_buffer(Application_Links *app, Buffer_Summary *buffer){
|
||||
*buffer = get_buffer(app, buffer->buffer_id, AccessAll);
|
||||
}
|
||||
|
||||
static void
|
||||
refresh_view(Application_Links *app, View_Summary *view){
|
||||
*view = get_view(app, view->view_id, AccessAll);
|
||||
}
|
||||
|
||||
inline float
|
||||
get_view_y(View_Summary *view){
|
||||
float y = view->cursor.wrapped_y;
|
||||
if (view->unwrapped_lines){
|
||||
y = view->cursor.unwrapped_y;
|
||||
}
|
||||
return(y);
|
||||
}
|
||||
|
||||
inline float
|
||||
get_view_x(View_Summary *view){
|
||||
float x = view->cursor.wrapped_x;
|
||||
if (view->unwrapped_lines){
|
||||
x = view->cursor.unwrapped_x;
|
||||
}
|
||||
return(x);
|
||||
}
|
||||
|
||||
inline Range
|
||||
get_range(View_Summary *view){
|
||||
Range range = make_range(view->cursor.pos, view->mark.pos);
|
||||
return(range);
|
||||
}
|
||||
|
||||
#if !defined(ArrayCount)
|
||||
# define ArrayCount(a) (sizeof(a)/sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Miscellaneous helpers for common operations.
|
||||
*/
|
||||
|
||||
#if !defined(FCODER_HELPER_H)
|
||||
#define FCODER_HELPER_H
|
||||
|
||||
#include "4coder_seek_types.h"
|
||||
|
||||
inline void
|
||||
exec_command(Application_Links *app, Custom_Command_Function *func){
|
||||
func(app);
|
||||
}
|
||||
|
||||
inline void
|
||||
exec_command(Application_Links *app, Generic_Command cmd){
|
||||
if (cmd.cmdid < cmdid_count){
|
||||
exec_command(app, cmd.cmdid);
|
||||
}
|
||||
else{
|
||||
exec_command(app, cmd.command);
|
||||
}
|
||||
}
|
||||
|
||||
inline View_Summary
|
||||
get_first_view_with_buffer(Application_Links *app, int32_t buffer_id){
|
||||
View_Summary result = {};
|
||||
View_Summary test = {};
|
||||
|
||||
if (buffer_id != 0){
|
||||
uint32_t access = AccessAll;
|
||||
for(test = get_view_first(app, access);
|
||||
test.exists;
|
||||
get_view_next(app, &test, access)){
|
||||
|
||||
Buffer_Summary buffer = get_buffer(app, test.buffer_id, access);
|
||||
|
||||
if(buffer.buffer_id == buffer_id){
|
||||
result = test;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
key_is_unmodified(Key_Event_Data *key){
|
||||
char *mods = key->modifiers;
|
||||
int32_t unmodified = !mods[MDFR_CONTROL_INDEX] && !mods[MDFR_ALT_INDEX];
|
||||
return(unmodified);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
query_user_general(Application_Links *app, Query_Bar *bar, bool32 force_number){
|
||||
User_Input in;
|
||||
int32_t success = 1;
|
||||
int32_t good_character = 0;
|
||||
|
||||
// NOTE(allen|a3.4.4): It will not cause an *error* if we continue on after failing to.
|
||||
// start a query bar, but it will be unusual behavior from the point of view of the
|
||||
// user, if this command starts intercepting input even though no prompt is shown.
|
||||
// This will only happen if you have a lot of bars open already or if the current view
|
||||
// doesn't support query bars.
|
||||
if (start_query_bar(app, bar, 0) == 0) return 0;
|
||||
|
||||
for (;;){
|
||||
// NOTE(allen|a3.4.4): This call will block until the user does one of the input
|
||||
// types specified in the flags. The first set of flags are inputs you'd like to intercept
|
||||
// that you don't want to abort on. The second set are inputs that you'd like to cause
|
||||
// the command to abort. If an event satisfies both flags, it is treated as an abort.
|
||||
in = get_user_input(app, EventOnAnyKey, EventOnEsc | EventOnButton);
|
||||
|
||||
// NOTE(allen|a3.4.4): The responsible thing to do on abort is to end the command
|
||||
// without waiting on get_user_input again.
|
||||
if (in.abort){
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
good_character = 0;
|
||||
if (key_is_unmodified(&in.key)){
|
||||
if (force_number){
|
||||
if (in.key.character >= '0' && in.key.character <= '9'){
|
||||
good_character = 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (in.key.character != 0){
|
||||
good_character = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(allen|a3.4.4): All we have to do to update the query bar is edit our
|
||||
// local Query_Bar struct! This is handy because it means our Query_Bar
|
||||
// is always correct for typical use without extra work updating the bar.
|
||||
if (in.type == UserInputKey){
|
||||
if (in.key.keycode == '\n' || in.key.keycode == '\t'){
|
||||
break;
|
||||
}
|
||||
else if (in.key.keycode == key_back){
|
||||
if (bar->string.size > 0){
|
||||
--bar->string.size;
|
||||
}
|
||||
}
|
||||
else if (good_character){
|
||||
append_s_char(&bar->string, in.key.character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
terminate_with_null(&bar->string);
|
||||
|
||||
return(success);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
query_user_string(Application_Links *app, Query_Bar *bar){
|
||||
int32_t success = query_user_general(app, bar, false);
|
||||
return(success);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
query_user_number(Application_Links *app, Query_Bar *bar){
|
||||
int32_t success = query_user_general(app, bar, true);
|
||||
return(success);
|
||||
}
|
||||
|
||||
inline char
|
||||
buffer_get_char(Application_Links *app, Buffer_Summary *buffer, int32_t pos){
|
||||
char result = ' ';
|
||||
*buffer = get_buffer(app, buffer->buffer_id, AccessAll);
|
||||
if (pos >= 0 && pos < buffer->size){
|
||||
buffer_read_range(app, buffer, pos, pos+1, &result);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline Buffer_Identifier
|
||||
buffer_identifier(char *str, int32_t len){
|
||||
Buffer_Identifier identifier;
|
||||
identifier.name = str;
|
||||
identifier.name_len = len;
|
||||
identifier.id = 0;
|
||||
return(identifier);
|
||||
}
|
||||
|
||||
inline Buffer_Identifier
|
||||
buffer_identifier(int32_t id){
|
||||
Buffer_Identifier identifier;
|
||||
identifier.name = 0;
|
||||
identifier.name_len = 0;
|
||||
identifier.id = id;
|
||||
return(identifier);
|
||||
}
|
||||
|
||||
static Buffer_Summary
|
||||
create_buffer(Application_Links *app, char *filename, int32_t filename_len, Buffer_Create_Flag flags){
|
||||
Buffer_Summary buffer = {0};
|
||||
|
||||
Buffer_Creation_Data data = {0};
|
||||
begin_buffer_creation(app, &data, flags);
|
||||
buffer_creation_name(app, &data, filename, filename_len, 0);
|
||||
buffer = end_buffer_creation(app, &data);
|
||||
|
||||
return(buffer);
|
||||
}
|
||||
|
||||
inline Range
|
||||
make_range(int32_t p1, int32_t p2){
|
||||
Range range;
|
||||
if (p1 < p2){
|
||||
range.min = p1;
|
||||
range.max = p2;
|
||||
}
|
||||
else{
|
||||
range.min = p2;
|
||||
range.max = p1;
|
||||
}
|
||||
return(range);
|
||||
}
|
||||
|
||||
static void
|
||||
adjust_all_buffer_wrap_widths(Application_Links *app, int32_t wrap_width, 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_width);
|
||||
buffer_set_setting(app, &buffer, BufferSetting_MinimumBaseWrapPosition, min_base_width);
|
||||
}
|
||||
}
|
||||
|
||||
struct Buffer_Rect{
|
||||
int32_t char0, line0;
|
||||
int32_t char1, line1;
|
||||
};
|
||||
|
||||
#ifndef Swap
|
||||
#define Swap(T,a,b) do{ T t = a; a = b; b = t; } while(0)
|
||||
#endif
|
||||
|
||||
inline Buffer_Rect
|
||||
get_rect(View_Summary *view){
|
||||
Buffer_Rect rect = {0};
|
||||
|
||||
rect.char0 = view->mark.character;
|
||||
rect.line0 = view->mark.line;
|
||||
|
||||
rect.char1 = view->cursor.character;
|
||||
rect.line1 = view->cursor.line;
|
||||
|
||||
if (rect.line0 > rect.line1){
|
||||
Swap(int32_t, rect.line0, rect.line1);
|
||||
}
|
||||
if (rect.char0 > rect.char1){
|
||||
Swap(int32_t, rect.char0, rect.char1);
|
||||
}
|
||||
|
||||
return(rect);
|
||||
}
|
||||
|
||||
inline i32_Rect
|
||||
get_line_x_rect(View_Summary *view){
|
||||
i32_Rect rect = {0};
|
||||
|
||||
if (view->unwrapped_lines){
|
||||
rect.x0 = (int32_t)view->mark.unwrapped_x;
|
||||
rect.x1 = (int32_t)view->cursor.unwrapped_x;
|
||||
}
|
||||
else{
|
||||
rect.x0 = (int32_t)view->mark.wrapped_x;
|
||||
rect.x1 = (int32_t)view->cursor.wrapped_x;
|
||||
}
|
||||
rect.y0 = view->mark.line;
|
||||
rect.y1 = view->cursor.line;
|
||||
|
||||
if (rect.y0 > rect.y1){
|
||||
Swap(int32_t, rect.y0, rect.y1);
|
||||
}
|
||||
if (rect.x0 > rect.x1){
|
||||
Swap(int32_t, rect.x0, rect.x1);
|
||||
}
|
||||
|
||||
return(rect);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
open_file(Application_Links *app, Buffer_Summary *buffer_out, char *filename, int32_t filename_len, int32_t background, int32_t never_new){
|
||||
int32_t result = false;
|
||||
Buffer_Summary buffer = get_buffer_by_name(app, filename, filename_len, AccessProtected|AccessHidden);
|
||||
|
||||
if (buffer.exists){
|
||||
if (buffer_out) *buffer_out = buffer;
|
||||
result = true;
|
||||
}
|
||||
else{
|
||||
Buffer_Create_Flag flags = 0;
|
||||
if (background){
|
||||
flags |= BufferCreate_Background;
|
||||
}
|
||||
if (never_new){
|
||||
flags |= BufferCreate_NeverNew;
|
||||
}
|
||||
buffer = create_buffer(app, filename, filename_len, flags);
|
||||
if (buffer.exists){
|
||||
if (buffer_out) *buffer_out = buffer;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
view_open_file(Application_Links *app, View_Summary *view, char *filename, int32_t filename_len, int32_t never_new){
|
||||
int32_t result = 0;
|
||||
|
||||
if (view){
|
||||
Buffer_Summary buffer = {0};
|
||||
if (open_file(app, &buffer, filename, filename_len, false, never_new)){
|
||||
view_set_buffer(app, view, buffer.buffer_id, 0);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static void
|
||||
get_view_next_looped(Application_Links *app, View_Summary *view, uint32_t access){
|
||||
get_view_next(app, view, access);
|
||||
if (!view->exists){
|
||||
*view = get_view_first(app, access);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
refresh_buffer(Application_Links *app, Buffer_Summary *buffer){
|
||||
*buffer = get_buffer(app, buffer->buffer_id, AccessAll);
|
||||
}
|
||||
|
||||
static void
|
||||
refresh_view(Application_Links *app, View_Summary *view){
|
||||
*view = get_view(app, view->view_id, AccessAll);
|
||||
}
|
||||
|
||||
inline float
|
||||
get_view_y(View_Summary *view){
|
||||
float y = view->cursor.wrapped_y;
|
||||
if (view->unwrapped_lines){
|
||||
y = view->cursor.unwrapped_y;
|
||||
}
|
||||
return(y);
|
||||
}
|
||||
|
||||
inline float
|
||||
get_view_x(View_Summary *view){
|
||||
float x = view->cursor.wrapped_x;
|
||||
if (view->unwrapped_lines){
|
||||
x = view->cursor.unwrapped_x;
|
||||
}
|
||||
return(x);
|
||||
}
|
||||
|
||||
inline Range
|
||||
get_range(View_Summary *view){
|
||||
Range range = make_range(view->cursor.pos, view->mark.pos);
|
||||
return(range);
|
||||
}
|
||||
|
||||
#if !defined(ArrayCount)
|
||||
# define ArrayCount(a) (sizeof(a)/sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -884,7 +884,7 @@ read_line(Application_Links *app, Partition *part, Buffer_Summary *buffer, int32
|
|||
int32_t success = 0;
|
||||
|
||||
if (buffer_compute_cursor(app, buffer, seek_line_char(line, 1), &begin)){
|
||||
if (buffer_compute_cursor(app, buffer, seek_line_char(line, 65536), &end)){
|
||||
if (buffer_compute_cursor(app, buffer, seek_line_char(line, -1), &end)){
|
||||
if (begin.line == line){
|
||||
if (0 <= begin.pos && begin.pos <= end.pos && end.pos <= buffer->size){
|
||||
int32_t size = (end.pos - begin.pos);
|
||||
|
@ -919,7 +919,7 @@ buffer_get_line_end(Application_Links *app, Buffer_Summary *buffer, int32_t line
|
|||
Partial_Cursor partial_cursor;
|
||||
int32_t result = buffer->size;
|
||||
if (line <= buffer->line_count){
|
||||
buffer_compute_cursor(app, buffer, seek_line_char(line, 65536), &partial_cursor);
|
||||
buffer_compute_cursor(app, buffer, seek_line_char(line, -1), &partial_cursor);
|
||||
result = partial_cursor.pos;
|
||||
}
|
||||
return(result);
|
||||
|
@ -931,7 +931,7 @@ buffer_line_is_blank(Application_Links *app, Buffer_Summary *buffer, int32_t lin
|
|||
bool32 result = 0;
|
||||
if (line <= buffer->line_count){
|
||||
buffer_compute_cursor(app, buffer, seek_line_char(line, 1), &start);
|
||||
buffer_compute_cursor(app, buffer, seek_line_char(line, 65536), &end);
|
||||
buffer_compute_cursor(app, buffer, seek_line_char(line, -1), &end);
|
||||
|
||||
static const int32_t chunk_size = 1024;
|
||||
char chunk[chunk_size];
|
||||
|
|
|
@ -22,13 +22,6 @@ typedef struct Name_Based_Jump_Location{
|
|||
int32_t column;
|
||||
} Name_Based_Jump_Location;
|
||||
|
||||
typedef struct ID_Based_Jump_Location{
|
||||
int32_t buffer_id;
|
||||
int32_t line;
|
||||
int32_t column;
|
||||
} ID_Based_Jump_Location;
|
||||
static ID_Based_Jump_Location null_location = {0};
|
||||
|
||||
static void
|
||||
jump_to_location(Application_Links *app, View_Summary *view, Name_Based_Jump_Location *l){
|
||||
if (view_open_file(app, view, l->file.str, l->file.size, true)){
|
||||
|
@ -55,8 +48,9 @@ static int32_t
|
|||
parse_jump_location(String line, Name_Based_Jump_Location *location, int32_t skip_sub_errors, int32_t *colon_char){
|
||||
int32_t result = false;
|
||||
|
||||
int32_t whitespace_length = 0;
|
||||
String original_line = line;
|
||||
line = skip_chop_whitespace(line);
|
||||
line = skip_chop_whitespace(line, &whitespace_length);
|
||||
|
||||
int32_t colon_pos = 0;
|
||||
int32_t is_ms_style = 0;
|
||||
|
@ -102,7 +96,7 @@ parse_jump_location(String line, Name_Based_Jump_Location *location, int32_t ski
|
|||
location->column = 1;
|
||||
}
|
||||
|
||||
*colon_char = colon_pos;
|
||||
*colon_char = colon_pos + whitespace_length;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +131,7 @@ parse_jump_location(String line, Name_Based_Jump_Location *location, int32_t ski
|
|||
location->file = filename;
|
||||
location->line = str_to_int_s(line_number);
|
||||
location->column = str_to_int_s(column_number);
|
||||
*colon_char = colon_pos3;
|
||||
*colon_char = colon_pos3 + whitespace_length;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
@ -151,7 +145,7 @@ parse_jump_location(String line, Name_Based_Jump_Location *location, int32_t ski
|
|||
location->file = filename;
|
||||
location->line = str_to_int_s(line_number);
|
||||
location->column = 0;
|
||||
*colon_char = colon_pos2;
|
||||
*colon_char = colon_pos2 + whitespace_length;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
@ -253,9 +247,7 @@ seek_next_jump_in_view(Application_Links *app, Partition *part, View_Summary *vi
|
|||
Name_Based_Jump_Location location = {0};
|
||||
int32_t line = view->cursor.line;
|
||||
int32_t colon_index = 0;
|
||||
if (seek_next_jump_in_buffer(app, part, view->buffer_id,
|
||||
line+direction, skip_sub_errors, direction,
|
||||
&line, &colon_index, &location)){
|
||||
if (seek_next_jump_in_buffer(app, part, view->buffer_id, line+direction, skip_sub_errors, direction, &line, &colon_index, &location)){
|
||||
result = true;
|
||||
*line_out = line;
|
||||
*colon_index_out = colon_index;
|
||||
|
@ -277,8 +269,6 @@ skip_this_jump(ID_Based_Jump_Location prev, ID_Based_Jump_Location jump){
|
|||
return(result);
|
||||
}
|
||||
|
||||
static ID_Based_Jump_Location prev_location = {0};
|
||||
|
||||
static int32_t
|
||||
advance_cursor_in_jump_view(Application_Links *app, Partition *part, View_Summary *view, int32_t skip_repeats, int32_t skip_sub_error, int32_t direction, Name_Based_Jump_Location *location_out){
|
||||
int32_t result = true;
|
||||
|
@ -289,10 +279,9 @@ advance_cursor_in_jump_view(Application_Links *app, Partition *part, View_Summar
|
|||
|
||||
do{
|
||||
Temp_Memory temp = begin_temp_memory(part);
|
||||
if (seek_next_jump_in_view(app, part, view,
|
||||
skip_sub_error, direction,
|
||||
&line, &colon_index, &location)){
|
||||
if (seek_next_jump_in_view(app, part, view, skip_sub_error, direction, &line, &colon_index, &location)){
|
||||
jump = convert_name_based_to_id_based(app, location);
|
||||
view_set_cursor(app, view, seek_line_char(line, colon_index+1), true);
|
||||
result = true;
|
||||
}
|
||||
else{
|
||||
|
@ -313,16 +302,14 @@ advance_cursor_in_jump_view(Application_Links *app, Partition *part, View_Summar
|
|||
}
|
||||
|
||||
static int32_t
|
||||
seek_error(Application_Links *app, Partition *part, int32_t skip_repeats, int32_t skip_sub_errors, int32_t direction){
|
||||
seek_jump(Application_Links *app, Partition *part, int32_t skip_repeats, int32_t skip_sub_errors, int32_t direction){
|
||||
int32_t result = 0;
|
||||
|
||||
View_Summary view = get_view_for_locked_jump_buffer(app);
|
||||
if (view.exists){
|
||||
|
||||
Name_Based_Jump_Location location = {0};
|
||||
if (advance_cursor_in_jump_view(app, &global_part, &view,
|
||||
skip_repeats, skip_sub_errors, direction,
|
||||
&location)){
|
||||
if (advance_cursor_in_jump_view(app, &global_part, &view, skip_repeats, skip_sub_errors, direction, &location)){
|
||||
View_Summary active_view = get_active_view(app, AccessAll);
|
||||
if (active_view.view_id == view.view_id){
|
||||
exec_command(app, change_active_panel);
|
||||
|
@ -342,28 +329,28 @@ CUSTOM_COMMAND_SIG(goto_next_jump){
|
|||
int32_t skip_repeats = true;
|
||||
int32_t skip_sub_errors = true;
|
||||
int32_t dir = 1;
|
||||
seek_error(app, &global_part, skip_repeats, skip_sub_errors, dir);
|
||||
seek_jump(app, &global_part, skip_repeats, skip_sub_errors, dir);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(goto_prev_jump){
|
||||
int32_t skip_repeats = true;
|
||||
int32_t skip_sub_errors = true;
|
||||
int32_t dir = -1;
|
||||
seek_error(app, &global_part, skip_repeats, skip_sub_errors, dir);
|
||||
seek_jump(app, &global_part, skip_repeats, skip_sub_errors, dir);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(goto_next_jump_no_skips){
|
||||
int32_t skip_repeats = false;
|
||||
int32_t skip_sub_errors = true;
|
||||
int32_t dir = 1;
|
||||
seek_error(app, &global_part, skip_repeats, skip_sub_errors, dir);
|
||||
seek_jump(app, &global_part, skip_repeats, skip_sub_errors, dir);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(goto_prev_jump_no_skips){
|
||||
int32_t skip_repeats = false;
|
||||
int32_t skip_sub_errors = true;
|
||||
int32_t dir = -1;
|
||||
seek_error(app, &global_part, skip_repeats, skip_sub_errors, dir);
|
||||
seek_jump(app, &global_part, skip_repeats, skip_sub_errors, dir);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(goto_first_jump){
|
||||
|
@ -374,11 +361,29 @@ CUSTOM_COMMAND_SIG(goto_first_jump){
|
|||
view_set_cursor(app, &view, seek_pos(0), true);
|
||||
|
||||
prev_location = null_location;
|
||||
seek_error(app, &global_part, false, true, 1);
|
||||
seek_jump(app, &global_part, false, true, 1);
|
||||
}
|
||||
end_temp_memory(temp);
|
||||
}
|
||||
|
||||
//
|
||||
// Insert Newline - or Tigger Jump on Read Only Buffer
|
||||
//
|
||||
|
||||
CUSTOM_COMMAND_SIG(newline_or_goto_position){
|
||||
View_Summary view = get_active_view(app, AccessProtected);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessProtected);
|
||||
|
||||
if (buffer.lock_flags & AccessProtected){
|
||||
exec_command(app, goto_jump_at_cursor);
|
||||
lock_jump_buffer(buffer);
|
||||
}
|
||||
else{
|
||||
exec_command(app, write_character);
|
||||
}
|
||||
}
|
||||
|
||||
#define seek_error seek_jump
|
||||
#define goto_next_error goto_next_jump
|
||||
#define goto_prev_error goto_prev_jump
|
||||
#define goto_next_error_no_skips goto_next_jump_no_skips
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
4coder_string.h - Version 1.0.14
|
||||
4coder_string.h - Version 1.0.59
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
This software is in the public domain. Where that dedication is not
|
||||
|
@ -94,8 +94,10 @@ FSTRING_INLINE String make_string_slowly(void *str);
|
|||
FSTRING_INLINE String substr_tail(String str, i32_4tech start);
|
||||
FSTRING_INLINE String substr(String str, i32_4tech start, i32_4tech size);
|
||||
FSTRING_LINK String skip_whitespace(String str);
|
||||
FSTRING_LINK String skip_whitespace_measure(String str, i32_4tech *skip_length);
|
||||
FSTRING_LINK String chop_whitespace(String str);
|
||||
FSTRING_LINK String skip_chop_whitespace(String str);
|
||||
FSTRING_LINK String skip_chop_whitespace_measure(String str, i32_4tech *skip_length);
|
||||
FSTRING_INLINE String tailstr(String str);
|
||||
FSTRING_LINK b32_4tech match_cc(char *a, char *b);
|
||||
FSTRING_LINK b32_4tech match_sc(String a, char *b);
|
||||
|
@ -199,6 +201,8 @@ FSTRING_LINK String get_first_word(String source);
|
|||
|
||||
FSTRING_INLINE String make_string(void *str, i32_4tech size, i32_4tech mem_size){return(make_string_cap(str,size,mem_size));}
|
||||
FSTRING_INLINE String substr(String str, i32_4tech start){return(substr_tail(str,start));}
|
||||
FSTRING_LINK String skip_whitespace(String str, i32_4tech *skip_length){return(skip_whitespace_measure(str,skip_length));}
|
||||
FSTRING_LINK String skip_chop_whitespace(String str, i32_4tech *skip_length){return(skip_chop_whitespace_measure(str,skip_length));}
|
||||
FSTRING_LINK b32_4tech match(char *a, char *b){return(match_cc(a,b));}
|
||||
FSTRING_LINK b32_4tech match(String a, char *b){return(match_sc(a,b));}
|
||||
FSTRING_INLINE b32_4tech match(char *a, String b){return(match_cs(a,b));}
|
||||
|
@ -460,6 +464,20 @@ skip_whitespace(String str)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(FSTRING_IMPLEMENTATION)
|
||||
FSTRING_LINK String
|
||||
skip_whitespace_measure(String str, i32_4tech *skip_length)
|
||||
{
|
||||
String result = {0};
|
||||
i32_4tech i = 0;
|
||||
for (; i < str.size && char_is_whitespace(str.str[i]); ++i);
|
||||
result = substr(str, i, str.size - i);
|
||||
*skip_length = i;
|
||||
return(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FSTRING_IMPLEMENTATION)
|
||||
FSTRING_LINK String
|
||||
chop_whitespace(String str)
|
||||
|
@ -482,6 +500,17 @@ skip_chop_whitespace(String str)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(FSTRING_IMPLEMENTATION)
|
||||
FSTRING_LINK String
|
||||
skip_chop_whitespace_measure(String str, i32_4tech *skip_length)
|
||||
{
|
||||
str = skip_whitespace_measure(str, skip_length);
|
||||
str = chop_whitespace(str);
|
||||
return(str);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(FSTRING_GUARD)
|
||||
FSTRING_INLINE String
|
||||
tailstr(String str)
|
||||
|
@ -2031,7 +2060,7 @@ static void
|
|||
get_absolutes(String name, Absolutes *absolutes, b32_4tech implicit_first, b32_4tech implicit_last){
|
||||
if (name.size != 0){
|
||||
i32_4tech count = 0;
|
||||
i32_4tech max = sizeof(absolutes->a)/sizeof(absolutes->a[0]) - 1;
|
||||
i32_4tech max = (sizeof(absolutes->a)/sizeof(*absolutes->a)) - 1;
|
||||
if (implicit_last) --max;
|
||||
|
||||
String str;
|
||||
|
|
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
4coder_project_commands.cpp - Commands for loading and using a project.
|
||||
|
||||
TYPE: 'drop-in-command-pack'
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#if !defined(FCODER_PROJECT_COMMANDS_CPP)
|
||||
#define FCODER_PROJECT_COMMANDS_CPP
|
||||
|
||||
#include "4coder_default_framework.h"
|
||||
#include "4coder_lib/4coder_mem.h"
|
||||
|
||||
#include "4coder_build_commands.cpp"
|
||||
|
||||
// TODO(allen): make this a string operation or a lexer operation or something
|
||||
static void
|
||||
interpret_escaped_string(char *dst, String src){
|
||||
int32_t mode = 0;
|
||||
int32_t j = 0;
|
||||
for (int32_t i = 0; i < src.size; ++i){
|
||||
switch (mode){
|
||||
case 0:
|
||||
{
|
||||
if (src.str[i] == '\\'){
|
||||
mode = 1;
|
||||
}
|
||||
else{
|
||||
dst[j++] = src.str[i];
|
||||
}
|
||||
}break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
switch (src.str[i]){
|
||||
case '\\':{dst[j++] = '\\'; mode = 0;}break;
|
||||
case 'n': {dst[j++] = '\n'; mode = 0;}break;
|
||||
case 't': {dst[j++] = '\t'; mode = 0;}break;
|
||||
case '"': {dst[j++] = '"'; mode = 0;}break;
|
||||
case '0': {dst[j++] = '\0'; mode = 0;}break;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
dst[j] = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
close_all_files_with_extension(Application_Links *app, Partition *scratch_part, char **extension_list, int32_t extension_count){
|
||||
Temp_Memory temp = begin_temp_memory(scratch_part);
|
||||
|
||||
int32_t buffers_to_close_max = partition_remaining(scratch_part)/sizeof(int32_t);
|
||||
int32_t *buffers_to_close = push_array(scratch_part, int32_t, buffers_to_close_max);
|
||||
|
||||
int32_t buffers_to_close_count = 0;
|
||||
bool32 do_repeat = 0;
|
||||
do{
|
||||
buffers_to_close_count = 0;
|
||||
do_repeat = 0;
|
||||
|
||||
uint32_t access = AccessAll;
|
||||
Buffer_Summary buffer = {0};
|
||||
for (buffer = get_buffer_first(app, access);
|
||||
buffer.exists;
|
||||
get_buffer_next(app, &buffer, access)){
|
||||
|
||||
bool32 is_match = 1;
|
||||
if (extension_count > 0){
|
||||
String extension = file_extension(make_string(buffer.file_name, buffer.file_name_len));
|
||||
is_match = 0;
|
||||
for (int32_t i = 0; i < extension_count; ++i){
|
||||
if (match(extension, extension_list[i])){
|
||||
is_match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_match){
|
||||
if (buffers_to_close_count >= buffers_to_close_max){
|
||||
do_repeat = 1;
|
||||
break;
|
||||
}
|
||||
buffers_to_close[buffers_to_close_count++] = buffer.buffer_id;
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < buffers_to_close_count; ++i){
|
||||
kill_buffer(app, buffer_identifier(buffers_to_close[i]), true, 0);
|
||||
}
|
||||
}
|
||||
while(do_repeat);
|
||||
|
||||
end_temp_memory(temp);
|
||||
}
|
||||
|
||||
static void
|
||||
open_all_files_with_extension(Application_Links *app, Partition *scratch_part, char **extension_list, int32_t extension_count){
|
||||
Temp_Memory temp = begin_temp_memory(scratch_part);
|
||||
|
||||
int32_t max_size = partition_remaining(scratch_part);
|
||||
char *memory = push_array(scratch_part, char, max_size);
|
||||
|
||||
String dir = make_string_cap(memory, 0, max_size);
|
||||
dir.size = directory_get_hot(app, dir.str, dir.memory_size);
|
||||
int32_t dir_size = dir.size;
|
||||
|
||||
// NOTE(allen|a3.4.4): Here we get the list of files in this directory.
|
||||
// Notice that we free_file_list at the end.
|
||||
File_List list = get_file_list(app, dir.str, dir.size);
|
||||
|
||||
for (int32_t i = 0; i < list.count; ++i){
|
||||
File_Info *info = list.infos + i;
|
||||
if (!info->folder){
|
||||
bool32 is_match = 1;
|
||||
|
||||
if (extension_count > 0){
|
||||
is_match = 0;
|
||||
|
||||
String extension = make_string_cap(info->filename, info->filename_len, info->filename_len+1);
|
||||
extension = file_extension(extension);
|
||||
for (int32_t j = 0; j < extension_count; ++j){
|
||||
if (match(extension, extension_list[j])){
|
||||
is_match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_match){
|
||||
// NOTE(allen): There's no way in the 4coder API to use relative
|
||||
// paths at the moment, so everything should be full paths. Which is
|
||||
// managable. Here simply set the dir string size back to where it
|
||||
// was originally, so that new appends overwrite old ones.
|
||||
dir.size = dir_size;
|
||||
append_sc(&dir, info->filename);
|
||||
create_buffer(app, dir.str, dir.size, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_file_list(app, list);
|
||||
|
||||
end_temp_memory(temp);
|
||||
}
|
||||
|
||||
// NOTE(allen|a4.0.14): open_all_code and close_all_code now use the extensions set in the loaded project. If there is no project loaded the extensions ".cpp.hpp.c.h.cc" are used.
|
||||
CUSTOM_COMMAND_SIG(open_all_code){
|
||||
int32_t extension_count = 0;
|
||||
char **extension_list = get_current_code_extensions(&extension_count);
|
||||
open_all_files_with_extension(app, &global_part, extension_list, extension_count);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(close_all_code){
|
||||
int32_t extension_count = 0;
|
||||
char **extension_list = get_current_code_extensions(&extension_count);
|
||||
close_all_files_with_extension(app, &global_part, extension_list, extension_count);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(load_project){
|
||||
Partition *part = &global_part;
|
||||
|
||||
char project_file_space[512];
|
||||
String project_name = make_fixed_width_string(project_file_space);
|
||||
project_name.size = directory_get_hot(app, project_name.str, project_name.memory_size);
|
||||
if (project_name.size >= project_name.memory_size){
|
||||
project_name.size = 0;
|
||||
}
|
||||
|
||||
if (project_name.size != 0){
|
||||
int32_t original_size = project_name.size;
|
||||
append_sc(&project_name, "project.4coder");
|
||||
terminate_with_null(&project_name);
|
||||
|
||||
FILE *file = fopen(project_name.str, "rb");
|
||||
if (file){
|
||||
project_name.size = original_size;
|
||||
terminate_with_null(&project_name);
|
||||
|
||||
Temp_Memory temp = begin_temp_memory(part);
|
||||
|
||||
char *mem = 0;
|
||||
int32_t size = 0;
|
||||
bool32 file_read_success = file_handle_dump(part, file, &mem, &size);
|
||||
if (file_read_success){
|
||||
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+1, HAS_NULL_TERM, &array, NO_OUT_LIMIT);
|
||||
|
||||
if (result == LexResult_Finished){
|
||||
// Clear out current project
|
||||
if (current_project.close_all_code_when_this_project_closes){
|
||||
exec_command(app, close_all_code);
|
||||
}
|
||||
current_project = null_project;
|
||||
|
||||
// Set new project directory
|
||||
{
|
||||
current_project.dir = current_project.dir_space;
|
||||
String str = make_fixed_width_string(current_project.dir_space);
|
||||
copy(&str, project_name);
|
||||
terminate_with_null(&str);
|
||||
current_project.dir_len = str.size;
|
||||
}
|
||||
|
||||
// Read the settings from project.4coder
|
||||
for (int32_t i = 0; i < array.count; ++i){
|
||||
Config_Line config_line = read_config_line(array, &i);
|
||||
if (config_line.read_success){
|
||||
Config_Item item = get_config_item(config_line, mem, array);
|
||||
|
||||
{
|
||||
String str = {0};
|
||||
if (config_string_var(item, "extensions", 0, &str)){
|
||||
if (str.size < sizeof(current_project.extension_space)){
|
||||
set_project_extensions(¤t_project, str);
|
||||
print_message(app, str.str, str.size);
|
||||
print_message(app, "\n", 1);
|
||||
}
|
||||
else{
|
||||
print_message(app, literal("STRING TOO LONG!\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
#define FKEY_COMMAND "fkey_command_win"
|
||||
#elif defined(__linux__)
|
||||
#define FKEY_COMMAND "fkey_command_linux"
|
||||
#else
|
||||
#error no project configuration names for this platform
|
||||
#endif
|
||||
|
||||
int32_t index = 0;
|
||||
Config_Array_Reader array_reader = {0};
|
||||
if (config_array_var(item, FKEY_COMMAND, &index, &array_reader)){
|
||||
if (index >= 1 && index <= 16){
|
||||
Config_Item array_item = {0};
|
||||
int32_t item_index = 0;
|
||||
|
||||
char space[256];
|
||||
String msg = make_fixed_width_string(space);
|
||||
append(&msg, FKEY_COMMAND"[");
|
||||
append_int_to_str(&msg, index);
|
||||
append(&msg, "] = {");
|
||||
|
||||
for (config_array_next_item(&array_reader, &array_item);
|
||||
config_array_good(&array_reader);
|
||||
config_array_next_item(&array_reader, &array_item)){
|
||||
|
||||
if (item_index >= 3){
|
||||
break;
|
||||
}
|
||||
|
||||
append(&msg, "[");
|
||||
append_int_to_str(&msg, item_index);
|
||||
append(&msg, "] = ");
|
||||
|
||||
bool32 read_string = 0;
|
||||
bool32 read_bool = 0;
|
||||
|
||||
char *dest_str = 0;
|
||||
int32_t dest_str_size = 0;
|
||||
|
||||
bool32 *dest_bool = 0;
|
||||
|
||||
switch (item_index){
|
||||
case 0:
|
||||
{
|
||||
dest_str = current_project.fkey_commands[index-1].command;
|
||||
dest_str_size = sizeof(current_project.fkey_commands[index-1].command);
|
||||
read_string = 1;
|
||||
}break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
dest_str = current_project.fkey_commands[index-1].out;
|
||||
dest_str_size = sizeof(current_project.fkey_commands[index-1].out);
|
||||
read_string = 1;
|
||||
}break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
dest_bool = ¤t_project.fkey_commands[index-1].use_build_panel;
|
||||
read_bool = 1;
|
||||
}break;
|
||||
}
|
||||
|
||||
if (read_string){
|
||||
if (config_int_var(array_item, 0, 0, 0)){
|
||||
append(&msg, "NULL, ");
|
||||
dest_str[0] = 0;
|
||||
}
|
||||
|
||||
String str = {0};
|
||||
if (config_string_var(array_item, 0, 0, &str)){
|
||||
if (str.size < dest_str_size){
|
||||
interpret_escaped_string(dest_str, str);
|
||||
append(&msg, dest_str);
|
||||
append(&msg, ", ");
|
||||
}
|
||||
else{
|
||||
append(&msg, "STRING TOO LONG!, ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (read_bool){
|
||||
if (config_bool_var(array_item, 0, 0, dest_bool)){
|
||||
if (dest_bool){
|
||||
append(&msg, "true, ");
|
||||
}
|
||||
else{
|
||||
append(&msg, "false, ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item_index++;
|
||||
}
|
||||
|
||||
append(&msg, "}\n");
|
||||
print_message(app, msg.str, msg.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current_project.close_all_files_when_project_opens){
|
||||
close_all_files_with_extension(app, &global_part, 0, 0);
|
||||
}
|
||||
|
||||
// Open all project files
|
||||
exec_command(app, open_all_code);
|
||||
}
|
||||
}
|
||||
|
||||
end_temp_memory(temp);
|
||||
}
|
||||
else{
|
||||
char message_space[512];
|
||||
String message = make_fixed_width_string(message_space);
|
||||
append_sc(&message, "Did not find project.4coder. ");
|
||||
if (current_project.dir != 0){
|
||||
append_sc(&message, "Continuing with: ");
|
||||
append_sc(&message, current_project.dir);
|
||||
}
|
||||
else{
|
||||
append_sc(&message, "Continuing without a project");
|
||||
}
|
||||
print_message(app, message.str, message.size);
|
||||
}
|
||||
}
|
||||
else{
|
||||
print_message(app, literal("Failed trying to get project file name"));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exec_project_fkey_command(Application_Links *app, int32_t command_ind){
|
||||
char *command = current_project.fkey_commands[command_ind].command;
|
||||
char *out = current_project.fkey_commands[command_ind].out;
|
||||
bool32 use_build_panel = current_project.fkey_commands[command_ind].use_build_panel;
|
||||
|
||||
if (command[0] != 0){
|
||||
int32_t command_len = str_size(command);
|
||||
|
||||
View_Summary view_ = {0};
|
||||
View_Summary *view = 0;
|
||||
Buffer_Identifier buffer_id = {0};
|
||||
uint32_t flags = 0;
|
||||
|
||||
bool32 set_fancy_font = 0;
|
||||
|
||||
if (out[0] != 0){
|
||||
int32_t out_len = str_size(out);
|
||||
buffer_id = buffer_identifier(out, out_len);
|
||||
|
||||
view = &view_;
|
||||
|
||||
if (use_build_panel){
|
||||
view_ = get_or_open_build_panel(app);
|
||||
if (match(out, "*compilation*")){
|
||||
set_fancy_font = 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
view_ = get_active_view(app, AccessAll);
|
||||
}
|
||||
|
||||
prev_location = null_location;
|
||||
lock_jump_buffer(out, out_len);
|
||||
}
|
||||
else{
|
||||
// TODO(allen): fix the exec_system_command call so it can take a null buffer_id.
|
||||
buffer_id = buffer_identifier(literal("*dump*"));
|
||||
}
|
||||
|
||||
exec_system_command(app, view, buffer_id, current_project.dir, current_project.dir_len, command, command_len, flags);
|
||||
if (set_fancy_font){
|
||||
set_fancy_compilation_buffer_font(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(project_fkey_command){
|
||||
User_Input input = get_command_input(app);
|
||||
if (input.type == UserInputKey){
|
||||
if (input.key.keycode >= key_f1 && input.key.keycode <= key_f16){
|
||||
int32_t ind = (input.key.keycode - key_f1);
|
||||
exec_project_fkey_command(app, ind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
4coder_system_command.cpp - Commands for executing arbitrary system command line instructions.
|
||||
|
||||
TYPE: 'drop-in-command-pack'
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#if !defined(FCODER_SYSTEM_COMMAND_CPP)
|
||||
#define FCODER_SYSTEM_COMMAND_CPP
|
||||
|
||||
#include "4coder_default_framework.h"
|
||||
|
||||
CUSTOM_COMMAND_SIG(execute_any_cli){
|
||||
Query_Bar bar_out = {0};
|
||||
Query_Bar bar_cmd = {0};
|
||||
|
||||
bar_out.prompt = make_lit_string("Output Buffer: ");
|
||||
bar_out.string = make_fixed_width_string(out_buffer_space);
|
||||
if (!query_user_string(app, &bar_out)) return;
|
||||
|
||||
bar_cmd.prompt = make_lit_string("Command: ");
|
||||
bar_cmd.string = make_fixed_width_string(command_space);
|
||||
if (!query_user_string(app, &bar_cmd)) return;
|
||||
|
||||
String hot_directory = make_fixed_width_string(hot_directory_space);
|
||||
hot_directory.size = directory_get_hot(app, hot_directory.str, hot_directory.memory_size);
|
||||
|
||||
uint32_t access = AccessAll;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
|
||||
exec_system_command(app, &view, buffer_identifier(bar_out.string.str, bar_out.string.size), hot_directory.str, hot_directory.size, bar_cmd.string.str, bar_cmd.string.size, CLI_OverlapWithConflict | CLI_CursorAtEnd);
|
||||
lock_jump_buffer(bar_out.string.str, bar_out.string.size);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(execute_previous_cli){
|
||||
String out_buffer = make_string_slowly(out_buffer_space);
|
||||
String cmd = make_string_slowly(command_space);
|
||||
String hot_directory = make_string_slowly(hot_directory_space);
|
||||
|
||||
if (out_buffer.size > 0 && cmd.size > 0 && hot_directory.size > 0){
|
||||
uint32_t access = AccessAll;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
|
||||
exec_system_command(app, &view, buffer_identifier(out_buffer.str, out_buffer.size), hot_directory.str, hot_directory.size, cmd.str, cmd.size, CLI_OverlapWithConflict | CLI_CursorAtEnd);
|
||||
lock_jump_buffer(out_buffer.str, out_buffer.size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
60
4ed.cpp
60
4ed.cpp
|
@ -62,22 +62,22 @@ typedef struct Consumption_Record{
|
|||
} Consumption_Record;
|
||||
|
||||
typedef struct Available_Input{
|
||||
Key_Summary *keys;
|
||||
Key_Input_Data *keys;
|
||||
Mouse_State *mouse;
|
||||
Consumption_Record records[Input_Count];
|
||||
} Available_Input;
|
||||
|
||||
internal Available_Input
|
||||
init_available_input(Key_Summary *keys, Mouse_State *mouse){
|
||||
init_available_input(Key_Input_Data *keys, Mouse_State *mouse){
|
||||
Available_Input result = {0};
|
||||
result.keys = keys;
|
||||
result.mouse = mouse;
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal Key_Summary
|
||||
internal Key_Input_Data
|
||||
direct_get_key_data(Available_Input *available){
|
||||
Key_Summary result = *available->keys;
|
||||
Key_Input_Data result = *available->keys;
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -87,9 +87,9 @@ direct_get_mouse_state(Available_Input *available){
|
|||
return(result);
|
||||
}
|
||||
|
||||
internal Key_Summary
|
||||
internal Key_Input_Data
|
||||
get_key_data(Available_Input *available){
|
||||
Key_Summary result = {0};
|
||||
Key_Input_Data result = {0};
|
||||
|
||||
if (!available->records[Input_AnyKey].consumed){
|
||||
result = *available->keys;
|
||||
|
@ -1688,46 +1688,32 @@ App_Step_Sig(app_step){
|
|||
|
||||
if (prev_width != current_width || prev_height != current_height){
|
||||
layout_refit(&models->layout, prev_width, prev_height);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(allen): prepare input information
|
||||
Key_Summary key_summary = {0};
|
||||
|
||||
{
|
||||
for (i32 i = 0; i < input->keys.press_count; ++i){
|
||||
key_summary.keys[key_summary.count++] = input->keys.press[i];
|
||||
}
|
||||
for (i32 i = 0; i < input->keys.hold_count; ++i){
|
||||
key_summary.keys[key_summary.count++] = input->keys.hold[i];
|
||||
}
|
||||
|
||||
if (models->input_filter){
|
||||
models->input_filter(&input->mouse);
|
||||
}
|
||||
|
||||
Key_Event_Data mouse_event = {0};
|
||||
memcpy(mouse_event.modifiers, input->keys.modifiers, sizeof(input->keys.modifiers));
|
||||
|
||||
if (input->mouse.press_l){
|
||||
mouse_event.keycode = key_mouse_left;
|
||||
key_summary.keys[key_summary.count++] = mouse_event;
|
||||
input->keys.keys[input->keys.count++] = mouse_event;
|
||||
}
|
||||
else if (input->mouse.release_l){
|
||||
mouse_event.keycode = key_mouse_left_release;
|
||||
input->keys.keys[input->keys.count++] = mouse_event;
|
||||
}
|
||||
|
||||
if (input->mouse.press_r){
|
||||
mouse_event.keycode = key_mouse_right;
|
||||
key_summary.keys[key_summary.count++] = mouse_event;
|
||||
input->keys.keys[input->keys.count++] = mouse_event;
|
||||
}
|
||||
|
||||
if (input->mouse.release_l){
|
||||
mouse_event.keycode = key_mouse_left_release;
|
||||
key_summary.keys[key_summary.count++] = mouse_event;
|
||||
}
|
||||
|
||||
if (input->mouse.release_r){
|
||||
else if (input->mouse.release_r){
|
||||
mouse_event.keycode = key_mouse_right_release;
|
||||
key_summary.keys[key_summary.count++] = mouse_event;
|
||||
input->keys.keys[input->keys.count++] = mouse_event;
|
||||
}
|
||||
|
||||
input->mouse.wheel = -input->mouse.wheel;
|
||||
|
@ -1996,11 +1982,11 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
|
||||
// NOTE(allen): pass events to debug
|
||||
vars->available_input = init_available_input(&key_summary, &input->mouse);
|
||||
vars->available_input = init_available_input(&input->keys, &input->mouse);
|
||||
|
||||
{
|
||||
Debug_Data *debug = &models->debug;
|
||||
Key_Summary key_data = get_key_data(&vars->available_input);
|
||||
Key_Input_Data key_data = get_key_data(&vars->available_input);
|
||||
|
||||
Debug_Input_Event *events = debug->input_events;
|
||||
|
||||
|
@ -2033,7 +2019,7 @@ App_Step_Sig(app_step){
|
|||
get_flags |= abort_flags;
|
||||
|
||||
if ((get_flags & EventOnAnyKey) || (get_flags & EventOnEsc)){
|
||||
Key_Summary key_data = get_key_data(&vars->available_input);
|
||||
Key_Input_Data key_data = get_key_data(&vars->available_input);
|
||||
|
||||
for (i32 key_i = 0; key_i < key_data.count; ++key_i){
|
||||
Key_Event_Data key = get_single_key(&key_data, key_i);
|
||||
|
@ -2259,7 +2245,7 @@ App_Step_Sig(app_step){
|
|||
|
||||
// NOTE(allen): command execution
|
||||
{
|
||||
Key_Summary key_data = get_key_data(&vars->available_input);
|
||||
Key_Input_Data key_data = get_key_data(&vars->available_input);
|
||||
b32 hit_something = 0;
|
||||
b32 hit_esc = 0;
|
||||
|
||||
|
@ -2379,6 +2365,11 @@ App_Step_Sig(app_step){
|
|||
"If you're new to 4coder there are some tutorials at http://4coder.net/tutorials.html\n"
|
||||
"\n"
|
||||
"Newest features:\n"
|
||||
"-<ctrl I> find all functions in the current buffer and list them in a jump buffer\n"
|
||||
"-option to set user name in config.4coder\n"
|
||||
" The user name is used in <alt t> and <alt y> comment writing commands\n"
|
||||
"\n"
|
||||
"New in alpha 4.0.14:\n"
|
||||
"-Option to have wrap widths automatically adjust based on average view width\n"
|
||||
"-The 'config.4coder' file can now be placed with the 4ed executable file\n"
|
||||
"-New options in 'config.4coder' to specify the font and color theme\n"
|
||||
|
@ -2389,7 +2380,7 @@ App_Step_Sig(app_step){
|
|||
"New in alpha 4.0.12 and 4.0.13:\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:"
|
||||
"-Introduced a 'config.4coder' for setting several wrapping options:\n"
|
||||
" enable_code_wrapping: set to false if you want the text like behavior\n"
|
||||
" default_wrap_width: the wrap width to set in new files\n"
|
||||
"-<ctrl 2> decrease the current buffer's wrap width\n"
|
||||
|
@ -2635,8 +2626,7 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
}
|
||||
|
||||
do_render_file_view(system, view, scroll_vars, active_view,
|
||||
panel->inner, active, target, &dead_input);
|
||||
do_render_file_view(system, view, scroll_vars, active_view, panel->inner, active, target, &dead_input);
|
||||
|
||||
draw_pop_clip(target);
|
||||
|
||||
|
|
27
4ed.h
27
4ed.h
|
@ -23,35 +23,24 @@ struct Application_Memory{
|
|||
i32 user_memory_size;
|
||||
};
|
||||
|
||||
#define KEY_INPUT_BUFFER_SIZE 4
|
||||
#define KEY_INPUT_BUFFER_DSIZE (KEY_INPUT_BUFFER_SIZE << 1)
|
||||
#define KEY_INPUT_BUFFER_SIZE 8
|
||||
#define KEY_EXTRA_SIZE 2
|
||||
|
||||
struct Key_Input_Data{
|
||||
Key_Event_Data press[KEY_INPUT_BUFFER_SIZE];
|
||||
Key_Event_Data hold[KEY_INPUT_BUFFER_SIZE];
|
||||
i32 press_count;
|
||||
i32 hold_count;
|
||||
|
||||
// TODO(allen): determine if we still need this.
|
||||
char modifiers[MDFR_INDEX_COUNT];
|
||||
Key_Event_Data keys[KEY_INPUT_BUFFER_SIZE + KEY_EXTRA_SIZE];
|
||||
i32 count;
|
||||
};
|
||||
static Key_Input_Data null_key_input_data = {0};
|
||||
|
||||
struct Key_Summary{
|
||||
i32 count;
|
||||
Key_Event_Data keys[KEY_INPUT_BUFFER_DSIZE + 2];
|
||||
};
|
||||
|
||||
inline Key_Event_Data
|
||||
get_single_key(Key_Summary *summary, i32 index){
|
||||
Key_Event_Data key;
|
||||
key = summary->keys[index];
|
||||
return key;
|
||||
get_single_key(Key_Input_Data *data, i32 index){
|
||||
Key_Event_Data key = data->keys[index];
|
||||
return(key);
|
||||
}
|
||||
|
||||
typedef struct Input_Summary{
|
||||
Mouse_State mouse;
|
||||
Key_Summary keys;
|
||||
Key_Input_Data keys;
|
||||
f32 dt;
|
||||
} Input_Summary;
|
||||
|
||||
|
|
|
@ -187,8 +187,7 @@ API_EXPORT bool32
|
|||
Exec_System_Command(Application_Links *app, View_Summary *view, Buffer_Identifier buffer, char *path, int32_t path_len, char *command, int32_t command_len, Command_Line_Interface_Flag flags)
|
||||
/*
|
||||
DOC_PARAM(view, If the view parameter is non-null it specifies a view to display the command's output buffer, otherwise the command will still work but if there is a buffer capturing the output it will not automatically be displayed.)
|
||||
DOC_PARAM(buffer, The buffer the command will output to is specified by the buffer parameter.
|
||||
See Buffer_Identifier for information on how this type specifies a buffer. The command will cause a crash if no file is specified.)
|
||||
DOC_PARAM(buffer, The buffer the command will output to is specified by the buffer parameter. See Buffer_Identifier for information on how this type specifies a buffer. The command will cause a crash if no file is specified.)
|
||||
DOC_PARAM(path, The path parameter specifies the path in which the command shall be executed. The string need not be null terminated.)
|
||||
DOC_PARAM(path_len, The parameter path_len specifies the length of the path string.)
|
||||
DOC_PARAM(command, The command parameter specifies the command that shall be executed. The string need not be null terminated.)
|
||||
|
@ -1636,9 +1635,6 @@ DOC_SEE(Full_Cursor)
|
|||
if (vptr){
|
||||
file = vptr->file_data.file;
|
||||
if (file && !file->is_loading){
|
||||
if (seek.type == buffer_seek_line_char && seek.character <= 0){
|
||||
seek.character = 1;
|
||||
}
|
||||
result = true;
|
||||
*cursor_out = view_compute_cursor(vptr, seek, 0);
|
||||
fill_view_summary(view, vptr, cmd);
|
||||
|
@ -1673,9 +1669,6 @@ DOC_SEE(Buffer_Seek)
|
|||
Assert(file);
|
||||
if (!file->is_loading){
|
||||
result = true;
|
||||
if (seek.type == buffer_seek_line_char && seek.character <= 0){
|
||||
seek.character = 1;
|
||||
}
|
||||
Full_Cursor cursor = view_compute_cursor(vptr, seek, 0);
|
||||
view_set_cursor(vptr, cursor, set_preferred_x, file->settings.unwrapped_lines);
|
||||
fill_view_summary(view, vptr, cmd);
|
||||
|
@ -1726,12 +1719,13 @@ DOC_SEE(Buffer_Seek)
|
|||
if (vptr){
|
||||
file = vptr->file_data.file;
|
||||
if (file && !file->is_loading){
|
||||
result = true;
|
||||
if (seek.type != buffer_seek_pos){
|
||||
result = true;
|
||||
cursor = view_compute_cursor(vptr, seek, 0);
|
||||
vptr->edit_pos->mark = cursor.pos;
|
||||
}
|
||||
else{
|
||||
result = true;
|
||||
vptr->edit_pos->mark = seek.pos;
|
||||
}
|
||||
fill_view_summary(view, vptr, cmd);
|
||||
|
@ -1905,17 +1899,17 @@ DOC_SEE(Mouse_State)
|
|||
/*
|
||||
API_EXPORT Event_Message
|
||||
Get_Event_Message (Application_Links *app){
|
||||
Event_Message message = {0};
|
||||
System_Functions *system = (System_Functions*)app->system_links;
|
||||
Coroutine *coroutine = (Coroutine*)app->current_coroutine;
|
||||
|
||||
if (app->type_coroutine == Co_View){
|
||||
Assert(coroutine);
|
||||
system->yield_coroutine(coroutine);
|
||||
message = *(Event_Message*)coroutine->in;
|
||||
}
|
||||
|
||||
return(message);
|
||||
Event_Message message = {0};
|
||||
System_Functions *system = (System_Functions*)app->system_links;
|
||||
Coroutine *coroutine = (Coroutine*)app->current_coroutine;
|
||||
|
||||
if (app->type_coroutine == Co_View){
|
||||
Assert(coroutine);
|
||||
system->yield_coroutine(coroutine);
|
||||
message = *(Event_Message*)coroutine->in;
|
||||
}
|
||||
|
||||
return(message);
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
|
@ -853,7 +853,7 @@ file_grow_starts_as_needed(General_Memory *general, Gap_Buffer *buffer, i32 addi
|
|||
i32 target_lines = count + additional_lines;
|
||||
|
||||
if (target_lines > max || max == 0){
|
||||
max = l_round_up(target_lines + max, KB(1));
|
||||
max = l_round_up_i32(target_lines + max, KB(1));
|
||||
|
||||
i32 *new_lines = (i32*)general_memory_reallocate(general, buffer->line_starts, sizeof(i32)*count, sizeof(f32)*max);
|
||||
|
||||
|
@ -1904,7 +1904,7 @@ file_create_from_string(System_Functions *system, Models *models, Editing_File *
|
|||
Gap_Buffer_Init init = buffer_begin_init(&file->state.buffer, val.str, val.size);
|
||||
for (; buffer_init_need_more(&init); ){
|
||||
i32 page_size = buffer_init_page_size(&init);
|
||||
page_size = l_round_up(page_size, KB(4));
|
||||
page_size = l_round_up_i32(page_size, KB(4));
|
||||
if (page_size < KB(4)){
|
||||
page_size = KB(4);
|
||||
}
|
||||
|
@ -2080,7 +2080,7 @@ Job_Callback_Sig(job_full_lex){
|
|||
}
|
||||
} while (still_lexing);
|
||||
|
||||
i32 new_max = l_round_up(tokens.count+1, KB(1));
|
||||
i32 new_max = l_round_up_i32(tokens.count+1, KB(1));
|
||||
|
||||
system->acquire_lock(FRAME_LOCK);
|
||||
{
|
||||
|
@ -2207,7 +2207,7 @@ file_first_lex_serial(Mem_Options *mem, Editing_File *file){
|
|||
}
|
||||
} while (still_lexing);
|
||||
|
||||
i32 new_max = l_round_up(tokens.count+1, KB(1));
|
||||
i32 new_max = l_round_up_i32(tokens.count+1, KB(1));
|
||||
|
||||
{
|
||||
Assert(file->state.swap_array.tokens == 0);
|
||||
|
@ -2321,7 +2321,7 @@ file_relex_parallel(System_Functions *system, Mem_Options *mem, Editing_File *fi
|
|||
if (inline_lex){
|
||||
i32 new_count = cpp_relex_get_new_count(&state, array->count, &relex_array);
|
||||
if (new_count > array->max_count){
|
||||
i32 new_max = l_round_up(new_count, KB(1));
|
||||
i32 new_max = l_round_up_i32(new_count, KB(1));
|
||||
array->tokens = (Cpp_Token*)
|
||||
general_memory_reallocate(general, array->tokens, array->count*sizeof(Cpp_Token), new_max*sizeof(Cpp_Token));
|
||||
array->max_count = new_max;
|
||||
|
@ -2436,7 +2436,7 @@ file_relex_serial(Mem_Options *mem, Editing_File *file, i32 start_i, i32 end_i,
|
|||
|
||||
i32 new_count = cpp_relex_get_new_count(&state, array->count, &relex_array);
|
||||
if (new_count > array->max_count){
|
||||
i32 new_max = l_round_up(new_count, KB(1));
|
||||
i32 new_max = l_round_up_i32(new_count, KB(1));
|
||||
array->tokens = (Cpp_Token*)general_memory_reallocate(general, array->tokens, array->count*sizeof(Cpp_Token), new_max*sizeof(Cpp_Token));
|
||||
array->max_count = new_max;
|
||||
}
|
||||
|
@ -2766,6 +2766,22 @@ view_cursor_move(View *view, i32 line, i32 character){
|
|||
view_cursor_move(view, cursor);
|
||||
}
|
||||
|
||||
inline void
|
||||
view_show_file(View *view){
|
||||
Editing_File *file = view->file_data.file;
|
||||
if (file){
|
||||
view->map = get_map(view->persistent.models, file->settings.base_map_id);
|
||||
}
|
||||
else{
|
||||
view->map = get_map(view->persistent.models, mapid_global);
|
||||
}
|
||||
|
||||
if (view->showing_ui != VUI_None){
|
||||
view->showing_ui = VUI_None;
|
||||
view->changed_context_in_step = 1;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
view_set_file(View *view, Editing_File *file, Models *models){
|
||||
Assert(file);
|
||||
|
@ -2792,6 +2808,10 @@ view_set_file(View *view, Editing_File *file, Models *models){
|
|||
if (edit_pos->cursor.line == 0){
|
||||
view_cursor_move(view, 0);
|
||||
}
|
||||
|
||||
if (view->showing_ui == VUI_None){
|
||||
view_show_file(view);
|
||||
}
|
||||
}
|
||||
|
||||
struct Relative_Scrolling{
|
||||
|
@ -3714,22 +3734,6 @@ view_show_theme(View *view){
|
|||
view->changed_context_in_step = 1;
|
||||
}
|
||||
|
||||
inline void
|
||||
view_show_file(View *view){
|
||||
Editing_File *file = view->file_data.file;
|
||||
if (file){
|
||||
view->map = get_map(view->persistent.models, file->settings.base_map_id);
|
||||
}
|
||||
else{
|
||||
view->map = get_map(view->persistent.models, mapid_global);
|
||||
}
|
||||
|
||||
if (view->showing_ui != VUI_None){
|
||||
view->showing_ui = VUI_None;
|
||||
view->changed_context_in_step = 1;
|
||||
}
|
||||
}
|
||||
|
||||
internal String
|
||||
make_string_terminated(Partition *part, char *str, i32 len){
|
||||
char *space = (char*)push_array(part, char, len + 1);
|
||||
|
@ -4600,7 +4604,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su
|
|||
View_Step_Result result = {0};
|
||||
GUI_Target *target = &view->gui_target;
|
||||
Models *models = view->persistent.models;
|
||||
Key_Summary keys = input.keys;
|
||||
Key_Input_Data keys = input.keys;
|
||||
|
||||
b32 show_scrollbar = !view->hide_scrollbar;
|
||||
|
||||
|
@ -5754,23 +5758,19 @@ do_step_file_view(System_Functions *system,
|
|||
}
|
||||
|
||||
{
|
||||
Key_Event_Data key;
|
||||
Key_Summary *keys = &user_input->keys;
|
||||
Key_Input_Data *keys = &user_input->keys;
|
||||
|
||||
void *ptr = (b + 1);
|
||||
String string;
|
||||
char activation_key;
|
||||
String string = gui_read_string(&ptr);
|
||||
AllowLocal(string);
|
||||
|
||||
i32 i, count;
|
||||
|
||||
string = gui_read_string(&ptr);
|
||||
activation_key = *(char*)ptr;
|
||||
char activation_key = *(char*)ptr;
|
||||
activation_key = char_to_upper(activation_key);
|
||||
|
||||
if (activation_key != 0){
|
||||
count = keys->count;
|
||||
for (i = 0; i < count; ++i){
|
||||
key = get_single_key(keys, i);
|
||||
i32 count = keys->count;
|
||||
for (i32 i = 0; i < count; ++i){
|
||||
Key_Event_Data key = get_single_key(keys, i);
|
||||
if (char_to_upper(key.character) == activation_key){
|
||||
target->active = b->id;
|
||||
result.is_animating = 1;
|
||||
|
|
|
@ -1254,9 +1254,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 user_up_key, i16 user_down_key){
|
||||
gui_standard_list(GUI_Target *target, GUI_id id, GUI_Scroll_Vars *vars, i32_Rect scroll_region, Key_Input_Data *keys, i32 *list_i, GUI_Item_Update *update, i16 user_up_key, i16 user_down_key){
|
||||
|
||||
if (update->has_adjustment){
|
||||
*list_i = update->adjustment_value;
|
||||
|
|
|
@ -277,29 +277,25 @@ layout_get_rect(Editing_Layout *layout, i32 id, i32 which_child){
|
|||
internal i32_Rect
|
||||
layout_get_panel_rect(Editing_Layout *layout, Panel *panel){
|
||||
Assert(layout->panel_count > 1);
|
||||
|
||||
i32_Rect r = layout_get_rect(layout, panel->parent, panel->which_child);
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
internal void
|
||||
layout_fix_all_panels(Editing_Layout *layout){
|
||||
Panel *panel;
|
||||
Panel_Divider *dividers = layout->dividers; AllowLocal(dividers);
|
||||
i32 panel_count = layout->panel_count;
|
||||
|
||||
if (panel_count > 1){
|
||||
for (panel = layout->used_sentinel.next;
|
||||
for (Panel *panel = layout->used_sentinel.next;
|
||||
panel != &layout->used_sentinel;
|
||||
panel = panel->next){
|
||||
panel->full = layout_get_panel_rect(layout, panel);
|
||||
panel_fix_internal_area(panel);
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
panel = layout->used_sentinel.next;
|
||||
Panel *panel = layout->used_sentinel.next;
|
||||
panel->full.x0 = 0;
|
||||
panel->full.y0 = 0;
|
||||
panel->full.x1 = layout->full_width;
|
||||
|
@ -316,10 +312,8 @@ layout_refit(Editing_Layout *layout, i32 prev_width, i32 prev_height){
|
|||
i32 max = layout->panel_max_count - 1;
|
||||
|
||||
Panel_Divider *divider = dividers;
|
||||
|
||||
if (layout->panel_count > 1){
|
||||
Assert(prev_width != 0 && prev_height != 0);
|
||||
|
||||
for (i32 i = 0; i < max; ++i, ++divider){
|
||||
if (divider->v_divider){
|
||||
divider->pos = divider->pos;
|
||||
|
@ -373,8 +367,8 @@ layout_compute_position(Editing_Layout *layout, Panel_Divider *divider, i32 pos)
|
|||
internal void
|
||||
layout_compute_abs_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i32 *abs_pos){
|
||||
Panel_Divider *div = layout->dividers + divider_id;
|
||||
i32 p0 = 0, p1 = 0;
|
||||
|
||||
i32 p0 = 0, p1 = 0;
|
||||
if (div->v_divider){
|
||||
p0 = rect.x0; p1 = rect.x1;
|
||||
}
|
||||
|
@ -405,11 +399,7 @@ layout_compute_abs_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i
|
|||
|
||||
internal void
|
||||
layout_compute_absolute_positions(Editing_Layout *layout, i32 *abs_pos){
|
||||
i32_Rect r;
|
||||
r.x0 = 0;
|
||||
r.y0 = 0;
|
||||
r.x1 = layout->full_width;
|
||||
r.y1 = layout->full_height;
|
||||
i32_Rect r = i32R(0, 0, layout->full_width, layout->full_height);
|
||||
if (layout->panel_count > 1){
|
||||
layout_compute_abs_step(layout, layout->root, r, abs_pos);
|
||||
}
|
||||
|
@ -434,14 +424,12 @@ layout_get_min_max_step_up(Editing_Layout *layout, b32 v, i32 divider_id, i32 wh
|
|||
}
|
||||
|
||||
if (divider->parent != -1){
|
||||
layout_get_min_max_step_up(layout, v, divider->parent, divider->which_child,
|
||||
abs_pos, min_out, max_out);
|
||||
layout_get_min_max_step_up(layout, v, divider->parent, divider->which_child, abs_pos, min_out, max_out);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
layout_get_min_max_step_down(Editing_Layout *layout, b32 v, i32 divider_id, i32 which_child,
|
||||
i32 *abs_pos, i32 *min_out, i32 *max_out){
|
||||
layout_get_min_max_step_down(Editing_Layout *layout, b32 v, i32 divider_id, i32 which_child, i32 *abs_pos, i32 *min_out, i32 *max_out){
|
||||
Panel_Divider *divider = layout->dividers + divider_id;
|
||||
|
||||
// NOTE(allen): The min/max is switched here, because children on the -1 side
|
||||
|
@ -504,8 +492,8 @@ layout_get_min_max(Editing_Layout *layout, Panel_Divider *divider, i32 *abs_pos,
|
|||
internal void
|
||||
layout_update_pos_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i32 *abs_pos){
|
||||
Panel_Divider *div = layout->dividers + divider_id;
|
||||
i32 p0 = 0, p1 = 0;
|
||||
|
||||
i32 p0 = 0, p1 = 0;
|
||||
if (div->v_divider){
|
||||
p0 = rect.x0; p1 = rect.x1;
|
||||
}
|
||||
|
@ -516,6 +504,7 @@ layout_update_pos_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i3
|
|||
i32 pos = abs_pos[divider_id];
|
||||
i32_Rect r1 = rect, r2 = rect;
|
||||
f32 lpos = unlerp((f32)p0, (f32)pos, (f32)p1);
|
||||
lpos = clamp(0.f, lpos, 1.f);
|
||||
|
||||
div->pos = lpos;
|
||||
|
||||
|
@ -539,11 +528,7 @@ layout_update_pos_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i3
|
|||
|
||||
internal void
|
||||
layout_update_all_positions(Editing_Layout *layout, i32 *abs_pos){
|
||||
i32_Rect r;
|
||||
r.x0 = 0;
|
||||
r.y0 = 0;
|
||||
r.x1 = layout->full_width;
|
||||
r.y1 = layout->full_height;
|
||||
i32_Rect r = i32R(0, 0, layout->full_width, layout->full_height);
|
||||
if (layout->panel_count > 1){
|
||||
layout_update_pos_step(layout, layout->root, r, abs_pos);
|
||||
}
|
||||
|
|
19
4ed_math.h
19
4ed_math.h
|
@ -647,13 +647,28 @@ hit_check(int32_t x, int32_t y, i32_Rect rect){
|
|||
}
|
||||
|
||||
inline i32_Rect
|
||||
get_inner_rect(i32_Rect outer, int32_t margin){
|
||||
get_inner_rect(i32_Rect outer, i32 margin){
|
||||
i32_Rect r;
|
||||
r.x0 = outer.x0 + margin;
|
||||
r.y0 = outer.y0 + margin;
|
||||
r.x1 = outer.x1 - margin;
|
||||
r.y1 = outer.y1 - margin;
|
||||
return r;
|
||||
return(r);
|
||||
}
|
||||
|
||||
inline f32_Rect
|
||||
get_inner_rect(f32_Rect outer, f32 margin){
|
||||
f32_Rect r;
|
||||
r.x0 = outer.x0 + margin;
|
||||
r.y0 = outer.y0 + margin;
|
||||
r.x1 = outer.x1 - margin;
|
||||
r.y1 = outer.y1 - margin;
|
||||
return(r);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
fits_inside(i32_Rect rect, i32_Rect outer){
|
||||
return(rect.x0 >= outer.x0 && rect.x1 <= outer.x1 && rect.y0 >= outer.y0 && rect.y1 <= outer.y1);
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
|
|
|
@ -151,6 +151,7 @@ struct Render_Target{
|
|||
void *context;
|
||||
i32_Rect clip_boxes[5];
|
||||
i32 clip_top;
|
||||
b32 clip_all;
|
||||
i32 width, height;
|
||||
i32 bound_texture;
|
||||
u32 color;
|
||||
|
@ -166,8 +167,6 @@ struct Render_Target{
|
|||
Draw_Push_Clip *push_clip;
|
||||
Draw_Pop_Clip *pop_clip;
|
||||
Draw_Push_Piece *push_piece;
|
||||
|
||||
//i32 dpi;
|
||||
};
|
||||
|
||||
#define DpiMultiplier(n,dpi) ((n) * (dpi) / 96)
|
||||
|
|
|
@ -9,20 +9,6 @@
|
|||
|
||||
// TOP
|
||||
|
||||
#if 0
|
||||
inline i32_Rect
|
||||
i32_rect_zero(){
|
||||
i32_Rect rect={0};
|
||||
return(rect);
|
||||
}
|
||||
|
||||
inline f32_Rect
|
||||
f32_rect_zero(){
|
||||
f32_Rect rect={0};
|
||||
return(rect);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void
|
||||
draw_push_clip(Render_Target *target, i32_Rect clip_box){
|
||||
target->push_clip(target, clip_box);
|
||||
|
|
BIN
4ed_site.ctm
BIN
4ed_site.ctm
Binary file not shown.
|
@ -266,69 +266,66 @@ draw_safe_push(Render_Target *target, i32 size, void *x){
|
|||
|
||||
internal void
|
||||
draw_push_piece(Render_Target *target, Render_Piece_Combined piece){
|
||||
PutStruct(Render_Piece_Header, piece.header);
|
||||
|
||||
switch (piece.header.type){
|
||||
case piece_type_rectangle:
|
||||
case piece_type_outline:
|
||||
PutStruct(Render_Piece_Rectangle, piece.rectangle);
|
||||
break;
|
||||
if (!target->clip_all){
|
||||
PutStruct(Render_Piece_Header, piece.header);
|
||||
|
||||
case piece_type_gradient:
|
||||
PutStruct(Render_Piece_Gradient, piece.gradient);
|
||||
break;
|
||||
switch (piece.header.type){
|
||||
case piece_type_rectangle:
|
||||
case piece_type_outline:
|
||||
PutStruct(Render_Piece_Rectangle, piece.rectangle);
|
||||
break;
|
||||
|
||||
case piece_type_gradient:
|
||||
PutStruct(Render_Piece_Gradient, piece.gradient);
|
||||
break;
|
||||
|
||||
case piece_type_glyph:
|
||||
case piece_type_mono_glyph:
|
||||
PutStruct(Render_Piece_Glyph, piece.glyph);
|
||||
break;
|
||||
|
||||
case piece_type_mono_glyph_advance:
|
||||
PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance);
|
||||
break;
|
||||
}
|
||||
|
||||
case piece_type_glyph:
|
||||
case piece_type_mono_glyph:
|
||||
PutStruct(Render_Piece_Glyph, piece.glyph);
|
||||
break;
|
||||
|
||||
case piece_type_mono_glyph_advance:
|
||||
PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance);
|
||||
break;
|
||||
Assert(target->size <= target->max);
|
||||
}
|
||||
|
||||
Assert(target->size <= target->max);
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_push_piece_clip(Render_Target *target, i32_Rect clip_box){
|
||||
// TODO(allen): optimize out if there are two clip box changes in a row
|
||||
Render_Piece_Change_Clip clip;
|
||||
Render_Piece_Header header;
|
||||
|
||||
header.type = piece_type_change_clip;
|
||||
clip.box = clip_box;
|
||||
|
||||
PutStruct(Render_Piece_Header, header);
|
||||
PutStruct(Render_Piece_Change_Clip, clip);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
fits_inside(i32_Rect rect, i32_Rect outer){
|
||||
return (rect.x0 >= outer.x0 && rect.x1 <= outer.x1 &&
|
||||
rect.y0 >= outer.y0 && rect.y1 <= outer.y1);
|
||||
if (!target->clip_all){
|
||||
// TODO(allen): optimize out if there are two clip box changes in a row
|
||||
Render_Piece_Change_Clip clip;
|
||||
Render_Piece_Header header;
|
||||
|
||||
header.type = piece_type_change_clip;
|
||||
clip.box = clip_box;
|
||||
|
||||
PutStruct(Render_Piece_Header, header);
|
||||
PutStruct(Render_Piece_Change_Clip, clip);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_push_clip(Render_Target *target, i32_Rect clip_box){
|
||||
Assert(target->clip_top == -1 ||
|
||||
fits_inside(clip_box, target->clip_boxes[target->clip_top]));
|
||||
Assert(target->clip_top == -1 || fits_inside(clip_box, target->clip_boxes[target->clip_top]));
|
||||
Assert(target->clip_top+1 < ArrayCount(target->clip_boxes));
|
||||
target->clip_boxes[++target->clip_top] = clip_box;
|
||||
|
||||
target->clip_all = (clip_box.x0 >= clip_box.x1 || clip_box.y0 >= clip_box.y1);
|
||||
draw_push_piece_clip(target, clip_box);
|
||||
}
|
||||
|
||||
internal i32_Rect
|
||||
draw_pop_clip(Render_Target *target){
|
||||
i32_Rect result = {0};
|
||||
i32_Rect clip_box = {0};
|
||||
|
||||
Assert(target->clip_top > 0);
|
||||
result = target->clip_boxes[target->clip_top];
|
||||
i32_Rect result = target->clip_boxes[target->clip_top];
|
||||
--target->clip_top;
|
||||
clip_box = target->clip_boxes[target->clip_top];
|
||||
i32_Rect clip_box = target->clip_boxes[target->clip_top];
|
||||
|
||||
target->clip_all = (clip_box.x0 >= clip_box.x1 || clip_box.y0 >= clip_box.y1);
|
||||
draw_push_piece_clip(target, clip_box);
|
||||
|
||||
return(result);
|
||||
|
@ -352,12 +349,7 @@ private_draw_rectangle(Render_Target *target, f32_Rect rect, u32 color){
|
|||
|
||||
inline void
|
||||
private_draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){
|
||||
f32_Rect r;
|
||||
r.x0 = rect.x0 + .5f;
|
||||
r.y0 = rect.y0 + .5f;
|
||||
r.x1 = rect.x1 - .5f;
|
||||
r.y1 = rect.y1 - .5f;
|
||||
|
||||
f32_Rect r = get_inner_rect(rect, .5f);
|
||||
draw_set_color(target, color);
|
||||
draw_bind_texture(target, 0);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
|
|
|
@ -59,18 +59,34 @@ typedef double f64;
|
|||
#define Max(a,b) (((a)>(b))?(a):(b))
|
||||
#define Min(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
#define ceil32(v) (((v)>0)?( (v == (i32)(v))?((i32)(v)):((i32)((v)+1.f)) ):( ((i32)(v)) ))
|
||||
|
||||
#define floor32(v) (((v)<0)?( (v == (i32)(v))?((i32)(v)):((i32)((v)-1.f)) ):( ((i32)(v)) ))
|
||||
|
||||
#define round32(v) (floor32(v + 0.5f))
|
||||
|
||||
#define trunc32(v) (i32)(v)
|
||||
|
||||
#define div_ceil(n,d) ( ((n) % (d) != 0) + ((n) / (d)) )
|
||||
|
||||
#define l_round_up(x,b) ( ((x)+(b)-1) - (((x)+(b)-1)%(b)) )
|
||||
|
||||
inline i32 ceil32(f32 v){
|
||||
return(((v)>0)?( (v == (i32)(v))?((i32)(v)):((i32)((v)+1.f)) ):( ((i32)(v)) ));
|
||||
}
|
||||
|
||||
inline i32 floor32(f32 v){
|
||||
return(((v)<0)?( (v == (i32)(v))?((i32)(v)):((i32)((v)-1.f)) ):( ((i32)(v)) ));
|
||||
}
|
||||
|
||||
inline i32 round32(f32 v){
|
||||
return(floor32(v + 0.5f));
|
||||
}
|
||||
|
||||
inline i32 trun32(f32 v){
|
||||
return((i32)(v));
|
||||
}
|
||||
|
||||
inline i32 div_ceil(i32 n, i32 d){
|
||||
return( ((n) % (d) != 0) + ((n) / (d)) );
|
||||
}
|
||||
|
||||
inline i32 l_round_up_i32(i32 x, i32 b){
|
||||
return( ((x)+(b)-1) - (((x)+(b)-1)%(b)) );
|
||||
}
|
||||
|
||||
inline u32 l_round_up_u32(u32 x, u32 b){
|
||||
return( ((x)+(b)-1) - (((x)+(b)-1)%(b)) );
|
||||
}
|
||||
|
||||
#define STR__(s) #s
|
||||
#define STR_(s) STR__(s)
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -502,7 +502,7 @@ buffer_replace_range(Gap_Buffer *buffer, i32 start, i32 end, char *str, i32 len,
|
|||
assert(buffer->size1 + buffer->gap_size + buffer->size2 == buffer->max);
|
||||
}
|
||||
else{
|
||||
*request_amount = l_round_up(2*(*shift_amount + size), 4 << 10);
|
||||
*request_amount = l_round_up_i32(2*(*shift_amount + size), 4 << 10);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
|
@ -1235,6 +1235,7 @@ buffer_partial_from_line_character(Gap_Buffer *buffer, i32 line, i32 character){
|
|||
}
|
||||
|
||||
i32 size = buffer_size(buffer);
|
||||
|
||||
i32 this_start = buffer->line_starts[line_index];
|
||||
i32 max_character = (size-this_start) + 1;
|
||||
if (line_index+1 < buffer->line_count){
|
||||
|
@ -1242,14 +1243,28 @@ buffer_partial_from_line_character(Gap_Buffer *buffer, i32 line, i32 character){
|
|||
max_character = (next_start-this_start);
|
||||
}
|
||||
|
||||
if (character <= 0){
|
||||
character = 1;
|
||||
i32 adjusted_pos = 0;
|
||||
if (character > 0){
|
||||
if (character > max_character){
|
||||
adjusted_pos = max_character - 1;
|
||||
}
|
||||
else{
|
||||
adjusted_pos = character - 1;
|
||||
}
|
||||
}
|
||||
if (character > max_character){
|
||||
character = max_character;
|
||||
else if (character == 0){
|
||||
adjusted_pos = 0;
|
||||
}
|
||||
else{
|
||||
if (-character > max_character){
|
||||
adjusted_pos = 0;
|
||||
}
|
||||
else{
|
||||
adjusted_pos = max_character + character;
|
||||
}
|
||||
}
|
||||
|
||||
result.pos = this_start + character - 1;
|
||||
result.pos = this_start + adjusted_pos;
|
||||
result.line = line_index + 1;
|
||||
result.character = character;
|
||||
|
||||
|
|
|
@ -285,7 +285,7 @@ file_compute_cursor_from_line_character(Editing_File *file, i32 line, i32 charac
|
|||
|
||||
inline b32
|
||||
file_compute_partial_cursor(Editing_File *file, Buffer_Seek seek, Partial_Cursor *cursor){
|
||||
b32 result = 1;
|
||||
b32 result = true;
|
||||
switch (seek.type){
|
||||
case buffer_seek_pos:
|
||||
{
|
||||
|
@ -299,7 +299,7 @@ file_compute_partial_cursor(Editing_File *file, Buffer_Seek seek, Partial_Cursor
|
|||
|
||||
default:
|
||||
{
|
||||
result = 0;
|
||||
result = false;
|
||||
}break;
|
||||
}
|
||||
return(result);
|
||||
|
|
|
@ -445,6 +445,7 @@ standard_build(char *cdir, u32 flags){
|
|||
fsm_generator(cdir);
|
||||
metagen(cdir);
|
||||
do_buildsuper(cdir, Custom_Experiments);
|
||||
//do_buildsuper(cdir, Custom_Casey);
|
||||
//do_buildsuper(cdir, Custom_ChronalVim);
|
||||
build_main(cdir, flags);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,16 @@
|
|||
/*
|
||||
4coder_experiments.cpp - Supplies extension bindings to the defaults with experimental new features.
|
||||
|
||||
TYPE: 'build-target'
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#include "4coder_default_include.cpp"
|
||||
#if !defined(FCODER_EXPERIMENTS_CPP)
|
||||
#define FCODER_EXPERIMENTS_CPP
|
||||
|
||||
#include "4coder_function_list.cpp"
|
||||
#include "4coder_default_include.cpp"
|
||||
#include "4coder_miblo_numbers.cpp"
|
||||
|
||||
#define NO_BINDING
|
||||
#include "4coder_default_bindings.cpp"
|
||||
|
@ -12,8 +19,6 @@
|
|||
# define BIND_4CODER_TESTS(context) ((void)context)
|
||||
#endif
|
||||
|
||||
#include "4coder_miblo_numbers.cpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static float
|
||||
|
@ -108,8 +113,8 @@ multi-cursor showing but it is unclear to me how to do that
|
|||
conveniently. Since this won't exist inside a coroutine
|
||||
what does such an API even look like??? It's clear to me now
|
||||
that I may need to start pushing for the view routine before
|
||||
I am even able to support the GUI. Because that will the
|
||||
system up to allow me to think about the problem in more ways.
|
||||
I am even able to support the GUI. Because that will set up the
|
||||
system to allow me to think about the problem in more ways.
|
||||
|
||||
Finally I have decided not to pursue this direction any more,
|
||||
it just seems like the wrong way to do it, so I'll stop without
|
||||
|
@ -540,7 +545,7 @@ view_set_to_region(Application_Links *app, View_Summary *view, int32_t major_pos
|
|||
|
||||
static float scope_center_threshold = 0.75f;
|
||||
|
||||
CUSTOM_COMMAND_SIG(highlight_surroundng_scope){
|
||||
CUSTOM_COMMAND_SIG(highlight_surrounding_scope){
|
||||
uint32_t access = AccessProtected;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
|
@ -714,6 +719,334 @@ CUSTOM_COMMAND_SIG(place_in_scope){
|
|||
}
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(delete_current_scope){
|
||||
uint32_t access = AccessOpen;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
|
||||
int32_t top = view.cursor.pos;
|
||||
int32_t bottom = view.mark.pos;
|
||||
|
||||
if (top > bottom){
|
||||
int32_t x = top;
|
||||
top = bottom;
|
||||
bottom = x;
|
||||
}
|
||||
|
||||
if (buffer_get_char(app, &buffer, top) == '{' && buffer_get_char(app, &buffer, bottom-1) == '}'){
|
||||
int32_t top_len = 1;
|
||||
int32_t bottom_len = 1;
|
||||
if (buffer_get_char(app, &buffer, top-1) == '\n'){
|
||||
top_len = 2;
|
||||
}
|
||||
if (buffer_get_char(app, &buffer, bottom+1) == '\n'){
|
||||
bottom_len = 2;
|
||||
}
|
||||
|
||||
Buffer_Edit edits[2];
|
||||
edits[0].str_start = 0;
|
||||
edits[0].len = 0;
|
||||
edits[0].start = top+1 - top_len;
|
||||
edits[0].end = top+1;
|
||||
|
||||
edits[1].str_start = 0;
|
||||
edits[1].len = 0;
|
||||
edits[1].start = bottom-1;
|
||||
edits[1].end = bottom-1 + bottom_len;
|
||||
|
||||
buffer_batch_edit(app, &buffer, 0, 0, edits, 2, BatchEdit_Normal);
|
||||
}
|
||||
}
|
||||
|
||||
struct Statement_Parser{
|
||||
Stream_Tokens stream;
|
||||
int32_t token_index;
|
||||
Buffer_Summary *buffer;
|
||||
};
|
||||
|
||||
static Cpp_Token*
|
||||
parser_next_token(Statement_Parser *parser){
|
||||
Cpp_Token *result = 0;
|
||||
bool32 still_looping = true;
|
||||
while (parser->token_index >= parser->stream.end && still_looping){
|
||||
still_looping = forward_stream_tokens(&parser->stream);
|
||||
}
|
||||
if (parser->token_index < parser->stream.end){
|
||||
result = &parser->stream.tokens[parser->token_index];
|
||||
++parser->token_index;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool32 parse_statement_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out);
|
||||
|
||||
static bool32
|
||||
parse_for_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out){
|
||||
bool32 success = false;
|
||||
Cpp_Token *token = parser_next_token(parser);
|
||||
|
||||
int32_t paren_level = 0;
|
||||
while (token != 0){
|
||||
if (!(token->flags & CPP_TFLAG_PP_BODY)){
|
||||
switch (token->type){
|
||||
case CPP_TOKEN_PARENTHESE_OPEN:
|
||||
{
|
||||
++paren_level;
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_PARENTHESE_CLOSE:
|
||||
{
|
||||
--paren_level;
|
||||
if (paren_level == 0){
|
||||
success = parse_statement_down(app, parser, token_out);
|
||||
goto finished;
|
||||
}
|
||||
else if (paren_level < 0){
|
||||
success = false;
|
||||
goto finished;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
token = parser_next_token(parser);
|
||||
}
|
||||
|
||||
finished:;
|
||||
return(success);
|
||||
}
|
||||
|
||||
static bool32
|
||||
parse_if_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out){
|
||||
bool32 success = false;
|
||||
Cpp_Token *token = parser_next_token(parser);
|
||||
|
||||
if (token != 0){
|
||||
success = parse_statement_down(app, parser, token_out);
|
||||
if (success){
|
||||
token = parser_next_token(parser);
|
||||
if (token != 0 && token->type == CPP_TOKEN_KEY_CONTROL_FLOW){
|
||||
char lexeme[32];
|
||||
if (sizeof(lexeme)-1 >= token->size){
|
||||
if (buffer_read_range(app, parser->buffer, token->start, token->start + token->size, lexeme)){
|
||||
lexeme[token->size] = 0;
|
||||
if (match(lexeme, "else")){
|
||||
success = parse_statement_down(app, parser, token_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(success);
|
||||
}
|
||||
|
||||
static bool32
|
||||
parse_block_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out){
|
||||
bool32 success = false;
|
||||
Cpp_Token *token = parser_next_token(parser);
|
||||
|
||||
int32_t nest_level = 0;
|
||||
while (token != 0){
|
||||
switch (token->type){
|
||||
case CPP_TOKEN_BRACE_OPEN:
|
||||
{
|
||||
++nest_level;
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_BRACE_CLOSE:
|
||||
{
|
||||
if (nest_level == 0){
|
||||
*token_out = *token;
|
||||
success = true;
|
||||
goto finished;
|
||||
}
|
||||
--nest_level;
|
||||
}break;
|
||||
}
|
||||
token = parser_next_token(parser);
|
||||
}
|
||||
|
||||
finished:;
|
||||
return(success);
|
||||
}
|
||||
|
||||
static bool32
|
||||
parse_statement_down(Application_Links *app, Statement_Parser *parser, Cpp_Token *token_out){
|
||||
bool32 success = false;
|
||||
Cpp_Token *token = parser_next_token(parser);
|
||||
|
||||
if (token != 0){
|
||||
bool32 not_getting_block = false;
|
||||
|
||||
do{
|
||||
switch (token->type){
|
||||
case CPP_TOKEN_BRACE_CLOSE:
|
||||
{
|
||||
goto finished;
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_KEY_CONTROL_FLOW:
|
||||
{
|
||||
char lexeme[32];
|
||||
if (sizeof(lexeme)-1 >= token->size){
|
||||
if (buffer_read_range(app, parser->buffer, token->start, token->start + token->size, lexeme)){
|
||||
lexeme[token->size] = 0;
|
||||
if (match(lexeme, "for")){
|
||||
success = parse_for_down(app, parser, token_out);
|
||||
goto finished;
|
||||
}
|
||||
else if (match(lexeme, "if")){
|
||||
success = parse_if_down(app, parser, token_out);
|
||||
goto finished;
|
||||
}
|
||||
else if (match(lexeme, "else")){
|
||||
success = false;
|
||||
goto finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_BRACE_OPEN:
|
||||
{
|
||||
if (!not_getting_block){
|
||||
success = parse_block_down(app, parser, token_out);
|
||||
goto finished;
|
||||
}
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_SEMICOLON:
|
||||
{
|
||||
success = true;
|
||||
*token_out = *token;
|
||||
goto finished;
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_EQ:
|
||||
{
|
||||
not_getting_block = true;
|
||||
}break;
|
||||
}
|
||||
|
||||
token = parser_next_token(parser);
|
||||
}while(token != 0);
|
||||
}
|
||||
|
||||
finished:;
|
||||
return(success);
|
||||
}
|
||||
|
||||
static bool32
|
||||
find_whole_statement_down(Application_Links *app, Buffer_Summary *buffer, int32_t pos, int32_t *start_out, int32_t *end_out){
|
||||
bool32 result = false;
|
||||
int32_t start = pos;
|
||||
int32_t end = start;
|
||||
|
||||
Cpp_Get_Token_Result get_result = {0};
|
||||
|
||||
if (buffer_get_token_index(app, buffer, pos, &get_result)){
|
||||
Statement_Parser parser = {0};
|
||||
parser.token_index = get_result.token_index;
|
||||
|
||||
if (parser.token_index < 0){
|
||||
parser.token_index = 0;
|
||||
}
|
||||
if (get_result.in_whitespace){
|
||||
parser.token_index += 1;
|
||||
}
|
||||
|
||||
static const int32_t chunk_cap = 512;
|
||||
Cpp_Token chunk[chunk_cap];
|
||||
|
||||
if (init_stream_tokens(&parser.stream, app, buffer, parser.token_index, chunk, chunk_cap)){
|
||||
parser.buffer = buffer;
|
||||
|
||||
Cpp_Token end_token = {0};
|
||||
if (parse_statement_down(app, &parser, &end_token)){
|
||||
end = end_token.start + end_token.size;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*start_out = start;
|
||||
*end_out = end;
|
||||
return(result);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(scope_absorb_down){
|
||||
uint32_t access = AccessOpen;
|
||||
View_Summary view = get_active_view(app, access);
|
||||
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
||||
|
||||
int32_t top = view.cursor.pos;
|
||||
int32_t bottom = view.mark.pos;
|
||||
|
||||
if (top > bottom){
|
||||
int32_t x = top;
|
||||
top = bottom;
|
||||
bottom = x;
|
||||
}
|
||||
|
||||
Partition *part = &global_part;
|
||||
|
||||
Temp_Memory temp = begin_temp_memory(part);
|
||||
if (buffer_get_char(app, &buffer, top) == '{' && buffer_get_char(app, &buffer, bottom-1) == '}'){
|
||||
Range range;
|
||||
if (find_whole_statement_down(app, &buffer, bottom, &range.start, &range.end)){
|
||||
char *string_space = push_array(part, char, range.end - range.start);
|
||||
buffer_read_range(app, &buffer, range.start, range.end, string_space);
|
||||
|
||||
String string = make_string(string_space, range.end - range.start);
|
||||
string = skip_chop_whitespace(string);
|
||||
|
||||
int32_t newline_count = 0;
|
||||
for (char *ptr = string_space; ptr < string.str; ++ptr){
|
||||
if (*ptr == '\n'){
|
||||
++newline_count;
|
||||
}
|
||||
}
|
||||
|
||||
bool32 extra_newline = false;
|
||||
if (newline_count >= 2){
|
||||
extra_newline = true;
|
||||
}
|
||||
|
||||
int32_t edit_len = string.size + 1;
|
||||
if (extra_newline){
|
||||
edit_len += 1;
|
||||
}
|
||||
|
||||
char *edit_str = push_array(part, char, edit_len);
|
||||
if (extra_newline){
|
||||
edit_str[0] = '\n';
|
||||
copy_fast_unsafe(edit_str+1, string);
|
||||
edit_str[edit_len-1] = '\n';
|
||||
}
|
||||
else{
|
||||
copy_fast_unsafe(edit_str, string);
|
||||
edit_str[edit_len-1] = '\n';
|
||||
}
|
||||
|
||||
Buffer_Edit edits[2];
|
||||
edits[0].str_start = 0;
|
||||
edits[0].len = edit_len;
|
||||
edits[0].start = bottom-1;
|
||||
edits[0].end = bottom-1;
|
||||
|
||||
edits[1].str_start = 0;
|
||||
edits[1].len = 0;
|
||||
edits[1].start = range.start;
|
||||
edits[1].end = range.end;
|
||||
|
||||
buffer_batch_edit(app, &buffer, edit_str, edit_len, edits, 2, BatchEdit_Normal);
|
||||
}
|
||||
}
|
||||
end_temp_memory(temp);
|
||||
}
|
||||
|
||||
// NOTE(allen): Some basic code manipulation ideas.
|
||||
|
||||
CUSTOM_COMMAND_SIG(rename_parameter){
|
||||
|
@ -890,17 +1223,17 @@ CUSTOM_COMMAND_SIG(write_explicit_enum_values){
|
|||
|
||||
++token_index;
|
||||
|
||||
int32_t closed_correctly = 0;
|
||||
int32_t seeker_index = token_index;
|
||||
Stream_Tokens seek_stream = begin_temp_stream_token(&stream);
|
||||
|
||||
int32_t still_looping = 0;
|
||||
bool32 closed_correctly = false;
|
||||
bool32 still_looping = false;
|
||||
do{
|
||||
for (; seeker_index < stream.end; ++seeker_index){
|
||||
Cpp_Token *token_seeker = stream.tokens + seeker_index;
|
||||
switch (token_seeker->type){
|
||||
case CPP_TOKEN_BRACE_CLOSE:
|
||||
closed_correctly = 1;
|
||||
closed_correctly = true;
|
||||
goto finished_seek;
|
||||
|
||||
case CPP_TOKEN_BRACE_OPEN:
|
||||
|
@ -915,15 +1248,15 @@ CUSTOM_COMMAND_SIG(write_explicit_enum_values){
|
|||
if (closed_correctly){
|
||||
int32_t count_estimate = 1 + (seeker_index - token_index)/2;
|
||||
|
||||
Buffer_Edit *edits = push_array(part, Buffer_Edit, count_estimate);
|
||||
int32_t edit_count = 0;
|
||||
Buffer_Edit *edits = push_array(part, Buffer_Edit, count_estimate);
|
||||
|
||||
char *string_base = (char*)partition_current(part);
|
||||
String string = make_string(string_base, 0, partition_remaining(part));
|
||||
|
||||
closed_correctly = false;
|
||||
still_looping = false;
|
||||
int32_t value = 0;
|
||||
closed_correctly = 0;
|
||||
still_looping = 0;
|
||||
do{
|
||||
for (;token_index < stream.end; ++token_index){
|
||||
Cpp_Token *token_ptr = stream.tokens + token_index;
|
||||
|
@ -1016,12 +1349,12 @@ get_bindings(void *data, int32_t size){
|
|||
Bind_Helper context_ = begin_bind_helper(data, size);
|
||||
Bind_Helper *context = &context_;
|
||||
|
||||
set_hook(context, hook_start, my_start);
|
||||
set_hook(context, hook_view_size_change, my_view_adjust);
|
||||
set_hook(context, hook_start, default_start);
|
||||
set_hook(context, hook_view_size_change, default_view_adjust);
|
||||
|
||||
set_open_file_hook(context, my_file_settings);
|
||||
set_save_file_hook(context, my_file_save);
|
||||
set_input_filter(context, my_suppress_mouse_filter);
|
||||
set_open_file_hook(context, default_file_settings);
|
||||
set_save_file_hook(context, default_file_save);
|
||||
set_input_filter(context, default_suppress_mouse_filter);
|
||||
set_command_caller(context, default_command_caller);
|
||||
|
||||
set_scroll_rule(context, smooth_scroll_rule);
|
||||
|
@ -1048,14 +1381,17 @@ get_bindings(void *data, int32_t size){
|
|||
|
||||
end_map(context);
|
||||
|
||||
begin_map(context, my_code_map);
|
||||
bind(context, '[', MDFR_ALT, highlight_surroundng_scope);
|
||||
begin_map(context, default_code_map);
|
||||
bind(context, '[', MDFR_ALT, highlight_surrounding_scope);
|
||||
bind(context, ']', MDFR_ALT, highlight_prev_scope_absolute);
|
||||
bind(context, '\'', MDFR_ALT, highlight_next_scope_absolute);
|
||||
|
||||
bind(context, '/', MDFR_ALT, place_in_scope);
|
||||
bind(context, '-', MDFR_ALT, delete_current_scope);
|
||||
bind(context, 'j', MDFR_ALT, scope_absorb_down);
|
||||
|
||||
bind(context, key_insert, MDFR_CTRL, write_explicit_enum_values);
|
||||
bind(context, 'p', MDFR_ALT, rename_parameter);
|
||||
bind(context, 'I', MDFR_CTRL, list_all_functions_current_buffer);
|
||||
end_map(context);
|
||||
|
||||
BIND_4CODER_TESTS(context);
|
||||
|
@ -1064,5 +1400,7 @@ get_bindings(void *data, int32_t size){
|
|||
return(result);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
/*
|
||||
4coder_miblo_numbers.cpp - Commands for so called "Miblo Number Operations" which involve incrementing
|
||||
and decrementing various forms of number as numerical objects despite being encoded as text objects.
|
||||
|
||||
#if !defined(MIBLO_NUMBERS_4CODER)
|
||||
#define MIBLO_NUMBERS_4CODER
|
||||
TYPE: 'drop-in-command-pack'
|
||||
*/
|
||||
|
||||
// TODO(allen): thevaber number converter idea
|
||||
// TOP
|
||||
|
||||
#if !defined(FCODER_MIBLO_NUMBERS_CPP)
|
||||
#define FCODER_MIBLO_NUMBERS_CPP
|
||||
|
||||
#include "4coder_API/custom.h"
|
||||
#include "4coder_helper/4coder_helper.h"
|
||||
#include "4coder_helper/4coder_streaming.h"
|
||||
|
||||
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){
|
||||
|
@ -198,14 +208,14 @@ increment_timestamp(Miblo_Timestamp t, int32_t type, int32_t amt){
|
|||
amt = 0;
|
||||
|
||||
// TODO(allen): someday do the math, instead of being lazy.
|
||||
while (r.second < 0){
|
||||
--amt;
|
||||
r.second += 60;
|
||||
while (r.second < 0){
|
||||
--amt;
|
||||
r.second += 60;
|
||||
}
|
||||
|
||||
while (r.second >= 60){
|
||||
++amt;
|
||||
r.second -= 60;
|
||||
while (r.second >= 60){
|
||||
++amt;
|
||||
r.second -= 60;
|
||||
}
|
||||
|
||||
case MIBLO_MINUTE:
|
||||
|
@ -236,7 +246,7 @@ timestamp_to_str(String *dest, Miblo_Timestamp t){
|
|||
|
||||
if (t.hour > 0){
|
||||
append_int_to_str(dest, t.hour);
|
||||
append(dest, ":");
|
||||
append(dest, ":");
|
||||
}
|
||||
|
||||
if (t.minute >= 10){
|
||||
|
@ -279,7 +289,7 @@ get_timestamp_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t
|
|||
int32_t count_colons = 0;
|
||||
for (int32_t i = 0; i < str.size; ++i){
|
||||
if (str.str[i] == ':'){
|
||||
++count_colons;
|
||||
++count_colons;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,19 +315,19 @@ get_timestamp_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t
|
|||
}
|
||||
|
||||
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]));
|
||||
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){
|
||||
|
||||
success = 1;
|
||||
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]));
|
||||
|
@ -331,10 +341,10 @@ get_timestamp_at_cursor(Application_Links *app, Buffer_Summary *buffer, int32_t
|
|||
}
|
||||
|
||||
if (success){
|
||||
info->start = timestamp_start;
|
||||
info->end = timestamp_end;
|
||||
info->time = t;
|
||||
result = 1;
|
||||
info->start = timestamp_start;
|
||||
info->end = timestamp_end;
|
||||
info->time = t;
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -378,4 +388,4 @@ CUSTOM_COMMAND_SIG(miblo_decrement_time_stamp_minute){
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
// BOTTOM
|
||||
|
|
|
@ -3,33 +3,14 @@ extensions=".c.cpp.h.hpp.bat.sh";
|
|||
fkey_command_win[1] = {"build.bat", "*compilation*", true};
|
||||
fkey_command_win[2] = {"site\\build.bat", "*compilation*", true};
|
||||
fkey_command_win[3] = {"string\\build.bat", "*compilation*", true};
|
||||
fkey_command_win[4] = {0, 0};
|
||||
|
||||
fkey_command_win[5] = {"..\\misc\\run.bat", "*run*"};
|
||||
fkey_command_win[6] = {0, 0};
|
||||
fkey_command_win[7] = {0, 0};
|
||||
fkey_command_win[8] = {0, 0};
|
||||
fkey_command_win[9] = {0, 0};
|
||||
fkey_command_win[10] = {0, 0};
|
||||
fkey_command_win[11] = {0, 0};
|
||||
fkey_command_win[8] = {"package.bat", "*package*"};
|
||||
fkey_command_win[13] = {0, 0};
|
||||
fkey_command_win[14] = {0, 0};
|
||||
fkey_command_win[15] = {0, 0};
|
||||
fkey_command_win[16] = {0, 0};
|
||||
|
||||
fkey_command_win[12] = {"package.bat", "*package*"};
|
||||
|
||||
fkey_command_linux[1] = {"./build.sh", "*compilation*", true};
|
||||
fkey_command_linux[2] = {"site/build.sh", "*compilation*", true};
|
||||
fkey_command_linux[3] = {0, 0};
|
||||
fkey_command_linux[4] = {0, 0};
|
||||
|
||||
fkey_command_linux[5] = {"../build/4ed", "*run*"};
|
||||
fkey_command_linux[6] = {0, 0};
|
||||
fkey_command_linux[7] = {0, 0};
|
||||
fkey_command_linux[8] = {0, 0};
|
||||
fkey_command_linux[9] = {0, 0};
|
||||
fkey_command_linux[10] = {0, 0};
|
||||
fkey_command_linux[11] = {0, 0};
|
||||
|
||||
fkey_command_linux[12] = {"./package.sh", "*package*"};
|
||||
fkey_command_linux[13] = {0, 0};
|
||||
fkey_command_linux[14] = {0, 0};
|
||||
fkey_command_linux[15] = {0, 0};
|
||||
fkey_command_linux[16] = {0, 0};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
1
|
||||
0
|
||||
59
|
||||
61
|
||||
|
||||
|
||||
|
|
Binary file not shown.
|
@ -230,6 +230,20 @@ considered immutable.) DOC_SEE(substr) */{
|
|||
return(result);
|
||||
}
|
||||
|
||||
CPP_NAME(skip_whitespace)
|
||||
API_EXPORT FSTRING_LINK String
|
||||
skip_whitespace_measure(String str, i32_4tech *skip_length)
|
||||
/* DOC(This call creates a substring that starts with the first non-whitespace character of str.
|
||||
Like other substr calls, the new string uses the underlying memory and so should usually be
|
||||
considered immutable.) DOC_SEE(substr) */{
|
||||
String result = {0};
|
||||
i32_4tech i = 0;
|
||||
for (; i < str.size && char_is_whitespace(str.str[i]); ++i);
|
||||
result = substr(str, i, str.size - i);
|
||||
*skip_length = i;
|
||||
return(result);
|
||||
}
|
||||
|
||||
API_EXPORT FSTRING_LINK String
|
||||
chop_whitespace(String str)
|
||||
/* DOC(This call creates a substring that ends with the last non-whitespace character of str.
|
||||
|
@ -251,6 +265,16 @@ DOC_SEE(skip_whitespace) DOC_SEE(chop_whitespace)*/{
|
|||
return(str);
|
||||
}
|
||||
|
||||
CPP_NAME(skip_chop_whitespace)
|
||||
API_EXPORT FSTRING_LINK String
|
||||
skip_chop_whitespace_measure(String str, i32_4tech *skip_length)
|
||||
/* DOC(This call is equivalent to calling skip_whitespace and chop_whitespace together.)
|
||||
DOC_SEE(skip_whitespace) DOC_SEE(chop_whitespace)*/{
|
||||
str = skip_whitespace_measure(str, skip_length);
|
||||
str = chop_whitespace(str);
|
||||
return(str);
|
||||
}
|
||||
|
||||
API_EXPORT_INLINE FSTRING_INLINE String
|
||||
tailstr(String str)
|
||||
/* DOC(This call returns an empty String with underlying memory taken from
|
||||
|
@ -1880,7 +1904,7 @@ static void
|
|||
get_absolutes(String name, Absolutes *absolutes, b32_4tech implicit_first, b32_4tech implicit_last){
|
||||
if (name.size != 0){
|
||||
i32_4tech count = 0;
|
||||
i32_4tech max = ArrayCount(absolutes->a) - 1;
|
||||
i32_4tech max = (sizeof(absolutes->a)/sizeof(*absolutes->a)) - 1;
|
||||
if (implicit_last) --max;
|
||||
|
||||
String str;
|
||||
|
|
622
win32_4ed.cpp
622
win32_4ed.cpp
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include <Windows.h>
|
||||
#include <GL/gl.h>
|
||||
#include "win32_gl.h"
|
||||
|
||||
#define GL_TEXTURE_MAX_LEVEL 0x813D
|
||||
|
||||
|
@ -594,7 +595,7 @@ Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
|||
system_acquire_lock(CANCEL_LOCK0 + memory->id - 1);
|
||||
void *old_data = memory->data;
|
||||
i32 old_size = memory->size;
|
||||
i32 new_size = l_round_up(memory->size*2, KB(4));
|
||||
i32 new_size = l_round_up_i32(memory->size*2, KB(4));
|
||||
memory->data = system_get_memory(new_size);
|
||||
memory->size = new_size;
|
||||
if (old_data){
|
||||
|
@ -1575,6 +1576,148 @@ Win32Resize(i32 width, i32 height){
|
|||
}
|
||||
}
|
||||
|
||||
internal void*
|
||||
win32_load_gl_always(char *name, HMODULE module){
|
||||
void *p = (void *)wglGetProcAddress(name), *r = 0;
|
||||
if(p == 0 ||
|
||||
(p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
|
||||
(p == (void*)-1) ){
|
||||
r = (void *)GetProcAddress(module, name);
|
||||
}
|
||||
else{
|
||||
r = p;
|
||||
}
|
||||
return(r);
|
||||
}
|
||||
|
||||
internal void
|
||||
OpenGLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
|
||||
{
|
||||
OutputDebugStringA(message);
|
||||
OutputDebugStringA("\n");
|
||||
}
|
||||
|
||||
internal void
|
||||
Win32InitGL(){
|
||||
// GL context initialization
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR format;
|
||||
int format_id;
|
||||
BOOL success;
|
||||
HDC dc;
|
||||
|
||||
format.nSize = sizeof(format);
|
||||
format.nVersion = 1;
|
||||
format.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
|
||||
format.iPixelType = PFD_TYPE_RGBA;
|
||||
format.cColorBits = 32;
|
||||
format.cRedBits = 0;
|
||||
format.cRedShift = 0;
|
||||
format.cGreenBits = 0;
|
||||
format.cGreenShift = 0;
|
||||
format.cBlueBits = 0;
|
||||
format.cBlueShift = 0;
|
||||
format.cAlphaBits = 0;
|
||||
format.cAlphaShift = 0;
|
||||
format.cAccumBits = 0;
|
||||
format.cAccumRedBits = 0;
|
||||
format.cAccumGreenBits = 0;
|
||||
format.cAccumBlueBits = 0;
|
||||
format.cAccumAlphaBits = 0;
|
||||
format.cDepthBits = 24;
|
||||
format.cStencilBits = 8;
|
||||
format.cAuxBuffers = 0;
|
||||
format.iLayerType = PFD_MAIN_PLANE;
|
||||
format.bReserved = 0;
|
||||
format.dwLayerMask = 0;
|
||||
format.dwVisibleMask = 0;
|
||||
format.dwDamageMask = 0;
|
||||
|
||||
dc = GetDC(win32vars.window_handle);
|
||||
Assert(dc);
|
||||
format_id = ChoosePixelFormat(dc, &format);
|
||||
Assert(format_id != 0);
|
||||
success = SetPixelFormat(dc, format_id, &format);
|
||||
Assert(success == TRUE);
|
||||
|
||||
HGLRC glcontext = wglCreateContext(dc);
|
||||
wglMakeCurrent(dc, glcontext);
|
||||
|
||||
{
|
||||
HMODULE module = LoadLibraryA("opengl32.dll");
|
||||
|
||||
wglCreateContextAttribsARB_Function *wglCreateContextAttribsARB = 0;
|
||||
wglCreateContextAttribsARB = (wglCreateContextAttribsARB_Function*)
|
||||
win32_load_gl_always("wglCreateContextAttribsARB", module);
|
||||
|
||||
wglChoosePixelFormatARB_Function *wglChoosePixelFormatARB = 0;
|
||||
wglChoosePixelFormatARB = (wglChoosePixelFormatARB_Function*)
|
||||
win32_load_gl_always("wglChoosePixelFormatARB", module);
|
||||
|
||||
if (wglCreateContextAttribsARB != 0 && wglChoosePixelFormatARB != 0){
|
||||
const int choosePixel_attribList[] =
|
||||
{
|
||||
WGL_DRAW_TO_WINDOW_ARB, TRUE,
|
||||
WGL_SUPPORT_OPENGL_ARB, TRUE,
|
||||
//WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
|
||||
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
|
||||
WGL_COLOR_BITS_ARB, 32,
|
||||
WGL_DEPTH_BITS_ARB, 24,
|
||||
WGL_STENCIL_BITS_ARB, 8,
|
||||
0,
|
||||
};
|
||||
|
||||
i32 extended_format_id;
|
||||
UINT num_formats = 0;
|
||||
BOOL result = 0;
|
||||
|
||||
result = wglChoosePixelFormatARB(dc, choosePixel_attribList, 0, 1, &extended_format_id, &num_formats);
|
||||
|
||||
if (result != 0 && num_formats > 0){
|
||||
const int createContext_attribList[] = {
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||
0
|
||||
};
|
||||
|
||||
if (extended_format_id == format_id){
|
||||
HGLRC extended_context = wglCreateContextAttribsARB(dc, 0, createContext_attribList);
|
||||
if (extended_context){
|
||||
wglMakeCurrent(dc, extended_context);
|
||||
wglDeleteContext(glcontext);
|
||||
glcontext = extended_context;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseDC(win32vars.window_handle, dc);
|
||||
}
|
||||
|
||||
#if FRED_INTERNAL
|
||||
// NOTE(casey): This slows down GL but puts error messages to
|
||||
// the debug console immediately whenever you do something wrong
|
||||
glDebugMessageCallback_type *glDebugMessageCallback =
|
||||
(glDebugMessageCallback_type *)wglGetProcAddress("glDebugMessageCallback");
|
||||
glDebugMessageControl_type *glDebugMessageControl =
|
||||
(glDebugMessageControl_type *)wglGetProcAddress("glDebugMessageControl");
|
||||
if(glDebugMessageCallback && glDebugMessageControl)
|
||||
{
|
||||
glDebugMessageCallback(OpenGLDebugCallback, 0);
|
||||
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
#endif
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
internal void
|
||||
Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){
|
||||
switch (cursor){
|
||||
|
@ -1602,6 +1745,120 @@ Win32HighResolutionTime(){
|
|||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
Win32Foo(WPARAM wParam, LPARAM lParam){
|
||||
b8 previous_state = ((lParam & Bit_30)?(1):(0));
|
||||
b8 current_state = ((lParam & Bit_31)?(0):(1));
|
||||
|
||||
if (current_state){
|
||||
u8 key = keycode_lookup_table[(u8)wParam];
|
||||
|
||||
i32 *count = &win32vars.input_chunk.trans.key_data.count;
|
||||
Key_Event_Data *data = win32vars.input_chunk.trans.key_data.keys;
|
||||
b8 *control_keys = win32vars.input_chunk.pers.control_keys;
|
||||
i32 control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys);
|
||||
|
||||
if (*count < KEY_INPUT_BUFFER_SIZE){
|
||||
if (!key){
|
||||
UINT vk = (UINT)wParam;
|
||||
UINT scan = (UINT)((lParam >> 16) & 0x7F);
|
||||
BYTE state[256];
|
||||
BYTE control_state = 0;
|
||||
WORD x1 = 0, x2 = 0, x = 0, junk_x;
|
||||
i32 result1 = 0, result2 = 0, result = 0;
|
||||
|
||||
GetKeyboardState(state);
|
||||
x1 = 0;
|
||||
result1 = ToAscii(vk, scan, state, &x1, 0);
|
||||
if (result1 < 0){
|
||||
ToAscii(vk, scan, state, &junk_x, 0);
|
||||
}
|
||||
result1 = (result1 == 1);
|
||||
if (!usable_ascii((char)x1)){
|
||||
result1 = 0;
|
||||
}
|
||||
|
||||
control_state = state[VK_CONTROL];
|
||||
state[VK_CONTROL] = 0;
|
||||
x2 = 0;
|
||||
result2 = ToAscii(vk, scan, state, &x2, 0);
|
||||
if (result2 < 0){
|
||||
ToAscii(vk, scan, state, &junk_x, 0);
|
||||
}
|
||||
result2 = (result2 == 1);
|
||||
if (!usable_ascii((char)x2)){
|
||||
result2 = 0;
|
||||
}
|
||||
|
||||
// TODO(allen): This is becoming a really major issue.
|
||||
// Apparently control + i outputs a '\t' which is VALID ascii
|
||||
// according to this system. So it reports the key as '\t'.
|
||||
// This wasn't an issue before because we were ignoring control
|
||||
// when computing character_no_caps_lock which is what is used
|
||||
// for commands. But that is incorrect for some keyboard layouts
|
||||
// where control+alt is used to signal AltGr for important keys.
|
||||
if (result1 && result2){
|
||||
char c1 = char_to_upper((char)x1);
|
||||
char cParam = char_to_upper((char)wParam);
|
||||
|
||||
if ((c1 == '\n' || c1 == '\r') && cParam != VK_RETURN){
|
||||
result1 = 0;
|
||||
}
|
||||
if (c1 == '\t' && cParam != VK_TAB){
|
||||
result1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (result1){
|
||||
x = x1;
|
||||
state[VK_CONTROL] = control_state;
|
||||
result = 1;
|
||||
}
|
||||
else if (result2){
|
||||
x = x2;
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (result == 1 && x < 128){
|
||||
key = (u8)x;
|
||||
if (key == '\r') key = '\n';
|
||||
data[*count].character = key;
|
||||
|
||||
state[VK_CAPITAL] = 0;
|
||||
x = 0;
|
||||
result = ToAscii(vk, scan, state, &x, 0);
|
||||
if (result < 0){
|
||||
ToAscii(vk, scan, state, &junk_x, 0);
|
||||
}
|
||||
result = (result == 1);
|
||||
if (!usable_ascii((char)x)){
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if (result){
|
||||
key = (u8)x;
|
||||
if (key == '\r') key = '\n';
|
||||
data[*count].character_no_caps_lock = key;
|
||||
data[*count].keycode = key;
|
||||
}
|
||||
}
|
||||
if (result != 1 || x >= 128){
|
||||
data[*count].character = 0;
|
||||
data[*count].character_no_caps_lock = 0;
|
||||
data[*count].keycode = 0;
|
||||
}
|
||||
}
|
||||
else{
|
||||
data[*count].character = 0;
|
||||
data[*count].character_no_caps_lock = 0;
|
||||
data[*count].keycode = key;
|
||||
}
|
||||
memcpy(data[*count].modifiers, control_keys, control_keys_size);
|
||||
data[*count].modifiers[MDFR_HOLD_INDEX] = previous_state;
|
||||
++(*count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal LRESULT
|
||||
|
@ -1609,8 +1866,7 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
|||
LRESULT result = 0;
|
||||
|
||||
switch (uMsg){
|
||||
case WM_MENUCHAR:
|
||||
case WM_SYSCHAR:break;
|
||||
case WM_MENUCHAR:break;
|
||||
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
|
@ -1648,9 +1904,8 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
|||
}break;
|
||||
}
|
||||
|
||||
b8 ctrl, alt;
|
||||
ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt));
|
||||
alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl));
|
||||
b8 ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt));
|
||||
b8 alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl));
|
||||
|
||||
if (win32vars.lctrl_lalt_is_altgr){
|
||||
if (controls->l_alt && controls->l_ctrl){
|
||||
|
@ -1666,136 +1921,71 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
|||
|
||||
default:
|
||||
{
|
||||
b8 previous_state = ((lParam & Bit_30)?(1):(0));
|
||||
b8 current_state = ((lParam & Bit_31)?(0):(1));
|
||||
|
||||
win32vars.got_useful_event = 1;
|
||||
|
||||
if (current_state){
|
||||
u8 key = keycode_lookup_table[(u8)wParam];
|
||||
|
||||
i32 *count = 0;
|
||||
Key_Event_Data *data = 0;
|
||||
b8 *control_keys = 0;
|
||||
i32 control_keys_size = 0;
|
||||
|
||||
if (!previous_state){
|
||||
count = &win32vars.input_chunk.trans.key_data.press_count;
|
||||
data = win32vars.input_chunk.trans.key_data.press;
|
||||
}
|
||||
else{
|
||||
count = &win32vars.input_chunk.trans.key_data.hold_count;
|
||||
data = win32vars.input_chunk.trans.key_data.hold;
|
||||
}
|
||||
control_keys = win32vars.input_chunk.pers.control_keys;
|
||||
control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys);
|
||||
|
||||
if (*count < KEY_INPUT_BUFFER_SIZE){
|
||||
if (!key){
|
||||
UINT vk = (UINT)wParam;
|
||||
UINT scan = (UINT)((lParam >> 16) & 0x7F);
|
||||
BYTE state[256];
|
||||
BYTE control_state = 0;
|
||||
WORD x1 = 0, x2 = 0, x = 0, junk_x;
|
||||
i32 result1 = 0, result2 = 0, result = 0;
|
||||
|
||||
GetKeyboardState(state);
|
||||
x1 = 0;
|
||||
result1 = ToAscii(vk, scan, state, &x1, 0);
|
||||
if (result1 < 0){
|
||||
ToAscii(vk, scan, state, &junk_x, 0);
|
||||
}
|
||||
result1 = (result1 == 1);
|
||||
if (!usable_ascii((char)x1)){
|
||||
result1 = 0;
|
||||
}
|
||||
|
||||
control_state = state[VK_CONTROL];
|
||||
state[VK_CONTROL] = 0;
|
||||
x2 = 0;
|
||||
result2 = ToAscii(vk, scan, state, &x2, 0);
|
||||
if (result2 < 0){
|
||||
ToAscii(vk, scan, state, &junk_x, 0);
|
||||
}
|
||||
result2 = (result2 == 1);
|
||||
if (!usable_ascii((char)x2)){
|
||||
result2 = 0;
|
||||
}
|
||||
|
||||
// TODO(allen): This is becoming a really major issue.
|
||||
// Apparently control + i outputs a '\t' which is VALID ascii
|
||||
// according to this system. So it reports the key as '\t'.
|
||||
// This wasn't an issue before because we were ignoring control
|
||||
// when computing character_no_caps_lock which is what is used
|
||||
// for commands. But that is incorrect for some keyboard layouts
|
||||
// where control+alt is used to signal AltGr for important keys.
|
||||
if (result1 && result2){
|
||||
char c1 = char_to_upper((char)x1);
|
||||
char cParam = char_to_upper((char)wParam);
|
||||
|
||||
if ((c1 == '\n' || c1 == '\r') && cParam != VK_RETURN){
|
||||
result1 = 0;
|
||||
}
|
||||
if (c1 == '\t' && cParam != VK_TAB){
|
||||
result1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (result1){
|
||||
x = x1;
|
||||
state[VK_CONTROL] = control_state;
|
||||
result = 1;
|
||||
}
|
||||
else if (result2){
|
||||
x = x2;
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (result == 1 && x < 128){
|
||||
key = (u8)x;
|
||||
if (key == '\r') key = '\n';
|
||||
data[*count].character = key;
|
||||
|
||||
state[VK_CAPITAL] = 0;
|
||||
x = 0;
|
||||
result = ToAscii(vk, scan, state, &x, 0);
|
||||
if (result < 0){
|
||||
ToAscii(vk, scan, state, &junk_x, 0);
|
||||
}
|
||||
result = (result == 1);
|
||||
if (!usable_ascii((char)x)){
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if (result){
|
||||
key = (u8)x;
|
||||
if (key == '\r') key = '\n';
|
||||
data[*count].character_no_caps_lock = key;
|
||||
data[*count].keycode = key;
|
||||
}
|
||||
}
|
||||
if (result != 1 || x >= 128){
|
||||
data[*count].character = 0;
|
||||
data[*count].character_no_caps_lock = 0;
|
||||
data[*count].keycode = 0;
|
||||
}
|
||||
}
|
||||
else{
|
||||
data[*count].character = 0;
|
||||
data[*count].character_no_caps_lock = 0;
|
||||
data[*count].keycode = key;
|
||||
}
|
||||
if (key != 0){
|
||||
i32 *count = &win32vars.input_chunk.trans.key_data.count;
|
||||
Key_Event_Data *data = win32vars.input_chunk.trans.key_data.keys;
|
||||
b8 *control_keys = win32vars.input_chunk.pers.control_keys;
|
||||
i32 control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys);
|
||||
|
||||
Assert(*count < KEY_INPUT_BUFFER_SIZE);
|
||||
data[*count].character = 0;
|
||||
data[*count].character_no_caps_lock = 0;
|
||||
data[*count].keycode = key;
|
||||
memcpy(data[*count].modifiers, control_keys, control_keys_size);
|
||||
data[*count].modifiers[MDFR_HOLD_INDEX] = previous_state;
|
||||
++(*count);
|
||||
|
||||
win32vars.got_useful_event = 1;
|
||||
}
|
||||
}
|
||||
|
||||
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}break;
|
||||
}/* switch */
|
||||
}break;
|
||||
|
||||
case WM_CHAR: case WM_SYSCHAR: case WM_UNICHAR:
|
||||
{
|
||||
u8 character = wParam & 0x7F;
|
||||
|
||||
if (character == '\r'){
|
||||
character = '\n';
|
||||
}
|
||||
else if ((character < 32 && character != '\t') || character == 127){
|
||||
break;
|
||||
}
|
||||
|
||||
u8 character_no_caps_lock = character;
|
||||
|
||||
i32 *count = &win32vars.input_chunk.trans.key_data.count;
|
||||
Key_Event_Data *data = win32vars.input_chunk.trans.key_data.keys;
|
||||
b8 *control_keys = win32vars.input_chunk.pers.control_keys;
|
||||
i32 control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys);
|
||||
|
||||
BYTE state[256];
|
||||
GetKeyboardState(state);
|
||||
if (state[VK_CAPITAL]){
|
||||
if (character_no_caps_lock >= 'a' && character_no_caps_lock <= 'z'){
|
||||
character_no_caps_lock += (u8)('A' - 'a');
|
||||
}
|
||||
else if (character_no_caps_lock >= 'A' && character_no_caps_lock <= 'Z'){
|
||||
character_no_caps_lock += (u8)('a' - 'A');
|
||||
}
|
||||
}
|
||||
|
||||
Assert(*count < KEY_INPUT_BUFFER_SIZE);
|
||||
data[*count].character = character;
|
||||
data[*count].character_no_caps_lock = character_no_caps_lock;
|
||||
data[*count].keycode = character_no_caps_lock;
|
||||
memcpy(data[*count].modifiers, control_keys, control_keys_size);
|
||||
++(*count);
|
||||
|
||||
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
win32vars.got_useful_event = 1;
|
||||
}break;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
i32 new_x = LOWORD(lParam);
|
||||
|
@ -1865,12 +2055,10 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
|||
case WM_SIZE:
|
||||
{
|
||||
win32vars.got_useful_event = 1;
|
||||
if (win32vars.target.handle){
|
||||
i32 new_width = LOWORD(lParam);
|
||||
i32 new_height = HIWORD(lParam);
|
||||
|
||||
Win32Resize(new_width, new_height);
|
||||
}
|
||||
i32 new_width = LOWORD(lParam);
|
||||
i32 new_height = HIWORD(lParam);
|
||||
|
||||
Win32Resize(new_width, new_height);
|
||||
}break;
|
||||
|
||||
case WM_PAINT:
|
||||
|
@ -1907,21 +2095,6 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
|||
return(result);
|
||||
}
|
||||
|
||||
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
|
||||
#define GL_DEBUG_OUTPUT 0x92E0
|
||||
|
||||
typedef void GLDEBUGPROC_TYPE(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char * message, const GLvoid * userParam);
|
||||
typedef GLDEBUGPROC_TYPE * GLDEBUGPROC;
|
||||
typedef void glDebugMessageControl_type(GLenum source, GLenum type, GLenum severity, GLsizei count, GLuint * ids, GLboolean enabled);
|
||||
typedef void glDebugMessageCallback_type(GLDEBUGPROC callback, void * userParam);
|
||||
|
||||
internal void
|
||||
OpenGLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
|
||||
{
|
||||
OutputDebugStringA(message);
|
||||
OutputDebugStringA("\n");
|
||||
}
|
||||
|
||||
int
|
||||
WinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
|
@ -2177,65 +2350,9 @@ WinMain(HINSTANCE hInstance,
|
|||
#endif
|
||||
|
||||
GetClientRect(win32vars.window_handle, &window_rect);
|
||||
|
||||
DWORD pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
|
||||
|
||||
// NOTE(allen): This is probably not an issue on linux and
|
||||
// does not need to be ported.
|
||||
if (!win32vars.settings.stream_mode){
|
||||
pfd_flags |= PFD_DOUBLEBUFFER;
|
||||
}
|
||||
|
||||
static PIXELFORMATDESCRIPTOR pfd = {
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
1,
|
||||
pfd_flags,
|
||||
PFD_TYPE_RGBA,
|
||||
32,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 0, 0, 0,
|
||||
16,
|
||||
0,
|
||||
0,
|
||||
PFD_MAIN_PLANE,
|
||||
0,
|
||||
0, 0, 0 };
|
||||
// TODO(allen): get an upgraded context to see if that fixes the nvidia card issues.
|
||||
{
|
||||
i32 pixel_format;
|
||||
pixel_format = ChoosePixelFormat(hdc, &pfd);
|
||||
SetPixelFormat(hdc, pixel_format, &pfd);
|
||||
|
||||
win32vars.target.handle = hdc;
|
||||
win32vars.target.context = wglCreateContext(hdc);
|
||||
wglMakeCurrent(hdc, (HGLRC)win32vars.target.context);
|
||||
}
|
||||
ReleaseDC(win32vars.window_handle, hdc);
|
||||
|
||||
#if FRED_INTERNAL
|
||||
// NOTE(casey): This slows down GL but puts error messages to
|
||||
// the debug console immediately whenever you do something wrong
|
||||
glDebugMessageCallback_type *glDebugMessageCallback =
|
||||
(glDebugMessageCallback_type *)wglGetProcAddress("glDebugMessageCallback");
|
||||
glDebugMessageControl_type *glDebugMessageControl =
|
||||
(glDebugMessageControl_type *)wglGetProcAddress("glDebugMessageControl");
|
||||
if(glDebugMessageCallback && glDebugMessageControl)
|
||||
{
|
||||
glDebugMessageCallback(OpenGLDebugCallback, 0);
|
||||
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
#endif
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
Win32InitGL();
|
||||
Win32Resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top);
|
||||
|
||||
|
||||
|
@ -2316,28 +2433,96 @@ WinMain(HINSTANCE hInstance,
|
|||
if (!(win32vars.first && win32vars.settings.stream_mode)){
|
||||
system_release_lock(FRAME_LOCK);
|
||||
|
||||
if (win32vars.running_cli == 0){
|
||||
win32vars.got_useful_event = 0;
|
||||
for (;win32vars.got_useful_event == 0;){
|
||||
if (GetMessage(&msg, 0, 0, 0)){
|
||||
if (msg.message == WM_QUIT){
|
||||
keep_playing = 0;
|
||||
}else{
|
||||
b32 get_more_messages = true;
|
||||
do{
|
||||
if (win32vars.got_useful_event == 0){
|
||||
get_more_messages = GetMessage(&msg, 0, 0, 0);
|
||||
}
|
||||
else{
|
||||
get_more_messages = PeekMessage(&msg, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
if (get_more_messages){
|
||||
if (msg.message == WM_QUIT){
|
||||
keep_playing = 0;
|
||||
}else{
|
||||
b32 treat_normally = true;
|
||||
if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN){
|
||||
switch (msg.wParam){
|
||||
case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL:
|
||||
case VK_MENU:case VK_LMENU:case VK_RMENU:
|
||||
case VK_SHIFT:case VK_LSHIFT:case VK_RSHIFT:break;
|
||||
|
||||
default: treat_normally = false; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (treat_normally){
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
else{
|
||||
Control_Keys *controls = &win32vars.input_chunk.pers.controls;
|
||||
|
||||
b8 ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt));
|
||||
b8 alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl));
|
||||
|
||||
if (win32vars.lctrl_lalt_is_altgr){
|
||||
if (controls->l_alt && controls->l_ctrl){
|
||||
ctrl = 0;
|
||||
alt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BYTE ctrl_state = 0, alt_state = 0;
|
||||
BYTE state[256];
|
||||
if (ctrl || alt){
|
||||
GetKeyboardState(state);
|
||||
if (ctrl){
|
||||
ctrl_state = state[VK_CONTROL];
|
||||
state[VK_CONTROL] = 0;
|
||||
}
|
||||
if (alt){
|
||||
alt_state = state[VK_MENU];
|
||||
state[VK_MENU] = 0;
|
||||
}
|
||||
SetKeyboardState(state);
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
|
||||
if (ctrl){
|
||||
state[VK_CONTROL] = ctrl_state;
|
||||
}
|
||||
if (alt){
|
||||
state[VK_MENU] = alt_state;
|
||||
}
|
||||
SetKeyboardState(state);
|
||||
}
|
||||
else{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
#if 0
|
||||
UINT count = 0;
|
||||
INPUT in[1];
|
||||
if (ctrl){
|
||||
in[count].type = INPUT_KEYBOARD;
|
||||
in[count].ki.wVk = VK_CONTROL;
|
||||
in[count].ki.wScan = 0;
|
||||
in[count].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
in[count].ki.time = 0;
|
||||
in[count].ki.dwExtraInfo = GetMessageExtraInfo();
|
||||
++count;
|
||||
}
|
||||
if(count > 0){
|
||||
SendInput(count, in, sizeof(in));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (PeekMessage(&msg, 0, 0, 0, 1)){
|
||||
if (msg.message == WM_QUIT){
|
||||
keep_playing = 0;
|
||||
}else{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}while(get_more_messages);
|
||||
|
||||
system_acquire_lock(FRAME_LOCK);
|
||||
}
|
||||
|
@ -2398,7 +2583,6 @@ WinMain(HINSTANCE hInstance,
|
|||
input.dt = frame_useconds / 1000000.f;
|
||||
|
||||
input.keys = input_chunk.trans.key_data;
|
||||
memcpy(input.keys.modifiers, input_chunk.pers.control_keys, sizeof(input_chunk.pers.control_keys));
|
||||
|
||||
input.mouse.out_of_window = input_chunk.trans.out_of_window;
|
||||
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
WGL declarations for 4coder.
|
||||
By Allen Webster
|
||||
Created 27.01.2017 (dd.mm.yyyy)
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
|
||||
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||
#define WGL_DRAW_TO_BITMAP_ARB 0x2002
|
||||
#define WGL_ACCELERATION_ARB 0x2003
|
||||
#define WGL_NEED_PALETTE_ARB 0x2004
|
||||
#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
|
||||
#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
|
||||
#define WGL_SWAP_METHOD_ARB 0x2007
|
||||
#define WGL_NUMBER_OVERLAYS_ARB 0x2008
|
||||
#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
|
||||
#define WGL_TRANSPARENT_ARB 0x200A
|
||||
#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
|
||||
#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
|
||||
#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
|
||||
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
|
||||
#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
|
||||
#define WGL_SHARE_DEPTH_ARB 0x200C
|
||||
#define WGL_SHARE_STENCIL_ARB 0x200D
|
||||
#define WGL_SHARE_ACCUM_ARB 0x200E
|
||||
#define WGL_SUPPORT_GDI_ARB 0x200F
|
||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||
#define WGL_STEREO_ARB 0x2012
|
||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||
#define WGL_COLOR_BITS_ARB 0x2014
|
||||
#define WGL_RED_BITS_ARB 0x2015
|
||||
#define WGL_RED_SHIFT_ARB 0x2016
|
||||
#define WGL_GREEN_BITS_ARB 0x2017
|
||||
#define WGL_GREEN_SHIFT_ARB 0x2018
|
||||
#define WGL_BLUE_BITS_ARB 0x2019
|
||||
#define WGL_BLUE_SHIFT_ARB 0x201A
|
||||
#define WGL_ALPHA_BITS_ARB 0x201B
|
||||
#define WGL_ALPHA_SHIFT_ARB 0x201C
|
||||
#define WGL_ACCUM_BITS_ARB 0x201D
|
||||
#define WGL_ACCUM_RED_BITS_ARB 0x201E
|
||||
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
|
||||
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
|
||||
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
|
||||
#define WGL_DEPTH_BITS_ARB 0x2022
|
||||
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||
#define WGL_AUX_BUFFERS_ARB 0x2024
|
||||
#define WGL_NO_ACCELERATION_ARB 0x2025
|
||||
#define WGL_GENERIC_ACCELERATION_ARB 0x2026
|
||||
#define WGL_FULL_ACCELERATION_ARB 0x2027
|
||||
#define WGL_SWAP_EXCHANGE_ARB 0x2028
|
||||
#define WGL_SWAP_COPY_ARB 0x2029
|
||||
#define WGL_SWAP_UNDEFINED_ARB 0x202A
|
||||
#define WGL_TYPE_RGBA_ARB 0x202B
|
||||
#define WGL_TYPE_COLORINDEX_ARB 0x202C
|
||||
typedef BOOL wglChoosePixelFormatARB_Function(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
||||
|
||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
||||
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
|
||||
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
||||
#define ERROR_INVALID_VERSION_ARB 0x2095
|
||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||
typedef HGLRC wglCreateContextAttribsARB_Function(HDC hDC, HGLRC hshareContext, const int *attribList);
|
||||
|
||||
typedef const char* wglGetExtensionsStringARB_Function(HDC hdc);
|
||||
|
||||
typedef void GLDEBUGPROC_TYPE(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char * message, const GLvoid * userParam);
|
||||
typedef GLDEBUGPROC_TYPE * GLDEBUGPROC;
|
||||
typedef void glDebugMessageControl_type(GLenum source, GLenum type, GLenum severity, GLsizei count, GLuint * ids, GLboolean enabled);
|
||||
typedef void glDebugMessageCallback_type(GLDEBUGPROC callback, void * userParam);
|
||||
|
||||
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
|
||||
#define GL_DEBUG_OUTPUT 0x92E0
|
||||
|
||||
// BOTTOM
|
||||
|
Loading…
Reference in New Issue