use crossterm::event::{self, Event, KeyCode, KeyModifiers};
use std::time::Duration;
use crate::error::Result;
use super::app::{App, View, Panel, SyncStatus, CommitFocus, WorkspaceFocus, WorkspaceConfirm, SnapshotFocus, BranchConfirm, TagConfirm, HistoryConfirm, RemoteConfirm, PrConfirm, IssueConfirm};
pub enum Action {
Quit,
Refresh,
SidebarUp,
SidebarDown,
SidebarEnter,
StageFile,
UnstageFile,
CommitConfirm,
BranchCheckout,
BranchDelete,
BranchCreate,
BranchPush,
SnapshotRestore,
SnapshotCreate,
SnapshotDelete,
SnapshotSaveInterval,
OpenDiffFromLog,
LogCopyHash,
SyncRun,
TagPush,
TagDelete,
TagCreate,
HistoryCherryPick,
HistoryRebase,
HistoryScan,
HistoryClean,
HistoryRemoveFile,
HistoryRewrite,
HistoryBlame,
RemoteInfo,
RemoteFetch,
RemoteAdd,
RemoteRemove,
RemoteRename,
RemoteEditUrl,
RemoteOpenBrowser,
MirrorSync,
MirrorSyncOne,
MirrorSyncForce,
MirrorRemove,
MirrorRename,
MirrorAdd,
MirrorSetPrimary,
WorkspaceSync,
WorkspaceSyncOne,
WorkspaceOpenRepo,
WorkspaceDelete,
WorkspaceSave,
WorkspaceAddRepo,
WorkspaceRemoveRepo,
WorkspaceRename,
PrMerge,
PrClose,
PrCreate,
PrCheckout,
PrOpenBrowser,
PrRefresh,
PrUpdate,
PrSwitchPlatform,
PrCreateMulti,
IssueClose,
IssueCreate,
IssueComment,
IssueOpenBrowser,
IssueRefresh,
ConfigEdit,
ConfigSave,
ConfigToggleScope,
SettingsToggle,
SettingsSave,
}
pub struct EventHandler;
impl EventHandler {
pub fn new() -> Self { Self }
pub fn next(&mut self, app: &mut App) -> Result<Option<Action>> {
if !event::poll(Duration::from_millis(200))? {
return Ok(None);
}
match event::read()? {
Event::Key(key) => {
if app.show_event_log {
if key.code == KeyCode::Char('c') && key.modifiers == KeyModifiers::NONE {
app.event_log.clear();
return Ok(None);
}
}
if key.code == KeyCode::Tab && key.modifiers == KeyModifiers::NONE {
app.tab_cycle();
return Ok(None);
}
if key.code == KeyCode::Char('W') && key.modifiers == KeyModifiers::SHIFT {
if app.repo_picker_open {
app.repo_picker_open = false;
} else {
app.open_repo_picker();
}
return Ok(None);
}
if app.repo_picker_open {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => { app.repo_picker_open = false; }
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.repo_picker_idx > 0 { app.repo_picker_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
let max = app.workspace_repo_paths().len().saturating_sub(1);
if app.repo_picker_idx < max { app.repo_picker_idx += 1; }
}
(_, KeyCode::Enter) => {
let ws_name = app.active_workspace.clone();
let paths = app.workspace_repo_paths();
if let Some(path) = paths.get(app.repo_picker_idx) {
app.repo_path = path.clone();
app.active_workspace = ws_name; app.repo_picker_open = false;
app.refresh().ok();
app.go_to(View::Dashboard);
}
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Ok(Some(Action::Quit)),
_ => {}
}
return Ok(None);
}
let typing = match app.view {
View::Commit => app.commit_view.focus == CommitFocus::Input,
View::Snapshot => app.snapshot_view.focus == SnapshotFocus::Create || app.snapshot_view.search_mode,
View::Log => app.log.search_mode,
View::Branch => app.branch_view.confirm == BranchConfirm::NewBranch,
View::Tag => matches!(app.tag_view.confirm, TagConfirm::CreateName | TagConfirm::CreateMessage),
View::History => matches!(app.history_view.confirm,
HistoryConfirm::Rebase | HistoryConfirm::RemoveFile |
HistoryConfirm::RewriteStart | HistoryConfirm::RewriteEnd |
HistoryConfirm::Blame),
View::Remote => matches!(app.remote_view.confirm,
RemoteConfirm::AddName | RemoteConfirm::AddUrl | RemoteConfirm::Rename |
RemoteConfirm::EditUrl |
RemoteConfirm::MirrorRename | RemoteConfirm::MirrorAddPlatform |
RemoteConfirm::MirrorAddAccount | RemoteConfirm::MirrorAddRepo),
View::Workspace => matches!(app.workspace_view.confirm,
WorkspaceConfirm::SaveMessage | WorkspaceConfirm::AddRepoPath),
View::Pr => matches!(app.pr_view.confirm,
PrConfirm::CreateTitle | PrConfirm::CreateDesc |
PrConfirm::EditTitle | PrConfirm::EditDesc),
View::Branch => app.branch_view.search_mode,
View::Tag => app.tag_view.search_mode,
View::Issue => matches!(app.issue_view.confirm,
IssueConfirm::CreateTitle | IssueConfirm::CreateDesc | IssueConfirm::Comment),
View::Config => app.config_view.editing,
_ => false,
};
if key.code == KeyCode::Char('e') && key.modifiers == KeyModifiers::NONE && !typing {
app.show_event_log = !app.show_event_log;
return Ok(None);
}
if app.sidebar_focused {
let is_nav = matches!(key.code,
KeyCode::Up | KeyCode::Down |
KeyCode::Char('j') | KeyCode::Char('k')
) && key.modifiers == KeyModifiers::NONE;
let is_enter = key.code == KeyCode::Enter && key.modifiers == KeyModifiers::NONE;
let is_quit = matches!(key.code, KeyCode::Char('q'))
|| (key.modifiers == KeyModifiers::CONTROL && key.code == KeyCode::Char('c'));
if typing {
return Ok(match app.view {
View::Pr => handle_pr(key, app),
View::Issue => handle_issue(key, app),
View::Branch => handle_branch(key, app),
View::Tag => handle_tag(key, app),
_ => None,
});
}
if is_nav || is_enter || is_quit {
return Ok(handle_sidebar(key, app));
}
let view_result = match app.view {
View::Log => handle_log(key, app),
View::Branch => handle_branch(key, app),
View::Tag => handle_tag(key, app),
View::History => handle_history(key, app),
View::Remote => handle_remote(key, app),
View::Mirror => handle_mirror(key, app),
View::Snapshot => handle_snapshot(key, app),
View::Workspace => handle_workspace(key, app),
View::Pr => handle_pr(key, app),
View::Issue => handle_issue(key, app),
_ => None,
};
if view_result.is_some() {
return Ok(view_result);
}
return Ok(handle_sidebar(key, app));
}
if key.code == KeyCode::Esc && key.modifiers == KeyModifiers::NONE && app.repo_picker_open {
app.repo_picker_open = false;
return Ok(None);
}
if key.code == KeyCode::Esc && key.modifiers == KeyModifiers::NONE {
let handled_by_view = match app.view {
View::Diff => { app.go_back(); true }
View::Commit => app.commit_view.focus == CommitFocus::Input,
View::Config => app.config_view.editing,
View::Settings => false,
View::Log => {
if app.log.ops_mode {
app.log.ops_mode = false;
true
} else if app.log.search_mode {
app.log.search_mode = false;
app.log.search_query.clear();
app.log.filtered.clear();
true
} else {
false
}
}
View::Branch => {
if app.branch_view.search_mode {
app.branch_view.search_mode = false;
app.branch_view.search_query.clear();
app.branch_view.filtered.clear();
true
} else if app.branch_view.ops_mode {
app.branch_view.ops_mode = false;
true
} else if app.branch_view.confirm != BranchConfirm::None {
app.branch_view.confirm = BranchConfirm::None;
app.branch_view.new_name.clear();
true
} else {
false
}
}
View::Tag => {
if app.tag_view.search_mode {
app.tag_view.search_mode = false;
app.tag_view.search_query.clear();
app.tag_view.filtered.clear();
true
} else if app.tag_view.ops_mode {
app.tag_view.ops_mode = false;
true
} else if app.tag_view.confirm != TagConfirm::None {
app.tag_view.confirm = TagConfirm::None;
app.tag_view.new_name.clear();
app.tag_view.new_message.clear();
true
} else {
false
}
}
View::History => {
if app.history_view.ops_mode {
app.history_view.ops_mode = false;
true
} else if app.history_view.confirm != HistoryConfirm::None {
app.history_view.confirm = HistoryConfirm::None;
app.history_view.input.clear();
app.history_view.input2.clear();
true
} else {
false
}
}
View::Snapshot => {
if app.snapshot_view.ops_mode {
app.snapshot_view.ops_mode = false;
true
} else if app.snapshot_view.search_mode {
app.snapshot_view.search_mode = false;
app.snapshot_view.search_query.clear();
app.snapshot_view.filtered.clear();
app.snapshot_view.idx = 0;
true
} else {
false
}
}
View::Mirror => {
if app.mirror_view.ops_mode {
app.mirror_view.ops_mode = false;
true
} else {
false
}
}
View::Pr => {
if app.pr_view.ops_mode {
app.pr_view.ops_mode = false;
true
} else if app.pr_view.confirm != PrConfirm::None {
app.pr_view.confirm = PrConfirm::None;
app.pr_view.create_input.clear();
true
} else {
false
}
}
View::Issue => {
if app.issue_view.ops_mode {
app.issue_view.ops_mode = false;
true
} else if app.issue_view.confirm != IssueConfirm::None {
app.issue_view.confirm = IssueConfirm::None;
app.issue_view.create_input.clear();
app.issue_view.comment_input.clear();
true
} else {
false
}
}
View::Workspace => {
if app.workspace_view.ops_mode {
app.workspace_view.ops_mode = false;
true
} else if app.workspace_view.confirm != WorkspaceConfirm::None {
app.workspace_view.confirm = WorkspaceConfirm::None;
app.workspace_view.input.clear();
true
} else if app.workspace_view.focus == WorkspaceFocus::Repos {
app.workspace_view.focus = WorkspaceFocus::Workspaces;
true
} else {
false
}
}
View::Remote => {
if app.remote_view.ops_mode {
app.remote_view.ops_mode = false;
true
} else if app.remote_view.confirm != RemoteConfirm::None {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_name.clear();
app.remote_view.new_url.clear();
app.remote_view.new_mirror_platform.clear();
app.remote_view.new_mirror_account.clear();
app.remote_view.new_mirror_repo.clear();
app.remote_view.new_mirror_type = 0;
true
} else {
false
}
}
_ => false,
};
if !handled_by_view {
app.sidebar_focused = true;
}
return Ok(None);
}
return Ok(match app.view {
View::Dashboard => handle_dashboard(key, app),
View::Diff => handle_diff(key, app),
View::Log => handle_log(key, app),
View::Branch => handle_branch(key, app),
View::Commit => handle_commit(key, app),
View::Snapshot => handle_snapshot(key, app),
View::Sync => handle_sync(key, app),
View::Tag => handle_tag(key, app),
View::History => handle_history(key, app),
View::Remote => handle_remote(key, app),
View::Mirror => handle_mirror(key, app),
View::Workspace => handle_workspace(key, app),
View::Pr => handle_pr(key, app),
View::Issue => handle_issue(key, app),
View::Config => handle_config(key, app),
View::Settings => handle_settings(key, app),
View::Help => handle_help(key, app),
});
}
Event::Resize(_, _) => {}
_ => {}
}
Ok(None)
}
}
fn handle_dashboard(key: event::KeyEvent, app: &mut App) -> Option<Action> {
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::BackTab) | (KeyModifiers::SHIFT, KeyCode::BackTab) => app.prev_panel(),
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.move_down(),
(KeyModifiers::CONTROL, KeyCode::Char('r')) => return Some(Action::Refresh),
(_, KeyCode::Char(' ')) => {
match app.dashboard.selected_panel {
Panel::Unstaged | Panel::Untracked => return Some(Action::StageFile),
Panel::Staged => return Some(Action::UnstageFile),
Panel::Log => {}
}
}
(_, KeyCode::Char('d')) => app.go_to(View::Diff),
_ => {}
}
None
}
fn handle_global_nav(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match (key.modifiers, key.code) {
(_, KeyCode::Char('q')) |
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
(_, KeyCode::Char('?')) => app.go_to(View::Help),
(_, KeyCode::Char('f')) => app.go_to(View::Dashboard),
(_, KeyCode::Char('c')) => {
app.commit_view.message.clear();
app.commit_view.cursor = 0;
app.commit_view.focus = CommitFocus::List;
app.go_to(View::Commit);
}
(_, KeyCode::Char('s')) => {
app.sync_view.status = SyncStatus::Idle;
app.go_to(View::Sync);
}
(_, KeyCode::Char('p')) => app.go_to(View::Snapshot),
(_, KeyCode::Char('l')) => app.go_to(View::Log),
(_, KeyCode::Char('b')) => app.go_to(View::Branch),
(_, KeyCode::Char('t')) => app.go_to(View::Tag),
(_, KeyCode::Char('h')) => app.go_to(View::History),
(_, KeyCode::Char('r')) => app.go_to(View::Remote),
(_, KeyCode::Char('m')) => app.go_to(View::Mirror),
(_, KeyCode::Char('w')) => app.go_to(View::Workspace),
(_, KeyCode::Char('n')) => app.go_to(View::Pr),
(_, KeyCode::Char('i')) => app.go_to(View::Issue),
(_, KeyCode::Char('g')) => app.go_to(View::Config),
(_, KeyCode::Char('x')) => app.go_to(View::Settings),
_ => return None,
}
None
}
fn handle_diff(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) | (_, KeyCode::Char('q')) => app.go_back(),
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.diff_scroll_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.diff_scroll_down(),
(_, KeyCode::PageUp) => app.diff_page_up(),
(_, KeyCode::PageDown) => app.diff_page_down(),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
None
}
fn handle_log(key: event::KeyEvent, app: &mut App) -> Option<Action> {
if app.log.search_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.log.search_mode = false;
app.log.search_query.clear();
app.log.filtered.clear();
}
(_, KeyCode::Enter) => {
app.log.search_mode = false;
}
(_, KeyCode::Backspace) => {
app.log.search_query.pop();
app.log_update_filter();
}
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> {
app.log.search_query.push(c);
app.log_update_filter();
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.log.ops_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.log.ops_idx > 0 { app.log.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.log.ops_idx < 2 { app.log.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.log.ops_idx;
app.log.ops_mode = false;
match idx {
0 => return Some(Action::OpenDiffFromLog),
1 => return Some(Action::LogCopyHash),
2 => {
app.log.search_mode = true;
app.log.search_query.clear();
app.log.filtered.clear();
}
_ => {}
}
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.log.ops_mode = false;
}
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => { app.log_move_up(); app.log.ops_mode = false; }
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => { app.log_move_down(); app.log.ops_mode = false; }
(_, KeyCode::Char('o')) => {
app.log.ops_mode = true;
app.log.ops_idx = 0;
}
(_, KeyCode::Char('/')) => {
app.log.search_mode = true;
app.log.search_query.clear();
app.log.filtered.clear();
}
_ => {}
}
None
}
fn handle_branch(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match app.branch_view.confirm.clone() {
BranchConfirm::Delete => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.branch_view.confirm = BranchConfirm::None;
return Some(Action::BranchDelete);
}
_ => {
app.branch_view.confirm = BranchConfirm::None;
app.branch_view.status = Some("cancelled".to_string());
}
}
return None;
}
BranchConfirm::NewBranch => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.branch_view.confirm = BranchConfirm::None;
app.branch_view.new_name.clear();
}
(_, KeyCode::Enter) => {
app.branch_view.confirm = BranchConfirm::None;
return Some(Action::BranchCreate);
}
(_, KeyCode::Backspace) => { app.branch_view.new_name.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.branch_view.new_name.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
BranchConfirm::None => {}
}
if app.branch_view.ops_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.branch_view.ops_idx > 0 { app.branch_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.branch_view.ops_idx < 3 { app.branch_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.branch_view.ops_idx;
app.branch_view.ops_mode = false;
match idx {
0 => return Some(Action::BranchCheckout),
1 => {
app.branch_view.new_name.clear();
app.branch_view.confirm = BranchConfirm::NewBranch;
}
2 => {
if !app.branch_view.current_has_upstream {
return Some(Action::BranchPush);
}
}
3 => {
if let Some(b) = app.branch_view.branches.get(app.branch_view.idx) {
if !b.is_current && !b.is_remote {
app.branch_view.confirm = BranchConfirm::Delete;
} else if b.is_remote {
app.branch_view.status = Some("cannot delete remote branch".to_string());
} else {
app.branch_view.status = Some("cannot delete current branch".to_string());
}
}
}
_ => {}
}
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.branch_view.ops_mode = false;
}
_ => {}
}
return None;
}
if app.branch_view.search_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.branch_view.search_mode = false;
app.branch_view.search_query.clear();
app.branch_view.filtered.clear();
}
(_, KeyCode::Enter) => { app.branch_view.search_mode = false; }
(_, KeyCode::Backspace) => {
app.branch_view.search_query.pop();
app.branch_update_filter();
}
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE || key.modifiers == KeyModifiers::SHIFT => {
app.branch_view.search_query.push(c);
app.branch_update_filter();
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.branch_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.branch_move_down(),
(_, KeyCode::Char('o')) => {
app.branch_view.ops_mode = true;
app.branch_view.ops_idx = 0;
}
(_, KeyCode::Char('/')) => {
app.branch_view.search_mode = true;
app.branch_view.search_query.clear();
app.branch_view.filtered.clear();
}
_ => {}
}
None
}
fn handle_commit(key: event::KeyEvent, app: &mut App) -> Option<Action> {
const N_TYPES: usize = 8;
match app.commit_view.focus {
CommitFocus::List => {
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Enter) => app.commit_view.focus = CommitFocus::TypeSelector,
(_, KeyCode::Char('i')) => {
app.commit_view.focus = CommitFocus::Input;
}
(_, KeyCode::Char('a')) => {
app.commit_view.amend = !app.commit_view.amend;
if app.commit_view.amend && app.commit_view.message.is_empty() {
if let Some(c) = app.commits.first() {
app.commit_view.message = c.message.clone();
app.commit_view.cursor = c.message.len();
}
}
}
_ => {}
}
}
CommitFocus::TypeSelector => {
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.commit_view.type_idx > 0 { app.commit_view.type_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.commit_view.type_idx < N_TYPES - 1 { app.commit_view.type_idx += 1; }
}
(_, KeyCode::Enter) => {
let prefix = COMMIT_TYPES[app.commit_view.type_idx].0;
let prefix_str = format!("{}: ", prefix);
if !app.commit_view.message.starts_with(&prefix_str) {
let base = if let Some(colon) = app.commit_view.message.find(": ") {
app.commit_view.message[colon + 2..].to_string()
} else {
app.commit_view.message.clone()
};
app.commit_view.message = format!("{}{}", prefix_str, base);
app.commit_view.cursor = app.commit_view.message.len();
}
app.commit_view.focus = CommitFocus::Input;
}
(_, KeyCode::Esc) => app.commit_view.focus = CommitFocus::List,
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
}
CommitFocus::Input => match (key.modifiers, key.code) {
(_, KeyCode::Esc) => app.commit_view.focus = CommitFocus::TypeSelector,
(_, KeyCode::Enter) => return Some(Action::CommitConfirm),
(_, KeyCode::Backspace) => app.commit_backspace(),
(_, KeyCode::Left) => app.commit_cursor_left(),
(_, KeyCode::Right) => app.commit_cursor_right(),
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.commit_type_char(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
},
}
None
}
pub const COMMIT_TYPES: &[(&str, &str)] = &[
("feat", "new feature"),
("fix", "bug fix"),
("chore", "maintenance task"),
("docs", "documentation"),
("refactor", "code restructure"),
("test", "tests"),
("ci", "CI/CD changes"),
("perf", "performance improvement"),
];
fn handle_snapshot(key: event::KeyEvent, app: &mut App) -> Option<Action> {
use crate::tui::app::{SnapshotFocus, AutoSnapshotInterval};
if app.snapshot_view.focus == SnapshotFocus::List && app.snapshot_view.ops_mode {
const OPS_LEN: usize = 3;
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.snapshot_view.ops_idx > 0 { app.snapshot_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.snapshot_view.ops_idx < OPS_LEN - 1 { app.snapshot_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.snapshot_view.ops_idx;
app.snapshot_view.ops_mode = false;
return match idx {
0 => Some(Action::SnapshotRestore),
1 => {
app.snapshot_view.create_name.clear();
app.snapshot_view.focus = SnapshotFocus::Create;
None
}
2 => Some(Action::SnapshotDelete),
_ => None,
};
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.snapshot_view.ops_mode = false;
}
_ => {}
}
return None;
}
match app.snapshot_view.focus {
SnapshotFocus::List => {
if app.snapshot_view.search_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.snapshot_view.search_mode = false;
app.snapshot_view.search_query.clear();
app.snapshot_view.filtered.clear();
app.snapshot_view.idx = 0;
}
(_, KeyCode::Enter) => {
app.snapshot_view.search_mode = false;
}
(_, KeyCode::Backspace) => {
app.snapshot_view.search_query.pop();
snapshot_update_filter(app);
}
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> {
app.snapshot_view.search_query.push(c);
snapshot_update_filter(app);
}
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.snapshot_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.snapshot_move_down(),
(_, KeyCode::Char('o')) => {
app.snapshot_view.ops_mode = true;
app.snapshot_view.ops_idx = 0;
}
(_, KeyCode::Char('/')) => {
app.snapshot_view.search_mode = true;
app.snapshot_view.search_query.clear();
app.snapshot_view.filtered.clear();
app.snapshot_view.idx = 0;
}
(_, KeyCode::Char('n')) => {
app.snapshot_view.create_name.clear();
app.snapshot_view.focus = SnapshotFocus::Create;
}
(_, KeyCode::Char('a')) => {
app.snapshot_view.auto_interval_idx = AutoSnapshotInterval::all()
.iter().position(|i| i == &app.snapshot_view.auto_interval)
.unwrap_or(0);
app.snapshot_view.focus = SnapshotFocus::AutoConfig;
}
_ => {}
}
}
SnapshotFocus::Create => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => app.snapshot_view.focus = SnapshotFocus::List,
(_, KeyCode::Enter) => return Some(Action::SnapshotCreate),
(_, KeyCode::Backspace) => { app.snapshot_view.create_name.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.snapshot_view.create_name.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
}
SnapshotFocus::AutoConfig => {
let n = AutoSnapshotInterval::all().len();
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.snapshot_view.auto_interval_idx > 0 {
app.snapshot_view.auto_interval_idx -= 1;
}
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.snapshot_view.auto_interval_idx < n - 1 {
app.snapshot_view.auto_interval_idx += 1;
}
}
(_, KeyCode::Enter) => {
app.snapshot_view.auto_interval =
AutoSnapshotInterval::all()[app.snapshot_view.auto_interval_idx].clone();
app.snapshot_view.focus = SnapshotFocus::List;
return Some(Action::SnapshotSaveInterval);
}
(_, KeyCode::Esc) => app.snapshot_view.focus = SnapshotFocus::List,
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
}
}
None
}
fn handle_sync(key: event::KeyEvent, app: &mut App) -> Option<Action> {
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.sync_op_prev(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.sync_op_next(),
(_, KeyCode::Enter) => return Some(Action::SyncRun),
_ => {}
}
None
}
fn snapshot_update_filter(app: &mut App) {
let q = app.snapshot_view.search_query.to_lowercase();
if q.is_empty() {
app.snapshot_view.filtered.clear();
} else {
app.snapshot_view.filtered = app.snapshot_view.snapshots
.iter().enumerate()
.filter(|(_, s)| s.name.to_lowercase().contains(&q) || s.id.to_lowercase().contains(&q))
.map(|(i, _)| i)
.collect();
}
app.snapshot_view.idx = 0;
}
fn handle_sidebar(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => return Some(Action::SidebarUp),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => return Some(Action::SidebarDown),
(_, KeyCode::Enter) => return Some(Action::SidebarEnter),
(_, KeyCode::Char('?')) => { app.go_to(View::Help); }
(_, KeyCode::Char('q')) |
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
None
}
fn handle_help(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) | (_, KeyCode::Char('?')) | (_, KeyCode::Char('q')) => app.go_back(),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
None
}
fn handle_tag(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match app.tag_view.confirm.clone() {
TagConfirm::Delete => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.tag_view.confirm = TagConfirm::None;
return Some(Action::TagDelete);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => { app.tag_view.confirm = TagConfirm::None; }
}
return None;
}
TagConfirm::CreateName => {
match (key.modifiers, key.code) {
(_, KeyCode::Enter) => {
if !app.tag_view.new_name.trim().is_empty() {
app.tag_view.confirm = TagConfirm::CreateMessage;
}
}
(_, KeyCode::Backspace) => { app.tag_view.new_name.pop(); }
(KeyModifiers::NONE, KeyCode::Char(c)) => app.tag_view.new_name.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
TagConfirm::CreateMessage => {
match (key.modifiers, key.code) {
(_, KeyCode::Enter) => {
app.tag_view.confirm = TagConfirm::None;
return Some(Action::TagCreate);
}
(_, KeyCode::Backspace) => { app.tag_view.new_message.pop(); }
(KeyModifiers::NONE, KeyCode::Char(c)) => app.tag_view.new_message.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
TagConfirm::None => {}
}
if app.tag_view.ops_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.tag_view.ops_idx > 0 { app.tag_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.tag_view.ops_idx < 2 { app.tag_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.tag_view.ops_idx;
app.tag_view.ops_mode = false;
match idx {
0 => return Some(Action::TagPush),
1 => {
app.tag_view.new_name.clear();
app.tag_view.new_message.clear();
app.tag_view.confirm = TagConfirm::CreateName;
}
2 => {
if !app.tag_view.tags.is_empty() {
app.tag_view.confirm = TagConfirm::Delete;
}
}
_ => {}
}
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.tag_view.ops_mode = false;
}
_ => {}
}
return None;
}
if app.tag_view.search_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.tag_view.search_mode = false;
app.tag_view.search_query.clear();
app.tag_view.filtered.clear();
}
(_, KeyCode::Enter) => { app.tag_view.search_mode = false; }
(_, KeyCode::Backspace) => {
app.tag_view.search_query.pop();
app.tag_update_filter();
}
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE || key.modifiers == KeyModifiers::SHIFT => {
app.tag_view.search_query.push(c);
app.tag_update_filter();
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.tag_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.tag_move_down(),
(_, KeyCode::Char('o')) => {
app.tag_view.ops_mode = true;
app.tag_view.ops_idx = 0;
}
(_, KeyCode::Char('/')) => {
app.tag_view.search_mode = true;
app.tag_view.search_query.clear();
app.tag_view.filtered.clear();
}
_ => {}
}
None
}
fn handle_history(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match app.history_view.confirm.clone() {
HistoryConfirm::CherryPick => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.history_view.confirm = HistoryConfirm::None;
return Some(Action::HistoryCherryPick);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => { app.history_view.confirm = HistoryConfirm::None; }
}
return None;
}
HistoryConfirm::Clean => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.history_view.confirm = HistoryConfirm::None;
return Some(Action::HistoryClean);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => { app.history_view.confirm = HistoryConfirm::None; }
}
return None;
}
HistoryConfirm::RemoveFile => {
match (key.modifiers, key.code) {
(_, KeyCode::Enter) => {
if !app.history_view.input.trim().is_empty() {
app.history_view.confirm = HistoryConfirm::None;
return Some(Action::HistoryRemoveFile);
}
}
(_, KeyCode::Backspace) => { app.history_view.input.pop(); }
(KeyModifiers::NONE, KeyCode::Char(c)) => app.history_view.input.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
HistoryConfirm::Rebase => {
match (key.modifiers, key.code) {
(_, KeyCode::Enter) => {
if !app.history_view.input.trim().is_empty() {
app.history_view.confirm = HistoryConfirm::None;
return Some(Action::HistoryRebase);
}
}
(_, KeyCode::Backspace) => { app.history_view.input.pop(); }
(KeyModifiers::NONE, KeyCode::Char(c)) => app.history_view.input.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
HistoryConfirm::RewriteStart => {
match (key.modifiers, key.code) {
(_, KeyCode::Enter) => {
if !app.history_view.input.trim().is_empty() {
app.history_view.confirm = HistoryConfirm::RewriteEnd;
}
}
(_, KeyCode::Backspace) => { app.history_view.input.pop(); }
(KeyModifiers::NONE, KeyCode::Char(c)) => app.history_view.input.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
HistoryConfirm::RewriteEnd => {
match (key.modifiers, key.code) {
(_, KeyCode::Enter) => {
if !app.history_view.input2.trim().is_empty() {
app.history_view.confirm = HistoryConfirm::None;
return Some(Action::HistoryRewrite);
}
}
(_, KeyCode::Backspace) => { app.history_view.input2.pop(); }
(KeyModifiers::NONE, KeyCode::Char(c)) => app.history_view.input2.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
HistoryConfirm::Blame => {
match (key.modifiers, key.code) {
(_, KeyCode::Enter) => {
if !app.history_view.input.trim().is_empty() {
app.history_view.confirm = HistoryConfirm::None;
return Some(Action::HistoryBlame);
}
}
(_, KeyCode::Backspace) => { app.history_view.input.pop(); }
(KeyModifiers::NONE, KeyCode::Char(c)) => app.history_view.input.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
HistoryConfirm::Scan => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('f')) => {
app.history_view.scan_full = !app.history_view.scan_full;
}
(_, KeyCode::Enter) => {
app.history_view.confirm = HistoryConfirm::None;
return Some(Action::HistoryScan);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => { app.history_view.confirm = HistoryConfirm::None; }
}
return None;
}
HistoryConfirm::None => {}
}
if app.history_view.ops_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.history_view.ops_idx > 0 { app.history_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.history_view.ops_idx < 6 { app.history_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.history_view.ops_idx;
app.history_view.ops_mode = false;
match idx {
0 => { app.history_view.confirm = HistoryConfirm::CherryPick; }
1 => { app.history_view.input.clear(); app.history_view.confirm = HistoryConfirm::Rebase; }
2 => { app.history_view.confirm = HistoryConfirm::Scan; }
3 => { app.history_view.confirm = HistoryConfirm::Clean; }
4 => { app.history_view.input.clear(); app.history_view.confirm = HistoryConfirm::Blame; }
5 => { app.history_view.input.clear(); app.history_view.input2.clear(); app.history_view.confirm = HistoryConfirm::RewriteStart; }
6 => { app.history_view.input.clear(); app.history_view.confirm = HistoryConfirm::RemoveFile; }
_ => {}
}
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.history_view.ops_mode = false;
}
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.history_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.history_move_down(),
(_, KeyCode::Char('o')) => {
app.history_view.ops_mode = true;
app.history_view.ops_idx = 0;
}
_ => {}
}
None
}
fn handle_remote(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match &app.remote_view.confirm {
RemoteConfirm::AddName => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_name.clear();
}
(_, KeyCode::Enter) => {
if !app.remote_view.new_name.is_empty() {
app.remote_view.confirm = RemoteConfirm::AddUrl;
}
}
(_, KeyCode::Backspace) => { app.remote_view.new_name.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.remote_view.new_name.push(c),
_ => {}
}
return None;
}
RemoteConfirm::AddUrl => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_name.clear();
app.remote_view.new_url.clear();
}
(_, KeyCode::Enter) => {
if !app.remote_view.new_url.is_empty() {
return Some(Action::RemoteAdd);
}
}
(_, KeyCode::Backspace) => { app.remote_view.new_url.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.remote_view.new_url.push(c),
_ => {}
}
return None;
}
RemoteConfirm::Remove => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.remote_view.confirm = RemoteConfirm::None;
return Some(Action::RemoteRemove);
}
_ => { app.remote_view.confirm = RemoteConfirm::None; }
}
return None;
}
RemoteConfirm::Rename => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_name.clear();
}
(_, KeyCode::Enter) => {
if !app.remote_view.new_name.is_empty() {
return Some(Action::RemoteRename);
}
}
(_, KeyCode::Backspace) => { app.remote_view.new_name.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.remote_view.new_name.push(c),
_ => {}
}
return None;
}
RemoteConfirm::EditUrl => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_url.clear();
}
(_, KeyCode::Enter) => {
if !app.remote_view.new_url.is_empty() {
return Some(Action::RemoteEditUrl);
}
}
(_, KeyCode::Backspace) => { app.remote_view.new_url.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.remote_view.new_url.push(c),
_ => {}
}
return None;
}
RemoteConfirm::MirrorRename => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_name.clear();
}
(_, KeyCode::Enter) => {
if !app.remote_view.new_name.is_empty() {
return Some(Action::MirrorRename);
}
}
(_, KeyCode::Backspace) => { app.remote_view.new_name.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.remote_view.new_name.push(c),
_ => {}
}
return None;
}
RemoteConfirm::MirrorAddPlatform => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_mirror_platform.clear();
}
(_, KeyCode::Enter) => {
if !app.remote_view.new_mirror_platform.is_empty() {
app.remote_view.new_mirror_account.clear();
app.remote_view.confirm = RemoteConfirm::MirrorAddAccount;
}
}
(_, KeyCode::Backspace) => { app.remote_view.new_mirror_platform.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.remote_view.new_mirror_platform.push(c),
_ => {}
}
return None;
}
RemoteConfirm::MirrorAddAccount => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_mirror_platform.clear();
app.remote_view.new_mirror_account.clear();
}
(_, KeyCode::Enter) => {
if !app.remote_view.new_mirror_account.is_empty() {
app.remote_view.new_mirror_repo.clear();
app.remote_view.confirm = RemoteConfirm::MirrorAddRepo;
}
}
(_, KeyCode::Backspace) => { app.remote_view.new_mirror_account.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.remote_view.new_mirror_account.push(c),
_ => {}
}
return None;
}
RemoteConfirm::MirrorAddRepo => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
app.remote_view.new_mirror_platform.clear();
app.remote_view.new_mirror_account.clear();
app.remote_view.new_mirror_repo.clear();
}
(_, KeyCode::Enter) => {
if !app.remote_view.new_mirror_repo.is_empty() {
app.remote_view.new_mirror_type = 0;
app.remote_view.confirm = RemoteConfirm::MirrorAddType;
}
}
(_, KeyCode::Backspace) => { app.remote_view.new_mirror_repo.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.remote_view.new_mirror_repo.push(c),
_ => {}
}
return None;
}
RemoteConfirm::MirrorAddType => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.remote_view.confirm = RemoteConfirm::None;
}
(_, KeyCode::Left) | (_, KeyCode::Char('h')) => {
app.remote_view.new_mirror_type = 0;
}
(_, KeyCode::Right) | (_, KeyCode::Char('l')) => {
app.remote_view.new_mirror_type = 1;
}
(_, KeyCode::Enter) => {
app.remote_view.confirm = RemoteConfirm::None;
return Some(Action::MirrorAdd);
}
_ => {}
}
return None;
}
RemoteConfirm::None => {}
}
if app.remote_view.ops_mode {
let is_mirror = app.remote_view.selected_is_mirror();
let ops_len = if is_mirror { 6 } else { 6 };
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.remote_view.ops_idx > 0 { app.remote_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.remote_view.ops_idx < ops_len - 1 { app.remote_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.remote_view.ops_idx;
app.remote_view.ops_mode = false;
if is_mirror {
return match idx {
0 => Some(Action::MirrorSync),
1 => Some(Action::MirrorSyncForce),
2 => {
app.remote_view.new_mirror_platform.clear();
app.remote_view.new_mirror_account.clear();
app.remote_view.new_mirror_repo.clear();
app.remote_view.new_mirror_type = 0;
app.remote_view.confirm = RemoteConfirm::MirrorAddPlatform;
None
}
3 => Some(Action::MirrorSetPrimary),
4 => {
app.remote_view.new_name.clear();
app.remote_view.confirm = RemoteConfirm::MirrorRename;
None
}
5 => Some(Action::MirrorRemove),
_ => None,
};
} else {
return match idx {
0 => Some(Action::RemoteFetch),
1 => {
app.remote_view.new_name.clear();
app.remote_view.confirm = RemoteConfirm::AddName;
None
}
2 => {
app.remote_view.new_name.clear();
app.remote_view.confirm = RemoteConfirm::Rename;
None
}
3 => {
app.remote_view.new_url.clear();
app.remote_view.confirm = RemoteConfirm::EditUrl;
None
}
4 => {
app.remote_view.confirm = RemoteConfirm::Remove;
None
}
5 => Some(Action::RemoteOpenBrowser),
_ => None,
};
}
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.remote_view.ops_mode = false;
}
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => { app.remote_move_up(); }
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => { app.remote_move_down(); }
(_, KeyCode::Char('o')) => {
app.remote_view.ops_mode = true;
app.remote_view.ops_idx = 0;
}
_ => {}
}
None
}
fn handle_mirror(key: event::KeyEvent, app: &mut App) -> Option<Action> {
if app.mirror_view.ops_mode {
const OPS_LEN: usize = 3;
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.mirror_view.ops_idx > 0 { app.mirror_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.mirror_view.ops_idx < OPS_LEN - 1 { app.mirror_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.mirror_view.ops_idx;
app.mirror_view.ops_mode = false;
return match idx {
0 => Some(Action::MirrorSync),
1 => Some(Action::MirrorSyncForce),
2 => Some(Action::MirrorRemove),
_ => None,
};
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.mirror_view.ops_mode = false;
}
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.mirror_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.mirror_move_down(),
(_, KeyCode::Char('o')) => {
app.mirror_view.ops_mode = true;
app.mirror_view.ops_idx = 0;
}
_ => {}
}
None
}
fn handle_workspace(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match &app.workspace_view.confirm {
WorkspaceConfirm::DeleteWorkspace => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.workspace_view.confirm = WorkspaceConfirm::None;
return Some(Action::WorkspaceDelete);
}
_ => { app.workspace_view.confirm = WorkspaceConfirm::None; }
}
return None;
}
WorkspaceConfirm::RemoveRepo => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.workspace_view.confirm = WorkspaceConfirm::None;
return Some(Action::WorkspaceRemoveRepo);
}
_ => { app.workspace_view.confirm = WorkspaceConfirm::None; }
}
return None;
}
WorkspaceConfirm::SaveMessage => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.workspace_view.confirm = WorkspaceConfirm::None;
app.workspace_view.input.clear();
}
(_, KeyCode::Enter) => {
if !app.workspace_view.input.trim().is_empty() {
app.workspace_view.confirm = WorkspaceConfirm::None;
return Some(Action::WorkspaceSave);
}
}
(_, KeyCode::Backspace) => { app.workspace_view.input.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.workspace_view.input.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
WorkspaceConfirm::AddRepoPath => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.workspace_view.confirm = WorkspaceConfirm::None;
app.workspace_view.input.clear();
}
(_, KeyCode::Enter) => {
if !app.workspace_view.input.trim().is_empty() {
app.workspace_view.confirm = WorkspaceConfirm::None;
return Some(Action::WorkspaceAddRepo);
}
}
(_, KeyCode::Backspace) => { app.workspace_view.input.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.workspace_view.input.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
WorkspaceConfirm::RenameWorkspace => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.workspace_view.confirm = WorkspaceConfirm::None;
app.workspace_view.input.clear();
}
(_, KeyCode::Enter) => {
if !app.workspace_view.input.trim().is_empty() {
app.workspace_view.confirm = WorkspaceConfirm::None;
return Some(Action::WorkspaceRename);
}
}
(_, KeyCode::Backspace) => { app.workspace_view.input.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.workspace_view.input.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
WorkspaceConfirm::None => {}
}
if app.workspace_view.ops_mode {
let is_repos = app.workspace_view.focus == WorkspaceFocus::Repos;
let ops_len = if is_repos { 4 } else { 5 };
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.workspace_view.ops_idx > 0 { app.workspace_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.workspace_view.ops_idx < ops_len - 1 { app.workspace_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.workspace_view.ops_idx;
app.workspace_view.ops_mode = false;
if is_repos {
return match idx {
0 => Some(Action::WorkspaceOpenRepo),
1 => Some(Action::WorkspaceSyncOne),
2 => Some(Action::WorkspaceSync),
3 => {
app.workspace_view.confirm = WorkspaceConfirm::RemoveRepo;
None
}
_ => None,
};
} else {
return match idx {
0 => Some(Action::WorkspaceSync),
1 => {
app.workspace_view.input.clear();
app.workspace_view.confirm = WorkspaceConfirm::SaveMessage;
None
}
2 => {
app.workspace_view.input.clear();
app.workspace_view.confirm = WorkspaceConfirm::RenameWorkspace;
None
}
3 => {
app.workspace_view.input.clear();
app.workspace_view.confirm = WorkspaceConfirm::AddRepoPath;
None
}
4 => {
app.workspace_view.confirm = WorkspaceConfirm::DeleteWorkspace;
None
}
_ => None,
};
}
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.workspace_view.ops_mode = false;
}
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match app.workspace_view.focus {
WorkspaceFocus::Workspaces => match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.workspace_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.workspace_move_down(),
(_, KeyCode::Right) | (_, KeyCode::Char('l')) => app.workspace_focus_repos(),
(_, KeyCode::Enter) => app.workspace_focus_repos(),
(_, KeyCode::Char('o')) => {
app.workspace_view.ops_mode = true;
app.workspace_view.ops_idx = 0;
}
_ => {}
},
WorkspaceFocus::Repos => match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.workspace_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.workspace_move_down(),
(_, KeyCode::Left) | (_, KeyCode::Char('h')) => app.workspace_focus_workspaces(),
(_, KeyCode::Enter) => return Some(Action::WorkspaceOpenRepo),
(_, KeyCode::Char('o')) => {
app.workspace_view.ops_mode = true;
app.workspace_view.ops_idx = 0;
}
_ => {}
},
}
None
}
fn handle_pr(key: event::KeyEvent, app: &mut App) -> Option<Action> {
use crate::tui::app::PrConfirm;
if matches!(app.pr_view.confirm, PrConfirm::CreateTitle | PrConfirm::CreateDesc) {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.pr_view.confirm = PrConfirm::None;
app.pr_view.create_input.clear();
app.pr_view.create_desc.clear();
}
(_, KeyCode::Backspace) => {
if app.pr_view.create_input.is_empty() && app.pr_view.confirm == PrConfirm::CreateDesc {
app.pr_view.create_desc.pop();
} else {
app.pr_view.create_input.pop();
}
}
(_, KeyCode::Enter) => {
match app.pr_view.confirm.clone() {
PrConfirm::CreateTitle => {
app.pr_view.create_title = app.pr_view.create_input.trim().to_string();
app.pr_view.create_input.clear();
app.load_pr_branches();
let current = git2::Repository::discover(&app.repo_path).ok()
.and_then(|r| {
r.head().ok()
.and_then(|h| h.shorthand().map(|s| s.to_string()))
})
.unwrap_or_default();
app.pr_view.create_head = current.clone();
app.pr_view.branch_idx = app.pr_view.branches.iter()
.position(|b| *b == current).unwrap_or(0);
app.pr_view.confirm = PrConfirm::CreateHead;
}
PrConfirm::CreateBase => {}
PrConfirm::CreateDesc => {
if !app.pr_view.create_input.is_empty() {
if !app.pr_view.create_desc.is_empty() {
app.pr_view.create_desc.push('\n');
}
app.pr_view.create_desc.push_str(&app.pr_view.create_input);
app.pr_view.create_input.clear();
} else {
app.pr_view.create_desc.push('\n');
}
}
_ => {}
}
}
(_, KeyCode::Tab) if app.pr_view.confirm == PrConfirm::CreateDesc => {
app.pr_view.create_draft = !app.pr_view.create_draft;
}
(KeyModifiers::CONTROL, KeyCode::Char('s')) if app.pr_view.confirm == PrConfirm::CreateDesc => {
if !app.pr_view.create_input.is_empty() {
if !app.pr_view.create_desc.is_empty() {
app.pr_view.create_desc.push('\n');
}
app.pr_view.create_desc.push_str(&app.pr_view.create_input);
app.pr_view.create_input.clear();
}
app.load_pr_platforms();
let n = app.pr_view.available_platforms.len();
app.pr_view.create_platform_selected = vec![false; n];
if n > 0 {
let cur_platform = app.pr_view.platform.clone();
let cur_owner = app.pr_view.owner.clone();
let idx = app.pr_view.available_platforms.iter()
.position(|p| p.platform == cur_platform && p.owner == cur_owner)
.unwrap_or(0);
if let Some(s) = app.pr_view.create_platform_selected.get_mut(idx) { *s = true; }
}
app.pr_view.create_platform_idx = 0;
app.pr_view.confirm = PrConfirm::CreatePlatforms;
}
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE
|| key.modifiers == KeyModifiers::SHIFT => {
if app.pr_view.confirm == PrConfirm::CreateTitle
&& app.pr_view.create_input.chars().count() >= 255 {
return None;
}
app.pr_view.create_input.push(c);
if app.pr_view.create_input.chars().count() >= 56 {
if !app.pr_view.create_desc.is_empty() {
app.pr_view.create_desc.push('\n');
}
app.pr_view.create_desc.push_str(&app.pr_view.create_input);
app.pr_view.create_input.clear();
}
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::CreateHead {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.pr_view.confirm = PrConfirm::None;
app.pr_view.create_input.clear();
}
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.pr_view.branch_idx > 0 { app.pr_view.branch_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.pr_view.branch_idx + 1 < app.pr_view.branches.len() {
app.pr_view.branch_idx += 1;
}
}
(_, KeyCode::Enter) => {
if let Some(branch) = app.pr_view.branches.get(app.pr_view.branch_idx) {
app.pr_view.create_head = branch.clone();
}
app.load_pr_branches();
let base = app.pr_view.create_base.clone();
app.pr_view.branch_idx = app.pr_view.branches.iter()
.position(|b| b == &base)
.or_else(|| app.pr_view.branches.iter().position(|b| b == "main"))
.or_else(|| app.pr_view.branches.iter().position(|b| b == "master"))
.unwrap_or(0);
app.pr_view.confirm = PrConfirm::CreateBase;
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::CreateBase {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.pr_view.confirm = PrConfirm::None;
app.pr_view.create_input.clear();
}
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.pr_view.branch_idx > 0 { app.pr_view.branch_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.pr_view.branch_idx + 1 < app.pr_view.branches.len() {
app.pr_view.branch_idx += 1;
}
}
(_, KeyCode::Enter) => {
if let Some(branch) = app.pr_view.branches.get(app.pr_view.branch_idx) {
app.pr_view.create_base = branch.clone();
}
app.pr_view.create_input.clear();
app.pr_view.confirm = PrConfirm::CreateDesc;
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::CreatePlatforms {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.pr_view.confirm = PrConfirm::None;
}
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.pr_view.create_platform_idx > 0 { app.pr_view.create_platform_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
let n = app.pr_view.available_platforms.len();
if app.pr_view.create_platform_idx + 1 < n { app.pr_view.create_platform_idx += 1; }
}
(_, KeyCode::Char(' ')) => {
let idx = app.pr_view.create_platform_idx;
if let Some(s) = app.pr_view.create_platform_selected.get_mut(idx) { *s = !*s; }
}
(_, KeyCode::Char('a')) if key.modifiers == KeyModifiers::NONE => {
let all = app.pr_view.create_platform_selected.iter().all(|&s| s);
app.pr_view.create_platform_selected.iter_mut().for_each(|s| *s = !all);
}
(_, KeyCode::Enter) => {
app.pr_view.confirm = PrConfirm::None;
return Some(Action::PrCreateMulti);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::SwitchPlatform {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => { app.pr_view.confirm = PrConfirm::None; }
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.pr_view.platform_idx > 0 { app.pr_view.platform_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.pr_view.platform_idx + 1 < app.pr_view.available_platforms.len() {
app.pr_view.platform_idx += 1;
}
}
(_, KeyCode::Enter) => {
return Some(Action::PrSwitchPlatform);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::EditTitle {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.pr_view.confirm = PrConfirm::None;
app.pr_view.edit_input.clear();
app.pr_view.edit_desc.clear();
}
(_, KeyCode::Enter) => {
app.pr_view.confirm = PrConfirm::EditDesc;
}
(_, KeyCode::Backspace) => { app.pr_view.edit_input.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE
|| key.modifiers == KeyModifiers::SHIFT => {
app.pr_view.edit_input.push(c);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::EditDesc {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.pr_view.confirm = PrConfirm::None;
app.pr_view.edit_input.clear();
app.pr_view.edit_desc.clear();
}
(_, KeyCode::Enter) => {
app.pr_view.edit_desc.push('\n');
}
(_, KeyCode::Backspace) => { app.pr_view.edit_desc.pop(); }
(KeyModifiers::CONTROL, KeyCode::Char('s')) => {
app.pr_view.confirm = PrConfirm::EditBase;
}
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE
|| key.modifiers == KeyModifiers::SHIFT => {
app.pr_view.edit_desc.push(c);
if app.pr_view.edit_desc.chars().rev().take_while(|&ch| ch != '\n').count() >= 56 {
app.pr_view.edit_desc.push('\n');
}
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::EditBase {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.pr_view.confirm = PrConfirm::None;
app.pr_view.edit_input.clear();
app.pr_view.edit_desc.clear();
}
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.pr_view.branch_idx > 0 { app.pr_view.branch_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.pr_view.branch_idx + 1 < app.pr_view.branches.len() {
app.pr_view.branch_idx += 1;
}
}
(_, KeyCode::Enter) => {
app.pr_view.confirm = PrConfirm::None;
return Some(Action::PrUpdate);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::Merge {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.pr_view.confirm = PrConfirm::None;
}
(_, KeyCode::Left) | (_, KeyCode::Char('h')) => {
if app.pr_view.merge_method > 0 { app.pr_view.merge_method -= 1; }
}
(_, KeyCode::Right) | (_, KeyCode::Char('l')) => {
if app.pr_view.merge_method < 2 { app.pr_view.merge_method += 1; }
}
(_, KeyCode::Enter) => {
app.pr_view.confirm = PrConfirm::None;
return Some(Action::PrMerge);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if app.pr_view.confirm == PrConfirm::Close {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.pr_view.confirm = PrConfirm::None;
return Some(Action::PrClose);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {
app.pr_view.confirm = PrConfirm::None;
}
}
return None;
}
if app.pr_view.ops_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.pr_view.ops_idx > 0 { app.pr_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.pr_view.ops_idx < 6 { app.pr_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.pr_view.ops_idx;
app.pr_view.ops_mode = false;
match idx {
0 => {
app.pr_view.create_title.clear();
app.pr_view.create_base = "main".to_string();
app.pr_view.create_desc.clear();
app.pr_view.create_draft = false;
app.pr_view.create_input.clear();
app.pr_view.confirm = PrConfirm::CreateTitle;
}
1 => {
let (title, desc, base) = app.pr_view.prs.get(app.pr_view.idx)
.map(|pr| (pr.title.clone(), pr.body.clone().unwrap_or_default(), pr.base.clone()))
.unwrap_or_default();
app.pr_view.edit_input = title;
app.pr_view.edit_desc = desc;
app.load_pr_branches();
app.pr_view.branch_idx = app.pr_view.branches.iter()
.position(|b| *b == base).unwrap_or(0);
app.pr_view.confirm = PrConfirm::EditTitle;
}
2 => {
app.pr_view.merge_method = 0;
app.pr_view.confirm = PrConfirm::Merge;
}
3 => { app.pr_view.confirm = PrConfirm::Close; }
4 => return Some(Action::PrCheckout),
5 => return Some(Action::PrOpenBrowser),
6 => {
app.load_pr_platforms();
app.pr_view.confirm = PrConfirm::SwitchPlatform;
}
_ => {}
}
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.pr_view.ops_mode = false;
}
_ => {}
}
return None;
}
if key.modifiers == KeyModifiers::CONTROL && key.code == KeyCode::Char('r') {
return Some(Action::PrRefresh);
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.pr_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.pr_move_down(),
(_, KeyCode::Tab) => {
app.pr_view.filter = match app.pr_view.filter {
crate::tui::app::PrStateFilter::Open => crate::tui::app::PrStateFilter::Closed,
crate::tui::app::PrStateFilter::Closed => crate::tui::app::PrStateFilter::All,
crate::tui::app::PrStateFilter::All => crate::tui::app::PrStateFilter::Open,
};
app.load_prs();
}
(_, KeyCode::Char('o')) => {
app.pr_view.ops_mode = true;
app.pr_view.ops_idx = 0;
}
_ => {}
}
None
}
fn handle_config(key: event::KeyEvent, app: &mut App) -> Option<Action> {
if app.config_view.editing {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => { app.config_view.editing = false; }
(_, KeyCode::Enter) => return Some(Action::ConfigSave),
(_, KeyCode::Backspace) => app.config_backspace(),
(_, KeyCode::Left) => app.config_cursor_left(),
(_, KeyCode::Right) => app.config_cursor_right(),
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.config_type_char(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.config_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.config_move_down(),
(_, KeyCode::Enter) => { app.config_start_edit(); return Some(Action::ConfigEdit); }
(_, KeyCode::Tab) => return Some(Action::ConfigToggleScope),
_ => {}
}
None
}
fn handle_settings(key: event::KeyEvent, app: &mut App) -> Option<Action> {
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => app.settings_move_up(),
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => app.settings_move_down(),
(_, KeyCode::Enter) => return Some(Action::SettingsToggle),
(_, KeyCode::Char('s')) => return Some(Action::SettingsSave),
_ => {}
}
None
}
fn handle_issue(key: event::KeyEvent, app: &mut App) -> Option<Action> {
match &app.issue_view.confirm {
IssueConfirm::CreateTitle => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.issue_view.confirm = IssueConfirm::None;
app.issue_view.create_title.clear();
}
(_, KeyCode::Enter) => {
if !app.issue_view.create_title.is_empty() {
app.issue_view.create_desc.clear();
app.issue_view.confirm = IssueConfirm::CreateDesc;
}
}
(_, KeyCode::Backspace) => { app.issue_view.create_title.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.issue_view.create_title.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
IssueConfirm::CreateDesc => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.issue_view.confirm = IssueConfirm::None;
app.issue_view.create_title.clear();
app.issue_view.create_desc.clear();
}
(_, KeyCode::Enter) => {
return Some(Action::IssueCreate);
}
(_, KeyCode::Backspace) => { app.issue_view.create_desc.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.issue_view.create_desc.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
IssueConfirm::Comment => {
match (key.modifiers, key.code) {
(_, KeyCode::Esc) => {
app.issue_view.confirm = IssueConfirm::None;
app.issue_view.comment_input.clear();
}
(_, KeyCode::Enter) => {
if !app.issue_view.comment_input.is_empty() {
return Some(Action::IssueComment);
}
}
(_, KeyCode::Backspace) => { app.issue_view.comment_input.pop(); }
(_, KeyCode::Char(c)) if key.modifiers == KeyModifiers::NONE ||
key.modifiers == KeyModifiers::SHIFT
=> app.issue_view.comment_input.push(c),
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => {}
}
return None;
}
IssueConfirm::Close => {
match (key.modifiers, key.code) {
(_, KeyCode::Char('y')) => {
app.issue_view.confirm = IssueConfirm::None;
return Some(Action::IssueClose);
}
(KeyModifiers::CONTROL, KeyCode::Char('c')) => return Some(Action::Quit),
_ => { app.issue_view.confirm = IssueConfirm::None; }
}
return None;
}
IssueConfirm::None => {}
}
if app.issue_view.ops_mode {
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.issue_view.ops_idx > 0 { app.issue_view.ops_idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.issue_view.ops_idx < 3 { app.issue_view.ops_idx += 1; }
}
(_, KeyCode::Enter) => {
let idx = app.issue_view.ops_idx;
app.issue_view.ops_mode = false;
match idx {
0 => {
app.issue_view.create_title.clear();
app.issue_view.confirm = IssueConfirm::CreateTitle;
}
1 => {
app.issue_view.comment_input.clear();
app.issue_view.confirm = IssueConfirm::Comment;
}
2 => return Some(Action::IssueOpenBrowser),
3 => { app.issue_view.confirm = IssueConfirm::Close; }
_ => {}
}
}
(_, KeyCode::Esc) | (KeyModifiers::CONTROL, KeyCode::Char('c')) => {
app.issue_view.ops_mode = false;
}
_ => {}
}
return None;
}
if key.modifiers == KeyModifiers::CONTROL && key.code == KeyCode::Char('r') {
return Some(Action::IssueRefresh);
}
if let Some(a) = handle_global_nav(key, app) { return Some(a); }
match (key.modifiers, key.code) {
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
if app.issue_view.idx > 0 { app.issue_view.idx -= 1; }
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
if app.issue_view.idx + 1 < app.issue_view.issues.len() { app.issue_view.idx += 1; }
}
(_, KeyCode::Char('o')) => {
app.issue_view.ops_mode = true;
app.issue_view.ops_idx = 0;
}
_ => {}
}
None
}