7 "github.com/zyedidia/micro/internal/util"
10 func (b *Buffer) findDown(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
11 start.Y = util.Clamp(start.Y, 0, b.LinesNum()-1)
12 end.Y = util.Clamp(end.Y, 0, b.LinesNum()-1)
14 if start.GreaterThan(end) {
15 start, end = end, start
18 for i := start.Y; i <= end.Y; i++ {
22 if i == start.Y && start.Y == end.Y {
23 nchars := utf8.RuneCount(l)
24 start.X = util.Clamp(start.X, 0, nchars)
25 end.X = util.Clamp(end.X, 0, nchars)
26 l = util.SliceStart(l, end.X)
27 l = util.SliceEnd(l, start.X)
29 } else if i == start.Y {
30 nchars := utf8.RuneCount(l)
31 start.X = util.Clamp(start.X, 0, nchars)
32 l = util.SliceEnd(l, start.X)
34 } else if i == end.Y {
35 nchars := utf8.RuneCount(l)
36 end.X = util.Clamp(end.X, 0, nchars)
37 l = util.SliceStart(l, end.X)
40 match := r.FindIndex(l)
43 start := Loc{charpos + util.RunePos(l, match[0]), i}
44 end := Loc{charpos + util.RunePos(l, match[1]), i}
45 return [2]Loc{start, end}, true
48 return [2]Loc{}, false
51 func (b *Buffer) findUp(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
52 start.Y = util.Clamp(start.Y, 0, b.LinesNum()-1)
53 end.Y = util.Clamp(end.Y, 0, b.LinesNum()-1)
55 if start.GreaterThan(end) {
56 start, end = end, start
59 for i := end.Y; i >= start.Y; i-- {
63 if i == start.Y && start.Y == end.Y {
64 nchars := utf8.RuneCount(l)
65 start.X = util.Clamp(start.X, 0, nchars)
66 end.X = util.Clamp(end.X, 0, nchars)
67 l = util.SliceStart(l, end.X)
68 l = util.SliceEnd(l, start.X)
70 } else if i == start.Y {
71 nchars := utf8.RuneCount(l)
72 start.X = util.Clamp(start.X, 0, nchars)
73 l = util.SliceEnd(l, start.X)
75 } else if i == end.Y {
76 nchars := utf8.RuneCount(l)
77 end.X = util.Clamp(end.X, 0, nchars)
78 l = util.SliceStart(l, end.X)
81 match := r.FindIndex(l)
84 start := Loc{charpos + util.RunePos(l, match[0]), i}
85 end := Loc{charpos + util.RunePos(l, match[1]), i}
86 return [2]Loc{start, end}, true
89 return [2]Loc{}, false
92 // FindNext finds the next occurrence of a given string in the buffer
93 // It returns the start and end location of the match (if found) and
94 // a boolean indicating if it was found
95 // May also return an error if the search regex is invalid
96 func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, useRegex bool) ([2]Loc, bool, error) {
98 return [2]Loc{}, false, nil
105 s = regexp.QuoteMeta(s)
108 if b.Settings["ignorecase"].(bool) {
109 r, err = regexp.Compile("(?i)" + s)
111 r, err = regexp.Compile(s)
115 return [2]Loc{}, false, err
121 l, found = b.findDown(r, from, end)
123 l, found = b.findDown(r, start, from)
126 l, found = b.findUp(r, from, start)
128 l, found = b.findUp(r, end, from)
134 // ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area
135 // and returns the number of replacements made
136 func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte) int {
137 if start.GreaterThan(end) {
138 start, end = end, start
143 for i := start.Y; i <= end.Y; i++ {
147 if start.Y == end.Y && i == start.Y {
148 l = util.SliceStart(l, end.X)
149 l = util.SliceEnd(l, start.X)
151 } else if i == start.Y {
152 l = util.SliceEnd(l, start.X)
154 } else if i == end.Y {
155 l = util.SliceStart(l, end.X)
157 newText := search.ReplaceAllFunc(l, func(in []byte) []byte {
162 from := Loc{charpos, i}
163 to := Loc{charpos + utf8.RuneCount(l), i}
165 deltas = append(deltas, Delta{newText, from, to})
167 b.MultipleReplace(deltas)