@@ -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+
143315void 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}
0 commit comments