diff options
author | Andrey Nazarov <skuller@skuller.net> | 2007-08-14 20:18:08 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2007-08-14 20:18:08 +0000 |
commit | f294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch) | |
tree | e8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/prompt.c |
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/prompt.c')
-rw-r--r-- | source/prompt.c | 464 |
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 ); +} + |