Add support for selection and copy in terminal

This commit adds mouse and copy support in the terminal emulator
in micro.
This commit is contained in:
Zachary Yedidia
2018-01-05 22:44:36 -05:00
parent d668050ebe
commit 3b36316b00
2 changed files with 81 additions and 12 deletions

View File

@@ -1,6 +1,8 @@
package main
import (
"fmt"
"os"
"os/exec"
"strconv"
@@ -16,10 +18,37 @@ const (
// A Terminal holds information for the terminal emulator
type Terminal struct {
state terminal.State
term *terminal.VT
title string
status int
state terminal.State
term *terminal.VT
title string
status int
selection [2]Loc
}
// HasSelection returns whether this terminal has a valid selection
func (t *Terminal) HasSelection() bool {
return t.selection[0] != t.selection[1]
}
// GetSelection returns the selected text
func (t *Terminal) GetSelection(width int) string {
start := t.selection[0]
end := t.selection[1]
if start.GreaterThan(end) {
start, end = end, start
}
var ret string
var l Loc
for y := start.Y; y <= end.Y; y++ {
for x := 0; x < width; x++ {
l.X, l.Y = x, y
if l.GreaterEqual(start) && l.LessThan(end) {
c, _, _ := t.state.Cell(x, y)
ret += string(c)
}
}
}
return ret
}
// Start begins a new command in this terminal with a given view
@@ -41,6 +70,7 @@ func (t *Terminal) Start(execCmd []string, view *View) error {
for {
err := term.Parse()
if err != nil {
fmt.Fprintln(os.Stderr, "[Press enter to close]")
break
}
updateterm <- true
@@ -91,9 +121,10 @@ func (t *Terminal) Display(v *View) {
t.state.Lock()
defer t.state.Unlock()
var l Loc
for y := 0; y < v.Height; y++ {
for x := 0; x < v.Width; x++ {
l.X, l.Y = x, y
c, f, b := t.state.Cell(x, y)
fg, bg := int(f), int(b)
@@ -105,6 +136,10 @@ func (t *Terminal) Display(v *View) {
}
st := tcell.StyleDefault.Foreground(GetColor256(int(fg))).Background(GetColor256(int(bg)))
if l.LessThan(t.selection[1]) && l.GreaterEqual(t.selection[0]) || l.LessThan(t.selection[0]) && l.GreaterEqual(t.selection[1]) {
st = st.Reverse(true)
}
screen.SetContent(v.x+x+divider, v.y+y, c, nil, st)
}
}

View File

@@ -8,6 +8,7 @@ import (
"strings"
"time"
"github.com/zyedidia/clipboard"
"github.com/zyedidia/tcell"
"github.com/zyedidia/terminal"
)
@@ -534,15 +535,48 @@ func (v *View) SetCursor(c *Cursor) bool {
// HandleEvent handles an event passed by the main loop
func (v *View) HandleEvent(event tcell.Event) {
if v.Type == vtTerm {
if e, ok := event.(*tcell.EventKey); ok && v.term.status == VTDone {
switch e.Key() {
case tcell.KeyEscape, tcell.KeyCtrlQ, tcell.KeyEnter:
v.term.Close()
v.Type = vtDefault
default:
if e, ok := event.(*tcell.EventKey); ok {
if v.term.status == VTDone {
switch e.Key() {
case tcell.KeyEscape, tcell.KeyCtrlQ, tcell.KeyEnter:
v.term.Close()
v.Type = vtDefault
default:
}
}
} else if _, ok := event.(*tcell.EventMouse); !ok || v.term.state.Mode(terminal.ModeMouseMask) {
if e.Key() == tcell.KeyCtrlC && v.term.HasSelection() {
clipboard.WriteAll(v.term.GetSelection(v.Width), "clipboard")
messenger.Message("Copied selection to clipboard")
} else if v.term.status != VTDone {
v.term.WriteString(event.EscSeq())
}
} else if e, ok := event.(*tcell.EventMouse); !ok || v.term.state.Mode(terminal.ModeMouseMask) {
v.term.WriteString(event.EscSeq())
} else {
x, y := e.Position()
x -= v.x
y += v.y
if e.Buttons() == tcell.Button1 {
if !v.mouseReleased {
// drag
v.term.selection[1].X = x
v.term.selection[1].Y = y
} else {
v.term.selection[0].X = x
v.term.selection[0].Y = y
v.term.selection[1].X = x
v.term.selection[1].Y = y
}
v.mouseReleased = false
} else if e.Buttons() == tcell.ButtonNone {
if !v.mouseReleased {
v.term.selection[1].X = x
v.term.selection[1].Y = y
}
v.mouseReleased = true
}
}
return
}