Skip to content

Commit 598005b

Browse files
committed
feat: initial layout with zi
1 parent de9940d commit 598005b

File tree

11 files changed

+1083
-2534
lines changed

11 files changed

+1083
-2534
lines changed

Cargo.lock

Lines changed: 742 additions & 2478 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ authors = ["Oleg Scherbakov <scherbakov.oleg@gmail.com>"]
55
edition = "2021"
66

77
[dependencies]
8-
iced = "0.3"
9-
pollster = "0.2"
10-
zbus = "2.0.0-beta.7"
8+
anyhow = { version = "1.0", features = ["backtrace"] }
9+
serde = { version = "1.0", features = ["serde_derive"] }
10+
zbus = "3.14"
11+
zi = "0.3"
12+
zi-term = "0.3"

src/cpu.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use serde::Deserialize;
2+
use zbus::zvariant::Type;
3+
4+
#[derive(Copy, Clone, Default)]
5+
pub struct Cpu {
6+
pub regs: Registers,
7+
}
8+
9+
#[derive(Copy, Clone, Default, Deserialize, PartialEq, Type)]
10+
pub struct Registers {
11+
pub eax: u32,
12+
pub ebx: u32,
13+
pub ecx: u32,
14+
pub edx: u32,
15+
pub esi: u32,
16+
pub edi: u32,
17+
pub ebp: u32,
18+
pub esp: u32,
19+
pub eip: u32,
20+
pub cs: u16,
21+
pub ds: u16,
22+
pub es: u16,
23+
pub _fs: u16,
24+
pub _gs: u16,
25+
pub ss: u16,
26+
pub _cf: bool,
27+
pub _pf: bool,
28+
pub _af: bool,
29+
pub zf: bool,
30+
pub _sf: bool,
31+
pub _tf: bool,
32+
pub _if: bool,
33+
pub _df: bool,
34+
pub _of: bool,
35+
pub _iopl: u8,
36+
pub _nt: bool,
37+
pub _vm: bool,
38+
pub _ac: bool,
39+
pub _id: bool,
40+
}

src/gui/main.rs

Lines changed: 0 additions & 45 deletions
This file was deleted.

src/gui/mod.rs

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/main.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
use iced::{Sandbox, Settings};
1+
use anyhow::Result;
2+
use zbus::blocking::Connection;
3+
use zi::prelude::*;
24

3-
use crate::gui::DebugBox;
5+
mod cpu;
6+
mod tui;
47

5-
mod gui;
8+
use crate::tui::debugbox::DebugBox;
69

7-
fn main() -> iced::Result {
8-
DebugBox::run(Settings::default())
10+
fn main() -> Result<()> {
11+
let app = DebugBox::with(Connection::session()?);
12+
13+
zi_term::incremental()?.run_event_loop(app)?;
14+
15+
Ok(())
916
}

src/tui/code.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use zi::{
2+
components::text::{Text, TextAlign, TextProperties},
3+
prelude::*,
4+
};
5+
6+
pub struct Properties {
7+
pub attached: bool,
8+
pub cs: u16,
9+
pub eip: u32,
10+
}
11+
12+
pub struct Code {
13+
attached: bool,
14+
cs: u16,
15+
eip: u32,
16+
}
17+
18+
impl Component for Code {
19+
type Message = ();
20+
type Properties = Properties;
21+
22+
fn create(props: Self::Properties, _: Rect, _: ComponentLink<Self>) -> Self {
23+
let Self::Properties { attached, cs, eip } = props;
24+
25+
Self { attached, cs, eip }
26+
}
27+
28+
fn view(&self) -> Layout {
29+
let tc = TextProperties::new().style(super::STYLE).align(TextAlign::Centre);
30+
let tc = if self.attached {
31+
tc.content(format!("{:04X}:{:08X}", self.cs, self.eip))
32+
} else {
33+
tc.content("This is a code")
34+
};
35+
36+
Text::with_key("code", tc).into()
37+
}
38+
}

src/tui/debugbox.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
use anyhow::Result;
2+
use zbus::blocking::Connection;
3+
use zi::prelude::*;
4+
5+
use crate::cpu::Cpu;
6+
use crate::tui::code::{Code, Properties as CodeProperties};
7+
use crate::tui::registers::Registers;
8+
use crate::tui::status_bar::{Status, StatusBar};
9+
10+
pub enum Message {
11+
Reload,
12+
Run,
13+
StepOver,
14+
TraceInto,
15+
}
16+
17+
pub struct DebugBox {
18+
link: ComponentLink<Self>,
19+
conn: Connection,
20+
status: Status,
21+
cpu: Cpu,
22+
}
23+
24+
impl DebugBox {
25+
fn update(&mut self) -> Result<()> {
26+
self.cpu.regs = self
27+
.conn
28+
.call_method(Some("com.dosbox"), "/cpu/regs", Some("com.dosbox"), "get", &())?
29+
.body_unchecked()?;
30+
31+
Ok(())
32+
}
33+
34+
fn run(&self) -> Result<()> {
35+
self.conn
36+
.call_method(Some("com.dosbox"), "/cpu", Some("com.dosbox"), "run", &())?;
37+
38+
Ok(())
39+
}
40+
}
41+
42+
impl Component for DebugBox {
43+
type Message = Message;
44+
type Properties = Connection;
45+
46+
fn create(conn: Self::Properties, _frame: Rect, link: ComponentLink<Self>) -> Self {
47+
let mut this = Self {
48+
link,
49+
conn,
50+
status: Status::Detached(None),
51+
cpu: Default::default(),
52+
};
53+
54+
// TODO: need to handle timeout with `monitor_activity` (Call failed: Connection timed out)
55+
this.status = if let Err(e) = this.update() {
56+
Status::Detached(Some(e.to_string()))
57+
} else {
58+
Status::Attached
59+
};
60+
61+
this
62+
}
63+
64+
fn update(&mut self, message: Self::Message) -> ShouldRender {
65+
let mut update = || -> Result<bool> {
66+
match message {
67+
Message::Reload => {
68+
self.update()?;
69+
self.status = Status::Attached;
70+
71+
Ok(true)
72+
}
73+
Message::Run => {
74+
if self.status != Status::Attached {
75+
return Ok(false);
76+
}
77+
78+
self.run()?;
79+
self.status = Status::Detached(None);
80+
81+
Ok(true)
82+
}
83+
Message::StepOver => Ok(true),
84+
Message::TraceInto => Ok(true),
85+
}
86+
};
87+
88+
update()
89+
.unwrap_or_else(|e| {
90+
self.status = Status::Detached(Some(e.to_string()));
91+
true
92+
})
93+
.into()
94+
}
95+
96+
fn bindings(&self, bindings: &mut Bindings<Self>) {
97+
if !bindings.is_empty() {
98+
return;
99+
}
100+
101+
bindings.set_focus(true);
102+
103+
bindings.command("reload", || Message::Reload).with([Key::Ctrl('r')]);
104+
bindings.command("run", || Message::Run).with([Key::F(5)]);
105+
bindings.command("step-over", || Message::StepOver).with([Key::F(10)]);
106+
bindings.command("trace-into", || Message::TraceInto).with([Key::F(11)]);
107+
108+
bindings
109+
.command("exit", |this: &Self| this.link.exit())
110+
.with([Key::Ctrl('c')])
111+
.with([Key::Esc]);
112+
}
113+
114+
fn view(&self) -> Layout {
115+
Layout::column([
116+
Item::auto(Layout::row([
117+
Item::auto(Code::with(CodeProperties {
118+
attached: self.status == Status::Attached,
119+
cs: self.cpu.regs.cs,
120+
eip: self.cpu.regs.eip,
121+
})),
122+
Item::fixed(50)(Registers::with(self.cpu.regs)),
123+
])),
124+
Item::fixed(1)(StatusBar::with(self.status.clone())),
125+
])
126+
}
127+
}

src/tui/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use zi::{Colour, Style};
2+
3+
pub mod code;
4+
pub mod debugbox;
5+
pub mod registers;
6+
pub mod status_bar;
7+
8+
const BACKGROUND: Colour = Colour::rgb(33, 34, 44);
9+
const BACKGROUND_DARK: Colour = Colour::rgb(14, 20, 25);
10+
const FOREGROUND: Colour = Colour::rgb(80, 250, 123);
11+
const FOREGROUND_GRAY: Colour = Colour::rgb(248, 248, 242);
12+
const STYLE: Style = Style::bold(BACKGROUND_DARK, FOREGROUND);

src/tui/registers.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use zi::{
2+
components::text::{Text, TextProperties},
3+
prelude::*,
4+
};
5+
6+
use crate::cpu::Registers as Regs;
7+
8+
pub struct Registers {
9+
regs: Regs,
10+
}
11+
12+
impl Component for Registers {
13+
type Message = ();
14+
type Properties = Regs;
15+
16+
fn create(regs: Self::Properties, _: Rect, _: ComponentLink<Self>) -> Self {
17+
Self { regs }
18+
}
19+
20+
fn change(&mut self, regs: Self::Properties) -> ShouldRender {
21+
if self.regs != regs {
22+
self.regs = regs;
23+
24+
true
25+
} else {
26+
false
27+
}
28+
.into()
29+
}
30+
31+
fn view(&self) -> Layout {
32+
let r = self.regs;
33+
34+
let regs = [
35+
[("EAX", r.eax), ("EBX", r.ebx), ("ECX", r.ecx), ("EDX", r.edx)],
36+
[("ESI", r.esi), ("EDI", r.edi), ("EBP", r.ebp), ("ESP", r.esp)],
37+
[
38+
("CS", r.cs.into()),
39+
("DS", r.ds.into()),
40+
("ES", r.es.into()),
41+
("SS", r.ss.into()),
42+
],
43+
];
44+
45+
Layout::row(regs.map(|col| {
46+
Item::auto(Layout::column(col.map(|(name, value)| {
47+
Item::fixed(1)(Text::with_key(
48+
name,
49+
TextProperties::new().style(super::STYLE).content(if name.len() == 2 {
50+
format!("{name}={value:04X}")
51+
} else {
52+
format!("{name}={value:08X}")
53+
}),
54+
))
55+
})))
56+
}))
57+
}
58+
}

0 commit comments

Comments
 (0)