intrange.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package intrange
  2. import (
  3. "strconv"
  4. "strings"
  5. "unicode"
  6. "github.com/Jguer/yay/v10/pkg/stringset"
  7. )
  8. // IntRange stores a max and min amount for range
  9. type IntRange struct {
  10. min int
  11. max int
  12. }
  13. // IntRanges is a slice of IntRange
  14. type IntRanges []IntRange
  15. func makeIntRange(min, max int) IntRange {
  16. return IntRange{
  17. min,
  18. max,
  19. }
  20. }
  21. // Get returns true if the argument n is included in the closed range
  22. // between min and max
  23. func (r IntRange) Get(n int) bool {
  24. return n >= r.min && n <= r.max
  25. }
  26. // Get returns true if the argument n is included in the closed range
  27. // between min and max of any of the provided IntRanges
  28. func (rs IntRanges) Get(n int) bool {
  29. for _, r := range rs {
  30. if r.Get(n) {
  31. return true
  32. }
  33. }
  34. return false
  35. }
  36. // Min returns min value between a and b
  37. func Min(a, b int) int {
  38. if a < b {
  39. return a
  40. }
  41. return b
  42. }
  43. // Max returns max value between a and b
  44. func Max(a, b int) int {
  45. if a < b {
  46. return b
  47. }
  48. return a
  49. }
  50. // ParseNumberMenu parses input for number menus split by spaces or commas
  51. // supports individual selection: 1 2 3 4
  52. // supports range selections: 1-4 10-20
  53. // supports negation: ^1 ^1-4
  54. //
  55. // include and excule holds numbers that should be added and should not be added
  56. // respectively. other holds anything that can't be parsed as an int. This is
  57. // intended to allow words inside of number menus. e.g. 'all' 'none' 'abort'
  58. // of course the implementation is up to the caller, this function mearley parses
  59. // the input and organizes it
  60. func ParseNumberMenu(input string) (include, exclude IntRanges,
  61. otherInclude, otherExclude stringset.StringSet) {
  62. include = make(IntRanges, 0)
  63. exclude = make(IntRanges, 0)
  64. otherInclude = make(stringset.StringSet)
  65. otherExclude = make(stringset.StringSet)
  66. words := strings.FieldsFunc(input, func(c rune) bool {
  67. return unicode.IsSpace(c) || c == ','
  68. })
  69. for _, word := range words {
  70. var num1 int
  71. var num2 int
  72. var err error
  73. invert := false
  74. other := otherInclude
  75. if word[0] == '^' {
  76. invert = true
  77. other = otherExclude
  78. word = word[1:]
  79. }
  80. ranges := strings.SplitN(word, "-", 2)
  81. num1, err = strconv.Atoi(ranges[0])
  82. if err != nil {
  83. other.Set(strings.ToLower(word))
  84. continue
  85. }
  86. if len(ranges) == 2 {
  87. num2, err = strconv.Atoi(ranges[1])
  88. if err != nil {
  89. other.Set(strings.ToLower(word))
  90. continue
  91. }
  92. } else {
  93. num2 = num1
  94. }
  95. mi := Min(num1, num2)
  96. ma := Max(num1, num2)
  97. if !invert {
  98. include = append(include, makeIntRange(mi, ma))
  99. } else {
  100. exclude = append(exclude, makeIntRange(mi, ma))
  101. }
  102. }
  103. return include, exclude, otherInclude, otherExclude
  104. }