mirror of https://github.com/encounter/objdiff.git
Improved Windows support & simple WSL2 integration
This commit is contained in:
parent
b55c919f4d
commit
daaa5c86a2
|
@ -1576,6 +1576,7 @@ dependencies = [
|
|||
"log",
|
||||
"notify",
|
||||
"object",
|
||||
"path-slash",
|
||||
"ppc750cl",
|
||||
"rabbitizer",
|
||||
"rfd",
|
||||
|
@ -1583,6 +1584,7 @@ dependencies = [
|
|||
"thiserror",
|
||||
"tracing-subscriber",
|
||||
"tracing-wasm",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1660,6 +1662,12 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "path-slash"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42"
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
|
|
|
@ -27,6 +27,10 @@ egui_extras = "0.19.0"
|
|||
ppc750cl = { git = "https://github.com/terorie/ppc750cl" }
|
||||
rabbitizer = { git = "https://github.com/encounter/rabbitizer-rs", rev = "10c279b2ef251c62885b1dcdcfe740b0db8e9956" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
path-slash = "0.2.0"
|
||||
winapi = "0.3.9"
|
||||
|
||||
# native:
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
tracing-subscriber = "0.3"
|
||||
|
|
10
src/app.rs
10
src/app.rs
|
@ -61,6 +61,11 @@ pub struct ViewState {
|
|||
#[derive(Default, Clone, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct AppConfig {
|
||||
pub custom_make: String,
|
||||
// WSL2 settings
|
||||
#[serde(skip)]
|
||||
pub available_wsl_distros: Option<Vec<String>>,
|
||||
pub selected_wsl_distro: Option<String>,
|
||||
// Split obj
|
||||
pub project_dir: Option<PathBuf>,
|
||||
pub build_asm_dir: Option<PathBuf>,
|
||||
|
@ -156,7 +161,6 @@ impl eframe::App for App {
|
|||
});
|
||||
} else {
|
||||
egui::SidePanel::left("side_panel").show(ctx, |ui| {
|
||||
ui.heading("Config");
|
||||
config_ui(ui, config, view_state);
|
||||
jobs_ui(ui, view_state);
|
||||
});
|
||||
|
@ -194,7 +198,9 @@ impl eframe::App for App {
|
|||
ui.separator();
|
||||
});
|
||||
|
||||
if view_state.jobs.iter().any(|job| {
|
||||
// Windows + request_repaint_after breaks dialogs:
|
||||
// https://github.com/emilk/egui/issues/2003
|
||||
if cfg!(windows) || view_state.jobs.iter().any(|job| {
|
||||
if let Some(handle) = &job.handle {
|
||||
return !handle.is_finished();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{
|
|||
path::Path,
|
||||
process::Command,
|
||||
str::from_utf8,
|
||||
sync::{mpsc::Receiver, Arc, RwLock},
|
||||
sync::{Arc, mpsc::Receiver, RwLock},
|
||||
};
|
||||
|
||||
use anyhow::{Context, Error, Result};
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||
app::AppConfig,
|
||||
diff::diff_objs,
|
||||
elf,
|
||||
jobs::{queue_job, update_status, Job, JobResult, JobState, Status},
|
||||
jobs::{Job, JobResult, JobState, queue_job, Status, update_status},
|
||||
obj::ObjInfo,
|
||||
};
|
||||
|
||||
|
@ -26,13 +26,36 @@ pub struct BuildResult {
|
|||
pub second_obj: Option<ObjInfo>,
|
||||
}
|
||||
|
||||
fn run_make(cwd: &Path, arg: &Path) -> BuildStatus {
|
||||
fn run_make(cwd: &Path, arg: &Path, config: &AppConfig) -> BuildStatus {
|
||||
match (|| -> Result<BuildStatus> {
|
||||
let output = Command::new("make")
|
||||
.current_dir(cwd)
|
||||
.arg(arg)
|
||||
.output()
|
||||
.context("Failed to execute build")?;
|
||||
let make = if config.custom_make.is_empty() { "make" } else { &config.custom_make };
|
||||
#[cfg(not(windows))]
|
||||
let mut command = Command::new(make).current_dir(cwd).arg(arg);
|
||||
#[cfg(windows)]
|
||||
let mut command = {
|
||||
use path_slash::PathExt;
|
||||
use std::os::windows::process::CommandExt;
|
||||
let mut command = if config.selected_wsl_distro.is_some() {
|
||||
Command::new("wsl")
|
||||
} else {
|
||||
Command::new(make)
|
||||
};
|
||||
if let Some(distro) = &config.selected_wsl_distro {
|
||||
command
|
||||
.arg("--cd")
|
||||
.arg(cwd)
|
||||
.arg("-d")
|
||||
.arg(distro)
|
||||
.arg("--")
|
||||
.arg(make)
|
||||
.arg(arg.to_slash_lossy().as_ref());
|
||||
} else {
|
||||
command.current_dir(cwd).arg(arg);
|
||||
}
|
||||
command.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
|
||||
command
|
||||
};
|
||||
let output = command.output().context("Failed to execute build")?;
|
||||
let stdout = from_utf8(&output.stdout).context("Failed to process stdout")?;
|
||||
let stderr = from_utf8(&output.stderr).context("Failed to process stderr")?;
|
||||
Ok(BuildStatus {
|
||||
|
@ -72,10 +95,10 @@ fn run_build(
|
|||
src_path.strip_prefix(project_dir).context("Failed to create relative src obj path")?;
|
||||
|
||||
update_status(status, format!("Building asm {}", obj_path), 0, 5, &cancel)?;
|
||||
let first_status = run_make(project_dir, asm_path_rel);
|
||||
let first_status = run_make(project_dir, asm_path_rel, &config);
|
||||
|
||||
update_status(status, format!("Building src {}", obj_path), 1, 5, &cancel)?;
|
||||
let second_status = run_make(project_dir, src_path_rel);
|
||||
let second_status = run_make(project_dir, src_path_rel, &config);
|
||||
|
||||
let mut first_obj = if first_status.success {
|
||||
update_status(status, format!("Loading asm {}", obj_path), 2, 5, &cancel)?;
|
||||
|
|
|
@ -1,13 +1,53 @@
|
|||
use std::process::Command;
|
||||
use std::string::FromUtf16Error;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use crate::{
|
||||
app::{AppConfig, DiffKind, ViewState},
|
||||
jobs::{bindiff::queue_bindiff, build::queue_build},
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
fn process_utf16(bytes: &[u8]) -> Result<String, FromUtf16Error> {
|
||||
let u16_bytes: Vec<u16> = bytes
|
||||
.chunks_exact(2)
|
||||
.filter_map(|c| Some(u16::from_ne_bytes(c.try_into().ok()?)))
|
||||
.collect();
|
||||
String::from_utf16(&u16_bytes)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn wsl_cmd(args: &[&str]) -> Result<String> {
|
||||
use std::os::windows::process::CommandExt;
|
||||
let output = Command::new("wsl")
|
||||
.args(args)
|
||||
.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW)
|
||||
.output()
|
||||
.context("Failed to execute wsl")?;
|
||||
process_utf16(&output.stdout).context("Failed to process stdout")
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn fetch_wsl2_distros() -> Vec<String> {
|
||||
wsl_cmd(&["-l", "-q"])
|
||||
.map(|stdout| {
|
||||
stdout
|
||||
.split('\n')
|
||||
.filter(|s| !s.trim().is_empty())
|
||||
.map(|s| s.trim().to_string())
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn config_ui(ui: &mut egui::Ui, config: &Arc<RwLock<AppConfig>>, view_state: &mut ViewState) {
|
||||
let mut config_guard = config.write().unwrap();
|
||||
let AppConfig {
|
||||
custom_make,
|
||||
available_wsl_distros,
|
||||
selected_wsl_distro,
|
||||
project_dir,
|
||||
project_dir_change,
|
||||
build_asm_dir,
|
||||
|
@ -17,6 +57,30 @@ pub fn config_ui(ui: &mut egui::Ui, config: &Arc<RwLock<AppConfig>>, view_state:
|
|||
right_obj,
|
||||
} = &mut *config_guard;
|
||||
|
||||
ui.heading("Build config");
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if available_wsl_distros.is_none() {
|
||||
*available_wsl_distros = Some(fetch_wsl2_distros());
|
||||
}
|
||||
egui::ComboBox::from_label("Run in WSL2")
|
||||
.selected_text(selected_wsl_distro.as_ref().unwrap_or(&"None".to_string()))
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(selected_wsl_distro, None, "None");
|
||||
for distro in available_wsl_distros.as_ref().unwrap() {
|
||||
ui.selectable_value(selected_wsl_distro, Some(distro.clone()), distro);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ui.label("Custom make program:");
|
||||
ui.text_edit_singleline(custom_make);
|
||||
|
||||
ui.separator();
|
||||
|
||||
ui.heading("Project config");
|
||||
|
||||
if view_state.diff_kind == DiffKind::SplitObj {
|
||||
if ui.button("Select project dir").clicked() {
|
||||
if let Some(path) = rfd::FileDialog::new().pick_folder() {
|
||||
|
|
Loading…
Reference in New Issue