9 "github.com/go-errors/errors"
10 homedir "github.com/mitchellh/go-homedir"
11 "github.com/zyedidia/micro/cmd/micro/terminfo"
12 "github.com/zyedidia/tcell"
16 doubleClickThreshold = 400 // How many milliseconds to wait before a second click is not a double click
17 undoThreshold = 500 // If two events are less than n milliseconds apart, undo both of them
18 autosaveTime = 8 // Number of seconds to wait before autosaving
25 // Where the user's configuration is
26 // This should be $XDG_CONFIG_HOME/micro
27 // If $XDG_CONFIG_HOME is not set, it is ~/.config/micro
30 // Version is the version number or commit hash
31 // These variables should be set by the linker when compiling
32 Version = "0.0.0-unknown"
33 // CommitHash is the commit this version was built on
34 CommitHash = "Unknown"
35 // CompileDate is the date this binary was compiled on
36 CompileDate = "Unknown"
41 events chan tcell.Event
44 // How many redraws have happened
48 flagVersion = flag.Bool("version", false, "Show the version number and information")
49 flagStartPos = flag.String("startpos", "", "LINE,COL to start the cursor at when opening a buffer.")
50 flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
51 flagOptions = flag.Bool("options", false, "Show all option help")
54 // InitConfigDir finds the configuration directory for micro according to the XDG spec.
55 // If no directory is found, it creates one.
56 func InitConfigDir() {
57 xdgHome := os.Getenv("XDG_CONFIG_HOME")
59 // The user has not set $XDG_CONFIG_HOME so we should act like it was set to ~/.config
60 home, err := homedir.Dir()
62 TermMessage("Error finding your home directory\nCan't load config files")
65 xdgHome = home + "/.config"
67 configDir = xdgHome + "/micro"
69 if len(*flagConfigDir) > 0 {
70 if _, err := os.Stat(*flagConfigDir); os.IsNotExist(err) {
71 TermMessage("Error: " + *flagConfigDir + " does not exist. Defaulting to " + configDir + ".")
73 configDir = *flagConfigDir
78 if _, err := os.Stat(xdgHome); os.IsNotExist(err) {
79 // If the xdgHome doesn't exist we should create it
80 err = os.Mkdir(xdgHome, os.ModePerm)
82 TermMessage("Error creating XDG_CONFIG_HOME directory: " + err.Error())
86 if _, err := os.Stat(configDir); os.IsNotExist(err) {
87 // If the micro specific config directory doesn't exist we should create that too
88 err = os.Mkdir(configDir, os.ModePerm)
90 TermMessage("Error creating configuration directory: " + err.Error())
95 // InitScreen creates and initializes the tcell screen
97 // Should we enable true color?
98 truecolor := os.Getenv("MICRO_TRUECOLOR") == "1"
100 tcelldb := os.Getenv("TCELLDB")
101 os.Setenv("TCELLDB", configDir+"/.tcelldb")
103 // In order to enable true color, we have to set the TERM to `xterm-truecolor` when
104 // initializing tcell, but after that, we can set the TERM back to whatever it was
105 oldTerm := os.Getenv("TERM")
107 os.Setenv("TERM", "xterm-truecolor")
112 screen, err = tcell.NewScreen()
114 if err == tcell.ErrTermNotFound {
115 err = terminfo.WriteDB(configDir + "/.tcelldb")
118 fmt.Println("Fatal: Micro could not create tcelldb")
121 screen, err = tcell.NewScreen()
124 fmt.Println("Fatal: Micro could not initialize a screen.")
129 fmt.Println("Fatal: Micro could not initialize a screen.")
133 if err = screen.Init(); err != nil {
138 // Now we can put the TERM back to what it was before
140 os.Setenv("TERM", oldTerm)
143 if GetGlobalOption("mouse").(bool) {
147 os.Setenv("TCELLDB", tcelldb)
149 // screen.SetStyle(defStyle)
153 flag.Usage = func() {
154 fmt.Println("Usage: micro [OPTIONS] [FILE]...")
155 fmt.Println("-config-dir dir")
156 fmt.Println(" \tSpecify a custom location for the configuration directory")
157 fmt.Println("-startpos LINE,COL")
158 fmt.Println("+LINE:COL")
159 fmt.Println(" \tSpecify a line and column to start the cursor at when opening a buffer")
160 fmt.Println(" \tThis can also be done by opening file:LINE:COL")
161 fmt.Println("-options")
162 fmt.Println(" \tShow all option help")
163 fmt.Println("-version")
164 fmt.Println(" \tShow the version number and information")
166 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")
167 fmt.Println("-option value")
168 fmt.Println(" \tSet `option` to `value` for this session")
169 fmt.Println(" \tFor example: `micro -syntax off file.c`")
170 fmt.Println("\nUse `micro -options` to see the full list of configuration options")
173 optionFlags := make(map[string]*string)
175 for k, v := range DefaultGlobalSettings() {
176 optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'", k, v))
182 // If -version was passed
183 fmt.Println("Version:", Version)
184 fmt.Println("Commit hash:", CommitHash)
185 fmt.Println("Compiled on", CompileDate)
190 // If -options was passed
191 for k, v := range DefaultGlobalSettings() {
192 fmt.Printf("-%s value\n", k)
193 fmt.Printf(" \tDefault value: '%v'\n", v)
211 err = InitColorscheme()
218 // If we have an error, we can exit cleanly and not completely
219 // mess up the terminal being worked in
220 // In other words we need to shut down tcell before the program crashes
222 if err := recover(); err != nil {
224 fmt.Println("Micro encountered an error:", err)
225 // Print the stack trace too
226 fmt.Print(errors.Wrap(err, 2).ErrorStack())
231 b, err := NewBufferFromFile(os.Args[1])
237 width, height := screen.Size()
239 w := NewWindow(0, 0, width/2, height/2, b)
241 for i := 0; i < 5; i++ {
244 w.DisplayStatusLine()
246 time.Sleep(200 * time.Millisecond)
250 // time.Sleep(2 * time.Second)