-
Notifications
You must be signed in to change notification settings - Fork 19
/
loader.go
258 lines (212 loc) · 5.95 KB
/
loader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
package cfg
import (
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"github.com/felixangell/strife"
// fork of BurntSushi with hexadecimal support.
"github.com/felixangell/toml"
)
// TODO:
// - make the $HOME/.phi-editor folder if it doesn't exist
// - make the $HOME/.phi-editor/config.toml file if it doesn't exist
// - write a default toml file
//
const (
CONFIG_DIR_PATH = "/.phi-editor/"
CONFIG_TOML_FILE = "config.toml"
)
// this is the absolute path to the
// config.toml file. todo rename/refactor
var CONFIG_FULL_PATH string = ""
// the absolute path to the config directory
// rename/refactor due here too!
var configDirAbsPath string = ""
// TODO we only had double key combos
// e.g. cmd+s. we want to handle things
// like cmd+alt+s
type shortcutRegister struct {
Supers map[string]string
Controls map[string]string
}
var Shortcuts = &shortcutRegister{
Supers: map[string]string{},
Controls: map[string]string{},
}
func loadSyntaxDef(lang string) *LanguageSyntaxConfig {
languagePath := filepath.Join(configDirAbsPath, "syntax", lang+".toml")
log.Println("Loading lang from ", languagePath)
syntaxTomlData, err := ioutil.ReadFile(languagePath)
if err != nil {
log.Println("Failed to load highlighting for language '"+lang+"' from path: ", languagePath)
return nil
}
var conf = &LanguageSyntaxConfig{}
if _, err := toml.Decode(string(syntaxTomlData), conf); err != nil {
panic(err)
}
log.Println("Loaded syntax definition for language", lang)
return conf
}
func findFontFolder() string {
// TODO
return "/usr/share/fonts/"
}
func configureAndValidate(conf *TomlConfig) {
// fonts
log.Println("Configuring fonts")
{
var fontFolder string
switch runtime.GOOS {
case "windows":
fontFolder = filepath.Join(os.Getenv("WINDIR"), "fonts")
case "darwin":
fontFolder = "/Library/Fonts/"
case "linux":
fontFolder = findFontFolder()
}
// we only support ttf at the moment.
fontPath := filepath.Join(fontFolder, conf.Editor.Font_Face) + ".ttf"
if _, err := os.Stat(fontPath); os.IsNotExist(err) {
log.Fatal("No such font '" + fontPath + "'")
// TODO cool error messages for the toml format?
os.Exit(0)
}
// load the font!
font, err := strife.LoadFont(fontPath, conf.Editor.Font_Size)
if err != nil {
panic(err)
}
conf.Editor.Loaded_Font = font
}
// config & validate the keyboard shortcuts
log.Println("Configuring keyboard shortcuts")
{
// keyboard commands
for commandName, cmd := range conf.Commands {
shortcut := cmd.Shortcut
vals := strings.Split(shortcut, "+")
// TODO handle conflicts
switch vals[0] {
case "super":
Shortcuts.Supers[vals[1]] = commandName
case "ctrl":
Shortcuts.Controls[vals[1]] = commandName
}
}
}
log.Println("Syntax Highlighting")
{
syntaxSet := []*LanguageSyntaxConfig{}
conf.associations = map[string]*LanguageSyntaxConfig{}
for lang, extSet := range conf.Associations {
log.Println(lang, "=>", extSet.Extensions)
languageConfig := loadSyntaxDef(lang)
// check for errors here
syntaxSet = append(syntaxSet, languageConfig)
for _, ext := range extSet.Extensions {
log.Println("registering", ext, "as", lang)
conf.associations[ext] = languageConfig
}
}
// go through each language
// and store the matches keywords
// as a hashmap for faster lookup
// in addition to this we compile any
// regular expressions if necessary.
for _, language := range syntaxSet {
for _, syn := range language.Syntax {
syn.MatchList = map[string]bool{}
if syn.Pattern != "" {
regex, err := regexp.Compile(syn.Pattern)
if err != nil {
log.Println(err.Error())
continue
}
syn.CompiledPattern = regex
} else {
for _, item := range syn.Match {
if _, ok := syn.MatchList[item]; ok {
log.Println("Warning duplicate match item '" + item + "'")
continue
}
syn.MatchList[item] = true
}
}
}
}
}
}
func Setup() TomlConfig {
log.Println("Setting up Phi Editor")
home := os.Getenv("HOME")
if runtime.GOOS == "windows" {
home = os.Getenv("USERPROFILE")
}
CONFIG_DIR := filepath.Join(home, CONFIG_DIR_PATH)
configDirAbsPath = CONFIG_DIR
CONFIG_PATH := filepath.Join(CONFIG_DIR, CONFIG_TOML_FILE)
// this folder is where we store all of the language syntax
SYNTAX_CONFIG_DIR := filepath.Join(CONFIG_DIR, "syntax")
CONFIG_FULL_PATH = CONFIG_PATH
// if the user doesn't have a /.phi-editor
// directory we create it for them.
if _, err := os.Stat(CONFIG_DIR); os.IsNotExist(err) {
if err := os.Mkdir(CONFIG_DIR, 0775); err != nil {
panic(err)
}
}
// try make the syntax config folder.
if _, err := os.Stat(SYNTAX_CONFIG_DIR); os.IsNotExist(err) {
if err := os.Mkdir(SYNTAX_CONFIG_DIR, 0775); err != nil {
panic(err)
}
// load all of the default language syntax
for name, syntaxDef := range DefaultSyntaxSet {
languagePath := filepath.Join(SYNTAX_CONFIG_DIR, name+".toml")
if _, err := os.Stat(languagePath); os.IsNotExist(err) {
file, err := os.Create(languagePath)
if err != nil {
panic(err)
}
defer file.Close()
if _, err := file.Write([]byte(syntaxDef)); err != nil {
panic(err)
}
log.Println("Wrote syntax for language '" + name + "'")
}
}
}
// make sure a config.toml file exists in the
// phi-editor directory.
if _, err := os.Stat(CONFIG_PATH); os.IsNotExist(err) {
configFile, fileCreateErr := os.Create(CONFIG_PATH)
if fileCreateErr != nil {
panic(fileCreateErr)
}
defer configFile.Close()
// write some stuff
_, writeErr := configFile.Write([]byte(DEFUALT_TOML_CONFIG))
if writeErr != nil {
panic(writeErr)
}
configFile.Sync()
}
if _, err := os.Open(CONFIG_PATH); err != nil {
panic(err)
}
configTomlData, err := ioutil.ReadFile(CONFIG_PATH)
if err != nil {
panic(err)
}
var conf TomlConfig
if _, err := toml.Decode(string(configTomlData), &conf); err != nil {
panic(err)
}
configureAndValidate(&conf)
return conf
}