X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_console.h;h=26c6a6d20c00414eef330fa18f7500b4caf52dd9;hp=5a137e3f05222366239791a68866745d474a0fda;hb=HEAD;hpb=fd8875baf8264b20731fb1bffaba4e1393beb189 diff --git a/vg_console.h b/vg_console.h index 5a137e3..c24423a 100644 --- a/vg_console.h +++ b/vg_console.h @@ -1,93 +1,47 @@ -/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */ +/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */ -#ifndef VG_CONSOLE_H -#define VG_CONSOLE_H +#pragma once +#include "vg_platform.h" -#ifndef VG_GAME - #define VG_GAME -#endif +#define VG_VAR_F32( NAME, ... ) \ + { u32 flags=0x00; __VA_ARGS__ ;\ + vg_console_reg_var( #NAME, &NAME, k_var_dtype_f32, flags ); } -#include "vg/vg_ui.h" -#include "vg/vg_log.h" +#define VG_VAR_I32( NAME, ... ) \ + { u32 flags=0x00; __VA_ARGS__ ;\ + vg_console_reg_var( #NAME, &NAME, k_var_dtype_i32, flags ); } -#define VG_VAR_F32_PERSISTENT( NAME ) \ - vg_var_push( (struct vg_var){ \ - .name = #NAME, \ - .data = &NAME, \ - .data_type = k_var_dtype_f32, \ - .persistent = 1 \ - }); - -#define VG_VAR_F32( NAME ) \ - vg_var_push( (struct vg_var){ \ - .name = #NAME, \ - .data = &NAME, \ - .data_type = k_var_dtype_f32, \ - }); - -#define VG_VAR_I32_PERSISTENT( NAME ) \ - vg_var_push( (struct vg_var){ \ - .name = #NAME, \ - .data = &NAME, \ - .data_type = k_var_dtype_i32, \ - .persistent = 1 \ - }); - -#define VG_VAR_I32( NAME ) \ - vg_var_push( (struct vg_var){ \ - .name = #NAME, \ - .data = &NAME, \ - .data_type = k_var_dtype_i32, \ - }); +#define VG_VAR_PERSISTENT 0x1 +#define VG_VAR_CHEAT 0x2 typedef struct vg_var vg_var; typedef struct vg_cmd vg_cmd; struct vg_console { - struct vg_var - { + struct vg_var{ void *data; const char *name; - enum vg_var_dtype - { + enum vg_var_dtype{ k_var_dtype_i32, k_var_dtype_u32, - k_var_dtype_f32 + k_var_dtype_f32, + k_var_dtype_str } data_type; - - union - { - struct - { - int min, max, clamp; - } - opt_i32; - - struct - { - float min, max; - int clamp; - } - opt_f32; - }; - - int persistent; /* Should this var be stored to cfg/auto.conf? */ + u32 flags; } - vars[ 64 ]; + vars[ 128 ]; - struct vg_cmd - { + struct vg_cmd{ int (*function)( int argc, char const *argv[] ); void (*poll_suggest)( int argc, char const *argv[] ); const char *name; } functions[ 32 ]; - struct - { + struct { const char *str; int len; @@ -103,991 +57,29 @@ struct vg_console char input[96], input_copy[96]; - int cursor_user, cursor_pos, string_length; char history[32][96]; int history_last, history_pos, history_count; - int enabled; -} -vg_console; - -VG_STATIC void vg_var_push( struct vg_var cv ); -VG_STATIC void vg_function_push( struct vg_cmd cmd ); - -VG_STATIC void _vg_console_draw( void ); -void _vg_console_println( const char *str ); -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 vg_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 int _vg_console_enabled(void); -VG_STATIC void console_proc_key( SDL_Keysym ev ); - -/* - * Implementation - */ -VG_STATIC int _vg_console_enabled(void) -{ - return vg_console.enabled; -} - -VG_STATIC void vg_var_push( vg_var cv ) -{ - if( vg_console.var_count > vg_list_size(vg_console.vars) ) - vg_fatal_exit_loop( "Too many vars registered" ); - - vg_info( "Console variable '%s' registered\n", cv.name ); - vg_console.vars[ vg_console.var_count ++ ] = cv; -} - -VG_STATIC void vg_function_push( struct vg_cmd 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; -} - -VG_STATIC void _vg_console_draw( void ) -{ - if( !vg_console.enabled ) - return; - - SDL_AtomicLock( &log_print_sl ); - - 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 ); - - vg_uictx.cursor[0] = 0; - vg_uictx.cursor[1] = 0; - vg_uictx.cursor[3] = log_lines*fh; - ui_fill_x(); - - /* - * log - */ - ui_new_node(); - { - ui_fill_rect( vg_uictx.cursor, 0x77181818 ); - - vg_uictx.cursor[3] = fh; - ui_align_bottom(); - - for( int i=0; iname ); - } - - for( int i=0; iname ); - } - - return 0; -} - -int _test_break( int argc, const char *argv[] ) -{ - vg_fatal_exit_loop( "Test crash from main, after loading (console)" ); - return 0; -} - -VG_STATIC void _vg_console_init(void) -{ - vg_function_push( (struct vg_cmd) - { - .name = "list", - .function = _vg_console_list - }); - - vg_function_push( (struct vg_cmd) - { - .name = "crash", - .function = _test_break - }); -} - -VG_STATIC void vg_console_load_autos(void) -{ - /* Read and exec persistent commands */ - FILE *fp = fopen( "cfg/auto.conf", "r" ); - if( fp ) - { - char line[256]; - - while( fgets( line, sizeof( line ), fp ) ) - { - line[ strcspn( line, "\r\n#" ) ] = 0x00; - - if( line[0] != 0x00 ) - { - vg_execute_console_input( line ); - } - } - - fclose( fp ); - } -} - -VG_STATIC void _vg_console_write_persistent(void) -{ - FILE *fp = fopen( "cfg/auto.conf", "w" ); - - for( int i=0; ipersistent ) - { - switch( cv->data_type ) - { - case k_var_dtype_i32: - fprintf( fp, "%s %d\n", cv->name, *(i32 *)(cv->data) ); - break; - case k_var_dtype_u32: - fprintf( fp, "%s %u\n", cv->name, *(u32 *)(cv->data) ); - break; - case k_var_dtype_f32: - fprintf( fp, "%s %.5f\n", cv->name, *(float *)(cv->data ) ); - break; - } - } - } - - fclose( fp ); -} - -VG_STATIC void _vg_console_free(void) -{ - _vg_console_write_persistent(); -} - -/* - * splits src into tokens and fills out args as pointers to those tokens - * returns number of tokens - * dst must be as long as src - */ -VG_STATIC int vg_console_tokenize( const char *src, char *dst, - const char *args[8] ) -{ - int arg_count = 0, - in_token = 0; - - for( int i=0; 1; i ++ ) - { - if( src[i] ) - { - if( src[i] == ' ' || src[i] == '\t' ) - { - if( in_token ) - dst[i] = '\0'; - - in_token = 0; - - if( arg_count == 8 ) - break; - } - else - { - dst[i] = src[i]; - - if( !in_token ) - { - args[ arg_count ++ ] = &dst[i]; - in_token = 1; - } - } - } - else - { - dst[i] = '\0'; - break; - } - } - - return arg_count; -} - -VG_STATIC vg_var *vg_console_match_var( const char *kw ) -{ - for( int i=0; iname, kw ) ) - { - return cv; - } - } - - return NULL; -} - -VG_STATIC vg_cmd *vg_console_match_cmd( const char *kw ) -{ - for( int i=0; iname, kw ) ) - { - return cmd; - } - } - - return NULL; -} - -VG_STATIC void vg_execute_console_input( const char *cmd ) -{ - char temp[512]; - char const *args[8]; - int arg_count = vg_console_tokenize( cmd, temp, args ); - - if( arg_count == 0 ) - return; - - int data_int; - float data_float; - - vg_var *cv = vg_console_match_var( args[0] ); - vg_cmd *fn = vg_console_match_cmd( args[0] ); - - assert( !(cv && fn) ); - - if( cv ) - { - /* Cvar Matched, try get value */ - if( arg_count >= 2 ) - { - if( (cv->data_type == k_var_dtype_u32) || - (cv->data_type == k_var_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; - } - else if( cv->data_type == k_var_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; - } - } - else - { - if( cv->data_type == k_var_dtype_i32 ) - vg_info( "= %d\n", *((int *)cv->data) ); - else if( cv->data_type == k_var_dtype_u32 ) - vg_info( "= %u\n", *((u32 *)cv->data) ); - else if( cv->data_type == k_var_dtype_f32 ) - vg_info( "= %.4f\n", *((float *)cv->data) ); - } - - return; - } - else if( fn ) - { - fn->function( arg_count-1, args+1 ); - return; - } - - vg_error( "No command/var named '%s'. Use 'list' to view all\n", args[0] ); -} - -u32 str_lev_distance( const char *s1, const char *s2 ) -{ - u32 m = strlen( s1 ), - n = strlen( s2 ); - - if( m==0 ) return n; - if( n==0 ) return m; - - assert( n+1 <= 256 ); - - u32 costs[ 256 ]; - - for( u32 k=0; k<=n; k++ ) - costs[k] = k; - - u32 i = 0; - for( u32 i=0; i=0; j -- ) - if( score > vg_console.suggestions[j].lev_score ) - best_pos = j; - - /* insert if good score */ - if( best_pos < vg_list_size( vg_console.suggestions ) ) - { - int start = VG_MIN( vg_console.suggestion_count, - vg_list_size( vg_console.suggestions )-1 ); - for( int j=start; j>best_pos; j -- ) - vg_console.suggestions[j] = vg_console.suggestions[j-1]; - - vg_console.suggestions[ best_pos ].str = str; - vg_console.suggestions[ best_pos ].len = strlen( str ); - vg_console.suggestions[ best_pos ].lev_score = score; - - if( vg_console.suggestion_count < - vg_list_size( vg_console.suggestions ) ) - vg_console.suggestion_count ++; - } -} - -VG_STATIC void console_update_suggestions(void) -{ - vg_console.suggestion_count = 0; - vg_console.suggestion_select = -1; - vg_console.suggestion_maxlen = 0; - - /* - * - must be typing something - * - must be at the end - * - prev char must not be a whitespace - * - cursors should match - */ - - if( vg_console.cursor_pos == 0 ) - return; - - if( vg_console.cursor_pos != vg_console.cursor_user ) - return; - - if( vg_console.input[ vg_console.cursor_pos ] != '\0' ) - return; - - if( (vg_console.input[ vg_console.cursor_pos -1 ] == ' ') || - (vg_console.input[ vg_console.cursor_pos -1 ] == '\t') ) - return; - - char temp[128]; - const char *args[8]; - - int token_count = vg_console_tokenize( vg_console.input, temp, args ); - - vg_console.suggestion_pastepos = args[token_count-1]-temp; - - /* Score all our commands and cvars */ - if( token_count == 1 ) - { - for( int i=0; iname, args[0], 1 ); - } - - for( int i=0; iname, args[0], 1 ); - } - } - else - { - vg_cmd *cmd = vg_console_match_cmd( args[0] ); - vg_var *var = vg_console_match_var( args[0] ); - - assert( !( cmd && var ) ); - - if( cmd ) - if( cmd->poll_suggest ) - cmd->poll_suggest( token_count-1, &args[1] ); - } - - /* some post processing */ - for( int i=0; iterminator to start */ - int remaining_length = strlen( vg_console.input )+1-end; - memmove( &vg_console.input[ start ], - &vg_console.input[ end ], - remaining_length ); - return start; -} - -VG_STATIC void console_to_clipboard(void) -{ - int start, end; - console_make_selection( &start, &end ); - char buffer[512]; - - if( end-start ) - { - memcpy( buffer, &vg_console.input[ start ], end-start ); - buffer[ end-start ] = 0x00; - SDL_SetClipboardText( buffer ); - } -} - -VG_STATIC void console_clipboard_paste(void) -{ - if( !SDL_HasClipboardText() ) - return; - - char *text = SDL_GetClipboardText(); - - if( !text ) - return; - - int datastart = console_delete_char( 0 ); - int length = strlen( text ); - int cpylength = console_makeroom( datastart, length ); - - memcpy( vg_console.input + datastart, text, cpylength); - console_move_cursor( &vg_console.cursor_user, - &vg_console.cursor_pos, cpylength, 1 ); - SDL_free( text ); - - console_update_suggestions(); -} - -VG_STATIC void console_put_char( char c ) -{ - if( !vg_console.enabled ) - return; - - vg_console.cursor_user = console_delete_char(0); - - if( console_makeroom( vg_console.cursor_user, 1 ) ) - vg_console.input[ vg_console.cursor_user ] = c; - - console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, 1, 1 ); -} - -VG_STATIC void console_history_get( char* buf, int entry_num ) -{ - if( !vg_console.history_count ) - return; - - 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 ] ); -} - -/* Receed secondary cursor */ -VG_STATIC void _console_left_select(void) -{ - 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, 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, 1); -} - -VG_STATIC void _console_backspace(void) -{ - vg_console.cursor_user = console_delete_char( -1 ); - vg_console.cursor_pos = vg_console.cursor_user; - - console_update_suggestions(); -} - -VG_STATIC void _console_delete(void) -{ - vg_console.cursor_user = console_delete_char( 1 ); - vg_console.cursor_pos = vg_console.cursor_user; - - console_update_suggestions(); -} - -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, 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; - vg_execute_console_input( vg_console.input ); - console_move_cursor( &vg_console.cursor_user, - &vg_console.cursor_pos, -10000, 1 ); - vg_console.input[0] = '\0'; - - console_update_suggestions(); -} - -/* - * Suggestion controls - */ -VG_STATIC void _console_fetch_suggestion(void) -{ - char *target = &vg_console.input[ vg_console.suggestion_pastepos ]; - - if( vg_console.suggestion_select == -1 ) - { - strcpy( target, vg_console.input_copy ); - console_move_cursor( &vg_console.cursor_user, - &vg_console.cursor_pos, 10000, 1 ); - } - else - { - strncpy( target, - vg_console.suggestions[ vg_console.suggestion_select ].str, - vg_list_size( vg_console.input )-1 ); - - console_move_cursor( &vg_console.cursor_user, - &vg_console.cursor_pos, 10000, 1 ); - console_put_char( ' ' ); - } -} - -VG_STATIC void _console_suggest_store_normal(void) -{ - if( vg_console.suggestion_select == -1 ) - { - char *target = &vg_console.input[ vg_console.suggestion_pastepos ]; - strcpy( vg_console.input_copy, target ); - } -} - -VG_STATIC void _console_suggest_next(void) -{ - if( vg_console.suggestion_count ) - { - _console_suggest_store_normal(); - - vg_console.suggestion_select ++; - - if( vg_console.suggestion_select >= vg_console.suggestion_count ) - vg_console.suggestion_select = -1; - - _console_fetch_suggestion(); - } -} - -VG_STATIC void _console_suggest_prev(void) -{ - if( vg_console.suggestion_count ) - { - _console_suggest_store_normal(); - - vg_console.suggestion_select --; - - if( vg_console.suggestion_select < -1 ) - vg_console.suggestion_select = vg_console.suggestion_count-1; - - _console_fetch_suggestion(); - } -} - -/* - * Handles binds - */ -VG_STATIC void console_proc_key( SDL_Keysym ev ) -{ - /* Open / close console */ - if( ev.sym == SDLK_BACKQUOTE ) - { - vg_console.enabled = !vg_console.enabled; - - if( vg_console.enabled ) - SDL_StartTextInput(); - else - SDL_StopTextInput(); - } - - if( !vg_console.enabled ) return; - - struct console_mapping - { - u16 mod; - SDL_Keycode key; - - void (*handler)(void); - } - mappings[] = - { - { 0, SDLK_LEFT, _console_left }, - { KMOD_SHIFT, SDLK_LEFT, _console_left_select }, - { 0, SDLK_RIGHT, _console_right }, - { KMOD_SHIFT, SDLK_RIGHT, _console_right_select }, - { 0, SDLK_DOWN, _console_down }, - { 0, SDLK_UP, _console_up }, - { 0, SDLK_BACKSPACE, _console_backspace }, - { 0, SDLK_DELETE, _console_delete }, - { 0, SDLK_HOME, _console_home }, - { KMOD_SHIFT, SDLK_HOME, _console_home_select }, - { 0, SDLK_END, _console_end }, - { KMOD_SHIFT, SDLK_END, _console_end_select }, - { KMOD_CTRL, SDLK_a, _console_select_all }, - { KMOD_CTRL, SDLK_c, console_to_clipboard }, - { KMOD_CTRL, SDLK_x, _console_cut }, - { KMOD_CTRL, SDLK_v, console_clipboard_paste }, - { 0, SDLK_RETURN, _console_enter }, - { KMOD_CTRL, SDLK_n, _console_suggest_next }, - { KMOD_CTRL, SDLK_p, _console_suggest_prev } - }; - - SDL_Keymod mod = 0; - - if( ev.mod & KMOD_SHIFT ) - mod |= KMOD_SHIFT; - - if( ev.mod & KMOD_CTRL ) - mod |= KMOD_CTRL; - - if( ev.mod & KMOD_ALT ) - mod |= KMOD_ALT; - - for( int i=0; ikey == ev.sym ) - { - if( mapping->mod == 0 ) - { - if( mod == 0 ) - { - mapping->handler(); - return; - } - } - else if( (mod & mapping->mod) == mapping->mod ) - { - mapping->handler(); - return; - } - } - } -} - -/* - * Callback for text entry mode - */ -VG_STATIC void console_proc_utf8( const char *text ) -{ - const char *ptr = text; - - while( *ptr ) - { - if( *ptr != '`' ) - console_put_char( *ptr ); - ptr ++; - } - - console_update_suggestions(); -} - -#endif /* VG_CONSOLE_H */ + i32 enabled, cheats; +} +extern vg_console; + +void vg_console_reg_var( const char *alias, void *ptr, enum vg_var_dtype type, + u32 flags ); + +void vg_console_reg_cmd( const char *alias, + int (*function)(int argc, const char *argv[]), + void (*poll_suggest)(int argc, const char *argv[]) ); +void vg_console_load_autos(void); +void vg_console_draw(void); +void vg_console_init(void); +int vg_console_exec( int argc, const char *argv[] ); +void vg_execute_console_input( const char *cmd, bool silent ); +static void vg_console_write_persistent(void); +void console_suggest_score_text( const char *str, const char *input, + int minscore ); +vg_var *vg_console_match_var( const char *kw ); +vg_cmd *vg_console_match_cmd( const char *kw ); +static void console_suggest_next(void); +static void console_suggest_prev(void);