e18515d45cd029e3d422da5c09881994193a7fc0
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
11 #include "vg/vg_log.h"
13 typedef struct vg_convar vg_convar
;
14 typedef struct vg_cmd vg_cmd
;
48 int persistent
; /* Should this var be stored to cfg/auto.conf? */
54 int (*function
)( int argc
, char const *argv
[] );
59 u32 convar_count
, function_count
;
62 int cursor_user
, cursor_pos
, string_length
;
65 int history_last
, history_pos
, history_count
;
71 VG_STATIC
void vg_convar_push( struct vg_convar cv
);
72 VG_STATIC
void vg_function_push( struct vg_cmd cmd
);
74 VG_STATIC
void _vg_console_draw( void );
75 void _vg_console_println( const char *str
);
76 VG_STATIC
int _vg_console_list( int argc
, char const *argv
[] );
77 VG_STATIC
void _vg_console_init(void);
78 VG_STATIC
void _vg_console_write_persistent(void);
79 VG_STATIC
void _vg_console_free(void);
80 VG_STATIC
void vg_execute_console_input( const char *cmd
);
85 VG_STATIC
void console_make_selection( int* start
, int* end
);
86 VG_STATIC
void console_move_cursor( int* cursor0
, int* cursor1
,
87 int dir
, int snap_together
);
88 VG_STATIC
int console_makeroom( int datastart
, int length
);
89 VG_STATIC
int console_delete_char( int direction
);
90 VG_STATIC
void console_to_clipboard(void);
91 VG_STATIC
void console_clipboard_paste(void);
92 VG_STATIC
void console_put_char( char c
);
93 VG_STATIC
void console_history_get( char* buf
, int entry_num
);
94 VG_STATIC
int _vg_console_enabled(void);
95 VG_STATIC
void console_proc_key( SDL_Keysym ev
);
100 VG_STATIC
int _vg_console_enabled(void)
102 return vg_console
.enabled
;
105 VG_STATIC
void vg_convar_push( vg_convar cv
)
107 if( vg_console
.convar_count
> vg_list_size(vg_console
.convars
) )
108 vg_fatal_exit_loop( "Too many convars registered" );
110 vg_info( "Console variable '%s' registered\n", cv
.name
);
111 vg_console
.convars
[ vg_console
.convar_count
++ ] = cv
;
114 VG_STATIC
void vg_function_push( struct vg_cmd cmd
)
116 if( vg_console
.function_count
> vg_list_size(vg_console
.functions
) )
117 vg_fatal_exit_loop( "Too many functions registered" );
119 vg_console
.functions
[ vg_console
.function_count
++ ] = cmd
;
122 VG_STATIC
void _vg_console_draw( void )
124 if( !vg_console
.enabled
)
127 SDL_AtomicLock( &log_print_sl
);
129 int ptr
= vg_log
.buffer_line_current
;
132 int console_lines
= VG_MIN( log_lines
, vg_log
.buffer_line_count
);
134 vg_uictx
.cursor
[0] = 0;
135 vg_uictx
.cursor
[1] = 0;
136 vg_uictx
.cursor
[3] = log_lines
*fh
;
141 ui_fill_rect( vg_uictx
.cursor
, 0x77333333 );
143 vg_uictx
.cursor
[3] = fh
;
146 for( int i
=0; i
<console_lines
; i
++ )
151 ptr
= vg_list_size( vg_log
.buffer
)-1;
153 ui_text( vg_uictx
.cursor
, vg_log
.buffer
[ptr
], 1, 0 );
154 vg_uictx
.cursor
[1] -= fh
;
160 vg_uictx
.cursor
[1] += 2;
161 vg_uictx
.cursor
[3] = fh
;
165 ui_fill_rect( vg_uictx
.cursor
, 0x77333333 );
166 ui_text( vg_uictx
.cursor
, vg_console
.input
, 1, 0 );
168 int start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
),
169 end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
171 vg_uictx
.cursor
[0] = start
* UI_GLYPH_SPACING_X
;
172 vg_uictx
.cursor
[2] = (start
== end
? 0.5f
: (float)(end
-start
))
173 * (float)UI_GLYPH_SPACING_X
;
175 ui_fill_rect( vg_uictx
.cursor
, 0x66ffffff );
178 SDL_AtomicUnlock( &log_print_sl
);
181 VG_STATIC
int _vg_console_list( int argc
, char const *argv
[] )
183 for( int i
=0; i
<vg_console
.function_count
; i
++ )
185 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
186 vg_info( "* %s\n", cmd
->name
);
189 for( int i
=0; i
<vg_console
.convar_count
; i
++ )
191 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
192 vg_info( "%s\n", cv
->name
);
198 int _test_break( int argc
, const char *argv
[] )
200 vg_fatal_exit_loop( "Test crash from main, after loading (console)" );
204 VG_STATIC
void _vg_console_init(void)
206 vg_function_push( (struct vg_cmd
)
209 .function
= _vg_console_list
212 vg_function_push( (struct vg_cmd
)
215 .function
= _test_break
219 VG_STATIC
void vg_console_load_autos(void)
221 /* Read and exec persistent commands */
222 FILE *fp
= fopen( "cfg/auto.conf", "r" );
227 while( fgets( line
, sizeof( line
), fp
) )
229 line
[ strcspn( line
, "\r\n#" ) ] = 0x00;
231 if( line
[0] != 0x00 )
233 vg_execute_console_input( line
);
241 VG_STATIC
void _vg_console_write_persistent(void)
243 FILE *fp
= fopen( "cfg/auto.conf", "w" );
245 for( int i
=0; i
<vg_console
.convar_count
; i
++ )
247 struct vg_convar
*cv
= &vg_console
.convars
[i
];
251 switch( cv
->data_type
)
253 case k_convar_dtype_i32
:
254 fprintf( fp
, "%s %d\n", cv
->name
, *(i32
*)(cv
->data
) );
256 case k_convar_dtype_u32
:
257 fprintf( fp
, "%s %u\n", cv
->name
, *(u32
*)(cv
->data
) );
259 case k_convar_dtype_f32
:
260 fprintf( fp
, "%s %.5f\n", cv
->name
, *(float *)(cv
->data
) );
269 VG_STATIC
void _vg_console_free(void)
271 _vg_console_write_persistent();
274 VG_STATIC
void vg_execute_console_input( const char *cmd
)
282 /* Split string into tokens */
283 for( int i
= 0; i
< vg_list_size( temp
); i
++ )
287 if( cmd
[i
] == ' ' || cmd
[i
] == '\t' )
292 if( arg_count
== vg_list_size( args
) )
301 args
[ arg_count
++ ] = temp
+ i
;
319 for( int i
=0; i
<vg_console
.convar_count
; i
++ )
321 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
322 if( !strcmp( cv
->name
, args
[0] ) )
324 /* Cvar Matched, try get value */
327 switch( cv
->data_type
)
329 case k_convar_dtype_u32
:
330 case k_convar_dtype_i32
:
332 data_int
= atoi( args
[1] );
334 *((int *)cv
->data
) = cv
->opt_i32
.clamp
?
335 VG_MIN( VG_MAX(data_int
, cv
->opt_i32
.min
), cv
->opt_i32
.max
):
339 case k_convar_dtype_f32
:
340 data_float
= atof( args
[1] );
341 *((float *)cv
->data
) = cv
->opt_f32
.clamp
?
342 vg_minf( vg_maxf( data_float
, cv
->opt_f32
.min
),
353 switch( cv
->data_type
)
355 case k_convar_dtype_i32
:
356 vg_info( "= %d\n", *((int *)cv
->data
) );
358 case k_convar_dtype_u32
:
359 vg_info( "= %u\n", *((u32
*)cv
->data
) );
361 case k_convar_dtype_f32
:
362 vg_info( "= %.4f\n", *((float *)cv
->data
) );
372 * Find and excecute command
374 for( int i
=0; i
<vg_console
.function_count
; i
++ )
376 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
377 if( !strcmp( cmd
->name
, args
[0] ) )
379 cmd
->function( arg_count
-1, args
+1 );
384 vg_error( "No command/var named '%s'. Use 'list' to view all\n", args
[0] );
390 VG_STATIC
void console_make_selection( int* start
, int* end
)
392 *start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
);
393 *end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
396 VG_STATIC
void console_move_cursor( int* cursor0
, int* cursor1
,
397 int dir
, int snap_together
)
399 *cursor0
= VG_MAX( 0, vg_console
.cursor_user
+ dir
);
402 VG_MIN( vg_list_size( vg_console
.input
), strlen( vg_console
.input
)),
409 VG_STATIC
int console_makeroom( int datastart
, int length
)
411 int move_to
= VG_MIN( datastart
+length
, vg_list_size( vg_console
.input
) );
412 int move_amount
= strlen( vg_console
.input
)-datastart
;
414 VG_MIN( move_to
+move_amount
, vg_list_size( vg_console
.input
) );
415 move_amount
= move_end
-move_to
;
418 memmove( &vg_console
.input
[ move_to
],
419 &vg_console
.input
[ datastart
],
422 vg_console
.input
[ move_end
] = '\0';
424 return VG_MIN( length
, vg_list_size( vg_console
.input
)-datastart
);
427 VG_STATIC
int console_delete_char( int direction
)
430 console_make_selection( &start
, &end
);
432 /* There is no selection */
435 if( direction
== 1 ) end
= VG_MIN( end
+1, strlen( vg_console
.input
) );
436 else if( direction
== -1 ) start
= VG_MAX( start
-1, 0 );
439 /* Still no selction, no need to do anything */
443 /* Copy the end->terminator to start */
444 int remaining_length
= strlen( vg_console
.input
)+1-end
;
445 memmove( &vg_console
.input
[ start
],
446 &vg_console
.input
[ end
],
451 VG_STATIC
void console_to_clipboard(void)
454 console_make_selection( &start
, &end
);
459 memcpy( buffer
, &vg_console
.input
[ start
], end
-start
);
460 buffer
[ end
-start
] = 0x00;
461 SDL_SetClipboardText( buffer
);
465 VG_STATIC
void console_clipboard_paste(void)
467 if( !SDL_HasClipboardText() )
470 char *text
= SDL_GetClipboardText();
475 int datastart
= console_delete_char( 0 );
476 int length
= strlen( text
);
477 int cpylength
= console_makeroom( datastart
, length
);
479 memcpy( vg_console
.input
+ datastart
, text
, cpylength
);
480 console_move_cursor( &vg_console
.cursor_user
,
481 &vg_console
.cursor_pos
, cpylength
, 1 );
486 VG_STATIC
void console_put_char( char c
)
488 if( !vg_console
.enabled
)
491 vg_console
.cursor_user
= console_delete_char(0);
493 if( console_makeroom( vg_console
.cursor_user
, 1 ) )
494 vg_console
.input
[ vg_console
.cursor_user
] = c
;
496 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, 1, 1 );
499 VG_STATIC
void console_history_get( char* buf
, int entry_num
)
501 if( !vg_console
.history_count
)
504 int offset
= VG_MIN( entry_num
, vg_console
.history_count
-1 ),
505 pick
= (vg_console
.history_last
- offset
) %
506 vg_list_size( vg_console
.history
);
507 strcpy( buf
, vg_console
.history
[ pick
] );
510 /* Receed secondary cursor */
511 VG_STATIC
void _console_left_select(void)
513 console_move_cursor( &vg_console
.cursor_user
, NULL
, -1, 0 );
516 /* Match and receed both cursors */
517 VG_STATIC
void _console_left(void)
519 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
521 console_move_cursor( &vg_console
.cursor_user
,
522 &vg_console
.cursor_pos
, -cursor_diff
, 1 );
525 VG_STATIC
void _console_right_select(void)
527 console_move_cursor( &vg_console
.cursor_user
, NULL
, 1, 0 );
530 VG_STATIC
void _console_right(void)
532 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
534 console_move_cursor( &vg_console
.cursor_user
,
535 &vg_console
.cursor_pos
, +cursor_diff
, 1 );
538 VG_STATIC
void _console_down(void)
540 vg_console
.history_pos
= VG_MAX( 0, vg_console
.history_pos
-1 );
541 console_history_get( vg_console
.input
, vg_console
.history_pos
);
543 console_move_cursor( &vg_console
.cursor_user
,
544 &vg_console
.cursor_pos
,
545 vg_list_size( vg_console
.input
), 1 );
548 VG_STATIC
void _console_up(void)
550 vg_console
.history_pos
= VG_MAX
555 vg_console
.history_pos
+1,
558 vg_list_size( vg_console
.history
),
559 vg_console
.history_count
- 1
564 console_history_get( vg_console
.input
, vg_console
.history_pos
);
565 console_move_cursor( &vg_console
.cursor_user
,
566 &vg_console
.cursor_pos
,
567 vg_list_size( vg_console
.input
), 1);
570 VG_STATIC
void _console_backspace(void)
572 vg_console
.cursor_user
= console_delete_char( -1 );
573 vg_console
.cursor_pos
= vg_console
.cursor_user
;
576 VG_STATIC
void _console_delete(void)
578 vg_console
.cursor_user
= console_delete_char( 1 );
579 vg_console
.cursor_pos
= vg_console
.cursor_user
;
582 VG_STATIC
void _console_home_select(void)
584 console_move_cursor( &vg_console
.cursor_user
, NULL
, -10000, 0 );
587 VG_STATIC
void _console_home(void)
589 console_move_cursor( &vg_console
.cursor_user
,
590 &vg_console
.cursor_pos
, -10000, 1 );
593 VG_STATIC
void _console_end_select(void)
595 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0 );
598 VG_STATIC
void _console_end(void)
600 console_move_cursor( &vg_console
.cursor_user
,
601 &vg_console
.cursor_pos
,
602 vg_list_size( vg_console
.input
), 1 );
605 VG_STATIC
void _console_select_all(void)
607 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0);
608 console_move_cursor( &vg_console
.cursor_pos
, NULL
, -10000, 0);
611 VG_STATIC
void _console_cut(void)
613 console_to_clipboard();
614 vg_console
.cursor_user
= console_delete_char(0);
615 vg_console
.cursor_pos
= vg_console
.cursor_user
;
618 VG_STATIC
void _console_enter(void)
620 if( !strlen( vg_console
.input
) )
623 vg_info( "%s\n", vg_console
.input
);
625 if( strcmp( vg_console
.input
,
626 vg_console
.history
[ vg_console
.history_last
]) )
628 vg_console
.history_last
= ( vg_console
.history_last
+ 1) %
629 vg_list_size(vg_console
.history
);
630 vg_console
.history_count
=
631 VG_MIN( vg_list_size( vg_console
.history
),
632 vg_console
.history_count
+ 1 );
633 strcpy( vg_console
.history
[ vg_console
.history_last
],
637 vg_console
.history_pos
= -1;
638 vg_execute_console_input( vg_console
.input
);
639 console_move_cursor( &vg_console
.cursor_user
,
640 &vg_console
.cursor_pos
, -10000, 1 );
641 vg_console
.input
[0] = '\0';
644 VG_STATIC
void console_proc_key( SDL_Keysym ev
)
646 /* Open / close console */
647 if( ev
.sym
== SDLK_BACKQUOTE
)
649 vg_console
.enabled
= !vg_console
.enabled
;
651 if( vg_console
.enabled
)
652 SDL_StartTextInput();
657 if( !vg_console
.enabled
) return;
659 struct console_mapping
664 void (*handler
)(void);
668 { 0, SDLK_LEFT
, _console_left
},
669 { KMOD_SHIFT
, SDLK_LEFT
, _console_left_select
},
670 { 0, SDLK_RIGHT
, _console_right
},
671 { KMOD_SHIFT
, SDLK_RIGHT
, _console_right_select
},
672 { 0, SDLK_DOWN
, _console_down
},
673 { 0, SDLK_UP
, _console_up
},
674 { 0, SDLK_BACKSPACE
, _console_backspace
},
675 { 0, SDLK_DELETE
, _console_delete
},
676 { 0, SDLK_HOME
, _console_home
},
677 { KMOD_SHIFT
, SDLK_HOME
, _console_home_select
},
678 { 0, SDLK_END
, _console_end
},
679 { KMOD_SHIFT
, SDLK_END
, _console_end_select
},
680 { KMOD_CTRL
, SDLK_a
, _console_select_all
},
681 { KMOD_CTRL
, SDLK_c
, console_to_clipboard
},
682 { KMOD_CTRL
, SDLK_x
, _console_cut
},
683 { KMOD_CTRL
, SDLK_v
, console_clipboard_paste
},
684 { 0, SDLK_RETURN
, _console_enter
}
687 SDL_Keymod mod
= ev
.mod
& (KMOD_SHIFT
|KMOD_CTRL
|KMOD_ALT
);
689 for( int i
=0; i
<vg_list_size( mappings
); i
++ )
691 struct console_mapping
*mapping
= &mappings
[i
];
693 if( mapping
->key
== ev
.sym
)
695 if( mapping
->mod
== 0 )
703 else if( (mod
& mapping
->mod
) == mapping
->mod
)
712 VG_STATIC
void console_proc_utf8( const char *text
)
714 const char *ptr
= text
;
719 console_put_char( *ptr
);
724 #endif /* VG_CONSOLE_H */