mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
929 lines
27 KiB
C
929 lines
27 KiB
C
#include "fastfetch.h"
|
||
#include "common/io/io.h"
|
||
#include "common/processing.h"
|
||
#include "common/properties.h"
|
||
#include "util/stringUtils.h"
|
||
#include "util/binary.h"
|
||
|
||
#include <ctype.h>
|
||
#ifdef __FreeBSD__
|
||
#include <paths.h>
|
||
#ifndef _PATH_LOCALBASE
|
||
#define _PATH_LOCALBASE "/usr/local"
|
||
#endif
|
||
#elif __OpenBSD__
|
||
#define _PATH_LOCALBASE "/usr/local"
|
||
#elif __NetBSD__
|
||
#define _PATH_LOCALBASE "/usr/pkg"
|
||
#elif _WIN32
|
||
|
||
#include "util/windows/version.h"
|
||
#include <windows.h>
|
||
|
||
static bool getFileVersion(const FFstrbuf* exePath, const wchar_t* stringName, FFstrbuf* version)
|
||
{
|
||
wchar_t exePathW[PATH_MAX];
|
||
int len = MultiByteToWideChar(CP_UTF8, 0, exePath->chars, (int)exePath->length, exePathW, ARRAY_SIZE(exePathW));
|
||
if (len <= 0) return false;
|
||
return ffGetFileVersion(exePathW, stringName, version);
|
||
}
|
||
|
||
#elif __HAIKU__
|
||
#include "util/haiku/version.h"
|
||
#endif
|
||
|
||
static bool getExeVersionRaw(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
return ffProcessAppendStdOut(version, (char* const[]) {
|
||
exe->chars,
|
||
"--version",
|
||
NULL
|
||
}) == NULL;
|
||
}
|
||
|
||
static bool getExeVersionGeneral(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(!getExeVersionRaw(exe, version))
|
||
return false;
|
||
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
static bool extractBashVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
|
||
{
|
||
if (!ffStrStartsWith(line, "@(#)Bash version ")) return true;
|
||
const char* start = line + strlen("@(#)Bash version ");
|
||
const char* end = strchr(start, '(');
|
||
if (!end) return true;
|
||
ffStrbufSetNS((FFstrbuf*) userdata, (uint32_t) (end - start), start);
|
||
return false;
|
||
}
|
||
|
||
static bool getShellVersionBash(FFstrbuf* exe, FFstrbuf* exePath, FFstrbuf* version)
|
||
{
|
||
const char* path = exePath->chars;
|
||
if (*path == '\0')
|
||
path = exe->chars;
|
||
ffBinaryExtractStrings(path, extractBashVersion, version, (uint32_t) strlen("@(#)Bash version 0.0.0(0) release GNU"));
|
||
|
||
if(!getExeVersionRaw(exe, version))
|
||
return false;
|
||
|
||
// GNU bash, version 5.1.16(1)-release (x86_64-pc-msys)\nCopyright...
|
||
ffStrbufSubstrBeforeFirstC(version, '('); // GNU bash, version 5.1.16
|
||
ffStrbufSubstrAfterLastC(version, ' '); // 5.1.16
|
||
return true;
|
||
}
|
||
|
||
static bool getShellVersionFish(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(!getExeVersionRaw(exe, version))
|
||
return false;
|
||
|
||
//fish, version 3.6.0
|
||
ffStrbufSubstrAfterLastC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
static bool getShellVersionPwsh(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
// Requires manually setting $POWERSHELL_VERSION
|
||
// $env:POWERSHELL_VERSION = $PSVersionTable.PSVersion.ToString(); fastfetch.exe
|
||
const char* env = getenv("POWERSHELL_VERSION");
|
||
if (env)
|
||
{
|
||
ffStrbufSetS(version, env);
|
||
return true;
|
||
}
|
||
|
||
#ifdef _WIN32
|
||
if(getFileVersion(exe, NULL, version))
|
||
{
|
||
ffStrbufSubstrBeforeLastC(version, '.');
|
||
return true;
|
||
}
|
||
#endif
|
||
|
||
if(!getExeVersionRaw(exe, version))
|
||
return false;
|
||
|
||
ffStrbufSubstrAfterLastC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
static bool getShellVersionKsh(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
#if __OpenBSD__ || __NetBSD__
|
||
if(ffProcessAppendStdOut(version, (char* const[]) {
|
||
exe->chars,
|
||
"-c",
|
||
"echo $KSH_VERSION",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
// @(#)PD KSH v5.2.14 99/07/13.2
|
||
ffStrbufSubstrAfterFirstC(version, 'v');
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
#else
|
||
if(ffProcessAppendStdErr(version, (char* const[]) {
|
||
exe->chars,
|
||
"--version",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
// version sh (AT&T Research) 93u+ 2012-08-01
|
||
ffStrbufSubstrAfterLastC(version, ')');
|
||
ffStrbufTrim(version, ' ');
|
||
#endif
|
||
return true;
|
||
}
|
||
|
||
static bool getShellVersionOksh(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdOut(version, (char* const[]) {
|
||
exe->chars,
|
||
"-c",
|
||
"echo $OKSH_VERSION",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
//oksh 7.3
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
static bool getShellVersionOils(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdOut(version, (char* const[]) {
|
||
exe->chars,
|
||
"--version",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
// Oils 0.18.0 https://www.oilshell.org/...
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
ffStrbufSubstrBeforeFirstC(version, '\t');
|
||
return true;
|
||
}
|
||
|
||
static bool getShellVersionNushell(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
ffStrbufSetS(version, getenv("NU_VERSION"));
|
||
if (version->length) return true;
|
||
return getExeVersionRaw(exe, version); //0.73.0
|
||
}
|
||
|
||
static bool getShellVersionAsh(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdErr(version, (char* const[]) {
|
||
exe->chars,
|
||
"--help",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
// BusyBox v1.36.1 (2023-11-07 18:53:09 UTC) multi-call binary...
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
ffStrbufTrimLeft(version, 'v');
|
||
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;
|
||
}
|
||
|
||
static bool extractZshVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
|
||
{
|
||
if (!ffStrStartsWith(line, "zsh-")) return true;
|
||
const char* start = line + strlen("zsh-");
|
||
const char* end = strchr(start, '-');
|
||
if (!end) return true;
|
||
|
||
ffStrbufSetNS((FFstrbuf*) userdata, (uint32_t) (end - start), start);
|
||
return false;
|
||
}
|
||
|
||
static bool getShellVersionZsh(FFstrbuf* exe, FFstrbuf* exePath, FFstrbuf* version)
|
||
{
|
||
const char* path = exePath->chars;
|
||
if (*path == '\0')
|
||
path = exe->chars;
|
||
|
||
ffBinaryExtractStrings(path, extractZshVersion, version, (uint32_t) strlen("zsh-0.0-0"));
|
||
if (version->length) return true;
|
||
|
||
return getExeVersionGeneral(exe, version); //zsh 5.9 (arm-apple-darwin21.3.0)
|
||
}
|
||
|
||
#ifdef _WIN32
|
||
static bool getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
const char* env = getenv("POWERSHELL_VERSION");
|
||
if (env)
|
||
{
|
||
ffStrbufSetS(version, env);
|
||
return true;
|
||
}
|
||
|
||
return ffProcessAppendStdOut(version, (char* const[]) {
|
||
exe->chars,
|
||
"-NoLogo",
|
||
"-NoProfile",
|
||
"-Command",
|
||
"$PSVersionTable.PSVersion.ToString()",
|
||
NULL
|
||
}) == NULL;
|
||
}
|
||
#endif
|
||
|
||
bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* exePath, FFstrbuf* version)
|
||
{
|
||
if (!instance.config.general.detectVersion) return false;
|
||
|
||
if(ffStrEqualsIgnCase(exeName, "sh")) // #849
|
||
return false;
|
||
|
||
if(ffStrEqualsIgnCase(exeName, "bash"))
|
||
return getShellVersionBash(exe, exePath, version);
|
||
if(ffStrEqualsIgnCase(exeName, "zsh"))
|
||
return getShellVersionZsh(exe, exePath, version);
|
||
if(ffStrEqualsIgnCase(exeName, "fish"))
|
||
return getShellVersionFish(exe, version);
|
||
if(ffStrEqualsIgnCase(exeName, "pwsh"))
|
||
return getShellVersionPwsh(exe, version);
|
||
if(ffStrEqualsIgnCase(exeName, "csh") || ffStrEqualsIgnCase(exeName, "tcsh"))
|
||
return getExeVersionGeneral(exe, version); //tcsh 6.24.07 (Astron) 2022-12-21 (aarch64-apple-darwin) options wide,nls,dl,al,kan,sm,rh,color,filec
|
||
if(ffStrEqualsIgnCase(exeName, "nu"))
|
||
return getShellVersionNushell(exe, version);
|
||
if(ffStrEqualsIgnCase(exeName, "ksh"))
|
||
return getShellVersionKsh(exe, version);
|
||
if(ffStrEqualsIgnCase(exeName, "oksh"))
|
||
return getShellVersionOksh(exe, version);
|
||
if(ffStrEqualsIgnCase(exeName, "oil.ovm"))
|
||
return getShellVersionOils(exe, version);
|
||
if(ffStrEqualsIgnCase(exeName, "elvish"))
|
||
return getExeVersionRaw(exe, version);
|
||
if(ffStrEqualsIgnCase(exeName, "ash"))
|
||
return getShellVersionAsh(exe, version);
|
||
if(ffStrEqualsIgnCase(exeName, "xonsh"))
|
||
return getShellVersionXonsh(exe, version);
|
||
|
||
#ifdef _WIN32
|
||
if(ffStrEqualsIgnCase(exeName, "powershell") || ffStrEqualsIgnCase(exeName, "powershell_ise"))
|
||
return getShellVersionWinPowerShell(exe, version);
|
||
|
||
return getFileVersion(exe, NULL, version);
|
||
#endif
|
||
|
||
return false;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionTermux(FFstrbuf* version)
|
||
{
|
||
ffStrbufSetS(version, getenv("TERMUX_VERSION"));
|
||
return version->length > 0;
|
||
}
|
||
|
||
static bool extractGeneralVersion(const char *str, FF_MAYBE_UNUSED uint32_t len, void *userdata)
|
||
{
|
||
if (!ffCharIsDigit(str[0])) return true;
|
||
int count = 0;
|
||
sscanf(str, "%*d.%*d.%*d%n", &count);
|
||
if (count == 0) return true;
|
||
ffStrbufSetS((FFstrbuf*) userdata, str);
|
||
return false;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionGnome(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if (exe->chars[0] == '/')
|
||
{
|
||
ffBinaryExtractStrings(exe->chars, extractGeneralVersion, version, (uint32_t) strlen("0.0.0"));
|
||
if (version->length) return true;
|
||
}
|
||
|
||
if(ffProcessAppendStdOut(version, (char* const[]){
|
||
"gnome-terminal",
|
||
"--version",
|
||
NULL
|
||
})) return false;
|
||
|
||
//# GNOME Terminal 3.46.7 using VTE 0.70.2 +BIDI +GNUTLS +ICU +SYSTEMD
|
||
ffStrbufSubstrAfterFirstS(version, "Terminal ");
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionXfce4Terminal(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if (exe->chars[0] == '/')
|
||
{
|
||
ffBinaryExtractStrings(exe->chars, extractGeneralVersion, version, (uint32_t) strlen("0.0.0"));
|
||
if (version->length) return true;
|
||
}
|
||
|
||
return getExeVersionGeneral(exe, version);//xfce4-terminal 1.0.4 (Xfce 4.18)...
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionKgx(FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdOut(version, (char* const[]){
|
||
"kgx",
|
||
"--version",
|
||
NULL
|
||
})) return false;
|
||
|
||
//# KGX 45.0 using VTE 0.74.0 +BIDI +GNUTLS +ICU +SYSTEMD
|
||
ffStrbufSubstrAfterFirstS(version, "KGX ");
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionKonsole(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
const char* konsoleVersion = getenv("KONSOLE_VERSION");
|
||
if(konsoleVersion)
|
||
{
|
||
//221201
|
||
long major = strtol(konsoleVersion, NULL, 10);
|
||
if (major >= 0)
|
||
{
|
||
long patch = major % 100;
|
||
major /= 100;
|
||
long minor = major % 100;
|
||
major /= 100;
|
||
ffStrbufSetF(version, "%ld.%ld.%ld", major, minor, patch);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return getExeVersionGeneral(exe, version);
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionFoot(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
uint32_t major = 0, minor = 0, patch = 0;
|
||
if (ffGetTerminalResponse("\e[>c", 3, "\e[>1;%2u%2u%2u;0c", &major, &minor, &patch) == NULL)
|
||
{
|
||
ffStrbufSetF(version, "%u.%u.%u", major, minor, patch);
|
||
return true;
|
||
}
|
||
|
||
if(!getExeVersionRaw(exe, version)) return false;
|
||
|
||
//foot version: 1.13.1 -pgo +ime -graphemes -assertions
|
||
ffStrbufSubstrAfterFirstS(version, "version: ");
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionMateTerminal(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
ffBinaryExtractStrings(exe->chars, extractGeneralVersion, version, (uint32_t) strlen("0.0.0"));
|
||
if (version->length > 0) return true;
|
||
|
||
if(!getExeVersionRaw(exe, version)) return false;
|
||
|
||
//MATE Terminal 1.26.1
|
||
ffStrbufSubstrAfterLastC(version, ' ');
|
||
return version->length > 0;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionCockpit(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(!getExeVersionRaw(exe, version)) return false;
|
||
|
||
//Version: 295\n...
|
||
ffStrbufSubstrBeforeFirstC(version, '\n');
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
return version->length > 0;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionXterm(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
ffStrbufSetS(version, getenv("XTERM_VERSION"));
|
||
if (!version->length)
|
||
{
|
||
if(ffProcessAppendStdOut(version, (char* const[]){
|
||
exe->chars,
|
||
"-v",
|
||
NULL
|
||
})) return false;
|
||
}
|
||
|
||
//xterm(273)
|
||
ffStrbufTrimRight(version, ')');
|
||
ffStrbufSubstrAfterFirstC(version, '(');
|
||
return version->length > 0;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionBlackbox(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdOut(version, (char* const[]){
|
||
exe->chars,
|
||
"--version",
|
||
NULL
|
||
})) return false;
|
||
|
||
//BlackBox version 0.14.0 (flatpak)
|
||
ffStrbufSubstrAfterFirstS(version, "version ");
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
return version->length > 0;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionUrxvt(FF_MAYBE_UNUSED FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdErr(version, (char* const[]){
|
||
"urxvt", // Don't use exe because of urxvtd
|
||
"-invalid",
|
||
NULL
|
||
})) return false;
|
||
|
||
//urxvt: "invalid": unknown or malformed option.
|
||
//rxvt-unicode (urxvt) v9.31 - released: 2023-01-02
|
||
ffStrbufSubstrAfterFirstS(version, "(urxvt) v");
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
|
||
return version->length > 0;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionSt(FF_MAYBE_UNUSED FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdErr(version, (char* const[]){
|
||
exe->chars,
|
||
"-v",
|
||
NULL
|
||
})) return false;
|
||
|
||
//st 0.9
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
|
||
return version->length > 0;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionLxterminal(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(!getExeVersionRaw(exe, version)) return false;
|
||
// lxterminal 0.3.2
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
return version->length > 0;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionWeston(FF_MAYBE_UNUSED FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
// weston-terminal doesn't report a version, use weston version instead
|
||
if(ffProcessAppendStdOut(version, (char* const[]){
|
||
"weston",
|
||
"--version",
|
||
NULL
|
||
})) return false;
|
||
|
||
//weston 8.0.0
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
|
||
return version->length > 0;
|
||
}
|
||
|
||
static bool getTerminalVersionContour(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
const char* env = getenv("TERMINAL_VERSION_STRING");
|
||
if (env)
|
||
{
|
||
ffStrbufAppendS(version, env);
|
||
return true;
|
||
}
|
||
if(!getExeVersionRaw(exe, version)) return false;
|
||
// Contour Terminal Emulator 0.3.12.262
|
||
ffStrbufSubstrAfterLastC(version, ' ');
|
||
return version->length > 0;
|
||
}
|
||
|
||
static bool getTerminalVersionScreen(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(!getExeVersionRaw(exe, version)) return false;
|
||
// Screen version 4.09.01 (GNU) 20-Aug-23
|
||
ffStrbufSubstrAfter(version, (uint32_t) strlen("Screen version ") - 1);
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
return version->length > 0;
|
||
}
|
||
|
||
static bool getTerminalVersionTmux(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if (ffProcessAppendStdOut(version, (char* const[]) {
|
||
exe->chars,
|
||
"-V",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
// tmux 3.4
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
return version->length > 0;
|
||
}
|
||
|
||
static bool getTerminalVersionZellij(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(!getExeVersionRaw(exe, version)) return false;
|
||
|
||
// zellij 0.39.2
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
return version->length > 0;
|
||
}
|
||
|
||
static bool getTerminalVersionZed(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
FF_STRBUF_AUTO_DESTROY cli = ffStrbufCreateCopy(exe);
|
||
ffStrbufSubstrBeforeLastC(&cli, '/');
|
||
ffStrbufAppendS(&cli, "/cli"
|
||
#ifdef _WIN32
|
||
".exe"
|
||
#endif
|
||
);
|
||
|
||
if(ffProcessAppendStdOut(version, (char* const[]) {
|
||
cli.chars,
|
||
"--version",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
// Zed 0.142.6 – /Applications/Zed.app
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
#ifndef _WIN32
|
||
static bool getTerminalVersionKitty(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||
char buffer[1024] = {};
|
||
if (
|
||
#ifdef __linux__
|
||
ffReadFileData(FASTFETCH_TARGET_DIR_USR "/lib64/kitty/kitty/constants.py", ARRAY_SIZE(buffer) - 1, buffer) ||
|
||
ffReadFileData(FASTFETCH_TARGET_DIR_USR "/lib/kitty/kitty/constants.py", ARRAY_SIZE(buffer) - 1, buffer)
|
||
#else
|
||
ffReadFileData(_PATH_LOCALBASE "/share/kitty/kitty/constants.py", ARRAY_SIZE(buffer) - 1, buffer)
|
||
#endif
|
||
)
|
||
{
|
||
// Starts from version 0.17.0
|
||
// https://github.com/kovidgoyal/kitty/blob/master/kitty/constants.py#L25
|
||
const char* p = memmem(buffer, ARRAY_SIZE(buffer) - 1, "version: Version = Version(", strlen("version: Version = Version("));
|
||
if (p)
|
||
{
|
||
p += strlen("version: Version = Version(");
|
||
int major, minor, patch;
|
||
if (sscanf(p, "%d,%d,%d", &major, &minor, &patch) == 3)
|
||
{
|
||
ffStrbufSetF(version, "%d.%d.%d", major, minor, patch);
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
#elif __APPLE__
|
||
if (ffStrbufEndsWithS(exe, "/kitty.app/Contents/MacOS/kitty"))
|
||
{
|
||
ffStrbufSet(version, exe);
|
||
ffStrbufSubstrBeforeLastC(version, '/');
|
||
ffStrbufSubstrBeforeLastC(version, '/');
|
||
ffStrbufAppendS(version, "/Info.plist");
|
||
char buf[4096];
|
||
ssize_t size = ffReadFileData(version->chars, ARRAY_SIZE(buf) - 1, buf);
|
||
if (size > 0)
|
||
{
|
||
buf[size] = '\0';
|
||
|
||
const char* p = strstr(buf, "<key>CFBundleShortVersionString</key>");
|
||
if (p)
|
||
{
|
||
p += strlen("<key>CFBundleShortVersionString</key>");
|
||
p = strchr(p, '>');
|
||
if (p)
|
||
{
|
||
p++;
|
||
const char* end = strchr(p, '<');
|
||
if (end)
|
||
{
|
||
ffStrbufSetNS(version, (uint32_t) (end - p), p);
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
ffStrbufClear(version);
|
||
}
|
||
#endif
|
||
|
||
char versionHex[64];
|
||
// https://github.com/fastfetch-cli/fastfetch/discussions/1030#discussioncomment-9845233
|
||
if (ffGetTerminalResponse(
|
||
"\eP+q6b697474792d71756572792d76657273696f6e\e\\", // kitty-query-version
|
||
1,
|
||
"\eP1+r%*[^=]=%63[^\e]\e\\\\", versionHex) == NULL)
|
||
{
|
||
// decode hex string
|
||
for (const char* p = versionHex; p[0] && p[1]; p += 2)
|
||
{
|
||
unsigned value;
|
||
if (sscanf(p, "%2x", &value) == 1)
|
||
ffStrbufAppendC(version, (char) value);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
//kitty 0.21.2 created by Kovid Goyal
|
||
return getExeVersionGeneral(exe, version);
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionPtyxis(FF_MAYBE_UNUSED FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdOut(version, (char* const[]) {
|
||
"ptyxis",
|
||
"--version",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
ffStrbufSubstrBeforeFirstC(version, '\n');
|
||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionTilix(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if (exe->chars[0] == '/')
|
||
{
|
||
ffBinaryExtractStrings(exe->chars, extractGeneralVersion, version, (uint32_t) strlen("0.0.0"));
|
||
if (version->length) return true;
|
||
}
|
||
|
||
if(ffProcessAppendStdOut(version, (char* const[]) {
|
||
exe->chars,
|
||
"--version",
|
||
NULL
|
||
}) != NULL)
|
||
return false;
|
||
|
||
uint32_t index = ffStrbufFirstIndexS(version, "Tilix version: ");
|
||
if (index == version->length) return false;
|
||
|
||
index += (uint32_t) strlen("Tilix version:");
|
||
uint32_t end = ffStrbufNextIndexC(version, index, '\n');
|
||
|
||
ffStrbufSubstrBefore(version, end);
|
||
ffStrbufSubstrAfter(version, index);
|
||
return true;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionSakura(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdErr(version, (char* const[]) {
|
||
exe->chars,
|
||
"--version",
|
||
NULL
|
||
}) != NULL) // sakura version is 3.8.8
|
||
return false;
|
||
|
||
ffStrbufSubstrAfterLastC(version, ' ');
|
||
return true;
|
||
}
|
||
|
||
FF_MAYBE_UNUSED static bool getTerminalVersionTermite(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if(ffProcessAppendStdOut(version, (char* const[]) {
|
||
exe->chars,
|
||
"--version",
|
||
NULL
|
||
}) != NULL) // termite v16.9\nvte 0.78.1 +BIDI +GNUTLS +ICU +SYSTEMD
|
||
return false;
|
||
|
||
ffStrbufSubstrBeforeFirstC(version, '\n');
|
||
ffStrbufSubstrAfterLastC(version, 'v');
|
||
return true;
|
||
}
|
||
#endif
|
||
|
||
#ifdef _WIN32
|
||
|
||
static bool getTerminalVersionWindowsTerminal(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
FF_STRBUF_AUTO_DESTROY buildInfoPath;
|
||
ffStrbufInitNS(&buildInfoPath, ffStrbufLastIndexC(exe, '\\') + 1, exe->chars);
|
||
ffStrbufAppendS(&buildInfoPath, "BuildInfo.xml");
|
||
|
||
if(ffParsePropFile(buildInfoPath.chars, "StoreVersion=\"", version))
|
||
{
|
||
ffStrbufTrimRight(version, '"');
|
||
return true;
|
||
}
|
||
|
||
return getFileVersion(exe, NULL, version);
|
||
}
|
||
|
||
static bool getTerminalVersionConEmu(FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
ffStrbufSetS(version, getenv("ConEmuBuild"));
|
||
|
||
if(version->length)
|
||
return true;
|
||
|
||
return getFileVersion(exe, NULL, version);
|
||
}
|
||
|
||
#endif
|
||
|
||
bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe, FFstrbuf* version)
|
||
{
|
||
if (!instance.config.general.detectVersion) return false;
|
||
|
||
#ifdef __ANDROID__
|
||
|
||
if(ffStrbufEqualS(processName, "com.termux"))
|
||
return getTerminalVersionTermux(version);
|
||
|
||
#endif
|
||
|
||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__HAIKU__)
|
||
|
||
if(ffStrbufStartsWithIgnCaseS(processName, "gnome-terminal"))
|
||
return getTerminalVersionGnome(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "konsole"))
|
||
return getTerminalVersionKonsole(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "yakuake"))
|
||
return getTerminalVersionKonsole(exe, version); // yakuake shares code with konsole
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "xfce4-terminal"))
|
||
return getTerminalVersionXfce4Terminal(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "terminator"))
|
||
return getExeVersionGeneral(exe, version);//terminator 2.1.3
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "deepin-terminal"))
|
||
return getExeVersionGeneral(exe, version);//deepin-terminal 5.4.36
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "foot"))
|
||
return getTerminalVersionFoot(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "qterminal"))
|
||
return getExeVersionRaw(exe, version); //1.2.0
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "mate-terminal"))
|
||
return getTerminalVersionMateTerminal(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "cockpit-bridge"))
|
||
return getTerminalVersionCockpit(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "xterm"))
|
||
return getTerminalVersionXterm(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "blackbox"))
|
||
return getTerminalVersionBlackbox(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "st"))
|
||
return getTerminalVersionSt(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "lxterminal"))
|
||
return getTerminalVersionLxterminal(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "weston-terminal"))
|
||
return getTerminalVersionWeston(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "urxvt") ||
|
||
ffStrbufIgnCaseEqualS(processName, "urxvtd") ||
|
||
ffStrbufIgnCaseEqualS(processName, "rxvt") ||
|
||
ffStrbufIgnCaseEqualS(processName, "rxvt-unicode")
|
||
)
|
||
return getTerminalVersionUrxvt(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "ptyxis-agent"))
|
||
return getTerminalVersionPtyxis(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "tilix"))
|
||
return getTerminalVersionTilix(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "sakura"))
|
||
return getTerminalVersionSakura(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "termite"))
|
||
return getTerminalVersionTermite(exe, version);
|
||
|
||
#endif
|
||
|
||
#ifdef _WIN32
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "WindowsTerminal.exe"))
|
||
return getTerminalVersionWindowsTerminal(exe, version);
|
||
|
||
if(ffStrbufStartsWithIgnCaseS(processName, "ConEmu"))
|
||
return getTerminalVersionConEmu(exe, version);
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "warp.exe"))
|
||
return getFileVersion(exe, L"ProductVersion", version);
|
||
|
||
#endif
|
||
|
||
#ifndef _WIN32
|
||
|
||
if(ffStrbufIgnCaseEqualS(processName, "kitty"))
|
||
return getTerminalVersionKitty(exe, version);
|
||
|
||
if (ffStrbufIgnCaseEqualS(processName, "Tabby") && getExeVersionRaw(exe, version))
|
||
return true;
|
||
|
||
#endif
|
||
|
||
if(ffStrbufStartsWithIgnCaseS(processName, "alacritty"))
|
||
return getExeVersionGeneral(exe, version);
|
||
|
||
if(ffStrbufStartsWithIgnCaseS(processName, "contour"))
|
||
return getTerminalVersionContour(exe, version);
|
||
|
||
if(ffStrbufStartsWithIgnCaseS(processName, "screen"))
|
||
return getTerminalVersionScreen(exe, version);
|
||
|
||
if(ffStrbufStartsWithIgnCaseS(processName, "zellij"))
|
||
return getTerminalVersionZellij(exe, version);
|
||
|
||
if(ffStrbufStartsWithIgnCaseS(processName, "zed"))
|
||
return getTerminalVersionZed(exe, version);
|
||
|
||
#if __HAIKU__
|
||
if(ffStrbufEqualS(processName, "Terminal"))
|
||
return ffGetFileVersion(exe->chars, version);
|
||
#endif
|
||
|
||
const char* termProgramVersion = getenv("TERM_PROGRAM_VERSION");
|
||
if(termProgramVersion)
|
||
{
|
||
const char* termProgram = getenv("TERM_PROGRAM");
|
||
if(termProgram)
|
||
{
|
||
if(ffStrbufStartsWithIgnCaseS(processName, termProgram) || // processName ends with `.exe` on Windows
|
||
(ffStrEquals(termProgram, "vscode") && ffStrbufStartsWithIgnCaseS(processName, "code")) ||
|
||
|
||
#ifdef __APPLE__
|
||
(ffStrEquals(termProgram, "iTerm.app") && ffStrbufStartsWithIgnCaseS(processName, "iTermServer-")) ||
|
||
#elif defined(__linux__)
|
||
(ffStrEquals(termProgram, "WarpTerminal") && ffStrbufEqualS(processName, "warp")) ||
|
||
#endif
|
||
false
|
||
) {
|
||
ffStrbufSetS(version, termProgramVersion);
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
termProgramVersion = getenv("LC_TERMINAL_VERSION");
|
||
if(termProgramVersion)
|
||
{
|
||
const char* termProgram = getenv("LC_TERMINAL");
|
||
if(termProgram)
|
||
{
|
||
if(ffStrbufStartsWithIgnCaseS(processName, termProgram) || // processName ends with `.exe` on Windows
|
||
(ffStrEquals(termProgram, "vscode") && ffStrbufStartsWithIgnCaseS(processName, "code")) ||
|
||
(ffStrStartsWith(termProgram, "iTerm") && ffStrbufStartsWithIgnCaseS(processName, "iTermServer-"))
|
||
) {
|
||
ffStrbufSetS(version, termProgramVersion);
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
if(ffStrbufStartsWithIgnCaseS(processName, "tmux"))
|
||
return getTerminalVersionTmux(exe, version);
|
||
|
||
#ifdef _WIN32
|
||
|
||
return getFileVersion(exe, NULL, version);
|
||
|
||
#else
|
||
|
||
return false;
|
||
|
||
#endif
|
||
}
|