Skip to content

Commit 26c9970

Browse files
committed
feat: implement step in (F11)
1 parent 9144173 commit 26c9970

File tree

4 files changed

+177
-108
lines changed

4 files changed

+177
-108
lines changed

src/tui/code.rs

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,26 @@ use zi::{
88

99
use crate::{
1010
bus::Proxy,
11-
x86::dec::{fetch_after, fetch_before},
11+
tui::PaneStatus,
12+
x86::{
13+
dec::{fetch_after, fetch_before},
14+
Address,
15+
},
1216
};
1317

14-
const FG_EIP: Colour = Colour::rgb(139, 233, 253);
18+
const FG_EIP: Colour = Colour::rgb(255, 0, 127);
1519
const STYLE_EIP: Style = Style::normal(super::BG_DARK, FG_EIP);
1620

1721
#[derive(Clone)]
1822
pub struct Properties {
23+
pub status: PaneStatus,
1924
pub proxy: Rc<Proxy>,
20-
pub attached: bool,
21-
pub focused: bool,
22-
pub cs: u16,
23-
pub eip: u32,
25+
pub addr: Address,
2426
}
2527

2628
impl PartialEq for Properties {
2729
fn eq(&self, other: &Properties) -> bool {
28-
self.attached == other.attached && self.focused == other.focused && self.cs == other.cs && self.eip == other.eip
30+
self.status == other.status && self.addr == other.addr
2931
}
3032
}
3133

@@ -50,10 +52,10 @@ impl Component for Code {
5052
type Properties = Properties;
5153

5254
fn create(props: Self::Properties, frame: Rect, _: ComponentLink<Self>) -> Self {
53-
let (code, error) = if !props.attached {
55+
let (code, error) = if !props.status.attached {
5456
(Vec::new(), Some(anyhow!("Not attached.")))
5557
} else {
56-
match fetch_after(&props.proxy, (props.cs, props.eip).into(), frame.size.height) {
58+
match fetch_after(&props.proxy, props.addr, frame.size.height) {
5759
Ok(c) => (c, None),
5860
Err(e) => (Vec::new(), Some(e)),
5961
}
@@ -70,29 +72,52 @@ impl Component for Code {
7072
}
7173

7274
fn change(&mut self, props: Self::Properties) -> ShouldRender {
73-
if self.props != props {
75+
if self.props == props {
76+
return false.into();
77+
}
78+
79+
if !props.status.attached {
7480
self.props = props;
81+
return true.into();
82+
}
7583

76-
if self.props.attached && self.code.is_empty() {
77-
match fetch_after(
78-
&self.props.proxy,
79-
(self.props.cs, self.props.eip).into(),
80-
self.frame.size.height,
81-
) {
82-
Ok(c) => self.code = c,
83-
Err(e) => self.error = Some(e),
84+
const BOTTOM_PADDING: usize = 4; // number of extra rows on the botoom
85+
let limit = self.frame.height();
86+
let pad = limit.saturating_sub(BOTTOM_PADDING);
87+
88+
let start = self
89+
.code
90+
.iter()
91+
.skip(self.skip)
92+
.take(limit)
93+
.enumerate()
94+
.map(|(i, (ins, _))| (i, ins.ip32()))
95+
.find_map(|(i, ip)| {
96+
if ip == props.addr.offset {
97+
self.code.get(self.skip + i.saturating_sub(pad)).map(|(x, _)| x.ip32())
98+
} else {
99+
None
84100
}
85-
}
101+
})
102+
.unwrap_or(props.addr.offset);
86103

87-
true
88-
} else {
89-
false
104+
match fetch_after(&props.proxy, (props.addr.segment, start).into(), limit) {
105+
Ok(c) => {
106+
self.code = c;
107+
self.skip = 0;
108+
self.pos = None;
109+
self.error = None;
110+
}
111+
Err(e) => self.error = Some(e),
90112
}
91-
.into()
113+
114+
self.props = props;
115+
116+
true.into()
92117
}
93118

94119
fn update(&mut self, message: Self::Message) -> ShouldRender {
95-
if !self.props.attached {
120+
if !self.props.status.attached {
96121
return false.into();
97122
}
98123

@@ -111,7 +136,7 @@ impl Component for Code {
111136
if let Some(offset) = self.code.first().map(|(i, _)| i.ip32()) {
112137
match fetch_before(
113138
&self.props.proxy,
114-
(self.props.cs, offset).into(),
139+
(self.props.addr.segment, offset).into(),
115140
self.frame.size.height,
116141
) {
117142
Ok(mut c) if !c.is_empty() => {
@@ -143,7 +168,7 @@ impl Component for Code {
143168
if let Some(offset) = self.code.last().map(|(i, _)| i.next_ip32()) {
144169
match fetch_after(
145170
&self.props.proxy,
146-
(self.props.cs, offset).into(),
171+
(self.props.addr.segment, offset).into(),
147172
self.frame.size.height,
148173
) {
149174
Ok(c) if !c.is_empty() => {
@@ -171,7 +196,7 @@ impl Component for Code {
171196
}
172197

173198
fn bindings(&self, bindings: &mut Bindings<Self>) {
174-
bindings.set_focus(self.props.focused);
199+
bindings.set_focus(self.props.status.focused);
175200

176201
if !bindings.is_empty() {
177202
return;
@@ -207,13 +232,13 @@ impl Component for Code {
207232
.take(self.frame.size.height)
208233
.enumerate()
209234
{
210-
let mut style = if ins.ip32() == self.props.eip {
235+
let mut style = if ins.ip32() == self.props.addr.offset {
211236
STYLE_EIP
212237
} else {
213238
super::STYLE
214239
};
215240

216-
if self.props.attached && self.pos == Some(y) {
241+
if self.props.status.attached && self.pos == Some(y) {
217242
style.background = super::STYLE_SEL.background;
218243

219244
canvas.clear_region(
@@ -222,7 +247,7 @@ impl Component for Code {
222247
);
223248
}
224249

225-
canvas.draw_str(0, y, style, &format!("{:04X}", self.props.cs));
250+
canvas.draw_str(0, y, style, &format!("{:04X}", self.props.addr.segment));
226251
canvas.draw_str(6, y, style, &format!("{:04X}", ins.ip16()));
227252
canvas.draw_str(
228253
12,

src/tui/data.rs

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,29 @@ use zi::{
55
prelude::*,
66
};
77

8-
use crate::{bus::Proxy, x86::Address};
8+
use crate::{bus::Proxy, tui::PaneStatus, x86::Address};
99

1010
const BYTES_PER_LINE: usize = 16;
1111
const NON_ASCII_CHAR: char = '.';
1212

1313
#[derive(Clone)]
1414
pub struct Properties {
15+
pub status: PaneStatus,
1516
pub proxy: Rc<Proxy>,
16-
pub attached: bool,
17-
pub focused: bool,
1817
pub addr: Address,
1918
}
2019

2120
impl PartialEq for Properties {
2221
fn eq(&self, other: &Properties) -> bool {
23-
self.attached == other.attached && self.focused == other.focused && self.addr == other.addr
22+
self.status == other.status && self.addr == other.addr
2423
}
2524
}
2625

2726
pub struct Data {
2827
props: Properties,
2928
frame: Rect,
3029
error: Option<Error>,
30+
addr: Address,
3131
data: Vec<u8>,
3232
skip: usize,
3333
pos: Option<usize>,
@@ -45,10 +45,12 @@ impl Component for Data {
4545
type Properties = Properties;
4646

4747
fn create(props: Self::Properties, frame: Rect, _: ComponentLink<Self>) -> Self {
48-
let (data, error) = if !props.attached {
48+
let addr = props.addr;
49+
50+
let (data, error) = if !props.status.attached {
4951
(Vec::new(), Some(anyhow!("Not attached.")))
5052
} else {
51-
match props.proxy.mem.get(props.addr.segment, props.addr.offset, 1024) {
53+
match props.proxy.mem.get(addr.segment, addr.offset, bytes_on_screen(&frame)) {
5254
Ok(c) => (c, None),
5355
Err(e) => (Vec::new(), Some(e.into())),
5456
}
@@ -58,37 +60,49 @@ impl Component for Data {
5860
props,
5961
frame,
6062
error,
63+
addr,
6164
data,
6265
skip: 0,
6366
pos: None,
6467
}
6568
}
6669

6770
fn change(&mut self, props: Self::Properties) -> ShouldRender {
68-
if self.props != props {
71+
if self.props == props {
72+
return false.into();
73+
}
74+
75+
if !props.status.attached {
6976
self.props = props;
77+
return true.into();
78+
}
7079

71-
if self.props.attached && self.data.is_empty() {
72-
match self
73-
.props
74-
.proxy
75-
.mem
76-
.get(self.props.addr.segment, self.props.addr.offset, 1024)
77-
{
78-
Ok(d) => self.data = d,
79-
Err(e) => self.error = Some(e.into()),
80-
}
80+
let offset = self.addr.offset + (self.skip * BYTES_PER_LINE) as u32;
81+
82+
match self
83+
.props
84+
.proxy
85+
.mem
86+
.get(self.addr.segment, offset, bytes_on_screen(&self.frame))
87+
{
88+
Ok(d) => {
89+
self.addr.offset = offset;
90+
self.data = d;
91+
self.skip = 0;
92+
self.pos = None;
93+
self.error = None;
8194
}
82-
83-
true
84-
} else {
85-
false
95+
Err(e) => self.error = Some(e.into()),
8696
}
87-
.into()
97+
98+
self.props = props;
99+
self.props.status.reload = false;
100+
101+
true.into()
88102
}
89103

90104
fn update(&mut self, message: Self::Message) -> ShouldRender {
91-
if !self.props.attached {
105+
if !self.props.status.attached {
92106
return false.into();
93107
}
94108

@@ -104,16 +118,16 @@ impl Component for Data {
104118
self.skip -= 1;
105119
}
106120
Message::Up => {
107-
let len = (self.frame.size.height / 2 * BYTES_PER_LINE) as u32;
108-
let start = self.props.addr.offset.saturating_sub(len);
121+
let limit = bytes_on_screen(&self.frame);
122+
let start = self.addr.offset.saturating_sub(limit);
109123

110-
if start < self.props.addr.offset {
111-
match self.props.proxy.mem.get(self.props.addr.segment, start, len) {
124+
if start < self.addr.offset {
125+
match self.props.proxy.mem.get(self.addr.segment, start, limit) {
112126
Ok(mut d) if !d.is_empty() => {
113127
self.skip = (d.len() / BYTES_PER_LINE).saturating_sub(1);
114128
d.append(&mut self.data);
115129
self.data = d;
116-
self.props.addr.offset = start;
130+
self.addr.offset = start;
117131
}
118132
Ok(_) => (),
119133
Err(e) => self.error = Some(e.into()),
@@ -134,10 +148,14 @@ impl Component for Data {
134148
self.skip += 1;
135149
}
136150
Message::Down => {
137-
let len = (self.frame.size.height / 2 * BYTES_PER_LINE) as u32;
138-
let start = self.props.addr.offset.saturating_add(self.data.len() as u32);
151+
let start = self.addr.offset.saturating_add(self.data.len() as u32);
139152

140-
match self.props.proxy.mem.get(self.props.addr.segment, start, len) {
153+
match self
154+
.props
155+
.proxy
156+
.mem
157+
.get(self.addr.segment, start, bytes_on_screen(&self.frame))
158+
{
141159
Ok(d) if !d.is_empty() => {
142160
self.skip += 1;
143161
self.data.extend(d)
@@ -162,7 +180,7 @@ impl Component for Data {
162180
}
163181

164182
fn bindings(&self, bindings: &mut Bindings<Self>) {
165-
bindings.set_focus(self.props.focused);
183+
bindings.set_focus(self.props.status.focused);
166184

167185
if !bindings.is_empty() {
168186
return;
@@ -199,15 +217,12 @@ impl Component for Data {
199217
);
200218
}
201219

202-
canvas.draw_str(0, y, style, &format!("{:04X}", self.props.addr.segment));
220+
canvas.draw_str(0, y, style, &format!("{:04X}", self.addr.segment));
203221
canvas.draw_str(
204222
6,
205223
y,
206224
style,
207-
&format!(
208-
"{:04X}",
209-
self.props.addr.offset as usize + (y + self.skip) * BYTES_PER_LINE
210-
),
225+
&format!("{:04X}", self.addr.offset as usize + (y + self.skip) * BYTES_PER_LINE),
211226
);
212227
canvas.draw_str(
213228
12,
@@ -229,3 +244,7 @@ impl Component for Data {
229244
canvas.into()
230245
}
231246
}
247+
248+
fn bytes_on_screen(rect: &Rect) -> u32 {
249+
(rect.size.height * BYTES_PER_LINE) as u32
250+
}

0 commit comments

Comments
 (0)