Refactor diff search to use new render layout
This commit is contained in:
parent
3dbb830a0e
commit
468168b9de
@ -59,7 +59,7 @@ type LogicalLine struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *LogicalLine) render_screen_line(n int, lp *loop.Loop, margin_size, columns int) {
|
func (self *LogicalLine) render_screen_line(n int, lp *loop.Loop, margin_size, columns int) {
|
||||||
if n >= len(self.screen_lines) {
|
if n >= len(self.screen_lines) || n < 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sl := self.screen_lines[n]
|
sl := self.screen_lines[n]
|
||||||
@ -147,7 +147,7 @@ func place_in(text string, sz int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var format_as_sgr struct {
|
var format_as_sgr struct {
|
||||||
title, margin, added, removed, added_margin, removed_margin, filler, margin_filler, hunk_margin, hunk, selection string
|
title, margin, added, removed, added_margin, removed_margin, filler, margin_filler, hunk_margin, hunk, selection, search string
|
||||||
}
|
}
|
||||||
|
|
||||||
var statusline_format, added_count_format, removed_count_format, message_format, selection_format func(...any) string
|
var statusline_format, added_count_format, removed_count_format, message_format, selection_format func(...any) string
|
||||||
@ -173,6 +173,7 @@ func create_formatters() {
|
|||||||
format_as_sgr.margin = only_open(fmt.Sprintf("fg=%s bg=%s", conf.Margin_fg.AsRGBSharp(), conf.Margin_bg.AsRGBSharp()))
|
format_as_sgr.margin = only_open(fmt.Sprintf("fg=%s bg=%s", conf.Margin_fg.AsRGBSharp(), conf.Margin_bg.AsRGBSharp()))
|
||||||
format_as_sgr.hunk = only_open(fmt.Sprintf("fg=%s bg=%s", conf.Margin_fg.AsRGBSharp(), conf.Hunk_bg.AsRGBSharp()))
|
format_as_sgr.hunk = only_open(fmt.Sprintf("fg=%s bg=%s", conf.Margin_fg.AsRGBSharp(), conf.Hunk_bg.AsRGBSharp()))
|
||||||
format_as_sgr.hunk_margin = only_open(fmt.Sprintf("fg=%s bg=%s", conf.Margin_fg.AsRGBSharp(), conf.Hunk_margin_bg.AsRGBSharp()))
|
format_as_sgr.hunk_margin = only_open(fmt.Sprintf("fg=%s bg=%s", conf.Margin_fg.AsRGBSharp(), conf.Hunk_margin_bg.AsRGBSharp()))
|
||||||
|
format_as_sgr.search = only_open(fmt.Sprintf("fg=%s bg=%s", conf.Search_fg.AsRGBSharp(), conf.Search_bg.AsRGBSharp()))
|
||||||
statusline_format = ctx.SprintFunc(fmt.Sprintf("fg=%s", conf.Margin_fg.AsRGBSharp()))
|
statusline_format = ctx.SprintFunc(fmt.Sprintf("fg=%s", conf.Margin_fg.AsRGBSharp()))
|
||||||
added_count_format = ctx.SprintFunc(fmt.Sprintf("fg=%s", conf.Highlight_added_bg.AsRGBSharp()))
|
added_count_format = ctx.SprintFunc(fmt.Sprintf("fg=%s", conf.Highlight_added_bg.AsRGBSharp()))
|
||||||
removed_count_format = ctx.SprintFunc(fmt.Sprintf("fg=%s", conf.Highlight_removed_bg.AsRGBSharp()))
|
removed_count_format = ctx.SprintFunc(fmt.Sprintf("fg=%s", conf.Highlight_removed_bg.AsRGBSharp()))
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"kitty/tools/tui/sgr"
|
"kitty/tools/tui"
|
||||||
"kitty/tools/utils"
|
"kitty/tools/utils"
|
||||||
"kitty/tools/utils/images"
|
"kitty/tools/utils/images"
|
||||||
"kitty/tools/wcswidth"
|
"kitty/tools/wcswidth"
|
||||||
@ -20,7 +20,7 @@ var _ = fmt.Print
|
|||||||
|
|
||||||
type Search struct {
|
type Search struct {
|
||||||
pat *regexp.Regexp
|
pat *regexp.Regexp
|
||||||
matches map[ScrollPos][]*sgr.Span
|
matches map[ScrollPos][]Span
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Search) Len() int { return len(self.matches) }
|
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)) {
|
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)
|
lengths := utils.Map(func(x string) int { return len(x) }, clean_lines)
|
||||||
offsets := make([]int, len(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 {
|
for i := range clean_lines {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
offsets[i] = offsets[i-1] + lengths[i-1]
|
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
|
pos := 0
|
||||||
|
|
||||||
find_pos := func(start int) int {
|
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)
|
end_line := find_pos(end)
|
||||||
if end_line > -1 {
|
if end_line > -1 {
|
||||||
for i := start_line; i <= end_line; i++ {
|
for i := start_line; i <= end_line; i++ {
|
||||||
offset := 0
|
cell_start := 0
|
||||||
if i == start_line {
|
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 {
|
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
|
half_width := cols / 2
|
||||||
right_offset := half_width + margin_size
|
right_offset := half_width + margin_size
|
||||||
left_clean_lines, right_clean_lines := make([]string, len(line.screen_lines)), make([]string, len(line.screen_lines))
|
left_clean_lines, right_clean_lines := make([]string, len(line.screen_lines)), make([]string, len(line.screen_lines))
|
||||||
lt := line.line_type
|
for i, sl := range line.screen_lines {
|
||||||
for i, line := range line.screen_lines {
|
if line.is_full_width {
|
||||||
line = wcswidth.StripEscapeCodes(line)
|
left_clean_lines[i] = wcswidth.StripEscapeCodes(sl.left.marked_up_text)
|
||||||
if lt == HUNK_TITLE_LINE || lt == FULL_TITLE_LINE {
|
|
||||||
if len(line) > margin_size {
|
|
||||||
left_clean_lines[i] = line[margin_size:]
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if len(line) >= half_width+1 {
|
left_clean_lines[i] = wcswidth.StripEscapeCodes(sl.left.marked_up_text)
|
||||||
left_clean_lines[i] = line[margin_size:half_width]
|
right_clean_lines[i] = wcswidth.StripEscapeCodes(sl.right.marked_up_text)
|
||||||
}
|
|
||||||
if len(line) > right_offset {
|
|
||||||
right_clean_lines[i] = line[right_offset:]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.find_matches_in_lines(left_clean_lines, margin_size, send_result)
|
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
|
return len(self.matches[pos]) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Span struct{ start, end int }
|
||||||
|
|
||||||
func (self *Search) search(logical_lines *LogicalLines) {
|
func (self *Search) search(logical_lines *LogicalLines) {
|
||||||
margin_size := logical_lines.margin_size
|
margin_size := logical_lines.margin_size
|
||||||
cols := logical_lines.columns
|
cols := logical_lines.columns
|
||||||
self.matches = make(map[ScrollPos][]*sgr.Span)
|
self.matches = make(map[ScrollPos][]Span)
|
||||||
ctx := images.Context{}
|
ctx := images.Context{}
|
||||||
mutex := sync.Mutex{}
|
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) {
|
ctx.Parallel(0, logical_lines.Len(), func(nums <-chan int) {
|
||||||
for i := range nums {
|
for i := range nums {
|
||||||
line := logical_lines.At(i)
|
line := logical_lines.At(i)
|
||||||
@ -116,30 +114,36 @@ func (self *Search) search(logical_lines *LogicalLines) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
self.find_matches_in_line(line, margin_size, cols, func(screen_line, offset, size int) {
|
self.find_matches_in_line(line, margin_size, cols, func(screen_line, offset, size int) {
|
||||||
|
if size > 0 {
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
defer mutex.Unlock()
|
defer mutex.Unlock()
|
||||||
sn := *s
|
|
||||||
sn.Offset, sn.Size = offset, size
|
|
||||||
pos := ScrollPos{i, screen_line}
|
pos := ScrollPos{i, screen_line}
|
||||||
self.matches[pos] = append(self.matches[pos], &sn)
|
self.matches[pos] = append(self.matches[pos], Span{offset, offset + size - 1})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
for _, spans := range self.matches {
|
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]
|
spans := self.matches[pos]
|
||||||
if spans == nil {
|
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 {
|
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)
|
ans.search(logical_lines)
|
||||||
return ans
|
return ans
|
||||||
}
|
}
|
||||||
|
|||||||
@ -140,7 +140,7 @@ func (ms *MouseSelection) LineBounds(line_pos LinePos) (start_x, end_x int) {
|
|||||||
return -1, -1
|
return -1, -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatPartOfLine(sgr string, start_x, end_x, y int) string {
|
func FormatPartOfLine(sgr string, start_x, end_x, y int) string { // uses zero based indices
|
||||||
// DECCARA used to set formatting in specified region using zero based indexing
|
// DECCARA used to set formatting in specified region using zero based indexing
|
||||||
return fmt.Sprintf("\x1b[%d;%d;%d;%d;%s$r", y+1, start_x+1, y+1, end_x+1, sgr)
|
return fmt.Sprintf("\x1b[%d;%d;%d;%d;%s$r", y+1, start_x+1, y+1, end_x+1, sgr)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user