11 "github.com/go-errors/errors"
12 isatty "github.com/mattn/go-isatty"
13 "github.com/zyedidia/micro/internal/action"
14 "github.com/zyedidia/micro/internal/buffer"
15 "github.com/zyedidia/micro/internal/config"
16 "github.com/zyedidia/micro/internal/screen"
17 "github.com/zyedidia/micro/internal/shell"
18 "github.com/zyedidia/micro/internal/util"
19 "github.com/zyedidia/tcell"
24 events chan tcell.Event
28 flagVersion = flag.Bool("version", false, "Show the version number and information")
29 flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
30 flagOptions = flag.Bool("options", false, "Show all option help")
31 optionFlags map[string]*string
36 fmt.Println("Usage: micro [OPTIONS] [FILE]...")
37 fmt.Println("-config-dir dir")
38 fmt.Println(" \tSpecify a custom location for the configuration directory")
39 fmt.Println("[FILE]:LINE:COL")
40 fmt.Println(" \tSpecify a line and column to start the cursor at when opening a buffer")
41 fmt.Println(" \tThis can also be done by opening file:LINE:COL")
42 fmt.Println("-options")
43 fmt.Println(" \tShow all option help")
44 fmt.Println("-version")
45 fmt.Println(" \tShow the version number and information")
47 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")
48 fmt.Println("-option value")
49 fmt.Println(" \tSet `option` to `value` for this session")
50 fmt.Println(" \tFor example: `micro -syntax off file.c`")
51 fmt.Println("\nUse `micro -options` to see the full list of configuration options")
54 optionFlags = make(map[string]*string)
56 for k, v := range config.DefaultAllSettings() {
57 optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'.", k, v))
63 // If -version was passed
64 fmt.Println("Version:", util.Version)
65 fmt.Println("Commit hash:", util.CommitHash)
66 fmt.Println("Compiled on", util.CompileDate)
71 // If -options was passed
73 m := config.DefaultAllSettings()
75 keys = append(keys, k)
78 for _, k := range keys {
80 fmt.Printf("-%s value\n", k)
81 fmt.Printf(" \tDefault value: '%v'\n", v)
87 // LoadInput determines which files should be loaded into buffers
88 // based on the input stored in flag.Args()
89 func LoadInput() []*buffer.Buffer {
90 // There are a number of ways micro should start given its input
92 // 1. If it is given a files in flag.Args(), it should open those
94 // 2. If there is no input file and the input is not a terminal, that means
95 // something is being piped in and the stdin should be opened in an
98 // 3. If there is no input file and the input is a terminal, an empty buffer
105 buffers := make([]*buffer.Buffer, 0, len(args))
109 // We go through each file and load it
110 for i := 0; i < len(args); i++ {
111 buf, err := buffer.NewBufferFromFile(args[i], buffer.BTDefault)
113 screen.TermMessage(err)
116 // If the file didn't exist, input will be empty, and we'll open an empty buffer
117 buffers = append(buffers, buf)
119 } else if !isatty.IsTerminal(os.Stdin.Fd()) {
121 // The input is not a terminal, so something is being piped in
122 // and we should read from stdin
123 input, err = ioutil.ReadAll(os.Stdin)
125 screen.TermMessage("Error reading from stdin: ", err)
128 buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
130 // Option 3, just open an empty buffer
131 buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault))
144 err = config.InitConfigDir(*flagConfigDir)
146 screen.TermMessage(err)
149 config.InitRuntimeFiles()
150 err = config.ReadSettings()
152 screen.TermMessage(err)
154 config.InitGlobalSettings()
157 for k, v := range optionFlags {
159 nativeValue, err := config.GetNativeValue(k, config.DefaultAllSettings()[k], *v)
161 screen.TermMessage(err)
164 config.GlobalSettings[k] = nativeValue
168 action.InitBindings()
169 action.InitCommands()
171 err = config.InitColorscheme()
173 screen.TermMessage(err)
176 err = config.LoadAllPlugins()
178 screen.TermMessage(err)
180 err = config.RunPluginFn("init")
182 screen.TermMessage(err)
187 // If we have an error, we can exit cleanly and not completely
188 // mess up the terminal being worked in
189 // In other words we need to shut down tcell before the program crashes
191 if err := recover(); err != nil {
193 fmt.Println("Micro encountered an error:", err)
194 // Print the stack trace too
195 fmt.Print(errors.Wrap(err, 2).ErrorStack())
204 // Here is the event loop which runs in a separate thread
206 events = make(chan tcell.Event)
209 e := screen.Screen.PollEvent()
218 // Display everything
219 screen.Screen.Fill(' ', config.DefStyle)
220 screen.Screen.HideCursor()
221 action.Tabs.Display()
222 for _, ep := range action.MainTab().Panes {
225 action.MainTab().Display()
226 action.InfoBar.Display()
229 var event tcell.Event
231 // Check for new events
233 case f := <-shell.Jobs:
234 // If a new job has finished while running in the background we should execute the callback
235 f.Function(f.Output, f.Args...)
236 case <-config.Autosave:
237 for _, b := range buffer.OpenBuffers {
240 case event = <-events:
241 case <-screen.DrawChan:
244 if action.InfoBar.HasPrompt {
245 action.InfoBar.HandleEvent(event)
247 action.Tabs.HandleEvent(event)
249 log.Println("Done event cycle")