1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
9 typedef struct vg_convar vg_convar
;
10 typedef struct vg_cmd vg_cmd
;
44 int persistent
; /* Should this var be stored to cfg/auto.conf? */
50 int (*function
)( int argc
, char const *argv
[] );
55 u32 convar_count
, function_count
;
58 int cursor_user
, cursor_pos
, string_length
;
61 int history_last
, history_pos
, history_count
;
67 VG_STATIC
void vg_convar_push( struct vg_convar cv
);
68 VG_STATIC
void vg_function_push( struct vg_cmd cmd
);
70 VG_STATIC
void vg_console_draw( void );
71 void vg_console_println( const char *str
);
72 VG_STATIC
int vg_console_list( int argc
, char const *argv
[] );
73 VG_STATIC
void vg_console_init(void);
74 VG_STATIC
void vg_console_write_persistent(void);
75 VG_STATIC
void vg_console_free(void);
76 VG_STATIC
void execute_console_input( const char *cmd
);
81 VG_STATIC
void console_make_selection( int* start
, int* end
);
82 VG_STATIC
void console_move_cursor( int* cursor0
, int* cursor1
,
83 int dir
, int snap_together
);
84 VG_STATIC
int console_makeroom( int datastart
, int length
);
85 VG_STATIC
int console_delete_char( int direction
);
86 VG_STATIC
void console_to_clipboard(void);
87 VG_STATIC
void console_clipboard_paste(void);
88 VG_STATIC
void console_put_char( char c
);
89 VG_STATIC
void console_history_get( char* buf
, int entry_num
);
90 VG_STATIC
void console_proc_key( GLFWwindow
* ptrW
, int key
,
91 int scancode
, int action
, int mods
);
92 VG_STATIC
void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
);
93 VG_STATIC
int vg_console_enabled(void);
98 VG_STATIC
int vg_console_enabled(void)
100 return vg_console
.enabled
;
103 VG_STATIC
void vg_convar_push( vg_convar cv
)
105 if( vg_console
.convar_count
> vg_list_size(vg_console
.convars
) )
106 vg_fatal_exit_loop( "Too many convars registered" );
108 vg_info( "Console variable '%s' registered\n", cv
.name
);
109 vg_console
.convars
[ vg_console
.convar_count
++ ] = cv
;
112 VG_STATIC
void vg_function_push( struct vg_cmd cmd
)
114 if( vg_console
.function_count
> vg_list_size(vg_console
.functions
) )
115 vg_fatal_exit_loop( "Too many functions registered" );
117 vg_console
.functions
[ vg_console
.function_count
++ ] = cmd
;
120 VG_STATIC
void vg_console_draw( void )
122 if( !vg_console
.enabled
)
125 vg_mutex_lock( &log_print_mutex
);
127 int ptr
= vg_log
.buffer_line_current
;
130 int console_lines
= VG_MIN( log_lines
, vg_log
.buffer_line_count
);
132 vg_uictx
.cursor
[0] = 0;
133 vg_uictx
.cursor
[1] = 0;
134 vg_uictx
.cursor
[3] = log_lines
*fh
;
139 ui_fill_rect( vg_uictx
.cursor
, 0x77333333 );
141 vg_uictx
.cursor
[3] = fh
;
144 for( int i
=0; i
<console_lines
; i
++ )
149 ptr
= vg_list_size( vg_log
.buffer
)-1;
151 ui_text( vg_uictx
.cursor
, vg_log
.buffer
[ptr
], 1, 0 );
152 vg_uictx
.cursor
[1] -= fh
;
158 vg_uictx
.cursor
[1] += 2;
159 vg_uictx
.cursor
[3] = fh
;
163 ui_fill_rect( vg_uictx
.cursor
, 0x77333333 );
164 ui_text( vg_uictx
.cursor
, vg_console
.input
, 1, 0 );
166 int start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
),
167 end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
169 vg_uictx
.cursor
[0] = start
* UI_GLYPH_SPACING_X
;
170 vg_uictx
.cursor
[2] = (start
== end
? 0.5f
: (float)(end
-start
))
171 * (float)UI_GLYPH_SPACING_X
;
173 ui_fill_rect( vg_uictx
.cursor
, 0x66ffffff );
176 vg_mutex_unlock( &log_print_mutex
);
179 VG_STATIC
int vg_console_list( int argc
, char const *argv
[] )
181 for( int i
=0; i
<vg_console
.function_count
; i
++ )
183 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
184 vg_info( "* %s\n", cmd
->name
);
187 for( int i
=0; i
<vg_console
.convar_count
; i
++ )
189 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
190 vg_info( "%s\n", cv
->name
);
196 int _test_break( int argc
, const char *argv
[] )
198 vg_fatal_exit_loop( "Test crash from main, after loading (console)" );
202 VG_STATIC
void vg_console_init(void)
204 vg_function_push( (struct vg_cmd
)
207 .function
= vg_console_list
210 vg_function_push( (struct vg_cmd
)
213 .function
= _test_break
217 VG_STATIC
void vg_console_load_autos(void)
219 /* Read and exec persistent commands */
220 FILE *fp
= fopen( "cfg/auto.conf", "r" );
225 while( fgets( line
, sizeof( line
), fp
) )
227 line
[ strcspn( line
, "\r\n#" ) ] = 0x00;
229 if( line
[0] != 0x00 )
231 execute_console_input( line
);
239 VG_STATIC
void vg_console_write_persistent(void)
241 FILE *fp
= fopen( "cfg/auto.conf", "w" );
243 for( int i
=0; i
<vg_console
.convar_count
; i
++ )
245 struct vg_convar
*cv
= &vg_console
.convars
[i
];
249 switch( cv
->data_type
)
251 case k_convar_dtype_i32
:
252 fprintf( fp
, "%s %d\n", cv
->name
, *(i32
*)(cv
->data
) );
254 case k_convar_dtype_u32
:
255 fprintf( fp
, "%s %u\n", cv
->name
, *(u32
*)(cv
->data
) );
257 case k_convar_dtype_f32
:
258 fprintf( fp
, "%s %.5f\n", cv
->name
, *(float *)(cv
->data
) );
267 VG_STATIC
void vg_console_free(void)
269 vg_console_write_persistent();
272 VG_STATIC
void execute_console_input( const char *cmd
)
280 /* Split string into tokens */
281 for( int i
= 0; i
< vg_list_size( temp
); i
++ )
285 if( cmd
[i
] == ' ' || cmd
[i
] == '\t' )
290 if( arg_count
== vg_list_size( args
) )
299 args
[ arg_count
++ ] = temp
+ i
;
317 for( int i
=0; i
<vg_console
.convar_count
; i
++ )
319 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
320 if( !strcmp( cv
->name
, args
[0] ) )
322 /* Cvar Matched, try get value */
325 switch( cv
->data_type
)
327 case k_convar_dtype_u32
:
328 case k_convar_dtype_i32
:
330 data_int
= atoi( args
[1] );
332 *((int *)cv
->data
) = cv
->opt_i32
.clamp
?
333 VG_MIN( VG_MAX(data_int
, cv
->opt_i32
.min
), cv
->opt_i32
.max
):
337 case k_convar_dtype_f32
:
338 data_float
= atof( args
[1] );
339 *((float *)cv
->data
) = cv
->opt_f32
.clamp
?
340 vg_minf( vg_maxf( data_float
, cv
->opt_f32
.min
),
351 switch( cv
->data_type
)
353 case k_convar_dtype_i32
:
354 vg_info( "= %d\n", *((int *)cv
->data
) );
356 case k_convar_dtype_u32
:
357 vg_info( "= %u\n", *((u32
*)cv
->data
) );
359 case k_convar_dtype_f32
:
360 vg_info( "= %.4f\n", *((float *)cv
->data
) );
370 * Find and excecute command
372 for( int i
=0; i
<vg_console
.function_count
; i
++ )
374 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
375 if( !strcmp( cmd
->name
, args
[0] ) )
377 cmd
->function( arg_count
-1, args
+1 );
382 vg_error( "No command/var named '%s'. Use 'list' to view all\n", args
[0] );
388 VG_STATIC
void console_make_selection( int* start
, int* end
)
390 *start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
);
391 *end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
394 VG_STATIC
void console_move_cursor( int* cursor0
, int* cursor1
,
395 int dir
, int snap_together
)
397 *cursor0
= VG_MAX( 0, vg_console
.cursor_user
+ dir
);
400 VG_MIN( vg_list_size( vg_console
.input
), strlen( vg_console
.input
)),
407 VG_STATIC
int console_makeroom( int datastart
, int length
)
409 int move_to
= VG_MIN( datastart
+length
, vg_list_size( vg_console
.input
) );
410 int move_amount
= strlen( vg_console
.input
)-datastart
;
412 VG_MIN( move_to
+move_amount
, vg_list_size( vg_console
.input
) );
413 move_amount
= move_end
-move_to
;
416 memmove( &vg_console
.input
[ move_to
],
417 &vg_console
.input
[ datastart
],
420 vg_console
.input
[ move_end
] = '\0';
422 return VG_MIN( length
, vg_list_size( vg_console
.input
)-datastart
);
425 VG_STATIC
int console_delete_char( int direction
)
428 console_make_selection( &start
, &end
);
430 /* There is no selection */
433 if( direction
== 1 ) end
= VG_MIN( end
+1, strlen( vg_console
.input
) );
434 else if( direction
== -1 ) start
= VG_MAX( start
-1, 0 );
437 /* Still no selction, no need to do anything */
441 /* Copy the end->terminator to start */
442 int remaining_length
= strlen( vg_console
.input
)+1-end
;
443 memmove( &vg_console
.input
[ start
],
444 &vg_console
.input
[ end
],
449 VG_STATIC
void console_to_clipboard(void)
452 console_make_selection( &start
, &end
);
457 memcpy( buffer
, &vg_console
.input
[ start
], end
-start
);
458 buffer
[ end
-start
] = 0x00;
459 glfwSetClipboardString( NULL
, buffer
);
463 VG_STATIC
void console_clipboard_paste(void)
465 int datastart
= console_delete_char(0);
466 const char* clipboard
= glfwGetClipboardString(NULL
);
467 int length
= strlen(clipboard
);
469 int cpylength
= console_makeroom(datastart
, length
);
471 memcpy( vg_console
.input
+ datastart
, clipboard
, cpylength
);
472 console_move_cursor( &vg_console
.cursor_user
,
473 &vg_console
.cursor_pos
, cpylength
, 1 );
476 VG_STATIC
void console_put_char( char c
)
478 if( !vg_console
.enabled
)
481 vg_console
.cursor_user
= console_delete_char(0);
483 if( console_makeroom( vg_console
.cursor_user
, 1 ) )
484 vg_console
.input
[ vg_console
.cursor_user
] = c
;
486 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, 1, 1 );
489 VG_STATIC
void console_history_get( char* buf
, int entry_num
)
491 if( !vg_console
.history_count
)
494 int offset
= VG_MIN( entry_num
, vg_console
.history_count
-1 ),
495 pick
= (vg_console
.history_last
- offset
) %
496 vg_list_size( vg_console
.history
);
497 strcpy( buf
, vg_console
.history
[ pick
] );
500 /* Receed secondary cursor */
501 VG_STATIC
void _console_left_select(void)
503 console_move_cursor( &vg_console
.cursor_user
, NULL
, -1, 0 );
506 /* Match and receed both cursors */
507 VG_STATIC
void _console_left(void)
509 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
511 console_move_cursor( &vg_console
.cursor_user
,
512 &vg_console
.cursor_pos
, -cursor_diff
, 1 );
515 VG_STATIC
void _console_right_select(void)
517 console_move_cursor( &vg_console
.cursor_user
, NULL
, 1, 0 );
520 VG_STATIC
void _console_right(void)
522 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
524 console_move_cursor( &vg_console
.cursor_user
,
525 &vg_console
.cursor_pos
, +cursor_diff
, 1 );
528 VG_STATIC
void _console_down(void)
530 vg_console
.history_pos
= VG_MAX( 0, vg_console
.history_pos
-1 );
531 console_history_get( vg_console
.input
, vg_console
.history_pos
);
533 console_move_cursor( &vg_console
.cursor_user
,
534 &vg_console
.cursor_pos
,
535 vg_list_size( vg_console
.input
), 1 );
538 VG_STATIC
void _console_up(void)
540 vg_console
.history_pos
= VG_MAX
545 vg_console
.history_pos
+1,
548 vg_list_size( vg_console
.history
),
549 vg_console
.history_count
- 1
554 console_history_get( vg_console
.input
, vg_console
.history_pos
);
555 console_move_cursor( &vg_console
.cursor_user
,
556 &vg_console
.cursor_pos
,
557 vg_list_size( vg_console
.input
), 1);
560 VG_STATIC
void _console_backspace(void)
562 vg_console
.cursor_user
= console_delete_char( -1 );
563 vg_console
.cursor_pos
= vg_console
.cursor_user
;
566 VG_STATIC
void _console_delete(void)
568 vg_console
.cursor_user
= console_delete_char( 1 );
569 vg_console
.cursor_pos
= vg_console
.cursor_user
;
572 VG_STATIC
void _console_home_select(void)
574 console_move_cursor( &vg_console
.cursor_user
, NULL
, -10000, 0 );
577 VG_STATIC
void _console_home(void)
579 console_move_cursor( &vg_console
.cursor_user
,
580 &vg_console
.cursor_pos
, -10000, 1 );
583 VG_STATIC
void _console_end_select(void)
585 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0 );
588 VG_STATIC
void _console_end(void)
590 console_move_cursor( &vg_console
.cursor_user
,
591 &vg_console
.cursor_pos
,
592 vg_list_size( vg_console
.input
), 1 );
595 VG_STATIC
void _console_select_all(void)
597 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0);
598 console_move_cursor( &vg_console
.cursor_pos
, NULL
, -10000, 0);
601 VG_STATIC
void _console_cut(void)
603 console_to_clipboard();
604 vg_console
.cursor_user
= console_delete_char(0);
605 vg_console
.cursor_pos
= vg_console
.cursor_user
;
608 VG_STATIC
void _console_enter(void)
610 if( !strlen( vg_console
.input
) )
613 vg_info( "%s\n", vg_console
.input
);
615 if( strcmp( vg_console
.input
,
616 vg_console
.history
[ vg_console
.history_last
]) )
618 vg_console
.history_last
= ( vg_console
.history_last
+ 1) %
619 vg_list_size(vg_console
.history
);
620 vg_console
.history_count
=
621 VG_MIN( vg_list_size( vg_console
.history
),
622 vg_console
.history_count
+ 1 );
623 strcpy( vg_console
.history
[ vg_console
.history_last
],
627 vg_console
.history_pos
= -1;
628 execute_console_input( vg_console
.input
);
629 console_move_cursor( &vg_console
.cursor_user
,
630 &vg_console
.cursor_pos
, -10000, 1 );
631 vg_console
.input
[0] = '\0';
634 VG_STATIC
void console_proc_key( GLFWwindow
* ptrW
, int key
, int scancode
,
635 int action
, int mods
)
640 /* Open / close console */
641 if( key
== GLFW_KEY_GRAVE_ACCENT
)
642 vg_console
.enabled
= !vg_console
.enabled
;
644 if( !vg_console
.enabled
) return;
646 struct console_mapping
649 void (*handler
)(void);
653 { 0, GLFW_KEY_LEFT
, _console_left
},
654 { GLFW_MOD_SHIFT
, GLFW_KEY_LEFT
, _console_left_select
},
655 { 0, GLFW_KEY_RIGHT
, _console_right
},
656 { GLFW_MOD_SHIFT
, GLFW_KEY_RIGHT
, _console_right_select
},
657 { 0, GLFW_KEY_DOWN
, _console_down
},
658 { 0, GLFW_KEY_UP
, _console_up
},
659 { 0, GLFW_KEY_BACKSPACE
, _console_backspace
},
660 { 0, GLFW_KEY_DELETE
, _console_delete
},
661 { 0, GLFW_KEY_HOME
, _console_home
},
662 { GLFW_MOD_SHIFT
, GLFW_KEY_HOME
, _console_home_select
},
663 { 0, GLFW_KEY_END
, _console_end
},
664 { GLFW_MOD_SHIFT
, GLFW_KEY_END
, _console_end_select
},
665 { GLFW_MOD_CONTROL
, GLFW_KEY_A
, _console_select_all
},
666 { GLFW_MOD_CONTROL
, GLFW_KEY_C
, console_to_clipboard
},
667 { GLFW_MOD_CONTROL
, GLFW_KEY_X
, _console_cut
},
668 { GLFW_MOD_CONTROL
, GLFW_KEY_V
, console_clipboard_paste
},
669 { 0, GLFW_KEY_ENTER
, _console_enter
}
672 for( int i
=0; i
<vg_list_size( mapping
); i
++ )
674 struct console_mapping
*mk
= &mapping
[i
];
686 else if( (mods
& mk
->mod
) == mk
->mod
)
695 /* Handle an OS based input of UTF32 character from the keyboard or such */
696 VG_STATIC
void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
)
698 if( uWchar
<= 0x7F && (char)uWchar
!= 0x60)
700 console_put_char((char)uWchar
);
704 #endif /* VG_CONSOLE_H */