master ohmu/fastfetch-openbsd / src / detection / terminaltheme / terminaltheme.c
ohmu  ·  2026-10-15
  1#include "terminaltheme.h"
  2#include "common/io.h"
  3#include "common/strutil.h"
  4
  5#include <inttypes.h>
  6
  7static bool detectByEscapeCode(FFTerminalThemeResult* result) {
  8    // Windows Terminal removes all `\e`s in its output
  9    if (ffGetTerminalResponse("\e]10;?\e\\" /*fg*/ "\e]11;?\e\\" /*bg*/,
 10            6,
 11            "%*[^0-9]10;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 /*"\e\\"*/ "%*[^0-9]11;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 /*"\e\\"*/,
 12            &result->fg.r,
 13            &result->fg.g,
 14            &result->fg.b,
 15            &result->bg.r,
 16            &result->bg.g,
 17            &result->bg.b) == nullptr) {
 18        if (result->fg.r > 0x0100 || result->fg.g > 0x0100 || result->fg.b > 0x0100) {
 19            result->fg.r /= 0x0100, result->fg.g /= 0x0100, result->fg.b /= 0x0100;
 20        }
 21        if (result->bg.r > 0x0100 || result->bg.g > 0x0100 || result->bg.b > 0x0100) {
 22            result->bg.r /= 0x0100, result->bg.g /= 0x0100, result->bg.b /= 0x0100;
 23        }
 24    } else {
 25        return false;
 26    }
 27
 28    return true;
 29}
 30
 31static FFTerminalThemeColor fgbgToColor(int num) {
 32    // https://github.com/dalance/termbg/blob/13c478a433fa182e65c401d26a1e7792a7f7f453/src/lib.rs#L251
 33    switch (num) {
 34        case 0:
 35            return (FFTerminalThemeColor) { 0, 0, 0, false }; // black
 36        case 1:
 37            return (FFTerminalThemeColor) { 205, 0, 0, false }; // red
 38        case 2:
 39            return (FFTerminalThemeColor) { 0, 205, 0, false }; // green
 40        case 3:
 41            return (FFTerminalThemeColor) { 205, 205, 0, false }; // yellow
 42        case 4:
 43            return (FFTerminalThemeColor) { 0, 0, 238, false }; // blue
 44        case 5:
 45            return (FFTerminalThemeColor) { 205, 0, 205, false }; // magenta
 46        case 6:
 47            return (FFTerminalThemeColor) { 0, 205, 205, false }; // cyan
 48        case 7:
 49            return (FFTerminalThemeColor) { 229, 229, 229, false }; // white
 50
 51        case 8:
 52            return (FFTerminalThemeColor) { 127, 127, 127, false }; // bright black
 53        case 9:
 54            return (FFTerminalThemeColor) { 255, 0, 0, false }; // bright red
 55        case 10:
 56            return (FFTerminalThemeColor) { 0, 255, 0, false }; // bright green
 57        case 11:
 58            return (FFTerminalThemeColor) { 255, 255, 0, false }; // bright yellow
 59        case 12:
 60            return (FFTerminalThemeColor) { 92, 92, 255, false }; // bright blue
 61        case 13:
 62            return (FFTerminalThemeColor) { 255, 0, 255, false }; // bright magenta
 63        case 14:
 64            return (FFTerminalThemeColor) { 0, 255, 255, false }; // bright cyan
 65        case 15:
 66            return (FFTerminalThemeColor) { 255, 255, 255, false }; // bright white
 67
 68        default:
 69            return (FFTerminalThemeColor) { 0, 0, 0, false }; // invalid
 70    }
 71}
 72
 73static bool detectByEnv(FFTerminalThemeResult* result) {
 74    const char* color = getenv("COLORFGBG"); // 7;0
 75
 76    if (!ffStrSet(color)) {
 77        return false;
 78    }
 79
 80    int f, g;
 81    if (sscanf(color, "%d;%d", &f, &g) != 2) {
 82        return false;
 83    }
 84
 85    result->fg = fgbgToColor(f);
 86    result->bg = fgbgToColor(g);
 87    return true;
 88}
 89
 90static inline bool detectColor(FFTerminalThemeResult* result, bool forceEnv) {
 91    if (!forceEnv && detectByEscapeCode(result)) {
 92        return true;
 93    }
 94
 95    return detectByEnv(result);
 96}
 97
 98bool ffDetectTerminalTheme(FFTerminalThemeResult* result, bool forceEnv) {
 99    if (!detectColor(result, forceEnv)) {
100        return false;
101    }
102    result->fg.dark = result->fg.r * 299 + result->fg.g * 587 + result->fg.b * 114 < 128000;
103    result->bg.dark = result->bg.r * 299 + result->bg.g * 587 + result->bg.b * 114 < 128000;
104    return true;
105}