55 lines
1.2 KiB
Go
55 lines
1.2 KiB
Go
package text
|
|
|
|
import (
|
|
"unicode"
|
|
|
|
"github.com/egoist/mygo/ui"
|
|
|
|
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
|
|
)
|
|
|
|
type HighlightOptions struct {
|
|
Slot pixel.Slot
|
|
// Mark is the marker slot; zero means Warn.
|
|
Mark pixel.Slot
|
|
}
|
|
|
|
// Highlight marks each match of query in s, ignoring case.
|
|
func Highlight(c *ui.Context, s, query string, o HighlightOptions) *ui.Element {
|
|
k := pixel.K(c)
|
|
mark := slotOr(o.Mark, pixel.Warn)
|
|
rs := []rune(s)
|
|
spans := matches(rs, []rune(query))
|
|
return block(c, k, s, pixel.Measure(s), pixel.LineHeight, func(g pixel.Canvas) {
|
|
for _, sp := range spans {
|
|
x0, x1 := pixel.Measure(string(rs[:sp[0]])), pixel.Measure(string(rs[:sp[1]]))
|
|
g.Veil(x0, 2, x1-x0, pixel.LineHeight-4, mark, 10)
|
|
}
|
|
g.Text(0, 0, s, o.Slot, 1)
|
|
})
|
|
}
|
|
|
|
// matches are the rune spans of q in s.
|
|
func matches(s, q []rune) [][2]int {
|
|
var out [][2]int
|
|
if len(q) == 0 {
|
|
return nil
|
|
}
|
|
for i := 0; i+len(q) <= len(s); {
|
|
same := true
|
|
for j := range q {
|
|
if unicode.ToLower(s[i+j]) != unicode.ToLower(q[j]) {
|
|
same = false
|
|
break
|
|
}
|
|
}
|
|
if same {
|
|
out = append(out, [2]int{i, i + len(q)})
|
|
i += len(q)
|
|
} else {
|
|
i++
|
|
}
|
|
}
|
|
return out
|
|
}
|