From 53dd9639328d50aab92e5f316cc4b0c19760a2ca Mon Sep 17 00:00:00 2001 From: Michal S Date: Tue, 23 Aug 2022 11:54:04 +0100 Subject: [PATCH] Added paging to results if they are larger than terminal size --- Cargo.lock | 119 ++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/internal/utils.rs | 22 ++++++- src/main.rs | 39 +++++++---- src/operations/aur_install.rs | 8 +-- src/operations/search.rs | 48 +++++++++----- 6 files changed, 201 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe08d1f..1c2440b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,7 @@ dependencies = [ "clap", "clap_complete", "colored", + "crossterm", "libc", "mimalloc", "native-tls", @@ -183,6 +184,31 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi", +] + [[package]] name = "fastrand" version = "1.8.0" @@ -317,6 +343,16 @@ dependencies = [ "cc", ] +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.17" @@ -353,6 +389,18 @@ dependencies = [ "libmimalloc-sys", ] +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + [[package]] name = "native-tls" version = "0.2.10" @@ -447,6 +495,29 @@ version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -576,6 +647,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "security-framework" version = "2.7.0" @@ -630,6 +707,42 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + [[package]] name = "smawk" version = "0.3.1" @@ -845,6 +958,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.82" diff --git a/Cargo.toml b/Cargo.toml index a244fa4..18a8519 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,3 +35,4 @@ spinoff = { version = "0.5.2", default-features = false } textwrap = { version = "0.15.0", features = [ "terminal_size" ] } chrono = { version = "0.4.22", default-features = false, features = [ "clock", "std", "wasmbind" ] } toml = { version = "0.5.9", default-features = false } +crossterm = { version = "0.25.0", default-features = false } \ No newline at end of file diff --git a/src/internal/utils.rs b/src/internal/utils.rs index f254d8a..f4796ae 100644 --- a/src/internal/utils.rs +++ b/src/internal/utils.rs @@ -1,7 +1,7 @@ use colored::Colorize; use std::io; use std::io::Write; -use std::process::exit; +use std::process::{exit, Command, Stdio}; use std::time::UNIX_EPOCH; use textwrap::{termwidth, wrap}; @@ -193,3 +193,23 @@ pub fn spinner_fn(text: String) -> Spinner { ), } } + +pub fn pager(text: &String) -> io::Result<()> { + let text = if internal::uwu_enabled() { + uwu!(text) + } else { + text.to_string() + }; + + let mut pager = Command::new("less") + .arg("-R") + .stdin(Stdio::piped()) + .spawn()?; + + let stdin = pager.stdin.as_mut().unwrap(); + stdin.write_all(text.as_bytes())?; + stdin.flush()?; + pager.wait()?; + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 97bd132..061b2d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use crate::args::{ GenCompArgs, InfoArgs, InstallArgs, Operation, QueryArgs, RemoveArgs, SearchArgs, UpgradeArgs, }; use crate::internal::exit_code::AppExitCode; +use crate::internal::utils::pager; use crate::internal::{detect, init, sort, start_sudoloop, structs::Options}; use clap_complete::{Generator, Shell}; @@ -153,26 +154,38 @@ fn cmd_remove(args: RemoveArgs, options: Options) { fn cmd_search(args: &SearchArgs, options: Options) { // Initialise variables let query_string = args.search.join(" "); - if args.aur { - info!("Searching AUR for {}", &query_string); - // Search AUR - operations::aur_search(&query_string, options); - } - if args.repo { + // Logic for searching + let both = !args.repo && !args.aur; + let repo = args.repo || both; + let aur = args.aur || both; + + let repo_results = if repo { info!("Searching repos for {}", &query_string); // Search repos - operations::search(&query_string, options); - } + operations::search(&query_string, options) + } else { + "".to_string() + }; + let aur_results = if aur { + info!("Searching AUR for {}", &query_string); - if !args.aur && !args.repo { - info!("Searching AUR and repos for {}", &query_string); + // Search AUR + operations::aur_search(&query_string, options) + } else { + "".to_string() + }; - // If no search type specified, search both - operations::search(&query_string, options); - operations::aur_search(&query_string, options); + // Check if results are longer than terminal height + let results = repo_results + &aur_results; + if results.lines().count() > crossterm::terminal::size().unwrap().1 as usize { + // If so, paginate results + #[allow(clippy::let_underscore_drop)] + let _ = pager(&results); } + // Print results either way, so that the user can see the results after they exit `less` + println!("{}", results); } fn cmd_query(args: &QueryArgs) { diff --git a/src/operations/aur_install.rs b/src/operations/aur_install.rs index 37f61f8..866376e 100644 --- a/src/operations/aur_install.rs +++ b/src/operations/aur_install.rs @@ -121,7 +121,7 @@ fn finish(cachedir: &str, pkg: &str, options: &Options) { // Get a list of packages in cachedir if dirs.len() > 1 { - info!("Installing all AUR dependencies"); + info!("Installing AUR dependencies for {}", pkg); let cmd = std::process::Command::new("bash") .args(&[ "-cO", @@ -139,7 +139,7 @@ fn finish(cachedir: &str, pkg: &str, options: &Options) { .wait() .unwrap(); if cmd.success() { - info!("All AUR dependencies installed"); + info!("All AUR dependencies for package {} installed", pkg); } else { crash!( AppExitCode::PacmanError, @@ -181,7 +181,7 @@ fn clone(pkg: &String, pkgcache: &str, options: &Options) { if dirs.contains(pkg) { // Enter directory and git pull if options.verbosity > 1 { - info!("Updating cached PKGBUILD for {}", pkg); + log!("Updating cached PKGBUILD for {}", pkg); } info!("Updating cached package source"); set_current_dir(Path::new(&format!( @@ -209,7 +209,7 @@ fn clone(pkg: &String, pkgcache: &str, options: &Options) { .silent_unwrap(AppExitCode::GitError); // Enter directory and `makepkg -o` to fetch sources if options.verbosity > 1 { - info!("Fetching sources for {}", pkg); + log!("Fetching sources for {}", pkg); } info!("Fetching sources"); set_current_dir(Path::new(&format!( diff --git a/src/operations/search.rs b/src/operations/search.rs index 2cdcdd6..87d7a9c 100644 --- a/src/operations/search.rs +++ b/src/operations/search.rs @@ -2,22 +2,27 @@ use crate::internal::commands::ShellCommand; use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; use crate::internal::rpc::rpcsearch; -use crate::{info, log, Options}; +use crate::{log, Options}; use chrono::{Local, TimeZone}; use colored::Colorize; +use textwrap::{termwidth, wrap}; #[allow(clippy::module_name_repetitions)] -pub fn aur_search(query: &str, options: Options) { - // Initialise variables - let verbosity = options.verbosity; - +pub fn aur_search(query: &str, options: Options) -> String { // Query AUR for package info let res = rpcsearch(query); + // Get verbosity + let verbosity = options.verbosity; + // Format output + let mut results_vec = vec![]; for package in &res.results { - println!( + // Define wrapping options + let opts = textwrap::Options::new(termwidth()).subsequent_indent(" "); + + let result = format!( "{}{} {} {}\n {}", "aur/".cyan().bold(), package.name.bold(), @@ -34,24 +39,31 @@ pub fn aur_search(query: &str, options: Options) { } else { "".bold() }, - package - .description - .as_ref() - .unwrap_or(&"No description".to_string()) + wrap( + package + .description + .as_ref() + .unwrap_or(&"No description".to_string()), + opts + ) + .join("\n"), ); + results_vec.push(result); } - if res.results.is_empty() { - info!("No results found for \"{}\" in the AUR", query); + if verbosity > 1 { + log!( + "Found {} results for \"{}\" in the AUR", + res.results.len(), + query + ); } - if verbosity >= 1 { - log!("Found {} resuls for \"{}\" in AUR", res.resultcount, query); - } + results_vec.join("\n") } #[allow(clippy::module_name_repetitions)] -pub fn repo_search(query: &str, options: Options) { +pub fn repo_search(query: &str, options: Options) -> String { // Initialise variables let verbosity = options.verbosity; @@ -72,8 +84,8 @@ pub fn repo_search(query: &str, options: Options) { } if output.trim().is_empty() { - info!("No results found for \"{}\" in the repos", query); + "".to_string() } else { - println!("{}", output.trim()); + output.trim().to_string() } }