|
| 1 | +use eframe::epaint::Color32; |
1 | 2 | use egui::text::LayoutJob; |
2 | | -use egui::util::cache::{ComputerMut, FrameCache}; |
3 | | -use egui::{Color32, FontId, TextFormat, TextStyle, Ui}; |
| 3 | +use egui::{FontId, Response, ScrollArea, TextStyle, Ui}; |
4 | 4 | use java_asm::smali::{SmaliNode, SmaliToken}; |
5 | 5 |
|
6 | | -#[derive(Default)] |
7 | | -struct SmaliHighlighter; |
8 | | - |
9 | | -// font, dft_color, dark_mode, smali_node |
10 | | -impl ComputerMut<(&FontId, Color32, bool, &SmaliNode), LayoutJob> for SmaliHighlighter { |
11 | | - fn compute(&mut self, key: (&FontId, Color32, bool, &SmaliNode)) -> LayoutJob { |
12 | | - let (font, dft_color, dark_mode, smali_node) = key; |
13 | | - let mut job = LayoutJob::default(); |
14 | | - let smali_style = if dark_mode { SmaliStyle::DARK } else { SmaliStyle::LIGHT }; |
15 | | - let max_offset_len = max_offset_hint(smali_node).to_string().len(); |
16 | | - append_node(&font, dft_color, &smali_style, smali_node, &mut job, 0, max_offset_len); |
17 | | - job |
18 | | - } |
19 | | -} |
20 | | - |
21 | 6 | pub fn smali_layout(ui: &mut Ui, smali_node: &SmaliNode) { |
22 | 7 | let ctx = &mut ui.ctx(); |
23 | 8 |
|
24 | | - type HighlightCache = FrameCache<LayoutJob, SmaliHighlighter>; |
25 | | - |
26 | 9 | let style = ui.ctx().style(); |
27 | 10 | let font = TextStyle::Monospace.resolve(&style); |
28 | 11 | let dft_color = style.visuals.text_color(); |
29 | 12 | let dark_mode = style.visuals.dark_mode; |
30 | | - let job = ctx.memory_mut(|mem| { |
31 | | - mem.caches.cache::<HighlightCache>() |
32 | | - .get( (&font, dft_color, dark_mode, smali_node)) |
33 | | - }); |
34 | | - ui.label(job); |
35 | | -} |
| 13 | + let smali_style = if dark_mode { SmaliStyle::DARK } else { SmaliStyle::LIGHT }; |
36 | 14 |
|
37 | | -fn append_node( |
38 | | - font: &FontId, dft_color: Color32, smali_style: &SmaliStyle, node: &SmaliNode, |
39 | | - job: &mut LayoutJob, indent: usize, max_offset_len: usize, |
40 | | -) { |
41 | | - let SmaliNode { tag, content, children, end_tag, .. } = node; |
42 | | - append_offset_or_stub(max_offset_len, node, job, font, smali_style); |
43 | | - append_indent(job, font, smali_style, indent); |
44 | | - if let Some(tag) = tag { |
45 | | - append(job, tag, font, dft_color); |
46 | | - append_space(job, font, smali_style); |
47 | | - } |
48 | | - for token in content { |
49 | | - append_token(font, dft_color, smali_style, token, job); |
50 | | - append_space(job, font, smali_style); |
51 | | - } |
52 | | - for child in children { |
53 | | - append(job, "\n", font, dft_color); |
54 | | - append_node(font, dft_color, smali_style, child, job, indent + 1, max_offset_len); |
55 | | - } |
56 | | - if children.len() > 0 { |
57 | | - append(job, "\n", font, dft_color); |
58 | | - } |
59 | | - if let Some(end_tag) = end_tag { |
60 | | - append_indent(job, font, smali_style, indent); |
61 | | - append(job, end_tag, font, dft_color); |
62 | | - append(job, "\n", font, dft_color); |
63 | | - } |
64 | | -} |
65 | | - |
66 | | -#[inline] |
67 | | -fn max_offset_hint(smali_node: &SmaliNode) -> u32 { |
68 | | - let mut max = 0; |
69 | | - for child in &smali_node.children { |
70 | | - max = max.max(max_offset_hint(child)); |
71 | | - } |
72 | | - if let Some(offset_hint) = smali_node.offset_hint { |
73 | | - max = max.max(offset_hint); |
74 | | - } |
75 | | - max |
| 15 | + let lines = smali_node.render_to_lines(); |
| 16 | + let row_height = font.size + ui.spacing().item_spacing.y; |
| 17 | + ScrollArea::vertical().auto_shrink(false).show_rows(ui, row_height, lines.len(), |ui, range| { |
| 18 | + for i in range { |
| 19 | + let line = &lines[i]; |
| 20 | + render_line(ui, &font, &smali_style, dft_color, line); |
| 21 | + } |
| 22 | + }); |
76 | 23 | } |
77 | 24 |
|
78 | | -fn append_offset_or_stub( |
79 | | - max_offset_len: usize, smali_node: &SmaliNode, job: &mut LayoutJob, |
80 | | - font: &FontId, smali_style: &SmaliStyle, |
| 25 | +fn render_line( |
| 26 | + ui: &mut Ui, font: &FontId, smali_style: &SmaliStyle, dft_color: Color32, line: &[SmaliToken], |
81 | 27 | ) { |
82 | | - if let Some(offset_hint) = smali_node.offset_hint { |
83 | | - let offset_str = format!("{:width$}", offset_hint, width = max_offset_len); |
84 | | - append(job, &offset_str, font, smali_style.offset); |
85 | | - } else { |
86 | | - append(job, &" ".repeat(max_offset_len), font, smali_style.offset); |
87 | | - } |
| 28 | + ui.horizontal(|ui| { |
| 29 | + ui.spacing_mut().item_spacing.x = 0.0; |
| 30 | + for token_item in line { |
| 31 | + token(ui, font, smali_style, dft_color, token_item); |
| 32 | + } |
| 33 | + }); |
88 | 34 | } |
89 | 35 |
|
90 | | -fn append_token( |
91 | | - font: &FontId, dft_color: Color32, smali_style: &SmaliStyle, token: &SmaliToken, |
92 | | - job: &mut LayoutJob, |
93 | | -) { |
| 36 | +fn token( |
| 37 | + ui: &mut Ui, font: &FontId, smali_style: &SmaliStyle, |
| 38 | + dft_color: Color32, token: &SmaliToken, |
| 39 | +) -> Response { |
94 | 40 | match token { |
95 | | - SmaliToken::Raw(s) => append(job, s, font, dft_color), |
96 | | - SmaliToken::Op(s) => append(job, s, font, smali_style.op), |
| 41 | + SmaliToken::Raw(s) => simple_text(ui, s.to_string(), font, dft_color), |
| 42 | + SmaliToken::Op(s) => simple_text(ui, s.to_string(), font, smali_style.op), |
97 | 43 | SmaliToken::Offset { relative, absolute } => { |
98 | 44 | let text = format!("@{absolute}({relative:+})"); |
99 | | - append(job, &text, font, smali_style.offset); |
| 45 | + simple_text(ui, text, font, smali_style.offset) |
100 | 46 | } |
101 | | - SmaliToken::Register(s) => append(job, &format!("v{s}"), font, smali_style.register), |
| 47 | + SmaliToken::Register(s) => simple_text(ui, format!("v{s}"), font, smali_style.register), |
102 | 48 | SmaliToken::RegisterRange(start, end) => { |
103 | 49 | let text = format!("v{start}..v{end}"); |
104 | | - append(job, &text, font, smali_style.register); |
| 50 | + simple_text(ui, text, font, smali_style.register) |
105 | 51 | } |
106 | | - SmaliToken::Descriptor(s) => append(job, s, font, smali_style.desc), |
107 | | - SmaliToken::Literal(s) => append(job, s, font, smali_style.literal), |
108 | | - SmaliToken::Other(s) => append(job, s, font, dft_color), |
| 52 | + SmaliToken::Descriptor(s) => simple_text(ui, s.to_string(), font, smali_style.desc), |
| 53 | + SmaliToken::Literal(s) => simple_text(ui, s.to_string(), font, smali_style.literal), |
| 54 | + SmaliToken::Other(s) => simple_text(ui, s.to_string(), font, dft_color), |
109 | 55 | } |
110 | 56 | } |
111 | 57 |
|
112 | | -#[inline] |
113 | | -fn append_indent(job: &mut LayoutJob, font: &FontId, smali_style: &SmaliStyle, indent: usize) { |
114 | | - let str = " ".repeat(indent); |
115 | | - append(job, &str, font, smali_style.offset); |
116 | | -} |
117 | | - |
118 | | -#[inline] |
119 | | -fn append_space(job: &mut LayoutJob, font: &FontId, smali_style: &SmaliStyle) { |
120 | | - append(job, " ", font, smali_style.offset); |
121 | | -} |
122 | | - |
123 | | -#[inline] |
124 | | -fn append(job: &mut LayoutJob, text: &str, font: &FontId, color: Color32) { |
125 | | - job.append(text, 0.0, TextFormat::simple(font.clone(), color)); |
| 58 | +fn simple_text( |
| 59 | + ui: &mut Ui, text: String, font: &FontId, color: Color32, |
| 60 | +) -> Response { |
| 61 | + ui.label(LayoutJob::simple_singleline(text, font.clone(), color)) |
126 | 62 | } |
127 | 63 |
|
128 | 64 | #[derive(Copy, Clone, Debug)] |
|
0 commit comments