summaryrefslogtreecommitdiff
path: root/source/prompt.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
committerAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
commitf294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch)
treee8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/prompt.c
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/prompt.c')
-rw-r--r--source/prompt.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/source/prompt.c b/source/prompt.c
new file mode 100644
index 0000000..a75ca29
--- /dev/null
+++ b/source/prompt.c
@@ -0,0 +1,464 @@
+/*
+Copyright (C) 2003-2006 Andrey Nazarov
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+//
+// prompt.c
+//
+
+#include "com_local.h"
+#include "q_field.h"
+#include "prompt.h"
+
+static char *matches[MAX_MATCHES];
+static char *sortedMatches[MAX_MATCHES];
+static int numMatches;
+static int numCommands;
+static int numCvars;
+static int numAliases;
+
+static cvar_t *com_completion_mode;
+static cvar_t *com_completion_treshold;
+
+/*
+====================
+Prompt_FreeMatches
+====================
+*/
+static void Prompt_FreeMatches( void ) {
+ int i;
+
+ // free them
+ for( i = 0; i < numMatches; i++ ) {
+ Z_Free( matches[i] );
+ }
+
+ numMatches = 0;
+ numCommands = 0;
+ numCvars = 0;
+ numAliases = 0;
+
+}
+
+static void Prompt_FooGenerator( xgenerator_t generator, const char *partial ) {
+ const char *match;
+
+ match = (*generator)( partial, 0 );
+ while( match ) {
+ matches[numMatches++] = Z_CopyString( match );
+ if( numMatches == MAX_MATCHES ) {
+ (*generator)( partial, 2 );
+ return;
+ }
+ match = (*generator)( partial, 1 );
+ }
+}
+
+static void Prompt_GenerateMatches( const char *partial ) {
+ Prompt_FooGenerator( Cmd_Command_g, partial );
+ numCommands = numMatches;
+
+ if( numMatches != MAX_MATCHES ) {
+ Prompt_FooGenerator( Cvar_Generator, partial );
+ numCvars = numMatches - numCommands;
+
+ if( numMatches != MAX_MATCHES ) {
+ Prompt_FooGenerator( Cmd_Alias_g, partial );
+ numAliases = numMatches - numCvars - numCommands;
+ }
+ }
+}
+
+static void Prompt_ShowMatches( commandPrompt_t *prompt, char **matches,
+ int start, int end )
+{
+ int count = end - start;
+ int numCols, numLines;
+ int i, j, k, max, len, total;
+ int colwidths[6];
+ char *match;
+
+ for( numCols = 6; numCols > 0; numCols-- ) {
+ numLines = ( count + numCols - 1 ) / numCols;
+ total = 0;
+ for( i = 0; i < numCols; i++ ) {
+ k = start + numLines * i;
+ if( k >= end ) {
+ break;
+ }
+ max = -9999;
+ j = k;
+ while( j - k < numLines && j < end ) {
+ len = strlen( matches[j++] );
+ if( max < len ) {
+ max = len;
+ }
+ }
+ colwidths[i] = max;
+ total += max + 2;
+ }
+ if( total < prompt->widthInChars ) {
+ break;
+ }
+ }
+
+ for( i = 0; i < numLines; i++ ) {
+ for( j = 0; j < numCols; j++ ) {
+ k = start + j * numLines + i;
+ if( k >= end ) {
+ break;
+ }
+ match = matches[k];
+ prompt->Printf( "%s", match );
+ len = colwidths[j] - strlen( match );
+ for( k = 0; k < len + 2; k++ ) {
+ prompt->Printf( " " );
+ }
+ }
+ prompt->Printf( "\n" );
+ }
+
+}
+
+static void Prompt_ShowIndividualMatches( commandPrompt_t *prompt ) {
+ int offset = 0;
+
+ if( numCommands ) {
+ qsort( matches + offset, numCommands,
+ sizeof( matches[0] ), SortStrcmp );
+
+ prompt->Printf( "\n" S_COLOR_YELLOW "%i possible command%s:\n",
+ numCommands, ( numCommands % 10 ) != 1 ? "s" : "" );
+
+ Prompt_ShowMatches( prompt, matches, offset, offset + numCommands );
+ offset += numCommands;
+ }
+
+ if( numCvars ) {
+ qsort( matches + offset, numCvars,
+ sizeof( matches[0] ), SortStrcmp );
+
+ prompt->Printf( "\n" S_COLOR_YELLOW "%i possible variable%s:\n",
+ numCvars, ( numCvars % 10 ) != 1 ? "s" : "" );
+
+ Prompt_ShowMatches( prompt, matches, offset, offset + numCvars );
+ offset += numCvars;
+ }
+
+ if( numAliases ) {
+ qsort( matches + offset, numAliases,
+ sizeof( matches[0] ), SortStrcmp );
+
+ prompt->Printf( "\n" S_COLOR_YELLOW "%i possible alias%s:\n",
+ numAliases, ( numAliases % 10 ) != 1 ? "es" : "" );
+
+ Prompt_ShowMatches( prompt, matches, offset, offset + numAliases );
+ offset += numAliases;
+ }
+}
+
+/*
+====================
+Prompt_CompleteCommand
+====================
+*/
+void Prompt_CompleteCommand( commandPrompt_t *prompt, qboolean backslash ) {
+ inputField_t *inputLine = &prompt->inputLine;
+ char *text, *partial, *s;
+ int i, argc, pos, currentArg, size, length, relative;
+ char *first, *last;
+ xgenerator_t generator;
+
+ text = inputLine->text;
+ size = sizeof( inputLine->text );
+ pos = inputLine->cursorPos;
+ if( backslash ) {
+ if( inputLine->text[0] != '\\' && inputLine->text[0] != '/' ) {
+ memmove( inputLine->text + 1, inputLine->text,
+ sizeof( inputLine->text ) - 1 );
+ inputLine->text[0] = '\\';
+ }
+ text++; size--; pos--;
+ }
+
+ Cmd_TokenizeString( text, qfalse );
+
+ argc = Cmd_Argc();
+
+ currentArg = Cmd_FindArgForOffset( pos );
+ i = strlen( text );
+ if( i != 0 && text[ i - 1 ] == ' ' ) {
+ if( currentArg == argc - 1 ) {
+ currentArg++;
+ }
+ }
+ relative = 0;
+ s = Cmd_Argv( 0 );
+ for( i = 0; i < currentArg; i++ ) {
+ partial = Cmd_Argv( i );
+ relative++;
+ if( *partial == ';' ) {
+ s = Cmd_Argv( i + 1 );
+ relative = 0;
+ }
+ }
+
+ partial = Cmd_Argv( currentArg );
+ if( *partial == ';' ) {
+ currentArg++;
+ partial = Cmd_Argv( currentArg );
+ relative = 0;
+ }
+
+ if( relative ) {
+ generator = Cmd_FindGenerator( s, relative );
+ if( generator ) {
+ Prompt_FooGenerator( generator, partial );
+ }
+ } else {
+ generator = NULL;
+ Prompt_GenerateMatches( partial );
+ }
+
+ if( !numMatches ) {
+ inputLine->cursorPos = strlen( inputLine->text );
+ prompt->tooMany = qfalse;
+ return; /* nothing found */
+ }
+
+ pos = Cmd_ArgOffset( currentArg );
+ text += pos;
+ size -= pos;
+
+ if( numMatches == 1 ) {
+ /* we have finished completion! */
+ s = matches[0];
+ while( *s ) {
+ if( *s <= 32 ) {
+ break;
+ }
+ s++;
+ }
+ *text = 0;
+ if( *s ) {
+ Q_strcat( inputLine->text, sizeof( inputLine->text ), "\"" );
+ }
+ Q_strcat( inputLine->text, sizeof( inputLine->text ), matches[0] );
+ if( *s ) {
+ Q_strcat( inputLine->text, sizeof( inputLine->text ), "\"" );
+ }
+ Q_strcat( inputLine->text, sizeof( inputLine->text ), " " );
+ Q_strcat( inputLine->text, sizeof( inputLine->text ),
+ Cmd_RawArgsFrom( currentArg + 1 ) );
+ inputLine->cursorPos = strlen( inputLine->text );
+ inputLine->selectStart = inputLine->cursorPos;
+ inputLine->selectEnd = inputLine->cursorPos;
+ prompt->tooMany = qfalse;
+ Prompt_FreeMatches();
+ return;
+ }
+
+ if( numMatches > com_completion_treshold->integer && !prompt->tooMany ) {
+ prompt->Printf( "Press TAB again to display all %d possibilities.\n",
+ numMatches );
+ inputLine->cursorPos = strlen( inputLine->text );
+ prompt->tooMany = qtrue;
+ Prompt_FreeMatches();
+ return;
+ }
+
+ prompt->tooMany = qfalse;
+
+ /* sort matches alphabethically */
+ for( i = 0; i < numMatches; i++ ) {
+ sortedMatches[i] = matches[i];
+ }
+ qsort( sortedMatches, numMatches, sizeof( sortedMatches[0] ), SortStrcmp );
+
+ /* copy matching part */
+ first = sortedMatches[0];
+ last = sortedMatches[ numMatches - 1 ];
+ length = 0;
+ do {
+ if( *first != *last ) {
+ break;
+ }
+ text[length++] = *first;
+ if( length == size - 1 ) {
+ break;
+ }
+
+ first++;
+ last++;
+ } while( *first );
+
+ text[length] = 0;
+
+ inputLine->cursorPos = strlen( inputLine->text );
+ inputLine->selectStart = inputLine->cursorPos;
+ inputLine->selectEnd = inputLine->cursorPos;
+
+ if( currentArg + 1 < argc ) {
+ Q_strcat( inputLine->text, sizeof( inputLine->text ), " " );
+ Q_strcat( inputLine->text, sizeof( inputLine->text ),
+ Cmd_RawArgsFrom( currentArg + 1 ) );
+ }
+
+ prompt->Printf( "]\\%s\n", Cmd_ArgsFrom( 0 ) );
+ if( generator ) {
+ goto multicolumn;
+ }
+
+ switch( com_completion_mode->integer ) {
+ case 0:
+ /* print in solid list */
+ for( i = 0 ; i < numMatches; i++ ) {
+ prompt->Printf( "%s\n", sortedMatches[i] );
+ }
+ break;
+ case 1:
+ multicolumn:
+ /* print in multiple columns */
+ Prompt_ShowMatches( prompt, sortedMatches, 0, numMatches );
+ break;
+ case 2:
+ default:
+ /* resort matches by type and print in multiple columns */
+ Prompt_ShowIndividualMatches( prompt );
+ break;
+ }
+
+ Prompt_FreeMatches();
+}
+
+/*
+====================
+Prompt_Action
+
+User just pressed enter
+====================
+*/
+char *Prompt_Action( commandPrompt_t *prompt ) {
+ char *s = prompt->inputLine.text;
+ int i, j;
+
+ prompt->tooMany = qfalse;
+ if( s[0] == 0 || ( ( s[0] == '/' || s[0] == '\\' ) && s[1] == 0 ) ) {
+ IF_Clear( &prompt->inputLine );
+ return NULL; /* empty line */
+ }
+
+ /* save current line in history */
+ i = prompt->inputLineNum & HISTORY_MASK;
+ j = ( prompt->inputLineNum - 1 ) & HISTORY_MASK;
+ if( !prompt->history[j] || strcmp( prompt->history[j], s ) ) {
+ if( prompt->history[i] ) {
+ Z_Free( prompt->history[i] );
+ }
+ prompt->history[i] = Z_CopyString( s );
+ prompt->inputLineNum++;
+ } else {
+ i = j;
+ }
+
+ /* stop history search */
+ prompt->historyLineNum = prompt->inputLineNum;
+
+ IF_Clear( &prompt->inputLine );
+
+ return prompt->history[i];
+}
+
+/*
+====================
+Prompt_HistoryUp
+====================
+*/
+void Prompt_HistoryUp( commandPrompt_t *prompt ) {
+ int i;
+
+ if( prompt->historyLineNum == prompt->inputLineNum ) {
+ /* save current line in history */
+ i = prompt->inputLineNum & HISTORY_MASK;
+ if( prompt->history[i] ) {
+ Z_Free( prompt->history[i] );
+ }
+ prompt->history[i] = Z_CopyString( prompt->inputLine.text );
+ }
+
+ if( prompt->inputLineNum - prompt->historyLineNum < HISTORY_SIZE &&
+ prompt->historyLineNum > 0 )
+ {
+ prompt->historyLineNum--;
+ }
+
+ i = prompt->historyLineNum & HISTORY_MASK;
+ IF_Replace( &prompt->inputLine, prompt->history[i] );
+}
+
+/*
+====================
+Prompt_HistoryDown
+====================
+*/
+void Prompt_HistoryDown( commandPrompt_t *prompt ) {
+ int i;
+
+ if( prompt->historyLineNum == prompt->inputLineNum ) {
+ return;
+ }
+
+ prompt->historyLineNum++;
+
+ i = prompt->historyLineNum & HISTORY_MASK;
+ IF_Replace( &prompt->inputLine, prompt->history[i] );
+}
+
+/*
+====================
+Prompt_Clear
+====================
+*/
+void Prompt_Clear( commandPrompt_t *prompt ) {
+ int i;
+
+ for( i = 0; i < HISTORY_SIZE; i++ ) {
+ if( prompt->history[i] ) {
+ Z_Free( prompt->history[i] );
+ prompt->history[i] = NULL;
+ }
+ }
+
+ prompt->historyLineNum = 0;
+ prompt->inputLineNum = 0;
+
+ IF_Clear( &prompt->inputLine );
+}
+
+/*
+====================
+Prompt_Init
+====================
+*/
+void Prompt_Init( void ) {
+ com_completion_mode = Cvar_Get( "com_completion_mode", "1", CVAR_ARCHIVE );
+ com_completion_treshold = Cvar_Get( "com_completion_treshold", "50",
+ CVAR_ARCHIVE );
+}
+