1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
//! Does all the magic to have you potentially long output piped through the //! external pager. Similar to what git does for its output. //! //! # Quick Start //! //! ```rust //! extern crate pager; //! use pager::Pager; //! fn main() { //! Pager::new().setup(); //! // The rest of your program goes here //! } //! ``` //! //! Under the hood this forks the current process, connects child' stdout //! to parent's stdin, and then replaces the parent with the pager of choice //! (environment variable PAGER). The child just continues as normal. If PAGER //! environment variable is not present `Pager` probes current PATH for `more`. //! If found it is used as a default pager. //! //! You can control pager to a limited degree. For example you can change the //! environment variable used for finding pager executable. //! //! ```rust //! extern crate pager; //! use pager::Pager; //! fn main() { //! Pager::env("MY_PAGER").setup(); //! // The rest of your program goes here //! } //! ``` //! //! If no suitable pager found `setup()` does nothing and your executable keeps //! running as usual. `Pager` cleans after itself and doesn't leak resources in //! case of setup failure. //! //! If you need to disable pager altogether set environment variable `NOPAGER` and `Pager::setup()` //! will skip initialization. The host application will continue as normal. `Pager::ok()` will //! reflect the fact that no Pager is active. extern crate libc; mod utils; use std::ffi::OsString; const DEFAULT_PAGER_ENV: &'static str = "PAGER"; #[derive(Debug, Default)] pub struct Pager { pager: Option<OsString>, env: String, ok: bool, } impl Pager { /// Creates new instance of pager with default settings pub fn new() -> Self { Pager::env(DEFAULT_PAGER_ENV) } /// Creates new instance of pager using `env` environment variable instead of PAGER pub fn env(env: &str) -> Self { let pager = utils::find_pager(env); Pager { pager: pager, env: env.into(), ok: true, } } /// Gives quick assessment of successful Pager setup pub fn ok(&self) -> bool { self.ok } /// Initiates Pager framework and sets up all the necessary environment for sending standard /// output to the activated pager. pub fn setup(&mut self) { if let Some(ref pager) = self.pager { let (pager_stdin, main_stdout) = utils::pipe(); let pid = utils::fork(); match pid { -1 => { // Fork failed utils::close(pager_stdin); utils::close(main_stdout); self.ok = false } 0 => { // I am child utils::dup2(main_stdout, libc::STDOUT_FILENO); utils::close(pager_stdin); } _ => { // I am parent utils::dup2(pager_stdin, libc::STDIN_FILENO); utils::close(main_stdout); utils::execvp(pager); } } } } }