Clean up terminal a bit and wait before closing

This commit is contained in:
Zachary Yedidia
2018-01-05 21:38:40 -05:00
parent 770cb87f7a
commit dd47f167f1
3 changed files with 138 additions and 79 deletions

View File

@@ -75,7 +75,7 @@ func (sline *Statusline) Display() {
fileRunes := []rune(file)
if sline.view.Type == vtTerm {
fileRunes = []rune(sline.view.termtitle)
fileRunes = []rune(sline.view.term.title)
rightText = ""
}

115
cmd/micro/terminal.go Normal file
View File

@@ -0,0 +1,115 @@
package main
import (
"os/exec"
"strconv"
"github.com/zyedidia/tcell"
"github.com/zyedidia/terminal"
)
const (
VTIdle = iota // Waiting for a new command
VTRunning // Currently running a command
VTDone // Finished running a command
)
// A Terminal holds information for the terminal emulator
type Terminal struct {
state terminal.State
term *terminal.VT
title string
status int
}
// Start begins a new command in this terminal with a given view
func (t *Terminal) Start(execCmd []string, view *View) error {
if len(execCmd) <= 0 {
return nil
}
cmd := exec.Command(execCmd[0], execCmd[1:]...)
term, _, err := terminal.Start(&t.state, cmd)
if err != nil {
return err
}
t.term = term
t.status = VTRunning
t.title = execCmd[0] + ":" + strconv.Itoa(cmd.Process.Pid)
go func() {
for {
err := term.Parse()
if err != nil {
break
}
updateterm <- true
}
closeterm <- view.Num
}()
return nil
}
// Resize informs the terminal of a resize event
func (t *Terminal) Resize(width, height int) {
t.term.Resize(width, height)
}
// Stop stops execution of the terminal and sets the status
// to VTDone
func (t *Terminal) Stop() {
t.term.File().Close()
t.term.Close()
t.status = VTDone
}
// Close sets the status to VTIdle indicating that the terminal
// is ready for a new command to execute
func (t *Terminal) Close() {
t.status = VTIdle
}
// WriteString writes a given string to this terminal's pty
func (t *Terminal) WriteString(str string) {
t.term.File().WriteString(str)
}
// Display displays this terminal in a view
func (t *Terminal) Display(v *View) {
divider := 0
if v.x != 0 {
divider = 1
dividerStyle := defStyle
if style, ok := colorscheme["divider"]; ok {
dividerStyle = style
}
for i := 0; i < v.Height; i++ {
screen.SetContent(v.x, v.y+i, '|', nil, dividerStyle.Reverse(true))
}
}
t.state.Lock()
defer t.state.Unlock()
for y := 0; y < v.Height; y++ {
for x := 0; x < v.Width; x++ {
c, f, b := t.state.Cell(x, y)
fg, bg := int(f), int(b)
if f == terminal.DefaultFG {
fg = int(tcell.ColorDefault)
}
if b == terminal.DefaultBG {
bg = int(tcell.ColorDefault)
}
st := tcell.StyleDefault.Foreground(GetColor256(int(fg))).Background(GetColor256(int(bg)))
screen.SetContent(v.x+x+divider, v.y+y, c, nil, st)
}
}
if t.state.CursorVisible() && tabs[curTab].CurView == v.Num {
curx, cury := t.state.Cursor()
screen.ShowCursor(curx+v.x+divider, cury+v.y)
}
}

View File

@@ -3,7 +3,6 @@ package main
import (
"fmt"
"os"
"os/exec"
"reflect"
"strconv"
"strings"
@@ -97,16 +96,16 @@ type View struct {
// Same here, just to keep track for mouse move events
tripleClick bool
// The cellview used for displaying and syntax highlighting
cellview *CellView
splitNode *LeafNode
// The scrollbar
scrollbar *ScrollBar
termState terminal.State
pty *os.File
term *terminal.VT
termtitle string
// Virtual terminal
term *Terminal
}
// NewView returns a new fullscreen view
@@ -144,6 +143,8 @@ func NewViewWidthHeight(buf *Buffer, w, h int) *View {
v.Height--
}
v.term = new(Terminal)
for pl := range loadedPlugins {
_, err := Call(pl+".onViewOpen", v)
if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
@@ -166,42 +167,18 @@ func (v *View) ToggleStatusLine() {
// StartTerminal execs a command in this view
func (v *View) StartTerminal(execCmd []string) error {
// cmd := exec.Command(os.Getenv("SHELL"), "-i")
if len(execCmd) <= 0 {
return nil
err := v.term.Start(execCmd, v)
if err == nil {
v.term.Resize(v.Width, v.Height)
v.Type = vtTerm
}
cmd := exec.Command(execCmd[0], execCmd[1:]...)
term, pty, err := terminal.Start(&v.termState, cmd)
if err != nil {
return err
}
term.Resize(v.Width, v.Height)
v.Type = vtTerm
v.term = term
v.termtitle = execCmd[0]
v.pty = pty
go func() {
for {
err := term.Parse()
if err != nil {
fmt.Fprintln(os.Stderr, err)
break
}
updateterm <- true
}
closeterm <- v.Num
}()
return nil
return err
}
// CloseTerminal shuts down the tty running in this view
// and returns it to the default view type
func (v *View) CloseTerminal() {
v.pty.Close()
v.term.Close()
v.Type = vtDefault
v.term.Stop()
}
// ToggleTabbar creates an extra row for the tabbar if necessary
@@ -557,8 +534,15 @@ 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 _, ok := event.(*tcell.EventMouse); !ok || v.termState.Mode(terminal.ModeMouseMask) {
v.pty.WriteString(event.EscSeq())
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:
}
} else if _, ok := event.(*tcell.EventMouse); !ok || v.term.state.Mode(terminal.ModeMouseMask) {
v.term.WriteString(event.EscSeq())
}
return
}
@@ -795,50 +779,10 @@ func (v *View) openHelp(helpPage string) {
}
}
// DisplayTerm draws a terminal in this window
// The view's type must be vtTerm
func (v *View) DisplayTerm() {
divider := 0
if v.x != 0 {
divider = 1
dividerStyle := defStyle
if style, ok := colorscheme["divider"]; ok {
dividerStyle = style
}
for i := 0; i < v.Height; i++ {
screen.SetContent(v.x, v.y+i, '|', nil, dividerStyle.Reverse(true))
}
}
v.termState.Lock()
defer v.termState.Unlock()
for y := 0; y < v.Height; y++ {
for x := 0; x < v.Width; x++ {
c, f, b := v.termState.Cell(x, y)
fg, bg := int(f), int(b)
if f == terminal.DefaultFG {
fg = int(tcell.ColorDefault)
}
if b == terminal.DefaultBG {
bg = int(tcell.ColorDefault)
}
st := tcell.StyleDefault.Foreground(GetColor256(int(fg))).Background(GetColor256(int(bg)))
screen.SetContent(v.x+x+divider, v.y+y, c, nil, st)
}
}
if v.termState.CursorVisible() && tabs[curTab].CurView == v.Num {
curx, cury := v.termState.Cursor()
screen.ShowCursor(curx+v.x+divider, cury+v.y)
}
}
// DisplayView draws the view to the screen
func (v *View) DisplayView() {
if v.Type == vtTerm {
v.DisplayTerm()
v.term.Display(v)
return
}