You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
3.2 KiB
Go
111 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"ccat/stack"
|
|
"embed"
|
|
"errors"
|
|
"io/fs"
|
|
"os"
|
|
"os/user"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
//go:embed config
|
|
var storedConfigs embed.FS // Embed the folder containing config files
|
|
|
|
func runningOnWindows() bool {
|
|
return runtime.GOOS == "windows"
|
|
}
|
|
|
|
// generateDefaultConfigs is used to generate a folder of default config files
|
|
// for common languages. These default config files are embedded into the program, and will
|
|
// be outputted into a directory.
|
|
//
|
|
// If there is an error encountered, the error is returned.
|
|
func generateDefaultConfigs() error {
|
|
|
|
var configOutputPath string // Location of config files, depends on OS
|
|
if runningOnWindows() {
|
|
configOutputPath = "%APPDATA%\\ccat"
|
|
} else {
|
|
currentUser, err := user.Current()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
configOutputPath = filepath.Join("/home/" + currentUser.Username + "/.config/ccat/")
|
|
}
|
|
err := os.MkdirAll(configOutputPath, 0755)
|
|
if err != nil {
|
|
if os.IsExist(err) {
|
|
return errors.New("Directory already exists.")
|
|
} else {
|
|
return errors.New("Unable to create directory.")
|
|
}
|
|
}
|
|
|
|
// Copy each folder from the embedded filesystem, into the destination path
|
|
err = fs.WalkDir(storedConfigs, "config", func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if d.IsDir() { // Skip directories
|
|
return nil
|
|
}
|
|
relPath, _ := filepath.Rel("config", path)
|
|
dstPath := filepath.Join(configOutputPath, relPath) // Destination path
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.WriteFile(dstPath, data, 0644); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
return nil
|
|
}
|
|
|
|
// loadConfig takes in the filename of a config file. It reads the file,
|
|
// and returns a stack of RegColors, with the item at the bottom being the one that
|
|
// was read first. This ensures that, _when accessing the RegColors in the stack, the last
|
|
// one (ie. the one that was read first) has highest precedence_.
|
|
// If there is an error compiling the regular expressions, the error is returned.
|
|
func loadConfig(configFilename string) (stack.Stack[regColor], error) {
|
|
configFile, err := os.ReadFile(configFilename)
|
|
if err != nil {
|
|
return *stack.NewStack[regColor](0), err
|
|
}
|
|
|
|
// Here, I create a MapSlice. This is a slice of key-value pairs, and will
|
|
// store the results of unmarshalling the YAML file.
|
|
tempMapSlice := yaml.MapSlice{}
|
|
if err := yaml.Unmarshal(configFile, &tempMapSlice); err != nil {
|
|
return *stack.NewStack[regColor](0), err
|
|
}
|
|
|
|
// Here, I create the stack which will eventually be returned.
|
|
// Each element of the MapSlice (created above) stores the key and value of a line
|
|
// in the file.
|
|
// Each regex string is compiled, and if there is an error, that error is
|
|
// returned.
|
|
regColorStack := stack.NewStack[regColor](len(strings.Split(string(configFile), "\n"))) // The stack will have the same size as the number of lines in the file
|
|
for _, item := range tempMapSlice {
|
|
re := regexp.MustCompile(item.Key.(string))
|
|
clr, err := newColor(item.Value.(string))
|
|
if err != nil {
|
|
return *stack.NewStack[regColor](0), err
|
|
}
|
|
// If we got past the errors, then the color _must_ be valid.
|
|
regColorStack.Push(regColor{re, clr})
|
|
}
|
|
|
|
return *regColorStack, nil
|
|
}
|