]> git.lizzy.rs Git - micro.git/blob - cmd/micro/terminal.go
45b61db1c673630d6708f458a22926a8a6fab76e
[micro.git] / cmd / micro / terminal.go
1 package main
2
3 import (
4         "fmt"
5         "os"
6         "os/exec"
7         "strconv"
8
9         "github.com/zyedidia/tcell"
10         "github.com/zyedidia/terminal"
11 )
12
13 const (
14         VTIdle    = iota // Waiting for a new command
15         VTRunning        // Currently running a command
16         VTDone           // Finished running a command
17 )
18
19 // A Terminal holds information for the terminal emulator
20 type Terminal struct {
21         state     terminal.State
22         term      *terminal.VT
23         title     string
24         status    int
25         selection [2]Loc
26 }
27
28 // HasSelection returns whether this terminal has a valid selection
29 func (t *Terminal) HasSelection() bool {
30         return t.selection[0] != t.selection[1]
31 }
32
33 // GetSelection returns the selected text
34 func (t *Terminal) GetSelection(width int) string {
35         start := t.selection[0]
36         end := t.selection[1]
37         if start.GreaterThan(end) {
38                 start, end = end, start
39         }
40         var ret string
41         var l Loc
42         for y := start.Y; y <= end.Y; y++ {
43                 for x := 0; x < width; x++ {
44                         l.X, l.Y = x, y
45                         if l.GreaterEqual(start) && l.LessThan(end) {
46                                 c, _, _ := t.state.Cell(x, y)
47                                 ret += string(c)
48                         }
49                 }
50         }
51         return ret
52 }
53
54 // Start begins a new command in this terminal with a given view
55 func (t *Terminal) Start(execCmd []string, view *View) error {
56         if len(execCmd) <= 0 {
57                 return nil
58         }
59
60         cmd := exec.Command(execCmd[0], execCmd[1:]...)
61         term, _, err := terminal.Start(&t.state, cmd)
62         if err != nil {
63                 return err
64         }
65         t.term = term
66         t.status = VTRunning
67         t.title = execCmd[0] + ":" + strconv.Itoa(cmd.Process.Pid)
68
69         go func() {
70                 for {
71                         err := term.Parse()
72                         if err != nil {
73                                 fmt.Fprintln(os.Stderr, "[Press enter to close]")
74                                 break
75                         }
76                         updateterm <- true
77                 }
78                 closeterm <- view.Num
79         }()
80
81         return nil
82 }
83
84 // Resize informs the terminal of a resize event
85 func (t *Terminal) Resize(width, height int) {
86         t.term.Resize(width, height)
87 }
88
89 // Stop stops execution of the terminal and sets the status
90 // to VTDone
91 func (t *Terminal) Stop() {
92         t.term.File().Close()
93         t.term.Close()
94         t.status = VTDone
95 }
96
97 // Close sets the status to VTIdle indicating that the terminal
98 // is ready for a new command to execute
99 func (t *Terminal) Close() {
100         t.status = VTIdle
101 }
102
103 // WriteString writes a given string to this terminal's pty
104 func (t *Terminal) WriteString(str string) {
105         t.term.File().WriteString(str)
106 }
107
108 // Display displays this terminal in a view
109 func (t *Terminal) Display(v *View) {
110         divider := 0
111         if v.x != 0 {
112                 divider = 1
113                 dividerStyle := defStyle
114                 if style, ok := colorscheme["divider"]; ok {
115                         dividerStyle = style
116                 }
117                 for i := 0; i < v.Height; i++ {
118                         screen.SetContent(v.x, v.y+i, '|', nil, dividerStyle.Reverse(true))
119                 }
120         }
121         t.state.Lock()
122         defer t.state.Unlock()
123
124         var l Loc
125         for y := 0; y < v.Height; y++ {
126                 for x := 0; x < v.Width; x++ {
127                         l.X, l.Y = x, y
128                         c, f, b := t.state.Cell(x, y)
129
130                         fg, bg := int(f), int(b)
131                         if f == terminal.DefaultFG {
132                                 fg = int(tcell.ColorDefault)
133                         }
134                         if b == terminal.DefaultBG {
135                                 bg = int(tcell.ColorDefault)
136                         }
137                         st := tcell.StyleDefault.Foreground(GetColor256(int(fg))).Background(GetColor256(int(bg)))
138
139                         if l.LessThan(t.selection[1]) && l.GreaterEqual(t.selection[0]) || l.LessThan(t.selection[0]) && l.GreaterEqual(t.selection[1]) {
140                                 st = st.Reverse(true)
141                         }
142
143                         screen.SetContent(v.x+x+divider, v.y+y, c, nil, st)
144                 }
145         }
146         if t.state.CursorVisible() && tabs[curTab].CurView == v.Num {
147                 curx, cury := t.state.Cursor()
148                 screen.ShowCursor(curx+v.x+divider, cury+v.y)
149         }
150 }