diff --git a/CHANGELOG.md b/CHANGELOG.md index a0ce8b65..00770fcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.13.2 + +Features: +* Add new module `Editor` which prints information of the default editor, i.e. $VISUAL or $EDITOR (Editor) + # 2.13.1 Fix a regression introduced in v2.13.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index bd65343c..b680c26e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -291,6 +291,7 @@ set(LIBFASTFETCH_SRC src/detection/disk/disk.c src/detection/diskio/diskio.c src/detection/displayserver/displayserver.c + src/detection/editor/editor.c src/detection/font/font.c src/detection/gpu/gpu.c src/detection/media/media.c @@ -330,6 +331,7 @@ set(LIBFASTFETCH_SRC src/modules/de/de.c src/modules/disk/disk.c src/modules/diskio/diskio.c + src/modules/editor/editor.c src/modules/font/font.c src/modules/gpu/gpu.c src/modules/host/host.c diff --git a/doc/json_schema.json b/doc/json_schema.json index 0b1fe82f..25587315 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -695,6 +695,7 @@ "disk", "diskio", "de", + "editor", "font", "gamepad", "gpu", @@ -795,6 +796,10 @@ "const": "datetime", "description": "Print current date and time" }, + { + "const": "editor", + "description": "Print information of the default editor ($VISUAL or $EDITOR)" + }, { "const": "font", "description": "Print system font name" diff --git a/presets/all.jsonc b/presets/all.jsonc index 313e1afe..263d214e 100644 --- a/presets/all.jsonc +++ b/presets/all.jsonc @@ -15,6 +15,7 @@ "processes", "packages", "shell", + "editor", "display", "brightness", "monitor", diff --git a/presets/ci.jsonc b/presets/ci.jsonc index ec9bac06..4fa7f753 100644 --- a/presets/ci.jsonc +++ b/presets/ci.jsonc @@ -22,6 +22,7 @@ "processes", "packages", "shell", + "editor", "display", "brightness", "monitor", diff --git a/src/common/modules.c b/src/common/modules.c index 84a22658..e7e2c20f 100644 --- a/src/common/modules.c +++ b/src/common/modules.c @@ -37,6 +37,7 @@ static FFModuleBaseInfo* D[] = { }; static FFModuleBaseInfo* E[] = { + (void*) &instance.config.modules.editor, NULL, }; diff --git a/src/detection/editor/editor.c b/src/detection/editor/editor.c new file mode 100644 index 00000000..6b42fbd0 --- /dev/null +++ b/src/detection/editor/editor.c @@ -0,0 +1,112 @@ +#include "editor.h" +#include "common/processing.h" +#include "util/stringUtils.h" + +#include + +#if defined(MAXPATH) +#define FF_EXE_PATH_LEN MAXPATH +#elif defined(PATH_MAX) +#define FF_EXE_PATH_LEN PATH_MAX +#else +#define FF_EXE_PATH_LEN 260 +#endif + +#ifdef _WIN32 +static inline char* realpath(const char* restrict file_name, char* restrict resolved_name) +{ + char* result = _fullpath(resolved_name, file_name, _MAX_PATH); + if(result) + { + resolved_name[1] = resolved_name[0]; // Drive Name + resolved_name[0] = '/'; + } + return result; +} +#endif + +const char* ffDetectEditor(FFEditorResult* result) +{ + ffStrbufSetS(&result->name, getenv("VISUAL")); + if (result->name.length == 0) + ffStrbufSetS(&result->name, getenv("EDITOR")); + if (result->name.length == 0) + return "$VISUAL or $EDITOR not set"; + + #ifndef _WIN32 + if (result->name.chars[0] != '/') + { + if (ffProcessAppendStdOut(&result->path, (char* const[]){ + "/usr/bin/which", + result->name.chars, + NULL, + }) != NULL || result->path.length == 0) + return NULL; + } + else + ffStrbufSet(&result->path, &result->name); + + char buf[FF_EXE_PATH_LEN]; + if (!realpath(result->path.chars, buf)) + return NULL; + + ffStrbufSetS(&result->path, buf); + const char* exe = &result->path.chars[ffStrbufLastIndexC(&result->path, '/')]; + if (!*exe) return NULL; + ++exe; + result->exe = exe; + + const char* param = NULL; + if ( + ffStrEquals(exe, "nano") || + ffStrEquals(exe, "vim") || + ffStrEquals(exe, "nvim") || + ffStrEquals(exe, "micro") || + ffStrEquals(exe, "emacs") || + ffStrStartsWith(exe, "emacs-") || // emacs-29.3 + ffStrEquals(exe, "hx") || + ffStrEquals(exe, "code") || + ffStrEquals(exe, "sublime_text") + ) param = "--version"; + else if ( + ffStrEquals(exe, "kak") || + ffStrEquals(exe, "pico") + ) param = "-version"; + else if ( + ffStrEquals(exe, "ne") + ) param = "-h"; + else return NULL; + + ffProcessAppendStdOut(&result->version, (char* const[]){ + result->path.chars, + (char*) param, + NULL, + }); + + if (result->version.length == 0) + return NULL; + + ffStrbufSubstrBeforeFirstC(&result->version, '\n'); + for (uint32_t iStart = 0; iStart < result->version.length; ++iStart) + { + char c = result->version.chars[iStart]; + if (c >= '0' && c <= '9') + { + for (uint32_t iEnd = iStart + 1; iEnd < result->version.length; ++iEnd) + { + char c = result->version.chars[iEnd]; + if (isspace(c)) + { + ffStrbufSubstrBefore(&result->version, iEnd); + break; + } + } + if (iStart > 0) + ffStrbufSubstrAfter(&result->version, iStart - 1); + break; + } + } + #endif + + return NULL; +} diff --git a/src/detection/editor/editor.h b/src/detection/editor/editor.h new file mode 100644 index 00000000..a90e5556 --- /dev/null +++ b/src/detection/editor/editor.h @@ -0,0 +1,13 @@ +#pragma once + +#include "fastfetch.h" + +typedef struct FFEditorResult +{ + FFstrbuf name; + const char* exe; + FFstrbuf path; + FFstrbuf version; +} FFEditorResult; + +const char* ffDetectEditor(FFEditorResult* result); diff --git a/src/modules/editor/editor.c b/src/modules/editor/editor.c new file mode 100644 index 00000000..43d78f2a --- /dev/null +++ b/src/modules/editor/editor.c @@ -0,0 +1,134 @@ +#include "common/printing.h" +#include "common/jsonconfig.h" +#include "detection/libc/libc.h" +#include "detection/editor/editor.h" +#include "modules/editor/editor.h" +#include "util/stringUtils.h" + +#define FF_EDITOR_NUM_FORMAT_ARGS 4 + +void ffPrintEditor(FFEditorOptions* options) +{ + FFEditorResult result = { + .name = ffStrbufCreate(), + .path = ffStrbufCreate(), + .version = ffStrbufCreate(), + }; + const char* error = ffDetectEditor(&result); + + if (error) + { + ffPrintError(FF_EDITOR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error); + return; + } + + ffPrintLogoAndKey(FF_EDITOR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + if (result.exe) + { + fputs(result.exe, stdout); + if (result.version.length) + printf(" (%s)", result.version.chars); + } + else + { + ffStrbufWriteTo(&result.name, stdout); + } + putchar('\n'); + + ffStrbufDestroy(&result.name); + ffStrbufDestroy(&result.path); + ffStrbufDestroy(&result.version); +} + +bool ffParseEditorCommandOptions(FFEditorOptions* options, const char* key, const char* value) +{ + const char* subKey = ffOptionTestPrefix(key, FF_EDITOR_MODULE_NAME); + if (!subKey) return false; + if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) + return true; + + return false; +} + +void ffParseEditorJsonObject(FFEditorOptions* options, yyjson_val* module) +{ + yyjson_val *key_, *val; + size_t idx, max; + yyjson_obj_foreach(module, idx, max, key_, val) + { + const char* key = yyjson_get_str(key_); + if(ffStrEqualsIgnCase(key, "type")) + continue; + + if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) + continue; + + ffPrintError(FF_EDITOR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", key); + } +} + +void ffGenerateEditorJsonConfig(FFEditorOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + __attribute__((__cleanup__(ffDestroyEditorOptions))) FFEditorOptions defaultOptions; + ffInitEditorOptions(&defaultOptions); + + ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); +} + +void ffGenerateEditorJsonResult(FF_MAYBE_UNUSED FFEditorOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + FFEditorResult result = { + .name = ffStrbufCreate(), + .path = ffStrbufCreate(), + .version = ffStrbufCreate(), + }; + + const char* error = ffDetectEditor(&result); + + if (error) + { + yyjson_mut_obj_add_str(doc, module, "error", error); + return; + } + + yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); + yyjson_mut_obj_add_strbuf(doc, obj, "name", &result.name); + yyjson_mut_obj_add_strcpy(doc, obj, "exe", result.exe); + yyjson_mut_obj_add_strbuf(doc, obj, "path", &result.path); + yyjson_mut_obj_add_strbuf(doc, obj, "version", &result.version); + + ffStrbufDestroy(&result.name); + ffStrbufDestroy(&result.path); + ffStrbufDestroy(&result.version); +} + +void ffPrintEditorHelpFormat(void) +{ + FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_EDITOR_MODULE_NAME, "{2} ({4})", FF_EDITOR_NUM_FORMAT_ARGS, ((const char* []) { + "Name", + "Exe name", + "Full path", + "Version", + })); +} + +void ffInitEditorOptions(FFEditorOptions* options) +{ + ffOptionInitModuleBaseInfo( + &options->moduleInfo, + FF_EDITOR_MODULE_NAME, + "Print information of the default editor ($VISUAL or $EDITOR)", + ffParseEditorCommandOptions, + ffParseEditorJsonObject, + ffPrintEditor, + ffGenerateEditorJsonResult, + ffPrintEditorHelpFormat, + ffGenerateEditorJsonConfig + ); + ffOptionInitModuleArg(&options->moduleArgs); +} + +void ffDestroyEditorOptions(FFEditorOptions* options) +{ + ffOptionDestroyModuleArg(&options->moduleArgs); +} diff --git a/src/modules/editor/editor.h b/src/modules/editor/editor.h new file mode 100644 index 00000000..c18c8f67 --- /dev/null +++ b/src/modules/editor/editor.h @@ -0,0 +1,9 @@ +#pragma once + +#include "fastfetch.h" + +#define FF_EDITOR_MODULE_NAME "Editor" + +void ffPrintEditor(FFEditorOptions* options); +void ffInitEditorOptions(FFEditorOptions* options); +void ffDestroyEditorOptions(FFEditorOptions* options); diff --git a/src/modules/editor/option.h b/src/modules/editor/option.h new file mode 100644 index 00000000..92503d65 --- /dev/null +++ b/src/modules/editor/option.h @@ -0,0 +1,11 @@ +#pragma once + +// This file will be included in "fastfetch.h", do NOT put unnecessary things here + +#include "common/option.h" + +typedef struct FFEditorOptions +{ + FFModuleBaseInfo moduleInfo; + FFModuleArgs moduleArgs; +} FFEditorOptions; diff --git a/src/modules/modules.h b/src/modules/modules.h index 50c2a4e9..7971b4ab 100644 --- a/src/modules/modules.h +++ b/src/modules/modules.h @@ -22,6 +22,7 @@ #include "modules/diskio/diskio.h" #include "modules/display/display.h" #include "modules/de/de.h" +#include "modules/editor/editor.h" #include "modules/font/font.h" #include "modules/gamepad/gamepad.h" #include "modules/gpu/gpu.h" diff --git a/src/modules/options.h b/src/modules/options.h index 3972eff1..e75dd6bc 100644 --- a/src/modules/options.h +++ b/src/modules/options.h @@ -22,6 +22,7 @@ #include "modules/disk/option.h" #include "modules/diskio/option.h" #include "modules/display/option.h" +#include "modules/editor/option.h" #include "modules/font/option.h" #include "modules/host/option.h" #include "modules/gamepad/option.h" diff --git a/src/options/modules.c b/src/options/modules.c index 77653bec..64faf0e6 100644 --- a/src/options/modules.c +++ b/src/options/modules.c @@ -23,6 +23,7 @@ void ffOptionsInitModules(FFOptionsModules* options) ffInitDiskOptions(&options->disk); ffInitDiskIOOptions(&options->diskIo); ffInitDisplayOptions(&options->display); + ffInitEditorOptions(&options->editor); ffInitFontOptions(&options->font); ffInitGPUOptions(&options->gpu); ffInitGamepadOptions(&options->gamepad); @@ -90,6 +91,7 @@ void ffOptionsDestroyModules(FFOptionsModules* options) ffDestroyDiskOptions(&options->disk); ffDestroyDiskIOOptions(&options->diskIo); ffDestroyDisplayOptions(&options->display); + ffDestroyEditorOptions(&options->editor); ffDestroyFontOptions(&options->font); ffDestroyGPUOptions(&options->gpu); ffDestroyGamepadOptions(&options->gamepad); diff --git a/src/options/modules.h b/src/options/modules.h index 3d5597e3..aeebe33f 100644 --- a/src/options/modules.h +++ b/src/options/modules.h @@ -24,6 +24,7 @@ typedef struct FFOptionsModules FFDiskOptions disk; FFDiskIOOptions diskIo; FFDisplayOptions display; + FFEditorOptions editor; FFFontOptions font; FFGPUOptions gpu; FFGamepadOptions gamepad; diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index 5c045c19..37f5cf2d 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -389,8 +389,8 @@ void ffStrbufSubstrAfter(FFstrbuf* strbuf, uint32_t index) if(strbuf->allocated == 0) { //static string - strbuf->length -= index; - strbuf->chars += index; + strbuf->length -= index + 1; + strbuf->chars += index + 1; return; } diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index bf355059..92ea2da1 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -68,7 +68,7 @@ FF_C_NODISCARD uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace); void ffStrbufSubstrBefore(FFstrbuf* strbuf, uint32_t index); -void ffStrbufSubstrAfter(FFstrbuf* strbuf, uint32_t index); +void ffStrbufSubstrAfter(FFstrbuf* strbuf, uint32_t index); // Not including the index void ffStrbufSubstrAfterFirstC(FFstrbuf* strbuf, char c); void ffStrbufSubstrAfterFirstS(FFstrbuf* strbuf, const char* str); void ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c);