Implement import/export for tester devtool
This commit is contained in:
parent
e548372fe0
commit
1fd6980f91
6 changed files with 287 additions and 45 deletions
149
Cargo.lock
generated
149
Cargo.lock
generated
|
|
@ -205,6 +205,25 @@ dependencies = [
|
|||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ashpd"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df"
|
||||
dependencies = [
|
||||
"async-fs",
|
||||
"async-net",
|
||||
"enumflags2",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"rand 0.9.1",
|
||||
"raw-window-handle 0.6.2",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"url",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.7.2"
|
||||
|
|
@ -585,6 +604,15 @@ dependencies = [
|
|||
"objc2 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2"
|
||||
dependencies = [
|
||||
"objc2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.6.1"
|
||||
|
|
@ -850,7 +878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f"
|
||||
dependencies = [
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
|
|
@ -1207,7 +1235,7 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18e1a09f280e29a8b00bc7e81eca5ac87dca0575639c9422a5fa25a07bb884b8"
|
||||
dependencies = [
|
||||
"ashpd",
|
||||
"ashpd 0.10.3",
|
||||
"async-std",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
|
|
@ -1273,6 +1301,28 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
||||
|
||||
[[package]]
|
||||
name = "dispatch2"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a0d569e003ff27784e0e14e4a594048698e0c0f0b66cabcb51511be55a7caa0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2 0.6.1",
|
||||
"libc",
|
||||
"objc2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"objc2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
|
|
@ -1365,7 +1415,7 @@ name = "editor"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"iced",
|
||||
"rfd",
|
||||
"rfd 0.13.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
|
@ -2461,6 +2511,7 @@ dependencies = [
|
|||
"iced_test",
|
||||
"iced_widget",
|
||||
"log",
|
||||
"rfd 0.15.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3646,7 +3697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"libc",
|
||||
"objc2 0.5.2",
|
||||
"objc2-core-data",
|
||||
|
|
@ -3655,6 +3706,18 @@ dependencies = [
|
|||
"objc2-quartz-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-app-kit"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2 0.6.1",
|
||||
"objc2 0.6.1",
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-cloud-kit"
|
||||
version = "0.2.2"
|
||||
|
|
@ -3662,7 +3725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation 0.2.2",
|
||||
|
|
@ -3674,7 +3737,7 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
|
@ -3686,18 +3749,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"dispatch2 0.3.0",
|
||||
"objc2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-image"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-metal",
|
||||
|
|
@ -3709,7 +3783,7 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-contacts",
|
||||
"objc2-foundation 0.2.2",
|
||||
|
|
@ -3728,7 +3802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"dispatch",
|
||||
"libc",
|
||||
"objc2 0.5.2",
|
||||
|
|
@ -3742,6 +3816,7 @@ checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
|
|||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"objc2 0.6.1",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3750,9 +3825,9 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
|
|
@ -3763,7 +3838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
|
@ -3775,7 +3850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-metal",
|
||||
|
|
@ -3798,7 +3873,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-cloud-kit",
|
||||
"objc2-core-data",
|
||||
|
|
@ -3818,7 +3893,7 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
|
@ -3830,7 +3905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation 0.2.2",
|
||||
|
|
@ -4291,6 +4366,12 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pollster"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.2"
|
||||
|
|
@ -4769,6 +4850,30 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfd"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80c844748fdc82aae252ee4594a89b6e7ebef1063de7951545564cbc4e57075d"
|
||||
dependencies = [
|
||||
"ashpd 0.11.0",
|
||||
"block2 0.6.1",
|
||||
"dispatch2 0.2.0",
|
||||
"js-sys",
|
||||
"log",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit 0.3.1",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.1",
|
||||
"pollster",
|
||||
"raw-window-handle 0.6.2",
|
||||
"urlencoding",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.50"
|
||||
|
|
@ -6195,6 +6300,12 @@ dependencies = [
|
|||
"iced",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urlencoding"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||
|
||||
[[package]]
|
||||
name = "usvg"
|
||||
version = "0.42.0"
|
||||
|
|
@ -7280,7 +7391,7 @@ dependencies = [
|
|||
"android-activity",
|
||||
"atomic-waker",
|
||||
"bitflags 2.9.1",
|
||||
"block2",
|
||||
"block2 0.5.1",
|
||||
"bytemuck",
|
||||
"calloop",
|
||||
"cfg_aliases",
|
||||
|
|
@ -7294,7 +7405,7 @@ dependencies = [
|
|||
"memmap2",
|
||||
"ndk",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-ui-kit",
|
||||
"orbclient",
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ pulldown-cmark = "0.12"
|
|||
qrcode = { version = "0.13", default-features = false }
|
||||
raw-window-handle = "0.6"
|
||||
resvg = "0.42"
|
||||
rfd = "0.15"
|
||||
rustc-hash = "2.0"
|
||||
serde = "1.0"
|
||||
semver = "1.0"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ workspace = true
|
|||
|
||||
[features]
|
||||
time-travel = ["iced_program/time-travel"]
|
||||
tester = ["dep:iced_test"]
|
||||
tester = ["dep:iced_test", "dep:rfd"]
|
||||
|
||||
[dependencies]
|
||||
iced_debug.workspace = true
|
||||
|
|
@ -25,3 +25,6 @@ log.workspace = true
|
|||
|
||||
iced_test.workspace = true
|
||||
iced_test.optional = true
|
||||
|
||||
rfd.workspace = true
|
||||
rfd.optional = true
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use crate::core::alignment::Horizontal::Right;
|
|||
use crate::core::border;
|
||||
use crate::core::window;
|
||||
use crate::core::{Element, Event, Size, Theme};
|
||||
use crate::executor;
|
||||
use crate::futures::Subscription;
|
||||
use crate::futures::futures::channel::mpsc;
|
||||
use crate::icon;
|
||||
|
|
@ -60,10 +61,14 @@ pub enum Message {
|
|||
Record,
|
||||
Stop,
|
||||
Play,
|
||||
Import,
|
||||
Export,
|
||||
Imported(Option<String>),
|
||||
}
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub enum Tick<P: Program> {
|
||||
Tester(Message),
|
||||
Program(P::Message),
|
||||
Recorder(Event),
|
||||
Emulator(emulator::Event<P>),
|
||||
|
|
@ -163,6 +168,67 @@ impl<P: Program + 'static> Tester<P> {
|
|||
|
||||
Task::run(receiver, Tick::Emulator)
|
||||
}
|
||||
Message::Import => {
|
||||
use std::fs;
|
||||
|
||||
let import = rfd::AsyncFileDialog::new()
|
||||
.add_filter("ice", &["ice"])
|
||||
.pick_file();
|
||||
|
||||
Task::future(import)
|
||||
.and_then(|file| {
|
||||
executor::spawn_blocking(move |mut sender| {
|
||||
let _ = sender
|
||||
.try_send(fs::read_to_string(file.path()).ok());
|
||||
})
|
||||
})
|
||||
.map(Message::Imported)
|
||||
.map(Tick::Tester)
|
||||
}
|
||||
Message::Export => {
|
||||
use std::fs;
|
||||
use std::thread;
|
||||
|
||||
let test: Vec<_> = self
|
||||
.instructions
|
||||
.iter()
|
||||
.map(Instruction::to_string)
|
||||
.collect();
|
||||
|
||||
let export = rfd::AsyncFileDialog::new()
|
||||
.add_filter("ice", &["ice"])
|
||||
.save_file();
|
||||
|
||||
Task::future(async move {
|
||||
let Some(file) = export.await else {
|
||||
return;
|
||||
};
|
||||
|
||||
let _ = thread::spawn(move || {
|
||||
fs::write(file.path(), test.join("\n"))
|
||||
});
|
||||
})
|
||||
.discard()
|
||||
}
|
||||
Message::Imported(instructions) => {
|
||||
let Some(instructions) = instructions else {
|
||||
return Task::none();
|
||||
};
|
||||
|
||||
let instructions: Result<Vec<_>, _> =
|
||||
instructions.lines().map(Instruction::parse).collect();
|
||||
|
||||
match instructions {
|
||||
Ok(instructions) => {
|
||||
self.instructions = instructions;
|
||||
}
|
||||
Err(error) => {
|
||||
log::error!("{error}");
|
||||
}
|
||||
}
|
||||
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,6 +246,7 @@ impl<P: Program + 'static> Tester<P> {
|
|||
|
||||
pub fn tick(&mut self, program: &P, tick: Tick<P>) -> Task<Tick<P>> {
|
||||
match tick {
|
||||
Tick::Tester(message) => self.update(program, message),
|
||||
Tick::Program(message) => {
|
||||
let State::Recording { state } = &mut self.state else {
|
||||
return Task::none();
|
||||
|
|
@ -473,29 +540,43 @@ impl<P: Program + 'static> Tester<P> {
|
|||
.height(Fill)
|
||||
.padding(5);
|
||||
|
||||
let controls = {
|
||||
row![
|
||||
button(icon::play().size(14).width(Fill).center())
|
||||
.on_press_maybe(
|
||||
(!matches!(self.state, State::Recording { .. })
|
||||
&& !self.instructions.is_empty())
|
||||
.then_some(Message::Play),
|
||||
),
|
||||
if let State::Recording { .. } = &self.state {
|
||||
button(icon::stop().size(14).width(Fill).center())
|
||||
.on_press(Message::Stop)
|
||||
.style(button::success)
|
||||
} else {
|
||||
button(icon::record().size(14).width(Fill).center())
|
||||
.on_press_maybe(
|
||||
(!self.is_busy()).then_some(Message::Record),
|
||||
)
|
||||
.style(button::danger)
|
||||
}
|
||||
]
|
||||
.spacing(10)
|
||||
let control = |icon: text::Text<'static, _, _>| {
|
||||
button(icon.size(14).width(Fill).height(Fill).center())
|
||||
};
|
||||
|
||||
let play = control(icon::play()).on_press_maybe(
|
||||
(!matches!(self.state, State::Recording { .. })
|
||||
&& !self.instructions.is_empty())
|
||||
.then_some(Message::Play),
|
||||
);
|
||||
|
||||
let record = if let State::Recording { .. } = &self.state {
|
||||
control(icon::stop())
|
||||
.on_press(Message::Stop)
|
||||
.style(button::success)
|
||||
} else {
|
||||
control(icon::record())
|
||||
.on_press_maybe(
|
||||
(!self.is_busy()).then_some(Message::Record),
|
||||
)
|
||||
.style(button::danger)
|
||||
};
|
||||
|
||||
let import = control(icon::folder())
|
||||
.on_press_maybe((!self.is_busy()).then_some(Message::Import))
|
||||
.style(button::secondary);
|
||||
|
||||
let export = control(icon::floppy())
|
||||
.on_press_maybe(
|
||||
(!matches!(self.state, State::Recording { .. })
|
||||
&& !self.instructions.is_empty())
|
||||
.then_some(Message::Export),
|
||||
)
|
||||
.style(button::success);
|
||||
|
||||
let controls =
|
||||
row![import, export, play, record].height(30).spacing(10);
|
||||
|
||||
column![instructions, controls].spacing(10).align_x(Center)
|
||||
};
|
||||
|
||||
|
|
|
|||
8
examples/todos/tests/carl_sagan.ice
Normal file
8
examples/todos/tests/carl_sagan.ice
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
click left at (377.80, 236.50)
|
||||
type "Create the universe"
|
||||
type enter
|
||||
type "Make an apple pie"
|
||||
type enter
|
||||
click left at (135.40, 351.70)
|
||||
click left at (153.80, 398.10)
|
||||
move cursor to (511.40, 448.50)
|
||||
|
|
@ -10,6 +10,12 @@ pub enum Instruction {
|
|||
Interact(Interaction),
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
pub fn parse(line: &str) -> Result<Self, ParseError> {
|
||||
parser::run(line)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Instruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
|
@ -331,15 +337,16 @@ mod format {
|
|||
}
|
||||
}
|
||||
|
||||
pub use parser::{Error as ParseError, run as parse};
|
||||
pub use parser::Error as ParseError;
|
||||
|
||||
mod parser {
|
||||
use super::*;
|
||||
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::character::complete::{char, multispace0};
|
||||
use nom::combinator::{map, opt};
|
||||
use nom::character::complete::{char, multispace0, satisfy};
|
||||
use nom::combinator::{map, opt, recognize};
|
||||
use nom::multi::many0;
|
||||
use nom::number::float;
|
||||
use nom::sequence::{delimited, preceded, separated_pair};
|
||||
use nom::{Finish, IResult, Parser};
|
||||
|
|
@ -360,7 +367,11 @@ mod parser {
|
|||
}
|
||||
|
||||
fn interaction(input: &str) -> IResult<&str, Interaction> {
|
||||
map(mouse, Interaction::Mouse).parse(input)
|
||||
alt((
|
||||
map(mouse, Interaction::Mouse),
|
||||
map(keyboard, Interaction::Keyboard),
|
||||
))
|
||||
.parse(input)
|
||||
}
|
||||
|
||||
fn mouse(input: &str) -> IResult<&str, Mouse> {
|
||||
|
|
@ -395,6 +406,33 @@ mod parser {
|
|||
.parse(input)
|
||||
}
|
||||
|
||||
fn keyboard(input: &str) -> IResult<&str, Keyboard> {
|
||||
alt((
|
||||
map(preceded(tag("type "), string), Keyboard::Typewrite),
|
||||
map(preceded(tag("type "), key), Keyboard::Type),
|
||||
))
|
||||
.parse(input)
|
||||
}
|
||||
|
||||
fn key(input: &str) -> IResult<&str, Key> {
|
||||
alt((
|
||||
map(tag("enter"), |_| Key::Enter),
|
||||
map(tag("escape"), |_| Key::Escape),
|
||||
map(tag("tab"), |_| Key::Tab),
|
||||
map(tag("backspace"), |_| Key::Backspace),
|
||||
))
|
||||
.parse(input)
|
||||
}
|
||||
|
||||
fn string(input: &str) -> IResult<&str, String> {
|
||||
delimited(
|
||||
char('"'),
|
||||
map(recognize(many0(satisfy(|c| c != '"'))), str::to_owned),
|
||||
char('"'),
|
||||
)
|
||||
.parse(input)
|
||||
}
|
||||
|
||||
fn point(input: &str) -> IResult<&str, Point> {
|
||||
let comma = (multispace0, char(','), multispace0);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue