TerminalSize: add new module

This commit is contained in:
李通洲
2023-07-26 10:27:40 +08:00
committed by 李通洲
parent 2f0d0a5a02
commit 8cbeb709f9
20 changed files with 279 additions and 17 deletions
+1
View File
@@ -29,6 +29,7 @@ Features:
* Support iTerm non-ascii font detection (Terminal, macOS)
* Add option `--title-color-user`, `--title-color-at` and `--title-color-host` (Title)
* Add Exherbo logo and package manager count (Packages, Linux, #503)
* Add module `Terminal Size` which prints the number of terminal width and height in charactors and pixels
Bugfixes:
* Fix possible hanging (TerminalFont, #493)
+6
View File
@@ -319,6 +319,7 @@ set(LIBFASTFETCH_SRC
src/modules/media/media.c
src/modules/terminal/terminal.c
src/modules/terminalfont/terminalfont.c
src/modules/terminalsize/terminalsize.c
src/modules/theme/theme.c
src/modules/title/title.c
src/modules/uptime/uptime.c
@@ -378,6 +379,7 @@ if(LINUX)
src/detection/temps/temps_linux.c
src/detection/terminalfont/terminalfont_linux.c
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_linux.c
src/detection/uptime/uptime_linux.c
src/detection/users/users_linux.c
@@ -421,6 +423,7 @@ elseif(ANDROID)
src/detection/temps/temps_linux.c
src/detection/terminalfont/terminalfont_android.c
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_nosupport.c
src/detection/uptime/uptime_linux.c
src/detection/users/users_linux.c
@@ -472,6 +475,7 @@ elseif(BSD)
src/detection/temps/temps_bsd.c
src/detection/terminalfont/terminalfont_linux.c
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_linux.c
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
@@ -517,6 +521,7 @@ elseif(APPLE)
src/detection/temps/temps_apple.c
src/detection/terminalfont/terminalfont_apple.m
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_nosupport.c
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
@@ -561,6 +566,7 @@ elseif(WIN32)
src/detection/swap/swap_windows.c
src/detection/terminalfont/terminalfont_windows.c
src/detection/terminalshell/terminalshell_windows.c
src/detection/terminalsize/terminalsize_windows.c
src/detection/temps/temps_windows.cpp
src/detection/theme/theme_nosupport.c
src/detection/uptime/uptime_windows.c
+1 -1
View File
@@ -91,7 +91,7 @@ All categories not listed here should work without needing a specific implementa
##### Available Modules
```
Battery, Bios, Bluetooth, Board, Break, Brightness, Colors, Command, CPU, CPUUsage, Cursor, Custom, Date, DateTime, DE, Disk, Display, Font, Gamepad, GPU, Host, Icons, Kernel, LM, Locale, LocalIP, Media, Memory, OpenCL, OpenGL, Packages, Player, Power Adapter, Processes, PublicIP, Separator, OS, Shell, Sound, Swap, Terminal, Terminal Font, Theme, Time, Title, Uptime, Vulkan, Wallpaper, Wifi, WM, WMTheme
Battery, Bios, Bluetooth, Board, Break, Brightness, Colors, Command, CPU, CPUUsage, Cursor, Custom, Date, DateTime, DE, Disk, Display, Font, Gamepad, GPU, Host, Icons, Kernel, LM, Locale, LocalIP, Media, Memory, OpenCL, OpenGL, Packages, Player, Power Adapter, Processes, PublicIP, Separator, OS, Shell, Sound, Swap, Terminal, Terminal Font, Terminal Size, Theme, Time, Title, Uptime, Vulkan, Wallpaper, Wifi, WM, WMTheme
```
##### Builtin logos
+2
View File
@@ -482,6 +482,7 @@
"swap",
"terminal",
"terminalfont",
"terminalsize",
"title",
"theme",
"uptime",
@@ -549,6 +550,7 @@
"swap",
"terminal",
"terminalfont",
"terminalsize",
"theme",
"uptime",
"users",
+1 -1
View File
@@ -1 +1 @@
--structure Title:Separator:OS:Host:Bios:Board:Chassis:Kernel:Uptime:Processes:Packages:Shell:Display:Brightness:LM:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Wallpaper:Terminal:TerminalFont:CPU:CPUUsage:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Media:PublicIP:LocalIP:Wifi:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Bluetooth:Sound:Gamepad:Weather:Break:Colors
--structure Title:Separator:OS:Host:Bios:Board:Chassis:Kernel:Uptime:Processes:Packages:Shell:Display:Brightness:LM:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Wallpaper:Terminal:TerminalFont:TerminalSize:CPU:CPUUsage:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Media:PublicIP:LocalIP:Wifi:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Bluetooth:Sound:Gamepad:Weather:Break:Colors
+1
View File
@@ -26,6 +26,7 @@
"wallpaper",
"terminal",
"terminalfont",
"terminalsize",
"cpu",
"cpuusage",
"gpu",
+2 -4
View File
@@ -83,10 +83,8 @@ typedef enum FFPathType
bool ffPathExists(const char* path, FFPathType pathType);
#ifndef _WIN32
FF_C_SCANF(2, 3)
void ffGetTerminalResponse(const char* request, const char* format, ...);
#endif
FF_C_SCANF(2, 3)
const char* ffGetTerminalResponse(const char* request, const char* format, ...);
// Not thread safe!
bool ffSuppressIO(bool suppress);
+8 -11
View File
@@ -107,30 +107,25 @@ bool ffPathExists(const char* path, FFPathType type)
return false;
}
void ffGetTerminalResponse(const char* request, const char* format, ...)
const char* ffGetTerminalResponse(const char* request, const char* format, ...)
{
struct termios oldTerm, newTerm;
if(tcgetattr(STDIN_FILENO, &oldTerm) == -1)
return;
return "tcgetattr(STDIN_FILENO, &oldTerm) failed";
newTerm = oldTerm;
newTerm.c_lflag &= (tcflag_t) ~(ICANON | ECHO);
if(tcsetattr(STDIN_FILENO, TCSANOW, &newTerm) == -1)
return;
return "tcsetattr(STDIN_FILENO, TCSANOW, &newTerm)";
fputs(request, stdout);
fflush(stdout);
struct pollfd pfd;
pfd.fd = STDIN_FILENO;
pfd.events = POLLIN;
pfd.revents = 0;
//Give the terminal 35ms to respond
if(poll(&pfd, 1, 35) <= 0)
if(poll(&(struct pollfd) { .fd = STDIN_FILENO, .events = POLLIN }, 1, 35) <= 0)
{
tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm);
return;
return "poll() timeout or failed";
}
char buffer[512];
@@ -139,7 +134,7 @@ void ffGetTerminalResponse(const char* request, const char* format, ...)
tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm);
if(readed <= 0)
return;
return "read(STDIN_FILENO, buffer, sizeof(buffer) - 1) failed";
buffer[readed] = '\0';
@@ -147,6 +142,8 @@ void ffGetTerminalResponse(const char* request, const char* format, ...)
va_start(args, format);
vsscanf(buffer, format, args);
va_end(args);
return NULL;
}
bool ffSuppressIO(bool suppress)
+57
View File
@@ -1,6 +1,8 @@
#include "io.h"
#include "util/stringUtils.h"
#include <windows.h>
static void createSubfolders(const char* fileName)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
@@ -144,3 +146,58 @@ void ffListFilesRecursively(const char* path)
ffStrbufEnsureEndsWithC(&folder, '/');
listFilesRecursively(&folder, 0, NULL);
}
const char* ffGetTerminalResponse(const char* request, const char* format, ...)
{
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
DWORD prev_mode;
GetConsoleMode(hInput, &prev_mode);
SetConsoleMode(hInput, 0);
FlushConsoleInputBuffer(hInput);
DWORD bytes = 0;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), request, (DWORD) strlen(request), &bytes, NULL);
while (true)
{
if (WaitForSingleObjectEx(hInput, 35, TRUE) != WAIT_OBJECT_0)
{
SetConsoleMode(hInput, prev_mode);
return "WaitForSingleObject() failed or timeout";
}
// Ignore all unexpected input events
INPUT_RECORD record;
DWORD len = 0;
if (!PeekConsoleInputW(hInput, &record, 1, &len))
break;
if (
record.EventType == KEY_EVENT &&
record.Event.KeyEvent.uChar.UnicodeChar != L'\r' &&
record.Event.KeyEvent.uChar.UnicodeChar != L'\n'
)
break;
else
ReadConsoleInputW(hInput, &record, 1, &len);
}
char buffer[512];
bytes = 0;
ReadFile(hInput, buffer, sizeof(buffer) - 1, &bytes, NULL);
SetConsoleMode(hInput, prev_mode);
if(bytes <= 0)
return "ReadFile() failed";
buffer[bytes] = '\0';
va_list args;
va_start(args, format);
vsscanf(buffer, format, args);
va_end(args);
return NULL;
}
+1
View File
@@ -188,6 +188,7 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* module)
return
tryModule(type, module, FF_TERMINAL_MODULE_NAME, ffParseTerminalJsonObject) ||
tryModule(type, module, FF_TERMINALFONT_MODULE_NAME, ffParseTerminalFontJsonObject) ||
tryModule(type, module, FF_TERMINALSIZE_MODULE_NAME, ffParseTerminalSizeJsonObject) ||
tryModule(type, module, FF_TITLE_MODULE_NAME, ffParseTitleJsonObject) ||
tryModule(type, module, FF_THEME_MODULE_NAME, ffParseThemeJsonObject) ||
false;
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#ifndef FF_INCLUDED_detection_terminalsize_terminalsize
#define FF_INCLUDED_detection_terminalsize_terminalsize
#include "fastfetch.h"
typedef struct FFTerminalSizeResult
{
uint16_t rows;
uint16_t columns;
uint16_t width;
uint16_t height;
} FFTerminalSizeResult;
bool ffDetectTerminalSize(FFTerminalSizeResult* result);
#endif
@@ -0,0 +1,26 @@
#include "terminalsize.h"
#include "common/io/io.h"
#include <sys/ioctl.h>
#include <unistd.h>
bool ffDetectTerminalSize(FFTerminalSizeResult* result)
{
struct winsize winsize = {};
ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
if (winsize.ws_row == 0 || winsize.ws_col == 0)
ffGetTerminalResponse("\033[18t", "\033[8;%hu;%hut", &winsize.ws_row, &winsize.ws_col);
if (winsize.ws_ypixel == 0 || winsize.ws_xpixel == 0)
ffGetTerminalResponse("\033[14t", "\033[4;%hu;%hut", &winsize.ws_ypixel, &winsize.ws_xpixel);
if (winsize.ws_row == 0 && winsize.ws_col == 0)
return false;
result->rows = winsize.ws_row;
result->columns = winsize.ws_col;
result->width = winsize.ws_xpixel;
result->height = winsize.ws_ypixel;
return true;
}
@@ -0,0 +1,41 @@
#include "terminalsize.h"
#include "common/io/io.h"
#include <windows.h>
bool ffDetectTerminalSize(FFTerminalSizeResult* result)
{
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
{
result->columns = (uint16_t) (csbi.srWindow.Right - csbi.srWindow.Left + 1);
result->rows = (uint16_t) (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
}
else
{
ffGetTerminalResponse("\033[18t", "\033[8;%hu;%hut", &result->rows, &result->columns);
}
}
if (result->columns == 0 && result->rows == 0)
return false;
{
CONSOLE_FONT_INFO cfi;
if(GetCurrentConsoleFont(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi)) // Only works for ConHost
{
result->width = result->columns * (uint16_t) cfi.dwFontSize.X;
result->height = result->rows * (uint16_t) cfi.dwFontSize.Y;
}
else
{
// Pending https://github.com/microsoft/terminal/issues/8581
// if (result->width == 0 && result->height == 0)
// ffGetTerminalResponse("\033[14t", "\033[4;%hu;%hut", &result->height, &result->width);
return false;
}
}
return result->columns > 0 && result->rows > 0;
}
+3
View File
@@ -971,6 +971,7 @@ static void parseOption(FFdata* data, const char* key, const char* value)
else if(ffParseCursorCommandOptions(&instance.config.cursor, key, value)) {}
else if(ffParseTerminalCommandOptions(&instance.config.terminal, key, value)) {}
else if(ffParseTerminalFontCommandOptions(&instance.config.terminalFont, key, value)) {}
else if(ffParseTerminalSizeCommandOptions(&instance.config.terminalSize, key, value)) {}
else if(ffParseCPUCommandOptions(&instance.config.cpu, key, value)) {}
else if(ffParseCPUUsageCommandOptions(&instance.config.cpuUsage, key, value)) {}
else if(ffParseGPUCommandOptions(&instance.config.gpu, key, value)) {}
@@ -1182,6 +1183,8 @@ static void parseStructureCommand(const char* line, FFlist* customValues)
ffPrintTerminal(&instance.config.terminal);
else if(ffStrEqualsIgnCase(line, FF_TERMINALFONT_MODULE_NAME))
ffPrintTerminalFont(&instance.config.terminalFont);
else if(ffStrEqualsIgnCase(line, FF_TERMINALSIZE_MODULE_NAME))
ffPrintTerminalSize(&instance.config.terminalSize);
else if(ffStrEqualsIgnCase(line, FF_CPU_MODULE_NAME))
ffPrintCPU(&instance.config.cpu);
else if(ffStrEqualsIgnCase(line, FF_CPUUSAGE_MODULE_NAME))
+1
View File
@@ -82,6 +82,7 @@ typedef struct FFconfig
FFCursorOptions cursor;
FFTerminalOptions terminal;
FFTerminalFontOptions terminalFont;
FFTerminalSizeOptions terminalSize;
FFCPUOptions cpu;
FFCPUUsageOptions cpuUsage;
FFCustomOptions custom;
+1
View File
@@ -44,6 +44,7 @@
#include "modules/swap/swap.h"
#include "modules/terminal/terminal.h"
#include "modules/terminalfont/terminalfont.h"
#include "modules/terminalsize/terminalsize.h"
#include "modules/theme/theme.h"
#include "modules/title/title.h"
#include "modules/uptime/uptime.h"
+1
View File
@@ -43,6 +43,7 @@
#include "modules/swap/option.h"
#include "modules/terminal/option.h"
#include "modules/terminalfont/option.h"
#include "modules/terminalsize/option.h"
#include "modules/theme/option.h"
#include "modules/title/option.h"
#include "modules/uptime/option.h"
+11
View File
@@ -0,0 +1,11 @@
#pragma once
// This file will be included in "fastfetch.h", do NOT put unnecessary things here
#include "common/option.h"
typedef struct FFTerminalSizeOptions
{
const char* moduleName;
FFModuleArgs moduleArgs;
} FFTerminalSizeOptions;
+86
View File
@@ -0,0 +1,86 @@
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "detection/terminalsize/terminalsize.h"
#include "modules/terminalsize/terminalsize.h"
#include "util/stringUtils.h"
#define FF_TERMINALSIZE_DISPLAY_NAME "Terminal Size"
#define FF_TERMINALSIZE_NUM_FORMAT_ARGS 4
void ffPrintTerminalSize(FFTerminalSizeOptions* options)
{
FFTerminalSizeResult result = {};
if(!ffDetectTerminalSize(&result))
{
ffPrintError(FF_TERMINALSIZE_DISPLAY_NAME, 0, &options->moduleArgs, "Failed to detect terminal size");
}
else
{
if(options->moduleArgs.outputFormat.length == 0)
{
ffPrintLogoAndKey(FF_TERMINALSIZE_DISPLAY_NAME, 0, &options->moduleArgs.key, &options->moduleArgs.keyColor);
printf("%u columns x %u rows", result.columns, result.rows);
if (result.width != 0 && result.height != 0)
printf(" (%upx x %upx)", result.width, result.height);
putchar('\n');
}
else
{
ffPrintFormat(FF_TERMINALSIZE_DISPLAY_NAME, 0, &options->moduleArgs, FF_TERMINALSIZE_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_UINT16, &result.rows},
{FF_FORMAT_ARG_TYPE_UINT16, &result.columns},
{FF_FORMAT_ARG_TYPE_UINT16, &result.width},
{FF_FORMAT_ARG_TYPE_UINT16, &result.height}
});
}
}
}
void ffInitTerminalSizeOptions(FFTerminalSizeOptions* options)
{
options->moduleName = FF_TERMINALSIZE_MODULE_NAME;
ffOptionInitModuleArg(&options->moduleArgs);
}
bool ffParseTerminalSizeCommandOptions(FFTerminalSizeOptions* options, const char* key, const char* value)
{
const char* subKey = ffOptionTestPrefix(key, FF_TERMINALSIZE_MODULE_NAME);
if (!subKey) return false;
if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs))
return true;
return false;
}
void ffDestroyTerminalSizeOptions(FFTerminalSizeOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
}
void ffParseTerminalSizeJsonObject(yyjson_val* module)
{
FFTerminalSizeOptions __attribute__((__cleanup__(ffDestroyTerminalSizeOptions))) options;
ffInitTerminalSizeOptions(&options);
if (module)
{
yyjson_val *key_, *val;
size_t idx, max;
yyjson_obj_foreach(module, idx, max, key_, val)
{
const char* key = yyjson_get_str(key_);
if(ffStrEqualsIgnCase(key, "type"))
continue;
if (ffJsonConfigParseModuleArgs(key, val, &options.moduleArgs))
continue;
ffPrintError(FF_TERMINALSIZE_MODULE_NAME, 0, &options.moduleArgs, "Unknown JSON key %s", key);
}
}
ffPrintTerminalSize(&options);
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "fastfetch.h"
#define FF_TERMINALSIZE_MODULE_NAME "TerminalSize"
void ffPrintTerminalSize(FFTerminalSizeOptions* options);
void ffInitTerminalSizeOptions(FFTerminalSizeOptions* options);
bool ffParseTerminalSizeCommandOptions(FFTerminalSizeOptions* options, const char* key, const char* value);
void ffDestroyTerminalSizeOptions(FFTerminalSizeOptions* options);
void ffParseTerminalSizeJsonObject(yyjson_val* module);