diff --git a/changelog.txt b/changelog.txt index 91cbe47..1c26dd6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ See the end of this file for known issues. DD Mmm 20 - 1.53 +add: /searchconsole begins a new console search + press ctrl-F when the console is down to bring up the command + press (shift-)F3 to find the next match going up or down + just like in cmdlist/cvarlist/etc, * will match any amount of characters + add: r_ignoreShaderSortKey <0|1> (default: 0) ignores the shader sort key of transparent surfaces instead, it sorts by depth and original registration order only this is a work-around for broken maps like bones_fkd_b4 (grates drawn in front of simple items) diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index bb1cea8..42fc2b4 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -42,6 +42,7 @@ static cvar_t* con_drawHelp; X(Cmd, "4FA7BD", qfalse, "RGB color of command names") \ X(Value, "E5BC39", qfalse, "RGB color of variable values") \ X(Help, "ABC1C6", qfalse, "RGB color of help text") \ + X(Search, "FFFF00", qfalse, "RGB color of search result marker") \ X(HL, "303033FF", qtrue, help_con_colHL) #define COLOR_LIST_ITEM( Name, Default, HasAlpha, Help ) \ @@ -93,6 +94,10 @@ struct console_t { int helpLines; // line count qbool helpDraw; float helpXAdjust; + + char searchPattern[256]; + qbool searchLineIndex; + qbool searchStarted; }; static console_t con; @@ -104,6 +109,8 @@ static console_t con; int g_console_field_width = CONSOLE_WIDTH; +static void Con_BeginSearch_f(); + static qbool IsValidHexChar( char c ) { return @@ -411,7 +418,8 @@ static const cmdTableItem_t con_cmds[] = { "messagemode3", Con_MessageMode3_f, NULL, "chat with the player being aimed at" }, { "messagemode4", Con_MessageMode4_f, NULL, "chat with the last attacker" }, { "clear", Con_Clear_f, NULL, "clears the console" }, - { "condump", Con_Dump_f, NULL, "dumps console history to a text file" } + { "condump", Con_Dump_f, NULL, "dumps console history to a text file" }, + { "searchconsole", Con_BeginSearch_f, NULL, help_searchconsole } }; @@ -805,6 +813,11 @@ static void Con_DrawSolidConsole( float frac ) SCR_DrawChar( 1 + con.xadjust + j * con.cw, 1 + y, con.cw, con.ch, (text[j] & 0xFF) ); } + if ((row % con.totallines) == con.searchLineIndex) { + re.SetColor( colSearch ); + SCR_DrawChar( con.xadjust - con.cw, y, con.cw, con.ch, 141 ); + } + re.SetColor( colText ); for (int j = 0; j < con.linewidth; ++j) { if ((text[j] >> 8) != color) { @@ -940,3 +953,72 @@ void Con_Close() con.finalFrac = 0; // none visible con.displayFrac = 0; } + + +static void Con_BeginSearch_f() +{ + if ( Cmd_Argc() != 2 ) { + Com_Printf( "usage: %s search_pattern\n", Cmd_Argv(0) ); + return; + } + + Q_strncpyz( con.searchPattern, Cmd_Argv(1), sizeof(con.searchPattern) ); + con.searchLineIndex = con.current; + con.searchStarted = qtrue; + Con_ContinueSearch( qtrue ); +} + + +void Con_ContinueSearch( qbool forward ) +{ + if ( !con.searchStarted ) + return; + + // end is 1 past the end + int incr, start, end; + if ( forward ) { + // bottom-up + incr = -1; + start = con.searchLineIndex + con.totallines - 1; + end = start - con.totallines; + } else { + // top-down + incr = 1; + start = con.searchLineIndex + 1; + end = start + con.totallines; + } + + char rawText[256]; + assert( sizeof(rawText) > con.linewidth ); + rawText[con.linewidth] = '\0'; + for ( int l = start; l != end; l += incr ) { + const int line = l % con.totallines; + const short* const coloredText = &con.text[line * con.linewidth]; + + for ( int i = 0; i < con.linewidth; i++ ) { + rawText[i] = coloredText[i] & 0xFF; + } + for ( int x = con.linewidth - 1; x >= 0; x-- ) { + if ( rawText[x] == ' ' ) { + rawText[x] = '\0'; + } else { + break; + } + } + + // ignore all "searchconsole" calls + if ( rawText[0] == ']' && + (rawText[1] == '/' || rawText[1] == '\\') && + Q_strncmp(rawText + 2, "searchconsole ", 14) == 0) { + continue; + } + + if ( Com_Filter( con.searchPattern, rawText ) ) { + con.searchLineIndex = line; + const int display = con.searchLineIndex + con.totallines + 1; + if ( display > con.display || display <= con.display - con.rowsVisible ) + con.display = display; + return; + } + } +} diff --git a/code/client/cl_keys.cpp b/code/client/cl_keys.cpp index 4c2c223..fe8b6c6 100644 --- a/code/client/cl_keys.cpp +++ b/code/client/cl_keys.cpp @@ -595,6 +595,19 @@ static void Console_Key( int key ) return; } + // ctrl-f begins a new search + if ( keys[K_CTRL].down && tolower(key) == 'f' ) { + Q_strncpyz( g_consoleField.buffer, "\\searchconsole ", sizeof( g_consoleField.buffer ) ); + g_consoleField.cursor = strlen( g_consoleField.buffer ); + return; + } + + // (shift-)f3 finds the next (or previous) match + if ( key == K_F3 ) { + Con_ContinueSearch( !keys[K_SHIFT].down ); + return; + } + // pass to the normal editline routine Field_KeyDownEvent( &g_consoleField, key ); } diff --git a/code/client/client.h b/code/client/client.h index 610fee3..fb0f38a 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -444,6 +444,7 @@ void Con_ScrollPages( int pages ); // positive means down void Con_Top(); void Con_Bottom(); void Con_Close(); +void Con_ContinueSearch( qbool forward ); const float* ConsoleColorFromChar( char ccode ); diff --git a/code/client/client_help.h b/code/client/client_help.h index ce7eeef..474f9be 100644 --- a/code/client/client_help.h +++ b/code/client/client_help.h @@ -135,3 +135,14 @@ S_COLOR_VAL " 2 " S_COLOR_HELP "= On in debug builds only" "Set this CVar before connecting to a server to join through a proxy.\n" \ "It works with /" S_COLOR_CMD "connect" S_COLOR_HELP ", /" S_COLOR_CMD "reconnect" S_COLOR_HELP " and the server browser UI.\n" \ "Set it to an empty string to not use a proxy server." + +#define help_searchconsole \ +"begins a new console search\n" \ +"Press ctrl-F when the console is down to bring up the command.\n" \ +"Press (shift-)F3 to find the next match going up or down.\n" \ +"The star character (*) will match 0, 1 or more characters.\n" \ +"\n" \ +" Argument Matches\n" \ +"Example: init lines starting with 'init'\n" \ +"Example: *init lines containing 'init'\n" \ +"Example: >*net lines starting with '>' AND containing 'net'"