Skip to content

Commit

Permalink
IO: allow issuing multiple terminal queries in one call
Browse files Browse the repository at this point in the history
  • Loading branch information
CarterLi committed Sep 10, 2024
1 parent fed2c87 commit a052033
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 63 deletions.
4 changes: 2 additions & 2 deletions src/common/io/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ bool ffPathExpandEnv(const char* in, FFstrbuf* out);

#define FF_IO_TERM_RESP_WAIT_MS 100 // #554

FF_C_SCANF(2, 3)
const char* ffGetTerminalResponse(const char* request, const char* format, ...);
FF_C_SCANF(3, 4)
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...);

// Not thread safe!
bool ffSuppressIO(bool suppress);
Expand Down
30 changes: 21 additions & 9 deletions src/common/io/io_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ void restoreTerm(void)
tcsetattr(ftty, TCSAFLUSH, &oldTerm);
}

const char* ffGetTerminalResponse(const char* request, const char* format, ...)
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...)
{
if (ftty < 0)
{
Expand Down Expand Up @@ -180,17 +180,29 @@ const char* ffGetTerminalResponse(const char* request, const char* format, ...)
}
#endif

char buffer[512];
ssize_t bytesRead = read(ftty, buffer, sizeof(buffer) - 1);

if(bytesRead <= 0)
return "read(STDIN_FILENO, buffer, sizeof(buffer) - 1) failed";

buffer[bytesRead] = '\0';
char buffer[1024];
size_t bytesRead = 0;

va_list args;
va_start(args, format);
vsscanf(buffer, format, args);

while (true)
{
ssize_t nRead = read(ftty, buffer + bytesRead, sizeof(buffer) - bytesRead - 1);

if (nRead <= 0)
return "read(STDIN_FILENO, buffer, sizeof(buffer) - 1) failed";

bytesRead += (size_t) nRead;
buffer[bytesRead] = '\0';

int ret = vsscanf(buffer, format, args);
if (ret <= 0)
return "vsscanf(buffer, format, args) failed";
if (ret >= nParams)
break;
}

va_end(args);

return NULL;
Expand Down
32 changes: 21 additions & 11 deletions src/common/io/io_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ void ffListFilesRecursively(const char* path, bool pretty)
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
}

const char* ffGetTerminalResponse(const char* request, const char* format, ...)
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...)
{
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
FF_AUTO_CLOSE_FD HANDLE hConin = INVALID_HANDLE_VALUE;
Expand Down Expand Up @@ -256,20 +256,30 @@ const char* ffGetTerminalResponse(const char* request, const char* format, ...)
ReadConsoleInputW(hInput, &record, 1, &len);
}

char buffer[512];
DWORD bytes = 0;
ReadFile(hInput, buffer, sizeof(buffer) - 1, &bytes, NULL);
va_list args;
va_start(args, format);

SetConsoleMode(hInput, inputMode);
char buffer[1024];
uint32_t bytesRead = 0;

if(bytes <= 0)
return "ReadFile() failed";
while (true)
{
DWORD bytes = 0;
if (!ReadFile(hInput, buffer, sizeof(buffer) - 1, &bytes, NULL) || bytes == 0)
return "ReadFile() failed";

buffer[bytes] = '\0';
bytesRead += bytes;
buffer[bytesRead] = '\0';

int ret = vsscanf(buffer, format, args);
if (ret <= 0)
return "vsscanf(buffer, format, args) failed";
if (ret >= nParams)
break;
}

SetConsoleMode(hInput, inputMode);

va_list args;
va_start(args, format);
vsscanf(buffer, format, args);
va_end(args);

return NULL;
Expand Down
37 changes: 17 additions & 20 deletions src/detection/terminalfont/terminalfont.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,35 +72,32 @@ FF_MAYBE_UNUSED static void detectTTY(FFTerminalFontResult* terminalFont)
ffStrbufAppendS(&terminalFont->error, "Couldn't find Font in "FASTFETCH_TARGET_DIR_ETC"/vconsole.conf");
}

static bool queryKittyTerm(const char* query, FFstrbuf* res)
FF_MAYBE_UNUSED static bool detectKitty(const FFstrbuf* exe, FFTerminalFontResult* result)
{
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();

char fontHex[512] = "", sizeHex[512] = "";
// https://github.com/fastfetch-cli/fastfetch/discussions/1030#discussioncomment-9845233
char buffer[256] = "";
if (ffGetTerminalResponse(
query, // kitty-query-font_family;kitty-query-font_size
"\eP1+r%*[^=]=%255[^\e]\e\\", buffer) == NULL)
"\eP+q6b697474792d71756572792d666f6e745f66616d696c79;6b697474792d71756572792d666f6e745f73697a65\e\\", // kitty-query-font_family;kitty-query-font_size
2,
"\eP1+r%*[^=]=%64[^\e]\e\\\eP1+r%*[^=]=%64[^\e]\e\\", fontHex, sizeHex) == NULL && *fontHex && *sizeHex)
{
// decode hex string
for (const char* p = buffer; p[0] && p[1]; p += 2)
for (const char* p = fontHex; p[0] && p[1]; p += 2)
{
unsigned value;
if (sscanf(p, "%2x", &value))
ffStrbufAppendC(&fontName, (char) value);
}
for (const char* p = sizeHex; p[0] && p[1]; p += 2)
{
unsigned value;
if (sscanf(p, "%2x", &value) == 1)
ffStrbufAppendC(res, (char) value);
if (sscanf(p, "%2x", &value))
ffStrbufAppendC(&fontSize, (char) value);
}
return true;
}
return false;
}

FF_MAYBE_UNUSED static bool detectKitty(const FFstrbuf* exe, FFTerminalFontResult* result)
{
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();

// Kitty generates response independently even if we query font family and size in one query
// which may result in short read in `ffGetTerminalResponse`
if (queryKittyTerm("\eP+q6b697474792d71756572792d666f6e745f66616d696c79\e\\", &fontName)) // kitty-query-font_family
queryKittyTerm("\eP+q6b697474792d71756572792d666f6e745f73697a65\e\\", &fontSize); // kitty-query-font_size
else
{
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
Expand Down
1 change: 1 addition & 0 deletions src/detection/terminalshell/terminalshell.c
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ static bool getTerminalVersionKitty(FFstrbuf* exe, FFstrbuf* version)
// https://github.com/fastfetch-cli/fastfetch/discussions/1030#discussioncomment-9845233
if (ffGetTerminalResponse(
"\eP+q6b697474792d71756572792d76657273696f6e\e\\", // kitty-query-version
1,
"\eP1+r%*[^=]=%63[^\e]\e\\\\", versionHex) == NULL)
{
// decode hex string
Expand Down
4 changes: 2 additions & 2 deletions src/detection/terminalsize/terminalsize_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ bool ffDetectTerminalSize(FFTerminalSizeResult* result)
ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);

if (winsize.ws_row == 0 || winsize.ws_col == 0)
ffGetTerminalResponse("\e[18t", "\e[8;%hu;%hut", &winsize.ws_row, &winsize.ws_col);
ffGetTerminalResponse("\e[18t", 2, "\e[8;%hu;%hut", &winsize.ws_row, &winsize.ws_col);

if (winsize.ws_ypixel == 0 || winsize.ws_xpixel == 0)
ffGetTerminalResponse("\e[14t", "\e[4;%hu;%hut", &winsize.ws_ypixel, &winsize.ws_xpixel);
ffGetTerminalResponse("\e[14t", 2, "\e[4;%hu;%hut", &winsize.ws_ypixel, &winsize.ws_xpixel);

if (winsize.ws_row == 0 && winsize.ws_col == 0)
return false;
Expand Down
4 changes: 2 additions & 2 deletions src/detection/terminalsize/terminalsize_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ bool ffDetectTerminalSize(FFTerminalSizeResult* result)
else
{
// Windows Terminal doesn't report `\e` for some reason
ffGetTerminalResponse("\e[18t", "%*[^;];%hu;%hut", &result->rows, &result->columns);
ffGetTerminalResponse("\e[18t", 2, "%*[^;];%hu;%hut", &result->rows, &result->columns);
}
}

Expand All @@ -42,7 +42,7 @@ bool ffDetectTerminalSize(FFTerminalSizeResult* result)
if (result->width == 0 || result->height == 0)
{
// Windows Terminal doesn't report `\e` for some reason
ffGetTerminalResponse("\e[14t", "%*[^;];%hu;%hut", &result->height, &result->width);
ffGetTerminalResponse("\e[14t", 2, "%*[^;];%hu;%hut", &result->height, &result->width);
}
}

Expand Down
20 changes: 6 additions & 14 deletions src/detection/terminaltheme/terminaltheme.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,15 @@

static bool detectByEscapeCode(FFTerminalThemeResult* result)
{
int command = 0;

// Windows Terminal doesn't report `\e` for some reason
if (ffGetTerminalResponse("\e]10;?\e\\", "%*[^0-9]%d;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 "\e\\", &command, &result->fg.r, &result->fg.g, &result->fg.b) == NULL)
// Windows Terminal removes all `\e`s in its output
if (ffGetTerminalResponse("\e]10;?\e\\" /*fg*/ "\e]11;?\e\\" /*bg*/,
6,
"%*[^0-9]10;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 /*"\e\\"*/ "%*[^0-9]11;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 /*"\e\\"*/,
&result->fg.r, &result->fg.g, &result->fg.b,
&result->bg.r, &result->bg.g, &result->bg.b) == NULL)
{
if (command != 10)
return false;
if (result->fg.r > 0x0100 || result->fg.g > 0x0100 || result->fg.b > 0x0100)
result->fg.r /= 0x0100, result->fg.g /= 0x0100, result->fg.b /= 0x0100;
}
else
return false;

if (ffGetTerminalResponse("\e]11;?\e\\", "%*[^0-9]%d;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 "\e\\", &command, &result->bg.r, &result->bg.g, &result->bg.b) == NULL)
{
if (command != 11)
return false;
if (result->bg.r > 0x0100 || result->bg.g > 0x0100 || result->bg.b > 0x0100)
result->bg.r /= 0x0100, result->bg.g /= 0x0100, result->bg.b /= 0x0100;
}
Expand Down
4 changes: 2 additions & 2 deletions src/logo/image/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static bool printImageIterm(bool printError)
if (options->position == FF_LOGO_POSITION_LEFT || options->position == FF_LOGO_POSITION_RIGHT)
{
uint16_t X = 0, Y = 0;
const char* error = ffGetTerminalResponse("\e[6n", "\e[%hu;%huR", &Y, &X);
const char* error = ffGetTerminalResponse("\e[6n", 2, "%*[^0-9]%hu;%huR", &Y, &X);
if (error)
{
fprintf(stderr, "\nLogo (iterm): fail to query cursor position: %s\n", error);
Expand Down Expand Up @@ -203,7 +203,7 @@ static bool printImageKittyDirect(bool printError)
if (options->position == FF_LOGO_POSITION_LEFT || options->position == FF_LOGO_POSITION_RIGHT)
{
uint16_t X = 0, Y = 0;
const char* error = ffGetTerminalResponse("\e[6n", "\e[%hu;%huR", &Y, &X);
const char* error = ffGetTerminalResponse("\e[6n", 2, "%*[^0-9]%hu;%huR", &Y, &X);
if (error)
{
if (printError)
Expand Down
2 changes: 1 addition & 1 deletion src/logo/logo.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static bool ffLogoPrintCharsRaw(const char* data, size_t length, bool printError
{
uint16_t X = 0, Y = 0;
// Windows Terminal doesn't report `\e` for some reason
const char* error = ffGetTerminalResponse("\e[6n", "%*[^0-9]%hu;%huR", &Y, &X); // %*[^0-9]: ignore optional \e[
const char* error = ffGetTerminalResponse("\e[6n", 2, "%*[^0-9]%hu;%huR", &Y, &X); // %*[^0-9]: ignore optional \e[
if (error)
{
if (printError)
Expand Down

0 comments on commit a052033

Please sign in to comment.