1+ use std:: path:: PathBuf ;
2+ use std:: process:: exit;
3+ use crate :: { app:: apps:: App , config:: Config , utils:: index_installed_apps} ;
4+
5+
6+ fn get_installed_apps ( dir : impl AsRef < Path > , store_icons : bool ) -> Vec < App > {
7+ let entries: Vec < _ > = fs:: read_dir ( dir. as_ref ( ) )
8+ . unwrap_or_else ( |x| {
9+ tracing:: error!(
10+ "An error occurred while reading dir ({}) {}" ,
11+ dir. as_ref( ) . to_str( ) . unwrap_or( "" ) ,
12+ x
13+ ) ;
14+ exit ( -1 )
15+ } )
16+ . filter_map ( |x| x. ok ( ) )
17+ . collect ( ) ;
18+
19+ entries
20+ . into_par_iter ( )
21+ . filter_map ( |x| {
22+ let file_type = x. file_type ( ) . unwrap_or_else ( |e| {
23+ tracing:: error!( "Failed to get file type: {}" , e. to_string( ) ) ;
24+ exit ( -1 )
25+ } ) ;
26+ if !file_type. is_dir ( ) {
27+ return None ;
28+ }
29+
30+ let file_name_os = x. file_name ( ) ;
31+ let file_name = file_name_os. into_string ( ) . unwrap_or_else ( |e| {
32+ tracing:: error!( "Failed to to get file_name_os: {}" , e. to_string_lossy( ) ) ;
33+ exit ( -1 )
34+ } ) ;
35+ if !file_name. ends_with ( ".app" ) {
36+ return None ;
37+ }
38+
39+ let path = x. path ( ) ;
40+ let path_str = path. to_str ( ) . map ( |x| x. to_string ( ) ) . unwrap_or_else ( || {
41+ tracing:: error!( "Unable to get file_name" ) ;
42+ exit ( -1 )
43+ } ) ;
44+
45+ let icons = if store_icons {
46+ match fs:: read_to_string ( format ! ( "{}/Contents/Info.plist" , path_str) ) . map (
47+ |content| {
48+ let icon_line = content
49+ . lines ( )
50+ . scan ( false , |expect_next, line| {
51+ if * expect_next {
52+ * expect_next = false ;
53+ // Return this line to the iterator
54+ return Some ( Some ( line) ) ;
55+ }
56+
57+ if line. trim ( ) == "<key>CFBundleIconFile</key>" {
58+ * expect_next = true ;
59+ }
60+
61+ // For lines that are not the one after the key, return None to skip
62+ Some ( None )
63+ } )
64+ . flatten ( ) // remove the Nones
65+ . next ( )
66+ . map ( |x| {
67+ x. trim ( )
68+ . strip_prefix ( "<string>" )
69+ . unwrap_or ( "" )
70+ . strip_suffix ( "</string>" )
71+ . unwrap_or ( "" )
72+ } ) ;
73+
74+ handle_from_icns ( Path :: new ( & format ! (
75+ "{}/Contents/Resources/{}" ,
76+ path_str,
77+ icon_line. unwrap_or( "AppIcon.icns" )
78+ ) ) )
79+ } ,
80+ ) {
81+ Ok ( Some ( a) ) => Some ( a) ,
82+ _ => {
83+ // Fallback method
84+ let direntry = fs:: read_dir ( format ! ( "{}/Contents/Resources" , path_str) )
85+ . into_iter ( )
86+ . flatten ( )
87+ . filter_map ( |x| {
88+ let file = x. ok ( ) ?;
89+ let name = file. file_name ( ) ;
90+ let file_name = name. to_str ( ) ?;
91+ if file_name. ends_with ( ".icns" ) {
92+ Some ( file. path ( ) )
93+ } else {
94+ None
95+ }
96+ } )
97+ . collect :: < Vec < PathBuf > > ( ) ;
98+
99+ if direntry. len ( ) > 1 {
100+ let icns_vec = direntry
101+ . iter ( )
102+ . filter ( |x| x. ends_with ( "AppIcon.icns" ) )
103+ . collect :: < Vec < & PathBuf > > ( ) ;
104+ handle_from_icns ( icns_vec. first ( ) . unwrap_or ( & & PathBuf :: new ( ) ) )
105+ } else if !direntry. is_empty ( ) {
106+ handle_from_icns ( direntry. first ( ) . unwrap_or ( & PathBuf :: new ( ) ) )
107+ } else {
108+ None
109+ }
110+ }
111+ }
112+ } else {
113+ None
114+ } ;
115+
116+ let name = file_name. strip_suffix ( ".app" ) . unwrap ( ) . to_string ( ) ;
117+ Some ( App :: new_executable (
118+ & name,
119+ & name. to_lowercase ( ) ,
120+ "Application" ,
121+ path,
122+ icons,
123+ ) )
124+ } )
125+ . collect ( )
126+ }
127+
128+ pub fn get_installed_macos_apps ( config : & Config ) -> anyhow:: Result < Vec < App > > {
129+ let store_icons = config. theme . show_icons ;
130+ let user_local_path = std:: env:: var ( "HOME" ) . unwrap ( ) + "/Applications/" ;
131+ let paths: Vec < String > = vec ! [
132+ "/Applications/" . to_string( ) ,
133+ user_local_path. to_string( ) ,
134+ "/System/Applications/" . to_string( ) ,
135+ "/System/Applications/Utilities/" . to_string( ) ,
136+ ] ;
137+
138+ let mut apps = index_installed_apps ( config) ?;
139+ apps. par_extend (
140+ paths
141+ . par_iter ( )
142+ . map ( |path| get_installed_apps ( path, store_icons) )
143+ . flatten ( ) ,
144+ ) ;
145+
146+ Ok ( apps)
147+ }
0 commit comments