1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
mod dump;
mod factorio_control;
mod get_setting;
#[cfg(all(debug_assertions, feature = "gui"))]
mod gui;
mod quit;
mod rcon_send;
#[cfg(feature = "restapi")]
mod restapi_control;
#[cfg(feature = "lua")]
mod run_script;
mod set_setting;
use crate::context::Context;
use crate::{paths, APP_ABOUT, APP_NAME};
use factorio_bot_core::miette;
use factorio_bot_core::miette::{miette, IntoDiagnostic};
use reedline_repl_rs::{yansi::Paint, Repl};
use std::fmt;
fn subcommands() -> Vec<Box<dyn Subcommand>> {
vec![
factorio_control::build(),
#[cfg(all(debug_assertions, feature = "gui"))]
gui::build(),
#[cfg(feature = "lua")]
run_script::build(),
rcon_send::build(),
#[cfg(feature = "restapi")]
restapi_control::build(),
set_setting::build(),
get_setting::build(),
quit::build(),
dump::build(),
]
}
pub async fn start(context: Context) -> miette::Result<()> {
let instance_state = context.instance_state.clone();
let mut repl: Repl<Context, Error> = Repl::new(context)
.with_name(APP_NAME)
.with_description(APP_ABOUT)
.with_version(env!("CARGO_PKG_VERSION"))
.with_prompt("repl")
.with_history(paths::data_local_dir().join("repl_history"), 50)
.with_on_after_command_async(|context| Box::pin(update_prompt(context)));
for subcommand in subcommands() {
repl = subcommand.build_command(repl);
}
repl.run_async().await.into_diagnostic()?;
let mut instance_state = instance_state.write().await;
if let Some(instance_state) = instance_state.take() {
instance_state.stop()?;
}
Ok(())
}
async fn update_prompt(context: &mut Context) -> Result<Option<String>> {
let instance_state = context.instance_state.read().await;
let mut prompt = "repl".to_owned();
if instance_state.is_some() {
prompt += &Box::new(Paint::blue(" [running]").bold()).to_string();
};
Ok(Some(prompt))
}
pub trait Subcommand {
fn name(&self) -> &str;
fn build_command(&self, repl: Repl<Context, Error>) -> Repl<Context, Error>;
}
pub struct Error(miette::Error);
pub type Result<T> = std::result::Result<T, Error>;
impl From<reedline_repl_rs::Error> for Error {
fn from(e: reedline_repl_rs::Error) -> Self {
Self(miette!(e.to_string()))
}
}
impl From<miette::Error> for Error {
fn from(e: miette::Error) -> Self {
Self(e)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}