mirror of
https://github.com/Jguer/yay.git
synced 2025-10-03 00:04:05 -04:00
Add parseNumberMenu()
This function is designed to replace the existing number menu in upcoming commits.
This commit is contained in:
parent
f0f20269a0
commit
6988537552
105
parser.go
105
parser.go
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -38,6 +39,20 @@ func (set stringSet) toSlice() []string {
|
||||
return slice
|
||||
}
|
||||
|
||||
func SliceToStringSet(in []string) stringSet {
|
||||
set := make(stringSet)
|
||||
|
||||
for _, v := range in {
|
||||
set.set(v)
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func makeStringSet(in ...string) stringSet {
|
||||
return SliceToStringSet(in)
|
||||
}
|
||||
|
||||
// Parses command line arguments in a way we can interact with programmatically but
|
||||
// also in a way that can easily be passed to pacman later on.
|
||||
type arguments struct {
|
||||
@ -554,3 +569,93 @@ func (parser *arguments) parseCommandLine() (err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type intRange struct {
|
||||
min int
|
||||
max int
|
||||
}
|
||||
|
||||
func makeIntRange(min, max int) intRange {
|
||||
return intRange{
|
||||
min,
|
||||
max,
|
||||
}
|
||||
}
|
||||
|
||||
func (r intRange) get(n int) bool {
|
||||
return n >= r.min && n <= r.max
|
||||
}
|
||||
|
||||
type intRanges []intRange
|
||||
|
||||
func (rs intRanges) get(n int) bool {
|
||||
for _, r := range rs {
|
||||
if r.get(n) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//parses input for number menus
|
||||
//supports individual selection: 1 2 3 4
|
||||
//supports range selections: 1-4 10-20
|
||||
//supports negation: ^1 ^1-4
|
||||
//
|
||||
//include and excule holds numbers that should be added and should not be added
|
||||
//respectively. other holds anythign that can't be parsed as an int. This is
|
||||
//intended to allow words inside of number menus. e.g. 'all' 'none' 'abort'
|
||||
//of course the implementation is up to the caller, this function mearley parses
|
||||
//the input and organizes it
|
||||
func parseNumberMenu(input string) (intRanges, intRanges, stringSet, stringSet) {
|
||||
include := make(intRanges, 0, 0)
|
||||
exclude := make(intRanges, 0, 0)
|
||||
otherInclude := make(stringSet)
|
||||
otherExclude := make(stringSet)
|
||||
|
||||
words := strings.Fields(input)
|
||||
|
||||
for _, word := range words {
|
||||
var num1 int
|
||||
var num2 int
|
||||
var err error
|
||||
invert := false
|
||||
other := otherInclude
|
||||
|
||||
if word[0] == '^' {
|
||||
invert = true
|
||||
other = otherExclude
|
||||
word = word[1:]
|
||||
}
|
||||
|
||||
ranges := strings.SplitN(word, "-", 2)
|
||||
|
||||
num1, err = strconv.Atoi(ranges[0])
|
||||
if err != nil {
|
||||
other.set(strings.ToLower(word))
|
||||
continue
|
||||
}
|
||||
|
||||
if len(ranges) == 2 {
|
||||
num2, err = strconv.Atoi(ranges[1])
|
||||
if err != nil {
|
||||
other.set(strings.ToLower(word))
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
num2 = num1
|
||||
}
|
||||
|
||||
mi := min(num1, num2)
|
||||
ma := max(num1, num2)
|
||||
|
||||
if !invert {
|
||||
include = append(include, makeIntRange(mi, ma))
|
||||
} else {
|
||||
exclude = append(exclude, makeIntRange(mi, ma))
|
||||
}
|
||||
}
|
||||
|
||||
return include, exclude, otherInclude, otherExclude
|
||||
}
|
||||
|
99
parser_test.go
Normal file
99
parser_test.go
Normal file
@ -0,0 +1,99 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func intRangesEqual(a, b intRanges) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for n := range a {
|
||||
r1 := a[n]
|
||||
r2 := b[n]
|
||||
|
||||
if r1.min != r1.min || r1.max != r2.max {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func stringSetEqual(a, b stringSet) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for n := range a {
|
||||
if !b.get(n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func TestParseNumberMenu(t *testing.T) {
|
||||
type result struct {
|
||||
Include intRanges
|
||||
Exclude intRanges
|
||||
OtherInclude stringSet
|
||||
OtherExclude stringSet
|
||||
}
|
||||
|
||||
inputs := []string{
|
||||
"1 2 3 4 5",
|
||||
"1-10 5-15",
|
||||
"10-5 90-85",
|
||||
"1 ^2 ^10-5 99 ^40-38 ^123 60-62",
|
||||
"abort all none",
|
||||
"a-b ^a-b ^abort",
|
||||
"1\t2 3 4\t\t \t 5",
|
||||
"",
|
||||
" \t ",
|
||||
"A B C D E",
|
||||
}
|
||||
|
||||
expected := []result{
|
||||
{intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, intRanges{}, make(stringSet), make(stringSet)},
|
||||
{intRanges{makeIntRange(1, 10), makeIntRange(5, 15)}, intRanges{}, make(stringSet), make(stringSet)},
|
||||
{intRanges{makeIntRange(5, 10), makeIntRange(85, 90)}, intRanges{}, make(stringSet), make(stringSet)},
|
||||
{intRanges{makeIntRange(1, 1), makeIntRange(99, 99), makeIntRange(60, 62)}, intRanges{makeIntRange(2, 2), makeIntRange(5, 10), makeIntRange(38, 40), makeIntRange(123, 123)}, make(stringSet), make(stringSet)},
|
||||
{intRanges{}, intRanges{}, makeStringSet("abort", "all", "none"), make(stringSet)},
|
||||
{intRanges{}, intRanges{}, makeStringSet("a-b"), makeStringSet("abort", "a-b")},
|
||||
{intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, intRanges{}, make(stringSet), make(stringSet)},
|
||||
{intRanges{}, intRanges{}, make(stringSet), make(stringSet)},
|
||||
{intRanges{}, intRanges{}, make(stringSet), make(stringSet)},
|
||||
{intRanges{}, intRanges{}, makeStringSet("a", "b", "c", "d", "e"), make(stringSet)},
|
||||
}
|
||||
|
||||
for n, in := range inputs {
|
||||
res := expected[n]
|
||||
include, exclude, otherInclude, otherExclude := parseNumberMenu(in)
|
||||
|
||||
if !intRangesEqual(include, res.Include) ||
|
||||
!intRangesEqual(exclude, res.Exclude) ||
|
||||
!stringSetEqual(otherInclude, res.OtherInclude) ||
|
||||
!stringSetEqual(otherExclude, res.OtherExclude) {
|
||||
|
||||
t.Fatalf("Test %d Failed: Expected: include=%+v exclude=%+v otherInclude=%+v otherExclude=%+v got include=%+v excluive=%+v otherInclude=%+v otherExclude=%+v",
|
||||
n+1, res.Include, res.Exclude, res.OtherInclude, res.OtherExclude, include, exclude, otherInclude, otherExclude)
|
||||
}
|
||||
}
|
||||
}
|
7
query.go
7
query.go
@ -317,6 +317,13 @@ func min(a, b int) int {
|
||||
return b
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a < b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Queries the aur for information about specified packages.
|
||||
// All packages should be queried in a single rpc request except when the number
|
||||
// of packages exceeds the number set in config.RequestSplitN.
|
||||
|
@ -60,7 +60,7 @@ func TestParsing(t *testing.T) {
|
||||
branch != compare.Branch ||
|
||||
!isEqual(protocols, compare.Protocols) {
|
||||
|
||||
t.Fatalf("Expected url=%+v branch=%+v protocols=%+v\ngot url=%+v branch=%+v protocols=%+v", url, branch, protocols, compare.URL, compare.Branch, compare.Protocols)
|
||||
t.Fatalf("Test %d failed: Expected: url=%+v branch=%+v protocols=%+v\ngot url=%+v branch=%+v protocols=%+v", n+1, url, branch, protocols, compare.URL, compare.Branch, compare.Protocols)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user