mirror of
https://github.com/encounter/objdiff.git
synced 2025-06-07 15:13:47 +00:00
Export function to decomp.me scratch (beta)
This commit is contained in:
parent
e88a58ba39
commit
c2fcf2797b
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -2537,6 +2537,16 @@ version = "0.3.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime_guess"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||||
|
dependencies = [
|
||||||
|
"mime",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime_guess2"
|
name = "mime_guess2"
|
||||||
version = "2.0.5"
|
version = "2.0.5"
|
||||||
@ -3403,6 +3413,7 @@ dependencies = [
|
|||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
|
"mime_guess",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
@ -64,12 +64,12 @@ twox-hash = "1.6.3"
|
|||||||
|
|
||||||
# For Linux static binaries, use rustls
|
# For Linux static binaries, use rustls
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "rustls"] }
|
reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "multipart", "rustls"] }
|
||||||
self_update = { version = "0.39.0", default-features = false, features = ["rustls"] }
|
self_update = { version = "0.39.0", default-features = false, features = ["rustls"] }
|
||||||
|
|
||||||
# For all other platforms, use native TLS
|
# For all other platforms, use native TLS
|
||||||
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
||||||
reqwest = "0.11.23"
|
reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "multipart", "default-tls"] }
|
||||||
self_update = "0.39.0"
|
self_update = "0.39.0"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
@ -16,7 +16,7 @@ use time::UtcOffset;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_config::{deserialize_config, AppConfigVersion},
|
app_config::{deserialize_config, AppConfigVersion},
|
||||||
config::{build_globset, load_project_config, ProjectObject, ProjectObjectNode},
|
config::{build_globset, load_project_config, ProjectObject, ProjectObjectNode, ScratchConfig},
|
||||||
diff::DiffAlg,
|
diff::DiffAlg,
|
||||||
jobs::{
|
jobs::{
|
||||||
objdiff::{start_build, ObjDiffConfig},
|
objdiff::{start_build, ObjDiffConfig},
|
||||||
@ -60,6 +60,7 @@ pub struct ObjectConfig {
|
|||||||
pub base_path: Option<PathBuf>,
|
pub base_path: Option<PathBuf>,
|
||||||
pub reverse_fn_order: Option<bool>,
|
pub reverse_fn_order: Option<bool>,
|
||||||
pub complete: Option<bool>,
|
pub complete: Option<bool>,
|
||||||
|
pub scratch: Option<ScratchConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
@ -128,6 +129,8 @@ pub struct AppConfig {
|
|||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub queue_reload: bool,
|
pub queue_reload: bool,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
pub queue_scratch: bool,
|
||||||
|
#[serde(skip)]
|
||||||
pub project_config_info: Option<ProjectConfigInfo>,
|
pub project_config_info: Option<ProjectConfigInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +160,7 @@ impl Default for AppConfig {
|
|||||||
obj_change: false,
|
obj_change: false,
|
||||||
queue_build: false,
|
queue_build: false,
|
||||||
queue_reload: false,
|
queue_reload: false,
|
||||||
|
queue_scratch: false,
|
||||||
project_config_info: None,
|
project_config_info: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +318,7 @@ impl App {
|
|||||||
|
|
||||||
let ViewState { jobs, diff_state, config_state, .. } = &mut self.view_state;
|
let ViewState { jobs, diff_state, config_state, .. } = &mut self.view_state;
|
||||||
config_state.post_update(ctx, jobs, &self.config);
|
config_state.post_update(ctx, jobs, &self.config);
|
||||||
diff_state.post_update(&self.config);
|
diff_state.post_update(ctx, jobs, &self.config);
|
||||||
|
|
||||||
let Ok(mut config) = self.config.write() else {
|
let Ok(mut config) = self.config.write() else {
|
||||||
return;
|
return;
|
||||||
|
@ -60,6 +60,7 @@ impl ObjectConfigV0 {
|
|||||||
base_path: Some(self.base_path),
|
base_path: Some(self.base_path),
|
||||||
reverse_fn_order: self.reverse_fn_order,
|
reverse_fn_order: self.reverse_fn_order,
|
||||||
complete: None,
|
complete: None,
|
||||||
|
scratch: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,22 @@ pub struct ProjectObject {
|
|||||||
pub reverse_fn_order: Option<bool>,
|
pub reverse_fn_order: Option<bool>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub complete: Option<bool>,
|
pub complete: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub scratch: Option<ScratchConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct ScratchConfig {
|
||||||
|
#[serde(default)]
|
||||||
|
pub platform: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub compiler: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub c_flags: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub ctx_path: Option<PathBuf>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub build_ctx: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectObject {
|
impl ProjectObject {
|
||||||
@ -66,7 +82,7 @@ impl ProjectObject {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ProjectObjectNode {
|
pub enum ProjectObjectNode {
|
||||||
File(String, ProjectObject),
|
File(String, Box<ProjectObject>),
|
||||||
Dir(String, Vec<ProjectObjectNode>),
|
Dir(String, Vec<ProjectObjectNode>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +130,7 @@ fn build_nodes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut object = object.clone();
|
let mut object = Box::new(object.clone());
|
||||||
if let (Some(target_obj_dir), Some(path), None) =
|
if let (Some(target_obj_dir), Some(path), None) =
|
||||||
(target_obj_dir, &object.path, &object.target_path)
|
(target_obj_dir, &object.path, &object.target_path)
|
||||||
{
|
{
|
||||||
|
135
src/jobs/create_scratch.rs
Normal file
135
src/jobs/create_scratch.rs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
use std::{fs, path::PathBuf, sync::mpsc::Receiver};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
|
use const_format::formatcp;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
app::AppConfig,
|
||||||
|
jobs::{
|
||||||
|
objdiff::{run_make, BuildConfig, BuildStatus},
|
||||||
|
start_job, update_status, Job, JobContext, JobResult, JobState,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CreateScratchConfig {
|
||||||
|
pub build_config: BuildConfig,
|
||||||
|
pub context_path: Option<PathBuf>,
|
||||||
|
pub build_context: bool,
|
||||||
|
|
||||||
|
// Scratch fields
|
||||||
|
pub compiler: String,
|
||||||
|
pub platform: String,
|
||||||
|
pub compiler_flags: String,
|
||||||
|
pub function_name: String,
|
||||||
|
pub target_obj: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateScratchConfig {
|
||||||
|
pub(crate) fn from_config(config: &AppConfig, function_name: String) -> Result<Self> {
|
||||||
|
let Some(selected_obj) = &config.selected_obj else {
|
||||||
|
bail!("No object selected");
|
||||||
|
};
|
||||||
|
let Some(target_path) = &selected_obj.target_path else {
|
||||||
|
bail!("No target path for {}", selected_obj.name);
|
||||||
|
};
|
||||||
|
let Some(scratch_config) = &selected_obj.scratch else {
|
||||||
|
bail!("No scratch configuration for {}", selected_obj.name);
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
build_config: BuildConfig::from_config(config),
|
||||||
|
context_path: scratch_config.ctx_path.clone(),
|
||||||
|
build_context: scratch_config.build_ctx,
|
||||||
|
compiler: scratch_config.compiler.clone().unwrap_or_default(),
|
||||||
|
platform: scratch_config.platform.clone().unwrap_or_default(),
|
||||||
|
compiler_flags: scratch_config.c_flags.clone().unwrap_or_default(),
|
||||||
|
function_name,
|
||||||
|
target_obj: target_path.to_path_buf(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_available(config: &AppConfig) -> bool {
|
||||||
|
let Some(selected_obj) = &config.selected_obj else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
selected_obj.target_path.is_some() && selected_obj.scratch.is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone)]
|
||||||
|
pub struct CreateScratchResult {
|
||||||
|
pub scratch_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, serde::Deserialize)]
|
||||||
|
struct CreateScratchResponse {
|
||||||
|
pub slug: String,
|
||||||
|
pub claim_token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const API_HOST: &str = "http://127.0.0.1:8000";
|
||||||
|
const WEB_HOST: &str = "http://localhost:8080";
|
||||||
|
|
||||||
|
fn run_create_scratch(
|
||||||
|
status: &JobContext,
|
||||||
|
cancel: Receiver<()>,
|
||||||
|
config: CreateScratchConfig,
|
||||||
|
) -> Result<Box<CreateScratchResult>> {
|
||||||
|
let project_dir =
|
||||||
|
config.build_config.project_dir.as_ref().ok_or_else(|| anyhow!("Missing project dir"))?;
|
||||||
|
|
||||||
|
let mut context = None;
|
||||||
|
if let Some(context_path) = &config.context_path {
|
||||||
|
if config.build_context {
|
||||||
|
update_status(status, "Building context".to_string(), 0, 2, &cancel)?;
|
||||||
|
match run_make(&config.build_config, context_path) {
|
||||||
|
BuildStatus { success: true, .. } => {}
|
||||||
|
BuildStatus { success: false, stdout, stderr, .. } => {
|
||||||
|
bail!("Failed to build context:\n{stdout}\n{stderr}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let context_path = project_dir.join(context_path);
|
||||||
|
context = Some(
|
||||||
|
fs::read_to_string(&context_path)
|
||||||
|
.map_err(|e| anyhow!("Failed to read {}: {}", context_path.display(), e))?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_status(status, "Creating scratch".to_string(), 1, 2, &cancel)?;
|
||||||
|
let diff_flags = [format!("--disassemble={}", config.function_name)];
|
||||||
|
let diff_flags = serde_json::to_string(&diff_flags).unwrap();
|
||||||
|
let obj_path = project_dir.join(&config.target_obj);
|
||||||
|
let file = reqwest::blocking::multipart::Part::file(&obj_path)
|
||||||
|
.with_context(|| format!("Failed to open {}", obj_path.display()))?;
|
||||||
|
let form = reqwest::blocking::multipart::Form::new()
|
||||||
|
.text("compiler", config.compiler.clone())
|
||||||
|
.text("platform", config.platform.clone())
|
||||||
|
.text("compiler_flags", config.compiler_flags.clone())
|
||||||
|
.text("diff_label", config.function_name.clone())
|
||||||
|
.text("diff_flags", diff_flags)
|
||||||
|
.text("context", context.unwrap_or_default())
|
||||||
|
.text("source_code", "// Move related code from Context tab to here")
|
||||||
|
.part("target_obj", file);
|
||||||
|
let client = reqwest::blocking::Client::new();
|
||||||
|
let response = client
|
||||||
|
.post(formatcp!("{API_HOST}/api/scratch"))
|
||||||
|
.multipart(form)
|
||||||
|
.send()
|
||||||
|
.map_err(|e| anyhow!("Failed to send request: {}", e))?;
|
||||||
|
if !response.status().is_success() {
|
||||||
|
return Err(anyhow!("Failed to create scratch: {}", response.text()?));
|
||||||
|
}
|
||||||
|
let body: CreateScratchResponse = response.json().context("Failed to parse response")?;
|
||||||
|
let scratch_url = format!("{WEB_HOST}/scratch/{}/claim?token={}", body.slug, body.claim_token);
|
||||||
|
|
||||||
|
update_status(status, "Complete".to_string(), 2, 2, &cancel)?;
|
||||||
|
Ok(Box::from(CreateScratchResult { scratch_url }))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_create_scratch(ctx: &egui::Context, config: CreateScratchConfig) -> JobState {
|
||||||
|
start_job(ctx, "Create scratch", Job::CreateScratch, move |context, cancel| {
|
||||||
|
run_create_scratch(&context, cancel, config)
|
||||||
|
.map(|result| JobResult::CreateScratch(Some(result)))
|
||||||
|
})
|
||||||
|
}
|
@ -9,9 +9,13 @@ use std::{
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::jobs::{check_update::CheckUpdateResult, objdiff::ObjDiffResult, update::UpdateResult};
|
use crate::jobs::{
|
||||||
|
check_update::CheckUpdateResult, create_scratch::CreateScratchResult, objdiff::ObjDiffResult,
|
||||||
|
update::UpdateResult,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod check_update;
|
pub mod check_update;
|
||||||
|
pub mod create_scratch;
|
||||||
pub mod objdiff;
|
pub mod objdiff;
|
||||||
pub mod update;
|
pub mod update;
|
||||||
|
|
||||||
@ -20,6 +24,7 @@ pub enum Job {
|
|||||||
ObjDiff,
|
ObjDiff,
|
||||||
CheckUpdate,
|
CheckUpdate,
|
||||||
Update,
|
Update,
|
||||||
|
CreateScratch,
|
||||||
}
|
}
|
||||||
pub static JOB_ID: AtomicUsize = AtomicUsize::new(0);
|
pub static JOB_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
@ -119,6 +124,7 @@ pub enum JobResult {
|
|||||||
ObjDiff(Option<Box<ObjDiffResult>>),
|
ObjDiff(Option<Box<ObjDiffResult>>),
|
||||||
CheckUpdate(Option<Box<CheckUpdateResult>>),
|
CheckUpdate(Option<Box<CheckUpdateResult>>),
|
||||||
Update(Box<UpdateResult>),
|
Update(Box<UpdateResult>),
|
||||||
|
CreateScratch(Option<Box<CreateScratchResult>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_cancel(rx: &Receiver<()>) -> bool {
|
fn should_cancel(rx: &Receiver<()>) -> bool {
|
||||||
|
@ -33,13 +33,28 @@ impl Default for BuildStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct BuildConfig {
|
||||||
|
pub project_dir: Option<PathBuf>,
|
||||||
|
pub custom_make: Option<String>,
|
||||||
|
pub selected_wsl_distro: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildConfig {
|
||||||
|
pub(crate) fn from_config(config: &AppConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
project_dir: config.project_dir.clone(),
|
||||||
|
custom_make: config.custom_make.clone(),
|
||||||
|
selected_wsl_distro: config.selected_wsl_distro.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ObjDiffConfig {
|
pub struct ObjDiffConfig {
|
||||||
|
pub build_config: BuildConfig,
|
||||||
pub build_base: bool,
|
pub build_base: bool,
|
||||||
pub build_target: bool,
|
pub build_target: bool,
|
||||||
pub custom_make: Option<String>,
|
|
||||||
pub project_dir: Option<PathBuf>,
|
|
||||||
pub selected_obj: Option<ObjectConfig>,
|
pub selected_obj: Option<ObjectConfig>,
|
||||||
pub selected_wsl_distro: Option<String>,
|
|
||||||
pub code_alg: DiffAlg,
|
pub code_alg: DiffAlg,
|
||||||
pub data_alg: DiffAlg,
|
pub data_alg: DiffAlg,
|
||||||
pub relax_reloc_diffs: bool,
|
pub relax_reloc_diffs: bool,
|
||||||
@ -47,13 +62,11 @@ pub struct ObjDiffConfig {
|
|||||||
|
|
||||||
impl ObjDiffConfig {
|
impl ObjDiffConfig {
|
||||||
pub(crate) fn from_config(config: &AppConfig) -> Self {
|
pub(crate) fn from_config(config: &AppConfig) -> Self {
|
||||||
ObjDiffConfig {
|
Self {
|
||||||
|
build_config: BuildConfig::from_config(config),
|
||||||
build_base: config.build_base,
|
build_base: config.build_base,
|
||||||
build_target: config.build_target,
|
build_target: config.build_target,
|
||||||
custom_make: config.custom_make.clone(),
|
|
||||||
project_dir: config.project_dir.clone(),
|
|
||||||
selected_obj: config.selected_obj.clone(),
|
selected_obj: config.selected_obj.clone(),
|
||||||
selected_wsl_distro: config.selected_wsl_distro.clone(),
|
|
||||||
code_alg: config.code_alg,
|
code_alg: config.code_alg,
|
||||||
data_alg: config.data_alg,
|
data_alg: config.data_alg,
|
||||||
relax_reloc_diffs: config.relax_reloc_diffs,
|
relax_reloc_diffs: config.relax_reloc_diffs,
|
||||||
@ -69,7 +82,14 @@ pub struct ObjDiffResult {
|
|||||||
pub time: OffsetDateTime,
|
pub time: OffsetDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_make(cwd: &Path, arg: &Path, config: &ObjDiffConfig) -> BuildStatus {
|
pub(crate) fn run_make(config: &BuildConfig, arg: &Path) -> BuildStatus {
|
||||||
|
let Some(cwd) = &config.project_dir else {
|
||||||
|
return BuildStatus {
|
||||||
|
success: false,
|
||||||
|
stderr: "Missing project dir".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
};
|
||||||
match (|| -> Result<BuildStatus> {
|
match (|| -> Result<BuildStatus> {
|
||||||
let make = config.custom_make.as_deref().unwrap_or("make");
|
let make = config.custom_make.as_deref().unwrap_or("make");
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@ -130,8 +150,11 @@ fn run_build(
|
|||||||
config: ObjDiffConfig,
|
config: ObjDiffConfig,
|
||||||
) -> Result<Box<ObjDiffResult>> {
|
) -> Result<Box<ObjDiffResult>> {
|
||||||
let obj_config = config.selected_obj.as_ref().ok_or_else(|| Error::msg("Missing obj path"))?;
|
let obj_config = config.selected_obj.as_ref().ok_or_else(|| Error::msg("Missing obj path"))?;
|
||||||
let project_dir =
|
let project_dir = config
|
||||||
config.project_dir.as_ref().ok_or_else(|| Error::msg("Missing project dir"))?;
|
.build_config
|
||||||
|
.project_dir
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| Error::msg("Missing project dir"))?;
|
||||||
let target_path_rel = if let Some(target_path) = &obj_config.target_path {
|
let target_path_rel = if let Some(target_path) = &obj_config.target_path {
|
||||||
Some(target_path.strip_prefix(project_dir).map_err(|_| {
|
Some(target_path.strip_prefix(project_dir).map_err(|_| {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
@ -171,7 +194,7 @@ fn run_build(
|
|||||||
total,
|
total,
|
||||||
&cancel,
|
&cancel,
|
||||||
)?;
|
)?;
|
||||||
run_make(project_dir, target_path_rel, &config)
|
run_make(&config.build_config, target_path_rel)
|
||||||
}
|
}
|
||||||
_ => BuildStatus::default(),
|
_ => BuildStatus::default(),
|
||||||
};
|
};
|
||||||
@ -185,7 +208,7 @@ fn run_build(
|
|||||||
total,
|
total,
|
||||||
&cancel,
|
&cancel,
|
||||||
)?;
|
)?;
|
||||||
run_make(project_dir, base_path_rel, &config)
|
run_make(&config.build_config, base_path_rel)
|
||||||
}
|
}
|
||||||
_ => BuildStatus::default(),
|
_ => BuildStatus::default(),
|
||||||
};
|
};
|
||||||
|
@ -93,6 +93,7 @@ impl ConfigViewState {
|
|||||||
base_path: Some(path),
|
base_path: Some(path),
|
||||||
reverse_fn_order: None,
|
reverse_fn_order: None,
|
||||||
complete: None,
|
complete: None,
|
||||||
|
scratch: None,
|
||||||
});
|
});
|
||||||
} else if let Ok(obj_path) = path.strip_prefix(target_dir) {
|
} else if let Ok(obj_path) = path.strip_prefix(target_dir) {
|
||||||
let base_path = base_dir.join(obj_path);
|
let base_path = base_dir.join(obj_path);
|
||||||
@ -102,6 +103,7 @@ impl ConfigViewState {
|
|||||||
base_path: Some(base_path),
|
base_path: Some(base_path),
|
||||||
reverse_fn_order: None,
|
reverse_fn_order: None,
|
||||||
complete: None,
|
complete: None,
|
||||||
|
scratch: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,6 +395,7 @@ fn display_object(
|
|||||||
base_path: object.base_path.clone(),
|
base_path: object.base_path.clone(),
|
||||||
reverse_fn_order: object.reverse_fn_order,
|
reverse_fn_order: object.reverse_fn_order,
|
||||||
complete: object.complete,
|
complete: object.complete,
|
||||||
|
scratch: object.scratch.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ pub fn data_diff_ui(ui: &mut egui::Ui, state: &mut DiffViewState, appearance: &A
|
|||||||
|ui| {
|
|ui| {
|
||||||
ui.set_width(column_width);
|
ui.set_width(column_width);
|
||||||
|
|
||||||
if ui.button("Back").clicked() {
|
if ui.button("⏴ Back").clicked() {
|
||||||
state.current_view = View::SymbolDiff;
|
state.current_view = View::SymbolDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,9 +586,23 @@ pub fn function_diff_ui(ui: &mut egui::Ui, state: &mut DiffViewState, appearance
|
|||||||
|ui| {
|
|ui| {
|
||||||
ui.set_width(column_width);
|
ui.set_width(column_width);
|
||||||
|
|
||||||
if ui.button("Back").clicked() {
|
ui.horizontal(|ui| {
|
||||||
state.current_view = View::SymbolDiff;
|
if ui.button("⏴ Back").clicked() {
|
||||||
}
|
state.current_view = View::SymbolDiff;
|
||||||
|
}
|
||||||
|
ui.separator();
|
||||||
|
if ui
|
||||||
|
.add_enabled(
|
||||||
|
!state.scratch_running && state.scratch_available,
|
||||||
|
egui::Button::new("📲 decomp.me"),
|
||||||
|
)
|
||||||
|
.on_hover_text_at_pointer("Create a new scratch on decomp.me (beta)")
|
||||||
|
.on_disabled_hover_text("Scratch configuration missing")
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
state.queue_scratch = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let demangled = demangle(&selected_symbol.symbol_name, &Default::default());
|
let demangled = demangle(&selected_symbol.symbol_name, &Default::default());
|
||||||
let name = demangled.as_deref().unwrap_or(&selected_symbol.symbol_name);
|
let name = demangled.as_deref().unwrap_or(&selected_symbol.symbol_name);
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use std::mem::take;
|
use std::mem::take;
|
||||||
|
|
||||||
use egui::{
|
use egui::{
|
||||||
text::LayoutJob, Align, CollapsingHeader, Color32, Id, Layout, ScrollArea, SelectableLabel,
|
text::LayoutJob, Align, CollapsingHeader, Color32, Id, Layout, OpenUrl, ScrollArea,
|
||||||
TextEdit, Ui, Vec2, Widget,
|
SelectableLabel, TextEdit, Ui, Vec2, Widget,
|
||||||
};
|
};
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::AppConfigRef,
|
app::AppConfigRef,
|
||||||
jobs::{
|
jobs::{
|
||||||
|
create_scratch::{start_create_scratch, CreateScratchConfig, CreateScratchResult},
|
||||||
objdiff::{BuildStatus, ObjDiffResult},
|
objdiff::{BuildStatus, ObjDiffResult},
|
||||||
Job, JobQueue, JobResult,
|
Job, JobQueue, JobResult,
|
||||||
},
|
},
|
||||||
@ -33,12 +34,16 @@ pub enum View {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DiffViewState {
|
pub struct DiffViewState {
|
||||||
pub build: Option<Box<ObjDiffResult>>,
|
pub build: Option<Box<ObjDiffResult>>,
|
||||||
|
pub scratch: Option<Box<CreateScratchResult>>,
|
||||||
pub current_view: View,
|
pub current_view: View,
|
||||||
pub symbol_state: SymbolViewState,
|
pub symbol_state: SymbolViewState,
|
||||||
pub function_state: FunctionViewState,
|
pub function_state: FunctionViewState,
|
||||||
pub search: String,
|
pub search: String,
|
||||||
pub queue_build: bool,
|
pub queue_build: bool,
|
||||||
pub build_running: bool,
|
pub build_running: bool,
|
||||||
|
pub scratch_available: bool,
|
||||||
|
pub queue_scratch: bool,
|
||||||
|
pub scratch_running: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -52,15 +57,19 @@ pub struct SymbolViewState {
|
|||||||
|
|
||||||
impl DiffViewState {
|
impl DiffViewState {
|
||||||
pub fn pre_update(&mut self, jobs: &mut JobQueue, config: &AppConfigRef) {
|
pub fn pre_update(&mut self, jobs: &mut JobQueue, config: &AppConfigRef) {
|
||||||
jobs.results.retain_mut(|result| {
|
jobs.results.retain_mut(|result| match result {
|
||||||
if let JobResult::ObjDiff(result) = result {
|
JobResult::ObjDiff(result) => {
|
||||||
self.build = take(result);
|
self.build = take(result);
|
||||||
false
|
false
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
JobResult::CreateScratch(result) => {
|
||||||
|
self.scratch = take(result);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
});
|
});
|
||||||
self.build_running = jobs.is_running(Job::ObjDiff);
|
self.build_running = jobs.is_running(Job::ObjDiff);
|
||||||
|
self.scratch_running = jobs.is_running(Job::CreateScratch);
|
||||||
|
|
||||||
self.symbol_state.disable_reverse_fn_order = false;
|
self.symbol_state.disable_reverse_fn_order = false;
|
||||||
if let Ok(config) = config.read() {
|
if let Ok(config) = config.read() {
|
||||||
@ -70,16 +79,41 @@ impl DiffViewState {
|
|||||||
self.symbol_state.disable_reverse_fn_order = true;
|
self.symbol_state.disable_reverse_fn_order = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.scratch_available = CreateScratchConfig::is_available(&config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post_update(&mut self, config: &AppConfigRef) {
|
pub fn post_update(&mut self, ctx: &egui::Context, jobs: &mut JobQueue, config: &AppConfigRef) {
|
||||||
|
if let Some(result) = take(&mut self.scratch) {
|
||||||
|
ctx.output_mut(|o| o.open_url = Some(OpenUrl::new_tab(result.scratch_url)));
|
||||||
|
}
|
||||||
|
|
||||||
if self.queue_build {
|
if self.queue_build {
|
||||||
self.queue_build = false;
|
self.queue_build = false;
|
||||||
if let Ok(mut config) = config.write() {
|
if let Ok(mut config) = config.write() {
|
||||||
config.queue_build = true;
|
config.queue_build = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.queue_scratch {
|
||||||
|
self.queue_scratch = false;
|
||||||
|
if let Some(function_name) =
|
||||||
|
self.symbol_state.selected_symbol.as_ref().map(|sym| sym.symbol_name.clone())
|
||||||
|
{
|
||||||
|
if let Ok(config) = config.read() {
|
||||||
|
match CreateScratchConfig::from_config(&config, function_name) {
|
||||||
|
Ok(config) => {
|
||||||
|
jobs.push_once(Job::CreateScratch, || {
|
||||||
|
start_create_scratch(ctx, config)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to create scratch config: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user