Refactor diff mouse selection to use new render layout
This commit is contained in:
parent
468168b9de
commit
aebfdaa69a
@ -6,10 +6,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"kitty"
|
"kitty"
|
||||||
"kitty/tools/config"
|
"kitty/tools/config"
|
||||||
|
"kitty/tools/tui"
|
||||||
"kitty/tools/tui/loop"
|
"kitty/tools/tui/loop"
|
||||||
"kitty/tools/utils"
|
"kitty/tools/utils"
|
||||||
"kitty/tools/wcswidth"
|
"kitty/tools/wcswidth"
|
||||||
@ -50,6 +50,38 @@ func (self *Handler) handle_wheel_event(up bool) {
|
|||||||
self.dispatch_action(`scroll_by`, strconv.Itoa(amt))
|
self.dispatch_action(`scroll_by`, strconv.Itoa(amt))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type line_pos struct {
|
||||||
|
min_x, max_x int
|
||||||
|
y ScrollPos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *line_pos) MinX() int { return self.min_x }
|
||||||
|
func (self *line_pos) MaxX() int { return self.max_x }
|
||||||
|
func (self *line_pos) Equal(other tui.LinePos) bool {
|
||||||
|
if o, ok := other.(*line_pos); ok {
|
||||||
|
return self.y == o.y
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (self *line_pos) LessThan(other tui.LinePos) bool {
|
||||||
|
if o, ok := other.(*line_pos); ok {
|
||||||
|
return self.y.Less(o.y)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Handler) line_pos_from_pos(x int, pos ScrollPos) *line_pos {
|
||||||
|
ans := line_pos{min_x: self.logical_lines.margin_size, y: pos}
|
||||||
|
available_cols := self.logical_lines.columns / 2
|
||||||
|
if x >= available_cols {
|
||||||
|
ans.min_x += available_cols
|
||||||
|
ans.max_x = utils.Max(ans.min_x, ans.min_x+self.logical_lines.ScreenLineAt(pos).right.wcswidth()-1)
|
||||||
|
} else {
|
||||||
|
ans.max_x = utils.Max(ans.min_x, ans.min_x+self.logical_lines.ScreenLineAt(pos).left.wcswidth()-1)
|
||||||
|
}
|
||||||
|
return &ans
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Handler) start_mouse_selection(ev *loop.MouseEvent) {
|
func (self *Handler) start_mouse_selection(ev *loop.MouseEvent) {
|
||||||
available_cols := self.logical_lines.columns / 2
|
available_cols := self.logical_lines.columns / 2
|
||||||
if ev.Cell.Y >= self.screen_size.num_lines || ev.Cell.X < self.logical_lines.margin_size || (ev.Cell.X >= available_cols && ev.Cell.X < available_cols+self.logical_lines.margin_size) {
|
if ev.Cell.Y >= self.screen_size.num_lines || ev.Cell.X < self.logical_lines.margin_size || (ev.Cell.X >= available_cols && ev.Cell.X < available_cols+self.logical_lines.margin_size) {
|
||||||
@ -61,14 +93,7 @@ func (self *Handler) start_mouse_selection(ev *loop.MouseEvent) {
|
|||||||
if ll.line_type == EMPTY_LINE || ll.line_type == IMAGE_LINE {
|
if ll.line_type == EMPTY_LINE || ll.line_type == IMAGE_LINE {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self.mouse_selection.StartNewSelection(ev, self.line_pos_from_pos(ev.Cell.X, pos), 0, self.screen_size.num_lines-1, self.screen_size.cell_width, self.screen_size.cell_height)
|
||||||
min_x := self.logical_lines.margin_size
|
|
||||||
max_x := available_cols - 1
|
|
||||||
if ev.Cell.X >= available_cols {
|
|
||||||
min_x += available_cols
|
|
||||||
max_x += available_cols
|
|
||||||
}
|
|
||||||
self.mouse_selection.StartNewSelection(ev, &pos, min_x, max_x, 0, self.screen_size.num_lines-1, self.screen_size.cell_width, self.screen_size.cell_height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Handler) update_mouse_selection(ev *loop.MouseEvent) {
|
func (self *Handler) update_mouse_selection(ev *loop.MouseEvent) {
|
||||||
@ -79,7 +104,8 @@ func (self *Handler) update_mouse_selection(ev *loop.MouseEvent) {
|
|||||||
y := ev.Cell.Y
|
y := ev.Cell.Y
|
||||||
y = utils.Max(0, utils.Min(y, self.screen_size.num_lines-1))
|
y = utils.Max(0, utils.Min(y, self.screen_size.num_lines-1))
|
||||||
self.logical_lines.IncrementScrollPosBy(&pos, y)
|
self.logical_lines.IncrementScrollPosBy(&pos, y)
|
||||||
self.mouse_selection.Update(ev, &pos)
|
x := self.mouse_selection.StartLine().MinX()
|
||||||
|
self.mouse_selection.Update(ev, self.line_pos_from_pos(x, pos))
|
||||||
self.draw_screen()
|
self.draw_screen()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,31 +118,39 @@ func (self *Handler) text_for_current_mouse_selection() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
text := make([]byte, 0, 2048)
|
text := make([]byte, 0, 2048)
|
||||||
start, end := *self.mouse_selection.StartLine().(*ScrollPos), *self.mouse_selection.EndLine().(*ScrollPos)
|
start_pos, end_pos := *self.mouse_selection.StartLine().(*line_pos), *self.mouse_selection.EndLine().(*line_pos)
|
||||||
for pos, prev_ll_idx := start, start.logical_line; pos.Less(end) || pos.Equal(&end); self.logical_lines.IncrementScrollPosBy(&pos, 1) {
|
start, end := start_pos.y, end_pos.y
|
||||||
|
is_left := start_pos.min_x == self.logical_lines.margin_size
|
||||||
|
|
||||||
|
line_for_pos := func(pos ScrollPos) string {
|
||||||
|
if is_left {
|
||||||
|
return self.logical_lines.ScreenLineAt(pos).left.marked_up_text
|
||||||
|
}
|
||||||
|
return self.logical_lines.ScreenLineAt(pos).right.marked_up_text
|
||||||
|
}
|
||||||
|
|
||||||
|
for pos, prev_ll_idx := start, start.logical_line; pos.Less(end) || pos == end; self.logical_lines.IncrementScrollPosBy(&pos, 1) {
|
||||||
ll := self.logical_lines.At(pos.logical_line)
|
ll := self.logical_lines.At(pos.logical_line)
|
||||||
var line string
|
var line string
|
||||||
switch ll.line_type {
|
switch ll.line_type {
|
||||||
case EMPTY_LINE:
|
case EMPTY_LINE:
|
||||||
case IMAGE_LINE:
|
case IMAGE_LINE:
|
||||||
if pos.screen_line < ll.image_lines_offset {
|
if pos.screen_line < ll.image_lines_offset {
|
||||||
line = self.logical_lines.ScreenLineAt(pos)
|
line = line_for_pos(pos)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
line = self.logical_lines.ScreenLineAt(pos)
|
line = line_for_pos(pos)
|
||||||
}
|
}
|
||||||
line = wcswidth.StripEscapeCodes(line)
|
line = wcswidth.StripEscapeCodes(line)
|
||||||
s, e := self.mouse_selection.LineBounds(&pos)
|
s, e := self.mouse_selection.LineBounds(self.line_pos_from_pos(start_pos.min_x, pos))
|
||||||
|
s -= start_pos.min_x
|
||||||
|
e -= start_pos.min_x
|
||||||
line = wcswidth.TruncateToVisualLength(line, e+1)
|
line = wcswidth.TruncateToVisualLength(line, e+1)
|
||||||
if s > 0 {
|
if s > 0 {
|
||||||
prefix := wcswidth.TruncateToVisualLength(line, s)
|
prefix := wcswidth.TruncateToVisualLength(line, s)
|
||||||
line = line[len(prefix):]
|
line = line[len(prefix):]
|
||||||
}
|
}
|
||||||
// TODO: look at the original line from the source and handle leading tabs and trailing spaces as per it
|
// TODO: look at the original line from the source and handle leading tabs as per it
|
||||||
tline := strings.TrimRight(line, " ")
|
|
||||||
if len(tline) < len(line) {
|
|
||||||
line = tline + " "
|
|
||||||
}
|
|
||||||
if pos.logical_line > prev_ll_idx {
|
if pos.logical_line > prev_ll_idx {
|
||||||
line = "\n" + line
|
line = "\n" + line
|
||||||
}
|
}
|
||||||
@ -140,6 +174,11 @@ func (self *Handler) finish_mouse_selection(ev *loop.MouseEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Handler) add_mouse_selection_to_line(line string, line_pos ScrollPos, y int) string {
|
func (self *Handler) add_mouse_selection_to_line(line_pos ScrollPos, y int) string {
|
||||||
return line + self.mouse_selection.LineFormatSuffix(&line_pos, selection_sgr, y)
|
if self.mouse_selection.IsEmpty() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
selection_sgr := format_as_sgr.selection
|
||||||
|
x := self.mouse_selection.StartLine().MinX()
|
||||||
|
return self.mouse_selection.LineFormatSuffix(self.line_pos_from_pos(x, line_pos), selection_sgr[2:len(selection_sgr)-1], y)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,14 @@ type HalfScreenLine struct {
|
|||||||
marked_up_margin_text string
|
marked_up_margin_text string
|
||||||
marked_up_text string
|
marked_up_text string
|
||||||
is_filler bool
|
is_filler bool
|
||||||
|
cached_wcswidth int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *HalfScreenLine) wcswidth() int {
|
||||||
|
if self.cached_wcswidth == 0 && self.marked_up_text != "" {
|
||||||
|
self.cached_wcswidth = wcswidth.Stringwidth(self.marked_up_text)
|
||||||
|
}
|
||||||
|
return self.cached_wcswidth
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScreenLine struct {
|
type ScreenLine struct {
|
||||||
@ -466,10 +474,10 @@ func lines_for_context_chunk(data *DiffData, hunk_num int, chunk *Chunk, chunk_n
|
|||||||
left_line_number_s := strconv.Itoa(left_line_number + 1)
|
left_line_number_s := strconv.Itoa(left_line_number + 1)
|
||||||
right_line_number_s := strconv.Itoa(right_line_number + 1)
|
right_line_number_s := strconv.Itoa(right_line_number + 1)
|
||||||
for _, text := range splitlines(data.left_lines[left_line_number], data.available_cols) {
|
for _, text := range splitlines(data.left_lines[left_line_number], data.available_cols) {
|
||||||
left_line := HalfScreenLine{left_line_number_s, text, false}
|
left_line := HalfScreenLine{marked_up_margin_text: left_line_number_s, marked_up_text: text}
|
||||||
right_line := left_line
|
right_line := left_line
|
||||||
if right_line_number_s != left_line_number_s {
|
if right_line_number_s != left_line_number_s {
|
||||||
right_line = HalfScreenLine{right_line_number_s, text, false}
|
right_line = HalfScreenLine{marked_up_margin_text: right_line_number_s, marked_up_text: text}
|
||||||
}
|
}
|
||||||
ll.screen_lines = append(ll.screen_lines, &ScreenLine{left_line, right_line})
|
ll.screen_lines = append(ll.screen_lines, &ScreenLine{left_line, right_line})
|
||||||
left_line_number_s, right_line_number_s = "", ""
|
left_line_number_s, right_line_number_s = "", ""
|
||||||
@ -494,7 +502,7 @@ func render_half_line(line_number int, line, ltype string, available_cols int, c
|
|||||||
}
|
}
|
||||||
lnum := strconv.Itoa(line_number + 1)
|
lnum := strconv.Itoa(line_number + 1)
|
||||||
for _, sc := range splitlines(line, available_cols) {
|
for _, sc := range splitlines(line, available_cols) {
|
||||||
ans = append(ans, HalfScreenLine{lnum, sc, false})
|
ans = append(ans, HalfScreenLine{marked_up_margin_text: lnum, marked_up_text: sc})
|
||||||
lnum = ""
|
lnum = ""
|
||||||
}
|
}
|
||||||
return ans
|
return ans
|
||||||
|
|||||||
@ -38,20 +38,6 @@ func (self ScrollPos) Less(other ScrollPos) bool {
|
|||||||
return self.logical_line < other.logical_line || (self.logical_line == other.logical_line && self.screen_line < other.screen_line)
|
return self.logical_line < other.logical_line || (self.logical_line == other.logical_line && self.screen_line < other.screen_line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ScrollPos) Equal(other tui.LinePos) bool {
|
|
||||||
if o, ok := other.(*ScrollPos); ok {
|
|
||||||
return *self == *o
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *ScrollPos) LessThan(other tui.LinePos) bool {
|
|
||||||
if o, ok := other.(*ScrollPos); ok {
|
|
||||||
return self.Less(*o)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self ScrollPos) Add(other ScrollPos) ScrollPos {
|
func (self ScrollPos) Add(other ScrollPos) ScrollPos {
|
||||||
return ScrollPos{self.logical_line + other.logical_line, self.screen_line + other.screen_line}
|
return ScrollPos{self.logical_line + other.logical_line, self.screen_line + other.screen_line}
|
||||||
}
|
}
|
||||||
@ -361,16 +347,19 @@ func (self *Handler) draw_screen() {
|
|||||||
for num_written := 0; num_written < self.screen_size.num_lines; num_written++ {
|
for num_written := 0; num_written < self.screen_size.num_lines; num_written++ {
|
||||||
ll := self.logical_lines.At(pos.logical_line)
|
ll := self.logical_lines.At(pos.logical_line)
|
||||||
is_image := ll != nil && ll.line_type == IMAGE_LINE
|
is_image := ll != nil && ll.line_type == IMAGE_LINE
|
||||||
sl := self.logical_lines.ScreenLineAt(pos)
|
ll.render_screen_line(pos.screen_line, lp, self.logical_lines.margin_size, self.logical_lines.columns)
|
||||||
if is_image && !seen_images.Has(pos.logical_line) && pos.screen_line >= ll.image_lines_offset {
|
if is_image && !seen_images.Has(pos.logical_line) && pos.screen_line >= ll.image_lines_offset {
|
||||||
seen_images.Add(pos.logical_line)
|
seen_images.Add(pos.logical_line)
|
||||||
self.draw_image_pair(ll, pos.screen_line-ll.image_lines_offset)
|
self.draw_image_pair(ll, pos.screen_line-ll.image_lines_offset)
|
||||||
}
|
}
|
||||||
if self.current_search != nil {
|
if self.current_search != nil {
|
||||||
sl = self.current_search.markup_line(sl, pos)
|
if mkp := self.current_search.markup_line(pos, num_written); mkp != "" {
|
||||||
|
lp.QueueWriteString(mkp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mkp := self.add_mouse_selection_to_line(pos, num_written); mkp != "" {
|
||||||
|
lp.QueueWriteString(mkp)
|
||||||
}
|
}
|
||||||
sl = self.add_mouse_selection_to_line(sl, pos, num_written)
|
|
||||||
lp.QueueWriteString(strings.ReplaceAll(sl, FILLER_CHAR, " "))
|
|
||||||
lp.MoveCursorVertically(1)
|
lp.MoveCursorVertically(1)
|
||||||
lp.QueueWriteString("\x1b[m\r")
|
lp.QueueWriteString("\x1b[m\r")
|
||||||
if self.logical_lines.IncrementScrollPosBy(&pos, 1) == 0 {
|
if self.logical_lines.IncrementScrollPosBy(&pos, 1) == 0 {
|
||||||
|
|||||||
@ -14,6 +14,8 @@ var _ = fmt.Print
|
|||||||
type LinePos interface {
|
type LinePos interface {
|
||||||
LessThan(other LinePos) bool
|
LessThan(other LinePos) bool
|
||||||
Equal(other LinePos) bool
|
Equal(other LinePos) bool
|
||||||
|
MinX() int
|
||||||
|
MaxX() int
|
||||||
}
|
}
|
||||||
|
|
||||||
type SelectionBoundary struct {
|
type SelectionBoundary struct {
|
||||||
@ -48,7 +50,6 @@ func (self *SelectionBoundary) Equal(other SelectionBoundary) bool {
|
|||||||
type MouseSelection struct {
|
type MouseSelection struct {
|
||||||
start, end SelectionBoundary
|
start, end SelectionBoundary
|
||||||
is_active bool
|
is_active bool
|
||||||
min_x, max_x int
|
|
||||||
min_y, max_y int
|
min_y, max_y int
|
||||||
cell_width, cell_height int
|
cell_width, cell_height int
|
||||||
}
|
}
|
||||||
@ -58,10 +59,10 @@ func (self *MouseSelection) IsActive() bool { return self.is_active }
|
|||||||
func (self *MouseSelection) Finish() { self.is_active = false }
|
func (self *MouseSelection) Finish() { self.is_active = false }
|
||||||
func (self *MouseSelection) Clear() { *self = MouseSelection{} }
|
func (self *MouseSelection) Clear() { *self = MouseSelection{} }
|
||||||
|
|
||||||
func (ms *MouseSelection) StartNewSelection(ev *loop.MouseEvent, line LinePos, min_x, max_x, min_y, max_y, cell_width, cell_height int) {
|
func (ms *MouseSelection) StartNewSelection(ev *loop.MouseEvent, line LinePos, min_y, max_y, cell_width, cell_height int) {
|
||||||
*ms = MouseSelection{min_x: min_x, max_x: max_x, cell_width: cell_width, cell_height: cell_height, min_y: min_y, max_y: max_y}
|
*ms = MouseSelection{cell_width: cell_width, cell_height: cell_height, min_y: min_y, max_y: max_y}
|
||||||
ms.start.line = line
|
ms.start.line = line
|
||||||
ms.start.x = utils.Max(ms.min_x, utils.Min(ev.Cell.X, ms.max_x))
|
ms.start.x = utils.Max(line.MinX(), utils.Min(ev.Cell.X, line.MaxX()))
|
||||||
cell_start := cell_width * ev.Cell.X
|
cell_start := cell_width * ev.Cell.X
|
||||||
ms.start.in_first_half_of_cell = ev.Pixel.X <= cell_start+cell_width/2
|
ms.start.in_first_half_of_cell = ev.Pixel.X <= cell_start+cell_width/2
|
||||||
ms.end = ms.start
|
ms.end = ms.start
|
||||||
@ -70,7 +71,7 @@ func (ms *MouseSelection) StartNewSelection(ev *loop.MouseEvent, line LinePos, m
|
|||||||
|
|
||||||
func (ms *MouseSelection) Update(ev *loop.MouseEvent, line LinePos) {
|
func (ms *MouseSelection) Update(ev *loop.MouseEvent, line LinePos) {
|
||||||
if ms.is_active {
|
if ms.is_active {
|
||||||
ms.end.x = utils.Max(ms.min_x, utils.Min(ev.Cell.X, ms.max_x))
|
ms.end.x = utils.Max(line.MinX(), utils.Min(ev.Cell.X, line.MaxX()))
|
||||||
cell_start := ms.cell_width * ms.end.x
|
cell_start := ms.cell_width * ms.end.x
|
||||||
ms.end.in_first_half_of_cell = ev.Pixel.X <= cell_start+ms.cell_width/2
|
ms.end.in_first_half_of_cell = ev.Pixel.X <= cell_start+ms.cell_width/2
|
||||||
ms.end.line = line
|
ms.end.line = line
|
||||||
@ -126,13 +127,13 @@ func (ms *MouseSelection) LineBounds(line_pos LinePos) (start_x, end_x int) {
|
|||||||
|
|
||||||
if a.line.LessThan(line_pos) {
|
if a.line.LessThan(line_pos) {
|
||||||
if line_pos.LessThan(b.line) {
|
if line_pos.LessThan(b.line) {
|
||||||
return ms.min_x, ms.max_x
|
return line_pos.MinX(), line_pos.MaxX()
|
||||||
} else if b.line.Equal(line_pos) {
|
} else if b.line.Equal(line_pos) {
|
||||||
return adjust_end(ms.min_x, b)
|
return adjust_end(line_pos.MinX(), b)
|
||||||
}
|
}
|
||||||
} else if a.line.Equal(line_pos) {
|
} else if a.line.Equal(line_pos) {
|
||||||
if line_pos.LessThan(b.line) {
|
if line_pos.LessThan(b.line) {
|
||||||
return adjust_start(a, ms.max_x)
|
return adjust_start(a, line_pos.MaxX())
|
||||||
} else if b.line.Equal(line_pos) {
|
} else if b.line.Equal(line_pos) {
|
||||||
return adjust_both(a, b)
|
return adjust_both(a, b)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user