This repository has been archived by the owner on Jun 5, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
langs.go
208 lines (167 loc) · 4.26 KB
/
langs.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
package lib
import (
"fmt"
"io/ioutil"
"os"
"path"
"sort"
"strings"
"gopkg.in/yaml.v3"
"cuelang.org/go/cue"
"github.com/hofstadter-io/mvs/lib/langs"
"github.com/hofstadter-io/mvs/lib/modder"
"github.com/hofstadter-io/mvs/lib/util"
)
// FROM the USER's HOME dir
const GLOBAL_MVS_CONFIG = ".mvs/config.cue"
const LOCAL_MVS_CONFIG = ".mvsconfig.cue"
var (
// Default known modderr
LangModderMap = langs.DefaultModders
)
const knownLangMessage = `
Known Languages:
%s
For more info on a language:
mvs info <lang>
`
func DiscoverLangs() (langs []string) {
for lang, mdr := range LangModderMap {
// Let's check for a custom
_, err := os.Lstat(mdr.ModFile)
if err != nil {
if _, ok := err.(*os.PathError); !ok && err.Error() != "file does not exist" && err.Error() != "no such file or directory" {
fmt.Println(err)
// return err // more of a warning right now
}
// file not found
continue
}
// we found a mod file
langs = append(langs, lang)
}
return langs
}
func KnownLangs() string {
langs := []string{}
for lang, _ := range LangModderMap {
langs = append(langs, lang)
}
sort.Strings(langs)
langStr := strings.Join(langs, "\n ")
msg := fmt.Sprintf(knownLangMessage, langStr)
return msg
}
const unknownLangMessage = `
Unknown language %q.
Please check the following files for definitions
%s (in the current directory)
$HOME/%s
To see a list of known languages from the current directory:
mvs info
`
func LangInfo(lang string) (string, error) {
if lang == "" {
return KnownLangs(), nil
}
modder, ok := LangModderMap[lang]
if !ok {
return "", fmt.Errorf(unknownLangMessage, lang, LOCAL_MVS_CONFIG, GLOBAL_MVS_CONFIG)
}
// fmt.Printf("=====\n%#+v\n=====\n", modder)
// TODO output as cue
bytes, err := yaml.Marshal(modder)
if err != nil {
return "", err
}
return string(bytes), nil
}
func InitLangs() {
var err error
cueSpec, err := util.CueRuntime.Compile("spec.cue", langs.ModderSpec)
if err != nil {
panic(err)
}
err = cueSpec.Value().Validate()
if err != nil {
panic(err)
}
for lang, cueString := range langs.DefaultModdersCue {
var mdrMap map[string]*modder.Modder
cueLang, err := util.CueRuntime.Compile(lang, cueString)
if err != nil {
panic(err)
}
cueLangMerged := cue.Merge(cueSpec, cueLang)
err = cueLangMerged.Value().Validate()
if err != nil {
panic(err)
}
err = cueLang.Value().Decode(&mdrMap)
if err != nil {
panic(err)
}
_, ok := mdrMap[lang]
if !ok || len(mdrMap) != 1 {
panic(fmt.Errorf("invalid builtin language default %s", lang))
}
mdrMap[lang].CueInstance = cueLangMerged
langs.DefaultModders[lang] = mdrMap[lang]
}
homedir := util.UserHomeDir()
// Global Language Modder Config
err = initFromFile(path.Join(homedir, GLOBAL_MVS_CONFIG))
if err != nil {
fmt.Println(err)
}
// Local Language Modder Config
err = initFromFile(LOCAL_MVS_CONFIG)
if err != nil {
fmt.Println(err)
}
}
func initFromFile(filepath string) error {
// Reand an MVS config file (cue format)
bytes, err := ioutil.ReadFile(filepath)
if err != nil {
if _, ok := err.(*os.PathError); !ok && err.Error() != "file does not exist" && err.Error() != "no such file or directory" {
return err
}
// The user has not setup a global $HOME/.mvs/mvsconfig file
return nil
}
var mdrMap map[string]*modder.Modder
// Compile the config into cue
i, err := util.CueRuntime.Compile(filepath, string(bytes))
if err != nil {
return err
}
err = i.Value().Decode(&mdrMap)
if err != nil {
return err
}
iMerged := i
// For each language in the local config file
for lang, _ := range mdrMap {
// TODO, do we want to merge every language in the config with the spec?
// If we find this is a language override,
// merge with the spec and builtin defaults (which were previously merged)
// TODO, maybe check for some value in the config which controls merging with defaults?
_, ok := langs.DefaultModders[lang]
if ok {
langSpec := langs.DefaultModders[lang].CueInstance
iMerged = cue.Merge(i, langSpec)
} else {
fmt.Printf("trying to customize unknown language %s\n", lang)
}
}
// util.PrintCueInstance(iMerged)
err = iMerged.Value().Decode(&mdrMap)
if err != nil {
return err
}
for lang, mdr := range mdrMap {
LangModderMap[lang] = mdr
}
return nil
}