33
44mod app;
55mod app_config;
6+ mod argp_version;
67mod config;
78mod fonts;
89mod hotkeys;
@@ -11,19 +12,83 @@ mod update;
1112mod views;
1213
1314use std:: {
15+ ffi:: OsStr ,
16+ fmt:: Display ,
1417 path:: PathBuf ,
1518 process:: ExitCode ,
1619 rc:: Rc ,
20+ str:: FromStr ,
1721 sync:: { Arc , Mutex } ,
1822} ;
1923
2024use anyhow:: { Result , ensure} ;
25+ use argp:: { FromArgValue , FromArgs } ;
2126use cfg_if:: cfg_if;
27+ use objdiff_core:: config:: path:: check_path_buf;
2228use time:: UtcOffset ;
23- use tracing_subscriber:: EnvFilter ;
29+ use tracing_subscriber:: { EnvFilter , filter:: LevelFilter } ;
30+ use typed_path:: Utf8PlatformPathBuf ;
2431
2532use crate :: views:: graphics:: { GraphicsBackend , GraphicsConfig , load_graphics_config} ;
2633
34+ #[ derive( Debug , Eq , PartialEq , Copy , Clone ) ]
35+ enum LogLevel {
36+ Error ,
37+ Warn ,
38+ Info ,
39+ Debug ,
40+ Trace ,
41+ }
42+
43+ impl FromStr for LogLevel {
44+ type Err = ( ) ;
45+
46+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
47+ Ok ( match s {
48+ "error" => Self :: Error ,
49+ "warn" => Self :: Warn ,
50+ "info" => Self :: Info ,
51+ "debug" => Self :: Debug ,
52+ "trace" => Self :: Trace ,
53+ _ => return Err ( ( ) ) ,
54+ } )
55+ }
56+ }
57+
58+ impl Display for LogLevel {
59+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
60+ f. write_str ( match self {
61+ LogLevel :: Error => "error" ,
62+ LogLevel :: Warn => "warn" ,
63+ LogLevel :: Info => "info" ,
64+ LogLevel :: Debug => "debug" ,
65+ LogLevel :: Trace => "trace" ,
66+ } )
67+ }
68+ }
69+
70+ impl FromArgValue for LogLevel {
71+ fn from_arg_value ( value : & OsStr ) -> Result < Self , String > {
72+ String :: from_arg_value ( value)
73+ . and_then ( |s| Self :: from_str ( & s) . map_err ( |_| "Invalid log level" . to_string ( ) ) )
74+ }
75+ }
76+
77+ #[ derive( FromArgs , PartialEq , Debug ) ]
78+ /// A local diffing tool for decompilation projects.
79+ struct TopLevel {
80+ #[ argp( option, short = 'L' ) ]
81+ /// Minimum logging level. (Default: info)
82+ /// Possible values: error, warn, info, debug, trace
83+ log_level : Option < LogLevel > ,
84+ #[ argp( option, short = 'p' ) ]
85+ /// Path to the project directory.
86+ project_dir : Option < PathBuf > ,
87+ /// Print version information and exit.
88+ #[ argp( switch, short = 'V' ) ]
89+ version : bool ,
90+ }
91+
2792fn load_icon ( ) -> Result < egui:: IconData > {
2893 let decoder = png:: Decoder :: new ( include_bytes ! ( "../assets/icon_64.png" ) . as_ref ( ) ) ;
2994 let mut reader = decoder. read_info ( ) ?;
@@ -38,23 +103,63 @@ fn load_icon() -> Result<egui::IconData> {
38103const APP_NAME : & str = "objdiff" ;
39104
40105fn main ( ) -> ExitCode {
41- // Log to stdout (if you run with `RUST_LOG=debug`).
42- tracing_subscriber:: fmt ( )
43- . with_env_filter (
44- EnvFilter :: builder ( )
45- // Default to info level
46- . with_default_directive ( tracing_subscriber:: filter:: LevelFilter :: INFO . into ( ) )
47- . from_env_lossy ( )
48- // This module is noisy at info level
49- . add_directive ( "wgpu_core::device::resource=warn" . parse ( ) . unwrap ( ) ) ,
50- )
51- . init ( ) ;
106+ let args: TopLevel = argp_version:: from_env ( ) ;
107+ let builder = tracing_subscriber:: fmt ( ) ;
108+ if let Some ( level) = args. log_level {
109+ builder
110+ . with_max_level ( match level {
111+ LogLevel :: Error => LevelFilter :: ERROR ,
112+ LogLevel :: Warn => LevelFilter :: WARN ,
113+ LogLevel :: Info => LevelFilter :: INFO ,
114+ LogLevel :: Debug => LevelFilter :: DEBUG ,
115+ LogLevel :: Trace => LevelFilter :: TRACE ,
116+ } )
117+ . init ( ) ;
118+ } else {
119+ builder
120+ . with_env_filter (
121+ EnvFilter :: builder ( )
122+ // Default to info level
123+ . with_default_directive ( LevelFilter :: INFO . into ( ) )
124+ . from_env_lossy ( )
125+ // This module is noisy at info level
126+ . add_directive ( "wgpu_core::device::resource=warn" . parse ( ) . unwrap ( ) ) ,
127+ )
128+ . init ( ) ;
129+ }
52130
53131 // Because localtime_r is unsound in multithreaded apps,
54132 // we must call this before initializing eframe.
55133 // https://github.com/time-rs/time/issues/293
56134 let utc_offset = UtcOffset :: current_local_offset ( ) . unwrap_or ( UtcOffset :: UTC ) ;
57135
136+ // Resolve project directory if provided
137+ let project_dir = if let Some ( path) = args. project_dir {
138+ match path. canonicalize ( ) {
139+ Ok ( path) => {
140+ // Ensure the path is a directory
141+ if path. is_dir ( ) {
142+ match check_path_buf ( path) {
143+ Ok ( path) => Some ( path) ,
144+ Err ( e) => {
145+ log:: error!( "Failed to convert project directory to UTF-8 path: {}" , e) ;
146+ None
147+ }
148+ }
149+ } else {
150+ log:: error!( "Project directory is not a directory: {}" , path. display( ) ) ;
151+ None
152+ }
153+ }
154+ Err ( e) => {
155+ log:: error!( "Failed to canonicalize project directory: {}" , e) ;
156+ None
157+ }
158+ }
159+ } else {
160+ None
161+ } ;
162+
58163 let app_path = std:: env:: current_exe ( ) . ok ( ) ;
59164 let exec_path: Rc < Mutex < Option < PathBuf > > > = Rc :: new ( Mutex :: new ( None ) ) ;
60165 let mut native_options = eframe:: NativeOptions {
@@ -113,6 +218,7 @@ fn main() -> ExitCode {
113218 app_path. clone ( ) ,
114219 graphics_config. clone ( ) ,
115220 graphics_config_path. clone ( ) ,
221+ project_dir. clone ( ) ,
116222 ) {
117223 eframe_error = Some ( e) ;
118224 }
@@ -139,6 +245,7 @@ fn main() -> ExitCode {
139245 app_path. clone ( ) ,
140246 graphics_config. clone ( ) ,
141247 graphics_config_path. clone ( ) ,
248+ project_dir. clone ( ) ,
142249 ) {
143250 eframe_error = Some ( e) ;
144251 } else {
@@ -161,6 +268,7 @@ fn main() -> ExitCode {
161268 app_path,
162269 graphics_config,
163270 graphics_config_path,
271+ project_dir,
164272 ) {
165273 eframe_error = Some ( e) ;
166274 } else {
@@ -204,6 +312,7 @@ fn run_eframe(
204312 app_path : Option < PathBuf > ,
205313 graphics_config : GraphicsConfig ,
206314 graphics_config_path : Option < PathBuf > ,
315+ project_dir : Option < Utf8PlatformPathBuf > ,
207316) -> Result < ( ) , eframe:: Error > {
208317 eframe:: run_native (
209318 APP_NAME ,
@@ -216,6 +325,7 @@ fn run_eframe(
216325 app_path,
217326 graphics_config,
218327 graphics_config_path,
328+ project_dir,
219329 ) ) )
220330 } ) ,
221331 )
0 commit comments