3
3
4
4
mod app;
5
5
mod app_config;
6
+ mod argp_version;
6
7
mod config;
7
8
mod fonts;
8
9
mod hotkeys;
@@ -11,19 +12,83 @@ mod update;
11
12
mod views;
12
13
13
14
use std:: {
15
+ ffi:: OsStr ,
16
+ fmt:: Display ,
14
17
path:: PathBuf ,
15
18
process:: ExitCode ,
16
19
rc:: Rc ,
20
+ str:: FromStr ,
17
21
sync:: { Arc , Mutex } ,
18
22
} ;
19
23
20
24
use anyhow:: { Result , ensure} ;
25
+ use argp:: { FromArgValue , FromArgs } ;
21
26
use cfg_if:: cfg_if;
27
+ use objdiff_core:: config:: path:: check_path_buf;
22
28
use time:: UtcOffset ;
23
- use tracing_subscriber:: EnvFilter ;
29
+ use tracing_subscriber:: { EnvFilter , filter:: LevelFilter } ;
30
+ use typed_path:: Utf8PlatformPathBuf ;
24
31
25
32
use crate :: views:: graphics:: { GraphicsBackend , GraphicsConfig , load_graphics_config} ;
26
33
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
+
27
92
fn load_icon ( ) -> Result < egui:: IconData > {
28
93
let decoder = png:: Decoder :: new ( include_bytes ! ( "../assets/icon_64.png" ) . as_ref ( ) ) ;
29
94
let mut reader = decoder. read_info ( ) ?;
@@ -38,23 +103,63 @@ fn load_icon() -> Result<egui::IconData> {
38
103
const APP_NAME : & str = "objdiff" ;
39
104
40
105
fn 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
+ }
52
130
53
131
// Because localtime_r is unsound in multithreaded apps,
54
132
// we must call this before initializing eframe.
55
133
// https://github.com/time-rs/time/issues/293
56
134
let utc_offset = UtcOffset :: current_local_offset ( ) . unwrap_or ( UtcOffset :: UTC ) ;
57
135
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
+
58
163
let app_path = std:: env:: current_exe ( ) . ok ( ) ;
59
164
let exec_path: Rc < Mutex < Option < PathBuf > > > = Rc :: new ( Mutex :: new ( None ) ) ;
60
165
let mut native_options = eframe:: NativeOptions {
@@ -113,6 +218,7 @@ fn main() -> ExitCode {
113
218
app_path. clone ( ) ,
114
219
graphics_config. clone ( ) ,
115
220
graphics_config_path. clone ( ) ,
221
+ project_dir. clone ( ) ,
116
222
) {
117
223
eframe_error = Some ( e) ;
118
224
}
@@ -139,6 +245,7 @@ fn main() -> ExitCode {
139
245
app_path. clone ( ) ,
140
246
graphics_config. clone ( ) ,
141
247
graphics_config_path. clone ( ) ,
248
+ project_dir. clone ( ) ,
142
249
) {
143
250
eframe_error = Some ( e) ;
144
251
} else {
@@ -161,6 +268,7 @@ fn main() -> ExitCode {
161
268
app_path,
162
269
graphics_config,
163
270
graphics_config_path,
271
+ project_dir,
164
272
) {
165
273
eframe_error = Some ( e) ;
166
274
} else {
@@ -204,6 +312,7 @@ fn run_eframe(
204
312
app_path : Option < PathBuf > ,
205
313
graphics_config : GraphicsConfig ,
206
314
graphics_config_path : Option < PathBuf > ,
315
+ project_dir : Option < Utf8PlatformPathBuf > ,
207
316
) -> Result < ( ) , eframe:: Error > {
208
317
eframe:: run_native (
209
318
APP_NAME ,
@@ -216,6 +325,7 @@ fn run_eframe(
216
325
app_path,
217
326
graphics_config,
218
327
graphics_config_path,
328
+ project_dir,
219
329
) ) )
220
330
} ) ,
221
331
)
0 commit comments