package utils import ( "slices" "strings" "sync" ) type PositionFinder interface { // advance position to line after pattern found. return true if found FindLineContaining(s string) bool // insert line at position AddLine(s string) // return current content Content() []byte } type positionFinder struct { sync.Mutex lines []string line_pos int // only advances forward, points to the next line } /* a position finder helps finding certain positions in pieces of text. for example: find the '}' after the first occurence of line "foo" and "bar". Each call advances the position further. AddLine inserts a new line at current position. */ func NewPositionFinder(ct []byte) PositionFinder { lines := strings.Split(string(ct), "\n") res := &positionFinder{lines: lines} return res } func (pf *positionFinder) remaining_lines() []string { if pf.line_pos >= len(pf.lines) { return nil } return pf.lines[pf.line_pos+1:] } // advance to position after a line containing... func (pf *positionFinder) FindLineContaining(s string) bool { pf.Lock() defer pf.Unlock() for i, l := range pf.remaining_lines() { // fmt.Printf("Line %d: \"%s\"\n", i, l) if strings.Contains(l, s) { pf.line_pos = pf.line_pos + i + 1 return true } } return false } func (pf *positionFinder) AddLine(line string) { pf.Lock() defer pf.Unlock() pos := pf.line_pos + 1 pf.lines = slices.Insert(pf.lines, pos, line) } func (pf *positionFinder) Content() []byte { s := strings.Join(pf.lines, "\n") return []byte(s) }