#![cfg_attr(
not(any(
feature = "tokio_lib",
feature = "async_std_lib",
feature = "static_output"
)),
allow(unused_imports),
allow(dead_code)
)]
#![deny(clippy::all)]
#![warn(clippy::pedantic)]
#[cfg(all(feature = "tokio_lib", feature = "async_std_lib"))]
compile_error!("Only tokio, or async_std_lib can be enabled at a time");
mod error;
mod input;
#[cfg(any(feature = "tokio_lib", feature = "async_std_lib"))]
mod rt_wrappers;
mod search;
#[cfg(feature = "static_output")]
mod static_pager;
mod utils;
#[cfg(feature = "search")]
pub use utils::SearchMode;
pub use utils::InputEvent;
pub use input::{DefaultInputHandler, InputHandler};
#[cfg(feature = "static_output")]
pub use static_pager::page_all;
#[cfg(feature = "async_std_lib")]
pub use {async_std::sync::Mutex, rt_wrappers::async_std_wrapper::async_std_updating};
#[cfg(feature = "tokio_lib")]
pub use {rt_wrappers::tokio_wrapper::tokio_updating, tokio::sync::Mutex};
#[cfg(any(feature = "tokio_lib", feature = "async_std_lib"))]
use std::sync::Arc;
pub use error::*;
pub use utils::LineNumbers;
mod init;
#[cfg(any(feature = "tokio_lib", feature = "async_std_lib"))]
pub type PagerMutex = Mutex<Pager>;
pub type ExitCallbacks = Vec<Box<dyn FnMut() + Send + Sync + 'static>>;
pub struct Pager {
pub lines: String,
line_numbers: LineNumbers,
pub prompt: String,
pub data_finished: bool,
pub input_handler: Box<dyn InputHandler + Send + Sync>,
on_exit_callbacks: ExitCallbacks,
exit_strategy: ExitStrategy,
upper_mark: usize,
page_if_havent_overflowed: bool,
searchable: bool,
#[cfg(feature = "search")]
search_term: String,
#[cfg(feature = "search")]
search_lines: String,
}
impl Pager {
#[must_use]
pub fn new() -> Self {
let input_handler = Box::new(DefaultInputHandler {});
Pager {
lines: String::new(),
line_numbers: LineNumbers::Disabled,
upper_mark: 0,
prompt: "minus".to_string(),
exit_strategy: ExitStrategy::ProcessQuit,
data_finished: false,
on_exit_callbacks: Vec::new(),
page_if_havent_overflowed: true,
input_handler,
searchable: true,
#[cfg(feature = "search")]
search_term: String::new(),
#[cfg(feature = "search")]
search_lines: String::new(),
}
}
pub fn set_text(mut self, t: impl Into<String>) -> Self {
self.lines = t.into();
self
}
#[must_use]
pub fn set_line_numbers(mut self, l: LineNumbers) -> Self {
self.line_numbers = l;
self
}
pub fn set_prompt(mut self, t: impl Into<String>) -> Self {
self.prompt = t.into();
self
}
#[must_use]
pub fn set_searchable(mut self, s: bool) -> Self {
self.searchable = s;
self
}
#[must_use]
pub fn set_page_if_havent_overflowed(mut self, p: bool) -> Self {
self.page_if_havent_overflowed = p;
self
}
#[must_use]
#[cfg(any(feature = "tokio_lib", feature = "async_std_lib"))]
pub fn finish(self) -> Arc<PagerMutex> {
Arc::new(PagerMutex::new(self))
}
#[must_use]
pub fn set_exit_strategy(mut self, strategy: ExitStrategy) -> Self {
self.exit_strategy = strategy;
self
}
#[must_use]
pub fn set_input_handler(mut self, input_handler: Box<dyn InputHandler + Send + Sync>) -> Self {
self.input_handler = input_handler;
self
}
pub(crate) fn get_lines(&self) -> String {
#[cfg(feature = "search")]
if self.search_term.is_empty() {
self.lines.clone()
} else {
self.search_lines.clone()
}
#[cfg(not(feature = "search"))]
self.lines.clone()
}
pub fn data_finished(&mut self) {
self.data_finished = true;
}
pub fn exit(&mut self) {
self.run_exit_callbacks();
}
pub fn add_exit_callback<F>(&mut self, callback: F)
where
F: FnMut() + Send + Sync + 'static,
{
self.on_exit_callbacks.push(Box::new(callback));
}
pub fn run_exit_callbacks(&mut self) {
for exit_callback in &mut self.on_exit_callbacks {
exit_callback();
}
}
}
impl std::default::Default for Pager {
fn default() -> Self {
Pager::new()
}
}
#[derive(PartialEq, Clone)]
pub enum ExitStrategy {
ProcessQuit,
PagerQuit,
}