use {
super::*,
crate::{
command::{Command, TriggerType},
display::{Screen, W},
errors::ProgramError,
flag::Flag,
pattern::*,
selection_type::SelectionType,
skin::PanelSkin,
task_sync::Dam,
verb::*,
},
std::path::{Path, PathBuf},
termimad::Area,
};
pub trait AppState {
fn clear_pending(&mut self) {}
fn on_click(
&mut self,
_x: u16,
_y: u16,
_screen: &mut Screen,
_con: &AppContext,
) -> Result<AppStateCmdResult, ProgramError> {
Ok(AppStateCmdResult::Keep)
}
fn on_double_click(
&mut self,
_x: u16,
_y: u16,
_screen: &mut Screen,
_con: &AppContext,
) -> Result<AppStateCmdResult, ProgramError> {
Ok(AppStateCmdResult::Keep)
}
fn on_pattern(
&mut self,
_pat: InputPattern,
_con: &AppContext,
) -> Result<AppStateCmdResult, ProgramError> {
Ok(AppStateCmdResult::Keep)
}
fn on_internal(
&mut self,
w: &mut W,
internal_exec: &InternalExecution,
input_invocation: Option<&VerbInvocation>,
trigger_type: TriggerType,
cc: &CmdContext,
screen: &mut Screen,
) -> Result<AppStateCmdResult, ProgramError>;
fn on_command(
&mut self,
w: &mut W,
cc: &CmdContext,
screen: &mut Screen,
) -> Result<AppStateCmdResult, ProgramError> {
self.clear_pending();
let con = &cc.con;
match cc.cmd {
Command::Click(x, y) => self.on_click(*x, *y, screen, con),
Command::DoubleClick(x, y) => self.on_double_click(*x, *y, screen, con),
Command::PatternEdit { raw, expr } => {
match InputPattern::new(raw.clone(), expr, &cc.con) {
Ok(pattern) => self.on_pattern(pattern, con),
Err(e) => Ok(AppStateCmdResult::DisplayError(format!("{}", e))),
}
}
Command::VerbTrigger {
index,
input_invocation,
} => {
let verb = &con.verb_store.verbs[*index];
match &verb.execution {
VerbExecution::Internal(internal_exec) => self.on_internal(
w,
internal_exec,
input_invocation.as_ref(),
TriggerType::Other,
cc,
screen,
),
VerbExecution::External(external) => external.to_cmd_result(
w,
self.selected_path(),
&cc.other_path,
if let Some(inv) = &input_invocation {
&inv.args
} else {
&None
},
con,
),
}
}
Command::Internal {
internal,
input_invocation,
} => self.on_internal(
w,
&InternalExecution::from_internal(*internal),
input_invocation.as_ref(),
TriggerType::Other,
cc,
screen,
),
Command::VerbInvocate(invocation) => match con.verb_store.search(&invocation.name) {
PrefixSearchResult::Match(_, verb) => {
if let Some(err) = verb.check_args(invocation, &cc.other_path) {
Ok(AppStateCmdResult::DisplayError(err))
} else {
match &verb.execution {
VerbExecution::Internal(internal_exec) => self.on_internal(
w,
internal_exec,
Some(invocation),
TriggerType::Input,
cc,
screen,
),
VerbExecution::External(external) => {
external.to_cmd_result(
w,
self.selected_path(),
&cc.other_path,
&invocation.args,
con,
)
}
}
}
}
_ => Ok(AppStateCmdResult::verb_not_found(&invocation.name)),
},
Command::None | Command::VerbEdit(_) => {
Ok(AppStateCmdResult::Keep)
}
}
}
fn selected_path(&self) -> &Path;
fn selection_type(&self) -> SelectionType;
fn refresh(&mut self, screen: &Screen, con: &AppContext) -> Command;
fn do_pending_task(
&mut self,
screen: &mut Screen,
con: &AppContext,
dam: &mut Dam,
);
fn get_pending_task(&self) -> Option<&'static str>;
fn display(
&mut self,
w: &mut W,
screen: &Screen,
state_area: Area,
skin: &PanelSkin,
con: &AppContext,
) -> Result<(), ProgramError>;
fn get_status(
&self,
cmd: &Command,
other_path: &Option<PathBuf>,
con: &AppContext,
) -> Status;
fn get_flags(&self) -> Vec<Flag>;
fn get_starting_input(&self) -> String {
String::new()
}
}