simplify gitignore
[vg.git] / src / vg / vg_console.h
index 07a90d2416813c16d693d9609aafda80c2e44c3a..b0758c1f4a64c5429d92ca65a1f645c77d6bbb2f 100644 (file)
@@ -1,10 +1,20 @@
-// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
+/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
+
+#ifndef VG_CONSOLE_H
+#define VG_CONSOLE_H
+
+#include "vg/vg_ui.h"
+#include "vg/vg_log.h"
+
+typedef struct vg_convar vg_convar;
+typedef struct vg_cmd vg_cmd;
 
 struct vg_console
 {
        struct vg_convar
        {
                void *data;
+      void (*update)(void);
                const char *name;
                
                enum vg_convar_dtype
@@ -20,158 +30,161 @@ struct vg_console
                        struct
                        {
                                int min, max, clamp;
-                       } opt_i32;
+                       } 
+         opt_i32;
+
+         struct
+         {
+            float min, max;
+            int clamp;
+         }
+         opt_f32;
                };
 
-               int persistent; // Should be stored to cfg/auto.conf
+               int persistent; /* Should this var be stored to cfg/auto.conf? */
        } 
-       *convars;
+       convars[ 32 ];
        
        struct vg_cmd
        {
                int (*function)( int argc, char const *argv[] );
                const char *name;
        }
-       *functions;
-       
-       char lines[16][512];
-       u32 current, len;
+       functions[ 32 ];
+
+   u32 convar_count, function_count;
        
-       char input[512];
+       char input[96];
        int cursor_user, cursor_pos, string_length;
        
-       char history[32][512];
+       char history[32][96];
        int history_last, history_pos, history_count;
        
        int enabled;
-       int scale;
 }
-vg_console = { .scale = 1 };
-
-// Declerations
-// ------------
+vg_console;
 
-// Registration
-static void vg_convar_push( struct vg_convar cv );
-static void vg_function_push( struct vg_cmd cmd );
+VG_STATIC void vg_convar_push( struct vg_convar cv );
+VG_STATIC void vg_function_push( struct vg_cmd cmd );
 
-static void vg_console_draw( void );
+VG_STATIC void vg_console_draw( void );
 void vg_console_println( const char *str );
-static int vg_console_list( int argc, char const *argv[] );
-static void vg_console_init(void);
-static void vg_console_write_persistent(void);
-static void vg_console_free(void);
-static void execute_console_input( const char *cmd );
-
-// Console interface
-// -----------------
-
-static void console_make_selection( int* start, int* end );
-static void console_move_cursor( int* cursor0, int* cursor1, int dir, int snap_together );
-static int console_makeroom( int datastart, int length );
-static int console_delete_char( int direction );
-static void console_to_clipboard(void);
-static void console_clipboard_paste(void);
-static void console_put_char( char c );
-static void console_history_get( char* buf, int entry_num );
-static void console_proc_key( GLFWwindow* ptrW, int key, int scancode, int action, int mods );
-static void console_proc_wchar( GLFWwindow* ptrW, u32 uWchar );
-static int vg_console_enabled(void);
-
-// =========================================================================================================
-// Implementation
-
-static int vg_console_enabled(void) 
+VG_STATIC int vg_console_list( int argc, char const *argv[] );
+VG_STATIC void vg_console_init(void);
+VG_STATIC void vg_console_write_persistent(void);
+VG_STATIC void vg_console_free(void);
+VG_STATIC void execute_console_input( const char *cmd );
+
+/*
+ * Console interface
+ */
+VG_STATIC void console_make_selection( int* start, int* end );
+VG_STATIC void console_move_cursor( int* cursor0, int* cursor1, 
+                                    int dir, int snap_together );
+VG_STATIC int console_makeroom( int datastart, int length );
+VG_STATIC int console_delete_char( int direction );
+VG_STATIC void console_to_clipboard(void);
+VG_STATIC void console_clipboard_paste(void);
+VG_STATIC void console_put_char( char c );
+VG_STATIC void console_history_get( char* buf, int entry_num );
+VG_STATIC void console_proc_key( GLFWwindow* ptrW, int key, 
+                                 int scancode, int action, int mods );
+VG_STATIC void console_proc_wchar( GLFWwindow* ptrW, u32 uWchar );
+VG_STATIC int vg_console_enabled(void);
+
+/*
+ * Implementation
+ */
+VG_STATIC int vg_console_enabled(void) 
 { 
        return vg_console.enabled; 
 }
 
-static void vg_convar_push( struct vg_convar cv )
+VG_STATIC void vg_convar_push( vg_convar cv )
 {
-       arrpush( vg_console.convars, cv ); 
+   if( vg_console.convar_count > vg_list_size(vg_console.convars) )
+      vg_fatal_exit_loop( "Too many convars registered" );
+
+   vg_info( "Console variable '%s' registered\n", cv.name );
+   vg_console.convars[ vg_console.convar_count ++ ] = cv;
 }
 
-static void vg_function_push( struct vg_cmd cmd )
+VG_STATIC void vg_function_push( struct vg_cmd cmd )
 {
-       arrpush( vg_console.functions, cmd );
+   if( vg_console.function_count > vg_list_size(vg_console.functions) )
+      vg_fatal_exit_loop( "Too many functions registered" );
+
+   vg_console.functions[ vg_console.function_count ++ ] = cmd;
 }
 
-static void vg_console_draw( void )
+VG_STATIC void vg_console_draw( void )
 {
        if( !vg_console.enabled )
                return;
 
-       int ptr = vg_console.current-1;
+   vg_mutex_lock( &log_print_mutex );
 
-   int const fh = 14;
+       int ptr = vg_log.buffer_line_current;
+   int const fh = 14,
+             log_lines = 32;
+   int console_lines = VG_MIN( log_lines, vg_log.buffer_line_count );
        
-       ui_global_ctx.cursor[0] = 0;
-       ui_global_ctx.cursor[1] = 0;
-       ui_global_ctx.cursor[3] = vg_list_size( vg_console.lines )*fh*vg_console.scale;
-       ui_fill_x( &ui_global_ctx );
+       vg_uictx.cursor[0] = 0;
+       vg_uictx.cursor[1] = 0;
+       vg_uictx.cursor[3] = log_lines*fh;
+       ui_fill_x();
        
-       ui_new_node( &ui_global_ctx );
+       ui_new_node();
        {
-               ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0x77333333 );
+               ui_fill_rect( vg_uictx.cursor, 0x77333333 );
        
-               ui_global_ctx.cursor[3] = fh*vg_console.scale;
-               ui_align_bottom( &ui_global_ctx ); 
-               
-               for( int i = 0; i < vg_console.len; i ++ )
+               vg_uictx.cursor[3] = fh;
+               ui_align_bottom();
+
+               for( int i=0; i<console_lines; i ++ )
                {
+                       ptr --;
+
                        if( ptr < 0 )
-                               ptr = vg_list_size( vg_console.lines )-1;
+                               ptr = vg_list_size( vg_log.buffer )-1;
          
-                       ui_text( &ui_global_ctx, ui_global_ctx.cursor, vg_console.lines[ptr], vg_console.scale, 0 );
-                       ui_global_ctx.cursor[1] -= fh*vg_console.scale;
-               
-                       ptr --;
+                       ui_text( vg_uictx.cursor, vg_log.buffer[ptr], 1, 0 );
+                       vg_uictx.cursor[1] -= fh;
                }
+
        }
-       ui_end_down( &ui_global_ctx );
+       ui_end_down();
        
-       ui_global_ctx.cursor[1] += 2;
-       ui_global_ctx.cursor[3] = fh*vg_console.scale;
+       vg_uictx.cursor[1] += 2;
+       vg_uictx.cursor[3] = fh;
        
-       ui_new_node( &ui_global_ctx );
+       ui_new_node();
        {
-               ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0x77333333 );
-               
-               ui_text( &ui_global_ctx, ui_global_ctx.cursor, vg_console.input, vg_console.scale, 0 );
+               ui_fill_rect( vg_uictx.cursor, 0x77333333 );
+               ui_text( vg_uictx.cursor, vg_console.input, 1, 0 );
                
                int start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user ),
                         end   = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user );
                
-               ui_global_ctx.cursor[0] = (start * UI_GLYPH_SPACING_X * vg_console.scale);
-               ui_global_ctx.cursor[2] = (start == end? 0.5f: (float)(end-start)) * (float)UI_GLYPH_SPACING_X * (float)vg_console.scale;
+               vg_uictx.cursor[0] = start * UI_GLYPH_SPACING_X;
+               vg_uictx.cursor[2] = (start == end? 0.5f: (float)(end-start)) 
+                                             * (float)UI_GLYPH_SPACING_X;
                
-               ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0x66ffffff );
+               ui_fill_rect( vg_uictx.cursor, 0x66ffffff );
        }
-       ui_end_down( &ui_global_ctx );
+       ui_end_down();
+   vg_mutex_unlock( &log_print_mutex );
 }
 
-void vg_console_println( const char *str )
+VG_STATIC int vg_console_list( int argc, char const *argv[] )
 {
-       if( vg_console.len < vg_list_size( vg_console.lines ) )
-               vg_console.len ++;
-       
-       strcpy( vg_console.lines[ vg_console.current ++ ], str );
-       
-       if( vg_console.current >= vg_list_size( vg_console.lines ) )
-               vg_console.current = 0;
-}
-
-static int vg_console_list( int argc, char const *argv[] )
-{
-       for( int i = 0; i < arrlen( vg_console.functions ); i ++ )
+       for( int i=0; i<vg_console.function_count; i ++ )
        {
                struct vg_cmd *cmd = &vg_console.functions[ i ];
                vg_info( "* %s\n", cmd->name );
        }
        
-       vg_info( "* snowsound\n" );
-       
-       for( int i = 0; i < arrlen( vg_console.convars ); i ++ )
+       for( int i=0; i<vg_console.convar_count; i ++ )
        {
                struct vg_convar *cv = &vg_console.convars[ i ];
                vg_info( "%s\n", cv->name );
@@ -180,33 +193,30 @@ static int vg_console_list( int argc, char const *argv[] )
        return 0;
 }
 
-static int vg_console_chartest( int argc, char const *argv[] )
+int _test_break( int argc, const char *argv[] )
 {
-   vg_info( "\"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\"\n" );
-   vg_info( "'the quick brown fox jumps over the lazy dog'\n" );
-   vg_info( ":;!@#$%^& 0123456789 +-*/=~ ()[]{}<>\n" );
+   vg_fatal_exit_loop( "Test crash from main, after loading (console)" );
    return 0;
 }
 
-static void vg_console_init(void)
+VG_STATIC void vg_console_init(void)
 {
-       vg_log_callback = vg_console_println;
-       
-       vg_convar_push( (struct vg_convar)
-       { .name = "console_scale", .data = &vg_console.scale, .data_type = k_convar_dtype_i32, 
-               .opt_i32 = { .clamp = 1, .min = 1, .max = 7 } } );
-       
-       vg_function_push( (struct vg_cmd){
+       vg_function_push( (struct vg_cmd)
+   {
                .name = "list",
                .function = vg_console_list
        });
 
-   vg_function_push( (struct vg_cmd){
-      .name = "chartest",
-      .function = vg_console_chartest
+   vg_function_push( (struct vg_cmd)
+   {
+      .name = "crash",
+      .function = _test_break
    });
+}
 
-       // Read and exec persistent commands
+VG_STATIC void vg_console_load_autos(void)
+{
+       /* Read and exec persistent commands */
        FILE *fp = fopen( "cfg/auto.conf", "r" );
        if( fp )
        {
@@ -226,11 +236,11 @@ static void vg_console_init(void)
        }
 }
 
-static void vg_console_write_persistent(void)
+VG_STATIC void vg_console_write_persistent(void)
 {
        FILE *fp = fopen( "cfg/auto.conf", "w" );
        
-       for( int i = 0; i < arrlen( vg_console.convars ); i ++ )
+       for( int i=0; i<vg_console.convar_count; i ++ )
        {
                struct vg_convar *cv = &vg_console.convars[i];
 
@@ -254,15 +264,12 @@ static void vg_console_write_persistent(void)
        fclose( fp );
 }
 
-static void vg_console_free(void)
+VG_STATIC void vg_console_free(void)
 {
        vg_console_write_persistent();
-
-       arrfree( vg_console.convars );
-       arrfree( vg_console.functions );
 }
 
-static void execute_console_input( const char *cmd )
+VG_STATIC void execute_console_input( const char *cmd )
 {
        char temp[512];
        char const *args[9];
@@ -270,12 +277,12 @@ static void execute_console_input( const char *cmd )
        
        int in_token = 0;
        
-       // Split string into tokens
+       /* Split string into tokens */
        for( int i = 0; i < vg_list_size( temp ); i ++ )
        {
                if( cmd[i] )
                {
-                       if( isspace( cmd[i] ) )
+                       if( cmd[i] == ' ' || cmd[i] == '\t' )
                        {
                                temp[i] = '\0';
                                in_token = 0;
@@ -305,13 +312,14 @@ static void execute_console_input( const char *cmd )
                return;
        
        int data_int;
+   float data_float;
        
-       for( int i = 0; i < arrlen( vg_console.convars ); i ++ )
+       for( int i=0; i<vg_console.convar_count; i ++ )
        {
                struct vg_convar *cv = &vg_console.convars[ i ];
                if( !strcmp( cv->name, args[0] ) )
                {
-                       // Cvar Matched, try get value
+                       /* Cvar Matched, try get value */
                        if( arg_count >= 2 )
                        {
                                switch( cv->data_type )
@@ -320,19 +328,37 @@ static void execute_console_input( const char *cmd )
                                        case k_convar_dtype_i32: 
                                                
                                                data_int = atoi( args[1] ); 
-                                               *((int *)cv->data) = cv->opt_i32.clamp? VG_MIN( VG_MAX(data_int, cv->opt_i32.min), cv->opt_i32.max ): data_int;
+                  
+                                               *((int *)cv->data) = cv->opt_i32.clamp? 
+                   VG_MIN( VG_MAX(data_int, cv->opt_i32.min), cv->opt_i32.max ): 
+                   data_int;
                                        
                                        break;
-                                       case k_convar_dtype_f32: *((float *)cv->data) = atof( temp ); break;
+                                       case k_convar_dtype_f32: 
+                  data_float = atof( args[1] );
+                  *((float *)cv->data) = cv->opt_f32.clamp?
+                     vg_minf( vg_maxf( data_float, cv->opt_f32.min), 
+                              cv->opt_f32.max ):
+                     data_float;
+               break;
                                }
+
+            if( cv->update )
+               cv->update();
                        }
                        else
                        {
                                switch( cv->data_type )
                                {
-                                       case k_convar_dtype_i32: vg_info( "= %d\n", *((int *)cv->data) ); break;
-                                       case k_convar_dtype_u32: vg_info( "= %u\n", *((u32 *)cv->data) ); break;
-                                       case k_convar_dtype_f32: vg_info( "= %.4f\n", *((float *)cv->data) ); break;
+                                       case k_convar_dtype_i32: 
+                  vg_info( "= %d\n", *((int *)cv->data) ); 
+               break;
+                                       case k_convar_dtype_u32: 
+                  vg_info( "= %u\n", *((u32 *)cv->data) );
+               break;
+                                       case k_convar_dtype_f32: 
+                  vg_info( "= %.4f\n", *((float *)cv->data) );
+               break;
                                }
                        }
                
@@ -340,76 +366,87 @@ static void execute_console_input( const char *cmd )
                }
        }
        
-       // Try commands
-       for( int i = 0; i < arrlen( vg_console.functions ); i ++ )
+   /*
+    * Find and excecute command
+    */
+       for( int i=0; i<vg_console.function_count; i ++ )
        {
                struct vg_cmd *cmd = &vg_console.functions[ i ];
                if( !strcmp( cmd->name, args[0] ) )
                {
-                       // Call function
                        cmd->function( arg_count-1, args+1 );
                        return;
                }
        }
        
-       vg_error( "No command/variable named '%s'. Use 'list' to view all\n", args[0] );
+       vg_error( "No command/var named '%s'. Use 'list' to view all\n", args[0] );
 }
 
-// =============================================================================================================================
-// Console interface
-
-static void console_make_selection( int* start, int* end )
+/*
+ * Console Interface
+ */
+VG_STATIC void console_make_selection( int* start, int* end )
 {
        *start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user );
        *end   = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user );
 }
 
-static void console_move_cursor( int* cursor0, int* cursor1, int dir, int snap_together )
+VG_STATIC void console_move_cursor( int* cursor0, int* cursor1, 
+      int dir, int snap_together )
 {
        *cursor0 = VG_MAX( 0, vg_console.cursor_user + dir );
-       *cursor0 = VG_MIN( VG_MIN( vg_list_size( vg_console.input ), strlen( vg_console.input )), *cursor0 );
+       *cursor0 = 
+      VG_MIN( 
+         VG_MIN( vg_list_size( vg_console.input ), strlen( vg_console.input )), 
+      *cursor0 );
+
        if( snap_together ) 
                *cursor1 = *cursor0;
 }
 
-static int console_makeroom( int datastart, int length )
+VG_STATIC int console_makeroom( int datastart, int length )
 {
        int move_to = VG_MIN( datastart+length, vg_list_size( vg_console.input ) );
        int move_amount = strlen( vg_console.input )-datastart;
-       int move_end = VG_MIN( move_to+move_amount, vg_list_size( vg_console.input ) );
+       int move_end = 
+      VG_MIN( move_to+move_amount, vg_list_size( vg_console.input ) );
        move_amount = move_end-move_to;
        
        if( move_amount )
-               memmove( &vg_console.input[ move_to ], &vg_console.input[ datastart ], move_end-move_to );
+               memmove( &vg_console.input[ move_to ], 
+               &vg_console.input[ datastart ], 
+               move_end-move_to );
        
        vg_console.input[ move_end ] = '\0';
        
        return VG_MIN( length, vg_list_size( vg_console.input )-datastart );
 }
 
-static int console_delete_char( int direction )
+VG_STATIC int console_delete_char( int direction )
 {
        int start, end;
        console_make_selection( &start, &end );
        
-       // There is no selection
+       /* There is no selection */
        if( !(end-start) )
        {
                if( direction == 1 ) end = VG_MIN( end+1, strlen( vg_console.input ) );
                else if( direction == -1 ) start = VG_MAX( start-1, 0 );
        }
        
-       // Still no selction, no need to do anything
+       /* Still no selction, no need to do anything */
        if( !(end-start) ) 
                return start;
        
-       // Copy the end->terminator to start
+       /* Copy the end->terminator to start */
        int remaining_length = strlen( vg_console.input )+1-end;
-       memmove( &vg_console.input[ start ], &vg_console.input[ end ], remaining_length );
+       memmove( &vg_console.input[ start ], 
+            &vg_console.input[ end ], 
+            remaining_length );
        return start;
 }
 
-static void console_to_clipboard(void)
+VG_STATIC void console_to_clipboard(void)
 {
        int start, end;
        console_make_selection( &start, &end );
@@ -423,7 +460,7 @@ static void console_to_clipboard(void)
        }
 }
 
-static void console_clipboard_paste(void)
+VG_STATIC void console_clipboard_paste(void)
 {
        int datastart = console_delete_char(0);
        const char* clipboard = glfwGetClipboardString(NULL);
@@ -432,11 +469,11 @@ static void console_clipboard_paste(void)
        int cpylength = console_makeroom(datastart, length);
 
        memcpy( vg_console.input + datastart, clipboard, cpylength);
-       
-       console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, cpylength, 1 );
+       console_move_cursor( &vg_console.cursor_user, 
+                        &vg_console.cursor_pos, cpylength, 1 );
 }
 
-static void console_put_char( char c )
+VG_STATIC void console_put_char( char c )
 {
        if( !vg_console.enabled ) 
                return;
@@ -449,168 +486,219 @@ static void console_put_char( char c )
        console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, 1, 1 );
 }
 
-static void console_history_get( char* buf, int entry_num )
+VG_STATIC void console_history_get( char* buf, int entry_num )
 {
        if( !vg_console.history_count )
                return;
        
-       int pick = (vg_console.history_last - VG_MIN( entry_num, vg_console.history_count -1 )) % vg_list_size( vg_console.history );
+   int offset = VG_MIN( entry_num, vg_console.history_count -1 ),
+       pick = (vg_console.history_last - offset) % 
+               vg_list_size( vg_console.history );
        strcpy( buf, vg_console.history[ pick ] );
 }
 
-static void console_proc_key( GLFWwindow* ptrW, int key, int scancode, int action, int mods )
+/* Receed secondary cursor */
+VG_STATIC void _console_left_select(void)
 {
-       if( action )
-       {
-               int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1;
-               
-               if( key == GLFW_KEY_GRAVE_ACCENT )
-               {
-                       vg_console.enabled = !vg_console.enabled;
-                       return;
-               }
-               
-               if( !vg_console.enabled ) 
-                       return;
+   console_move_cursor( &vg_console.cursor_user, NULL, -1, 0 );
+}
+
+/* Match and receed both cursors */
+VG_STATIC void _console_left(void)
+{
+   int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1;
+
+   console_move_cursor( &vg_console.cursor_user, 
+                        &vg_console.cursor_pos, -cursor_diff, 1 );
+}
+
+VG_STATIC void _console_right_select(void)
+{
+   console_move_cursor( &vg_console.cursor_user, NULL, 1, 0 );
+}
+
+VG_STATIC void _console_right(void)
+{
+   int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1;
+
+   console_move_cursor( &vg_console.cursor_user, 
+                        &vg_console.cursor_pos, +cursor_diff, 1 );
+}
+
+VG_STATIC void _console_down(void)
+{
+   vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 );
+   console_history_get( vg_console.input, vg_console.history_pos );
+
+   console_move_cursor( &vg_console.cursor_user, 
+                        &vg_console.cursor_pos, 
+                        vg_list_size( vg_console.input ), 1 );
+}
+
+VG_STATIC void _console_up(void)
+{
+   vg_console.history_pos = VG_MAX
+   ( 
+      0, 
+      VG_MIN
+      (
+         vg_console.history_pos+1, 
+         VG_MIN
+         ( 
+            vg_list_size( vg_console.history ), 
+            vg_console.history_count - 1 
+         )
+      )
+   );
+   
+   console_history_get( vg_console.input, vg_console.history_pos );
+   console_move_cursor( &vg_console.cursor_user, 
+                        &vg_console.cursor_pos, 
+                        vg_list_size( vg_console.input ), 1);
+}
+
+VG_STATIC void _console_backspace(void)
+{
+   vg_console.cursor_user = console_delete_char( -1 );
+   vg_console.cursor_pos = vg_console.cursor_user;
+}
+
+VG_STATIC void _console_delete(void)
+{
+   vg_console.cursor_user = console_delete_char( 1 );
+   vg_console.cursor_pos = vg_console.cursor_user;
+}
+
+VG_STATIC void _console_home_select(void)
+{
+   console_move_cursor( &vg_console.cursor_user, NULL, -10000, 0 );
+}
+
+VG_STATIC void _console_home(void)
+{
+   console_move_cursor( &vg_console.cursor_user, 
+                        &vg_console.cursor_pos, -10000, 1 );
+}
+
+VG_STATIC void _console_end_select(void)
+{
+   console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0 );
+}
+
+VG_STATIC void _console_end(void)
+{
+   console_move_cursor( &vg_console.cursor_user, 
+                        &vg_console.cursor_pos, 
+                        vg_list_size( vg_console.input ), 1 );
+}
+
+VG_STATIC void _console_select_all(void)
+{
+   console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0);
+   console_move_cursor( &vg_console.cursor_pos, NULL, -10000, 0);
+}
+
+VG_STATIC void _console_cut(void)
+{
+   console_to_clipboard();
+   vg_console.cursor_user = console_delete_char(0);
+   vg_console.cursor_pos = vg_console.cursor_user;
+}
+
+VG_STATIC void _console_enter(void)
+{
+   if( !strlen( vg_console.input ) ) 
+      return;
+
+   vg_info( "%s\n", vg_console.input );
+
+   if( strcmp( vg_console.input, 
+            vg_console.history[ vg_console.history_last ]) )
+   {
+      vg_console.history_last = ( vg_console.history_last + 1) % 
+                                 vg_list_size(vg_console.history );
+      vg_console.history_count = 
+         VG_MIN( vg_list_size( vg_console.history ), 
+               vg_console.history_count + 1 );
+      strcpy( vg_console.history[ vg_console.history_last ], 
+              vg_console.input );
+   }
+
+   vg_console.history_pos = -1;
+   execute_console_input( vg_console.input );
+   console_move_cursor( &vg_console.cursor_user, 
+                        &vg_console.cursor_pos, -10000, 1 );
+   vg_console.input[0] = '\0';
+}
+
+VG_STATIC void console_proc_key( GLFWwindow* ptrW, int key, int scancode, 
+                              int action, int mods )
+{
+       if( !action )
+      return;
                
-               if( key == GLFW_KEY_LEFT )
-               {
-                       if( mods & GLFW_MOD_SHIFT ) // Receed secondary cursor
-                       { 
-                               console_move_cursor( &vg_console.cursor_user, NULL, -1, 0 );
-                       } 
-                       else // Match and receed both cursors
-                       {
-                               console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, -cursor_diff, 1 );
-                       }
-               }
-               else if( key == GLFW_KEY_RIGHT ) // Advance secondary cursor
-               {
-                       if( mods & GLFW_MOD_SHIFT )
-                       {
-                               console_move_cursor( &vg_console.cursor_user, NULL, 1, 0 );
-                       } 
-                       else // Match and advance both cursors 
-                       {
-                               console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, +cursor_diff, 1 );
-                       }
-               } 
-               else if( key == GLFW_KEY_DOWN )
-               {
-                       if( mods & GLFW_MOD_SHIFT ){} 
-                       else 
-                       {
-                               vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 );
-                               console_history_get( vg_console.input, vg_console.history_pos );
-                               console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, vg_list_size( vg_console.input ), 1 );
-                       }
-               } 
-               else if( key == GLFW_KEY_UP )
-               {
-                       if( mods & GLFW_MOD_SHIFT ){} 
-                       else 
-                       {
-                               vg_console.history_pos = VG_MAX
-                               ( 
-                                       0, 
-                                       VG_MIN
-                                       (
-                                               vg_console.history_pos+1, 
-                                               VG_MIN
-                                               ( 
-                                                       vg_list_size( vg_console.history ), 
-                                                       vg_console.history_count - 1 
-                                               )
-                                       )
-                               );
-                               
-                               console_history_get( vg_console.input, vg_console.history_pos );
-                               console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, vg_list_size( vg_console.input ), 1);
-                       }
-               } 
-               else if( key == GLFW_KEY_BACKSPACE ) // Lookback delete
-               {
-                       vg_console.cursor_user = console_delete_char( -1 );
-                       vg_console.cursor_pos = vg_console.cursor_user;
-               } 
-               else if( key == GLFW_KEY_DELETE ) // Lookforward delete
-               {
-                       vg_console.cursor_user = console_delete_char( 1 );
-                       vg_console.cursor_pos = vg_console.cursor_user;
-               } 
-               else if( key == GLFW_KEY_HOME ) // Home key
-               {
-                       if( mods & GLFW_MOD_SHIFT ) 
-                               console_move_cursor( &vg_console.cursor_user, NULL, -10000, 0 );
-                       else 
-                               console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, -10000, 1 );
-               } 
-               else if( key == GLFW_KEY_END ) // End key
-               {
-                       if( mods & GLFW_MOD_SHIFT ) 
-                               console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0 );
-                       else 
-                               console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, vg_list_size( vg_console.input ), 1 );
-               }
-               else if( key == GLFW_KEY_A )
-               {
-                       if( mods & GLFW_MOD_CONTROL ) // Select all
-                       {
-                               console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0);
-                               console_move_cursor( &vg_console.cursor_pos, NULL, -10000, 0);
-                       }
-               } 
-               else if( key == GLFW_KEY_C ) // Copy
-               {
-                       if( mods & GLFW_MOD_CONTROL )
-                       {
-                               console_to_clipboard();
-                       }
-               } 
-               else if( key == GLFW_KEY_X ) // Cut
-               {
-                       if( mods & GLFW_MOD_CONTROL )
-                       {
-                               console_to_clipboard();
-                               vg_console.cursor_user = console_delete_char(0);
-                               vg_console.cursor_pos = vg_console.cursor_user;
-                       }
-               } 
-               else if( key == GLFW_KEY_V ) // Paste
-               {
-                       if( mods & GLFW_MOD_CONTROL )
-                       {
-                               console_clipboard_paste();
-                       }
-               } 
-               else if( key == GLFW_KEY_ENTER )
-               {
-                       if( !strlen( vg_console.input ) ) 
-                               return;
-                       
-                       vg_info( "%s\n", vg_console.input );
-                       
-                       if( strcmp( vg_console.input, vg_console.history[ vg_console.history_last ]) )
-                       {
-                               vg_console.history_last = ( vg_console.history_last + 1) % vg_list_size(vg_console.history );
-                               vg_console.history_count = VG_MIN( vg_list_size( vg_console.history ), vg_console.history_count + 1 );
-                               strcpy( vg_console.history[ vg_console.history_last ], vg_console.input );
-                       }
-                       
-                       vg_console.history_pos = -1;
-                       execute_console_input( vg_console.input );
-                       console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, -10000, 1 );
-                       vg_console.input[0] = '\0';
-               }
-       }
+   /* Open / close console */
+   if( key == GLFW_KEY_GRAVE_ACCENT )
+      vg_console.enabled = !vg_console.enabled;
+   
+   if( !vg_console.enabled ) return;
+   
+   struct console_mapping
+   {
+      u32 mod, key;
+      void (*handler)(void);
+   }
+   mapping[] =
+   {
+      { 0,                 GLFW_KEY_LEFT,       _console_left              },
+      { GLFW_MOD_SHIFT,    GLFW_KEY_LEFT,       _console_left_select       },
+      { 0,                 GLFW_KEY_RIGHT,      _console_right             },
+      { GLFW_MOD_SHIFT,    GLFW_KEY_RIGHT,      _console_right_select      },
+      { 0,                 GLFW_KEY_DOWN,       _console_down              },
+      { 0,                 GLFW_KEY_UP,         _console_up                },
+      { 0,                 GLFW_KEY_BACKSPACE,  _console_backspace         },
+      { 0,                 GLFW_KEY_DELETE,     _console_delete            },
+      { 0,                 GLFW_KEY_HOME,       _console_home              },
+      { GLFW_MOD_SHIFT,    GLFW_KEY_HOME,       _console_home_select       },
+      { 0,                 GLFW_KEY_END,        _console_end               },
+      { GLFW_MOD_SHIFT,    GLFW_KEY_END,        _console_end_select        },
+      { GLFW_MOD_CONTROL,  GLFW_KEY_A,          _console_select_all        },
+      { GLFW_MOD_CONTROL,  GLFW_KEY_C,          console_to_clipboard       },
+      { GLFW_MOD_CONTROL,  GLFW_KEY_X,          _console_cut               },
+      { GLFW_MOD_CONTROL,  GLFW_KEY_V,          console_clipboard_paste    },
+      { 0,                 GLFW_KEY_ENTER,      _console_enter             }
+   };
+
+   for( int i=0; i<vg_list_size( mapping ); i++ )
+   {
+      struct console_mapping *mk = &mapping[i];
+
+      if( mk->key == key )
+      {
+         if( mk->mod == 0 )
+         {
+            if( mods == 0 )
+            {
+               mk->handler();
+               return;
+            }
+         }
+         else if( (mods & mk->mod) == mk->mod )
+         {
+            mk->handler();
+            return;
+         }
+      }
+   }
 }
 
-// Handle an OS based input of UTF32 character from the keyboard or such
-static void console_proc_wchar( GLFWwindow* ptrW, u32 uWchar )
+/* Handle an OS based input of UTF32 character from the keyboard or such */
+VG_STATIC void console_proc_wchar( GLFWwindow* ptrW, u32 uWchar )
 {
-       //LOG_INFO("Recieved wchar: %u\n", uWchar);
        if( uWchar <= 0x7F && (char)uWchar != 0x60)
        {
                console_put_char((char)uWchar);
        }
 }
+
+#endif /* VG_CONSOLE_H */