2024-05-22 16:13:36 +08:00
|
|
|
#include "editor.h"
|
2026-01-06 09:48:38 +08:00
|
|
|
#include "common/processing.h"
|
|
|
|
|
#include "common/library.h"
|
2026-05-28 15:58:08 +08:00
|
|
|
#include "common/strutil.h"
|
2026-01-06 09:48:38 +08:00
|
|
|
#include "common/path.h"
|
|
|
|
|
#include "common/binary.h"
|
2024-05-22 16:13:36 +08:00
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
2026-04-09 16:20:59 +08:00
|
|
|
static bool extractNvimVersionFromBinary(const char* str, FF_A_UNUSED uint32_t len, void* userdata) {
|
2026-03-29 09:28:49 +08:00
|
|
|
if (!ffStrStartsWith(str, "NVIM v")) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-08-20 16:37:54 +08:00
|
|
|
ffStrbufSetS((FFstrbuf*) userdata, str + strlen("NVIM v"));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 16:20:59 +08:00
|
|
|
static bool extractVimVersionFromBinary(const char* str, FF_A_UNUSED uint32_t len, void* userdata) {
|
2026-03-29 09:28:49 +08:00
|
|
|
if (!ffStrStartsWith(str, "VIM - Vi IMproved ")) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-08-20 16:37:54 +08:00
|
|
|
ffStrbufSetS((FFstrbuf*) userdata, str + strlen("VIM - Vi IMproved "));
|
|
|
|
|
ffStrbufSubstrBeforeFirstC(userdata, ' ');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 16:20:59 +08:00
|
|
|
static bool extractNanoVersionFromBinary(const char* str, FF_A_UNUSED uint32_t len, void* userdata) {
|
2026-03-29 09:28:49 +08:00
|
|
|
if (!ffStrStartsWith(str, "GNU nano ")) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-08-20 16:37:54 +08:00
|
|
|
ffStrbufSetS((FFstrbuf*) userdata, str + strlen("GNU nano "));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 09:28:49 +08:00
|
|
|
const char* ffDetectEditor(FFEditorResult* result) {
|
2024-05-22 16:13:36 +08:00
|
|
|
ffStrbufSetS(&result->name, getenv("VISUAL"));
|
2026-03-29 09:28:49 +08:00
|
|
|
if (result->name.length) {
|
2024-05-27 16:41:37 +08:00
|
|
|
result->type = "Visual";
|
2026-03-29 09:28:49 +08:00
|
|
|
} else {
|
2024-05-22 16:13:36 +08:00
|
|
|
ffStrbufSetS(&result->name, getenv("EDITOR"));
|
2026-03-29 09:28:49 +08:00
|
|
|
if (result->name.length) {
|
2024-05-27 16:41:37 +08:00
|
|
|
result->type = "Editor";
|
2026-03-29 09:28:49 +08:00
|
|
|
} else {
|
2024-05-27 16:41:37 +08:00
|
|
|
return "$VISUAL or $EDITOR not set";
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-05-27 16:41:37 +08:00
|
|
|
}
|
2024-05-22 16:13:36 +08:00
|
|
|
|
2026-03-29 09:28:49 +08:00
|
|
|
if (ffIsAbsolutePath(result->name.chars)) {
|
2024-08-20 16:37:54 +08:00
|
|
|
ffStrbufSet(&result->path, &result->name);
|
2026-03-29 09:28:49 +08:00
|
|
|
} else {
|
2024-08-20 16:37:54 +08:00
|
|
|
const char* error = ffFindExecutableInPath(result->name.chars, &result->path);
|
2026-03-29 09:28:49 +08:00
|
|
|
if (error) {
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-05-24 23:43:01 +08:00
|
|
|
}
|
2024-08-20 16:37:54 +08:00
|
|
|
|
2024-08-23 10:17:06 +08:00
|
|
|
{
|
|
|
|
|
char buf[PATH_MAX + 1];
|
2026-03-29 09:28:49 +08:00
|
|
|
if (!realpath(result->path.chars, buf)) {
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-05-22 16:13:36 +08:00
|
|
|
|
2024-08-23 10:17:06 +08:00
|
|
|
// WIN32: Should we handle scoop shim exe here?
|
2024-08-22 16:41:06 +08:00
|
|
|
|
2026-03-29 09:28:49 +08:00
|
|
|
#ifdef __linux__
|
2024-08-23 10:17:06 +08:00
|
|
|
if (!ffStrEndsWith(buf, "/snap"))
|
2026-03-29 09:28:49 +08:00
|
|
|
#endif
|
2024-08-23 10:17:06 +08:00
|
|
|
ffStrbufSetS(&result->path, buf);
|
|
|
|
|
}
|
2024-05-24 23:43:01 +08:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
uint32_t index = ffStrbufLastIndexC(&result->path,
|
2026-03-29 09:28:49 +08:00
|
|
|
#ifndef _WIN32
|
2024-05-24 23:43:01 +08:00
|
|
|
'/'
|
2026-03-29 09:28:49 +08:00
|
|
|
#else
|
2024-05-24 23:43:01 +08:00
|
|
|
'\\'
|
2026-03-29 09:28:49 +08:00
|
|
|
#endif
|
2024-05-24 23:43:01 +08:00
|
|
|
);
|
2026-03-29 09:28:49 +08:00
|
|
|
if (index == result->path.length) {
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-05-24 23:43:01 +08:00
|
|
|
ffStrbufSetS(&result->exe, &result->path.chars[index + 1]);
|
2026-03-29 09:28:49 +08:00
|
|
|
if (!result->exe.length) {
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-05-24 23:43:01 +08:00
|
|
|
|
2026-03-29 09:28:49 +08:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
if (ffStrbufEndsWithS(&result->exe, ".exe")) {
|
2024-05-24 23:43:01 +08:00
|
|
|
ffStrbufSubstrBefore(&result->exe, result->exe.length - 4);
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
|
|
|
|
#endif
|
2024-05-24 23:43:01 +08:00
|
|
|
}
|
2024-05-22 16:13:36 +08:00
|
|
|
|
2026-03-29 09:28:49 +08:00
|
|
|
if (!instance.config.general.detectVersion) {
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-08-22 16:41:06 +08:00
|
|
|
|
2026-03-29 09:28:49 +08:00
|
|
|
if (ffStrbufEqualS(&result->exe, "nvim")) {
|
2024-08-27 16:19:05 +08:00
|
|
|
ffBinaryExtractStrings(result->path.chars, extractNvimVersionFromBinary, &result->version, (uint32_t) strlen("NVIM v0.0.0"));
|
2026-03-29 09:28:49 +08:00
|
|
|
} else if (ffStrbufEqualS(&result->exe, "vim") || ffStrbufStartsWithS(&result->exe, "vim.")) {
|
2024-08-27 16:19:05 +08:00
|
|
|
ffBinaryExtractStrings(result->path.chars, extractVimVersionFromBinary, &result->version, (uint32_t) strlen("VIM - Vi IMproved 0.0"));
|
2026-03-29 09:28:49 +08:00
|
|
|
} else if (ffStrbufEqualS(&result->exe, "nano")) {
|
2024-08-27 16:19:05 +08:00
|
|
|
ffBinaryExtractStrings(result->path.chars, extractNanoVersionFromBinary, &result->version, (uint32_t) strlen("GNU nano 0.0"));
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-08-20 16:37:54 +08:00
|
|
|
|
2026-03-29 09:28:49 +08:00
|
|
|
if (result->version.length > 0) {
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-08-20 16:37:54 +08:00
|
|
|
|
2026-07-10 18:08:04 +08:00
|
|
|
const char* param = nullptr;
|
2024-05-22 16:13:36 +08:00
|
|
|
if (
|
2024-05-24 23:43:01 +08:00
|
|
|
ffStrbufEqualS(&result->exe, "nano") ||
|
|
|
|
|
ffStrbufEqualS(&result->exe, "vim") ||
|
2024-10-26 11:08:18 +08:00
|
|
|
ffStrbufStartsWithS(&result->exe, "vim.") || // vim.basic/vim.tiny
|
2024-05-24 23:43:01 +08:00
|
|
|
ffStrbufEqualS(&result->exe, "nvim") ||
|
|
|
|
|
ffStrbufEqualS(&result->exe, "micro") ||
|
|
|
|
|
ffStrbufEqualS(&result->exe, "emacs") ||
|
|
|
|
|
ffStrbufStartsWithS(&result->exe, "emacs-") || // emacs-29.3
|
|
|
|
|
ffStrbufEqualS(&result->exe, "hx") ||
|
|
|
|
|
ffStrbufEqualS(&result->exe, "code") ||
|
2024-06-17 12:37:32 +08:00
|
|
|
ffStrbufEqualS(&result->exe, "pluma") ||
|
2026-02-25 03:56:28 +01:00
|
|
|
ffStrbufEqualS(&result->exe, "sublime_text") ||
|
2026-03-29 09:28:49 +08:00
|
|
|
ffStrbufEqualS(&result->exe, "zeditor")) {
|
|
|
|
|
param = "--version";
|
|
|
|
|
} else if (
|
2024-05-24 23:43:01 +08:00
|
|
|
ffStrbufEqualS(&result->exe, "kak") ||
|
2026-03-29 09:28:49 +08:00
|
|
|
ffStrbufEqualS(&result->exe, "pico")) {
|
|
|
|
|
param = "-version";
|
|
|
|
|
} else if (
|
|
|
|
|
ffStrbufEqualS(&result->exe, "ne")) {
|
|
|
|
|
param = "-h";
|
|
|
|
|
} else {
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffProcessAppendStdOut(&result->version, (char* const[]) {
|
|
|
|
|
result->path.chars,
|
|
|
|
|
(char*) param,
|
2026-07-10 18:08:04 +08:00
|
|
|
nullptr,
|
2026-03-29 09:28:49 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (result->version.length == 0) {
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2026-03-29 09:28:49 +08:00
|
|
|
}
|
2024-05-22 16:13:36 +08:00
|
|
|
|
|
|
|
|
ffStrbufSubstrBeforeFirstC(&result->version, '\n');
|
2024-10-24 09:43:23 +08:00
|
|
|
const char* versionStart = strpbrk(result->version.chars, "0123456789");
|
2026-07-10 18:08:04 +08:00
|
|
|
if (versionStart != nullptr) {
|
2024-10-24 09:43:23 +08:00
|
|
|
const char* versionEnd = strpbrk(versionStart, " \t\v\f\r");
|
2026-07-10 18:08:04 +08:00
|
|
|
if (versionEnd != nullptr) {
|
2026-03-29 09:28:49 +08:00
|
|
|
ffStrbufSubstrBefore(&result->version, (uint32_t) (versionEnd - result->version.chars));
|
|
|
|
|
}
|
2024-10-24 09:43:23 +08:00
|
|
|
|
2026-03-29 09:28:49 +08:00
|
|
|
if (versionStart != result->version.chars) {
|
|
|
|
|
ffStrbufSubstrAfter(&result->version, (uint32_t) (versionStart - result->version.chars - 1));
|
|
|
|
|
}
|
2024-05-22 16:13:36 +08:00
|
|
|
}
|
|
|
|
|
|
2026-07-10 18:08:04 +08:00
|
|
|
return nullptr;
|
2024-05-22 16:13:36 +08:00
|
|
|
}
|