4.0.15 various bug fixes, feature polish, added experimental scope command

This commit is contained in:
Allen Webster 2017-01-28 19:03:23 -05:00
parent e410404208
commit 0417cab3d0
40 changed files with 3601 additions and 2822 deletions

View File

@ -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

234
4coder_build_commands.cpp Normal file
View File

@ -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

147
4coder_clipboard.cpp Normal file
View File

@ -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

View File

@ -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

View File

@ -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

255
4coder_default_hooks.cpp Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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;

428
4coder_project_commands.cpp Normal file
View File

@ -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(&current_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 = &current_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

53
4coder_system_command.cpp Normal file
View File

@ -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
View File

@ -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
View File

@ -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;

View File

@ -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);
}
*/

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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);

Binary file not shown.

View File

@ -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);

View File

@ -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)

BIN
custom_4coder.dll Normal file

Binary file not shown.

BIN
custom_4coder.pdb Normal file

Binary file not shown.

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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};

View File

@ -1,5 +1,5 @@
1
0
59
61

Binary file not shown.

View File

@ -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;

View File

@ -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;

83
win32_gl.h Normal file
View File

@ -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