use jk_cli::{
DiffQuery, EvologQuery, LogTemplateSelection, OperationQuery, ShowQuery, StatusQuery,
WorkspaceInspectionQuery,
};
use jk_core::CommandHistory;
use jk_tui::command_discovery::BindingContext;
use jk_tui::command_history_view::CommandHistoryView;
use jk_tui::diff_view::DiffView;
use jk_tui::log_view::LogView;
use jk_tui::operation_log_view::OperationLogView;
use jk_tui::rendered_view::RenderedView;
use jk_tui::workspaces_view::WorkspacesView;
use crate::mutation_preview::PendingCommandPreview;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AppView {
Log(LogView),
Diff {
view: DiffView,
query: DiffQuery,
},
Show {
view: RenderedView,
query: ShowQuery,
},
Evolog {
view: RenderedView,
query: EvologQuery,
},
Status {
view: RenderedView,
query: StatusQuery,
},
Workspaces {
view: WorkspacesView,
},
CommandHistory {
view: CommandHistoryView,
},
CommandHistoryDetails {
view: RenderedView,
},
CommandOutput {
view: RenderedView,
input: String,
},
OperationLog {
view: OperationLogView,
},
OperationShow {
view: RenderedView,
query: OperationQuery,
},
OperationDiff {
view: RenderedView,
query: OperationQuery,
},
WorkspaceStatus {
view: RenderedView,
query: WorkspaceInspectionQuery,
},
WorkspaceLog {
view: RenderedView,
query: WorkspaceInspectionQuery,
},
WorkspaceDiff {
view: RenderedView,
query: WorkspaceInspectionQuery,
},
}
#[derive(Debug)]
pub struct AppState {
pub(crate) views: ViewStack,
pub(crate) modes: ModeStack,
pub(crate) history: CommandHistory,
}
impl AppState {
#[cfg(test)]
pub(crate) fn new(root: AppView) -> Self {
Self::with_history(root, CommandHistory::default())
}
pub(crate) fn with_history(root: AppView, history: CommandHistory) -> Self {
Self {
views: ViewStack::new(root),
modes: ModeStack::default(),
history,
}
}
#[cfg(test)]
pub(crate) const fn command_history(&self) -> &CommandHistory {
&self.history
}
}
#[derive(Debug)]
pub struct ViewStack {
views: Vec<AppView>,
}
impl ViewStack {
pub(crate) fn new(root: AppView) -> Self {
Self { views: vec![root] }
}
pub(crate) fn active(&self) -> &AppView {
match self.views.last() {
Some(view) => view,
None => panic!("view stack always keeps one root view"),
}
}
pub(crate) fn active_mut(&mut self) -> &mut AppView {
match self.views.last_mut() {
Some(view) => view,
None => panic!("view stack always keeps one root view"),
}
}
pub(crate) fn push(&mut self, view: AppView) {
self.views.push(view);
}
pub(crate) fn pop(&mut self) -> bool {
if self.views.len() == 1 {
return false;
}
self.views.pop();
true
}
#[cfg(test)]
pub(crate) const fn len(&self) -> usize {
self.views.len()
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ModeStack {
modes: Vec<InputMode>,
}
impl ModeStack {
pub(crate) fn active(&self) -> Option<&InputMode> {
self.modes.last()
}
pub(crate) fn active_mut(&mut self) -> Option<&mut InputMode> {
self.modes.last_mut()
}
pub(crate) fn push(&mut self, mode: InputMode) {
self.modes.push(mode);
}
pub(crate) fn pop(&mut self) -> Option<InputMode> {
self.modes.pop()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum InputMode {
ViewOptions {
context: BindingContext,
selected: usize,
},
DiffFileList {
selected: usize,
},
DiffSearch {
query: String,
},
InspectionSearch {
query: String,
},
CommandDiscovery {
context: BindingContext,
query: String,
selected: usize,
},
DescribeMessage {
rev: String,
message: String,
},
CommandPreview {
pending: PendingCommandPreview,
},
JjCommand {
input: String,
error: Option<String>,
},
LogTemplate {
options: Vec<LogTemplateSelection>,
selected: usize,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum InputModeResult {
Handled,
Unhandled,
}