diff --git a/config/config.json5 b/config/config.json5 index 1a43d79..ef7ba9b 100644 --- a/config/config.json5 +++ b/config/config.json5 @@ -6,11 +6,23 @@ "": "Quit", "": "Suspend", }, + "ExplorerActive": { + "": "Quit", + "": "Quit", + "": "Quit", + "": "Suspend", + }, "Empty": { "": "Quit", "": "Quit", "": "Quit", "": "Suspend", + }, + "EmptyActive": { + "": "Quit", + "": "Quit", + "": "Quit", + "": "Suspend", } } } diff --git a/src/action.rs b/src/action.rs index e931d0e..053b4ab 100644 --- a/src/action.rs +++ b/src/action.rs @@ -19,7 +19,6 @@ pub enum Action { Help, SetMode(crate::app::Mode), - //MenuItem(bool), GetNodeName, GetSyncState, diff --git a/src/app.rs b/src/app.rs index beb9a61..783f48d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -17,13 +17,15 @@ use crate::{ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Mode { - Explorer(#[serde(skip)] bool), - Empty(#[serde(skip)] bool), + Explorer, + ExplorerActive, + Empty, + EmptyActive, } impl Default for Mode { fn default() -> Self { - Self::Explorer(false) + Self::Explorer } } @@ -233,7 +235,7 @@ impl App { } match self.mode { - Mode::Explorer(_) => { + Mode::Explorer | Mode::ExplorerActive => { if let Some(component) = self.components.get_mut(4) { if let Err(err) = component.draw(frame, frame.area()) { let _ = self diff --git a/src/components/empty.rs b/src/components/empty.rs index 4a923dc..e54dfa4 100644 --- a/src/components/empty.rs +++ b/src/components/empty.rs @@ -98,8 +98,8 @@ impl Empty { impl Component for Empty { fn update(&mut self, action: Action) -> Result> { match action { - Action::SetMode(Mode::Empty(true)) if !self.is_active => self.set_active()?, - Action::SetMode(Mode::Empty(false)) if self.is_active => self.unset_active()?, + Action::SetMode(Mode::EmptyActive) if !self.is_active => self.set_active()?, + Action::SetMode(_) if self.is_active => self.unset_active()?, _ => {} }; Ok(None) diff --git a/src/components/explorer/current_era.rs b/src/components/explorer/current_era.rs index 8247122..203da5f 100644 --- a/src/components/explorer/current_era.rs +++ b/src/components/explorer/current_era.rs @@ -1,5 +1,4 @@ use color_eyre::Result; -use std::time::Instant; use ratatui::{ layout::{Alignment, Rect}, text::Line, diff --git a/src/components/explorer/explorer_blocks.rs b/src/components/explorer/explorer_blocks.rs index 3420903..6d35e8b 100644 --- a/src/components/explorer/explorer_blocks.rs +++ b/src/components/explorer/explorer_blocks.rs @@ -34,15 +34,15 @@ pub struct ExplorerBlocks { is_active: bool, used_paragraph_index: usize, - used_block_index: Option, + used_block_index: Option<(usize, u32)>, used_ext_index: Option<(String, usize, usize)>, } impl ExplorerBlocks { - const MAX_BLOCKS: usize = 50; - const LENGTH_OF_BLOCK_HASH: u16 = 66; // hash + 0x prefix - const LENGTH_OF_ADDRESS: u16 = 49; - const TOTAL_OFFSETS: u16 = 18; + const MAX_BLOCKS: usize = 50; + const LENGTH_OF_BLOCK_HASH: u16 = 66; // hash + 0x prefix + const LENGTH_OF_ADDRESS: u16 = 49; + const TOTAL_OFFSETS: u16 = 18; fn update_validator_list(&mut self, validators: Vec) -> Result<()> { self.validators = validators; @@ -125,19 +125,14 @@ impl ExplorerBlocks { let number_hex_str = number_hex_str.trim_start_matches("0x"); let block_number = u32::from_str_radix(&number_hex_str, 16)?; - if !self.blocks.is_empty() { - for current_block_info in self.blocks.iter_mut() { - if current_block_info.block_number <= block_number { - *current_block_info = BlockInfo { - block_number: current_block_info.block_number, - hash: hash.clone(), - finalized: true, - }; - self.extrinsics.insert(hash.clone(), extrinsics.clone()); - self.logs.insert(hash.clone(), logs.clone()); - } else { - break; - } + for idx in 0..self.blocks.len() { + if self.blocks[idx].finalized { break; } + else if self.blocks[idx].block_number > block_number { continue; } + else { + self.blocks[idx].finalized = true; + self.blocks[idx].hash = hash.clone(); + self.extrinsics.insert(hash.clone(), extrinsics.clone()); + self.logs.insert(hash.clone(), logs.clone()); } } @@ -145,74 +140,85 @@ impl ExplorerBlocks { } fn prepare_block_line_info(&self, current_block: &BlockInfo, width: u16) -> Line { - let block_number_length = self - .max_block_len - .max(current_block.block_number.checked_ilog10().unwrap_or(0) + 1) as usize; + let block_number_length = self + .max_block_len + .max(current_block.block_number.checked_ilog10().unwrap_or(0) + 1) as usize; - let free_space = width - .saturating_sub(block_number_length as u16) - .saturating_sub(Self::TOTAL_OFFSETS); + let free_space = width + .saturating_sub(block_number_length as u16) + .saturating_sub(Self::TOTAL_OFFSETS); - let author = self - .logs - .get(¤t_block.hash) - .map_or(String::from("..."), |maybe_logs| { - self.get_author_from_digest(maybe_logs.to_vec()) - .map_or(String::from("..."), |maybe_author| maybe_author) + let author = self + .logs + .get(¤t_block.hash) + .map_or(String::from("..."), |maybe_logs| { + self.get_author_from_digest(maybe_logs.to_vec()) + .map_or(String::from("..."), |maybe_author| maybe_author) }); - if free_space < Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS { - let len_for_author = free_space * Self::LENGTH_OF_ADDRESS / (Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS); - let len_for_hash = (free_space - len_for_author) / 2; + if free_space < Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS { + let len_for_author = free_space * Self::LENGTH_OF_ADDRESS / (Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS); + let len_for_hash = (free_space - len_for_author) / 2; - let hash_to_print = format!("{}...{}", - ¤t_block.hash[..len_for_hash as usize], - ¤t_block.hash[(Self::LENGTH_OF_BLOCK_HASH - len_for_hash) as usize..]); + let hash_to_print = format!("{}...{}", + ¤t_block.hash[..len_for_hash as usize], + ¤t_block.hash[(Self::LENGTH_OF_BLOCK_HASH - len_for_hash) as usize..]); - if &author == "..." { - Line::raw(format!("{:^left$}| {} | {:^right$}", - current_block.block_number, - hash_to_print, - author, - left=block_number_length, - right=(len_for_author + 2) as usize)) - } else { - Line::raw(format!("{} | {} | {}", - current_block.block_number, - hash_to_print, - format!("{}...", &author[..(len_for_author) as usize]))) - } - } else { - let total_space_used = block_number_length as u16 + Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS; - let margin = (width - total_space_used) as usize / 3; - Line::raw(format!("{:^margin$}|{:^margin$}|{:^margin$}", + if &author == "..." { + Line::raw(format!("{:^left$}| {} | {:^right$}", current_block.block_number, - current_block.hash, - author)) + hash_to_print, + author, + left=block_number_length, + right=(len_for_author + 2) as usize)) + } else { + Line::raw(format!("{} | {} | {}", + current_block.block_number, + hash_to_print, + format!("{}...", &author[..(len_for_author) as usize]))) } + } else { + let total_space_used = block_number_length as u16 + Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS; + let margin = (width - total_space_used) as usize / 3; + Line::raw(format!("{:^margin$}|{:^margin$}|{:^margin$}", + current_block.block_number, + current_block.hash, + author)) + } } fn prepare_block_lines(&mut self, rect: Rect) -> Vec { let width = rect.as_size().width; - let total_length = rect.as_size().height - 2; - let mut total_index = 0; + let total_length = rect.as_size().height as usize - 2; let mut items = Vec::new(); let active_style = self.palette.create_text_style(true); let latest_style = self.palette.create_text_style(false); let finalized_style = Style::new().fg(self.palette.foreground_hover()); - for current_block_info in self.blocks.iter() { - if total_length == total_index { break; } + let start_index = match self.used_block_index { + Some((_, used_block)) if total_length < self.blocks.len() => { + self.blocks + .iter() + .position(|b| b.block_number == used_block) + .unwrap_or_default() + .saturating_add(1) + .saturating_sub(total_length) + }, + _ => 0, + }; - let style = if let Some(used_block_index) = self.used_block_index { - if total_index as usize == used_block_index { active_style } else { latest_style } - } else { - if current_block_info.finalized { finalized_style } else { latest_style } + for (idx, current_block_info) in self.blocks.iter().skip(start_index).enumerate() { + if idx == total_length { break; } + + let style = match self.used_block_index { + Some((_, used_block)) if current_block_info.block_number == used_block => active_style, + _ => { + if current_block_info.finalized { finalized_style } else { latest_style } + } }; items.push(self.prepare_block_line_info(¤t_block_info, width).style(style)); - total_index += 1; } items @@ -229,17 +235,22 @@ impl ExplorerBlocks { fn prepare_ext_lines(&mut self, rect: Rect) -> Vec { let width = rect.as_size().width; - let total_length = rect.as_size().height - 2; - let mut total_index = 0; + let mut total_length = rect.as_size().height - 2; let mut items = Vec::new(); let normal_style = self.palette.create_text_style(false); let active_style = self.palette.create_text_style(true); - if let Some((used_block_hash, _, _)) = &self.used_ext_index { - if let Some(exts) = self.extrinsics.get(used_block_hash) { + if let Some((_, used_block_number)) = self.used_block_index { + let hash = self.blocks + .iter() + .find(|b| b.block_number == used_block_number) + .map(|b| b.hash.clone()) + .unwrap_or_default(); + + if let Some(exts) = self.extrinsics.get(&hash) { for (index, ext) in exts.iter().enumerate() { - if total_length == total_index { break; } + if total_length == 0 { break; } let style = if let Some((_, _, used_ext_index)) = self.used_ext_index { if index == used_ext_index { active_style } else { normal_style } @@ -248,14 +259,31 @@ impl ExplorerBlocks { }; items.push(self.prepare_ext_line_info(0, ext.to_string(), width).style(style)); - total_index += 1; + total_length -= 1; } } + } items } + fn prepare_event_lines(&mut self, rect: Rect) -> Line { + let _width = rect.as_size().width; + + let style = self.palette.create_text_style(false); + + if let Some((hash, _, ext_index)) = &self.used_ext_index { + if let Some(exts) = &self.extrinsics.get(&hash.clone()) { + Line::from(format!("{}", exts.get(*ext_index).unwrap_or(&String::from("nothing here")))).style(style) + } else { + Line::from("nothing here") + } + } else { + Line::from("nothing here") + } + } + fn move_right(&mut self) { let new_index = self.used_paragraph_index + 1; if new_index < 2 { @@ -264,8 +292,10 @@ impl ExplorerBlocks { } fn move_left(&mut self) { - self.used_paragraph_index = self.used_paragraph_index + self.used_paragraph_index = self + .used_paragraph_index .saturating_sub(1); + self.used_ext_index = None; } fn move_down(&mut self) { @@ -285,54 +315,6 @@ impl ExplorerBlocks { } fn move_up_extrinsics(&mut self) { - match &self.used_ext_index { - Some((header, block_index, used_index)) => { - let new_index = used_index + 1; - - let maybe_exts = self.extrinsics.get(&*header); - if maybe_exts.is_none() { return } - let exts = maybe_exts.unwrap(); - - let found = exts - .get(new_index) - .is_some(); - - if found && new_index < exts.len() { - self.used_ext_index = - Some(((&*header).clone(), *block_index, new_index)); - } - }, - None => { - self.used_ext_index = self.blocks - .front() - .map(|block| { - self.extrinsics - .get(&block.hash) - .map(|_| (block.hash.clone(), 0, 0)) - }) - .flatten() - } - } - } - - fn move_up_blocks(&mut self) { - match &self.used_block_index { - Some(used_index) => { - let new_index = used_index + 1; - let maybe_new_extrinsic = self.blocks.get(new_index); - if new_index < self.blocks.len() && maybe_new_extrinsic.is_some() { - self.used_block_index = maybe_new_extrinsic.map(|_| new_index); - } - }, - None => { - self.used_block_index = self.blocks - .front() - .map(|_| 0); - } - } - } - - fn move_down_extrinsics(&mut self) { match &self.used_ext_index { Some((header, block_index, used_index)) => { if *used_index == 0 { return } @@ -365,14 +347,64 @@ impl ExplorerBlocks { } } + fn move_up_blocks(&mut self) { + self.used_block_index = match &self.used_block_index { + Some((used_index, used_block)) => { + Some(self.blocks + .iter() + .enumerate() + .find(|(_, b)| b.block_number == used_block + 1) + .map(|(idx, b)| (idx, b.block_number)) + .unwrap_or((*used_index, *used_block))) + }, + None => self.blocks.front().map(|b| (0usize, b.block_number)), + } + } + + fn move_down_extrinsics(&mut self) { + match &self.used_ext_index { + Some((header, block_index, used_index)) => { + let new_index = used_index + 1; + + let maybe_exts = self.extrinsics.get(&*header); + if maybe_exts.is_none() { return } + let exts = maybe_exts.unwrap(); + + let found = exts + .get(new_index) + .is_some(); + + if found && new_index < exts.len() { + self.used_ext_index = + Some(((&*header).clone(), *block_index, new_index)); + } + }, + None => { + self.used_ext_index = self.blocks + .front() + .map(|block| { + self.extrinsics + .get(&block.hash) + .map(|_| (block.hash.clone(), 0, 0)) + }) + .flatten() + } + } + } + fn move_down_blocks(&mut self) { self.used_block_index = match &self.used_block_index { - Some(used_index) => { - if *used_index == 0 { return } - let new_index = used_index - 1; - self.blocks.get(new_index).map(|_| new_index) + Some((used_index, used_block)) => { + Some(self.blocks + .iter() + .enumerate() + .find(|(_, b)| b.block_number == used_block.saturating_sub(1)) + .map(|(idx, b)| (idx, b.block_number)) + .unwrap_or((*used_index, *used_block))) }, - None => self.blocks.front().map(|_| 0), + None => { + self.blocks.front().map(|b| (0usize, b.block_number)) + } } } @@ -422,12 +454,12 @@ impl ExplorerBlocks { fn prepare_event_paragraph( &mut self, - _place: Rect, + place: Rect, border_style: Color, border_type: BorderType, ) -> Paragraph { let title_style = self.palette.create_title_style(); - Paragraph::new("") + Paragraph::new(self.prepare_event_lines(place)) .block(Block::bordered() .border_style(border_style) .border_type(border_type) @@ -441,16 +473,16 @@ impl ExplorerBlocks { impl Component for ExplorerBlocks { fn handle_key_event(&mut self, key: KeyEvent) -> Result> { match key.code { - KeyCode::Char('k') | KeyCode::Up => self.move_up(), - KeyCode::Char('j') | KeyCode::Down if self.is_active => self.move_down(), - KeyCode::Char('l') | KeyCode::Right if self.is_active => self.move_right(), - KeyCode::Char('h') | KeyCode::Left if self.is_active => self.move_left(), - KeyCode::Esc => { - self.used_block_index = None; - self.used_ext_index = None; - self.used_paragraph_index = 0; - }, - _ => {}, + KeyCode::Char('k') | KeyCode::Up if self.is_active => self.move_up(), + KeyCode::Char('j') | KeyCode::Down if self.is_active => self.move_down(), + KeyCode::Char('l') | KeyCode::Right if self.is_active => self.move_right(), + KeyCode::Char('h') | KeyCode::Left if self.is_active => self.move_left(), + KeyCode::Esc => { + self.used_block_index = None; + self.used_ext_index = None; + self.used_paragraph_index = 0; + }, + _ => {}, }; Ok(None) @@ -461,8 +493,8 @@ impl Component for ExplorerBlocks { Action::SetLatestBlock(hash, block) => self.update_latest_block_info(hash, block.header.number, block.header.digest.logs, block.extrinsics)?, Action::SetFinalizedBlock(hash, block) => self.update_finalized_block_info(hash, block.header.number, block.header.digest.logs, block.extrinsics)?, Action::SetValidators(validators) => self.update_validator_list(validators)?, - Action::SetMode(Mode::Explorer(true)) if !self.is_active => self.set_active()?, - Action::SetMode(Mode::Explorer(false)) if self.is_active => self.unset_active()?, + Action::SetMode(Mode::ExplorerActive) if !self.is_active => self.set_active()?, + Action::SetMode(_) if self.is_active => self.unset_active()?, _ => {} }; Ok(None) @@ -474,6 +506,7 @@ impl Component for ExplorerBlocks { let (border_style_block, border_type_block) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 0); let (border_style_extrinsics, border_type_extrinsics) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 1); + // TODO: never used, revisit let (border_style_event, border_type_event) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 2); frame.render_widget(self.prepare_blocks_paragraph(blocks_place, border_style_block, border_type_block), blocks_place); diff --git a/src/components/explorer/mod.rs b/src/components/explorer/mod.rs index c9cbd23..1fab59e 100644 --- a/src/components/explorer/mod.rs +++ b/src/components/explorer/mod.rs @@ -1,4 +1,5 @@ use color_eyre::Result; +use crossterm::event::KeyEvent; use ratatui::{ layout::{Constraint, Flex, Layout, Rect}, Frame, @@ -44,6 +45,13 @@ impl Default for Explorer { } impl Component for Explorer { + fn handle_key_event(&mut self, key: KeyEvent) -> Result> { + for component in self.components.iter_mut() { + component.handle_key_event(key)?; + } + Ok(None) + } + fn update(&mut self, action: Action) -> Result> { for component in self.components.iter_mut() { component.update(action.clone())?; diff --git a/src/components/menu.rs b/src/components/menu.rs index 705732c..a0a050f 100644 --- a/src/components/menu.rs +++ b/src/components/menu.rs @@ -47,8 +47,8 @@ impl Menu { if let Some(command_tx) = &self.command_tx { match self.current_item_index { - 0 => command_tx.send(Action::SetMode(Mode::Explorer(false)))?, - _ => command_tx.send(Action::SetMode(Mode::Empty(false)))?, + 0 => command_tx.send(Action::SetMode(Mode::Explorer))?, + _ => command_tx.send(Action::SetMode(Mode::Empty))?, } }; Ok(()) @@ -62,8 +62,8 @@ impl Menu { if let Some(command_tx) = &self.command_tx { match self.current_item_index { - 0 => command_tx.send(Action::SetMode(Mode::Explorer(false)))?, - _ => command_tx.send(Action::SetMode(Mode::Empty(false)))?, + 0 => command_tx.send(Action::SetMode(Mode::Explorer))?, + _ => command_tx.send(Action::SetMode(Mode::Empty))?, } }; Ok(()) @@ -73,8 +73,8 @@ impl Menu { self.is_active = true; if let Some(command_tx) = &self.command_tx { match self.current_item_index { - 0 => command_tx.send(Action::SetMode(Mode::Explorer(false)))?, - _ => command_tx.send(Action::SetMode(Mode::Empty(false)))?, + 0 => command_tx.send(Action::SetMode(Mode::Explorer))?, + _ => command_tx.send(Action::SetMode(Mode::Empty))?, } }; Ok(()) @@ -84,8 +84,8 @@ impl Menu { self.is_active = false; if let Some(command_tx) = &self.command_tx { match self.current_item_index { - 0 => command_tx.send(Action::SetMode(Mode::Explorer(true)))?, - _ => command_tx.send(Action::SetMode(Mode::Empty(true)))?, + 0 => command_tx.send(Action::SetMode(Mode::ExplorerActive))?, + _ => command_tx.send(Action::SetMode(Mode::EmptyActive))?, } }; Ok(())