feat(tui): add search via capture bar and absorb flow
Search uses existing parse grammar ?prefix — type `?query #tag` in capture bar to filter entities client-side. Substring match on body+title+description with AND tag filtering. Esc clears search. Absorb via m key on fluid entities — opens source picker showing all other entities, enter merges source into target. Uses existing store.Absorb() backend.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/lerko/nib/internal/db"
|
||||
)
|
||||
|
||||
func filterEntities(entities []*db.Entity, query string, tags []string) []*db.Entity {
|
||||
if query == "" && len(tags) == 0 {
|
||||
return entities
|
||||
}
|
||||
|
||||
query = strings.ToLower(query)
|
||||
lowerTags := make([]string, len(tags))
|
||||
for i, t := range tags {
|
||||
lowerTags[i] = strings.ToLower(t)
|
||||
}
|
||||
|
||||
var result []*db.Entity
|
||||
for _, e := range entities {
|
||||
if !matchesSearch(e, query, lowerTags) {
|
||||
continue
|
||||
}
|
||||
result = append(result, e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func matchesSearch(e *db.Entity, query string, tags []string) bool {
|
||||
if len(tags) > 0 {
|
||||
eTags := make(map[string]bool, len(e.Tags))
|
||||
for _, t := range e.Tags {
|
||||
eTags[strings.ToLower(t)] = true
|
||||
}
|
||||
for _, t := range tags {
|
||||
if !eTags[t] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if query == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
haystack := strings.ToLower(e.Body)
|
||||
if e.Title != nil {
|
||||
haystack += " " + strings.ToLower(*e.Title)
|
||||
}
|
||||
if e.Description != nil {
|
||||
haystack += " " + strings.ToLower(*e.Description)
|
||||
}
|
||||
return strings.Contains(haystack, query)
|
||||
}
|
||||
Reference in New Issue
Block a user