Skip to content

Commit

Permalink
src/init.rs: Move event handling code to src/utils/ev_handler.rs
Browse files Browse the repository at this point in the history
This change unifies event handling between `static_paging` and
`dynamic_paging` basically DRYing up the code

The change also renames the following items:-
  * `Pager::input_handler` -> `Pager::input_classifier`
  * `input::InputHandler` -> `input::InputClassifier`
  * `input::InputHandler::handle_input` ->
    `input::InputClassifier::classify_input`
  • Loading branch information
AMythicDev committed Aug 22, 2021
1 parent e519543 commit f3ab74c
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 179 deletions.
186 changes: 27 additions & 159 deletions src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
error::AlternateScreenPagingError,
input::InputEvent,
utils::{
draw,
draw, ev_handler,
term::{cleanup, setup},
},
Pager,
Expand All @@ -31,7 +31,6 @@ use std::sync::Arc;
// Setting/cleaning up the terminal can fail and IO to/from the terminal can
// fail.
#[cfg(any(feature = "async_std_lib", feature = "tokio_lib"))]
#[allow(clippy::too_many_lines)]
pub(crate) async fn dynamic_paging(
p: &Arc<Mutex<Pager>>,
) -> std::result::Result<(), AlternateScreenPagingError> {
Expand Down Expand Up @@ -85,7 +84,7 @@ pub(crate) async fn dynamic_paging(
let mut lock = p.lock().await;

// Get the events
let input = lock.input_handler.handle_input(
let input = lock.input_classifier.classify_input(
event::read().map_err(|e| AlternateScreenPagingError::HandleEvent(e.into()))?,
lock.upper_mark,
#[cfg(feature = "search")]
Expand All @@ -94,90 +93,14 @@ pub(crate) async fn dynamic_paging(
lock.message.0.is_some(),
lock.rows,
);
#[allow(clippy::match_same_arms)]
match input {
Some(InputEvent::Exit) => {
lock.exit();
return Ok(cleanup(out, &lock.exit_strategy, true)?);
}
Some(InputEvent::RestorePrompt) => {
lock.message.0 = None;
lock.message.1 = false;
redraw = true;
}
Some(InputEvent::UpdateTermArea(c, r)) => {
lock.cols = c;
lock.rows = r;
lock.readjust_wraps();
redraw = true;
}
Some(InputEvent::UpdateUpperMark(um)) => {
lock.upper_mark = um;
redraw = true;
}
Some(InputEvent::UpdateLineNumber(l)) => {
lock.line_numbers = l;
redraw = true;
}
ev_handler::handle_input(
&input,
&mut lock,
&mut out,
&mut redraw,
#[cfg(feature = "search")]
Some(InputEvent::Search(m)) => {
lock.search_mode = m;
// Fetch the search query
let string = search::fetch_input(&mut out, lock.search_mode, lock.rows)?;
// If the string is not empty, highlight all instances of the
// match and return a vector of match coordinates
if !string.is_empty() {
// If it isn't empty, generate a regex for it
let regex = regex::Regex::new(&string);
if let Ok(r) = regex {
// If the regex is ok, set it as the search_term
lock.search_term = Some(r);
// These calls sets a index of the lines where search matches are
// found and moves the display to the next match after the
// upper_mark
search::set_match_indices(&mut lock);
search::next_match(&mut lock, &mut s_mark);
} else {
// If there's a a error in regex, send a message
lock.send_message("Invalid regular expression. Press Enter")
}
}
redraw = true;
}

#[cfg(feature = "search")]
Some(InputEvent::NextMatch) if lock.search_term.is_some() => {
// Increment the search mark only if it is less than search index's length
// and it is not the last page
if s_mark < lock.search_idx.len().saturating_sub(1)
&& lock.upper_mark + lock.rows < lock.num_lines()
{
s_mark += 1;
}
if lock.search_idx.len() > s_mark {
search::next_match(&mut lock, &mut s_mark);
redraw = true;
}
}

#[cfg(feature = "search")]
Some(InputEvent::PrevMatch) if lock.search_term.is_some() => {
if lock.search_idx.is_empty() {
continue;
}
s_mark = s_mark.saturating_sub(1);
// Get the search line
let y = lock.search_idx[s_mark];
// If it's passed by the user, go back to it
if usize::from(y) <= lock.upper_mark {
lock.upper_mark = y.into();
}
redraw = true;
}
#[cfg(feature = "search")]
Some(_) => continue,
None => continue,
}
&mut s_mark,
)?;
// If redraw is true, then redraw the screen
if redraw {
draw(&mut out, &mut lock)?;
Expand All @@ -186,8 +109,13 @@ pub(crate) async fn dynamic_paging(
}
}

// Runs the pager in dynamic mode for the `Pager`.
//
// ## Errors
//
// Setting/cleaning up the terminal can fail and IO to/from the terminal can
// fail.
#[cfg(feature = "static_output")]
#[allow(clippy::too_many_lines)]
pub(crate) fn static_paging(mut pager: Pager) -> Result<(), AlternateScreenPagingError> {
let mut out = io::stdout();
setup(&out, false, pager.run_no_overflow)?;
Expand All @@ -205,7 +133,7 @@ pub(crate) fn static_paging(mut pager: Pager) -> Result<(), AlternateScreenPagin
.map_err(|e| AlternateScreenPagingError::HandleEvent(e.into()))?
{
// Get the event
let input = pager.input_handler.handle_input(
let input = pager.input_classifier.classify_input(
event::read().map_err(|e| AlternateScreenPagingError::HandleEvent(e.into()))?,
pager.upper_mark,
#[cfg(feature = "search")]
Expand All @@ -214,78 +142,18 @@ pub(crate) fn static_paging(mut pager: Pager) -> Result<(), AlternateScreenPagin
pager.message.0.is_some(),
pager.rows,
);
// Update any data that may have changed
// Do the same steps that we have did in dynamic_paging
#[allow(clippy::match_same_arms)]
match input {
Some(InputEvent::Exit) => {
pager.exit();
return Ok(cleanup(out, &pager.exit_strategy, true)?);
}
Some(InputEvent::RestorePrompt) => {
pager.message.0 = None;
pager.message.1 = false;
redraw = true;
}
Some(InputEvent::UpdateTermArea(c, r)) => {
pager.rows = r;
pager.cols = c;
pager.readjust_wraps();
redraw = true;
}
Some(InputEvent::UpdateUpperMark(um)) => {
pager.upper_mark = um;
redraw = true;
}
Some(InputEvent::UpdateLineNumber(l)) => {
pager.line_numbers = l;
redraw = true;
}
#[cfg(feature = "search")]
Some(InputEvent::Search(m)) => {
pager.search_mode = m;
// Fetch the query
let string = search::fetch_input(&mut out, pager.search_mode, pager.rows)?;
if !string.is_empty() {
let regex = regex::Regex::new(&string);
if let Ok(r) = regex {
pager.search_term = Some(r);
search::set_match_indices(&mut pager);
search::next_match(&mut pager, &mut s_mark);
} else {
pager.send_message("Invalid regular expression. Press Enter")
}
}
redraw = true;
}
// Handle the event
ev_handler::handle_input(
&input,
&mut pager,
&mut out,
&mut redraw,
#[cfg(feature = "search")]
Some(InputEvent::NextMatch) if pager.search_term.is_some() => {
if s_mark < pager.search_idx.len().saturating_sub(1)
&& pager.upper_mark + pager.rows < pager.num_lines()
{
s_mark += 1;
}
if pager.search_idx.len() > s_mark {
search::next_match(&mut pager, &mut s_mark);
redraw = true;
}
}
#[cfg(feature = "search")]
Some(InputEvent::PrevMatch) if pager.search_term.is_some() => {
if pager.search_idx.is_empty() {
continue;
}
s_mark = s_mark.saturating_sub(1);
let y = pager.search_idx[s_mark];
if usize::from(y) <= pager.upper_mark {
pager.upper_mark = y.into();
}
redraw = true;
}
#[cfg(feature = "search")]
Some(_) => continue,
None => continue,
}
&mut s_mark,
)?;

// If there is some input, or messages and redraw is true
// Redraw the screen
if (input.is_some() || pager.message.1) && redraw {
draw(&mut out, &mut pager)?;
}
Expand Down
14 changes: 7 additions & 7 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ pub enum InputEvent {
///
/// # Example
/// ```
/// use minus::{input::{InputEvent, InputHandler}, LineNumbers, Pager};
/// use minus::{input::{InputEvent, InputClassifier}, LineNumbers, Pager};
#[cfg_attr(feature = "search", doc = "use minus::SearchMode;")]
/// use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};
///
/// struct CustomInputHandler;
/// impl InputHandler for CustomInputHandler {
/// fn handle_input(
/// impl InputClassifier for CustomInputHandler {
/// fn classify_input(
/// &self,
/// ev: Event,
/// upper_mark: usize,
Expand Down Expand Up @@ -82,8 +82,8 @@ pub enum InputEvent {
/// );
/// ```
#[allow(clippy::module_name_repetitions)]
pub trait InputHandler {
fn handle_input(
pub trait InputClassifier {
fn classify_input(
&self,
ev: Event,
upper_mark: usize,
Expand All @@ -98,9 +98,9 @@ pub trait InputHandler {
/// making a custom input handler struct and implementing the [`InputHandler`] trait
pub struct DefaultInputHandler;

impl InputHandler for DefaultInputHandler {
impl InputClassifier for DefaultInputHandler {
#[allow(clippy::too_many_lines)]
fn handle_input(
fn classify_input(
&self,
ev: Event,
upper_mark: usize,
Expand Down
12 changes: 6 additions & 6 deletions src/input/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, Mouse
// versions
// TODO: Remove this later in favour of how handle_event should actually be called
fn handle_input(ev: Event, p: &Pager) -> Option<InputEvent> {
p.input_handler.handle_input(
p.input_classifier.classify_input(
ev,
p.upper_mark,
#[cfg(feature = "search")]
Expand Down Expand Up @@ -182,7 +182,7 @@ fn test_restore_prompt() {
// therefore upper_mark += 1
assert_eq!(
Some(InputEvent::RestorePrompt),
pager.input_handler.handle_input(
pager.input_classifier.classify_input(
ev,
pager.upper_mark,
#[cfg(feature = "search")]
Expand Down Expand Up @@ -362,7 +362,7 @@ fn test_search_bindings() {
});

assert_eq!(
pager.input_handler.handle_input(
pager.input_classifier.classify_input(
next_event,
pager.upper_mark,
SearchMode::Forward,
Expand All @@ -373,7 +373,7 @@ fn test_search_bindings() {
Some(InputEvent::NextMatch)
);
assert_eq!(
pager.input_handler.handle_input(
pager.input_classifier.classify_input(
prev_event,
pager.upper_mark,
SearchMode::Forward,
Expand All @@ -397,7 +397,7 @@ fn test_search_bindings() {
});

assert_eq!(
pager.input_handler.handle_input(
pager.input_classifier.classify_input(
next_event,
pager.upper_mark,
SearchMode::Reverse,
Expand All @@ -408,7 +408,7 @@ fn test_search_bindings() {
Some(InputEvent::PrevMatch)
);
assert_eq!(
pager.input_handler.handle_input(
pager.input_classifier.classify_input(
prev_event,
pager.upper_mark,
SearchMode::Reverse,
Expand Down
14 changes: 7 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ pub struct Pager {
// Text which may have come through `push_str` (or `writeln`) that isn't
// flushed to wrap_lines, since it isn't terminated yet with a \n
lines: String,
// The input handler to be called when a input is found
input_handler: Box<dyn input::InputHandler + Sync + Send>,
// The input classifier to be called when a input is found
input_classifier: Box<dyn input::InputClassifier + Sync + Send>,
// Functions to run when the pager quits
exit_callbacks: Vec<Box<dyn FnMut() + Send + Sync + 'static>>,
// The behaviour to do when user quits the program using `q` or `Ctrl+C`
Expand Down Expand Up @@ -235,7 +235,7 @@ impl Pager {
upper_mark: 0,
prompt: wrap_str("minus", cols.into()),
exit_strategy: ExitStrategy::ProcessQuit,
input_handler: Box::new(input::DefaultInputHandler {}),
input_classifier: Box::new(input::DefaultInputHandler {}),
exit_callbacks: Vec::new(),
run_no_overflow: false,
message: (None, false),
Expand Down Expand Up @@ -299,7 +299,7 @@ impl Pager {
pub fn send_message(&mut self, text: impl Into<String>) {
let message = text.into();
if message.contains('\n') {
panic!("Prompt text cannot contain newlines")
panic!("Prompt text cannot contain newlines");
}
self.message.0 = Some(wrap_str(&message, self.cols));
self.message.1 = true;
Expand All @@ -322,7 +322,7 @@ impl Pager {
pub fn set_prompt(&mut self, t: impl Into<String>) {
let prompt = t.into();
if prompt.contains('\n') {
panic!("Prompt text cannot contain newlines")
panic!("Prompt text cannot contain newlines");
}
self.prompt = wrap_str(&prompt, self.cols);
}
Expand Down Expand Up @@ -460,8 +460,8 @@ impl Pager {
///
/// See example in [`InputHandler`](input::InputHandler) on using this
/// function
pub fn set_input_handler(&mut self, handler: Box<dyn input::InputHandler + Send + Sync>) {
self.input_handler = handler;
pub fn set_input_handler(&mut self, handler: Box<dyn input::InputClassifier + Send + Sync>) {
self.input_classifier = handler;
}

// Runs the exit callbacks
Expand Down
Loading

0 comments on commit f3ab74c

Please sign in to comment.