Skip to content

Commit c92c821

Browse files
committed
auto navigate to specific offset if available.
1 parent 46b2e6f commit c92c821

File tree

5 files changed

+120
-52
lines changed

5 files changed

+120
-52
lines changed

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ members = [
99
]
1010

1111
[workspace.package]
12-
version = "0.0.13" # JAVA_ASM_VERSION
12+
version = "0.0.14" # JAVA_ASM_VERSION
1313
authors = ["zsqw123"]
1414
edition = "2021"
1515
license = "Apache-2.0"
@@ -20,9 +20,9 @@ homepage = "https://crates.io/crates/java_asm"
2020
readme = "README.md"
2121

2222
[workspace.dependencies]
23-
java_asm_macro = { path = "asm_macro", version = "0.0.13" } # JAVA_ASM_VERSION
24-
java_asm = { path = "asm", version = "0.0.13" } # JAVA_ASM_VERSION
25-
java_asm_server = { path = "asm_server", version = "0.0.13" } # JAVA_ASM_VERSION
23+
java_asm_macro = { path = "asm_macro", version = "0.0.14" } # JAVA_ASM_VERSION
24+
java_asm = { path = "asm", version = "0.0.14" } # JAVA_ASM_VERSION
25+
java_asm_server = { path = "asm_server", version = "0.0.14" } # JAVA_ASM_VERSION
2626

2727
enum_dispatch = "0.3.13"
2828
zip = "2.2.0"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ see some examples.
5050
- [ ] GUI frontend:
5151
- [x] basic window with egui.
5252
- [x] load files from the backend
53-
- [ ] add progress bar UI when loading files
53+
- [x] add progress bar UI when loading files
5454
- [x] show metadata in a tree view
5555
- [x] show instructions in a list view
5656
- [ ] quick jump to specific metadata

asm/src/impls/smali/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ fn render_to_lines(
4747
let mut lines = Vec::new();
4848

4949
let mut current_line = Vec::new();
50-
let SmaliNode { tag, content, children, end_tag, .. } = node;
51-
current_line.push(offset_or_stub(max_offset_len, node));
50+
let SmaliNode { tag, content, offset_hint, children, end_tag } = node;
51+
current_line.push(offset_or_stub(max_offset_len, offset_hint));
5252
current_line.push(indent(ident_width));
5353
if let Some(tag) = tag {
5454
current_line.push(SmaliToken::Raw(tag));
@@ -88,14 +88,14 @@ fn max_offset_hint(smali_node: &SmaliNode) -> u32 {
8888
}
8989

9090
fn offset_or_stub(
91-
max_offset_len: usize, smali_node: &SmaliNode,
91+
max_offset_len: usize, offset_hint: &Option<u32>,
9292
) -> SmaliToken {
93-
let raw = if let Some(offset_hint) = smali_node.offset_hint {
94-
format!("{:width$}", offset_hint, width = max_offset_len)
93+
let raw = if let Some(offset_hint) = offset_hint {
94+
format!("{offset_hint:width$}", width = max_offset_len)
9595
} else {
9696
" ".repeat(max_offset_len)
9797
};
98-
SmaliToken::Other(raw.to_ref())
98+
SmaliToken::LineStartOffsetMarker { offset: *offset_hint, raw }
9999
}
100100

101101
fn indent(indent_width: usize) -> SmaliToken {

asm/src/smali.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,18 @@ pub enum SmaliToken {
1515
Raw(ConstStr),
1616
Op(ConstStr),
1717

18+
LineStartOffsetMarker {
19+
// the offset of this instruction.
20+
// None if this isn't a instruction.
21+
offset: Option<u32>,
22+
// rendered text for this marker.
23+
raw: String,
24+
},
1825
Offset {
1926
relative: i32,
2027
absolute: u32,
2128
},
29+
2230
Register(u16),
2331
RegisterRange(u16, u16),
2432
Descriptor(StrRef),
@@ -119,6 +127,7 @@ impl SmaliToken {
119127
match self {
120128
Self::Raw(tag) => tag.to_string(),
121129
Self::Op(op) => op.to_string(),
130+
Self::LineStartOffsetMarker { raw, .. } => raw.clone(),
122131
Self::Offset { relative, absolute } => {
123132
format!("@{absolute}({relative:+})")
124133
}

asm_egui/src/smali.rs

Lines changed: 100 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use eframe::epaint::Color32;
22
use egui::text::LayoutJob;
3-
use egui::{FontId, Response, ScrollArea, TextStyle, Ui};
3+
use egui::{CursorIcon, FontId, Response, ScrollArea, TextStyle, Ui, Vec2};
44
use java_asm::smali::SmaliToken;
55
use java_asm_server::ui::{AppContainer, Content};
66
use java_asm_server::AsmServer;
@@ -23,61 +23,120 @@ pub fn smali_layout(ui: &mut Ui, server: &AsmServer, app: &AppContainer) {
2323
let smali_style = if dark_mode { SmaliStyle::DARK } else { SmaliStyle::LIGHT };
2424

2525
let lines = smali_node.render_to_lines();
26-
let row_height = font.size;
26+
let row_height = ui.text_style_height(&TextStyle::Monospace);
2727

2828
let content_mut = content_locked.deref_mut();
29-
ScrollArea::vertical().auto_shrink(false).show_rows(ui, row_height, lines.len(), |ui, range| {
29+
let scroll_area = ScrollArea::vertical().auto_shrink(false);
30+
let spacing_y = ui.spacing().item_spacing.y;
31+
let mut render_context = RenderContext {
32+
server,
33+
font: &font,
34+
content: content_mut,
35+
lines: &lines,
36+
smali_style: &smali_style,
37+
dft_color,
38+
row_height,
39+
spacing_y,
40+
};
41+
scroll_area.show_rows(ui, row_height, lines.len(), |ui, range| {
3042
for i in range {
31-
let line = &lines[i];
32-
render_line(ui, server, content_mut, line, &font, &smali_style, dft_color);
43+
render_context.render_line(ui, i);
3344
}
3445
});
3546
}
3647

37-
fn render_line(
38-
ui: &mut Ui, server: &AsmServer, content: &mut Content, line: &[SmaliToken],
39-
font: &FontId, smali_style: &SmaliStyle, dft_color: Color32,
40-
) {
41-
ui.horizontal(|ui| {
42-
ui.spacing_mut().item_spacing.x = 0.0;
43-
for token_item in line {
44-
token(ui, server, content, token_item, font, smali_style, dft_color);
45-
}
46-
});
48+
struct RenderContext<'a> {
49+
pub server: &'a AsmServer,
50+
pub content: &'a mut Content,
51+
pub lines: &'a Vec<Vec<SmaliToken>>,
52+
53+
pub font: &'a FontId,
54+
pub smali_style: &'a SmaliStyle,
55+
pub dft_color: Color32,
56+
pub row_height: f32,
57+
pub spacing_y: f32,
4758
}
4859

49-
fn token(
50-
ui: &mut Ui, server: &AsmServer, content: &mut Content, token: &SmaliToken,
51-
font: &FontId, smali_style: &SmaliStyle, dft_color: Color32,
52-
) -> Response {
53-
match token {
54-
SmaliToken::Raw(s) => simple_text(ui, s.to_string(), font, dft_color),
55-
SmaliToken::Op(s) => simple_text(ui, s.to_string(), font, smali_style.op),
56-
SmaliToken::Offset { relative, absolute } => {
57-
let text = format!("@{absolute}({relative:+})");
58-
simple_text(ui, text, font, smali_style.offset)
59-
}
60-
SmaliToken::Register(s) => simple_text(ui, format!("v{s}"), font, smali_style.register),
61-
SmaliToken::RegisterRange(start, end) => {
62-
let text = format!("v{start}..v{end}");
63-
simple_text(ui, text, font, smali_style.register)
60+
impl<'a> RenderContext<'a> {
61+
pub fn render_line(&mut self, ui: &mut Ui, line_index: usize) {
62+
let line = &self.lines[line_index];
63+
ui.horizontal(|ui| {
64+
ui.spacing_mut().item_spacing.x = 0.0;
65+
for token_item in line {
66+
self.token(ui, token_item, line_index);
67+
}
68+
});
69+
}
70+
71+
fn scroll_lines(&self, ui: &mut Ui, line_delta: usize) {
72+
let row_height_with_spacing = self.row_height + self.spacing_y;
73+
let y_delta = line_delta as f32 * row_height_with_spacing;
74+
let delta = Vec2::new(0.0, -y_delta);
75+
ui.scroll_with_delta(delta)
76+
}
77+
78+
fn scroll_to_offset(&self, ui: &mut Ui, current_line: usize, target_offset: u32) {
79+
let start = current_line;
80+
let mut i = current_line;
81+
loop {
82+
let current = i;
83+
i += 1;
84+
let Some(current_line) = self.lines.get(current) else { continue; };
85+
let Some(first_node) = current_line.first() else { continue; };
86+
let SmaliToken::LineStartOffsetMarker { offset: Some(current_offset), .. } = first_node else { continue; };
87+
if *current_offset >= target_offset {
88+
self.scroll_lines(ui, current - start);
89+
break;
90+
}
6491
}
65-
SmaliToken::Descriptor(s) => {
66-
let text_ui = simple_text(ui, s.to_string(), font, smali_style.desc)
67-
.on_hover_ui(|ui| {
68-
ui.style_mut().interaction.selectable_labels = true;
92+
}
93+
94+
95+
fn token(
96+
&mut self, ui: &mut Ui, token: &SmaliToken, line_index: usize,
97+
) -> Response {
98+
let RenderContext {
99+
server, content, font, smali_style, dft_color, ..
100+
} = self;
101+
let dft_color = *dft_color;
102+
match token {
103+
SmaliToken::Raw(s) => simple_text(ui, s.to_string(), font, dft_color),
104+
SmaliToken::Op(s) => simple_text(ui, s.to_string(), font, smali_style.op),
105+
SmaliToken::LineStartOffsetMarker { raw, .. } => {
106+
simple_text(ui, raw.to_string(), font, dft_color)
107+
},
108+
SmaliToken::Offset { relative, absolute } => {
109+
let text = format!("@{absolute}({relative:+})");
110+
let text_ui = simple_text(ui, text, font, smali_style.offset)
111+
.on_hover_cursor(CursorIcon::PointingHand);
112+
if text_ui.clicked() {
113+
self.scroll_to_offset(ui, line_index, *absolute);
114+
}
115+
text_ui
116+
}
117+
SmaliToken::Register(s) => simple_text(ui, format!("v{s}"), font, smali_style.register),
118+
SmaliToken::RegisterRange(start, end) => {
119+
let text = format!("v{start}..v{end}");
120+
simple_text(ui, text, font, smali_style.register)
121+
}
122+
SmaliToken::Descriptor(s) => {
123+
let text_ui = simple_text(ui, s.to_string(), font, smali_style.desc)
124+
.on_hover_ui(|ui| {
125+
ui.style_mut().interaction.selectable_labels = true;
126+
descriptor_menu(ui, s, server, content);
127+
});
128+
text_ui.context_menu(|ui| {
69129
descriptor_menu(ui, s, server, content);
70130
});
71-
text_ui.context_menu(|ui| {
72-
descriptor_menu(ui, s, server, content);
73-
});
74-
text_ui
75-
},
76-
SmaliToken::Literal(s) => simple_text(ui, s.to_string(), font, smali_style.literal),
77-
SmaliToken::Other(s) => simple_text(ui, s.to_string(), font, dft_color),
131+
text_ui
132+
},
133+
SmaliToken::Literal(s) => simple_text(ui, s.to_string(), font, smali_style.literal),
134+
SmaliToken::Other(s) => simple_text(ui, s.to_string(), font, dft_color),
135+
}
78136
}
79137
}
80138

139+
81140
fn descriptor_menu(
82141
ui: &mut Ui, descriptor: &str,
83142
server: &AsmServer, content: &mut Content,

0 commit comments

Comments
 (0)