diff --git a/examples/config/default.nuon b/examples/config/default.nuon index a2bc734..2895c62 100644 --- a/examples/config/default.nuon +++ b/examples/config/default.nuon @@ -1,6 +1,7 @@ { show_cell_path: true, # whether or not to show the current cell path above the status bar show_table_header: true, # whether or not to show the table header in "table" layout + show_hints: true, # whether or not to show the hints with keybindings layout: "table", # the layout of the data, either "table" or "compact" margin: 10, # the number of lines to keep between the cursor and the top / bottom number: false, # show line numbers diff --git a/src/config/mod.rs b/src/config/mod.rs index 6e82135..24a7482 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -149,6 +149,7 @@ pub struct Config { pub margin: usize, pub number: bool, pub relativenumber: bool, + pub show_hints: bool, } impl Default for Config { @@ -162,6 +163,7 @@ impl Default for Config { margin: 10, number: false, relativenumber: false, + show_hints: true, colors: ColorConfig { normal: TableRowColorConfig { name: BgFgColorConfig { @@ -297,6 +299,11 @@ impl Config { config.relativenumber = val } } + "show_hints" => { + if let Some(val) = try_bool(value, &["show_hints"])? { + config.show_hints = val + } + } "colors" => { let cell = follow_cell_path(value, &["colors"]).unwrap(); let columns = match &cell { diff --git a/src/ui.rs b/src/ui.rs index 5246a42..11516ab 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -355,7 +355,11 @@ fn render_data(frame: &mut Frame, app: &mut App) { line_numbers.push(i as usize); } - let mut lines = vec![ListItem::new(Line::from("")); 2]; + let mut lines = if app.config.layout == Layout::Compact && !is_a_table { + vec![] + } else { + vec![ListItem::new(Line::from("")); 2] + }; for i in line_numbers { lines.push(ListItem::new(Line::from(Span::styled( format!("{}", i), @@ -363,10 +367,15 @@ fn render_data(frame: &mut Frame, app: &mut App) { )))); } + let mut offset = selected - margin_offset; + if app.config.layout == Layout::Table || is_a_table { + offset += 2; + } + frame.render_stateful_widget( List::new(lines).highlight_style(highlight_line_style), rect_lines_without_bottom_bar, - &mut ListState::default().with_selected(Some(selected - margin_offset + 2)), + &mut ListState::default().with_selected(Some(offset)), ); } @@ -451,11 +460,17 @@ fn render_data(frame: &mut Frame, app: &mut App) { .highlight_style(highlight_style) .highlight_symbol(&config.colors.selected_symbol); + let selected = if app.is_at_bottom() { + None + } else { + Some(selected) + }; + frame.render_stateful_widget( items, rect_without_bottom_bar, &mut ListState::default() - .with_selected(Some(selected)) + .with_selected(selected) .with_offset(margin_offset), ) } @@ -646,69 +661,74 @@ fn render_status_bar(frame: &mut Frame, app: &App) { Mode::Bottom => bg_style.fg(config.colors.status_bar.bottom.foreground), }; - let hints = match app.mode { - Mode::Normal => format!( - "{} to {} | {}{}{}{} to move around | {} to peek | {} to transpose | {} to quit", - repr_key(&config.keybindings.insert), - Mode::Insert, - repr_key(&config.keybindings.navigation.left), - repr_key(&config.keybindings.navigation.down), - repr_key(&config.keybindings.navigation.up), - repr_key(&config.keybindings.navigation.right), - repr_key(&config.keybindings.peek), - repr_key(&config.keybindings.transpose), - repr_key(&config.keybindings.quit), - ), - Mode::Waiting(n) => format!( - "{} to quit | will run next motion {} times", - repr_key(&KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE)), - n - ), - Mode::Insert => format!( - "{} to quit | {}{}{}{} to move the cursor | {}{} to delete characters | {} to confirm", - repr_key(&KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE)), - repr_key(&KeyEvent::new(KeyCode::Left, KeyModifiers::NONE)), - repr_key(&KeyEvent::new(KeyCode::Right, KeyModifiers::NONE)), - repr_key(&KeyEvent::new(KeyCode::Up, KeyModifiers::NONE)), - repr_key(&KeyEvent::new(KeyCode::Down, KeyModifiers::NONE)), - repr_key(&KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE)), - repr_key(&KeyEvent::new(KeyCode::Delete, KeyModifiers::NONE)), - repr_key(&KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)), - ), - Mode::Peeking => format!( - "{} to {} | {} to peek all | {} to peek current view | {} to peek under cursor | {} to peek the cell path", - repr_key(&config.keybindings.normal), - Mode::Normal, - repr_key(&config.keybindings.peeking.all), - repr_key(&config.keybindings.peeking.view), - repr_key(&config.keybindings.peeking.under), - repr_key(&config.keybindings.peeking.cell_path), - ), - Mode::Bottom => format!( - "{} to {} | {} to peek | {} to quit", - repr_key(&config.keybindings.navigation.left), - Mode::Normal, - repr_key(&config.keybindings.peek), - repr_key(&config.keybindings.quit), - ), - }; - - let left = Line::from(Span::styled( - format!(" {} ", app.mode), - style.add_modifier(Modifier::REVERSED), - )); - let right = Line::from(Span::styled(hints, style)); - frame.render_widget( - Paragraph::new(left) - .alignment(Alignment::Left) - .style(bg_style), - bottom_bar_rect, - ); - frame.render_widget( - Paragraph::new(right).alignment(Alignment::Right), + Paragraph::new(Line::from(Span::styled( + format!(" {} ", app.mode), + style.add_modifier(Modifier::REVERSED), + ))) + .alignment(Alignment::Left) + .style(bg_style), bottom_bar_rect, ); + + if app.config.show_hints || matches!(app.mode, Mode::Waiting(..)) { + let hints = match app.mode { + Mode::Normal => format!( + "{} to {} | {}{}{}{} to move around | {} to peek | {} to transpose | {} to quit", + repr_key(&config.keybindings.insert), + Mode::Insert, + repr_key(&config.keybindings.navigation.left), + repr_key(&config.keybindings.navigation.down), + repr_key(&config.keybindings.navigation.up), + repr_key(&config.keybindings.navigation.right), + repr_key(&config.keybindings.peek), + repr_key(&config.keybindings.transpose), + repr_key(&config.keybindings.quit), + ), + Mode::Waiting(n) => { + if app.config.show_hints { + format!( + "{} to quit | will run next motion {} times", + repr_key(&KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE)), + n + ) + } else { + format!("{}", n) + } + }, + Mode::Insert => format!( + "{} to quit | {}{}{}{} to move the cursor | {}{} to delete characters | {} to confirm", + repr_key(&KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE)), + repr_key(&KeyEvent::new(KeyCode::Left, KeyModifiers::NONE)), + repr_key(&KeyEvent::new(KeyCode::Right, KeyModifiers::NONE)), + repr_key(&KeyEvent::new(KeyCode::Up, KeyModifiers::NONE)), + repr_key(&KeyEvent::new(KeyCode::Down, KeyModifiers::NONE)), + repr_key(&KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE)), + repr_key(&KeyEvent::new(KeyCode::Delete, KeyModifiers::NONE)), + repr_key(&KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)), + ), + Mode::Peeking => format!( + "{} to {} | {} to peek all | {} to peek current view | {} to peek under cursor | {} to peek the cell path", + repr_key(&config.keybindings.normal), + Mode::Normal, + repr_key(&config.keybindings.peeking.all), + repr_key(&config.keybindings.peeking.view), + repr_key(&config.keybindings.peeking.under), + repr_key(&config.keybindings.peeking.cell_path), + ), + Mode::Bottom => format!( + "{} to {} | {} to peek | {} to quit", + repr_key(&config.keybindings.navigation.left), + Mode::Normal, + repr_key(&config.keybindings.peek), + repr_key(&config.keybindings.quit), + ), + }; + frame.render_widget( + Paragraph::new(Line::from(Span::styled(hints, style))).alignment(Alignment::Right), + bottom_bar_rect, + ); + } } // TODO: add proper assert error messages