10 "github.com/go-errors/errors"
11 isatty "github.com/mattn/go-isatty"
12 "github.com/zyedidia/micro/internal/action"
13 "github.com/zyedidia/micro/internal/buffer"
14 "github.com/zyedidia/micro/internal/config"
15 "github.com/zyedidia/micro/internal/screen"
16 "github.com/zyedidia/micro/internal/shell"
17 "github.com/zyedidia/micro/internal/util"
18 "github.com/zyedidia/tcell"
23 events chan tcell.Event
27 flagVersion = flag.Bool("version", false, "Show the version number and information")
28 flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
29 flagOptions = flag.Bool("options", false, "Show all option help")
30 optionFlags map[string]*string
35 fmt.Println("Usage: micro [OPTIONS] [FILE]...")
36 fmt.Println("-config-dir dir")
37 fmt.Println(" \tSpecify a custom location for the configuration directory")
38 fmt.Println("[FILE]:LINE:COL")
39 fmt.Println(" \tSpecify a line and column to start the cursor at when opening a buffer")
40 fmt.Println(" \tThis can also be done by opening file:LINE:COL")
41 fmt.Println("-options")
42 fmt.Println(" \tShow all option help")
43 fmt.Println("-version")
44 fmt.Println(" \tShow the version number and information")
46 fmt.Print("\nMicro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the settings.json\nfile (see 'help options').\n\n")
47 fmt.Println("-option value")
48 fmt.Println(" \tSet `option` to `value` for this session")
49 fmt.Println(" \tFor example: `micro -syntax off file.c`")
50 fmt.Println("\nUse `micro -options` to see the full list of configuration options")
53 optionFlags = make(map[string]*string)
55 for k, v := range config.DefaultAllSettings() {
56 optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'.", k, v))
62 // If -version was passed
63 fmt.Println("Version:", util.Version)
64 fmt.Println("Commit hash:", util.CommitHash)
65 fmt.Println("Compiled on", util.CompileDate)
70 // If -options was passed
72 m := config.DefaultAllSettings()
74 keys = append(keys, k)
77 for _, k := range keys {
79 fmt.Printf("-%s value\n", k)
80 fmt.Printf(" \tDefault value: '%v'\n", v)
86 // LoadInput determines which files should be loaded into buffers
87 // based on the input stored in flag.Args()
88 func LoadInput() []*buffer.Buffer {
89 // There are a number of ways micro should start given its input
91 // 1. If it is given a files in flag.Args(), it should open those
93 // 2. If there is no input file and the input is not a terminal, that means
94 // something is being piped in and the stdin should be opened in an
97 // 3. If there is no input file and the input is a terminal, an empty buffer
104 buffers := make([]*buffer.Buffer, 0, len(args))
108 // We go through each file and load it
109 for i := 0; i < len(args); i++ {
110 buf, err := buffer.NewBufferFromFile(args[i], buffer.BTDefault)
112 screen.TermMessage(err)
115 // If the file didn't exist, input will be empty, and we'll open an empty buffer
116 buffers = append(buffers, buf)
118 } else if !isatty.IsTerminal(os.Stdin.Fd()) {
120 // The input is not a terminal, so something is being piped in
121 // and we should read from stdin
122 input, err = ioutil.ReadAll(os.Stdin)
124 screen.TermMessage("Error reading from stdin: ", err)
127 buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
129 // Option 3, just open an empty buffer
130 buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
139 // runtime.SetCPUProfileRate(400)
140 // f, _ := os.Create("micro.prof")
141 // pprof.StartCPUProfile(f)
142 // defer pprof.StopCPUProfile()
150 err = config.InitConfigDir(*flagConfigDir)
152 screen.TermMessage(err)
155 config.InitRuntimeFiles()
156 err = config.ReadSettings()
158 screen.TermMessage(err)
160 config.InitGlobalSettings()
163 for k, v := range optionFlags {
165 nativeValue, err := config.GetNativeValue(k, config.DefaultAllSettings()[k], *v)
167 screen.TermMessage(err)
170 config.GlobalSettings[k] = nativeValue
174 action.InitBindings()
175 action.InitCommands()
177 err = config.InitColorscheme()
179 screen.TermMessage(err)
182 err = config.LoadAllPlugins()
184 screen.TermMessage(err)
186 err = config.RunPluginFn("init")
188 screen.TermMessage(err)
193 // If we have an error, we can exit cleanly and not completely
194 // mess up the terminal being worked in
195 // In other words we need to shut down tcell before the program crashes
197 if err := recover(); err != nil {
199 fmt.Println("Micro encountered an error:", err)
200 // backup all open buffers
201 for _, b := range buffer.OpenBuffers {
204 // Print the stack trace too
205 fmt.Print(errors.Wrap(err, 2).ErrorStack())
214 // Here is the event loop which runs in a separate thread
216 events = make(chan tcell.Event)
219 e := screen.Screen.PollEvent()
228 // Display everything
229 screen.Screen.Fill(' ', config.DefStyle)
230 screen.Screen.HideCursor()
231 action.Tabs.Display()
232 for _, ep := range action.MainTab().Panes {
235 action.MainTab().Display()
236 action.InfoBar.Display()
239 var event tcell.Event
241 // Check for new events
243 case f := <-shell.Jobs:
244 // If a new job has finished while running in the background we should execute the callback
245 f.Function(f.Output, f.Args...)
246 case <-config.Autosave:
247 for _, b := range buffer.OpenBuffers {
250 case <-shell.CloseTerms:
251 case event = <-events:
252 case <-screen.DrawChan:
255 if action.InfoBar.HasPrompt {
256 action.InfoBar.HandleEvent(event)
258 action.Tabs.HandleEvent(event)