12 "github.com/go-errors/errors"
13 isatty "github.com/mattn/go-isatty"
14 "github.com/zyedidia/micro/internal/action"
15 "github.com/zyedidia/micro/internal/buffer"
16 "github.com/zyedidia/micro/internal/config"
17 "github.com/zyedidia/micro/internal/screen"
18 "github.com/zyedidia/micro/internal/shell"
19 "github.com/zyedidia/micro/internal/util"
20 "github.com/zyedidia/tcell"
25 events chan tcell.Event
29 flagVersion = flag.Bool("version", false, "Show the version number and information")
30 flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
31 flagOptions = flag.Bool("options", false, "Show all option help")
32 flagDebug = flag.Bool("debug", false, "Enable debug mode (prints debug info to ./log.txt)")
33 optionFlags map[string]*string
38 fmt.Println("Usage: micro [OPTIONS] [FILE]...")
39 fmt.Println("-config-dir dir")
40 fmt.Println(" \tSpecify a custom location for the configuration directory")
41 fmt.Println("[FILE]:LINE:COL")
42 fmt.Println(" \tSpecify a line and column to start the cursor at when opening a buffer")
43 fmt.Println(" \tThis can also be done by opening file:LINE:COL")
44 fmt.Println("-options")
45 fmt.Println(" \tShow all option help")
47 fmt.Println(" \tEnable debug mode (enables logging to ./log.txt)")
48 fmt.Println("-version")
49 fmt.Println(" \tShow the version number and information")
51 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")
52 fmt.Println("-option value")
53 fmt.Println(" \tSet `option` to `value` for this session")
54 fmt.Println(" \tFor example: `micro -syntax off file.c`")
55 fmt.Println("\nUse `micro -options` to see the full list of configuration options")
58 optionFlags = make(map[string]*string)
60 for k, v := range config.DefaultAllSettings() {
61 optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'.", k, v))
67 // If -version was passed
68 fmt.Println("Version:", util.Version)
69 fmt.Println("Commit hash:", util.CommitHash)
70 fmt.Println("Compiled on", util.CompileDate)
75 // If -options was passed
77 m := config.DefaultAllSettings()
79 keys = append(keys, k)
82 for _, k := range keys {
84 fmt.Printf("-%s value\n", k)
85 fmt.Printf(" \tDefault value: '%v'\n", v)
90 if util.Debug == "OFF" && *flagDebug {
95 // LoadInput determines which files should be loaded into buffers
96 // based on the input stored in flag.Args()
97 func LoadInput() []*buffer.Buffer {
98 // There are a number of ways micro should start given its input
100 // 1. If it is given a files in flag.Args(), it should open those
102 // 2. If there is no input file and the input is not a terminal, that means
103 // something is being piped in and the stdin should be opened in an
106 // 3. If there is no input file and the input is a terminal, an empty buffer
113 buffers := make([]*buffer.Buffer, 0, len(args))
117 // We go through each file and load it
118 for i := 0; i < len(args); i++ {
119 buf, err := buffer.NewBufferFromFile(args[i], buffer.BTDefault)
121 screen.TermMessage(err)
124 // If the file didn't exist, input will be empty, and we'll open an empty buffer
125 buffers = append(buffers, buf)
127 } else if !isatty.IsTerminal(os.Stdin.Fd()) {
129 // The input is not a terminal, so something is being piped in
130 // and we should read from stdin
131 input, err = ioutil.ReadAll(os.Stdin)
133 screen.TermMessage("Error reading from stdin: ", err)
136 buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
138 // Option 3, just open an empty buffer
139 buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
148 // runtime.SetCPUProfileRate(400)
149 // f, _ := os.Create("micro.prof")
150 // pprof.StartCPUProfile(f)
151 // defer pprof.StopCPUProfile()
159 err = config.InitConfigDir(*flagConfigDir)
161 screen.TermMessage(err)
164 config.InitRuntimeFiles()
165 err = config.ReadSettings()
167 screen.TermMessage(err)
169 config.InitGlobalSettings()
172 for k, v := range optionFlags {
174 nativeValue, err := config.GetNativeValue(k, config.DefaultAllSettings()[k], *v)
176 screen.TermMessage(err)
179 config.GlobalSettings[k] = nativeValue
185 // If we have an error, we can exit cleanly and not completely
186 // mess up the terminal being worked in
187 // In other words we need to shut down tcell before the program crashes
189 if err := recover(); err != nil {
191 fmt.Println("Micro encountered an error:", err)
192 // backup all open buffers
193 for _, b := range buffer.OpenBuffers {
196 // Print the stack trace too
197 fmt.Print(errors.Wrap(err, 2).ErrorStack())
202 action.InitBindings()
203 action.InitCommands()
205 err = config.InitColorscheme()
207 screen.TermMessage(err)
210 err = config.LoadAllPlugins()
212 screen.TermMessage(err)
214 err = config.RunPluginFn("init")
216 screen.TermMessage(err)
222 // No buffers to open
230 events = make(chan tcell.Event)
232 // Here is the event loop which runs in a separate thread
236 e := screen.Screen.PollEvent()
244 // clear the drawchan so we don't redraw excessively
245 // if someone requested a redraw before we started displaying
246 for len(screen.DrawChan) > 0 {
250 var event tcell.Event
252 // wait for initial resize event
254 case event = <-events:
255 action.Tabs.HandleEvent(event)
256 case <-time.After(20 * time.Millisecond):
257 // time out after 10ms
261 // Display everything
262 screen.Screen.Fill(' ', config.DefStyle)
263 screen.Screen.HideCursor()
264 action.Tabs.Display()
265 for _, ep := range action.MainTab().Panes {
268 action.MainTab().Display()
269 action.InfoBar.Display()
274 // Check for new events
276 case f := <-shell.Jobs:
277 // If a new job has finished while running in the background we should execute the callback
278 f.Function(f.Output, f.Args...)
279 case <-config.Autosave:
280 for _, b := range buffer.OpenBuffers {
283 case <-shell.CloseTerms:
284 case event = <-events:
285 case <-screen.DrawChan:
288 if action.InfoBar.HasPrompt {
289 action.InfoBar.HandleEvent(event)
291 action.Tabs.HandleEvent(event)