mirror of
https://github.com/orhun/systeroid
synced 2024-07-23 19:34:58 +00:00
feat(tui): support scrolling the kernel documentation
This commit is contained in:
parent
afb9b9430e
commit
9a61d9fbc8
|
@ -1,7 +1,6 @@
|
|||
use crate::command::Command;
|
||||
use crate::error::Result;
|
||||
use crate::options::CopyOption;
|
||||
use crate::options::Direction;
|
||||
use crate::options::{CopyOption, Direction, ScrollArea};
|
||||
use crate::widgets::StatefulTable;
|
||||
#[cfg(feature = "clipboard")]
|
||||
use copypasta_ext::{display::DisplayServer, prelude::ClipboardProvider};
|
||||
|
@ -26,6 +25,8 @@ pub struct App<'a> {
|
|||
pub input_cursor: u16,
|
||||
/// Whether if the search mode is enabled.
|
||||
pub search_mode: bool,
|
||||
/// Y-scroll offset for the documentation.
|
||||
pub docs_scroll_amount: u16,
|
||||
/// Entries of the options menu.
|
||||
pub options: Option<StatefulTable<&'a str>>,
|
||||
/// List of sysctl parameters.
|
||||
|
@ -46,6 +47,7 @@ impl<'a> App<'a> {
|
|||
input_time: None,
|
||||
input_cursor: 0,
|
||||
search_mode: false,
|
||||
docs_scroll_amount: 0,
|
||||
options: None,
|
||||
parameter_list: StatefulTable::default(),
|
||||
#[cfg(feature = "clipboard")]
|
||||
|
@ -92,6 +94,7 @@ impl<'a> App<'a> {
|
|||
} else {
|
||||
self.parameter_list = StatefulTable::with_items(self.sysctl.parameters.clone());
|
||||
}
|
||||
self.docs_scroll_amount = 0;
|
||||
}
|
||||
|
||||
/// Copies the selected entry to the clipboard.
|
||||
|
@ -165,10 +168,11 @@ impl<'a> App<'a> {
|
|||
self.input_time = Some(Instant::now());
|
||||
}
|
||||
}
|
||||
Command::Scroll(Direction::Up, amount) => {
|
||||
Command::Scroll(ScrollArea::List, Direction::Up, amount) => {
|
||||
if let Some(options) = self.options.as_mut() {
|
||||
options.previous();
|
||||
} else if !self.parameter_list.items.is_empty() {
|
||||
self.docs_scroll_amount = 0;
|
||||
if amount == 1 {
|
||||
self.parameter_list.previous();
|
||||
} else {
|
||||
|
@ -182,10 +186,11 @@ impl<'a> App<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Command::Scroll(Direction::Down, amount) => {
|
||||
Command::Scroll(ScrollArea::List, Direction::Down, amount) => {
|
||||
if let Some(options) = self.options.as_mut() {
|
||||
options.next();
|
||||
} else if !self.parameter_list.items.is_empty() {
|
||||
self.docs_scroll_amount = 0;
|
||||
if amount == 1 {
|
||||
self.parameter_list.next();
|
||||
} else {
|
||||
|
@ -204,16 +209,31 @@ impl<'a> App<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Command::Scroll(Direction::Top, _) => {
|
||||
Command::Scroll(ScrollArea::List, Direction::Top, _) => {
|
||||
if !self.parameter_list.items.is_empty() {
|
||||
self.docs_scroll_amount = 0;
|
||||
self.parameter_list.state.select(Some(0));
|
||||
}
|
||||
}
|
||||
Command::Scroll(Direction::Bottom, _) => {
|
||||
Command::Scroll(ScrollArea::List, Direction::Bottom, _) => {
|
||||
if let Some(last_index) = self.parameter_list.items.len().checked_sub(1) {
|
||||
self.docs_scroll_amount = 0;
|
||||
self.parameter_list.state.select(Some(last_index))
|
||||
}
|
||||
}
|
||||
Command::Scroll(ScrollArea::Documentation, Direction::Up, amount) => {
|
||||
self.docs_scroll_amount = self
|
||||
.docs_scroll_amount
|
||||
.checked_sub(amount.into())
|
||||
.unwrap_or_default();
|
||||
}
|
||||
Command::Scroll(ScrollArea::Documentation, Direction::Down, amount) => {
|
||||
self.docs_scroll_amount = self
|
||||
.docs_scroll_amount
|
||||
.checked_add(amount.into())
|
||||
.unwrap_or(self.docs_scroll_amount);
|
||||
}
|
||||
Command::Scroll(_, _, _) => {}
|
||||
Command::EnableSearch => {
|
||||
if self.input_time.is_some() {
|
||||
self.input_time = None;
|
||||
|
@ -312,6 +332,7 @@ impl<'a> App<'a> {
|
|||
Command::Refresh => {
|
||||
self.input = None;
|
||||
self.sysctl.parameters = Sysctl::init(self.sysctl.config.clone())?.parameters;
|
||||
self.docs_scroll_amount = 0;
|
||||
self.parameter_list.items.iter_mut().for_each(|parameter| {
|
||||
if let Some(param) = self
|
||||
.sysctl
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::options::Direction;
|
||||
use crate::options::{Direction, ScrollArea};
|
||||
use std::str::FromStr;
|
||||
use termion::event::Key;
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub enum Command {
|
|||
/// Set the value of a parameter.
|
||||
Set(String, String),
|
||||
/// Scroll the widget.
|
||||
Scroll(Direction, u8),
|
||||
Scroll(ScrollArea, Direction, u8),
|
||||
/// Move cursor to right/left.
|
||||
MoveCursor(u8),
|
||||
/// Enable the search mode.
|
||||
|
@ -48,13 +48,10 @@ impl FromStr for Command {
|
|||
values.next().ok_or(())?.to_string(),
|
||||
))
|
||||
} else if s.starts_with("scroll") {
|
||||
let mut values = s.trim_start_matches("scroll").trim().split_whitespace();
|
||||
Ok(Command::Scroll(
|
||||
Direction::try_from(
|
||||
*(s.split_whitespace()
|
||||
.collect::<Vec<&str>>()
|
||||
.get(1)
|
||||
.ok_or(())?),
|
||||
)?,
|
||||
ScrollArea::try_from(values.next().ok_or(())?)?,
|
||||
Direction::try_from(values.next().ok_or(())?)?,
|
||||
1,
|
||||
))
|
||||
} else {
|
||||
|
@ -81,12 +78,14 @@ impl Command {
|
|||
}
|
||||
} else {
|
||||
match key {
|
||||
Key::Up => Command::Scroll(Direction::Up, 1),
|
||||
Key::Down => Command::Scroll(Direction::Down, 1),
|
||||
Key::PageUp => Command::Scroll(Direction::Up, 4),
|
||||
Key::PageDown => Command::Scroll(Direction::Down, 4),
|
||||
Key::Char('t') => Command::Scroll(Direction::Top, 0),
|
||||
Key::Char('b') => Command::Scroll(Direction::Bottom, 0),
|
||||
Key::Up => Command::Scroll(ScrollArea::List, Direction::Up, 1),
|
||||
Key::Down => Command::Scroll(ScrollArea::List, Direction::Down, 1),
|
||||
Key::PageUp => Command::Scroll(ScrollArea::List, Direction::Up, 4),
|
||||
Key::PageDown => Command::Scroll(ScrollArea::List, Direction::Down, 4),
|
||||
Key::Char('t') => Command::Scroll(ScrollArea::List, Direction::Top, 0),
|
||||
Key::Char('b') => Command::Scroll(ScrollArea::List, Direction::Bottom, 0),
|
||||
Key::Left => Command::Scroll(ScrollArea::Documentation, Direction::Up, 1),
|
||||
Key::Right => Command::Scroll(ScrollArea::Documentation, Direction::Down, 1),
|
||||
Key::Char(':') => Command::UpdateInput(' '),
|
||||
Key::Char('/') => Command::EnableSearch,
|
||||
Key::Char('\n') => Command::Select,
|
||||
|
|
|
@ -54,3 +54,9 @@ generate_option!(
|
|||
Top => "top",
|
||||
Bottom => "bottom",
|
||||
);
|
||||
|
||||
generate_option!(
|
||||
ScrollArea,
|
||||
List => "list",
|
||||
Documentation => "documentation",
|
||||
);
|
||||
|
|
|
@ -38,7 +38,12 @@ pub fn render<B: Backend>(frame: &mut Frame<'_, B>, app: &mut App) {
|
|||
}
|
||||
}
|
||||
if let Some(documentation) = documentation {
|
||||
render_parameter_documentation(frame, chunks[1], documentation);
|
||||
render_parameter_documentation(
|
||||
frame,
|
||||
chunks[1],
|
||||
documentation,
|
||||
&mut app.docs_scroll_amount,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +226,18 @@ fn render_parameter_documentation<B: Backend>(
|
|||
frame: &mut Frame<'_, B>,
|
||||
rect: Rect,
|
||||
documentation: String,
|
||||
scroll_amount: &mut u16,
|
||||
) {
|
||||
match (documentation.lines().count() * 2).checked_sub(rect.height.into()) {
|
||||
Some(scroll_overflow) => {
|
||||
if scroll_overflow < (*scroll_amount).into() {
|
||||
*scroll_amount = scroll_overflow as u16;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
*scroll_amount = scroll_amount.checked_sub(1).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
frame.render_widget(
|
||||
Paragraph::new(documentation)
|
||||
.block(
|
||||
|
@ -236,6 +252,7 @@ fn render_parameter_documentation<B: Backend>(
|
|||
.border_type(BorderType::Rounded)
|
||||
.style(Style::default().bg(Color::Black)),
|
||||
)
|
||||
.scroll((*scroll_amount, 0))
|
||||
.wrap(Wrap { trim: false }),
|
||||
rect,
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue