simplified matchers and fixed duplicate highlights

This commit is contained in:
Mikael Fangel 2023-04-06 18:14:15 +02:00 committed by Maas Lalani
parent 86c66fd6cb
commit c576e347a0
No known key found for this signature in database
GPG key ID: 5A6ED5CBF1A0A000

View file

@ -11,11 +11,12 @@ import (
)
type search struct {
active bool
input textinput.Model
query *regexp.Regexp
lastMatchLoc int
prevMatch string
active bool
input textinput.Model
query *regexp.Regexp
matchIndex int
matchLipglossStr string
matchString string
}
func (s *search) new() {
@ -46,8 +47,9 @@ func (s *search) Execute(m *model) {
func (s *search) Done() {
s.active = false
s.lastMatchLoc = 0
s.prevMatch = ""
// To account for the first match is always executed.
s.matchIndex = -1
}
func (s *search) NextMatch(m *model) {
@ -56,32 +58,16 @@ func (s *search) NextMatch(m *model) {
return
}
// Removed last highlight.
if s.prevMatch != "" {
leftPadding, rightPadding := utils.LipglossLengthPadding(s.prevMatch, m.matchHighlightStyle)
metastring := regexp.QuoteMeta(m.matchHighlightStyle.Render(s.query.String()))
query := regexp.MustCompile("(" + metastring[:leftPadding+1] + ")(" + s.query.String() + ")(" + metastring[len(metastring)-rightPadding-1:] + ")")
m.content = query.ReplaceAllString(m.content, "$2")
}
// Find the string to highlight.
nextMatch := s.query.FindString(m.content[s.lastMatchLoc:])
s.prevMatch = nextMatch
m.content = strings.Replace(m.content, s.matchLipglossStr, s.matchString, 1)
leftPadding, _ := utils.LipglossLengthPadding(s.prevMatch, m.matchHighlightStyle)
allMatches := s.query.FindAllSubmatchIndex([]byte(m.content), -1)
for i, subm := range allMatches {
if subm[1]+leftPadding == s.lastMatchLoc {
// Highliht the current match.
m.content = m.content[:allMatches[i+1][0]] + strings.Replace(m.content[allMatches[i+1][0]:], m.content[allMatches[i+1][0]:allMatches[i+1][1]], m.matchHighlightStyle.Render(m.content[allMatches[i+1][0]:allMatches[i+1][1]]), 1)
s.lastMatchLoc = allMatches[i+1][1] + leftPadding
break
}
if i == len(allMatches)-1 {
m.content = m.content[:allMatches[0][0]] + strings.Replace(m.content[allMatches[0][0]:], m.content[allMatches[0][0]:allMatches[0][1]], m.matchHighlightStyle.Render(m.content[allMatches[0][0]:allMatches[0][1]]), 1)
s.lastMatchLoc = allMatches[0][1] + leftPadding
break
}
}
allMatches := s.query.FindAllStringSubmatchIndex(m.content, -1)
s.matchIndex = (s.matchIndex + 1) % len(allMatches)
match := allMatches[s.matchIndex]
lhs := m.content[:match[0]]
rhs := m.content[match[0]:]
s.matchString = m.content[match[0]:match[1]]
s.matchLipglossStr = m.matchHighlightStyle.Render(s.matchString)
m.content = lhs + strings.Replace(rhs, m.content[match[0]:match[1]], s.matchLipglossStr, 1)
// Update the viewport position.
line := 0
@ -89,13 +75,13 @@ func (s *search) NextMatch(m *model) {
if c == '\n' {
line++
}
if i == s.lastMatchLoc {
if i == match[0]+len(s.matchLipglossStr) {
break
}
}
// Only update if the match is not within the viewport.
if line > m.viewport.YOffset+m.viewport.VisibleLineCount()-1 || line < m.viewport.YOffset {
if line > m.viewport.YOffset-1+m.viewport.VisibleLineCount()-1 || line < m.viewport.YOffset {
m.viewport.SetYOffset(line)
}
}
@ -106,32 +92,20 @@ func (s *search) PrevMatch(m *model) {
return
}
// Removed last highlight.
if s.prevMatch != "" {
leftPadding, rightPadding := utils.LipglossLengthPadding(s.prevMatch, m.matchHighlightStyle)
metastring := regexp.QuoteMeta(m.matchHighlightStyle.Render(s.query.String()))
query := regexp.MustCompile("(" + metastring[:leftPadding+1] + ")(" + s.query.String() + ")(" + metastring[len(metastring)-rightPadding-1:] + ")")
m.content = query.ReplaceAllString(m.content, "$2")
m.content = strings.Replace(m.content, s.matchLipglossStr, s.matchString, 1)
allMatches := s.query.FindAllStringSubmatchIndex(m.content, -1)
s.matchIndex = (s.matchIndex - 1) % len(allMatches)
if s.matchIndex < 0 {
s.matchIndex = 0
}
var prev []int
leftPadding, _ := utils.LipglossLengthPadding(s.prevMatch, m.matchHighlightStyle)
allMatches := s.query.FindAllSubmatchIndex([]byte(m.content), -1)
for i, subm := range allMatches {
if prev != nil && subm[1]+leftPadding == s.lastMatchLoc {
// Highliht the current match.
m.content = m.content[:prev[0]] + strings.Replace(m.content[prev[0]:], m.content[prev[0]:prev[1]], m.matchHighlightStyle.Render(m.content[prev[0]:prev[1]]), 1)
s.lastMatchLoc = prev[1] + leftPadding
break
}
// If reaching this at the end of the loop we have looked through all matches.
if i == len(allMatches)-1 {
m.content = m.content[:subm[0]] + strings.Replace(m.content[subm[0]:], m.content[subm[0]:subm[1]], m.matchHighlightStyle.Render(m.content[subm[0]:subm[1]]), 1)
s.lastMatchLoc = subm[1] + leftPadding
}
prev = subm
}
match := allMatches[s.matchIndex]
lhs := m.content[:match[0]]
rhs := m.content[match[0]:]
s.matchString = m.content[match[0]:match[1]]
s.matchLipglossStr = m.matchHighlightStyle.Render(s.matchString)
m.content = lhs + strings.Replace(rhs, m.content[match[0]:match[1]], s.matchLipglossStr, 1)
// Update the viewport position.
line := 0
@ -139,13 +113,13 @@ func (s *search) PrevMatch(m *model) {
if c == '\n' {
line++
}
if i == s.lastMatchLoc {
if i == match[0]+len(s.matchLipglossStr) {
break
}
}
// Only update if the match is not within the viewport.
if line > m.viewport.YOffset+m.viewport.VisibleLineCount()-1 || line < m.viewport.YOffset {
if line > m.viewport.YOffset-1+m.viewport.VisibleLineCount()-1 || line < m.viewport.YOffset {
m.viewport.SetYOffset(line)
}
}