diff --git a/CHANGELOG.md b/CHANGELOG.md index ddb717c..a1215f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +main +---- + +- Introduce eval feature + 0.1.1 ----- diff --git a/src/app.rs b/src/app.rs index 916f045..d440834 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,12 +5,13 @@ use crate::dbgp::client::ContextGetResponse; use crate::dbgp::client::ContinuationResponse; use crate::dbgp::client::ContinuationStatus; use crate::dbgp::client::DbgpClient; +use crate::dbgp::client::EvalResponse; use crate::dbgp::client::Property; use crate::event::input::AppEvent; use crate::notification::Notification; use crate::theme::Scheme; use crate::theme::Theme; -use crate::view::eval::draw_properties; +use crate::view::eval::EvalDialog; use crate::view::help::HelpView; use crate::view::layout::LayoutView; use crate::view::listen::ListenView; @@ -21,14 +22,13 @@ use crate::view::View; use crate::workspace::Workspace; use anyhow::Result; use crossterm::event::KeyCode; +use log::error; use log::info; use log::warn; -use log::error; use ratatui::layout::Rect; use ratatui::prelude::CrosstermBackend; use ratatui::style::Color; use ratatui::style::Style; -use ratatui::text::Line; use ratatui::widgets::Block; use ratatui::widgets::Padding; use ratatui::widgets::Paragraph; @@ -66,6 +66,13 @@ impl StackFrame { #[derive(Clone, Debug)] pub struct HistoryEntry { pub stacks: Vec, + pub eval: Option, +} + +#[derive(Clone, Debug)] +pub struct EvalEntry { + pub expr: String, + pub response: EvalResponse, } impl HistoryEntry { @@ -74,7 +81,7 @@ impl HistoryEntry { } fn new() -> Self { let stacks = Vec::new(); - HistoryEntry { stacks } + HistoryEntry { stacks, eval: None } } fn initial(filename: String, source: String) -> HistoryEntry { @@ -88,6 +95,7 @@ impl HistoryEntry { }, context: None, }], + eval: None, } } @@ -178,6 +186,11 @@ pub enum SelectedView { Help, } +#[derive(Debug, Clone)] +pub enum ActiveDialog { + Eval, +} + #[derive(PartialEq)] pub enum ListenStatus { Connected, @@ -189,7 +202,6 @@ impl ListenStatus { pub fn is_connected(&self) -> bool { *self == ListenStatus::Connected } - } pub struct App { @@ -213,6 +225,7 @@ pub struct App { pub view_current: SelectedView, pub focus_view: bool, pub session_view: SessionViewState, + pub active_dialog: Option, pub input_plurality: Vec, pub counter: u16, @@ -251,6 +264,7 @@ impl App { command_input: Input::default(), command_response: None, view_current: SelectedView::Listen, + active_dialog: None, focus_view: false, session_view: SessionViewState::new(), @@ -285,15 +299,10 @@ impl App { loop { match listener.accept().await { - Ok(s) => { - match sender.send(AppEvent::ClientConnected(s.0)).await { - Ok(_) => (), - Err(e) => error!( - "Could not send connection event: {}", - e - ), - } - } + Ok(s) => match sender.send(AppEvent::ClientConnected(s.0)).await { + Ok(_) => (), + Err(e) => error!("Could not send connection event: {}", e), + }, Err(_) => panic!("Could not connect"), } } @@ -311,6 +320,7 @@ impl App { let event = event.unwrap(); if let Err(e) = self.handle_event(terminal, event).await { + self.active_dialog = None; self.notification = Notification::error(e.to_string()); continue; }; @@ -334,7 +344,7 @@ impl App { match event { AppEvent::Tick => { self.tick = self.tick.wrapping_add(1); - }, + } _ => info!("Handling event {:?}", event), }; match event { @@ -374,7 +384,9 @@ impl App { for _ in 0..self.take_motion() { self.history.next(); self.recenter(); - if self.history.is_current() && (self.listening_status == ListenStatus::Connected) { + if self.history.is_current() + && (self.listening_status == ListenStatus::Connected) + { self.sender .send(AppEvent::ChangeSessionViewMode(SessionViewMode::Current)) .await?; @@ -392,10 +404,11 @@ impl App { self.view_current = SelectedView::Listen; self.session_view.mode = SessionViewMode::Current; self.notification = Notification::info("listening for next connection".to_string()) - }, + } AppEvent::ClientConnected(s) => { if self.listening_status != ListenStatus::Listening { - self.notification = Notification::warning("refused incoming connection".to_string()); + self.notification = + Notification::warning("refused incoming connection".to_string()); } else { self.notification = Notification::info("connected".to_string()); let filepath = { @@ -437,7 +450,7 @@ impl App { } AppEvent::ContextDepth(inc) => { let depth = self.context_depth; - self.context_depth = depth.wrapping_add(inc as u16).max(0); + self.context_depth = depth.wrapping_add(inc as u16); self.client .lock() .await @@ -447,11 +460,11 @@ impl App { AppEvent::ContextFilterOpen => { self.session_view.context_filter.show = true; self.focus_view = true; - }, + } AppEvent::ContextSearchClose => { self.session_view.context_filter.show = false; self.focus_view = false; - }, + } AppEvent::ScrollSource(amount) => { self.session_view.source_scroll = apply_scroll( self.session_view.source_scroll, @@ -466,6 +479,13 @@ impl App { self.take_motion() as i16, ); } + AppEvent::ScrollEval(amount) => { + self.session_view.eval_state.scroll = apply_scroll( + self.session_view.eval_state.scroll, + amount, + self.take_motion() as i16, + ); + } AppEvent::ScrollStack(amount) => { self.session_view.stack_scroll = apply_scroll( self.session_view.stack_scroll, @@ -493,29 +513,39 @@ impl App { } AppEvent::PushInputPlurality(char) => self.input_plurality.push(char), AppEvent::EvalStart => { - self.session_view.eval_state.active = true; - self.focus_view = true; - }, + if !self.history.is_current() { + self.notification = + Notification::warning("Cannot eval in history mode".to_string()); + } else { + self.active_dialog = Some(ActiveDialog::Eval); + } + } AppEvent::EvalCancel => { - self.session_view.eval_state.active = false; - self.focus_view = false; - }, + self.active_dialog = None; + } AppEvent::EvalExecute => { - self.session_view.eval_state.active = false; - self.focus_view = false; - let response = self.client - .lock() - .await - .eval( - self.session_view.eval_state.input.to_string(), - self.session_view.stack_depth() - ) - .await?; + if self.session_view.eval_state.input.to_string().is_empty() { + self.session_view.eval_state.response = None; + } else { + let response = self + .client + .lock() + .await + .eval( + self.session_view.eval_state.input.to_string(), + self.session_view.stack_depth(), + ) + .await?; - self.session_view.eval_state.properties = response.properties; - }, + self.session_view.eval_state.response = Some(response); + self.sender.send(AppEvent::Snapshot()).await.unwrap(); + } + self.active_dialog = None; + } AppEvent::Input(key_event) => { - if self.focus_view { + if self.active_dialog.is_some() { + self.send_event_to_current_dialog(event).await; + } else if self.focus_view { // event shandled exclusively by view (e.g. input needs focus) self.send_event_to_current_view(event).await; } else { @@ -535,7 +565,7 @@ impl App { _ => self.send_event_to_current_view(event).await, } } - }, + } _ => self.send_event_to_current_view(event).await, }; @@ -599,6 +629,17 @@ impl App { }); } + async fn send_event_to_current_dialog(&mut self, event: AppEvent) { + if let Some(dialog) = &self.active_dialog { + let subsequent_event = match &dialog { + ActiveDialog::Eval => EvalDialog::handle(self, event), + }; + if let Some(event) = subsequent_event { + self.sender.send(event).await.unwrap() + }; + } + } + // route the event to the currently selected view async fn send_event_to_current_view(&mut self, event: AppEvent) { let subsequent_event = match self.view_current { @@ -629,16 +670,21 @@ impl App { /// capture the current status and push it onto the history stack pub async fn snapshot(&mut self) -> Result<()> { - let stack = { - self.client.lock().await.deref_mut().get_stack().await? - }; + let stack = { self.client.lock().await.deref_mut().get_stack().await? }; let mut entry = HistoryEntry::new(); for (level, frame) in stack.entries.iter().enumerate() { let filename = &frame.filename; let line_no = frame.line; let context = { match (level as u16) < self.stack_max_context_fetch { - true => Some(self.client.lock().await.deref_mut().context_get(level as u16).await?), + true => Some( + self.client + .lock() + .await + .deref_mut() + .context_get(level as u16) + .await?, + ), false => None, } }; @@ -664,6 +710,28 @@ impl App { context, }); } + + // *xdebug* only evalutes expressions on the current stack frame + let eval = if !self.session_view.eval_state.input.to_string().is_empty() { + let response = self + .client + .lock() + .await + .eval( + self.session_view.eval_state.input.to_string(), + self.session_view.stack_depth(), + ) + .await?; + + Some(EvalEntry{ + expr: self.session_view.eval_state.input.to_string(), + response + }) + } else { + None + }; + + entry.eval = eval; self.session_view.reset(); self.history.push(entry); self.recenter(); @@ -702,7 +770,10 @@ impl App { fn recenter(&mut self) { let entry = self.history.current(); - if let Some(entry) = entry { self.session_view.scroll_to_line(entry.source(self.session_view.stack_depth()).line_no) } + if let Some(entry) = entry { + self.session_view + .scroll_to_line(entry.source(self.session_view.stack_depth()).line_no) + } } } diff --git a/src/event/input.rs b/src/event/input.rs index 1ad2dfd..5dbe4be 100644 --- a/src/event/input.rs +++ b/src/event/input.rs @@ -43,6 +43,7 @@ pub enum AppEvent { ScrollSource(Scroll), ScrollContext(Scroll), ScrollStack(Scroll), + ScrollEval(Scroll), ToggleFullscreen, PushInputPlurality(char), ContextDepth(i8), @@ -52,6 +53,7 @@ pub enum AppEvent { Listen, EvalCancel, EvalExecute, + EvalRefresh, EvalStart, } diff --git a/src/theme.rs b/src/theme.rs index bb14cae..65c1051 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -28,13 +28,14 @@ impl Theme { scheme.pane_border_active = Style::default().fg(Solarized::Base01.to_color()).bg(Solarized::Base3.to_color()); - scheme.pane_border_inactive = Style::default().fg(Solarized::Base02.to_color()).bg(Solarized::Base3.to_color()); + scheme.pane_border_inactive = Style::default().fg(Solarized::Base02.to_color()).bg(Solarized::Base2.to_color()); scheme.source_line = scheme.source_line.fg(Solarized::Base00.to_color()); scheme.source_line_highlight = scheme.source_line_highlight.bg(Solarized::Base2.to_color()).fg(Solarized::Base01.to_color()); scheme.widget_mode_debug = scheme.widget_mode_debug.fg(Solarized::Base03.to_color()).bg(Solarized::Base3.to_color()); scheme.widget_mode_history = scheme.widget_mode_debug.bg(Solarized::Base3.to_color()).fg(Solarized::Red.to_color()); + scheme.text_input = Style::default().fg(Solarized::Base0.to_color()); scheme } @@ -62,6 +63,8 @@ impl Theme { widget_mode_debug: Style::default().fg(Solarized::Base1.to_color()).bg(Solarized::Base03.to_color()), widget_mode_history: Style::default().fg(Solarized::Red.to_color()).bg(Solarized::Base03.to_color()), + text_input: Style::default().fg(Solarized::Base2.to_color()), + background: Style::default().bg(Color::Black), cursor: Style::default().bg(Color::White), }, @@ -92,6 +95,7 @@ impl Theme { widget_inactive: Style::default().fg(Color::Black).bg(Color::Yellow), widget_mode_debug: Style::default().bg(Color::Blue), widget_mode_history: Style::default().bg(Color::Red), + text_input: Style::default().fg(Solarized::Red.to_color()).bg(Solarized::Green.to_color()), background: Style::default().bg(Color::Black), cursor: Style::default().bg(Color::White) }, @@ -127,6 +131,7 @@ pub struct Scheme { pub widget_inactive: Style, pub widget_mode_debug: Style, pub widget_mode_history: Style, + pub text_input: Style, pub cursor: Style, } diff --git a/src/view/context.rs b/src/view/context.rs index f88b4b3..a06846a 100644 --- a/src/view/context.rs +++ b/src/view/context.rs @@ -65,10 +65,16 @@ impl View for ContextComponent { let areas = layout.split(area); frame.render_widget(Paragraph::new(Line::from(vec![ - Span::raw(app.session_view.context_filter.input.value()), - Span::raw(" ").style(app.theme().cursor), + Span::raw(app.session_view.context_filter.input.value()).style(app.theme().text_input), ]) ).block(Block::default().borders(Borders::all())), areas[0]); + + if app.session_view.context_filter.show { + let width = area.width.max(3); + let scroll = app.session_view.context_filter.input.visual_scroll(width as usize); + let x = app.session_view.context_filter.input.visual_cursor().max(scroll) - scroll + 1; + frame.set_cursor_position((area.x + x as u16, area.y + 1)); + } let mut filter_path = app.session_view.context_filter.segments().clone(); draw_properties( diff --git a/src/view/eval.rs b/src/view/eval.rs index 8d9cb51..eea398c 100644 --- a/src/view/eval.rs +++ b/src/view/eval.rs @@ -1,74 +1,120 @@ +use super::centered_rect_absolute; use super::View; use crate::app::App; +use crate::dbgp::client::EvalResponse; use crate::dbgp::client::Property; use crate::dbgp::client::PropertyType; use crate::event::input::AppEvent; use crate::theme::Scheme; use crossterm::event::KeyCode; -use ratatui::layout::Constraint; -use ratatui::layout::Layout; use ratatui::layout::Rect; use ratatui::text::Line; use ratatui::text::Span; +use ratatui::widgets::Block; +use ratatui::widgets::Borders; +use ratatui::widgets::Clear; use ratatui::widgets::Paragraph; use ratatui::Frame; use tui_input::backend::crossterm::EventHandler; +use tui_input::Input; pub struct EvalComponent {} +pub struct EvalDialog {} #[derive(Default)] pub struct EvalState { - pub active: bool, - pub properties: Vec, - pub input: tui_input::Input, + pub response: Option, + pub input: Input, + pub scroll: (u16, u16), } impl View for EvalComponent { - fn handle(app: &mut App, event: AppEvent) -> Option { - if app.session_view.eval_state.active { - return match event { - AppEvent::Input(e) => { - if e.code == KeyCode::Esc { - return Some(AppEvent::EvalCancel); - } - if e.code == KeyCode::Enter { - return Some(AppEvent::EvalExecute); - } - app.session_view.eval_state.input.handle_event(&crossterm::event::Event::Key(e)); - return None; - }, - _ => None, + fn handle(_app: &mut App, event: AppEvent) -> Option { + match event { + AppEvent::Scroll(scroll) => Some(AppEvent::ScrollEval(scroll)), + _ => None, + } + } + + fn draw(app: &App, frame: &mut Frame, area: Rect) { + if let Some(entry) = &app.history.current() { + if let Some(eval_entry) = &entry.eval { + if let Some(error) = &eval_entry.response.error { + frame.render_widget( + Paragraph::new(error.message.clone()).style(app.theme().notification_error), + area, + ); + } else { + let mut lines: Vec = Vec::new(); + draw_properties( + &app.theme(), + &eval_entry.response.properties, + &mut lines, + 0, + &mut Vec::new(), + ); + frame.render_widget( + Paragraph::new(lines).scroll(app.session_view.eval_state.scroll), + area, + ); + } } } + } +} + +impl View for EvalDialog { + fn handle(app: &mut App, event: AppEvent) -> Option { match event { - AppEvent::Scroll(scroll) => Some(AppEvent::ScrollContext(scroll)), AppEvent::Input(e) => { - match e.code { - KeyCode::Char('i') => Some(AppEvent::EvalStart), - _ => None, + if e.code == KeyCode::Esc { + return Some(AppEvent::EvalCancel); } - }, + if e.code == KeyCode::Enter { + return Some(AppEvent::EvalExecute); + } + app.session_view + .eval_state + .input + .handle_event(&crossterm::event::Event::Key(e)); + None + } _ => None, } } fn draw(app: &App, frame: &mut Frame, area: Rect) { - let layout = Layout::default() - .constraints([Constraint::Length(1), Constraint::Fill(1)]); - - let areas = layout.split(area); - frame.render_widget(Paragraph::new(Line::from(vec![ - Span::raw(app.session_view.eval_state.input.value()), - Span::raw(" ").style(app.theme().cursor), - ]) - ), areas[0]); - - let mut lines: Vec = Vec::new(); - draw_properties(&app.theme(), &app.session_view.eval_state.properties, &mut lines, 0, &mut Vec::new()); + let darea = centered_rect_absolute(area.width - 10, 3, area); + frame.render_widget(Clear, darea); frame.render_widget( - Paragraph::new(lines).scroll(app.session_view.context_scroll), - areas[1], + Paragraph::new(Line::from(vec![Span::raw( + app.session_view.eval_state.input.value(), + ) + .style(app.theme().text_input)])) + .block( + Block::default() + .borders(Borders::all()) + .title("Enter expression") + .style(app.theme().pane_border_active), + ), + darea, ); + + let width = darea.width.max(3); + let scroll = app + .session_view + .eval_state + .input + .visual_scroll(width as usize); + let x = app + .session_view + .eval_state + .input + .visual_cursor() + .max(scroll) + - scroll + + 1; + frame.set_cursor_position((darea.x + x as u16, darea.y + 1)); } } @@ -138,10 +184,9 @@ pub fn render_value<'a>(theme: &Scheme, property: &Property) -> Span<'a> { #[cfg(test)] mod test { + use super::*; use crate::theme::Theme; use anyhow::Result; - - use super::*; use pretty_assertions::assert_eq; #[test] @@ -164,27 +209,23 @@ mod test { let mut prop1 = Property::default(); let mut prop2 = Property::default(); prop2.name = "bar".to_string(); - prop1.children = vec![ - prop2 - ]; + prop1.children = vec![prop2]; prop1.name = "foo".to_string(); draw_properties( &Theme::SolarizedDark.scheme(), - &vec![ - prop1 - ], + &vec![prop1], &mut lines, 0, &mut Vec::new(), ); - assert_eq!(vec![ - "foo string = \"\"{", - " bar string = \"\"", - "}", - ], lines.iter().map( - |l| { l.to_string()} - ).collect::>()); + assert_eq!( + vec!["foo string = \"\"{", " bar string = \"\"", "}",], + lines + .iter() + .map(|l| { l.to_string() }) + .collect::>() + ); Ok(()) } @@ -196,35 +237,27 @@ mod test { let prop3 = Property::default(); prop2.name = "bar".to_string(); - prop1.children = vec![ - prop2 - ]; + prop1.children = vec![prop2]; prop1.name = "foo".to_string(); // segments are reversed - let filter = &mut vec![ - "bar", - "foo", - ]; + let filter = &mut vec!["bar", "foo"]; draw_properties( &Theme::SolarizedDark.scheme(), - &vec![ - prop1, - prop3 - ], + &vec![prop1, prop3], &mut lines, 0, filter, ); - assert_eq!(vec![ - "foo string = \"\"{", - " bar string = \"\"", - "}", - ], lines.iter().map( - |l| { l.to_string()} - ).collect::>()); + assert_eq!( + vec!["foo string = \"\"{", " bar string = \"\"", "}",], + lines + .iter() + .map(|l| { l.to_string() }) + .collect::>() + ); Ok(()) } diff --git a/src/view/help.rs b/src/view/help.rs index 315665b..546301d 100644 --- a/src/view/help.rs +++ b/src/view/help.rs @@ -39,6 +39,7 @@ Key mappings (prefix with number to repeat): [N] step over [p] previous (switches to history mode if in current mode) [o] step out +[e] enter an expression [j] scroll down [J] scroll down 10 [k] scroll up diff --git a/src/view/layout.rs b/src/view/layout.rs index 7c659dc..4094a4f 100644 --- a/src/view/layout.rs +++ b/src/view/layout.rs @@ -1,8 +1,10 @@ +use super::eval::EvalDialog; use super::help::HelpView; use super::listen::ListenView; use super::session::SessionView; use super::session::SessionViewMode; use super::View; +use crate::app::ActiveDialog; use crate::app::App; use crate::app::ListenStatus; use crate::app::SelectedView; @@ -42,6 +44,12 @@ impl View for LayoutView { SelectedView::Session => SessionView::draw(app, f, rows[1]), SelectedView::Help => HelpView::draw(app, f, rows[1]), } + + if let Some(dialog) = &app.active_dialog { + match &dialog { + ActiveDialog::Eval => EvalDialog::draw(app, f, area), + } + } } } diff --git a/src/view/mod.rs b/src/view/mod.rs index baaa9a5..17435e9 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -42,3 +42,12 @@ pub struct Pane { } pub type Scroll = (i16,i16); + +pub fn centered_rect_absolute(width: u16, height: u16, r: Rect) -> Rect { + Rect::new( + (r.width.saturating_sub(width)) / 2, + (r.height.saturating_sub(height)) / 2, + width.min(r.width), + height.min(r.height), + ) +} diff --git a/src/view/session.rs b/src/view/session.rs index 1abf31f..d58de95 100644 --- a/src/view/session.rs +++ b/src/view/session.rs @@ -1,6 +1,3 @@ -use std::cell::Cell; -use std::rc::Rc; - use super::context::ContextComponent; use super::eval::EvalComponent; use super::eval::EvalState; @@ -22,6 +19,8 @@ use ratatui::widgets::Block; use ratatui::widgets::Borders; use ratatui::widgets::Clear; use ratatui::Frame; +use std::cell::Cell; +use std::rc::Rc; pub struct SessionView {} @@ -42,6 +41,7 @@ impl View for SessionView { KeyCode::BackTab => return Some(AppEvent::PreviousPane), KeyCode::Enter => return Some(AppEvent::ToggleFullscreen), KeyCode::Char(char) => match char { + 'e' => return Some(AppEvent::EvalStart), 'j' => return Some(AppEvent::Scroll((1, 0))), 'k' => return Some(AppEvent::Scroll((-1, 0))), 'J' => return Some(AppEvent::Scroll((10, 0))), @@ -132,13 +132,13 @@ impl View for SessionView { } fn split_rows(panes: &Vec<&Pane>, area: Rect) -> Rc<[Rect]> { - let mut vertical_constraints = Vec::new(); + let mut vertical_constraints = Vec::new(); - for pane in panes { - vertical_constraints.push(pane.constraint); - } + for pane in panes { + vertical_constraints.push(pane.constraint); + } - Layout::vertical(vertical_constraints).split(area) + Layout::vertical(vertical_constraints).split(area) } fn delegate_event_to_pane(app: &mut App, event: AppEvent) -> Option { @@ -167,7 +167,7 @@ fn build_pane_widget(frame: &mut Frame, app: &App, pane: &Pane, area: Rect, inde "Context(fetch-depth: {}, filter: {})", app.context_depth, match app.session_view.context_filter.input.value() { - "" => "n/a", + "" => "press 'f' to filter with dot notation", _ => app.session_view.context_filter.input.value(), } ), @@ -180,7 +180,17 @@ fn build_pane_widget(frame: &mut Frame, app: &App, pane: &Pane, area: Rect, inde }, app.stack_max_context_fetch, ), - ComponentType::Eval => "Eval".to_string(), + ComponentType::Eval => match app.history.current() { + Some(entry) => format!( + "Eval: {}", + if let Some(eval) = &entry.eval { + eval.expr.clone() + } else { + "Press 'e' to enter an expression".to_string() + } + ), + None => "".to_string(), + }, }) .style(match index == app.session_view.current_pane { true => app.theme().pane_border_active, @@ -252,22 +262,22 @@ impl SessionViewState { panes: vec![ Pane { component_type: ComponentType::Source, - constraint: ratatui::layout::Constraint::Percentage(50), + constraint: ratatui::layout::Constraint::Percentage(75), col: Col::Left, }, Pane { component_type: ComponentType::Eval, - constraint: ratatui::layout::Constraint::Percentage(50), + constraint: ratatui::layout::Constraint::Fill(1), col: Col::Left, }, Pane { component_type: ComponentType::Context, - constraint: ratatui::layout::Constraint::Percentage(70), + constraint: ratatui::layout::Constraint::Percentage(75), col: Col::Right, }, Pane { component_type: ComponentType::Stack, - constraint: ratatui::layout::Constraint::Min(1), + constraint: ratatui::layout::Constraint::Fill(1), col: Col::Right, }, ], @@ -275,7 +285,7 @@ impl SessionViewState { } fn panes(&self, col: Col) -> Vec<&Pane> { - self.panes.iter().filter(|p|p.col == col).collect() + self.panes.iter().filter(|p| p.col == col).collect() } pub fn next_pane(&mut self) { @@ -333,9 +343,21 @@ mod test { pub fn panes() { let mut view = SessionViewState::default(); view.panes = vec![ - Pane{ component_type: ComponentType::Stack, constraint: Constraint::Min(1), col: Col::Left}, - Pane{ component_type: ComponentType::Stack, constraint: Constraint::Min(1), col: Col::Right}, - Pane{ component_type: ComponentType::Stack, constraint: Constraint::Min(1), col: Col::Right} + Pane { + component_type: ComponentType::Stack, + constraint: Constraint::Min(1), + col: Col::Left, + }, + Pane { + component_type: ComponentType::Stack, + constraint: Constraint::Min(1), + col: Col::Right, + }, + Pane { + component_type: ComponentType::Stack, + constraint: Constraint::Min(1), + col: Col::Right, + }, ]; assert_eq!(1, view.panes(Col::Left).len()); assert_eq!(2, view.panes(Col::Right).len()); @@ -344,11 +366,11 @@ mod test { #[test] pub fn scroll_to_line() { let mut view = SessionViewState::default(); - view.source_area = Cell::new(Rect{ + view.source_area = Cell::new(Rect { x: 0, y: 0, width: 0, - height: 10, + height: 10, }); view.scroll_to_line(0);