summaryrefslogtreecommitdiffstats
path: root/src/detection/terminaltheme/terminaltheme.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/terminaltheme/terminaltheme.c
Add the files
Diffstat (limited to 'src/detection/terminaltheme/terminaltheme.c')
-rw-r--r--src/detection/terminaltheme/terminaltheme.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/detection/terminaltheme/terminaltheme.c b/src/detection/terminaltheme/terminaltheme.c
new file mode 100644
index 0000000..e609754
--- /dev/null
+++ b/src/detection/terminaltheme/terminaltheme.c
@@ -0,0 +1,105 @@
+#include "terminaltheme.h"
+#include "common/io.h"
+#include "common/strutil.h"
+
+#include <inttypes.h>
+
+static bool detectByEscapeCode(FFTerminalThemeResult* result) {
+ // Windows Terminal removes all `\e`s in its output
+ if (ffGetTerminalResponse("\e]10;?\e\\" /*fg*/ "\e]11;?\e\\" /*bg*/,
+ 6,
+ "%*[^0-9]10;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 /*"\e\\"*/ "%*[^0-9]11;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 /*"\e\\"*/,
+ &result->fg.r,
+ &result->fg.g,
+ &result->fg.b,
+ &result->bg.r,
+ &result->bg.g,
+ &result->bg.b) == NULL) {
+ if (result->fg.r > 0x0100 || result->fg.g > 0x0100 || result->fg.b > 0x0100) {
+ result->fg.r /= 0x0100, result->fg.g /= 0x0100, result->fg.b /= 0x0100;
+ }
+ if (result->bg.r > 0x0100 || result->bg.g > 0x0100 || result->bg.b > 0x0100) {
+ result->bg.r /= 0x0100, result->bg.g /= 0x0100, result->bg.b /= 0x0100;
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+static FFTerminalThemeColor fgbgToColor(int num) {
+ // https://github.com/dalance/termbg/blob/13c478a433fa182e65c401d26a1e7792a7f7f453/src/lib.rs#L251
+ switch (num) {
+ case 0:
+ return (FFTerminalThemeColor) { 0, 0, 0, false }; // black
+ case 1:
+ return (FFTerminalThemeColor) { 205, 0, 0, false }; // red
+ case 2:
+ return (FFTerminalThemeColor) { 0, 205, 0, false }; // green
+ case 3:
+ return (FFTerminalThemeColor) { 205, 205, 0, false }; // yellow
+ case 4:
+ return (FFTerminalThemeColor) { 0, 0, 238, false }; // blue
+ case 5:
+ return (FFTerminalThemeColor) { 205, 0, 205, false }; // magenta
+ case 6:
+ return (FFTerminalThemeColor) { 0, 205, 205, false }; // cyan
+ case 7:
+ return (FFTerminalThemeColor) { 229, 229, 229, false }; // white
+
+ case 8:
+ return (FFTerminalThemeColor) { 127, 127, 127, false }; // bright black
+ case 9:
+ return (FFTerminalThemeColor) { 255, 0, 0, false }; // bright red
+ case 10:
+ return (FFTerminalThemeColor) { 0, 255, 0, false }; // bright green
+ case 11:
+ return (FFTerminalThemeColor) { 255, 255, 0, false }; // bright yellow
+ case 12:
+ return (FFTerminalThemeColor) { 92, 92, 255, false }; // bright blue
+ case 13:
+ return (FFTerminalThemeColor) { 255, 0, 255, false }; // bright magenta
+ case 14:
+ return (FFTerminalThemeColor) { 0, 255, 255, false }; // bright cyan
+ case 15:
+ return (FFTerminalThemeColor) { 255, 255, 255, false }; // bright white
+
+ default:
+ return (FFTerminalThemeColor) { 0, 0, 0, false }; // invalid
+ }
+}
+
+static bool detectByEnv(FFTerminalThemeResult* result) {
+ const char* color = getenv("COLORFGBG"); // 7;0
+
+ if (!ffStrSet(color)) {
+ return false;
+ }
+
+ int f, g;
+ if (sscanf(color, "%d;%d", &f, &g) != 2) {
+ return false;
+ }
+
+ result->fg = fgbgToColor(f);
+ result->bg = fgbgToColor(g);
+ return true;
+}
+
+static inline bool detectColor(FFTerminalThemeResult* result, bool forceEnv) {
+ if (!forceEnv && detectByEscapeCode(result)) {
+ return true;
+ }
+
+ return detectByEnv(result);
+}
+
+bool ffDetectTerminalTheme(FFTerminalThemeResult* result, bool forceEnv) {
+ if (!detectColor(result, forceEnv)) {
+ return false;
+ }
+ result->fg.dark = result->fg.r * 299 + result->fg.g * 587 + result->fg.b * 114 < 128000;
+ result->bg.dark = result->bg.r * 299 + result->bg.g * 587 + result->bg.b * 114 < 128000;
+ return true;
+}