Merge pull request #1 from crystal-linux/development

Development
i18n
Julius Riegel 2 years ago committed by GitHub
commit 5bf076585f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

1
Cargo.lock generated

@ -18,6 +18,7 @@ dependencies = [
"rm_rf",
"serde",
"spinoff",
"strsim",
"textwrap",
"toml",
"ureq",

@ -35,4 +35,5 @@ spinoff = { version = "0.5.2", default-features = false }
textwrap = { version = "0.15.0", features = [ "terminal_size", "smawk" ] }
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 }
crossterm = { version = "0.25.0", default-features = false }
strsim = { version = "0.10.0", default-features = false }

@ -104,7 +104,7 @@ pub struct SearchArgs {
/// The string the package must match in the search
#[clap(required = true)]
pub search: Vec<String>,
pub search: String,
}
#[derive(Default, Debug, Clone, Parser)]

@ -4,8 +4,11 @@
use args::Args;
use clap::{CommandFactory, Parser};
use clap_complete::{Generator, Shell};
use strsim::sorensen_dice;
use internal::commands::ShellCommand;
use internal::error::SilentUnwrap;
use std::env;
use std::fs;
use std::path::Path;
@ -17,6 +20,7 @@ use crate::args::{
use crate::internal::exit_code::AppExitCode;
use crate::internal::utils::pager;
use crate::internal::{detect, init, sort, start_sudoloop, structs::Options};
use crate::operations::ResultsVec;
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
@ -186,7 +190,7 @@ fn cmd_remove(args: RemoveArgs, options: Options) {
fn cmd_search(args: &SearchArgs, options: Options) {
// Initialise variables
let query_string = args.search.join(" ");
let query_string = &args.search;
// Logic for searching
let repo = args.repo || env::args().collect::<Vec<String>>()[1] == "-Ssr";
@ -198,12 +202,12 @@ fn cmd_search(args: &SearchArgs, options: Options) {
let rsp = spinner!("Searching repos for {}", query_string);
// Search repos
let ret = operations::search(&query_string, options);
let ret = operations::search(query_string, options);
rsp.stop_bold("Repo search complete");
ret
} else {
"".to_string()
Vec::new()
};
// Start AUR spinner
@ -219,25 +223,41 @@ fn cmd_search(args: &SearchArgs, options: Options) {
ret
} else {
"".to_string()
Vec::new()
};
let results = repo_results + "\n" + &aur_results;
let mut results = repo_results
.into_iter()
.chain(aur_results)
.collect::<Vec<_>>();
// Sort results by how closely they match the query
results.sort_by(|a, b| {
let a_score = sorensen_dice(&a.name, query_string);
let b_score = sorensen_dice(&b.name, query_string);
b_score
.partial_cmp(&a_score)
.unwrap_or(std::cmp::Ordering::Equal)
});
let results = ResultsVec::from(results);
// Print results either way, so that the user can see the results after they exit `less`
let text = if internal::uwu_enabled() {
uwu!(results.trim())
uwu!(results.to_string())
} else {
results.trim().to_string()
results.to_string()
};
let text = text.trim().to_string();
println!("{}", text);
// Check if results are longer than terminal height
if results.lines().count() > crossterm::terminal::size().unwrap().1 as usize {
if results.0.len() > (crossterm::terminal::size().unwrap().1 / 2).into() {
// If so, paginate results
#[allow(clippy::let_underscore_drop)]
let _ = pager(&results.trim().to_string());
let _ = pager(&results.to_string());
}
}

@ -1,7 +1,7 @@
pub use aur_install::*;
pub use clean::*;
pub use install::*;
pub use search::{aur_search, repo_search as search};
pub use search::{aur_search, repo_search as search, ResultsVec};
pub use uninstall::*;
pub use upgrade::*;

@ -2,6 +2,8 @@ use chrono::{Local, TimeZone};
use colored::Colorize;
use textwrap::wrap;
use std::fmt::Display;
use crate::internal::commands::ShellCommand;
use crate::internal::error::SilentUnwrap;
use crate::internal::exit_code::AppExitCode;
@ -9,47 +11,87 @@ use crate::internal::rpc::rpcsearch;
use crate::{log, Options};
#[allow(clippy::module_name_repetitions)]
/// Searches for packages from the AUR and returns wrapped results
pub fn aur_search(query: &str, options: Options) -> String {
// Query AUR for package info
let res = rpcsearch(query);
// Get verbosity
let verbosity = options.verbosity;
#[derive(Debug, Clone)]
pub struct SearchResult {
pub repo: String,
pub name: String,
pub version: String,
pub ood: Option<usize>,
pub description: String,
}
// Format output
let mut results_vec = vec![];
for package in &res.results {
// Define wrapping options
impl Display for SearchResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 4)
.subsequent_indent(" ");
let result = format!(
let description = wrap(&self.description, opts).join("\n");
write!(
f,
"{}{} {} {}\n {}",
"aur/".cyan().bold(),
package.name.bold(),
package.version.green().bold(),
if package.out_of_date.is_some() {
if self.repo == "aur" {
(self.repo.clone() + "/").bold().cyan()
} else {
(self.repo.clone() + "/").bold().purple()
},
self.name.bold(),
self.version.bold().green(),
if self.ood.is_some() {
format!(
"[out of date: since {}]",
Local
.timestamp(package.out_of_date.unwrap().try_into().unwrap(), 0)
.timestamp(self.ood.unwrap().try_into().unwrap(), 0)
.date_naive()
)
.red()
.bold()
.red()
} else {
"".bold()
},
wrap(
package
.description
.as_ref()
.unwrap_or(&"No description".to_string()),
opts,
)
.join("\n"),
);
description
)
}
}
pub struct ResultsVec(pub Vec<SearchResult>);
impl From<Vec<SearchResult>> for ResultsVec {
fn from(v: Vec<SearchResult>) -> Self {
Self(v)
}
}
impl Display for ResultsVec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for result in &self.0 {
writeln!(f, "{}", result)?;
}
Ok(())
}
}
#[allow(clippy::module_name_repetitions)]
/// Searches for packages from the AUR and returns wrapped results
pub fn aur_search(query: &str, options: Options) -> Vec<SearchResult> {
// 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 {
let result = SearchResult {
repo: "aur".to_string(),
name: package.name.to_string(),
version: package.version.to_string(),
ood: package.out_of_date,
description: package
.description
.as_ref()
.unwrap_or(&"No description".to_string())
.to_string(),
};
results_vec.push(result);
}
@ -61,19 +103,12 @@ pub fn aur_search(query: &str, options: Options) -> String {
);
}
results_vec.join("\n")
}
struct SearchResult {
repo: String,
name: String,
version: String,
description: String,
results_vec
}
#[allow(clippy::module_name_repetitions)]
/// Searches for packages from the repos and returns wrapped results
pub fn repo_search(query: &str, options: Options) -> String {
pub fn repo_search(query: &str, options: Options) -> Vec<SearchResult> {
// Initialise variables
let verbosity = options.verbosity;
@ -91,22 +126,19 @@ pub fn repo_search(query: &str, options: Options) -> String {
// Initialise results vector
let mut results_vec: Vec<SearchResult> = vec![];
let clone = lines.clone().collect::<Vec<&str>>();
if clone.len() == 1 && clone[0].is_empty() {
// If no results, return empty string
return "".to_string();
}
// Iterate over lines
for line in lines {
let parts: Vec<&str> = line.split('\\').collect();
let res = SearchResult {
repo: parts[0].to_string(),
name: parts[1].to_string(),
version: parts[2].to_string(),
description: parts[3].to_string(),
};
results_vec.push(res);
if line.contains('\\') {
let parts: Vec<&str> = line.split('\\').collect();
let res = SearchResult {
repo: parts[0].to_string(),
name: parts[1].to_string(),
version: parts[2].to_string(),
ood: None,
description: parts[3].to_string(),
};
results_vec.push(res);
}
}
if verbosity >= 1 {
@ -117,30 +149,5 @@ pub fn repo_search(query: &str, options: Options) -> String {
);
}
// Format output
let results_vec = results_vec
.into_iter()
.map(|res| {
let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 4)
.subsequent_indent(" ");
format!(
"{}{}{} {}\n {}",
res.repo.purple().bold(),
"/".purple().bold(),
res.name.bold(),
res.version.green().bold(),
if res.description.is_empty() {
"No description".to_string()
} else {
wrap(&res.description, opts).join("\n")
},
)
})
.collect::<Vec<String>>();
if output.trim().is_empty() {
"".to_string()
} else {
results_vec.join("\n")
}
results_vec
}

Loading…
Cancel
Save