]> git.lizzy.rs Git - micro.git/blob - src/micro.go
Add help text
[micro.git] / src / micro.go
1 package main
2
3 import (
4         "fmt"
5         "github.com/gdamore/tcell"
6         "github.com/go-errors/errors"
7         "github.com/mattn/go-isatty"
8         "io/ioutil"
9         "os"
10 )
11
12 const (
13         synLinesUp           = 75  // How many lines up to look to do syntax highlighting
14         synLinesDown         = 75  // How many lines down to look to do syntax highlighting
15         doubleClickThreshold = 400 // How many milliseconds to wait before a second click is not a double click
16 )
17
18 // The main screen
19 var screen tcell.Screen
20
21 // Object to send messages and prompts to the user
22 var messenger *Messenger
23
24 // LoadInput loads the file input for the editor
25 func LoadInput() (string, []byte, error) {
26         // There are a number of ways micro should start given its input
27         // 1. If it is given a file in os.Args, it should open that
28
29         // 2. If there is no input file and the input is not a terminal, that means
30         // something is being piped in and the stdin should be opened in an
31         // empty buffer
32
33         // 3. If there is no input file and the input is a terminal, an empty buffer
34         // should be opened
35
36         // These are empty by default so if we get to option 3, we can just returns the
37         // default values
38         var filename string
39         var input []byte
40         var err error
41
42         if len(os.Args) > 1 {
43                 // Option 1
44                 filename = os.Args[1]
45                 // Check that the file exists
46                 if _, e := os.Stat(filename); e == nil {
47                         input, err = ioutil.ReadFile(filename)
48                 }
49         } else if !isatty.IsTerminal(os.Stdin.Fd()) {
50                 // Option 2
51                 // The input is not a terminal, so something is being piped in
52                 // and we should read from stdin
53                 input, err = ioutil.ReadAll(os.Stdin)
54         }
55
56         // Option 3, or just return whatever we got
57         return filename, input, err
58 }
59
60 func main() {
61         filename, input, err := LoadInput()
62         if err != nil {
63                 fmt.Println(err)
64                 os.Exit(1)
65         }
66
67         InitOptions()
68
69         // Should we enable true color?
70         truecolor := os.Getenv("MICRO_TRUECOLOR") == "1"
71
72         // In order to enable true color, we have to set the TERM to `xterm-truecolor` when
73         // initializing tcell, but after that, we can set the TERM back to whatever it was
74         oldTerm := os.Getenv("TERM")
75         if truecolor {
76                 os.Setenv("TERM", "xterm-truecolor")
77         }
78
79         // Load the syntax files, including the colorscheme
80         LoadSyntaxFiles()
81
82         // Initilize tcell
83         screen, err = tcell.NewScreen()
84         if err != nil {
85                 fmt.Println(err)
86                 os.Exit(1)
87         }
88         if err = screen.Init(); err != nil {
89                 fmt.Println(err)
90                 os.Exit(1)
91         }
92
93         // Now we can put the TERM back to what it was before
94         if truecolor {
95                 os.Setenv("TERM", oldTerm)
96         }
97
98         // This is just so if we have an error, we can exit cleanly and not completely
99         // mess up the terminal being worked in
100         defer func() {
101                 if err := recover(); err != nil {
102                         screen.Fini()
103                         fmt.Println("Micro encountered an error:", err)
104                         // Print the stack trace too
105                         fmt.Print(errors.Wrap(err, 2).ErrorStack())
106                         os.Exit(1)
107                 }
108         }()
109
110         // Default style
111         defStyle := tcell.StyleDefault.
112                 Foreground(tcell.ColorDefault).
113                 Background(tcell.ColorDefault)
114
115         // There may be another default style defined in the colorscheme
116         if style, ok := colorscheme["default"]; ok {
117                 defStyle = style
118         }
119
120         screen.SetStyle(defStyle)
121         screen.EnableMouse()
122
123         messenger = new(Messenger)
124         view := NewView(NewBuffer(string(input), filename))
125
126         for {
127                 // Display everything
128                 screen.Clear()
129
130                 view.Display()
131                 messenger.Display()
132
133                 screen.Show()
134
135                 // Wait for the user's action
136                 event := screen.PollEvent()
137
138                 // Check if we should quit
139                 switch e := event.(type) {
140                 case *tcell.EventKey:
141                         switch e.Key() {
142                         case tcell.KeyCtrlQ:
143                                 // Make sure not to quit if there are unsaved changes
144                                 if view.CanClose("Quit anyway? ") {
145                                         screen.Fini()
146                                         os.Exit(0)
147                                 }
148                         case tcell.KeyCtrlE:
149                                 SetOption(view)
150                         case tcell.KeyCtrlH:
151                                 DisplayHelp()
152                                 // Make sure to resize the view if the user resized the terminal while looking at the help text
153                                 view.Resize(screen.Size())
154                         }
155                 }
156
157                 // Send it to the view
158                 view.HandleEvent(event)
159         }
160 }