10 "github.com/zyedidia/tcell"
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"
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 events = make(chan tcell.Event)
216 // Here is the event loop which runs in a separate thread
220 e := screen.Screen.PollEvent()
229 // Display everything
230 screen.Screen.Fill(' ', config.DefStyle)
231 screen.Screen.HideCursor()
232 action.Tabs.Display()
233 for _, ep := range action.MainTab().Panes {
236 action.MainTab().Display()
237 action.InfoBar.Display()
240 var event tcell.Event
242 // Check for new events
244 case f := <-shell.Jobs:
245 // If a new job has finished while running in the background we should execute the callback
246 f.Function(f.Output, f.Args...)
247 case <-config.Autosave:
248 for _, b := range buffer.OpenBuffers {
251 case <-shell.CloseTerms:
252 case event = <-events:
253 case <-screen.DrawChan:
256 if action.InfoBar.HasPrompt {
257 action.InfoBar.HandleEvent(event)
259 action.Tabs.HandleEvent(event)