use std::io::Result;
use crossterm::event::KeyModifiers;
use ratatui::crossterm::event::{KeyCode, KeyEvent};
use crate::{app::App, editor::AppView};
const NUMBER_OF_TABS: usize = 5;
fn tab_next(app: &mut App) {
if app.header_view.tab_index < NUMBER_OF_TABS - 1 {
app.header_view.tab_index = app.header_view.tab_index.saturating_add(1);
} else {
app.header_view.tab_index = 0;
}
}
fn tab_prev(app: &mut App) {
if app.header_view.tab_index == 0 {
app.header_view.tab_index = NUMBER_OF_TABS - 1;
} else {
app.header_view.tab_index -= 1;
}
}
fn tab_elf_header_events(app: &mut App, key: KeyEvent) -> Result<bool> {
match key.code {
KeyCode::Down | KeyCode::Char('j') => app
.header_view
.elf_state
.elf_header_table_state
.select_next(),
KeyCode::Up | KeyCode::Char('k') => app
.header_view
.elf_state
.elf_header_table_state
.select_previous(),
KeyCode::Left | KeyCode::Char('h') => tab_prev(app),
KeyCode::Right | KeyCode::Char('l') => tab_next(app),
KeyCode::Char('g') | KeyCode::Home => app
.header_view
.elf_state
.elf_header_table_state
.select_first(),
KeyCode::Char('G') | KeyCode::End => app
.header_view
.elf_state
.elf_header_table_state
.select_last(),
KeyCode::Char('f') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.elf_header_table_state
.scroll_down_by(height.saturating_sub(5));
}
KeyCode::Char('b') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.elf_header_table_state
.scroll_up_by(height.saturating_sub(5));
}
KeyCode::Enter => {
if let Some(idx) = app.header_view.elf_state.elf_header_table_state.selected()
&& idx == 8
{
let elf = app.header_view.elf.as_ref().unwrap();
let offset = elf.header.e_entry;
app.goto(offset as usize);
}
}
_ => {}
}
Ok(false)
}
fn tab_program_headers_events(app: &mut App, key: KeyEvent) -> Result<bool> {
match key.code {
KeyCode::Down | KeyCode::Char('j') => app
.header_view
.elf_state
.program_header_table_state
.select_next(),
KeyCode::Up | KeyCode::Char('k') => app
.header_view
.elf_state
.program_header_table_state
.select_previous(),
KeyCode::Left | KeyCode::Char('h') => tab_prev(app),
KeyCode::Right | KeyCode::Char('l') => tab_next(app),
KeyCode::Enter => {
if let Some(idx) = app
.header_view
.elf_state
.program_header_table_state
.selected()
{
let elf = app.header_view.elf.as_ref().unwrap();
if let Some(phdr) = elf.phdrs.get(idx) {
let ofs = phdr.p_offset;
app.goto(ofs as usize);
app.editor_view = AppView::Hex;
}
}
}
KeyCode::Char('g') | KeyCode::Home => app
.header_view
.elf_state
.program_header_table_state
.select_first(),
KeyCode::Char('G') | KeyCode::End => app
.header_view
.elf_state
.program_header_table_state
.select_last(),
KeyCode::Char('f') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.program_header_table_state
.scroll_down_by(height.saturating_sub(5));
}
KeyCode::Char('b') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.program_header_table_state
.scroll_up_by(height.saturating_sub(5));
}
_ => {}
}
Ok(false)
}
fn tab_sections_events(app: &mut App, key: KeyEvent) -> Result<bool> {
match key.code {
KeyCode::Down | KeyCode::Char('j') => {
app.header_view.elf_state.sections_table_state.select_next()
}
KeyCode::Up | KeyCode::Char('k') => app
.header_view
.elf_state
.sections_table_state
.select_previous(),
KeyCode::Left | KeyCode::Char('h') => tab_prev(app),
KeyCode::Right | KeyCode::Char('l') => tab_next(app),
KeyCode::Enter => {
if let Some(idx) = app.header_view.elf_state.sections_table_state.selected() {
let elf = app.header_view.elf.as_ref().unwrap();
if let Some(sec) = elf.sections.get(idx) {
let ofs = sec.sh_offset;
app.goto(ofs as usize);
app.editor_view = AppView::Hex;
}
}
}
KeyCode::Char('g') | KeyCode::Home => app
.header_view
.elf_state
.sections_table_state
.select_first(),
KeyCode::Char('G') | KeyCode::End => {
app.header_view.elf_state.sections_table_state.select_last()
}
KeyCode::Char('f') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.sections_table_state
.scroll_down_by(height.saturating_sub(5));
}
KeyCode::Char('b') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.sections_table_state
.scroll_up_by(height.saturating_sub(5));
}
_ => {}
}
Ok(false)
}
fn tab_symbols_events(app: &mut App, key: KeyEvent) -> Result<bool> {
match key.code {
KeyCode::Down | KeyCode::Char('j') => {
app.header_view.elf_state.symbols_table_state.select_next()
}
KeyCode::Up | KeyCode::Char('k') => app
.header_view
.elf_state
.symbols_table_state
.select_previous(),
KeyCode::Left | KeyCode::Char('h') => tab_prev(app),
KeyCode::Right | KeyCode::Char('l') => tab_next(app),
KeyCode::Enter => {
if let Some(idx) = app.header_view.elf_state.symbols_table_state.selected() {
let elf = app.header_view.elf.as_ref().unwrap();
if let Some(sym) = elf.dynsymtab.get(idx) {
let ofs = sym.st_value;
app.goto(ofs as usize);
app.editor_view = AppView::Hex;
}
}
}
KeyCode::Char('g') | KeyCode::Home => {
app.header_view.elf_state.symbols_table_state.select_first()
}
KeyCode::Char('G') | KeyCode::End => {
app.header_view.elf_state.symbols_table_state.select_last()
}
KeyCode::Char('f') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.symbols_table_state
.scroll_down_by(height.saturating_sub(5));
}
KeyCode::Char('b') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.symbols_table_state
.scroll_up_by(height.saturating_sub(5));
}
_ => {}
}
Ok(false)
}
fn tab_relocations_events(app: &mut App, key: KeyEvent) -> Result<bool> {
match key.code {
KeyCode::Down | KeyCode::Char('j') => app
.header_view
.elf_state
.relocations_table_state
.select_next(),
KeyCode::Up | KeyCode::Char('k') => app
.header_view
.elf_state
.relocations_table_state
.select_previous(),
KeyCode::Left | KeyCode::Char('h') => tab_prev(app),
KeyCode::Right | KeyCode::Char('l') => tab_next(app),
KeyCode::Char('g') | KeyCode::Home => app
.header_view
.elf_state
.relocations_table_state
.select_first(),
KeyCode::Char('G') | KeyCode::End => app
.header_view
.elf_state
.relocations_table_state
.select_last(),
KeyCode::Char('f') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.relocations_table_state
.scroll_down_by(height.saturating_sub(5));
}
KeyCode::Char('b') if key.modifiers.contains(KeyModifiers::CONTROL) => {
let height = app.screen.height;
app.header_view
.elf_state
.relocations_table_state
.scroll_up_by(height.saturating_sub(5));
}
_ => {}
}
Ok(false)
}
pub fn view_header_elf_events(app: &mut App, key: KeyEvent) -> Result<bool> {
match key.code {
KeyCode::Char(' ') => {
app.config.header_base = if app.config.header_base == 10 { 16 } else { 10 };
Ok(true)
}
KeyCode::Char(c) if ('1'..='5').contains(&c) => {
app.header_view.tab_index = (c as u8 - b'1') as usize;
Ok(true)
}
_ => match app.header_view.tab_index {
0 => tab_elf_header_events(app, key),
1 => tab_program_headers_events(app, key),
2 => tab_sections_events(app, key),
3 => tab_symbols_events(app, key),
4 => tab_relocations_events(app, key),
_ => Ok(false),
},
}
}