Skip to content

Commit

Permalink
Add "Open source file" option
Browse files Browse the repository at this point in the history
Available when right-clicking an object in
the object list or when viewing an object

Resolves #99
  • Loading branch information
encounter committed Sep 28, 2024
1 parent 8fc142d commit bb039a1
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 13 deletions.
37 changes: 37 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions objdiff-core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ impl ProjectObject {
pub fn hidden(&self) -> bool {
self.metadata.as_ref().and_then(|m| m.auto_generated).unwrap_or(false)
}

pub fn source_path(&self) -> Option<&String> {
self.metadata.as_ref().and_then(|m| m.source_path.as_ref())
}
}

#[derive(Default, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
Expand Down
1 change: 1 addition & 0 deletions objdiff-gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ globset = { version = "0.4", features = ["serde1"] }
log = "0.4"
notify = { git = "https://github.com/notify-rs/notify", rev = "128bf6230c03d39dbb7f301ff7b20e594e34c3a2" }
objdiff-core = { path = "../objdiff-core", features = ["all"] }
open = "5.3"
png = "0.17"
pollster = "0.3"
regex = "1.10"
Expand Down
1 change: 1 addition & 0 deletions objdiff-gui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub struct ObjectConfig {
pub reverse_fn_order: Option<bool>,
pub complete: Option<bool>,
pub scratch: Option<ScratchConfig>,
pub source_path: Option<String>,
}

#[inline]
Expand Down
1 change: 1 addition & 0 deletions objdiff-gui/src/app_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ impl ObjectConfigV0 {
reverse_fn_order: self.reverse_fn_order,
complete: None,
scratch: None,
source_path: None,
}
}
}
Expand Down
57 changes: 46 additions & 11 deletions objdiff-gui/src/views/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::string::FromUtf16Error;
use std::{
mem::take,
path::{PathBuf, MAIN_SEPARATOR},
path::{Path, PathBuf, MAIN_SEPARATOR},
};

#[cfg(all(windows, feature = "wsl"))]
Expand Down Expand Up @@ -96,6 +96,7 @@ impl ConfigViewState {
reverse_fn_order: None,
complete: None,
scratch: None,
source_path: None,
});
} else if let Ok(obj_path) = path.strip_prefix(target_dir) {
let base_path = base_dir.join(obj_path);
Expand All @@ -106,6 +107,7 @@ impl ConfigViewState {
reverse_fn_order: None,
complete: None,
scratch: None,
source_path: None,
});
}
}
Expand Down Expand Up @@ -174,7 +176,10 @@ pub fn config_ui(
) {
let mut state_guard = state.write().unwrap();
let AppState {
config: AppConfig { target_obj_dir, base_obj_dir, selected_obj, auto_update_check, .. },
config:
AppConfig {
project_dir, target_obj_dir, base_obj_dir, selected_obj, auto_update_check, ..
},
objects,
object_nodes,
..
Expand Down Expand Up @@ -318,7 +323,14 @@ pub fn config_ui(
config_state.show_hidden,
)
}) {
display_node(ui, &mut new_selected_obj, &node, appearance, node_open);
display_node(
ui,
&mut new_selected_obj,
project_dir.as_deref(),
&node,
appearance,
node_open,
);
}
});
}
Expand All @@ -333,13 +345,12 @@ pub fn config_ui(
{
config_state.queue_build = true;
}

ui.separator();
}

fn display_object(
ui: &mut egui::Ui,
selected_obj: &mut Option<ObjectConfig>,
project_dir: Option<&Path>,
name: &str,
object: &ProjectObject,
appearance: &Appearance,
Expand All @@ -357,7 +368,7 @@ fn display_object(
} else {
appearance.text_color
};
let clicked = SelectableLabel::new(
let response = SelectableLabel::new(
selected,
RichText::new(name)
.font(FontId {
Expand All @@ -366,22 +377,45 @@ fn display_object(
})
.color(color),
)
.ui(ui)
.clicked();
.ui(ui);
if get_source_path(project_dir, object).is_some() {
response.context_menu(|ui| object_context_ui(ui, object, project_dir));
}
// Always recreate ObjectConfig if selected, in case the project config changed.
// ObjectConfig is compared using equality, so this won't unnecessarily trigger a rebuild.
if selected || clicked {
if selected || response.clicked() {
*selected_obj = Some(ObjectConfig {
name: object_name.to_string(),
target_path: object.target_path.clone(),
base_path: object.base_path.clone(),
reverse_fn_order: object.reverse_fn_order(),
complete: object.complete(),
scratch: object.scratch.clone(),
source_path: object.source_path().cloned(),
});
}
}

fn get_source_path(project_dir: Option<&Path>, object: &ProjectObject) -> Option<PathBuf> {
project_dir.and_then(|dir| object.source_path().map(|path| dir.join(path)))
}

fn object_context_ui(ui: &mut egui::Ui, object: &ProjectObject, project_dir: Option<&Path>) {
if let Some(source_path) = get_source_path(project_dir, object) {
if ui
.button("Open source file")
.on_hover_text("Open the source file in the default editor")
.clicked()
{
log::info!("Opening file {}", source_path.display());
if let Err(e) = open::that_detached(&source_path) {
log::error!("Failed to open source file: {e}");
}
ui.close_menu();
}
}
}

#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
enum NodeOpen {
#[default]
Expand All @@ -394,13 +428,14 @@ enum NodeOpen {
fn display_node(
ui: &mut egui::Ui,
selected_obj: &mut Option<ObjectConfig>,
project_dir: Option<&Path>,
node: &ProjectObjectNode,
appearance: &Appearance,
node_open: NodeOpen,
) {
match node {
ProjectObjectNode::File(name, object) => {
display_object(ui, selected_obj, name, object, appearance);
display_object(ui, selected_obj, project_dir, name, object, appearance);
}
ProjectObjectNode::Dir(name, children) => {
let contains_obj = selected_obj.as_ref().map(|path| contains_node(node, path));
Expand All @@ -426,7 +461,7 @@ fn display_node(
.open(open)
.show(ui, |ui| {
for node in children {
display_node(ui, selected_obj, node, appearance, node_open);
display_node(ui, selected_obj, project_dir, node, appearance, node_open);
}
});
}
Expand Down
12 changes: 12 additions & 0 deletions objdiff-gui/src/views/function_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,18 @@ pub fn function_diff_ui(ui: &mut egui::Ui, state: &mut DiffViewState, appearance
);
}
});
ui.separator();
if ui
.add_enabled(
state.source_path_available,
egui::Button::new("🖹 Source file"),
)
.on_hover_text_at_pointer("Open the source file in the default editor")
.on_disabled_hover_text("Source file metadata missing")
.clicked()
{
state.queue_open_source_path = true;
}
});

ui.scope(|ui| {
Expand Down
42 changes: 40 additions & 2 deletions objdiff-gui/src/views/symbol_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub struct DiffViewState {
pub scratch_available: bool,
pub queue_scratch: bool,
pub scratch_running: bool,
pub source_path_available: bool,
pub queue_open_source_path: bool,
}

#[derive(Default)]
Expand Down Expand Up @@ -86,6 +88,9 @@ impl DiffViewState {
self.symbol_state.reverse_fn_order = value;
self.symbol_state.disable_reverse_fn_order = true;
}
self.source_path_available = obj_config.source_path.is_some();
} else {
self.source_path_available = false;
}
self.scratch_available = CreateScratchConfig::is_available(&state.config);
}
Expand Down Expand Up @@ -122,6 +127,22 @@ impl DiffViewState {
}
}
}

if self.queue_open_source_path {
self.queue_open_source_path = false;
if let Ok(state) = state.read() {
if let (Some(project_dir), Some(source_path)) = (
&state.config.project_dir,
state.config.selected_obj.as_ref().and_then(|obj| obj.source_path.as_ref()),
) {
let source_path = project_dir.join(source_path);
log::info!("Opening file {}", source_path.display());
open::that_detached(source_path).unwrap_or_else(|err| {
log::error!("Failed to open source file: {err}");
});
}
}
}
}
}

Expand Down Expand Up @@ -518,10 +539,27 @@ pub fn symbol_diff_ui(ui: &mut Ui, state: &mut DiffViewState, appearance: &Appea
|ui| {
ui.set_width(column_width);

ui.horizontal(|ui| {
ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
ui.label("Build base:");
});
ui.separator();
if ui
.add_enabled(
state.source_path_available,
egui::Button::new("🖹 Source file"),
)
.on_hover_text_at_pointer("Open the source file in the default editor")
.on_disabled_hover_text("Source file metadata missing")
.clicked()
{
state.queue_open_source_path = true;
}
});

ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);

ui.label("Build base:");
if result.second_status.success {
if result.second_obj.is_none() {
ui.colored_label(appearance.replace_color, "Missing");
Expand Down

0 comments on commit bb039a1

Please sign in to comment.