Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 38 additions & 14 deletions command-signatures/json/paru.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,6 @@
"args": {
"name": "glob"
}
},
{
"name": [
"-i",
"--install"
],
"description": "Install package as well as building"
}
],
"isVariadic": true,
Expand Down Expand Up @@ -179,13 +172,6 @@
"args": {
"name": "glob"
}
},
{
"name": [
"-i",
"--install"
],
"description": "Install package as well as building"
}
],
"isVariadic": true,
Expand Down Expand Up @@ -1249,6 +1235,44 @@
"description": "Upgrade the chroot"
}
]
},
{
"name": "-B",
"description": "Build a PKGBUILD in a given directory",
"options": [
{
"name": [
"-i",
"--install"
],
"description": "Install package as well as building"
}
],
"isVariadic": true,
"args": {
"name": "dir",
"template": "folders",
"isOptional": true
}
},
{
"name": "--build",
"description": "Build a PKGBUILD in a given directory",
"options": [
{
"name": [
"-i",
"--install"
],
"description": "Install package as well as building"
}
],
"isVariadic": true,
"args": {
"name": "dir",
"template": "folders",
"isOptional": true
}
}
],
"options": [
Expand Down
32 changes: 18 additions & 14 deletions command-signatures/json/yay.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,6 @@
"args": {
"name": "glob"
}
},
{
"name": [
"-i",
"--install"
],
"description": "Install package as well as building"
}
],
"isVariadic": true,
Expand Down Expand Up @@ -179,13 +172,6 @@
"args": {
"name": "glob"
}
},
{
"name": [
"-i",
"--install"
],
"description": "Install package as well as building"
}
],
"isVariadic": true,
Expand Down Expand Up @@ -1247,6 +1233,15 @@
{
"name": "-B",
"description": "Build from a local PKGBUILD",
"options": [
{
"name": [
"-i",
"--install"
],
"description": "Build and install a PKGBUILD in a given directory"
}
],
"args": {
"name": "dir",
"template": "folders",
Expand All @@ -1256,6 +1251,15 @@
{
"name": "--build",
"description": "Build from a local PKGBUILD",
"options": [
{
"name": [
"-i",
"--install"
],
"description": "Build and install a PKGBUILD in a given directory"
}
],
"args": {
"name": "dir",
"template": "folders",
Expand Down
102 changes: 87 additions & 15 deletions command-signatures/src/generators/paru.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,106 @@
use warp_completion_metadata::{
CommandBuilder, CommandSignatureGenerators, Generator, GeneratorResultsCollector, Suggestion,
CommandBuilder, CommandSignatureGenerators, Generator, GeneratorResults,
GeneratorResultsCollector, Suggestion,
};

use super::common::{pacman_installed_packages_generator, pacman_pkg_tar_files_in_cwd_generator};

/// Parses the space-separated `name source` lines produced by `paru -P/--show -c/--complete`,
/// where `source` is either `AUR` or the (sync or local pkgbuild) repository the package
/// belongs to (e.g. `core`, `extra`). See `repo_list`/`pkgbuild_list`/`aur_list` in paru's
/// `src/completion.rs`, which write `pkg.name()`, `b" "`, `db.name()`, `b"\n"` and
/// `line`, `b" AUR\n"` respectively.
fn parse_package_list(output: &str) -> GeneratorResults {
output
.lines()
.filter_map(|line| {
let mut fields = line.splitn(2, ' ');
let name = fields.next()?.trim();
if name.is_empty() {
return None;
}
Some(
match fields
.next()
.map(str::trim)
.filter(|source| !source.is_empty())
{
Some(source) => Suggestion::with_description(name, source),
None => Suggestion::new(name),
},
)
})
.collect_unordered_results()
}

pub fn generator() -> CommandSignatureGenerators {
CommandSignatureGenerators::new("paru")
.add_generator(
"list_installed_packages",
pacman_installed_packages_generator(),
)
.add_generator(
// `paru -P/--show -c/--complete` prints AUR and repo package names, one per line,
// for use by shell completion scripts. This is how paru's own official fish
// completions list packages for `-S`/`sync`, unlike plain pacman, which only knows
// about the sync repositories and not the AUR.
"list_all_packages",
Generator::script(CommandBuilder::single_command("paru -Pc"), |output| {
let mut targets = Vec::new();
for package_name in output.lines() {
targets.push(Suggestion::with_description(
package_name.to_string(),
"package",
));
}
targets.into_iter().collect_unordered_results()
}),
Generator::script(
CommandBuilder::single_command("paru -Pc"),
parse_package_list,
),
)
.add_generator(
"list_all_pkg_tar_files_in_cwd",
pacman_pkg_tar_files_in_cwd_generator(),
)
}

#[cfg(test)]
mod tests {
use super::parse_package_list;

#[test]
fn test_parses_aur_and_repo_packages() {
let output = "btrfs-progs core\nyay-bin AUR\n";
let results = parse_package_list(output);

let suggestions: Vec<(&str, Option<&str>)> = results
.suggestions
.iter()
.map(|suggestion| {
(
suggestion.exact_string.as_str(),
suggestion.description.as_deref(),
)
})
.collect();

assert_eq!(
suggestions,
vec![("btrfs-progs", Some("core")), ("yay-bin", Some("AUR"))]
);
}

#[test]
fn test_handles_single_field_line_without_panicking() {
// A line with no space-separated source shouldn't panic, and should still surface the
// package name (just without a description).
let output = "btrfs-progs\n";
let results = parse_package_list(output);

assert_eq!(results.suggestions.len(), 1);
assert_eq!(results.suggestions[0].exact_string, "btrfs-progs");
assert_eq!(results.suggestions[0].description, None);
}

#[test]
fn test_skips_blank_lines_and_lines_with_no_name() {
let output = "\n \nbtrfs-progs core\n";
let results = parse_package_list(output);

assert_eq!(results.suggestions.len(), 1);
assert_eq!(results.suggestions[0].exact_string, "btrfs-progs");
}

#[test]
fn test_empty_output() {
assert!(parse_package_list("").suggestions.is_empty());
}
}
101 changes: 86 additions & 15 deletions command-signatures/src/generators/yay.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,105 @@
use warp_completion_metadata::{
CommandBuilder, CommandSignatureGenerators, Generator, GeneratorResultsCollector, Suggestion,
CommandBuilder, CommandSignatureGenerators, Generator, GeneratorResults,
GeneratorResultsCollector, Suggestion,
};

use super::common::{pacman_installed_packages_generator, pacman_pkg_tar_files_in_cwd_generator};

/// Parses the tab-separated `name\tsource` lines produced by `yay -P/--show -c/--complete`,
/// where `source` is either `AUR` or the sync repository the package belongs to (e.g. `core`,
/// `extra`). See `createAURList`/`createRepoList` in yay's `pkg/completion/completion.go`, which
/// write `pkgName+"\tAUR\n"` and `pkg.Name()+"\t"+pkg.DB().Name()+"\n"` respectively.
fn parse_package_list(output: &str) -> GeneratorResults {
output
.lines()
.filter_map(|line| {
let mut fields = line.splitn(2, '\t');
let name = fields.next()?.trim();
if name.is_empty() {
return None;
}
Some(
match fields
.next()
.map(str::trim)
.filter(|source| !source.is_empty())
{
Some(source) => Suggestion::with_description(name, source),
None => Suggestion::new(name),
},
)
})
.collect_unordered_results()
}

pub fn generator() -> CommandSignatureGenerators {
CommandSignatureGenerators::new("yay")
.add_generator(
"list_installed_packages",
pacman_installed_packages_generator(),
)
.add_generator(
// `yay -P/--show -c/--complete` prints AUR and repo package names, one per line,
// for use by shell completion scripts. This is how yay's own official fish/bash/zsh
// completions list packages for `-S`/`sync`, unlike plain pacman, which only knows
// about the sync repositories and not the AUR.
"list_all_packages",
Generator::script(CommandBuilder::single_command("yay -Pc"), |output| {
let mut targets = Vec::new();
for package_name in output.lines() {
targets.push(Suggestion::with_description(
package_name.to_string(),
"package",
));
}
targets.into_iter().collect_unordered_results()
}),
Generator::script(
CommandBuilder::single_command("yay -Pc"),
parse_package_list,
),
)
.add_generator(
"list_all_pkg_tar_files_in_cwd",
pacman_pkg_tar_files_in_cwd_generator(),
)
}

#[cfg(test)]
mod tests {
use super::parse_package_list;

#[test]
fn test_parses_aur_and_repo_packages() {
let output = "btrfs-progs\tcore\nyay-bin\tAUR\n";
let results = parse_package_list(output);

let suggestions: Vec<(&str, Option<&str>)> = results
.suggestions
.iter()
.map(|suggestion| {
(
suggestion.exact_string.as_str(),
suggestion.description.as_deref(),
)
})
.collect();

assert_eq!(
suggestions,
vec![("btrfs-progs", Some("core")), ("yay-bin", Some("AUR"))]
);
}

#[test]
fn test_handles_single_field_line_without_panicking() {
// A line with no tab-separated source shouldn't panic, and should still surface the
// package name (just without a description).
let output = "btrfs-progs\n";
let results = parse_package_list(output);

assert_eq!(results.suggestions.len(), 1);
assert_eq!(results.suggestions[0].exact_string, "btrfs-progs");
assert_eq!(results.suggestions[0].description, None);
}

#[test]
fn test_skips_blank_lines_and_lines_with_no_name() {
let output = "\n\t\nbtrfs-progs\tcore\n";
let results = parse_package_list(output);

assert_eq!(results.suggestions.len(), 1);
assert_eq!(results.suggestions[0].exact_string, "btrfs-progs");
}

#[test]
fn test_empty_output() {
assert!(parse_package_list("").suggestions.is_empty());
}
}
Loading