136 lines
2.8 KiB
Go
136 lines
2.8 KiB
Go
package model
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/derailed/k9s/internal/dao"
|
|
"github.com/sahilm/fuzzy"
|
|
)
|
|
|
|
// Filterable represents an entity that can be filtered.
|
|
type Filterable interface {
|
|
Filter(string)
|
|
ClearFilter()
|
|
}
|
|
|
|
// Textable represents a text resource.
|
|
type Textable interface {
|
|
Peek() []string
|
|
SetText(string)
|
|
AddListener(TextListener)
|
|
RemoveListener(TextListener)
|
|
}
|
|
|
|
// TextListener represents a text model listener.
|
|
type TextListener interface {
|
|
// TextChanged notifies the model changed.
|
|
TextChanged([]string)
|
|
|
|
// TextFiltered notifies when the filter changed.
|
|
TextFiltered([]string, fuzzy.Matches)
|
|
}
|
|
|
|
// Text represents a text model.
|
|
type Text struct {
|
|
lines []string
|
|
listeners []TextListener
|
|
query string
|
|
}
|
|
|
|
// NewText returns a new model.
|
|
func NewText() *Text {
|
|
return &Text{}
|
|
}
|
|
|
|
// Peek returns the current model state.
|
|
func (t *Text) Peek() []string {
|
|
return t.lines
|
|
}
|
|
|
|
// ClearFilter clear out filter.
|
|
func (t *Text) ClearFilter() {
|
|
t.query = ""
|
|
t.filterChanged(t.lines)
|
|
}
|
|
|
|
// Filter filters out the text.
|
|
func (t *Text) Filter(q string) {
|
|
t.query = q
|
|
t.filterChanged(t.lines)
|
|
}
|
|
|
|
// SetText sets the current model content.
|
|
func (t *Text) SetText(buff string) {
|
|
t.lines = strings.Split(buff, "\n")
|
|
t.fireTextChanged(t.lines)
|
|
}
|
|
|
|
// AddListener adds a new model listener.
|
|
func (t *Text) AddListener(listener TextListener) {
|
|
t.listeners = append(t.listeners, listener)
|
|
}
|
|
|
|
// RemoveListener delete a listener from the list.
|
|
func (t *Text) RemoveListener(listener TextListener) {
|
|
victim := -1
|
|
for i, lis := range t.listeners {
|
|
if lis == listener {
|
|
victim = i
|
|
break
|
|
}
|
|
}
|
|
|
|
if victim >= 0 {
|
|
t.listeners = append(t.listeners[:victim], t.listeners[victim+1:]...)
|
|
}
|
|
}
|
|
|
|
func (t *Text) filterChanged(lines []string) {
|
|
t.fireTextFiltered(lines, t.filter(t.query, lines))
|
|
}
|
|
|
|
func (t *Text) fireTextChanged(lines []string) {
|
|
for _, lis := range t.listeners {
|
|
lis.TextChanged(lines)
|
|
}
|
|
}
|
|
|
|
func (t *Text) fireTextFiltered(lines []string, matches fuzzy.Matches) {
|
|
for _, lis := range t.listeners {
|
|
lis.TextFiltered(lines, matches)
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Helpers...
|
|
|
|
func (t *Text) filter(q string, lines []string) fuzzy.Matches {
|
|
if q == "" {
|
|
return nil
|
|
}
|
|
if dao.IsFuzzySelector(q) {
|
|
return t.fuzzyFilter(strings.TrimSpace(q[2:]), lines)
|
|
}
|
|
return t.rxFilter(q, lines)
|
|
}
|
|
|
|
func (*Text) fuzzyFilter(q string, lines []string) fuzzy.Matches {
|
|
return fuzzy.Find(q, lines)
|
|
}
|
|
|
|
func (*Text) rxFilter(q string, lines []string) fuzzy.Matches {
|
|
rx, err := regexp.Compile(`(?i)` + q)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
matches := make(fuzzy.Matches, 0, len(lines))
|
|
for i, l := range lines {
|
|
if loc := rx.FindStringIndex(l); len(loc) == 2 {
|
|
matches = append(matches, fuzzy.Match{Str: q, Index: i, MatchedIndexes: loc})
|
|
}
|
|
}
|
|
|
|
return matches
|
|
}
|