Skip to content

Commit 6efe186

Browse files
Merge pull request #254 from CarterLi/master
TerminalFont: support Windows Terminal on WSL
2 parents f33f172 + d6a1caa commit 6efe186

File tree

11 files changed

+205
-7
lines changed

11 files changed

+205
-7
lines changed

.github/workflows/push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
uses: actions/checkout@v3
1818

1919
- name: install required packages
20-
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev
20+
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libcjson-dev
2121

2222
- name: Initialize CodeQL
2323
uses: github/codeql-action/init@v2

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR BSD" OFF)
4747
cmake_dependent_option(ENABLE_OSMESA "Enable osmesa" ON "LINUX OR BSD" OFF)
4848
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD" OFF)
4949
cmake_dependent_option(ENABLE_LIBPLIST "Enable libplist" ON "APPLE" OFF)
50+
cmake_dependent_option(ENABLE_LIBCJSON "Enable libcjson" ON "LINUX" OFF)
5051

5152
option(BUILD_TESTS "Build tests" OFF) # Also create test executables
5253
option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds
@@ -375,6 +376,7 @@ ff_lib_enable(GLX glx)
375376
ff_lib_enable(OSMESA osmesa)
376377
ff_lib_enable(OPENCL OpenCL)
377378
ff_lib_enable(LIBPLIST libplist-2.0)
379+
ff_lib_enable(LIBCJSON libcjson)
378380

379381
if(APPLE)
380382
target_link_libraries(libfastfetch

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ The following libraries are used if present at runtime:
4545
* [`libsqlite3`](https://www.sqlite.org/index.html): Needed for pkg & rpm package count.
4646
* [`librpm`](http://rpm.org/): Slower fallback for rpm package count. Needed on openSUSE.
4747
* [`libplist`](https://github.com/libimobiledevice/libplist): Binary `plist` file parser ( macOS ). Needed for iTerm2 Terminal font and WM Theme.
48+
* [`libcJSON`](https://github.com/DaveGamble/cJSON): Needed for Windows Terminal font ( WSL ).
4849

4950
## Support status
5051
All categories not listed here should work without needing a specific implementation.
@@ -81,7 +82,7 @@ KDE Plasma, Gnome, Cinnamon, Mate, XFCE4, LXQt
8182

8283
##### Terminal fonts
8384
```
84-
Konsole, Gnome Terminal, Tilix, XFCE4 Terminal, Alacritty, LXTerminal, iTerm2, Apple Terminal, TTY
85+
Konsole, Gnome Terminal, Tilix, XFCE4 Terminal, Alacritty, LXTerminal, iTerm2, Apple Terminal, TTY, Windows Terminal
8586
```
8687

8788
## Building

src/common/init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ static void defaultConfig(FFinstance* instance)
218218
ffStrbufInitA(&instance->config.libOSMesa, 0);
219219
ffStrbufInitA(&instance->config.libOpenCL, 0);
220220
ffStrbufInitA(&instance->config.libplist, 0);
221+
ffStrbufInitA(&instance->config.libcJSON, 0);
221222

222223
instance->config.titleFQDN = false;
223224

src/data/config_user.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,3 +324,4 @@
324324
#--lib-osmesa /usr/lib/libOSMesa.so
325325
#--lib-opencl /usr/lib/libOpenCL.so
326326
#--lib-plist /usr/local/bin/libplist-2.0.dylib
327+
#--lib-cjson /usr/lib/libcjson.so

src/data/help.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Library options: Set the path of a library to load
8585
--lib-osmesa <path>
8686
--lib-opencl <path>
8787
--lib-plist <path>
88+
--lib-cjson <path>
8889

8990
Module specific options:
9091
--title-fqdn <?value>: Sets if the title should use fully qualified domain name. Default is false.

src/detection/terminalShell.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ static void getTerminalFromEnv(FFTerminalShellResult* result)
153153
if(!ffStrSet(term))
154154
term = getenv("TERM_PROGRAM");
155155

156+
//We are in WSL but not in Windows Terminal
157+
if(!ffStrSet(term) && (
158+
getenv("WSLENV") != NULL ||
159+
getenv("WSL_DISTRO") != NULL ||
160+
getenv("WSL_INTEROP") != NULL
161+
))
162+
term = "conhost";
163+
156164
//Normal Terminal
157165
if(!ffStrSet(term))
158166
term = getenv("TERM");

src/detection/terminalfont/terminalfont_apple.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,13 @@ static const char* iterm2ParsePList(const FFinstance* instance, const FFstrbuf*
3232
else
3333
ffplist_from_xml(content->chars, content->length, &root_node);
3434

35+
const char* error = NULL;
36+
3537
if(root_node == NULL)
36-
return "parsing iTerm preference file failed";
38+
{
39+
error = "parsing iTerm preference file failed";
40+
goto exit;
41+
}
3742

3843
plist_t bookmarks = ffplist_access_path(root_node, 1, "New Bookmarks");
3944

@@ -50,20 +55,22 @@ static const char* iterm2ParsePList(const FFinstance* instance, const FFstrbuf*
5055

5156
if(item == NULL)
5257
{
53-
ffplist_free(root_node);
54-
return "find profile bookmark failed";
58+
error = "find profile bookmark failed";
59+
goto exit;
5560
}
5661

5762
item = ffplist_dict_get_item(item, "Normal Font");
5863
if (item == NULL)
5964
{
60-
ffplist_free(root_node);
61-
return "find Normal Font key failed";
65+
error = "find Normal Font key failed";
66+
goto exit;
6267
}
6368

6469
ffFontInitWithSpace(&terminalFont->font, ffplist_get_string_ptr(item, NULL));
6570

71+
exit:
6672
ffplist_free(root_node);
73+
dlclose(libplist);
6774
return NULL;
6875
}
6976

src/detection/terminalfont/terminalfont_linux.c

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,178 @@ static void detectXFCETerminal(const FFinstance* instance, FFTerminalFontResult*
140140
ffStrbufDestroy(&useSysFont);
141141
}
142142

143+
#ifdef FF_HAVE_LIBCJSON
144+
145+
#include "common/library.h"
146+
#include "common/processing.h"
147+
148+
#include <cjson/cJSON.h>
149+
#include <stdlib.h>
150+
151+
typedef struct CJSONData
152+
{
153+
FF_LIBRARY_SYMBOL(cJSON_Parse)
154+
FF_LIBRARY_SYMBOL(cJSON_IsObject)
155+
FF_LIBRARY_SYMBOL(cJSON_GetObjectItemCaseSensitive)
156+
FF_LIBRARY_SYMBOL(cJSON_IsString)
157+
FF_LIBRARY_SYMBOL(cJSON_GetStringValue)
158+
FF_LIBRARY_SYMBOL(cJSON_IsNumber)
159+
FF_LIBRARY_SYMBOL(cJSON_GetNumberValue)
160+
FF_LIBRARY_SYMBOL(cJSON_IsArray)
161+
FF_LIBRARY_SYMBOL(cJSON_Delete)
162+
} CJSONData;
163+
164+
static const char* detectWTProfile(CJSONData* cjsonData, cJSON* profile, FFstrbuf* name, int* size)
165+
{
166+
if(!cjsonData->ffcJSON_IsObject(profile))
167+
return "cJSON_IsObject(profile) returns false";
168+
169+
cJSON* font = cjsonData->ffcJSON_GetObjectItemCaseSensitive(profile, "font");
170+
if(!cjsonData->ffcJSON_IsObject(font))
171+
return "cJSON_IsObject(font) returns false";
172+
173+
if(name->length == 0)
174+
{
175+
cJSON* pface = cjsonData->ffcJSON_GetObjectItemCaseSensitive(font, "face");
176+
if(cjsonData->ffcJSON_IsString(pface))
177+
ffStrbufAppendS(name, cjsonData->ffcJSON_GetStringValue(pface));
178+
}
179+
if(*size < 0)
180+
{
181+
cJSON* psize = cjsonData->ffcJSON_GetObjectItemCaseSensitive(font, "size");
182+
if(cjsonData->ffcJSON_IsNumber(psize))
183+
*size = (int)cjsonData->ffcJSON_GetNumberValue(psize);
184+
}
185+
return NULL;
186+
}
187+
188+
static const char* detectFromWTImpl(const FFinstance* instance, FFstrbuf* content, FFstrbuf* name, int* size)
189+
{
190+
CJSONData cjsonData;
191+
192+
FF_LIBRARY_LOAD(libcjson, &instance->config.libcJSON, "dlopen libcjson failed", "libcjson"FF_LIBRARY_EXTENSION, 1)
193+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_Parse)
194+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_IsObject)
195+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_GetObjectItemCaseSensitive)
196+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_IsString)
197+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_GetStringValue)
198+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_IsNumber)
199+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_GetNumberValue)
200+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_IsArray)
201+
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_Delete)
202+
203+
const char* error = NULL;
204+
205+
cJSON* root = cjsonData.ffcJSON_Parse(content->chars);
206+
if(!cjsonData.ffcJSON_IsObject(root))
207+
{
208+
error = "cJSON_Parse() failed";
209+
goto exit;
210+
}
211+
212+
cJSON* profiles = cjsonData.ffcJSON_GetObjectItemCaseSensitive(root, "profiles");
213+
if(!cjsonData.ffcJSON_IsObject(profiles))
214+
{
215+
error = "cJSON_GetObjectItemCaseSensitive(root, \"profiles\") failed";
216+
goto exit;
217+
}
218+
219+
FFstrbuf wtProfileId;
220+
ffStrbufInitS(&wtProfileId, getenv("WT_PROFILE_ID"));
221+
ffStrbufTrim(&wtProfileId, '\'');
222+
if(wtProfileId.length > 0)
223+
{
224+
cJSON* list = cjsonData.ffcJSON_GetObjectItemCaseSensitive(profiles, "list");
225+
if(cjsonData.ffcJSON_IsArray(list))
226+
{
227+
cJSON* profile;
228+
cJSON_ArrayForEach(profile, list)
229+
{
230+
if(!cjsonData.ffcJSON_IsObject(profile))
231+
continue;
232+
cJSON* guid = cjsonData.ffcJSON_GetObjectItemCaseSensitive(profile, "guid");
233+
if(!cjsonData.ffcJSON_IsString(guid))
234+
continue;
235+
if(ffStrbufCompS(&wtProfileId, cjsonData.ffcJSON_GetStringValue(guid)) == 0)
236+
{
237+
detectWTProfile(&cjsonData, profile, name, size);
238+
break;
239+
}
240+
}
241+
}
242+
}
243+
ffStrbufDestroy(&wtProfileId);
244+
245+
cJSON* defaults = cjsonData.ffcJSON_GetObjectItemCaseSensitive(profiles, "defaults");
246+
detectWTProfile(&cjsonData, defaults, name, size);
247+
248+
if(name->length == 0)
249+
ffStrbufSetS(name, "Cascadia Mono");
250+
if(*size < 0)
251+
*size = 12;
252+
253+
exit:
254+
cjsonData.ffcJSON_Delete(root);
255+
dlclose(libcjson);
256+
return error;
257+
}
258+
259+
static void detectFromWindowsTeriminal(const FFinstance* instance, FFTerminalFontResult* terminalFont)
260+
{
261+
//https://learn.microsoft.com/en-us/windows/terminal/install#settings-json-file
262+
FFstrbuf json;
263+
ffStrbufInit(&json);
264+
const char* error;
265+
error = ffProcessAppendStdOut(&json, (char* const[]) {
266+
"cmd.exe",
267+
"/c",
268+
//print the file content directly, so we don't need to handle the difference of Windows and POSIX path
269+
"if exist %LOCALAPPDATA%\\Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\settings.json "
270+
"( type %LOCALAPPDATA%\\Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\settings.json ) "
271+
"else if exist %LOCALAPPDATA%\\Packages\\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\\LocalState\\settings.json "
272+
"( type %LOCALAPPDATA%\\Packages\\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\\LocalState\\settings.json ) "
273+
"else if exist \"%LOCALAPPDATA%\\Microsoft\\Windows Terminal\\settings.json\" "
274+
"( type %LOCALAPPDATA%\\Microsoft\\Windows Terminal\\settings.json ) "
275+
"else ( call )",
276+
NULL
277+
});
278+
if(error)
279+
{
280+
ffStrbufAppendS(&terminalFont->error, error);
281+
ffStrbufDestroy(&json);
282+
return;
283+
}
284+
ffStrbufTrimRight(&json, '\n');
285+
if(json.length == 0)
286+
{
287+
ffStrbufAppendS(&terminalFont->error, "Cannot find file \"settings.json\"");
288+
ffStrbufDestroy(&json);
289+
return;
290+
}
291+
292+
FFstrbuf name;
293+
ffStrbufInit(&name);
294+
int size = -1;
295+
detectFromWTImpl(instance, &json, &name, &size);
296+
ffStrbufDestroy(&json);
297+
298+
char sizeStr[16];
299+
snprintf(sizeStr, sizeof(sizeStr), "%d", size);
300+
ffFontInitValues(&terminalFont->font, name.chars, sizeStr);
301+
302+
ffStrbufDestroy(&name);
303+
}
304+
305+
#else
306+
307+
static void detectFromWindowsTeriminal(const FFinstance* instance, FFTerminalFontResult* terminalFont)
308+
{
309+
FF_UNUSED(instance, terminalFont);
310+
ffStrbufAppendS(&terminalFont->error, "fastfetch is built without libcjson support");
311+
}
312+
313+
#endif
314+
143315
void ffDetectTerminalFontPlatform(const FFinstance* instance, const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont)
144316
{
145317
if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "konsole") == 0)
@@ -152,4 +324,6 @@ void ffDetectTerminalFontPlatform(const FFinstance* instance, const FFTerminalSh
152324
detectFromGSettings(instance, "/com/gexperts/Tilix/profiles/", "com.gexperts.Tilix.ProfilesList", "com.gexperts.Tilix.Profile", terminalFont);
153325
else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "gnome-terminal-") == 0)
154326
detectFromGSettings(instance, "/org/gnome/terminal/legacy/profiles:/:", "org.gnome.Terminal.ProfilesList", "org.gnome.Terminal.Legacy.Profile", terminalFont);
327+
else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "Windows Terminal") == 0)
328+
detectFromWindowsTeriminal(instance, terminalFont);
155329
}

src/fastfetch.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
12461246
optionParseString(key, value, &instance->config.libOpenCL);
12471247
else if(strcasecmp(key, "--lib-plist") == 0)
12481248
optionParseString(key, value, &instance->config.libplist);
1249+
else if(strcasecmp(key, "--lib-cjson") == 0)
1250+
optionParseString(key, value, &instance->config.libcJSON);
12491251

12501252
//////////////////
12511253
//Module options//

0 commit comments

Comments
 (0)