diff --git a/kittens/diff/mouse.go b/kittens/diff/mouse.go index 54853d067..de3074b23 100644 --- a/kittens/diff/mouse.go +++ b/kittens/diff/mouse.go @@ -6,11 +6,13 @@ import ( "fmt" "path/filepath" "strconv" + "strings" "kitty" "kitty/tools/config" "kitty/tools/tui/loop" "kitty/tools/utils" + "kitty/tools/wcswidth" ) var _ = fmt.Print @@ -85,12 +87,57 @@ func (self *Handler) clear_mouse_selection() { self.mouse_selection.Clear() } +func (self *Handler) text_for_current_mouse_selection() string { + if self.mouse_selection.IsEmpty() { + return "" + } + text := make([]byte, 0, 2048) + start, end := *self.mouse_selection.StartLine().(*ScrollPos), *self.mouse_selection.EndLine().(*ScrollPos) + for pos, prev_ll_idx := start, start.logical_line; pos.Less(end) || pos.Equal(&end); self.logical_lines.IncrementScrollPosBy(&pos, 1) { + ll := self.logical_lines.At(pos.logical_line) + var line string + switch ll.line_type { + case EMPTY_LINE: + case IMAGE_LINE: + if pos.screen_line < ll.image_lines_offset { + line = self.logical_lines.ScreenLineAt(pos) + } + default: + line = self.logical_lines.ScreenLineAt(pos) + } + line = wcswidth.StripEscapeCodes(line) + s, e := self.mouse_selection.LineBounds(&pos) + line = wcswidth.TruncateToVisualLength(line, e+1) + if s > 0 { + prefix := wcswidth.TruncateToVisualLength(line, s) + line = line[len(prefix):] + } + // TODO: look at the original line from the source and handle leading tabs and trailing spaces as per it + tline := strings.TrimRight(line, " ") + if len(tline) < len(line) { + line = tline + " " + } + if pos.logical_line > prev_ll_idx { + line = "\n" + line + } + prev_ll_idx = pos.logical_line + if line != "" { + text = append(text, line...) + } + } + return utils.UnsafeBytesToString(text) +} + func (self *Handler) finish_mouse_selection(ev *loop.MouseEvent) { if !self.mouse_selection.IsActive() { return } self.update_mouse_selection(ev) self.mouse_selection.Finish() + text := self.text_for_current_mouse_selection() + if text != "" { + self.lp.CopyTextToPrimarySelection(text) + } } func (self *Handler) add_mouse_selection_to_line(line string, line_pos ScrollPos, y int) string { diff --git a/tools/tui/loop/api.go b/tools/tui/loop/api.go index 0802870bc..234ba7972 100644 --- a/tools/tui/loop/api.go +++ b/tools/tui/loop/api.go @@ -405,3 +405,17 @@ const ( func (self *Loop) SetDefaultColor(which DefaultColor, val style.RGBA) { self.QueueWriteString(fmt.Sprintf("\033]%d;%s\033\\", int(which), val.AsRGBSharp())) } + +func (self *Loop) copy_text_to(text, dest string) { + self.QueueWriteString("\x1b]52;" + dest + ";") + self.QueueWriteString(base64.StdEncoding.EncodeToString(utils.UnsafeStringToBytes(text))) + self.QueueWriteString("\x1b\\") +} + +func (self *Loop) CopyTextToPrimarySelection(text string) { + self.copy_text_to(text, "p") +} + +func (self *Loop) CopyTextToClipboard(text string) { + self.copy_text_to(text, "c") +} diff --git a/tools/tui/mouse.go b/tools/tui/mouse.go index 04514c5d1..dc0b6a8b4 100644 --- a/tools/tui/mouse.go +++ b/tools/tui/mouse.go @@ -152,3 +152,11 @@ func (ms *MouseSelection) LineFormatSuffix(line_pos LinePos, sgr string, y int) } return "" } + +func (ms *MouseSelection) StartLine() LinePos { + return ms.start.line +} + +func (ms *MouseSelection) EndLine() LinePos { + return ms.end.line +}