From c749f214e0d6c30e225e87a3186d3a765127d49d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 17 Jan 2024 23:12:55 +0800 Subject: [PATCH 01/36] Global: silence warnings when building in 32bit environments --- src/common/format.c | 2 +- src/common/time.h | 2 +- src/detection/diskio/diskio_linux.c | 3 ++- src/detection/displayserver/linux/drm.c | 2 +- src/detection/gpu/gpu_windows.c | 2 +- src/detection/terminalshell/terminalshell_linux.c | 1 + 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/common/format.c b/src/common/format.c index a381c2094..6c65ff473 100644 --- a/src/common/format.c +++ b/src/common/format.c @@ -57,7 +57,7 @@ static inline uint32_t getArgumentIndex(const FFstrbuf* placeholderValue) uint32_t result = UINT32_MAX; if(placeholderValue->chars[0] != '-') - sscanf(placeholderValue->chars, "%u", &result); + sscanf(placeholderValue->chars, "%" PRIu32, &result); return result == 0 ? UINT32_MAX : result; } diff --git a/src/common/time.h b/src/common/time.h index 4dd00f0e3..ddcd3f1c1 100644 --- a/src/common/time.h +++ b/src/common/time.h @@ -42,6 +42,6 @@ static inline void ffTimeSleep(uint32_t msec) #ifdef _WIN32 SleepEx(msec, TRUE); #else - nanosleep(&(struct timespec){ msec / 1000, (msec % 1000) * 1000000 }, NULL); + nanosleep(&(struct timespec){ msec / 1000, (long) (msec % 1000) * 1000000 }, NULL); #endif } diff --git a/src/detection/diskio/diskio_linux.c b/src/detection/diskio/diskio_linux.c index 5edf65901..f34345da9 100644 --- a/src/detection/diskio/diskio_linux.c +++ b/src/detection/diskio/diskio_linux.c @@ -5,6 +5,7 @@ #include #include +#include const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) { @@ -89,7 +90,7 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) ssize_t fileSize = ffReadFileData(pathSysBlock, sizeof(sysBlockStat) - 1, sysBlockStat); if (fileSize <= 0) continue; sysBlockStat[fileSize] = '\0'; - if (sscanf(sysBlockStat, "%lu%*u%lu%*u%lu%*u%lu%*u", &nRead, §orRead, &nWritten, §orWritten) <= 0) + if (sscanf(sysBlockStat, "%" PRIu64 "%*u%" PRIu64 "%*u%" PRIu64 "%*u%" PRIu64 "%*u", &nRead, §orRead, &nWritten, §orWritten) <= 0) continue; } diff --git a/src/detection/displayserver/linux/drm.c b/src/detection/displayserver/linux/drm.c index cf6bf3cde..8de938fcd 100644 --- a/src/detection/displayserver/linux/drm.c +++ b/src/detection/displayserver/linux/drm.c @@ -46,7 +46,7 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) continue; } - uint32_t width = 0, height = 0; + unsigned width = 0, height = 0; int scanned = sscanf(modes, "%ux%u", &width, &height); if(scanned == 2 && width > 0 && height > 0) diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index 3096e0a52..dc809727f 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -77,7 +77,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* // See: https://download.nvidia.com/XFree86/Linux-x86_64/545.23.06/README/supportedchips.html // displayDevice.DeviceID = MatchingDeviceId "PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1" - uint32_t vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0; + unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0; swscanf(displayDevice.DeviceID, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId); FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus); diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 6bbbec717..a9cbb9a47 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -79,6 +79,7 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) buf[nRead] = '\0'; *ppid = 0; + static_assert(sizeof(*ppid) == sizeof(int), ""); if( sscanf(buf, "%*s (%255[^)]) %*c %d", name, ppid) != 2 || //stat (comm) state ppid !ffStrSet(name) || From 2808b1a6533b1dc4e3dfa584037b746c86692c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 17 Jan 2024 23:45:39 +0800 Subject: [PATCH 02/36] TerminalShell: improve xonsh version detection --- src/detection/terminalshell/terminalshell.c | 2 +- src/detection/terminalshell/terminalshell_linux.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index 118b4c70f..98faad02c 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -228,7 +228,7 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version) return getExeVersionRaw(exe, version); if(strcasecmp(exeName, "ash") == 0) return getShellVersionAsh(exe, version); - if(strcasecmp(exeName, "python") == 0 && getenv("XONSH_VERSION")) + if((strcasecmp(exeName, "xonsh") == 0 || strcasecmp(exeName, "python") == 0) && getenv("XONSH_VERSION")) { ffStrbufSetS(version, getenv("XONSH_VERSION")); return true; diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index a9cbb9a47..397191e4e 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -186,7 +186,8 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) ffStrEquals(name, "git-shell") || ffStrEquals(name, "elvish") || ffStrEquals(name, "oil.ovm") || - (ffStrEquals(name, "python") && getenv("XONSH_VERSION")) + ffStrEquals(name, "xonsh") || + ffStrEndsWith(name, ".sh") ) { pid = ppid; From 1e4f17441570fe5abc6ebfc711655aa49362ff88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jan 2024 14:07:29 +0800 Subject: [PATCH 03/36] Shell (macOS): improve handling of xonsh --- .../terminalshell/terminalshell_linux.c | 54 ++++++++++++------- src/modules/shell/shell.c | 1 + src/util/mallocHelper.h | 2 +- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 397191e4e..fac9df60e 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -4,14 +4,13 @@ #include "common/processing.h" #include "common/thread.h" #include "util/stringUtils.h" +#include "util/mallocHelper.h" #include #include #include -#ifdef __APPLE__ - #include -#elif defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__APPLE__) #include #include #include @@ -38,15 +37,31 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex if(ffAppendFileBuffer(cmdlineFilePath, exe)) { ffStrbufTrimRightSpace(exe); - ffStrbufSubstrBeforeFirstC(exe, '\0'); //Trim the arguments - ffStrbufTrimLeft(exe, '-'); //Happens in TTY + ffStrbufRecalculateLength(exe); //Trim the arguments + ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash } #elif defined(__APPLE__) - int length = proc_pidpath((int)pid, exe->chars, exe->allocated); - if(length > 0) - exe->length = (uint32_t)length; + size_t len = 0; + int mibs[] = { CTL_KERN, KERN_PROCARGS2, pid }; + if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), NULL, &len, NULL, 0) == 0) + { + FF_AUTO_FREE char* const procArgs2 = malloc(len); + if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), procArgs2, &len, NULL, 0) == 0) + { + // https://gist.github.com/nonowarn/770696#file-getargv-c-L46 + uint32_t argc = *(uint32_t*) procArgs2; + const char* realExePath = procArgs2 + sizeof(argc); + + const char* arg0 = memchr(realExePath, '\0', len - (size_t) (realExePath - procArgs2)); + while (*arg0 == '\0') arg0++; + assert(arg0 < procArgs2 + len); + if (*arg0 == '-') arg0++; // Login shells + + ffStrbufSetS(exe, arg0); + } + } #elif defined(__FreeBSD__) @@ -89,12 +104,17 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) #elif defined(__APPLE__) - struct proc_bsdshortinfo proc; - if(proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) <= 0) - return "proc_pidinfo(pid) failed"; + struct kinfo_proc proc; + size_t size = sizeof(proc); + if(sysctl( + (int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4, + &proc, &size, + NULL, 0 + )) + return "sysctl(KERN_PROC_PID) failed"; - *ppid = (pid_t)proc.pbsi_ppid; - strncpy(name, proc.pbsi_comm, 16); //trancated to 16 chars + *ppid = (pid_t)proc.kp_eproc.e_ppid; + strncpy(name, proc.kp_proc.p_comm, MAXCOMLEN); //trancated to 16 chars #elif defined(__FreeBSD__) @@ -186,7 +206,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) ffStrEquals(name, "git-shell") || ffStrEquals(name, "elvish") || ffStrEquals(name, "oil.ovm") || - ffStrEquals(name, "xonsh") || + ffStrEquals(name, "xonsh") || // works in Linux but not in macOS because kernel returns `Python` in this case ffStrEndsWith(name, ".sh") ) { @@ -318,8 +338,6 @@ static void setShellInfoDetails(FFShellResult* result) ffStrbufInitStatic(&result->prettyName, "PowerShell"); else if(ffStrbufEqualS(&result->processName, "nu")) ffStrbufInitStatic(&result->prettyName, "nushell"); - else if(ffStrbufEqualS(&result->processName, "python") && getenv("XONSH_VERSION")) - ffStrbufInitStatic(&result->prettyName, "xonsh"); else if(ffStrbufEqualS(&result->processName, "oil.ovm")) ffStrbufInitStatic(&result->prettyName, "Oils"); else @@ -383,9 +401,7 @@ static void setTerminalInfoDetails(FFTerminalResult* result) fftsGetTerminalVersion(&result->processName, &result->exe, &result->version); } -#ifdef __APPLE__ -#define FF_EXE_PATH_LEN PROC_PIDPATHINFO_MAXSIZE -#elif defined(MAXPATH) +#if defined(MAXPATH) #define FF_EXE_PATH_LEN MAXPATH #elif defined(PATH_MAX) #define FF_EXE_PATH_LEN PATH_MAX diff --git a/src/modules/shell/shell.c b/src/modules/shell/shell.c index 9bb590eea..0c6d82f8c 100644 --- a/src/modules/shell/shell.c +++ b/src/modules/shell/shell.c @@ -93,6 +93,7 @@ void ffGenerateShellJsonResult(FF_MAYBE_UNUSED FFShellOptions* options, yyjson_m yyjson_mut_obj_add_uint(doc, obj, "pid", result->pid); yyjson_mut_obj_add_uint(doc, obj, "ppid", result->ppid); yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->processName); + yyjson_mut_obj_add_strbuf(doc, obj, "prettyName", &result->prettyName); yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->version); } diff --git a/src/util/mallocHelper.h b/src/util/mallocHelper.h index 3cf19fad2..cacba8ecd 100644 --- a/src/util/mallocHelper.h +++ b/src/util/mallocHelper.h @@ -6,7 +6,7 @@ #include #include -static inline void ffWrapFree(void* pPtr) +static inline void ffWrapFree(const void* pPtr) { assert(pPtr); if(*(void**)pPtr) From 947d2ff0a9a07796b071aef61cdd31011cc5c86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jan 2024 14:54:14 +0800 Subject: [PATCH 04/36] Processing (Linux): return error when command is not found --- src/common/processing_linux.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/common/processing_linux.c b/src/common/processing_linux.c index fe312e587..e0f2db4d9 100644 --- a/src/common/processing_linux.c +++ b/src/common/processing_linux.c @@ -13,13 +13,6 @@ enum { FF_PIPE_BUFSIZ = 8192 }; -static inline void waitpid_wrapper(const pid_t* pid) -{ - // remove zombie processes - if (*pid > 0) - waitpid(*pid, NULL, 0); -} - static inline int ffPipe2(int *fds, int flags) { #ifdef __APPLE__ @@ -41,7 +34,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use if(ffPipe2(pipes, O_CLOEXEC) == -1) return "pipe() failed"; - __attribute__((__cleanup__(waitpid_wrapper))) pid_t childPid = fork(); + pid_t childPid = fork(); if(childPid == -1) { close(pipes[0]); @@ -74,11 +67,13 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use if (poll(&pollfd, 1, timeout) == 0) { kill(childPid, SIGTERM); + waitpid(childPid, NULL, 0); return "poll(&pollfd, 1, timeout) timeout"; } else if (pollfd.revents & POLLERR) { kill(childPid, SIGTERM); + waitpid(childPid, NULL, 0); return "poll(&pollfd, 1, timeout) error"; } } @@ -87,7 +82,19 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use if (nRead > 0) ffStrbufAppendNS(buffer, (uint32_t) nRead, str); else if (nRead == 0) - return NULL; + { + int stat_loc = 0; + if (waitpid(childPid, &stat_loc, 0) == childPid) + { + if (!WIFEXITED(stat_loc)) + return "child process exited abnormally"; + if (WEXITSTATUS(stat_loc) == 127) + return "command was not found"; + // We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c` + return NULL; + } + return "waitpid() failed"; + } else if (nRead < 0) break; }; From 5096180e922d933f1b734443c2100c14b9d16eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jan 2024 15:06:47 +0800 Subject: [PATCH 05/36] CPU (Linux): don't access out-of-bound memory --- src/detection/cpu/cpu_linux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 8f33c491e..227af12bb 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -191,6 +191,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) ffStrbufAppendS(&cpu->vendor, pstart); } pstart = pend + 1; + if (pstart >= buffer.chars + buffer.length) + return NULL; } } } @@ -222,6 +224,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) } pstart = pend + 1; + if (pstart >= buffer.chars + buffer.length) + return NULL; } } } From 3992d85eb62628078ea5fd869f225e31f8569053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jan 2024 15:16:46 +0800 Subject: [PATCH 06/36] CPU (Linux): show vendor if no model name available --- src/detection/cpu/cpu_linux.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 227af12bb..fbc5a9749 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -209,7 +209,10 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) if (*pstart == '-') { - ffStrbufAppendS(&cpu->name, "Unknown"); + if (cpu->vendor.length > 0) + ffStrbufAppend(&cpu->name, &cpu->vendor); + else + ffStrbufAppendS(&cpu->name, "Unknown"); ++pstart; continue; } From 0168f2e9a8b5ea3953de14be534fe543316c5df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jan 2024 15:27:31 +0800 Subject: [PATCH 07/36] Shell: improve xonsh version detection --- src/detection/terminalshell/terminalshell.c | 24 ++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index 98faad02c..78c309766 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -168,6 +168,23 @@ static bool getShellVersionAsh(FFstrbuf* exe, FFstrbuf* version) return true; } +static bool getShellVersionXonsh(FFstrbuf* exe, FFstrbuf* version) +{ + ffStrbufSetS(version, getenv("XONSH_VERSION")); + if (version->length) return true; + + if(ffProcessAppendStdErr(version, (char* const[]) { + exe->chars, + "--version", + NULL + }) != NULL) + return false; + + // xonsh/0.14.1 + ffStrbufSubstrAfterFirstC(version, '/'); + return true; +} + #ifdef _WIN32 static bool getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version) { @@ -228,11 +245,8 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version) return getExeVersionRaw(exe, version); if(strcasecmp(exeName, "ash") == 0) return getShellVersionAsh(exe, version); - if((strcasecmp(exeName, "xonsh") == 0 || strcasecmp(exeName, "python") == 0) && getenv("XONSH_VERSION")) - { - ffStrbufSetS(version, getenv("XONSH_VERSION")); - return true; - } + if(strcasecmp(exeName, "xonsh") == 0) + return getShellVersionXonsh(exe, version); #ifdef _WIN32 if(strcasecmp(exeName, "powershell") == 0 || strcasecmp(exeName, "powershell_ise") == 0) From b2a853cb6e8c1d71c20b791543cfa4adb0915874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jan 2024 15:28:49 +0800 Subject: [PATCH 08/36] Doc: update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0683c6727..caa7f0f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 2.6.1 + +Bugfixes: +* Fix segfault in CPU module when running in aarch64 machine without `lscpu` installed (CPU, Linux) +* Improve xonsh shell detection (Shell, Linux) +* Silence warnings when building in 32bit machines. + # 2.6.0 Changes: From d6cb405afec119f6a0b88a95aa55d5c0d42e710a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jan 2024 15:31:36 +0800 Subject: [PATCH 09/36] Release: v2.6.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1247d7f9..86670934f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.6.0 + VERSION 2.6.1 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" From a44daa04d66f754fd6e93f279db5682a4bc6633a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jan 2024 18:08:08 +0800 Subject: [PATCH 10/36] Shell (Windows): better support xonsh detection --- src/detection/terminalshell/terminalshell_windows.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index a462ab566..c706693b4 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -103,7 +103,8 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) ffStrbufIgnCaseEqualS(&result->prettyName, "gdb") || ffStrbufIgnCaseEqualS(&result->prettyName, "lldb") || ffStrbufIgnCaseEqualS(&result->prettyName, "guake-wrapped") || - ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || //scoop warps the real binaries with a "shim" exe + ffStrbufIgnCaseEqualS(&result->prettyName, "python") || // python on windows generates shim executables + ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || // scoop warps the real binaries with a "shim" exe ffStrbufIgnCaseEqualS(&result->prettyName, "flashfetch") || ffStrbufContainIgnCaseS(&result->prettyName, "debug") || ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014 From 413f91260d099dcf65c3fe6fad1ebc55bf454f17 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 19 Jan 2024 10:13:46 +0800 Subject: [PATCH 11/36] Processes (FreeBSD): don't count sub-threads as processes --- src/detection/processes/processes_bsd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/detection/processes/processes_bsd.c b/src/detection/processes/processes_bsd.c index bc8cdaaeb..0cd169cfa 100644 --- a/src/detection/processes/processes_bsd.c +++ b/src/detection/processes/processes_bsd.c @@ -6,13 +6,17 @@ #include #endif +#ifndef KERN_PROC_PROC + #define KERN_PROC_PROC KERN_PROC_ALL // Apple +#endif + const char* ffDetectProcesses(uint32_t* result) { - int request[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; + int request[] = {CTL_KERN, KERN_PROC, KERN_PROC_PROC}; size_t length; if(sysctl(request, sizeof(request) / sizeof(*request), NULL, &length, NULL, 0) != 0) - return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}) failed"; + return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}) failed"; *result = (uint32_t)(length / sizeof(struct kinfo_proc)); return NULL; From eee8fb78d29f764c9770a80400b23a17ed297680 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 19 Jan 2024 10:15:02 +0800 Subject: [PATCH 12/36] Shell (FreeBSD): detect arg0 instead of exe path --- .../terminalshell/terminalshell_linux.c | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index fac9df60e..439cf6535 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -65,13 +65,31 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex #elif defined(__FreeBSD__) - size_t size = exe->allocated; - if(!sysctl( - (int[]){CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}, 4, - exe->chars, &size, + size_t size = ARG_MAX; + FF_AUTO_FREE char* args = malloc(size); + if(sysctl( + (int[]){CTL_KERN, KERN_PROC, KERN_PROC_ARGS, pid}, 4, + args, &size, NULL, 0 - )) - exe->length = (uint32_t)size - 1; + ) == 0) + { + char* arg0 = args; + size_t arg0Len = strlen(args); + if (size > arg0Len + 1) + { + char* p = (char*) memrchr(args, '/', arg0Len); + if (p) + { + p++; + if (ffStrStartsWith(p, "python")) // /usr/local/bin/python3.9 /home/carter/.local/bin/xonsh + { + arg0 += arg0Len + 1; + } + } + } + if (arg0[0] == '-') arg0++; + ffStrbufSetS(exe, arg0); + } #endif From 06af39835a485f89cfbaa5726307d4264a89418f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 10:46:19 +0800 Subject: [PATCH 13/36] Terminal: don't use `login` as terminal process; set ppid --- CHANGELOG.md | 5 ++++- src/detection/terminalshell/terminalshell_linux.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index caa7f0f58..eafb2f57f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ # 2.6.1 +Features: +* Improve xonsh shell detection (Shell) + Bugfixes: * Fix segfault in CPU module when running in aarch64 machine without `lscpu` installed (CPU, Linux) -* Improve xonsh shell detection (Shell, Linux) +* Don't use `login` as terminal process (Terminal, Linux) * Silence warnings when building in 32bit machines. # 2.6.0 diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 439cf6535..e3440cd05 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -225,6 +225,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) ffStrEquals(name, "elvish") || ffStrEquals(name, "oil.ovm") || ffStrEquals(name, "xonsh") || // works in Linux but not in macOS because kernel returns `Python` in this case + ffStrEquals(name, "login") || ffStrEndsWith(name, ".sh") ) { @@ -242,6 +243,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) #endif result->pid = (uint32_t) pid; + result->ppid = (uint32_t) ppid; ffStrbufSetS(&result->processName, name); getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); break; From 7d78d92a92d5e14be50b2a15828ab6bf9adf27e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 10:50:02 +0800 Subject: [PATCH 14/36] TerminalShell (macOS): detect full exe path --- src/detection/terminalshell/terminalshell.h | 4 +++- src/detection/terminalshell/terminalshell_linux.c | 14 +++++++++----- src/modules/shell/shell.c | 9 ++++++--- src/modules/terminal/terminal.c | 11 +++++++---- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/detection/terminalshell/terminalshell.h b/src/detection/terminalshell/terminalshell.h index 921fb7098..0ba1cb227 100644 --- a/src/detection/terminalshell/terminalshell.h +++ b/src/detection/terminalshell/terminalshell.h @@ -5,8 +5,9 @@ typedef struct FFShellResult { FFstrbuf processName; - FFstrbuf exe; + FFstrbuf exe; //Actually arg0 const char* exeName; //pointer to a char in exe + FFstrbuf exePath; //Full real path to executable file FFstrbuf prettyName; FFstrbuf version; uint32_t pid; @@ -19,6 +20,7 @@ typedef struct FFTerminalResult FFstrbuf exe; FFstrbuf prettyName; const char* exeName; //pointer to a char in exe + FFstrbuf exePath; //Full real path to executable file FFstrbuf version; uint32_t pid; uint32_t ppid; diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index e3440cd05..ed40f3773 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -24,7 +24,7 @@ static void setExeName(FFstrbuf* exe, const char** exeName) *exeName = exe->chars + lastSlashIndex + 1; } -static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName) +static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath) { assert(processName->length > 0); ffStrbufClear(exe); @@ -55,7 +55,9 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex const char* realExePath = procArgs2 + sizeof(argc); const char* arg0 = memchr(realExePath, '\0', len - (size_t) (realExePath - procArgs2)); - while (*arg0 == '\0') arg0++; + ffStrbufSetNS(exePath, (uint32_t) (arg0 - realExePath), realExePath); + + do arg0++; while (*arg0 == '\0'); assert(arg0 < procArgs2 + len); if (*arg0 == '-') arg0++; // Login shells @@ -192,7 +194,7 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid) result->pid = (uint32_t) pid; result->ppid = (uint32_t) ppid; ffStrbufSetS(&result->processName, name); - getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); + getProcessInformation(pid, &result->processName, &result->exe, &result->exeName, &result->exePath); break; } return ppid; @@ -245,7 +247,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) result->pid = (uint32_t) pid; result->ppid = (uint32_t) ppid; ffStrbufSetS(&result->processName, name); - getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); + getProcessInformation(pid, &result->processName, &result->exe, &result->exeName, &result->exePath); break; } return ppid; @@ -417,7 +419,6 @@ static void setTerminalInfoDetails(FFTerminalResult* result) else ffStrbufInitCopy(&result->prettyName, &result->processName); - ffStrbufInit(&result->version); fftsGetTerminalVersion(&result->processName, &result->exe, &result->version); } @@ -440,6 +441,7 @@ const FFShellResult* ffDetectShell() ffStrbufInit(&result.processName); ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN); result.exeName = result.exe.chars; + ffStrbufInit(&result.exePath); ffStrbufInit(&result.version); result.pid = 0; result.ppid = 0; @@ -463,6 +465,8 @@ const FFTerminalResult* ffDetectTerminal() ffStrbufInit(&result.processName); ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN); result.exeName = result.exe.chars; + ffStrbufInit(&result.exePath); + ffStrbufInit(&result.version); result.pid = 0; result.ppid = 0; diff --git a/src/modules/shell/shell.c b/src/modules/shell/shell.c index 0c6d82f8c..a0792d5c2 100644 --- a/src/modules/shell/shell.c +++ b/src/modules/shell/shell.c @@ -38,6 +38,7 @@ void ffPrintShell(FFShellOptions* options) {FF_FORMAT_ARG_TYPE_STRBUF, &result->version}, {FF_FORMAT_ARG_TYPE_UINT, &result->pid}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->exePath}, }); } } @@ -90,6 +91,7 @@ void ffGenerateShellJsonResult(FF_MAYBE_UNUSED FFShellOptions* options, yyjson_m yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->exe); yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->exeName); + yyjson_mut_obj_add_strbuf(doc, obj, "exePath", &result->exePath); yyjson_mut_obj_add_uint(doc, obj, "pid", result->pid); yyjson_mut_obj_add_uint(doc, obj, "ppid", result->ppid); yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->processName); @@ -101,11 +103,12 @@ void ffPrintShellHelpFormat(void) { ffPrintModuleFormatHelp(FF_SHELL_MODULE_NAME, "{3} {4}", FF_SHELL_NUM_FORMAT_ARGS, (const char* []) { "Shell process name", - "Shell path with exe name", - "Shell exe name", + "The first argument of the command line when running the shell", + "Shell base name of arg0", "Shell version", "Shell pid", - "Shell pretty name" + "Shell pretty name", + "Shell full exe path", }); } diff --git a/src/modules/terminal/terminal.c b/src/modules/terminal/terminal.c index d456ea771..c5295d5bb 100644 --- a/src/modules/terminal/terminal.c +++ b/src/modules/terminal/terminal.c @@ -6,7 +6,7 @@ #include -#define FF_TERMINAL_NUM_FORMAT_ARGS 6 +#define FF_TERMINAL_NUM_FORMAT_ARGS 7 void ffPrintTerminal(FFTerminalOptions* options) { @@ -36,6 +36,7 @@ void ffPrintTerminal(FFTerminalOptions* options) {FF_FORMAT_ARG_TYPE_UINT, &result->pid}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->version}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->exePath}, }); } } @@ -89,6 +90,7 @@ void ffGenerateTerminalJsonResult(FF_MAYBE_UNUSED FFTerminalOptions* options, yy yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->processName); yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->exe); yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->exeName); + yyjson_mut_obj_add_strbuf(doc, obj, "exePath", &result->exePath); yyjson_mut_obj_add_uint(doc, obj, "pid", result->pid); yyjson_mut_obj_add_uint(doc, obj, "ppid", result->ppid); yyjson_mut_obj_add_strbuf(doc, obj, "prettyName", &result->prettyName); @@ -99,11 +101,12 @@ void ffPrintTerminalHelpFormat(void) { ffPrintModuleFormatHelp(FF_TERMINAL_MODULE_NAME, "{5} {6}", FF_TERMINAL_NUM_FORMAT_ARGS, (const char* []) { "Terminal process name", - "Terminal path with exe name", - "Terminal exe name", + "The first argument of the command line when running the terminal", + "Terminal base name of arg0", "Terminal pid", "Terminal pretty name", - "Terminal version" + "Terminal version", + "Terminal full exe path", }); } From e013c878909f707ebae952796fd9c157665df4df Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 19 Jan 2024 11:00:25 +0800 Subject: [PATCH 15/36] TerminalShell (Linux): detect real exe path --- src/detection/terminalshell/terminalshell_linux.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index ed40f3773..d25e959be 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -31,16 +31,25 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex #ifdef __linux__ - char cmdlineFilePath[64]; - snprintf(cmdlineFilePath, sizeof(cmdlineFilePath), "/proc/%d/cmdline", (int)pid); + char filePath[64]; + snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int)pid); - if(ffAppendFileBuffer(cmdlineFilePath, exe)) + if(ffAppendFileBuffer(filePath, exe)) { ffStrbufTrimRightSpace(exe); ffStrbufRecalculateLength(exe); //Trim the arguments ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash } + snprintf(filePath, sizeof(filePath), "/proc/%d/exe", (int)pid); + ffStrbufEnsureFixedLengthFree(exePath, PATH_MAX); + ssize_t length = readlink(filePath, exePath->chars, exePath->allocated - 1); + if (length > 0) // doesn't contain trailing NUL + { + exePath->chars[length + 1] = '\0'; + exePath->length = (uint32_t) length; + } + #elif defined(__APPLE__) size_t len = 0; From 356488be0c04198e0ad2d98b4b0b470abd26ff93 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 19 Jan 2024 11:10:36 +0800 Subject: [PATCH 16/36] TerminalShell (FreeBSD): detect real exe path --- src/detection/terminalshell/terminalshell_linux.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index d25e959be..89afe0ebc 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -78,6 +78,17 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex size_t size = ARG_MAX; FF_AUTO_FREE char* args = malloc(size); + + static_assert(ARG_MAX > PATH_MAX, ""); + + if(sysctl( + (int[]){CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}, 4, + args, &size, + NULL, 0 + ) == 0) + ffStrbufSetS(exePath, args); + + size = ARG_MAX; if(sysctl( (int[]){CTL_KERN, KERN_PROC, KERN_PROC_ARGS, pid}, 4, args, &size, From 5f147819703585fa24061e454ed4d316b6a17ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 14:05:34 +0800 Subject: [PATCH 17/36] TerminalShell (Windows): set exePath --- .../terminalshell/terminalshell_windows.c | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index c706693b4..6eec484c9 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -39,15 +39,15 @@ static bool getProductVersion(const wchar_t* filePath, FFstrbuf* version) return false; } -static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName) +static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath) { - HANDLE hProcess = pid == 0 + FF_AUTO_CLOSE_FD HANDLE hProcess = pid == 0 ? GetCurrentProcess() : OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid); if(ppid) { - PROCESS_BASIC_INFORMATION info; + PROCESS_BASIC_INFORMATION info = {}; ULONG size; if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size))) { @@ -55,21 +55,20 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb *ppid = (uint32_t)info.InheritedFromUniqueProcessId; } else - { - CloseHandle(hProcess); return false; - } } if(exe) { DWORD bufSize = exe->allocated; if(QueryFullProcessImageNameA(hProcess, 0, exe->chars, &bufSize)) - exe->length = bufSize; - else { - CloseHandle(hProcess); - return false; + // We use full path here + // Querying command line of remote processes in Windows requires either WMI or ReadProcessMemory + exe->length = bufSize; + if (exePath) ffStrbufSet(exePath, exe); } + else + return false; } if(pname && exeName) { @@ -77,7 +76,6 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb ffStrbufSetS(pname, *exeName); } - CloseHandle(hProcess); return true; } @@ -87,7 +85,7 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) { uint32_t ppid; - while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName)) + while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath)) { ffStrbufSet(&result->prettyName, &result->processName); if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) @@ -188,7 +186,7 @@ static bool getTerminalFromEnv(FFTerminalResult* result) //ConEmu uint32_t pid = (uint32_t) strtoul(term, NULL, 10); result->pid = pid; - if(getProcessInfo(pid, NULL, &result->processName, &result->exe, &result->exeName)) + if(getProcessInfo(pid, NULL, &result->processName, &result->exe, &result->exeName, &result->exePath)) { ffStrbufSet(&result->prettyName, &result->processName); if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) @@ -299,7 +297,7 @@ static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid) { uint32_t ppid; - while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName)) + while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath)) { ffStrbufSet(&result->prettyName, &result->processName); if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) @@ -381,15 +379,16 @@ const FFShellResult* ffDetectShell(void) init = true; ffStrbufInit(&result.processName); - ffStrbufInitA(&result.exe, 128); + ffStrbufInitA(&result.exe, MAX_PATH); result.exeName = ""; + ffStrbufInit(&result.exePath); ffStrbufInit(&result.prettyName); ffStrbufInit(&result.version); result.pid = 0; result.ppid = 0; uint32_t ppid; - if(!getProcessInfo(0, &ppid, NULL, NULL, NULL)) + if(!getProcessInfo(0, &ppid, NULL, NULL, NULL, NULL)) return &result; ppid = getShellInfo(&result, ppid); @@ -407,8 +406,9 @@ const FFTerminalResult* ffDetectTerminal(void) init = true; ffStrbufInit(&result.processName); - ffStrbufInitA(&result.exe, 128); + ffStrbufInitA(&result.exe, MAX_PATH); result.exeName = ""; + ffStrbufInit(&result.exePath); ffStrbufInit(&result.prettyName); ffStrbufInit(&result.version); result.pid = 0; From 9610a1ab23a9b56ea376dd31fea9d9a4eb8e6127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 15:00:10 +0800 Subject: [PATCH 18/36] TerminalShell (Windows): simplify nested shell detection by looking up GUI objects --- .../terminalshell/terminalshell_windows.c | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index 6eec484c9..d6821ede6 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -39,12 +39,15 @@ static bool getProductVersion(const wchar_t* filePath, FFstrbuf* version) return false; } -static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath) +static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui) { FF_AUTO_CLOSE_FD HANDLE hProcess = pid == 0 ? GetCurrentProcess() : OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid); + if (gui) + *gui = GetGuiResources(hProcess, GR_GDIOBJECTS) > 0; + if(ppid) { PROCESS_BASIC_INFORMATION info = {}; @@ -85,7 +88,7 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) { uint32_t ppid; - while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath)) + while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath, NULL)) { ffStrbufSet(&result->prettyName, &result->processName); if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) @@ -186,7 +189,7 @@ static bool getTerminalFromEnv(FFTerminalResult* result) //ConEmu uint32_t pid = (uint32_t) strtoul(term, NULL, 10); result->pid = pid; - if(getProcessInfo(pid, NULL, &result->processName, &result->exe, &result->exeName, &result->exePath)) + if(getProcessInfo(pid, NULL, &result->processName, &result->exe, &result->exeName, &result->exePath, NULL)) { ffStrbufSet(&result->prettyName, &result->processName); if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) @@ -296,26 +299,12 @@ conhost: static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid) { uint32_t ppid; + bool hasGui; - while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath)) + while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath, &hasGui)) { - ffStrbufSet(&result->prettyName, &result->processName); - if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) - ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); - - if( - ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh") || - ffStrbufIgnCaseEqualS(&result->prettyName, "cmd") || - ffStrbufIgnCaseEqualS(&result->prettyName, "bash") || - ffStrbufIgnCaseEqualS(&result->prettyName, "zsh") || - ffStrbufIgnCaseEqualS(&result->prettyName, "fish") || - ffStrbufIgnCaseEqualS(&result->prettyName, "nu") || - ffStrbufIgnCaseEqualS(&result->prettyName, "powershell") || - ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise") || - ffStrbufIgnCaseEqualS(&result->prettyName, "wsl") || // running inside wsl - ffStrbufIgnCaseEqualS(&result->prettyName, "servercoreshell") || // ServerCore Shell Launcher - ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmuC") // wrapper process of ConEmu - ) { + if(!hasGui) + { //We are nested shell ffStrbufClear(&result->processName); ffStrbufClear(&result->prettyName); @@ -325,6 +314,10 @@ static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid) continue; } + ffStrbufSet(&result->prettyName, &result->processName); + if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) + ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); + if(ffStrbufIgnCaseEqualS(&result->prettyName, "sihost") || ffStrbufIgnCaseEqualS(&result->prettyName, "explorer") ) { @@ -388,7 +381,7 @@ const FFShellResult* ffDetectShell(void) result.ppid = 0; uint32_t ppid; - if(!getProcessInfo(0, &ppid, NULL, NULL, NULL, NULL)) + if(!getProcessInfo(0, &ppid, NULL, NULL, NULL, NULL, NULL)) return &result; ppid = getShellInfo(&result, ppid); From 87813b3306f1f018f93d26c33368447939ded602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 15:42:48 +0800 Subject: [PATCH 19/36] Shell: detect associated TTY --- src/detection/terminalshell/terminalshell.h | 3 +- .../terminalshell/terminalshell_linux.c | 39 +++++++++++++++---- .../terminalshell/terminalshell_windows.c | 1 + src/modules/shell/shell.c | 5 +++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/detection/terminalshell/terminalshell.h b/src/detection/terminalshell/terminalshell.h index 0ba1cb227..235a29f60 100644 --- a/src/detection/terminalshell/terminalshell.h +++ b/src/detection/terminalshell/terminalshell.h @@ -5,13 +5,14 @@ typedef struct FFShellResult { FFstrbuf processName; - FFstrbuf exe; //Actually arg0 + FFstrbuf exe; //Actually arg0 in *nix const char* exeName; //pointer to a char in exe FFstrbuf exePath; //Full real path to executable file FFstrbuf prettyName; FFstrbuf version; uint32_t pid; uint32_t ppid; + int32_t tty; } FFShellResult; typedef struct FFTerminalResult diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 89afe0ebc..c83dffde4 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -121,7 +121,7 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex setExeName(exe, exeName); } -static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) +static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid, int32_t* tty) { #ifdef __linux__ @@ -135,13 +135,18 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) *ppid = 0; static_assert(sizeof(*ppid) == sizeof(int), ""); + + int tty_; if( - sscanf(buf, "%*s (%255[^)]) %*c %d", name, ppid) != 2 || //stat (comm) state ppid + sscanf(buf, "%*s (%255[^)]) %*c %d %*d %*d %d", name, ppid, &tty_) < 2 || //stat (comm) state ppid pgrp session tty !ffStrSet(name) || *ppid == 0 ) return "sscanf(stat) failed"; + if (tty && (tty_ >> 8) == 0x88) + *tty = tty_ & 0xFF; + #elif defined(__APPLE__) struct kinfo_proc proc; @@ -154,7 +159,13 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) return "sysctl(KERN_PROC_PID) failed"; *ppid = (pid_t)proc.kp_eproc.e_ppid; - strncpy(name, proc.kp_proc.p_comm, MAXCOMLEN); //trancated to 16 chars + strcpy(name, proc.kp_proc.p_comm); //trancated to 16 chars + if (tty) + { + *tty = ((proc.kp_eproc.e_tdev >> 24) & 0xFF) == 0x10 + ? proc.kp_eproc.e_tdev & 0xFFFFFF + : -1; + } #elif defined(__FreeBSD__) @@ -168,7 +179,20 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) return "sysctl(KERN_PROC_PID) failed"; *ppid = (pid_t)proc.ki_ppid; - strncpy(name, proc.ki_comm, COMMLEN); + strcpy(name, proc.ki_comm); + if (tty) + { + if (proc.ki_tdev != NODEV && proc.ki_flag & P_CONTROLT) + { + const char* ttyName = devname(proc.ki_tdev, S_IFCHR); + if (ffStrStartsWith(ttyName, "pts/")) + *tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10); + else + *tty = -1; + } + else + *tty = -1; + } #else @@ -186,7 +210,7 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid) pid_t ppid = 0; - while (getProcessNameAndPpid(pid, name, &ppid) == NULL) + while (getProcessNameAndPpid(pid, name, &ppid, &result->tty) == NULL) { //Common programs that are between terminal and own process, but are not the shell if( @@ -227,7 +251,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) pid_t ppid = 0; - while (getProcessNameAndPpid(pid, name, &ppid) == NULL) + while (getProcessNameAndPpid(pid, name, &ppid, NULL) == NULL) { //Known shells if ( @@ -259,7 +283,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) // https://github.com/fastfetch-cli/fastfetch/discussions/501 if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)")) { - if (__builtin_expect(getProcessNameAndPpid(ppid, name, &ppid) != NULL, false)) + if (__builtin_expect(getProcessNameAndPpid(ppid, name, &ppid, NULL) != NULL, false)) return 0; } #endif @@ -465,6 +489,7 @@ const FFShellResult* ffDetectShell() ffStrbufInit(&result.version); result.pid = 0; result.ppid = 0; + result.tty = -1; pid_t ppid = getppid(); ppid = getShellInfo(&result, ppid); diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index d6821ede6..67b91a677 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -379,6 +379,7 @@ const FFShellResult* ffDetectShell(void) ffStrbufInit(&result.version); result.pid = 0; result.ppid = 0; + result.tty = -1; uint32_t ppid; if(!getProcessInfo(0, &ppid, NULL, NULL, NULL, NULL, NULL)) diff --git a/src/modules/shell/shell.c b/src/modules/shell/shell.c index a0792d5c2..c3e4fcc1a 100644 --- a/src/modules/shell/shell.c +++ b/src/modules/shell/shell.c @@ -39,6 +39,7 @@ void ffPrintShell(FFShellOptions* options) {FF_FORMAT_ARG_TYPE_UINT, &result->pid}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->exePath}, + {FF_FORMAT_ARG_TYPE_INT, &result->tty}, }); } } @@ -97,6 +98,10 @@ void ffGenerateShellJsonResult(FF_MAYBE_UNUSED FFShellOptions* options, yyjson_m yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->processName); yyjson_mut_obj_add_strbuf(doc, obj, "prettyName", &result->prettyName); yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->version); + if (result->tty >= 0) + yyjson_mut_obj_add_int(doc, obj, "tty", result->tty); + else + yyjson_mut_obj_add_null(doc, obj, "tty"); } void ffPrintShellHelpFormat(void) From 8e7d465333be58dfafb3e04cce0fbbd06393f445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 20:59:52 +0800 Subject: [PATCH 20/36] Fastfetch: create sub folders when writing config file Fix #690 --- CHANGELOG.md | 1 + src/fastfetch.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eafb2f57f..ebd82da00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Bugfixes: * Fix segfault in CPU module when running in aarch64 machine without `lscpu` installed (CPU, Linux) * Don't use `login` as terminal process (Terminal, Linux) * Silence warnings when building in 32bit machines. +* Create sub folders when writing config file (#690) # 2.6.0 diff --git a/src/fastfetch.c b/src/fastfetch.c index f60ae9ad3..68bcea67f 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -7,6 +7,7 @@ #include "common/jsonconfig.h" #include "detection/version/version.h" #include "util/stringUtils.h" +#include "util/mallocHelper.h" #include "logo/logo.h" #include "fastfetch_datatext.h" @@ -831,7 +832,14 @@ static void writeConfigFile(FFdata* data, const FFstrbuf* filename) yyjson_mut_write_fp(stdout, doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES, NULL, NULL); else { - if (yyjson_mut_write_file(filename->chars, doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES, NULL, NULL)) + size_t len; + FF_AUTO_FREE const char* str = yyjson_mut_write(doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES, &len); + if (!str) + { + printf("Error: failed to generate config file\n"); + exit(1); + } + if (ffWriteFileData(filename->chars, len, str)) printf("The generated config file has been written in `%s`\n", filename->chars); else { From 8404ae034f3544f3f4a6f2cad9d90c6da9d2ea4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 21:06:42 +0800 Subject: [PATCH 21/36] Locale: improve detection Linux: always use `setlocale`, fix #688 Windows: don't append `UTF-8` --- src/detection/locale/locale_linux.c | 56 +++------------------------ src/detection/locale/locale_windows.c | 5 --- 2 files changed, 5 insertions(+), 56 deletions(-) diff --git a/src/detection/locale/locale_linux.c b/src/detection/locale/locale_linux.c index 99edccec0..2b0ad2d4f 100644 --- a/src/detection/locale/locale_linux.c +++ b/src/detection/locale/locale_linux.c @@ -1,61 +1,15 @@ #include "detection/locale/locale.h" -#include "common/properties.h" -#include "common/parsing.h" -#include #include -FF_MAYBE_UNUSED -static void getLocaleFromEnv(FFstrbuf* locale) -{ - ffStrbufAppendS(locale, getenv("LANG")); - if(locale->length > 0) - return; - - ffStrbufAppendS(locale, getenv("LC_ALL")); - if(locale->length > 0) - return; - - ffStrbufAppendS(locale, getenv("LC_MESSAGES")); -} - -static void getLocaleFromStdFn(FFstrbuf* locale) -{ - #ifdef LC_MESSAGES - ffStrbufAppendS(locale, setlocale(LC_MESSAGES, NULL)); - - if(locale->length > 0) - return; - #endif - - ffStrbufAppendS(locale, setlocale(LC_ALL, NULL)); -} - void ffDetectLocale(FFstrbuf* result) { - #if !(defined(__APPLE__) || defined(_WIN32)) - - //Ubuntu (and deriviates) use a non standard locale file. - //Parse it first, because on distributions where it exists, it takes precedence. - //Otherwise use the standard etc/locale.conf file. - ffParsePropFile(FASTFETCH_TARGET_DIR_ETC"/default/locale", "LANG =", result); - - if(result->length > 0) - return; - - ffParsePropFile(FASTFETCH_TARGET_DIR_ETC"/locale.conf", "LANG =", result); - if(result->length > 0) - return; + #ifdef LC_MESSAGES + ffStrbufAppendS(result, setlocale(LC_MESSAGES, NULL)); + if(result->length > 0) + return; #endif - #ifndef _WIN32 - - getLocaleFromEnv(result); - if(result->length > 0) - return; - - #endif - - getLocaleFromStdFn(result); + ffStrbufAppendS(result, setlocale(LC_ALL, NULL)); } diff --git a/src/detection/locale/locale_windows.c b/src/detection/locale/locale_windows.c index 128913129..c14732ffb 100644 --- a/src/detection/locale/locale_windows.c +++ b/src/detection/locale/locale_windows.c @@ -9,10 +9,5 @@ void ffDetectLocale(FFstrbuf* result) wchar_t name[LOCALE_NAME_MAX_LENGTH]; int size = GetUserDefaultLocaleName(name, LOCALE_NAME_MAX_LENGTH); if (size > 1) // including '\0' - { ffStrbufSetNWS(result, (uint32_t)size - 1, name); - ffStrbufAppendS(result, ".UTF-8"); // set explicitly in `ffInitInstance` - } - else - ffStrbufSetS(result, setlocale(LC_ALL, NULL)); } From 06181ec433f23ffd03107b4234b857ce5f91a01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 21:50:22 +0800 Subject: [PATCH 22/36] Terminal (Windows): default `default terminal` to conhost --- src/detection/terminalshell/terminalshell_windows.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index 67b91a677..b16e3d945 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -245,12 +245,8 @@ static bool detectDefaultTerminal(FFTerminalResult* result) DWORD bufSize = 80; if (RegGetValueW(HKEY_CURRENT_USER, L"Console\\%%Startup", L"DelegationTerminal", RRF_RT_REG_SZ, NULL, uuid, &bufSize) == ERROR_SUCCESS) { - if(wcscmp(uuid, L"{00000000-0000-0000-0000-000000000000}") == 0) - { - // Let Windows decide - return false; - } - if(wcscmp(uuid, L"{B23D10C0-E52E-411E-9D5B-C09FDF709C7D}") == 0) + if(wcscmp(uuid, L"{00000000-0000-0000-0000-000000000000}") == 0 || // Let Windows decide + wcscmp(uuid, L"{B23D10C0-E52E-411E-9D5B-C09FDF709C7D}") == 0) // Conhost { goto conhost; } From d810245d5515d7e3da2bc311f0510063c0bb642e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 21:52:23 +0800 Subject: [PATCH 23/36] Doc: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebd82da00..81a034917 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Bugfixes: * Don't use `login` as terminal process (Terminal, Linux) * Silence warnings when building in 32bit machines. * Create sub folders when writing config file (#690) +* Improve user specific locale detection; fix locale detection in Windows 7 (Locale) # 2.6.0 From 4d1f242e1defeb8c634d248af5ce488e2613e548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 19 Jan 2024 22:23:32 +0800 Subject: [PATCH 24/36] Terminal (Windows): tidy --- .../terminalshell/terminalshell_windows.c | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index b16e3d945..5317ac97f 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -118,9 +118,6 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) continue; } - ffStrbufClear(&result->version); - fftsGetShellVersion(&result->exe, result->prettyName.chars, &result->version); - result->pid = pid; result->ppid = ppid; @@ -320,14 +317,11 @@ static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid) // A CUI program created by Windows Explorer will spawn a conhost as its child. // However the conhost process is just a placeholder; // The true terminal can be Windows Terminal or others. - if (!getTerminalFromEnv(result) && !detectDefaultTerminal(result)) - { - ffStrbufClear(&result->processName); - ffStrbufClear(&result->prettyName); - ffStrbufClear(&result->exe); - result->exeName = ""; - return 0; - } + ffStrbufClear(&result->processName); + ffStrbufClear(&result->prettyName); + ffStrbufClear(&result->exe); + result->exeName = ""; + return 0; } else { @@ -382,7 +376,16 @@ const FFShellResult* ffDetectShell(void) return &result; ppid = getShellInfo(&result, ppid); - setShellInfoDetails(&result); + + if (result.processName.length > 0) + { + setShellInfoDetails(&result); + char tmp[MAX_PATH]; + strcpy(tmp, result.exeName); + char* ext = strrchr(tmp, '.'); + if (ext) *ext = '\0'; + fftsGetShellVersion(&result.exe, tmp, &result.version); + } return &result; } @@ -410,10 +413,14 @@ const FFTerminalResult* ffDetectTerminal(void) if(result.processName.length == 0) getTerminalFromEnv(&result); + if(result.processName.length == 0) + detectDefaultTerminal(&result); - setTerminalInfoDetails(&result); - - fftsGetTerminalVersion(&result.processName, &result.exe, &result.version); + if(result.processName.length > 0) + { + setTerminalInfoDetails(&result); + fftsGetTerminalVersion(&result.processName, &result.exe, &result.version); + } return &result; } From bd71aa931fd6b5078e867aed71efef2a4d079dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 11:28:38 +0800 Subject: [PATCH 25/36] Global: rename `common/bar` to `common/percent` --- CMakeLists.txt | 2 +- src/common/{bar.c => percent.c} | 2 +- src/common/{bar.h => percent.h} | 0 src/modules/battery/battery.c | 2 +- src/modules/brightness/brightness.c | 2 +- src/modules/cpuusage/cpuusage.c | 2 +- src/modules/disk/disk.c | 2 +- src/modules/gamepad/gamepad.c | 2 +- src/modules/gpu/gpu.c | 2 +- src/modules/memory/memory.c | 2 +- src/modules/swap/swap.c | 2 +- 11 files changed, 10 insertions(+), 10 deletions(-) rename src/common/{bar.c => percent.c} (99%) rename src/common/{bar.h => percent.h} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86670934f..4670d012e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,7 +265,7 @@ file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}") ####################### set(LIBFASTFETCH_SRC - src/common/bar.c + src/common/percent.c src/common/commandoption.c src/common/font.c src/common/format.c diff --git a/src/common/bar.c b/src/common/percent.c similarity index 99% rename from src/common/bar.c rename to src/common/percent.c index 558f5d542..206850083 100644 --- a/src/common/bar.c +++ b/src/common/percent.c @@ -1,5 +1,5 @@ -#include "common/bar.h" #include "common/color.h" +#include "common/percent.h" #include "util/textModifier.h" void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, uint8_t red) diff --git a/src/common/bar.h b/src/common/percent.h similarity index 100% rename from src/common/bar.h rename to src/common/percent.h diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 0a2bd8afd..3accac67c 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -1,6 +1,6 @@ #include "common/printing.h" #include "common/jsonconfig.h" -#include "common/bar.h" +#include "common/percent.h" #include "common/parsing.h" #include "detection/battery/battery.h" #include "modules/battery/battery.h" diff --git a/src/modules/brightness/brightness.c b/src/modules/brightness/brightness.c index 48519af6a..4f3342227 100644 --- a/src/modules/brightness/brightness.c +++ b/src/modules/brightness/brightness.c @@ -1,4 +1,4 @@ -#include "common/bar.h" +#include "common/percent.h" #include "common/printing.h" #include "common/jsonconfig.h" #include "detection/brightness/brightness.h" diff --git a/src/modules/cpuusage/cpuusage.c b/src/modules/cpuusage/cpuusage.c index 93de287d3..c21491f4e 100644 --- a/src/modules/cpuusage/cpuusage.c +++ b/src/modules/cpuusage/cpuusage.c @@ -1,6 +1,6 @@ #include "common/printing.h" #include "common/jsonconfig.h" -#include "common/bar.h" +#include "common/percent.h" #include "detection/cpuusage/cpuusage.h" #include "modules/cpuusage/cpuusage.h" #include "util/stringUtils.h" diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index a13d1e432..cd7e582e4 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -1,7 +1,7 @@ #include "common/printing.h" #include "common/jsonconfig.h" #include "common/parsing.h" -#include "common/bar.h" +#include "common/percent.h" #include "detection/disk/disk.h" #include "modules/disk/disk.h" #include "util/stringUtils.h" diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index a74d603cc..96afdd4d0 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -1,4 +1,4 @@ -#include "common/bar.h" +#include "common/percent.h" #include "common/printing.h" #include "common/jsonconfig.h" #include "detection/gamepad/gamepad.h" diff --git a/src/modules/gpu/gpu.c b/src/modules/gpu/gpu.c index 7646ad5bd..588c1c14c 100644 --- a/src/modules/gpu/gpu.c +++ b/src/modules/gpu/gpu.c @@ -1,4 +1,4 @@ -#include "common/bar.h" +#include "common/percent.h" #include "common/parsing.h" #include "common/printing.h" #include "common/jsonconfig.h" diff --git a/src/modules/memory/memory.c b/src/modules/memory/memory.c index b0e2830a1..73f1a3e2c 100644 --- a/src/modules/memory/memory.c +++ b/src/modules/memory/memory.c @@ -1,7 +1,7 @@ #include "common/printing.h" #include "common/jsonconfig.h" #include "common/parsing.h" -#include "common/bar.h" +#include "common/percent.h" #include "detection/memory/memory.h" #include "modules/memory/memory.h" #include "util/stringUtils.h" diff --git a/src/modules/swap/swap.c b/src/modules/swap/swap.c index 19bc4deca..6b4fb168b 100644 --- a/src/modules/swap/swap.c +++ b/src/modules/swap/swap.c @@ -1,7 +1,7 @@ #include "common/printing.h" #include "common/jsonconfig.h" #include "common/parsing.h" -#include "common/bar.h" +#include "common/percent.h" #include "detection/swap/swap.h" #include "modules/swap/swap.h" #include "util/stringUtils.h" From da5c44b3d04c4a7fb5f7f2695bba00bce625a160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 13:27:55 +0800 Subject: [PATCH 26/36] Percentage: simplify usage of `ffAppendPercentBar` --- src/common/percent.c | 50 ++++++++++++----------------- src/common/percent.h | 12 ++++++- src/modules/battery/battery.c | 9 ++---- src/modules/brightness/brightness.c | 4 +-- src/modules/cpuusage/cpuusage.c | 2 +- src/modules/disk/disk.c | 2 +- src/modules/memory/memory.c | 2 +- src/modules/swap/swap.c | 4 +-- 8 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/common/percent.c b/src/common/percent.c index 206850083..703ce40a3 100644 --- a/src/common/percent.c +++ b/src/common/percent.c @@ -1,17 +1,15 @@ -#include "common/color.h" +#include "fastfetch.h" #include "common/percent.h" +#include "common/color.h" #include "util/textModifier.h" -void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, uint8_t red) +void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow) { - assert(green <= 100 && yellow <= 100 && red <= 100); + assert(green <= 100 && yellow <= 100); const FFOptionsDisplay* options = &instance.config.display; uint32_t blocksPercent = (uint32_t) (percent / 100.0 * options->barWidth + 0.5); - uint32_t blocksGreen = (uint32_t) (green / 100.0 * options->barWidth + 0.5); - uint32_t blocksYellow = (uint32_t) (yellow / 100.0 * options->barWidth + 0.5); - uint32_t blocksRed = (uint32_t) (red / 100.0 * options->barWidth + 0.5); assert(blocksPercent <= options->barWidth); if(options->barBorder) @@ -26,12 +24,14 @@ void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t { if(!options->pipe) { - if (i == blocksGreen) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m"); - else if (i == blocksYellow) + uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5); + uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5); + if (i == section2Begin) + ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? FF_COLOR_FG_LIGHT_GREEN : FF_COLOR_FG_LIGHT_RED)); + else if (i == section1Begin) ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m"); - else if (i == blocksRed) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m"); + else if (i == 0) + ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? FF_COLOR_FG_GREEN : FF_COLOR_FG_LIGHT_RED)); } ffStrbufAppend(buffer, &options->barCharElapsed); } @@ -56,15 +56,6 @@ void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); } -// if (green < yellow) -// [0, green]: print green -// (green, yellow]: print yellow -// (yellow, 100]: print red -// -// if (green > yellow) -// [green, 100]: print green -// [yellow, green): print yellow -// [0, yellow): PRINT RED void ffAppendPercentNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses) { assert(green <= 100 && yellow <= 100); @@ -80,23 +71,24 @@ void ffAppendPercentNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t { if(percent != percent) ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m"); - else if(green < yellow) + else if(green <= yellow) { - if (percent <= green) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m"); - else if (percent <= yellow) + if (percent > yellow) + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m"); + else if (percent > green) ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m"); else - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m"); + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m"); + } else { - if (percent >= green) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m"); - else if (percent >= yellow) + if (percent < yellow) + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m"); + else if (percent < green) ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m"); else - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m"); + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m"); } } ffStrbufAppendF(buffer, "%.*f%%", options->percentNdigits, percent); diff --git a/src/common/percent.h b/src/common/percent.h index c77234ae6..43a1f49d9 100644 --- a/src/common/percent.h +++ b/src/common/percent.h @@ -10,5 +10,15 @@ enum FF_PERCENTAGE_TYPE_NUM_COLOR_BIT = 1 << 3, }; -void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, uint8_t red); +// if (green <= yellow) +// [0, green]: print green +// (green, yellow]: print yellow +// (yellow, 100]: print red +// +// if (green > yellow) +// [green, 100]: print green +// [yellow, green): print yellow +// [0, yellow): print red + +void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow); void ffAppendPercentNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses); diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 3accac67c..89d339a30 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -24,12 +24,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - if(result->capacity <= 20) - ffAppendPercentBar(&str, result->capacity, 100, 100, 0); - else if(result->capacity <= 50) - ffAppendPercentBar(&str, result->capacity, 100, 0, 100); - else - ffAppendPercentBar(&str, result->capacity, 0, 100, 100); + ffAppendPercentBar(&str, result->capacity, 50, 20); } if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -37,7 +32,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffAppendPercentNum(&str, result->capacity, 51, 21, str.length > 0); + ffAppendPercentNum(&str, result->capacity, 50, 20, str.length > 0); } } diff --git a/src/modules/brightness/brightness.c b/src/modules/brightness/brightness.c index 4f3342227..67074b07a 100644 --- a/src/modules/brightness/brightness.c +++ b/src/modules/brightness/brightness.c @@ -52,7 +52,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, percent, 0, 100, 100); + ffAppendPercentBar(&str, percent, 100, 100); } if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -60,7 +60,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffAppendPercentNum(&str, percent, 10, 10, str.length > 0); + ffAppendPercentNum(&str, percent, 100, 100, str.length > 0); } ffStrbufPutTo(&str, stdout); diff --git a/src/modules/cpuusage/cpuusage.c b/src/modules/cpuusage/cpuusage.c index c21491f4e..85797a213 100644 --- a/src/modules/cpuusage/cpuusage.c +++ b/src/modules/cpuusage/cpuusage.c @@ -52,7 +52,7 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) if (!options->separate) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) - ffAppendPercentBar(&str, avgValue, 0, 50, 80); + ffAppendPercentBar(&str, avgValue, 50, 80); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) { if(str.length > 0) diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index cd7e582e4..69cb6333a 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -59,7 +59,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, bytesPercentage, 0, 50, 80); + ffAppendPercentBar(&str, bytesPercentage, 50, 80); ffStrbufAppendC(&str, ' '); } diff --git a/src/modules/memory/memory.c b/src/modules/memory/memory.c index 73f1a3e2c..bccb12e9f 100644 --- a/src/modules/memory/memory.c +++ b/src/modules/memory/memory.c @@ -40,7 +40,7 @@ void ffPrintMemory(FFMemoryOptions* options) if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, percentage, 0, 50, 80); + ffAppendPercentBar(&str, percentage, 50, 80); ffStrbufAppendC(&str, ' '); } diff --git a/src/modules/swap/swap.c b/src/modules/swap/swap.c index 6b4fb168b..83c0d86cf 100644 --- a/src/modules/swap/swap.c +++ b/src/modules/swap/swap.c @@ -37,7 +37,7 @@ void ffPrintSwap(FFSwapOptions* options) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, 0, 0, 50, 80); + ffAppendPercentBar(&str, 0, 50, 80); ffStrbufAppendC(&str, ' '); } if(!(instance.config.display.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) @@ -47,7 +47,7 @@ void ffPrintSwap(FFSwapOptions* options) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, percentage, 0, 50, 80); + ffAppendPercentBar(&str, percentage, 50, 80); ffStrbufAppendC(&str, ' '); } From 24cb83dd18e39f9707b498e71a8f3118b3dbf8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 13:32:17 +0800 Subject: [PATCH 27/36] Bluetooth / Gamepad / Sound: support percentage number formatting --- src/modules/bluetooth/bluetooth.c | 23 +++++++++++------- src/modules/gamepad/gamepad.c | 16 +++++++++---- src/modules/sound/sound.c | 39 ++++++++++++++++++++++++------- src/modules/swap/swap.c | 2 ++ 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/modules/bluetooth/bluetooth.c b/src/modules/bluetooth/bluetooth.c index 91fb46724..0d669af44 100644 --- a/src/modules/bluetooth/bluetooth.c +++ b/src/modules/bluetooth/bluetooth.c @@ -1,3 +1,4 @@ +#include "common/percent.h" #include "common/printing.h" #include "common/jsonconfig.h" #include "detection/bluetooth/bluetooth.h" @@ -11,23 +12,29 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - ffStrbufWriteTo(&device->name, stdout); - if(device->battery > 0) - printf(" (%d%%)", device->battery); + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateCopy(&device->name); - if(!device->connected) - puts(" [disconnected]"); - else - putchar('\n'); + if (device->battery > 0 && device->battery <= 100) + { + if (buffer.length) + ffStrbufAppendC(&buffer, ' '); + ffAppendPercentNum(&buffer, device->battery, 50, 20, buffer.length > 0); + } + + if (!device->connected) + ffStrbufAppendS(&buffer, " [disconnected]"); } else { + FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); + ffAppendPercentNum(&percentageStr, device->battery, 50, 20, false); + ffPrintFormat(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_BLUETOOTH_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->address}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->type}, - {FF_FORMAT_ARG_TYPE_UINT8, &device->battery} + {FF_FORMAT_ARG_TYPE_STRBUF, &percentageStr} }); } } diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index 96afdd4d0..2e639b36f 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -11,21 +11,27 @@ static void printDevice(FFGamepadOptions* options, const FFGamepadDevice* device { if(options->moduleArgs.outputFormat.length == 0) { - FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateCopy(&device->name); ffPrintLogoAndKey(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateCopy(&device->name); + if (device->battery > 0 && device->battery <= 100) { - ffStrbufAppendC(&buffer, ' '); - ffAppendPercentNum(&buffer, device->battery, 51, 21, true); + if (buffer.length) + ffStrbufAppendC(&buffer, ' '); + ffAppendPercentNum(&buffer, device->battery, 50, 20, buffer.length > 0); } ffStrbufPutTo(&buffer, stdout); } else { + FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); + ffAppendPercentNum(&percentageStr, device->battery, 50, 20, false); + ffPrintFormat(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_GAMEPAD_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->serial}, - {FF_FORMAT_ARG_TYPE_UINT8, &device->battery}, + {FF_FORMAT_ARG_TYPE_STRBUF, &percentageStr}, }); } } @@ -130,7 +136,7 @@ void ffPrintGamepadHelpFormat(void) ffPrintModuleFormatHelp(FF_GAMEPAD_MODULE_NAME, "{1}", FF_GAMEPAD_NUM_FORMAT_ARGS, (const char* []) { "Name", "Serial number", - "Battery", + "Battery percentage", }); } diff --git a/src/modules/sound/sound.c b/src/modules/sound/sound.c index 39411b5d4..54ea63927 100644 --- a/src/modules/sound/sound.c +++ b/src/modules/sound/sound.c @@ -1,3 +1,4 @@ +#include "common/percent.h" #include "common/printing.h" #include "common/jsonconfig.h" #include "detection/sound/sound.h" @@ -11,27 +12,47 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_SOUND_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - ffStrbufWriteTo(&device->name, stdout); + + FF_STRBUF_AUTO_DESTROY str = ffStrbufCreate(); + if (!(instance.config.display.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) + ffStrbufAppend(&str, &device->name); if(device->volume != FF_SOUND_VOLUME_UNKNOWN) { - if(device->volume > 0) - printf(" (%d%%)", device->volume); - else - fputs(" (muted)", stdout); + if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) + { + if (str.length) + ffStrbufAppendC(&str, ' '); + + ffAppendPercentBar(&str, device->volume, 80, 90); + } + + if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) + { + if (str.length) + ffStrbufAppendC(&str, ' '); + + ffAppendPercentNum(&str, device->volume, 80, 90, str.length > 0); + } } - if(device->main && index > 0) - fputs(" (*)", stdout); + if (!(instance.config.display.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) + { + if (device->main && index > 0) + ffStrbufAppendS(&str, " (*)"); + } - putchar('\n'); + ffStrbufPutTo(&str, stdout); } else { + FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); + ffAppendPercentNum(&percentageStr, device->volume, 80, 90, false); + ffPrintFormat(FF_SOUND_MODULE_NAME, index, &options->moduleArgs, FF_SOUND_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_BOOL, &device->main}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, - {FF_FORMAT_ARG_TYPE_UINT8, &device->volume}, + {FF_FORMAT_ARG_TYPE_STRBUF, &percentageStr}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->identifier} }); } diff --git a/src/modules/swap/swap.c b/src/modules/swap/swap.c index 83c0d86cf..2635c8d00 100644 --- a/src/modules/swap/swap.c +++ b/src/modules/swap/swap.c @@ -42,6 +42,8 @@ void ffPrintSwap(FFSwapOptions* options) } if(!(instance.config.display.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) ffStrbufAppendS(&str, "Disabled"); + else + ffAppendPercentNum(&str, 0, 50, 80, str.length > 0); } else { From e7974a7ceaae066473a5118757ce47dd470db640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 13:49:04 +0800 Subject: [PATCH 28/36] Percentage: refactor function names --- src/common/percent.c | 4 ++-- src/common/percent.h | 4 ++-- src/modules/battery/battery.c | 6 +++--- src/modules/bluetooth/bluetooth.c | 4 ++-- src/modules/brightness/brightness.c | 6 +++--- src/modules/cpuusage/cpuusage.c | 12 ++++++------ src/modules/disk/disk.c | 8 ++++---- src/modules/gamepad/gamepad.c | 4 ++-- src/modules/gpu/gpu.c | 2 +- src/modules/memory/memory.c | 6 +++--- src/modules/sound/sound.c | 6 +++--- src/modules/swap/swap.c | 10 +++++----- 12 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/common/percent.c b/src/common/percent.c index 703ce40a3..766f610f7 100644 --- a/src/common/percent.c +++ b/src/common/percent.c @@ -3,7 +3,7 @@ #include "common/color.h" #include "util/textModifier.h" -void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow) +void ffPercentAppendBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow) { assert(green <= 100 && yellow <= 100); @@ -56,7 +56,7 @@ void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); } -void ffAppendPercentNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses) +void ffPercentAppendNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses) { assert(green <= 100 && yellow <= 100); diff --git a/src/common/percent.h b/src/common/percent.h index 43a1f49d9..f97fcb1c8 100644 --- a/src/common/percent.h +++ b/src/common/percent.h @@ -20,5 +20,5 @@ enum // [yellow, green): print yellow // [0, yellow): print red -void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow); -void ffAppendPercentNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses); +void ffPercentAppendBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow); +void ffPercentAppendNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses); diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 89d339a30..b811bdb3e 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -24,7 +24,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, result->capacity, 50, 20); + ffPercentAppendBar(&str, result->capacity, 50, 20); } if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -32,7 +32,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffAppendPercentNum(&str, result->capacity, 50, 20, str.length > 0); + ffPercentAppendNum(&str, result->capacity, 50, 20, str.length > 0); } } @@ -57,7 +57,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin else { FF_STRBUF_AUTO_DESTROY capacityStr = ffStrbufCreate(); - ffAppendPercentNum(&capacityStr, result->capacity, 51, 21, false); + ffPercentAppendNum(&capacityStr, result->capacity, 51, 21, false); ffPrintFormat(FF_BATTERY_MODULE_NAME, index, &options->moduleArgs, FF_BATTERY_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName}, diff --git a/src/modules/bluetooth/bluetooth.c b/src/modules/bluetooth/bluetooth.c index 0d669af44..078759831 100644 --- a/src/modules/bluetooth/bluetooth.c +++ b/src/modules/bluetooth/bluetooth.c @@ -19,7 +19,7 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de { if (buffer.length) ffStrbufAppendC(&buffer, ' '); - ffAppendPercentNum(&buffer, device->battery, 50, 20, buffer.length > 0); + ffPercentAppendNum(&buffer, device->battery, 50, 20, buffer.length > 0); } if (!device->connected) @@ -28,7 +28,7 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffAppendPercentNum(&percentageStr, device->battery, 50, 20, false); + ffPercentAppendNum(&percentageStr, device->battery, 50, 20, false); ffPrintFormat(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_BLUETOOTH_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, diff --git a/src/modules/brightness/brightness.c b/src/modules/brightness/brightness.c index 67074b07a..80ceb0cfd 100644 --- a/src/modules/brightness/brightness.c +++ b/src/modules/brightness/brightness.c @@ -52,7 +52,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, percent, 100, 100); + ffPercentAppendBar(&str, percent, 100, 100); } if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -60,7 +60,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffAppendPercentNum(&str, percent, 100, 100, str.length > 0); + ffPercentAppendNum(&str, percent, 100, 100, str.length > 0); } ffStrbufPutTo(&str, stdout); @@ -68,7 +68,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) else { FF_STRBUF_AUTO_DESTROY valueStr = ffStrbufCreate(); - ffAppendPercentNum(&valueStr, percent, 10, 10, false); + ffPercentAppendNum(&valueStr, percent, 10, 10, false); ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_BRIGHTNESS_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &valueStr}, {FF_FORMAT_ARG_TYPE_STRBUF, &item->name}, diff --git a/src/modules/cpuusage/cpuusage.c b/src/modules/cpuusage/cpuusage.c index 85797a213..ea1a0ffeb 100644 --- a/src/modules/cpuusage/cpuusage.c +++ b/src/modules/cpuusage/cpuusage.c @@ -52,12 +52,12 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) if (!options->separate) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) - ffAppendPercentBar(&str, avgValue, 50, 80); + ffPercentAppendBar(&str, avgValue, 50, 80); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) { if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffAppendPercentNum(&str, avgValue, 50, 80, str.length > 0); + ffPercentAppendNum(&str, avgValue, 50, 80, str.length > 0); } } else @@ -66,7 +66,7 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) { if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffAppendPercentNum(&str, *percent, 50, 80, false); + ffPercentAppendNum(&str, *percent, 50, 80, false); } } ffStrbufPutTo(&str, stdout); @@ -74,11 +74,11 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) else { FF_STRBUF_AUTO_DESTROY avgStr = ffStrbufCreate(); - ffAppendPercentNum(&avgStr, avgValue, 50, 80, false); + ffPercentAppendNum(&avgStr, avgValue, 50, 80, false); FF_STRBUF_AUTO_DESTROY minStr = ffStrbufCreate(); - ffAppendPercentNum(&minStr, minValue, 50, 80, false); + ffPercentAppendNum(&minStr, minValue, 50, 80, false); FF_STRBUF_AUTO_DESTROY maxStr = ffStrbufCreate(); - ffAppendPercentNum(&maxStr, maxValue, 50, 80, false); + ffPercentAppendNum(&maxStr, maxValue, 50, 80, false); ffPrintFormat(FF_CPUUSAGE_DISPLAY_NAME, 0, &options->moduleArgs, FF_CPUUSAGE_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &avgStr}, {FF_FORMAT_ARG_TYPE_STRBUF, &maxStr}, diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index 69cb6333a..3bf539359 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -59,7 +59,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, bytesPercentage, 50, 80); + ffPercentAppendBar(&str, bytesPercentage, 50, 80); ffStrbufAppendC(&str, ' '); } @@ -68,7 +68,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) { - ffAppendPercentNum(&str, bytesPercentage, 50, 80, str.length > 0); + ffPercentAppendNum(&str, bytesPercentage, 50, 80, str.length > 0); ffStrbufAppendC(&str, ' '); } } @@ -104,10 +104,10 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) else { FF_STRBUF_AUTO_DESTROY bytesPercentageStr = ffStrbufCreate(); - ffAppendPercentNum(&bytesPercentageStr, bytesPercentage, 50, 80, false); + ffPercentAppendNum(&bytesPercentageStr, bytesPercentage, 50, 80, false); FF_STRBUF_AUTO_DESTROY filesPercentageStr = ffStrbufCreate(); double filesPercentage = disk->filesTotal > 0 ? ((double) disk->filesUsed / (double) disk->filesTotal) * 100.0 : 0; - ffAppendPercentNum(&filesPercentageStr, filesPercentage, 50, 80, false); + ffPercentAppendNum(&filesPercentageStr, filesPercentage, 50, 80, false); bool isExternal = !!(disk->type & FF_DISK_VOLUME_TYPE_EXTERNAL_BIT); bool isHidden = !!(disk->type & FF_DISK_VOLUME_TYPE_HIDDEN_BIT); diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index 2e639b36f..34d79978d 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -19,14 +19,14 @@ static void printDevice(FFGamepadOptions* options, const FFGamepadDevice* device { if (buffer.length) ffStrbufAppendC(&buffer, ' '); - ffAppendPercentNum(&buffer, device->battery, 50, 20, buffer.length > 0); + ffPercentAppendNum(&buffer, device->battery, 50, 20, buffer.length > 0); } ffStrbufPutTo(&buffer, stdout); } else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffAppendPercentNum(&percentageStr, device->battery, 50, 20, false); + ffPercentAppendNum(&percentageStr, device->battery, 50, 20, false); ffPrintFormat(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_GAMEPAD_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, diff --git a/src/modules/gpu/gpu.c b/src/modules/gpu/gpu.c index 588c1c14c..dd19e8614 100644 --- a/src/modules/gpu/gpu.c +++ b/src/modules/gpu/gpu.c @@ -60,7 +60,7 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu if(gpu->dedicated.used != FF_GPU_VMEM_SIZE_UNSET) { ffStrbufAppendS(&output, ", "); - ffAppendPercentNum(&output, (double) gpu->dedicated.used / (double) gpu->dedicated.total * 100.0, 50, 80, false); + ffPercentAppendNum(&output, (double) gpu->dedicated.used / (double) gpu->dedicated.total * 100.0, 50, 80, false); } ffStrbufAppendC(&output, ')'); } diff --git a/src/modules/memory/memory.c b/src/modules/memory/memory.c index bccb12e9f..ac2eea94f 100644 --- a/src/modules/memory/memory.c +++ b/src/modules/memory/memory.c @@ -40,7 +40,7 @@ void ffPrintMemory(FFMemoryOptions* options) if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, percentage, 50, 80); + ffPercentAppendBar(&str, percentage, 50, 80); ffStrbufAppendC(&str, ' '); } @@ -48,7 +48,7 @@ void ffPrintMemory(FFMemoryOptions* options) ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) - ffAppendPercentNum(&str, percentage, 50, 80, str.length > 0); + ffPercentAppendNum(&str, percentage, 50, 80, str.length > 0); ffStrbufTrimRight(&str, ' '); ffStrbufPutTo(&str, stdout); @@ -57,7 +57,7 @@ void ffPrintMemory(FFMemoryOptions* options) else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffAppendPercentNum(&percentageStr, percentage, 50, 80, false); + ffPercentAppendNum(&percentageStr, percentage, 50, 80, false); ffPrintFormat(FF_MEMORY_MODULE_NAME, 0, &options->moduleArgs, FF_MEMORY_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &usedPretty}, {FF_FORMAT_ARG_TYPE_STRBUF, &totalPretty}, diff --git a/src/modules/sound/sound.c b/src/modules/sound/sound.c index 54ea63927..a7665865b 100644 --- a/src/modules/sound/sound.c +++ b/src/modules/sound/sound.c @@ -24,7 +24,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui if (str.length) ffStrbufAppendC(&str, ' '); - ffAppendPercentBar(&str, device->volume, 80, 90); + ffPercentAppendBar(&str, device->volume, 80, 90); } if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -32,7 +32,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui if (str.length) ffStrbufAppendC(&str, ' '); - ffAppendPercentNum(&str, device->volume, 80, 90, str.length > 0); + ffPercentAppendNum(&str, device->volume, 80, 90, str.length > 0); } } @@ -47,7 +47,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffAppendPercentNum(&percentageStr, device->volume, 80, 90, false); + ffPercentAppendNum(&percentageStr, device->volume, 80, 90, false); ffPrintFormat(FF_SOUND_MODULE_NAME, index, &options->moduleArgs, FF_SOUND_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_BOOL, &device->main}, diff --git a/src/modules/swap/swap.c b/src/modules/swap/swap.c index 2635c8d00..cfc1e36cb 100644 --- a/src/modules/swap/swap.c +++ b/src/modules/swap/swap.c @@ -37,19 +37,19 @@ void ffPrintSwap(FFSwapOptions* options) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, 0, 50, 80); + ffPercentAppendBar(&str, 0, 50, 80); ffStrbufAppendC(&str, ' '); } if(!(instance.config.display.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) ffStrbufAppendS(&str, "Disabled"); else - ffAppendPercentNum(&str, 0, 50, 80, str.length > 0); + ffPercentAppendNum(&str, 0, 50, 80, str.length > 0); } else { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffAppendPercentBar(&str, percentage, 50, 80); + ffPercentAppendBar(&str, percentage, 50, 80); ffStrbufAppendC(&str, ' '); } @@ -57,7 +57,7 @@ void ffPrintSwap(FFSwapOptions* options) ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) - ffAppendPercentNum(&str, percentage, 50, 80, str.length > 0); + ffPercentAppendNum(&str, percentage, 50, 80, str.length > 0); } ffStrbufTrimRight(&str, ' '); @@ -66,7 +66,7 @@ void ffPrintSwap(FFSwapOptions* options) else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffAppendPercentNum(&percentageStr, percentage, 50, 80, false); + ffPercentAppendNum(&percentageStr, percentage, 50, 80, false); ffPrintFormat(FF_SWAP_MODULE_NAME, 0, &options->moduleArgs, FF_SWAP_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &usedPretty}, {FF_FORMAT_ARG_TYPE_STRBUF, &totalPretty}, From 62ca4951554783a4371938cbed20326ad558bfe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 14:10:13 +0800 Subject: [PATCH 29/36] Percentage: prepare to make threshold configurable --- src/common/percent.c | 6 ++++-- src/common/percent.h | 12 +++++++++--- src/modules/battery/battery.c | 7 ++++--- src/modules/battery/option.h | 2 ++ src/modules/bluetooth/bluetooth.c | 5 +++-- src/modules/bluetooth/option.h | 2 ++ src/modules/brightness/brightness.c | 7 ++++--- src/modules/brightness/option.h | 2 ++ src/modules/cpuusage/cpuusage.c | 13 +++++++------ src/modules/cpuusage/option.h | 2 ++ src/modules/disk/disk.c | 9 +++++---- src/modules/disk/option.h | 2 ++ src/modules/gamepad/gamepad.c | 7 ++++--- src/modules/gamepad/option.h | 2 ++ src/modules/gpu/gpu.c | 3 ++- src/modules/gpu/option.h | 2 ++ src/modules/memory/memory.c | 7 ++++--- src/modules/memory/option.h | 3 +++ src/modules/sound/option.h | 2 ++ src/modules/sound/sound.c | 7 ++++--- src/modules/swap/option.h | 3 +++ src/modules/swap/swap.c | 11 ++++++----- 22 files changed, 78 insertions(+), 38 deletions(-) diff --git a/src/common/percent.c b/src/common/percent.c index 766f610f7..0dff8b169 100644 --- a/src/common/percent.c +++ b/src/common/percent.c @@ -3,8 +3,9 @@ #include "common/color.h" #include "util/textModifier.h" -void ffPercentAppendBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow) +void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentConfig config) { + uint8_t green = config.green, yellow = config.yellow; assert(green <= 100 && yellow <= 100); const FFOptionsDisplay* options = &instance.config.display; @@ -56,8 +57,9 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); } -void ffPercentAppendNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses) +void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentConfig config, bool parentheses) { + uint8_t green = config.green, yellow = config.yellow; assert(green <= 100 && yellow <= 100); const FFOptionsDisplay* options = &instance.config.display; diff --git a/src/common/percent.h b/src/common/percent.h index f97fcb1c8..190c8a374 100644 --- a/src/common/percent.h +++ b/src/common/percent.h @@ -1,6 +1,6 @@ #pragma once -#include "fastfetch.h" +#include "util/FFstrbuf.h" enum { @@ -10,6 +10,12 @@ enum FF_PERCENTAGE_TYPE_NUM_COLOR_BIT = 1 << 3, }; +typedef struct FFPercentConfig +{ + uint8_t green; + uint8_t yellow; +} FFPercentConfig; + // if (green <= yellow) // [0, green]: print green // (green, yellow]: print yellow @@ -20,5 +26,5 @@ enum // [yellow, green): print yellow // [0, yellow): print red -void ffPercentAppendBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow); -void ffPercentAppendNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses); +void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentConfig config); +void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentConfig config, bool parentheses); diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index b811bdb3e..d667ea846 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -24,7 +24,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, result->capacity, 50, 20); + ffPercentAppendBar(&str, result->capacity, options->percent); } if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -32,7 +32,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, result->capacity, 50, 20, str.length > 0); + ffPercentAppendNum(&str, result->capacity, options->percent, str.length > 0); } } @@ -57,7 +57,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin else { FF_STRBUF_AUTO_DESTROY capacityStr = ffStrbufCreate(); - ffPercentAppendNum(&capacityStr, result->capacity, 51, 21, false); + ffPercentAppendNum(&capacityStr, result->capacity, options->percent, false); ffPrintFormat(FF_BATTERY_MODULE_NAME, index, &options->moduleArgs, FF_BATTERY_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName}, @@ -240,6 +240,7 @@ void ffInitBatteryOptions(FFBatteryOptions* options) ); ffOptionInitModuleArg(&options->moduleArgs); options->temp = false; + options->percent = (FFPercentConfig) { 50, 20 }; #ifdef _WIN32 options->useSetupApi = false; diff --git a/src/modules/battery/option.h b/src/modules/battery/option.h index 401816ae7..c03537a37 100644 --- a/src/modules/battery/option.h +++ b/src/modules/battery/option.h @@ -3,6 +3,7 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef struct FFBatteryOptions { @@ -10,6 +11,7 @@ typedef struct FFBatteryOptions FFModuleArgs moduleArgs; bool temp; + FFPercentConfig percent; #ifdef _WIN32 bool useSetupApi; diff --git a/src/modules/bluetooth/bluetooth.c b/src/modules/bluetooth/bluetooth.c index 078759831..cd0692746 100644 --- a/src/modules/bluetooth/bluetooth.c +++ b/src/modules/bluetooth/bluetooth.c @@ -19,7 +19,7 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de { if (buffer.length) ffStrbufAppendC(&buffer, ' '); - ffPercentAppendNum(&buffer, device->battery, 50, 20, buffer.length > 0); + ffPercentAppendNum(&buffer, device->battery, options->percent, buffer.length > 0); } if (!device->connected) @@ -28,7 +28,7 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, device->battery, 50, 20, false); + ffPercentAppendNum(&percentageStr, device->battery, options->percent, false); ffPrintFormat(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_BLUETOOTH_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, @@ -188,6 +188,7 @@ void ffInitBluetoothOptions(FFBluetoothOptions* options) ); ffOptionInitModuleArg(&options->moduleArgs); options->showDisconnected = false; + options->percent = (FFPercentConfig) { 50, 20 }; } void ffDestroyBluetoothOptions(FFBluetoothOptions* options) diff --git a/src/modules/bluetooth/option.h b/src/modules/bluetooth/option.h index bbe9e1c54..bab9cce67 100644 --- a/src/modules/bluetooth/option.h +++ b/src/modules/bluetooth/option.h @@ -3,6 +3,7 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef struct FFBluetoothOptions { @@ -10,4 +11,5 @@ typedef struct FFBluetoothOptions FFModuleArgs moduleArgs; bool showDisconnected; + FFPercentConfig percent; } FFBluetoothOptions; diff --git a/src/modules/brightness/brightness.c b/src/modules/brightness/brightness.c index 80ceb0cfd..4dd295a36 100644 --- a/src/modules/brightness/brightness.c +++ b/src/modules/brightness/brightness.c @@ -52,7 +52,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, percent, 100, 100); + ffPercentAppendBar(&str, percent, options->percent); } if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -60,7 +60,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, percent, 100, 100, str.length > 0); + ffPercentAppendNum(&str, percent, options->percent, str.length > 0); } ffStrbufPutTo(&str, stdout); @@ -68,7 +68,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) else { FF_STRBUF_AUTO_DESTROY valueStr = ffStrbufCreate(); - ffPercentAppendNum(&valueStr, percent, 10, 10, false); + ffPercentAppendNum(&valueStr, percent, options->percent, false); ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_BRIGHTNESS_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &valueStr}, {FF_FORMAT_ARG_TYPE_STRBUF, &item->name}, @@ -197,6 +197,7 @@ void ffInitBrightnessOptions(FFBrightnessOptions* options) ffOptionInitModuleArg(&options->moduleArgs); options->ddcciSleep = 10; + options->percent = (FFPercentConfig) { 100, 100 }; } void ffDestroyBrightnessOptions(FFBrightnessOptions* options) diff --git a/src/modules/brightness/option.h b/src/modules/brightness/option.h index cad3e7ac8..89d08a8ed 100644 --- a/src/modules/brightness/option.h +++ b/src/modules/brightness/option.h @@ -3,6 +3,7 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef struct FFBrightnessOptions { @@ -10,4 +11,5 @@ typedef struct FFBrightnessOptions FFModuleArgs moduleArgs; uint32_t ddcciSleep; // ms + FFPercentConfig percent; } FFBrightnessOptions; diff --git a/src/modules/cpuusage/cpuusage.c b/src/modules/cpuusage/cpuusage.c index ea1a0ffeb..38738fabb 100644 --- a/src/modules/cpuusage/cpuusage.c +++ b/src/modules/cpuusage/cpuusage.c @@ -52,12 +52,12 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) if (!options->separate) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) - ffPercentAppendBar(&str, avgValue, 50, 80); + ffPercentAppendBar(&str, avgValue, options->percent); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) { if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, avgValue, 50, 80, str.length > 0); + ffPercentAppendNum(&str, avgValue, options->percent, str.length > 0); } } else @@ -66,7 +66,7 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) { if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, *percent, 50, 80, false); + ffPercentAppendNum(&str, *percent, options->percent, false); } } ffStrbufPutTo(&str, stdout); @@ -74,11 +74,11 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) else { FF_STRBUF_AUTO_DESTROY avgStr = ffStrbufCreate(); - ffPercentAppendNum(&avgStr, avgValue, 50, 80, false); + ffPercentAppendNum(&avgStr, avgValue, options->percent, false); FF_STRBUF_AUTO_DESTROY minStr = ffStrbufCreate(); - ffPercentAppendNum(&minStr, minValue, 50, 80, false); + ffPercentAppendNum(&minStr, minValue, options->percent, false); FF_STRBUF_AUTO_DESTROY maxStr = ffStrbufCreate(); - ffPercentAppendNum(&maxStr, maxValue, 50, 80, false); + ffPercentAppendNum(&maxStr, maxValue, options->percent, false); ffPrintFormat(FF_CPUUSAGE_DISPLAY_NAME, 0, &options->moduleArgs, FF_CPUUSAGE_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &avgStr}, {FF_FORMAT_ARG_TYPE_STRBUF, &maxStr}, @@ -182,6 +182,7 @@ void ffInitCPUUsageOptions(FFCPUUsageOptions* options) ); ffOptionInitModuleArg(&options->moduleArgs); options->separate = false; + options->percent = (FFPercentConfig) { 50, 80 }; } void ffDestroyCPUUsageOptions(FFCPUUsageOptions* options) diff --git a/src/modules/cpuusage/option.h b/src/modules/cpuusage/option.h index d7fea247d..380fc9b56 100644 --- a/src/modules/cpuusage/option.h +++ b/src/modules/cpuusage/option.h @@ -3,6 +3,7 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef struct FFCPUUsageOptions { @@ -10,4 +11,5 @@ typedef struct FFCPUUsageOptions FFModuleArgs moduleArgs; bool separate; + FFPercentConfig percent; } FFCPUUsageOptions; diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index 3bf539359..fae7e3501 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -59,7 +59,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, bytesPercentage, 50, 80); + ffPercentAppendBar(&str, bytesPercentage, options->percent); ffStrbufAppendC(&str, ' '); } @@ -68,7 +68,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) { - ffPercentAppendNum(&str, bytesPercentage, 50, 80, str.length > 0); + ffPercentAppendNum(&str, bytesPercentage, options->percent, str.length > 0); ffStrbufAppendC(&str, ' '); } } @@ -104,10 +104,10 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) else { FF_STRBUF_AUTO_DESTROY bytesPercentageStr = ffStrbufCreate(); - ffPercentAppendNum(&bytesPercentageStr, bytesPercentage, 50, 80, false); + ffPercentAppendNum(&bytesPercentageStr, bytesPercentage, options->percent, false); FF_STRBUF_AUTO_DESTROY filesPercentageStr = ffStrbufCreate(); double filesPercentage = disk->filesTotal > 0 ? ((double) disk->filesUsed / (double) disk->filesTotal) * 100.0 : 0; - ffPercentAppendNum(&filesPercentageStr, filesPercentage, 50, 80, false); + ffPercentAppendNum(&filesPercentageStr, filesPercentage, options->percent, false); bool isExternal = !!(disk->type & FF_DISK_VOLUME_TYPE_EXTERNAL_BIT); bool isHidden = !!(disk->type & FF_DISK_VOLUME_TYPE_HIDDEN_BIT); @@ -476,6 +476,7 @@ void ffInitDiskOptions(FFDiskOptions* options) ffStrbufInit(&options->folders); options->showTypes = FF_DISK_VOLUME_TYPE_REGULAR_BIT | FF_DISK_VOLUME_TYPE_EXTERNAL_BIT | FF_DISK_VOLUME_TYPE_READONLY_BIT; options->calcType = FF_DISK_CALC_TYPE_FREE; + options->percent = (FFPercentConfig) { 50, 80 }; } void ffDestroyDiskOptions(FFDiskOptions* options) diff --git a/src/modules/disk/option.h b/src/modules/disk/option.h index 9b727e542..a02505d5e 100644 --- a/src/modules/disk/option.h +++ b/src/modules/disk/option.h @@ -3,6 +3,7 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef enum FFDiskVolumeType { @@ -29,4 +30,5 @@ typedef struct FFDiskOptions FFstrbuf folders; FFDiskVolumeType showTypes; FFDiskCalcType calcType; + FFPercentConfig percent; } FFDiskOptions; diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index 34d79978d..76de33845 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -19,14 +19,14 @@ static void printDevice(FFGamepadOptions* options, const FFGamepadDevice* device { if (buffer.length) ffStrbufAppendC(&buffer, ' '); - ffPercentAppendNum(&buffer, device->battery, 50, 20, buffer.length > 0); + ffPercentAppendNum(&buffer, device->battery, options->percent, buffer.length > 0); } ffStrbufPutTo(&buffer, stdout); } else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, device->battery, 50, 20, false); + ffPercentAppendNum(&percentageStr, device->battery, options->percent, false); ffPrintFormat(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_GAMEPAD_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, @@ -133,7 +133,7 @@ void ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjs void ffPrintGamepadHelpFormat(void) { - ffPrintModuleFormatHelp(FF_GAMEPAD_MODULE_NAME, "{1}", FF_GAMEPAD_NUM_FORMAT_ARGS, (const char* []) { + ffPrintModuleFormatHelp(FF_GAMEPAD_MODULE_NAME, "{1} ({3})", FF_GAMEPAD_NUM_FORMAT_ARGS, (const char* []) { "Name", "Serial number", "Battery percentage", @@ -154,6 +154,7 @@ void ffInitGamepadOptions(FFGamepadOptions* options) ffGenerateGamepadJsonConfig ); ffOptionInitModuleArg(&options->moduleArgs); + options->percent = (FFPercentConfig) { 50, 20 }; } void ffDestroyGamepadOptions(FFGamepadOptions* options) diff --git a/src/modules/gamepad/option.h b/src/modules/gamepad/option.h index f455b3a42..bc49128e8 100644 --- a/src/modules/gamepad/option.h +++ b/src/modules/gamepad/option.h @@ -8,4 +8,6 @@ typedef struct FFGamepadOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; + + FFPercentConfig percent; } FFGamepadOptions; diff --git a/src/modules/gpu/gpu.c b/src/modules/gpu/gpu.c index dd19e8614..f1b348d18 100644 --- a/src/modules/gpu/gpu.c +++ b/src/modules/gpu/gpu.c @@ -60,7 +60,7 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu if(gpu->dedicated.used != FF_GPU_VMEM_SIZE_UNSET) { ffStrbufAppendS(&output, ", "); - ffPercentAppendNum(&output, (double) gpu->dedicated.used / (double) gpu->dedicated.total * 100.0, 50, 80, false); + ffPercentAppendNum(&output, (double) gpu->dedicated.used / (double) gpu->dedicated.total * 100.0, options->percent, false); } ffStrbufAppendC(&output, ')'); } @@ -363,6 +363,7 @@ void ffInitGPUOptions(FFGPUOptions* options) options->forceVulkan = false; options->temp = false; options->hideType = FF_GPU_TYPE_UNKNOWN; + options->percent = (FFPercentConfig) { 50, 80 }; } void ffDestroyGPUOptions(FFGPUOptions* options) diff --git a/src/modules/gpu/option.h b/src/modules/gpu/option.h index 77babf437..e251f834e 100644 --- a/src/modules/gpu/option.h +++ b/src/modules/gpu/option.h @@ -3,6 +3,7 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef enum FFGPUType { @@ -20,4 +21,5 @@ typedef struct FFGPUOptions bool temp; bool driverSpecific; bool forceVulkan; + FFPercentConfig percent; } FFGPUOptions; diff --git a/src/modules/memory/memory.c b/src/modules/memory/memory.c index ac2eea94f..c71ca9167 100644 --- a/src/modules/memory/memory.c +++ b/src/modules/memory/memory.c @@ -40,7 +40,7 @@ void ffPrintMemory(FFMemoryOptions* options) if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, percentage, 50, 80); + ffPercentAppendBar(&str, percentage, options->percent); ffStrbufAppendC(&str, ' '); } @@ -48,7 +48,7 @@ void ffPrintMemory(FFMemoryOptions* options) ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) - ffPercentAppendNum(&str, percentage, 50, 80, str.length > 0); + ffPercentAppendNum(&str, percentage, options->percent, str.length > 0); ffStrbufTrimRight(&str, ' '); ffStrbufPutTo(&str, stdout); @@ -57,7 +57,7 @@ void ffPrintMemory(FFMemoryOptions* options) else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, percentage, 50, 80, false); + ffPercentAppendNum(&percentageStr, percentage, options->percent, false); ffPrintFormat(FF_MEMORY_MODULE_NAME, 0, &options->moduleArgs, FF_MEMORY_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &usedPretty}, {FF_FORMAT_ARG_TYPE_STRBUF, &totalPretty}, @@ -140,6 +140,7 @@ void ffInitMemoryOptions(FFMemoryOptions* options) ffGenerateMemoryJsonConfig ); ffOptionInitModuleArg(&options->moduleArgs); + options->percent = (FFPercentConfig) { 50, 80 }; } void ffDestroyMemoryOptions(FFMemoryOptions* options) diff --git a/src/modules/memory/option.h b/src/modules/memory/option.h index b908943e4..a63153264 100644 --- a/src/modules/memory/option.h +++ b/src/modules/memory/option.h @@ -3,9 +3,12 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef struct FFMemoryOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; + + FFPercentConfig percent; } FFMemoryOptions; diff --git a/src/modules/sound/option.h b/src/modules/sound/option.h index 11f652602..dae67bb49 100644 --- a/src/modules/sound/option.h +++ b/src/modules/sound/option.h @@ -3,6 +3,7 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef enum FFSoundType { @@ -17,4 +18,5 @@ typedef struct FFSoundOptions FFModuleArgs moduleArgs; FFSoundType soundType; + FFPercentConfig percent; } FFSoundOptions; diff --git a/src/modules/sound/sound.c b/src/modules/sound/sound.c index a7665865b..d7fbebf99 100644 --- a/src/modules/sound/sound.c +++ b/src/modules/sound/sound.c @@ -24,7 +24,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui if (str.length) ffStrbufAppendC(&str, ' '); - ffPercentAppendBar(&str, device->volume, 80, 90); + ffPercentAppendBar(&str, device->volume, options->percent); } if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -32,7 +32,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui if (str.length) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, device->volume, 80, 90, str.length > 0); + ffPercentAppendNum(&str, device->volume, options->percent, str.length > 0); } } @@ -47,7 +47,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, device->volume, 80, 90, false); + ffPercentAppendNum(&percentageStr, device->volume, options->percent, false); ffPrintFormat(FF_SOUND_MODULE_NAME, index, &options->moduleArgs, FF_SOUND_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_BOOL, &device->main}, @@ -247,6 +247,7 @@ void ffInitSoundOptions(FFSoundOptions* options) ffOptionInitModuleArg(&options->moduleArgs); options->soundType = FF_SOUND_TYPE_MAIN; + options->percent = (FFPercentConfig) { 80, 90 }; } void ffDestroySoundOptions(FFSoundOptions* options) diff --git a/src/modules/swap/option.h b/src/modules/swap/option.h index 52fea1733..6940a39e1 100644 --- a/src/modules/swap/option.h +++ b/src/modules/swap/option.h @@ -3,9 +3,12 @@ // This file will be included in "fastfetch.h", do NOT put unnecessary things here #include "common/option.h" +#include "common/percent.h" typedef struct FFSwapOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; + + FFPercentConfig percent; } FFSwapOptions; diff --git a/src/modules/swap/swap.c b/src/modules/swap/swap.c index cfc1e36cb..b4103bf6b 100644 --- a/src/modules/swap/swap.c +++ b/src/modules/swap/swap.c @@ -37,19 +37,19 @@ void ffPrintSwap(FFSwapOptions* options) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, 0, 50, 80); + ffPercentAppendBar(&str, 0, options->percent); ffStrbufAppendC(&str, ' '); } if(!(instance.config.display.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) ffStrbufAppendS(&str, "Disabled"); else - ffPercentAppendNum(&str, 0, 50, 80, str.length > 0); + ffPercentAppendNum(&str, 0, options->percent, str.length > 0); } else { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, percentage, 50, 80); + ffPercentAppendBar(&str, percentage, options->percent); ffStrbufAppendC(&str, ' '); } @@ -57,7 +57,7 @@ void ffPrintSwap(FFSwapOptions* options) ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) - ffPercentAppendNum(&str, percentage, 50, 80, str.length > 0); + ffPercentAppendNum(&str, percentage, options->percent, str.length > 0); } ffStrbufTrimRight(&str, ' '); @@ -66,7 +66,7 @@ void ffPrintSwap(FFSwapOptions* options) else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, percentage, 50, 80, false); + ffPercentAppendNum(&percentageStr, percentage, options->percent, false); ffPrintFormat(FF_SWAP_MODULE_NAME, 0, &options->moduleArgs, FF_SWAP_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &usedPretty}, {FF_FORMAT_ARG_TYPE_STRBUF, &totalPretty}, @@ -149,6 +149,7 @@ void ffInitSwapOptions(FFSwapOptions* options) ffGenerateSwapJsonConfig ); ffOptionInitModuleArg(&options->moduleArgs); + options->percent = (FFPercentConfig) { 50, 80 }; } void ffDestroySwapOptions(FFSwapOptions* options) From d1a791b333faf41a15ce4e2132288baa2994451e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 18:40:12 +0800 Subject: [PATCH 30/36] Global: make threshold of percentage colors configurable Fix #689 --- doc/json_schema.json | 123 +++++++++++++++++++++++++--- src/common/percent.c | 87 ++++++++++++++++++++ src/common/percent.h | 7 ++ src/data/help.json | 23 ++++++ src/modules/battery/battery.c | 8 ++ src/modules/bluetooth/bluetooth.c | 8 ++ src/modules/brightness/brightness.c | 8 ++ src/modules/cpuusage/cpuusage.c | 8 ++ src/modules/disk/disk.c | 8 ++ src/modules/gamepad/gamepad.c | 8 ++ src/modules/gpu/gpu.c | 8 ++ src/modules/memory/memory.c | 8 ++ src/modules/sound/sound.c | 8 ++ src/modules/swap/swap.c | 8 ++ 14 files changed, 308 insertions(+), 12 deletions(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index ce00756da..884fd4c2e 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -26,6 +26,24 @@ "format": { "description": "Output format of the module", "type": "string" + }, + "percent": { + "description": "Threshold of percentage colors", + "type": "object", + "properties": { + "green": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "description": "Value less then green will be shown in green" + }, + "yellow": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "description": "Value greater than green and less then yellow will be shown in yellow.\nValue greater than yellow will be shown in red" + } + } } }, "type": "object", @@ -672,10 +690,6 @@ "const": "font", "description": "Print system font name" }, - { - "const": "gamepad", - "description": "List connected gamepads" - }, { "const": "host", "description": "Print product name of your computer" @@ -700,10 +714,6 @@ "const": "media", "description": "Print playing song name" }, - { - "const": "memory", - "description": "Print system memory usage info" - }, { "const": "monitor", "description": "Print connected physical monitor information" @@ -732,10 +742,6 @@ "const": "shell", "description": "Print current shell name and version" }, - { - "const": "swap", - "description": "Print swap (paging file) space usage" - }, { "const": "terminal", "description": "Print current terminal name and version" @@ -814,6 +820,9 @@ "type": "boolean", "default": false }, + "percent": { + "$ref": "#/$defs/percent" + }, "key": { "$ref": "#/$defs/key" }, @@ -841,6 +850,9 @@ "type": "boolean", "default": false }, + "percent": { + "$ref": "#/$defs/percent" + }, "key": { "$ref": "#/$defs/key" }, @@ -863,6 +875,9 @@ "const": "brightness", "description": "Print current brightness level of your monitors" }, + "percent": { + "$ref": "#/$defs/percent" + }, "ddcciSleep": { "type": "integer", "description": "Set the sleep times (in ms) when sending DDC/CI requests.\nSee for detail", @@ -934,6 +949,9 @@ "const": "cpuusage", "description": "Print CPU usage. Costs some time to collect data" }, + "percent": { + "$ref": "#/$defs/percent" + }, "separate": { "type": "boolean", "description": "Display CPU usage per CPU logical core, instead of an average result", @@ -1103,6 +1121,9 @@ "description": "Use f_bavail (lpFreeBytesAvailableToCaller for Windows) instead of f_bfree to calculate used bytes", "default": false }, + "percent": { + "$ref": "#/$defs/percent" + }, "key": { "$ref": "#/$defs/key" }, @@ -1170,6 +1191,31 @@ } } }, + { + "title": "Gamepad", + "properties": { + "type": { + "const": "gamepad", + "description": "List connected gamepads" + }, + "percent": { + "$ref": "#/$defs/percent" + }, + "key": { + "$ref": "#/$defs/key" + }, + "keyColor": { + "$ref": "#/$defs/keyColor" + }, + "keyWidth": { + "$ref": "#/$defs/keyWidth" + }, + "format": { + "$ref": "#/$defs/format" + } + }, + "additionalProperties": false + }, { "title": "GPU", "properties": { @@ -1272,6 +1318,31 @@ }, "additionalProperties": false }, + { + "title": "Memory", + "properties": { + "type": { + "const": "memory", + "description": "Print system memory usage info" + }, + "percent": { + "$ref": "#/$defs/percent" + }, + "key": { + "$ref": "#/$defs/key" + }, + "keyColor": { + "$ref": "#/$defs/keyColor" + }, + "keyWidth": { + "$ref": "#/$defs/keyWidth" + }, + "format": { + "$ref": "#/$defs/format" + } + }, + "additionalProperties": false + }, { "title": "NetIO", "properties": { @@ -1458,6 +1529,34 @@ ], "default": "main" }, + "percent": { + "$ref": "#/$defs/percent" + }, + "key": { + "$ref": "#/$defs/key" + }, + "keyColor": { + "$ref": "#/$defs/keyColor" + }, + "keyWidth": { + "$ref": "#/$defs/keyWidth" + }, + "format": { + "$ref": "#/$defs/format" + } + }, + "additionalProperties": false + }, + { + "title": "Swap", + "properties": { + "type": { + "const": "swap", + "description": "Print swap (paging file) space usage" + }, + "percent": { + "$ref": "#/$defs/percent" + }, "key": { "$ref": "#/$defs/key" }, diff --git a/src/common/percent.c b/src/common/percent.c index 0dff8b169..0b154e744 100644 --- a/src/common/percent.c +++ b/src/common/percent.c @@ -1,7 +1,10 @@ #include "fastfetch.h" #include "common/percent.h" #include "common/color.h" +#include "common/option.h" +#include "common/jsonconfig.h" #include "util/textModifier.h" +#include "util/stringUtils.h" void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentConfig config) { @@ -103,3 +106,87 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentConfig config if (parentheses) ffStrbufAppendC(buffer, ')'); } + +bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentConfig* config) +{ + if (!ffStrStartsWithIgnCase(subkey, "percent-")) + return false; + + subkey += strlen("percent-"); + + if (ffStrEqualsIgnCase(subkey, "green")) + { + uint32_t num = ffOptionParseUInt32(key, value); + if (num > 100) + { + fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key); + exit(480); + } + config->green = (uint8_t) num; + return true; + } + + if (ffStrEqualsIgnCase(subkey, "yellow")) + { + uint32_t num = ffOptionParseUInt32(key, value); + if (num > 100) + { + fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key); + exit(480); + } + config->yellow = (uint8_t) num; + return true; + } + + return false; +} + +bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentConfig* config) +{ + if (!ffStrEqualsIgnCase(key, "percent")) + return false; + + if (!yyjson_is_obj(value)) + { + fprintf(stderr, "Error: usage: %s must be an object\n", key); + exit(480); + } + + yyjson_val* greenVal = yyjson_obj_get(value, "green"); + if (greenVal) + { + int num = yyjson_get_int(greenVal); + if (num < 0 || num > 100) + { + fputs("Error: usage: percent.green must be between 0 and 100\n", stderr); + exit(480); + } + config->green = (uint8_t) num; + } + + yyjson_val* yellowVal = yyjson_obj_get(value, "yellow"); + if (yellowVal) + { + int num = yyjson_get_int(yellowVal); + if (num < 0 || num > 100) + { + fputs("Error: usage: percent.yellow must be between 0 and 100\n", stderr); + exit(480); + } + config->yellow = (uint8_t) num; + } + + return true; +} + +void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentConfig defaultConfig, FFPercentConfig config) +{ + if (config.green == defaultConfig.green && config.yellow == defaultConfig.yellow) + return; + + yyjson_mut_val* percent = yyjson_mut_obj_add_obj(doc, module, "percent"); + if (config.green != defaultConfig.green) + yyjson_mut_obj_add_uint(doc, percent, "green", config.green); + if (config.yellow != defaultConfig.yellow) + yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow); +} diff --git a/src/common/percent.h b/src/common/percent.h index 190c8a374..e3e83b4a4 100644 --- a/src/common/percent.h +++ b/src/common/percent.h @@ -28,3 +28,10 @@ typedef struct FFPercentConfig void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentConfig config); void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentConfig config, bool parentheses); + +typedef struct yyjson_val yyjson_val; +typedef struct yyjson_mut_doc yyjson_mut_doc; +typedef struct yyjson_mut_val yyjson_mut_val; +bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentConfig* config); +bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentConfig* config); +void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentConfig defaultConfig, FFPercentConfig config); diff --git a/src/data/help.json b/src/data/help.json index d3da78a82..c22c42ef5 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1351,6 +1351,29 @@ "type": "num" }, "pseudo": true + }, + { + "long": "-percent-green", + "desc": [ + "Threshold of percentage colors", + "Value less then percent-green will be shown in green" + ], + "arg": { + "type": "num" + }, + "pseudo": true + }, + { + "long": "-percent-yellow", + "desc": [ + "Threshold of percentage colors", + "Value greater than percent-green and less then yellow will be shown in yellow", + "Value greater than percent-yellow will be shown in red" + ], + "arg": { + "type": "num" + }, + "pseudo": true } ] } diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index d667ea846..a97dd263b 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -122,6 +122,9 @@ bool ffParseBatteryCommandOptions(FFBatteryOptions* options, const char* key, co } #endif + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -152,6 +155,9 @@ void ffParseBatteryJsonObject(FFBatteryOptions* options, yyjson_val* module) continue; } + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -170,6 +176,8 @@ void ffGenerateBatteryJsonConfig(FFBatteryOptions* options, yyjson_mut_doc* doc, if (options->temp != defaultOptions.temp) yyjson_mut_obj_add_bool(doc, module, "temp", options->temp); + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/bluetooth/bluetooth.c b/src/modules/bluetooth/bluetooth.c index cd0692746..20bb9707c 100644 --- a/src/modules/bluetooth/bluetooth.c +++ b/src/modules/bluetooth/bluetooth.c @@ -93,6 +93,9 @@ bool ffParseBluetoothCommandOptions(FFBluetoothOptions* options, const char* key return true; } + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -115,6 +118,9 @@ void ffParseBluetoothJsonObject(FFBluetoothOptions* options, yyjson_val* module) continue; } + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_BLUETOOTH_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -128,6 +134,8 @@ void ffGenerateBluetoothJsonConfig(FFBluetoothOptions* options, yyjson_mut_doc* if (options->showDisconnected != defaultOptions.showDisconnected) yyjson_mut_obj_add_bool(doc, module, "showDisconnected", options->showDisconnected); + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateBluetoothJsonResult(FF_MAYBE_UNUSED FFBluetoothOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/brightness/brightness.c b/src/modules/brightness/brightness.c index 4dd295a36..49283474f 100644 --- a/src/modules/brightness/brightness.c +++ b/src/modules/brightness/brightness.c @@ -97,6 +97,9 @@ bool ffParseBrightnessCommandOptions(FFBrightnessOptions* options, const char* k return true; } + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -119,6 +122,9 @@ void ffParseBrightnessJsonObject(FFBrightnessOptions* options, yyjson_val* modul continue; } + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_BRIGHTNESS_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -132,6 +138,8 @@ void ffGenerateBrightnessJsonConfig(FFBrightnessOptions* options, yyjson_mut_doc if (defaultOptions.ddcciSleep != options->ddcciSleep) yyjson_mut_obj_add_uint(doc, module, "ddcciSleep", options->ddcciSleep); + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateBrightnessJsonResult(FF_MAYBE_UNUSED FFBrightnessOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/cpuusage/cpuusage.c b/src/modules/cpuusage/cpuusage.c index 38738fabb..e8787dd33 100644 --- a/src/modules/cpuusage/cpuusage.c +++ b/src/modules/cpuusage/cpuusage.c @@ -102,6 +102,9 @@ bool ffParseCPUUsageCommandOptions(FFCPUUsageOptions* options, const char* key, return true; } + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -124,6 +127,9 @@ void ffParseCPUUsageJsonObject(FFCPUUsageOptions* options, yyjson_val* module) continue; } + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_CPUUSAGE_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -137,6 +143,8 @@ void ffGenerateCPUUsageJsonConfig(FFCPUUsageOptions* options, yyjson_mut_doc* do if (options->separate != defaultOptions.separate) yyjson_mut_obj_add_bool(doc, module, "separate", options->separate); + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateCPUUsageJsonResult(FF_MAYBE_UNUSED FFCPUUsageOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index fae7e3501..a874cc892 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -278,6 +278,9 @@ bool ffParseDiskCommandOptions(FFDiskOptions* options, const char* key, const ch return true; } + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -354,6 +357,9 @@ void ffParseDiskJsonObject(FFDiskOptions* options, yyjson_val* module) continue; } + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_DISK_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -388,6 +394,8 @@ void ffGenerateDiskJsonConfig(FFDiskOptions* options, yyjson_mut_doc* doc, yyjso if (defaultOptions.calcType != options->calcType) yyjson_mut_obj_add_bool(doc, module, "useAvailable", options->calcType == FF_DISK_CALC_TYPE_AVAILABLE); + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateDiskJsonResult(FFDiskOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index 76de33845..2c5341333 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -70,6 +70,9 @@ bool ffParseGamepadCommandOptions(FFGamepadOptions* options, const char* key, co if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -86,6 +89,9 @@ void ffParseGamepadJsonObject(FFGamepadOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_GAMEPAD_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -96,6 +102,8 @@ void ffGenerateGamepadJsonConfig(FFGamepadOptions* options, yyjson_mut_doc* doc, ffInitGamepadOptions(&defaultOptions); ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/gpu/gpu.c b/src/modules/gpu/gpu.c index f1b348d18..b8c3118a4 100644 --- a/src/modules/gpu/gpu.c +++ b/src/modules/gpu/gpu.c @@ -162,6 +162,9 @@ bool ffParseGPUCommandOptions(FFGPUOptions* options, const char* key, const char }); } + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -212,6 +215,9 @@ void ffParseGPUJsonObject(FFGPUOptions* options, yyjson_val* module) continue; } + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_GPU_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -247,6 +253,8 @@ void ffGenerateGPUJsonConfig(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_ break; } } + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateGPUJsonResult(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/memory/memory.c b/src/modules/memory/memory.c index c71ca9167..485b62130 100644 --- a/src/modules/memory/memory.c +++ b/src/modules/memory/memory.c @@ -73,6 +73,9 @@ bool ffParseMemoryCommandOptions(FFMemoryOptions* options, const char* key, cons if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -89,6 +92,9 @@ void ffParseMemoryJsonObject(FFMemoryOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_MEMORY_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -99,6 +105,8 @@ void ffGenerateMemoryJsonConfig(FFMemoryOptions* options, yyjson_mut_doc* doc, y ffInitMemoryOptions(&defaultOptions); ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateMemoryJsonResult(FF_MAYBE_UNUSED FFMemoryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/sound/sound.c b/src/modules/sound/sound.c index d7fbebf99..0d0950011 100644 --- a/src/modules/sound/sound.c +++ b/src/modules/sound/sound.c @@ -121,6 +121,9 @@ bool ffParseSoundCommandOptions(FFSoundOptions* options, const char* key, const return true; } + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -153,6 +156,9 @@ void ffParseSoundJsonObject(FFSoundOptions* options, yyjson_val* module) continue; } + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_SOUND_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -179,6 +185,8 @@ void ffGenerateSoundJsonConfig(FFSoundOptions* options, yyjson_mut_doc* doc, yyj break; } } + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } void ffGenerateSoundJsonResult(FF_MAYBE_UNUSED FFSoundOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) diff --git a/src/modules/swap/swap.c b/src/modules/swap/swap.c index b4103bf6b..bf7c7481a 100644 --- a/src/modules/swap/swap.c +++ b/src/modules/swap/swap.c @@ -82,6 +82,9 @@ bool ffParseSwapCommandOptions(FFSwapOptions* options, const char* key, const ch if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + return false; } @@ -98,6 +101,9 @@ void ffParseSwapJsonObject(FFSwapOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + ffPrintError(FF_SWAP_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -107,6 +113,8 @@ void ffGenerateSwapJsonConfig(FFSwapOptions* options, yyjson_mut_doc* doc, yyjso __attribute__((__cleanup__(ffDestroySwapOptions))) FFSwapOptions defaultOptions; ffInitSwapOptions(&defaultOptions); + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); + ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); } From 7ddc207574f5d1bdccdb104583729ca2df279f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 19:59:13 +0800 Subject: [PATCH 31/36] Percentage: add options `--percent-color-*` --- doc/json_schema.json | 18 ++++++++++++ src/common/option.c | 2 +- src/common/percent.c | 67 +++++++++++++++++++++++++++---------------- src/data/help.json | 33 +++++++++++++++++++++ src/options/display.c | 40 +++++++++++++++++++++++--- src/options/display.h | 3 ++ 6 files changed, 134 insertions(+), 29 deletions(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index 884fd4c2e..88ffbec0b 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -457,6 +457,24 @@ "minimum": 0, "maximum": 9, "default": 0 + }, + "color": { + "type": "object", + "description": "Set color used in different states of percentage bars and numbers", + "properties": { + "green": { + "description": "Color used in green state", + "$ref": "#/$defs/colors" + }, + "yellow": { + "description": "Color used in yellow state", + "$ref": "#/$defs/colors" + }, + "red": { + "description": "Color used in red state", + "$ref": "#/$defs/colors" + } + } } } }, diff --git a/src/common/option.c b/src/common/option.c index cb72a385e..81efd69d1 100644 --- a/src/common/option.c +++ b/src/common/option.c @@ -143,7 +143,7 @@ void ffOptionParseColor(const char* value, FFstrbuf* buffer) while(*value != '\0') { #define FF_APPEND_COLOR_CODE_COND(prefix, code) \ - if(strncasecmp(value, #prefix, strlen(#prefix)) == 0) { ffStrbufAppendS(buffer, code); value += strlen(#prefix); } + if(ffStrStartsWithIgnCase(value, #prefix)) { ffStrbufAppendS(buffer, code); value += strlen(#prefix); } FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET) else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD) diff --git a/src/common/percent.c b/src/common/percent.c index 0b154e744..306838d06 100644 --- a/src/common/percent.c +++ b/src/common/percent.c @@ -24,28 +24,43 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentConfig config ffStrbufAppendS(buffer, "[ "); } - for (uint32_t i = 0; i < blocksPercent; ++i) + if (percent != percent) { if(!options->pipe) - { - uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5); - uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5); - if (i == section2Begin) - ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? FF_COLOR_FG_LIGHT_GREEN : FF_COLOR_FG_LIGHT_RED)); - else if (i == section1Begin) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m"); - else if (i == 0) - ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? FF_COLOR_FG_GREEN : FF_COLOR_FG_LIGHT_RED)); - } - ffStrbufAppend(buffer, &options->barCharElapsed); - } + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m"); - if (blocksPercent < options->barWidth) + for (uint32_t i = 0; i < options->barWidth; ++i) + ffStrbufAppend(buffer, &options->barCharElapsed); + } + else { - if(!options->pipe) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m"); - for (uint32_t i = blocksPercent; i < options->barWidth; ++i) - ffStrbufAppend(buffer, &options->barCharTotal); + const char* colorGreen = instance.config.display.percentColorGreen.chars; + const char* colorYellow = instance.config.display.percentColorYellow.chars; + const char* colorRed = instance.config.display.percentColorRed.chars; + + for (uint32_t i = 0; i < blocksPercent; ++i) + { + if(!options->pipe) + { + uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5); + uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5); + if (i == section2Begin) + ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed)); + else if (i == section1Begin) + ffStrbufAppendF(buffer, "\e[%sm", colorYellow); + else if (i == 0) + ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed)); + } + ffStrbufAppend(buffer, &options->barCharElapsed); + } + + if (blocksPercent < options->barWidth) + { + if(!options->pipe) + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m"); + for (uint32_t i = blocksPercent; i < options->barWidth; ++i) + ffStrbufAppend(buffer, &options->barCharTotal); + } } if(options->barBorder) @@ -74,26 +89,30 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentConfig config if (colored && !options->pipe) { + const char* colorGreen = instance.config.display.percentColorGreen.chars; + const char* colorYellow = instance.config.display.percentColorYellow.chars; + const char* colorRed = instance.config.display.percentColorRed.chars; + if(percent != percent) ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m"); else if(green <= yellow) { if (percent > yellow) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m"); + ffStrbufAppendF(buffer, "\e[%sm", colorRed); else if (percent > green) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m"); + ffStrbufAppendF(buffer, "\e[%sm", colorYellow); else - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m"); + ffStrbufAppendF(buffer, "\e[%sm", colorGreen); } else { if (percent < yellow) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m"); + ffStrbufAppendF(buffer, "\e[%sm", colorRed); else if (percent < green) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m"); + ffStrbufAppendF(buffer, "\e[%sm", colorYellow); else - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m"); + ffStrbufAppendF(buffer, "\e[%sm", colorGreen); } } ffStrbufAppendF(buffer, "%.*f%%", options->percentNdigits, percent); diff --git a/src/data/help.json b/src/data/help.json index c22c42ef5..9af1a17e6 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -198,6 +198,7 @@ { "long": "logo-color-[1-9]", "desc": "Overwrite a color in the logo", + "remark": "See `-h color` for the list of available colors", "arg": { "type": "color" }, @@ -432,6 +433,7 @@ { "long": "color-keys", "desc": "Set the color of the keys", + "remark": "See `-h color` for the list of available colors", "arg": { "type": "color" } @@ -439,6 +441,7 @@ { "long": "color-title", "desc": "Set the color of the title", + "remark": "See `-h color` for the list of available colors", "arg": { "type": "color" } @@ -548,6 +551,33 @@ "default": 0 } }, + { + "long": "percent-color-green", + "desc": "Set color used in green state of percentage bars and numbers", + "remark": "See `-h color` for the list of available colors", + "arg": { + "type": "color", + "default": "green" + } + }, + { + "long": "percent-color-yellow", + "desc": "Set color used in yellow state of percentage bars and numbers", + "remark": "See `-h color` for the list of available colors", + "arg": { + "type": "color", + "default": "light_yellow" + } + }, + { + "long": "percent-color-red", + "desc": "Set color used in red state of percentage bars and numbers", + "remark": "See `-h color` for the list of available colors", + "arg": { + "type": "color", + "default": "light_red" + } + }, { "long": "bar-char-elapsed", "desc": "Set the character to use in elapsed part of percentage bars", @@ -821,6 +851,7 @@ { "long": "title-color-user", "desc": "Set color of the user name (left part)", + "remark": "See `-h color` for the list of available colors", "arg": { "type": "color", "default": "Use color of \"--color-title\"" @@ -829,6 +860,7 @@ { "long": "title-color-at", "desc": "Set color of the @ symbol (middle part)", + "remark": "See `-h color` for the list of available colors", "arg": { "type": "color", "default": "Use color of \"--color-title\"" @@ -837,6 +869,7 @@ { "long": "title-color-host", "desc": "Set color of the host name (right part)", + "remark": "See `-h color` for the list of available colors", "arg": { "type": "color", "default": "default" diff --git a/src/options/display.c b/src/options/display.c index 3236a7b1d..5ba60b58e 100644 --- a/src/options/display.c +++ b/src/options/display.c @@ -1,4 +1,5 @@ #include "fastfetch.h" +#include "common/color.h" #include "common/jsonconfig.h" #include "util/stringUtils.h" #include "options/display.h" @@ -118,6 +119,22 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va yyjson_val* ndigits = yyjson_obj_get(val, "ndigits"); if (ndigits) options->percentNdigits = (uint8_t) yyjson_get_uint(ndigits); + + yyjson_val* color = yyjson_obj_get(val, "color"); + if (color) + { + if (!yyjson_is_obj(color)) + return "display.percent.color must be an object"; + + yyjson_val* green = yyjson_obj_get(color, "green"); + if (green) ffOptionParseColor(yyjson_get_str(green), &options->percentColorGreen); + + yyjson_val* yellow = yyjson_obj_get(color, "yellow"); + if (yellow) ffOptionParseColor(yyjson_get_str(yellow), &options->percentColorYellow); + + yyjson_val* red = yyjson_obj_get(color, "red"); + if (red) ffOptionParseColor(yyjson_get_str(red), &options->percentColorRed); + } } else if (ffStrEqualsIgnCase(key, "bar")) { @@ -248,10 +265,22 @@ bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key {}, }); } - else if(ffStrEqualsIgnCase(key, "--percent-type")) - options->percentType = (uint8_t) ffOptionParseUInt32(key, value); - else if(ffStrEqualsIgnCase(key, "--percent-ndigits")) - options->percentNdigits = (uint8_t) ffOptionParseUInt32(key, value); + else if(ffStrStartsWithIgnCase(key, "--percent-")) + { + const char* subkey = key + strlen("--percent-"); + if(ffStrEqualsIgnCase(subkey, "type")) + options->percentType = (uint8_t) ffOptionParseUInt32(key, value); + else if(ffStrEqualsIgnCase(subkey, "ndigits")) + options->percentNdigits = (uint8_t) ffOptionParseUInt32(key, value); + else if(ffStrEqualsIgnCase(subkey, "color-green")) + ffOptionParseColor(value, &options->percentColorGreen); + else if(ffStrEqualsIgnCase(subkey, "color-yellow")) + ffOptionParseColor(value, &options->percentColorYellow); + else if(ffStrEqualsIgnCase(subkey, "color-red")) + ffOptionParseColor(value, &options->percentColorRed); + else + return false; + } else if(ffStrEqualsIgnCase(key, "--no-buffer")) options->noBuffer = ffOptionParseBoolean(value); else if(ffStrStartsWithIgnCase(key, "--bar-")) @@ -305,6 +334,9 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) options->barBorder = true; options->percentType = 9; options->percentNdigits = 0; + ffStrbufInitStatic(&options->percentColorGreen, FF_COLOR_FG_GREEN); + ffStrbufInitStatic(&options->percentColorYellow, FF_COLOR_FG_LIGHT_YELLOW); + ffStrbufInitStatic(&options->percentColorRed, FF_COLOR_FG_LIGHT_RED); } void ffOptionsDestroyDisplay(FFOptionsDisplay* options) diff --git a/src/options/display.h b/src/options/display.h index c1ef5a886..296e95a24 100644 --- a/src/options/display.h +++ b/src/options/display.h @@ -41,6 +41,9 @@ typedef struct FFOptionsDisplay bool barBorder; uint8_t percentType; uint8_t percentNdigits; + FFstrbuf percentColorGreen; + FFstrbuf percentColorYellow; + FFstrbuf percentColorRed; bool noBuffer; uint32_t keyWidth; } FFOptionsDisplay; From b0acf168bf6f178f1be6f181efc20a44ee61c062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 20:14:56 +0800 Subject: [PATCH 32/36] Doc: update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81a034917..f2f5ba089 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Features: * Improve xonsh shell detection (Shell) +* Support colored percentage values (Bluetooth / Gamepad / Sound) +* Add `---percent-[green|yellow]` options to specify threshold of percentage colors + * eg. `--disk-percent-green 20 --disk-percent-yellow 50` will show green if disk usage is less than 20%, yellow if disk usage is less then 50%, and red otherwise. +* Add `--percent-color-[green|yellow|red]` options to specify color of different percent value states. + * eg. `--percent-color-green blue` will show blue color if percent value falls in green state. Bugfixes: * Fix segfault in CPU module when running in aarch64 machine without `lscpu` installed (CPU, Linux) From 8b1ee64a3e2de8a87e94bab405ae8a9d5e355684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 20:57:33 +0800 Subject: [PATCH 33/36] GPU (macOS): fix gpu type detection --- CHANGELOG.md | 1 + src/detection/gpu/gpu_apple.m | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2f5ba089..9c26213e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Bugfixes: * Silence warnings when building in 32bit machines. * Create sub folders when writing config file (#690) * Improve user specific locale detection; fix locale detection in Windows 7 (Locale) +* Fix GPU type detection (GPU, macOS) # 2.6.0 diff --git a/src/detection/gpu/gpu_apple.m b/src/detection/gpu/gpu_apple.m index 0323fdaff..85d951724 100644 --- a/src/detection/gpu/gpu_apple.m +++ b/src/detection/gpu/gpu_apple.m @@ -32,7 +32,7 @@ const char* ffGpuDetectMetal(FFlist* gpus) else if ([device supportsFamily:MTLGPUFamilyCommon1]) ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1"); - if (gpu->type == device.hasUnifiedMemory) + if (device.hasUnifiedMemory) { gpu->type = FF_GPU_TYPE_INTEGRATED; gpu->shared.total = device.recommendedMaxWorkingSetSize; From 0eb76e9636bc83ce19d76fe7a12a2a6565407098 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 20 Jan 2024 21:38:24 +0800 Subject: [PATCH 34/36] Battery (macOS): improve manufacture info detection --- src/detection/battery/battery_apple.c | 33 +++++++++++++++++-------- src/detection/battery/battery_windows.c | 6 ++--- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index 8aafed206..a77cf6369 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -44,10 +44,12 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) ffCfDictGetString(properties, CFSTR(kIOPMDeviceNameKey), &battery->modelName); ffCfDictGetString(properties, CFSTR(kIOPMPSSerialKey), &battery->serial); + ffCfDictGetString(properties, CFSTR(kIOPMPSManufacturerKey), &battery->manufacturer); if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue) { - ffStrbufAppendS(&battery->manufacturer, "Apple Inc."); + if (!battery->manufacturer.length) + ffStrbufAppendS(&battery->manufacturer, "Apple Inc."); ffStrbufAppendS(&battery->technology, "Lithium"); if (!battery->modelName.length) ffStrbufAppendS(&battery->modelName, "Built-in"); @@ -68,17 +70,28 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) ffStrbufTrimRight(&battery->status, ' '); ffStrbufTrimRight(&battery->status, ','); - CFDictionaryRef batteryData; - if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL) + int sbdsManufactureDate = 0; + if (ffCfDictGetInt(properties, CFSTR(kIOPMPSManufactureDateKey), &sbdsManufactureDate) == NULL) { - char manufactureDate[sizeof(uint64_t)]; - if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL) + int day = sbdsManufactureDate & 0b11111; + int month = (sbdsManufactureDate >> 5) & 0b1111; + int year = (sbdsManufactureDate >> 9) + 1800; + ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day); + } + else + { + CFDictionaryRef batteryData; + if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL) { - // https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419 - int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8; - int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0'); - int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '5'); - ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day); + char manufactureDate[sizeof(uint64_t)]; + if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL) + { + // https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419 + int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8; + int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0'); + int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '5'); + ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day); + } } } diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index 4e1a44db4..d0fec9557 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -203,9 +203,9 @@ const char* detectBySmbios(FFBatteryResult* battery) } else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsManufactureDate)) { - uint16_t day = data->SbdsManufactureDate & 0b11111; - uint16_t month = (data->SbdsManufactureDate >> 5) & 0b1111; - uint16_t year = (data->SbdsManufactureDate >> 9) + 1800; + int day = data->SbdsManufactureDate & 0b11111; + int month = (data->SbdsManufactureDate >> 5) & 0b1111; + int year = (data->SbdsManufactureDate >> 9) + 1800; ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day); } From 7d7789565bd59ddbb39b5192bbd332c8e08be1de Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 20 Jan 2024 21:46:57 +0800 Subject: [PATCH 35/36] PowerAdapter (macOS): improve detection for Intel macbook --- src/detection/poweradapter/poweradapter_apple.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/detection/poweradapter/poweradapter_apple.c b/src/detection/poweradapter/poweradapter_apple.c index 794fccd45..ab35a7ad6 100644 --- a/src/detection/poweradapter/poweradapter_apple.c +++ b/src/detection/poweradapter/poweradapter_apple.c @@ -7,7 +7,6 @@ const char* ffDetectPowerAdapter(FFlist* results) { - FF_CFTYPE_AUTO_RELEASE CFDictionaryRef details = IOPSCopyExternalPowerAdapterDetails(); FFPowerAdapterResult* adapter = ffListAdd(results); ffStrbufInit(&adapter->name); @@ -17,13 +16,24 @@ const char* ffDetectPowerAdapter(FFlist* results) ffStrbufInit(&adapter->serial); adapter->watts = FF_POWERADAPTER_NOT_CONNECTED; + FF_CFTYPE_AUTO_RELEASE CFDictionaryRef details = IOPSCopyExternalPowerAdapterDetails(); if (details) { ffCfDictGetString(details, CFSTR(kIOPSNameKey), &adapter->name); - ffCfDictGetString(details, CFSTR("Model"), &adapter->modelName); + if (ffCfDictGetString(details, CFSTR("Model"), &adapter->modelName) != NULL) + { + int adapterId; + if (ffCfDictGetInt(details, CFSTR(kIOPSPowerAdapterIDKey), &adapterId) == 0) + ffStrbufSetF(&adapter->modelName, "%d", adapterId); + } ffCfDictGetString(details, CFSTR("Manufacturer"), &adapter->manufacturer); ffCfDictGetString(details, CFSTR("Description"), &adapter->description); - ffCfDictGetString(details, CFSTR("SerialString"), &adapter->serial); + if (ffCfDictGetString(details, CFSTR("SerialString"), &adapter->serial) != NULL) + { + int serialNumber; + if (ffCfDictGetInt(details, CFSTR(kIOPSPowerAdapterSerialNumberKey), &serialNumber) == 0) + ffStrbufSetF(&adapter->serial, "%X", serialNumber); + } ffCfDictGetInt(details, CFSTR(kIOPSPowerAdapterWattsKey), &adapter->watts); } From 6af57ff5b6a25eedb6d2ae8b3d97db62a751ca5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 20 Jan 2024 22:20:28 +0800 Subject: [PATCH 36/36] Doc: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c26213e5..654acc8dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Features: * eg. `--disk-percent-green 20 --disk-percent-yellow 50` will show green if disk usage is less than 20%, yellow if disk usage is less then 50%, and red otherwise. * Add `--percent-color-[green|yellow|red]` options to specify color of different percent value states. * eg. `--percent-color-green blue` will show blue color if percent value falls in green state. +* Improve Intel macbook support (macOS) Bugfixes: * Fix segfault in CPU module when running in aarch64 machine without `lscpu` installed (CPU, Linux)