master ohmu/fastfetch-openbsd / src / modules / editor / editor.c
ohmu  ·  2026-10-15
  1#include "common/printing.h"
  2#include "common/jsonconfig.h"
  3#include "common/strutil.h"
  4#include "detection/libc/libc.h"
  5#include "detection/editor/editor.h"
  6#include "modules/editor/editor.h"
  7
  8// `FFEditorResult` owns four buffers and has no destructor of its own. Both entry points below
  9// have to free them on the error path too — which used to be skipped, and which became the common
 10// path once `ffDetectEditor()` started reporting an `$EDITOR` that does not name an executable
 11// instead of quietly succeeding.
 12static void destroyEditorResult(FFEditorResult* result) {
 13    ffStrbufDestroy(&result->name);
 14    ffStrbufDestroy(&result->path);
 15    ffStrbufDestroy(&result->exe);
 16    ffStrbufDestroy(&result->version);
 17}
 18
 19bool ffPrintEditor(FFEditorOptions* options) {
 20    FFEditorResult result = {
 21        .type = "Unknown",
 22        .name = ffStrbufCreate(),
 23        .path = ffStrbufCreate(),
 24        .exe = ffStrbufCreate(),
 25        .version = ffStrbufCreate(),
 26    };
 27    const char* error = ffDetectEditor(&result);
 28
 29    if (error) {
 30        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Editor), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
 31        destroyEditorResult(&result);
 32        return false;
 33    }
 34
 35    if (options->moduleArgs.outputFormat.length == 0) {
 36        ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Editor), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
 37        if (result.exe.length) {
 38            ffStrbufWriteTo(&result.exe, stdout);
 39            if (result.version.length) {
 40                printf(" %s", result.version.chars);
 41            }
 42        } else {
 43            ffStrbufWriteTo(&result.name, stdout);
 44        }
 45        putchar('\n');
 46    } else {
 47        FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Editor), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
 48                                                                                                           FF_ARG(result.type, "type"),
 49                                                                                                           FF_ARG(result.name, "name"),
 50                                                                                                           FF_ARG(result.exe, "exe-name"),
 51                                                                                                           FF_ARG(result.path, "path"),
 52                                                                                                           FF_ARG(result.version, "version"),
 53                                                                                                       }));
 54    }
 55
 56    destroyEditorResult(&result);
 57
 58    return true;
 59}
 60
 61void ffParseEditorJsonObject(FFEditorOptions* options, yyjson_val* module) {
 62    yyjson_val *key, *val;
 63    size_t idx, max;
 64    yyjson_obj_foreach (module, idx, max, key, val) {
 65        if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
 66            continue;
 67        }
 68
 69        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Editor), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
 70    }
 71}
 72
 73[[gnu::cold]]
 74void ffGenerateEditorJsonConfig(FFEditorOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
 75    ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
 76}
 77
 78bool ffGenerateEditorJsonResult([[maybe_unused]] FFEditorOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
 79    FFEditorResult result = {
 80        .name = ffStrbufCreate(),
 81        .path = ffStrbufCreate(),
 82        .version = ffStrbufCreate(),
 83    };
 84
 85    const char* error = ffDetectEditor(&result);
 86
 87    if (error) {
 88        yyjson_mut_obj_add_str(doc, module, "error", error);
 89        destroyEditorResult(&result);
 90        return false;
 91    }
 92
 93    yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result");
 94    yyjson_mut_obj_add_str(doc, obj, "type", result.type);
 95    yyjson_mut_obj_add_strbuf(doc, obj, "name", &result.name);
 96    yyjson_mut_obj_add_strbuf(doc, obj, "path", &result.path);
 97    yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result.exe);
 98    yyjson_mut_obj_add_strbuf(doc, obj, "version", &result.version);
 99
100    destroyEditorResult(&result);
101
102    return true;
103}
104
105void ffInitEditorOptions(FFEditorOptions* options) {
106    ffOptionInitModuleArg(&options->moduleArgs, "󱞎");
107}
108
109void ffDestroyEditorOptions(FFEditorOptions* options) {
110    ffOptionDestroyModuleArg(&options->moduleArgs);
111}
112
113FFModuleBaseInfo ffEditorModuleInfo = {
114    .name = "Editor",
115    .description = "Print information about the default editor ($VISUAL or $EDITOR)",
116    .displayName = {
117        .en = "Editor",
118        .ar = "المحرر",
119        .cs = "Editor",
120        .de = "Editor",
121        .es = "Editor",
122        .fi = "Editori",
123        .fr = "Éditeur",
124        .gl = "Editor",
125        .he = "עורך",
126        .id = "Editor",
127        .it = "Editor",
128        .ja = "エディター",
129        .ko = "편집기",
130        .pl = "Edytor",
131        .pt = "Editor",
132        .ru = "Редактор",
133        .tr = "Düzenleyici",
134        .uk = "Редактор",
135        .vi = "Trình soạn thảo",
136        .zh_CN = "编辑器",
137        .zh_TW = "編輯器",
138    },
139    .initOptions = (void*) ffInitEditorOptions,
140    .destroyOptions = (void*) ffDestroyEditorOptions,
141    .parseJsonObject = (void*) ffParseEditorJsonObject,
142    .printModule = (void*) ffPrintEditor,
143    .generateJsonResult = (void*) ffGenerateEditorJsonResult,
144    .generateJsonConfig = (void*) ffGenerateEditorJsonConfig,
145    .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
146        { "Type (Visual / Editor)", "type" },
147        { "Name", "name" },
148        { "Exe name of real path", "exe-name" },
149        { "Full path of real path", "path" },
150        { "Version", "version" },
151    })),
152    .defaultOrder = 16,
153};