mirror of
https://github.com/encounter/objdiff.git
synced 2025-08-18 09:51:35 +00:00
Add CLI args to objdiff-gui (incl. --project-dir/-p)
Resolves #41 Resolves #211
This commit is contained in:
parent
247d6da94b
commit
b21892be31
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -3517,6 +3517,7 @@ name = "objdiff-gui"
|
||||
version = "3.0.0-beta.14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
"cfg-if",
|
||||
"const_format",
|
||||
"cwdemangle",
|
||||
|
@ -25,6 +25,7 @@ wsl = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
argp = "0.4"
|
||||
cfg-if = "1.0"
|
||||
const_format = "0.2"
|
||||
cwdemangle = "1.0"
|
||||
|
@ -431,6 +431,7 @@ impl App {
|
||||
app_path: Option<PathBuf>,
|
||||
graphics_config: GraphicsConfig,
|
||||
graphics_config_path: Option<PathBuf>,
|
||||
project_dir: Option<Utf8PlatformPathBuf>,
|
||||
) -> Self {
|
||||
// Load previous app state (if any).
|
||||
// Note that you must enable the `persistence` feature for this to work.
|
||||
@ -440,7 +441,17 @@ impl App {
|
||||
app.appearance = appearance;
|
||||
}
|
||||
if let Some(config) = deserialize_config(storage) {
|
||||
let mut state = AppState { config, ..Default::default() };
|
||||
let state = AppState { config, ..Default::default() };
|
||||
app.state = Arc::new(RwLock::new(state));
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut state = app.state.write().unwrap();
|
||||
if let Some(project_dir) = project_dir
|
||||
&& state.config.project_dir.as_ref().is_none_or(|p| *p != project_dir)
|
||||
{
|
||||
state.set_project_dir(project_dir);
|
||||
}
|
||||
if state.config.project_dir.is_some() {
|
||||
state.config_change = true;
|
||||
state.watcher_change = true;
|
||||
@ -449,8 +460,6 @@ impl App {
|
||||
state.queue_build = true;
|
||||
}
|
||||
app.view_state.config_state.queue_check_update = state.config.auto_update_check;
|
||||
app.state = Arc::new(RwLock::new(state));
|
||||
}
|
||||
}
|
||||
app.appearance.init_fonts(&cc.egui_ctx);
|
||||
app.appearance.utc_offset = utc_offset;
|
||||
|
63
objdiff-gui/src/argp_version.rs
Normal file
63
objdiff-gui/src/argp_version.rs
Normal file
@ -0,0 +1,63 @@
|
||||
// Originally from https://gist.github.com/suluke/e0c672492126be0a4f3b4f0e1115d77c
|
||||
//! Extend `argp` to be better integrated with the `cargo` ecosystem
|
||||
//!
|
||||
//! For now, this only adds a --version/-V option which causes early-exit.
|
||||
use std::ffi::OsStr;
|
||||
|
||||
use argp::{EarlyExit, FromArgs, TopLevelCommand, parser::ParseGlobalOptions};
|
||||
|
||||
struct ArgsOrVersion<T>(T)
|
||||
where T: FromArgs;
|
||||
|
||||
impl<T> TopLevelCommand for ArgsOrVersion<T> where T: FromArgs {}
|
||||
|
||||
impl<T> FromArgs for ArgsOrVersion<T>
|
||||
where T: FromArgs
|
||||
{
|
||||
fn _from_args(
|
||||
command_name: &[&str],
|
||||
args: &[&OsStr],
|
||||
parent: Option<&mut dyn ParseGlobalOptions>,
|
||||
) -> Result<Self, EarlyExit> {
|
||||
/// Also use argp for catching `--version`-only invocations
|
||||
#[derive(FromArgs)]
|
||||
struct Version {
|
||||
/// Print version information and exit.
|
||||
#[argp(switch, short = 'V')]
|
||||
pub version: bool,
|
||||
}
|
||||
|
||||
match Version::from_args(command_name, args) {
|
||||
Ok(v) => {
|
||||
if v.version {
|
||||
println!(
|
||||
"{} {}",
|
||||
command_name.first().unwrap_or(&""),
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
);
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
// Pass through empty arguments
|
||||
T::_from_args(command_name, args, parent).map(Self)
|
||||
}
|
||||
}
|
||||
Err(exit) => match exit {
|
||||
EarlyExit::Help(_help) => {
|
||||
// TODO: Chain help info from Version
|
||||
// For now, we just put the switch on T as well
|
||||
T::from_args(command_name, &["--help"]).map(Self)
|
||||
}
|
||||
EarlyExit::Err(_) => T::_from_args(command_name, args, parent).map(Self),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `FromArgs` type from the current process’s `env::args`.
|
||||
///
|
||||
/// This function will exit early from the current process if argument parsing was unsuccessful or if information like `--help` was requested.
|
||||
/// Error messages will be printed to stderr, and `--help` output to stdout.
|
||||
pub fn from_env<T>() -> T
|
||||
where T: TopLevelCommand {
|
||||
argp::parse_args_or_exit::<ArgsOrVersion<T>>(argp::DEFAULT).0
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
mod app;
|
||||
mod app_config;
|
||||
mod argp_version;
|
||||
mod config;
|
||||
mod fonts;
|
||||
mod hotkeys;
|
||||
@ -11,19 +12,83 @@ mod update;
|
||||
mod views;
|
||||
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fmt::Display,
|
||||
path::PathBuf,
|
||||
process::ExitCode,
|
||||
rc::Rc,
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use anyhow::{Result, ensure};
|
||||
use argp::{FromArgValue, FromArgs};
|
||||
use cfg_if::cfg_if;
|
||||
use objdiff_core::config::path::check_path_buf;
|
||||
use time::UtcOffset;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use tracing_subscriber::{EnvFilter, filter::LevelFilter};
|
||||
use typed_path::Utf8PlatformPathBuf;
|
||||
|
||||
use crate::views::graphics::{GraphicsBackend, GraphicsConfig, load_graphics_config};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||
enum LogLevel {
|
||||
Error,
|
||||
Warn,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
}
|
||||
|
||||
impl FromStr for LogLevel {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"error" => Self::Error,
|
||||
"warn" => Self::Warn,
|
||||
"info" => Self::Info,
|
||||
"debug" => Self::Debug,
|
||||
"trace" => Self::Trace,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LogLevel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
LogLevel::Error => "error",
|
||||
LogLevel::Warn => "warn",
|
||||
LogLevel::Info => "info",
|
||||
LogLevel::Debug => "debug",
|
||||
LogLevel::Trace => "trace",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArgValue for LogLevel {
|
||||
fn from_arg_value(value: &OsStr) -> Result<Self, String> {
|
||||
String::from_arg_value(value)
|
||||
.and_then(|s| Self::from_str(&s).map_err(|_| "Invalid log level".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
/// A local diffing tool for decompilation projects.
|
||||
struct TopLevel {
|
||||
#[argp(option, short = 'L')]
|
||||
/// Minimum logging level. (Default: info)
|
||||
/// Possible values: error, warn, info, debug, trace
|
||||
log_level: Option<LogLevel>,
|
||||
#[argp(option, short = 'p')]
|
||||
/// Path to the project directory.
|
||||
project_dir: Option<PathBuf>,
|
||||
/// Print version information and exit.
|
||||
#[argp(switch, short = 'V')]
|
||||
version: bool,
|
||||
}
|
||||
|
||||
fn load_icon() -> Result<egui::IconData> {
|
||||
let decoder = png::Decoder::new(include_bytes!("../assets/icon_64.png").as_ref());
|
||||
let mut reader = decoder.read_info()?;
|
||||
@ -38,23 +103,63 @@ fn load_icon() -> Result<egui::IconData> {
|
||||
const APP_NAME: &str = "objdiff";
|
||||
|
||||
fn main() -> ExitCode {
|
||||
// Log to stdout (if you run with `RUST_LOG=debug`).
|
||||
tracing_subscriber::fmt()
|
||||
let args: TopLevel = argp_version::from_env();
|
||||
let builder = tracing_subscriber::fmt();
|
||||
if let Some(level) = args.log_level {
|
||||
builder
|
||||
.with_max_level(match level {
|
||||
LogLevel::Error => LevelFilter::ERROR,
|
||||
LogLevel::Warn => LevelFilter::WARN,
|
||||
LogLevel::Info => LevelFilter::INFO,
|
||||
LogLevel::Debug => LevelFilter::DEBUG,
|
||||
LogLevel::Trace => LevelFilter::TRACE,
|
||||
})
|
||||
.init();
|
||||
} else {
|
||||
builder
|
||||
.with_env_filter(
|
||||
EnvFilter::builder()
|
||||
// Default to info level
|
||||
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
.from_env_lossy()
|
||||
// This module is noisy at info level
|
||||
.add_directive("wgpu_core::device::resource=warn".parse().unwrap()),
|
||||
)
|
||||
.init();
|
||||
}
|
||||
|
||||
// Because localtime_r is unsound in multithreaded apps,
|
||||
// we must call this before initializing eframe.
|
||||
// https://github.com/time-rs/time/issues/293
|
||||
let utc_offset = UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC);
|
||||
|
||||
// Resolve project directory if provided
|
||||
let project_dir = if let Some(path) = args.project_dir {
|
||||
match path.canonicalize() {
|
||||
Ok(path) => {
|
||||
// Ensure the path is a directory
|
||||
if path.is_dir() {
|
||||
match check_path_buf(path) {
|
||||
Ok(path) => Some(path),
|
||||
Err(e) => {
|
||||
log::error!("Failed to convert project directory to UTF-8 path: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::error!("Project directory is not a directory: {}", path.display());
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to canonicalize project directory: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let app_path = std::env::current_exe().ok();
|
||||
let exec_path: Rc<Mutex<Option<PathBuf>>> = Rc::new(Mutex::new(None));
|
||||
let mut native_options = eframe::NativeOptions {
|
||||
@ -113,6 +218,7 @@ fn main() -> ExitCode {
|
||||
app_path.clone(),
|
||||
graphics_config.clone(),
|
||||
graphics_config_path.clone(),
|
||||
project_dir.clone(),
|
||||
) {
|
||||
eframe_error = Some(e);
|
||||
}
|
||||
@ -139,6 +245,7 @@ fn main() -> ExitCode {
|
||||
app_path.clone(),
|
||||
graphics_config.clone(),
|
||||
graphics_config_path.clone(),
|
||||
project_dir.clone(),
|
||||
) {
|
||||
eframe_error = Some(e);
|
||||
} else {
|
||||
@ -161,6 +268,7 @@ fn main() -> ExitCode {
|
||||
app_path,
|
||||
graphics_config,
|
||||
graphics_config_path,
|
||||
project_dir,
|
||||
) {
|
||||
eframe_error = Some(e);
|
||||
} else {
|
||||
@ -204,6 +312,7 @@ fn run_eframe(
|
||||
app_path: Option<PathBuf>,
|
||||
graphics_config: GraphicsConfig,
|
||||
graphics_config_path: Option<PathBuf>,
|
||||
project_dir: Option<Utf8PlatformPathBuf>,
|
||||
) -> Result<(), eframe::Error> {
|
||||
eframe::run_native(
|
||||
APP_NAME,
|
||||
@ -216,6 +325,7 @@ fn run_eframe(
|
||||
app_path,
|
||||
graphics_config,
|
||||
graphics_config_path,
|
||||
project_dir,
|
||||
)))
|
||||
}),
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user