Skip to content

Commit

Permalink
Inspector links
Browse files Browse the repository at this point in the history
  • Loading branch information
Gui-Yom committed Sep 12, 2022
1 parent cc7fc5b commit 39f4154
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 66 deletions.
49 changes: 19 additions & 30 deletions hlbc-gui/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release

use std::cell::{Ref, RefCell, RefMut};
use std::cell::{Cell, Ref, RefCell, RefMut};
use std::io::BufReader;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::{env, fs};

Expand Down Expand Up @@ -88,7 +88,7 @@ struct App {
impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
{
if let Some(tab) = self.ctx.as_ref().and_then(|app| app.new_tab()) {
if let Some(tab) = self.ctx.as_ref().and_then(|app| app.take_tab_to_open()) {
self.tree[NodeIndex::root().left()].append_tab(tab);
}
}
Expand Down Expand Up @@ -179,57 +179,46 @@ impl eframe::App for App {
/// Usage warning ! The methods 'lock' the inner RefCell immutably and mutably (RW lock).
/// Be careful of guards (Ref<> and RefMut<>) lifetimes.
#[derive(Clone)]
struct AppCtxHandle(Rc<RefCell<AppCtx>>);
struct AppCtxHandle(Rc<AppCtx>);

impl AppCtxHandle {
fn new(appctx: AppCtx) -> Self {
Self(Rc::new(RefCell::new(appctx)))
Self(Rc::new(appctx))
}

fn lock(&self) -> Ref<AppCtx> {
self.0.borrow()
fn file(&self) -> &Path {
&self.0.file
}

/// mut lock
fn lock_mut(&self) -> RefMut<AppCtx> {
self.0.borrow_mut()
}

fn file(&self) -> Ref<PathBuf> {
Ref::map(self.lock(), |app| &app.file)
}

fn code(&self) -> Ref<Bytecode> {
Ref::map(self.lock(), |app| &app.code)
fn code(&self) -> &Bytecode {
&self.0.code
}

/// mut lock
fn open_tab(&self, tab: impl AppTab) {
self.lock_mut().new_tab = Some(tab.make_tab(self.clone()));
self.0.new_tab.set(Some(tab.make_tab(self.clone())));
}

/// mut lock
fn new_tab(&self) -> Option<Box<dyn Tab>> {
self.lock_mut().new_tab.take()
fn take_tab_to_open(&self) -> Option<Box<dyn Tab>> {
self.0.new_tab.take()
}

fn selected(&self) -> ItemSelection {
self.lock().selected
self.0.selected.get()
}

/// mut lock
fn set_selected(&self, s: ItemSelection) {
self.lock_mut().selected = s;
self.0.selected.set(s);
}
}

struct AppCtx {
file: PathBuf,
code: Bytecode,
selected: ItemSelection,
selected: Cell<ItemSelection>,
/// To open a tab from another tab.
/// This can't be done directly because this would need a mutable reference to a tree and the tree owns the tab.
new_tab: Option<Box<dyn Tab>>,
new_tab: Cell<Option<Box<dyn Tab>>>,
}

impl AppCtx {
Expand All @@ -241,16 +230,16 @@ impl AppCtx {
AppCtx {
file,
code,
selected: ItemSelection::None,
new_tab: None,
selected: Cell::new(ItemSelection::None),
new_tab: Cell::new(None),
}
}
}

fn default_tabs_ui(ctx: AppCtxHandle) -> DynamicTree {
let mut tree = Tree::new(vec![
InfoView::default().make_tab(ctx.clone()),
SyncInspectorView::default().make_tab(ctx.clone()),
InfoView::default().make_tab(ctx.clone()),
]);

tree.split_left(
Expand Down
103 changes: 67 additions & 36 deletions hlbc-gui/src/views/inspector.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::ops::Deref;

use eframe::egui::style::Margin;
use eframe::egui::{Color32, Frame, Grid, RichText, ScrollArea, TextStyle, Ui, WidgetText};
use eframe::egui::{
Color32, Frame, Grid, Hyperlink, Link, RichText, ScrollArea, TextStyle, Ui, WidgetText,
};

use hlbc::types::{FunPtr, RefField, RefFun, RefGlobal, RefString, RefType};
use hlbc::Bytecode;
Expand Down Expand Up @@ -68,31 +70,42 @@ fn inspector_ui(ui: &mut Ui, ctx: AppCtxHandle, item: ItemSelection) {
ScrollArea::vertical()
.id_source("functions_scroll_area")
.auto_shrink([false, false])
.show(ui, |ui| {
let code = ctx.code();
let code = code.deref();
match item {
ItemSelection::Fun(fun) => {
function_inspector(ui, fun, code);
}
ItemSelection::Class(t) => {
class_inspector(ui, t, code);
}
ItemSelection::Global(g) => {
global_inspector(ui, g, code);
}
ItemSelection::String(s) => {
string_inspector(ui, s, code);
}
_ => {
ui.label("Select a function or a class.");
}
.show(ui, |ui| match item {
ItemSelection::Fun(fun) => {
function_inspector(ui, ctx, fun);
}
ItemSelection::Class(t) => {
class_inspector(ui, ctx, t);
}
ItemSelection::Global(g) => {
global_inspector(ui, ctx, g);
}
ItemSelection::String(s) => {
string_inspector(ui, ctx, s);
}
_ => {
ui.label("Select a function or a class.");
}
});
});
}

fn function_inspector(ui: &mut Ui, fun: RefFun, code: &Bytecode) {
fn inspector_link(ui: &mut Ui, ctx: AppCtxHandle, item: ItemSelection) {
let res = ui
.add(Link::new(item.name(ctx.code().deref())))
.context_menu(|ui| {
if ui.button("Open in inspector").clicked() {
ctx.open_tab(InspectorView::new(item, ctx.code().deref()));
ui.close_menu();
}
});
if res.clicked() {
ctx.set_selected(item);
}
}

fn function_inspector(ui: &mut Ui, ctx: AppCtxHandle, fun: RefFun) {
let code = ctx.code();
match fun.resolve(code) {
FunPtr::Fun(f) => {
ui.heading(format!(
Expand All @@ -101,10 +114,10 @@ fn function_inspector(ui: &mut Ui, fun: RefFun, code: &Bytecode) {
f.findex.0
));
if let Some(parent) = f.parent {
ui.label(format!(
"static/instance method of {}",
parent.display_id(code)
));
ui.horizontal(|ui| {
ui.label("static/instance method of");
inspector_link(ui, ctx.clone(), ItemSelection::Class(parent));
});
} else {
ui.label("Probably a closure.");
}
Expand Down Expand Up @@ -154,14 +167,25 @@ fn function_inspector(ui: &mut Ui, fun: RefFun, code: &Bytecode) {
}
}

fn class_inspector(ui: &mut Ui, t: RefType, code: &Bytecode) {
fn class_inspector(ui: &mut Ui, ctx: AppCtxHandle, t: RefType) {
let code = ctx.code();
ui.heading(format!("Class : {}", t.display_id(code)));
if let Some(obj) = t.resolve_as_obj(&code.types) {
if let Some(super_) = obj.super_ {
ui.label(format!("extends {}", super_.display_id(code)));
ui.horizontal(|ui| {
ui.label("extends");
inspector_link(ui, ctx.clone(), ItemSelection::Class(super_));
});
}
if obj.global.0 >= 1 {
ui.label(format!("initialized by global {}", obj.global.0 - 1));
ui.horizontal(|ui| {
ui.label("initialized by global");
inspector_link(
ui,
ctx.clone(),
ItemSelection::Global(RefGlobal(obj.global.0 - 1)),
);
});
}

if obj.own_fields.is_empty() {
Expand All @@ -176,11 +200,12 @@ fn class_inspector(ui: &mut Ui, t: RefType, code: &Bytecode) {
for (i, f) in obj.own_fields.iter().enumerate() {
ui.label(f.name.resolve(&code.strings));
ui.label(f.t.display_id(code));
if let Some(binding) = obj
if let Some(&binding) = obj
.bindings
.get(&RefField(i + obj.fields.len() - obj.own_fields.len()))
{
ui.monospace(format!("bound to {}", binding.display_id(code)));
ui.monospace("bound to");
inspector_link(ui, ctx.clone(), ItemSelection::Fun(binding));
} else {
ui.monospace("variable");
}
Expand All @@ -201,7 +226,7 @@ fn class_inspector(ui: &mut Ui, t: RefType, code: &Bytecode) {
.show(ui, |ui| {
for f in &obj.protos {
ui.label(f.name.resolve(&code.strings));
ui.label(f.findex.display_id(code).to_string());
inspector_link(ui, ctx.clone(), ItemSelection::Fun(f.findex));
ui.end_row();
}
});
Expand All @@ -212,21 +237,27 @@ fn class_inspector(ui: &mut Ui, t: RefType, code: &Bytecode) {
}
}

fn global_inspector(ui: &mut Ui, g: RefGlobal, code: &Bytecode) {
fn global_inspector(ui: &mut Ui, ctx: AppCtxHandle, g: RefGlobal) {
ui.heading(format!("Global@{}", g.0));
ui.label(format!("Type : {}", code.globals[g.0].display_id(code)));
ui.label(format!(
"Type : {}",
ctx.code().globals[g.0].display_id(ctx.code().deref())
));

if let (Some(&cst), Some(constants)) = (code.globals_initializers.get(&g), &code.constants) {
if let (Some(&cst), Some(constants)) = (
ctx.code().globals_initializers.get(&g),
&ctx.code().constants,
) {
let def = &constants[cst];
ui.label(format!("{:?}", def.fields));
} else {
ui.label("This global is initialized with code");
}
}

fn string_inspector(ui: &mut Ui, s: RefString, code: &Bytecode) {
fn string_inspector(ui: &mut Ui, ctx: AppCtxHandle, s: RefString) {
ui.heading(format!("String@{}", s.0));
ui.separator();
ui.add_space(4.0);
ui.label(RichText::new(s.resolve(&code.strings)).monospace());
ui.label(RichText::new(s.resolve(&ctx.code().strings)).monospace());
}

0 comments on commit 39f4154

Please sign in to comment.