use crossterm::event::{KeyCode, KeyEvent};
use super::{Action, ScriptOperation};
use crate::ui::state::{AppState, ScriptNode, ScriptsMode};
pub(super) fn handle_scripts_panel(state: &mut AppState, key: KeyEvent) -> Action {
match &state.scripts.mode {
ScriptsMode::ConfirmDelete { .. } => return handle_scripts_confirm(state, key),
ScriptsMode::Insert { .. } => return handle_scripts_insert(state, key),
ScriptsMode::Rename { .. } => return handle_scripts_rename_mode(state, key),
ScriptsMode::PendingD => return handle_scripts_pending_d(state, key),
ScriptsMode::PendingY => return handle_scripts_pending_y(state, key),
ScriptsMode::Normal => {}
}
let visible = state.scripts.visible_scripts();
let count = visible.len();
let selected: Option<(usize, ScriptNode)> = visible
.get(state.scripts.cursor)
.map(|(idx, node)| (*idx, (*node).clone()));
drop(visible);
match key.code {
KeyCode::Char('j') | KeyCode::Down => {
if count > 0 && state.scripts.cursor + 1 < count {
state.scripts.cursor += 1;
}
Action::Render
}
KeyCode::Char('k') | KeyCode::Up => {
if state.scripts.cursor > 0 {
state.scripts.cursor -= 1;
}
Action::Render
}
KeyCode::Char('g') => {
state.scripts.cursor = 0;
state.scripts.offset = 0;
Action::Render
}
KeyCode::Char('G') => {
if count > 0 {
state.scripts.cursor = count - 1;
}
Action::Render
}
KeyCode::Enter | KeyCode::Char('l') => {
if let Some((idx, node)) = selected {
match node {
ScriptNode::Collection { .. } => {
if let Some(ScriptNode::Collection { expanded, .. }) =
state.scripts.tree.get_mut(idx)
{
*expanded = !*expanded;
}
Action::Render
}
ScriptNode::Script { file_path, .. } => {
let name = file_path
.strip_suffix(".sql")
.unwrap_or(&file_path)
.to_string();
Action::OpenScript { name }
}
}
} else {
Action::None
}
}
KeyCode::Char('h') => {
if let Some((idx, node)) = selected {
match node {
ScriptNode::Collection { .. } => {
if let Some(ScriptNode::Collection { expanded, .. }) =
state.scripts.tree.get_mut(idx)
{
*expanded = false;
}
}
ScriptNode::Script {
collection: Some(coll_name),
..
} => {
for tnode in state.scripts.tree.iter_mut() {
if let ScriptNode::Collection { name, expanded } = tnode
&& *name == coll_name
{
*expanded = false;
break;
}
}
let vis = state.scripts.visible_scripts();
for (vi, (_, vnode)) in vis.iter().enumerate() {
if let ScriptNode::Collection { name, .. } = vnode
&& *name == coll_name
{
state.scripts.cursor = vi;
break;
}
}
}
_ => {}
}
}
Action::Render
}
KeyCode::Char('d') => {
state.scripts.mode = ScriptsMode::PendingD;
Action::Render
}
KeyCode::Char('y') => {
state.scripts.mode = ScriptsMode::PendingY;
Action::Render
}
KeyCode::Char('p') => {
if let Some(from) = state.scripts.yank.clone() {
let to_collection = state.scripts.current_collection();
state.scripts.yank = None;
return Action::ScriptOp {
op: ScriptOperation::Move {
from,
to_collection,
},
};
}
Action::None
}
KeyCode::Char('i') | KeyCode::Char('o') => {
state.scripts.mode = ScriptsMode::Insert { buf: String::new() };
Action::Render
}
KeyCode::Char('r') => {
if let Some((_, node)) = selected {
let (buf, path) = match node {
ScriptNode::Collection { name, .. } => (format!("{name}/"), name),
ScriptNode::Script {
name, file_path, ..
} => (name, file_path),
};
state.scripts.mode = ScriptsMode::Rename {
buf,
original_path: path,
};
}
Action::Render
}
_ => Action::None,
}
}
pub(super) fn handle_scripts_confirm(state: &mut AppState, key: KeyEvent) -> Action {
let path = if let ScriptsMode::ConfirmDelete { path } = &state.scripts.mode {
path.clone()
} else {
return Action::None;
};
match key.code {
KeyCode::Char('y') | KeyCode::Enter => {
state.scripts.mode = ScriptsMode::Normal;
if !path.contains('.') {
Action::ScriptOp {
op: ScriptOperation::DeleteCollection { name: path },
}
} else {
Action::ScriptOp {
op: ScriptOperation::Delete { path },
}
}
}
_ => {
state.scripts.mode = ScriptsMode::Normal;
Action::Render
}
}
}
pub(super) fn handle_scripts_insert(state: &mut AppState, key: KeyEvent) -> Action {
match key.code {
KeyCode::Esc => {
state.scripts.mode = ScriptsMode::Normal;
Action::Render
}
KeyCode::Enter => {
let buf = if let ScriptsMode::Insert { buf } = &state.scripts.mode {
buf.clone()
} else {
return Action::None;
};
state.scripts.mode = ScriptsMode::Normal;
if buf.is_empty() {
return Action::Render;
}
let in_collection = state.scripts.current_collection();
Action::ScriptOp {
op: ScriptOperation::Create {
name: buf,
in_collection,
},
}
}
KeyCode::Backspace => {
if let ScriptsMode::Insert { buf } = &mut state.scripts.mode {
buf.pop();
}
Action::Render
}
KeyCode::Char(c) => {
if let ScriptsMode::Insert { buf } = &mut state.scripts.mode {
buf.push(c);
}
Action::Render
}
_ => Action::None,
}
}
pub(super) fn handle_scripts_rename_mode(state: &mut AppState, key: KeyEvent) -> Action {
match key.code {
KeyCode::Esc => {
state.scripts.mode = ScriptsMode::Normal;
Action::Render
}
KeyCode::Enter => {
let (buf, original_path) =
if let ScriptsMode::Rename { buf, original_path } = &state.scripts.mode {
(buf.clone(), original_path.clone())
} else {
return Action::None;
};
state.scripts.mode = ScriptsMode::Normal;
if buf.is_empty() {
return Action::Render;
}
if buf.ends_with('/') {
let new_name = buf.trim_end_matches('/').to_string();
Action::ScriptOp {
op: ScriptOperation::RenameCollection {
old_name: original_path,
new_name,
},
}
} else {
Action::ScriptOp {
op: ScriptOperation::Rename {
old_path: original_path,
new_name: buf,
},
}
}
}
KeyCode::Backspace => {
if let ScriptsMode::Rename { buf, .. } = &mut state.scripts.mode {
buf.pop();
}
Action::Render
}
KeyCode::Char(c) => {
if let ScriptsMode::Rename { buf, .. } = &mut state.scripts.mode {
buf.push(c);
}
Action::Render
}
_ => Action::None,
}
}
pub(super) fn handle_scripts_pending_d(state: &mut AppState, key: KeyEvent) -> Action {
state.scripts.mode = ScriptsMode::Normal;
if key.code == KeyCode::Char('d') {
let visible = state.scripts.visible_scripts();
let selected = visible
.get(state.scripts.cursor)
.map(|(_, node)| (*node).clone());
drop(visible);
if let Some(node) = selected {
let path = match node {
ScriptNode::Collection { name, .. } => name,
ScriptNode::Script { file_path, .. } => file_path,
};
state.scripts.mode = ScriptsMode::ConfirmDelete { path };
}
}
Action::Render
}
pub(super) fn handle_scripts_pending_y(state: &mut AppState, key: KeyEvent) -> Action {
state.scripts.mode = ScriptsMode::Normal;
if key.code == KeyCode::Char('y') {
let visible = state.scripts.visible_scripts();
let selected = visible
.get(state.scripts.cursor)
.map(|(_, node)| (*node).clone());
drop(visible);
if let Some(ScriptNode::Script { file_path, .. }) = selected {
state.scripts.yank = Some(file_path);
}
}
Action::Render
}