2018-08-27 22:53:10 +03:00
|
|
|
package config
|
2016-09-15 17:42:45 +03:00
|
|
|
|
|
|
|
import (
|
2019-12-28 04:28:25 +03:00
|
|
|
"errors"
|
2016-09-15 17:42:45 +03:00
|
|
|
"io/ioutil"
|
2019-09-02 23:38:14 +03:00
|
|
|
"log"
|
2016-09-16 18:02:10 +03:00
|
|
|
"os"
|
2016-09-15 17:42:45 +03:00
|
|
|
"path"
|
|
|
|
"path/filepath"
|
2019-09-02 23:38:14 +03:00
|
|
|
"regexp"
|
2019-03-19 01:40:53 +03:00
|
|
|
"strings"
|
2021-08-25 05:02:29 +03:00
|
|
|
|
|
|
|
rt "github.com/zyedidia/micro/v2/runtime"
|
2016-09-15 17:42:45 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-12-29 02:53:51 +03:00
|
|
|
RTColorscheme = 0
|
|
|
|
RTSyntax = 1
|
|
|
|
RTHelp = 2
|
|
|
|
RTPlugin = 3
|
|
|
|
RTSyntaxHeader = 4
|
2016-09-15 17:42:45 +03:00
|
|
|
)
|
|
|
|
|
2020-01-31 22:21:27 +03:00
|
|
|
var (
|
|
|
|
NumTypes = 5 // How many filetypes are there
|
|
|
|
)
|
|
|
|
|
|
|
|
type RTFiletype int
|
2018-08-26 06:06:44 +03:00
|
|
|
|
2016-09-15 17:42:45 +03:00
|
|
|
// RuntimeFile allows the program to read runtime data like colorschemes or syntax files
|
|
|
|
type RuntimeFile interface {
|
|
|
|
// Name returns a name of the file without paths or extensions
|
|
|
|
Name() string
|
|
|
|
// Data returns the content of the file.
|
|
|
|
Data() ([]byte, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// allFiles contains all available files, mapped by filetype
|
2020-01-31 22:21:27 +03:00
|
|
|
var allFiles [][]RuntimeFile
|
|
|
|
var realFiles [][]RuntimeFile
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
allFiles = make([][]RuntimeFile, NumTypes)
|
|
|
|
realFiles = make([][]RuntimeFile, NumTypes)
|
|
|
|
}
|
|
|
|
|
2020-02-09 02:31:06 +03:00
|
|
|
// NewRTFiletype creates a new RTFiletype
|
2020-01-31 22:21:27 +03:00
|
|
|
func NewRTFiletype() int {
|
|
|
|
NumTypes++
|
|
|
|
allFiles = append(allFiles, []RuntimeFile{})
|
|
|
|
realFiles = append(realFiles, []RuntimeFile{})
|
|
|
|
return NumTypes - 1
|
|
|
|
}
|
2016-09-15 17:42:45 +03:00
|
|
|
|
|
|
|
// some file on filesystem
|
|
|
|
type realFile string
|
|
|
|
|
|
|
|
// some asset file
|
|
|
|
type assetFile string
|
|
|
|
|
|
|
|
// some file on filesystem but with a different name
|
|
|
|
type namedFile struct {
|
|
|
|
realFile
|
|
|
|
name string
|
|
|
|
}
|
|
|
|
|
2017-04-15 21:45:44 +03:00
|
|
|
// a file with the data stored in memory
|
|
|
|
type memoryFile struct {
|
|
|
|
name string
|
|
|
|
data []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mf memoryFile) Name() string {
|
|
|
|
return mf.name
|
|
|
|
}
|
|
|
|
func (mf memoryFile) Data() ([]byte, error) {
|
|
|
|
return mf.data, nil
|
|
|
|
}
|
|
|
|
|
2016-09-15 17:42:45 +03:00
|
|
|
func (rf realFile) Name() string {
|
|
|
|
fn := filepath.Base(string(rf))
|
|
|
|
return fn[:len(fn)-len(filepath.Ext(fn))]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rf realFile) Data() ([]byte, error) {
|
|
|
|
return ioutil.ReadFile(string(rf))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (af assetFile) Name() string {
|
|
|
|
fn := path.Base(string(af))
|
|
|
|
return fn[:len(fn)-len(path.Ext(fn))]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (af assetFile) Data() ([]byte, error) {
|
2021-08-25 05:02:29 +03:00
|
|
|
return rt.Asset(string(af))
|
2016-09-15 17:42:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (nf namedFile) Name() string {
|
|
|
|
return nf.name
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddRuntimeFile registers a file for the given filetype
|
2018-08-26 06:06:44 +03:00
|
|
|
func AddRuntimeFile(fileType RTFiletype, file RuntimeFile) {
|
2016-09-15 17:42:45 +03:00
|
|
|
allFiles[fileType] = append(allFiles[fileType], file)
|
|
|
|
}
|
|
|
|
|
2019-12-29 05:26:22 +03:00
|
|
|
// AddRealRuntimeFile registers a file for the given filetype
|
|
|
|
func AddRealRuntimeFile(fileType RTFiletype, file RuntimeFile) {
|
|
|
|
allFiles[fileType] = append(allFiles[fileType], file)
|
|
|
|
realFiles[fileType] = append(realFiles[fileType], file)
|
|
|
|
}
|
|
|
|
|
2016-09-15 17:42:45 +03:00
|
|
|
// AddRuntimeFilesFromDirectory registers each file from the given directory for
|
|
|
|
// the filetype which matches the file-pattern
|
2018-08-26 06:06:44 +03:00
|
|
|
func AddRuntimeFilesFromDirectory(fileType RTFiletype, directory, pattern string) {
|
2016-09-15 17:42:45 +03:00
|
|
|
files, _ := ioutil.ReadDir(directory)
|
|
|
|
for _, f := range files {
|
|
|
|
if ok, _ := filepath.Match(pattern, f.Name()); !f.IsDir() && ok {
|
|
|
|
fullPath := filepath.Join(directory, f.Name())
|
2019-12-29 05:26:22 +03:00
|
|
|
AddRealRuntimeFile(fileType, realFile(fullPath))
|
2016-09-15 17:42:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-16 23:15:44 +03:00
|
|
|
// AddRuntimeFilesFromAssets registers each file from the given asset-directory for
|
2016-09-15 17:42:45 +03:00
|
|
|
// the filetype which matches the file-pattern
|
2018-08-26 06:06:44 +03:00
|
|
|
func AddRuntimeFilesFromAssets(fileType RTFiletype, directory, pattern string) {
|
2021-08-25 05:02:29 +03:00
|
|
|
files, err := rt.AssetDir(directory)
|
2016-09-15 17:42:45 +03:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, f := range files {
|
|
|
|
if ok, _ := path.Match(pattern, f); ok {
|
|
|
|
AddRuntimeFile(fileType, assetFile(path.Join(directory, f)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindRuntimeFile finds a runtime file of the given filetype and name
|
|
|
|
// will return nil if no file was found
|
2018-08-26 06:06:44 +03:00
|
|
|
func FindRuntimeFile(fileType RTFiletype, name string) RuntimeFile {
|
2016-09-15 17:42:45 +03:00
|
|
|
for _, f := range ListRuntimeFiles(fileType) {
|
|
|
|
if f.Name() == name {
|
|
|
|
return f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-09-16 23:15:44 +03:00
|
|
|
// ListRuntimeFiles lists all known runtime files for the given filetype
|
2018-08-26 06:06:44 +03:00
|
|
|
func ListRuntimeFiles(fileType RTFiletype) []RuntimeFile {
|
|
|
|
return allFiles[fileType]
|
2016-09-15 17:42:45 +03:00
|
|
|
}
|
|
|
|
|
2019-12-29 05:26:22 +03:00
|
|
|
// ListRealRuntimeFiles lists all real runtime files (on disk) for a filetype
|
|
|
|
// these runtime files will be ones defined by the user and loaded from the config directory
|
|
|
|
func ListRealRuntimeFiles(fileType RTFiletype) []RuntimeFile {
|
|
|
|
return realFiles[fileType]
|
|
|
|
}
|
|
|
|
|
2016-09-16 23:15:44 +03:00
|
|
|
// InitRuntimeFiles initializes all assets file and the config directory
|
2016-09-15 17:42:45 +03:00
|
|
|
func InitRuntimeFiles() {
|
2018-08-26 06:06:44 +03:00
|
|
|
add := func(fileType RTFiletype, dir, pattern string) {
|
2018-08-27 22:53:10 +03:00
|
|
|
AddRuntimeFilesFromDirectory(fileType, filepath.Join(ConfigDir, dir), pattern)
|
2016-09-15 17:42:45 +03:00
|
|
|
AddRuntimeFilesFromAssets(fileType, path.Join("runtime", dir), pattern)
|
|
|
|
}
|
|
|
|
|
2016-09-16 23:15:44 +03:00
|
|
|
add(RTColorscheme, "colorschemes", "*.micro")
|
2017-02-18 23:17:07 +03:00
|
|
|
add(RTSyntax, "syntax", "*.yaml")
|
2019-12-29 05:26:22 +03:00
|
|
|
add(RTSyntaxHeader, "syntax", "*.hdr")
|
2016-09-16 23:15:44 +03:00
|
|
|
add(RTHelp, "help", "*.md")
|
2016-09-19 15:40:56 +03:00
|
|
|
|
2019-08-06 07:36:58 +03:00
|
|
|
initlua := filepath.Join(ConfigDir, "init.lua")
|
|
|
|
if _, err := os.Stat(initlua); !os.IsNotExist(err) {
|
|
|
|
p := new(Plugin)
|
|
|
|
p.Name = "initlua"
|
2019-12-28 04:28:25 +03:00
|
|
|
p.DirName = "initlua"
|
2019-08-06 07:36:58 +03:00
|
|
|
p.Srcs = append(p.Srcs, realFile(initlua))
|
|
|
|
Plugins = append(Plugins, p)
|
|
|
|
}
|
|
|
|
|
2018-08-27 22:53:10 +03:00
|
|
|
// Search ConfigDir for plugin-scripts
|
2019-09-02 23:38:14 +03:00
|
|
|
plugdir := filepath.Join(ConfigDir, "plug")
|
2019-03-19 01:40:53 +03:00
|
|
|
files, _ := ioutil.ReadDir(plugdir)
|
2019-09-02 23:38:14 +03:00
|
|
|
|
|
|
|
isID := regexp.MustCompile(`^[_A-Za-z0-9]+$`).MatchString
|
|
|
|
|
2019-03-19 01:40:53 +03:00
|
|
|
for _, d := range files {
|
|
|
|
if d.IsDir() {
|
|
|
|
srcs, _ := ioutil.ReadDir(filepath.Join(plugdir, d.Name()))
|
|
|
|
p := new(Plugin)
|
|
|
|
p.Name = d.Name()
|
2019-12-28 04:28:25 +03:00
|
|
|
p.DirName = d.Name()
|
2019-03-19 01:40:53 +03:00
|
|
|
for _, f := range srcs {
|
|
|
|
if strings.HasSuffix(f.Name(), ".lua") {
|
|
|
|
p.Srcs = append(p.Srcs, realFile(filepath.Join(plugdir, d.Name(), f.Name())))
|
2020-02-02 07:54:38 +03:00
|
|
|
} else if strings.HasSuffix(f.Name(), ".json") {
|
|
|
|
data, err := ioutil.ReadFile(filepath.Join(plugdir, d.Name(), f.Name()))
|
2019-08-07 08:24:03 +03:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2020-02-02 07:54:38 +03:00
|
|
|
p.Info, err = NewPluginInfo(data)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2019-09-02 23:38:14 +03:00
|
|
|
p.Name = p.Info.Name
|
2019-03-19 01:40:53 +03:00
|
|
|
}
|
2016-09-19 15:40:56 +03:00
|
|
|
}
|
2019-09-02 23:38:14 +03:00
|
|
|
|
2020-01-29 07:49:51 +03:00
|
|
|
if !isID(p.Name) || len(p.Srcs) <= 0 {
|
|
|
|
log.Println(p.Name, "is not a plugin")
|
2019-09-02 23:38:14 +03:00
|
|
|
continue
|
|
|
|
}
|
2019-03-19 01:40:53 +03:00
|
|
|
Plugins = append(Plugins, p)
|
2016-09-19 15:40:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-19 01:40:53 +03:00
|
|
|
plugdir = filepath.Join("runtime", "plugins")
|
2021-08-25 05:02:29 +03:00
|
|
|
if files, err := rt.AssetDir(plugdir); err == nil {
|
2019-03-19 01:40:53 +03:00
|
|
|
for _, d := range files {
|
2021-08-25 05:02:29 +03:00
|
|
|
if srcs, err := rt.AssetDir(filepath.Join(plugdir, d)); err == nil {
|
2019-03-19 01:40:53 +03:00
|
|
|
p := new(Plugin)
|
|
|
|
p.Name = d
|
2019-12-28 04:28:25 +03:00
|
|
|
p.DirName = d
|
2019-08-07 08:24:03 +03:00
|
|
|
p.Default = true
|
2019-03-19 01:40:53 +03:00
|
|
|
for _, f := range srcs {
|
|
|
|
if strings.HasSuffix(f, ".lua") {
|
|
|
|
p.Srcs = append(p.Srcs, assetFile(filepath.Join(plugdir, d, f)))
|
2020-02-02 07:54:38 +03:00
|
|
|
} else if strings.HasSuffix(f, ".json") {
|
2021-08-25 05:02:29 +03:00
|
|
|
data, err := rt.Asset(filepath.Join(plugdir, d, f))
|
2020-02-02 07:54:38 +03:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
p.Info, err = NewPluginInfo(data)
|
2019-08-07 08:24:03 +03:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2019-09-02 23:38:14 +03:00
|
|
|
p.Name = p.Info.Name
|
2019-03-19 01:40:53 +03:00
|
|
|
}
|
|
|
|
}
|
2020-01-29 07:49:51 +03:00
|
|
|
if !isID(p.Name) || len(p.Srcs) <= 0 {
|
|
|
|
log.Println(p.Name, "is not a plugin")
|
2019-09-02 23:38:14 +03:00
|
|
|
continue
|
|
|
|
}
|
2019-03-19 01:40:53 +03:00
|
|
|
Plugins = append(Plugins, p)
|
2016-09-19 15:40:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-09-15 17:42:45 +03:00
|
|
|
}
|
|
|
|
|
2016-09-16 23:15:44 +03:00
|
|
|
// PluginReadRuntimeFile allows plugin scripts to read the content of a runtime file
|
2018-08-26 06:06:44 +03:00
|
|
|
func PluginReadRuntimeFile(fileType RTFiletype, name string) string {
|
2016-09-15 17:42:45 +03:00
|
|
|
if file := FindRuntimeFile(fileType, name); file != nil {
|
|
|
|
if data, err := file.Data(); err == nil {
|
|
|
|
return string(data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2016-09-16 23:15:44 +03:00
|
|
|
// PluginListRuntimeFiles allows plugins to lists all runtime files of the given type
|
2018-08-26 06:06:44 +03:00
|
|
|
func PluginListRuntimeFiles(fileType RTFiletype) []string {
|
2016-09-15 17:42:45 +03:00
|
|
|
files := ListRuntimeFiles(fileType)
|
|
|
|
result := make([]string, len(files))
|
|
|
|
for i, f := range files {
|
|
|
|
result[i] = f.Name()
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
2016-09-16 18:02:10 +03:00
|
|
|
|
2016-09-16 23:15:44 +03:00
|
|
|
// PluginAddRuntimeFile adds a file to the runtime files for a plugin
|
2019-12-28 04:28:25 +03:00
|
|
|
func PluginAddRuntimeFile(plugin string, filetype RTFiletype, filePath string) error {
|
|
|
|
pl := FindPlugin(plugin)
|
|
|
|
if pl == nil {
|
|
|
|
return errors.New("Plugin " + plugin + " does not exist")
|
|
|
|
}
|
|
|
|
pldir := pl.DirName
|
|
|
|
fullpath := filepath.Join(ConfigDir, "plug", pldir, filePath)
|
2016-09-16 18:02:10 +03:00
|
|
|
if _, err := os.Stat(fullpath); err == nil {
|
2020-01-02 09:18:16 +03:00
|
|
|
AddRealRuntimeFile(filetype, realFile(fullpath))
|
2016-09-16 18:02:10 +03:00
|
|
|
} else {
|
2019-12-28 04:28:25 +03:00
|
|
|
fullpath = path.Join("runtime", "plugins", pldir, filePath)
|
2016-09-16 18:02:10 +03:00
|
|
|
AddRuntimeFile(filetype, assetFile(fullpath))
|
|
|
|
}
|
2019-12-28 04:28:25 +03:00
|
|
|
return nil
|
2016-09-16 18:02:10 +03:00
|
|
|
}
|
2016-09-16 23:15:44 +03:00
|
|
|
|
|
|
|
// PluginAddRuntimeFilesFromDirectory adds files from a directory to the runtime files for a plugin
|
2019-12-28 04:28:25 +03:00
|
|
|
func PluginAddRuntimeFilesFromDirectory(plugin string, filetype RTFiletype, directory, pattern string) error {
|
|
|
|
pl := FindPlugin(plugin)
|
|
|
|
if pl == nil {
|
|
|
|
return errors.New("Plugin " + plugin + " does not exist")
|
|
|
|
}
|
|
|
|
pldir := pl.DirName
|
|
|
|
fullpath := filepath.Join(ConfigDir, "plug", pldir, directory)
|
2016-09-16 23:15:44 +03:00
|
|
|
if _, err := os.Stat(fullpath); err == nil {
|
|
|
|
AddRuntimeFilesFromDirectory(filetype, fullpath, pattern)
|
|
|
|
} else {
|
2019-12-28 04:28:25 +03:00
|
|
|
fullpath = path.Join("runtime", "plugins", pldir, directory)
|
2016-09-16 23:15:44 +03:00
|
|
|
AddRuntimeFilesFromAssets(filetype, fullpath, pattern)
|
|
|
|
}
|
2019-12-28 04:28:25 +03:00
|
|
|
return nil
|
2016-09-16 23:15:44 +03:00
|
|
|
}
|
2017-04-15 21:45:44 +03:00
|
|
|
|
|
|
|
// PluginAddRuntimeFileFromMemory adds a file to the runtime files for a plugin from a given string
|
2019-12-28 04:28:25 +03:00
|
|
|
func PluginAddRuntimeFileFromMemory(filetype RTFiletype, filename, data string) {
|
2020-01-02 09:18:16 +03:00
|
|
|
AddRealRuntimeFile(filetype, memoryFile{filename, []byte(data)})
|
2017-04-15 21:45:44 +03:00
|
|
|
}
|