use crate::AppModel;
use crate::keymap::{self, Held, Key, KeyAction, Mods};
use super::ShellState;
const DIGIT_KEYS: [(egui::Key, u8); 10] = [
(egui::Key::Num0, 0),
(egui::Key::Num1, 1),
(egui::Key::Num2, 2),
(egui::Key::Num3, 3),
(egui::Key::Num4, 4),
(egui::Key::Num5, 5),
(egui::Key::Num6, 6),
(egui::Key::Num7, 7),
(egui::Key::Num8, 8),
(egui::Key::Num9, 9),
];
const LETTER_KEYS: [(egui::Key, char); 13] = [
(egui::Key::I, 'i'),
(egui::Key::N, 'n'),
(egui::Key::W, 'w'),
(egui::Key::S, 's'),
(egui::Key::X, 'x'),
(egui::Key::F, 'f'),
(egui::Key::C, 'c'),
(egui::Key::R, 'r'),
(egui::Key::B, 'b'),
(egui::Key::M, 'm'),
(egui::Key::G, 'g'),
(egui::Key::A, 'a'),
(egui::Key::J, 'j'),
];
const SIGN_KEYS: [(egui::Key, Key); 3] = [
(egui::Key::Plus, Key::Plus),
(egui::Key::Equals, Key::Plus),
(egui::Key::Minus, Key::Minus),
];
pub(super) fn handle(ctx: &egui::Context, model: &mut AppModel, state: &mut ShellState) {
ctx.set_zoom_factor(model.zoom());
let held = if super::modal::open(state) {
Held::Modal
} else if ctx.wants_keyboard_input() {
Held::TextBox
} else {
Held::Nothing
};
let pressed: Vec<(Key, Mods)> = ctx.input(|i| {
let mods = match (i.modifiers.command, i.modifiers.shift) {
(true, false) => Mods::Command,
(true, true) => Mods::CommandShift,
(false, _) => Mods::Bare,
};
let mut keys = Vec::new();
for (egui_key, key) in [
(egui::Key::ArrowUp, Key::Up),
(egui::Key::ArrowDown, Key::Down),
(egui::Key::ArrowLeft, Key::Left),
(egui::Key::ArrowRight, Key::Right),
(egui::Key::Enter, Key::Enter),
(egui::Key::Escape, Key::Escape),
] {
if i.key_pressed(egui_key) {
keys.push((key, mods));
}
}
for (egui_key, n) in DIGIT_KEYS {
if i.key_pressed(egui_key) {
keys.push((Key::Digit(n), mods));
}
}
for (egui_key, c) in LETTER_KEYS {
if i.key_pressed(egui_key) {
keys.push((Key::Char(c), mods));
}
}
for (egui_key, key) in SIGN_KEYS {
if i.key_pressed(egui_key) {
keys.push((key, mods));
}
}
keys
});
for action in pressed
.into_iter()
.filter_map(|(key, mods)| keymap::keymap(key, mods, held))
{
effect(action, model, state);
}
}
fn effect(action: KeyAction, model: &mut AppModel, state: &mut ShellState) {
match action {
KeyAction::ListPrev => super::focus::list_step(model, state, -1),
KeyAction::ListNext => super::focus::list_step(model, state, 1),
KeyAction::ExpandRow => super::focus::expand_row(model, state),
KeyAction::CollapseRow => super::focus::collapse_row(model, state),
KeyAction::Tab(tab) => model.select_tab(tab),
KeyAction::Center(tab) => super::center::focus(model, state, tab),
KeyAction::FocusComposer => super::focus::request(state),
KeyAction::NewConversation => new_conversation(model, state),
KeyAction::NewWorkspace => super::new_ws::open(state),
KeyAction::StartHead => start_head(model, state),
KeyAction::Stop => super::dispatch::stop_selected(model, state),
KeyAction::Scan => super::dispatch::scan_focused(model),
KeyAction::Search => search_line(model, state),
KeyAction::CloseBall => super::ball_bar::close_focused(model),
KeyAction::ReleaseBall => super::ball_bar::release_focused(model),
KeyAction::ToggleBalls => toggle_balls(model),
KeyAction::ToggleModelPicker => state.wall.picker.toggle(),
KeyAction::ToggleGrouping => state.group_by_ball = !state.group_by_ball,
KeyAction::ToggleActivity => state.activity_open = !state.activity_open,
KeyAction::Zoom(step) => model.zoom_nudge(step),
KeyAction::Fire => fire_pending(model, state),
KeyAction::Cancel => cancel_pending(model, state),
KeyAction::DismissModal => super::modal::dismiss(state),
}
}
fn fire_pending(model: &mut AppModel, state: &mut ShellState) {
super::start_pane::send_pending(model, state);
}
fn cancel_pending(model: &AppModel, state: &mut ShellState) {
if state.start.pending.take().is_some() {
super::focus::request(state);
} else if !super::center::conversation_open(state) {
super::center::focus(model, state, crate::keymap::CenterTab::Conversation);
}
}
pub(super) fn new_conversation(model: &mut AppModel, state: &mut ShellState) {
let Some(ws) = model.focused_ws_name() else {
return;
};
super::focus::workspace(model, state, &ws);
}
fn search_line(model: &AppModel, state: &mut ShellState) {
let key = crate::actions::drafts::DraftKey::composer(
model.focused_workspace(),
model.focused_agent_id(),
);
state.actions.drafts.set(key, "/search ".to_owned());
super::focus::request(state);
}
fn start_head(model: &mut AppModel, state: &mut ShellState) {
let Some(inputs) = model.startable().into_iter().next() else {
return;
};
super::start_pane::run_prepare(model, state, inputs);
}
fn toggle_balls(model: &mut AppModel) {
let collapsed = model.is_collapsed("balls");
model.set_collapsed("balls", !collapsed);
}