diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ecd7ec7a1..be682e7b0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -59,6 +59,10 @@ strace /path/to/fastfetch --multithreading false -s {MODULE} --pipe If you cannot do the instructions above, please upload the core dump file: +## If fastfetch is slow + +Use `time fastfetch --stat` to show time usage for each module. + ## If my image logo didn't show / work diff --git a/CHANGELOG.md b/CHANGELOG.md index 17f58128a..0c6c673fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 2.10.3 +# 2.11.0 Changes: * Default `hideCursor` to false. It doesn't make much difference but makes user's terminal unusable if fastfetch is not exited correctly. @@ -10,14 +10,21 @@ Bugfixes: * Fix wifi detection on platforms that don't use NetworkManager (#811, Wifi, Linux) * Fix NixOS wrapped process name (#814, Terminal, Linux) * Fix GPU type detection for AMD cards (#816, GPU, Linux) +* Silence system deprecation warnings (#822, Camera, macOS) Features: * Add basic support DE detection support for UKUI (DE, Linux) * Support printing total number of nix / flatpak / brew packages (Packages) * See `fastfetch -h packages-format` for detail * Better max CPU frequency detection support with `CPUID / 16H` instruction (CPU, Windows) - * This requires Core I Gen 6 or newer, and with `Virtual Machine Platform` Windows feature disabled. X86 only. + * This requires Intel Core I Gen 6 or newer, and with `Virtual Machine Platform` Windows feature disabled. X86 only. * Improve performance of nix packages detection (Packages, Linux) +* Make config specified in JSONC overridable by command line flags + * Note this change only make global config overridable; module configs are still not +* Suggest increasing `--processing-timeout` when child process timeouts +* Only detect folders that specified by `--disk-folders` + * Previously `--disk-folders` only omits unmatched disks from output + * This option can be used to improve detection performance by ignoring slow network drives # 2.10.2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f2fff8dc..1bcbb32cb 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.10.3 + VERSION 2.11.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" diff --git a/src/common/processing_linux.c b/src/common/processing_linux.c index e0f2db4d9..4401e3212 100644 --- a/src/common/processing_linux.c +++ b/src/common/processing_linux.c @@ -68,7 +68,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use { kill(childPid, SIGTERM); waitpid(childPid, NULL, 0); - return "poll(&pollfd, 1, timeout) timeout"; + return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)"; } else if (pollfd.revents & POLLERR) { diff --git a/src/common/processing_windows.c b/src/common/processing_windows.c index c93e5a9e4..5cbd0819f 100644 --- a/src/common/processing_windows.c +++ b/src/common/processing_windows.c @@ -96,7 +96,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use { CancelIo(hChildPipeRead); TerminateProcess(hProcess, 1); - return "WaitForSingleObject(hChildPipeRead) failed or timeout"; + return "WaitForSingleObject(hChildPipeRead) failed or timeout (try increasing --processing-timeout)"; } if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE)) diff --git a/src/detection/camera/camera_apple.m b/src/detection/camera/camera_apple.m index cf8d8cec1..a3da90540 100644 --- a/src/detection/camera/camera_apple.m +++ b/src/detection/camera/camera_apple.m @@ -1,10 +1,14 @@ #include "camera.h" +#include "common/io/io.h" #import const char* ffDetectCamera(FFlist* result) { - AVCaptureDeviceDiscoverySession* session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; + FF_SUPPRESS_IO(); // #822 + AVCaptureDeviceDiscoverySession* session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeExternalUnknown] + mediaType:AVMediaTypeVideo + position:AVCaptureDevicePositionUnspecified]; if (!session) return "Failed to create AVCaptureDeviceDiscoverySession"; diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 6a4d8195e..81bae35a1 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -68,7 +68,7 @@ inline static const char* detectSpeedByCpuid(FFCPUResult* cpu) #else -inline static const char* detectSpeedByCpuid(FFCPUResult* cpu) +inline static const char* detectSpeedByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu) { return "Unsupported platform"; } diff --git a/src/detection/disk/disk.c b/src/detection/disk/disk.c index e712a9c12..21520b532 100644 --- a/src/detection/disk/disk.c +++ b/src/detection/disk/disk.c @@ -1,6 +1,29 @@ #include "disk.h" -const char* ffDetectDisksImpl(FFlist* disks); +bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint) +{ + #ifdef _WIN32 + const char separator = ';'; + #else + const char separator = ':'; + #endif + + uint32_t mountpointLength = (uint32_t) strlen(mountpoint); + + uint32_t startIndex = 0; + while(startIndex < options->folders.length) + { + uint32_t colonIndex = ffStrbufNextIndexC(&options->folders, startIndex, separator); + + uint32_t folderLength = colonIndex - startIndex; + if (folderLength == mountpointLength && memcmp(options->folders.chars + startIndex, mountpoint, mountpointLength) == 0) + return true; + + startIndex = colonIndex + 1; + } + + return false; +} static int compareDisks(const FFDisk* disk1, const FFDisk* disk2) { @@ -9,7 +32,7 @@ static int compareDisks(const FFDisk* disk1, const FFDisk* disk2) const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks) { - const char* error = ffDetectDisksImpl(disks); + const char* error = ffDetectDisksImpl(options, disks); if (error) return error; if (disks->length == 0) return "No disks found"; diff --git a/src/detection/disk/disk.h b/src/detection/disk/disk.h index dc70bb88a..1700c6078 100644 --- a/src/detection/disk/disk.h +++ b/src/detection/disk/disk.h @@ -26,3 +26,6 @@ typedef struct FFDisk * If error is not set, disks contains at least one disk. */ const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */); + +const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks); +bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint); diff --git a/src/detection/disk/disk_bsd.c b/src/detection/disk/disk_bsd.c index c6f9a1c82..dcd6cc507 100644 --- a/src/detection/disk/disk_bsd.c +++ b/src/detection/disk/disk_bsd.c @@ -90,7 +90,7 @@ void detectFsInfo(struct statfs* fs, FFDisk* disk) } #endif -const char* ffDetectDisksImpl(FFlist* disks) +const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) { int size = getfsstat(NULL, 0, MNT_WAIT); @@ -103,7 +103,12 @@ const char* ffDetectDisksImpl(FFlist* disks) for(struct statfs* fs = buf; fs < buf + size; ++fs) { - if(!ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs")) + if(__builtin_expect(options->folders.length, 0)) + { + if(!ffDiskMatchMountpoint(options, fs->f_mntonname)) + continue; + } + else if(!ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs")) continue; #ifdef __FreeBSD__ diff --git a/src/detection/disk/disk_linux.c b/src/detection/disk/disk_linux.c index 31715e6d5..812cb5884 100644 --- a/src/detection/disk/disk_linux.c +++ b/src/detection/disk/disk_linux.c @@ -250,7 +250,7 @@ static void detectStats(FFDisk* disk) #endif } -const char* ffDetectDisksImpl(FFlist* disks) +const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) { FILE* mountsFile = setmntent("/proc/mounts", "r"); if(mountsFile == NULL) @@ -260,7 +260,12 @@ const char* ffDetectDisksImpl(FFlist* disks) while((device = getmntent(mountsFile))) { - if(!isPhysicalDevice(device)) + if (__builtin_expect(options->folders.length, 0)) + { + if (!ffDiskMatchMountpoint(options, device->mnt_dir)) + continue; + } + else if(!isPhysicalDevice(device)) continue; //We have a valid device, add it to the list diff --git a/src/detection/disk/disk_windows.c b/src/detection/disk/disk_windows.c index ef5329e50..8c0890eb6 100644 --- a/src/detection/disk/disk_windows.c +++ b/src/detection/disk/disk_windows.c @@ -6,23 +6,31 @@ #include #include -const char* ffDetectDisksImpl(FFlist* disks) +const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) { wchar_t buf[MAX_PATH + 1]; uint32_t length = GetLogicalDriveStringsW(sizeof(buf) / sizeof(*buf), buf); if (length == 0 || length >= sizeof(buf) / sizeof(*buf)) return "GetLogicalDriveStringsW(sizeof(buf) / sizeof(*buf), buf) failed"; + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + for(uint32_t i = 0; i < length; i++) { wchar_t* mountpoint = buf + i; + ffStrbufSetWS(&buffer, mountpoint); + i += buffer.length; + UINT driveType = GetDriveTypeW(mountpoint); - if(driveType == DRIVE_NO_ROOT_DIR) + + if (__builtin_expect((long) options->folders.length, 0)) { - i += (uint32_t)wcslen(mountpoint); - continue; + if (!ffDiskMatchMountpoint(options, buffer.chars)) + continue; } + else if(driveType == DRIVE_NO_ROOT_DIR) + continue; FFDisk* disk = ffListAdd(disks); @@ -77,7 +85,7 @@ const char* ffDetectDisksImpl(FFlist* disks) else disk->createTime = 0; - ffStrbufInitWS(&disk->mountpoint, mountpoint); + ffStrbufInitMove(&disk->mountpoint, &buffer); if (mountpoint[2] == L'\\' && mountpoint[3] == L'\0') { wchar_t volumeName[MAX_PATH + 1]; @@ -91,8 +99,6 @@ const char* ffDetectDisksImpl(FFlist* disks) //Unsupported disk->filesUsed = 0; disk->filesTotal = 0; - - i += disk->mountpoint.length; } return NULL; diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index 7afe12ada..a8801cb31 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -84,7 +84,7 @@ static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0))) { ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total")); - ffStrbufAppendS(pciDir, "/mem_info_vram_used"); + ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used"); if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0))) { if (gpu->type == FF_GPU_TYPE_DISCRETE) diff --git a/src/fastfetch.c b/src/fastfetch.c index 3959d7f8a..629c4dad0 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -321,21 +321,42 @@ static void parseOption(FFdata* data, const char* key, const char* value); static bool parseJsoncFile(const char* path) { - yyjson_read_err error; - yyjson_doc* doc = yyjson_read_file(path, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INF_AND_NAN, NULL, &error); - if (!doc) + assert(!instance.state.configDoc); + { - if (error.code != YYJSON_READ_ERROR_FILE_OPEN) + yyjson_read_err error; + instance.state.configDoc = yyjson_read_file(path, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INF_AND_NAN, NULL, &error); + if (!instance.state.configDoc) { - fprintf(stderr, "Error: failed to parse JSON config file `%s` at pos %zu: %s\n", path, error.pos, error.msg); + if (error.code != YYJSON_READ_ERROR_FILE_OPEN) + { + fprintf(stderr, "Error: failed to parse JSON config file `%s` at pos %zu: %s\n", path, error.pos, error.msg); + exit(477); + } + return false; + } + } + + { + const char* error = NULL; + + yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc); + if (!yyjson_is_obj(root)) + error = "Invalid JSON config format. Root value must be an object"; + + if ( + error || + (error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root)) || + (error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root)) || + (error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root)) || + (error = ffOptionsParseLibraryJsonConfig(&instance.config.library, root)) || + false + ) { + fprintf(stderr, "JsonConfig Error: %s\n", error); exit(477); } - return false; } - if (instance.state.configDoc) - yyjson_doc_free(instance.state.configDoc); // for `--load-config` - instance.state.configDoc = doc; return true; } @@ -779,27 +800,6 @@ static void parseArguments(FFdata* data, int argc, char** argv, void (*parser)(F static void run(FFdata* data) { - if (instance.state.configDoc) - { - const char* error = NULL; - - yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc); - if (!yyjson_is_obj(root)) - error = "Invalid JSON config format. Root value must be an object"; - - if ( - error || - (error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root)) || - (error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root)) || - (error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root)) || - (error = ffOptionsParseLibraryJsonConfig(&instance.config.library, root)) || - false - ) { - fprintf(stderr, "JsonConfig Error: %s\n", error); - exit(477); - } - } - const bool useJsonConfig = data->structure.length == 0 && instance.state.configDoc; if (useJsonConfig) diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index 364d5bf2d..d4946cf05 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -131,54 +131,6 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) } } -static void printMountpoint(FFDiskOptions* options, const FFlist* disks, const char* mountpoint) -{ - FF_LIST_FOR_EACH(FFDisk, disk, *disks) - { - if(ffStrbufEqualS(&disk->mountpoint, mountpoint)) - { - printDisk(options, disk); - return; - } - } - - ffPrintError(FF_DISK_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No disk found for mountpoint: %s", mountpoint); -} - -static void printMountpoints(FFDiskOptions* options, const FFlist* disks) -{ - #ifdef _WIN32 - const char separator = ';'; - #else - const char separator = ':'; - #endif - - FF_STRBUF_AUTO_DESTROY mountpoints = ffStrbufCreateCopy(&options->folders); - ffStrbufTrim(&mountpoints, separator); - - uint32_t startIndex = 0; - while(startIndex < mountpoints.length) - { - uint32_t colonIndex = ffStrbufNextIndexC(&mountpoints, startIndex, separator); - mountpoints.chars[colonIndex] = '\0'; - - printMountpoint(options, disks, mountpoints.chars + startIndex); - - startIndex = colonIndex + 1; - } -} - -static void printAutodetected(FFDiskOptions* options, const FFlist* disks) -{ - FF_LIST_FOR_EACH(FFDisk, disk, *disks) - { - if(disk->type & ~options->showTypes) - continue; - - printDisk(options, disk); - } -} - void ffPrintDisk(FFDiskOptions* options) { FF_LIST_AUTO_DESTROY disks = ffListCreate(sizeof (FFDisk)); @@ -190,10 +142,13 @@ void ffPrintDisk(FFDiskOptions* options) } else { - if(options->folders.length == 0) - printAutodetected(options, &disks); - else - printMountpoints(options, &disks); + FF_LIST_FOR_EACH(FFDisk, disk, disks) + { + if(__builtin_expect(options->folders.length == 0, 1) && (disk->type & ~options->showTypes)) + continue; + + printDisk(options, disk); + } } FF_LIST_FOR_EACH(FFDisk, disk, disks)