1package jid 2 3import ( 4 "regexp" 5 "strings" 6 7 runewidth "github.com/mattn/go-runewidth" 8) 9 10type QueryInterface interface { 11 Get() []rune 12 Set(query []rune) []rune 13 Insert(query []rune, idx int) []rune 14 Add(query []rune) []rune 15 Delete(i int) []rune 16 Clear() []rune 17 Length() int 18 IndexOffset(int) int 19 GetChar(int) rune 20 GetKeywords() [][]rune 21 GetLastKeyword() []rune 22 PopKeyword() ([]rune, []rune) 23 StringGet() string 24 StringSet(query string) string 25 StringInsert(query string, idx int) string 26 StringAdd(query string) string 27 StringGetKeywords() []string 28 StringGetLastKeyword() string 29 StringPopKeyword() (string, []rune) 30} 31 32type Query struct { 33 query *[]rune 34 complete *[]rune 35} 36 37func NewQuery(query []rune) *Query { 38 q := &Query{ 39 query: &[]rune{}, 40 complete: &[]rune{}, 41 } 42 _ = q.Set(query) 43 return q 44} 45func NewQueryWithString(query string) *Query { 46 return NewQuery([]rune(query)) 47} 48 49func (q *Query) Get() []rune { 50 return *q.query 51} 52 53func (q *Query) GetChar(idx int) rune { 54 var r rune = 0 55 qq := q.Get() 56 if l := len(qq); l > idx && idx >= 0 { 57 r = qq[idx] 58 } 59 return r 60} 61 62func (q *Query) Length() int { 63 return len(q.Get()) 64} 65 66func (q *Query) IndexOffset(i int) int { 67 o := 0 68 if l := q.Length(); i >= l { 69 o = runewidth.StringWidth(q.StringGet()) 70 } else if i >= 0 && i < l { 71 o = runewidth.StringWidth(string(q.Get()[:i])) 72 } 73 return o 74} 75 76func (q *Query) Set(query []rune) []rune { 77 if validate(query) { 78 q.query = &query 79 } 80 return q.Get() 81} 82 83func (q *Query) Insert(query []rune, idx int) []rune { 84 qq := q.Get() 85 if idx == 0 { 86 qq = append(query, qq...) 87 } else if idx > 0 && len(qq) >= idx { 88 _q := make([]rune, idx+len(query)-1) 89 copy(_q, qq[:idx]) 90 qq = append(append(_q, query...), qq[idx:]...) 91 } 92 return q.Set(qq) 93} 94 95func (q *Query) StringInsert(query string, idx int) string { 96 return string(q.Insert([]rune(query), idx)) 97} 98 99func (q *Query) Add(query []rune) []rune { 100 return q.Set(append(q.Get(), query...)) 101} 102 103func (q *Query) Delete(i int) []rune { 104 var d []rune 105 qq := q.Get() 106 lastIdx := len(qq) 107 if i < 0 { 108 if lastIdx+i >= 0 { 109 d = qq[lastIdx+i:] 110 qq = qq[0 : lastIdx+i] 111 } else { 112 d = qq 113 qq = qq[0:0] 114 } 115 } else if i == 0 { 116 d = []rune{} 117 qq = qq[1:] 118 } else if i > 0 && i < lastIdx { 119 d = []rune{qq[i]} 120 qq = append(qq[:i], qq[i+1:]...) 121 } 122 _ = q.Set(qq) 123 return d 124} 125 126func (q *Query) Clear() []rune { 127 return q.Set([]rune("")) 128} 129 130func (q *Query) GetKeywords() [][]rune { 131 qq := *q.query 132 133 if qq == nil || string(qq) == "" { 134 return [][]rune{} 135 } 136 137 splitQuery := []string{} 138 rr := []rune{} 139 enclosed := true 140 ql := len(*q.query) 141 for i := 0; i < ql; i++ { 142 r := qq[i] 143 if ii := i + 1; r == '\\' && ql > ii && qq[ii] == '"' { 144 enclosed = !enclosed 145 i++ // skip '"(double quortation)' 146 continue 147 } 148 if enclosed && r == '.' { 149 splitQuery = append(splitQuery, string(rr)) 150 rr = []rune{} 151 } else { 152 rr = append(rr, r) 153 } 154 } 155 if rr != nil { 156 v := []string{string(rr)} 157 if !enclosed { 158 v = strings.Split(string(rr), ".") 159 } 160 splitQuery = append(splitQuery, v...) 161 } 162 lastIdx := len(splitQuery) - 1 163 164 keywords := [][]rune{} 165 for i, keyword := range splitQuery { 166 if keyword != "" || i == lastIdx { 167 re := regexp.MustCompile(`\[[0-9]*\]?`) 168 matchIndexes := re.FindAllStringIndex(keyword, -1) 169 if len(matchIndexes) < 1 { 170 keywords = append(keywords, []rune(keyword)) 171 } else { 172 if matchIndexes[0][0] > 0 { 173 keywords = append(keywords, []rune(keyword[0:matchIndexes[0][0]])) 174 } 175 for _, matchIndex := range matchIndexes { 176 k := keyword[matchIndex[0]:matchIndex[1]] 177 keywords = append(keywords, []rune(k)) 178 } 179 } 180 } 181 } 182 return keywords 183} 184 185func (q *Query) GetLastKeyword() []rune { 186 keywords := q.GetKeywords() 187 if l := len(keywords); l > 0 { 188 return keywords[l-1] 189 } 190 return []rune("") 191} 192 193func (q *Query) StringGetLastKeyword() string { 194 return string(q.GetLastKeyword()) 195} 196 197func (q *Query) PopKeyword() ([]rune, []rune) { 198 keyword := q.GetLastKeyword() 199 nq := string(keyword) 200 qq := q.StringGet() 201 202 for _, r := range keyword { 203 if r == '.' { 204 nq = `\"` + string(keyword) + `\"` 205 break 206 } 207 } 208 re := regexp.MustCompile(`(\.)?(\\")?` + regexp.QuoteMeta(nq) + "$") 209 210 qq = re.ReplaceAllString(qq, "") 211 212 query := q.Set([]rune(qq)) 213 return keyword, query 214} 215 216func (q *Query) StringGet() string { 217 return string(q.Get()) 218} 219 220func (q *Query) StringSet(query string) string { 221 return string(q.Set([]rune(query))) 222} 223 224func (q *Query) StringAdd(query string) string { 225 return string(q.Add([]rune(query))) 226} 227 228func (q *Query) StringGetKeywords() []string { 229 var keywords []string 230 for _, keyword := range q.GetKeywords() { 231 keywords = append(keywords, string(keyword)) 232 } 233 return keywords 234} 235 236func (q *Query) StringPopKeyword() (string, []rune) { 237 keyword, query := q.PopKeyword() 238 return string(keyword), query 239} 240 241func validate(r []rune) bool { 242 s := string(r) 243 if s == "" { 244 return true 245 } 246 if regexp.MustCompile(`^[^.]`).MatchString(s) { 247 return false 248 } 249 if regexp.MustCompile(`\.{2,}`).MatchString(s) { 250 return false 251 } 252 if regexp.MustCompile(`\[[0-9]*\][^\.\[]`).MatchString(s) { 253 return false 254 } 255 if regexp.MustCompile(`\[{2,}|\]{2,}`).MatchString(s) { 256 return false 257 } 258 if regexp.MustCompile(`.\.\[`).MatchString(s) { 259 return false 260 } 261 return true 262} 263