diff options
-rw-r--r-- | code/client/cl_console.c | 12 | ||||
-rw-r--r-- | code/client/cl_keys.c | 46 | ||||
-rw-r--r-- | code/client/cl_main.c | 35 | ||||
-rw-r--r-- | code/qcommon/cmd.c | 45 | ||||
-rw-r--r-- | code/qcommon/common.c | 96 | ||||
-rw-r--r-- | code/qcommon/cvar.c | 22 | ||||
-rw-r--r-- | code/qcommon/qcommon.h | 13 | ||||
-rw-r--r-- | code/server/sv_ccmds.c | 15 |
8 files changed, 195 insertions, 89 deletions
diff --git a/code/client/cl_console.c b/code/client/cl_console.c index 5aad766..80e4e43 100644 --- a/code/client/cl_console.c +++ b/code/client/cl_console.c @@ -302,6 +302,17 @@ void Con_CheckResize (void) con.display = con.current; } +/* +================== +Cmd_CompleteTxtName +================== +*/ +void Cmd_CompleteTxtName( char *args, int argNum ) { + if( argNum == 2 ) { + Field_CompleteFilename( "", "txt", qfalse ); + } +} + /* ================ @@ -329,6 +340,7 @@ void Con_Init (void) { Cmd_AddCommand ("messagemode4", Con_MessageMode4_f); Cmd_AddCommand ("clear", Con_Clear_f); Cmd_AddCommand ("condump", Con_Dump_f); + Cmd_SetCommandCompletionFunc( "condump", Cmd_CompleteTxtName ); } diff --git a/code/client/cl_keys.c b/code/client/cl_keys.c index 3097f54..f2932d9 100644 --- a/code/client/cl_keys.c +++ b/code/client/cl_keys.c @@ -1058,6 +1058,50 @@ void Key_KeynameCompletion( void(*callback)(const char *s) ) { } /* +==================== +Key_CompleteUnbind +==================== +*/ +static void Key_CompleteUnbind( char *args, int argNum ) +{ + if( argNum == 2 ) + { + // Skip "unbind " + char *p = Com_SkipTokens( args, 1, " " ); + + if( p > args ) + Field_CompleteKeyname( ); + } +} + +/* +==================== +Key_CompleteBind +==================== +*/ +static void Key_CompleteBind( char *args, int argNum ) +{ + char *p; + + if( argNum == 2 ) + { + // Skip "bind " + p = Com_SkipTokens( args, 1, " " ); + + if( p > args ) + Field_CompleteKeyname( ); + } + else if( argNum >= 3 ) + { + // Skip "bind <key> " + p = Com_SkipTokens( args, 2, " " ); + + if( p > args ) + Field_CompleteCommand( p, qtrue, qtrue ); + } +} + +/* =================== CL_InitKeyCommands =================== @@ -1065,7 +1109,9 @@ CL_InitKeyCommands void CL_InitKeyCommands( void ) { // register our functions Cmd_AddCommand ("bind",Key_Bind_f); + Cmd_SetCommandCompletionFunc( "bind", Key_CompleteBind ); Cmd_AddCommand ("unbind",Key_Unbind_f); + Cmd_SetCommandCompletionFunc( "unbind", Key_CompleteUnbind ); Cmd_AddCommand ("unbindall",Key_Unbindall_f); Cmd_AddCommand ("bindlist",Key_Bindlist_f); } diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 64c1cfb..01c044a 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -872,6 +872,22 @@ static void CL_WalkDemoExt(char *arg, char *name, int *demofile) /* ==================== +CL_CompleteDemoName +==================== +*/ +static void CL_CompleteDemoName( char *args, int argNum ) +{ + if( argNum == 2 ) + { + char demoExt[ 16 ]; + + Com_sprintf( demoExt, sizeof( demoExt ), ".dm_%d", PROTOCOL_VERSION ); + Field_CompleteFilename( "demos", demoExt, qtrue ); + } +} + +/* +==================== CL_PlayDemo_f demo <demoname> @@ -1566,6 +1582,23 @@ void CL_Connect_f( void ) { #define MAX_RCON_MESSAGE 1024 /* +================== +CL_CompleteRcon +================== +*/ +static void CL_CompleteRcon( char *args, int argNum ) +{ + if( argNum == 2 ) + { + // Skip "rcon " + char *p = Com_SkipTokens( args, 1, " " ); + + if( p > args ) + Field_CompleteCommand( p, qtrue, qtrue ); + } +} + +/* ===================== CL_Rcon_f @@ -3150,6 +3183,7 @@ void CL_Init( void ) { Cmd_AddCommand ("disconnect", CL_Disconnect_f); Cmd_AddCommand ("record", CL_Record_f); Cmd_AddCommand ("demo", CL_PlayDemo_f); + Cmd_SetCommandCompletionFunc( "demo", CL_CompleteDemoName ); Cmd_AddCommand ("cinematic", CL_PlayCinematic_f); Cmd_AddCommand ("stoprecord", CL_StopRecord_f); Cmd_AddCommand ("connect", CL_Connect_f); @@ -3157,6 +3191,7 @@ void CL_Init( void ) { Cmd_AddCommand ("localservers", CL_LocalServers_f); Cmd_AddCommand ("globalservers", CL_GlobalServers_f); Cmd_AddCommand ("rcon", CL_Rcon_f); + Cmd_SetCommandCompletionFunc( "rcon", CL_CompleteRcon ); Cmd_AddCommand ("setenv", CL_Setenv_f ); Cmd_AddCommand ("ping", CL_Ping_f ); Cmd_AddCommand ("serverstatus", CL_ServerStatus_f ); diff --git a/code/qcommon/cmd.c b/code/qcommon/cmd.c index 8ce1526..1f05452 100644 --- a/code/qcommon/cmd.c +++ b/code/qcommon/cmd.c @@ -313,6 +313,7 @@ typedef struct cmd_function_s struct cmd_function_s *next; char *name; xcommand_t function; + completionFunc_t complete; } cmd_function_t; @@ -584,12 +585,28 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) { cmd = S_Malloc (sizeof(cmd_function_t)); cmd->name = CopyString( cmd_name ); cmd->function = function; + cmd->complete = NULL; cmd->next = cmd_functions; cmd_functions = cmd; } /* ============ +Cmd_SetCommandCompletionFunc +============ +*/ +void Cmd_SetCommandCompletionFunc( const char *command, completionFunc_t complete ) { + cmd_function_t *cmd; + + for( cmd = cmd_functions; cmd; cmd = cmd->next ) { + if( !Q_stricmp( command, cmd->name ) ) { + cmd->complete = complete; + } + } +} + +/* +============ Cmd_RemoveCommand ============ */ @@ -629,6 +646,21 @@ void Cmd_CommandCompletion( void(*callback)(const char *s) ) { } } +/* +============ +Cmd_CompleteArgument +============ +*/ +void Cmd_CompleteArgument( const char *command, char *args, int argNum ) { + cmd_function_t *cmd; + + for( cmd = cmd_functions; cmd; cmd = cmd->next ) { + if( !Q_stricmp( command, cmd->name ) && cmd->complete ) { + cmd->complete( args, argNum ); + } + } +} + /* ============ @@ -720,6 +752,17 @@ void Cmd_List_f (void) } /* +================== +Cmd_CompleteCfgName +================== +*/ +void Cmd_CompleteCfgName( char *args, int argNum ) { + if( argNum == 2 ) { + Field_CompleteFilename( "", "cfg", qfalse ); + } +} + +/* ============ Cmd_Init ============ @@ -727,7 +770,9 @@ Cmd_Init void Cmd_Init (void) { Cmd_AddCommand ("cmdlist",Cmd_List_f); Cmd_AddCommand ("exec",Cmd_Exec_f); + Cmd_SetCommandCompletionFunc( "exec", Cmd_CompleteCfgName ); Cmd_AddCommand ("vstr",Cmd_Vstr_f); + Cmd_SetCommandCompletionFunc( "vstr", Cvar_CompleteCvarName ); Cmd_AddCommand ("echo",Cmd_Echo_f); Cmd_AddCommand ("wait", Cmd_Wait_f); } diff --git a/code/qcommon/common.c b/code/qcommon/common.c index 5dda171..4436aea 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -2621,6 +2621,7 @@ void Com_Init( char *commandLine ) { Cmd_AddCommand ("quit", Com_Quit_f); Cmd_AddCommand ("changeVectors", MSG_ReportChangeVectors_f ); Cmd_AddCommand ("writeconfig", Com_WriteConfig_f ); + Cmd_SetCommandCompletionFunc( "writeconfig", Cmd_CompleteCfgName ); s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, __DATE__ ); com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO ); @@ -3168,7 +3169,7 @@ static qboolean Field_Complete( void ) Field_CompleteKeyname =============== */ -static void Field_CompleteKeyname( void ) +void Field_CompleteKeyname( void ) { matchCount = 0; shortestMatch[ 0 ] = 0; @@ -3185,7 +3186,7 @@ static void Field_CompleteKeyname( void ) Field_CompleteFilename =============== */ -static void Field_CompleteFilename( const char *dir, +void Field_CompleteFilename( const char *dir, const char *ext, qboolean stripExt ) { matchCount = 0; @@ -3202,11 +3203,10 @@ static void Field_CompleteFilename( const char *dir, Field_CompleteCommand =============== */ -static void Field_CompleteCommand( char *cmd, +void Field_CompleteCommand( char *cmd, qboolean doCommands, qboolean doCvars ) { int completionArgument = 0; - char *p; // Skip leading whitespace and quotes cmd = Com_SkipCharset( cmd, " \"" ); @@ -3248,6 +3248,7 @@ static void Field_CompleteCommand( char *cmd, if( completionArgument > 1 ) { const char *baseCmd = Cmd_Argv( 0 ); + char *p; #ifndef DEDICATED // This should always be true @@ -3256,92 +3257,9 @@ static void Field_CompleteCommand( char *cmd, #endif if( ( p = Field_FindFirstSeparator( cmd ) ) ) - { - // Compound command - Field_CompleteCommand( p + 1, qtrue, qtrue ); - } + Field_CompleteCommand( p + 1, qtrue, qtrue ); // Compound command else - { - // FIXME: all this junk should really be associated with the respective - // commands, instead of being hard coded here - if( ( !Q_stricmp( baseCmd, "map" ) || - !Q_stricmp( baseCmd, "devmap" ) || - !Q_stricmp( baseCmd, "spmap" ) || - !Q_stricmp( baseCmd, "spdevmap" ) ) && - completionArgument == 2 ) - { - Field_CompleteFilename( "maps", "bsp", qtrue ); - } - else if( ( !Q_stricmp( baseCmd, "exec" ) || - !Q_stricmp( baseCmd, "writeconfig" ) ) && - completionArgument == 2 ) - { - Field_CompleteFilename( "", "cfg", qfalse ); - } - else if( !Q_stricmp( baseCmd, "condump" ) && - completionArgument == 2 ) - { - Field_CompleteFilename( "", "txt", qfalse ); - } - else if( ( !Q_stricmp( baseCmd, "toggle" ) || - !Q_stricmp( baseCmd, "vstr" ) || - !Q_stricmp( baseCmd, "set" ) || - !Q_stricmp( baseCmd, "seta" ) || - !Q_stricmp( baseCmd, "setu" ) || - !Q_stricmp( baseCmd, "sets" ) ) && - completionArgument == 2 ) - { - // Skip "<cmd> " - p = Com_SkipTokens( cmd, 1, " " ); - - if( p > cmd ) - Field_CompleteCommand( p, qfalse, qtrue ); - } -#ifndef DEDICATED - else if( !Q_stricmp( baseCmd, "demo" ) && completionArgument == 2 ) - { - char demoExt[ 16 ]; - - Com_sprintf( demoExt, sizeof( demoExt ), ".dm_%d", PROTOCOL_VERSION ); - Field_CompleteFilename( "demos", demoExt, qtrue ); - } - else if( !Q_stricmp( baseCmd, "rcon" ) && completionArgument == 2 ) - { - // Skip "rcon " - p = Com_SkipTokens( cmd, 1, " " ); - - if( p > cmd ) - Field_CompleteCommand( p, qtrue, qtrue ); - } - else if( !Q_stricmp( baseCmd, "bind" ) ) - { - if( completionArgument == 2 ) - { - // Skip "bind " - p = Com_SkipTokens( cmd, 1, " " ); - - if( p > cmd ) - Field_CompleteKeyname( ); - } - else if( completionArgument >= 3 ) - { - // Skip "bind <key> " - p = Com_SkipTokens( cmd, 2, " " ); - - if( p > cmd ) - Field_CompleteCommand( p, qtrue, qtrue ); - } - } - else if( !Q_stricmp( baseCmd, "unbind" ) && completionArgument == 2 ) - { - // Skip "unbind " - p = Com_SkipTokens( cmd, 1, " " ); - - if( p > cmd ) - Field_CompleteKeyname( ); - } -#endif - } + Cmd_CompleteArgument( baseCmd, cmd, completionArgument ); } else { diff --git a/code/qcommon/cvar.c b/code/qcommon/cvar.c index fc2a9fa..6f6092b 100644 --- a/code/qcommon/cvar.c +++ b/code/qcommon/cvar.c @@ -1055,6 +1055,22 @@ void Cvar_Update( vmCvar_t *vmCvar ) { vmCvar->integer = cv->integer; } +/* +================== +Cvar_CompleteCvarName +================== +*/ +void Cvar_CompleteCvarName( char *args, int argNum ) +{ + if( argNum == 2 ) + { + // Skip "<cmd> " + char *p = Com_SkipTokens( args, 1, " " ); + + if( p > args ) + Field_CompleteCommand( p, qfalse, qtrue ); + } +} /* ============ @@ -1068,11 +1084,17 @@ void Cvar_Init (void) { Cmd_AddCommand ("print", Cvar_Print_f); Cmd_AddCommand ("toggle", Cvar_Toggle_f); + Cmd_SetCommandCompletionFunc( "toggle", Cvar_CompleteCvarName ); Cmd_AddCommand ("set", Cvar_Set_f); + Cmd_SetCommandCompletionFunc( "set", Cvar_CompleteCvarName ); Cmd_AddCommand ("sets", Cvar_Set_f); + Cmd_SetCommandCompletionFunc( "sets", Cvar_CompleteCvarName ); Cmd_AddCommand ("setu", Cvar_Set_f); + Cmd_SetCommandCompletionFunc( "setu", Cvar_CompleteCvarName ); Cmd_AddCommand ("seta", Cvar_Set_f); + Cmd_SetCommandCompletionFunc( "seta", Cvar_CompleteCvarName ); Cmd_AddCommand ("reset", Cvar_Reset_f); + Cmd_SetCommandCompletionFunc( "reset", Cvar_CompleteCvarName ); Cmd_AddCommand ("cvarlist", Cvar_List_f); Cmd_AddCommand ("cvar_restart", Cvar_Restart_f); } diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 006342a..381da64 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -421,8 +421,14 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function ); void Cmd_RemoveCommand( const char *cmd_name ); +typedef void (*completionFunc_t)( char *args, int argNum ); + void Cmd_CommandCompletion( void(*callback)(const char *s) ); // callback with each valid string +void Cmd_SetCommandCompletionFunc( const char *command, + completionFunc_t complete ); +void Cmd_CompleteArgument( const char *command, char *args, int argNum ); +void Cmd_CompleteCfgName( char *args, int argNum ); int Cmd_Argc (void); char *Cmd_Argv (int arg); @@ -533,6 +539,8 @@ void Cvar_CheckRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeI void Cvar_Restart_f( void ); +void Cvar_CompleteCvarName( char *args, int argNum ); + extern int cvar_modifiedFlags; // whenever a cvar is modifed, its flags will be OR'd into this, so // a single check can determine if any CVAR_USERINFO, CVAR_SERVERINFO, @@ -712,6 +720,11 @@ typedef struct { void Field_Clear( field_t *edit ); void Field_AutoComplete( field_t *edit ); +void Field_CompleteKeyname( void ); +void Field_CompleteFilename( const char *dir, + const char *ext, qboolean stripExt ); +void Field_CompleteCommand( char *cmd, + qboolean doCommands, qboolean doCvars ); /* ============================================================== diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 07a3b44..01bc60d 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1053,6 +1053,17 @@ static void SV_KillServer_f( void ) { /* ================== +SV_CompleteMapName +================== +*/ +static void SV_CompleteMapName( char *args, int argNum ) { + if( argNum == 2 ) { + Field_CompleteFilename( "maps", "bsp", qtrue ); + } +} + +/* +================== SV_AddOperatorCommands ================== */ @@ -1081,10 +1092,14 @@ void SV_AddOperatorCommands( void ) { Cmd_AddCommand ("map_restart", SV_MapRestart_f); Cmd_AddCommand ("sectorlist", SV_SectorList_f); Cmd_AddCommand ("map", SV_Map_f); + Cmd_SetCommandCompletionFunc( "map", SV_CompleteMapName ); #ifndef PRE_RELEASE_DEMO Cmd_AddCommand ("devmap", SV_Map_f); + Cmd_SetCommandCompletionFunc( "devmap", SV_CompleteMapName ); Cmd_AddCommand ("spmap", SV_Map_f); + Cmd_SetCommandCompletionFunc( "spmap", SV_CompleteMapName ); Cmd_AddCommand ("spdevmap", SV_Map_f); + Cmd_SetCommandCompletionFunc( "spdevmap", SV_CompleteMapName ); #endif Cmd_AddCommand ("killserver", SV_KillServer_f); if( com_dedicated->integer ) { |