micro/internal/shell/terminal.go

147 lines
3 KiB
Go
Raw Normal View History

2019-01-11 05:26:58 +03:00
package shell
import (
"bytes"
"os/exec"
"strconv"
2020-05-04 17:16:15 +03:00
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/screen"
2019-01-11 05:26:58 +03:00
"github.com/zyedidia/terminal"
)
type TermType int
2019-08-26 21:47:27 +03:00
type CallbackFunc func(string)
2019-01-11 05:26:58 +03:00
const (
2019-01-11 22:49:22 +03:00
TTClose = iota // Should be closed
2019-01-11 05:26:58 +03:00
TTRunning // Currently running a command
TTDone // Finished running a command
)
2019-08-26 21:47:27 +03:00
var CloseTerms chan bool
func init() {
CloseTerms = make(chan bool)
}
2019-01-11 05:26:58 +03:00
// A Terminal holds information for the terminal emulator
type Terminal struct {
State terminal.State
Term *terminal.VT
title string
Status TermType
Selection [2]buffer.Loc
wait bool
getOutput bool
output *bytes.Buffer
2019-08-26 21:47:27 +03:00
callback CallbackFunc
2019-01-11 05:26:58 +03:00
}
// HasSelection returns whether this terminal has a valid selection
func (t *Terminal) HasSelection() bool {
return t.Selection[0] != t.Selection[1]
}
2019-01-11 22:49:22 +03:00
func (t *Terminal) Name() string {
return t.title
}
2019-01-11 05:26:58 +03:00
// 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 buffer.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
func (t *Terminal) Start(execCmd []string, getOutput bool, wait bool, callback func(out string, userargs []interface{}), userargs []interface{}) error {
2019-01-11 05:26:58 +03:00
if len(execCmd) <= 0 {
return nil
}
cmd := exec.Command(execCmd[0], execCmd[1:]...)
t.output = nil
if getOutput {
t.output = bytes.NewBuffer([]byte{})
2023-09-09 09:27:39 +03:00
cmd.Stdout = t.output
2019-01-11 05:26:58 +03:00
}
Term, _, err := terminal.Start(&t.State, cmd)
2019-01-11 05:26:58 +03:00
if err != nil {
return err
}
t.Term = Term
t.getOutput = getOutput
t.Status = TTRunning
t.title = execCmd[0] + ":" + strconv.Itoa(cmd.Process.Pid)
2019-01-11 22:49:22 +03:00
t.wait = wait
t.callback = func(out string) {
callback(out, userargs)
2019-08-26 21:47:27 +03:00
}
2019-01-11 05:26:58 +03:00
go func() {
for {
err := Term.Parse()
if err != nil {
Term.Write([]byte("Press enter to close"))
screen.Redraw()
2019-01-11 05:26:58 +03:00
break
}
screen.Redraw()
}
2019-01-11 22:49:22 +03:00
t.Stop()
2019-01-11 05:26:58 +03:00
}()
return nil
}
// Stop stops execution of the terminal and sets the Status
// to TTDone
func (t *Terminal) Stop() {
t.Term.File().Close()
t.Term.Close()
if t.wait {
t.Status = TTDone
} else {
t.Close()
2019-08-26 21:47:27 +03:00
CloseTerms <- true
2019-01-11 05:26:58 +03:00
}
}
2019-01-11 22:49:22 +03:00
// Close sets the Status to TTClose indicating that the terminal
// is done and should be closed
2019-01-11 05:26:58 +03:00
func (t *Terminal) Close() {
2019-01-11 22:49:22 +03:00
t.Status = TTClose
2019-01-11 05:26:58 +03:00
// call the lua function that the user has given as a callback
if t.getOutput {
2019-08-26 21:47:27 +03:00
if t.callback != nil {
Jobs <- JobFunction{
Function: func(out string, args []interface{}) {
t.callback(out)
},
Output: t.output.String(),
Args: nil,
}
2019-08-26 21:47:27 +03:00
}
2019-01-11 05:26:58 +03:00
}
}
// WriteString writes a given string to this terminal's pty
func (t *Terminal) WriteString(str string) {
t.Term.File().WriteString(str)
}