@@ -3,6 +3,7 @@ use clap_complete::generator::generate;
33use clap_complete:: { Generator , Shell } ;
44use std:: io:: stdout;
55use std:: process:: exit;
6+ use std:: str:: from_utf8;
67use std:: { env:: var, fmt:: Display , path:: PathBuf , process:: Command } ;
78
89/// Generate a native-style macOS folder icon from a mask file.
@@ -47,6 +48,10 @@ struct FolderifyArgs {
4748 #[ clap( long = "macOS" , alias = "osx" , short_alias = 'x' , id = "MACOS_VERSION" ) ]
4849 mac_os : Option < String > , // TODO: enum, default?
4950
51+ /// Render the folder as empty.
52+ #[ clap( long, default_value_t = false ) ]
53+ empty_folder : bool ,
54+
5055 /// Color scheme — auto matches the current system value.
5156 #[ clap( long, value_enum, default_value_t = ColorSchemeOrAuto :: Auto ) ]
5257 color_scheme : ColorSchemeOrAuto ,
@@ -136,6 +141,8 @@ pub struct Options {
136141 pub color_scheme : ColorScheme ,
137142 pub no_trim : bool ,
138143 pub target : Option < PathBuf > ,
144+ pub folder_style : FolderStyle ,
145+ pub empty_folder : bool ,
139146 pub output_icns : Option < PathBuf > ,
140147 pub output_iconset : Option < PathBuf > ,
141148 pub set_icon_using : SetIconUsing ,
@@ -150,17 +157,41 @@ fn completions_for_shell(cmd: &mut clap::Command, generator: impl Generator) {
150157 generate ( generator, cmd, "folderify" , & mut stdout ( ) ) ;
151158}
152159
153- fn known_mac_os_version ( mac_os : & str ) -> bool {
154- for major_version_string in [ "15" , "14" , "13" , "12" , "11" ] {
160+ fn is_major_macos_version_one_of ( mac_os : & str , versions : & [ & str ] ) -> bool {
161+ for major_version_string in versions {
155162 if mac_os. starts_with ( & format ! ( "{}." , major_version_string) )
156- || mac_os == major_version_string
163+ || mac_os == * major_version_string
157164 {
158165 return true ;
159166 }
160167 }
161168 false
162169}
163170
171+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
172+ pub enum FolderStyle {
173+ BigSur ,
174+ Tahoe ,
175+ }
176+
177+ impl Display for FolderStyle {
178+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
179+ match self {
180+ FolderStyle :: BigSur => write ! ( f, "Big Sur" ) ,
181+ FolderStyle :: Tahoe => write ! ( f, "Tahoe" ) ,
182+ }
183+ }
184+ }
185+
186+ impl FolderStyle {
187+ pub fn dark_mode_and_light_mode_are_identical ( & self ) -> bool {
188+ match self {
189+ FolderStyle :: BigSur => false ,
190+ FolderStyle :: Tahoe => true ,
191+ }
192+ }
193+ }
194+
164195pub fn get_options ( ) -> Options {
165196 let mut command = FolderifyArgs :: command ( ) ;
166197
@@ -178,8 +209,12 @@ pub fn get_options() -> Options {
178209 }
179210 } ;
180211
181- if let Some ( mac_os) = & args. mac_os {
182- let mac_os: & str = mac_os;
212+ let folder_style = {
213+ let mac_os: String = args
214+ . mac_os
215+ . map ( |s| s. to_owned ( ) )
216+ . unwrap_or_else ( current_macOS_version) ;
217+ let mac_os = mac_os. as_str ( ) ;
183218 // macOS 11.0 reports itself as macOS 10.16 in some APIs. Someone might pass such a value on to `folderify`, so we can't just check for major version 10.
184219 // Instead, we denylist the versions that previously had different folder icons, so that we don't accidentally apply the Big Sur style when one of these versions was specified.
185220 if matches ! (
@@ -199,10 +234,21 @@ pub fn get_options() -> Options {
199234 eprintln ! ( "Error: OS X / macOS 10 was specified. This is no longer supported by folderify v3.\n To generate these icons, please use folderify v2: https://github.com/lgarron/folderify/tree/main#os-x-macos-10" ) ;
200235 exit ( 1 )
201236 }
202- if !known_mac_os_version ( mac_os) {
203- eprintln ! ( "Warning: Unknown macOS version specified. Assuming macOS 11 or later" ) ;
237+ if is_major_macos_version_one_of ( mac_os, & [ "15" , "14" , "13" , "12" , "11" ] ) {
238+ FolderStyle :: BigSur
239+ } else if is_major_macos_version_one_of (
240+ mac_os,
241+ & [ "26" ] , // Note: macOS 16 through 25 do not exist.
242+ ) {
243+ eprintln ! ( "Warning: macOS Tahoe is still in beta. The icon may not match the final macOS 26 release." ) ;
244+ FolderStyle :: Tahoe
245+ } else {
246+ eprintln ! (
247+ "Warning: Unknown macOS version specified. Assuming Big Sur (macOS 11 through 15)."
248+ ) ;
249+ FolderStyle :: BigSur
204250 }
205- }
251+ } ;
206252 let debug = var ( "FOLDERIFY_DEBUG" ) == Ok ( "1" . into ( ) ) ;
207253 let verbose = args. verbose || debug;
208254 let show_progress = !args. no_progress && !args. verbose ;
@@ -213,9 +259,11 @@ pub fn get_options() -> Options {
213259 } ;
214260 Options {
215261 mask_path : mask,
216- color_scheme : map_color_scheme_auto ( args. color_scheme ) ,
262+ color_scheme : map_color_scheme_auto ( args. color_scheme , folder_style ) ,
217263 no_trim : args. no_trim ,
218264 target : args. target ,
265+ folder_style,
266+ empty_folder : args. empty_folder ,
219267 output_icns : args. output_icns ,
220268 output_iconset : args. output_iconset ,
221269 badge : args. badge ,
@@ -227,7 +275,20 @@ pub fn get_options() -> Options {
227275 }
228276}
229277
230- fn map_color_scheme_auto ( color_scheme : ColorSchemeOrAuto ) -> ColorScheme {
278+ fn map_color_scheme_auto (
279+ color_scheme : ColorSchemeOrAuto ,
280+ folder_style : FolderStyle ,
281+ ) -> ColorScheme {
282+ if folder_style. dark_mode_and_light_mode_are_identical ( ) {
283+ match color_scheme {
284+ ColorSchemeOrAuto :: Auto => { }
285+ _ => {
286+ eprintln ! ( "Dark and light mode folder icons are identical for the folder style of this macOS version. Ignoring the `--color-scheme` argument." ) ;
287+ }
288+ }
289+ return ColorScheme :: Light ;
290+ }
291+
231292 match color_scheme {
232293 ColorSchemeOrAuto :: Dark => return ColorScheme :: Dark ,
233294 ColorSchemeOrAuto :: Light => return ColorScheme :: Light ,
@@ -251,3 +312,18 @@ fn map_color_scheme_auto(color_scheme: ColorSchemeOrAuto) -> ColorScheme {
251312 }
252313 }
253314}
315+
316+ const DEFAULT_MACOS_VERSION : & str = "15.0" ;
317+
318+ #[ allow( non_snake_case) ]
319+ fn current_macOS_version ( ) -> String {
320+ let Ok ( o) = Command :: new ( "sw_vers" ) . args ( [ "-productVersion" ] ) . output ( ) else {
321+ return DEFAULT_MACOS_VERSION . to_owned ( ) ;
322+ } ;
323+
324+ let Ok ( stdout) = from_utf8 ( & o. stdout ) else {
325+ return DEFAULT_MACOS_VERSION . to_owned ( ) ;
326+ } ;
327+
328+ stdout. to_owned ( )
329+ }
0 commit comments