diff --git a/cmd/micro/terminal.go b/cmd/micro/terminal.go index 6049cf0f..45b61db1 100644 --- a/cmd/micro/terminal.go +++ b/cmd/micro/terminal.go @@ -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) } } diff --git a/cmd/micro/view.go b/cmd/micro/view.go index 860e72e9..62763428 100644 --- a/cmd/micro/view.go +++ b/cmd/micro/view.go @@ -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 }