Refactor diff search to use new render layout

This commit is contained in:
Kovid Goyal
2023-03-29 13:22:34 +05:30
parent 3dbb830a0e
commit 468168b9de
3 changed files with 43 additions and 38 deletions

View File

@@ -8,7 +8,7 @@ import (
"strings"
"sync"
"kitty/tools/tui/sgr"
"kitty/tools/tui"
"kitty/tools/utils"
"kitty/tools/utils/images"
"kitty/tools/wcswidth"
@@ -20,7 +20,7 @@ var _ = fmt.Print
type Search struct {
pat *regexp.Regexp
matches map[ScrollPos][]*sgr.Span
matches map[ScrollPos][]Span
}
func (self *Search) Len() int { return len(self.matches) }
@@ -28,12 +28,16 @@ func (self *Search) Len() int { return len(self.matches) }
func (self *Search) find_matches_in_lines(clean_lines []string, origin int, send_result func(screen_line, offset, size int)) {
lengths := utils.Map(func(x string) int { return len(x) }, clean_lines)
offsets := make([]int, len(clean_lines))
cell_lengths := utils.Map(wcswidth.Stringwidth, clean_lines)
cell_offsets := make([]int, len(clean_lines))
for i := range clean_lines {
if i > 0 {
offsets[i] = offsets[i-1] + lengths[i-1]
cell_offsets[i] = cell_offsets[i-1] + cell_lengths[i-1]
}
}
matches := self.pat.FindAllStringIndex(strings.Join(clean_lines, ""), -1)
joined_text := strings.Join(clean_lines, "")
matches := self.pat.FindAllStringIndex(joined_text, -1)
pos := 0
find_pos := func(start int) int {
@@ -57,15 +61,17 @@ func (self *Search) find_matches_in_lines(clean_lines []string, origin int, send
end_line := find_pos(end)
if end_line > -1 {
for i := start_line; i <= end_line; i++ {
offset := 0
cell_start := 0
if i == start_line {
offset = start - offsets[i]
byte_offset := start - offsets[i]
cell_start = wcswidth.Stringwidth(clean_lines[i][:byte_offset])
}
size := len(clean_lines[i]) - offset
cell_end := cell_lengths[i]
if i == end_line {
size = (end - offsets[i]) - offset
byte_offset := end - offsets[i]
cell_end = wcswidth.Stringwidth(clean_lines[i][:byte_offset])
}
send_result(i, origin+offset, size)
send_result(i, origin+cell_start, cell_end-cell_start)
}
}
}
@@ -77,20 +83,12 @@ func (self *Search) find_matches_in_line(line *LogicalLine, margin_size, cols in
half_width := cols / 2
right_offset := half_width + margin_size
left_clean_lines, right_clean_lines := make([]string, len(line.screen_lines)), make([]string, len(line.screen_lines))
lt := line.line_type
for i, line := range line.screen_lines {
line = wcswidth.StripEscapeCodes(line)
if lt == HUNK_TITLE_LINE || lt == FULL_TITLE_LINE {
if len(line) > margin_size {
left_clean_lines[i] = line[margin_size:]
}
for i, sl := range line.screen_lines {
if line.is_full_width {
left_clean_lines[i] = wcswidth.StripEscapeCodes(sl.left.marked_up_text)
} else {
if len(line) >= half_width+1 {
left_clean_lines[i] = line[margin_size:half_width]
}
if len(line) > right_offset {
right_clean_lines[i] = line[right_offset:]
}
left_clean_lines[i] = wcswidth.StripEscapeCodes(sl.left.marked_up_text)
right_clean_lines[i] = wcswidth.StripEscapeCodes(sl.right.marked_up_text)
}
}
self.find_matches_in_lines(left_clean_lines, margin_size, send_result)
@@ -101,14 +99,14 @@ func (self *Search) Has(pos ScrollPos) bool {
return len(self.matches[pos]) > 0
}
type Span struct{ start, end int }
func (self *Search) search(logical_lines *LogicalLines) {
margin_size := logical_lines.margin_size
cols := logical_lines.columns
self.matches = make(map[ScrollPos][]*sgr.Span)
self.matches = make(map[ScrollPos][]Span)
ctx := images.Context{}
mutex := sync.Mutex{}
s := sgr.NewSpan(0, 0)
s.SetForeground(conf.Search_fg).SetBackground(conf.Search_bg)
ctx.Parallel(0, logical_lines.Len(), func(nums <-chan int) {
for i := range nums {
line := logical_lines.At(i)
@@ -116,30 +114,36 @@ func (self *Search) search(logical_lines *LogicalLines) {
continue
}
self.find_matches_in_line(line, margin_size, cols, func(screen_line, offset, size int) {
mutex.Lock()
defer mutex.Unlock()
sn := *s
sn.Offset, sn.Size = offset, size
pos := ScrollPos{i, screen_line}
self.matches[pos] = append(self.matches[pos], &sn)
if size > 0 {
mutex.Lock()
defer mutex.Unlock()
pos := ScrollPos{i, screen_line}
self.matches[pos] = append(self.matches[pos], Span{offset, offset + size - 1})
}
})
}
})
for _, spans := range self.matches {
slices.SortFunc(spans, func(a, b *sgr.Span) bool { return a.Offset < b.Offset })
slices.SortFunc(spans, func(a, b Span) bool { return a.start < b.start })
}
}
func (self *Search) markup_line(line string, pos ScrollPos) string {
func (self *Search) markup_line(pos ScrollPos, y int) string {
spans := self.matches[pos]
if spans == nil {
return line
return ""
}
return sgr.InsertFormatting(line, spans...)
sgr := format_as_sgr.search[2:]
sgr = sgr[:len(sgr)-1]
ans := make([]byte, 0, 32)
for _, span := range spans {
ans = append(ans, tui.FormatPartOfLine(sgr, span.start, span.end, y)...)
}
return utils.UnsafeBytesToString(ans)
}
func do_search(pat *regexp.Regexp, logical_lines *LogicalLines) *Search {
ans := &Search{pat: pat, matches: make(map[ScrollPos][]*sgr.Span)}
ans := &Search{pat: pat, matches: make(map[ScrollPos][]Span)}
ans.search(logical_lines)
return ans
}