]> git.lizzy.rs Git - micro.git/blob - cmd/micro/micro.go
c37467594b6317a9a27d7bf5a5d2cbb2c0f0a116
[micro.git] / cmd / micro / micro.go
1 package main
2
3 import (
4         "flag"
5         "fmt"
6         "os"
7
8         "github.com/go-errors/errors"
9         "github.com/zyedidia/micro/cmd/micro/buffer"
10         "github.com/zyedidia/micro/cmd/micro/config"
11         "github.com/zyedidia/micro/cmd/micro/screen"
12         "github.com/zyedidia/micro/cmd/micro/util"
13         "github.com/zyedidia/tcell"
14 )
15
16 const (
17         doubleClickThreshold = 400 // How many milliseconds to wait before a second click is not a double click
18         autosaveTime         = 8   // Number of seconds to wait before autosaving
19 )
20
21 var (
22         // Version is the version number or commit hash
23         // These variables should be set by the linker when compiling
24         Version = "0.0.0-unknown"
25         // CommitHash is the commit this version was built on
26         CommitHash = "Unknown"
27         // CompileDate is the date this binary was compiled on
28         CompileDate = "Unknown"
29         // Debug logging
30         Debug = "ON"
31
32         // Event channel
33         events   chan tcell.Event
34         autosave chan bool
35
36         // How many redraws have happened
37         numRedraw uint
38
39         // Command line flags
40         flagVersion   = flag.Bool("version", false, "Show the version number and information")
41         flagStartPos  = flag.String("startpos", "", "LINE,COL to start the cursor at when opening a buffer.")
42         flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
43         flagOptions   = flag.Bool("options", false, "Show all option help")
44 )
45
46 func InitFlags() {
47         flag.Usage = func() {
48                 fmt.Println("Usage: micro [OPTIONS] [FILE]...")
49                 fmt.Println("-config-dir dir")
50                 fmt.Println("    \tSpecify a custom location for the configuration directory")
51                 fmt.Println("-startpos LINE,COL")
52                 fmt.Println("+LINE:COL")
53                 fmt.Println("    \tSpecify a line and column to start the cursor at when opening a buffer")
54                 fmt.Println("    \tThis can also be done by opening file:LINE:COL")
55                 fmt.Println("-options")
56                 fmt.Println("    \tShow all option help")
57                 fmt.Println("-version")
58                 fmt.Println("    \tShow the version number and information")
59
60                 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")
61                 fmt.Println("-option value")
62                 fmt.Println("    \tSet `option` to `value` for this session")
63                 fmt.Println("    \tFor example: `micro -syntax off file.c`")
64                 fmt.Println("\nUse `micro -options` to see the full list of configuration options")
65         }
66
67         optionFlags := make(map[string]*string)
68
69         for k, v := range config.DefaultGlobalSettings() {
70                 optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'", k, v))
71         }
72
73         flag.Parse()
74
75         if *flagVersion {
76                 // If -version was passed
77                 fmt.Println("Version:", Version)
78                 fmt.Println("Commit hash:", CommitHash)
79                 fmt.Println("Compiled on", CompileDate)
80                 os.Exit(0)
81         }
82
83         if *flagOptions {
84                 // If -options was passed
85                 for k, v := range config.DefaultGlobalSettings() {
86                         fmt.Printf("-%s value\n", k)
87                         fmt.Printf("    \tDefault value: '%v'\n", v)
88                 }
89                 os.Exit(0)
90         }
91 }
92
93 func main() {
94         var err error
95
96         InitLog()
97         InitFlags()
98         err = config.InitConfigDir(*flagConfigDir)
99         if err != nil {
100                 util.TermMessage(err)
101         }
102         config.InitRuntimeFiles()
103         err = config.ReadSettings()
104         if err != nil {
105                 util.TermMessage(err)
106         }
107         config.InitGlobalSettings()
108         InitBindings()
109         err = config.InitColorscheme()
110         if err != nil {
111                 util.TermMessage(err)
112         }
113
114         screen.Init()
115
116         // If we have an error, we can exit cleanly and not completely
117         // mess up the terminal being worked in
118         // In other words we need to shut down tcell before the program crashes
119         defer func() {
120                 if err := recover(); err != nil {
121                         screen.Screen.Fini()
122                         fmt.Println("Micro encountered an error:", err)
123                         // Print the stack trace too
124                         fmt.Print(errors.Wrap(err, 2).ErrorStack())
125                         os.Exit(1)
126                 }
127         }()
128
129         TryBindKey("Ctrl-z", "Undo", true)
130
131         b, err := buffer.NewBufferFromFile(os.Args[1])
132
133         if err != nil {
134                 util.TermMessage(err)
135         }
136
137         width, height := screen.Screen.Size()
138         w := NewWindow(0, 0, width, height-1, b)
139
140         a := NewBufActionHandler(b, w)
141
142         // Here is the event loop which runs in a separate thread
143         go func() {
144                 events = make(chan tcell.Event)
145                 for {
146                         // TODO: fix race condition with screen.Screen = nil
147                         events <- screen.Screen.PollEvent()
148                 }
149         }()
150
151         for {
152                 // Display everything
153                 w.Clear()
154                 w.DisplayBuffer()
155                 w.DisplayStatusLine()
156                 screen.Screen.Show()
157
158                 var event tcell.Event
159
160                 // Check for new events
161                 select {
162                 case event = <-events:
163                 }
164
165                 if event != nil {
166                         a.HandleEvent(event)
167                 }
168         }
169
170         screen.Screen.Fini()
171 }