]> git.lizzy.rs Git - micro.git/blob - internal/shell/terminal.go
Use shell job for terminal callback
[micro.git] / internal / shell / terminal.go
1 package shell
2
3 import (
4         "bytes"
5         "os/exec"
6         "strconv"
7
8         "github.com/zyedidia/micro/v2/internal/buffer"
9         "github.com/zyedidia/micro/v2/internal/screen"
10         "github.com/zyedidia/terminal"
11 )
12
13 type TermType int
14 type CallbackFunc func(string)
15
16 const (
17         TTClose   = iota // Should be closed
18         TTRunning        // Currently running a command
19         TTDone           // Finished running a command
20 )
21
22 var CloseTerms chan bool
23
24 func init() {
25         CloseTerms = make(chan bool)
26 }
27
28 // A Terminal holds information for the terminal emulator
29 type Terminal struct {
30         State     terminal.State
31         Term      *terminal.VT
32         title     string
33         Status    TermType
34         Selection [2]buffer.Loc
35         wait      bool
36         getOutput bool
37         output    *bytes.Buffer
38         callback  CallbackFunc
39 }
40
41 // HasSelection returns whether this terminal has a valid selection
42 func (t *Terminal) HasSelection() bool {
43         return t.Selection[0] != t.Selection[1]
44 }
45
46 func (t *Terminal) Name() string {
47         return t.title
48 }
49
50 // GetSelection returns the selected text
51 func (t *Terminal) GetSelection(width int) string {
52         start := t.Selection[0]
53         end := t.Selection[1]
54         if start.GreaterThan(end) {
55                 start, end = end, start
56         }
57         var ret string
58         var l buffer.Loc
59         for y := start.Y; y <= end.Y; y++ {
60                 for x := 0; x < width; x++ {
61                         l.X, l.Y = x, y
62                         if l.GreaterEqual(start) && l.LessThan(end) {
63                                 c, _, _ := t.State.Cell(x, y)
64                                 ret += string(c)
65                         }
66                 }
67         }
68         return ret
69 }
70
71 // Start begins a new command in this terminal with a given view
72 func (t *Terminal) Start(execCmd []string, getOutput bool, wait bool, callback func(out string, userargs []interface{}), userargs []interface{}) error {
73         if len(execCmd) <= 0 {
74                 return nil
75         }
76
77         cmd := exec.Command(execCmd[0], execCmd[1:]...)
78         t.output = nil
79         if getOutput {
80                 t.output = bytes.NewBuffer([]byte{})
81         }
82         Term, _, err := terminal.Start(&t.State, cmd, t.output)
83         if err != nil {
84                 return err
85         }
86         t.Term = Term
87         t.getOutput = getOutput
88         t.Status = TTRunning
89         t.title = execCmd[0] + ":" + strconv.Itoa(cmd.Process.Pid)
90         t.wait = wait
91         t.callback = func(out string) {
92                 callback(out, userargs)
93         }
94
95         go func() {
96                 for {
97                         err := Term.Parse()
98                         if err != nil {
99                                 Term.Write([]byte("Press enter to close"))
100                                 screen.Redraw()
101                                 break
102                         }
103                         screen.Redraw()
104                 }
105                 t.Stop()
106         }()
107
108         return nil
109 }
110
111 // Stop stops execution of the terminal and sets the Status
112 // to TTDone
113 func (t *Terminal) Stop() {
114         t.Term.File().Close()
115         t.Term.Close()
116         if t.wait {
117                 t.Status = TTDone
118         } else {
119                 t.Close()
120                 CloseTerms <- true
121         }
122 }
123
124 // Close sets the Status to TTClose indicating that the terminal
125 // is done and should be closed
126 func (t *Terminal) Close() {
127         t.Status = TTClose
128         // call the lua function that the user has given as a callback
129         if t.getOutput {
130                 if t.callback != nil {
131                         Jobs <- JobFunction{
132                                 Function: func(out string, args []interface{}) {
133                                         t.callback(out)
134                                 },
135                                 Output: t.output.String(),
136                                 Args:   nil,
137                         }
138                 }
139         }
140 }
141
142 // WriteString writes a given string to this terminal's pty
143 func (t *Terminal) WriteString(str string) {
144         t.Term.File().WriteString(str)
145 }